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