1bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/* 2bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * USB descriptor handling functions for libusb 3bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> 4bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> 5bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 6bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This library is free software; you can redistribute it and/or 7bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * modify it under the terms of the GNU Lesser General Public 8bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * License as published by the Free Software Foundation; either 9bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * version 2.1 of the License, or (at your option) any later version. 10bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 11bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This library is distributed in the hope that it will be useful, 12bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * but WITHOUT ANY WARRANTY; without even the implied warranty of 13bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Lesser General Public License for more details. 15bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 16bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * You should have received a copy of the GNU Lesser General Public 17bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * License along with this library; if not, write to the Free Software 18bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 20bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 21bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <errno.h> 22bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <stdlib.h> 23bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <string.h> 24bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 25bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include "libusbi.h" 26bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 27bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define DESC_HEADER_LENGTH 2 28bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define DEVICE_DESC_LENGTH 18 29bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define CONFIG_DESC_LENGTH 9 30bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define INTERFACE_DESC_LENGTH 9 31bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define ENDPOINT_DESC_LENGTH 7 32bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#define ENDPOINT_AUDIO_DESC_LENGTH 9 33bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 34bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/** @defgroup desc USB descriptors 35bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This page details how to examine the various standard USB descriptors 36bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * for detected devices 37bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 38bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 39bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/* set host_endian if the w values are already in host endian format, 40bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * as opposed to bus endian. */ 41bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevint usbi_parse_descriptor(unsigned char *source, char *descriptor, void *dest, 42bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int host_endian) 43bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 44bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char *sp = source, *dp = dest; 45bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint16_t w; 46bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev char *cp; 47bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 48bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (cp = descriptor; *cp; cp++) { 49bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (*cp) { 50bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case 'b': /* 8-bit byte */ 51bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *dp++ = *sp++; 52bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 53bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case 'w': /* 16-bit word, convert from little endian to CPU */ 54bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dp += ((unsigned long)dp & 1); /* Align to word boundary */ 55bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 56bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (host_endian) { 57bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memcpy(dp, sp, 2); 58bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else { 59bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev w = (sp[1] << 8) | sp[0]; 60bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *((uint16_t *)dp) = w; 61bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 62bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sp += 2; 63bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dp += 2; 64bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 65bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 66bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 67bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 68bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return sp - source; 69bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 70bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 71bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) 72bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 73bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (endpoint->extra) 74bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free((unsigned char *) endpoint->extra); 75bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 76bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 77bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int parse_endpoint(struct libusb_context *ctx, 78bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, 79bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int size, int host_endian) 80bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 81bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct usb_descriptor_header header; 82bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char *extra; 83bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char *begin; 84bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int parsed = 0; 85bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int len; 86bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 87bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bb", &header, 0); 88bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 89bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Everything should be fine being passed into here, but we sanity */ 90bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* check JIC */ 91bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (header.bLength > size) { 92bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(ctx, "ran out of descriptors parsing"); 93bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 94bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 95bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 96bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) { 97bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(ctx, "unexpected descriptor %x (expected %x)", 98bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev header.bDescriptorType, LIBUSB_DT_ENDPOINT); 99bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return parsed; 100bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 101bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 102bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) 103bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian); 104bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev else if (header.bLength >= ENDPOINT_DESC_LENGTH) 105bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian); 106bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 107bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buffer += header.bLength; 108bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size -= header.bLength; 109bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev parsed += header.bLength; 110bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 111bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Skip over the rest of the Class Specific or Vendor Specific */ 112bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* descriptors */ 113bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev begin = buffer; 114bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (size >= DESC_HEADER_LENGTH) { 115bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bb", &header, 0); 116bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 117bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (header.bLength < 2) { 118bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(ctx, "invalid descriptor length %d", header.bLength); 119bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 120bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 121bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 122bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* If we find another "proper" descriptor then we're done */ 123bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || 124bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_INTERFACE) || 125bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_CONFIG) || 126bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_DEVICE)) 127bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 128bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 129bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_dbg("skipping descriptor %x", header.bDescriptorType); 130bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buffer += header.bLength; 131bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size -= header.bLength; 132bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev parsed += header.bLength; 133bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 134bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 135bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Copy any unknown descriptors into a storage area for drivers */ 136bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* to later parse */ 137bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev len = (int)(buffer - begin); 138bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!len) { 139bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev endpoint->extra = NULL; 140bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev endpoint->extra_length = 0; 141bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return parsed; 142bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 143bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 144bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev extra = malloc(len); 145bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev endpoint->extra = extra; 146bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!extra) { 147bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev endpoint->extra_length = 0; 148bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NO_MEM; 149bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 150bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 151bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memcpy(extra, begin, len); 152bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev endpoint->extra_length = len; 153bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 154bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return parsed; 155bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 156bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 157bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void clear_interface(struct libusb_interface *interface) 158bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 159bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 160bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int j; 161bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 162bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (interface->altsetting) { 163bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0; i < interface->num_altsetting; i++) { 164bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_interface_descriptor *ifp = 165bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (struct libusb_interface_descriptor *) 166bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev interface->altsetting + i; 167bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ifp->extra) 168bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free((void *) ifp->extra); 169bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ifp->endpoint) { 170bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (j = 0; j < ifp->bNumEndpoints; j++) 171bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev clear_endpoint((struct libusb_endpoint_descriptor *) 172bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp->endpoint + j); 173bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free((void *) ifp->endpoint); 174bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 175bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 176bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free((void *) interface->altsetting); 177bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev interface->altsetting = NULL; 178bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 179bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 180bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 181bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 182bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int parse_interface(libusb_context *ctx, 183bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_interface *interface, unsigned char *buffer, int size, 184bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int host_endian) 185bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 186bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 187bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int len; 188bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 189bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int parsed = 0; 190bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int tmp; 191bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct usb_descriptor_header header; 192bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_interface_descriptor *ifp; 193bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char *begin; 194bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 195bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev interface->num_altsetting = 0; 196bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 197bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (size >= INTERFACE_DESC_LENGTH) { 198bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_interface_descriptor *altsetting = 199bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (struct libusb_interface_descriptor *) interface->altsetting; 200bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev altsetting = realloc(altsetting, 201bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sizeof(struct libusb_interface_descriptor) * 202bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (interface->num_altsetting + 1)); 203bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!altsetting) { 204bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_NO_MEM; 205bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 206bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 207bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev interface->altsetting = altsetting; 208bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 209bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp = altsetting + interface->num_altsetting; 210bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev interface->num_altsetting++; 211bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0); 212bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp->extra = NULL; 213bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp->extra_length = 0; 214bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp->endpoint = NULL; 215bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 216bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Skip over the interface */ 217bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buffer += ifp->bLength; 218bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev parsed += ifp->bLength; 219bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size -= ifp->bLength; 220bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 221bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev begin = buffer; 222bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 223bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Skip over any interface, class or vendor descriptors */ 224bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (size >= DESC_HEADER_LENGTH) { 225bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bb", &header, 0); 226bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (header.bLength < 2) { 227bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(ctx, "invalid descriptor of length %d", 228bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev header.bLength); 229bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_IO; 230bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 231bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 232bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 233bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* If we find another "proper" descriptor then we're done */ 234bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) || 235bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_ENDPOINT) || 236bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_CONFIG) || 237bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_DEVICE)) 238bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 239bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 240bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buffer += header.bLength; 241bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev parsed += header.bLength; 242bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size -= header.bLength; 243bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 244bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 245bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Copy any unknown descriptors into a storage area for */ 246bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* drivers to later parse */ 247bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev len = (int)(buffer - begin); 248bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (len) { 249bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp->extra = malloc(len); 250bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!ifp->extra) { 251bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_NO_MEM; 252bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 253bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 254bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memcpy((unsigned char *) ifp->extra, begin, len); 255bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp->extra_length = len; 256bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 257bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 258bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Did we hit an unexpected descriptor? */ 259bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bb", &header, 0); 260bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((size >= DESC_HEADER_LENGTH) && 261bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ((header.bDescriptorType == LIBUSB_DT_CONFIG) || 262bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_DEVICE))) 263bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return parsed; 264bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 265bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { 266bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints); 267bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_IO; 268bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 269bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 270bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 271bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ifp->bNumEndpoints > 0) { 272bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_endpoint_descriptor *endpoint; 273bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor); 274bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev endpoint = malloc(tmp); 275bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp->endpoint = endpoint; 276bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!endpoint) { 277bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_NO_MEM; 278bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 279bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 280bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 281bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memset(endpoint, 0, tmp); 282bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0; i < ifp->bNumEndpoints; i++) { 283bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bb", &header, 0); 284bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 285bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (header.bLength > size) { 286bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(ctx, "ran out of descriptors parsing"); 287bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_IO; 288bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 289bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 290bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 291bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = parse_endpoint(ctx, endpoint + i, buffer, size, 292bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev host_endian); 293bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 294bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 295bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 296bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buffer += r; 297bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev parsed += r; 298bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size -= r; 299bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 300bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 301bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 302bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* We check to see if it's an alternate to this one */ 303bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp = (struct libusb_interface_descriptor *) buffer; 304bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (size < LIBUSB_DT_INTERFACE_SIZE || 305bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ifp->bDescriptorType != LIBUSB_DT_INTERFACE || 306bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev !ifp->bAlternateSetting) 307bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return parsed; 308bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 309bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 310bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return parsed; 311bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulisheverr: 312bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev clear_interface(interface); 313bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 314bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 315bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 316bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void clear_configuration(struct libusb_config_descriptor *config) 317bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 318bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (config->interface) { 319bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 320bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0; i < config->bNumInterfaces; i++) 321bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev clear_interface((struct libusb_interface *) 322bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev config->interface + i); 323bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free((void *) config->interface); 324bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 325bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (config->extra) 326bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free((void *) config->extra); 327bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 328bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 329bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int parse_configuration(struct libusb_context *ctx, 330bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_config_descriptor *config, unsigned char *buffer, 331bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int host_endian) 332bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 333bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 334bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 335bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int size; 336bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int tmp; 337bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct usb_descriptor_header header; 338bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_interface *interface; 339bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 340bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian); 341bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size = config->wTotalLength; 342bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 343bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (config->bNumInterfaces > USB_MAXINTERFACES) { 344bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces); 345bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_IO; 346bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 347bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 348bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tmp = config->bNumInterfaces * sizeof(struct libusb_interface); 349bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev interface = malloc(tmp); 350bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev config->interface = interface; 351bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!config->interface) 352bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NO_MEM; 353bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 354bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memset(interface, 0, tmp); 355bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buffer += config->bLength; 356bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size -= config->bLength; 357bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 358bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev config->extra = NULL; 359bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev config->extra_length = 0; 360bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 361bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0; i < config->bNumInterfaces; i++) { 362bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int len; 363bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char *begin; 364bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 365bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Skip over the rest of the Class Specific or Vendor */ 366bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Specific descriptors */ 367bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev begin = buffer; 368bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (size >= DESC_HEADER_LENGTH) { 369bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(buffer, "bb", &header, 0); 370bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 371bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((header.bLength > size) || 372bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bLength < DESC_HEADER_LENGTH)) { 373bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(ctx, "invalid descriptor length of %d", 374bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev header.bLength); 375bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_IO; 376bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 377bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 378bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 379bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* If we find another "proper" descriptor then we're done */ 380bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || 381bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_INTERFACE) || 382bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_CONFIG) || 383bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (header.bDescriptorType == LIBUSB_DT_DEVICE)) 384bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 385bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 386bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType); 387bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buffer += header.bLength; 388bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size -= header.bLength; 389bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 390bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 391bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Copy any unknown descriptors into a storage area for */ 392bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* drivers to later parse */ 393bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev len = (int)(buffer - begin); 394bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (len) { 395bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* FIXME: We should realloc and append here */ 396bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!config->extra_length) { 397bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev config->extra = malloc(len); 398bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!config->extra) { 399bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_NO_MEM; 400bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 401bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 402bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 403bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memcpy((unsigned char *) config->extra, begin, len); 404bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev config->extra_length = len; 405bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 406bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 407bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 408bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = parse_interface(ctx, interface + i, buffer, size, host_endian); 409bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 410bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 411bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 412bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buffer += r; 413bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev size -= r; 414bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 415bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 416bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return size; 417bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 418bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulisheverr: 419bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev clear_configuration(config); 420bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 421bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 422bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 423bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/** \ingroup desc 424bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Get the USB device descriptor for a given device. 425bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 426bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This is a non-blocking function; the device descriptor is cached in memory. 427bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 428bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param dev the device 429bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param desc output location for the descriptor data 430bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns 0 on success or a LIBUSB_ERROR code on failure 431bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 432bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor GoulishevAPI_EXPORTED int libusb_get_device_descriptor(libusb_device *dev, 433bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_device_descriptor *desc) 434bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 435bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char raw_desc[DEVICE_DESC_LENGTH]; 436bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int host_endian = 0; 437bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 438bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 439bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_dbg(""); 440bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = usbi_backend->get_device_descriptor(dev, raw_desc, &host_endian); 441bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 442bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 443bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 444bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memcpy((unsigned char *) desc, raw_desc, sizeof(raw_desc)); 445bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!host_endian) { 446bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev desc->bcdUSB = libusb_le16_to_cpu(desc->bcdUSB); 447bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev desc->idVendor = libusb_le16_to_cpu(desc->idVendor); 448bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev desc->idProduct = libusb_le16_to_cpu(desc->idProduct); 449bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev desc->bcdDevice = libusb_le16_to_cpu(desc->bcdDevice); 450bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 451bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 452bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 453bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 454bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/** \ingroup desc 455bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Get the USB configuration descriptor for the currently active configuration. 456bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This is a non-blocking function which does not involve any requests being 457bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * sent to the device. 458bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 459bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param dev a device 460bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param config output location for the USB configuration descriptor. Only 461bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() 462bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * after use. 463bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns 0 on success 464bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state 465bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns another LIBUSB_ERROR code on error 466bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \see libusb_get_config_descriptor 467bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 468bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor GoulishevAPI_EXPORTED int libusb_get_active_config_descriptor(libusb_device *dev, 469bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_config_descriptor **config) 470bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 471bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_config_descriptor *_config = malloc(sizeof(*_config)); 472bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char tmp[8]; 473bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char *buf = NULL; 474bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int host_endian = 0; 475bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 476bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 477bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_dbg(""); 478bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!_config) 479bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NO_MEM; 480bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 481bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = usbi_backend->get_active_config_descriptor(dev, tmp, sizeof(tmp), 482bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev &host_endian); 483bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 484bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 485bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 486bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(tmp, "bbw", _config, host_endian); 487bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buf = malloc(_config->wTotalLength); 488bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!buf) { 489bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_NO_MEM; 490bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 491bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 492bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 493bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = usbi_backend->get_active_config_descriptor(dev, buf, 494bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev _config->wTotalLength, &host_endian); 495bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 496bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 497bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 498bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = parse_configuration(dev->ctx, _config, buf, host_endian); 499bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 500bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(dev->ctx, "parse_configuration failed with error %d", r); 501bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 502bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else if (r > 0) { 503bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_warn(dev->ctx, "descriptor data still left"); 504bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 505bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 506bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(buf); 507bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *config = _config; 508bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 509bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 510bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulisheverr: 511bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(_config); 512bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (buf) 513bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(buf); 514bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 515bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 516bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 517bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/** \ingroup desc 518bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Get a USB configuration descriptor based on its index. 519bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This is a non-blocking function which does not involve any requests being 520bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * sent to the device. 521bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 522bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param dev a device 523bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param config_index the index of the configuration you wish to retrieve 524bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param config output location for the USB configuration descriptor. Only 525bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() 526bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * after use. 527bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns 0 on success 528bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist 529bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns another LIBUSB_ERROR code on error 530bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \see libusb_get_active_config_descriptor() 531bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \see libusb_get_config_descriptor_by_value() 532bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 533bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor GoulishevAPI_EXPORTED int libusb_get_config_descriptor(libusb_device *dev, 534bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t config_index, struct libusb_config_descriptor **config) 535bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 536bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_config_descriptor *_config; 537bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char tmp[8]; 538bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char *buf = NULL; 539bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int host_endian = 0; 540bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r; 541bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 542bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_dbg("index %d", config_index); 543bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (config_index >= dev->num_configurations) 544bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_FOUND; 545bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 546bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev _config = malloc(sizeof(*_config)); 547bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!_config) 548bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NO_MEM; 549bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 550bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = usbi_backend->get_config_descriptor(dev, config_index, tmp, 551bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sizeof(tmp), &host_endian); 552bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 553bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 554bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 555bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_parse_descriptor(tmp, "bbw", _config, host_endian); 556bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev buf = malloc(_config->wTotalLength); 557bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!buf) { 558bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = LIBUSB_ERROR_NO_MEM; 559bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 560bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 561bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 562bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev host_endian = 0; 563bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = usbi_backend->get_config_descriptor(dev, config_index, buf, 564bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev _config->wTotalLength, &host_endian); 565bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 566bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 567bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 568bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = parse_configuration(dev->ctx, _config, buf, host_endian); 569bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) { 570bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err(dev->ctx, "parse_configuration failed with error %d", r); 571bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev goto err; 572bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else if (r > 0) { 573bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_warn(dev->ctx, "descriptor data still left"); 574bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 575bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 576bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(buf); 577bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *config = _config; 578bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 579bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 580bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulisheverr: 581bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(_config); 582bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (buf) 583bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(buf); 584bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 585bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 586bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 587bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/* iterate through all configurations, returning the index of the configuration 588bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * matching a specific bConfigurationValue in the idx output parameter, or -1 589bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * if the config was not found. 590bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * returns 0 or a LIBUSB_ERROR code 591bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 592bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevint usbi_get_config_index_by_value(struct libusb_device *dev, 593bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t bConfigurationValue, int *idx) 594bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 595bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 596bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 597bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_dbg("value %d", bConfigurationValue); 598bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0; i < dev->num_configurations; i++) { 599bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char tmp[6]; 600bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int host_endian; 601bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp), 602bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev &host_endian); 603bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 604bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 605bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (tmp[5] == bConfigurationValue) { 606bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *idx = i; 607bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 608bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 609bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 610bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 611bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *idx = -1; 612bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 613bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 614bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 615bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/** \ingroup desc 616bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Get a USB configuration descriptor with a specific bConfigurationValue. 617bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This is a non-blocking function which does not involve any requests being 618bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * sent to the device. 619bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 620bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param dev a device 621bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param bConfigurationValue the bConfigurationValue of the configuration you 622bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * wish to retrieve 623bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param config output location for the USB configuration descriptor. Only 624bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() 625bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * after use. 626bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns 0 on success 627bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist 628bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns another LIBUSB_ERROR code on error 629bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \see libusb_get_active_config_descriptor() 630bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \see libusb_get_config_descriptor() 631bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 632bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor GoulishevAPI_EXPORTED int libusb_get_config_descriptor_by_value(libusb_device *dev, 633bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 634bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 635bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int idx; 636bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx); 637bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 638bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 639bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev else if (idx == -1) 640bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_FOUND; 641bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev else 642bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return libusb_get_config_descriptor(dev, idx, config); 643bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 644bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 645bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/** \ingroup desc 646bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Free a configuration descriptor obtained from 647bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). 648bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * It is safe to call this function with a NULL config parameter, in which 649bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * case the function simply returns. 650bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 651bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param config the configuration descriptor to free 652bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 653bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor GoulishevAPI_EXPORTED void libusb_free_config_descriptor( 654bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_config_descriptor *config) 655bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 656bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!config) 657bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return; 658bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 659bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev clear_configuration(config); 660bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(config); 661bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 662bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 663bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/** \ingroup desc 664bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Retrieve a string descriptor in C style ASCII. 665bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 666bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Wrapper around libusb_get_string_descriptor(). Uses the first language 667bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * supported by the device. 668bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 669bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param dev a device handle 670bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param desc_index the index of the descriptor to retrieve 671bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param data output buffer for ASCII string descriptor 672bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \param length size of data buffer 673bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure 674bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 675bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor GoulishevAPI_EXPORTED int libusb_get_string_descriptor_ascii(libusb_device_handle *dev, 676bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t desc_index, unsigned char *data, int length) 677bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev{ 678bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev unsigned char tbuf[255]; /* Some devices choke on size > 255 */ 679bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int r, langid, si, di; 680bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 681bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Asking for the zero'th index is special - it returns a string 682bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * descriptor that contains all the language IDs supported by the device. 683bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Typically there aren't many - often only one. The language IDs are 16 684bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * bit numbers, and they start at the third byte in the descriptor. See 685bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * USB 2.0 specification section 9.6.7 for more information. */ 686bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_get_string_descriptor(dev, 0, 0, tbuf, sizeof(tbuf)); 687bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 688bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 689bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 690bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 4) 691bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_IO; 692bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 693bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev langid = tbuf[2] | (tbuf[3] << 8); 694bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 695bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev r = libusb_get_string_descriptor(dev, desc_index, langid, tbuf, 696bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev sizeof(tbuf)); 697bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (r < 0) 698bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return r; 699bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 700bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (tbuf[1] != LIBUSB_DT_STRING) 701bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_IO; 702bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 703bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (tbuf[0] > r) 704bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_IO; 705bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 706bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (di = 0, si = 2; si < tbuf[0]; si += 2) { 707bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (di >= (length - 1)) 708bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 709bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 710bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (tbuf[si + 1]) /* high byte */ 711bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev data[di++] = '?'; 712bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev else 713bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev data[di++] = tbuf[si]; 714bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 715bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 716bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev data[di] = 0; 717bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return di; 718bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 719bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 720