libusb10_desc.c revision 199055
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10_desc.c 199055 2009-11-08 20:03:52Z thompsa $ */
2194676Sthompsa/*-
3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
4194676Sthompsa *
5194676Sthompsa * Redistribution and use in source and binary forms, with or without
6194676Sthompsa * modification, are permitted provided that the following conditions
7194676Sthompsa * are met:
8194676Sthompsa * 1. Redistributions of source code must retain the above copyright
9194676Sthompsa *    notice, this list of conditions and the following disclaimer.
10194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright
11194676Sthompsa *    notice, this list of conditions and the following disclaimer in the
12194676Sthompsa *    documentation and/or other materials provided with the distribution.
13194676Sthompsa *
14194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17194676Sthompsa * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24194676Sthompsa * SUCH DAMAGE.
25194676Sthompsa */
26194676Sthompsa
27194676Sthompsa#include <stdlib.h>
28194676Sthompsa#include <stdio.h>
29194676Sthompsa#include <pthread.h>
30195957Salfred#include <sys/queue.h>
31194676Sthompsa
32194676Sthompsa#include "libusb20.h"
33194676Sthompsa#include "libusb20_desc.h"
34194676Sthompsa#include "libusb20_int.h"
35194676Sthompsa#include "libusb.h"
36194676Sthompsa#include "libusb10.h"
37194676Sthompsa
38199055Sthompsa#define	N_ALIGN(n) (-((-(n)) & (-8UL)))
39199055Sthompsa
40194676Sthompsa/* USB descriptors */
41194676Sthompsa
42194676Sthompsaint
43195957Salfredlibusb_get_device_descriptor(libusb_device *dev,
44194676Sthompsa    struct libusb_device_descriptor *desc)
45194676Sthompsa{
46194676Sthompsa	struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
47194676Sthompsa	struct libusb20_device *pdev;
48194676Sthompsa
49194676Sthompsa	if ((dev == NULL) || (desc == NULL))
50194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
51194676Sthompsa
52194676Sthompsa	pdev = dev->os_priv;
53194676Sthompsa	pdesc = libusb20_dev_get_device_desc(pdev);
54194676Sthompsa
55194676Sthompsa	desc->bLength = pdesc->bLength;
56194676Sthompsa	desc->bDescriptorType = pdesc->bDescriptorType;
57194676Sthompsa	desc->bcdUSB = pdesc->bcdUSB;
58194676Sthompsa	desc->bDeviceClass = pdesc->bDeviceClass;
59194676Sthompsa	desc->bDeviceSubClass = pdesc->bDeviceSubClass;
60194676Sthompsa	desc->bDeviceProtocol = pdesc->bDeviceProtocol;
61194676Sthompsa	desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0;
62194676Sthompsa	desc->idVendor = pdesc->idVendor;
63194676Sthompsa	desc->idProduct = pdesc->idProduct;
64194676Sthompsa	desc->bcdDevice = pdesc->bcdDevice;
65194676Sthompsa	desc->iManufacturer = pdesc->iManufacturer;
66194676Sthompsa	desc->iProduct = pdesc->iProduct;
67194676Sthompsa	desc->iSerialNumber = pdesc->iSerialNumber;
68194676Sthompsa	desc->bNumConfigurations = pdesc->bNumConfigurations;
69194676Sthompsa
70194676Sthompsa	return (0);
71194676Sthompsa}
72194676Sthompsa
73194676Sthompsaint
74195957Salfredlibusb_get_active_config_descriptor(libusb_device *dev,
75194676Sthompsa    struct libusb_config_descriptor **config)
76194676Sthompsa{
77194676Sthompsa	struct libusb20_device *pdev;
78195957Salfred	uint8_t config_index;
79194676Sthompsa
80194676Sthompsa	pdev = dev->os_priv;
81195957Salfred	config_index = libusb20_dev_get_config_index(pdev);
82194676Sthompsa
83195957Salfred	return (libusb_get_config_descriptor(dev, config_index, config));
84194676Sthompsa}
85194676Sthompsa
86194676Sthompsaint
87195957Salfredlibusb_get_config_descriptor(libusb_device *dev, uint8_t config_index,
88194676Sthompsa    struct libusb_config_descriptor **config)
89194676Sthompsa{
90194676Sthompsa	struct libusb20_device *pdev;
91194676Sthompsa	struct libusb20_config *pconf;
92194676Sthompsa	struct libusb20_interface *pinf;
93194676Sthompsa	struct libusb20_endpoint *pend;
94195957Salfred	struct libusb_config_descriptor *pconfd;
95195957Salfred	struct libusb_interface_descriptor *ifd;
96195957Salfred	struct libusb_endpoint_descriptor *endd;
97195957Salfred	uint8_t *pextra;
98195957Salfred	uint16_t nextra;
99195957Salfred	uint8_t nif;
100195957Salfred	uint8_t nep;
101195957Salfred	uint8_t nalt;
102195957Salfred	uint8_t i;
103195957Salfred	uint8_t j;
104195957Salfred	uint8_t k;
105194676Sthompsa
106194676Sthompsa	if (dev == NULL || config == NULL)
107194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
108194676Sthompsa
109195957Salfred	*config = NULL;
110195957Salfred
111194676Sthompsa	pdev = dev->os_priv;
112194676Sthompsa	pconf = libusb20_dev_alloc_config(pdev, config_index);
113194676Sthompsa
114194676Sthompsa	if (pconf == NULL)
115194676Sthompsa		return (LIBUSB_ERROR_NOT_FOUND);
116194676Sthompsa
117194676Sthompsa	nalt = nif = pconf->num_interface;
118195957Salfred	nep = 0;
119199055Sthompsa	nextra = N_ALIGN(pconf->extra.len);
120195957Salfred
121195957Salfred	for (i = 0; i < nif; i++) {
122195957Salfred
123195957Salfred		pinf = pconf->interface + i;
124199055Sthompsa		nextra += N_ALIGN(pinf->extra.len);
125195957Salfred		nep += pinf->num_endpoints;
126195957Salfred		k = pinf->num_endpoints;
127195957Salfred		pend = pinf->endpoints;
128195957Salfred		while (k--) {
129199055Sthompsa			nextra += N_ALIGN(pend->extra.len);
130195957Salfred			pend++;
131195957Salfred		}
132195957Salfred
133195957Salfred		j = pinf->num_altsetting;
134195957Salfred		nalt += pinf->num_altsetting;
135195957Salfred		pinf = pinf->altsetting;
136195957Salfred		while (j--) {
137199055Sthompsa			nextra += N_ALIGN(pinf->extra.len);
138195957Salfred			nep += pinf->num_endpoints;
139195957Salfred			k = pinf->num_endpoints;
140195957Salfred			pend = pinf->endpoints;
141195957Salfred			while (k--) {
142199055Sthompsa				nextra += N_ALIGN(pend->extra.len);
143195957Salfred				pend++;
144194676Sthompsa			}
145195957Salfred			pinf++;
146194676Sthompsa		}
147194676Sthompsa	}
148194676Sthompsa
149195957Salfred	nextra = nextra +
150195957Salfred	    (1 * sizeof(libusb_config_descriptor)) +
151194676Sthompsa	    (nif * sizeof(libusb_interface)) +
152194676Sthompsa	    (nalt * sizeof(libusb_interface_descriptor)) +
153195957Salfred	    (nep * sizeof(libusb_endpoint_descriptor));
154195957Salfred
155199055Sthompsa	nextra = N_ALIGN(nextra);
156199055Sthompsa
157195957Salfred	pconfd = malloc(nextra);
158195957Salfred
159195957Salfred	if (pconfd == NULL) {
160194676Sthompsa		free(pconf);
161194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
162194676Sthompsa	}
163199055Sthompsa	/* make sure memory is initialised */
164195957Salfred	memset(pconfd, 0, nextra);
165194676Sthompsa
166199055Sthompsa	pconfd->interface = (libusb_interface *) (pconfd + 1);
167194676Sthompsa
168195957Salfred	ifd = (libusb_interface_descriptor *) (pconfd->interface + nif);
169195957Salfred	endd = (libusb_endpoint_descriptor *) (ifd + nalt);
170195957Salfred	pextra = (uint8_t *)(endd + nep);
171195957Salfred
172195957Salfred	/* fill in config descriptor */
173195957Salfred
174195957Salfred	pconfd->bLength = pconf->desc.bLength;
175195957Salfred	pconfd->bDescriptorType = pconf->desc.bDescriptorType;
176195957Salfred	pconfd->wTotalLength = pconf->desc.wTotalLength;
177195957Salfred	pconfd->bNumInterfaces = pconf->desc.bNumInterfaces;
178195957Salfred	pconfd->bConfigurationValue = pconf->desc.bConfigurationValue;
179195957Salfred	pconfd->iConfiguration = pconf->desc.iConfiguration;
180195957Salfred	pconfd->bmAttributes = pconf->desc.bmAttributes;
181195957Salfred	pconfd->MaxPower = pconf->desc.bMaxPower;
182195957Salfred
183195957Salfred	if (pconf->extra.len != 0) {
184195957Salfred		pconfd->extra_length = pconf->extra.len;
185195957Salfred		pconfd->extra = pextra;
186195957Salfred		memcpy(pextra, pconf->extra.ptr, pconfd->extra_length);
187199055Sthompsa		pextra += N_ALIGN(pconfd->extra_length);
188195957Salfred	}
189195957Salfred	/* setup all interface and endpoint pointers */
190195957Salfred
191195957Salfred	for (i = 0; i < nif; i++) {
192195957Salfred
193195957Salfred		pconfd->interface[i].altsetting = ifd;
194195957Salfred		ifd->endpoint = endd;
195195957Salfred		endd += pconf->interface[i].num_endpoints;
196195957Salfred		ifd++;
197195957Salfred
198195957Salfred		for (j = 0; j < pconf->interface[i].num_altsetting; j++) {
199195957Salfred			ifd->endpoint = endd;
200195957Salfred			endd += pconf->interface[i].altsetting[j].num_endpoints;
201195957Salfred			ifd++;
202194676Sthompsa		}
203194676Sthompsa	}
204194676Sthompsa
205195957Salfred	/* fill in all interface and endpoint data */
206194676Sthompsa
207195957Salfred	for (i = 0; i < nif; i++) {
208194676Sthompsa		pinf = &pconf->interface[i];
209195957Salfred		pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1;
210195957Salfred		for (j = 0; j < pconfd->interface[i].num_altsetting; j++) {
211194676Sthompsa			if (j != 0)
212194676Sthompsa				pinf = &pconf->interface[i].altsetting[j - 1];
213195957Salfred			ifd = &pconfd->interface[i].altsetting[j];
214194676Sthompsa			ifd->bLength = pinf->desc.bLength;
215194676Sthompsa			ifd->bDescriptorType = pinf->desc.bDescriptorType;
216194676Sthompsa			ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber;
217194676Sthompsa			ifd->bAlternateSetting = pinf->desc.bAlternateSetting;
218194676Sthompsa			ifd->bNumEndpoints = pinf->desc.bNumEndpoints;
219194676Sthompsa			ifd->bInterfaceClass = pinf->desc.bInterfaceClass;
220194676Sthompsa			ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass;
221194676Sthompsa			ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol;
222194676Sthompsa			ifd->iInterface = pinf->desc.iInterface;
223195957Salfred			if (pinf->extra.len != 0) {
224195957Salfred				ifd->extra_length = pinf->extra.len;
225195957Salfred				ifd->extra = pextra;
226195957Salfred				memcpy(pextra, pinf->extra.ptr, pinf->extra.len);
227199055Sthompsa				pextra += N_ALIGN(pinf->extra.len);
228195957Salfred			}
229195957Salfred			for (k = 0; k < pinf->num_endpoints; k++) {
230194676Sthompsa				pend = &pinf->endpoints[k];
231194676Sthompsa				endd = &ifd->endpoint[k];
232194676Sthompsa				endd->bLength = pend->desc.bLength;
233194676Sthompsa				endd->bDescriptorType = pend->desc.bDescriptorType;
234194676Sthompsa				endd->bEndpointAddress = pend->desc.bEndpointAddress;
235194676Sthompsa				endd->bmAttributes = pend->desc.bmAttributes;
236194676Sthompsa				endd->wMaxPacketSize = pend->desc.wMaxPacketSize;
237194676Sthompsa				endd->bInterval = pend->desc.bInterval;
238194676Sthompsa				endd->bRefresh = pend->desc.bRefresh;
239194676Sthompsa				endd->bSynchAddress = pend->desc.bSynchAddress;
240195957Salfred				if (pend->extra.len != 0) {
241195957Salfred					endd->extra_length = pend->extra.len;
242195957Salfred					endd->extra = pextra;
243195957Salfred					memcpy(pextra, pend->extra.ptr, pend->extra.len);
244199055Sthompsa					pextra += N_ALIGN(pend->extra.len);
245195957Salfred				}
246194676Sthompsa			}
247195957Salfred		}
248194676Sthompsa	}
249194676Sthompsa
250194676Sthompsa	free(pconf);
251195957Salfred
252195957Salfred	*config = pconfd;
253195957Salfred
254195957Salfred	return (0);			/* success */
255194676Sthompsa}
256194676Sthompsa
257194676Sthompsaint
258195957Salfredlibusb_get_config_descriptor_by_value(libusb_device *dev,
259194676Sthompsa    uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
260194676Sthompsa{
261194676Sthompsa	struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
262194676Sthompsa	struct libusb20_device *pdev;
263194676Sthompsa	int i;
264195957Salfred	int err;
265194676Sthompsa
266194676Sthompsa	if (dev == NULL || config == NULL)
267194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
268195957Salfred
269194676Sthompsa	pdev = dev->os_priv;
270194676Sthompsa	pdesc = libusb20_dev_get_device_desc(pdev);
271194676Sthompsa
272195957Salfred	for (i = 0; i < pdesc->bNumConfigurations; i++) {
273195957Salfred		err = libusb_get_config_descriptor(dev, i, config);
274195957Salfred		if (err)
275195957Salfred			return (err);
276194676Sthompsa
277195957Salfred		if ((*config)->bConfigurationValue == bConfigurationValue)
278195957Salfred			return (0);	/* success */
279195957Salfred
280195957Salfred		libusb_free_config_descriptor(*config);
281194676Sthompsa	}
282194676Sthompsa
283195957Salfred	*config = NULL;
284195957Salfred
285194676Sthompsa	return (LIBUSB_ERROR_NOT_FOUND);
286194676Sthompsa}
287194676Sthompsa
288194676Sthompsavoid
289194676Sthompsalibusb_free_config_descriptor(struct libusb_config_descriptor *config)
290194676Sthompsa{
291194676Sthompsa	free(config);
292194676Sthompsa}
293194676Sthompsa
294194676Sthompsaint
295195957Salfredlibusb_get_string_descriptor_ascii(libusb_device_handle *pdev,
296194676Sthompsa    uint8_t desc_index, unsigned char *data, int length)
297194676Sthompsa{
298195957Salfred	if (pdev == NULL || data == NULL || length < 1)
299195957Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
300194676Sthompsa
301195957Salfred	/* put some default data into the destination buffer */
302195957Salfred	data[0] = 0;
303194676Sthompsa
304195957Salfred	if (libusb20_dev_req_string_simple_sync(pdev, desc_index,
305194676Sthompsa	    data, length) == 0)
306194676Sthompsa		return (strlen(data));
307194676Sthompsa
308194676Sthompsa	return (LIBUSB_ERROR_OTHER);
309194676Sthompsa}
310199055Sthompsa
311199055Sthompsaint
312199055Sthompsalibusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type,
313199055Sthompsa    uint8_t desc_index, uint8_t *data, int length)
314199055Sthompsa{
315199055Sthompsa	return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN,
316199055Sthompsa	    LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data,
317199055Sthompsa	    length, 1000));
318199055Sthompsa}
319