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 312485d8a7SHans Petter Selasky #include <sys/queue.h> 322485d8a7SHans Petter Selasky 332485d8a7SHans Petter Selasky #include <errno.h> 342485d8a7SHans Petter Selasky #include <stdio.h> 352485d8a7SHans Petter Selasky #include <stdlib.h> 362485d8a7SHans Petter Selasky 372485d8a7SHans Petter Selasky #include "libusb20.h" 382485d8a7SHans Petter Selasky #include "libusb20_desc.h" 392485d8a7SHans Petter Selasky #include "libusb20_int.h" 402485d8a7SHans Petter Selasky #include "usb.h" 412485d8a7SHans Petter Selasky 422485d8a7SHans Petter Selasky /* 432485d8a7SHans Petter Selasky * The two following macros were taken from the original LibUSB v0.1 442485d8a7SHans Petter Selasky * for sake of compatibility: 452485d8a7SHans Petter Selasky */ 462485d8a7SHans Petter Selasky #define LIST_ADD(begin, ent) \ 472485d8a7SHans Petter Selasky do { \ 482485d8a7SHans Petter Selasky if (begin) { \ 492485d8a7SHans Petter Selasky ent->next = begin; \ 502485d8a7SHans Petter Selasky ent->next->prev = ent; \ 512485d8a7SHans Petter Selasky } else { \ 522485d8a7SHans Petter Selasky ent->next = NULL; \ 532485d8a7SHans Petter Selasky } \ 542485d8a7SHans Petter Selasky ent->prev = NULL; \ 552485d8a7SHans Petter Selasky begin = ent; \ 562485d8a7SHans Petter Selasky } while(0) 572485d8a7SHans Petter Selasky 582485d8a7SHans Petter Selasky #define LIST_DEL(begin, ent) \ 592485d8a7SHans Petter Selasky do { \ 602485d8a7SHans Petter Selasky if (ent->prev) { \ 612485d8a7SHans Petter Selasky ent->prev->next = ent->next; \ 622485d8a7SHans Petter Selasky } else { \ 632485d8a7SHans Petter Selasky begin = ent->next; \ 642485d8a7SHans Petter Selasky } \ 652485d8a7SHans Petter Selasky if (ent->next) { \ 662485d8a7SHans Petter Selasky ent->next->prev = ent->prev; \ 672485d8a7SHans Petter Selasky } \ 682485d8a7SHans Petter Selasky ent->prev = NULL; \ 692485d8a7SHans Petter Selasky ent->next = NULL; \ 702485d8a7SHans Petter Selasky } while (0) 712485d8a7SHans Petter Selasky 722485d8a7SHans Petter Selasky struct usb_bus *usb_busses = NULL; 732485d8a7SHans Petter Selasky 742485d8a7SHans Petter Selasky static struct usb_bus usb_global_bus = { 752485d8a7SHans Petter Selasky .dirname = {"/dev/usb"}, 762485d8a7SHans Petter Selasky .root_dev = NULL, 772485d8a7SHans Petter Selasky .devices = NULL, 782485d8a7SHans Petter Selasky }; 792485d8a7SHans Petter Selasky 802485d8a7SHans Petter Selasky static struct libusb20_backend *usb_backend = NULL; 812485d8a7SHans Petter Selasky 822485d8a7SHans Petter Selasky struct usb_parse_state { 832485d8a7SHans Petter Selasky 842485d8a7SHans Petter Selasky struct { 852485d8a7SHans Petter Selasky struct libusb20_endpoint *currep; 862485d8a7SHans Petter Selasky struct libusb20_interface *currifc; 872485d8a7SHans Petter Selasky struct libusb20_config *currcfg; 882485d8a7SHans Petter Selasky struct libusb20_me_struct *currextra; 892485d8a7SHans Petter Selasky } a; 902485d8a7SHans Petter Selasky 912485d8a7SHans Petter Selasky struct { 922485d8a7SHans Petter Selasky struct usb_config_descriptor *currcfg; 932485d8a7SHans Petter Selasky struct usb_interface_descriptor *currifc; 942485d8a7SHans Petter Selasky struct usb_endpoint_descriptor *currep; 952485d8a7SHans Petter Selasky struct usb_interface *currifcw; 962485d8a7SHans Petter Selasky uint8_t *currextra; 972485d8a7SHans Petter Selasky } b; 982485d8a7SHans Petter Selasky 992485d8a7SHans Petter Selasky uint8_t preparse; 1002485d8a7SHans Petter Selasky }; 1012485d8a7SHans Petter Selasky 1022485d8a7SHans Petter Selasky static struct libusb20_transfer * 1032485d8a7SHans Petter Selasky usb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no) 1042485d8a7SHans Petter Selasky { 1052485d8a7SHans Petter Selasky struct libusb20_device *pdev = (void *)dev; 1062485d8a7SHans Petter Selasky struct libusb20_transfer *xfer; 1072485d8a7SHans Petter Selasky int err; 1082485d8a7SHans Petter Selasky uint32_t bufsize; 1092485d8a7SHans Petter Selasky uint8_t x; 1102485d8a7SHans Petter Selasky uint8_t speed; 1112485d8a7SHans Petter Selasky 1122485d8a7SHans Petter Selasky x = (ep_no & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 2; 1132485d8a7SHans Petter Selasky 1142485d8a7SHans Petter Selasky if (ep_no & LIBUSB20_ENDPOINT_DIR_MASK) { 1152485d8a7SHans Petter Selasky /* this is an IN endpoint */ 1162485d8a7SHans Petter Selasky x |= 1; 1172485d8a7SHans Petter Selasky } 1182485d8a7SHans Petter Selasky speed = libusb20_dev_get_speed(pdev); 1192485d8a7SHans Petter Selasky 1202485d8a7SHans Petter Selasky /* select a sensible buffer size */ 1212485d8a7SHans Petter Selasky if (speed == LIBUSB20_SPEED_LOW) { 1222485d8a7SHans Petter Selasky bufsize = 256; 1232485d8a7SHans Petter Selasky } else if (speed == LIBUSB20_SPEED_FULL) { 1242485d8a7SHans Petter Selasky bufsize = 4096; 1252485d8a7SHans Petter Selasky } else { 1262485d8a7SHans Petter Selasky bufsize = 16384; 1272485d8a7SHans Petter Selasky } 1282485d8a7SHans Petter Selasky 1292485d8a7SHans Petter Selasky xfer = libusb20_tr_get_pointer(pdev, x); 1302485d8a7SHans Petter Selasky 1312485d8a7SHans Petter Selasky if (xfer == NULL) 1322485d8a7SHans Petter Selasky return (xfer); 1332485d8a7SHans Petter Selasky 1342485d8a7SHans Petter Selasky err = libusb20_tr_open(xfer, bufsize, 1, ep_no); 1352485d8a7SHans Petter Selasky if (err == LIBUSB20_ERROR_BUSY) { 1362485d8a7SHans Petter Selasky /* already opened */ 1372485d8a7SHans Petter Selasky return (xfer); 1382485d8a7SHans Petter Selasky } else if (err) { 1392485d8a7SHans Petter Selasky return (NULL); 1402485d8a7SHans Petter Selasky } 1412485d8a7SHans Petter Selasky /* success */ 1422485d8a7SHans Petter Selasky return (xfer); 1432485d8a7SHans Petter Selasky } 1442485d8a7SHans Petter Selasky 1452485d8a7SHans Petter Selasky usb_dev_handle * 1462485d8a7SHans Petter Selasky usb_open(struct usb_device *dev) 1472485d8a7SHans Petter Selasky { 1482485d8a7SHans Petter Selasky int err; 1492485d8a7SHans Petter Selasky 1502485d8a7SHans Petter Selasky err = libusb20_dev_open(dev->dev, 16 * 2); 1512485d8a7SHans Petter Selasky if (err == LIBUSB20_ERROR_BUSY) { 1522485d8a7SHans Petter Selasky /* 1532485d8a7SHans Petter Selasky * Workaround buggy USB applications which open the USB 1542485d8a7SHans Petter Selasky * device multiple times: 1552485d8a7SHans Petter Selasky */ 1562485d8a7SHans Petter Selasky return (dev->dev); 1572485d8a7SHans Petter Selasky } 1582485d8a7SHans Petter Selasky if (err) 1592485d8a7SHans Petter Selasky return (NULL); 1602485d8a7SHans Petter Selasky 1612485d8a7SHans Petter Selasky /* 1622485d8a7SHans Petter Selasky * Dequeue USB device from backend queue so that it does not get 1632485d8a7SHans Petter Selasky * freed when the backend is re-scanned: 1642485d8a7SHans Petter Selasky */ 1652485d8a7SHans Petter Selasky libusb20_be_dequeue_device(usb_backend, dev->dev); 1662485d8a7SHans Petter Selasky 1672485d8a7SHans Petter Selasky return (dev->dev); 1682485d8a7SHans Petter Selasky } 1692485d8a7SHans Petter Selasky 1702485d8a7SHans Petter Selasky int 1712485d8a7SHans Petter Selasky usb_close(usb_dev_handle * udev) 1722485d8a7SHans Petter Selasky { 1732485d8a7SHans Petter Selasky struct usb_device *dev; 1742485d8a7SHans Petter Selasky int err; 1752485d8a7SHans Petter Selasky 1762485d8a7SHans Petter Selasky err = libusb20_dev_close((void *)udev); 1772485d8a7SHans Petter Selasky 1782485d8a7SHans Petter Selasky if (err) 1792485d8a7SHans Petter Selasky return (-1); 1802485d8a7SHans Petter Selasky 1812485d8a7SHans Petter Selasky if (usb_backend != NULL) { 1822485d8a7SHans Petter Selasky /* 1832485d8a7SHans Petter Selasky * Enqueue USB device to backend queue so that it gets freed 1842485d8a7SHans Petter Selasky * when the backend is re-scanned: 1852485d8a7SHans Petter Selasky */ 1862485d8a7SHans Petter Selasky libusb20_be_enqueue_device(usb_backend, (void *)udev); 1872485d8a7SHans Petter Selasky } else { 1882485d8a7SHans Petter Selasky /* 1892485d8a7SHans Petter Selasky * The backend is gone. Free device data so that we 1902485d8a7SHans Petter Selasky * don't start leaking memory! 1912485d8a7SHans Petter Selasky */ 1922485d8a7SHans Petter Selasky dev = usb_device(udev); 1932485d8a7SHans Petter Selasky libusb20_dev_free((void *)udev); 1942485d8a7SHans Petter Selasky LIST_DEL(usb_global_bus.devices, dev); 1952485d8a7SHans Petter Selasky free(dev); 1962485d8a7SHans Petter Selasky } 1972485d8a7SHans Petter Selasky return (0); 1982485d8a7SHans Petter Selasky } 1992485d8a7SHans Petter Selasky 2002485d8a7SHans Petter Selasky int 2012485d8a7SHans Petter Selasky usb_get_string(usb_dev_handle * dev, int strindex, 2022485d8a7SHans Petter Selasky int langid, char *buf, size_t buflen) 2032485d8a7SHans Petter Selasky { 2042485d8a7SHans Petter Selasky int err; 2052485d8a7SHans Petter Selasky 206*4eb5923dSHans Petter Selasky if (dev == NULL) 207*4eb5923dSHans Petter Selasky return (-1); 208*4eb5923dSHans Petter Selasky 209*4eb5923dSHans Petter Selasky if (buflen > 65535) 210*4eb5923dSHans Petter Selasky buflen = 65535; 211*4eb5923dSHans Petter Selasky 2122485d8a7SHans Petter Selasky err = libusb20_dev_req_string_sync((void *)dev, 2132485d8a7SHans Petter Selasky strindex, langid, buf, buflen); 2142485d8a7SHans Petter Selasky 2152485d8a7SHans Petter Selasky if (err) 2162485d8a7SHans Petter Selasky return (-1); 2172485d8a7SHans Petter Selasky 2182485d8a7SHans Petter Selasky return (0); 2192485d8a7SHans Petter Selasky } 2202485d8a7SHans Petter Selasky 2212485d8a7SHans Petter Selasky int 2222485d8a7SHans Petter Selasky usb_get_string_simple(usb_dev_handle * dev, int strindex, 2232485d8a7SHans Petter Selasky char *buf, size_t buflen) 2242485d8a7SHans Petter Selasky { 2252485d8a7SHans Petter Selasky int err; 2262485d8a7SHans Petter Selasky 227*4eb5923dSHans Petter Selasky if (dev == NULL) 228*4eb5923dSHans Petter Selasky return (-1); 229*4eb5923dSHans Petter Selasky 230*4eb5923dSHans Petter Selasky if (buflen > 65535) 231*4eb5923dSHans Petter Selasky buflen = 65535; 232*4eb5923dSHans Petter Selasky 2332485d8a7SHans Petter Selasky err = libusb20_dev_req_string_simple_sync((void *)dev, 2342485d8a7SHans Petter Selasky strindex, buf, buflen); 2352485d8a7SHans Petter Selasky 2362485d8a7SHans Petter Selasky if (err) 2372485d8a7SHans Petter Selasky return (-1); 2382485d8a7SHans Petter Selasky 2392485d8a7SHans Petter Selasky return (strlen(buf)); 2402485d8a7SHans Petter Selasky } 2412485d8a7SHans Petter Selasky 2422485d8a7SHans Petter Selasky int 2432485d8a7SHans Petter Selasky usb_get_descriptor_by_endpoint(usb_dev_handle * udev, int ep, uint8_t type, 2442485d8a7SHans Petter Selasky uint8_t ep_index, void *buf, int size) 2452485d8a7SHans Petter Selasky { 2462485d8a7SHans Petter Selasky memset(buf, 0, size); 2472485d8a7SHans Petter Selasky 248*4eb5923dSHans Petter Selasky if (udev == NULL) 249*4eb5923dSHans Petter Selasky return (-1); 250*4eb5923dSHans Petter Selasky 251*4eb5923dSHans Petter Selasky if (size > 65535) 252*4eb5923dSHans Petter Selasky size = 65535; 253*4eb5923dSHans Petter Selasky 2542485d8a7SHans Petter Selasky return (usb_control_msg(udev, ep | USB_ENDPOINT_IN, 2552485d8a7SHans Petter Selasky USB_REQ_GET_DESCRIPTOR, (type << 8) + ep_index, 0, 2562485d8a7SHans Petter Selasky buf, size, 1000)); 2572485d8a7SHans Petter Selasky } 2582485d8a7SHans Petter Selasky 2592485d8a7SHans Petter Selasky int 2602485d8a7SHans Petter Selasky usb_get_descriptor(usb_dev_handle * udev, uint8_t type, uint8_t desc_index, 2612485d8a7SHans Petter Selasky void *buf, int size) 2622485d8a7SHans Petter Selasky { 2632485d8a7SHans Petter Selasky memset(buf, 0, size); 2642485d8a7SHans Petter Selasky 265*4eb5923dSHans Petter Selasky if (udev == NULL) 266*4eb5923dSHans Petter Selasky return (-1); 267*4eb5923dSHans Petter Selasky 268*4eb5923dSHans Petter Selasky if (size > 65535) 269*4eb5923dSHans Petter Selasky size = 65535; 270*4eb5923dSHans Petter Selasky 2712485d8a7SHans Petter Selasky return (usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, 2722485d8a7SHans Petter Selasky (type << 8) + desc_index, 0, buf, size, 1000)); 2732485d8a7SHans Petter Selasky } 2742485d8a7SHans Petter Selasky 2752485d8a7SHans Petter Selasky int 2762485d8a7SHans Petter Selasky usb_parse_descriptor(uint8_t *source, char *description, void *dest) 2772485d8a7SHans Petter Selasky { 2782485d8a7SHans Petter Selasky uint8_t *sp = source; 2792485d8a7SHans Petter Selasky uint8_t *dp = dest; 2802485d8a7SHans Petter Selasky uint16_t w; 2812485d8a7SHans Petter Selasky uint32_t d; 2822485d8a7SHans Petter Selasky char *cp; 2832485d8a7SHans Petter Selasky 2842485d8a7SHans Petter Selasky for (cp = description; *cp; cp++) { 2852485d8a7SHans Petter Selasky switch (*cp) { 2862485d8a7SHans Petter Selasky case 'b': /* 8-bit byte */ 2872485d8a7SHans Petter Selasky *dp++ = *sp++; 2882485d8a7SHans Petter Selasky break; 2892485d8a7SHans Petter Selasky /* 2902485d8a7SHans Petter Selasky * 16-bit word, convert from little endian to CPU 2912485d8a7SHans Petter Selasky */ 2922485d8a7SHans Petter Selasky case 'w': 2932485d8a7SHans Petter Selasky w = (sp[1] << 8) | sp[0]; 2942485d8a7SHans Petter Selasky sp += 2; 2952485d8a7SHans Petter Selasky /* Align to word boundary */ 2962485d8a7SHans Petter Selasky dp += ((dp - (uint8_t *)0) & 1); 2972485d8a7SHans Petter Selasky *((uint16_t *)dp) = w; 2982485d8a7SHans Petter Selasky dp += 2; 2992485d8a7SHans Petter Selasky break; 3002485d8a7SHans Petter Selasky /* 3012485d8a7SHans Petter Selasky * 32-bit dword, convert from little endian to CPU 3022485d8a7SHans Petter Selasky */ 3032485d8a7SHans Petter Selasky case 'd': 3042485d8a7SHans Petter Selasky d = (sp[3] << 24) | (sp[2] << 16) | 3052485d8a7SHans Petter Selasky (sp[1] << 8) | sp[0]; 3062485d8a7SHans Petter Selasky sp += 4; 3072485d8a7SHans Petter Selasky /* Align to word boundary */ 3082485d8a7SHans Petter Selasky dp += ((dp - (uint8_t *)0) & 1); 3092485d8a7SHans Petter Selasky /* Align to double word boundary */ 3102485d8a7SHans Petter Selasky dp += ((dp - (uint8_t *)0) & 2); 3112485d8a7SHans Petter Selasky *((uint32_t *)dp) = d; 3122485d8a7SHans Petter Selasky dp += 4; 3132485d8a7SHans Petter Selasky break; 3142485d8a7SHans Petter Selasky } 3152485d8a7SHans Petter Selasky } 3162485d8a7SHans Petter Selasky return (sp - source); 3172485d8a7SHans Petter Selasky } 3182485d8a7SHans Petter Selasky 3192485d8a7SHans Petter Selasky static void 3202485d8a7SHans Petter Selasky usb_parse_extra(struct usb_parse_state *ps, uint8_t **pptr, int *plen) 3212485d8a7SHans Petter Selasky { 3222485d8a7SHans Petter Selasky void *ptr; 3232485d8a7SHans Petter Selasky uint16_t len; 3242485d8a7SHans Petter Selasky 3252485d8a7SHans Petter Selasky ptr = ps->a.currextra->ptr; 3262485d8a7SHans Petter Selasky len = ps->a.currextra->len; 3272485d8a7SHans Petter Selasky 3282485d8a7SHans Petter Selasky if (ps->preparse == 0) { 3292485d8a7SHans Petter Selasky memcpy(ps->b.currextra, ptr, len); 3302485d8a7SHans Petter Selasky *pptr = ps->b.currextra; 3312485d8a7SHans Petter Selasky *plen = len; 3322485d8a7SHans Petter Selasky } 3332485d8a7SHans Petter Selasky ps->b.currextra += len; 3342485d8a7SHans Petter Selasky return; 3352485d8a7SHans Petter Selasky } 3362485d8a7SHans Petter Selasky 3372485d8a7SHans Petter Selasky static void 3382485d8a7SHans Petter Selasky usb_parse_endpoint(struct usb_parse_state *ps) 3392485d8a7SHans Petter Selasky { 3402485d8a7SHans Petter Selasky struct usb_endpoint_descriptor *bep; 3412485d8a7SHans Petter Selasky struct libusb20_endpoint *aep; 3422485d8a7SHans Petter Selasky 3432485d8a7SHans Petter Selasky aep = ps->a.currep; 3442485d8a7SHans Petter Selasky bep = ps->b.currep++; 3452485d8a7SHans Petter Selasky 3462485d8a7SHans Petter Selasky if (ps->preparse == 0) { 3472485d8a7SHans Petter Selasky /* copy descriptor fields */ 3482485d8a7SHans Petter Selasky bep->bLength = aep->desc.bLength; 3492485d8a7SHans Petter Selasky bep->bDescriptorType = aep->desc.bDescriptorType; 3502485d8a7SHans Petter Selasky bep->bEndpointAddress = aep->desc.bEndpointAddress; 3512485d8a7SHans Petter Selasky bep->bmAttributes = aep->desc.bmAttributes; 3522485d8a7SHans Petter Selasky bep->wMaxPacketSize = aep->desc.wMaxPacketSize; 3532485d8a7SHans Petter Selasky bep->bInterval = aep->desc.bInterval; 3542485d8a7SHans Petter Selasky bep->bRefresh = aep->desc.bRefresh; 3552485d8a7SHans Petter Selasky bep->bSynchAddress = aep->desc.bSynchAddress; 3562485d8a7SHans Petter Selasky } 3572485d8a7SHans Petter Selasky ps->a.currextra = &aep->extra; 3582485d8a7SHans Petter Selasky usb_parse_extra(ps, &bep->extra, &bep->extralen); 3592485d8a7SHans Petter Selasky return; 3602485d8a7SHans Petter Selasky } 3612485d8a7SHans Petter Selasky 3622485d8a7SHans Petter Selasky static void 3632485d8a7SHans Petter Selasky usb_parse_iface_sub(struct usb_parse_state *ps) 3642485d8a7SHans Petter Selasky { 3652485d8a7SHans Petter Selasky struct libusb20_interface *aifc; 3662485d8a7SHans Petter Selasky struct usb_interface_descriptor *bifc; 3672485d8a7SHans Petter Selasky uint8_t x; 3682485d8a7SHans Petter Selasky 3692485d8a7SHans Petter Selasky aifc = ps->a.currifc; 3702485d8a7SHans Petter Selasky bifc = ps->b.currifc++; 3712485d8a7SHans Petter Selasky 3722485d8a7SHans Petter Selasky if (ps->preparse == 0) { 3732485d8a7SHans Petter Selasky /* copy descriptor fields */ 3742485d8a7SHans Petter Selasky bifc->bLength = aifc->desc.bLength; 3752485d8a7SHans Petter Selasky bifc->bDescriptorType = aifc->desc.bDescriptorType; 3762485d8a7SHans Petter Selasky bifc->bInterfaceNumber = aifc->desc.bInterfaceNumber; 3772485d8a7SHans Petter Selasky bifc->bAlternateSetting = aifc->desc.bAlternateSetting; 3782485d8a7SHans Petter Selasky bifc->bNumEndpoints = aifc->num_endpoints; 3792485d8a7SHans Petter Selasky bifc->bInterfaceClass = aifc->desc.bInterfaceClass; 3802485d8a7SHans Petter Selasky bifc->bInterfaceSubClass = aifc->desc.bInterfaceSubClass; 3812485d8a7SHans Petter Selasky bifc->bInterfaceProtocol = aifc->desc.bInterfaceProtocol; 3822485d8a7SHans Petter Selasky bifc->iInterface = aifc->desc.iInterface; 3832485d8a7SHans Petter Selasky bifc->endpoint = ps->b.currep; 3842485d8a7SHans Petter Selasky } 3852485d8a7SHans Petter Selasky for (x = 0; x != aifc->num_endpoints; x++) { 3862485d8a7SHans Petter Selasky ps->a.currep = aifc->endpoints + x; 3872485d8a7SHans Petter Selasky usb_parse_endpoint(ps); 3882485d8a7SHans Petter Selasky } 3892485d8a7SHans Petter Selasky 3902485d8a7SHans Petter Selasky ps->a.currextra = &aifc->extra; 3912485d8a7SHans Petter Selasky usb_parse_extra(ps, &bifc->extra, &bifc->extralen); 3922485d8a7SHans Petter Selasky return; 3932485d8a7SHans Petter Selasky } 3942485d8a7SHans Petter Selasky 3952485d8a7SHans Petter Selasky static void 3962485d8a7SHans Petter Selasky usb_parse_iface(struct usb_parse_state *ps) 3972485d8a7SHans Petter Selasky { 3982485d8a7SHans Petter Selasky struct libusb20_interface *aifc; 3992485d8a7SHans Petter Selasky struct usb_interface *bifc; 4002485d8a7SHans Petter Selasky uint8_t x; 4012485d8a7SHans Petter Selasky 4022485d8a7SHans Petter Selasky aifc = ps->a.currifc; 4032485d8a7SHans Petter Selasky bifc = ps->b.currifcw++; 4042485d8a7SHans Petter Selasky 4052485d8a7SHans Petter Selasky if (ps->preparse == 0) { 4062485d8a7SHans Petter Selasky /* initialise interface wrapper */ 4072485d8a7SHans Petter Selasky bifc->altsetting = ps->b.currifc; 4082485d8a7SHans Petter Selasky bifc->num_altsetting = aifc->num_altsetting + 1; 4092485d8a7SHans Petter Selasky } 4102485d8a7SHans Petter Selasky usb_parse_iface_sub(ps); 4112485d8a7SHans Petter Selasky 4122485d8a7SHans Petter Selasky for (x = 0; x != aifc->num_altsetting; x++) { 4132485d8a7SHans Petter Selasky ps->a.currifc = aifc->altsetting + x; 4142485d8a7SHans Petter Selasky usb_parse_iface_sub(ps); 4152485d8a7SHans Petter Selasky } 4162485d8a7SHans Petter Selasky return; 4172485d8a7SHans Petter Selasky } 4182485d8a7SHans Petter Selasky 4192485d8a7SHans Petter Selasky static void 4202485d8a7SHans Petter Selasky usb_parse_config(struct usb_parse_state *ps) 4212485d8a7SHans Petter Selasky { 4222485d8a7SHans Petter Selasky struct libusb20_config *acfg; 4232485d8a7SHans Petter Selasky struct usb_config_descriptor *bcfg; 4242485d8a7SHans Petter Selasky uint8_t x; 4252485d8a7SHans Petter Selasky 4262485d8a7SHans Petter Selasky acfg = ps->a.currcfg; 4272485d8a7SHans Petter Selasky bcfg = ps->b.currcfg; 4282485d8a7SHans Petter Selasky 4292485d8a7SHans Petter Selasky if (ps->preparse == 0) { 4302485d8a7SHans Petter Selasky /* initialise config wrapper */ 4312485d8a7SHans Petter Selasky bcfg->bLength = acfg->desc.bLength; 4322485d8a7SHans Petter Selasky bcfg->bDescriptorType = acfg->desc.bDescriptorType; 4332485d8a7SHans Petter Selasky bcfg->wTotalLength = acfg->desc.wTotalLength; 4342485d8a7SHans Petter Selasky bcfg->bNumInterfaces = acfg->num_interface; 4352485d8a7SHans Petter Selasky bcfg->bConfigurationValue = acfg->desc.bConfigurationValue; 4362485d8a7SHans Petter Selasky bcfg->iConfiguration = acfg->desc.iConfiguration; 4372485d8a7SHans Petter Selasky bcfg->bmAttributes = acfg->desc.bmAttributes; 4382485d8a7SHans Petter Selasky bcfg->MaxPower = acfg->desc.bMaxPower; 4392485d8a7SHans Petter Selasky bcfg->interface = ps->b.currifcw; 4402485d8a7SHans Petter Selasky } 4412485d8a7SHans Petter Selasky for (x = 0; x != acfg->num_interface; x++) { 4422485d8a7SHans Petter Selasky ps->a.currifc = acfg->interface + x; 4432485d8a7SHans Petter Selasky usb_parse_iface(ps); 4442485d8a7SHans Petter Selasky } 4452485d8a7SHans Petter Selasky 4462485d8a7SHans Petter Selasky ps->a.currextra = &acfg->extra; 4472485d8a7SHans Petter Selasky usb_parse_extra(ps, &bcfg->extra, &bcfg->extralen); 4482485d8a7SHans Petter Selasky return; 4492485d8a7SHans Petter Selasky } 4502485d8a7SHans Petter Selasky 4512485d8a7SHans Petter Selasky int 4522485d8a7SHans Petter Selasky usb_parse_configuration(struct usb_config_descriptor *config, 4532485d8a7SHans Petter Selasky uint8_t *buffer) 4542485d8a7SHans Petter Selasky { 4552485d8a7SHans Petter Selasky struct usb_parse_state ps; 4562485d8a7SHans Petter Selasky uint8_t *ptr; 4572485d8a7SHans Petter Selasky uint32_t a; 4582485d8a7SHans Petter Selasky uint32_t b; 4592485d8a7SHans Petter Selasky uint32_t c; 4602485d8a7SHans Petter Selasky uint32_t d; 4612485d8a7SHans Petter Selasky 4622485d8a7SHans Petter Selasky if ((buffer == NULL) || (config == NULL)) { 4632485d8a7SHans Petter Selasky return (-1); 4642485d8a7SHans Petter Selasky } 4652485d8a7SHans Petter Selasky memset(&ps, 0, sizeof(ps)); 4662485d8a7SHans Petter Selasky 4672485d8a7SHans Petter Selasky ps.a.currcfg = libusb20_parse_config_desc(buffer); 4682485d8a7SHans Petter Selasky ps.b.currcfg = config; 4692485d8a7SHans Petter Selasky if (ps.a.currcfg == NULL) { 4702485d8a7SHans Petter Selasky /* could not parse config or out of memory */ 4712485d8a7SHans Petter Selasky return (-1); 4722485d8a7SHans Petter Selasky } 4732485d8a7SHans Petter Selasky /* do the pre-parse */ 4742485d8a7SHans Petter Selasky ps.preparse = 1; 4752485d8a7SHans Petter Selasky usb_parse_config(&ps); 4762485d8a7SHans Petter Selasky 4772485d8a7SHans Petter Selasky a = ((uint8_t *)(ps.b.currifcw) - ((uint8_t *)0)); 4782485d8a7SHans Petter Selasky b = ((uint8_t *)(ps.b.currifc) - ((uint8_t *)0)); 4792485d8a7SHans Petter Selasky c = ((uint8_t *)(ps.b.currep) - ((uint8_t *)0)); 4802485d8a7SHans Petter Selasky d = ((uint8_t *)(ps.b.currextra) - ((uint8_t *)0)); 4812485d8a7SHans Petter Selasky 4822485d8a7SHans Petter Selasky /* allocate memory for our configuration */ 4832485d8a7SHans Petter Selasky ptr = malloc(a + b + c + d); 4842485d8a7SHans Petter Selasky if (ptr == NULL) { 4852485d8a7SHans Petter Selasky /* free config structure */ 4862485d8a7SHans Petter Selasky free(ps.a.currcfg); 4872485d8a7SHans Petter Selasky return (-1); 4882485d8a7SHans Petter Selasky } 4892485d8a7SHans Petter Selasky 4902485d8a7SHans Petter Selasky /* "currifcw" must be first, hence this pointer is freed */ 4912485d8a7SHans Petter Selasky ps.b.currifcw = (void *)(ptr); 4922485d8a7SHans Petter Selasky ps.b.currifc = (void *)(ptr + a); 4932485d8a7SHans Petter Selasky ps.b.currep = (void *)(ptr + a + b); 4942485d8a7SHans Petter Selasky ps.b.currextra = (void *)(ptr + a + b + c); 4952485d8a7SHans Petter Selasky 4962485d8a7SHans Petter Selasky /* generate a libusb v0.1 compatible structure */ 4972485d8a7SHans Petter Selasky ps.preparse = 0; 4982485d8a7SHans Petter Selasky usb_parse_config(&ps); 4992485d8a7SHans Petter Selasky 5002485d8a7SHans Petter Selasky /* free config structure */ 5012485d8a7SHans Petter Selasky free(ps.a.currcfg); 5022485d8a7SHans Petter Selasky 5032485d8a7SHans Petter Selasky return (0); /* success */ 5042485d8a7SHans Petter Selasky } 5052485d8a7SHans Petter Selasky 5062485d8a7SHans Petter Selasky void 5072485d8a7SHans Petter Selasky usb_destroy_configuration(struct usb_device *dev) 5082485d8a7SHans Petter Selasky { 5092485d8a7SHans Petter Selasky uint8_t c; 5102485d8a7SHans Petter Selasky 5112485d8a7SHans Petter Selasky if (dev->config == NULL) { 5122485d8a7SHans Petter Selasky return; 5132485d8a7SHans Petter Selasky } 5142485d8a7SHans Petter Selasky for (c = 0; c != dev->descriptor.bNumConfigurations; c++) { 5152485d8a7SHans Petter Selasky struct usb_config_descriptor *cf = &dev->config[c]; 5162485d8a7SHans Petter Selasky 5172485d8a7SHans Petter Selasky if (cf->interface != NULL) { 5182485d8a7SHans Petter Selasky free(cf->interface); 5192485d8a7SHans Petter Selasky cf->interface = NULL; 5202485d8a7SHans Petter Selasky } 5212485d8a7SHans Petter Selasky } 5222485d8a7SHans Petter Selasky 5232485d8a7SHans Petter Selasky free(dev->config); 5242485d8a7SHans Petter Selasky dev->config = NULL; 5252485d8a7SHans Petter Selasky return; 5262485d8a7SHans Petter Selasky } 5272485d8a7SHans Petter Selasky 5282485d8a7SHans Petter Selasky void 5292485d8a7SHans Petter Selasky usb_fetch_and_parse_descriptors(usb_dev_handle * udev) 5302485d8a7SHans Petter Selasky { 5312485d8a7SHans Petter Selasky struct usb_device *dev; 5322485d8a7SHans Petter Selasky struct libusb20_device *pdev; 5332485d8a7SHans Petter Selasky uint8_t *ptr; 5342485d8a7SHans Petter Selasky int error; 5352485d8a7SHans Petter Selasky uint32_t size; 5362485d8a7SHans Petter Selasky uint16_t len; 5372485d8a7SHans Petter Selasky uint8_t x; 5382485d8a7SHans Petter Selasky 5392485d8a7SHans Petter Selasky if (udev == NULL) { 5402485d8a7SHans Petter Selasky /* be NULL safe */ 5412485d8a7SHans Petter Selasky return; 5422485d8a7SHans Petter Selasky } 5432485d8a7SHans Petter Selasky dev = usb_device(udev); 5442485d8a7SHans Petter Selasky pdev = (void *)udev; 5452485d8a7SHans Petter Selasky 5462485d8a7SHans Petter Selasky if (dev->descriptor.bNumConfigurations == 0) { 5472485d8a7SHans Petter Selasky /* invalid device */ 5482485d8a7SHans Petter Selasky return; 5492485d8a7SHans Petter Selasky } 5502485d8a7SHans Petter Selasky size = dev->descriptor.bNumConfigurations * 5512485d8a7SHans Petter Selasky sizeof(struct usb_config_descriptor); 5522485d8a7SHans Petter Selasky 5532485d8a7SHans Petter Selasky dev->config = malloc(size); 5542485d8a7SHans Petter Selasky if (dev->config == NULL) { 5552485d8a7SHans Petter Selasky /* out of memory */ 5562485d8a7SHans Petter Selasky return; 5572485d8a7SHans Petter Selasky } 5582485d8a7SHans Petter Selasky memset(dev->config, 0, size); 5592485d8a7SHans Petter Selasky 5602485d8a7SHans Petter Selasky for (x = 0; x != dev->descriptor.bNumConfigurations; x++) { 5612485d8a7SHans Petter Selasky 5622485d8a7SHans Petter Selasky error = (pdev->methods->get_config_desc_full) ( 5632485d8a7SHans Petter Selasky pdev, &ptr, &len, x); 5642485d8a7SHans Petter Selasky 5652485d8a7SHans Petter Selasky if (error) { 5662485d8a7SHans Petter Selasky usb_destroy_configuration(dev); 5672485d8a7SHans Petter Selasky return; 5682485d8a7SHans Petter Selasky } 5692485d8a7SHans Petter Selasky usb_parse_configuration(dev->config + x, ptr); 5702485d8a7SHans Petter Selasky 5712485d8a7SHans Petter Selasky /* free config buffer */ 5722485d8a7SHans Petter Selasky free(ptr); 5732485d8a7SHans Petter Selasky } 5742485d8a7SHans Petter Selasky return; 5752485d8a7SHans Petter Selasky } 5762485d8a7SHans Petter Selasky 5772485d8a7SHans Petter Selasky static int 5782485d8a7SHans Petter Selasky usb_std_io(usb_dev_handle * dev, int ep, char *bytes, int size, 5792485d8a7SHans Petter Selasky int timeout, int is_intr) 5802485d8a7SHans Petter Selasky { 5812485d8a7SHans Petter Selasky struct libusb20_transfer *xfer; 5822485d8a7SHans Petter Selasky uint32_t temp; 5832485d8a7SHans Petter Selasky uint32_t maxsize; 5842485d8a7SHans Petter Selasky uint32_t actlen; 5852485d8a7SHans Petter Selasky char *oldbytes; 5862485d8a7SHans Petter Selasky 5872485d8a7SHans Petter Selasky xfer = usb_get_transfer_by_ep_no(dev, ep); 5882485d8a7SHans Petter Selasky if (xfer == NULL) 5892485d8a7SHans Petter Selasky return (-1); 5902485d8a7SHans Petter Selasky 5912485d8a7SHans Petter Selasky if (libusb20_tr_pending(xfer)) { 5922485d8a7SHans Petter Selasky /* there is already a transfer ongoing */ 5932485d8a7SHans Petter Selasky return (-1); 5942485d8a7SHans Petter Selasky } 5952485d8a7SHans Petter Selasky maxsize = libusb20_tr_get_max_total_length(xfer); 5962485d8a7SHans Petter Selasky oldbytes = bytes; 5972485d8a7SHans Petter Selasky 5982485d8a7SHans Petter Selasky /* 5992485d8a7SHans Petter Selasky * We allow transferring zero bytes which is the same 6002485d8a7SHans Petter Selasky * equivalent to a zero length USB packet. 6012485d8a7SHans Petter Selasky */ 6022485d8a7SHans Petter Selasky do { 6032485d8a7SHans Petter Selasky 6042485d8a7SHans Petter Selasky temp = size; 6052485d8a7SHans Petter Selasky if (temp > maxsize) { 6062485d8a7SHans Petter Selasky /* find maximum possible length */ 6072485d8a7SHans Petter Selasky temp = maxsize; 6082485d8a7SHans Petter Selasky } 6092485d8a7SHans Petter Selasky if (is_intr) 6102485d8a7SHans Petter Selasky libusb20_tr_setup_intr(xfer, bytes, temp, timeout); 6112485d8a7SHans Petter Selasky else 6122485d8a7SHans Petter Selasky libusb20_tr_setup_bulk(xfer, bytes, temp, timeout); 6132485d8a7SHans Petter Selasky 6142485d8a7SHans Petter Selasky libusb20_tr_start(xfer); 6152485d8a7SHans Petter Selasky 6162485d8a7SHans Petter Selasky while (1) { 6172485d8a7SHans Petter Selasky 6182485d8a7SHans Petter Selasky if (libusb20_dev_process((void *)dev) != 0) { 6192485d8a7SHans Petter Selasky /* device detached */ 6202485d8a7SHans Petter Selasky return (-1); 6212485d8a7SHans Petter Selasky } 6222485d8a7SHans Petter Selasky if (libusb20_tr_pending(xfer) == 0) { 6232485d8a7SHans Petter Selasky /* transfer complete */ 6242485d8a7SHans Petter Selasky break; 6252485d8a7SHans Petter Selasky } 6262485d8a7SHans Petter Selasky /* wait for USB event from kernel */ 6272485d8a7SHans Petter Selasky libusb20_dev_wait_process((void *)dev, -1); 6282485d8a7SHans Petter Selasky } 6292485d8a7SHans Petter Selasky 6302485d8a7SHans Petter Selasky switch (libusb20_tr_get_status(xfer)) { 6312485d8a7SHans Petter Selasky case 0: 6322485d8a7SHans Petter Selasky /* success */ 6332485d8a7SHans Petter Selasky break; 6342485d8a7SHans Petter Selasky case LIBUSB20_TRANSFER_TIMED_OUT: 6352485d8a7SHans Petter Selasky /* transfer timeout */ 6362485d8a7SHans Petter Selasky return (-ETIMEDOUT); 6372485d8a7SHans Petter Selasky default: 6382485d8a7SHans Petter Selasky /* other transfer error */ 6392485d8a7SHans Petter Selasky return (-ENXIO); 6402485d8a7SHans Petter Selasky } 6412485d8a7SHans Petter Selasky actlen = libusb20_tr_get_actual_length(xfer); 6422485d8a7SHans Petter Selasky 6432485d8a7SHans Petter Selasky bytes += actlen; 6442485d8a7SHans Petter Selasky size -= actlen; 6452485d8a7SHans Petter Selasky 6462485d8a7SHans Petter Selasky if (actlen != temp) { 6472485d8a7SHans Petter Selasky /* short transfer */ 6482485d8a7SHans Petter Selasky break; 6492485d8a7SHans Petter Selasky } 6502485d8a7SHans Petter Selasky } while (size > 0); 6512485d8a7SHans Petter Selasky 6522485d8a7SHans Petter Selasky return (bytes - oldbytes); 6532485d8a7SHans Petter Selasky } 6542485d8a7SHans Petter Selasky 6552485d8a7SHans Petter Selasky int 6562485d8a7SHans Petter Selasky usb_bulk_write(usb_dev_handle * dev, int ep, char *bytes, 6572485d8a7SHans Petter Selasky int size, int timeout) 6582485d8a7SHans Petter Selasky { 6592485d8a7SHans Petter Selasky return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK, 6602485d8a7SHans Petter Selasky bytes, size, timeout, 0)); 6612485d8a7SHans Petter Selasky } 6622485d8a7SHans Petter Selasky 6632485d8a7SHans Petter Selasky int 6642485d8a7SHans Petter Selasky usb_bulk_read(usb_dev_handle * dev, int ep, char *bytes, 6652485d8a7SHans Petter Selasky int size, int timeout) 6662485d8a7SHans Petter Selasky { 6672485d8a7SHans Petter Selasky return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK, 6682485d8a7SHans Petter Selasky bytes, size, timeout, 0)); 6692485d8a7SHans Petter Selasky } 6702485d8a7SHans Petter Selasky 6712485d8a7SHans Petter Selasky int 6722485d8a7SHans Petter Selasky usb_interrupt_write(usb_dev_handle * dev, int ep, char *bytes, 6732485d8a7SHans Petter Selasky int size, int timeout) 6742485d8a7SHans Petter Selasky { 6752485d8a7SHans Petter Selasky return (usb_std_io(dev, ep & ~USB_ENDPOINT_DIR_MASK, 6762485d8a7SHans Petter Selasky bytes, size, timeout, 1)); 6772485d8a7SHans Petter Selasky } 6782485d8a7SHans Petter Selasky 6792485d8a7SHans Petter Selasky int 6802485d8a7SHans Petter Selasky usb_interrupt_read(usb_dev_handle * dev, int ep, char *bytes, 6812485d8a7SHans Petter Selasky int size, int timeout) 6822485d8a7SHans Petter Selasky { 6832485d8a7SHans Petter Selasky return (usb_std_io(dev, ep | USB_ENDPOINT_DIR_MASK, 6842485d8a7SHans Petter Selasky bytes, size, timeout, 1)); 6852485d8a7SHans Petter Selasky } 6862485d8a7SHans Petter Selasky 6872485d8a7SHans Petter Selasky int 6882485d8a7SHans Petter Selasky usb_control_msg(usb_dev_handle * dev, int requesttype, int request, 6892485d8a7SHans Petter Selasky int value, int wIndex, char *bytes, int size, int timeout) 6902485d8a7SHans Petter Selasky { 6912485d8a7SHans Petter Selasky struct LIBUSB20_CONTROL_SETUP_DECODED req; 6922485d8a7SHans Petter Selasky int err; 6932485d8a7SHans Petter Selasky uint16_t actlen; 6942485d8a7SHans Petter Selasky 6952485d8a7SHans Petter Selasky LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 6962485d8a7SHans Petter Selasky 6972485d8a7SHans Petter Selasky req.bmRequestType = requesttype; 6982485d8a7SHans Petter Selasky req.bRequest = request; 6992485d8a7SHans Petter Selasky req.wValue = value; 7002485d8a7SHans Petter Selasky req.wIndex = wIndex; 7012485d8a7SHans Petter Selasky req.wLength = size; 7022485d8a7SHans Petter Selasky 7032485d8a7SHans Petter Selasky err = libusb20_dev_request_sync((void *)dev, &req, bytes, 7042485d8a7SHans Petter Selasky &actlen, timeout, 0); 7052485d8a7SHans Petter Selasky 7062485d8a7SHans Petter Selasky if (err) 7072485d8a7SHans Petter Selasky return (-1); 7082485d8a7SHans Petter Selasky 7092485d8a7SHans Petter Selasky return (actlen); 7102485d8a7SHans Petter Selasky } 7112485d8a7SHans Petter Selasky 7122485d8a7SHans Petter Selasky int 7132485d8a7SHans Petter Selasky usb_set_configuration(usb_dev_handle * udev, int bConfigurationValue) 7142485d8a7SHans Petter Selasky { 7152485d8a7SHans Petter Selasky struct usb_device *dev; 7162485d8a7SHans Petter Selasky int err; 7172485d8a7SHans Petter Selasky uint8_t i; 7182485d8a7SHans Petter Selasky 7192485d8a7SHans Petter Selasky /* 7202485d8a7SHans Petter Selasky * Need to translate from "bConfigurationValue" to 7212485d8a7SHans Petter Selasky * configuration index: 7222485d8a7SHans Petter Selasky */ 7232485d8a7SHans Petter Selasky 7242485d8a7SHans Petter Selasky if (bConfigurationValue == 0) { 7252485d8a7SHans Petter Selasky /* unconfigure */ 7262485d8a7SHans Petter Selasky i = 255; 7272485d8a7SHans Petter Selasky } else { 7282485d8a7SHans Petter Selasky /* lookup configuration index */ 7292485d8a7SHans Petter Selasky dev = usb_device(udev); 7302485d8a7SHans Petter Selasky 7312485d8a7SHans Petter Selasky /* check if the configuration array is not there */ 7322485d8a7SHans Petter Selasky if (dev->config == NULL) { 7332485d8a7SHans Petter Selasky return (-1); 7342485d8a7SHans Petter Selasky } 7352485d8a7SHans Petter Selasky for (i = 0;; i++) { 7362485d8a7SHans Petter Selasky if (i == dev->descriptor.bNumConfigurations) { 7372485d8a7SHans Petter Selasky /* "bConfigurationValue" not found */ 7382485d8a7SHans Petter Selasky return (-1); 7392485d8a7SHans Petter Selasky } 7402485d8a7SHans Petter Selasky if ((dev->config + i)->bConfigurationValue == 7412485d8a7SHans Petter Selasky bConfigurationValue) { 7422485d8a7SHans Petter Selasky break; 7432485d8a7SHans Petter Selasky } 7442485d8a7SHans Petter Selasky } 7452485d8a7SHans Petter Selasky } 7462485d8a7SHans Petter Selasky 7472485d8a7SHans Petter Selasky err = libusb20_dev_set_config_index((void *)udev, i); 7482485d8a7SHans Petter Selasky 7492485d8a7SHans Petter Selasky if (err) 7502485d8a7SHans Petter Selasky return (-1); 7512485d8a7SHans Petter Selasky 7522485d8a7SHans Petter Selasky return (0); 7532485d8a7SHans Petter Selasky } 7542485d8a7SHans Petter Selasky 7552485d8a7SHans Petter Selasky int 7562485d8a7SHans Petter Selasky usb_claim_interface(usb_dev_handle * dev, int interface) 7572485d8a7SHans Petter Selasky { 7582485d8a7SHans Petter Selasky struct libusb20_device *pdev = (void *)dev; 7592485d8a7SHans Petter Selasky 7602485d8a7SHans Petter Selasky pdev->claimed_interface = interface; 7612485d8a7SHans Petter Selasky 7622485d8a7SHans Petter Selasky return (0); 7632485d8a7SHans Petter Selasky } 7642485d8a7SHans Petter Selasky 7652485d8a7SHans Petter Selasky int 7662485d8a7SHans Petter Selasky usb_release_interface(usb_dev_handle * dev, int interface) 7672485d8a7SHans Petter Selasky { 7682485d8a7SHans Petter Selasky /* do nothing */ 7692485d8a7SHans Petter Selasky return (0); 7702485d8a7SHans Petter Selasky } 7712485d8a7SHans Petter Selasky 7722485d8a7SHans Petter Selasky int 7732485d8a7SHans Petter Selasky usb_set_altinterface(usb_dev_handle * dev, int alternate) 7742485d8a7SHans Petter Selasky { 7752485d8a7SHans Petter Selasky struct libusb20_device *pdev = (void *)dev; 7762485d8a7SHans Petter Selasky int err; 7772485d8a7SHans Petter Selasky uint8_t iface; 7782485d8a7SHans Petter Selasky 7792485d8a7SHans Petter Selasky iface = pdev->claimed_interface; 7802485d8a7SHans Petter Selasky 7812485d8a7SHans Petter Selasky err = libusb20_dev_set_alt_index((void *)dev, iface, alternate); 7822485d8a7SHans Petter Selasky 7832485d8a7SHans Petter Selasky if (err) 7842485d8a7SHans Petter Selasky return (-1); 7852485d8a7SHans Petter Selasky 7862485d8a7SHans Petter Selasky return (0); 7872485d8a7SHans Petter Selasky } 7882485d8a7SHans Petter Selasky 7892485d8a7SHans Petter Selasky int 7902485d8a7SHans Petter Selasky usb_resetep(usb_dev_handle * dev, unsigned int ep) 7912485d8a7SHans Petter Selasky { 7922485d8a7SHans Petter Selasky /* emulate an endpoint reset through clear-STALL */ 7932485d8a7SHans Petter Selasky return (usb_clear_halt(dev, ep)); 7942485d8a7SHans Petter Selasky } 7952485d8a7SHans Petter Selasky 7962485d8a7SHans Petter Selasky int 7972485d8a7SHans Petter Selasky usb_clear_halt(usb_dev_handle * dev, unsigned int ep) 7982485d8a7SHans Petter Selasky { 7992485d8a7SHans Petter Selasky struct libusb20_transfer *xfer; 8002485d8a7SHans Petter Selasky 8012485d8a7SHans Petter Selasky xfer = usb_get_transfer_by_ep_no(dev, ep); 8022485d8a7SHans Petter Selasky if (xfer == NULL) 8032485d8a7SHans Petter Selasky return (-1); 8042485d8a7SHans Petter Selasky 8052485d8a7SHans Petter Selasky libusb20_tr_clear_stall_sync(xfer); 8062485d8a7SHans Petter Selasky 8072485d8a7SHans Petter Selasky return (0); 8082485d8a7SHans Petter Selasky } 8092485d8a7SHans Petter Selasky 8102485d8a7SHans Petter Selasky int 8112485d8a7SHans Petter Selasky usb_reset(usb_dev_handle * dev) 8122485d8a7SHans Petter Selasky { 8132485d8a7SHans Petter Selasky int err; 8142485d8a7SHans Petter Selasky 8152485d8a7SHans Petter Selasky err = libusb20_dev_reset((void *)dev); 8162485d8a7SHans Petter Selasky 8172485d8a7SHans Petter Selasky if (err) 8182485d8a7SHans Petter Selasky return (-1); 8192485d8a7SHans Petter Selasky 8202485d8a7SHans Petter Selasky /* 8212485d8a7SHans Petter Selasky * Be compatible with LibUSB from sourceforge and close the 8222485d8a7SHans Petter Selasky * handle after reset! 8232485d8a7SHans Petter Selasky */ 8242485d8a7SHans Petter Selasky return (usb_close(dev)); 8252485d8a7SHans Petter Selasky } 8262485d8a7SHans Petter Selasky 8272485d8a7SHans Petter Selasky int 8282485d8a7SHans Petter Selasky usb_check_connected(usb_dev_handle * dev) 8292485d8a7SHans Petter Selasky { 8302485d8a7SHans Petter Selasky int err; 8312485d8a7SHans Petter Selasky 8322485d8a7SHans Petter Selasky err = libusb20_dev_check_connected((void *)dev); 8332485d8a7SHans Petter Selasky 8342485d8a7SHans Petter Selasky if (err) 8352485d8a7SHans Petter Selasky return (-1); 8362485d8a7SHans Petter Selasky 8372485d8a7SHans Petter Selasky return (0); 8382485d8a7SHans Petter Selasky } 8392485d8a7SHans Petter Selasky 8402485d8a7SHans Petter Selasky const char * 8412485d8a7SHans Petter Selasky usb_strerror(void) 8422485d8a7SHans Petter Selasky { 8432485d8a7SHans Petter Selasky /* TODO */ 8442485d8a7SHans Petter Selasky return ("Unknown error"); 8452485d8a7SHans Petter Selasky } 8462485d8a7SHans Petter Selasky 8472485d8a7SHans Petter Selasky void 8482485d8a7SHans Petter Selasky usb_init(void) 8492485d8a7SHans Petter Selasky { 8502485d8a7SHans Petter Selasky /* nothing to do */ 8512485d8a7SHans Petter Selasky return; 8522485d8a7SHans Petter Selasky } 8532485d8a7SHans Petter Selasky 8542485d8a7SHans Petter Selasky void 8552485d8a7SHans Petter Selasky usb_set_debug(int level) 8562485d8a7SHans Petter Selasky { 8572485d8a7SHans Petter Selasky /* use kernel UGEN debugging if you need to see what is going on */ 8582485d8a7SHans Petter Selasky return; 8592485d8a7SHans Petter Selasky } 8602485d8a7SHans Petter Selasky 8612485d8a7SHans Petter Selasky int 8622485d8a7SHans Petter Selasky usb_find_busses(void) 8632485d8a7SHans Petter Selasky { 8642485d8a7SHans Petter Selasky usb_busses = &usb_global_bus; 8652485d8a7SHans Petter Selasky return (1); 8662485d8a7SHans Petter Selasky } 8672485d8a7SHans Petter Selasky 8682485d8a7SHans Petter Selasky int 8692485d8a7SHans Petter Selasky usb_find_devices(void) 8702485d8a7SHans Petter Selasky { 8712485d8a7SHans Petter Selasky struct libusb20_device *pdev; 8722485d8a7SHans Petter Selasky struct usb_device *udev; 8732485d8a7SHans Petter Selasky struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; 8742485d8a7SHans Petter Selasky int devnum; 8752485d8a7SHans Petter Selasky int err; 8762485d8a7SHans Petter Selasky 8772485d8a7SHans Petter Selasky /* cleanup after last device search */ 8782485d8a7SHans Petter Selasky /* close all opened devices, if any */ 8792485d8a7SHans Petter Selasky 8802485d8a7SHans Petter Selasky while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 8812485d8a7SHans Petter Selasky udev = pdev->privLuData; 8822485d8a7SHans Petter Selasky libusb20_be_dequeue_device(usb_backend, pdev); 8832485d8a7SHans Petter Selasky libusb20_dev_free(pdev); 8842485d8a7SHans Petter Selasky if (udev != NULL) { 8852485d8a7SHans Petter Selasky LIST_DEL(usb_global_bus.devices, udev); 8862485d8a7SHans Petter Selasky free(udev); 8872485d8a7SHans Petter Selasky } 8882485d8a7SHans Petter Selasky } 8892485d8a7SHans Petter Selasky 8902485d8a7SHans Petter Selasky /* free old USB backend, if any */ 8912485d8a7SHans Petter Selasky 8922485d8a7SHans Petter Selasky libusb20_be_free(usb_backend); 8932485d8a7SHans Petter Selasky 8942485d8a7SHans Petter Selasky /* do a new backend device search */ 8952485d8a7SHans Petter Selasky usb_backend = libusb20_be_alloc_default(); 8962485d8a7SHans Petter Selasky if (usb_backend == NULL) { 8972485d8a7SHans Petter Selasky return (-1); 8982485d8a7SHans Petter Selasky } 8992485d8a7SHans Petter Selasky /* iterate all devices */ 9002485d8a7SHans Petter Selasky 9012485d8a7SHans Petter Selasky devnum = 1; 9022485d8a7SHans Petter Selasky pdev = NULL; 9032485d8a7SHans Petter Selasky while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) { 9042485d8a7SHans Petter Selasky udev = malloc(sizeof(*udev)); 9052485d8a7SHans Petter Selasky if (udev == NULL) 9062485d8a7SHans Petter Selasky break; 9072485d8a7SHans Petter Selasky 9082485d8a7SHans Petter Selasky memset(udev, 0, sizeof(*udev)); 9092485d8a7SHans Petter Selasky 9102485d8a7SHans Petter Selasky udev->bus = &usb_global_bus; 9112485d8a7SHans Petter Selasky 9122485d8a7SHans Petter Selasky snprintf(udev->filename, sizeof(udev->filename), 9132485d8a7SHans Petter Selasky "/dev/ugen%u.%u", 9142485d8a7SHans Petter Selasky libusb20_dev_get_bus_number(pdev), 9152485d8a7SHans Petter Selasky libusb20_dev_get_address(pdev)); 9162485d8a7SHans Petter Selasky 9172485d8a7SHans Petter Selasky ddesc = libusb20_dev_get_device_desc(pdev); 9182485d8a7SHans Petter Selasky 9192485d8a7SHans Petter Selasky udev->descriptor.bLength = sizeof(udev->descriptor); 9202485d8a7SHans Petter Selasky udev->descriptor.bDescriptorType = ddesc->bDescriptorType; 9212485d8a7SHans Petter Selasky udev->descriptor.bcdUSB = ddesc->bcdUSB; 9222485d8a7SHans Petter Selasky udev->descriptor.bDeviceClass = ddesc->bDeviceClass; 9232485d8a7SHans Petter Selasky udev->descriptor.bDeviceSubClass = ddesc->bDeviceSubClass; 9242485d8a7SHans Petter Selasky udev->descriptor.bDeviceProtocol = ddesc->bDeviceProtocol; 9252485d8a7SHans Petter Selasky udev->descriptor.bMaxPacketSize0 = ddesc->bMaxPacketSize0; 9262485d8a7SHans Petter Selasky udev->descriptor.idVendor = ddesc->idVendor; 9272485d8a7SHans Petter Selasky udev->descriptor.idProduct = ddesc->idProduct; 9282485d8a7SHans Petter Selasky udev->descriptor.bcdDevice = ddesc->bcdDevice; 9292485d8a7SHans Petter Selasky udev->descriptor.iManufacturer = ddesc->iManufacturer; 9302485d8a7SHans Petter Selasky udev->descriptor.iProduct = ddesc->iProduct; 9312485d8a7SHans Petter Selasky udev->descriptor.iSerialNumber = ddesc->iSerialNumber; 9322485d8a7SHans Petter Selasky udev->descriptor.bNumConfigurations = 9332485d8a7SHans Petter Selasky ddesc->bNumConfigurations; 9342485d8a7SHans Petter Selasky if (udev->descriptor.bNumConfigurations > USB_MAXCONFIG) { 9352485d8a7SHans Petter Selasky /* truncate number of configurations */ 9362485d8a7SHans Petter Selasky udev->descriptor.bNumConfigurations = USB_MAXCONFIG; 9372485d8a7SHans Petter Selasky } 9382485d8a7SHans Petter Selasky udev->devnum = devnum++; 9392485d8a7SHans Petter Selasky /* link together the two structures */ 9402485d8a7SHans Petter Selasky udev->dev = pdev; 9412485d8a7SHans Petter Selasky pdev->privLuData = udev; 9422485d8a7SHans Petter Selasky 9432485d8a7SHans Petter Selasky err = libusb20_dev_open(pdev, 0); 9442485d8a7SHans Petter Selasky if (err == 0) { 9452485d8a7SHans Petter Selasky /* XXX get all config descriptors by default */ 9462485d8a7SHans Petter Selasky usb_fetch_and_parse_descriptors((void *)pdev); 9472485d8a7SHans Petter Selasky libusb20_dev_close(pdev); 9482485d8a7SHans Petter Selasky } 9492485d8a7SHans Petter Selasky LIST_ADD(usb_global_bus.devices, udev); 9502485d8a7SHans Petter Selasky } 9512485d8a7SHans Petter Selasky 9522485d8a7SHans Petter Selasky return (devnum - 1); /* success */ 9532485d8a7SHans Petter Selasky } 9542485d8a7SHans Petter Selasky 9552485d8a7SHans Petter Selasky struct usb_device * 9562485d8a7SHans Petter Selasky usb_device(usb_dev_handle * dev) 9572485d8a7SHans Petter Selasky { 9582485d8a7SHans Petter Selasky struct libusb20_device *pdev; 9592485d8a7SHans Petter Selasky 9602485d8a7SHans Petter Selasky pdev = (void *)dev; 9612485d8a7SHans Petter Selasky 9622485d8a7SHans Petter Selasky return (pdev->privLuData); 9632485d8a7SHans Petter Selasky } 9642485d8a7SHans Petter Selasky 9652485d8a7SHans Petter Selasky struct usb_bus * 9662485d8a7SHans Petter Selasky usb_get_busses(void) 9672485d8a7SHans Petter Selasky { 9682485d8a7SHans Petter Selasky return (usb_busses); 9692485d8a7SHans Petter Selasky } 970*4eb5923dSHans Petter Selasky 971*4eb5923dSHans Petter Selasky int 972*4eb5923dSHans Petter Selasky usb_get_driver_np(usb_dev_handle * dev, int interface, char *name, int namelen) 973*4eb5923dSHans Petter Selasky { 974*4eb5923dSHans Petter Selasky struct libusb20_device *pdev; 975*4eb5923dSHans Petter Selasky char *ptr; 976*4eb5923dSHans Petter Selasky int err; 977*4eb5923dSHans Petter Selasky 978*4eb5923dSHans Petter Selasky pdev = (void *)dev; 979*4eb5923dSHans Petter Selasky 980*4eb5923dSHans Petter Selasky if (pdev == NULL) 981*4eb5923dSHans Petter Selasky return (-1); 982*4eb5923dSHans Petter Selasky if (namelen < 1) 983*4eb5923dSHans Petter Selasky return (-1); 984*4eb5923dSHans Petter Selasky if (namelen > 255) 985*4eb5923dSHans Petter Selasky namelen = 255; 986*4eb5923dSHans Petter Selasky 987*4eb5923dSHans Petter Selasky err = libusb20_dev_get_iface_desc(pdev, interface, name, namelen); 988*4eb5923dSHans Petter Selasky if (err != 0) 989*4eb5923dSHans Petter Selasky return (-1); 990*4eb5923dSHans Petter Selasky 991*4eb5923dSHans Petter Selasky /* we only want the driver name */ 992*4eb5923dSHans Petter Selasky ptr = strstr(name, ":"); 993*4eb5923dSHans Petter Selasky if (ptr != NULL) 994*4eb5923dSHans Petter Selasky *ptr = 0; 995*4eb5923dSHans Petter Selasky 996*4eb5923dSHans Petter Selasky return (0); 997*4eb5923dSHans Petter Selasky } 998*4eb5923dSHans Petter Selasky 999*4eb5923dSHans Petter Selasky int 1000*4eb5923dSHans Petter Selasky usb_detach_kernel_driver_np(usb_dev_handle * dev, int interface) 1001*4eb5923dSHans Petter Selasky { 1002*4eb5923dSHans Petter Selasky struct libusb20_device *pdev; 1003*4eb5923dSHans Petter Selasky int err; 1004*4eb5923dSHans Petter Selasky 1005*4eb5923dSHans Petter Selasky pdev = (void *)dev; 1006*4eb5923dSHans Petter Selasky 1007*4eb5923dSHans Petter Selasky if (pdev == NULL) 1008*4eb5923dSHans Petter Selasky return (-1); 1009*4eb5923dSHans Petter Selasky 1010*4eb5923dSHans Petter Selasky err = libusb20_dev_detach_kernel_driver(pdev, interface); 1011*4eb5923dSHans Petter Selasky if (err != 0) 1012*4eb5923dSHans Petter Selasky return (-1); 1013*4eb5923dSHans Petter Selasky 1014*4eb5923dSHans Petter Selasky return (0); 1015*4eb5923dSHans Petter Selasky } 1016