From d7ab8990be4312169ffa45bcfcd715dcc9e811f9 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Fri, 23 Oct 2026 00:13:05 +0400 Subject: [PATCH] feat(usb): migrate to libusb 1.0 Replace the old libusb 0.1 API with libusb 1.0. - Update device detection and USB transfers. - Update USB interface and resource handling. - Use pkg-config to find the library. - Update build dependencies and installation instructions. --- .travis.yml | 3 +- INSTALL | 12 ++- config.mk | 5 + src/Makefile | 8 +- src/cold-flash.c | 30 +++--- src/disk.c | 19 +--- src/mkii.c | 13 ++- src/nolo.c | 48 ++++----- src/usb-device.c | 271 ++++++++++++++++++++++++++++------------------- src/usb-device.h | 19 ++-- 10 files changed, 245 insertions(+), 183 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6192a3f..ff69cc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,8 @@ compiler: addons: &addons apt: packages: - - libusb-dev + - libusb-1.0-0-dev + - pkg-config matrix: include: diff --git a/INSTALL b/INSTALL index 84b5547..d2eecb9 100644 --- a/INSTALL +++ b/INSTALL @@ -1,9 +1,15 @@ Installation instructions: ========================== -To build the flasher you will need gcc, make and libusb. For crosscompiling -to arm you can use scratchbox. But you will probably need the libusb.so of -the scratchbox environment to the device. +To build the flasher you will need gcc, make and libusb-1.0 (version 1.0.16 +or newer). Compiler and linker flags for libusb-1.0 are detected by pkg-config; +without it set LIBUSB_CFLAGS and LIBUSB_LIBS manually (see config.mk), e.g.: + + $ make LIBUSB_CFLAGS=-I/opt/homebrew/opt/libusb/include/libusb-1.0 \ + LIBUSB_LIBS="-L/opt/homebrew/opt/libusb/lib -lusb-1.0" + +For crosscompiling to arm you can use scratchbox. But you will probably need +the libusb-1.0.so of the scratchbox environment to the device. Just type: diff --git a/config.mk b/config.mk index ec685de..5e0fe82 100644 --- a/config.mk +++ b/config.mk @@ -4,3 +4,8 @@ PREFIX = /usr/local # NetBSD stuff #CPPFLAGS += -I/usr/pkg/include #LDFLAGS += -L/usr/pkg/lib -Wl,-R/usr/pkg/lib + +# libusb-1.0 flags are detected by pkg-config, set them manually without it +# (e.g. macOS with Homebrew libusb on Apple Silicon) +#LIBUSB_CFLAGS = -I/opt/homebrew/opt/libusb/include/libusb-1.0 +#LIBUSB_LIBS = -L/opt/homebrew/opt/libusb/lib -lusb-1.0 diff --git a/src/Makefile b/src/Makefile index 0f05ed6..e76f572 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,9 +9,13 @@ CC ?= cc CROSS_CC ?= $(CROSS_COMPILE)$(CC) HOST_CC ?= $(HOST_COMPILE)$(CC) +PKG_CONFIG ?= pkg-config +LIBUSB_CFLAGS ?= $(shell $(PKG_CONFIG) --cflags libusb-1.0 2>/dev/null) +LIBUSB_LIBS ?= $(shell $(PKG_CONFIG) --libs libusb-1.0 2>/dev/null || echo -lusb-1.0) + CPPFLAGS += -DVERSION=\"$(VERSION)\" -DBUILD_DATE="\"$(BUILD_DATE)\"" -D_POSIX_C_SOURCE=200809L -D_FILE_OFFSET_BITS=64 CFLAGS += -W -Wall -O2 -pedantic -std=c99 -LIBS += -lusb -ldl +LIBS += $(LIBUSB_LIBS) DEPENDS = Makefile ../config.mk @@ -39,7 +43,7 @@ libusb-sniff-64.so: libusb-sniff.c $(DEPENDS) $(CC) $(CFLAGS) $(LDFLAGS) -fPIC $< -ldl -shared -m64 -o $@ %.o: %.c $(DEPENDS) - $(CROSS_CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + $(CROSS_CC) $(CFLAGS) $(CPPFLAGS) $(LIBUSB_CFLAGS) -c -o $@ $< install: $(BIN) $(BIN).1 $(INSTALL) -D -m 755 $(BIN) $(DESTDIR)$(PREFIX)/bin/$(BIN) diff --git a/src/cold-flash.c b/src/cold-flash.c index bfc31d0..5bfa41c 100644 --- a/src/cold-flash.c +++ b/src/cold-flash.c @@ -167,12 +167,12 @@ struct xloader_msg xloader_msg_create(uint32_t type, struct image * image) { } -static int read_asic(usb_dev_handle * udev, uint8_t * asic_buffer, int size, int asic_size) { +static int read_asic(libusb_device_handle * udev, uint8_t * asic_buffer, int size, int asic_size) { int ret; printf("Waiting for ASIC ID...\n"); - ret = usb_bulk_read(udev, USB_READ_EP, (char *)asic_buffer, size, READ_TIMEOUT); + ret = usb_bulk_recv(udev, USB_READ_EP, asic_buffer, size, READ_TIMEOUT); if ( ret != asic_size ) ERROR_RETURN("Invalid size of ASIC ID", -1); @@ -180,21 +180,21 @@ static int read_asic(usb_dev_handle * udev, uint8_t * asic_buffer, int size, int } -static int send_2nd(usb_dev_handle * udev, struct image * image) { +static int send_2nd(libusb_device_handle * udev, struct image * image) { uint8_t buffer[1024]; uint32_t need, sent; int ret; printf("Sending OMAP peripheral boot message...\n"); - ret = usb_bulk_write(udev, USB_WRITE_EP, (char *)&omap_peripheral_msg, sizeof(omap_peripheral_msg), WRITE_TIMEOUT); + ret = usb_bulk_send(udev, USB_WRITE_EP, &omap_peripheral_msg, sizeof(omap_peripheral_msg), WRITE_TIMEOUT); if ( ret != sizeof(omap_peripheral_msg) ) ERROR_RETURN("Sending OMAP peripheral boot message failed", -1); MSLEEP(5); printf("Sending 2nd X-Loader image size...\n"); - ret = usb_bulk_write(udev, USB_WRITE_EP, (char *)&image->size, 4, WRITE_TIMEOUT); + ret = usb_bulk_send(udev, USB_WRITE_EP, &image->size, 4, WRITE_TIMEOUT); if ( ret != 4 ) ERROR_RETURN("Sending 2nd X-Loader image size failed", -1); @@ -211,7 +211,7 @@ static int send_2nd(usb_dev_handle * udev, struct image * image) { ret = image_read(image, buffer, need); if ( ret == 0 ) break; - if ( usb_bulk_write(udev, USB_WRITE_EP, (char *)buffer, ret, WRITE_TIMEOUT) != ret ) + if ( usb_bulk_send(udev, USB_WRITE_EP, buffer, ret, WRITE_TIMEOUT) != ret ) PRINTF_ERROR_RETURN("Sending 2nd X-Loader image failed", -1); sent += ret; printf_progressbar(sent, image->size); @@ -222,7 +222,7 @@ static int send_2nd(usb_dev_handle * udev, struct image * image) { } -static int send_secondary(usb_dev_handle * udev, struct image * image) { +static int send_secondary(libusb_device_handle * udev, struct image * image) { struct xloader_msg init_msg; uint8_t buffer[1024]; @@ -232,13 +232,13 @@ static int send_secondary(usb_dev_handle * udev, struct image * image) { init_msg = xloader_msg_create(XLOADER_MSG_TYPE_SEND, image); printf("Sending X-Loader init message...\n"); - ret = usb_bulk_write(udev, USB_WRITE_EP, (char *)&init_msg, sizeof(init_msg), WRITE_TIMEOUT); + ret = usb_bulk_send(udev, USB_WRITE_EP, &init_msg, sizeof(init_msg), WRITE_TIMEOUT); if ( ret != sizeof(init_msg) ) ERROR_RETURN("Sending X-Loader init message failed", -1); printf("Waiting for X-Loader response...\n"); MSLEEP(5); - ret = usb_bulk_read(udev, USB_READ_EP, (char *)&buffer, 4, READ_TIMEOUT); /* 4 bytes - dummy value */ + ret = usb_bulk_recv(udev, USB_READ_EP, &buffer, 4, READ_TIMEOUT); /* 4 bytes - dummy value */ if ( ret != 4 ) ERROR_RETURN("No response", -1); @@ -253,7 +253,7 @@ static int send_secondary(usb_dev_handle * udev, struct image * image) { ret = image_read(image, buffer, need); if ( ret == 0 ) break; - if ( usb_bulk_write(udev, USB_WRITE_EP, (char *)buffer, ret, WRITE_TIMEOUT) != ret ) + if ( usb_bulk_send(udev, USB_WRITE_EP, buffer, ret, WRITE_TIMEOUT) != ret ) PRINTF_ERROR_RETURN("Sending Secondary image failed", -1); sent += ret; printf_progressbar(sent, image->size); @@ -261,7 +261,7 @@ static int send_secondary(usb_dev_handle * udev, struct image * image) { printf("Waiting for X-Loader response...\n"); MSLEEP(5); - ret = usb_bulk_read(udev, USB_READ_EP, (char *)&buffer, 4, READ_TIMEOUT); /* 4 bytes - dummy value */ + ret = usb_bulk_recv(udev, USB_READ_EP, &buffer, 4, READ_TIMEOUT); /* 4 bytes - dummy value */ if ( ret != 4 ) ERROR_RETURN("No response", -1); @@ -269,7 +269,7 @@ static int send_secondary(usb_dev_handle * udev, struct image * image) { } -static int ping_timeout(usb_dev_handle * udev) { +static int ping_timeout(libusb_device_handle * udev) { int ret; int pong = 0; @@ -281,7 +281,7 @@ static int ping_timeout(usb_dev_handle * udev) { int try_read = 4; printf("Sending X-Loader ping message\n"); - ret = usb_bulk_write(udev, USB_WRITE_EP, (char *)&ping_msg, sizeof(ping_msg), WRITE_TIMEOUT); + ret = usb_bulk_send(udev, USB_WRITE_EP, &ping_msg, sizeof(ping_msg), WRITE_TIMEOUT); if ( ret != sizeof(ping_msg) ) ERROR_RETURN("Sending X-Loader ping message failed", -1); @@ -289,7 +289,7 @@ static int ping_timeout(usb_dev_handle * udev) { while ( try_read > 0 ) { uint32_t ping_read; - ret = usb_bulk_read(udev, USB_READ_EP, (char *)&ping_read, sizeof(ping_read), READ_TIMEOUT); + ret = usb_bulk_recv(udev, USB_READ_EP, &ping_read, sizeof(ping_read), READ_TIMEOUT); if ( ret == sizeof(ping_read) ) { printf("Got it\n"); pong = 1; @@ -409,7 +409,7 @@ int leave_cold_flash(struct usb_device_info * dev) { int ret; printf("Sending OMAP memory boot message...\n"); - ret = usb_bulk_write(dev->udev, USB_WRITE_EP, (char *)&omap_memory_msg, sizeof(omap_memory_msg), WRITE_TIMEOUT); + ret = usb_bulk_send(dev->udev, USB_WRITE_EP, &omap_memory_msg, sizeof(omap_memory_msg), WRITE_TIMEOUT); if ( ret != sizeof(omap_memory_msg) ) ERROR_RETURN("Sending OMAP memory boot message failed", -1); diff --git a/src/disk.c b/src/disk.c index 41d1823..eeda053 100644 --- a/src/disk.c +++ b/src/disk.c @@ -385,13 +385,9 @@ int disk_init(struct usb_device_info * dev) { unsigned int devnum; unsigned int busnum; - struct usb_device * device; + libusb_device * device; - device = usb_device(dev->udev); - if ( ! device || ! device->bus ) { - ERROR_INFO("Cannot read usb devnum and busnum"); - return -1; - } + device = libusb_get_device(dev->udev); dir = opendir("/sys/dev/block/"); if ( ! dir ) { @@ -432,16 +428,11 @@ int disk_init(struct usb_device_info * dev) { fclose(f); - if ( device->devnum != devnum ) + if ( (unsigned int)libusb_get_device_address(device) != devnum ) continue; - if ( device->bus->location ) { - if ( device->bus->location != busnum ) - continue; - } else if ( device->bus->dirname[0] ) { - if ( atoi(device->bus->dirname) != (int)busnum ) - continue; - } + if ( (unsigned int)libusb_get_bus_number(device) != busnum ) + continue; if ( sscanf(dirent->d_name, "%d:%d", &maj2, &min2) != 2 ) { maj2 = -1; diff --git a/src/mkii.c b/src/mkii.c index 51045f6..b8ad6bd 100644 --- a/src/mkii.c +++ b/src/mkii.c @@ -48,7 +48,7 @@ struct mkii_message { } __attribute__((__packed__)); -static int mkii_send_receive(usb_dev_handle * udev, uint8_t type, struct mkii_message * in_msg, size_t data_size, struct mkii_message * out_msg, size_t out_size) { +static int mkii_send_receive(libusb_device_handle * udev, uint8_t type, struct mkii_message * in_msg, size_t data_size, struct mkii_message * out_msg, size_t out_size) { int ret; static uint8_t number = 0; @@ -59,13 +59,13 @@ static int mkii_send_receive(usb_dev_handle * udev, uint8_t type, struct mkii_me in_msg->num = number++; in_msg->type = type; - ret = usb_bulk_write(udev, USB_WRITE_EP, (char *)in_msg, data_size + sizeof(*in_msg), 5000); + ret = usb_bulk_send(udev, USB_WRITE_EP, in_msg, data_size + sizeof(*in_msg), 5000); if ( ret < 0 ) return ret; if ( (size_t)ret != data_size + sizeof(*in_msg) ) return -1; - ret = usb_bulk_read(udev, USB_READ_EP, (char *)out_msg, out_size, 5000); + ret = usb_bulk_recv(udev, USB_READ_EP, out_msg, out_size, 5000); if ( ret < 0 ) return ret; @@ -89,6 +89,7 @@ int mkii_init(struct usb_device_info * dev) { char buf[2048]; struct mkii_message * msg; + struct libusb_config_descriptor * config; enum device device; int ret; char * newptr; @@ -159,8 +160,10 @@ int mkii_init(struct usb_device_info * dev) { printf("\n"); memset(buf, 0, sizeof(buf)); - if ( usb_device(dev->udev)->descriptor.bNumConfigurations >= 1 ) - usb_get_string_simple(dev->udev, usb_device(dev->udev)->config[0].iConfiguration, buf, sizeof(buf)); + if ( libusb_get_config_descriptor(libusb_get_device(dev->udev), 0, &config) == 0 ) { + libusb_get_string_descriptor_ascii(dev->udev, config->iConfiguration, (unsigned char *)buf, sizeof(buf)); + libusb_free_config_descriptor(config); + } if ( strncmp(buf, "Firmware Upgrade Configuration", sizeof("Firmware Upgrade Configuration")) == 0 ) dev->data |= MKII_UPDATE_MODE; diff --git a/src/nolo.c b/src/nolo.c index 0684145..6e750da 100644 --- a/src/nolo.c +++ b/src/nolo.c @@ -88,7 +88,7 @@ static void nolo_error_log(struct usb_device_info * dev, int only_clear) { memset(buf, 0, sizeof(buf)); - ret = usb_control_msg(dev->udev, NOLO_QUERY, NOLO_ERROR_LOG, 0, 0, buf, sizeof(buf), 2000); + ret = libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_ERROR_LOG, 0, 0, (unsigned char *)buf, sizeof(buf), 2000); if ( ret < 0 ) break; @@ -118,7 +118,7 @@ static int nolo_identify_string(struct usb_device_info * dev, const char * str, memset(buf, 0, sizeof(buf)); - ret = usb_control_msg(dev->udev, NOLO_QUERY, NOLO_IDENTIFY, 0, 0, (char *)buf, sizeof(buf), 2000); + ret = libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_IDENTIFY, 0, 0, (unsigned char *)buf, sizeof(buf), 2000); if ( ret < 0 ) NOLO_ERROR_RETURN("NOLO_IDENTIFY failed", -1); @@ -148,10 +148,10 @@ static int nolo_set_string(struct usb_device_info * dev, char * str, char * arg) if ( simulate ) return 0; - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_STRING, 0, 0, str, strlen(str), 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_STRING, 0, 0, (unsigned char *)str, strlen(str), 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_STRING failed", -1); - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET_STRING, 0, 0, arg, strlen(arg), 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET_STRING, 0, 0, (unsigned char *)arg, strlen(arg), 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_SET_STRING failed", -1); return 0; @@ -162,10 +162,10 @@ static int nolo_get_string(struct usb_device_info * dev, char * str, char * out, int ret = 0; - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_STRING, 0, 0, str, strlen(str), 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_STRING, 0, 0, (unsigned char *)str, strlen(str), 2000) < 0 ) return -1; - if ( ( ret = usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET_STRING, 0, 0, out, size-1, 2000) ) < 0 ) + if ( ( ret = libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET_STRING, 0, 0, (unsigned char *)out, size-1, 2000) ) < 0 ) return -1; if ( (size_t)ret > size-1 ) @@ -209,7 +209,7 @@ int nolo_init(struct usb_device_info * dev) { printf("Initializing NOLO...\n"); while ( val != 0 ) - if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_STATUS, 0, 0, (char *)&val, 4, 2000) == -1 ) + if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_STATUS, 0, 0, (unsigned char *)&val, 4, 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_STATUS failed", -1); /* clear error log */ @@ -372,7 +372,7 @@ static int nolo_send_image(struct usb_device_info * dev, struct image * image, i printf("Sending image header...\n"); if ( ! simulate ) { - if ( usb_control_msg(dev->udev, NOLO_WRITE, request, 0, 0, buf, ptr-buf, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, request, 0, 0, (unsigned char *)buf, ptr-buf, 2000) < 0 ) NOLO_ERROR_RETURN("Sending image header failed", -1); } @@ -391,7 +391,7 @@ static int nolo_send_image(struct usb_device_info * dev, struct image * image, i if ( ret == 0 ) break; if ( ! simulate ) { - if ( usb_bulk_write(dev->udev, USB_WRITE_DATA_EP, buf, ret, 5000) != ret ) { + if ( usb_bulk_send(dev->udev, USB_WRITE_DATA_EP, buf, ret, 5000) != ret ) { PRINTF_END(); NOLO_ERROR_RETURN("Sending image failed", -1); } @@ -403,7 +403,7 @@ static int nolo_send_image(struct usb_device_info * dev, struct image * image, i if ( flash ) { printf("Finishing flashing...\n"); if ( ! simulate ) { - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SEND_FLASH_FINISH, 0, 0, NULL, 0, 30000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SEND_FLASH_FINISH, 0, 0, NULL, 0, 30000) < 0 ) NOLO_ERROR_RETURN("Finishing failed", -1); } } @@ -460,7 +460,7 @@ int nolo_flash_image(struct usb_device_info * dev, struct image * image) { printf("Flashing image...\n"); if ( ! simulate ) { - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_FLASH_IMAGE, 0, index, NULL, 0, 10000) ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_FLASH_IMAGE, 0, index, NULL, 0, 10000) ) NOLO_ERROR_RETURN("Flashing failed", -1); } @@ -581,7 +581,7 @@ int nolo_boot_device(struct usb_device_info * dev, const char * cmdline) { cmdline = NULL; } - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_BOOT, mode, 0, (char *)cmdline, size, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_BOOT, mode, 0, (unsigned char *)cmdline, size, 2000) < 0 ) NOLO_ERROR_RETURN("Booting failed", -1); return 0; @@ -591,7 +591,7 @@ int nolo_boot_device(struct usb_device_info * dev, const char * cmdline) { int nolo_reboot_device(struct usb_device_info * dev) { printf("Rebooting device...\n"); - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_REBOOT, 0, 0, NULL, 0, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_REBOOT, 0, 0, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_REBOOT failed", -1); return 0; @@ -600,7 +600,7 @@ int nolo_reboot_device(struct usb_device_info * dev) { int nolo_get_root_device(struct usb_device_info * dev) { uint8_t device = 0; - if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_ROOT_DEVICE, (char *)&device, 1, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_ROOT_DEVICE, (unsigned char *)&device, 1, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get root device", -1); return device; @@ -611,7 +611,7 @@ int nolo_set_root_device(struct usb_device_info * dev, int device) { printf("Setting root device to %d...\n", device); if ( simulate ) return 0; - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, device, NOLO_ROOT_DEVICE, NULL, 0, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, device, NOLO_ROOT_DEVICE, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot set root device", -1); return 0; @@ -620,7 +620,7 @@ int nolo_set_root_device(struct usb_device_info * dev, int device) { int nolo_get_usb_host_mode(struct usb_device_info * dev) { uint32_t enabled = 0; - if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_USB_HOST_MODE, (void *)&enabled, 4, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_USB_HOST_MODE, (unsigned char *)&enabled, 4, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get USB host mode status", -1); return enabled ? 1 : 0; @@ -631,7 +631,7 @@ int nolo_set_usb_host_mode(struct usb_device_info * dev, int enable) { printf("%s USB host mode...\n", enable ? "Enabling" : "Disabling"); if ( simulate ) return 0; - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, enable, NOLO_USB_HOST_MODE, NULL, 0, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, enable, NOLO_USB_HOST_MODE, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot change USB host mode status", -1); return 0; @@ -640,7 +640,7 @@ int nolo_set_usb_host_mode(struct usb_device_info * dev, int enable) { int nolo_get_rd_mode(struct usb_device_info * dev) { uint8_t enabled = 0; - if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_RD_MODE, (char *)&enabled, 1, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_RD_MODE, (unsigned char *)&enabled, 1, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get R&D mode status", -1); return enabled ? 1 : 0; @@ -651,7 +651,7 @@ int nolo_set_rd_mode(struct usb_device_info * dev, int enable) { printf("%s R&D mode...\n", enable ? "Enabling" : "Disabling"); if ( simulate ) return 0; - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, enable, NOLO_RD_MODE, NULL, 0, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, enable, NOLO_RD_MODE, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot change R&D mode status", -1); return 0; @@ -664,7 +664,7 @@ int nolo_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size) { uint16_t add_flags = 0; char * ptr = flags; - if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_ADD_RD_FLAGS, (char *)&add_flags, 2, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_ADD_RD_FLAGS, (unsigned char *)&add_flags, 2, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get R&D flags", -1); if ( add_flags & NOLO_RD_FLAG_NO_OMAP_WD ) @@ -764,10 +764,10 @@ int nolo_set_rd_flags(struct usb_device_info * dev, const char * flags) { if ( simulate ) return 0; - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, add_flags, NOLO_ADD_RD_FLAGS, NULL, 0, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, add_flags, NOLO_ADD_RD_FLAGS, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot add R&D flags", -1); - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET, del_flags, NOLO_DEL_RD_FLAGS, NULL, 0, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, del_flags, NOLO_DEL_RD_FLAGS, NULL, 0, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot del R&D flags", -1); return 0; @@ -827,7 +827,7 @@ int nolo_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size) { uint32_t version = 0; - if ( usb_control_msg(dev->udev, NOLO_QUERY, NOLO_GET_NOLO_VERSION, 0, 0, (char *)&version, 4, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET_NOLO_VERSION, 0, 0, (unsigned char *)&version, 4, 2000) < 0 ) NOLO_ERROR_RETURN("Cannot get NOLO version", -1); if ( (version & 255) > 1 ) @@ -886,7 +886,7 @@ int nolo_set_sw_ver(struct usb_device_info * dev, const char * ver) { memcpy(ptr, ver, len); ptr += len; - if ( usb_control_msg(dev->udev, NOLO_WRITE, NOLO_SET_SW_RELEASE, 0, 0, buf, ptr-buf, 2000) < 0 ) + if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET_SW_RELEASE, 0, 0, (unsigned char *)buf, ptr-buf, 2000) < 0 ) NOLO_ERROR_RETURN("NOLO_SET_SW_RELEASE failed", -1); return 0; diff --git a/src/usb-device.c b/src/usb-device.c index affda2e..7d64b47 100644 --- a/src/usb-device.c +++ b/src/usb-device.c @@ -17,11 +17,6 @@ */ -/* Enable RTLD_DEFAULT for glibc */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - #include #include #include @@ -29,7 +24,6 @@ #include #include #include -#include #include "global.h" #include "device.h" @@ -39,11 +33,9 @@ #include "cold-flash.h" #include "mkii.h" -#ifdef __linux__ -#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP -#include -#endif -#endif +#define USB_ERROR(str, err) do { PRINTF_END(); ERROR("%s: %s", str, libusb_strerror(err)); } while (0) + +static libusb_context * usb_ctx; static struct usb_flash_device usb_devices[] = { /* vend prod i a protocol devices */ @@ -92,31 +84,20 @@ static void usb_flash_device_info_print(const struct usb_flash_device * dev) { } -static void usb_reattach_kernel_driver(usb_dev_handle * udev, int interface) { - -#ifdef __linux__ -#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP - struct { - int ifno; - int ioctl_code; - void * data; - } command = { - .ifno = interface, - .ioctl_code = _IO('U', 23), - .data = NULL, - }; +static void usb_reattach_kernel_driver(libusb_device_handle * udev, int interface, int detached) { if ( interface < 0 ) return; - usb_release_interface(udev, interface); - ioctl(*((int *)udev), _IOWR('U', 18, command), &command); -#endif -#endif + libusb_release_interface(udev, interface); + + /* Reattach only driver detached by us, on macOS reattaching re-enumerates (resets) device */ + if ( detached ) + libusb_attach_kernel_driver(udev, interface); } -static void usb_descriptor_info_print(usb_dev_handle * udev, struct usb_device * dev, char * product, size_t size) { +static void usb_descriptor_info_print(libusb_device_handle * udev, const struct libusb_device_descriptor * desc, char * product, size_t size) { char buf[1024]; char buf2[1024]; @@ -125,7 +106,7 @@ static void usb_descriptor_info_print(usb_dev_handle * udev, struct usb_device * int i; memset(buf, 0, sizeof(buf)); - usb_get_string_simple(udev, dev->descriptor.iProduct, buf, sizeof(buf)); + libusb_get_string_descriptor_ascii(udev, desc->iProduct, (unsigned char *)buf, sizeof(buf)); PRINTF_LINE("USB device product string: %s", buf[0] ? buf : "(not detected)"); PRINTF_END(); @@ -134,7 +115,7 @@ static void usb_descriptor_info_print(usb_dev_handle * udev, struct usb_device * memset(buf, 0, sizeof(buf)); memset(buf2, 0, sizeof(buf2)); - ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber, buf, sizeof(buf)); + ret = libusb_get_string_descriptor_ascii(udev, desc->iSerialNumber, (unsigned char *)buf, sizeof(buf)); if ( ! isalnum(buf[0]) ) buf[0] = 0; for ( i = 0; i < ret; i+=2 ) { @@ -153,30 +134,51 @@ static void usb_descriptor_info_print(usb_dev_handle * udev, struct usb_device * } -static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { +static int usb_device_has_interface(libusb_device * dev, int interface, int alternate) { + + struct libusb_config_descriptor * config; + int ret = 1; + + if ( interface == -1 ) + return 1; + + if ( libusb_get_config_descriptor(dev, 0, &config) < 0 ) + return 0; + + if ( interface >= config->bNumInterfaces ) + ret = 0; + else if ( alternate != -1 && alternate >= config->interface[interface].num_altsetting ) + ret = 0; + + libusb_free_config_descriptor(config); + return ret; + +} + +static struct usb_device_info * usb_device_is_valid(libusb_device * dev) { size_t i; + int err; + int detached = 0; char product[1024]; + struct libusb_device_descriptor desc; struct usb_device_info * ret = NULL; + if ( libusb_get_device_descriptor(dev, &desc) < 0 ) + return NULL; + for ( i = 0; i < sizeof(usb_devices)/sizeof(usb_devices[0]); ++i ) { - if ( dev->descriptor.idVendor == usb_devices[i].vendor && dev->descriptor.idProduct == usb_devices[i].product ) { + if ( desc.idVendor == usb_devices[i].vendor && desc.idProduct == usb_devices[i].product ) { if ( usb_devices[i].protocol == FLASH_UNKN ) continue; - if ( dev->descriptor.bNumConfigurations < 1 ) + if ( desc.bNumConfigurations < 1 ) continue; - if ( usb_devices[i].interface != -1 ) { - if ( usb_devices[i].interface >= dev->config[0].bNumInterfaces ) - continue; - if ( usb_devices[i].alternate != -1 ) { - if ( usb_devices[i].alternate >= dev->config[0].interface[usb_devices[i].interface].num_altsetting ) - continue; - } - } + if ( ! usb_device_has_interface(dev, usb_devices[i].interface, usb_devices[i].alternate) ) + continue; printf("\b\b "); PRINTF_END(); @@ -185,28 +187,37 @@ static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { PRINTF_END(); PRINTF_LINE("Opening USB..."); - usb_dev_handle * udev = usb_open(dev); - if ( ! udev ) { - PRINTF_ERROR("usb_open failed"); + libusb_device_handle * udev; + err = libusb_open(dev, &udev); + if ( err < 0 ) { + USB_ERROR("libusb_open failed", err); fprintf(stderr, "\n"); return NULL; } - usb_descriptor_info_print(udev, dev, product, sizeof(product)); + memset(product, 0, sizeof(product)); + usb_descriptor_info_print(udev, &desc, product, sizeof(product)); if ( usb_devices[i].interface >= 0 ) { -#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP - PRINTF_LINE("Detaching kernel from USB interface..."); - usb_detach_kernel_driver_np(udev, usb_devices[i].interface); -#endif + if ( libusb_kernel_driver_active(udev, usb_devices[i].interface) == 1 ) { + PRINTF_LINE("Detaching kernel from USB interface..."); + err = libusb_detach_kernel_driver(udev, usb_devices[i].interface); + if ( err == 0 ) + detached = 1; + else { + PRINTF_END(); + WARNING("Cannot detach kernel driver: %s", libusb_strerror(err)); + } + } PRINTF_LINE("Claiming USB interface..."); - if ( usb_claim_interface(udev, usb_devices[i].interface) < 0 ) { - PRINTF_ERROR("usb_claim_interface failed"); + err = libusb_claim_interface(udev, usb_devices[i].interface); + if ( err < 0 ) { + USB_ERROR("libusb_claim_interface failed", err); fprintf(stderr, "\n"); - usb_reattach_kernel_driver(udev, usb_devices[i].interface); - usb_close(udev); + usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached); + libusb_close(udev); return NULL; } @@ -214,11 +225,12 @@ static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { if ( usb_devices[i].alternate >= 0 ) { PRINTF_LINE("Setting alternate USB interface..."); - if ( usb_set_altinterface(udev, usb_devices[i].alternate) < 0 ) { - PRINTF_ERROR("usb_set_altinterface failed"); + err = libusb_set_interface_alt_setting(udev, usb_devices[i].interface, usb_devices[i].alternate); + if ( err < 0 ) { + USB_ERROR("libusb_set_interface_alt_setting failed", err); fprintf(stderr, "\n"); - usb_reattach_kernel_driver(udev, usb_devices[i].interface); - usb_close(udev); + usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached); + libusb_close(udev); return NULL; } } @@ -226,8 +238,8 @@ static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { ret = calloc(1, sizeof(struct usb_device_info)); if ( ! ret ) { ALLOC_ERROR(); - usb_reattach_kernel_driver(udev, usb_devices[i].interface); - usb_close(udev); + usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached); + libusb_close(udev); return NULL; } @@ -259,8 +271,8 @@ static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { if ( ! noverify && ret->device == DEVICE_UNKNOWN ) { ERROR("Device detection failed"); fprintf(stderr, "\n"); - usb_reattach_kernel_driver(udev, usb_devices[i].interface); - usb_close(udev); + usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached); + libusb_close(udev); free(ret); return NULL; } @@ -273,8 +285,8 @@ static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { if ( ! *device ) { ERROR("Device mishmash"); fprintf(stderr, "\n"); - usb_reattach_kernel_driver(udev, usb_devices[i].interface); - usb_close(udev); + usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached); + libusb_close(udev); free(ret); return NULL; } @@ -283,6 +295,7 @@ static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { ret->hwrev = -1; ret->flash_device = &usb_devices[i]; ret->udev = udev; + ret->detached = detached; break; } } @@ -291,28 +304,6 @@ static struct usb_device_info * usb_device_is_valid(struct usb_device * dev) { } -static struct usb_device_info * usb_search_device(struct usb_device * dev, int level) { - - int i; - struct usb_device_info * ret = NULL; - - if ( ! dev ) - return NULL; - - ret = usb_device_is_valid(dev); - if ( ret ) - return ret; - - for ( i = 0; i < dev->num_children; i++ ) { - ret = usb_search_device(dev->children[i], level + 1); - if ( ret ) - break; - } - - return ret; - -} - static volatile sig_atomic_t signal_quit; static void signal_handler(int signum) { @@ -322,19 +313,33 @@ static void signal_handler(int signum) { } +static void usb_exit(void) { + + libusb_exit(usb_ctx); + usb_ctx = NULL; + +} + struct usb_device_info * usb_open_and_wait_for_device(void) { - struct usb_bus * bus; + libusb_device ** devs; + ssize_t count; + ssize_t j; struct usb_device_info * ret = NULL; int i = 0; + int err; void (*prev)(int); static char progress[] = {'/','-','\\', '|'}; - if ( dlsym(RTLD_DEFAULT, "libusb_init") ) - ERROR_RETURN("You are trying to use broken libusb-1.0 library (either directly or via wrapper) which has slow listing of usb devices. It cannot be used for flashing or cold-flashing. Please use libusb 0.1.", NULL); - - usb_init(); - usb_find_busses(); + /* Context is kept until exit, so device list stays up to date between waits */ + if ( ! usb_ctx ) { + err = libusb_init(&usb_ctx); + if ( err < 0 ) { + USB_ERROR("libusb_init failed", err); + return NULL; + } + atexit(usb_exit); + } PRINTF_BACK(); printf("\n"); @@ -347,26 +352,21 @@ struct usb_device_info * usb_open_and_wait_for_device(void) { PRINTF_LINE("Waiting for USB device... %c", progress[++i%sizeof(progress)]); - usb_find_devices(); - - for ( bus = usb_get_busses(); bus; bus = bus->next ) { - - if ( bus->root_dev ) - ret = usb_search_device(bus->root_dev, 0); - else { - struct usb_device *dev; - for ( dev = bus->devices; dev; dev = dev->next ) { - ret = usb_search_device(dev, 0); - if ( ret ) - break; - } - } + count = libusb_get_device_list(usb_ctx, &devs); + if ( count < 0 ) { + USB_ERROR("libusb_get_device_list failed", (int)count); + break; + } + for ( j = 0; j < count; ++j ) { + ret = usb_device_is_valid(devs[j]); if ( ret ) break; - } + /* Opened device handle holds its own reference */ + libusb_free_device_list(devs, 1); + if ( ret ) break; @@ -390,12 +390,65 @@ struct usb_device_info * usb_open_and_wait_for_device(void) { void usb_close_device(struct usb_device_info * dev) { if ( dev->flash_device->protocol != FLASH_COLD ) - usb_reattach_kernel_driver(dev->udev, dev->flash_device->interface); - usb_close(dev->udev); + usb_reattach_kernel_driver(dev->udev, dev->flash_device->interface, dev->detached); + libusb_close(dev->udev); free(dev); } +/* Translate libusb error, so error messages which print errno stay meaningful */ +static int usb_error_to_errno(int err) { + + switch ( err ) { + case LIBUSB_ERROR_INVALID_PARAM: return EINVAL; + case LIBUSB_ERROR_ACCESS: return EACCES; + case LIBUSB_ERROR_NO_DEVICE: return ENODEV; + case LIBUSB_ERROR_NOT_FOUND: return ENOENT; + case LIBUSB_ERROR_BUSY: return EBUSY; + case LIBUSB_ERROR_TIMEOUT: return ETIMEDOUT; + case LIBUSB_ERROR_OVERFLOW: return EOVERFLOW; + case LIBUSB_ERROR_PIPE: return EPIPE; + case LIBUSB_ERROR_INTERRUPTED: return EINTR; + case LIBUSB_ERROR_NO_MEM: return ENOMEM; + case LIBUSB_ERROR_NOT_SUPPORTED: return ENOTSUP; + default: return EIO; + } + +} + +/* Returns number of transferred bytes or negative libusb error code */ +static int usb_bulk_transfer(libusb_device_handle * udev, unsigned char endpoint, unsigned char * data, int size, unsigned int timeout) { + + int transferred = 0; + int ret; + + ret = libusb_bulk_transfer(udev, endpoint, data, size, &transferred, timeout); + if ( ret == 0 ) + return transferred; + + errno = usb_error_to_errno(ret); + + /* Timed out transfer which moved some data is reported as short transfer, callers check its size */ + if ( ret == LIBUSB_ERROR_TIMEOUT && transferred > 0 ) + return transferred; + + return ret; + +} + +int usb_bulk_send(libusb_device_handle * udev, unsigned char endpoint, const void * data, int size, unsigned int timeout) { + + /* libusb does not modify buffer of OUT transfer */ + return usb_bulk_transfer(udev, endpoint, (unsigned char *)data, size, timeout); + +} + +int usb_bulk_recv(libusb_device_handle * udev, unsigned char endpoint, void * data, int size, unsigned int timeout) { + + return usb_bulk_transfer(udev, endpoint, data, size, timeout); + +} + void usb_switch_to_nolo(struct usb_device_info * dev) { printf("\nSwitching to NOLO mode...\n"); diff --git a/src/usb-device.h b/src/usb-device.h index 1f3277a..bec330d 100644 --- a/src/usb-device.h +++ b/src/usb-device.h @@ -22,16 +22,11 @@ #include -/* u_int*_t types are not defined without _GNU_SOURCE but usb.h needs them */ -#define u_int8_t uint8_t -#define u_int16_t uint16_t -#define u_int32_t uint32_t +#include -#include - -#define USB_READ_EP (USB_ENDPOINT_IN | 0x1) -#define USB_WRITE_EP (USB_ENDPOINT_OUT | 0x1) -#define USB_WRITE_DATA_EP (USB_ENDPOINT_OUT | 0x2) +#define USB_READ_EP (LIBUSB_ENDPOINT_IN | 0x1) +#define USB_WRITE_EP (LIBUSB_ENDPOINT_OUT | 0x1) +#define USB_WRITE_DATA_EP (LIBUSB_ENDPOINT_OUT | 0x2) #include "device.h" @@ -57,7 +52,8 @@ struct usb_device_info { enum device device; int16_t hwrev; const struct usb_flash_device * flash_device; - usb_dev_handle * udev; + libusb_device_handle * udev; + int detached; int data; }; @@ -65,6 +61,9 @@ const char * usb_flash_protocol_to_string(enum usb_flash_protocol protocol); struct usb_device_info * usb_open_and_wait_for_device(void); void usb_close_device(struct usb_device_info * dev); +int usb_bulk_send(libusb_device_handle * udev, unsigned char endpoint, const void * data, int size, unsigned int timeout); +int usb_bulk_recv(libusb_device_handle * udev, unsigned char endpoint, void * data, int size, unsigned int timeout); + void usb_switch_to_nolo(struct usb_device_info * dev); void usb_switch_to_cold(struct usb_device_info * dev); void usb_switch_to_update(struct usb_device_info * dev);