Little-Wire
 All Classes Functions Groups Pages
opendevice.c
1 /* Name: opendevice.c
2  * Project: V-USB host-side library
3  * Author: Christian Starkjohann
4  * Creation Date: 2008-04-10
5  * Tabsize: 4
6  * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
7  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
8  * This Revision: $Id: opendevice.c 740 2009-04-13 18:23:31Z cs $
9  */
10 
11 /*
12 General Description:
13 The functions in this module can be used to find and open a device based on
14 libusb or libusb-win32.
15 */
16 
17 #include <stdio.h>
18 #include "opendevice.h"
19 
20 /* ------------------------------------------------------------------------- */
21 
22 #define MATCH_SUCCESS 1
23 #define MATCH_FAILED 0
24 #define MATCH_ABORT -1
25 
26 /* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */
27 static int _shellStyleMatch(char *text, char *p)
28 {
29 int last, matched, reverse;
30 
31  for(; *p; text++, p++){
32  if(*text == 0 && *p != '*')
33  return MATCH_ABORT;
34  switch(*p){
35  case '\\':
36  /* Literal match with following character. */
37  p++;
38  /* FALLTHROUGH */
39  default:
40  if(*text != *p)
41  return MATCH_FAILED;
42  continue;
43  case '?':
44  /* Match anything. */
45  continue;
46  case '*':
47  while(*++p == '*')
48  /* Consecutive stars act just like one. */
49  continue;
50  if(*p == 0)
51  /* Trailing star matches everything. */
52  return MATCH_SUCCESS;
53  while(*text)
54  if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED)
55  return matched;
56  return MATCH_ABORT;
57  case '[':
58  reverse = p[1] == '^';
59  if(reverse) /* Inverted character class. */
60  p++;
61  matched = MATCH_FAILED;
62  if(p[1] == ']' || p[1] == '-')
63  if(*++p == *text)
64  matched = MATCH_SUCCESS;
65  for(last = *p; *++p && *p != ']'; last = *p)
66  if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p)
67  matched = MATCH_SUCCESS;
68  if(matched == reverse)
69  return MATCH_FAILED;
70  continue;
71  }
72  }
73  return *text == 0;
74 }
75 
76 /* public interface for shell style matching: returns 0 if fails, 1 if matches */
77 static int shellStyleMatch(char *text, char *pattern)
78 {
79  if(pattern == NULL) /* NULL pattern is synonymous to "*" */
80  return 1;
81  return _shellStyleMatch(text, pattern) == MATCH_SUCCESS;
82 }
83 
84 /* ------------------------------------------------------------------------- */
85 
86 int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen)
87 {
88 char buffer[256];
89 int rval, i;
90 
91  if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */
92  return rval;
93  if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0)
94  return rval;
95  if(buffer[1] != USB_DT_STRING){
96  *buf = 0;
97  return 0;
98  }
99  if((unsigned char)buffer[0] < rval)
100  rval = (unsigned char)buffer[0];
101  rval /= 2;
102  /* lossy conversion to ISO Latin1: */
103  for(i=1;i<rval;i++){
104  if(i > buflen) /* destination buffer overflow */
105  break;
106  buf[i-1] = buffer[2 * i];
107  if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
108  buf[i-1] = '?';
109  }
110  buf[i-1] = 0;
111  return i-1;
112 }
113 
114 /* ------------------------------------------------------------------------- */
115 
116 int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp)
117 {
118 struct usb_bus *bus;
119 struct usb_device *dev;
120 usb_dev_handle *handle = NULL;
121 int errorCode = USBOPEN_ERR_NOTFOUND;
122 
123  usb_find_busses();
124  usb_find_devices();
125  for(bus = usb_get_busses(); bus; bus = bus->next){
126  for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */
127  if((vendorID == 0 || dev->descriptor.idVendor == vendorID)
128  && (productID == 0 || dev->descriptor.idProduct == productID)){
129  char vendor[256], product[256], serial[256];
130  int len;
131  handle = usb_open(dev); /* we need to open the device in order to query strings */
132  if(!handle){
133  errorCode = USBOPEN_ERR_ACCESS;
134  if(warningsFp != NULL)
135  fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
136  continue;
137  }
138  /* now check whether the names match: */
139  len = vendor[0] = 0;
140  if(dev->descriptor.iManufacturer > 0){
141  len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor));
142  }
143  if(len < 0){
144  errorCode = USBOPEN_ERR_ACCESS;
145  if(warningsFp != NULL)
146  fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
147  }else{
148  errorCode = USBOPEN_ERR_NOTFOUND;
149  /* printf("seen device from vendor ->%s<-\n", vendor); */
150  if(shellStyleMatch(vendor, vendorNamePattern)){
151  len = product[0] = 0;
152  if(dev->descriptor.iProduct > 0){
153  len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product));
154  }
155  if(len < 0){
156  errorCode = USBOPEN_ERR_ACCESS;
157  if(warningsFp != NULL)
158  fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
159  }else{
160  errorCode = USBOPEN_ERR_NOTFOUND;
161  /* printf("seen product ->%s<-\n", product); */
162  if(shellStyleMatch(product, productNamePattern)){
163  len = serial[0] = 0;
164  if(dev->descriptor.iSerialNumber > 0){
165  len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial));
166  }
167  if(len < 0){
168  errorCode = USBOPEN_ERR_ACCESS;
169  if(warningsFp != NULL)
170  fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
171  }
172  if(shellStyleMatch(serial, serialNamePattern)){
173  if(printMatchingDevicesFp != NULL){
174  if(serial[0] == 0){
175  fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product);
176  }else{
177  fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial);
178  }
179  }else{
180  break;
181  }
182  }
183  }
184  }
185  }
186  }
187  usb_close(handle);
188  handle = NULL;
189  }
190  }
191  if(handle) /* we have found a deice */
192  break;
193  }
194  if(handle != NULL){
195  errorCode = 0;
196  *device = handle;
197  }
198  if(printMatchingDevicesFp != NULL) /* never return an error for listing only */
199  errorCode = 0;
200  return errorCode;
201 }
202 
203 /* ------------------------------------------------------------------------- */