libusb01.c revision 188678
1240330Smarcel/* $FreeBSD: head/lib/libusb20/libusb20_compat01.c 188678 2009-02-16 15:32:12Z thompsa $ */
2240330Smarcel/*-
3240330Smarcel * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4240330Smarcel *
5240330Smarcel * Redistribution and use in source and binary forms, with or without
6240330Smarcel * modification, are permitted provided that the following conditions
7240330Smarcel * are met:
8240330Smarcel * 1. Redistributions of source code must retain the above copyright
9240330Smarcel *    notice, this list of conditions and the following disclaimer.
10240330Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11240330Smarcel *    notice, this list of conditions and the following disclaimer in the
12240330Smarcel *    documentation and/or other materials provided with the distribution.
13240330Smarcel *
14240330Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15240330Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16240330Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17240330Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18240330Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240330Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20238152Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21238152Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22238152Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23238152Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24238152Sobrien * SUCH DAMAGE.
25238152Sobrien */
26238152Sobrien
27238152Sobrien/*
28238152Sobrien * This file contains the emulation layer for LibUSB v0.1 from sourceforge.
29238152Sobrien */
30238152Sobrien
31238152Sobrien#include <sys/queue.h>
32238152Sobrien
33238152Sobrien#include <stdlib.h>
34238152Sobrien#include <stdio.h>
35238152Sobrien#include <errno.h>
36237578Sobrien
37237578Sobrien#include "libusb20.h"
38237578Sobrien#include "libusb20_desc.h"
39237578Sobrien#include "libusb20_int.h"
40237578Sobrien#include "libusb20_compat01.h"
41237578Sobrien
42237578Sobrien/*
43237578Sobrien * The two following macros were taken from the original LibUSB v0.1
44237578Sobrien * for sake of compatibility:
45237578Sobrien */
46237578Sobrien#define	LIST_ADD(begin, ent)	   \
47237578Sobrien  do {				   \
48237578Sobrien    if (begin) {		   \
49237578Sobrien      ent->next = begin;	   \
50237578Sobrien      ent->next->prev = ent;	   \
51237578Sobrien    } else {			   \
52237578Sobrien      ent->next = NULL;		   \
53237578Sobrien    }				   \
54237578Sobrien    ent->prev = NULL;		   \
55237578Sobrien    begin = ent;		   \
56237578Sobrien  } while(0)
57236769Sobrien
58236769Sobrien#define	LIST_DEL(begin, ent)		 \
59236769Sobrien  do {					 \
60236769Sobrien    if (ent->prev) {			 \
61236769Sobrien      ent->prev->next = ent->next;	 \
62236769Sobrien    } else {				 \
63236769Sobrien      begin = ent->next;		 \
64236769Sobrien    }					 \
65236769Sobrien    if (ent->next) {			 \
66236769Sobrien      ent->next->prev = ent->prev;	 \
67236769Sobrien    }					 \
68236769Sobrien    ent->prev = NULL;			 \
69236769Sobrien    ent->next = NULL;			 \
70236769Sobrien  } while (0)
71236769Sobrien
72236769Sobrienstruct usb_bus *usb_busses = NULL;
73236769Sobrien
74236769Sobrienstatic struct usb_bus usb_global_bus = {
75236769Sobrien	.dirname = {"/dev/usb"},
76236769Sobrien	.root_dev = NULL,
77236769Sobrien	.devices = NULL,
78236769Sobrien};
79236769Sobrien
80236769Sobrienstatic struct libusb20_backend *usb_backend = NULL;
81236769Sobrien
82236769Sobrienstruct usb_parse_state {
83236769Sobrien
84236769Sobrien	struct {
85236769Sobrien		struct libusb20_endpoint *currep;
86236769Sobrien		struct libusb20_interface *currifc;
87236769Sobrien		struct libusb20_config *currcfg;
88236769Sobrien		struct libusb20_me_struct *currextra;
89236769Sobrien	}	a;
90236769Sobrien
91236769Sobrien	struct {
92236769Sobrien		struct usb_config_descriptor *currcfg;
93236769Sobrien		struct usb_interface_descriptor *currifc;
94236769Sobrien		struct usb_endpoint_descriptor *currep;
95236769Sobrien		struct usb_interface *currifcw;
96236769Sobrien		uint8_t *currextra;
97236769Sobrien	}	b;
98236769Sobrien
99236769Sobrien	uint8_t	preparse;
100236769Sobrien};
101236769Sobrien
102236769Sobrienstatic uint8_t
103236769Sobrienusb_get_first_claimed_interface(usb_dev_handle * dev)
104236769Sobrien{
105236769Sobrien	struct libusb20_device *pdev = (void *)dev;
106236769Sobrien	uint32_t x;
107236769Sobrien	uint8_t y;
108236769Sobrien
109236769Sobrien	x = pdev->claimed_interfaces;
110236769Sobrien
111236769Sobrien	for (y = 0; y != 32; y++) {
112236769Sobrien		if (x & (1 << y))
113236769Sobrien			break;
114236769Sobrien	}
115236769Sobrien
116236769Sobrien	if (y == 32)
117236769Sobrien		y = 0xFF;		/* dummy */
118236769Sobrien
119236769Sobrien	return (y);
120236769Sobrien}
121236769Sobrien
122236769Sobrienstatic struct libusb20_transfer *
123236769Sobrienusb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no)
124236769Sobrien{
125236769Sobrien	struct libusb20_device *pdev = (void *)dev;
126236769Sobrien	struct libusb20_transfer *xfer;
127236769Sobrien	int err;
128236769Sobrien	uint32_t bufsize;
129236769Sobrien	uint8_t x;
130236769Sobrien	uint8_t speed;
131236769Sobrien
132236769Sobrien	x = (ep_no & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 2;
133236769Sobrien
134236769Sobrien	if (ep_no & LIBUSB20_ENDPOINT_DIR_MASK) {
135236769Sobrien		/* this is an IN endpoint */
136236769Sobrien		x |= 1;
137236769Sobrien	}
138236769Sobrien	speed = libusb20_dev_get_speed(pdev);
139236769Sobrien
140236769Sobrien	/* select a sensible buffer size */
141236769Sobrien	if (speed == LIBUSB20_SPEED_LOW) {
142236769Sobrien		bufsize = 256;
143236769Sobrien	} else if (speed == LIBUSB20_SPEED_FULL) {
144236769Sobrien		bufsize = 4096;
145236769Sobrien	} else {
146236769Sobrien		bufsize = 16384;
147236769Sobrien	}
148236769Sobrien
149236769Sobrien	xfer = libusb20_tr_get_pointer(pdev, x);
150236769Sobrien
151236769Sobrien	if (xfer == NULL)
152236769Sobrien		return (xfer);
153236769Sobrien
154236769Sobrien	err = libusb20_tr_open(xfer, bufsize, 1, ep_no);
155236769Sobrien	if (err == LIBUSB20_ERROR_BUSY) {
156236769Sobrien		/* already opened */
157236769Sobrien		return (xfer);
158236769Sobrien	} else if (err) {
159236769Sobrien		return (NULL);
160236769Sobrien	}
161236769Sobrien	/* success */
162236769Sobrien	return (xfer);
163236769Sobrien}
164236769Sobrien
165236769Sobrienusb_dev_handle *
166236769Sobrienusb_open(struct usb_device *dev)
167236769Sobrien{
168236769Sobrien	int err;
169236769Sobrien
170236769Sobrien	err = libusb20_dev_open(dev->dev, 16 * 2);
171236769Sobrien	if (err == LIBUSB20_ERROR_BUSY) {
172236769Sobrien		/*
173236769Sobrien		 * Workaround buggy USB applications which open the USB
174236769Sobrien		 * device multiple times:
175236769Sobrien		 */
176236769Sobrien		return (dev->dev);
177236769Sobrien	}
178236769Sobrien	if (err)
179236769Sobrien		return (NULL);
180236769Sobrien
181236769Sobrien	/*
182236769Sobrien	 * Dequeue USB device from backend queue so that it does not get
183236769Sobrien	 * freed when the backend is re-scanned:
184236769Sobrien	 */
185236769Sobrien	libusb20_be_dequeue_device(usb_backend, dev->dev);
186236769Sobrien
187236769Sobrien	return (dev->dev);
188236769Sobrien}
189236769Sobrien
190236769Sobrienint
191236769Sobrienusb_close(usb_dev_handle * udev)
192236769Sobrien{
193236769Sobrien	struct usb_device *dev;
194236769Sobrien	int err;
195236769Sobrien
196236769Sobrien	err = libusb20_dev_close((void *)udev);
197236769Sobrien
198236769Sobrien	if (err)
199236769Sobrien		return (-1);
200236769Sobrien
201236769Sobrien	if (usb_backend != NULL) {
202236769Sobrien		/*
203236769Sobrien		 * Enqueue USB device to backend queue so that it gets freed
204236769Sobrien		 * when the backend is re-scanned:
205236769Sobrien		 */
206236769Sobrien		libusb20_be_enqueue_device(usb_backend, (void *)udev);
207236769Sobrien	} else {
208236769Sobrien		/*
209236769Sobrien		 * The backend is gone. Free device data so that we
210236769Sobrien		 * don't start leaking memory!
211236769Sobrien		 */
212236769Sobrien		dev = usb_device(udev);
213236769Sobrien		libusb20_dev_free((void *)udev);
214236769Sobrien		LIST_DEL(usb_global_bus.devices, dev);
215236769Sobrien		free(dev);
216236769Sobrien	}
217236769Sobrien	return (0);
218236769Sobrien}
219236769Sobrien
220236769Sobrienint
221236769Sobrienusb_get_string(usb_dev_handle * dev, int strindex,
222236769Sobrien    int langid, char *buf, size_t buflen)
223236769Sobrien{
224236769Sobrien	int err;
225236769Sobrien
226236769Sobrien	err = libusb20_dev_req_string_sync((void *)dev,
227236769Sobrien	    strindex, langid, buf, buflen);
228236769Sobrien
229236769Sobrien	if (err)
230236769Sobrien		return (-1);
231236769Sobrien
232236769Sobrien	return (0);
233236769Sobrien}
234236769Sobrien
235236769Sobrienint
236236769Sobrienusb_get_string_simple(usb_dev_handle * dev, int strindex,
237236769Sobrien    char *buf, size_t buflen)
238236769Sobrien{
239236769Sobrien	int err;
240236769Sobrien
241236769Sobrien	err = libusb20_dev_req_string_simple_sync((void *)dev,
242236769Sobrien	    strindex, buf, buflen);
243236769Sobrien
244236769Sobrien	if (err)
245236769Sobrien		return (-1);
246236769Sobrien
247236769Sobrien	return (strlen(buf));
248236769Sobrien}
249236769Sobrien
250236769Sobrienint
251236769Sobrienusb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type,
252236769Sobrien    uint8_t ep_index, void *buf, int size)
253236769Sobrien{
254236769Sobrien	memset(buf, 0, size);
255236769Sobrien
256236769Sobrien	return (usb_control_msg(udev, ep | USB_ENDPOINT_IN,
257236769Sobrien	    USB_REQ_GET_DESCRIPTOR, (type << 8) + ep_index, 0,
258236769Sobrien	    buf, size, 1000));
259236769Sobrien}
260236769Sobrien
261236769Sobrienint
262236769Sobrienusb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t desc_index,
263236769Sobrien    void *buf, int size)
264236769Sobrien{
265236769Sobrien	memset(buf, 0, size);
266236769Sobrien
267236769Sobrien	return (usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
268236769Sobrien	    (type << 8) + desc_index, 0, buf, size, 1000));
269236769Sobrien}
270236769Sobrien
271236769Sobrienint
272236769Sobrienusb_parse_descriptor(uint8_t *source, char *description, void *dest)
273236769Sobrien{
274236769Sobrien	uint8_t *sp = source;
275236769Sobrien	uint8_t *dp = dest;
276236769Sobrien	uint16_t w;
277236769Sobrien	uint32_t d;
278236769Sobrien	char *cp;
279236769Sobrien
280236769Sobrien	for (cp = description; *cp; cp++) {
281236769Sobrien		switch (*cp) {
282236769Sobrien		case 'b':		/* 8-bit byte */
283236769Sobrien			*dp++ = *sp++;
284236769Sobrien			break;
285236769Sobrien			/*
286236769Sobrien			 * 16-bit word, convert from little endian to CPU
287236769Sobrien			 */
288236769Sobrien		case 'w':
289236769Sobrien			w = (sp[1] << 8) | sp[0];
290236769Sobrien			sp += 2;
291236769Sobrien			/* Align to word boundary */
292236769Sobrien			dp += ((dp - (uint8_t *)0) & 1);
293236769Sobrien			*((uint16_t *)dp) = w;
294236769Sobrien			dp += 2;
295236769Sobrien			break;
296236769Sobrien			/*
297236769Sobrien			 * 32-bit dword, convert from little endian to CPU
298236769Sobrien			 */
299236769Sobrien		case 'd':
300236769Sobrien			d = (sp[3] << 24) | (sp[2] << 16) |
301236769Sobrien			    (sp[1] << 8) | sp[0];
302236769Sobrien			sp += 4;
303236769Sobrien			/* Align to word boundary */
304236769Sobrien			dp += ((dp - (uint8_t *)0) & 1);
305236769Sobrien			/* Align to double word boundary */
306236769Sobrien			dp += ((dp - (uint8_t *)0) & 2);
307236769Sobrien			*((uint32_t *)dp) = d;
308236769Sobrien			dp += 4;
309236769Sobrien			break;
310236769Sobrien		}
311236769Sobrien	}
312236769Sobrien	return (sp - source);
313236769Sobrien}
314236769Sobrien
315236769Sobrienstatic void
316236769Sobrienusb_parse_extra(struct usb_parse_state *ps, uint8_t **pptr, int *plen)
317236769Sobrien{
318236769Sobrien	void *ptr;
319236769Sobrien	uint16_t len;
320236769Sobrien
321236769Sobrien	ptr = ps->a.currextra->ptr;
322236769Sobrien	len = ps->a.currextra->len;
323236769Sobrien
324236769Sobrien	if (ps->preparse == 0) {
325236769Sobrien		memcpy(ps->b.currextra, ptr, len);
326236769Sobrien		*pptr = ps->b.currextra;
327236769Sobrien		*plen = len;
328236769Sobrien	}
329236769Sobrien	ps->b.currextra += len;
330236769Sobrien	return;
331236769Sobrien}
332236769Sobrien
333236769Sobrienstatic void
334236769Sobrienusb_parse_endpoint(struct usb_parse_state *ps)
335236769Sobrien{
336236769Sobrien	struct usb_endpoint_descriptor *bep;
337236769Sobrien	struct libusb20_endpoint *aep;
338236769Sobrien
339236769Sobrien	aep = ps->a.currep;
340236769Sobrien	bep = ps->b.currep++;
341236769Sobrien
342236769Sobrien	if (ps->preparse == 0) {
343236769Sobrien		/* copy descriptor fields */
344236769Sobrien		bep->bLength = aep->desc.bLength;
345236769Sobrien		bep->bDescriptorType = aep->desc.bDescriptorType;
346236769Sobrien		bep->bEndpointAddress = aep->desc.bEndpointAddress;
347236769Sobrien		bep->bmAttributes = aep->desc.bmAttributes;
348236769Sobrien		bep->wMaxPacketSize = aep->desc.wMaxPacketSize;
349236769Sobrien		bep->bInterval = aep->desc.bInterval;
350236769Sobrien		bep->bRefresh = aep->desc.bRefresh;
351236769Sobrien		bep->bSynchAddress = aep->desc.bSynchAddress;
352236769Sobrien	}
353236769Sobrien	ps->a.currextra = &aep->extra;
354236769Sobrien	usb_parse_extra(ps, &bep->extra, &bep->extralen);
355236769Sobrien	return;
356236769Sobrien}
357236769Sobrien
358236769Sobrienstatic void
359236769Sobrienusb_parse_iface_sub(struct usb_parse_state *ps)
360236769Sobrien{
361236769Sobrien	struct libusb20_interface *aifc;
362236769Sobrien	struct usb_interface_descriptor *bifc;
363236769Sobrien	uint8_t x;
364236769Sobrien
365236769Sobrien	aifc = ps->a.currifc;
366236769Sobrien	bifc = ps->b.currifc++;
367236769Sobrien
368236769Sobrien	if (ps->preparse == 0) {
369236769Sobrien		/* copy descriptor fields */
370236769Sobrien		bifc->bLength = aifc->desc.bLength;
371236769Sobrien		bifc->bDescriptorType = aifc->desc.bDescriptorType;
372236769Sobrien		bifc->bInterfaceNumber = aifc->desc.bInterfaceNumber;
373236769Sobrien		bifc->bAlternateSetting = aifc->desc.bAlternateSetting;
374236769Sobrien		bifc->bNumEndpoints = aifc->num_endpoints;
375236769Sobrien		bifc->bInterfaceClass = aifc->desc.bInterfaceClass;
376236769Sobrien		bifc->bInterfaceSubClass = aifc->desc.bInterfaceSubClass;
377236769Sobrien		bifc->bInterfaceProtocol = aifc->desc.bInterfaceProtocol;
378236769Sobrien		bifc->iInterface = aifc->desc.iInterface;
379236769Sobrien		bifc->endpoint = ps->b.currep;
380236769Sobrien	}
381236769Sobrien	for (x = 0; x != aifc->num_endpoints; x++) {
382236769Sobrien		ps->a.currep = aifc->endpoints + x;
383236769Sobrien		usb_parse_endpoint(ps);
384236769Sobrien	}
385236769Sobrien
386236769Sobrien	ps->a.currextra = &aifc->extra;
387236769Sobrien	usb_parse_extra(ps, &bifc->extra, &bifc->extralen);
388236769Sobrien	return;
389236769Sobrien}
390236769Sobrien
391236769Sobrienstatic void
392236769Sobrienusb_parse_iface(struct usb_parse_state *ps)
393236769Sobrien{
394236769Sobrien	struct libusb20_interface *aifc;
395236769Sobrien	struct usb_interface *bifc;
396236769Sobrien	uint8_t x;
397236769Sobrien
398236769Sobrien	aifc = ps->a.currifc;
399236769Sobrien	bifc = ps->b.currifcw++;
400236769Sobrien
401236769Sobrien	if (ps->preparse == 0) {
402236769Sobrien		/* initialise interface wrapper */
403236769Sobrien		bifc->altsetting = ps->b.currifc;
404236769Sobrien		bifc->num_altsetting = aifc->num_altsetting + 1;
405236769Sobrien	}
406236769Sobrien	usb_parse_iface_sub(ps);
407236769Sobrien
408236769Sobrien	for (x = 0; x != aifc->num_altsetting; x++) {
409236769Sobrien		ps->a.currifc = aifc->altsetting + x;
410236769Sobrien		usb_parse_iface_sub(ps);
411236769Sobrien	}
412236769Sobrien	return;
413236769Sobrien}
414236769Sobrien
415236769Sobrienstatic void
416236769Sobrienusb_parse_config(struct usb_parse_state *ps)
417236769Sobrien{
418236769Sobrien	struct libusb20_config *acfg;
419236769Sobrien	struct usb_config_descriptor *bcfg;
420236769Sobrien	uint8_t x;
421236769Sobrien
422236769Sobrien	acfg = ps->a.currcfg;
423236769Sobrien	bcfg = ps->b.currcfg;
424236769Sobrien
425236769Sobrien	if (ps->preparse == 0) {
426236769Sobrien		/* initialise config wrapper */
427236769Sobrien		bcfg->bLength = acfg->desc.bLength;
428236769Sobrien		bcfg->bDescriptorType = acfg->desc.bDescriptorType;
429236769Sobrien		bcfg->wTotalLength = acfg->desc.wTotalLength;
430236769Sobrien		bcfg->bNumInterfaces = acfg->num_interface;
431236769Sobrien		bcfg->bConfigurationValue = acfg->desc.bConfigurationValue;
432236769Sobrien		bcfg->iConfiguration = acfg->desc.iConfiguration;
433236769Sobrien		bcfg->bmAttributes = acfg->desc.bmAttributes;
434236769Sobrien		bcfg->MaxPower = acfg->desc.bMaxPower;
435236769Sobrien		bcfg->interface = ps->b.currifcw;
436236769Sobrien	}
437236769Sobrien	for (x = 0; x != acfg->num_interface; x++) {
438236769Sobrien		ps->a.currifc = acfg->interface + x;
439236769Sobrien		usb_parse_iface(ps);
440236769Sobrien	}
441236769Sobrien
442236769Sobrien	ps->a.currextra = &acfg->extra;
443236769Sobrien	usb_parse_extra(ps, &bcfg->extra, &bcfg->extralen);
444236769Sobrien	return;
445236769Sobrien}
446236769Sobrien
447236769Sobrienint
448236769Sobrienusb_parse_configuration(struct usb_config_descriptor *config,
449236769Sobrien    uint8_t *buffer)
450236769Sobrien{
451236769Sobrien	struct usb_parse_state ps;
452236769Sobrien	uint8_t *ptr;
453236769Sobrien	uint32_t a;
454236769Sobrien	uint32_t b;
455236769Sobrien	uint32_t c;
456236769Sobrien	uint32_t d;
457236769Sobrien
458236769Sobrien	if ((buffer == NULL) || (config == NULL)) {
459236769Sobrien		return (-1);
460236769Sobrien	}
461236769Sobrien	memset(&ps, 0, sizeof(ps));
462236769Sobrien
463236769Sobrien	ps.a.currcfg = libusb20_parse_config_desc(buffer);
464236769Sobrien	ps.b.currcfg = config;
465236769Sobrien	if (ps.a.currcfg == NULL) {
466236769Sobrien		/* could not parse config or out of memory */
467236769Sobrien		return (-1);
468236769Sobrien	}
469236769Sobrien	/* do the pre-parse */
470236769Sobrien	ps.preparse = 1;
471236769Sobrien	usb_parse_config(&ps);
472236769Sobrien
473236769Sobrien	a = ((uint8_t *)(ps.b.currifcw) - ((uint8_t *)0));
474236769Sobrien	b = ((uint8_t *)(ps.b.currifc) - ((uint8_t *)0));
475236769Sobrien	c = ((uint8_t *)(ps.b.currep) - ((uint8_t *)0));
476236769Sobrien	d = ((uint8_t *)(ps.b.currextra) - ((uint8_t *)0));
477236769Sobrien
478236769Sobrien	/* allocate memory for our configuration */
479236769Sobrien	ptr = malloc(a + b + c + d);
480236769Sobrien
481236769Sobrien	/* "currifcw" must be first, hence this pointer is freed */
482236769Sobrien	ps.b.currifcw = (void *)(ptr);
483236769Sobrien	ps.b.currifc = (void *)(ptr + a);
484236769Sobrien	ps.b.currep = (void *)(ptr + a + b);
485236769Sobrien	ps.b.currextra = (void *)(ptr + a + b + c);
486236769Sobrien
487236769Sobrien	/* generate a libusb v0.1 compatible structure */
488236769Sobrien	ps.preparse = 0;
489236769Sobrien	usb_parse_config(&ps);
490236769Sobrien
491236769Sobrien	/* free config structure */
492236769Sobrien	free(ps.a.currcfg);
493236769Sobrien
494236769Sobrien	return (0);			/* success */
495236769Sobrien}
496236769Sobrien
497236769Sobrienvoid
498236769Sobrienusb_destroy_configuration(struct usb_device *dev)
499236769Sobrien{
500236769Sobrien	uint8_t c;
501236769Sobrien
502236769Sobrien	if (dev->config == NULL) {
503236769Sobrien		return;
504236769Sobrien	}
505236769Sobrien	for (c = 0; c != dev->descriptor.bNumConfigurations; c++) {
506236769Sobrien		struct usb_config_descriptor *cf = &dev->config[c];
507236769Sobrien
508236769Sobrien		if (cf->interface != NULL) {
509236769Sobrien			free(cf->interface);
510236769Sobrien			cf->interface = NULL;
511236769Sobrien		}
512236769Sobrien	}
513236769Sobrien
514236769Sobrien	free(dev->config);
515236769Sobrien	dev->config = NULL;
516236769Sobrien	return;
517236769Sobrien}
518236769Sobrien
519236769Sobrienvoid
520236769Sobrienusb_fetch_and_parse_descriptors(usb_dev_handle * udev)
521236769Sobrien{
522236769Sobrien	struct usb_device *dev;
523236769Sobrien	struct libusb20_device *pdev;
524236769Sobrien	uint8_t *ptr;
525236769Sobrien	int error;
526236769Sobrien	uint32_t size;
527236769Sobrien	uint16_t len;
528236769Sobrien	uint8_t x;
529236769Sobrien
530236769Sobrien	if (udev == NULL) {
531236769Sobrien		/* be NULL safe */
532236769Sobrien		return;
533236769Sobrien	}
534236769Sobrien	dev = usb_device(udev);
535236769Sobrien	pdev = (void *)udev;
536236769Sobrien
537236769Sobrien	if (dev->descriptor.bNumConfigurations == 0) {
538236769Sobrien		/* invalid device */
539236769Sobrien		return;
540236769Sobrien	}
541236769Sobrien	size = dev->descriptor.bNumConfigurations *
542236769Sobrien	    sizeof(struct usb_config_descriptor);
543236769Sobrien
544236769Sobrien	dev->config = malloc(size);
545236769Sobrien	if (dev->config == NULL) {
546236769Sobrien		/* out of memory */
547236769Sobrien		return;
548236769Sobrien	}
549236769Sobrien	memset(dev->config, 0, size);
550236769Sobrien
551236769Sobrien	for (x = 0; x != dev->descriptor.bNumConfigurations; x++) {
552236769Sobrien
553236769Sobrien		error = (pdev->methods->get_config_desc_full) (
554236769Sobrien		    pdev, &ptr, &len, x);
555236769Sobrien
556236769Sobrien		if (error) {
557236769Sobrien			usb_destroy_configuration(dev);
558236769Sobrien			return;
559236769Sobrien		}
560236769Sobrien		usb_parse_configuration(dev->config + x, ptr);
561236769Sobrien
562236769Sobrien		/* free config buffer */
563236769Sobrien		free(ptr);
564236769Sobrien	}
565236769Sobrien	return;
566236769Sobrien}
567236769Sobrien
568236769Sobrienstatic int
569236769Sobrienusb_std_io(usb_dev_handle * dev, int ep, char *bytes, int size,
570236769Sobrien    int timeout, int is_intr)
571236769Sobrien{
572236769Sobrien	struct libusb20_transfer *xfer;
573236769Sobrien	uint32_t temp;
574236769Sobrien	uint32_t maxsize;
575236769Sobrien	uint32_t actlen;
576236769Sobrien	char *oldbytes;
577236769Sobrien
578236769Sobrien	xfer = usb_get_transfer_by_ep_no(dev, ep);
579236769Sobrien	if (xfer == NULL)
580236769Sobrien		return (-1);
581236769Sobrien
582236769Sobrien	if (libusb20_tr_pending(xfer)) {
583236769Sobrien		/* there is already a transfer ongoing */
584236769Sobrien		return (-1);
585236769Sobrien	}
586236769Sobrien	maxsize = libusb20_tr_get_max_total_length(xfer);
587236769Sobrien	oldbytes = bytes;
588236769Sobrien
589236769Sobrien	/*
590236769Sobrien	 * We allow transferring zero bytes which is the same
591236769Sobrien	 * equivalent to a zero length USB packet.
592236769Sobrien	 */
593236769Sobrien	do {
594236769Sobrien
595236769Sobrien		temp = size;
596236769Sobrien		if (temp > maxsize) {
597236769Sobrien			/* find maximum possible length */
598236769Sobrien			temp = maxsize;
599236769Sobrien		}
600236769Sobrien		if (is_intr)
601236769Sobrien			libusb20_tr_setup_intr(xfer, bytes, temp, timeout);
602236769Sobrien		else
603236769Sobrien			libusb20_tr_setup_bulk(xfer, bytes, temp, timeout);
604236769Sobrien
605236769Sobrien		libusb20_tr_start(xfer);
606236769Sobrien
607236769Sobrien		while (1) {
608236769Sobrien
609236769Sobrien			if (libusb20_dev_process((void *)dev) != 0) {
610236769Sobrien				/* device detached */
611236769Sobrien				return (-1);
612236769Sobrien			}
613236769Sobrien			if (libusb20_tr_pending(xfer) == 0) {
614236769Sobrien				/* transfer complete */
615236769Sobrien				break;
616236769Sobrien			}
617236769Sobrien			/* wait for USB event from kernel */
618236769Sobrien			libusb20_dev_wait_process((void *)dev, -1);
619236769Sobrien		}
620236769Sobrien
621236769Sobrien		switch (libusb20_tr_get_status(xfer)) {
622236769Sobrien		case 0:
623236769Sobrien			/* success */
624236769Sobrien			break;
625236769Sobrien		case LIBUSB20_TRANSFER_TIMED_OUT:
626236769Sobrien			/* transfer timeout */
627236769Sobrien			return (-ETIMEDOUT);
628236769Sobrien		default:
629236769Sobrien			/* other transfer error */
630236769Sobrien			return (-ENXIO);
631236769Sobrien		}
632236769Sobrien		actlen = libusb20_tr_get_actual_length(xfer);
633236769Sobrien
634236769Sobrien		bytes += actlen;
635236769Sobrien		size -= actlen;
636236769Sobrien
637236769Sobrien		if (actlen != temp) {
638236769Sobrien			/* short transfer */
639236769Sobrien			break;
640236769Sobrien		}
641236769Sobrien	} while (size > 0);
642236769Sobrien
643236769Sobrien	return (bytes - oldbytes);
644236769Sobrien}
645236769Sobrien
646236769Sobrienint
647236769Sobrienusb_bulk_write(usb_dev_handle * dev, int ep, char *bytes,
648236769Sobrien    int size, int timeout)
649236769Sobrien{
650236769Sobrien	return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK,
651236769Sobrien	    bytes, size, timeout, 0));
652236769Sobrien}
653236769Sobrien
654236769Sobrienint
655236769Sobrienusb_bulk_read(usb_dev_handle * dev, int ep, char *bytes,
656236769Sobrien    int size, int timeout)
657236769Sobrien{
658236769Sobrien	return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK,
659236769Sobrien	    bytes, size, timeout, 0));
660236769Sobrien}
661236769Sobrien
662236769Sobrienint
663236769Sobrienusb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes,
664236769Sobrien    int size, int timeout)
665236769Sobrien{
666236769Sobrien	return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK,
667236769Sobrien	    bytes, size, timeout, 1));
668236769Sobrien}
669236769Sobrien
670236769Sobrienint
671236769Sobrienusb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes,
672236769Sobrien    int size, int timeout)
673236769Sobrien{
674236769Sobrien	return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK,
675236769Sobrien	    bytes, size, timeout, 1));
676236769Sobrien}
677236769Sobrien
678236769Sobrienint
679236769Sobrienusb_control_msg(usb_dev_handle * dev, int requesttype, int request,
680236769Sobrien    int value, int wIndex, char *bytes, int size, int timeout)
681236769Sobrien{
682236769Sobrien	struct LIBUSB20_CONTROL_SETUP_DECODED req;
683236769Sobrien	int err;
684236769Sobrien	uint16_t actlen;
685236769Sobrien
686236769Sobrien	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
687236769Sobrien
688236769Sobrien	req.bmRequestType = requesttype;
689236769Sobrien	req.bRequest = request;
690236769Sobrien	req.wValue = value;
691236769Sobrien	req.wIndex = wIndex;
692236769Sobrien	req.wLength = size;
693236769Sobrien
694236769Sobrien	err = libusb20_dev_request_sync((void *)dev, &req, bytes,
695236769Sobrien	    &actlen, timeout, 0);
696236769Sobrien
697236769Sobrien	if (err)
698236769Sobrien		return (-1);
699236769Sobrien
700236769Sobrien	return (actlen);
701236769Sobrien}
702236769Sobrien
703236769Sobrienint
704236769Sobrienusb_set_configuration(usb_dev_handle * udev, int bConfigurationValue)
705236769Sobrien{
706236769Sobrien	struct usb_device *dev;
707236769Sobrien	int err;
708236769Sobrien	uint8_t i;
709236769Sobrien
710236769Sobrien	/*
711236769Sobrien	 * Need to translate from "bConfigurationValue" to
712236769Sobrien	 * configuration index:
713236769Sobrien	 */
714236769Sobrien
715236769Sobrien	if (bConfigurationValue == 0) {
716236769Sobrien		/* unconfigure */
717236769Sobrien		i = 255;
718236769Sobrien	} else {
719236769Sobrien		/* lookup configuration index */
720236769Sobrien		dev = usb_device(udev);
721236769Sobrien
722236769Sobrien		/* check if the configuration array is not there */
723236769Sobrien		if (dev->config == NULL) {
724236769Sobrien			return (-1);
725236769Sobrien		}
726236769Sobrien		for (i = 0;; i++) {
727236769Sobrien			if (i == dev->descriptor.bNumConfigurations) {
728236769Sobrien				/* "bConfigurationValue" not found */
729236769Sobrien				return (-1);
730236769Sobrien			}
731236769Sobrien			if ((dev->config + i)->bConfigurationValue ==
732236769Sobrien			    bConfigurationValue) {
733236769Sobrien				break;
734236769Sobrien			}
735236769Sobrien		}
736236769Sobrien	}
737236769Sobrien
738236769Sobrien	err = libusb20_dev_set_config_index((void *)udev, i);
739236769Sobrien
740236769Sobrien	if (err)
741236769Sobrien		return (-1);
742236769Sobrien
743236769Sobrien	return (0);
744236769Sobrien}
745236769Sobrien
746236769Sobrienint
747236769Sobrienusb_claim_interface(usb_dev_handle * dev, int interface)
748236769Sobrien{
749236769Sobrien	int err;
750236769Sobrien
751236769Sobrien	err = libusb20_dev_claim_interface((void *)dev, interface);
752236769Sobrien
753236769Sobrien	if (err)
754236769Sobrien		return (-1);
755236769Sobrien
756236769Sobrien	return (0);
757236769Sobrien}
758236769Sobrien
759236769Sobrienint
760236769Sobrienusb_release_interface(usb_dev_handle * dev, int interface)
761236769Sobrien{
762236769Sobrien	int err;
763236769Sobrien
764236769Sobrien	err = libusb20_dev_release_interface((void *)dev, interface);
765236769Sobrien
766236769Sobrien	if (err)
767236769Sobrien		return (-1);
768236769Sobrien
769236769Sobrien	return (0);
770236769Sobrien}
771236769Sobrien
772236769Sobrienint
773236769Sobrienusb_set_altinterface(usb_dev_handle * dev, int alternate)
774236769Sobrien{
775236769Sobrien	int err;
776236769Sobrien	uint8_t iface;
777236769Sobrien
778236769Sobrien	iface = usb_get_first_claimed_interface(dev);
779236769Sobrien
780236769Sobrien	err = libusb20_dev_set_alt_index((void *)dev, iface, alternate);
781236769Sobrien
782236769Sobrien	if (err)
783236769Sobrien		return (-1);
784236769Sobrien
785236769Sobrien	return (0);
786236769Sobrien}
787236769Sobrien
788236769Sobrienint
789236769Sobrienusb_resetep(usb_dev_handle * dev, unsigned int ep)
790236769Sobrien{
791236769Sobrien	/* emulate an endpoint reset through clear-STALL */
792236769Sobrien	return (usb_clear_halt(dev, ep));
793236769Sobrien}
794236769Sobrien
795236769Sobrienint
796236769Sobrienusb_clear_halt(usb_dev_handle * dev, unsigned int ep)
797236769Sobrien{
798236769Sobrien	struct libusb20_transfer *xfer;
799236769Sobrien
800236769Sobrien	xfer = usb_get_transfer_by_ep_no(dev, ep);
801236769Sobrien	if (xfer == NULL)
802236769Sobrien		return (-1);
803236769Sobrien
804236769Sobrien	libusb20_tr_clear_stall_sync(xfer);
805236769Sobrien
806236769Sobrien	return (0);
807236769Sobrien}
808236769Sobrien
809236769Sobrienint
810236769Sobrienusb_reset(usb_dev_handle * dev)
811236769Sobrien{
812236769Sobrien	int err;
813236769Sobrien
814236769Sobrien	err = libusb20_dev_reset((void *)dev);
815236769Sobrien
816236769Sobrien	if (err)
817236769Sobrien		return (-1);
818236769Sobrien
819236769Sobrien	return (0);
820236769Sobrien}
821236769Sobrien
822236769Sobrienconst char *
823236769Sobrienusb_strerror(void)
824236769Sobrien{
825236769Sobrien	/* TODO */
826236769Sobrien	return ("Unknown error");
827236769Sobrien}
828236769Sobrien
829236769Sobrienvoid
830236769Sobrienusb_init(void)
831236769Sobrien{
832236769Sobrien	/* nothing to do */
833236769Sobrien	return;
834236769Sobrien}
835236769Sobrien
836236769Sobrienvoid
837236769Sobrienusb_set_debug(int level)
838236769Sobrien{
839236769Sobrien	/* use kernel UGEN debugging if you need to see what is going on */
840236769Sobrien	return;
841236769Sobrien}
842236769Sobrien
843236769Sobrienint
844236769Sobrienusb_find_busses(void)
845236769Sobrien{
846236769Sobrien	usb_busses = &usb_global_bus;
847236769Sobrien	return (0);
848236769Sobrien}
849236769Sobrien
850236769Sobrienint
851236769Sobrienusb_find_devices(void)
852236769Sobrien{
853236769Sobrien	struct libusb20_device *pdev;
854236769Sobrien	struct usb_device *udev;
855236769Sobrien	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
856236769Sobrien	int err;
857236769Sobrien
858236769Sobrien	/* cleanup after last device search */
859236769Sobrien	/* close all opened devices, if any */
860236769Sobrien
861236769Sobrien	while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
862236769Sobrien		udev = pdev->priv01Data;
863236769Sobrien		libusb20_be_dequeue_device(usb_backend, pdev);
864236769Sobrien		libusb20_dev_free(pdev);
865236769Sobrien		if (udev != NULL) {
866236769Sobrien			LIST_DEL(usb_global_bus.devices, udev);
867236769Sobrien			free(udev);
868236769Sobrien		}
869236769Sobrien	}
870236769Sobrien
871236769Sobrien	/* free old USB backend, if any */
872236769Sobrien
873236769Sobrien	libusb20_be_free(usb_backend);
874236769Sobrien
875236769Sobrien	/* do a new backend device search */
876236769Sobrien	usb_backend = libusb20_be_alloc_default();
877236769Sobrien	if (usb_backend == NULL) {
878236769Sobrien		return (-1);
879236769Sobrien	}
880236769Sobrien	/* iterate all devices */
881236769Sobrien
882236769Sobrien	pdev = NULL;
883236769Sobrien	while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) {
884236769Sobrien		udev = malloc(sizeof(*udev));
885236769Sobrien		if (udev == NULL)
886236769Sobrien			break;
887236769Sobrien
888236769Sobrien		memset(udev, 0, sizeof(*udev));
889236769Sobrien
890236769Sobrien		udev->bus = &usb_global_bus;
891236769Sobrien
892236769Sobrien		snprintf(udev->filename, sizeof(udev->filename),
893236769Sobrien		    "/dev/ugen%u.%u",
894236769Sobrien		    libusb20_dev_get_bus_number(pdev),
895236769Sobrien		    libusb20_dev_get_address(pdev));
896236769Sobrien
897236769Sobrien		ddesc = libusb20_dev_get_device_desc(pdev);
898236769Sobrien
899236769Sobrien		udev->descriptor.bLength = sizeof(udev->descriptor);
900236769Sobrien		udev->descriptor.bDescriptorType = ddesc->bDescriptorType;
901236769Sobrien		udev->descriptor.bcdUSB = ddesc->bcdUSB;
902236769Sobrien		udev->descriptor.bDeviceClass = ddesc->bDeviceClass;
903236769Sobrien		udev->descriptor.bDeviceSubClass = ddesc->bDeviceSubClass;
904236769Sobrien		udev->descriptor.bDeviceProtocol = ddesc->bDeviceProtocol;
905236769Sobrien		udev->descriptor.bMaxPacketSize0 = ddesc->bMaxPacketSize0;
906236769Sobrien		udev->descriptor.idVendor = ddesc->idVendor;
907236769Sobrien		udev->descriptor.idProduct = ddesc->idProduct;
908236769Sobrien		udev->descriptor.bcdDevice = ddesc->bcdDevice;
909236769Sobrien		udev->descriptor.iManufacturer = ddesc->iManufacturer;
910236769Sobrien		udev->descriptor.iProduct = ddesc->iProduct;
911236769Sobrien		udev->descriptor.iSerialNumber = ddesc->iSerialNumber;
912236769Sobrien		udev->descriptor.bNumConfigurations =
913236769Sobrien		    ddesc->bNumConfigurations;
914236769Sobrien		if (udev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
915236769Sobrien			/* truncate number of configurations */
916236769Sobrien			udev->descriptor.bNumConfigurations = USB_MAXCONFIG;
917236769Sobrien		}
918236769Sobrien		/* link together the two structures */
919236769Sobrien		udev->dev = pdev;
920236769Sobrien		pdev->priv01Data = udev;
921236769Sobrien
922236769Sobrien		err = libusb20_dev_open(pdev, 0);
923236769Sobrien		if (err == 0) {
924236769Sobrien			/* XXX get all config descriptors by default */
925236769Sobrien			usb_fetch_and_parse_descriptors((void *)pdev);
926236769Sobrien			libusb20_dev_close(pdev);
927236769Sobrien		}
928236769Sobrien		LIST_ADD(usb_global_bus.devices, udev);
929236769Sobrien	}
930236769Sobrien
931236769Sobrien	return (0);			/* success */
932236769Sobrien}
933236769Sobrien
934236769Sobrienstruct usb_device *
935236769Sobrienusb_device(usb_dev_handle * dev)
936236769Sobrien{
937236769Sobrien	struct libusb20_device *pdev;
938236769Sobrien
939236769Sobrien	pdev = (void *)dev;
940236769Sobrien
941236769Sobrien	return (pdev->priv01Data);
942236769Sobrien}
943236769Sobrien
944236769Sobrienstruct usb_bus *
945236769Sobrienusb_get_busses(void)
946236769Sobrien{
947236769Sobrien	return (usb_busses);
948236769Sobrien}
949236769Sobrien