From 8f3c91e91b634adaca77dac6cf314445cceefc78 Mon Sep 17 00:00:00 2001 From: Jonathan McCrohan Date: Fri, 19 Oct 2012 19:38:06 +0100 Subject: Imported Upstream version 2.1.8.20120912 --- linux/cusblinux-1.0.c | 233 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 169 insertions(+), 64 deletions(-) (limited to 'linux/cusblinux-1.0.c') diff --git a/linux/cusblinux-1.0.c b/linux/cusblinux-1.0.c index 204ef53..0e3a5e8 100644 --- a/linux/cusblinux-1.0.c +++ b/linux/cusblinux-1.0.c @@ -10,6 +10,8 @@ #include "stdafx.h" #include "cusb.h" #include +#include +#include int CUSBCloseHandle(CPhidgetHandle phid) { int ret = 0; @@ -106,7 +108,10 @@ int CUSBSendPacket(CPhidgetHandle phid, unsigned char *buffer) { LOG(PHIDGET_LOG_INFO, "Device was unplugged - detach."); return EPHIDGET_NOTATTACHED; default: - LOG(PHIDGET_LOG_ERROR, "libusb_control_msg failed with error code: %d", ret); + if(phid->interruptOutEndpoint) + LOG(PHIDGET_LOG_ERROR, "libusb_interrupt_transfer failed in CUSBSendPacket with error code: %d", ret); + else + LOG(PHIDGET_LOG_ERROR, "libusb_control_msg failed in CUSBSendPacket with error code: %d", ret); return EPHIDGET_UNEXPECTED; } } @@ -123,53 +128,60 @@ int CUSBSendPacket(CPhidgetHandle phid, unsigned char *buffer) { } int CUSBSetLabel(CPhidgetHandle phid, char *buffer) { - int BytesWritten = 0; - int size = buffer[0]; - - if(size>22) return EPHIDGET_INVALID; - - if (!phid) - return EPHIDGET_INVALIDARG; - - if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG) - && !CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHING_FLAG)) - return EPHIDGET_NOTATTACHED; - - if (phid->deviceHandle == NULL) + if(deviceSupportsGeneralUSBProtocol(phid)) { - LOG(PHIDGET_LOG_WARNING,"Handle for writing is not valid"); - return EPHIDGET_UNEXPECTED; + return CPhidgetGPP_setLabel(phid, buffer); } - - BytesWritten = libusb_control_transfer((libusb_device_handle *)phid->deviceHandle, - LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_SET_DESCRIPTOR, - 0x0304, /* value */ - 0x0409, /* index*/ - (char *)buffer, - size, /* size */ - 500); /* FIXME? timeout */ - - if(BytesWritten < 0) + else { - switch(BytesWritten) + int BytesWritten = 0; + int size = buffer[0]; + + if(size>22) return EPHIDGET_INVALID; + + if (!phid) + return EPHIDGET_INVALIDARG; + + if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG) + && !CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHING_FLAG)) + return EPHIDGET_NOTATTACHED; + + if (phid->deviceHandle == NULL) { - case LIBUSB_ERROR_TIMEOUT: //important case? - default: - LOG(PHIDGET_LOG_INFO, "usb_control_msg failed with error code: %d", BytesWritten); - return EPHIDGET_UNSUPPORTED; + LOG(PHIDGET_LOG_WARNING,"Handle for writing is not valid"); + return EPHIDGET_UNEXPECTED; + } + + BytesWritten = libusb_control_transfer((libusb_device_handle *)phid->deviceHandle, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, + LIBUSB_REQUEST_SET_DESCRIPTOR, + 0x0304, /* value */ + 0x0409, /* index*/ + (char *)buffer, + size, /* size */ + 500); /* FIXME? timeout */ + + if(BytesWritten < 0) + { + switch(BytesWritten) + { + case LIBUSB_ERROR_TIMEOUT: //important case? + default: + LOG(PHIDGET_LOG_INFO, "usb_control_msg failed in CUSBSetLabel with error code: %d", BytesWritten); + return EPHIDGET_UNSUPPORTED; + } } - } - if (BytesWritten != size) - { - LOG(PHIDGET_LOG_WARNING,"Failure in CUSBSetLabel - Report Length" - ": %d, bytes written: %d", - size, (int)BytesWritten); - return EPHIDGET_UNEXPECTED; + if (BytesWritten != size) + { + LOG(PHIDGET_LOG_WARNING,"Failure in CUSBSetLabel - Report Length" + ": %d, bytes written: %d", + size, (int)BytesWritten); + return EPHIDGET_UNEXPECTED; + } + + return EPHIDGET_OK; } - - return EPHIDGET_OK; } /* Buffer should be at least 8 bytes long */ @@ -202,7 +214,7 @@ int CUSBReadPacket(CPhidgetHandle phid, unsigned char *buffer) { { // A timeout occured, but we'll just try again case LIBUSB_ERROR_TIMEOUT: - LOG(PHIDGET_LOG_VERBOSE, "libusb_interrupt_transfer timeout"); + LOG(PHIDGET_LOG_VERBOSE, "libusb_interrupt_transfer timeout in CUSBReadPacket"); return EPHIDGET_TIMEOUT; case LIBUSB_ERROR_BUSY: //This happens when someone else calls claim_interface on this interface (a manager for ex.) - basically just wait until they release it. @@ -216,7 +228,7 @@ int CUSBReadPacket(CPhidgetHandle phid, unsigned char *buffer) { case LIBUSB_ERROR_PIPE: case LIBUSB_ERROR_OVERFLOW: default: - LOG(PHIDGET_LOG_ERROR, "libusb_interrupt_transfer returned: %d \"%s\"", ret); + LOG(PHIDGET_LOG_ERROR, "libusb_interrupt_transfer in CUSBReadPacket returned: %d", ret); goto tryagain; } } @@ -248,27 +260,42 @@ tryagain: static int getLabelString(CPhidgetHandle phid, struct libusb_device_handle *handle) { - int len = 0; + int len = 0, ret; char labelBuf[22]; memset(labelBuf, 0, sizeof(labelBuf)); + libusb_device *device = libusb_get_device(handle); + struct libusb_device_descriptor desc; - //Note that this returns the whole descriptor, including the length and type bytes - len = libusb_get_string_descriptor(handle, 4, 0, (char *)labelBuf, 22); + if((ret = libusb_get_device_descriptor(device, &desc)) != 0) + { + LOG(PHIDGET_LOG_ERROR, "libusb_get_device_descriptor failed with error code: %d", ret); + return EPHIDGET_UNEXPECTED; + } - if(len < 0) + if(desc.iSerialNumber == 3) { - switch(len) + + //Note that this returns the whole descriptor, including the length and type bytes + len = libusb_get_string_descriptor(handle, 4, 0, (char *)labelBuf, 22); + + if(len < 0) { - case LIBUSB_ERROR_TIMEOUT: //important case? - default: - LOG(PHIDGET_LOG_INFO, "libusb_get_string_descriptor failed in CUSBGetDeviceCapabilities with error code: %d while reading label"\ - " - this probably just means the device doesn't support labels, so this is fine.", len); + switch(len) + { + case LIBUSB_ERROR_TIMEOUT: //important case? + default: + LOG(PHIDGET_LOG_INFO, "libusb_get_string_descriptor failed in CUSBGetDeviceCapabilities with error code: %d while reading label"\ + " - this probably just means the device doesn't support labels, so this is fine.", len); + } + phid->label[0]='\0'; + return EPHIDGET_OK; } - phid->label[0]='\0'; - return EPHIDGET_OK; + else + return decodeLabelString(labelBuf, phid->label, phid->serialNumber); } - else - return decodeLabelString(labelBuf, phid->label, phid->serialNumber); + + phid->label[0]='\0'; + return EPHIDGET_OK; } int CUSBRefreshLabelString(CPhidgetHandle phid) @@ -488,6 +515,15 @@ int CUSBBuildList(CPhidgetList **curList) { getLabelString(phid, handle); } } + if (desc.iProduct) { + if((ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, phid->usbProduct, sizeof(phid->usbProduct))) < 0) + { + LOG(PHIDGET_LOG_ERROR, "libusb_get_string_descriptor_ascii failed with error code: %d", ret); + libusb_close(handle); + free(phid); + goto next; + } + } phid->specificDevice = TRUE; phid->attr = Phid_Device_Def[i].pdd_attr; @@ -520,6 +556,49 @@ done: return ret; } +/* + * Got this from libusb-0.1 because 1.0 doesn't expose driver name! + */ +#define USB_MAXDRIVERNAME 255 +struct usb_getdriver { + unsigned int interface; + char driver[USB_MAXDRIVERNAME + 1]; +}; +struct linux_device_handle_priv { + int fd; +}; +struct list_head { + struct list_head *prev, *next; +}; +struct libusb_device_handle_internal { + pthread_mutex_t lock; + unsigned long claimed_interfaces; + struct list_head list; + void *dev; + unsigned char os_priv[0]; +}; +static struct linux_device_handle_priv *_device_handle_priv(struct libusb_device_handle_internal *handle) +{ + return (struct linux_device_handle_priv *) handle->os_priv; +} +#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver) +static int libusb_get_driver_name(libusb_device_handle *handle, int interface, char *name, unsigned int namelen) +{ + int fd = _device_handle_priv((struct libusb_device_handle_internal *)handle)->fd; + struct usb_getdriver getdrv; + int ret; + + getdrv.interface = interface; + ret = ioctl(fd, IOCTL_USB_GETDRIVER, &getdrv); + if (ret) + LOG(PHIDGET_LOG_ERROR, "could not get bound driver: %d", errno); + + strncpy(name, getdrv.driver, namelen - 1); + name[namelen - 1] = 0; + + return 0; +} + void CUSBCleanup(void) { ; @@ -535,7 +614,7 @@ int CUSBOpenHandle(CPhidgetHandle phid) int idVendor; int idProduct; int serial = 0; - int i, j,ret = EPHIDGET_OK; + int i, j, ret, retVal = EPHIDGET_NOTFOUND; libusb_device **list = NULL; ssize_t cnt = libusb_get_device_list(libusbContext, &list); @@ -582,6 +661,15 @@ int CUSBOpenHandle(CPhidgetHandle phid) serial = atol(string); } } + if (desc.iProduct) { + if((ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, phid->usbProduct, sizeof(phid->usbProduct))) < 0) + { + LOG(PHIDGET_LOG_ERROR, "libusb_get_string_descriptor_ascii failed with error code: %d", ret); + libusb_close(handle); + free(phid); + goto next; + } + } if (serial == phid->serialNumber) { //Detach any Kernel Drivers if((ret = libusb_kernel_driver_active(handle, Phid_Device_Def[i].pdd_iid)) < 0) @@ -590,20 +678,37 @@ int CUSBOpenHandle(CPhidgetHandle phid) } else if(ret == 1) { - LOG(PHIDGET_LOG_INFO, "Kernel driver is active - will attempt a detach"); - if((ret = libusb_detach_kernel_driver(handle, Phid_Device_Def[i].pdd_iid)) != 0) + char name[64]; + if((ret = libusb_get_driver_name(handle, Phid_Device_Def[i].pdd_iid, name, 32)) < 0) { - LOG(PHIDGET_LOG_WARNING, "libusb_detach_kernel_driver failed with error code: %d", ret); + LOG(PHIDGET_LOG_WARNING, "libusb_get_driver_name failed with error code: %d", ret); } else { - LOG(PHIDGET_LOG_INFO, "Successfully detached kernel driver"); + LOG(PHIDGET_LOG_INFO, "Kernel driver name: %s", name); + if(strncmp(name, "usbfs", 5)) //not usbfs + { + LOG(PHIDGET_LOG_INFO, "Kernel driver is active - will attempt a detach"); + if((ret = libusb_detach_kernel_driver(handle, Phid_Device_Def[i].pdd_iid)) != 0) + { + LOG(PHIDGET_LOG_WARNING, "libusb_detach_kernel_driver failed with error code: %d", ret); + } + else + { + LOG(PHIDGET_LOG_INFO, "Successfully detached kernel driver"); + } + } + else + LOG(PHIDGET_LOG_INFO, "Not detaching kernel driver - already using usbfs."); } } if((ret = libusb_claim_interface(handle, Phid_Device_Def[i].pdd_iid)) != 0) { - LOG(PHIDGET_LOG_WARNING, "libusb_claim_interface failed with error code: %d", ret); + if(ret == LIBUSB_ERROR_BUSY) + LOG(PHIDGET_LOG_WARNING, "libusb_claim_interface failed with BUSY - probably the device is opened by another program."); + else + LOG(PHIDGET_LOG_WARNING, "libusb_claim_interface failed with error code: %d", ret); libusb_close(handle); } else @@ -632,7 +737,7 @@ int CUSBOpenHandle(CPhidgetHandle phid) phid->attr = Phid_Device_Def[i].pdd_attr; - ret = EPHIDGET_OK; + retVal = EPHIDGET_OK; goto done; } /* usb_claim_interface */ } /* serial matches */ @@ -656,5 +761,5 @@ done: if(list) libusb_free_device_list(list, 1); - return ret; + return retVal; } -- cgit v1.2.3