blink1-tool/blink1-mini-tool/hiddata.c

384 lines
14 KiB
C

/* 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 <stdio.h>
#include "hiddata.h"
/* ######################################################################## */
#if defined(WIN32) /* ##################################################### */
/* ######################################################################## */
#include <windows.h>
#include <setupapi.h>
#include "hidsdi.h"
#include <ddk/hidpi.h>
#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 <string.h>
#include <usb.h>
#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<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 usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int _usesReportIDs)
{
char drivername[2];
int detachrc;
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;
}
// Likely no need to capture the return code. It will return an error if no driver is
// attached, which is A-OK. Nothing will be detached in that case.
usb_get_driver_np(handle, 0, drivername, sizeof(drivername));
// If we have an empty then nothing is attached, otherwise will be something like "dummy".
if(strlen(drivername) > 0){
// Not doing this causes several issues writing control messages to the interface.
detachrc = usb_detach_kernel_driver_np(handle, 0);
if (detachrc != 0) {
errorCode = USBOPEN_ERR_IO;
fprintf(stderr, "Warning: cannot detach kernel driver from interface 0: %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];
int claimrc, releaserc;
if(!usesReportIDs){
buffer++; /* skip dummy report ID */
len--;
}
claimrc = usb_claim_interface((void *)device, 0);
if(claimrc != 0){
fprintf(stderr, "Error claiming interface 0 before sending a control message: %s\n", usb_strerror());
return USBOPEN_ERR_IO;
}
// original hiddata.h
// 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);
// modification by todbot, matches roughly what hiddata does
// change by tod to use USB_RECIP_INTERFACE instead of USB_RECIP_DEVICE
bytesSent = usb_control_msg((void *)device, USB_TYPE_CLASS | USB_RECIP_INTERFACE | 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());
}
usb_release_interface((void *)device, 0);
return USBOPEN_ERR_IO;
}
releaserc = usb_release_interface((void *)device, 0);
if(releaserc != 0){
fprintf(stderr, "Error releasing interface 0 after sending a control 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;
int claimrc, releaserc;
if(!usesReportIDs){
buffer++; /* make room for dummy report ID */
maxLen--;
}
claimrc = usb_claim_interface((void *)device, 0);
if(claimrc != 0){
fprintf(stderr, "Error claiming interface 0 before sending a control message: %s\n", usb_strerror());
return USBOPEN_ERR_IO;
}
// original hiddata.h
//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);
// change by tod to use USB_RECIP_INTERFACE instead of USB_RECIP_DEVICE
bytesReceived = usb_control_msg((void *)device, USB_TYPE_CLASS | USB_RECIP_INTERFACE | 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());
usb_release_interface((void *)device, 0);
return USBOPEN_ERR_IO;
}
*len = bytesReceived;
if(!usesReportIDs){
buffer[-1] = reportNumber; /* add dummy report ID */
(*len)++;
}
releaserc = usb_release_interface((void *)device, 0);
if(releaserc != 0){
fprintf(stderr, "Error releasing interface 0 after sending a control message: %s\n", usb_strerror());
return USBOPEN_ERR_IO;
}
return 0;
}
/* ######################################################################## */
#endif /* defined WIN32 ################################################### */
/* ######################################################################## */