keyboard/qmk/lib/vusb/libs-host/opendevice.c

203 lines
8.4 KiB
C

/* 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 <stdio.h>
#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<rval;i++){
if(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;
}
/* ------------------------------------------------------------------------- */