xref: /freebsd/lib/libusb/libusb01.c (revision 2485d8a793b882e77fe7be4dc1a034390c96abbb)
1*2485d8a7SHans Petter Selasky /* $FreeBSD$ */
2*2485d8a7SHans Petter Selasky /*-
3*2485d8a7SHans Petter Selasky  * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4*2485d8a7SHans Petter Selasky  *
5*2485d8a7SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
6*2485d8a7SHans Petter Selasky  * modification, are permitted provided that the following conditions
7*2485d8a7SHans Petter Selasky  * are met:
8*2485d8a7SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
9*2485d8a7SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
10*2485d8a7SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
11*2485d8a7SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
12*2485d8a7SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
13*2485d8a7SHans Petter Selasky  *
14*2485d8a7SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*2485d8a7SHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*2485d8a7SHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*2485d8a7SHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*2485d8a7SHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*2485d8a7SHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*2485d8a7SHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*2485d8a7SHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*2485d8a7SHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*2485d8a7SHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*2485d8a7SHans Petter Selasky  * SUCH DAMAGE.
25*2485d8a7SHans Petter Selasky  */
26*2485d8a7SHans Petter Selasky 
27*2485d8a7SHans Petter Selasky /*
28*2485d8a7SHans Petter Selasky  * This file contains the emulation layer for LibUSB v0.1 from sourceforge.
29*2485d8a7SHans Petter Selasky  */
30*2485d8a7SHans Petter Selasky 
31*2485d8a7SHans Petter Selasky #include <sys/queue.h>
32*2485d8a7SHans Petter Selasky 
33*2485d8a7SHans Petter Selasky #include <errno.h>
34*2485d8a7SHans Petter Selasky #include <stdio.h>
35*2485d8a7SHans Petter Selasky #include <stdlib.h>
36*2485d8a7SHans Petter Selasky 
37*2485d8a7SHans Petter Selasky #include "libusb20.h"
38*2485d8a7SHans Petter Selasky #include "libusb20_desc.h"
39*2485d8a7SHans Petter Selasky #include "libusb20_int.h"
40*2485d8a7SHans Petter Selasky #include "usb.h"
41*2485d8a7SHans Petter Selasky 
42*2485d8a7SHans Petter Selasky /*
43*2485d8a7SHans Petter Selasky  * The two following macros were taken from the original LibUSB v0.1
44*2485d8a7SHans Petter Selasky  * for sake of compatibility:
45*2485d8a7SHans Petter Selasky  */
46*2485d8a7SHans Petter Selasky #define	LIST_ADD(begin, ent)	   \
47*2485d8a7SHans Petter Selasky   do {				   \
48*2485d8a7SHans Petter Selasky     if (begin) {		   \
49*2485d8a7SHans Petter Selasky       ent->next = begin;	   \
50*2485d8a7SHans Petter Selasky       ent->next->prev = ent;	   \
51*2485d8a7SHans Petter Selasky     } else {			   \
52*2485d8a7SHans Petter Selasky       ent->next = NULL;		   \
53*2485d8a7SHans Petter Selasky     }				   \
54*2485d8a7SHans Petter Selasky     ent->prev = NULL;		   \
55*2485d8a7SHans Petter Selasky     begin = ent;		   \
56*2485d8a7SHans Petter Selasky   } while(0)
57*2485d8a7SHans Petter Selasky 
58*2485d8a7SHans Petter Selasky #define	LIST_DEL(begin, ent)		 \
59*2485d8a7SHans Petter Selasky   do {					 \
60*2485d8a7SHans Petter Selasky     if (ent->prev) {			 \
61*2485d8a7SHans Petter Selasky       ent->prev->next = ent->next;	 \
62*2485d8a7SHans Petter Selasky     } else {				 \
63*2485d8a7SHans Petter Selasky       begin = ent->next;		 \
64*2485d8a7SHans Petter Selasky     }					 \
65*2485d8a7SHans Petter Selasky     if (ent->next) {			 \
66*2485d8a7SHans Petter Selasky       ent->next->prev = ent->prev;	 \
67*2485d8a7SHans Petter Selasky     }					 \
68*2485d8a7SHans Petter Selasky     ent->prev = NULL;			 \
69*2485d8a7SHans Petter Selasky     ent->next = NULL;			 \
70*2485d8a7SHans Petter Selasky   } while (0)
71*2485d8a7SHans Petter Selasky 
72*2485d8a7SHans Petter Selasky struct usb_bus *usb_busses = NULL;
73*2485d8a7SHans Petter Selasky 
74*2485d8a7SHans Petter Selasky static struct usb_bus usb_global_bus = {
75*2485d8a7SHans Petter Selasky 	.dirname = {"/dev/usb"},
76*2485d8a7SHans Petter Selasky 	.root_dev = NULL,
77*2485d8a7SHans Petter Selasky 	.devices = NULL,
78*2485d8a7SHans Petter Selasky };
79*2485d8a7SHans Petter Selasky 
80*2485d8a7SHans Petter Selasky static struct libusb20_backend *usb_backend = NULL;
81*2485d8a7SHans Petter Selasky 
82*2485d8a7SHans Petter Selasky struct usb_parse_state {
83*2485d8a7SHans Petter Selasky 
84*2485d8a7SHans Petter Selasky 	struct {
85*2485d8a7SHans Petter Selasky 		struct libusb20_endpoint *currep;
86*2485d8a7SHans Petter Selasky 		struct libusb20_interface *currifc;
87*2485d8a7SHans Petter Selasky 		struct libusb20_config *currcfg;
88*2485d8a7SHans Petter Selasky 		struct libusb20_me_struct *currextra;
89*2485d8a7SHans Petter Selasky 	}	a;
90*2485d8a7SHans Petter Selasky 
91*2485d8a7SHans Petter Selasky 	struct {
92*2485d8a7SHans Petter Selasky 		struct usb_config_descriptor *currcfg;
93*2485d8a7SHans Petter Selasky 		struct usb_interface_descriptor *currifc;
94*2485d8a7SHans Petter Selasky 		struct usb_endpoint_descriptor *currep;
95*2485d8a7SHans Petter Selasky 		struct usb_interface *currifcw;
96*2485d8a7SHans Petter Selasky 		uint8_t *currextra;
97*2485d8a7SHans Petter Selasky 	}	b;
98*2485d8a7SHans Petter Selasky 
99*2485d8a7SHans Petter Selasky 	uint8_t	preparse;
100*2485d8a7SHans Petter Selasky };
101*2485d8a7SHans Petter Selasky 
102*2485d8a7SHans Petter Selasky static struct libusb20_transfer *
103*2485d8a7SHans Petter Selasky usb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no)
104*2485d8a7SHans Petter Selasky {
105*2485d8a7SHans Petter Selasky 	struct libusb20_device *pdev = (void *)dev;
106*2485d8a7SHans Petter Selasky 	struct libusb20_transfer *xfer;
107*2485d8a7SHans Petter Selasky 	int err;
108*2485d8a7SHans Petter Selasky 	uint32_t bufsize;
109*2485d8a7SHans Petter Selasky 	uint8_t x;
110*2485d8a7SHans Petter Selasky 	uint8_t speed;
111*2485d8a7SHans Petter Selasky 
112*2485d8a7SHans Petter Selasky 	x = (ep_no & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 2;
113*2485d8a7SHans Petter Selasky 
114*2485d8a7SHans Petter Selasky 	if (ep_no & LIBUSB20_ENDPOINT_DIR_MASK) {
115*2485d8a7SHans Petter Selasky 		/* this is an IN endpoint */
116*2485d8a7SHans Petter Selasky 		x |= 1;
117*2485d8a7SHans Petter Selasky 	}
118*2485d8a7SHans Petter Selasky 	speed = libusb20_dev_get_speed(pdev);
119*2485d8a7SHans Petter Selasky 
120*2485d8a7SHans Petter Selasky 	/* select a sensible buffer size */
121*2485d8a7SHans Petter Selasky 	if (speed == LIBUSB20_SPEED_LOW) {
122*2485d8a7SHans Petter Selasky 		bufsize = 256;
123*2485d8a7SHans Petter Selasky 	} else if (speed == LIBUSB20_SPEED_FULL) {
124*2485d8a7SHans Petter Selasky 		bufsize = 4096;
125*2485d8a7SHans Petter Selasky 	} else {
126*2485d8a7SHans Petter Selasky 		bufsize = 16384;
127*2485d8a7SHans Petter Selasky 	}
128*2485d8a7SHans Petter Selasky 
129*2485d8a7SHans Petter Selasky 	xfer = libusb20_tr_get_pointer(pdev, x);
130*2485d8a7SHans Petter Selasky 
131*2485d8a7SHans Petter Selasky 	if (xfer == NULL)
132*2485d8a7SHans Petter Selasky 		return (xfer);
133*2485d8a7SHans Petter Selasky 
134*2485d8a7SHans Petter Selasky 	err = libusb20_tr_open(xfer, bufsize, 1, ep_no);
135*2485d8a7SHans Petter Selasky 	if (err == LIBUSB20_ERROR_BUSY) {
136*2485d8a7SHans Petter Selasky 		/* already opened */
137*2485d8a7SHans Petter Selasky 		return (xfer);
138*2485d8a7SHans Petter Selasky 	} else if (err) {
139*2485d8a7SHans Petter Selasky 		return (NULL);
140*2485d8a7SHans Petter Selasky 	}
141*2485d8a7SHans Petter Selasky 	/* success */
142*2485d8a7SHans Petter Selasky 	return (xfer);
143*2485d8a7SHans Petter Selasky }
144*2485d8a7SHans Petter Selasky 
145*2485d8a7SHans Petter Selasky usb_dev_handle *
146*2485d8a7SHans Petter Selasky usb_open(struct usb_device *dev)
147*2485d8a7SHans Petter Selasky {
148*2485d8a7SHans Petter Selasky 	int err;
149*2485d8a7SHans Petter Selasky 
150*2485d8a7SHans Petter Selasky 	err = libusb20_dev_open(dev->dev, 16 * 2);
151*2485d8a7SHans Petter Selasky 	if (err == LIBUSB20_ERROR_BUSY) {
152*2485d8a7SHans Petter Selasky 		/*
153*2485d8a7SHans Petter Selasky 		 * Workaround buggy USB applications which open the USB
154*2485d8a7SHans Petter Selasky 		 * device multiple times:
155*2485d8a7SHans Petter Selasky 		 */
156*2485d8a7SHans Petter Selasky 		return (dev->dev);
157*2485d8a7SHans Petter Selasky 	}
158*2485d8a7SHans Petter Selasky 	if (err)
159*2485d8a7SHans Petter Selasky 		return (NULL);
160*2485d8a7SHans Petter Selasky 
161*2485d8a7SHans Petter Selasky 	/*
162*2485d8a7SHans Petter Selasky 	 * Dequeue USB device from backend queue so that it does not get
163*2485d8a7SHans Petter Selasky 	 * freed when the backend is re-scanned:
164*2485d8a7SHans Petter Selasky 	 */
165*2485d8a7SHans Petter Selasky 	libusb20_be_dequeue_device(usb_backend, dev->dev);
166*2485d8a7SHans Petter Selasky 
167*2485d8a7SHans Petter Selasky 	return (dev->dev);
168*2485d8a7SHans Petter Selasky }
169*2485d8a7SHans Petter Selasky 
170*2485d8a7SHans Petter Selasky int
171*2485d8a7SHans Petter Selasky usb_close(usb_dev_handle * udev)
172*2485d8a7SHans Petter Selasky {
173*2485d8a7SHans Petter Selasky 	struct usb_device *dev;
174*2485d8a7SHans Petter Selasky 	int err;
175*2485d8a7SHans Petter Selasky 
176*2485d8a7SHans Petter Selasky 	err = libusb20_dev_close((void *)udev);
177*2485d8a7SHans Petter Selasky 
178*2485d8a7SHans Petter Selasky 	if (err)
179*2485d8a7SHans Petter Selasky 		return (-1);
180*2485d8a7SHans Petter Selasky 
181*2485d8a7SHans Petter Selasky 	if (usb_backend != NULL) {
182*2485d8a7SHans Petter Selasky 		/*
183*2485d8a7SHans Petter Selasky 		 * Enqueue USB device to backend queue so that it gets freed
184*2485d8a7SHans Petter Selasky 		 * when the backend is re-scanned:
185*2485d8a7SHans Petter Selasky 		 */
186*2485d8a7SHans Petter Selasky 		libusb20_be_enqueue_device(usb_backend, (void *)udev);
187*2485d8a7SHans Petter Selasky 	} else {
188*2485d8a7SHans Petter Selasky 		/*
189*2485d8a7SHans Petter Selasky 		 * The backend is gone. Free device data so that we
190*2485d8a7SHans Petter Selasky 		 * don't start leaking memory!
191*2485d8a7SHans Petter Selasky 		 */
192*2485d8a7SHans Petter Selasky 		dev = usb_device(udev);
193*2485d8a7SHans Petter Selasky 		libusb20_dev_free((void *)udev);
194*2485d8a7SHans Petter Selasky 		LIST_DEL(usb_global_bus.devices, dev);
195*2485d8a7SHans Petter Selasky 		free(dev);
196*2485d8a7SHans Petter Selasky 	}
197*2485d8a7SHans Petter Selasky 	return (0);
198*2485d8a7SHans Petter Selasky }
199*2485d8a7SHans Petter Selasky 
200*2485d8a7SHans Petter Selasky int
201*2485d8a7SHans Petter Selasky usb_get_string(usb_dev_handle * dev, int strindex,
202*2485d8a7SHans Petter Selasky     int langid, char *buf, size_t buflen)
203*2485d8a7SHans Petter Selasky {
204*2485d8a7SHans Petter Selasky 	int err;
205*2485d8a7SHans Petter Selasky 
206*2485d8a7SHans Petter Selasky 	err = libusb20_dev_req_string_sync((void *)dev,
207*2485d8a7SHans Petter Selasky 	    strindex, langid, buf, buflen);
208*2485d8a7SHans Petter Selasky 
209*2485d8a7SHans Petter Selasky 	if (err)
210*2485d8a7SHans Petter Selasky 		return (-1);
211*2485d8a7SHans Petter Selasky 
212*2485d8a7SHans Petter Selasky 	return (0);
213*2485d8a7SHans Petter Selasky }
214*2485d8a7SHans Petter Selasky 
215*2485d8a7SHans Petter Selasky int
216*2485d8a7SHans Petter Selasky usb_get_string_simple(usb_dev_handle * dev, int strindex,
217*2485d8a7SHans Petter Selasky     char *buf, size_t buflen)
218*2485d8a7SHans Petter Selasky {
219*2485d8a7SHans Petter Selasky 	int err;
220*2485d8a7SHans Petter Selasky 
221*2485d8a7SHans Petter Selasky 	err = libusb20_dev_req_string_simple_sync((void *)dev,
222*2485d8a7SHans Petter Selasky 	    strindex, buf, buflen);
223*2485d8a7SHans Petter Selasky 
224*2485d8a7SHans Petter Selasky 	if (err)
225*2485d8a7SHans Petter Selasky 		return (-1);
226*2485d8a7SHans Petter Selasky 
227*2485d8a7SHans Petter Selasky 	return (strlen(buf));
228*2485d8a7SHans Petter Selasky }
229*2485d8a7SHans Petter Selasky 
230*2485d8a7SHans Petter Selasky int
231*2485d8a7SHans Petter Selasky usb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type,
232*2485d8a7SHans Petter Selasky     uint8_t ep_index, void *buf, int size)
233*2485d8a7SHans Petter Selasky {
234*2485d8a7SHans Petter Selasky 	memset(buf, 0, size);
235*2485d8a7SHans Petter Selasky 
236*2485d8a7SHans Petter Selasky 	return (usb_control_msg(udev, ep | USB_ENDPOINT_IN,
237*2485d8a7SHans Petter Selasky 	    USB_REQ_GET_DESCRIPTOR, (type << 8) + ep_index, 0,
238*2485d8a7SHans Petter Selasky 	    buf, size, 1000));
239*2485d8a7SHans Petter Selasky }
240*2485d8a7SHans Petter Selasky 
241*2485d8a7SHans Petter Selasky int
242*2485d8a7SHans Petter Selasky usb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t desc_index,
243*2485d8a7SHans Petter Selasky     void *buf, int size)
244*2485d8a7SHans Petter Selasky {
245*2485d8a7SHans Petter Selasky 	memset(buf, 0, size);
246*2485d8a7SHans Petter Selasky 
247*2485d8a7SHans Petter Selasky 	return (usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
248*2485d8a7SHans Petter Selasky 	    (type << 8) + desc_index, 0, buf, size, 1000));
249*2485d8a7SHans Petter Selasky }
250*2485d8a7SHans Petter Selasky 
251*2485d8a7SHans Petter Selasky int
252*2485d8a7SHans Petter Selasky usb_parse_descriptor(uint8_t *source, char *description, void *dest)
253*2485d8a7SHans Petter Selasky {
254*2485d8a7SHans Petter Selasky 	uint8_t *sp = source;
255*2485d8a7SHans Petter Selasky 	uint8_t *dp = dest;
256*2485d8a7SHans Petter Selasky 	uint16_t w;
257*2485d8a7SHans Petter Selasky 	uint32_t d;
258*2485d8a7SHans Petter Selasky 	char *cp;
259*2485d8a7SHans Petter Selasky 
260*2485d8a7SHans Petter Selasky 	for (cp = description; *cp; cp++) {
261*2485d8a7SHans Petter Selasky 		switch (*cp) {
262*2485d8a7SHans Petter Selasky 		case 'b':		/* 8-bit byte */
263*2485d8a7SHans Petter Selasky 			*dp++ = *sp++;
264*2485d8a7SHans Petter Selasky 			break;
265*2485d8a7SHans Petter Selasky 			/*
266*2485d8a7SHans Petter Selasky 			 * 16-bit word, convert from little endian to CPU
267*2485d8a7SHans Petter Selasky 			 */
268*2485d8a7SHans Petter Selasky 		case 'w':
269*2485d8a7SHans Petter Selasky 			w = (sp[1] << 8) | sp[0];
270*2485d8a7SHans Petter Selasky 			sp += 2;
271*2485d8a7SHans Petter Selasky 			/* Align to word boundary */
272*2485d8a7SHans Petter Selasky 			dp += ((dp - (uint8_t *)0) & 1);
273*2485d8a7SHans Petter Selasky 			*((uint16_t *)dp) = w;
274*2485d8a7SHans Petter Selasky 			dp += 2;
275*2485d8a7SHans Petter Selasky 			break;
276*2485d8a7SHans Petter Selasky 			/*
277*2485d8a7SHans Petter Selasky 			 * 32-bit dword, convert from little endian to CPU
278*2485d8a7SHans Petter Selasky 			 */
279*2485d8a7SHans Petter Selasky 		case 'd':
280*2485d8a7SHans Petter Selasky 			d = (sp[3] << 24) | (sp[2] << 16) |
281*2485d8a7SHans Petter Selasky 			    (sp[1] << 8) | sp[0];
282*2485d8a7SHans Petter Selasky 			sp += 4;
283*2485d8a7SHans Petter Selasky 			/* Align to word boundary */
284*2485d8a7SHans Petter Selasky 			dp += ((dp - (uint8_t *)0) & 1);
285*2485d8a7SHans Petter Selasky 			/* Align to double word boundary */
286*2485d8a7SHans Petter Selasky 			dp += ((dp - (uint8_t *)0) & 2);
287*2485d8a7SHans Petter Selasky 			*((uint32_t *)dp) = d;
288*2485d8a7SHans Petter Selasky 			dp += 4;
289*2485d8a7SHans Petter Selasky 			break;
290*2485d8a7SHans Petter Selasky 		}
291*2485d8a7SHans Petter Selasky 	}
292*2485d8a7SHans Petter Selasky 	return (sp - source);
293*2485d8a7SHans Petter Selasky }
294*2485d8a7SHans Petter Selasky 
295*2485d8a7SHans Petter Selasky static void
296*2485d8a7SHans Petter Selasky usb_parse_extra(struct usb_parse_state *ps, uint8_t **pptr, int *plen)
297*2485d8a7SHans Petter Selasky {
298*2485d8a7SHans Petter Selasky 	void *ptr;
299*2485d8a7SHans Petter Selasky 	uint16_t len;
300*2485d8a7SHans Petter Selasky 
301*2485d8a7SHans Petter Selasky 	ptr = ps->a.currextra->ptr;
302*2485d8a7SHans Petter Selasky 	len = ps->a.currextra->len;
303*2485d8a7SHans Petter Selasky 
304*2485d8a7SHans Petter Selasky 	if (ps->preparse == 0) {
305*2485d8a7SHans Petter Selasky 		memcpy(ps->b.currextra, ptr, len);
306*2485d8a7SHans Petter Selasky 		*pptr = ps->b.currextra;
307*2485d8a7SHans Petter Selasky 		*plen = len;
308*2485d8a7SHans Petter Selasky 	}
309*2485d8a7SHans Petter Selasky 	ps->b.currextra += len;
310*2485d8a7SHans Petter Selasky 	return;
311*2485d8a7SHans Petter Selasky }
312*2485d8a7SHans Petter Selasky 
313*2485d8a7SHans Petter Selasky static void
314*2485d8a7SHans Petter Selasky usb_parse_endpoint(struct usb_parse_state *ps)
315*2485d8a7SHans Petter Selasky {
316*2485d8a7SHans Petter Selasky 	struct usb_endpoint_descriptor *bep;
317*2485d8a7SHans Petter Selasky 	struct libusb20_endpoint *aep;
318*2485d8a7SHans Petter Selasky 
319*2485d8a7SHans Petter Selasky 	aep = ps->a.currep;
320*2485d8a7SHans Petter Selasky 	bep = ps->b.currep++;
321*2485d8a7SHans Petter Selasky 
322*2485d8a7SHans Petter Selasky 	if (ps->preparse == 0) {
323*2485d8a7SHans Petter Selasky 		/* copy descriptor fields */
324*2485d8a7SHans Petter Selasky 		bep->bLength = aep->desc.bLength;
325*2485d8a7SHans Petter Selasky 		bep->bDescriptorType = aep->desc.bDescriptorType;
326*2485d8a7SHans Petter Selasky 		bep->bEndpointAddress = aep->desc.bEndpointAddress;
327*2485d8a7SHans Petter Selasky 		bep->bmAttributes = aep->desc.bmAttributes;
328*2485d8a7SHans Petter Selasky 		bep->wMaxPacketSize = aep->desc.wMaxPacketSize;
329*2485d8a7SHans Petter Selasky 		bep->bInterval = aep->desc.bInterval;
330*2485d8a7SHans Petter Selasky 		bep->bRefresh = aep->desc.bRefresh;
331*2485d8a7SHans Petter Selasky 		bep->bSynchAddress = aep->desc.bSynchAddress;
332*2485d8a7SHans Petter Selasky 	}
333*2485d8a7SHans Petter Selasky 	ps->a.currextra = &aep->extra;
334*2485d8a7SHans Petter Selasky 	usb_parse_extra(ps, &bep->extra, &bep->extralen);
335*2485d8a7SHans Petter Selasky 	return;
336*2485d8a7SHans Petter Selasky }
337*2485d8a7SHans Petter Selasky 
338*2485d8a7SHans Petter Selasky static void
339*2485d8a7SHans Petter Selasky usb_parse_iface_sub(struct usb_parse_state *ps)
340*2485d8a7SHans Petter Selasky {
341*2485d8a7SHans Petter Selasky 	struct libusb20_interface *aifc;
342*2485d8a7SHans Petter Selasky 	struct usb_interface_descriptor *bifc;
343*2485d8a7SHans Petter Selasky 	uint8_t x;
344*2485d8a7SHans Petter Selasky 
345*2485d8a7SHans Petter Selasky 	aifc = ps->a.currifc;
346*2485d8a7SHans Petter Selasky 	bifc = ps->b.currifc++;
347*2485d8a7SHans Petter Selasky 
348*2485d8a7SHans Petter Selasky 	if (ps->preparse == 0) {
349*2485d8a7SHans Petter Selasky 		/* copy descriptor fields */
350*2485d8a7SHans Petter Selasky 		bifc->bLength = aifc->desc.bLength;
351*2485d8a7SHans Petter Selasky 		bifc->bDescriptorType = aifc->desc.bDescriptorType;
352*2485d8a7SHans Petter Selasky 		bifc->bInterfaceNumber = aifc->desc.bInterfaceNumber;
353*2485d8a7SHans Petter Selasky 		bifc->bAlternateSetting = aifc->desc.bAlternateSetting;
354*2485d8a7SHans Petter Selasky 		bifc->bNumEndpoints = aifc->num_endpoints;
355*2485d8a7SHans Petter Selasky 		bifc->bInterfaceClass = aifc->desc.bInterfaceClass;
356*2485d8a7SHans Petter Selasky 		bifc->bInterfaceSubClass = aifc->desc.bInterfaceSubClass;
357*2485d8a7SHans Petter Selasky 		bifc->bInterfaceProtocol = aifc->desc.bInterfaceProtocol;
358*2485d8a7SHans Petter Selasky 		bifc->iInterface = aifc->desc.iInterface;
359*2485d8a7SHans Petter Selasky 		bifc->endpoint = ps->b.currep;
360*2485d8a7SHans Petter Selasky 	}
361*2485d8a7SHans Petter Selasky 	for (x = 0; x != aifc->num_endpoints; x++) {
362*2485d8a7SHans Petter Selasky 		ps->a.currep = aifc->endpoints + x;
363*2485d8a7SHans Petter Selasky 		usb_parse_endpoint(ps);
364*2485d8a7SHans Petter Selasky 	}
365*2485d8a7SHans Petter Selasky 
366*2485d8a7SHans Petter Selasky 	ps->a.currextra = &aifc->extra;
367*2485d8a7SHans Petter Selasky 	usb_parse_extra(ps, &bifc->extra, &bifc->extralen);
368*2485d8a7SHans Petter Selasky 	return;
369*2485d8a7SHans Petter Selasky }
370*2485d8a7SHans Petter Selasky 
371*2485d8a7SHans Petter Selasky static void
372*2485d8a7SHans Petter Selasky usb_parse_iface(struct usb_parse_state *ps)
373*2485d8a7SHans Petter Selasky {
374*2485d8a7SHans Petter Selasky 	struct libusb20_interface *aifc;
375*2485d8a7SHans Petter Selasky 	struct usb_interface *bifc;
376*2485d8a7SHans Petter Selasky 	uint8_t x;
377*2485d8a7SHans Petter Selasky 
378*2485d8a7SHans Petter Selasky 	aifc = ps->a.currifc;
379*2485d8a7SHans Petter Selasky 	bifc = ps->b.currifcw++;
380*2485d8a7SHans Petter Selasky 
381*2485d8a7SHans Petter Selasky 	if (ps->preparse == 0) {
382*2485d8a7SHans Petter Selasky 		/* initialise interface wrapper */
383*2485d8a7SHans Petter Selasky 		bifc->altsetting = ps->b.currifc;
384*2485d8a7SHans Petter Selasky 		bifc->num_altsetting = aifc->num_altsetting + 1;
385*2485d8a7SHans Petter Selasky 	}
386*2485d8a7SHans Petter Selasky 	usb_parse_iface_sub(ps);
387*2485d8a7SHans Petter Selasky 
388*2485d8a7SHans Petter Selasky 	for (x = 0; x != aifc->num_altsetting; x++) {
389*2485d8a7SHans Petter Selasky 		ps->a.currifc = aifc->altsetting + x;
390*2485d8a7SHans Petter Selasky 		usb_parse_iface_sub(ps);
391*2485d8a7SHans Petter Selasky 	}
392*2485d8a7SHans Petter Selasky 	return;
393*2485d8a7SHans Petter Selasky }
394*2485d8a7SHans Petter Selasky 
395*2485d8a7SHans Petter Selasky static void
396*2485d8a7SHans Petter Selasky usb_parse_config(struct usb_parse_state *ps)
397*2485d8a7SHans Petter Selasky {
398*2485d8a7SHans Petter Selasky 	struct libusb20_config *acfg;
399*2485d8a7SHans Petter Selasky 	struct usb_config_descriptor *bcfg;
400*2485d8a7SHans Petter Selasky 	uint8_t x;
401*2485d8a7SHans Petter Selasky 
402*2485d8a7SHans Petter Selasky 	acfg = ps->a.currcfg;
403*2485d8a7SHans Petter Selasky 	bcfg = ps->b.currcfg;
404*2485d8a7SHans Petter Selasky 
405*2485d8a7SHans Petter Selasky 	if (ps->preparse == 0) {
406*2485d8a7SHans Petter Selasky 		/* initialise config wrapper */
407*2485d8a7SHans Petter Selasky 		bcfg->bLength = acfg->desc.bLength;
408*2485d8a7SHans Petter Selasky 		bcfg->bDescriptorType = acfg->desc.bDescriptorType;
409*2485d8a7SHans Petter Selasky 		bcfg->wTotalLength = acfg->desc.wTotalLength;
410*2485d8a7SHans Petter Selasky 		bcfg->bNumInterfaces = acfg->num_interface;
411*2485d8a7SHans Petter Selasky 		bcfg->bConfigurationValue = acfg->desc.bConfigurationValue;
412*2485d8a7SHans Petter Selasky 		bcfg->iConfiguration = acfg->desc.iConfiguration;
413*2485d8a7SHans Petter Selasky 		bcfg->bmAttributes = acfg->desc.bmAttributes;
414*2485d8a7SHans Petter Selasky 		bcfg->MaxPower = acfg->desc.bMaxPower;
415*2485d8a7SHans Petter Selasky 		bcfg->interface = ps->b.currifcw;
416*2485d8a7SHans Petter Selasky 	}
417*2485d8a7SHans Petter Selasky 	for (x = 0; x != acfg->num_interface; x++) {
418*2485d8a7SHans Petter Selasky 		ps->a.currifc = acfg->interface + x;
419*2485d8a7SHans Petter Selasky 		usb_parse_iface(ps);
420*2485d8a7SHans Petter Selasky 	}
421*2485d8a7SHans Petter Selasky 
422*2485d8a7SHans Petter Selasky 	ps->a.currextra = &acfg->extra;
423*2485d8a7SHans Petter Selasky 	usb_parse_extra(ps, &bcfg->extra, &bcfg->extralen);
424*2485d8a7SHans Petter Selasky 	return;
425*2485d8a7SHans Petter Selasky }
426*2485d8a7SHans Petter Selasky 
427*2485d8a7SHans Petter Selasky int
428*2485d8a7SHans Petter Selasky usb_parse_configuration(struct usb_config_descriptor *config,
429*2485d8a7SHans Petter Selasky     uint8_t *buffer)
430*2485d8a7SHans Petter Selasky {
431*2485d8a7SHans Petter Selasky 	struct usb_parse_state ps;
432*2485d8a7SHans Petter Selasky 	uint8_t *ptr;
433*2485d8a7SHans Petter Selasky 	uint32_t a;
434*2485d8a7SHans Petter Selasky 	uint32_t b;
435*2485d8a7SHans Petter Selasky 	uint32_t c;
436*2485d8a7SHans Petter Selasky 	uint32_t d;
437*2485d8a7SHans Petter Selasky 
438*2485d8a7SHans Petter Selasky 	if ((buffer == NULL) || (config == NULL)) {
439*2485d8a7SHans Petter Selasky 		return (-1);
440*2485d8a7SHans Petter Selasky 	}
441*2485d8a7SHans Petter Selasky 	memset(&ps, 0, sizeof(ps));
442*2485d8a7SHans Petter Selasky 
443*2485d8a7SHans Petter Selasky 	ps.a.currcfg = libusb20_parse_config_desc(buffer);
444*2485d8a7SHans Petter Selasky 	ps.b.currcfg = config;
445*2485d8a7SHans Petter Selasky 	if (ps.a.currcfg == NULL) {
446*2485d8a7SHans Petter Selasky 		/* could not parse config or out of memory */
447*2485d8a7SHans Petter Selasky 		return (-1);
448*2485d8a7SHans Petter Selasky 	}
449*2485d8a7SHans Petter Selasky 	/* do the pre-parse */
450*2485d8a7SHans Petter Selasky 	ps.preparse = 1;
451*2485d8a7SHans Petter Selasky 	usb_parse_config(&ps);
452*2485d8a7SHans Petter Selasky 
453*2485d8a7SHans Petter Selasky 	a = ((uint8_t *)(ps.b.currifcw) - ((uint8_t *)0));
454*2485d8a7SHans Petter Selasky 	b = ((uint8_t *)(ps.b.currifc) - ((uint8_t *)0));
455*2485d8a7SHans Petter Selasky 	c = ((uint8_t *)(ps.b.currep) - ((uint8_t *)0));
456*2485d8a7SHans Petter Selasky 	d = ((uint8_t *)(ps.b.currextra) - ((uint8_t *)0));
457*2485d8a7SHans Petter Selasky 
458*2485d8a7SHans Petter Selasky 	/* allocate memory for our configuration */
459*2485d8a7SHans Petter Selasky 	ptr = malloc(a + b + c + d);
460*2485d8a7SHans Petter Selasky 	if (ptr == NULL) {
461*2485d8a7SHans Petter Selasky 		/* free config structure */
462*2485d8a7SHans Petter Selasky 		free(ps.a.currcfg);
463*2485d8a7SHans Petter Selasky 		return (-1);
464*2485d8a7SHans Petter Selasky 	}
465*2485d8a7SHans Petter Selasky 
466*2485d8a7SHans Petter Selasky 	/* "currifcw" must be first, hence this pointer is freed */
467*2485d8a7SHans Petter Selasky 	ps.b.currifcw = (void *)(ptr);
468*2485d8a7SHans Petter Selasky 	ps.b.currifc = (void *)(ptr + a);
469*2485d8a7SHans Petter Selasky 	ps.b.currep = (void *)(ptr + a + b);
470*2485d8a7SHans Petter Selasky 	ps.b.currextra = (void *)(ptr + a + b + c);
471*2485d8a7SHans Petter Selasky 
472*2485d8a7SHans Petter Selasky 	/* generate a libusb v0.1 compatible structure */
473*2485d8a7SHans Petter Selasky 	ps.preparse = 0;
474*2485d8a7SHans Petter Selasky 	usb_parse_config(&ps);
475*2485d8a7SHans Petter Selasky 
476*2485d8a7SHans Petter Selasky 	/* free config structure */
477*2485d8a7SHans Petter Selasky 	free(ps.a.currcfg);
478*2485d8a7SHans Petter Selasky 
479*2485d8a7SHans Petter Selasky 	return (0);			/* success */
480*2485d8a7SHans Petter Selasky }
481*2485d8a7SHans Petter Selasky 
482*2485d8a7SHans Petter Selasky void
483*2485d8a7SHans Petter Selasky usb_destroy_configuration(struct usb_device *dev)
484*2485d8a7SHans Petter Selasky {
485*2485d8a7SHans Petter Selasky 	uint8_t c;
486*2485d8a7SHans Petter Selasky 
487*2485d8a7SHans Petter Selasky 	if (dev->config == NULL) {
488*2485d8a7SHans Petter Selasky 		return;
489*2485d8a7SHans Petter Selasky 	}
490*2485d8a7SHans Petter Selasky 	for (c = 0; c != dev->descriptor.bNumConfigurations; c++) {
491*2485d8a7SHans Petter Selasky 		struct usb_config_descriptor *cf = &dev->config[c];
492*2485d8a7SHans Petter Selasky 
493*2485d8a7SHans Petter Selasky 		if (cf->interface != NULL) {
494*2485d8a7SHans Petter Selasky 			free(cf->interface);
495*2485d8a7SHans Petter Selasky 			cf->interface = NULL;
496*2485d8a7SHans Petter Selasky 		}
497*2485d8a7SHans Petter Selasky 	}
498*2485d8a7SHans Petter Selasky 
499*2485d8a7SHans Petter Selasky 	free(dev->config);
500*2485d8a7SHans Petter Selasky 	dev->config = NULL;
501*2485d8a7SHans Petter Selasky 	return;
502*2485d8a7SHans Petter Selasky }
503*2485d8a7SHans Petter Selasky 
504*2485d8a7SHans Petter Selasky void
505*2485d8a7SHans Petter Selasky usb_fetch_and_parse_descriptors(usb_dev_handle * udev)
506*2485d8a7SHans Petter Selasky {
507*2485d8a7SHans Petter Selasky 	struct usb_device *dev;
508*2485d8a7SHans Petter Selasky 	struct libusb20_device *pdev;
509*2485d8a7SHans Petter Selasky 	uint8_t *ptr;
510*2485d8a7SHans Petter Selasky 	int error;
511*2485d8a7SHans Petter Selasky 	uint32_t size;
512*2485d8a7SHans Petter Selasky 	uint16_t len;
513*2485d8a7SHans Petter Selasky 	uint8_t x;
514*2485d8a7SHans Petter Selasky 
515*2485d8a7SHans Petter Selasky 	if (udev == NULL) {
516*2485d8a7SHans Petter Selasky 		/* be NULL safe */
517*2485d8a7SHans Petter Selasky 		return;
518*2485d8a7SHans Petter Selasky 	}
519*2485d8a7SHans Petter Selasky 	dev = usb_device(udev);
520*2485d8a7SHans Petter Selasky 	pdev = (void *)udev;
521*2485d8a7SHans Petter Selasky 
522*2485d8a7SHans Petter Selasky 	if (dev->descriptor.bNumConfigurations == 0) {
523*2485d8a7SHans Petter Selasky 		/* invalid device */
524*2485d8a7SHans Petter Selasky 		return;
525*2485d8a7SHans Petter Selasky 	}
526*2485d8a7SHans Petter Selasky 	size = dev->descriptor.bNumConfigurations *
527*2485d8a7SHans Petter Selasky 	    sizeof(struct usb_config_descriptor);
528*2485d8a7SHans Petter Selasky 
529*2485d8a7SHans Petter Selasky 	dev->config = malloc(size);
530*2485d8a7SHans Petter Selasky 	if (dev->config == NULL) {
531*2485d8a7SHans Petter Selasky 		/* out of memory */
532*2485d8a7SHans Petter Selasky 		return;
533*2485d8a7SHans Petter Selasky 	}
534*2485d8a7SHans Petter Selasky 	memset(dev->config, 0, size);
535*2485d8a7SHans Petter Selasky 
536*2485d8a7SHans Petter Selasky 	for (x = 0; x != dev->descriptor.bNumConfigurations; x++) {
537*2485d8a7SHans Petter Selasky 
538*2485d8a7SHans Petter Selasky 		error = (pdev->methods->get_config_desc_full) (
539*2485d8a7SHans Petter Selasky 		    pdev, &ptr, &len, x);
540*2485d8a7SHans Petter Selasky 
541*2485d8a7SHans Petter Selasky 		if (error) {
542*2485d8a7SHans Petter Selasky 			usb_destroy_configuration(dev);
543*2485d8a7SHans Petter Selasky 			return;
544*2485d8a7SHans Petter Selasky 		}
545*2485d8a7SHans Petter Selasky 		usb_parse_configuration(dev->config + x, ptr);
546*2485d8a7SHans Petter Selasky 
547*2485d8a7SHans Petter Selasky 		/* free config buffer */
548*2485d8a7SHans Petter Selasky 		free(ptr);
549*2485d8a7SHans Petter Selasky 	}
550*2485d8a7SHans Petter Selasky 	return;
551*2485d8a7SHans Petter Selasky }
552*2485d8a7SHans Petter Selasky 
553*2485d8a7SHans Petter Selasky static int
554*2485d8a7SHans Petter Selasky usb_std_io(usb_dev_handle * dev, int ep, char *bytes, int size,
555*2485d8a7SHans Petter Selasky     int timeout, int is_intr)
556*2485d8a7SHans Petter Selasky {
557*2485d8a7SHans Petter Selasky 	struct libusb20_transfer *xfer;
558*2485d8a7SHans Petter Selasky 	uint32_t temp;
559*2485d8a7SHans Petter Selasky 	uint32_t maxsize;
560*2485d8a7SHans Petter Selasky 	uint32_t actlen;
561*2485d8a7SHans Petter Selasky 	char *oldbytes;
562*2485d8a7SHans Petter Selasky 
563*2485d8a7SHans Petter Selasky 	xfer = usb_get_transfer_by_ep_no(dev, ep);
564*2485d8a7SHans Petter Selasky 	if (xfer == NULL)
565*2485d8a7SHans Petter Selasky 		return (-1);
566*2485d8a7SHans Petter Selasky 
567*2485d8a7SHans Petter Selasky 	if (libusb20_tr_pending(xfer)) {
568*2485d8a7SHans Petter Selasky 		/* there is already a transfer ongoing */
569*2485d8a7SHans Petter Selasky 		return (-1);
570*2485d8a7SHans Petter Selasky 	}
571*2485d8a7SHans Petter Selasky 	maxsize = libusb20_tr_get_max_total_length(xfer);
572*2485d8a7SHans Petter Selasky 	oldbytes = bytes;
573*2485d8a7SHans Petter Selasky 
574*2485d8a7SHans Petter Selasky 	/*
575*2485d8a7SHans Petter Selasky 	 * We allow transferring zero bytes which is the same
576*2485d8a7SHans Petter Selasky 	 * equivalent to a zero length USB packet.
577*2485d8a7SHans Petter Selasky 	 */
578*2485d8a7SHans Petter Selasky 	do {
579*2485d8a7SHans Petter Selasky 
580*2485d8a7SHans Petter Selasky 		temp = size;
581*2485d8a7SHans Petter Selasky 		if (temp > maxsize) {
582*2485d8a7SHans Petter Selasky 			/* find maximum possible length */
583*2485d8a7SHans Petter Selasky 			temp = maxsize;
584*2485d8a7SHans Petter Selasky 		}
585*2485d8a7SHans Petter Selasky 		if (is_intr)
586*2485d8a7SHans Petter Selasky 			libusb20_tr_setup_intr(xfer, bytes, temp, timeout);
587*2485d8a7SHans Petter Selasky 		else
588*2485d8a7SHans Petter Selasky 			libusb20_tr_setup_bulk(xfer, bytes, temp, timeout);
589*2485d8a7SHans Petter Selasky 
590*2485d8a7SHans Petter Selasky 		libusb20_tr_start(xfer);
591*2485d8a7SHans Petter Selasky 
592*2485d8a7SHans Petter Selasky 		while (1) {
593*2485d8a7SHans Petter Selasky 
594*2485d8a7SHans Petter Selasky 			if (libusb20_dev_process((void *)dev) != 0) {
595*2485d8a7SHans Petter Selasky 				/* device detached */
596*2485d8a7SHans Petter Selasky 				return (-1);
597*2485d8a7SHans Petter Selasky 			}
598*2485d8a7SHans Petter Selasky 			if (libusb20_tr_pending(xfer) == 0) {
599*2485d8a7SHans Petter Selasky 				/* transfer complete */
600*2485d8a7SHans Petter Selasky 				break;
601*2485d8a7SHans Petter Selasky 			}
602*2485d8a7SHans Petter Selasky 			/* wait for USB event from kernel */
603*2485d8a7SHans Petter Selasky 			libusb20_dev_wait_process((void *)dev, -1);
604*2485d8a7SHans Petter Selasky 		}
605*2485d8a7SHans Petter Selasky 
606*2485d8a7SHans Petter Selasky 		switch (libusb20_tr_get_status(xfer)) {
607*2485d8a7SHans Petter Selasky 		case 0:
608*2485d8a7SHans Petter Selasky 			/* success */
609*2485d8a7SHans Petter Selasky 			break;
610*2485d8a7SHans Petter Selasky 		case LIBUSB20_TRANSFER_TIMED_OUT:
611*2485d8a7SHans Petter Selasky 			/* transfer timeout */
612*2485d8a7SHans Petter Selasky 			return (-ETIMEDOUT);
613*2485d8a7SHans Petter Selasky 		default:
614*2485d8a7SHans Petter Selasky 			/* other transfer error */
615*2485d8a7SHans Petter Selasky 			return (-ENXIO);
616*2485d8a7SHans Petter Selasky 		}
617*2485d8a7SHans Petter Selasky 		actlen = libusb20_tr_get_actual_length(xfer);
618*2485d8a7SHans Petter Selasky 
619*2485d8a7SHans Petter Selasky 		bytes += actlen;
620*2485d8a7SHans Petter Selasky 		size -= actlen;
621*2485d8a7SHans Petter Selasky 
622*2485d8a7SHans Petter Selasky 		if (actlen != temp) {
623*2485d8a7SHans Petter Selasky 			/* short transfer */
624*2485d8a7SHans Petter Selasky 			break;
625*2485d8a7SHans Petter Selasky 		}
626*2485d8a7SHans Petter Selasky 	} while (size > 0);
627*2485d8a7SHans Petter Selasky 
628*2485d8a7SHans Petter Selasky 	return (bytes - oldbytes);
629*2485d8a7SHans Petter Selasky }
630*2485d8a7SHans Petter Selasky 
631*2485d8a7SHans Petter Selasky int
632*2485d8a7SHans Petter Selasky usb_bulk_write(usb_dev_handle * dev, int ep, char *bytes,
633*2485d8a7SHans Petter Selasky     int size, int timeout)
634*2485d8a7SHans Petter Selasky {
635*2485d8a7SHans Petter Selasky 	return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK,
636*2485d8a7SHans Petter Selasky 	    bytes, size, timeout, 0));
637*2485d8a7SHans Petter Selasky }
638*2485d8a7SHans Petter Selasky 
639*2485d8a7SHans Petter Selasky int
640*2485d8a7SHans Petter Selasky usb_bulk_read(usb_dev_handle * dev, int ep, char *bytes,
641*2485d8a7SHans Petter Selasky     int size, int timeout)
642*2485d8a7SHans Petter Selasky {
643*2485d8a7SHans Petter Selasky 	return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK,
644*2485d8a7SHans Petter Selasky 	    bytes, size, timeout, 0));
645*2485d8a7SHans Petter Selasky }
646*2485d8a7SHans Petter Selasky 
647*2485d8a7SHans Petter Selasky int
648*2485d8a7SHans Petter Selasky usb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes,
649*2485d8a7SHans Petter Selasky     int size, int timeout)
650*2485d8a7SHans Petter Selasky {
651*2485d8a7SHans Petter Selasky 	return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK,
652*2485d8a7SHans Petter Selasky 	    bytes, size, timeout, 1));
653*2485d8a7SHans Petter Selasky }
654*2485d8a7SHans Petter Selasky 
655*2485d8a7SHans Petter Selasky int
656*2485d8a7SHans Petter Selasky usb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes,
657*2485d8a7SHans Petter Selasky     int size, int timeout)
658*2485d8a7SHans Petter Selasky {
659*2485d8a7SHans Petter Selasky 	return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK,
660*2485d8a7SHans Petter Selasky 	    bytes, size, timeout, 1));
661*2485d8a7SHans Petter Selasky }
662*2485d8a7SHans Petter Selasky 
663*2485d8a7SHans Petter Selasky int
664*2485d8a7SHans Petter Selasky usb_control_msg(usb_dev_handle * dev, int requesttype, int request,
665*2485d8a7SHans Petter Selasky     int value, int wIndex, char *bytes, int size, int timeout)
666*2485d8a7SHans Petter Selasky {
667*2485d8a7SHans Petter Selasky 	struct LIBUSB20_CONTROL_SETUP_DECODED req;
668*2485d8a7SHans Petter Selasky 	int err;
669*2485d8a7SHans Petter Selasky 	uint16_t actlen;
670*2485d8a7SHans Petter Selasky 
671*2485d8a7SHans Petter Selasky 	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
672*2485d8a7SHans Petter Selasky 
673*2485d8a7SHans Petter Selasky 	req.bmRequestType = requesttype;
674*2485d8a7SHans Petter Selasky 	req.bRequest = request;
675*2485d8a7SHans Petter Selasky 	req.wValue = value;
676*2485d8a7SHans Petter Selasky 	req.wIndex = wIndex;
677*2485d8a7SHans Petter Selasky 	req.wLength = size;
678*2485d8a7SHans Petter Selasky 
679*2485d8a7SHans Petter Selasky 	err = libusb20_dev_request_sync((void *)dev, &req, bytes,
680*2485d8a7SHans Petter Selasky 	    &actlen, timeout, 0);
681*2485d8a7SHans Petter Selasky 
682*2485d8a7SHans Petter Selasky 	if (err)
683*2485d8a7SHans Petter Selasky 		return (-1);
684*2485d8a7SHans Petter Selasky 
685*2485d8a7SHans Petter Selasky 	return (actlen);
686*2485d8a7SHans Petter Selasky }
687*2485d8a7SHans Petter Selasky 
688*2485d8a7SHans Petter Selasky int
689*2485d8a7SHans Petter Selasky usb_set_configuration(usb_dev_handle * udev, int bConfigurationValue)
690*2485d8a7SHans Petter Selasky {
691*2485d8a7SHans Petter Selasky 	struct usb_device *dev;
692*2485d8a7SHans Petter Selasky 	int err;
693*2485d8a7SHans Petter Selasky 	uint8_t i;
694*2485d8a7SHans Petter Selasky 
695*2485d8a7SHans Petter Selasky 	/*
696*2485d8a7SHans Petter Selasky 	 * Need to translate from "bConfigurationValue" to
697*2485d8a7SHans Petter Selasky 	 * configuration index:
698*2485d8a7SHans Petter Selasky 	 */
699*2485d8a7SHans Petter Selasky 
700*2485d8a7SHans Petter Selasky 	if (bConfigurationValue == 0) {
701*2485d8a7SHans Petter Selasky 		/* unconfigure */
702*2485d8a7SHans Petter Selasky 		i = 255;
703*2485d8a7SHans Petter Selasky 	} else {
704*2485d8a7SHans Petter Selasky 		/* lookup configuration index */
705*2485d8a7SHans Petter Selasky 		dev = usb_device(udev);
706*2485d8a7SHans Petter Selasky 
707*2485d8a7SHans Petter Selasky 		/* check if the configuration array is not there */
708*2485d8a7SHans Petter Selasky 		if (dev->config == NULL) {
709*2485d8a7SHans Petter Selasky 			return (-1);
710*2485d8a7SHans Petter Selasky 		}
711*2485d8a7SHans Petter Selasky 		for (i = 0;; i++) {
712*2485d8a7SHans Petter Selasky 			if (i == dev->descriptor.bNumConfigurations) {
713*2485d8a7SHans Petter Selasky 				/* "bConfigurationValue" not found */
714*2485d8a7SHans Petter Selasky 				return (-1);
715*2485d8a7SHans Petter Selasky 			}
716*2485d8a7SHans Petter Selasky 			if ((dev->config + i)->bConfigurationValue ==
717*2485d8a7SHans Petter Selasky 			    bConfigurationValue) {
718*2485d8a7SHans Petter Selasky 				break;
719*2485d8a7SHans Petter Selasky 			}
720*2485d8a7SHans Petter Selasky 		}
721*2485d8a7SHans Petter Selasky 	}
722*2485d8a7SHans Petter Selasky 
723*2485d8a7SHans Petter Selasky 	err = libusb20_dev_set_config_index((void *)udev, i);
724*2485d8a7SHans Petter Selasky 
725*2485d8a7SHans Petter Selasky 	if (err)
726*2485d8a7SHans Petter Selasky 		return (-1);
727*2485d8a7SHans Petter Selasky 
728*2485d8a7SHans Petter Selasky 	return (0);
729*2485d8a7SHans Petter Selasky }
730*2485d8a7SHans Petter Selasky 
731*2485d8a7SHans Petter Selasky int
732*2485d8a7SHans Petter Selasky usb_claim_interface(usb_dev_handle * dev, int interface)
733*2485d8a7SHans Petter Selasky {
734*2485d8a7SHans Petter Selasky 	struct libusb20_device *pdev = (void *)dev;
735*2485d8a7SHans Petter Selasky 
736*2485d8a7SHans Petter Selasky 	pdev->claimed_interface = interface;
737*2485d8a7SHans Petter Selasky 
738*2485d8a7SHans Petter Selasky 	return (0);
739*2485d8a7SHans Petter Selasky }
740*2485d8a7SHans Petter Selasky 
741*2485d8a7SHans Petter Selasky int
742*2485d8a7SHans Petter Selasky usb_release_interface(usb_dev_handle * dev, int interface)
743*2485d8a7SHans Petter Selasky {
744*2485d8a7SHans Petter Selasky 	/* do nothing */
745*2485d8a7SHans Petter Selasky 	return (0);
746*2485d8a7SHans Petter Selasky }
747*2485d8a7SHans Petter Selasky 
748*2485d8a7SHans Petter Selasky int
749*2485d8a7SHans Petter Selasky usb_set_altinterface(usb_dev_handle * dev, int alternate)
750*2485d8a7SHans Petter Selasky {
751*2485d8a7SHans Petter Selasky 	struct libusb20_device *pdev = (void *)dev;
752*2485d8a7SHans Petter Selasky 	int err;
753*2485d8a7SHans Petter Selasky 	uint8_t iface;
754*2485d8a7SHans Petter Selasky 
755*2485d8a7SHans Petter Selasky 	iface = pdev->claimed_interface;
756*2485d8a7SHans Petter Selasky 
757*2485d8a7SHans Petter Selasky 	err = libusb20_dev_set_alt_index((void *)dev, iface, alternate);
758*2485d8a7SHans Petter Selasky 
759*2485d8a7SHans Petter Selasky 	if (err)
760*2485d8a7SHans Petter Selasky 		return (-1);
761*2485d8a7SHans Petter Selasky 
762*2485d8a7SHans Petter Selasky 	return (0);
763*2485d8a7SHans Petter Selasky }
764*2485d8a7SHans Petter Selasky 
765*2485d8a7SHans Petter Selasky int
766*2485d8a7SHans Petter Selasky usb_resetep(usb_dev_handle * dev, unsigned int ep)
767*2485d8a7SHans Petter Selasky {
768*2485d8a7SHans Petter Selasky 	/* emulate an endpoint reset through clear-STALL */
769*2485d8a7SHans Petter Selasky 	return (usb_clear_halt(dev, ep));
770*2485d8a7SHans Petter Selasky }
771*2485d8a7SHans Petter Selasky 
772*2485d8a7SHans Petter Selasky int
773*2485d8a7SHans Petter Selasky usb_clear_halt(usb_dev_handle * dev, unsigned int ep)
774*2485d8a7SHans Petter Selasky {
775*2485d8a7SHans Petter Selasky 	struct libusb20_transfer *xfer;
776*2485d8a7SHans Petter Selasky 
777*2485d8a7SHans Petter Selasky 	xfer = usb_get_transfer_by_ep_no(dev, ep);
778*2485d8a7SHans Petter Selasky 	if (xfer == NULL)
779*2485d8a7SHans Petter Selasky 		return (-1);
780*2485d8a7SHans Petter Selasky 
781*2485d8a7SHans Petter Selasky 	libusb20_tr_clear_stall_sync(xfer);
782*2485d8a7SHans Petter Selasky 
783*2485d8a7SHans Petter Selasky 	return (0);
784*2485d8a7SHans Petter Selasky }
785*2485d8a7SHans Petter Selasky 
786*2485d8a7SHans Petter Selasky int
787*2485d8a7SHans Petter Selasky usb_reset(usb_dev_handle * dev)
788*2485d8a7SHans Petter Selasky {
789*2485d8a7SHans Petter Selasky 	int err;
790*2485d8a7SHans Petter Selasky 
791*2485d8a7SHans Petter Selasky 	err = libusb20_dev_reset((void *)dev);
792*2485d8a7SHans Petter Selasky 
793*2485d8a7SHans Petter Selasky 	if (err)
794*2485d8a7SHans Petter Selasky 		return (-1);
795*2485d8a7SHans Petter Selasky 
796*2485d8a7SHans Petter Selasky 	/*
797*2485d8a7SHans Petter Selasky 	 * Be compatible with LibUSB from sourceforge and close the
798*2485d8a7SHans Petter Selasky 	 * handle after reset!
799*2485d8a7SHans Petter Selasky 	 */
800*2485d8a7SHans Petter Selasky 	return (usb_close(dev));
801*2485d8a7SHans Petter Selasky }
802*2485d8a7SHans Petter Selasky 
803*2485d8a7SHans Petter Selasky int
804*2485d8a7SHans Petter Selasky usb_check_connected(usb_dev_handle * dev)
805*2485d8a7SHans Petter Selasky {
806*2485d8a7SHans Petter Selasky 	int err;
807*2485d8a7SHans Petter Selasky 
808*2485d8a7SHans Petter Selasky 	err = libusb20_dev_check_connected((void *)dev);
809*2485d8a7SHans Petter Selasky 
810*2485d8a7SHans Petter Selasky 	if (err)
811*2485d8a7SHans Petter Selasky 		return (-1);
812*2485d8a7SHans Petter Selasky 
813*2485d8a7SHans Petter Selasky 	return (0);
814*2485d8a7SHans Petter Selasky }
815*2485d8a7SHans Petter Selasky 
816*2485d8a7SHans Petter Selasky const char *
817*2485d8a7SHans Petter Selasky usb_strerror(void)
818*2485d8a7SHans Petter Selasky {
819*2485d8a7SHans Petter Selasky 	/* TODO */
820*2485d8a7SHans Petter Selasky 	return ("Unknown error");
821*2485d8a7SHans Petter Selasky }
822*2485d8a7SHans Petter Selasky 
823*2485d8a7SHans Petter Selasky void
824*2485d8a7SHans Petter Selasky usb_init(void)
825*2485d8a7SHans Petter Selasky {
826*2485d8a7SHans Petter Selasky 	/* nothing to do */
827*2485d8a7SHans Petter Selasky 	return;
828*2485d8a7SHans Petter Selasky }
829*2485d8a7SHans Petter Selasky 
830*2485d8a7SHans Petter Selasky void
831*2485d8a7SHans Petter Selasky usb_set_debug(int level)
832*2485d8a7SHans Petter Selasky {
833*2485d8a7SHans Petter Selasky 	/* use kernel UGEN debugging if you need to see what is going on */
834*2485d8a7SHans Petter Selasky 	return;
835*2485d8a7SHans Petter Selasky }
836*2485d8a7SHans Petter Selasky 
837*2485d8a7SHans Petter Selasky int
838*2485d8a7SHans Petter Selasky usb_find_busses(void)
839*2485d8a7SHans Petter Selasky {
840*2485d8a7SHans Petter Selasky 	usb_busses = &usb_global_bus;
841*2485d8a7SHans Petter Selasky 	return (1);
842*2485d8a7SHans Petter Selasky }
843*2485d8a7SHans Petter Selasky 
844*2485d8a7SHans Petter Selasky int
845*2485d8a7SHans Petter Selasky usb_find_devices(void)
846*2485d8a7SHans Petter Selasky {
847*2485d8a7SHans Petter Selasky 	struct libusb20_device *pdev;
848*2485d8a7SHans Petter Selasky 	struct usb_device *udev;
849*2485d8a7SHans Petter Selasky 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
850*2485d8a7SHans Petter Selasky 	int devnum;
851*2485d8a7SHans Petter Selasky 	int err;
852*2485d8a7SHans Petter Selasky 
853*2485d8a7SHans Petter Selasky 	/* cleanup after last device search */
854*2485d8a7SHans Petter Selasky 	/* close all opened devices, if any */
855*2485d8a7SHans Petter Selasky 
856*2485d8a7SHans Petter Selasky 	while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
857*2485d8a7SHans Petter Selasky 		udev = pdev->privLuData;
858*2485d8a7SHans Petter Selasky 		libusb20_be_dequeue_device(usb_backend, pdev);
859*2485d8a7SHans Petter Selasky 		libusb20_dev_free(pdev);
860*2485d8a7SHans Petter Selasky 		if (udev != NULL) {
861*2485d8a7SHans Petter Selasky 			LIST_DEL(usb_global_bus.devices, udev);
862*2485d8a7SHans Petter Selasky 			free(udev);
863*2485d8a7SHans Petter Selasky 		}
864*2485d8a7SHans Petter Selasky 	}
865*2485d8a7SHans Petter Selasky 
866*2485d8a7SHans Petter Selasky 	/* free old USB backend, if any */
867*2485d8a7SHans Petter Selasky 
868*2485d8a7SHans Petter Selasky 	libusb20_be_free(usb_backend);
869*2485d8a7SHans Petter Selasky 
870*2485d8a7SHans Petter Selasky 	/* do a new backend device search */
871*2485d8a7SHans Petter Selasky 	usb_backend = libusb20_be_alloc_default();
872*2485d8a7SHans Petter Selasky 	if (usb_backend == NULL) {
873*2485d8a7SHans Petter Selasky 		return (-1);
874*2485d8a7SHans Petter Selasky 	}
875*2485d8a7SHans Petter Selasky 	/* iterate all devices */
876*2485d8a7SHans Petter Selasky 
877*2485d8a7SHans Petter Selasky 	devnum = 1;
878*2485d8a7SHans Petter Selasky 	pdev = NULL;
879*2485d8a7SHans Petter Selasky 	while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) {
880*2485d8a7SHans Petter Selasky 		udev = malloc(sizeof(*udev));
881*2485d8a7SHans Petter Selasky 		if (udev == NULL)
882*2485d8a7SHans Petter Selasky 			break;
883*2485d8a7SHans Petter Selasky 
884*2485d8a7SHans Petter Selasky 		memset(udev, 0, sizeof(*udev));
885*2485d8a7SHans Petter Selasky 
886*2485d8a7SHans Petter Selasky 		udev->bus = &usb_global_bus;
887*2485d8a7SHans Petter Selasky 
888*2485d8a7SHans Petter Selasky 		snprintf(udev->filename, sizeof(udev->filename),
889*2485d8a7SHans Petter Selasky 		    "/dev/ugen%u.%u",
890*2485d8a7SHans Petter Selasky 		    libusb20_dev_get_bus_number(pdev),
891*2485d8a7SHans Petter Selasky 		    libusb20_dev_get_address(pdev));
892*2485d8a7SHans Petter Selasky 
893*2485d8a7SHans Petter Selasky 		ddesc = libusb20_dev_get_device_desc(pdev);
894*2485d8a7SHans Petter Selasky 
895*2485d8a7SHans Petter Selasky 		udev->descriptor.bLength = sizeof(udev->descriptor);
896*2485d8a7SHans Petter Selasky 		udev->descriptor.bDescriptorType = ddesc->bDescriptorType;
897*2485d8a7SHans Petter Selasky 		udev->descriptor.bcdUSB = ddesc->bcdUSB;
898*2485d8a7SHans Petter Selasky 		udev->descriptor.bDeviceClass = ddesc->bDeviceClass;
899*2485d8a7SHans Petter Selasky 		udev->descriptor.bDeviceSubClass = ddesc->bDeviceSubClass;
900*2485d8a7SHans Petter Selasky 		udev->descriptor.bDeviceProtocol = ddesc->bDeviceProtocol;
901*2485d8a7SHans Petter Selasky 		udev->descriptor.bMaxPacketSize0 = ddesc->bMaxPacketSize0;
902*2485d8a7SHans Petter Selasky 		udev->descriptor.idVendor = ddesc->idVendor;
903*2485d8a7SHans Petter Selasky 		udev->descriptor.idProduct = ddesc->idProduct;
904*2485d8a7SHans Petter Selasky 		udev->descriptor.bcdDevice = ddesc->bcdDevice;
905*2485d8a7SHans Petter Selasky 		udev->descriptor.iManufacturer = ddesc->iManufacturer;
906*2485d8a7SHans Petter Selasky 		udev->descriptor.iProduct = ddesc->iProduct;
907*2485d8a7SHans Petter Selasky 		udev->descriptor.iSerialNumber = ddesc->iSerialNumber;
908*2485d8a7SHans Petter Selasky 		udev->descriptor.bNumConfigurations =
909*2485d8a7SHans Petter Selasky 		    ddesc->bNumConfigurations;
910*2485d8a7SHans Petter Selasky 		if (udev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
911*2485d8a7SHans Petter Selasky 			/* truncate number of configurations */
912*2485d8a7SHans Petter Selasky 			udev->descriptor.bNumConfigurations = USB_MAXCONFIG;
913*2485d8a7SHans Petter Selasky 		}
914*2485d8a7SHans Petter Selasky 		udev->devnum = devnum++;
915*2485d8a7SHans Petter Selasky 		/* link together the two structures */
916*2485d8a7SHans Petter Selasky 		udev->dev = pdev;
917*2485d8a7SHans Petter Selasky 		pdev->privLuData = udev;
918*2485d8a7SHans Petter Selasky 
919*2485d8a7SHans Petter Selasky 		err = libusb20_dev_open(pdev, 0);
920*2485d8a7SHans Petter Selasky 		if (err == 0) {
921*2485d8a7SHans Petter Selasky 			/* XXX get all config descriptors by default */
922*2485d8a7SHans Petter Selasky 			usb_fetch_and_parse_descriptors((void *)pdev);
923*2485d8a7SHans Petter Selasky 			libusb20_dev_close(pdev);
924*2485d8a7SHans Petter Selasky 		}
925*2485d8a7SHans Petter Selasky 		LIST_ADD(usb_global_bus.devices, udev);
926*2485d8a7SHans Petter Selasky 	}
927*2485d8a7SHans Petter Selasky 
928*2485d8a7SHans Petter Selasky 	return (devnum - 1);			/* success */
929*2485d8a7SHans Petter Selasky }
930*2485d8a7SHans Petter Selasky 
931*2485d8a7SHans Petter Selasky struct usb_device *
932*2485d8a7SHans Petter Selasky usb_device(usb_dev_handle * dev)
933*2485d8a7SHans Petter Selasky {
934*2485d8a7SHans Petter Selasky 	struct libusb20_device *pdev;
935*2485d8a7SHans Petter Selasky 
936*2485d8a7SHans Petter Selasky 	pdev = (void *)dev;
937*2485d8a7SHans Petter Selasky 
938*2485d8a7SHans Petter Selasky 	return (pdev->privLuData);
939*2485d8a7SHans Petter Selasky }
940*2485d8a7SHans Petter Selasky 
941*2485d8a7SHans Petter Selasky struct usb_bus *
942*2485d8a7SHans Petter Selasky usb_get_busses(void)
943*2485d8a7SHans Petter Selasky {
944*2485d8a7SHans Petter Selasky 	return (usb_busses);
945*2485d8a7SHans Petter Selasky }
946