/* Name: opendevice.c * Project: V-USB host-side library * Author: Christian Starkjohann * Creation Date: 2008-04-10 * Tabsize: 4 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) */ /* General Description: The functions in this module can be used to find and open a device based on libusb or libusb-win32. */ #include #include "opendevice.h" /* ------------------------------------------------------------------------- */ #define MATCH_SUCCESS 1 #define MATCH_FAILED 0 #define MATCH_ABORT -1 /* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */ static int _shellStyleMatch(char *text, char *p) { int last, matched, reverse; for(; *p; text++, p++){ if(*text == 0 && *p != '*') return MATCH_ABORT; switch(*p){ case '\\': /* Literal match with following character. */ p++; /* FALLTHROUGH */ default: if(*text != *p) return MATCH_FAILED; continue; case '?': /* Match anything. */ continue; case '*': while(*++p == '*') /* Consecutive stars act just like one. */ continue; if(*p == 0) /* Trailing star matches everything. */ return MATCH_SUCCESS; while(*text) if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED) return matched; return MATCH_ABORT; case '[': reverse = p[1] == '^'; if(reverse) /* Inverted character class. */ p++; matched = MATCH_FAILED; if(p[1] == ']' || p[1] == '-') if(*++p == *text) matched = MATCH_SUCCESS; for(last = *p; *++p && *p != ']'; last = *p) if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p) matched = MATCH_SUCCESS; if(matched == reverse) return MATCH_FAILED; continue; } } return *text == 0; } /* public interface for shell style matching: returns 0 if fails, 1 if matches */ static int shellStyleMatch(char *text, char *pattern) { if(pattern == NULL) /* NULL pattern is synonymous to "*" */ return 1; return _shellStyleMatch(text, pattern) == MATCH_SUCCESS; } /* ------------------------------------------------------------------------- */ int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen) { char buffer[256]; int rval, i; if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ return rval; if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0) return rval; if(buffer[1] != USB_DT_STRING){ *buf = 0; return 0; } if((unsigned char)buffer[0] < rval) rval = (unsigned char)buffer[0]; rval /= 2; /* lossy conversion to ISO Latin1: */ for(i=1;i buflen) /* destination buffer overflow */ break; buf[i-1] = buffer[2 * i]; if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ buf[i-1] = '?'; } buf[i-1] = 0; return i-1; } /* ------------------------------------------------------------------------- */ int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp) { struct usb_bus *bus; struct usb_device *dev; usb_dev_handle *handle = NULL; int errorCode = USBOPEN_ERR_NOTFOUND; usb_find_busses(); usb_find_devices(); for(bus = usb_get_busses(); bus; bus = bus->next){ for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */ if((vendorID == 0 || dev->descriptor.idVendor == vendorID) && (productID == 0 || dev->descriptor.idProduct == productID)){ char vendor[256], product[256], serial[256]; int len; handle = usb_open(dev); /* we need to open the device in order to query strings */ if(!handle){ errorCode = USBOPEN_ERR_ACCESS; if(warningsFp != NULL) fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); continue; } /* now check whether the names match: */ len = vendor[0] = 0; if(dev->descriptor.iManufacturer > 0){ len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor)); } if(len < 0){ errorCode = USBOPEN_ERR_ACCESS; if(warningsFp != NULL) fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); }else{ errorCode = USBOPEN_ERR_NOTFOUND; /* printf("seen device from vendor ->%s<-\n", vendor); */ if(shellStyleMatch(vendor, vendorNamePattern)){ len = product[0] = 0; if(dev->descriptor.iProduct > 0){ len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product)); } if(len < 0){ errorCode = USBOPEN_ERR_ACCESS; if(warningsFp != NULL) fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); }else{ errorCode = USBOPEN_ERR_NOTFOUND; /* printf("seen product ->%s<-\n", product); */ if(shellStyleMatch(product, productNamePattern)){ len = serial[0] = 0; if(dev->descriptor.iSerialNumber > 0){ len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial)); } if(len < 0){ errorCode = USBOPEN_ERR_ACCESS; if(warningsFp != NULL) fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); } if(shellStyleMatch(serial, serialNamePattern)){ if(printMatchingDevicesFp != NULL){ if(serial[0] == 0){ fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product); }else{ fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial); } }else{ break; } } } } } } usb_close(handle); handle = NULL; } } if(handle) /* we have found a deice */ break; } if(handle != NULL){ errorCode = 0; *device = handle; } if(printMatchingDevicesFp != NULL) /* never return an error for listing only */ errorCode = 0; return errorCode; } /* ------------------------------------------------------------------------- */