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