diff options
author | Jenna Fox <a@creativepony.com> | 2012-09-23 16:10:31 +1000 |
---|---|---|
committer | Jenna Fox <a@creativepony.com> | 2012-09-23 16:10:31 +1000 |
commit | 0b63b7b37c027ae58fa29698c5181ecf212f961b (patch) | |
tree | cbd2711939c9c29be8ca9b0840aeb9f38978265d /commandline | |
parent | 824c303782a62b57b6525875b3c2dee81056baa4 (diff) | |
download | micronucleus-0b63b7b37c027ae58fa29698c5181ecf212f961b.tar.gz micronucleus-0b63b7b37c027ae58fa29698c5181ecf212f961b.tar.bz2 micronucleus-0b63b7b37c027ae58fa29698c5181ecf212f961b.zip |
bring in slightly modified version of bootloadHID host programming app by objective development - including delays tiny85 requires (though they could be tuned to be a bit shorter for quicker programming later)
Diffstat (limited to 'commandline')
-rw-r--r-- | commandline/Makefile | 46 | ||||
-rw-r--r-- | commandline/Makefile.windows | 18 | ||||
-rwxr-xr-x | commandline/bootloadHID | bin | 0 -> 15040 bytes | |||
-rwxr-xr-x | commandline/hidsdi.h | 50 | ||||
-rw-r--r-- | commandline/main.c | 272 | ||||
-rw-r--r-- | commandline/main.o | bin | 0 -> 6116 bytes | |||
-rw-r--r-- | commandline/usb-libusb.c | 203 | ||||
-rwxr-xr-x | commandline/usb-windows.c | 180 | ||||
-rw-r--r-- | commandline/usbcalls.c | 20 | ||||
-rw-r--r-- | commandline/usbcalls.h | 81 | ||||
-rw-r--r-- | commandline/usbcalls.o | bin | 0 -> 4012 bytes |
11 files changed, 870 insertions, 0 deletions
diff --git a/commandline/Makefile b/commandline/Makefile new file mode 100644 index 0000000..5c8f81a --- /dev/null +++ b/commandline/Makefile @@ -0,0 +1,46 @@ +# Name: Makefile +# Project: Automator +# Author: Christian Starkjohann +# Creation Date: 2006-02-01 +# Tabsize: 4 +# Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH +# License: Proprietary, free under certain conditions. See Documentation. +# This Revision: $Id: Makefile 281 2007-03-20 13:22:10Z cs $ + +# Please read the definitions below and edit them as appropriate for your +# system: + +# Use the following 3 lines on Unix and Mac OS X: +USBFLAGS= `libusb-config --cflags` +USBLIBS= `libusb-config --libs` +EXE_SUFFIX= + +# Use the following 3 lines on Windows and comment out the 3 above: +#USBFLAGS= +#USBLIBS= -lhid -lusb -lsetupapi +#EXE_SUFFIX= .exe + +CC= gcc +CXX= g++ +CFLAGS= -O2 -Wall $(USBFLAGS) +LIBS= $(USBLIBS) +ARCH_COMPILE= +ARCH_LINK= + +OBJ= main.o usbcalls.o +PROGRAM= bootloadHID$(EXE_SUFFIX) + +all: $(PROGRAM) + +$(PROGRAM): $(OBJ) + $(CC) $(ARCH_LINK) $(CFLAGS) -o $(PROGRAM) $(OBJ) $(LIBS) + + +strip: $(PROGRAM) + strip $(PROGRAM) + +clean: + rm -f $(OBJ) $(PROGRAM) + +.c.o: + $(CC) $(ARCH_COMPILE) $(CFLAGS) -c $*.c -o $*.o diff --git a/commandline/Makefile.windows b/commandline/Makefile.windows new file mode 100644 index 0000000..16f3ba8 --- /dev/null +++ b/commandline/Makefile.windows @@ -0,0 +1,18 @@ +# Name: Makefile.windows +# Project: Automator +# Author: Christian Starkjohann +# Creation Date: 2006-02-20 +# Tabsize: 4 +# Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH +# License: Proprietary, free under certain conditions. See Documentation. +# This Revision: $Id$ + +# You may use this file with +# make -f Makefile.windows +# on Windows with MinGW instead of editing the main Makefile. + +include Makefile + +USBFLAGS= +USBLIBS= -lhid -lusb -lsetupapi +EXE_SUFFIX= .exe diff --git a/commandline/bootloadHID b/commandline/bootloadHID Binary files differnew file mode 100755 index 0000000..db51c59 --- /dev/null +++ b/commandline/bootloadHID diff --git a/commandline/hidsdi.h b/commandline/hidsdi.h new file mode 100755 index 0000000..cabb995 --- /dev/null +++ b/commandline/hidsdi.h @@ -0,0 +1,50 @@ +/* Name: hidsdi.h + * Project: usbcalls library + * Author: Christian Starkjohann + * Creation Date: 2006-02-02 + * Tabsize: 4 + * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: hidsdi.h 281 2007-03-20 13:22:10Z cs $ + */ + +/* +General Description +This file is a replacement for hidsdi.h from the Windows DDK. It defines some +of the types and function prototypes of this header for our project. If you +have the Windows DDK version of this file or a version shipped with MinGW, use +that instead. +*/ + +#ifndef _HIDSDI_H +#define _HIDSDI_H + +#include <pshpack4.h> + +#include <ddk/hidusage.h> +#include <ddk/hidpi.h> + +typedef struct{ + ULONG Size; + USHORT VendorID; + USHORT ProductID; + USHORT VersionNumber; +}HIDD_ATTRIBUTES; + +void __stdcall HidD_GetHidGuid(OUT LPGUID hidGuid); + +BOOLEAN __stdcall HidD_GetAttributes(IN HANDLE device, OUT HIDD_ATTRIBUTES *attributes); + +BOOLEAN __stdcall HidD_GetManufacturerString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_GetProductString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_GetSerialNumberString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); + +BOOLEAN __stdcall HidD_GetFeature(IN HANDLE device, OUT void *reportBuffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_SetFeature(IN HANDLE device, IN void *reportBuffer, IN ULONG bufferLen); + +BOOLEAN __stdcall HidD_GetNumInputBuffers(IN HANDLE device, OUT ULONG *numBuffers); +BOOLEAN __stdcall HidD_SetNumInputBuffers(IN HANDLE device, OUT ULONG numBuffers); + +#include <poppack.h> + +#endif diff --git a/commandline/main.c b/commandline/main.c new file mode 100644 index 0000000..1b507d3 --- /dev/null +++ b/commandline/main.c @@ -0,0 +1,272 @@ +/* Name: main.c + * Project: AVR bootloader HID + * Author: Christian Starkjohann + * Creation Date: 2007-03-19 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: main.c 787 2010-05-30 20:54:25Z cs $ + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include "usbcalls.h" + +#define IDENT_VENDOR_NUM 0x16c0 +#define IDENT_VENDOR_STRING "obdev.at" +#define IDENT_PRODUCT_NUM 1503 +#define IDENT_PRODUCT_STRING "HIDBoot" + +// extra delays before more USB requests for tiny85 compatibility +#define TINY85_POSTWRITE_DELAY 8000 +#define TINY85_FIRSTWRITE_DELAY 500000 + +/* ------------------------------------------------------------------------- */ + +static char dataBuffer[65536 + 256]; /* buffer for file data */ +static int startAddress, endAddress; +static char leaveBootLoader = 0; + +/* ------------------------------------------------------------------------- */ + +static int parseUntilColon(FILE *fp) +{ +int c; + + do{ + c = getc(fp); + }while(c != ':' && c != EOF); + return c; +} + +static int parseHex(FILE *fp, int numDigits) +{ +int i; +char temp[9]; + + for(i = 0; i < numDigits; i++) + temp[i] = getc(fp); + temp[i] = 0; + return strtol(temp, NULL, 16); +} + +/* ------------------------------------------------------------------------- */ + +static int parseIntelHex(char *hexfile, char buffer[65536 + 256], int *startAddr, int *endAddr) +{ +int address, base, d, segment, i, lineLen, sum; +FILE *input; + + input = fopen(hexfile, "r"); + if(input == NULL){ + fprintf(stderr, "error opening %s: %s\n", hexfile, strerror(errno)); + return 1; + } + while(parseUntilColon(input) == ':'){ + sum = 0; + sum += lineLen = parseHex(input, 2); + base = address = parseHex(input, 4); + sum += address >> 8; + sum += address; + sum += segment = parseHex(input, 2); /* segment value? */ + if(segment != 0) /* ignore lines where this byte is not 0 */ + continue; + for(i = 0; i < lineLen ; i++){ + d = parseHex(input, 2); + buffer[address++] = d; + sum += d; + } + sum += parseHex(input, 2); + if((sum & 0xff) != 0){ + fprintf(stderr, "Warning: Checksum error between address 0x%x and 0x%x\n", base, address); + } + if(*startAddr > base) + *startAddr = base; + if(*endAddr < address) + *endAddr = address; + } + fclose(input); + return 0; +} + +/* ------------------------------------------------------------------------- */ + +char *usbErrorMessage(int errCode) +{ +static char buffer[80]; + + switch(errCode){ + case USB_ERROR_ACCESS: return "Access to device denied"; + case USB_ERROR_NOTFOUND: return "The specified device was not found"; + case USB_ERROR_BUSY: return "The device is used by another application"; + case USB_ERROR_IO: return "Communication error with device"; + default: + sprintf(buffer, "Unknown USB error %d", errCode); + return buffer; + } + return NULL; /* not reached */ +} + +static int getUsbInt(char *buffer, int numBytes) +{ +int shift = 0, value = 0, i; + + for(i = 0; i < numBytes; i++){ + value |= ((int)*buffer & 0xff) << shift; + shift += 8; + buffer++; + } + return value; +} + +static void setUsbInt(char *buffer, int value, int numBytes) +{ +int i; + + for(i = 0; i < numBytes; i++){ + *buffer++ = value; + value >>= 8; + } +} + +/* ------------------------------------------------------------------------- */ + +typedef struct deviceInfo{ + char reportId; + char pageSize[2]; // TODO: change this to one byte? + char flashSize[4]; // TODO: change this to two bytes? +}deviceInfo_t; + +typedef struct deviceData{ + char reportId; + char address[3]; + char data[128]; +}deviceData_t; + +static int uploadData(char *dataBuffer, int startAddr, int endAddr) +{ +usbDevice_t *dev = NULL; +int err = 0, len, mask, pageSize, deviceSize; +union{ + char bytes[1]; + deviceInfo_t info; + deviceData_t data; +} buffer; +unsigned char firstWrite = 1; // track first page write request, accept extra delay + + if((err = usbOpenDevice(&dev, IDENT_VENDOR_NUM, IDENT_VENDOR_STRING, IDENT_PRODUCT_NUM, IDENT_PRODUCT_STRING, 1)) != 0){ + fprintf(stderr, "Error opening HIDBoot device: %s\n", usbErrorMessage(err)); + goto errorOccurred; + } + len = sizeof(buffer); + if(endAddr > startAddr){ // we need to upload data + if((err = usbGetReport(dev, USB_HID_REPORT_TYPE_FEATURE, 1, buffer.bytes, &len)) != 0){ + fprintf(stderr, "Error reading page size: %s\n", usbErrorMessage(err)); + goto errorOccurred; + } + if(len < sizeof(buffer.info)){ + fprintf(stderr, "Not enough bytes in device info report (%d instead of %d)\n", len, (int)sizeof(buffer.info)); + err = -1; + goto errorOccurred; + } + pageSize = getUsbInt(buffer.info.pageSize, 2); + deviceSize = getUsbInt(buffer.info.flashSize, 4); + printf("Page size = %d (0x%x)\n", pageSize, pageSize); + printf("Device size = %d (0x%x)\n", deviceSize, deviceSize); + if(endAddr > deviceSize){ + fprintf(stderr, "Data (%d bytes) exceeds remaining flash size!\n", endAddr); + err = -1; + goto errorOccurred; + } + if(pageSize < 128){ + mask = 127; + }else{ + mask = pageSize - 1; + } + startAddr &= ~mask; /* round down */ + endAddr = (endAddr + mask) & ~mask; /* round up */ + printf("Uploading %d (0x%x) bytes starting at %d (0x%x)\n", endAddr - startAddr, endAddr - startAddr, startAddr, startAddr); + while(startAddr < endAddr){ + buffer.data.reportId = 2; + memcpy(buffer.data.data, dataBuffer + startAddr, 128); + setUsbInt(buffer.data.address, startAddr, 3); + printf("\r0x%05x ... 0x%05x", startAddr, startAddr + (int)sizeof(buffer.data.data)); + fflush(stdout); + if((err = usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buffer.bytes, sizeof(buffer.data))) != 0){ + fprintf(stderr, "Error uploading data block: %s\n", usbErrorMessage(err)); + goto errorOccurred; + } + startAddr += sizeof(buffer.data.data); + + // special tiny85 chillout session - chip freezes after write, so we + // need to make sure we don't send it any requests while it's busy + // erasing or writing + if (firstWrite) usleep(TINY85_FIRSTWRITE_DELAY); // progmem erase extra time + usleep(TINY85_POSTWRITE_DELAY); // regular page write duration + firstWrite = 0; + } + printf("\n"); + } + if(leaveBootLoader){ + /* and now leave boot loader: */ + buffer.info.reportId = 1; + usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buffer.bytes, sizeof(buffer.info)); + /* Ignore errors here. If the device reboots before we poll the response, + * this request fails. + */ + } +errorOccurred: + if(dev != NULL) + usbCloseDevice(dev); + return err; +} + +/* ------------------------------------------------------------------------- */ + +static void printUsage(char *pname) +{ + fprintf(stderr, "usage: %s [-r] [<intel-hexfile>]\n", pname); +} + +int main(int argc, char **argv) +{ +char *file = NULL; + + if(argc < 2){ + printUsage(argv[0]); + return 1; + } + if(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0){ + printUsage(argv[0]); + return 1; + } + if(strcmp(argv[1], "-r") == 0){ + leaveBootLoader = 1; + if(argc >= 3){ + file = argv[2]; + } + }else{ + file = argv[1]; + } + startAddress = sizeof(dataBuffer); + endAddress = 0; + if(file != NULL){ // an upload file was given, load the data + memset(dataBuffer, -1, sizeof(dataBuffer)); + if(parseIntelHex(file, dataBuffer, &startAddress, &endAddress)) + return 1; + if(startAddress >= endAddress){ + fprintf(stderr, "No data in input file, exiting.\n"); + return 0; + } + } + // if no file was given, endAddress is less than startAddress and no data is uploaded + if(uploadData(dataBuffer, startAddress, endAddress)) + return 1; + return 0; +} + +/* ------------------------------------------------------------------------- */ + + diff --git a/commandline/main.o b/commandline/main.o Binary files differnew file mode 100644 index 0000000..709f98e --- /dev/null +++ b/commandline/main.o diff --git a/commandline/usb-libusb.c b/commandline/usb-libusb.c new file mode 100644 index 0000000..886da3b --- /dev/null +++ b/commandline/usb-libusb.c @@ -0,0 +1,203 @@ +/* Name: usb-libusb.c + * Project: usbcalls library + * Author: Christian Starkjohann + * Creation Date: 2006-02-02 + * Tabsize: 4 + * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: usb-libusb.c 323 2007-03-29 17:25:03Z cs $ + */ + +/* +General Description: +This module implements USB HID report receiving/sending based on libusb. It +does not read and parse the report descriptor. You must therefore be careful +to pass correctly formatted data blocks of correct size. In order to be +compatible with the Windows implementation, we add a zero report ID for all +reports which don't have an ID. Since we don't parse the descriptor, the caller +must tell us whether report IDs are used or not in usbOpenDevice(). + +The implementation of dummy report IDs is a hack. Whether they are used is +stored in a global variable, not in the device structure (just laziness, don't +want to allocate memory for that). If you open more than one device and the +devices differ in report ID usage, you must change the code. +*/ + +#include <stdio.h> +#include <string.h> +#include <usb.h> + +#define usbDevice usb_dev_handle /* use libusb's device structure */ +#include "usbcalls.h" + +/* ------------------------------------------------------------------------- */ + +#define USBRQ_HID_GET_REPORT 0x01 +#define USBRQ_HID_SET_REPORT 0x09 + +static int usesReportIDs; + +/* ------------------------------------------------------------------------- */ + +static int usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen) +{ +char buffer[256]; +int rval, i; + + if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0) + return rval; + if(buffer[1] != USB_DT_STRING) + 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(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 = USB_ERROR_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 = USB_ERROR_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 = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string)); + if(len < 0){ + errorCode = USB_ERROR_IO; + fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror()); + }else{ + errorCode = USB_ERROR_NOTFOUND; + /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */ + if(strcmp(string, vendorName) == 0){ + len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string)); + if(len < 0){ + errorCode = USB_ERROR_IO; + fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror()); + }else{ + errorCode = USB_ERROR_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){ + int rval, retries = 3; + if(usb_set_configuration(handle, 1)){ + fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror()); + } + /* now try to claim the interface and detach the kernel HID driver on + * linux and other operating systems which support the call. + */ + while((rval = usb_claim_interface(handle, 0)) != 0 && retries-- > 0){ +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + if(usb_detach_kernel_driver_np(handle, 0) < 0){ + fprintf(stderr, "Warning: could not detach kernel HID driver: %s\n", usb_strerror()); + } +#endif + } +#ifndef __APPLE__ + if(rval != 0) + fprintf(stderr, "Warning: could not claim interface\n"); +#endif +/* Continue anyway, even if we could not claim the interface. Control transfers + * should still work. + */ + errorCode = 0; + *device = handle; + usesReportIDs = _usesReportIDs; + } + return errorCode; +} + +/* ------------------------------------------------------------------------- */ + +void usbCloseDevice(usbDevice_t *device) +{ + if(device != NULL) + usb_close(device); +} + +/* ------------------------------------------------------------------------- */ + +int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len) +{ +int bytesSent; + + if(!usesReportIDs){ + buffer++; /* skip dummy report ID */ + len--; + } + bytesSent = usb_control_msg(device, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT, reportType << 8 | buffer[0], 0, buffer, len, 5000); + if(bytesSent != len){ + if(bytesSent < 0) + fprintf(stderr, "Error sending message: %s\n", usb_strerror()); + return USB_ERROR_IO; + } + return 0; +} + +/* ------------------------------------------------------------------------- */ + +int usbGetReport(usbDevice_t *device, int reportType, int reportNumber, char *buffer, int *len) +{ +int bytesReceived, maxLen = *len; + + if(!usesReportIDs){ + buffer++; /* make room for dummy report ID */ + maxLen--; + } + bytesReceived = usb_control_msg(device, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT, reportType << 8 | reportNumber, 0, buffer, maxLen, 5000); + if(bytesReceived < 0){ + fprintf(stderr, "Error sending message: %s\n", usb_strerror()); + return USB_ERROR_IO; + } + *len = bytesReceived; + if(!usesReportIDs){ + buffer[-1] = reportNumber; /* add dummy report ID */ + *len++; + } + return 0; +} + +/* ------------------------------------------------------------------------- */ + + diff --git a/commandline/usb-windows.c b/commandline/usb-windows.c new file mode 100755 index 0000000..fac3b02 --- /dev/null +++ b/commandline/usb-windows.c @@ -0,0 +1,180 @@ +/* Name: usb-windows.c + * Project: usbcalls library + * Author: Christian Starkjohann + * Creation Date: 2006-02-02 + * Tabsize: 4 + * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: usb-windows.c 281 2007-03-20 13:22:10Z cs $ + */ + +/* +General Description: +This module implements USB HID report receiving and sending with native +Windows API functions. If you compile with MinGW, no software from Microsoft +(no DDK) is needed. We supply the missing types and function prototypes in +hidsdi.h. +*/ + +#include <stdio.h> +#include <windows.h> +#include <setupapi.h> +#include "hidsdi.h" +#include <ddk/hidpi.h> + +#include "usbcalls.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 usbOpenDevice(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 = USB_ERROR_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)); + /* 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 = USB_ERROR_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 = USB_ERROR_NOTFOUND; + if(vendorName != NULL && productName != NULL){ + char buffer[512]; + if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){ + DEBUG_PRINT(("error obtaining vendor name\n")); + errorCode = USB_ERROR_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 = USB_ERROR_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 usbCloseDevice(usbDevice_t *device) +{ + CloseHandle((HANDLE)device); +} + +/* ------------------------------------------------------------------------ */ + +int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len) +{ +HANDLE handle = (HANDLE)device; +BOOLEAN rval = 0; +DWORD bytesWritten; + + switch(reportType){ + case USB_HID_REPORT_TYPE_INPUT: + break; + case USB_HID_REPORT_TYPE_OUTPUT: + rval = WriteFile(handle, buffer, len, &bytesWritten, NULL); + break; + case USB_HID_REPORT_TYPE_FEATURE: + rval = HidD_SetFeature(handle, buffer, len); + break; + } + return rval == 0 ? USB_ERROR_IO : 0; +} + +/* ------------------------------------------------------------------------ */ + +int usbGetReport(usbDevice_t *device, int reportType, int reportNumber, char *buffer, int *len) +{ +HANDLE handle = (HANDLE)device; +BOOLEAN rval = 0; +DWORD bytesRead; + + switch(reportType){ + case USB_HID_REPORT_TYPE_INPUT: + buffer[0] = reportNumber; + rval = ReadFile(handle, buffer, *len, &bytesRead, NULL); + if(rval) + *len = bytesRead; + break; + case USB_HID_REPORT_TYPE_OUTPUT: + break; + case USB_HID_REPORT_TYPE_FEATURE: + buffer[0] = reportNumber; + rval = HidD_GetFeature(handle, buffer, *len); + break; + } + return rval == 0 ? USB_ERROR_IO : 0; +} + +/* ------------------------------------------------------------------------ */ diff --git a/commandline/usbcalls.c b/commandline/usbcalls.c new file mode 100644 index 0000000..f8a1857 --- /dev/null +++ b/commandline/usbcalls.c @@ -0,0 +1,20 @@ +/* Name: usbcalls.c + * Project: usbcalls library + * Author: Christian Starkjohann + * Creation Date: 2006-02-02 + * Tabsize: 4 + * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: usbcalls.c 281 2007-03-20 13:22:10Z cs $ + */ + +/* This file includes the appropriate implementation based on platform + * specific defines. + */ + +#if defined(WIN32) +# include "usb-windows.c" +#else +/* e.g. defined(__APPLE__) */ +# include "usb-libusb.c" +#endif diff --git a/commandline/usbcalls.h b/commandline/usbcalls.h new file mode 100644 index 0000000..3f329b2 --- /dev/null +++ b/commandline/usbcalls.h @@ -0,0 +1,81 @@ +/* Name: usbcalls.h + * Project: usbcalls library + * Author: Christian Starkjohann + * Creation Date: 2006-02-02 + * Tabsize: 4 + * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: usbcalls.h 281 2007-03-20 13:22:10Z cs $ + */ + +#ifndef __usbcalls_h_INCLUDED__ +#define __usbcalls_h_INCLUDED__ + +/* +General Description: +This module implements an abstraction layer for access to USB/HID communication +functions. An implementation based on libusb (portable to Linux, FreeBSD and +Mac OS X) and a native implementation for Windows are provided. +*/ + +/* ------------------------------------------------------------------------ */ + +#define USB_HID_REPORT_TYPE_INPUT 1 +#define USB_HID_REPORT_TYPE_OUTPUT 2 +#define USB_HID_REPORT_TYPE_FEATURE 3 +/* Numeric constants for 'reportType' parameters */ + +#define USB_ERROR_NONE 0 +#define USB_ERROR_ACCESS 1 +#define USB_ERROR_NOTFOUND 2 +#define USB_ERROR_BUSY 16 +#define USB_ERROR_IO 5 +/* These are the error codes which can be returned by functions of this + * module. + */ + +/* ------------------------------------------------------------------------ */ + +typedef struct usbDevice usbDevice_t; +/* This type represents a USB device internally. Only opaque pointers to this + * type are available outside the module implementation. + */ + +/* ------------------------------------------------------------------------ */ + +int usbOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs); +/* This function opens a USB device. 'vendor' and 'product' are the numeric + * Vendor-ID and Product-ID of the device we want to open. If 'vendorName' and + * 'productName' are both not NULL, only devices with matching manufacturer- + * and product name strings are accepted. If the device uses report IDs, + * 'usesReportIDs' must be set to a non-zero value. + * Returns: If a matching device has been found, USB_ERROR_NONE is returned and + * '*device' is set to an opaque pointer representing the device. The device + * must be closed with usbCloseDevice(). If the device has not been found or + * opening failed, an error code is returned. + */ +void usbCloseDevice(usbDevice_t *device); +/* Every device opened with usbOpenDevice() must be closed with this function. + */ +int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len); +/* This function sends a report to the device. 'reportType' specifies the type + * of report (see USB_HID_REPORT_TYPE* constants). The report ID must be in the + * first byte of buffer and the length 'len' of the report is specified + * including this report ID. If no report IDs are used, buffer[0] must be set + * to 0 (dummy report ID). + * Returns: 0 on success, an error code otherwise. + */ +int usbGetReport(usbDevice_t *device, int reportType, int reportID, char *buffer, int *len); +/* This function obtains a report from the device. 'reportType' specifies the + * type of report (see USB_HID_REPORT_TYPE* constants). The requested report ID + * is passed in 'reportID'. The caller must pass a buffer of the size of the + * expected report in 'buffer' and initialize the variable in '*len' to the + * total size of this buffer. Upon successful return, the report (prefixed with + * a report ID) is in 'buffer' and the actual length of the report is returned + * in '*len'. + * Returns: 0 on success, an error code otherwise. + */ + +/* ------------------------------------------------------------------------ */ + +#endif /* __usbcalls_h_INCLUDED__ */ diff --git a/commandline/usbcalls.o b/commandline/usbcalls.o Binary files differnew file mode 100644 index 0000000..4a43f0f --- /dev/null +++ b/commandline/usbcalls.o |