12485d8a7SHans Petter Selasky /* $FreeBSD$ */ 22485d8a7SHans Petter Selasky /*- 32485d8a7SHans Petter Selasky * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 42485d8a7SHans Petter Selasky * 52485d8a7SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 62485d8a7SHans Petter Selasky * modification, are permitted provided that the following conditions 72485d8a7SHans Petter Selasky * are met: 82485d8a7SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 92485d8a7SHans Petter Selasky * notice, this list of conditions and the following disclaimer. 102485d8a7SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 112485d8a7SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 122485d8a7SHans Petter Selasky * documentation and/or other materials provided with the distribution. 132485d8a7SHans Petter Selasky * 142485d8a7SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152485d8a7SHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162485d8a7SHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172485d8a7SHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182485d8a7SHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192485d8a7SHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202485d8a7SHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212485d8a7SHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222485d8a7SHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232485d8a7SHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242485d8a7SHans Petter Selasky * SUCH DAMAGE. 252485d8a7SHans Petter Selasky */ 262485d8a7SHans Petter Selasky 272485d8a7SHans Petter Selasky /* 282485d8a7SHans Petter Selasky * This file contains the emulation layer for LibUSB v0.1 from sourceforge. 292485d8a7SHans Petter Selasky */ 302485d8a7SHans Petter Selasky 31*66194130SHans Petter Selasky #ifdef LIBUSB_GLOBAL_INCLUDE_FILE 32*66194130SHans Petter Selasky #include LIBUSB_GLOBAL_INCLUDE_FILE 33*66194130SHans Petter Selasky #else 342485d8a7SHans Petter Selasky #include <errno.h> 352485d8a7SHans Petter Selasky #include <stdio.h> 362485d8a7SHans Petter Selasky #include <stdlib.h> 37*66194130SHans Petter Selasky #include <string.h> 38*66194130SHans Petter Selasky #include <time.h> 39*66194130SHans Petter Selasky #include <sys/queue.h> 40*66194130SHans Petter Selasky #endif 412485d8a7SHans Petter Selasky 422485d8a7SHans Petter Selasky #include "libusb20.h" 432485d8a7SHans Petter Selasky #include "libusb20_desc.h" 442485d8a7SHans Petter Selasky #include "libusb20_int.h" 452485d8a7SHans Petter Selasky #include "usb.h" 462485d8a7SHans Petter Selasky 472485d8a7SHans Petter Selasky /* 482485d8a7SHans Petter Selasky * The two following macros were taken from the original LibUSB v0.1 492485d8a7SHans Petter Selasky * for sake of compatibility: 502485d8a7SHans Petter Selasky */ 512485d8a7SHans Petter Selasky #define LIST_ADD(begin, ent) \ 522485d8a7SHans Petter Selasky do { \ 532485d8a7SHans Petter Selasky if (begin) { \ 542485d8a7SHans Petter Selasky ent->next = begin; \ 552485d8a7SHans Petter Selasky ent->next->prev = ent; \ 562485d8a7SHans Petter Selasky } else { \ 572485d8a7SHans Petter Selasky ent->next = NULL; \ 582485d8a7SHans Petter Selasky } \ 592485d8a7SHans Petter Selasky ent->prev = NULL; \ 602485d8a7SHans Petter Selasky begin = ent; \ 612485d8a7SHans Petter Selasky } while(0) 622485d8a7SHans Petter Selasky 632485d8a7SHans Petter Selasky #define LIST_DEL(begin, ent) \ 642485d8a7SHans Petter Selasky do { \ 652485d8a7SHans Petter Selasky if (ent->prev) { \ 662485d8a7SHans Petter Selasky ent->prev->next = ent->next; \ 672485d8a7SHans Petter Selasky } else { \ 682485d8a7SHans Petter Selasky begin = ent->next; \ 692485d8a7SHans Petter Selasky } \ 702485d8a7SHans Petter Selasky if (ent->next) { \ 712485d8a7SHans Petter Selasky ent->next->prev = ent->prev; \ 722485d8a7SHans Petter Selasky } \ 732485d8a7SHans Petter Selasky ent->prev = NULL; \ 742485d8a7SHans Petter Selasky ent->next = NULL; \ 752485d8a7SHans Petter Selasky } while (0) 762485d8a7SHans Petter Selasky 772485d8a7SHans Petter Selasky struct usb_bus *usb_busses = NULL; 782485d8a7SHans Petter Selasky 792485d8a7SHans Petter Selasky static struct usb_bus usb_global_bus = { 802485d8a7SHans Petter Selasky .dirname = {"/dev/usb"}, 812485d8a7SHans Petter Selasky .root_dev = NULL, 822485d8a7SHans Petter Selasky .devices = NULL, 832485d8a7SHans Petter Selasky }; 842485d8a7SHans Petter Selasky 852485d8a7SHans Petter Selasky static struct libusb20_backend *usb_backend = NULL; 862485d8a7SHans Petter Selasky 872485d8a7SHans Petter Selasky struct usb_parse_state { 882485d8a7SHans Petter Selasky 892485d8a7SHans Petter Selasky struct { 902485d8a7SHans Petter Selasky struct libusb20_endpoint *currep; 912485d8a7SHans Petter Selasky struct libusb20_interface *currifc; 922485d8a7SHans Petter Selasky struct libusb20_config *currcfg; 932485d8a7SHans Petter Selasky struct libusb20_me_struct *currextra; 942485d8a7SHans Petter Selasky } a; 952485d8a7SHans Petter Selasky 962485d8a7SHans Petter Selasky struct { 972485d8a7SHans Petter Selasky struct usb_config_descriptor *currcfg; 982485d8a7SHans Petter Selasky struct usb_interface_descriptor *currifc; 992485d8a7SHans Petter Selasky struct usb_endpoint_descriptor *currep; 1002485d8a7SHans Petter Selasky struct usb_interface *currifcw; 1012485d8a7SHans Petter Selasky uint8_t *currextra; 1022485d8a7SHans Petter Selasky } b; 1032485d8a7SHans Petter Selasky 1042485d8a7SHans Petter Selasky uint8_t preparse; 1052485d8a7SHans Petter Selasky }; 1062485d8a7SHans Petter Selasky 1072485d8a7SHans Petter Selasky static struct libusb20_transfer * 1082485d8a7SHans Petter Selasky usb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no) 1092485d8a7SHans Petter Selasky { 1102485d8a7SHans Petter Selasky struct libusb20_device *pdev = (void *)dev; 1112485d8a7SHans Petter Selasky struct libusb20_transfer *xfer; 1122485d8a7SHans Petter Selasky int err; 1132485d8a7SHans Petter Selasky uint32_t bufsize; 1142485d8a7SHans Petter Selasky uint8_t x; 1152485d8a7SHans Petter Selasky uint8_t speed; 1162485d8a7SHans Petter Selasky 1172485d8a7SHans Petter Selasky x = (ep_no & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 2; 1182485d8a7SHans Petter Selasky 1192485d8a7SHans Petter Selasky if (ep_no & LIBUSB20_ENDPOINT_DIR_MASK) { 1202485d8a7SHans Petter Selasky /* this is an IN endpoint */ 1212485d8a7SHans Petter Selasky x |= 1; 1222485d8a7SHans Petter Selasky } 1232485d8a7SHans Petter Selasky speed = libusb20_dev_get_speed(pdev); 1242485d8a7SHans Petter Selasky 1252485d8a7SHans Petter Selasky /* select a sensible buffer size */ 1262485d8a7SHans Petter Selasky if (speed == LIBUSB20_SPEED_LOW) { 1272485d8a7SHans Petter Selasky bufsize = 256; 1282485d8a7SHans Petter Selasky } else if (speed == LIBUSB20_SPEED_FULL) { 1292485d8a7SHans Petter Selasky bufsize = 4096; 1302485d8a7SHans Petter Selasky } else { 1312485d8a7SHans Petter Selasky bufsize = 16384; 1322485d8a7SHans Petter Selasky } 1332485d8a7SHans Petter Selasky 1342485d8a7SHans Petter Selasky xfer = libusb20_tr_get_pointer(pdev, x); 1352485d8a7SHans Petter Selasky 1362485d8a7SHans Petter Selasky if (xfer == NULL) 1372485d8a7SHans Petter Selasky return (xfer); 1382485d8a7SHans Petter Selasky 1392485d8a7SHans Petter Selasky err = libusb20_tr_open(xfer, bufsize, 1, ep_no); 1402485d8a7SHans Petter Selasky if (err == LIBUSB20_ERROR_BUSY) { 1412485d8a7SHans Petter Selasky /* already opened */ 1422485d8a7SHans Petter Selasky return (xfer); 1432485d8a7SHans Petter Selasky } else if (err) { 1442485d8a7SHans Petter Selasky return (NULL); 1452485d8a7SHans Petter Selasky } 1462485d8a7SHans Petter Selasky /* success */ 1472485d8a7SHans Petter Selasky return (xfer); 1482485d8a7SHans Petter Selasky } 1492485d8a7SHans Petter Selasky 1502485d8a7SHans Petter Selasky usb_dev_handle * 1512485d8a7SHans Petter Selasky usb_open(struct usb_device *dev) 1522485d8a7SHans Petter Selasky { 1532485d8a7SHans Petter Selasky int err; 1542485d8a7SHans Petter Selasky 1552485d8a7SHans Petter Selasky err = libusb20_dev_open(dev->dev, 16 * 2); 1562485d8a7SHans Petter Selasky if (err == LIBUSB20_ERROR_BUSY) { 1572485d8a7SHans Petter Selasky /* 1582485d8a7SHans Petter Selasky * Workaround buggy USB applications which open the USB 1592485d8a7SHans Petter Selasky * device multiple times: 1602485d8a7SHans Petter Selasky */ 1612485d8a7SHans Petter Selasky return (dev->dev); 1622485d8a7SHans Petter Selasky } 1632485d8a7SHans Petter Selasky if (err) 1642485d8a7SHans Petter Selasky return (NULL); 1652485d8a7SHans Petter Selasky 1662485d8a7SHans Petter Selasky /* 1672485d8a7SHans Petter Selasky * Dequeue USB device from backend queue so that it does not get 1682485d8a7SHans Petter Selasky * freed when the backend is re-scanned: 1692485d8a7SHans Petter Selasky */ 1702485d8a7SHans Petter Selasky libusb20_be_dequeue_device(usb_backend, dev->dev); 1712485d8a7SHans Petter Selasky 1722485d8a7SHans Petter Selasky return (dev->dev); 1732485d8a7SHans Petter Selasky } 1742485d8a7SHans Petter Selasky 1752485d8a7SHans Petter Selasky int 1762485d8a7SHans Petter Selasky usb_close(usb_dev_handle * udev) 1772485d8a7SHans Petter Selasky { 1782485d8a7SHans Petter Selasky struct usb_device *dev; 1792485d8a7SHans Petter Selasky int err; 1802485d8a7SHans Petter Selasky 1812485d8a7SHans Petter Selasky err = libusb20_dev_close((void *)udev); 1822485d8a7SHans Petter Selasky 1832485d8a7SHans Petter Selasky if (err) 1842485d8a7SHans Petter Selasky return (-1); 1852485d8a7SHans Petter Selasky 1862485d8a7SHans Petter Selasky if (usb_backend != NULL) { 1872485d8a7SHans Petter Selasky /* 1882485d8a7SHans Petter Selasky * Enqueue USB device to backend queue so that it gets freed 1892485d8a7SHans Petter Selasky * when the backend is re-scanned: 1902485d8a7SHans Petter Selasky */ 1912485d8a7SHans Petter Selasky libusb20_be_enqueue_device(usb_backend, (void *)udev); 1922485d8a7SHans Petter Selasky } else { 1932485d8a7SHans Petter Selasky /* 1942485d8a7SHans Petter Selasky * The backend is gone. Free device data so that we 1952485d8a7SHans Petter Selasky * don't start leaking memory! 1962485d8a7SHans Petter Selasky */ 1972485d8a7SHans Petter Selasky dev = usb_device(udev); 1982485d8a7SHans Petter Selasky libusb20_dev_free((void *)udev); 1992485d8a7SHans Petter Selasky LIST_DEL(usb_global_bus.devices, dev); 2002485d8a7SHans Petter Selasky free(dev); 2012485d8a7SHans Petter Selasky } 2022485d8a7SHans Petter Selasky return (0); 2032485d8a7SHans Petter Selasky } 2042485d8a7SHans Petter Selasky 2052485d8a7SHans Petter Selasky int 2062485d8a7SHans Petter Selasky usb_get_string(usb_dev_handle * dev, int strindex, 2072485d8a7SHans Petter Selasky int langid, char *buf, size_t buflen) 2082485d8a7SHans Petter Selasky { 2092485d8a7SHans Petter Selasky int err; 2102485d8a7SHans Petter Selasky 2114eb5923dSHans Petter Selasky if (dev == NULL) 2124eb5923dSHans Petter Selasky return (-1); 2134eb5923dSHans Petter Selasky 2144eb5923dSHans Petter Selasky if (buflen > 65535) 2154eb5923dSHans Petter Selasky buflen = 65535; 2164eb5923dSHans Petter Selasky 2172485d8a7SHans Petter Selasky err = libusb20_dev_req_string_sync((void *)dev, 2182485d8a7SHans Petter Selasky strindex, langid, buf, buflen); 2192485d8a7SHans Petter Selasky 2202485d8a7SHans Petter Selasky if (err) 2212485d8a7SHans Petter Selasky return (-1); 2222485d8a7SHans Petter Selasky 2232485d8a7SHans Petter Selasky return (0); 2242485d8a7SHans Petter Selasky } 2252485d8a7SHans Petter Selasky 2262485d8a7SHans Petter Selasky int 2272485d8a7SHans Petter Selasky usb_get_string_simple(usb_dev_handle * dev, int strindex, 2282485d8a7SHans Petter Selasky char *buf, size_t buflen) 2292485d8a7SHans Petter Selasky { 2302485d8a7SHans Petter Selasky int err; 2312485d8a7SHans Petter Selasky 2324eb5923dSHans Petter Selasky if (dev == NULL) 2334eb5923dSHans Petter Selasky return (-1); 2344eb5923dSHans Petter Selasky 2354eb5923dSHans Petter Selasky if (buflen > 65535) 2364eb5923dSHans Petter Selasky buflen = 65535; 2374eb5923dSHans Petter Selasky 2382485d8a7SHans Petter Selasky err = libusb20_dev_req_string_simple_sync((void *)dev, 2392485d8a7SHans Petter Selasky strindex, buf, buflen); 2402485d8a7SHans Petter Selasky 2412485d8a7SHans Petter Selasky if (err) 2422485d8a7SHans Petter Selasky return (-1); 2432485d8a7SHans Petter Selasky 2442485d8a7SHans Petter Selasky return (strlen(buf)); 2452485d8a7SHans Petter Selasky } 2462485d8a7SHans Petter Selasky 2472485d8a7SHans Petter Selasky int 2482485d8a7SHans Petter Selasky usb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type, 2492485d8a7SHans Petter Selasky uint8_t ep_index, void *buf, int size) 2502485d8a7SHans Petter Selasky { 2512485d8a7SHans Petter Selasky memset(buf, 0, size); 2522485d8a7SHans Petter Selasky 2534eb5923dSHans Petter Selasky if (udev == NULL) 2544eb5923dSHans Petter Selasky return (-1); 2554eb5923dSHans Petter Selasky 2564eb5923dSHans Petter Selasky if (size > 65535) 2574eb5923dSHans Petter Selasky size = 65535; 2584eb5923dSHans Petter Selasky 2592485d8a7SHans Petter Selasky return (usb_control_msg(udev, ep | USB_ENDPOINT_IN, 2602485d8a7SHans Petter Selasky USB_REQ_GET_DESCRIPTOR, (type << 8) + ep_index, 0, 2612485d8a7SHans Petter Selasky buf, size, 1000)); 2622485d8a7SHans Petter Selasky } 2632485d8a7SHans Petter Selasky 2642485d8a7SHans Petter Selasky int 2652485d8a7SHans Petter Selasky usb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t desc_index, 2662485d8a7SHans Petter Selasky void *buf, int size) 2672485d8a7SHans Petter Selasky { 2682485d8a7SHans Petter Selasky memset(buf, 0, size); 2692485d8a7SHans Petter Selasky 2704eb5923dSHans Petter Selasky if (udev == NULL) 2714eb5923dSHans Petter Selasky return (-1); 2724eb5923dSHans Petter Selasky 2734eb5923dSHans Petter Selasky if (size > 65535) 2744eb5923dSHans Petter Selasky size = 65535; 2754eb5923dSHans Petter Selasky 2762485d8a7SHans Petter Selasky return (usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, 2772485d8a7SHans Petter Selasky (type << 8) + desc_index, 0, buf, size, 1000)); 2782485d8a7SHans Petter Selasky } 2792485d8a7SHans Petter Selasky 2802485d8a7SHans Petter Selasky int 2812485d8a7SHans Petter Selasky usb_parse_descriptor(uint8_t *source, char *description, void *dest) 2822485d8a7SHans Petter Selasky { 2832485d8a7SHans Petter Selasky uint8_t *sp = source; 2842485d8a7SHans Petter Selasky uint8_t *dp = dest; 2852485d8a7SHans Petter Selasky uint16_t w; 2862485d8a7SHans Petter Selasky uint32_t d; 2872485d8a7SHans Petter Selasky char *cp; 2882485d8a7SHans Petter Selasky 2892485d8a7SHans Petter Selasky for (cp = description; *cp; cp++) { 2902485d8a7SHans Petter Selasky switch (*cp) { 2912485d8a7SHans Petter Selasky case 'b': /* 8-bit byte */ 2922485d8a7SHans Petter Selasky *dp++ = *sp++; 2932485d8a7SHans Petter Selasky break; 2942485d8a7SHans Petter Selasky /* 2952485d8a7SHans Petter Selasky * 16-bit word, convert from little endian to CPU 2962485d8a7SHans Petter Selasky */ 2972485d8a7SHans Petter Selasky case 'w': 2982485d8a7SHans Petter Selasky w = (sp[1] << 8) | sp[0]; 2992485d8a7SHans Petter Selasky sp += 2; 3002485d8a7SHans Petter Selasky /* Align to word boundary */ 3012485d8a7SHans Petter Selasky dp += ((dp - (uint8_t *)0) & 1); 3022485d8a7SHans Petter Selasky *((uint16_t *)dp) = w; 3032485d8a7SHans Petter Selasky dp += 2; 3042485d8a7SHans Petter Selasky break; 3052485d8a7SHans Petter Selasky /* 3062485d8a7SHans Petter Selasky * 32-bit dword, convert from little endian to CPU 3072485d8a7SHans Petter Selasky */ 3082485d8a7SHans Petter Selasky case 'd': 3092485d8a7SHans Petter Selasky d = (sp[3] << 24) | (sp[2] << 16) | 3102485d8a7SHans Petter Selasky (sp[1] << 8) | sp[0]; 3112485d8a7SHans Petter Selasky sp += 4; 3122485d8a7SHans Petter Selasky /* Align to word boundary */ 3132485d8a7SHans Petter Selasky dp += ((dp - (uint8_t *)0) & 1); 3142485d8a7SHans Petter Selasky /* Align to double word boundary */ 3152485d8a7SHans Petter Selasky dp += ((dp - (uint8_t *)0) & 2); 3162485d8a7SHans Petter Selasky *((uint32_t *)dp) = d; 3172485d8a7SHans Petter Selasky dp += 4; 3182485d8a7SHans Petter Selasky break; 3192485d8a7SHans Petter Selasky } 3202485d8a7SHans Petter Selasky } 3212485d8a7SHans Petter Selasky return (sp - source); 3222485d8a7SHans Petter Selasky } 3232485d8a7SHans Petter Selasky 3242485d8a7SHans Petter Selasky static void 3252485d8a7SHans Petter Selasky usb_parse_extra(struct usb_parse_state *ps, uint8_t **pptr, int *plen) 3262485d8a7SHans Petter Selasky { 3272485d8a7SHans Petter Selasky void *ptr; 3282485d8a7SHans Petter Selasky uint16_t len; 3292485d8a7SHans Petter Selasky 3302485d8a7SHans Petter Selasky ptr = ps->a.currextra->ptr; 3312485d8a7SHans Petter Selasky len = ps->a.currextra->len; 3322485d8a7SHans Petter Selasky 3332485d8a7SHans Petter Selasky if (ps->preparse == 0) { 3342485d8a7SHans Petter Selasky memcpy(ps->b.currextra, ptr, len); 3352485d8a7SHans Petter Selasky *pptr = ps->b.currextra; 3362485d8a7SHans Petter Selasky *plen = len; 3372485d8a7SHans Petter Selasky } 3382485d8a7SHans Petter Selasky ps->b.currextra += len; 3392485d8a7SHans Petter Selasky return; 3402485d8a7SHans Petter Selasky } 3412485d8a7SHans Petter Selasky 3422485d8a7SHans Petter Selasky static void 3432485d8a7SHans Petter Selasky usb_parse_endpoint(struct usb_parse_state *ps) 3442485d8a7SHans Petter Selasky { 3452485d8a7SHans Petter Selasky struct usb_endpoint_descriptor *bep; 3462485d8a7SHans Petter Selasky struct libusb20_endpoint *aep; 3472485d8a7SHans Petter Selasky 3482485d8a7SHans Petter Selasky aep = ps->a.currep; 3492485d8a7SHans Petter Selasky bep = ps->b.currep++; 3502485d8a7SHans Petter Selasky 3512485d8a7SHans Petter Selasky if (ps->preparse == 0) { 3522485d8a7SHans Petter Selasky /* copy descriptor fields */ 3532485d8a7SHans Petter Selasky bep->bLength = aep->desc.bLength; 3542485d8a7SHans Petter Selasky bep->bDescriptorType = aep->desc.bDescriptorType; 3552485d8a7SHans Petter Selasky bep->bEndpointAddress = aep->desc.bEndpointAddress; 3562485d8a7SHans Petter Selasky bep->bmAttributes = aep->desc.bmAttributes; 3572485d8a7SHans Petter Selasky bep->wMaxPacketSize = aep->desc.wMaxPacketSize; 3582485d8a7SHans Petter Selasky bep->bInterval = aep->desc.bInterval; 3592485d8a7SHans Petter Selasky bep->bRefresh = aep->desc.bRefresh; 3602485d8a7SHans Petter Selasky bep->bSynchAddress = aep->desc.bSynchAddress; 3612485d8a7SHans Petter Selasky } 3622485d8a7SHans Petter Selasky ps->a.currextra = &aep->extra; 3632485d8a7SHans Petter Selasky usb_parse_extra(ps, &bep->extra, &bep->extralen); 3642485d8a7SHans Petter Selasky return; 3652485d8a7SHans Petter Selasky } 3662485d8a7SHans Petter Selasky 3672485d8a7SHans Petter Selasky static void 3682485d8a7SHans Petter Selasky usb_parse_iface_sub(struct usb_parse_state *ps) 3692485d8a7SHans Petter Selasky { 3702485d8a7SHans Petter Selasky struct libusb20_interface *aifc; 3712485d8a7SHans Petter Selasky struct usb_interface_descriptor *bifc; 3722485d8a7SHans Petter Selasky uint8_t x; 3732485d8a7SHans Petter Selasky 3742485d8a7SHans Petter Selasky aifc = ps->a.currifc; 3752485d8a7SHans Petter Selasky bifc = ps->b.currifc++; 3762485d8a7SHans Petter Selasky 3772485d8a7SHans Petter Selasky if (ps->preparse == 0) { 3782485d8a7SHans Petter Selasky /* copy descriptor fields */ 3792485d8a7SHans Petter Selasky bifc->bLength = aifc->desc.bLength; 3802485d8a7SHans Petter Selasky bifc->bDescriptorType = aifc->desc.bDescriptorType; 3812485d8a7SHans Petter Selasky bifc->bInterfaceNumber = aifc->desc.bInterfaceNumber; 3822485d8a7SHans Petter Selasky bifc->bAlternateSetting = aifc->desc.bAlternateSetting; 3832485d8a7SHans Petter Selasky bifc->bNumEndpoints = aifc->num_endpoints; 3842485d8a7SHans Petter Selasky bifc->bInterfaceClass = aifc->desc.bInterfaceClass; 3852485d8a7SHans Petter Selasky bifc->bInterfaceSubClass = aifc->desc.bInterfaceSubClass; 3862485d8a7SHans Petter Selasky bifc->bInterfaceProtocol = aifc->desc.bInterfaceProtocol; 3872485d8a7SHans Petter Selasky bifc->iInterface = aifc->desc.iInterface; 3882485d8a7SHans Petter Selasky bifc->endpoint = ps->b.currep; 3892485d8a7SHans Petter Selasky } 3902485d8a7SHans Petter Selasky for (x = 0; x != aifc->num_endpoints; x++) { 3912485d8a7SHans Petter Selasky ps->a.currep = aifc->endpoints + x; 3922485d8a7SHans Petter Selasky usb_parse_endpoint(ps); 3932485d8a7SHans Petter Selasky } 3942485d8a7SHans Petter Selasky 3952485d8a7SHans Petter Selasky ps->a.currextra = &aifc->extra; 3962485d8a7SHans Petter Selasky usb_parse_extra(ps, &bifc->extra, &bifc->extralen); 3972485d8a7SHans Petter Selasky return; 3982485d8a7SHans Petter Selasky } 3992485d8a7SHans Petter Selasky 4002485d8a7SHans Petter Selasky static void 4012485d8a7SHans Petter Selasky usb_parse_iface(struct usb_parse_state *ps) 4022485d8a7SHans Petter Selasky { 4032485d8a7SHans Petter Selasky struct libusb20_interface *aifc; 4042485d8a7SHans Petter Selasky struct usb_interface *bifc; 4052485d8a7SHans Petter Selasky uint8_t x; 4062485d8a7SHans Petter Selasky 4072485d8a7SHans Petter Selasky aifc = ps->a.currifc; 4082485d8a7SHans Petter Selasky bifc = ps->b.currifcw++; 4092485d8a7SHans Petter Selasky 4102485d8a7SHans Petter Selasky if (ps->preparse == 0) { 4112485d8a7SHans Petter Selasky /* initialise interface wrapper */ 4122485d8a7SHans Petter Selasky bifc->altsetting = ps->b.currifc; 4132485d8a7SHans Petter Selasky bifc->num_altsetting = aifc->num_altsetting + 1; 4142485d8a7SHans Petter Selasky } 4152485d8a7SHans Petter Selasky usb_parse_iface_sub(ps); 4162485d8a7SHans Petter Selasky 4172485d8a7SHans Petter Selasky for (x = 0; x != aifc->num_altsetting; x++) { 4182485d8a7SHans Petter Selasky ps->a.currifc = aifc->altsetting + x; 4192485d8a7SHans Petter Selasky usb_parse_iface_sub(ps); 4202485d8a7SHans Petter Selasky } 4212485d8a7SHans Petter Selasky return; 4222485d8a7SHans Petter Selasky } 4232485d8a7SHans Petter Selasky 4242485d8a7SHans Petter Selasky static void 4252485d8a7SHans Petter Selasky usb_parse_config(struct usb_parse_state *ps) 4262485d8a7SHans Petter Selasky { 4272485d8a7SHans Petter Selasky struct libusb20_config *acfg; 4282485d8a7SHans Petter Selasky struct usb_config_descriptor *bcfg; 4292485d8a7SHans Petter Selasky uint8_t x; 4302485d8a7SHans Petter Selasky 4312485d8a7SHans Petter Selasky acfg = ps->a.currcfg; 4322485d8a7SHans Petter Selasky bcfg = ps->b.currcfg; 4332485d8a7SHans Petter Selasky 4342485d8a7SHans Petter Selasky if (ps->preparse == 0) { 4352485d8a7SHans Petter Selasky /* initialise config wrapper */ 4362485d8a7SHans Petter Selasky bcfg->bLength = acfg->desc.bLength; 4372485d8a7SHans Petter Selasky bcfg->bDescriptorType = acfg->desc.bDescriptorType; 4382485d8a7SHans Petter Selasky bcfg->wTotalLength = acfg->desc.wTotalLength; 4392485d8a7SHans Petter Selasky bcfg->bNumInterfaces = acfg->num_interface; 4402485d8a7SHans Petter Selasky bcfg->bConfigurationValue = acfg->desc.bConfigurationValue; 4412485d8a7SHans Petter Selasky bcfg->iConfiguration = acfg->desc.iConfiguration; 4422485d8a7SHans Petter Selasky bcfg->bmAttributes = acfg->desc.bmAttributes; 4432485d8a7SHans Petter Selasky bcfg->MaxPower = acfg->desc.bMaxPower; 4442485d8a7SHans Petter Selasky bcfg->interface = ps->b.currifcw; 4452485d8a7SHans Petter Selasky } 4462485d8a7SHans Petter Selasky for (x = 0; x != acfg->num_interface; x++) { 4472485d8a7SHans Petter Selasky ps->a.currifc = acfg->interface + x; 4482485d8a7SHans Petter Selasky usb_parse_iface(ps); 4492485d8a7SHans Petter Selasky } 4502485d8a7SHans Petter Selasky 4512485d8a7SHans Petter Selasky ps->a.currextra = &acfg->extra; 4522485d8a7SHans Petter Selasky usb_parse_extra(ps, &bcfg->extra, &bcfg->extralen); 4532485d8a7SHans Petter Selasky return; 4542485d8a7SHans Petter Selasky } 4552485d8a7SHans Petter Selasky 4562485d8a7SHans Petter Selasky int 4572485d8a7SHans Petter Selasky usb_parse_configuration(struct usb_config_descriptor *config, 4582485d8a7SHans Petter Selasky uint8_t *buffer) 4592485d8a7SHans Petter Selasky { 4602485d8a7SHans Petter Selasky struct usb_parse_state ps; 4612485d8a7SHans Petter Selasky uint8_t *ptr; 4622485d8a7SHans Petter Selasky uint32_t a; 4632485d8a7SHans Petter Selasky uint32_t b; 4642485d8a7SHans Petter Selasky uint32_t c; 4652485d8a7SHans Petter Selasky uint32_t d; 4662485d8a7SHans Petter Selasky 4672485d8a7SHans Petter Selasky if ((buffer == NULL) || (config == NULL)) { 4682485d8a7SHans Petter Selasky return (-1); 4692485d8a7SHans Petter Selasky } 4702485d8a7SHans Petter Selasky memset(&ps, 0, sizeof(ps)); 4712485d8a7SHans Petter Selasky 4722485d8a7SHans Petter Selasky ps.a.currcfg = libusb20_parse_config_desc(buffer); 4732485d8a7SHans Petter Selasky ps.b.currcfg = config; 4742485d8a7SHans Petter Selasky if (ps.a.currcfg == NULL) { 4752485d8a7SHans Petter Selasky /* could not parse config or out of memory */ 4762485d8a7SHans Petter Selasky return (-1); 4772485d8a7SHans Petter Selasky } 4782485d8a7SHans Petter Selasky /* do the pre-parse */ 4792485d8a7SHans Petter Selasky ps.preparse = 1; 4802485d8a7SHans Petter Selasky usb_parse_config(&ps); 4812485d8a7SHans Petter Selasky 4822485d8a7SHans Petter Selasky a = ((uint8_t *)(ps.b.currifcw) - ((uint8_t *)0)); 4832485d8a7SHans Petter Selasky b = ((uint8_t *)(ps.b.currifc) - ((uint8_t *)0)); 4842485d8a7SHans Petter Selasky c = ((uint8_t *)(ps.b.currep) - ((uint8_t *)0)); 4852485d8a7SHans Petter Selasky d = ((uint8_t *)(ps.b.currextra) - ((uint8_t *)0)); 4862485d8a7SHans Petter Selasky 4872485d8a7SHans Petter Selasky /* allocate memory for our configuration */ 4882485d8a7SHans Petter Selasky ptr = malloc(a + b + c + d); 4892485d8a7SHans Petter Selasky if (ptr == NULL) { 4902485d8a7SHans Petter Selasky /* free config structure */ 4912485d8a7SHans Petter Selasky free(ps.a.currcfg); 4922485d8a7SHans Petter Selasky return (-1); 4932485d8a7SHans Petter Selasky } 4942485d8a7SHans Petter Selasky 4952485d8a7SHans Petter Selasky /* "currifcw" must be first, hence this pointer is freed */ 4962485d8a7SHans Petter Selasky ps.b.currifcw = (void *)(ptr); 4972485d8a7SHans Petter Selasky ps.b.currifc = (void *)(ptr + a); 4982485d8a7SHans Petter Selasky ps.b.currep = (void *)(ptr + a + b); 4992485d8a7SHans Petter Selasky ps.b.currextra = (void *)(ptr + a + b + c); 5002485d8a7SHans Petter Selasky 5012485d8a7SHans Petter Selasky /* generate a libusb v0.1 compatible structure */ 5022485d8a7SHans Petter Selasky ps.preparse = 0; 5032485d8a7SHans Petter Selasky usb_parse_config(&ps); 5042485d8a7SHans Petter Selasky 5052485d8a7SHans Petter Selasky /* free config structure */ 5062485d8a7SHans Petter Selasky free(ps.a.currcfg); 5072485d8a7SHans Petter Selasky 5082485d8a7SHans Petter Selasky return (0); /* success */ 5092485d8a7SHans Petter Selasky } 5102485d8a7SHans Petter Selasky 5112485d8a7SHans Petter Selasky void 5122485d8a7SHans Petter Selasky usb_destroy_configuration(struct usb_device *dev) 5132485d8a7SHans Petter Selasky { 5142485d8a7SHans Petter Selasky uint8_t c; 5152485d8a7SHans Petter Selasky 5162485d8a7SHans Petter Selasky if (dev->config == NULL) { 5172485d8a7SHans Petter Selasky return; 5182485d8a7SHans Petter Selasky } 5192485d8a7SHans Petter Selasky for (c = 0; c != dev->descriptor.bNumConfigurations; c++) { 5202485d8a7SHans Petter Selasky struct usb_config_descriptor *cf = &dev->config[c]; 5212485d8a7SHans Petter Selasky 5222485d8a7SHans Petter Selasky if (cf->interface != NULL) { 5232485d8a7SHans Petter Selasky free(cf->interface); 5242485d8a7SHans Petter Selasky cf->interface = NULL; 5252485d8a7SHans Petter Selasky } 5262485d8a7SHans Petter Selasky } 5272485d8a7SHans Petter Selasky 5282485d8a7SHans Petter Selasky free(dev->config); 5292485d8a7SHans Petter Selasky dev->config = NULL; 5302485d8a7SHans Petter Selasky return; 5312485d8a7SHans Petter Selasky } 5322485d8a7SHans Petter Selasky 5332485d8a7SHans Petter Selasky void 5342485d8a7SHans Petter Selasky usb_fetch_and_parse_descriptors(usb_dev_handle * udev) 5352485d8a7SHans Petter Selasky { 5362485d8a7SHans Petter Selasky struct usb_device *dev; 5372485d8a7SHans Petter Selasky struct libusb20_device *pdev; 5382485d8a7SHans Petter Selasky uint8_t *ptr; 5392485d8a7SHans Petter Selasky int error; 5402485d8a7SHans Petter Selasky uint32_t size; 5412485d8a7SHans Petter Selasky uint16_t len; 5422485d8a7SHans Petter Selasky uint8_t x; 5432485d8a7SHans Petter Selasky 5442485d8a7SHans Petter Selasky if (udev == NULL) { 5452485d8a7SHans Petter Selasky /* be NULL safe */ 5462485d8a7SHans Petter Selasky return; 5472485d8a7SHans Petter Selasky } 5482485d8a7SHans Petter Selasky dev = usb_device(udev); 5492485d8a7SHans Petter Selasky pdev = (void *)udev; 5502485d8a7SHans Petter Selasky 5512485d8a7SHans Petter Selasky if (dev->descriptor.bNumConfigurations == 0) { 5522485d8a7SHans Petter Selasky /* invalid device */ 5532485d8a7SHans Petter Selasky return; 5542485d8a7SHans Petter Selasky } 5552485d8a7SHans Petter Selasky size = dev->descriptor.bNumConfigurations * 5562485d8a7SHans Petter Selasky sizeof(struct usb_config_descriptor); 5572485d8a7SHans Petter Selasky 5582485d8a7SHans Petter Selasky dev->config = malloc(size); 5592485d8a7SHans Petter Selasky if (dev->config == NULL) { 5602485d8a7SHans Petter Selasky /* out of memory */ 5612485d8a7SHans Petter Selasky return; 5622485d8a7SHans Petter Selasky } 5632485d8a7SHans Petter Selasky memset(dev->config, 0, size); 5642485d8a7SHans Petter Selasky 5652485d8a7SHans Petter Selasky for (x = 0; x != dev->descriptor.bNumConfigurations; x++) { 5662485d8a7SHans Petter Selasky 5672485d8a7SHans Petter Selasky error = (pdev->methods->get_config_desc_full) ( 5682485d8a7SHans Petter Selasky pdev, &ptr, &len, x); 5692485d8a7SHans Petter Selasky 5702485d8a7SHans Petter Selasky if (error) { 5712485d8a7SHans Petter Selasky usb_destroy_configuration(dev); 5722485d8a7SHans Petter Selasky return; 5732485d8a7SHans Petter Selasky } 5742485d8a7SHans Petter Selasky usb_parse_configuration(dev->config + x, ptr); 5752485d8a7SHans Petter Selasky 5762485d8a7SHans Petter Selasky /* free config buffer */ 5772485d8a7SHans Petter Selasky free(ptr); 5782485d8a7SHans Petter Selasky } 5792485d8a7SHans Petter Selasky return; 5802485d8a7SHans Petter Selasky } 5812485d8a7SHans Petter Selasky 5822485d8a7SHans Petter Selasky static int 5832485d8a7SHans Petter Selasky usb_std_io(usb_dev_handle * dev, int ep, char *bytes, int size, 5842485d8a7SHans Petter Selasky int timeout, int is_intr) 5852485d8a7SHans Petter Selasky { 5862485d8a7SHans Petter Selasky struct libusb20_transfer *xfer; 5872485d8a7SHans Petter Selasky uint32_t temp; 5882485d8a7SHans Petter Selasky uint32_t maxsize; 5892485d8a7SHans Petter Selasky uint32_t actlen; 5902485d8a7SHans Petter Selasky char *oldbytes; 5912485d8a7SHans Petter Selasky 5922485d8a7SHans Petter Selasky xfer = usb_get_transfer_by_ep_no(dev, ep); 5932485d8a7SHans Petter Selasky if (xfer == NULL) 5942485d8a7SHans Petter Selasky return (-1); 5952485d8a7SHans Petter Selasky 5962485d8a7SHans Petter Selasky if (libusb20_tr_pending(xfer)) { 5972485d8a7SHans Petter Selasky /* there is already a transfer ongoing */ 5982485d8a7SHans Petter Selasky return (-1); 5992485d8a7SHans Petter Selasky } 6002485d8a7SHans Petter Selasky maxsize = libusb20_tr_get_max_total_length(xfer); 6012485d8a7SHans Petter Selasky oldbytes = bytes; 6022485d8a7SHans Petter Selasky 6032485d8a7SHans Petter Selasky /* 6042485d8a7SHans Petter Selasky * We allow transferring zero bytes which is the same 6052485d8a7SHans Petter Selasky * equivalent to a zero length USB packet. 6062485d8a7SHans Petter Selasky */ 6072485d8a7SHans Petter Selasky do { 6082485d8a7SHans Petter Selasky 6092485d8a7SHans Petter Selasky temp = size; 6102485d8a7SHans Petter Selasky if (temp > maxsize) { 6112485d8a7SHans Petter Selasky /* find maximum possible length */ 6122485d8a7SHans Petter Selasky temp = maxsize; 6132485d8a7SHans Petter Selasky } 6142485d8a7SHans Petter Selasky if (is_intr) 6152485d8a7SHans Petter Selasky libusb20_tr_setup_intr(xfer, bytes, temp, timeout); 6162485d8a7SHans Petter Selasky else 6172485d8a7SHans Petter Selasky libusb20_tr_setup_bulk(xfer, bytes, temp, timeout); 6182485d8a7SHans Petter Selasky 6192485d8a7SHans Petter Selasky libusb20_tr_start(xfer); 6202485d8a7SHans Petter Selasky 6212485d8a7SHans Petter Selasky while (1) { 6222485d8a7SHans Petter Selasky 6232485d8a7SHans Petter Selasky if (libusb20_dev_process((void *)dev) != 0) { 6242485d8a7SHans Petter Selasky /* device detached */ 6252485d8a7SHans Petter Selasky return (-1); 6262485d8a7SHans Petter Selasky } 6272485d8a7SHans Petter Selasky if (libusb20_tr_pending(xfer) == 0) { 6282485d8a7SHans Petter Selasky /* transfer complete */ 6292485d8a7SHans Petter Selasky break; 6302485d8a7SHans Petter Selasky } 6312485d8a7SHans Petter Selasky /* wait for USB event from kernel */ 6322485d8a7SHans Petter Selasky libusb20_dev_wait_process((void *)dev, -1); 6332485d8a7SHans Petter Selasky } 6342485d8a7SHans Petter Selasky 6352485d8a7SHans Petter Selasky switch (libusb20_tr_get_status(xfer)) { 6362485d8a7SHans Petter Selasky case 0: 6372485d8a7SHans Petter Selasky /* success */ 6382485d8a7SHans Petter Selasky break; 6392485d8a7SHans Petter Selasky case LIBUSB20_TRANSFER_TIMED_OUT: 6402485d8a7SHans Petter Selasky /* transfer timeout */ 6412485d8a7SHans Petter Selasky return (-ETIMEDOUT); 6422485d8a7SHans Petter Selasky default: 6432485d8a7SHans Petter Selasky /* other transfer error */ 6442485d8a7SHans Petter Selasky return (-ENXIO); 6452485d8a7SHans Petter Selasky } 6462485d8a7SHans Petter Selasky actlen = libusb20_tr_get_actual_length(xfer); 6472485d8a7SHans Petter Selasky 6482485d8a7SHans Petter Selasky bytes += actlen; 6492485d8a7SHans Petter Selasky size -= actlen; 6502485d8a7SHans Petter Selasky 6512485d8a7SHans Petter Selasky if (actlen != temp) { 6522485d8a7SHans Petter Selasky /* short transfer */ 6532485d8a7SHans Petter Selasky break; 6542485d8a7SHans Petter Selasky } 6552485d8a7SHans Petter Selasky } while (size > 0); 6562485d8a7SHans Petter Selasky 6572485d8a7SHans Petter Selasky return (bytes - oldbytes); 6582485d8a7SHans Petter Selasky } 6592485d8a7SHans Petter Selasky 6602485d8a7SHans Petter Selasky int 6612485d8a7SHans Petter Selasky usb_bulk_write(usb_dev_handle * dev, int ep, char *bytes, 6622485d8a7SHans Petter Selasky int size, int timeout) 6632485d8a7SHans Petter Selasky { 6642485d8a7SHans Petter Selasky return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK, 6652485d8a7SHans Petter Selasky bytes, size, timeout, 0)); 6662485d8a7SHans Petter Selasky } 6672485d8a7SHans Petter Selasky 6682485d8a7SHans Petter Selasky int 6692485d8a7SHans Petter Selasky usb_bulk_read(usb_dev_handle * dev, int ep, char *bytes, 6702485d8a7SHans Petter Selasky int size, int timeout) 6712485d8a7SHans Petter Selasky { 6722485d8a7SHans Petter Selasky return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK, 6732485d8a7SHans Petter Selasky bytes, size, timeout, 0)); 6742485d8a7SHans Petter Selasky } 6752485d8a7SHans Petter Selasky 6762485d8a7SHans Petter Selasky int 6772485d8a7SHans Petter Selasky usb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes, 6782485d8a7SHans Petter Selasky int size, int timeout) 6792485d8a7SHans Petter Selasky { 6802485d8a7SHans Petter Selasky return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK, 6812485d8a7SHans Petter Selasky bytes, size, timeout, 1)); 6822485d8a7SHans Petter Selasky } 6832485d8a7SHans Petter Selasky 6842485d8a7SHans Petter Selasky int 6852485d8a7SHans Petter Selasky usb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes, 6862485d8a7SHans Petter Selasky int size, int timeout) 6872485d8a7SHans Petter Selasky { 6882485d8a7SHans Petter Selasky return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK, 6892485d8a7SHans Petter Selasky bytes, size, timeout, 1)); 6902485d8a7SHans Petter Selasky } 6912485d8a7SHans Petter Selasky 6922485d8a7SHans Petter Selasky int 6932485d8a7SHans Petter Selasky usb_control_msg(usb_dev_handle * dev, int requesttype, int request, 6942485d8a7SHans Petter Selasky int value, int wIndex, char *bytes, int size, int timeout) 6952485d8a7SHans Petter Selasky { 6962485d8a7SHans Petter Selasky struct LIBUSB20_CONTROL_SETUP_DECODED req; 6972485d8a7SHans Petter Selasky int err; 6982485d8a7SHans Petter Selasky uint16_t actlen; 6992485d8a7SHans Petter Selasky 7002485d8a7SHans Petter Selasky LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 7012485d8a7SHans Petter Selasky 7022485d8a7SHans Petter Selasky req.bmRequestType = requesttype; 7032485d8a7SHans Petter Selasky req.bRequest = request; 7042485d8a7SHans Petter Selasky req.wValue = value; 7052485d8a7SHans Petter Selasky req.wIndex = wIndex; 7062485d8a7SHans Petter Selasky req.wLength = size; 7072485d8a7SHans Petter Selasky 7082485d8a7SHans Petter Selasky err = libusb20_dev_request_sync((void *)dev, &req, bytes, 7092485d8a7SHans Petter Selasky &actlen, timeout, 0); 7102485d8a7SHans Petter Selasky 7112485d8a7SHans Petter Selasky if (err) 7122485d8a7SHans Petter Selasky return (-1); 7132485d8a7SHans Petter Selasky 7142485d8a7SHans Petter Selasky return (actlen); 7152485d8a7SHans Petter Selasky } 7162485d8a7SHans Petter Selasky 7172485d8a7SHans Petter Selasky int 7182485d8a7SHans Petter Selasky usb_set_configuration(usb_dev_handle * udev, int bConfigurationValue) 7192485d8a7SHans Petter Selasky { 7202485d8a7SHans Petter Selasky struct usb_device *dev; 7212485d8a7SHans Petter Selasky int err; 7222485d8a7SHans Petter Selasky uint8_t i; 7232485d8a7SHans Petter Selasky 7242485d8a7SHans Petter Selasky /* 7252485d8a7SHans Petter Selasky * Need to translate from "bConfigurationValue" to 7262485d8a7SHans Petter Selasky * configuration index: 7272485d8a7SHans Petter Selasky */ 7282485d8a7SHans Petter Selasky 7292485d8a7SHans Petter Selasky if (bConfigurationValue == 0) { 7302485d8a7SHans Petter Selasky /* unconfigure */ 7312485d8a7SHans Petter Selasky i = 255; 7322485d8a7SHans Petter Selasky } else { 7332485d8a7SHans Petter Selasky /* lookup configuration index */ 7342485d8a7SHans Petter Selasky dev = usb_device(udev); 7352485d8a7SHans Petter Selasky 7362485d8a7SHans Petter Selasky /* check if the configuration array is not there */ 7372485d8a7SHans Petter Selasky if (dev->config == NULL) { 7382485d8a7SHans Petter Selasky return (-1); 7392485d8a7SHans Petter Selasky } 7402485d8a7SHans Petter Selasky for (i = 0;; i++) { 7412485d8a7SHans Petter Selasky if (i == dev->descriptor.bNumConfigurations) { 7422485d8a7SHans Petter Selasky /* "bConfigurationValue" not found */ 7432485d8a7SHans Petter Selasky return (-1); 7442485d8a7SHans Petter Selasky } 7452485d8a7SHans Petter Selasky if ((dev->config + i)->bConfigurationValue == 7462485d8a7SHans Petter Selasky bConfigurationValue) { 7472485d8a7SHans Petter Selasky break; 7482485d8a7SHans Petter Selasky } 7492485d8a7SHans Petter Selasky } 7502485d8a7SHans Petter Selasky } 7512485d8a7SHans Petter Selasky 7522485d8a7SHans Petter Selasky err = libusb20_dev_set_config_index((void *)udev, i); 7532485d8a7SHans Petter Selasky 7542485d8a7SHans Petter Selasky if (err) 7552485d8a7SHans Petter Selasky return (-1); 7562485d8a7SHans Petter Selasky 7572485d8a7SHans Petter Selasky return (0); 7582485d8a7SHans Petter Selasky } 7592485d8a7SHans Petter Selasky 7602485d8a7SHans Petter Selasky int 7612485d8a7SHans Petter Selasky usb_claim_interface(usb_dev_handle * dev, int interface) 7622485d8a7SHans Petter Selasky { 7632485d8a7SHans Petter Selasky struct libusb20_device *pdev = (void *)dev; 7642485d8a7SHans Petter Selasky 7652485d8a7SHans Petter Selasky pdev->claimed_interface = interface; 7662485d8a7SHans Petter Selasky 7672485d8a7SHans Petter Selasky return (0); 7682485d8a7SHans Petter Selasky } 7692485d8a7SHans Petter Selasky 7702485d8a7SHans Petter Selasky int 7712485d8a7SHans Petter Selasky usb_release_interface(usb_dev_handle * dev, int interface) 7722485d8a7SHans Petter Selasky { 7732485d8a7SHans Petter Selasky /* do nothing */ 7742485d8a7SHans Petter Selasky return (0); 7752485d8a7SHans Petter Selasky } 7762485d8a7SHans Petter Selasky 7772485d8a7SHans Petter Selasky int 7782485d8a7SHans Petter Selasky usb_set_altinterface(usb_dev_handle * dev, int alternate) 7792485d8a7SHans Petter Selasky { 7802485d8a7SHans Petter Selasky struct libusb20_device *pdev = (void *)dev; 7812485d8a7SHans Petter Selasky int err; 7822485d8a7SHans Petter Selasky uint8_t iface; 7832485d8a7SHans Petter Selasky 7842485d8a7SHans Petter Selasky iface = pdev->claimed_interface; 7852485d8a7SHans Petter Selasky 7862485d8a7SHans Petter Selasky err = libusb20_dev_set_alt_index((void *)dev, iface, alternate); 7872485d8a7SHans Petter Selasky 7882485d8a7SHans Petter Selasky if (err) 7892485d8a7SHans Petter Selasky return (-1); 7902485d8a7SHans Petter Selasky 7912485d8a7SHans Petter Selasky return (0); 7922485d8a7SHans Petter Selasky } 7932485d8a7SHans Petter Selasky 7942485d8a7SHans Petter Selasky int 7952485d8a7SHans Petter Selasky usb_resetep(usb_dev_handle * dev, unsigned int ep) 7962485d8a7SHans Petter Selasky { 7972485d8a7SHans Petter Selasky /* emulate an endpoint reset through clear-STALL */ 7982485d8a7SHans Petter Selasky return (usb_clear_halt(dev, ep)); 7992485d8a7SHans Petter Selasky } 8002485d8a7SHans Petter Selasky 8012485d8a7SHans Petter Selasky int 8022485d8a7SHans Petter Selasky usb_clear_halt(usb_dev_handle * dev, unsigned int ep) 8032485d8a7SHans Petter Selasky { 8042485d8a7SHans Petter Selasky struct libusb20_transfer *xfer; 8052485d8a7SHans Petter Selasky 8062485d8a7SHans Petter Selasky xfer = usb_get_transfer_by_ep_no(dev, ep); 8072485d8a7SHans Petter Selasky if (xfer == NULL) 8082485d8a7SHans Petter Selasky return (-1); 8092485d8a7SHans Petter Selasky 8102485d8a7SHans Petter Selasky libusb20_tr_clear_stall_sync(xfer); 8112485d8a7SHans Petter Selasky 8122485d8a7SHans Petter Selasky return (0); 8132485d8a7SHans Petter Selasky } 8142485d8a7SHans Petter Selasky 8152485d8a7SHans Petter Selasky int 8162485d8a7SHans Petter Selasky usb_reset(usb_dev_handle * dev) 8172485d8a7SHans Petter Selasky { 8182485d8a7SHans Petter Selasky int err; 8192485d8a7SHans Petter Selasky 8202485d8a7SHans Petter Selasky err = libusb20_dev_reset((void *)dev); 8212485d8a7SHans Petter Selasky 8222485d8a7SHans Petter Selasky if (err) 8232485d8a7SHans Petter Selasky return (-1); 8242485d8a7SHans Petter Selasky 8252485d8a7SHans Petter Selasky /* 8262485d8a7SHans Petter Selasky * Be compatible with LibUSB from sourceforge and close the 8272485d8a7SHans Petter Selasky * handle after reset! 8282485d8a7SHans Petter Selasky */ 8292485d8a7SHans Petter Selasky return (usb_close(dev)); 8302485d8a7SHans Petter Selasky } 8312485d8a7SHans Petter Selasky 8322485d8a7SHans Petter Selasky int 8332485d8a7SHans Petter Selasky usb_check_connected(usb_dev_handle * dev) 8342485d8a7SHans Petter Selasky { 8352485d8a7SHans Petter Selasky int err; 8362485d8a7SHans Petter Selasky 8372485d8a7SHans Petter Selasky err = libusb20_dev_check_connected((void *)dev); 8382485d8a7SHans Petter Selasky 8392485d8a7SHans Petter Selasky if (err) 8402485d8a7SHans Petter Selasky return (-1); 8412485d8a7SHans Petter Selasky 8422485d8a7SHans Petter Selasky return (0); 8432485d8a7SHans Petter Selasky } 8442485d8a7SHans Petter Selasky 8452485d8a7SHans Petter Selasky const char * 8462485d8a7SHans Petter Selasky usb_strerror(void) 8472485d8a7SHans Petter Selasky { 8482485d8a7SHans Petter Selasky /* TODO */ 8492485d8a7SHans Petter Selasky return ("Unknown error"); 8502485d8a7SHans Petter Selasky } 8512485d8a7SHans Petter Selasky 8522485d8a7SHans Petter Selasky void 8532485d8a7SHans Petter Selasky usb_init(void) 8542485d8a7SHans Petter Selasky { 8552485d8a7SHans Petter Selasky /* nothing to do */ 8562485d8a7SHans Petter Selasky return; 8572485d8a7SHans Petter Selasky } 8582485d8a7SHans Petter Selasky 8592485d8a7SHans Petter Selasky void 8602485d8a7SHans Petter Selasky usb_set_debug(int level) 8612485d8a7SHans Petter Selasky { 8622485d8a7SHans Petter Selasky /* use kernel UGEN debugging if you need to see what is going on */ 8632485d8a7SHans Petter Selasky return; 8642485d8a7SHans Petter Selasky } 8652485d8a7SHans Petter Selasky 8662485d8a7SHans Petter Selasky int 8672485d8a7SHans Petter Selasky usb_find_busses(void) 8682485d8a7SHans Petter Selasky { 8692485d8a7SHans Petter Selasky usb_busses = &usb_global_bus; 8702485d8a7SHans Petter Selasky return (1); 8712485d8a7SHans Petter Selasky } 8722485d8a7SHans Petter Selasky 8732485d8a7SHans Petter Selasky int 8742485d8a7SHans Petter Selasky usb_find_devices(void) 8752485d8a7SHans Petter Selasky { 8762485d8a7SHans Petter Selasky struct libusb20_device *pdev; 8772485d8a7SHans Petter Selasky struct usb_device *udev; 8782485d8a7SHans Petter Selasky struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; 8792485d8a7SHans Petter Selasky int devnum; 8802485d8a7SHans Petter Selasky int err; 8812485d8a7SHans Petter Selasky 8822485d8a7SHans Petter Selasky /* cleanup after last device search */ 8832485d8a7SHans Petter Selasky /* close all opened devices, if any */ 8842485d8a7SHans Petter Selasky 8852485d8a7SHans Petter Selasky while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 8862485d8a7SHans Petter Selasky udev = pdev->privLuData; 8872485d8a7SHans Petter Selasky libusb20_be_dequeue_device(usb_backend, pdev); 8882485d8a7SHans Petter Selasky libusb20_dev_free(pdev); 8892485d8a7SHans Petter Selasky if (udev != NULL) { 8902485d8a7SHans Petter Selasky LIST_DEL(usb_global_bus.devices, udev); 8912485d8a7SHans Petter Selasky free(udev); 8922485d8a7SHans Petter Selasky } 8932485d8a7SHans Petter Selasky } 8942485d8a7SHans Petter Selasky 8952485d8a7SHans Petter Selasky /* free old USB backend, if any */ 8962485d8a7SHans Petter Selasky 8972485d8a7SHans Petter Selasky libusb20_be_free(usb_backend); 8982485d8a7SHans Petter Selasky 8992485d8a7SHans Petter Selasky /* do a new backend device search */ 9002485d8a7SHans Petter Selasky usb_backend = libusb20_be_alloc_default(); 9012485d8a7SHans Petter Selasky if (usb_backend == NULL) { 9022485d8a7SHans Petter Selasky return (-1); 9032485d8a7SHans Petter Selasky } 9042485d8a7SHans Petter Selasky /* iterate all devices */ 9052485d8a7SHans Petter Selasky 9062485d8a7SHans Petter Selasky devnum = 1; 9072485d8a7SHans Petter Selasky pdev = NULL; 9082485d8a7SHans Petter Selasky while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) { 9092485d8a7SHans Petter Selasky udev = malloc(sizeof(*udev)); 9102485d8a7SHans Petter Selasky if (udev == NULL) 9112485d8a7SHans Petter Selasky break; 9122485d8a7SHans Petter Selasky 9132485d8a7SHans Petter Selasky memset(udev, 0, sizeof(*udev)); 9142485d8a7SHans Petter Selasky 9152485d8a7SHans Petter Selasky udev->bus = &usb_global_bus; 9162485d8a7SHans Petter Selasky 9172485d8a7SHans Petter Selasky snprintf(udev->filename, sizeof(udev->filename), 9182485d8a7SHans Petter Selasky "/dev/ugen%u.%u", 9192485d8a7SHans Petter Selasky libusb20_dev_get_bus_number(pdev), 9202485d8a7SHans Petter Selasky libusb20_dev_get_address(pdev)); 9212485d8a7SHans Petter Selasky 9222485d8a7SHans Petter Selasky ddesc = libusb20_dev_get_device_desc(pdev); 9232485d8a7SHans Petter Selasky 9242485d8a7SHans Petter Selasky udev->descriptor.bLength = sizeof(udev->descriptor); 9252485d8a7SHans Petter Selasky udev->descriptor.bDescriptorType = ddesc->bDescriptorType; 9262485d8a7SHans Petter Selasky udev->descriptor.bcdUSB = ddesc->bcdUSB; 9272485d8a7SHans Petter Selasky udev->descriptor.bDeviceClass = ddesc->bDeviceClass; 9282485d8a7SHans Petter Selasky udev->descriptor.bDeviceSubClass = ddesc->bDeviceSubClass; 9292485d8a7SHans Petter Selasky udev->descriptor.bDeviceProtocol = ddesc->bDeviceProtocol; 9302485d8a7SHans Petter Selasky udev->descriptor.bMaxPacketSize0 = ddesc->bMaxPacketSize0; 9312485d8a7SHans Petter Selasky udev->descriptor.idVendor = ddesc->idVendor; 9322485d8a7SHans Petter Selasky udev->descriptor.idProduct = ddesc->idProduct; 9332485d8a7SHans Petter Selasky udev->descriptor.bcdDevice = ddesc->bcdDevice; 9342485d8a7SHans Petter Selasky udev->descriptor.iManufacturer = ddesc->iManufacturer; 9352485d8a7SHans Petter Selasky udev->descriptor.iProduct = ddesc->iProduct; 9362485d8a7SHans Petter Selasky udev->descriptor.iSerialNumber = ddesc->iSerialNumber; 9372485d8a7SHans Petter Selasky udev->descriptor.bNumConfigurations = 9382485d8a7SHans Petter Selasky ddesc->bNumConfigurations; 9392485d8a7SHans Petter Selasky if (udev->descriptor.bNumConfigurations > USB_MAXCONFIG) { 9402485d8a7SHans Petter Selasky /* truncate number of configurations */ 9412485d8a7SHans Petter Selasky udev->descriptor.bNumConfigurations = USB_MAXCONFIG; 9422485d8a7SHans Petter Selasky } 9432485d8a7SHans Petter Selasky udev->devnum = devnum++; 9442485d8a7SHans Petter Selasky /* link together the two structures */ 9452485d8a7SHans Petter Selasky udev->dev = pdev; 9462485d8a7SHans Petter Selasky pdev->privLuData = udev; 9472485d8a7SHans Petter Selasky 9482485d8a7SHans Petter Selasky err = libusb20_dev_open(pdev, 0); 9492485d8a7SHans Petter Selasky if (err == 0) { 9502485d8a7SHans Petter Selasky /* XXX get all config descriptors by default */ 9512485d8a7SHans Petter Selasky usb_fetch_and_parse_descriptors((void *)pdev); 9522485d8a7SHans Petter Selasky libusb20_dev_close(pdev); 9532485d8a7SHans Petter Selasky } 9542485d8a7SHans Petter Selasky LIST_ADD(usb_global_bus.devices, udev); 9552485d8a7SHans Petter Selasky } 9562485d8a7SHans Petter Selasky 9572485d8a7SHans Petter Selasky return (devnum - 1); /* success */ 9582485d8a7SHans Petter Selasky } 9592485d8a7SHans Petter Selasky 9602485d8a7SHans Petter Selasky struct usb_device * 9612485d8a7SHans Petter Selasky usb_device(usb_dev_handle * dev) 9622485d8a7SHans Petter Selasky { 9632485d8a7SHans Petter Selasky struct libusb20_device *pdev; 9642485d8a7SHans Petter Selasky 9652485d8a7SHans Petter Selasky pdev = (void *)dev; 9662485d8a7SHans Petter Selasky 9672485d8a7SHans Petter Selasky return (pdev->privLuData); 9682485d8a7SHans Petter Selasky } 9692485d8a7SHans Petter Selasky 9702485d8a7SHans Petter Selasky struct usb_bus * 9712485d8a7SHans Petter Selasky usb_get_busses(void) 9722485d8a7SHans Petter Selasky { 9732485d8a7SHans Petter Selasky return (usb_busses); 9742485d8a7SHans Petter Selasky } 9754eb5923dSHans Petter Selasky 9764eb5923dSHans Petter Selasky int 9774eb5923dSHans Petter Selasky usb_get_driver_np(usb_dev_handle * dev, int interface, char *name, int namelen) 9784eb5923dSHans Petter Selasky { 9794eb5923dSHans Petter Selasky struct libusb20_device *pdev; 9804eb5923dSHans Petter Selasky char *ptr; 9814eb5923dSHans Petter Selasky int err; 9824eb5923dSHans Petter Selasky 9834eb5923dSHans Petter Selasky pdev = (void *)dev; 9844eb5923dSHans Petter Selasky 9854eb5923dSHans Petter Selasky if (pdev == NULL) 9864eb5923dSHans Petter Selasky return (-1); 9874eb5923dSHans Petter Selasky if (namelen < 1) 9884eb5923dSHans Petter Selasky return (-1); 9894eb5923dSHans Petter Selasky if (namelen > 255) 9904eb5923dSHans Petter Selasky namelen = 255; 9914eb5923dSHans Petter Selasky 9924eb5923dSHans Petter Selasky err = libusb20_dev_get_iface_desc(pdev, interface, name, namelen); 9934eb5923dSHans Petter Selasky if (err != 0) 9944eb5923dSHans Petter Selasky return (-1); 9954eb5923dSHans Petter Selasky 9964eb5923dSHans Petter Selasky /* we only want the driver name */ 9974eb5923dSHans Petter Selasky ptr = strstr(name, ":"); 9984eb5923dSHans Petter Selasky if (ptr != NULL) 9994eb5923dSHans Petter Selasky *ptr = 0; 10004eb5923dSHans Petter Selasky 10014eb5923dSHans Petter Selasky return (0); 10024eb5923dSHans Petter Selasky } 10034eb5923dSHans Petter Selasky 10044eb5923dSHans Petter Selasky int 10054eb5923dSHans Petter Selasky usb_detach_kernel_driver_np(usb_dev_handle * dev, int interface) 10064eb5923dSHans Petter Selasky { 10074eb5923dSHans Petter Selasky struct libusb20_device *pdev; 10084eb5923dSHans Petter Selasky int err; 10094eb5923dSHans Petter Selasky 10104eb5923dSHans Petter Selasky pdev = (void *)dev; 10114eb5923dSHans Petter Selasky 10124eb5923dSHans Petter Selasky if (pdev == NULL) 10134eb5923dSHans Petter Selasky return (-1); 10144eb5923dSHans Petter Selasky 10154eb5923dSHans Petter Selasky err = libusb20_dev_detach_kernel_driver(pdev, interface); 10164eb5923dSHans Petter Selasky if (err != 0) 10174eb5923dSHans Petter Selasky return (-1); 10184eb5923dSHans Petter Selasky 10194eb5923dSHans Petter Selasky return (0); 10204eb5923dSHans Petter Selasky } 1021