/** * Get a USB configuration descriptor based on its index. */ int libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config) { struct libusb_config_descriptor *_config; unsigned char tmp[8]; unsigned char *buf = NULL; int host_endian = 0; int r; usb_dbg("index %d", config_index); if (config_index >= dev->num_configurations) return LIBUSB_ERROR_NOT_FOUND; _config = malloc(sizeof(*_config)); if (!_config) return LIBUSB_ERROR_NO_MEM; r = usb_backend->get_config_descriptor(dev, config_index, tmp, sizeof(tmp), &host_endian); if (r < 0) goto err; usb_parse_descriptor(tmp, "bbw", _config, host_endian); buf = malloc(_config->wTotalLength); if (!buf) { r = LIBUSB_ERROR_NO_MEM; goto err; } host_endian = 0; r = usb_backend->get_config_descriptor(dev, config_index, buf, _config->wTotalLength, &host_endian); if (r < 0) goto err; r = parse_configuration(dev->ctx, _config, buf, host_endian); if (r < 0) { usb_err(dev->ctx, "parse_configuration failed with error %d", r); goto err; } else if (r > 0) { usb_warn(dev->ctx, "descriptor data still left"); } free(buf); *config = _config; return 0; err: free(_config); if (buf) free(buf); return r; }
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices) { struct usb_device *fdev = NULL; DIR *dir; struct dirent *entry; char dirpath[PATH_MAX + 1]; snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname); dir = opendir(dirpath); if (!dir) USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath, strerror(errno)); while ((entry = readdir(dir)) != NULL) { unsigned char device_desc[DEVICE_DESC_LENGTH]; char filename[PATH_MAX + 1]; struct usb_device *dev; struct usb_connectinfo connectinfo; int i, fd, ret; /* Skip anything starting with a . */ if (entry->d_name[0] == '.') continue; dev = malloc(sizeof(*dev)); if (!dev) USB_ERROR(-ENOMEM); memset((void *)dev, 0, sizeof(*dev)); dev->bus = bus; strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1); dev->filename[sizeof(dev->filename) - 1] = 0; snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name); fd = open(filename, O_RDWR); if (fd < 0) { fd = open(filename, O_RDONLY); if (fd < 0) { if (usb_debug >= 2) fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n", filename); free(dev); continue; } } /* Get the device number */ ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo); if (ret < 0) { if (usb_debug) fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n"); } else dev->devnum = connectinfo.devnum; ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH); if (ret < 0) { if (usb_debug) fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n"); free(dev); goto err; } /* * Linux kernel converts the words in this descriptor to CPU endian, so * we use the undocumented W character for usb_parse_descriptor() that * doesn't convert endianess when parsing the descriptor */ usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb", &dev->descriptor); LIST_ADD(fdev, dev); if (usb_debug >= 2) fprintf(stderr, "usb_os_find_devices: Found %s on %s\n", dev->filename, bus->dirname); /* Now try to fetch the rest of the descriptors */ if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) /* Silent since we'll try again later */ goto err; if (dev->descriptor.bNumConfigurations < 1) /* Silent since we'll try again later */ goto err; dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); if (!dev->config) /* Silent since we'll try again later */ goto err; memset(dev->config, 0, dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { unsigned char buffer[8], *bigbuffer; struct usb_config_descriptor config; /* Get the first 8 bytes so we can figure out what the total length is */ ret = read(fd, (void *)buffer, 8); if (ret < 8) { if (usb_debug >= 1) { if (ret < 0) fprintf(stderr, "Unable to get descriptor (%d)\n", ret); else fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret); } goto err; } usb_parse_descriptor(buffer, "bbw", &config); bigbuffer = malloc(config.wTotalLength); if (!bigbuffer) { if (usb_debug >= 1) fprintf(stderr, "Unable to allocate memory for descriptors\n"); goto err; } /* Read the rest of the config descriptor */ memcpy(bigbuffer, buffer, 8); ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8); if (ret < config.wTotalLength - 8) { if (usb_debug >= 1) { if (ret < 0) fprintf(stderr, "Unable to get descriptor (%d)\n", ret); else fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret); } free(bigbuffer); goto err; } ret = usb_parse_configuration(&dev->config[i], bigbuffer); if (usb_debug >= 2) { if (ret > 0) fprintf(stderr, "Descriptor data still left\n"); else if (ret < 0) fprintf(stderr, "Unable to parse descriptors\n"); } free(bigbuffer); } err: close(fd); } closedir(dir); *devices = fdev; return 0; }
static int parse_endpoint(struct libusb_context *ctx, struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, int size, int host_endian) { struct usb_descriptor_header header; unsigned char *extra; unsigned char *begin; int parsed = 0; int len; usb_parse_descriptor(buffer, "bb", &header, 0); /* Everything should be fine being passed into here, but we sanity */ /* check JIC */ if (header.bLength > size) { usb_err(ctx, "ran out of descriptors parsing"); return -1; } if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) { usb_err(ctx, "unexpected descriptor %x (expected %x)", header.bDescriptorType, LIBUSB_DT_ENDPOINT); return parsed; } if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) usb_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian); else if (header.bLength >= ENDPOINT_DESC_LENGTH) usb_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian); buffer += header.bLength; size -= header.bLength; parsed += header.bLength; /* Skip over the rest of the Class Specific or Vendor Specific */ /* descriptors */ begin = buffer; while (size >= DESC_HEADER_LENGTH) { usb_parse_descriptor(buffer, "bb", &header, 0); if (header.bLength < 2) { usb_err(ctx, "invalid descriptor length %d", header.bLength); return -1; } /* If we find another "proper" descriptor then we're done */ if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || (header.bDescriptorType == LIBUSB_DT_INTERFACE) || (header.bDescriptorType == LIBUSB_DT_CONFIG) || (header.bDescriptorType == LIBUSB_DT_DEVICE)) break; usb_dbg("skipping descriptor %x", header.bDescriptorType); buffer += header.bLength; size -= header.bLength; parsed += header.bLength; } /* Copy any unknown descriptors into a storage area for drivers */ /* to later parse */ len = (int)(buffer - begin); if (!len) { endpoint->extra = NULL; endpoint->extra_length = 0; return parsed; } extra = malloc(len); endpoint->extra = extra; if (!extra) { endpoint->extra_length = 0; return LIBUSB_ERROR_NO_MEM; } memcpy(extra, begin, len); endpoint->extra_length = len; return parsed; }
static int parse_interface(libusb_context *ctx, struct libusb_interface *usb_interface, unsigned char *buffer, int size, int host_endian) { int i; int len; int r; int parsed = 0; size_t tmp; struct usb_descriptor_header header; struct libusb_interface_descriptor *ifp; unsigned char *begin; usb_interface->num_altsetting = 0; while (size >= INTERFACE_DESC_LENGTH) { struct libusb_interface_descriptor *altsetting = (struct libusb_interface_descriptor *) usb_interface->altsetting; altsetting = realloc(altsetting, sizeof(struct libusb_interface_descriptor) * (usb_interface->num_altsetting + 1)); if (!altsetting) { r = LIBUSB_ERROR_NO_MEM; goto err; } usb_interface->altsetting = altsetting; ifp = altsetting + usb_interface->num_altsetting; usb_interface->num_altsetting++; usb_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0); ifp->extra = NULL; ifp->extra_length = 0; ifp->endpoint = NULL; /* Skip over the interface */ buffer += ifp->bLength; parsed += ifp->bLength; size -= ifp->bLength; begin = buffer; /* Skip over any interface, class or vendor descriptors */ while (size >= DESC_HEADER_LENGTH) { usb_parse_descriptor(buffer, "bb", &header, 0); if (header.bLength < 2) { usb_err(ctx, "invalid descriptor of length %d", header.bLength); r = LIBUSB_ERROR_IO; goto err; } /* If we find another "proper" descriptor then we're done */ if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) || (header.bDescriptorType == LIBUSB_DT_ENDPOINT) || (header.bDescriptorType == LIBUSB_DT_CONFIG) || (header.bDescriptorType == LIBUSB_DT_DEVICE)) break; buffer += header.bLength; parsed += header.bLength; size -= header.bLength; } /* Copy any unknown descriptors into a storage area for */ /* drivers to later parse */ len = (int)(buffer - begin); if (len) { ifp->extra = malloc(len); if (!ifp->extra) { r = LIBUSB_ERROR_NO_MEM; goto err; } memcpy((unsigned char *) ifp->extra, begin, len); ifp->extra_length = len; } /* Did we hit an unexpected descriptor? */ if (size >= DESC_HEADER_LENGTH) { usb_parse_descriptor(buffer, "bb", &header, 0); if ((header.bDescriptorType == LIBUSB_DT_CONFIG) || (header.bDescriptorType == LIBUSB_DT_DEVICE)) { return parsed; } } if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { usb_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints); r = LIBUSB_ERROR_IO; goto err; } if (ifp->bNumEndpoints > 0) { struct libusb_endpoint_descriptor *endpoint; tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor); endpoint = malloc(tmp); ifp->endpoint = endpoint; if (!endpoint) { r = LIBUSB_ERROR_NO_MEM; goto err; } memset(endpoint, 0, tmp); for (i = 0; i < ifp->bNumEndpoints; i++) { usb_parse_descriptor(buffer, "bb", &header, 0); if (header.bLength > size) { usb_err(ctx, "ran out of descriptors parsing"); r = LIBUSB_ERROR_IO; goto err; } r = parse_endpoint(ctx, endpoint + i, buffer, size, host_endian); if (r < 0) goto err; buffer += r; parsed += r; size -= r; } } /* We check to see if it's an alternate to this one */ ifp = (struct libusb_interface_descriptor *) buffer; if (size < LIBUSB_DT_INTERFACE_SIZE || ifp->bDescriptorType != LIBUSB_DT_INTERFACE || !ifp->bAlternateSetting) return parsed; } return parsed; err: clear_interface(usb_interface); return r; }
static int parse_configuration(struct libusb_context *ctx, struct libusb_config_descriptor *config, unsigned char *buffer, int host_endian) { int i; int r; int size; size_t tmp; struct usb_descriptor_header header; struct libusb_interface *usb_interface; usb_parse_descriptor(buffer, "bbwbbbbb", config, host_endian); size = config->wTotalLength; if (config->bNumInterfaces > USB_MAXINTERFACES) { usb_err(ctx, "too many interfaces (%d)", config->bNumInterfaces); return LIBUSB_ERROR_IO; } tmp = config->bNumInterfaces * sizeof(struct libusb_interface); usb_interface = malloc(tmp); config->interface = usb_interface; if (!config->interface) return LIBUSB_ERROR_NO_MEM; memset(usb_interface, 0, tmp); buffer += config->bLength; size -= config->bLength; config->extra = NULL; config->extra_length = 0; for (i = 0; i < config->bNumInterfaces; i++) { int len; unsigned char *begin; /* Skip over the rest of the Class Specific or Vendor */ /* Specific descriptors */ begin = buffer; while (size >= DESC_HEADER_LENGTH) { usb_parse_descriptor(buffer, "bb", &header, 0); if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) { usb_err(ctx, "invalid descriptor length of %d", header.bLength); r = LIBUSB_ERROR_IO; goto err; } /* If we find another "proper" descriptor then we're done */ if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || (header.bDescriptorType == LIBUSB_DT_INTERFACE) || (header.bDescriptorType == LIBUSB_DT_CONFIG) || (header.bDescriptorType == LIBUSB_DT_DEVICE)) break; usb_dbg("skipping descriptor 0x%x\n", header.bDescriptorType); buffer += header.bLength; size -= header.bLength; } /* Copy any unknown descriptors into a storage area for */ /* drivers to later parse */ len = (int)(buffer - begin); if (len) { /* FIXME: We should realloc and append here */ if (!config->extra_length) { config->extra = malloc(len); if (!config->extra) { r = LIBUSB_ERROR_NO_MEM; goto err; } memcpy((unsigned char *) config->extra, begin, len); config->extra_length = len; } } r = parse_interface(ctx, usb_interface + i, buffer, size, host_endian); if (r < 0) goto err; buffer += r; size -= r; } return size; err: clear_configuration(config); return r; }
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices) { struct usb_device *fdev = NULL; int cfd, dfd; int device; cfd = open(bus->dirname, O_RDONLY); if (cfd < 0) USB_ERROR_STR(-errno, "couldn't open(%s): %s", bus->dirname, strerror(errno)); for (device = 1; device < USB_MAX_DEVICES; device++) { struct usb_device_info di; struct usb_device *dev; unsigned char device_desc[DEVICE_DESC_LENGTH]; char buf[20]; di.udi_addr = device; if (ioctl(cfd, USB_DEVICEINFO, &di) < 0) continue; /* There's a device; is it one we should mess with? */ if (strncmp(di.udi_devnames[0], "ugen", 4) != 0) /* best not to play with things we don't understand */ continue; #ifdef __FreeBSD_kernel__ snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]); #else snprintf(buf, sizeof(buf) - 1, "/dev/%s.00", di.udi_devnames[0]); #endif /* Open its control endpoint */ dfd = open(buf, O_RDONLY); if (dfd < 0) { if (usb_debug >= 2) fprintf(stderr, "usb_os_find_devices: couldn't open device %s: %s\n", buf, strerror(errno)); continue; } dev = malloc(sizeof(*dev)); if (!dev) USB_ERROR(-ENOMEM); memset((void *)dev, 0, sizeof(*dev)); dev->bus = bus; /* we need to report the device name as /dev/ugenx NOT /dev/ugenx.00 * This seemed easier than having 2 variables... */ #if (__NetBSD__ || __OpenBSD__) snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]); #endif strncpy(dev->filename, buf, sizeof(dev->filename) - 1); dev->filename[sizeof(dev->filename) - 1] = 0; if (ioctl(dfd, USB_GET_DEVICE_DESC, device_desc) < 0) USB_ERROR_STR(-errno, "couldn't get device descriptor for %s: %s", buf, strerror(errno)); close(dfd); usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor); LIST_ADD(fdev, dev); if (usb_debug >= 2) fprintf(stderr, "usb_os_find_devices: Found %s on %s\n", dev->filename, bus->dirname); } close(cfd); *devices = fdev; return 0; }
static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) { struct usb_descriptor_header header; unsigned char *begin; int parsed = 0, len, numskipped; usb_parse_descriptor(buffer, "bb", &header); /* Everything should be fine being passed into here, but we sanity */ /* check JIC */ if (header.bLength > size) { if (usb_debug >= 1) fprintf(stderr, "ran out of descriptors parsing\n"); return -1; } if (header.bDescriptorType != USB_DT_ENDPOINT) { if (usb_debug >= 2) fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n", header.bDescriptorType, USB_DT_ENDPOINT); return parsed; } if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) usb_parse_descriptor(buffer, "bbbbwbbb", endpoint); else if (header.bLength >= ENDPOINT_DESC_LENGTH) usb_parse_descriptor(buffer, "bbbbwb", endpoint); buffer += header.bLength; size -= header.bLength; parsed += header.bLength; /* Skip over the rest of the Class Specific or Vendor Specific */ /* descriptors */ begin = buffer; numskipped = 0; while (size >= DESC_HEADER_LENGTH) { usb_parse_descriptor(buffer, "bb", &header); if (header.bLength < 2) { if (usb_debug >= 1) fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); return -1; } /* If we find another "proper" descriptor then we're done */ if ((header.bDescriptorType == USB_DT_ENDPOINT) || (header.bDescriptorType == USB_DT_INTERFACE) || (header.bDescriptorType == USB_DT_CONFIG) || (header.bDescriptorType == USB_DT_DEVICE)) break; if (usb_debug >= 1) fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); numskipped++; buffer += header.bLength; size -= header.bLength; parsed += header.bLength; } if (numskipped && usb_debug >= 2) fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); /* Copy any unknown descriptors into a storage area for drivers */ /* to later parse */ len = (int)(buffer - begin); if (!len) { endpoint->extra = NULL; endpoint->extralen = 0; return parsed; } endpoint->extra = malloc(len); if (!endpoint->extra) { if (usb_debug >= 1) fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n"); endpoint->extralen = 0; return parsed; } memcpy(endpoint->extra, begin, len); endpoint->extralen = len; return parsed; }
void usb_fetch_and_parse_descriptors(usb_dev_handle *udev) { struct usb_device *dev = udev->device; int i; if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { if (usb_debug >= 1) fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG); return; } if (dev->descriptor.bNumConfigurations < 1) { if (usb_debug >= 1) fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1); return; } dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); if (!dev->config) { if (usb_debug >= 1) fprintf(stderr, "Unable to allocate memory for config descriptor\n"); return; } memset(dev->config, 0, dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { unsigned char buffer[8], *bigbuffer; struct usb_config_descriptor config; int res; /* Get the first 8 bytes so we can figure out what the total length is */ res = usb_get_descriptor(udev, USB_DT_CONFIG, (unsigned char)i, buffer, 8); if (res < 8) { if (usb_debug >= 1) { if (res < 0) fprintf(stderr, "Unable to get descriptor (%d)\n", res); else fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res); } goto err; } usb_parse_descriptor(buffer, "bbw", &config); bigbuffer = malloc(config.wTotalLength); if (!bigbuffer) { if (usb_debug >= 1) fprintf(stderr, "Unable to allocate memory for descriptors\n"); goto err; } res = usb_get_descriptor(udev, USB_DT_CONFIG, (unsigned char)i, bigbuffer, config.wTotalLength); if (res < config.wTotalLength) { if (usb_debug >= 1) { if (res < 0) fprintf(stderr, "Unable to get descriptor (%d)\n", res); else fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res); } free(bigbuffer); goto err; } res = usb_parse_configuration(&dev->config[i], bigbuffer); if (usb_debug >= 2) { if (res > 0) fprintf(stderr, "Descriptor data still left\n"); else if (res < 0) fprintf(stderr, "Unable to parse descriptors\n"); } free(bigbuffer); } return; err: free(dev->config); dev->config = NULL; }
int usb_parse_configuration(struct usb_config_descriptor *config, unsigned char *buffer) { int i, retval, size; struct usb_descriptor_header header; usb_parse_descriptor(buffer, "bbwbbbbb", config); size = config->wTotalLength; if (config->bNumInterfaces > USB_MAXINTERFACES) { if (usb_debug >= 1) fprintf(stderr, "too many interfaces\n"); return -1; } config->interface = (struct usb_interface *) malloc(config->bNumInterfaces * sizeof(struct usb_interface)); if (!config->interface) { if (usb_debug >= 1) fprintf(stderr, "out of memory\n"); return -1; } memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface)); buffer += config->bLength; size -= config->bLength; config->extra = NULL; config->extralen = 0; for (i = 0; i < config->bNumInterfaces; i++) { int numskipped, len; unsigned char *begin; /* Skip over the rest of the Class Specific or Vendor */ /* Specific descriptors */ begin = buffer; numskipped = 0; while (size >= DESC_HEADER_LENGTH) { usb_parse_descriptor(buffer, "bb", &header); if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) { if (usb_debug >= 1) fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); return -1; } /* If we find another "proper" descriptor then we're done */ if ((header.bDescriptorType == USB_DT_ENDPOINT) || (header.bDescriptorType == USB_DT_INTERFACE) || (header.bDescriptorType == USB_DT_CONFIG) || (header.bDescriptorType == USB_DT_DEVICE)) break; if (usb_debug >= 2) fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); numskipped++; buffer += header.bLength; size -= header.bLength; } if (numskipped && usb_debug >= 2) fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); /* Copy any unknown descriptors into a storage area for */ /* drivers to later parse */ len = (int)(buffer - begin); if (len) { /* FIXME: We should realloc and append here */ if (!config->extralen) { config->extra = malloc(len); if (!config->extra) { if (usb_debug >= 1) fprintf(stderr, "couldn't allocate memory for config extra descriptors\n"); config->extralen = 0; return -1; } memcpy(config->extra, begin, len); config->extralen = len; } } retval = usb_parse_interface(config->interface + i, buffer, size); if (retval < 0) return retval; buffer += retval; size -= retval; } return size; }
static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size) { int i, len, numskipped, retval, parsed = 0; struct usb_descriptor_header header; struct usb_interface_descriptor *ifp; unsigned char *begin; interface->num_altsetting = 0; while (size >= INTERFACE_DESC_LENGTH) { interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1)); if (!interface->altsetting) { if (usb_debug >= 1) fprintf(stderr, "couldn't malloc interface->altsetting\n"); return -1; } ifp = interface->altsetting + interface->num_altsetting; interface->num_altsetting++; usb_parse_descriptor(buffer, "bbbbbbbbb", ifp); /* Skip over the interface */ buffer += ifp->bLength; parsed += ifp->bLength; size -= ifp->bLength; begin = buffer; numskipped = 0; /* Skip over any interface, class or vendor descriptors */ while (size >= DESC_HEADER_LENGTH) { usb_parse_descriptor(buffer, "bb", &header); if (header.bLength < 2) { if (usb_debug >= 1) fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); return -1; } /* If we find another "proper" descriptor then we're done */ if ((header.bDescriptorType == USB_DT_INTERFACE) || (header.bDescriptorType == USB_DT_ENDPOINT) || (header.bDescriptorType == USB_DT_CONFIG) || (header.bDescriptorType == USB_DT_DEVICE)) break; numskipped++; buffer += header.bLength; parsed += header.bLength; size -= header.bLength; } if (numskipped && usb_debug >= 2) fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped); /* Copy any unknown descriptors into a storage area for */ /* drivers to later parse */ len = (int)(buffer - begin); if (!len) { ifp->extra = NULL; ifp->extralen = 0; } else { ifp->extra = malloc(len); if (!ifp->extra) { if (usb_debug >= 1) fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n"); ifp->extralen = 0; return -1; } memcpy(ifp->extra, begin, len); ifp->extralen = len; } /* Did we hit an unexpected descriptor? */ usb_parse_descriptor(buffer, "bb", &header); if ((size >= DESC_HEADER_LENGTH) && ((header.bDescriptorType == USB_DT_CONFIG) || (header.bDescriptorType == USB_DT_DEVICE))) return parsed; if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { if (usb_debug >= 1) fprintf(stderr, "too many endpoints\n"); return -1; } if (ifp->bNumEndpoints > 0) { ifp->endpoint = (struct usb_endpoint_descriptor *) malloc(ifp->bNumEndpoints * sizeof(struct usb_endpoint_descriptor)); if (!ifp->endpoint) { if (usb_debug >= 1) fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n"); return -1; } memset(ifp->endpoint, 0, ifp->bNumEndpoints * sizeof(struct usb_endpoint_descriptor)); for (i = 0; i < ifp->bNumEndpoints; i++) { usb_parse_descriptor(buffer, "bb", &header); if (header.bLength > size) { if (usb_debug >= 1) fprintf(stderr, "ran out of descriptors parsing\n"); return -1; } retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); if (retval < 0) return retval; buffer += retval; parsed += retval; size -= retval; } } else ifp->endpoint = NULL; /* We check to see if it's an alternate to this one */ ifp = (struct usb_interface_descriptor *)buffer; if (size < USB_DT_INTERFACE_SIZE || ifp->bDescriptorType != USB_DT_INTERFACE || !ifp->bAlternateSetting) return parsed; } return parsed; }