/* Name: hiddata.c * Author: Christian Starkjohann * Creation Date: 2008-04-11 * Tabsize: 4 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) */ #include #include "hiddata.h" /* ######################################################################## */ #if defined(WIN32) /* ##################################################### */ /* ######################################################################## */ #include #include #include "hidsdi.h" #include #ifdef DEBUG #define DEBUG_PRINT(arg) printf arg #else #define DEBUG_PRINT(arg) #endif /* ------------------------------------------------------------------------ */ static void convertUniToAscii(char *buffer) { unsigned short *uni = (void *)buffer; char *ascii = buffer; while(*uni != 0){ if(*uni >= 256){ *ascii++ = '?'; }else{ *ascii++ = *uni++; } } *ascii++ = 0; } int usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs) { GUID hidGuid; /* GUID for HID driver */ HDEVINFO deviceInfoList; SP_DEVICE_INTERFACE_DATA deviceInfo; SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = NULL; DWORD size; int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */ int errorCode = USBOPEN_ERR_NOTFOUND; HANDLE handle = INVALID_HANDLE_VALUE; HIDD_ATTRIBUTES deviceAttributes; HidD_GetHidGuid(&hidGuid); deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); deviceInfo.cbSize = sizeof(deviceInfo); for(i=0;;i++){ if(handle != INVALID_HANDLE_VALUE){ CloseHandle(handle); handle = INVALID_HANDLE_VALUE; } if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo)) break; /* no more entries */ /* first do a dummy call just to determine the actual size required */ SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL); if(deviceDetails != NULL) free(deviceDetails); deviceDetails = malloc(size); deviceDetails->cbSize = sizeof(*deviceDetails); /* this call is for real: */ SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL); DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath)); #if 0 /* If we want to access a mouse our keyboard, we can only use feature * requests as the device is locked by Windows. It must be opened * with ACCESS_TYPE_NONE. */ handle = CreateFile(deviceDetails->DevicePath, ACCESS_TYPE_NONE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL); #endif /* attempt opening for R/W -- we don't care about devices which can't be accessed */ handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL); if(handle == INVALID_HANDLE_VALUE){ DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError())); /* errorCode = USBOPEN_ERR_ACCESS; opening will always fail for mouse -- ignore */ continue; } deviceAttributes.Size = sizeof(deviceAttributes); HidD_GetAttributes(handle, &deviceAttributes); DEBUG_PRINT(("device attributes: vid=%d pid=%d\n", deviceAttributes.VendorID, deviceAttributes.ProductID)); if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product) continue; /* ignore this device */ errorCode = USBOPEN_ERR_NOTFOUND; if(vendorName != NULL && productName != NULL){ char buffer[512]; if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){ DEBUG_PRINT(("error obtaining vendor name\n")); errorCode = USBOPEN_ERR_IO; continue; } convertUniToAscii(buffer); DEBUG_PRINT(("vendorName = \"%s\"\n", buffer)); if(strcmp(vendorName, buffer) != 0) continue; if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){ DEBUG_PRINT(("error obtaining product name\n")); errorCode = USBOPEN_ERR_IO; continue; } convertUniToAscii(buffer); DEBUG_PRINT(("productName = \"%s\"\n", buffer)); if(strcmp(productName, buffer) != 0) continue; } break; /* we have found the device we are looking for! */ } SetupDiDestroyDeviceInfoList(deviceInfoList); if(deviceDetails != NULL) free(deviceDetails); if(handle != INVALID_HANDLE_VALUE){ *device = (usbDevice_t *)handle; errorCode = 0; } return errorCode; } /* ------------------------------------------------------------------------ */ void usbhidCloseDevice(usbDevice_t *device) { CloseHandle((HANDLE)device); } /* ------------------------------------------------------------------------ */ int usbhidSetReport(usbDevice_t *device, char *buffer, int len) { BOOLEAN rval; rval = HidD_SetFeature((HANDLE)device, buffer, len); return rval == 0 ? USBOPEN_ERR_IO : 0; } /* ------------------------------------------------------------------------ */ int usbhidGetReport(usbDevice_t *device, int reportNumber, char *buffer, int *len) { BOOLEAN rval = 0; buffer[0] = reportNumber; rval = HidD_GetFeature((HANDLE)device, buffer, *len); return rval == 0 ? USBOPEN_ERR_IO : 0; } /* ------------------------------------------------------------------------ */ /* ######################################################################## */ #else /* defined WIN32 #################################################### */ /* ######################################################################## */ #include #include #define usbDevice usb_dev_handle /* use libusb's device structure */ /* ------------------------------------------------------------------------- */ #define USBRQ_HID_GET_REPORT 0x01 #define USBRQ_HID_SET_REPORT 0x09 #define USB_HID_REPORT_TYPE_FEATURE 3 static int usesReportIDs; /* ------------------------------------------------------------------------- */ static int usbhidGetStringAscii(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 usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int _usesReportIDs) { struct usb_bus *bus; struct usb_device *dev; usb_dev_handle *handle = NULL; int errorCode = USBOPEN_ERR_NOTFOUND; static int didUsbInit = 0; if(!didUsbInit){ usb_init(); didUsbInit = 1; } usb_find_busses(); usb_find_devices(); for(bus=usb_get_busses(); bus; bus=bus->next){ for(dev=bus->devices; dev; dev=dev->next){ if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product){ char string[256]; int len; handle = usb_open(dev); /* we need to open the device in order to query strings */ if(!handle){ errorCode = USBOPEN_ERR_ACCESS; fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror()); continue; } if(vendorName == NULL && productName == NULL){ /* name does not matter */ break; } /* now check whether the names match: */ len = usbhidGetStringAscii(handle, dev->descriptor.iManufacturer, string, sizeof(string)); if(len < 0){ errorCode = USBOPEN_ERR_IO; fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror()); }else{ errorCode = USBOPEN_ERR_NOTFOUND; /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */ if(strcmp(string, vendorName) == 0){ len = usbhidGetStringAscii(handle, dev->descriptor.iProduct, string, sizeof(string)); if(len < 0){ errorCode = USBOPEN_ERR_IO; fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror()); }else{ errorCode = USBOPEN_ERR_NOTFOUND; /* fprintf(stderr, "seen product ->%s<-\n", string); */ if(strcmp(string, productName) == 0) break; } } } usb_close(handle); handle = NULL; } } if(handle) break; } if(handle != NULL){ errorCode = 0; *device = (void *)handle; usesReportIDs = _usesReportIDs; } return errorCode; } /* ------------------------------------------------------------------------- */ void usbhidCloseDevice(usbDevice_t *device) { if(device != NULL) usb_close((void *)device); } /* ------------------------------------------------------------------------- */ int usbhidSetReport(usbDevice_t *device, char *buffer, int len) { int bytesSent, reportId = buffer[0]; if(!usesReportIDs){ buffer++; /* skip dummy report ID */ len--; } bytesSent = usb_control_msg((void *)device, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | (reportId & 0xff), 0, buffer, len, 5000); if(bytesSent != len){ if(bytesSent < 0) fprintf(stderr, "Error sending message: %s\n", usb_strerror()); return USBOPEN_ERR_IO; } return 0; } /* ------------------------------------------------------------------------- */ int usbhidGetReport(usbDevice_t *device, int reportNumber, char *buffer, int *len) { int bytesReceived, maxLen = *len; if(!usesReportIDs){ buffer++; /* make room for dummy report ID */ maxLen--; } bytesReceived = usb_control_msg((void *)device, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | reportNumber, 0, buffer, maxLen, 5000); if(bytesReceived < 0){ fprintf(stderr, "Error sending message: %s\n", usb_strerror()); return USBOPEN_ERR_IO; } *len = bytesReceived; if(!usesReportIDs){ buffer[-1] = reportNumber; /* add dummy report ID */ (*len)++; } return 0; } /* ######################################################################## */ #endif /* defined WIN32 ################################################### */ /* ######################################################################## */