From: Alexander Ponyatykh Date: Fri, 15 Nov 2019 08:46:54 +0300 Subject: Migrate from legacy libusb-0.1 to libusb-1.0 --- configure.in | 5 +- libg15.c | 624 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 332 insertions(+), 297 deletions(-) diff --git a/configure.in b/configure.in index 074d98e..b533d2c 100644 --- a/configure.in +++ b/configure.in @@ -31,7 +31,8 @@ case $host_os in esac # Checks for libraries. -AC_CHECK_LIB([usb], [main], ,AC_MSG_ERROR(["libusb not found. please install it"])) +AC_CHECK_LIB([usb-1.0], [main], ,AC_MSG_ERROR(["libusb-1.0 not found. Please install it."])) +AC_CHECK_LIB([usb-1.0], [libusb_set_option], ,AC_MSG_ERROR(["libusb-1.0 is too old. Please upgrade to version 1.0.22 or later."])) dnl Some versions of libusb do not honour timeout and block. Suns' version is one of them. if test "x$libusb_blocks" == "xtrue"; then @@ -41,7 +42,7 @@ fi # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([string.h]) -AC_CHECK_HEADERS([usb.h]) +AC_CHECK_HEADERS([libusb-1.0/libusb.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/libg15.c b/libg15.c index 56df958..4c0afc4 100644 --- a/libg15.c +++ b/libg15.c @@ -24,20 +24,22 @@ #include "libg15.h" #include #include -#include +#include #include #include +#include #include "config.h" -static usb_dev_handle *keyboard_device = 0; +static libusb_device_handle *keyboard_device = 0; static int libg15_debugging_enabled = 0; -static int enospc_slowdown = 0; static int found_devicetype = -1; static int shared_device = 0; static int g15_keys_endpoint = 0; static int g15_lcd_endpoint = 0; +static int g15_interface_id = -1; static pthread_mutex_t libusb_mutex; +static libusb_context *libg15_libusb_context = NULL; /* to add a new device, simply create a new DEVICE() in this list */ /* Fields are: "Name",VendorID,ProductID,Capabilities */ @@ -67,7 +69,9 @@ int g15DeviceCapabilities() { void libg15Debug(int option) { libg15_debugging_enabled = option; - usb_set_debug(option); + if (option && libg15_libusb_context) { + libusb_set_option(libg15_libusb_context, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_WARNING); + } } /* debugging wrapper */ @@ -86,216 +90,280 @@ static int g15_log (FILE *fd, unsigned int level, const char *fmt, ...) { /* return number of connected and supported devices */ int g15NumberOfConnectedDevices() { - struct usb_bus *bus = 0; - struct usb_device *dev = 0; - int i=0; + struct libusb_device_descriptor desc; + libusb_device **list; unsigned int found = 0; - for (i=0; g15_devices[i].name !=NULL;i++) - for (bus = usb_busses; bus; bus = bus->next) + ssize_t cnt = libusb_get_device_list(libg15_libusb_context, &list); + + if (cnt < 0) { - for (dev = bus->devices; dev; dev = dev->next) + g15_log(stderr, G15_LOG_INFO, "Unable to list USB devices: %s\n", libusb_strerror(cnt)); + return 0; + } + + for (ssize_t i = 0; i < cnt; i++) + { + libusb_get_device_descriptor(list[i], &desc); + + for (int j = 0; g15_devices[i].name != NULL; j++) { - if ((dev->descriptor.idVendor == g15_devices[i].vendorid && dev->descriptor.idProduct == g15_devices[i].productid)) + if ((desc.idVendor == g15_devices[j].vendorid && desc.idProduct == g15_devices[j].productid)) found++; + break; } } + + libusb_free_device_list(list, 1); + g15_log(stderr,G15_LOG_INFO,"Found %i supported devices\n",found); return found; } static int initLibUsb() { - usb_init(); - - /** - * usb_find_busses and usb_find_devices both report the number of devices - * / busses added / removed since the last call. since this is the first - * call we have to return values != 0 or else we didnt find anything */ + int errcode = libusb_init(&libg15_libusb_context); - if (!usb_find_busses()) + if (errcode != 0) + { + g15_log(stderr, G15_LOG_INFO, "Failed to initialize libusb-1.0: %s\n", libusb_strerror(errcode)); return G15_ERROR_OPENING_USB_DEVICE; + } - if (!usb_find_devices()) - return G15_ERROR_OPENING_USB_DEVICE; + libg15Debug(libg15_debugging_enabled); return G15_NO_ERROR; } -static usb_dev_handle * findAndOpenDevice(libg15_devices_t handled_device, int device_index) +static libusb_device_handle* findAndOpenG15() { - struct usb_bus *bus = 0; - struct usb_device *dev = 0; - int retries=0; - int j,i,k,l; - int interface=0; + struct libusb_config_descriptor *cfg = NULL; + libusb_device_handle *devh = 0; + libusb_device *dev = NULL; + libusb_device **list = 0; + /* Use configuration 1 by default. */ + int configuration = 1; + int unconfigured = 0; + int found_dev = -1; + int ret; + + ssize_t cnt = libusb_get_device_list(libg15_libusb_context, &list); + + if (cnt < 0) + { + g15_log(stderr, G15_LOG_INFO, "Unable to list USB devices: %s\n", libusb_strerror(cnt)); + return 0; + } - for (bus = usb_busses; bus; bus = bus->next) + for (ssize_t devno = 0; devno < cnt && found_dev == -1; devno++) { - for (dev = bus->devices; dev; dev = dev->next) - { - if ((dev->descriptor.idVendor == handled_device.vendorid && dev->descriptor.idProduct == handled_device.productid)) + struct libusb_device_descriptor desc; + libusb_get_device_descriptor(list[devno], &desc); + for (int i = 0; g15_devices[i].name != NULL && found_dev == -1; i++) { + if (desc.idVendor == g15_devices[i].vendorid && desc.idProduct == g15_devices[i].productid) { - int ret=0; - char name_buffer[65535]; - name_buffer[0] = 0; - usb_dev_handle *devh = 0; - found_devicetype = device_index; - g15_log(stderr,G15_LOG_INFO,"Found %s, trying to open it\n",handled_device.name); -#if 0 - devh = usb_open(dev); - usb_reset(devh); - usleep(50*1000); - usb_close(devh); -#endif - devh = usb_open(dev); - if (!devh) - { - g15_log(stderr,G15_LOG_INFO, "Error, could not open the keyboard\n"); - g15_log(stderr,G15_LOG_INFO, "Perhaps you don't have enough permissions to access it\n"); - return 0; - } - - usleep(50*1000); - - g15_log(stderr, G15_LOG_INFO, "Device has %i possible configurations\n",dev->descriptor.bNumConfigurations); - - /* if device is shared with another driver, such as the Z-10 speakers sharing with alsa, we have to disable some calls */ - if(g15DeviceCapabilities() & G15_DEVICE_IS_SHARED) - shared_device = 1; - - for (j = 0; jdescriptor.bNumConfigurations;j++){ - struct usb_config_descriptor *cfg = &dev->config[j]; - - for (i=0;ibNumInterfaces; i++){ - if (g15DeviceCapabilities()&G15_DEVICE_G510){ - if (i==G510_STANDARD_KEYBOARD_INTERFACE) continue; - } - - struct usb_interface *ifp = &cfg->interface[i]; - /* if endpoints are already known, finish up */ - if(g15_keys_endpoint && g15_lcd_endpoint) - break; - g15_log(stderr, G15_LOG_INFO, "Device has %i Alternate Settings\n", ifp->num_altsetting); - - for(k=0;knum_altsetting;k++){ - struct usb_interface_descriptor *as = &ifp->altsetting[k]; - /* verify that the interface is for a HID device */ - if(as->bInterfaceClass==USB_CLASS_HID){ - g15_log(stderr, G15_LOG_INFO, "Interface %i has %i Endpoints\n", i, as->bNumEndpoints); - usleep(50*1000); - /* libusb functions ending in _np are not portable between OS's - * Non-linux users will need some way to detach the HID driver from - * the G15 until we work out how to do this for other OS's automatically. - * For the moment, we just skip this code.. - */ -#ifdef LIBUSB_HAS_GET_DRIVER_NP - ret = usb_get_driver_np(devh, i, name_buffer, 65535); - /* some kernel versions say that a driver is attached even though there is none - in this case the name buffer has not been changed - thanks to RobEngle for pointing this out */ - if (!ret && name_buffer[0]) - { - g15_log(stderr,G15_LOG_INFO,"Trying to detach driver currently attached: \"%s\"\n",name_buffer); - - ret = usb_detach_kernel_driver_np(devh, i); - if (!ret) - { - g15_log(stderr,G15_LOG_INFO,"Success, detached the driver\n"); - } - else - { - g15_log(stderr,G15_LOG_INFO,"Sorry, I could not detach the driver, giving up\n"); - return 0; - } - - } -#endif - /* don't set configuration if device is shared */ - if(0 == shared_device) { - ret = usb_set_configuration(devh, 1); - if (ret) - { - g15_log(stderr,G15_LOG_INFO,"Error setting the configuration, this is fatal\n"); - return 0; - } - } - usleep(50*1000); - while((ret = usb_claim_interface(devh,i)) && retries <10) { - usleep(50*1000); - retries++; - g15_log(stderr,G15_LOG_INFO,"Trying to claim interface\n"); - } - - if (ret) - { - g15_log(stderr,G15_LOG_INFO,"Error claiming interface, good day cruel world\n"); - return 0; - } - - for (l=0; l< as->bNumEndpoints;l++){ - struct usb_endpoint_descriptor *ep=&as->endpoint[l]; - g15_log(stderr, G15_LOG_INFO, "Found %s endpoint %i with address 0x%X maxtransfersize=%i \n", - 0x80&ep->bEndpointAddress?"\"Extra Keys\"":"\"LCD\"", - ep->bEndpointAddress&0x0f,ep->bEndpointAddress, ep->wMaxPacketSize - ); - - if(0x80 & ep->bEndpointAddress) { - g15_keys_endpoint = ep->bEndpointAddress; - } else { - g15_lcd_endpoint = ep->bEndpointAddress; - } -#if 0 - usb_resetep(devh,ep->bEndpointAddress); -#endif - } - - if (ret) - { - g15_log(stderr, G15_LOG_INFO, "Error setting Alternate Interface\n"); - } - } - } - } - } - - - g15_log(stderr,G15_LOG_INFO,"Done opening the keyboard\n"); - usleep(500*1000); // sleep a bit for good measure - return devh; + found_dev = i; + dev = list[devno]; + g15_log(stderr, G15_LOG_INFO, "Found bus %03u port %03u device %03u ID %04x:%04x %s\n", + libusb_get_bus_number(list[devno]), + libusb_get_port_number(list[devno]), + libusb_get_device_address(list[devno]), + desc.idVendor, + desc.idProduct, + g15_devices[i].name); + g15_log(stderr, G15_LOG_INFO, "Device has %u possible configuration%s\n", desc.bNumConfigurations, desc.bNumConfigurations > 1 ? "s" : ""); } } } - return 0; -} + if (found_dev == -1) { + libusb_free_device_list(list, 1); + g15_log(stderr, G15_LOG_INFO, "No supported devices found\n"); + return 0; + } -static usb_dev_handle * findAndOpenG15() { - int i; - for (i=0; g15_devices[i].name !=NULL ;i++){ - g15_log(stderr,G15_LOG_INFO,"Trying to find %s\n",g15_devices[i].name); - if(keyboard_device = findAndOpenDevice(g15_devices[i],i)){ + pthread_mutex_lock(&libusb_mutex); + + if (found_devicetype != -1) + { + g15_log(stderr, G15_LOG_INFO, "Error, device is already open\n"); + goto error; + } + + found_devicetype = found_dev; + ret = libusb_open(dev, &devh); + libusb_free_device_list(list, 1); + list = NULL; + + if (ret || !devh) + { + g15_log(stderr, G15_LOG_INFO, "Error, could not open the keyboard: %s\n", libusb_strerror(ret)); + goto error; + } + + /* If device is shared with another driver, such as the Z-10 speakers sharing with alsa, we have to disable some calls. */ + if(g15DeviceCapabilities() & G15_DEVICE_IS_SHARED) + { + shared_device = 1; + ret = libusb_get_configuration(devh, &configuration); + if (ret) + { + g15_log(stderr, G15_LOG_INFO, "Error, could not retrieve current configuration: %s\n", libusb_strerror(ret)); + goto error; + } + else if (configuration < 1) + { + unconfigured = 1; + configuration = 1; + } + else if (configuration != 1) + { + g15_log(stderr, G15_LOG_INFO, "Warning, using unknown configuration %i for shared device\n", configuration); + } + } + + ret = libusb_get_config_descriptor_by_value(dev, configuration, &cfg); + + if (ret) + { + g15_log(stderr, G15_LOG_INFO, "Error, could not retrieve descriptor for configuration %i: %s\n", + configuration, libusb_strerror(ret)); + + goto error; + } + + g15_log(stderr, G15_LOG_INFO, "Device has %u possible interface%s for configuration %i\n", + cfg->bNumInterfaces, cfg->bNumInterfaces > 1 ? "s" : "", configuration); + + const struct libusb_interface_descriptor *iface = NULL; + for (int i = 0; i < cfg->bNumInterfaces; i++) + { + /* Always use altsetting 0, others are not supported even if exist. */ + iface = &cfg->interface[i].altsetting[0]; + if ((g15DeviceCapabilities() & G15_DEVICE_G510) && iface->bInterfaceNumber == G510_STANDARD_KEYBOARD_INTERFACE) continue; + + if (iface->bInterfaceClass == LIBUSB_CLASS_HID && iface->bNumEndpoints > 0) + { + g15_log(stderr, G15_LOG_INFO, "Selecting HID interface %u, it has %u possible altsetting%s\n", + iface->bInterfaceNumber, cfg->interface[i].num_altsetting, cfg->interface[i].num_altsetting > 1 ? "s" : ""); + + g15_interface_id = iface->bInterfaceNumber; break; } + } + + if (g15_interface_id == -1) + { + g15_log(stderr, G15_LOG_INFO, "Error, could not find suitable HID interface\n"); + goto error; + } + + for (int i = 0; i < iface->bNumEndpoints; i++) + { + const struct libusb_endpoint_descriptor *ep = &iface->endpoint[i]; + g15_log(stderr, G15_LOG_INFO, "Found %s endpoint %i with address 0x%X maxtransfersize=%i\n", + 0x80 & ep->bEndpointAddress ? "\"Extra Keys\"" : "\"LCD\"", + ep->bEndpointAddress & 0x0f, ep->bEndpointAddress, ep->wMaxPacketSize); + + if (0x80 & ep->bEndpointAddress) + { + g15_keys_endpoint = ep->bEndpointAddress; + } + else + { + g15_lcd_endpoint = ep->bEndpointAddress; + } + } + + if (libusb_kernel_driver_active(devh, g15_interface_id) == 1) + { + g15_log(stderr, G15_LOG_INFO, "Trying to detach driver currently attached\n"); + + ret = libusb_detach_kernel_driver(devh, g15_interface_id); + if (!ret) + { + g15_log(stderr,G15_LOG_INFO,"Success, detached the driver\n"); + } else - g15_log(stderr,G15_LOG_INFO,"%s not found\n",g15_devices[i].name); + { + g15_log(stderr,G15_LOG_INFO,"Could not detach the driver, giving up: %s\n", libusb_strerror(ret)); + goto error; + } + } + + if(!shared_device || unconfigured) + { + /* Set configuration, reset state, reset altsetting to 0 */ + ret = libusb_set_configuration(devh, 1); + if (ret) + { + g15_log(stderr,G15_LOG_INFO,"Error setting the configuration: %s\n", libusb_strerror(ret)); + goto error; + } + } + + ret = 1; + for (int i = 0; i < 10 && ret; i++) + { + usleep(50 * 1000); + g15_log(stderr, G15_LOG_INFO, "Trying to claim interface\n"); + ret = libusb_claim_interface(devh, g15_interface_id); + } + + if (ret) + { + g15_log(stderr, G15_LOG_INFO, "Error claiming interface, good day cruel world: %s\n", libusb_strerror(ret)); + goto error; + } + + libusb_free_config_descriptor(cfg); + + g15_log(stderr, G15_LOG_INFO, "Done opening the keyboard\n"); + + pthread_mutex_unlock(&libusb_mutex); + + return devh; + +error: + if (devh) + { + libusb_attach_kernel_driver(devh, 0); + libusb_close(devh); } - return keyboard_device; + if (cfg) libusb_free_config_descriptor(cfg); + if (list) libusb_free_device_list(list, 1); + shared_device = g15_keys_endpoint = g15_lcd_endpoint = 0; + g15_interface_id = found_devicetype = -1; + pthread_mutex_unlock(&libusb_mutex); + + return 0; } -int re_initLibG15() +/* reset the keyboard, returning it to a known state */ +static int closeKeyboardDevice() { + int retval = G15_ERROR_OPENING_USB_DEVICE; - usb_init(); + pthread_mutex_lock(&libusb_mutex); + if (keyboard_device) { + retval = libusb_release_interface(keyboard_device, 0); + libusb_attach_kernel_driver(keyboard_device, 0); + libusb_close(keyboard_device); + keyboard_device = NULL; + retval = G15_NO_ERROR; + } - /** - * usb_find_busses and usb_find_devices both report the number of devices - * / busses added / removed since the last call. since this is the first - * call we have to return values != 0 or else we didnt find anything */ + shared_device = g15_keys_endpoint = g15_lcd_endpoint = 0; + g15_interface_id = found_devicetype = -1; + pthread_mutex_unlock(&libusb_mutex); - if (!usb_find_devices()) - return G15_ERROR_OPENING_USB_DEVICE; + return retval; +} + +int re_initLibG15() +{ + closeKeyboardDevice(); keyboard_device = findAndOpenG15(); if (!keyboard_device) @@ -306,48 +374,34 @@ int re_initLibG15() int initLibG15() { - int retval = G15_NO_ERROR; - retval = initLibUsb(); - if (retval) - return retval; + int retval = initLibUsb(); - g15_log(stderr,G15_LOG_INFO,"%s\n",PACKAGE_STRING); + if (retval) return retval; -#ifdef SUN_LIBUSB - g15_log(stderr,G15_LOG_INFO,"Using Sun libusb.\n"); -#endif + g15_log(stderr, G15_LOG_INFO, "%s\n", PACKAGE_STRING); - g15NumberOfConnectedDevices(); + if (libg15_debugging_enabled) g15NumberOfConnectedDevices(); + pthread_mutex_init(&libusb_mutex, NULL); keyboard_device = findAndOpenG15(); - if (!keyboard_device) + if (!keyboard_device) + { + pthread_mutex_destroy(&libusb_mutex); return G15_ERROR_OPENING_USB_DEVICE; + } - pthread_mutex_init(&libusb_mutex, NULL); - return retval; + return G15_NO_ERROR; } -/* reset the keyboard, returning it to a known state */ int exitLibG15() { - int retval = G15_NO_ERROR; - if (keyboard_device){ -#ifndef SUN_LIBUSB - retval = usb_release_interface (keyboard_device, 0); - usleep(50*1000); -#endif -#if 0 - retval = usb_reset(keyboard_device); - usleep(50*1000); -#endif - usb_close(keyboard_device); - keyboard_device=0; - pthread_mutex_destroy(&libusb_mutex); - return retval; - } - return -1; -} + closeKeyboardDevice(); + if (libg15_libusb_context) libusb_exit(libg15_libusb_context); + libg15_libusb_context = NULL; + pthread_mutex_destroy(&libusb_mutex); + return G15_NO_ERROR; +} static void dumpPixmapIntoLCDFormat(unsigned char *lcd_buffer, unsigned char const *data) { @@ -427,36 +481,6 @@ static void dumpPixmapIntoLCDFormat(unsigned char *lcd_buffer, unsigned char con } } -int handle_usb_errors(const char *prefix, int ret) { - - switch (ret){ - case -ETIMEDOUT: - return G15_ERROR_READING_USB_DEVICE; /* backward-compatibility */ - break; - case -ENOSPC: /* the we don't have enough bandwidth, apparently.. something has to give here.. */ - g15_log(stderr,G15_LOG_INFO,"usb error: ENOSPC.. reducing speed\n"); - enospc_slowdown = 1; - break; - case -ENODEV: /* the device went away - we probably should attempt to reattach */ - case -ENXIO: /* host controller bug */ - case -EINVAL: /* invalid request */ - case -EAGAIN: /* try again */ - case -EFBIG: /* too many frames to handle */ - case -EMSGSIZE: /* msgsize is invalid */ - g15_log(stderr,G15_LOG_INFO,"usb error: %s %s (%i)\n",prefix,usb_strerror(),ret); - break; - case -EPIPE: /* endpoint is stalled */ - g15_log(stderr,G15_LOG_INFO,"usb error: %s EPIPE! clearing...\n",prefix); - pthread_mutex_lock(&libusb_mutex); - usb_clear_halt(keyboard_device, 0x81); - pthread_mutex_unlock(&libusb_mutex); - break; - default: /* timed out */ - g15_log(stderr,G15_LOG_INFO,"Unknown usb error: %s !! (err is %i (%s))\n",prefix,ret,usb_strerror()); - } - return ret; -} - int writePixmapToLCD(unsigned char const *data) { int ret = 0; @@ -473,43 +497,27 @@ int writePixmapToLCD(unsigned char const *data) /* the keyboard needs this magic byte */ lcd_buffer[0] = 0x03; - /* in an attempt to reduce peak bus utilisation, we break the transfer into 32 byte chunks and sleep a bit in between. - It shouldnt make much difference, but then again, the g15 shouldnt be flooding the bus enough to cause ENOSPC, yet - apparently does on some machines... - I'm not sure how successful this will be in combatting ENOSPC, but we'll give it try in the real-world. */ - - if(enospc_slowdown != 0){ -#ifndef LIBUSB_BLOCKS - pthread_mutex_lock(&libusb_mutex); -#endif - for(transfercount = 0;transfercount<=31;transfercount++){ - ret = usb_interrupt_write(keyboard_device, g15_lcd_endpoint, (char*)lcd_buffer+(32*transfercount), 32, 1000); - if (ret != 32) - { - handle_usb_errors ("LCDPixmap Slow Write",ret); - return G15_ERROR_WRITING_PIXMAP; - } - usleep(100); + + /* transfer entire buffer in one hit */ + int transferred = 0; + pthread_mutex_lock(&libusb_mutex); + ret = libusb_interrupt_transfer(keyboard_device, g15_lcd_endpoint, (char*)lcd_buffer, G15_BUFFER_LEN, &transferred, 1000); + pthread_mutex_unlock(&libusb_mutex); + if (ret || transferred != G15_BUFFER_LEN) + { + if (!ret) { + g15_log(stderr,G15_LOG_INFO,"LCDPixmap write error: short write\n"); + } else { + g15_log(stderr,G15_LOG_INFO,"LCDPixmap write error: %s\n", libusb_strerror(ret)); } -#ifndef LIBUSB_BLOCKS - pthread_mutex_unlock(&libusb_mutex); -#endif - }else{ - /* transfer entire buffer in one hit */ -#ifdef LIBUSB_BLOCKS - ret = usb_interrupt_write(keyboard_device, g15_lcd_endpoint, (char*)lcd_buffer, G15_BUFFER_LEN, 1000); -#else - pthread_mutex_lock(&libusb_mutex); - ret = usb_interrupt_write(keyboard_device, g15_lcd_endpoint, (char*)lcd_buffer, G15_BUFFER_LEN, 1000); - pthread_mutex_unlock(&libusb_mutex); -#endif - if (ret != G15_BUFFER_LEN) - { - handle_usb_errors ("LCDPixmap Write",ret); - return G15_ERROR_WRITING_PIXMAP; + if (ret == LIBUSB_ERROR_PIPE) { + pthread_mutex_lock(&libusb_mutex); + libusb_clear_halt(keyboard_device, g15_lcd_endpoint); + pthread_mutex_unlock(&libusb_mutex); } - usleep(100); + return G15_ERROR_WRITING_PIXMAP; } + usleep(100); return 0; } @@ -534,7 +542,9 @@ int setLCDContrast(unsigned int level) usb_data[3] = 18; } pthread_mutex_lock(&libusb_mutex); - retval = usb_control_msg(keyboard_device, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 9, 0x302, 0, (char*)usb_data, 4, 10000); + retval = libusb_control_transfer(keyboard_device, + LIBUSB_REQUEST_TYPE_CLASS + LIBUSB_RECIPIENT_INTERFACE + LIBUSB_ENDPOINT_OUT, + 9, 0x302, 0, (char*)usb_data, 4, 10000); pthread_mutex_unlock(&libusb_mutex); return retval; } @@ -552,7 +562,9 @@ int setLEDs(unsigned int leds) return G15_ERROR_UNSUPPORTED; pthread_mutex_lock(&libusb_mutex); - retval = usb_control_msg(keyboard_device, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 9, 0x302, 0, (char*)m_led_buf, 4, 10000); + retval = libusb_control_transfer(keyboard_device, + LIBUSB_REQUEST_TYPE_CLASS + LIBUSB_RECIPIENT_INTERFACE + LIBUSB_ENDPOINT_OUT, + 9, 0x302, 0, (char*)m_led_buf, 4, 10000); pthread_mutex_unlock(&libusb_mutex); return retval; } @@ -577,7 +589,9 @@ int setLCDBrightness(unsigned int level) usb_data[2] = 0x00; } pthread_mutex_lock(&libusb_mutex); - retval = usb_control_msg(keyboard_device, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 9, 0x302, 0, (char*)usb_data, 4, 10000); + retval = libusb_control_transfer(keyboard_device, + LIBUSB_REQUEST_TYPE_CLASS + LIBUSB_RECIPIENT_INTERFACE + LIBUSB_ENDPOINT_OUT, + 9, 0x302, 0, (char*)usb_data, 4, 10000); pthread_mutex_unlock(&libusb_mutex); return retval; } @@ -603,7 +617,9 @@ int setKBBrightness(unsigned int level) usb_data[2] = 0x0; } pthread_mutex_lock(&libusb_mutex); - retval = usb_control_msg(keyboard_device, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 9, 0x302, 0, (char*)usb_data, 4, 10000); + retval = libusb_control_transfer(keyboard_device, + LIBUSB_REQUEST_TYPE_CLASS + LIBUSB_RECIPIENT_INTERFACE + LIBUSB_ENDPOINT_OUT, + 9, 0x302, 0, (char*)usb_data, 4, 10000); pthread_mutex_unlock(&libusb_mutex); return retval; } @@ -618,7 +634,9 @@ int setG510LEDColor(unsigned char r, unsigned char g, unsigned char b) usb_data[3] = b; pthread_mutex_lock(&libusb_mutex); - retval = usb_control_msg(keyboard_device, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 9, 0x305, 1, (char*)usb_data, 4, 10000); + retval = libusb_control_transfer(keyboard_device, + LIBUSB_REQUEST_TYPE_CLASS + LIBUSB_RECIPIENT_INTERFACE + LIBUSB_ENDPOINT_OUT, + 9, 0x305, 1, (char*)usb_data, 4, 10000); pthread_mutex_unlock(&libusb_mutex); return retval; } @@ -1032,38 +1050,54 @@ static void processKeyEvent4Byte(unsigned int *pressed_keys, unsigned char *buff int getPressedKeys(unsigned int *pressed_keys, unsigned int timeout) { unsigned char buffer[G15_KEY_READ_LENGTH]; + int transferred = 0; int ret = 0; int caps = 0; -#ifdef LIBUSB_BLOCKS - ret = usb_interrupt_read(keyboard_device, g15_keys_endpoint, (char*)buffer, G15_KEY_READ_LENGTH, timeout); -#else pthread_mutex_lock(&libusb_mutex); - ret = usb_interrupt_read(keyboard_device, g15_keys_endpoint, (char*)buffer, G15_KEY_READ_LENGTH, timeout); + ret = libusb_interrupt_transfer(keyboard_device, g15_keys_endpoint, (char*)buffer, G15_KEY_READ_LENGTH, &transferred, timeout); pthread_mutex_unlock(&libusb_mutex); -#endif - if(ret>0) { - if(buffer[0] == 1) + + switch (ret) + { + case 0: + break; + case LIBUSB_ERROR_TIMEOUT: + return G15_ERROR_TIMEOUT; + case LIBUSB_ERROR_PIPE: + pthread_mutex_lock(&libusb_mutex); + libusb_clear_halt(keyboard_device, g15_keys_endpoint); + pthread_mutex_unlock(&libusb_mutex); + //no break + default: + g15_log(stderr,G15_LOG_INFO,"USB error on keybaord read: %s\n", libusb_strerror(ret)); + return G15_ERROR_READING_USB_DEVICE; + } + + if (transferred > 0 && buffer[0] == 1) { return G15_ERROR_TRY_AGAIN; } caps = g15DeviceCapabilities(); - if((caps & G15_DEVICE_G13) && buffer[0]==0x25){ - processKeyEventG13(pressed_keys, buffer); - return G15_NO_ERROR; + if ((caps & G15_DEVICE_G13) && buffer[0]==0x25) + { + processKeyEventG13(pressed_keys, buffer); + return G15_NO_ERROR; } - switch(ret) { - case 4: - processKeyEvent4Byte(pressed_keys, buffer); - return G15_NO_ERROR; - case 5: - processKeyEvent5Byte(pressed_keys, buffer); - return G15_NO_ERROR; - case 9: - processKeyEvent9Byte(pressed_keys, buffer); - return G15_NO_ERROR; - default: - return handle_usb_errors("Keyboard Read", ret); /* allow the app to deal with errors */ + switch (transferred) + { + case 4: + processKeyEvent4Byte(pressed_keys, buffer); + return G15_NO_ERROR; + case 5: + processKeyEvent5Byte(pressed_keys, buffer); + return G15_NO_ERROR; + case 9: + processKeyEvent9Byte(pressed_keys, buffer); + return G15_NO_ERROR; + default: + g15_log(stderr, G15_LOG_INFO,"USB error on keybaord read: unsupported packet size\n"); + return G15_ERROR_READING_USB_DEVICE; } }