204 lines
7.3 KiB
C
204 lines
7.3 KiB
C
/* 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;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|