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