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 | |
| 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)
| -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/bootloadHIDBinary files differ new 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.oBinary files differ new 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.oBinary files differ new file mode 100644 index 0000000..4a43f0f --- /dev/null +++ b/commandline/usbcalls.o | 
