xref: /dflybsd-src/lib/libusb/libusb01.c (revision c5739aa6cd45a7da955214b8d5766d51b21e5031)
1*c5739aa6SSascha Wildner /* $FreeBSD: head/lib/libusb/libusb01.c 264344 2014-04-11 14:11:55Z hselasky $ */
21d96047eSMarkus Pfeiffer /*-
31d96047eSMarkus Pfeiffer  * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
41d96047eSMarkus Pfeiffer  *
51d96047eSMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
61d96047eSMarkus Pfeiffer  * modification, are permitted provided that the following conditions
71d96047eSMarkus Pfeiffer  * are met:
81d96047eSMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
91d96047eSMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
101d96047eSMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
111d96047eSMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
121d96047eSMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
131d96047eSMarkus Pfeiffer  *
141d96047eSMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151d96047eSMarkus Pfeiffer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161d96047eSMarkus Pfeiffer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171d96047eSMarkus Pfeiffer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181d96047eSMarkus Pfeiffer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191d96047eSMarkus Pfeiffer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201d96047eSMarkus Pfeiffer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211d96047eSMarkus Pfeiffer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221d96047eSMarkus Pfeiffer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231d96047eSMarkus Pfeiffer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241d96047eSMarkus Pfeiffer  * SUCH DAMAGE.
251d96047eSMarkus Pfeiffer  */
261d96047eSMarkus Pfeiffer 
271d96047eSMarkus Pfeiffer /*
281d96047eSMarkus Pfeiffer  * This file contains the emulation layer for LibUSB v0.1 from sourceforge.
291d96047eSMarkus Pfeiffer  */
301d96047eSMarkus Pfeiffer 
319b0c1abeSSascha Wildner #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
329b0c1abeSSascha Wildner #include LIBUSB_GLOBAL_INCLUDE_FILE
339b0c1abeSSascha Wildner #else
341d96047eSMarkus Pfeiffer #include <errno.h>
351d96047eSMarkus Pfeiffer #include <stdio.h>
361d96047eSMarkus Pfeiffer #include <stdlib.h>
379b0c1abeSSascha Wildner #include <string.h>
389b0c1abeSSascha Wildner #include <time.h>
399b0c1abeSSascha Wildner #include <sys/queue.h>
409b0c1abeSSascha Wildner #endif
411d96047eSMarkus Pfeiffer 
421d96047eSMarkus Pfeiffer #include "libusb20.h"
431d96047eSMarkus Pfeiffer #include "libusb20_desc.h"
441d96047eSMarkus Pfeiffer #include "libusb20_int.h"
451d96047eSMarkus Pfeiffer #include "usb.h"
461d96047eSMarkus Pfeiffer 
471d96047eSMarkus Pfeiffer /*
481d96047eSMarkus Pfeiffer  * The two following macros were taken from the original LibUSB v0.1
491d96047eSMarkus Pfeiffer  * for sake of compatibility:
501d96047eSMarkus Pfeiffer  */
511d96047eSMarkus Pfeiffer #define	LIST_ADD(begin, ent)	   \
521d96047eSMarkus Pfeiffer   do {				   \
531d96047eSMarkus Pfeiffer     if (begin) {		   \
541d96047eSMarkus Pfeiffer       ent->next = begin;	   \
551d96047eSMarkus Pfeiffer       ent->next->prev = ent;	   \
561d96047eSMarkus Pfeiffer     } else {			   \
571d96047eSMarkus Pfeiffer       ent->next = NULL;		   \
581d96047eSMarkus Pfeiffer     }				   \
591d96047eSMarkus Pfeiffer     ent->prev = NULL;		   \
601d96047eSMarkus Pfeiffer     begin = ent;		   \
611d96047eSMarkus Pfeiffer   } while(0)
621d96047eSMarkus Pfeiffer 
631d96047eSMarkus Pfeiffer #define	LIST_DEL(begin, ent)		 \
641d96047eSMarkus Pfeiffer   do {					 \
651d96047eSMarkus Pfeiffer     if (ent->prev) {			 \
661d96047eSMarkus Pfeiffer       ent->prev->next = ent->next;	 \
671d96047eSMarkus Pfeiffer     } else {				 \
681d96047eSMarkus Pfeiffer       begin = ent->next;		 \
691d96047eSMarkus Pfeiffer     }					 \
701d96047eSMarkus Pfeiffer     if (ent->next) {			 \
711d96047eSMarkus Pfeiffer       ent->next->prev = ent->prev;	 \
721d96047eSMarkus Pfeiffer     }					 \
731d96047eSMarkus Pfeiffer     ent->prev = NULL;			 \
741d96047eSMarkus Pfeiffer     ent->next = NULL;			 \
751d96047eSMarkus Pfeiffer   } while (0)
761d96047eSMarkus Pfeiffer 
771d96047eSMarkus Pfeiffer struct usb_bus *usb_busses = NULL;
781d96047eSMarkus Pfeiffer 
791d96047eSMarkus Pfeiffer static struct usb_bus usb_global_bus = {
801d96047eSMarkus Pfeiffer 	.dirname = {"/dev/usb"},
811d96047eSMarkus Pfeiffer 	.root_dev = NULL,
821d96047eSMarkus Pfeiffer 	.devices = NULL,
831d96047eSMarkus Pfeiffer };
841d96047eSMarkus Pfeiffer 
851d96047eSMarkus Pfeiffer static struct libusb20_backend *usb_backend = NULL;
861d96047eSMarkus Pfeiffer 
871d96047eSMarkus Pfeiffer struct usb_parse_state {
881d96047eSMarkus Pfeiffer 
891d96047eSMarkus Pfeiffer 	struct {
901d96047eSMarkus Pfeiffer 		struct libusb20_endpoint *currep;
911d96047eSMarkus Pfeiffer 		struct libusb20_interface *currifc;
921d96047eSMarkus Pfeiffer 		struct libusb20_config *currcfg;
931d96047eSMarkus Pfeiffer 		struct libusb20_me_struct *currextra;
941d96047eSMarkus Pfeiffer 	}	a;
951d96047eSMarkus Pfeiffer 
961d96047eSMarkus Pfeiffer 	struct {
971d96047eSMarkus Pfeiffer 		struct usb_config_descriptor *currcfg;
981d96047eSMarkus Pfeiffer 		struct usb_interface_descriptor *currifc;
991d96047eSMarkus Pfeiffer 		struct usb_endpoint_descriptor *currep;
1001d96047eSMarkus Pfeiffer 		struct usb_interface *currifcw;
1011d96047eSMarkus Pfeiffer 		uint8_t *currextra;
1021d96047eSMarkus Pfeiffer 	}	b;
1031d96047eSMarkus Pfeiffer 
1041d96047eSMarkus Pfeiffer 	uint8_t	preparse;
1051d96047eSMarkus Pfeiffer };
1061d96047eSMarkus Pfeiffer 
1071d96047eSMarkus Pfeiffer static struct libusb20_transfer *
usb_get_transfer_by_ep_no(usb_dev_handle * dev,uint8_t ep_no)1081d96047eSMarkus Pfeiffer usb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no)
1091d96047eSMarkus Pfeiffer {
1101d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev = (void *)dev;
1111d96047eSMarkus Pfeiffer 	struct libusb20_transfer *xfer;
1121d96047eSMarkus Pfeiffer 	int err;
1131d96047eSMarkus Pfeiffer 	uint32_t bufsize;
1141d96047eSMarkus Pfeiffer 	uint8_t x;
1151d96047eSMarkus Pfeiffer 	uint8_t speed;
1161d96047eSMarkus Pfeiffer 
1171d96047eSMarkus Pfeiffer 	x = (ep_no & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 2;
1181d96047eSMarkus Pfeiffer 
1191d96047eSMarkus Pfeiffer 	if (ep_no & LIBUSB20_ENDPOINT_DIR_MASK) {
1201d96047eSMarkus Pfeiffer 		/* this is an IN endpoint */
1211d96047eSMarkus Pfeiffer 		x |= 1;
1221d96047eSMarkus Pfeiffer 	}
1231d96047eSMarkus Pfeiffer 	speed = libusb20_dev_get_speed(pdev);
1241d96047eSMarkus Pfeiffer 
1251d96047eSMarkus Pfeiffer 	/* select a sensible buffer size */
1261d96047eSMarkus Pfeiffer 	if (speed == LIBUSB20_SPEED_LOW) {
1271d96047eSMarkus Pfeiffer 		bufsize = 256;
1281d96047eSMarkus Pfeiffer 	} else if (speed == LIBUSB20_SPEED_FULL) {
1291d96047eSMarkus Pfeiffer 		bufsize = 4096;
130*c5739aa6SSascha Wildner 	} else if (speed == LIBUSB20_SPEED_SUPER) {
131*c5739aa6SSascha Wildner 		bufsize = 65536;
1321d96047eSMarkus Pfeiffer 	} else {
1331d96047eSMarkus Pfeiffer 		bufsize = 16384;
1341d96047eSMarkus Pfeiffer 	}
1351d96047eSMarkus Pfeiffer 
1361d96047eSMarkus Pfeiffer 	xfer = libusb20_tr_get_pointer(pdev, x);
1371d96047eSMarkus Pfeiffer 
1381d96047eSMarkus Pfeiffer 	if (xfer == NULL)
1391d96047eSMarkus Pfeiffer 		return (xfer);
1401d96047eSMarkus Pfeiffer 
1411d96047eSMarkus Pfeiffer 	err = libusb20_tr_open(xfer, bufsize, 1, ep_no);
1421d96047eSMarkus Pfeiffer 	if (err == LIBUSB20_ERROR_BUSY) {
1431d96047eSMarkus Pfeiffer 		/* already opened */
1441d96047eSMarkus Pfeiffer 		return (xfer);
1451d96047eSMarkus Pfeiffer 	} else if (err) {
1461d96047eSMarkus Pfeiffer 		return (NULL);
1471d96047eSMarkus Pfeiffer 	}
1481d96047eSMarkus Pfeiffer 	/* success */
1491d96047eSMarkus Pfeiffer 	return (xfer);
1501d96047eSMarkus Pfeiffer }
1511d96047eSMarkus Pfeiffer 
1521d96047eSMarkus Pfeiffer usb_dev_handle *
usb_open(struct usb_device * dev)1531d96047eSMarkus Pfeiffer usb_open(struct usb_device *dev)
1541d96047eSMarkus Pfeiffer {
1551d96047eSMarkus Pfeiffer 	int err;
1561d96047eSMarkus Pfeiffer 
1571d96047eSMarkus Pfeiffer 	err = libusb20_dev_open(dev->dev, 16 * 2);
1581d96047eSMarkus Pfeiffer 	if (err == LIBUSB20_ERROR_BUSY) {
1591d96047eSMarkus Pfeiffer 		/*
1601d96047eSMarkus Pfeiffer 		 * Workaround buggy USB applications which open the USB
1611d96047eSMarkus Pfeiffer 		 * device multiple times:
1621d96047eSMarkus Pfeiffer 		 */
1631d96047eSMarkus Pfeiffer 		return (dev->dev);
1641d96047eSMarkus Pfeiffer 	}
1651d96047eSMarkus Pfeiffer 	if (err)
1661d96047eSMarkus Pfeiffer 		return (NULL);
1671d96047eSMarkus Pfeiffer 
1681d96047eSMarkus Pfeiffer 	/*
1691d96047eSMarkus Pfeiffer 	 * Dequeue USB device from backend queue so that it does not get
1701d96047eSMarkus Pfeiffer 	 * freed when the backend is re-scanned:
1711d96047eSMarkus Pfeiffer 	 */
1721d96047eSMarkus Pfeiffer 	libusb20_be_dequeue_device(usb_backend, dev->dev);
1731d96047eSMarkus Pfeiffer 
1741d96047eSMarkus Pfeiffer 	return (dev->dev);
1751d96047eSMarkus Pfeiffer }
1761d96047eSMarkus Pfeiffer 
1771d96047eSMarkus Pfeiffer int
usb_close(usb_dev_handle * udev)1781d96047eSMarkus Pfeiffer usb_close(usb_dev_handle * udev)
1791d96047eSMarkus Pfeiffer {
1801d96047eSMarkus Pfeiffer 	struct usb_device *dev;
1811d96047eSMarkus Pfeiffer 	int err;
1821d96047eSMarkus Pfeiffer 
1831d96047eSMarkus Pfeiffer 	err = libusb20_dev_close((void *)udev);
1841d96047eSMarkus Pfeiffer 
1851d96047eSMarkus Pfeiffer 	if (err)
1861d96047eSMarkus Pfeiffer 		return (-1);
1871d96047eSMarkus Pfeiffer 
1881d96047eSMarkus Pfeiffer 	if (usb_backend != NULL) {
1891d96047eSMarkus Pfeiffer 		/*
1901d96047eSMarkus Pfeiffer 		 * Enqueue USB device to backend queue so that it gets freed
1911d96047eSMarkus Pfeiffer 		 * when the backend is re-scanned:
1921d96047eSMarkus Pfeiffer 		 */
1931d96047eSMarkus Pfeiffer 		libusb20_be_enqueue_device(usb_backend, (void *)udev);
1941d96047eSMarkus Pfeiffer 	} else {
1951d96047eSMarkus Pfeiffer 		/*
1961d96047eSMarkus Pfeiffer 		 * The backend is gone. Free device data so that we
1971d96047eSMarkus Pfeiffer 		 * don't start leaking memory!
1981d96047eSMarkus Pfeiffer 		 */
1991d96047eSMarkus Pfeiffer 		dev = usb_device(udev);
2001d96047eSMarkus Pfeiffer 		libusb20_dev_free((void *)udev);
2011d96047eSMarkus Pfeiffer 		LIST_DEL(usb_global_bus.devices, dev);
2021d96047eSMarkus Pfeiffer 		free(dev);
2031d96047eSMarkus Pfeiffer 	}
2041d96047eSMarkus Pfeiffer 	return (0);
2051d96047eSMarkus Pfeiffer }
2061d96047eSMarkus Pfeiffer 
2071d96047eSMarkus Pfeiffer int
usb_get_string(usb_dev_handle * dev,int strindex,int langid,char * buf,size_t buflen)2081d96047eSMarkus Pfeiffer usb_get_string(usb_dev_handle * dev, int strindex,
2091d96047eSMarkus Pfeiffer     int langid, char *buf, size_t buflen)
2101d96047eSMarkus Pfeiffer {
2111d96047eSMarkus Pfeiffer 	int err;
2121d96047eSMarkus Pfeiffer 
2131d96047eSMarkus Pfeiffer 	if (dev == NULL)
2141d96047eSMarkus Pfeiffer 		return (-1);
2151d96047eSMarkus Pfeiffer 
2161d96047eSMarkus Pfeiffer 	if (buflen > 65535)
2171d96047eSMarkus Pfeiffer 		buflen = 65535;
2181d96047eSMarkus Pfeiffer 
2191d96047eSMarkus Pfeiffer 	err = libusb20_dev_req_string_sync((void *)dev,
2201d96047eSMarkus Pfeiffer 	    strindex, langid, buf, buflen);
2211d96047eSMarkus Pfeiffer 
2221d96047eSMarkus Pfeiffer 	if (err)
2231d96047eSMarkus Pfeiffer 		return (-1);
2241d96047eSMarkus Pfeiffer 
2251d96047eSMarkus Pfeiffer 	return (0);
2261d96047eSMarkus Pfeiffer }
2271d96047eSMarkus Pfeiffer 
2281d96047eSMarkus Pfeiffer int
usb_get_string_simple(usb_dev_handle * dev,int strindex,char * buf,size_t buflen)2291d96047eSMarkus Pfeiffer usb_get_string_simple(usb_dev_handle * dev, int strindex,
2301d96047eSMarkus Pfeiffer     char *buf, size_t buflen)
2311d96047eSMarkus Pfeiffer {
2321d96047eSMarkus Pfeiffer 	int err;
2331d96047eSMarkus Pfeiffer 
2341d96047eSMarkus Pfeiffer 	if (dev == NULL)
2351d96047eSMarkus Pfeiffer 		return (-1);
2361d96047eSMarkus Pfeiffer 
2371d96047eSMarkus Pfeiffer 	if (buflen > 65535)
2381d96047eSMarkus Pfeiffer 		buflen = 65535;
2391d96047eSMarkus Pfeiffer 
2401d96047eSMarkus Pfeiffer 	err = libusb20_dev_req_string_simple_sync((void *)dev,
2411d96047eSMarkus Pfeiffer 	    strindex, buf, buflen);
2421d96047eSMarkus Pfeiffer 
2431d96047eSMarkus Pfeiffer 	if (err)
2441d96047eSMarkus Pfeiffer 		return (-1);
2451d96047eSMarkus Pfeiffer 
2461d96047eSMarkus Pfeiffer 	return (strlen(buf));
2471d96047eSMarkus Pfeiffer }
2481d96047eSMarkus Pfeiffer 
2491d96047eSMarkus Pfeiffer int
usb_get_descriptor_by_endpoint(usb_dev_handle * udev,int ep,uint8_t type,uint8_t ep_index,void * buf,int size)2501d96047eSMarkus Pfeiffer usb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type,
2511d96047eSMarkus Pfeiffer     uint8_t ep_index, void *buf, int size)
2521d96047eSMarkus Pfeiffer {
2531d96047eSMarkus Pfeiffer 	memset(buf, 0, size);
2541d96047eSMarkus Pfeiffer 
2551d96047eSMarkus Pfeiffer 	if (udev == NULL)
2561d96047eSMarkus Pfeiffer 		return (-1);
2571d96047eSMarkus Pfeiffer 
2581d96047eSMarkus Pfeiffer 	if (size > 65535)
2591d96047eSMarkus Pfeiffer 		size = 65535;
2601d96047eSMarkus Pfeiffer 
2611d96047eSMarkus Pfeiffer 	return (usb_control_msg(udev, ep | USB_ENDPOINT_IN,
2621d96047eSMarkus Pfeiffer 	    USB_REQ_GET_DESCRIPTOR, (type << 8) + ep_index, 0,
2631d96047eSMarkus Pfeiffer 	    buf, size, 1000));
2641d96047eSMarkus Pfeiffer }
2651d96047eSMarkus Pfeiffer 
2661d96047eSMarkus Pfeiffer int
usb_get_descriptor(usb_dev_handle * udev,uint8_t type,uint8_t desc_index,void * buf,int size)2671d96047eSMarkus Pfeiffer usb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t desc_index,
2681d96047eSMarkus Pfeiffer     void *buf, int size)
2691d96047eSMarkus Pfeiffer {
2701d96047eSMarkus Pfeiffer 	memset(buf, 0, size);
2711d96047eSMarkus Pfeiffer 
2721d96047eSMarkus Pfeiffer 	if (udev == NULL)
2731d96047eSMarkus Pfeiffer 		return (-1);
2741d96047eSMarkus Pfeiffer 
2751d96047eSMarkus Pfeiffer 	if (size > 65535)
2761d96047eSMarkus Pfeiffer 		size = 65535;
2771d96047eSMarkus Pfeiffer 
2781d96047eSMarkus Pfeiffer 	return (usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
2791d96047eSMarkus Pfeiffer 	    (type << 8) + desc_index, 0, buf, size, 1000));
2801d96047eSMarkus Pfeiffer }
2811d96047eSMarkus Pfeiffer 
2821d96047eSMarkus Pfeiffer int
usb_parse_descriptor(uint8_t * source,char * description,void * dest)2831d96047eSMarkus Pfeiffer usb_parse_descriptor(uint8_t *source, char *description, void *dest)
2841d96047eSMarkus Pfeiffer {
2851d96047eSMarkus Pfeiffer 	uint8_t *sp = source;
2861d96047eSMarkus Pfeiffer 	uint8_t *dp = dest;
2871d96047eSMarkus Pfeiffer 	uint16_t w;
2881d96047eSMarkus Pfeiffer 	uint32_t d;
2891d96047eSMarkus Pfeiffer 	char *cp;
2901d96047eSMarkus Pfeiffer 
2911d96047eSMarkus Pfeiffer 	for (cp = description; *cp; cp++) {
2921d96047eSMarkus Pfeiffer 		switch (*cp) {
2931d96047eSMarkus Pfeiffer 		case 'b':		/* 8-bit byte */
2941d96047eSMarkus Pfeiffer 			*dp++ = *sp++;
2951d96047eSMarkus Pfeiffer 			break;
2961d96047eSMarkus Pfeiffer 			/*
2971d96047eSMarkus Pfeiffer 			 * 16-bit word, convert from little endian to CPU
2981d96047eSMarkus Pfeiffer 			 */
2991d96047eSMarkus Pfeiffer 		case 'w':
3001d96047eSMarkus Pfeiffer 			w = (sp[1] << 8) | sp[0];
3011d96047eSMarkus Pfeiffer 			sp += 2;
3021d96047eSMarkus Pfeiffer 			/* Align to word boundary */
3031d96047eSMarkus Pfeiffer 			dp += ((dp - (uint8_t *)0) & 1);
3041d96047eSMarkus Pfeiffer 			*((uint16_t *)dp) = w;
3051d96047eSMarkus Pfeiffer 			dp += 2;
3061d96047eSMarkus Pfeiffer 			break;
3071d96047eSMarkus Pfeiffer 			/*
3081d96047eSMarkus Pfeiffer 			 * 32-bit dword, convert from little endian to CPU
3091d96047eSMarkus Pfeiffer 			 */
3101d96047eSMarkus Pfeiffer 		case 'd':
3111d96047eSMarkus Pfeiffer 			d = (sp[3] << 24) | (sp[2] << 16) |
3121d96047eSMarkus Pfeiffer 			    (sp[1] << 8) | sp[0];
3131d96047eSMarkus Pfeiffer 			sp += 4;
3141d96047eSMarkus Pfeiffer 			/* Align to word boundary */
3151d96047eSMarkus Pfeiffer 			dp += ((dp - (uint8_t *)0) & 1);
3161d96047eSMarkus Pfeiffer 			/* Align to double word boundary */
3171d96047eSMarkus Pfeiffer 			dp += ((dp - (uint8_t *)0) & 2);
3181d96047eSMarkus Pfeiffer 			*((uint32_t *)dp) = d;
3191d96047eSMarkus Pfeiffer 			dp += 4;
3201d96047eSMarkus Pfeiffer 			break;
3211d96047eSMarkus Pfeiffer 		}
3221d96047eSMarkus Pfeiffer 	}
3231d96047eSMarkus Pfeiffer 	return (sp - source);
3241d96047eSMarkus Pfeiffer }
3251d96047eSMarkus Pfeiffer 
3261d96047eSMarkus Pfeiffer static void
usb_parse_extra(struct usb_parse_state * ps,uint8_t ** pptr,int * plen)3271d96047eSMarkus Pfeiffer usb_parse_extra(struct usb_parse_state *ps, uint8_t **pptr, int *plen)
3281d96047eSMarkus Pfeiffer {
3291d96047eSMarkus Pfeiffer 	void *ptr;
3301d96047eSMarkus Pfeiffer 	uint16_t len;
3311d96047eSMarkus Pfeiffer 
3321d96047eSMarkus Pfeiffer 	ptr = ps->a.currextra->ptr;
3331d96047eSMarkus Pfeiffer 	len = ps->a.currextra->len;
3341d96047eSMarkus Pfeiffer 
3351d96047eSMarkus Pfeiffer 	if (ps->preparse == 0) {
3361d96047eSMarkus Pfeiffer 		memcpy(ps->b.currextra, ptr, len);
3371d96047eSMarkus Pfeiffer 		*pptr = ps->b.currextra;
3381d96047eSMarkus Pfeiffer 		*plen = len;
3391d96047eSMarkus Pfeiffer 	}
3401d96047eSMarkus Pfeiffer 	ps->b.currextra += len;
3411d96047eSMarkus Pfeiffer 	return;
3421d96047eSMarkus Pfeiffer }
3431d96047eSMarkus Pfeiffer 
3441d96047eSMarkus Pfeiffer static void
usb_parse_endpoint(struct usb_parse_state * ps)3451d96047eSMarkus Pfeiffer usb_parse_endpoint(struct usb_parse_state *ps)
3461d96047eSMarkus Pfeiffer {
3471d96047eSMarkus Pfeiffer 	struct usb_endpoint_descriptor *bep;
3481d96047eSMarkus Pfeiffer 	struct libusb20_endpoint *aep;
3491d96047eSMarkus Pfeiffer 
3501d96047eSMarkus Pfeiffer 	aep = ps->a.currep;
3511d96047eSMarkus Pfeiffer 	bep = ps->b.currep++;
3521d96047eSMarkus Pfeiffer 
3531d96047eSMarkus Pfeiffer 	if (ps->preparse == 0) {
3541d96047eSMarkus Pfeiffer 		/* copy descriptor fields */
3551d96047eSMarkus Pfeiffer 		bep->bLength = aep->desc.bLength;
3561d96047eSMarkus Pfeiffer 		bep->bDescriptorType = aep->desc.bDescriptorType;
3571d96047eSMarkus Pfeiffer 		bep->bEndpointAddress = aep->desc.bEndpointAddress;
3581d96047eSMarkus Pfeiffer 		bep->bmAttributes = aep->desc.bmAttributes;
3591d96047eSMarkus Pfeiffer 		bep->wMaxPacketSize = aep->desc.wMaxPacketSize;
3601d96047eSMarkus Pfeiffer 		bep->bInterval = aep->desc.bInterval;
3611d96047eSMarkus Pfeiffer 		bep->bRefresh = aep->desc.bRefresh;
3621d96047eSMarkus Pfeiffer 		bep->bSynchAddress = aep->desc.bSynchAddress;
3631d96047eSMarkus Pfeiffer 	}
3641d96047eSMarkus Pfeiffer 	ps->a.currextra = &aep->extra;
3651d96047eSMarkus Pfeiffer 	usb_parse_extra(ps, &bep->extra, &bep->extralen);
3661d96047eSMarkus Pfeiffer 	return;
3671d96047eSMarkus Pfeiffer }
3681d96047eSMarkus Pfeiffer 
3691d96047eSMarkus Pfeiffer static void
usb_parse_iface_sub(struct usb_parse_state * ps)3701d96047eSMarkus Pfeiffer usb_parse_iface_sub(struct usb_parse_state *ps)
3711d96047eSMarkus Pfeiffer {
3721d96047eSMarkus Pfeiffer 	struct libusb20_interface *aifc;
3731d96047eSMarkus Pfeiffer 	struct usb_interface_descriptor *bifc;
3741d96047eSMarkus Pfeiffer 	uint8_t x;
3751d96047eSMarkus Pfeiffer 
3761d96047eSMarkus Pfeiffer 	aifc = ps->a.currifc;
3771d96047eSMarkus Pfeiffer 	bifc = ps->b.currifc++;
3781d96047eSMarkus Pfeiffer 
3791d96047eSMarkus Pfeiffer 	if (ps->preparse == 0) {
3801d96047eSMarkus Pfeiffer 		/* copy descriptor fields */
3811d96047eSMarkus Pfeiffer 		bifc->bLength = aifc->desc.bLength;
3821d96047eSMarkus Pfeiffer 		bifc->bDescriptorType = aifc->desc.bDescriptorType;
3831d96047eSMarkus Pfeiffer 		bifc->bInterfaceNumber = aifc->desc.bInterfaceNumber;
3841d96047eSMarkus Pfeiffer 		bifc->bAlternateSetting = aifc->desc.bAlternateSetting;
3851d96047eSMarkus Pfeiffer 		bifc->bNumEndpoints = aifc->num_endpoints;
3861d96047eSMarkus Pfeiffer 		bifc->bInterfaceClass = aifc->desc.bInterfaceClass;
3871d96047eSMarkus Pfeiffer 		bifc->bInterfaceSubClass = aifc->desc.bInterfaceSubClass;
3881d96047eSMarkus Pfeiffer 		bifc->bInterfaceProtocol = aifc->desc.bInterfaceProtocol;
3891d96047eSMarkus Pfeiffer 		bifc->iInterface = aifc->desc.iInterface;
3901d96047eSMarkus Pfeiffer 		bifc->endpoint = ps->b.currep;
3911d96047eSMarkus Pfeiffer 	}
3921d96047eSMarkus Pfeiffer 	for (x = 0; x != aifc->num_endpoints; x++) {
3931d96047eSMarkus Pfeiffer 		ps->a.currep = aifc->endpoints + x;
3941d96047eSMarkus Pfeiffer 		usb_parse_endpoint(ps);
3951d96047eSMarkus Pfeiffer 	}
3961d96047eSMarkus Pfeiffer 
3971d96047eSMarkus Pfeiffer 	ps->a.currextra = &aifc->extra;
3981d96047eSMarkus Pfeiffer 	usb_parse_extra(ps, &bifc->extra, &bifc->extralen);
3991d96047eSMarkus Pfeiffer 	return;
4001d96047eSMarkus Pfeiffer }
4011d96047eSMarkus Pfeiffer 
4021d96047eSMarkus Pfeiffer static void
usb_parse_iface(struct usb_parse_state * ps)4031d96047eSMarkus Pfeiffer usb_parse_iface(struct usb_parse_state *ps)
4041d96047eSMarkus Pfeiffer {
4051d96047eSMarkus Pfeiffer 	struct libusb20_interface *aifc;
4061d96047eSMarkus Pfeiffer 	struct usb_interface *bifc;
4071d96047eSMarkus Pfeiffer 	uint8_t x;
4081d96047eSMarkus Pfeiffer 
4091d96047eSMarkus Pfeiffer 	aifc = ps->a.currifc;
4101d96047eSMarkus Pfeiffer 	bifc = ps->b.currifcw++;
4111d96047eSMarkus Pfeiffer 
4121d96047eSMarkus Pfeiffer 	if (ps->preparse == 0) {
4131d96047eSMarkus Pfeiffer 		/* initialise interface wrapper */
4141d96047eSMarkus Pfeiffer 		bifc->altsetting = ps->b.currifc;
4151d96047eSMarkus Pfeiffer 		bifc->num_altsetting = aifc->num_altsetting + 1;
4161d96047eSMarkus Pfeiffer 	}
4171d96047eSMarkus Pfeiffer 	usb_parse_iface_sub(ps);
4181d96047eSMarkus Pfeiffer 
4191d96047eSMarkus Pfeiffer 	for (x = 0; x != aifc->num_altsetting; x++) {
4201d96047eSMarkus Pfeiffer 		ps->a.currifc = aifc->altsetting + x;
4211d96047eSMarkus Pfeiffer 		usb_parse_iface_sub(ps);
4221d96047eSMarkus Pfeiffer 	}
4231d96047eSMarkus Pfeiffer 	return;
4241d96047eSMarkus Pfeiffer }
4251d96047eSMarkus Pfeiffer 
4261d96047eSMarkus Pfeiffer static void
usb_parse_config(struct usb_parse_state * ps)4271d96047eSMarkus Pfeiffer usb_parse_config(struct usb_parse_state *ps)
4281d96047eSMarkus Pfeiffer {
4291d96047eSMarkus Pfeiffer 	struct libusb20_config *acfg;
4301d96047eSMarkus Pfeiffer 	struct usb_config_descriptor *bcfg;
4311d96047eSMarkus Pfeiffer 	uint8_t x;
4321d96047eSMarkus Pfeiffer 
4331d96047eSMarkus Pfeiffer 	acfg = ps->a.currcfg;
4341d96047eSMarkus Pfeiffer 	bcfg = ps->b.currcfg;
4351d96047eSMarkus Pfeiffer 
4361d96047eSMarkus Pfeiffer 	if (ps->preparse == 0) {
4371d96047eSMarkus Pfeiffer 		/* initialise config wrapper */
4381d96047eSMarkus Pfeiffer 		bcfg->bLength = acfg->desc.bLength;
4391d96047eSMarkus Pfeiffer 		bcfg->bDescriptorType = acfg->desc.bDescriptorType;
4401d96047eSMarkus Pfeiffer 		bcfg->wTotalLength = acfg->desc.wTotalLength;
4411d96047eSMarkus Pfeiffer 		bcfg->bNumInterfaces = acfg->num_interface;
4421d96047eSMarkus Pfeiffer 		bcfg->bConfigurationValue = acfg->desc.bConfigurationValue;
4431d96047eSMarkus Pfeiffer 		bcfg->iConfiguration = acfg->desc.iConfiguration;
4441d96047eSMarkus Pfeiffer 		bcfg->bmAttributes = acfg->desc.bmAttributes;
4451d96047eSMarkus Pfeiffer 		bcfg->MaxPower = acfg->desc.bMaxPower;
4461d96047eSMarkus Pfeiffer 		bcfg->interface = ps->b.currifcw;
4471d96047eSMarkus Pfeiffer 	}
4481d96047eSMarkus Pfeiffer 	for (x = 0; x != acfg->num_interface; x++) {
4491d96047eSMarkus Pfeiffer 		ps->a.currifc = acfg->interface + x;
4501d96047eSMarkus Pfeiffer 		usb_parse_iface(ps);
4511d96047eSMarkus Pfeiffer 	}
4521d96047eSMarkus Pfeiffer 
4531d96047eSMarkus Pfeiffer 	ps->a.currextra = &acfg->extra;
4541d96047eSMarkus Pfeiffer 	usb_parse_extra(ps, &bcfg->extra, &bcfg->extralen);
4551d96047eSMarkus Pfeiffer 	return;
4561d96047eSMarkus Pfeiffer }
4571d96047eSMarkus Pfeiffer 
4581d96047eSMarkus Pfeiffer int
usb_parse_configuration(struct usb_config_descriptor * config,uint8_t * buffer)4591d96047eSMarkus Pfeiffer usb_parse_configuration(struct usb_config_descriptor *config,
4601d96047eSMarkus Pfeiffer     uint8_t *buffer)
4611d96047eSMarkus Pfeiffer {
4621d96047eSMarkus Pfeiffer 	struct usb_parse_state ps;
4631d96047eSMarkus Pfeiffer 	uint8_t *ptr;
4641d96047eSMarkus Pfeiffer 	uint32_t a;
4651d96047eSMarkus Pfeiffer 	uint32_t b;
4661d96047eSMarkus Pfeiffer 	uint32_t c;
4671d96047eSMarkus Pfeiffer 	uint32_t d;
4681d96047eSMarkus Pfeiffer 
4691d96047eSMarkus Pfeiffer 	if ((buffer == NULL) || (config == NULL)) {
4701d96047eSMarkus Pfeiffer 		return (-1);
4711d96047eSMarkus Pfeiffer 	}
4721d96047eSMarkus Pfeiffer 	memset(&ps, 0, sizeof(ps));
4731d96047eSMarkus Pfeiffer 
4741d96047eSMarkus Pfeiffer 	ps.a.currcfg = libusb20_parse_config_desc(buffer);
4751d96047eSMarkus Pfeiffer 	ps.b.currcfg = config;
4761d96047eSMarkus Pfeiffer 	if (ps.a.currcfg == NULL) {
4771d96047eSMarkus Pfeiffer 		/* could not parse config or out of memory */
4781d96047eSMarkus Pfeiffer 		return (-1);
4791d96047eSMarkus Pfeiffer 	}
4801d96047eSMarkus Pfeiffer 	/* do the pre-parse */
4811d96047eSMarkus Pfeiffer 	ps.preparse = 1;
4821d96047eSMarkus Pfeiffer 	usb_parse_config(&ps);
4831d96047eSMarkus Pfeiffer 
4841d96047eSMarkus Pfeiffer 	a = ((uint8_t *)(ps.b.currifcw) - ((uint8_t *)0));
4851d96047eSMarkus Pfeiffer 	b = ((uint8_t *)(ps.b.currifc) - ((uint8_t *)0));
4861d96047eSMarkus Pfeiffer 	c = ((uint8_t *)(ps.b.currep) - ((uint8_t *)0));
4871d96047eSMarkus Pfeiffer 	d = ((uint8_t *)(ps.b.currextra) - ((uint8_t *)0));
4881d96047eSMarkus Pfeiffer 
4891d96047eSMarkus Pfeiffer 	/* allocate memory for our configuration */
4901d96047eSMarkus Pfeiffer 	ptr = malloc(a + b + c + d);
4911d96047eSMarkus Pfeiffer 	if (ptr == NULL) {
4921d96047eSMarkus Pfeiffer 		/* free config structure */
4931d96047eSMarkus Pfeiffer 		free(ps.a.currcfg);
4941d96047eSMarkus Pfeiffer 		return (-1);
4951d96047eSMarkus Pfeiffer 	}
4961d96047eSMarkus Pfeiffer 
4971d96047eSMarkus Pfeiffer 	/* "currifcw" must be first, hence this pointer is freed */
4981d96047eSMarkus Pfeiffer 	ps.b.currifcw = (void *)(ptr);
4991d96047eSMarkus Pfeiffer 	ps.b.currifc = (void *)(ptr + a);
5001d96047eSMarkus Pfeiffer 	ps.b.currep = (void *)(ptr + a + b);
5011d96047eSMarkus Pfeiffer 	ps.b.currextra = (void *)(ptr + a + b + c);
5021d96047eSMarkus Pfeiffer 
5031d96047eSMarkus Pfeiffer 	/* generate a libusb v0.1 compatible structure */
5041d96047eSMarkus Pfeiffer 	ps.preparse = 0;
5051d96047eSMarkus Pfeiffer 	usb_parse_config(&ps);
5061d96047eSMarkus Pfeiffer 
5071d96047eSMarkus Pfeiffer 	/* free config structure */
5081d96047eSMarkus Pfeiffer 	free(ps.a.currcfg);
5091d96047eSMarkus Pfeiffer 
5101d96047eSMarkus Pfeiffer 	return (0);			/* success */
5111d96047eSMarkus Pfeiffer }
5121d96047eSMarkus Pfeiffer 
5131d96047eSMarkus Pfeiffer void
usb_destroy_configuration(struct usb_device * dev)5141d96047eSMarkus Pfeiffer usb_destroy_configuration(struct usb_device *dev)
5151d96047eSMarkus Pfeiffer {
5161d96047eSMarkus Pfeiffer 	uint8_t c;
5171d96047eSMarkus Pfeiffer 
5181d96047eSMarkus Pfeiffer 	if (dev->config == NULL) {
5191d96047eSMarkus Pfeiffer 		return;
5201d96047eSMarkus Pfeiffer 	}
5211d96047eSMarkus Pfeiffer 	for (c = 0; c != dev->descriptor.bNumConfigurations; c++) {
5221d96047eSMarkus Pfeiffer 		struct usb_config_descriptor *cf = &dev->config[c];
5231d96047eSMarkus Pfeiffer 
5241d96047eSMarkus Pfeiffer 		if (cf->interface != NULL) {
5251d96047eSMarkus Pfeiffer 			free(cf->interface);
5261d96047eSMarkus Pfeiffer 			cf->interface = NULL;
5271d96047eSMarkus Pfeiffer 		}
5281d96047eSMarkus Pfeiffer 	}
5291d96047eSMarkus Pfeiffer 
5301d96047eSMarkus Pfeiffer 	free(dev->config);
5311d96047eSMarkus Pfeiffer 	dev->config = NULL;
5321d96047eSMarkus Pfeiffer 	return;
5331d96047eSMarkus Pfeiffer }
5341d96047eSMarkus Pfeiffer 
5351d96047eSMarkus Pfeiffer void
usb_fetch_and_parse_descriptors(usb_dev_handle * udev)5361d96047eSMarkus Pfeiffer usb_fetch_and_parse_descriptors(usb_dev_handle * udev)
5371d96047eSMarkus Pfeiffer {
5381d96047eSMarkus Pfeiffer 	struct usb_device *dev;
5391d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
5401d96047eSMarkus Pfeiffer 	uint8_t *ptr;
5411d96047eSMarkus Pfeiffer 	int error;
5421d96047eSMarkus Pfeiffer 	uint32_t size;
5431d96047eSMarkus Pfeiffer 	uint16_t len;
5441d96047eSMarkus Pfeiffer 	uint8_t x;
5451d96047eSMarkus Pfeiffer 
5461d96047eSMarkus Pfeiffer 	if (udev == NULL) {
5471d96047eSMarkus Pfeiffer 		/* be NULL safe */
5481d96047eSMarkus Pfeiffer 		return;
5491d96047eSMarkus Pfeiffer 	}
5501d96047eSMarkus Pfeiffer 	dev = usb_device(udev);
5511d96047eSMarkus Pfeiffer 	pdev = (void *)udev;
5521d96047eSMarkus Pfeiffer 
5531d96047eSMarkus Pfeiffer 	if (dev->descriptor.bNumConfigurations == 0) {
5541d96047eSMarkus Pfeiffer 		/* invalid device */
5551d96047eSMarkus Pfeiffer 		return;
5561d96047eSMarkus Pfeiffer 	}
5571d96047eSMarkus Pfeiffer 	size = dev->descriptor.bNumConfigurations *
5581d96047eSMarkus Pfeiffer 	    sizeof(struct usb_config_descriptor);
5591d96047eSMarkus Pfeiffer 
5601d96047eSMarkus Pfeiffer 	dev->config = malloc(size);
5611d96047eSMarkus Pfeiffer 	if (dev->config == NULL) {
5621d96047eSMarkus Pfeiffer 		/* out of memory */
5631d96047eSMarkus Pfeiffer 		return;
5641d96047eSMarkus Pfeiffer 	}
5651d96047eSMarkus Pfeiffer 	memset(dev->config, 0, size);
5661d96047eSMarkus Pfeiffer 
5671d96047eSMarkus Pfeiffer 	for (x = 0; x != dev->descriptor.bNumConfigurations; x++) {
5681d96047eSMarkus Pfeiffer 
5691d96047eSMarkus Pfeiffer 		error = (pdev->methods->get_config_desc_full) (
5701d96047eSMarkus Pfeiffer 		    pdev, &ptr, &len, x);
5711d96047eSMarkus Pfeiffer 
5721d96047eSMarkus Pfeiffer 		if (error) {
5731d96047eSMarkus Pfeiffer 			usb_destroy_configuration(dev);
5741d96047eSMarkus Pfeiffer 			return;
5751d96047eSMarkus Pfeiffer 		}
5761d96047eSMarkus Pfeiffer 		usb_parse_configuration(dev->config + x, ptr);
5771d96047eSMarkus Pfeiffer 
5781d96047eSMarkus Pfeiffer 		/* free config buffer */
5791d96047eSMarkus Pfeiffer 		free(ptr);
5801d96047eSMarkus Pfeiffer 	}
5811d96047eSMarkus Pfeiffer 	return;
5821d96047eSMarkus Pfeiffer }
5831d96047eSMarkus Pfeiffer 
5841d96047eSMarkus Pfeiffer static int
usb_std_io(usb_dev_handle * dev,int ep,char * bytes,int size,int timeout,int is_intr)5851d96047eSMarkus Pfeiffer usb_std_io(usb_dev_handle * dev, int ep, char *bytes, int size,
5861d96047eSMarkus Pfeiffer     int timeout, int is_intr)
5871d96047eSMarkus Pfeiffer {
5881d96047eSMarkus Pfeiffer 	struct libusb20_transfer *xfer;
5891d96047eSMarkus Pfeiffer 	uint32_t temp;
5901d96047eSMarkus Pfeiffer 	uint32_t maxsize;
5911d96047eSMarkus Pfeiffer 	uint32_t actlen;
5921d96047eSMarkus Pfeiffer 	char *oldbytes;
5931d96047eSMarkus Pfeiffer 
5941d96047eSMarkus Pfeiffer 	xfer = usb_get_transfer_by_ep_no(dev, ep);
5951d96047eSMarkus Pfeiffer 	if (xfer == NULL)
5961d96047eSMarkus Pfeiffer 		return (-1);
5971d96047eSMarkus Pfeiffer 
5981d96047eSMarkus Pfeiffer 	if (libusb20_tr_pending(xfer)) {
5991d96047eSMarkus Pfeiffer 		/* there is already a transfer ongoing */
6001d96047eSMarkus Pfeiffer 		return (-1);
6011d96047eSMarkus Pfeiffer 	}
6021d96047eSMarkus Pfeiffer 	maxsize = libusb20_tr_get_max_total_length(xfer);
6031d96047eSMarkus Pfeiffer 	oldbytes = bytes;
6041d96047eSMarkus Pfeiffer 
6051d96047eSMarkus Pfeiffer 	/*
6061d96047eSMarkus Pfeiffer 	 * We allow transferring zero bytes which is the same
6071d96047eSMarkus Pfeiffer 	 * equivalent to a zero length USB packet.
6081d96047eSMarkus Pfeiffer 	 */
6091d96047eSMarkus Pfeiffer 	do {
6101d96047eSMarkus Pfeiffer 
6111d96047eSMarkus Pfeiffer 		temp = size;
6121d96047eSMarkus Pfeiffer 		if (temp > maxsize) {
6131d96047eSMarkus Pfeiffer 			/* find maximum possible length */
6141d96047eSMarkus Pfeiffer 			temp = maxsize;
6151d96047eSMarkus Pfeiffer 		}
6161d96047eSMarkus Pfeiffer 		if (is_intr)
6171d96047eSMarkus Pfeiffer 			libusb20_tr_setup_intr(xfer, bytes, temp, timeout);
6181d96047eSMarkus Pfeiffer 		else
6191d96047eSMarkus Pfeiffer 			libusb20_tr_setup_bulk(xfer, bytes, temp, timeout);
6201d96047eSMarkus Pfeiffer 
6211d96047eSMarkus Pfeiffer 		libusb20_tr_start(xfer);
6221d96047eSMarkus Pfeiffer 
6231d96047eSMarkus Pfeiffer 		while (1) {
6241d96047eSMarkus Pfeiffer 
6251d96047eSMarkus Pfeiffer 			if (libusb20_dev_process((void *)dev) != 0) {
6261d96047eSMarkus Pfeiffer 				/* device detached */
6271d96047eSMarkus Pfeiffer 				return (-1);
6281d96047eSMarkus Pfeiffer 			}
6291d96047eSMarkus Pfeiffer 			if (libusb20_tr_pending(xfer) == 0) {
6301d96047eSMarkus Pfeiffer 				/* transfer complete */
6311d96047eSMarkus Pfeiffer 				break;
6321d96047eSMarkus Pfeiffer 			}
6331d96047eSMarkus Pfeiffer 			/* wait for USB event from kernel */
6341d96047eSMarkus Pfeiffer 			libusb20_dev_wait_process((void *)dev, -1);
6351d96047eSMarkus Pfeiffer 		}
6361d96047eSMarkus Pfeiffer 
6371d96047eSMarkus Pfeiffer 		switch (libusb20_tr_get_status(xfer)) {
6381d96047eSMarkus Pfeiffer 		case 0:
6391d96047eSMarkus Pfeiffer 			/* success */
6401d96047eSMarkus Pfeiffer 			break;
6411d96047eSMarkus Pfeiffer 		case LIBUSB20_TRANSFER_TIMED_OUT:
6421d96047eSMarkus Pfeiffer 			/* transfer timeout */
6431d96047eSMarkus Pfeiffer 			return (-ETIMEDOUT);
6441d96047eSMarkus Pfeiffer 		default:
6451d96047eSMarkus Pfeiffer 			/* other transfer error */
6461d96047eSMarkus Pfeiffer 			return (-ENXIO);
6471d96047eSMarkus Pfeiffer 		}
6481d96047eSMarkus Pfeiffer 		actlen = libusb20_tr_get_actual_length(xfer);
6491d96047eSMarkus Pfeiffer 
6501d96047eSMarkus Pfeiffer 		bytes += actlen;
6511d96047eSMarkus Pfeiffer 		size -= actlen;
6521d96047eSMarkus Pfeiffer 
6531d96047eSMarkus Pfeiffer 		if (actlen != temp) {
6541d96047eSMarkus Pfeiffer 			/* short transfer */
6551d96047eSMarkus Pfeiffer 			break;
6561d96047eSMarkus Pfeiffer 		}
6571d96047eSMarkus Pfeiffer 	} while (size > 0);
6581d96047eSMarkus Pfeiffer 
6591d96047eSMarkus Pfeiffer 	return (bytes - oldbytes);
6601d96047eSMarkus Pfeiffer }
6611d96047eSMarkus Pfeiffer 
6621d96047eSMarkus Pfeiffer int
usb_bulk_write(usb_dev_handle * dev,int ep,char * bytes,int size,int timeout)6631d96047eSMarkus Pfeiffer usb_bulk_write(usb_dev_handle * dev, int ep, char *bytes,
6641d96047eSMarkus Pfeiffer     int size, int timeout)
6651d96047eSMarkus Pfeiffer {
6661d96047eSMarkus Pfeiffer 	return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK,
6671d96047eSMarkus Pfeiffer 	    bytes, size, timeout, 0));
6681d96047eSMarkus Pfeiffer }
6691d96047eSMarkus Pfeiffer 
6701d96047eSMarkus Pfeiffer int
usb_bulk_read(usb_dev_handle * dev,int ep,char * bytes,int size,int timeout)6711d96047eSMarkus Pfeiffer usb_bulk_read(usb_dev_handle * dev, int ep, char *bytes,
6721d96047eSMarkus Pfeiffer     int size, int timeout)
6731d96047eSMarkus Pfeiffer {
6741d96047eSMarkus Pfeiffer 	return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK,
6751d96047eSMarkus Pfeiffer 	    bytes, size, timeout, 0));
6761d96047eSMarkus Pfeiffer }
6771d96047eSMarkus Pfeiffer 
6781d96047eSMarkus Pfeiffer int
usb_interrupt_write(usb_dev_handle * dev,int ep,char * bytes,int size,int timeout)6791d96047eSMarkus Pfeiffer usb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes,
6801d96047eSMarkus Pfeiffer     int size, int timeout)
6811d96047eSMarkus Pfeiffer {
6821d96047eSMarkus Pfeiffer 	return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK,
6831d96047eSMarkus Pfeiffer 	    bytes, size, timeout, 1));
6841d96047eSMarkus Pfeiffer }
6851d96047eSMarkus Pfeiffer 
6861d96047eSMarkus Pfeiffer int
usb_interrupt_read(usb_dev_handle * dev,int ep,char * bytes,int size,int timeout)6871d96047eSMarkus Pfeiffer usb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes,
6881d96047eSMarkus Pfeiffer     int size, int timeout)
6891d96047eSMarkus Pfeiffer {
6901d96047eSMarkus Pfeiffer 	return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK,
6911d96047eSMarkus Pfeiffer 	    bytes, size, timeout, 1));
6921d96047eSMarkus Pfeiffer }
6931d96047eSMarkus Pfeiffer 
6941d96047eSMarkus Pfeiffer int
usb_control_msg(usb_dev_handle * dev,int requesttype,int request,int value,int wIndex,char * bytes,int size,int timeout)6951d96047eSMarkus Pfeiffer usb_control_msg(usb_dev_handle * dev, int requesttype, int request,
6961d96047eSMarkus Pfeiffer     int value, int wIndex, char *bytes, int size, int timeout)
6971d96047eSMarkus Pfeiffer {
6981d96047eSMarkus Pfeiffer 	struct LIBUSB20_CONTROL_SETUP_DECODED req;
6991d96047eSMarkus Pfeiffer 	int err;
7001d96047eSMarkus Pfeiffer 	uint16_t actlen;
7011d96047eSMarkus Pfeiffer 
7021d96047eSMarkus Pfeiffer 	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
7031d96047eSMarkus Pfeiffer 
7041d96047eSMarkus Pfeiffer 	req.bmRequestType = requesttype;
7051d96047eSMarkus Pfeiffer 	req.bRequest = request;
7061d96047eSMarkus Pfeiffer 	req.wValue = value;
7071d96047eSMarkus Pfeiffer 	req.wIndex = wIndex;
7081d96047eSMarkus Pfeiffer 	req.wLength = size;
7091d96047eSMarkus Pfeiffer 
7101d96047eSMarkus Pfeiffer 	err = libusb20_dev_request_sync((void *)dev, &req, bytes,
7111d96047eSMarkus Pfeiffer 	    &actlen, timeout, 0);
7121d96047eSMarkus Pfeiffer 
7131d96047eSMarkus Pfeiffer 	if (err)
7141d96047eSMarkus Pfeiffer 		return (-1);
7151d96047eSMarkus Pfeiffer 
7161d96047eSMarkus Pfeiffer 	return (actlen);
7171d96047eSMarkus Pfeiffer }
7181d96047eSMarkus Pfeiffer 
7191d96047eSMarkus Pfeiffer int
usb_set_configuration(usb_dev_handle * udev,int bConfigurationValue)7201d96047eSMarkus Pfeiffer usb_set_configuration(usb_dev_handle * udev, int bConfigurationValue)
7211d96047eSMarkus Pfeiffer {
7221d96047eSMarkus Pfeiffer 	struct usb_device *dev;
7231d96047eSMarkus Pfeiffer 	int err;
7241d96047eSMarkus Pfeiffer 	uint8_t i;
7251d96047eSMarkus Pfeiffer 
7261d96047eSMarkus Pfeiffer 	/*
7271d96047eSMarkus Pfeiffer 	 * Need to translate from "bConfigurationValue" to
7281d96047eSMarkus Pfeiffer 	 * configuration index:
7291d96047eSMarkus Pfeiffer 	 */
7301d96047eSMarkus Pfeiffer 
7311d96047eSMarkus Pfeiffer 	if (bConfigurationValue == 0) {
7321d96047eSMarkus Pfeiffer 		/* unconfigure */
7331d96047eSMarkus Pfeiffer 		i = 255;
7341d96047eSMarkus Pfeiffer 	} else {
7351d96047eSMarkus Pfeiffer 		/* lookup configuration index */
7361d96047eSMarkus Pfeiffer 		dev = usb_device(udev);
7371d96047eSMarkus Pfeiffer 
7381d96047eSMarkus Pfeiffer 		/* check if the configuration array is not there */
7391d96047eSMarkus Pfeiffer 		if (dev->config == NULL) {
7401d96047eSMarkus Pfeiffer 			return (-1);
7411d96047eSMarkus Pfeiffer 		}
7421d96047eSMarkus Pfeiffer 		for (i = 0;; i++) {
7431d96047eSMarkus Pfeiffer 			if (i == dev->descriptor.bNumConfigurations) {
7441d96047eSMarkus Pfeiffer 				/* "bConfigurationValue" not found */
7451d96047eSMarkus Pfeiffer 				return (-1);
7461d96047eSMarkus Pfeiffer 			}
7471d96047eSMarkus Pfeiffer 			if ((dev->config + i)->bConfigurationValue ==
7481d96047eSMarkus Pfeiffer 			    bConfigurationValue) {
7491d96047eSMarkus Pfeiffer 				break;
7501d96047eSMarkus Pfeiffer 			}
7511d96047eSMarkus Pfeiffer 		}
7521d96047eSMarkus Pfeiffer 	}
7531d96047eSMarkus Pfeiffer 
7541d96047eSMarkus Pfeiffer 	err = libusb20_dev_set_config_index((void *)udev, i);
7551d96047eSMarkus Pfeiffer 
7561d96047eSMarkus Pfeiffer 	if (err)
7571d96047eSMarkus Pfeiffer 		return (-1);
7581d96047eSMarkus Pfeiffer 
7591d96047eSMarkus Pfeiffer 	return (0);
7601d96047eSMarkus Pfeiffer }
7611d96047eSMarkus Pfeiffer 
7621d96047eSMarkus Pfeiffer int
usb_claim_interface(usb_dev_handle * dev,int interface)7631d96047eSMarkus Pfeiffer usb_claim_interface(usb_dev_handle * dev, int interface)
7641d96047eSMarkus Pfeiffer {
7651d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev = (void *)dev;
7661d96047eSMarkus Pfeiffer 
7671d96047eSMarkus Pfeiffer 	pdev->claimed_interface = interface;
7681d96047eSMarkus Pfeiffer 
7691d96047eSMarkus Pfeiffer 	return (0);
7701d96047eSMarkus Pfeiffer }
7711d96047eSMarkus Pfeiffer 
7721d96047eSMarkus Pfeiffer int
usb_release_interface(usb_dev_handle * dev,int interface)7731d96047eSMarkus Pfeiffer usb_release_interface(usb_dev_handle * dev, int interface)
7741d96047eSMarkus Pfeiffer {
7751d96047eSMarkus Pfeiffer 	/* do nothing */
7761d96047eSMarkus Pfeiffer 	return (0);
7771d96047eSMarkus Pfeiffer }
7781d96047eSMarkus Pfeiffer 
7791d96047eSMarkus Pfeiffer int
usb_set_altinterface(usb_dev_handle * dev,int alternate)7801d96047eSMarkus Pfeiffer usb_set_altinterface(usb_dev_handle * dev, int alternate)
7811d96047eSMarkus Pfeiffer {
7821d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev = (void *)dev;
7831d96047eSMarkus Pfeiffer 	int err;
7841d96047eSMarkus Pfeiffer 	uint8_t iface;
7851d96047eSMarkus Pfeiffer 
7861d96047eSMarkus Pfeiffer 	iface = pdev->claimed_interface;
7871d96047eSMarkus Pfeiffer 
7881d96047eSMarkus Pfeiffer 	err = libusb20_dev_set_alt_index((void *)dev, iface, alternate);
7891d96047eSMarkus Pfeiffer 
7901d96047eSMarkus Pfeiffer 	if (err)
7911d96047eSMarkus Pfeiffer 		return (-1);
7921d96047eSMarkus Pfeiffer 
7931d96047eSMarkus Pfeiffer 	return (0);
7941d96047eSMarkus Pfeiffer }
7951d96047eSMarkus Pfeiffer 
7961d96047eSMarkus Pfeiffer int
usb_resetep(usb_dev_handle * dev,unsigned int ep)7971d96047eSMarkus Pfeiffer usb_resetep(usb_dev_handle * dev, unsigned int ep)
7981d96047eSMarkus Pfeiffer {
7991d96047eSMarkus Pfeiffer 	/* emulate an endpoint reset through clear-STALL */
8001d96047eSMarkus Pfeiffer 	return (usb_clear_halt(dev, ep));
8011d96047eSMarkus Pfeiffer }
8021d96047eSMarkus Pfeiffer 
8031d96047eSMarkus Pfeiffer int
usb_clear_halt(usb_dev_handle * dev,unsigned int ep)8041d96047eSMarkus Pfeiffer usb_clear_halt(usb_dev_handle * dev, unsigned int ep)
8051d96047eSMarkus Pfeiffer {
8061d96047eSMarkus Pfeiffer 	struct libusb20_transfer *xfer;
8071d96047eSMarkus Pfeiffer 
8081d96047eSMarkus Pfeiffer 	xfer = usb_get_transfer_by_ep_no(dev, ep);
8091d96047eSMarkus Pfeiffer 	if (xfer == NULL)
8101d96047eSMarkus Pfeiffer 		return (-1);
8111d96047eSMarkus Pfeiffer 
8121d96047eSMarkus Pfeiffer 	libusb20_tr_clear_stall_sync(xfer);
8131d96047eSMarkus Pfeiffer 
8141d96047eSMarkus Pfeiffer 	return (0);
8151d96047eSMarkus Pfeiffer }
8161d96047eSMarkus Pfeiffer 
8171d96047eSMarkus Pfeiffer int
usb_reset(usb_dev_handle * dev)8181d96047eSMarkus Pfeiffer usb_reset(usb_dev_handle * dev)
8191d96047eSMarkus Pfeiffer {
8201d96047eSMarkus Pfeiffer 	int err;
8211d96047eSMarkus Pfeiffer 
8221d96047eSMarkus Pfeiffer 	err = libusb20_dev_reset((void *)dev);
8231d96047eSMarkus Pfeiffer 
8241d96047eSMarkus Pfeiffer 	if (err)
8251d96047eSMarkus Pfeiffer 		return (-1);
8261d96047eSMarkus Pfeiffer 
8271d96047eSMarkus Pfeiffer 	/*
8281d96047eSMarkus Pfeiffer 	 * Be compatible with LibUSB from sourceforge and close the
8291d96047eSMarkus Pfeiffer 	 * handle after reset!
8301d96047eSMarkus Pfeiffer 	 */
8311d96047eSMarkus Pfeiffer 	return (usb_close(dev));
8321d96047eSMarkus Pfeiffer }
8331d96047eSMarkus Pfeiffer 
8341d96047eSMarkus Pfeiffer int
usb_check_connected(usb_dev_handle * dev)8351d96047eSMarkus Pfeiffer usb_check_connected(usb_dev_handle * dev)
8361d96047eSMarkus Pfeiffer {
8371d96047eSMarkus Pfeiffer 	int err;
8381d96047eSMarkus Pfeiffer 
8391d96047eSMarkus Pfeiffer 	err = libusb20_dev_check_connected((void *)dev);
8401d96047eSMarkus Pfeiffer 
8411d96047eSMarkus Pfeiffer 	if (err)
8421d96047eSMarkus Pfeiffer 		return (-1);
8431d96047eSMarkus Pfeiffer 
8441d96047eSMarkus Pfeiffer 	return (0);
8451d96047eSMarkus Pfeiffer }
8461d96047eSMarkus Pfeiffer 
8471d96047eSMarkus Pfeiffer const char *
usb_strerror(void)8481d96047eSMarkus Pfeiffer usb_strerror(void)
8491d96047eSMarkus Pfeiffer {
8501d96047eSMarkus Pfeiffer 	/* TODO */
8511d96047eSMarkus Pfeiffer 	return ("Unknown error");
8521d96047eSMarkus Pfeiffer }
8531d96047eSMarkus Pfeiffer 
8541d96047eSMarkus Pfeiffer void
usb_init(void)8551d96047eSMarkus Pfeiffer usb_init(void)
8561d96047eSMarkus Pfeiffer {
8571d96047eSMarkus Pfeiffer 	/* nothing to do */
8581d96047eSMarkus Pfeiffer 	return;
8591d96047eSMarkus Pfeiffer }
8601d96047eSMarkus Pfeiffer 
8611d96047eSMarkus Pfeiffer void
usb_set_debug(int level)8621d96047eSMarkus Pfeiffer usb_set_debug(int level)
8631d96047eSMarkus Pfeiffer {
8641d96047eSMarkus Pfeiffer 	/* use kernel UGEN debugging if you need to see what is going on */
8651d96047eSMarkus Pfeiffer 	return;
8661d96047eSMarkus Pfeiffer }
8671d96047eSMarkus Pfeiffer 
8681d96047eSMarkus Pfeiffer int
usb_find_busses(void)8691d96047eSMarkus Pfeiffer usb_find_busses(void)
8701d96047eSMarkus Pfeiffer {
8711d96047eSMarkus Pfeiffer 	usb_busses = &usb_global_bus;
8721d96047eSMarkus Pfeiffer 	return (1);
8731d96047eSMarkus Pfeiffer }
8741d96047eSMarkus Pfeiffer 
8751d96047eSMarkus Pfeiffer int
usb_find_devices(void)8761d96047eSMarkus Pfeiffer usb_find_devices(void)
8771d96047eSMarkus Pfeiffer {
8781d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
8791d96047eSMarkus Pfeiffer 	struct usb_device *udev;
8801d96047eSMarkus Pfeiffer 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
8811d96047eSMarkus Pfeiffer 	int devnum;
8821d96047eSMarkus Pfeiffer 	int err;
8831d96047eSMarkus Pfeiffer 
8841d96047eSMarkus Pfeiffer 	/* cleanup after last device search */
8851d96047eSMarkus Pfeiffer 	/* close all opened devices, if any */
8861d96047eSMarkus Pfeiffer 
8871d96047eSMarkus Pfeiffer 	while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
8881d96047eSMarkus Pfeiffer 		udev = pdev->privLuData;
8891d96047eSMarkus Pfeiffer 		libusb20_be_dequeue_device(usb_backend, pdev);
8901d96047eSMarkus Pfeiffer 		libusb20_dev_free(pdev);
8911d96047eSMarkus Pfeiffer 		if (udev != NULL) {
8921d96047eSMarkus Pfeiffer 			LIST_DEL(usb_global_bus.devices, udev);
8931d96047eSMarkus Pfeiffer 			free(udev);
8941d96047eSMarkus Pfeiffer 		}
8951d96047eSMarkus Pfeiffer 	}
8961d96047eSMarkus Pfeiffer 
8971d96047eSMarkus Pfeiffer 	/* free old USB backend, if any */
8981d96047eSMarkus Pfeiffer 
8991d96047eSMarkus Pfeiffer 	libusb20_be_free(usb_backend);
9001d96047eSMarkus Pfeiffer 
9011d96047eSMarkus Pfeiffer 	/* do a new backend device search */
9021d96047eSMarkus Pfeiffer 	usb_backend = libusb20_be_alloc_default();
9031d96047eSMarkus Pfeiffer 	if (usb_backend == NULL) {
9041d96047eSMarkus Pfeiffer 		return (-1);
9051d96047eSMarkus Pfeiffer 	}
9061d96047eSMarkus Pfeiffer 	/* iterate all devices */
9071d96047eSMarkus Pfeiffer 
9081d96047eSMarkus Pfeiffer 	devnum = 1;
9091d96047eSMarkus Pfeiffer 	pdev = NULL;
9101d96047eSMarkus Pfeiffer 	while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) {
9111d96047eSMarkus Pfeiffer 		udev = malloc(sizeof(*udev));
9121d96047eSMarkus Pfeiffer 		if (udev == NULL)
9131d96047eSMarkus Pfeiffer 			break;
9141d96047eSMarkus Pfeiffer 
9151d96047eSMarkus Pfeiffer 		memset(udev, 0, sizeof(*udev));
9161d96047eSMarkus Pfeiffer 
9171d96047eSMarkus Pfeiffer 		udev->bus = &usb_global_bus;
9181d96047eSMarkus Pfeiffer 
9191d96047eSMarkus Pfeiffer 		snprintf(udev->filename, sizeof(udev->filename),
9201d96047eSMarkus Pfeiffer 		    "/dev/ugen%u.%u",
9211d96047eSMarkus Pfeiffer 		    libusb20_dev_get_bus_number(pdev),
9221d96047eSMarkus Pfeiffer 		    libusb20_dev_get_address(pdev));
9231d96047eSMarkus Pfeiffer 
9241d96047eSMarkus Pfeiffer 		ddesc = libusb20_dev_get_device_desc(pdev);
9251d96047eSMarkus Pfeiffer 
9261d96047eSMarkus Pfeiffer 		udev->descriptor.bLength = sizeof(udev->descriptor);
9271d96047eSMarkus Pfeiffer 		udev->descriptor.bDescriptorType = ddesc->bDescriptorType;
9281d96047eSMarkus Pfeiffer 		udev->descriptor.bcdUSB = ddesc->bcdUSB;
9291d96047eSMarkus Pfeiffer 		udev->descriptor.bDeviceClass = ddesc->bDeviceClass;
9301d96047eSMarkus Pfeiffer 		udev->descriptor.bDeviceSubClass = ddesc->bDeviceSubClass;
9311d96047eSMarkus Pfeiffer 		udev->descriptor.bDeviceProtocol = ddesc->bDeviceProtocol;
9321d96047eSMarkus Pfeiffer 		udev->descriptor.bMaxPacketSize0 = ddesc->bMaxPacketSize0;
9331d96047eSMarkus Pfeiffer 		udev->descriptor.idVendor = ddesc->idVendor;
9341d96047eSMarkus Pfeiffer 		udev->descriptor.idProduct = ddesc->idProduct;
9351d96047eSMarkus Pfeiffer 		udev->descriptor.bcdDevice = ddesc->bcdDevice;
9361d96047eSMarkus Pfeiffer 		udev->descriptor.iManufacturer = ddesc->iManufacturer;
9371d96047eSMarkus Pfeiffer 		udev->descriptor.iProduct = ddesc->iProduct;
9381d96047eSMarkus Pfeiffer 		udev->descriptor.iSerialNumber = ddesc->iSerialNumber;
9391d96047eSMarkus Pfeiffer 		udev->descriptor.bNumConfigurations =
9401d96047eSMarkus Pfeiffer 		    ddesc->bNumConfigurations;
9411d96047eSMarkus Pfeiffer 		if (udev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
9421d96047eSMarkus Pfeiffer 			/* truncate number of configurations */
9431d96047eSMarkus Pfeiffer 			udev->descriptor.bNumConfigurations = USB_MAXCONFIG;
9441d96047eSMarkus Pfeiffer 		}
9451d96047eSMarkus Pfeiffer 		udev->devnum = devnum++;
9461d96047eSMarkus Pfeiffer 		/* link together the two structures */
9471d96047eSMarkus Pfeiffer 		udev->dev = pdev;
9481d96047eSMarkus Pfeiffer 		pdev->privLuData = udev;
9491d96047eSMarkus Pfeiffer 
9501d96047eSMarkus Pfeiffer 		err = libusb20_dev_open(pdev, 0);
9511d96047eSMarkus Pfeiffer 		if (err == 0) {
9521d96047eSMarkus Pfeiffer 			/* XXX get all config descriptors by default */
9531d96047eSMarkus Pfeiffer 			usb_fetch_and_parse_descriptors((void *)pdev);
9541d96047eSMarkus Pfeiffer 			libusb20_dev_close(pdev);
9551d96047eSMarkus Pfeiffer 		}
9561d96047eSMarkus Pfeiffer 		LIST_ADD(usb_global_bus.devices, udev);
9571d96047eSMarkus Pfeiffer 	}
9581d96047eSMarkus Pfeiffer 
9591d96047eSMarkus Pfeiffer 	return (devnum - 1);			/* success */
9601d96047eSMarkus Pfeiffer }
9611d96047eSMarkus Pfeiffer 
9621d96047eSMarkus Pfeiffer struct usb_device *
usb_device(usb_dev_handle * dev)9631d96047eSMarkus Pfeiffer usb_device(usb_dev_handle * dev)
9641d96047eSMarkus Pfeiffer {
9651d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
9661d96047eSMarkus Pfeiffer 
9671d96047eSMarkus Pfeiffer 	pdev = (void *)dev;
9681d96047eSMarkus Pfeiffer 
9691d96047eSMarkus Pfeiffer 	return (pdev->privLuData);
9701d96047eSMarkus Pfeiffer }
9711d96047eSMarkus Pfeiffer 
9721d96047eSMarkus Pfeiffer struct usb_bus *
usb_get_busses(void)9731d96047eSMarkus Pfeiffer usb_get_busses(void)
9741d96047eSMarkus Pfeiffer {
9751d96047eSMarkus Pfeiffer 	return (usb_busses);
9761d96047eSMarkus Pfeiffer }
9771d96047eSMarkus Pfeiffer 
9781d96047eSMarkus Pfeiffer int
usb_get_driver_np(usb_dev_handle * dev,int interface,char * name,int namelen)9791d96047eSMarkus Pfeiffer usb_get_driver_np(usb_dev_handle * dev, int interface, char *name, int namelen)
9801d96047eSMarkus Pfeiffer {
9811d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
9821d96047eSMarkus Pfeiffer 	char *ptr;
9831d96047eSMarkus Pfeiffer 	int err;
9841d96047eSMarkus Pfeiffer 
9851d96047eSMarkus Pfeiffer 	pdev = (void *)dev;
9861d96047eSMarkus Pfeiffer 
9871d96047eSMarkus Pfeiffer 	if (pdev == NULL)
9881d96047eSMarkus Pfeiffer 		return (-1);
9891d96047eSMarkus Pfeiffer 	if (namelen < 1)
9901d96047eSMarkus Pfeiffer 		return (-1);
9911d96047eSMarkus Pfeiffer 	if (namelen > 255)
9921d96047eSMarkus Pfeiffer 		namelen = 255;
9931d96047eSMarkus Pfeiffer 
9941d96047eSMarkus Pfeiffer 	err = libusb20_dev_get_iface_desc(pdev, interface, name, namelen);
9951d96047eSMarkus Pfeiffer 	if (err != 0)
9961d96047eSMarkus Pfeiffer 		return (-1);
9971d96047eSMarkus Pfeiffer 
9981d96047eSMarkus Pfeiffer 	/* we only want the driver name */
9991d96047eSMarkus Pfeiffer 	ptr = strstr(name, ":");
10001d96047eSMarkus Pfeiffer 	if (ptr != NULL)
10011d96047eSMarkus Pfeiffer 		*ptr = 0;
10021d96047eSMarkus Pfeiffer 
10031d96047eSMarkus Pfeiffer 	return (0);
10041d96047eSMarkus Pfeiffer }
10051d96047eSMarkus Pfeiffer 
10061d96047eSMarkus Pfeiffer int
usb_detach_kernel_driver_np(usb_dev_handle * dev,int interface)10071d96047eSMarkus Pfeiffer usb_detach_kernel_driver_np(usb_dev_handle * dev, int interface)
10081d96047eSMarkus Pfeiffer {
10091d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
10101d96047eSMarkus Pfeiffer 	int err;
10111d96047eSMarkus Pfeiffer 
10121d96047eSMarkus Pfeiffer 	pdev = (void *)dev;
10131d96047eSMarkus Pfeiffer 
10141d96047eSMarkus Pfeiffer 	if (pdev == NULL)
10151d96047eSMarkus Pfeiffer 		return (-1);
10161d96047eSMarkus Pfeiffer 
10171d96047eSMarkus Pfeiffer 	err = libusb20_dev_detach_kernel_driver(pdev, interface);
10181d96047eSMarkus Pfeiffer 	if (err != 0)
10191d96047eSMarkus Pfeiffer 		return (-1);
10201d96047eSMarkus Pfeiffer 
10211d96047eSMarkus Pfeiffer 	return (0);
10221d96047eSMarkus Pfeiffer }
1023