libusb20_ugen20.c revision 310280
1139749Simp/* $FreeBSD: stable/10/lib/libusb/libusb20_ugen20.c 310280 2016-12-19 18:26:26Z trasz $ */ 2102682Sgibbs/*- 397883Sgibbs * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4133122Sgibbs * 5102682Sgibbs * Redistribution and use in source and binary forms, with or without 697883Sgibbs * modification, are permitted provided that the following conditions 797883Sgibbs * are met: 897883Sgibbs * 1. Redistributions of source code must retain the above copyright 997883Sgibbs * notice, this list of conditions and the following disclaimer. 1097883Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1197883Sgibbs * notice, this list of conditions and the following disclaimer in the 1297883Sgibbs * documentation and/or other materials provided with the distribution. 1397883Sgibbs * 1497883Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1597883Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1697883Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1797883Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1897883Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1997883Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2097883Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2197883Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2297883Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2397883Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2497883Sgibbs * SUCH DAMAGE. 2597883Sgibbs */ 2697883Sgibbs 2797883Sgibbs#ifdef LIBUSB_GLOBAL_INCLUDE_FILE 2897883Sgibbs#include LIBUSB_GLOBAL_INCLUDE_FILE 2997883Sgibbs#else 3097883Sgibbs#include <errno.h> 3197883Sgibbs#include <fcntl.h> 3297883Sgibbs#include <stdio.h> 3397883Sgibbs#include <stdlib.h> 3497883Sgibbs#include <string.h> 3597883Sgibbs#include <unistd.h> 3697883Sgibbs#include <time.h> 3797883Sgibbs#include <sys/queue.h> 3897883Sgibbs#include <sys/types.h> 3997883Sgibbs#endif 4097883Sgibbs 4197883Sgibbs#include <dev/usb/usb.h> 4297883Sgibbs#include <dev/usb/usbdi.h> 43129134Sgibbs#include <dev/usb/usb_ioctl.h> 4497883Sgibbs 45102682Sgibbs#include "libusb20.h" 4697883Sgibbs#include "libusb20_desc.h" 4797883Sgibbs#include "libusb20_int.h" 4897883Sgibbs 4997883Sgibbs#ifndef IOUSB 50107441Sscottl#define IOUSB(a) a 51107441Sscottl#endif 52107441Sscottl 53107441Sscottlstatic libusb20_init_backend_t ugen20_init_backend; 54107441Sscottlstatic libusb20_open_device_t ugen20_open_device; 55107441Sscottlstatic libusb20_close_device_t ugen20_close_device; 5697883Sgibbsstatic libusb20_get_backend_name_t ugen20_get_backend_name; 57107441Sscottlstatic libusb20_exit_backend_t ugen20_exit_backend; 58107441Sscottlstatic libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc; 59107441Sscottlstatic libusb20_dev_get_info_t ugen20_dev_get_info; 60107441Sscottlstatic libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk; 61107441Sscottlstatic libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name; 62107441Sscottlstatic libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk; 63107441Sscottlstatic libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk; 64107441Sscottlstatic libusb20_root_set_template_t ugen20_root_set_template; 65107628Sscottlstatic libusb20_root_get_template_t ugen20_root_get_template; 66107441Sscottl 67107628Sscottlconst struct libusb20_backend_methods libusb20_ugen20_backend = { 68107441Sscottl LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20) 69104023Sgibbs}; 7097883Sgibbs 71125448Sgibbs/* USB device specific */ 72125448Sgibbsstatic libusb20_get_config_desc_full_t ugen20_get_config_desc_full; 73125448Sgibbsstatic libusb20_get_config_index_t ugen20_get_config_index; 74125448Sgibbsstatic libusb20_set_config_index_t ugen20_set_config_index; 75125448Sgibbsstatic libusb20_set_alt_index_t ugen20_set_alt_index; 76125448Sgibbsstatic libusb20_reset_device_t ugen20_reset_device; 77125448Sgibbsstatic libusb20_check_connected_t ugen20_check_connected; 78125448Sgibbsstatic libusb20_set_power_mode_t ugen20_set_power_mode; 79125448Sgibbsstatic libusb20_get_power_mode_t ugen20_get_power_mode; 80125448Sgibbsstatic libusb20_get_port_path_t ugen20_get_port_path; 81125448Sgibbsstatic libusb20_get_power_usage_t ugen20_get_power_usage; 82125448Sgibbsstatic libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 83125448Sgibbsstatic libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 84125448Sgibbsstatic libusb20_do_request_sync_t ugen20_do_request_sync; 85125448Sgibbsstatic libusb20_process_t ugen20_process; 86125448Sgibbs 87125448Sgibbs/* USB transfer specific */ 88125448Sgibbsstatic libusb20_tr_open_t ugen20_tr_open; 89125448Sgibbsstatic libusb20_tr_close_t ugen20_tr_close; 90125448Sgibbsstatic libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 91125448Sgibbsstatic libusb20_tr_submit_t ugen20_tr_submit; 92125448Sgibbsstatic libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 93125448Sgibbs 94125448Sgibbsstatic const struct libusb20_device_methods libusb20_ugen20_device_methods = { 95125448Sgibbs LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 96125448Sgibbs}; 97125448Sgibbs 98125448Sgibbsstatic const char * 99125448Sgibbsugen20_get_backend_name(void) 100125448Sgibbs{ 101125448Sgibbs return ("FreeBSD UGEN 2.0"); 102125448Sgibbs} 103125448Sgibbs 104125448Sgibbsstatic uint32_t 105125448Sgibbsugen20_path_convert_one(const char **pp) 106125448Sgibbs{ 10797883Sgibbs const char *ptr; 10897883Sgibbs uint32_t temp = 0; 10997883Sgibbs 11097883Sgibbs ptr = *pp; 11197883Sgibbs 11297883Sgibbs while ((*ptr >= '0') && (*ptr <= '9')) { 11397883Sgibbs temp *= 10; 11497883Sgibbs temp += (*ptr - '0'); 11597883Sgibbs if (temp >= 1000000) { 11697883Sgibbs /* catch overflow early */ 11797883Sgibbs return (0xFFFFFFFF); 11897883Sgibbs } 11997883Sgibbs ptr++; 12097883Sgibbs } 12197883Sgibbs 122107441Sscottl if (*ptr == '.') { 12397883Sgibbs /* skip dot */ 124114623Sgibbs ptr++; 125123579Sgibbs } 126123579Sgibbs *pp = ptr; 127123579Sgibbs 128123579Sgibbs return (temp); 129123579Sgibbs} 130123579Sgibbs 131123579Sgibbsstatic int 132114623Sgibbsugen20_enumerate(struct libusb20_device *pdev, const char *id) 133114623Sgibbs{ 134114623Sgibbs const char *tmp = id; 135114623Sgibbs struct usb_device_descriptor ddesc; 136114623Sgibbs struct usb_device_info devinfo; 137114623Sgibbs uint32_t plugtime; 138107441Sscottl char buf[64]; 139107441Sscottl int f; 140107441Sscottl int error; 141107441Sscottl 142107441Sscottl pdev->bus_number = ugen20_path_convert_one(&tmp); 143107441Sscottl pdev->device_address = ugen20_path_convert_one(&tmp); 144107441Sscottl 145123579Sgibbs snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 146107441Sscottl pdev->bus_number, pdev->device_address); 147107441Sscottl 14897883Sgibbs f = open(buf, O_RDWR); 14997883Sgibbs if (f < 0) { 150114623Sgibbs return (LIBUSB20_ERROR_OTHER); 151114623Sgibbs } 15297883Sgibbs if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 15397883Sgibbs error = LIBUSB20_ERROR_OTHER; 15497883Sgibbs goto done; 15597883Sgibbs } 156109588Sgibbs /* store when the device was plugged */ 157109588Sgibbs pdev->session_data.plugtime = plugtime; 158109588Sgibbs 159109588Sgibbs if (ioctl(f, IOUSB(USB_GET_DEVICE_DESC), &ddesc)) { 160109588Sgibbs error = LIBUSB20_ERROR_OTHER; 161109588Sgibbs goto done; 162109588Sgibbs } 163109588Sgibbs LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 164109588Sgibbs 165109588Sgibbs libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 16697883Sgibbs 16797883Sgibbs if (pdev->ddesc.bNumConfigurations == 0) { 16897883Sgibbs error = LIBUSB20_ERROR_OTHER; 16997883Sgibbs goto done; 17097883Sgibbs } else if (pdev->ddesc.bNumConfigurations >= 8) { 171111653Sgibbs error = LIBUSB20_ERROR_OTHER; 17297883Sgibbs goto done; 17397883Sgibbs } 174111653Sgibbs if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo)) { 175111653Sgibbs error = LIBUSB20_ERROR_OTHER; 17697883Sgibbs goto done; 177114623Sgibbs } 178114623Sgibbs switch (devinfo.udi_mode) { 179114623Sgibbs case USB_MODE_DEVICE: 18097883Sgibbs pdev->usb_mode = LIBUSB20_MODE_DEVICE; 181111653Sgibbs break; 18297883Sgibbs default: 183111653Sgibbs pdev->usb_mode = LIBUSB20_MODE_HOST; 18497883Sgibbs break; 18597883Sgibbs } 18697883Sgibbs 187114623Sgibbs switch (devinfo.udi_speed) { 18897883Sgibbs case USB_SPEED_LOW: 18997883Sgibbs pdev->usb_speed = LIBUSB20_SPEED_LOW; 190107441Sscottl break; 191107441Sscottl case USB_SPEED_FULL: 19297883Sgibbs pdev->usb_speed = LIBUSB20_SPEED_FULL; 193104023Sgibbs break; 194123579Sgibbs case USB_SPEED_HIGH: 19597883Sgibbs pdev->usb_speed = LIBUSB20_SPEED_HIGH; 19697883Sgibbs break; 197123579Sgibbs case USB_SPEED_VARIABLE: 19897883Sgibbs pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 199104023Sgibbs break; 200123579Sgibbs case USB_SPEED_SUPER: 201107441Sscottl pdev->usb_speed = LIBUSB20_SPEED_SUPER; 202123579Sgibbs break; 203114623Sgibbs default: 204107441Sscottl pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 20597883Sgibbs break; 20697883Sgibbs } 207104023Sgibbs 208109588Sgibbs /* get parent HUB index and port */ 209123579Sgibbs 210109588Sgibbs pdev->parent_address = devinfo.udi_hubindex; 211109588Sgibbs pdev->parent_port = devinfo.udi_hubport; 212104023Sgibbs 21397883Sgibbs /* generate a nice description for printout */ 21497883Sgibbs 21597883Sgibbs snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 21697883Sgibbs USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, 21797883Sgibbs pdev->device_address, devinfo.udi_vendor, 21897883Sgibbs devinfo.udi_product, pdev->bus_number); 21997883Sgibbs 220299375Spfg error = 0; 221114623Sgibbsdone: 222114623Sgibbs close(f); 223114623Sgibbs return (error); 224114623Sgibbs} 225123579Sgibbs 22697883Sgibbsstruct ugen20_urd_state { 227125448Sgibbs struct usb_read_dir urd; 228125448Sgibbs uint32_t nparsed; 229125448Sgibbs int f; 230125448Sgibbs uint8_t *ptr; 231123579Sgibbs const char *src; 232125448Sgibbs const char *dst; 233125448Sgibbs uint8_t buf[256]; 234123579Sgibbs uint8_t dummy_zero[1]; 235123579Sgibbs}; 236123579Sgibbs 23797883Sgibbsstatic int 23897883Sgibbsugen20_readdir(struct ugen20_urd_state *st) 239109588Sgibbs{ 24097883Sgibbs ; /* style fix */ 24197883Sgibbsrepeat: 24297883Sgibbs if (st->ptr == NULL) { 243102682Sgibbs st->urd.urd_startentry += st->nparsed; 244102682Sgibbs st->urd.urd_data = libusb20_pass_ptr(st->buf); 245123579Sgibbs st->urd.urd_maxlen = sizeof(st->buf); 24697883Sgibbs st->nparsed = 0; 247109588Sgibbs 248109588Sgibbs if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) { 249109588Sgibbs return (EINVAL); 250115329Sgibbs } 251109588Sgibbs st->ptr = st->buf; 252109588Sgibbs } 253115329Sgibbs if (st->ptr[0] == 0) { 254115329Sgibbs if (st->nparsed) { 255115329Sgibbs st->ptr = NULL; 256109588Sgibbs goto repeat; 257109588Sgibbs } else { 258109588Sgibbs return (ENXIO); 259109588Sgibbs } 260109588Sgibbs } 261115329Sgibbs st->src = (void *)(st->ptr + 1); 262109588Sgibbs st->dst = st->src + strlen(st->src) + 1; 263115329Sgibbs st->ptr = st->ptr + st->ptr[0]; 264109588Sgibbs st->nparsed++; 265109588Sgibbs 266109588Sgibbs if ((st->ptr < st->buf) || 267109588Sgibbs (st->ptr > st->dummy_zero)) { 268115329Sgibbs /* invalid entry */ 269109588Sgibbs return (EINVAL); 270109588Sgibbs } 271115329Sgibbs return (0); 272115329Sgibbs} 273115329Sgibbs 274109588Sgibbsstatic int 275109588Sgibbsugen20_init_backend(struct libusb20_backend *pbe) 276109588Sgibbs{ 277109588Sgibbs struct ugen20_urd_state state; 278109588Sgibbs struct libusb20_device *pdev; 279109588Sgibbs 280115329Sgibbs memset(&state, 0, sizeof(state)); 281109588Sgibbs 282109588Sgibbs state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 283109588Sgibbs if (state.f < 0) 284109588Sgibbs return (LIBUSB20_ERROR_OTHER); 285109588Sgibbs 286109588Sgibbs while (ugen20_readdir(&state) == 0) { 287115329Sgibbs 288109588Sgibbs if ((state.src[0] != 'u') || 289109588Sgibbs (state.src[1] != 'g') || 290104023Sgibbs (state.src[2] != 'e') || 29197883Sgibbs (state.src[3] != 'n')) { 29297883Sgibbs continue; 29397883Sgibbs } 29497883Sgibbs pdev = libusb20_dev_alloc(); 295109588Sgibbs if (pdev == NULL) { 296109588Sgibbs continue; 297109588Sgibbs } 298115331Sgibbs if (ugen20_enumerate(pdev, state.src + 4)) { 299115331Sgibbs libusb20_dev_free(pdev); 300115331Sgibbs continue; 301115331Sgibbs } 302115331Sgibbs /* put the device on the backend list */ 303115331Sgibbs libusb20_be_enqueue_device(pbe, pdev); 304115331Sgibbs } 305115331Sgibbs close(state.f); 306115331Sgibbs return (0); /* success */ 307114623Sgibbs} 308114623Sgibbs 309114623Sgibbsstatic void 310114623Sgibbsugen20_tr_release(struct libusb20_device *pdev) 311114623Sgibbs{ 312114623Sgibbs struct usb_fs_uninit fs_uninit; 313116937Sgibbs 31497883Sgibbs if (pdev->nTransfer == 0) { 31597883Sgibbs return; 316133122Sgibbs } 317133122Sgibbs /* release all pending USB transfers */ 318133122Sgibbs if (pdev->privBeData != NULL) { 319133122Sgibbs memset(&fs_uninit, 0, sizeof(fs_uninit)); 32097883Sgibbs if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 32197883Sgibbs /* ignore any errors of this kind */ 322107441Sscottl } 323107441Sscottl } 324133122Sgibbs return; 32597883Sgibbs} 326133122Sgibbs 327133122Sgibbsstatic int 328133122Sgibbsugen20_tr_renew(struct libusb20_device *pdev) 329133122Sgibbs{ 330133122Sgibbs struct usb_fs_init fs_init; 33197883Sgibbs struct usb_fs_endpoint *pfse; 332133122Sgibbs int error; 333133122Sgibbs uint32_t size; 334133122Sgibbs uint16_t nMaxTransfer; 335133122Sgibbs 336133122Sgibbs nMaxTransfer = pdev->nTransfer; 337133122Sgibbs error = 0; 338133122Sgibbs 33997883Sgibbs if (nMaxTransfer == 0) { 34097883Sgibbs goto done; 34197883Sgibbs } 34297883Sgibbs size = nMaxTransfer * sizeof(*pfse); 34397883Sgibbs 344133122Sgibbs if (pdev->privBeData == NULL) { 345133122Sgibbs pfse = malloc(size); 346133122Sgibbs if (pfse == NULL) { 347133122Sgibbs error = LIBUSB20_ERROR_NO_MEM; 34897883Sgibbs goto done; 349133122Sgibbs } 350133122Sgibbs pdev->privBeData = pfse; 351133122Sgibbs } 352133122Sgibbs /* reset endpoint data */ 353133122Sgibbs memset(pdev->privBeData, 0, size); 35497883Sgibbs 355133122Sgibbs memset(&fs_init, 0, sizeof(fs_init)); 356133122Sgibbs 357133122Sgibbs fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData); 358133122Sgibbs fs_init.ep_index_max = nMaxTransfer; 359133122Sgibbs 360133122Sgibbs if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) { 361133122Sgibbs error = LIBUSB20_ERROR_OTHER; 362133122Sgibbs goto done; 363133122Sgibbs } 364133122Sgibbsdone: 365133122Sgibbs return (error); 366133122Sgibbs} 367133122Sgibbs 368133122Sgibbsstatic int 369133122Sgibbsugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 370133122Sgibbs{ 371133122Sgibbs uint32_t plugtime; 372133122Sgibbs char buf[64]; 373133122Sgibbs int f; 374133122Sgibbs int g; 375133122Sgibbs int error; 376133122Sgibbs 377133122Sgibbs snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 378133122Sgibbs pdev->bus_number, pdev->device_address); 379133122Sgibbs 380133122Sgibbs /* 381133122Sgibbs * We need two file handles, one for the control endpoint and one 382133122Sgibbs * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 383133122Sgibbs * kernel locking. 384133122Sgibbs */ 385133122Sgibbs g = open(buf, O_RDWR); 386133122Sgibbs if (g < 0) { 387133122Sgibbs return (LIBUSB20_ERROR_NO_DEVICE); 388133122Sgibbs } 389133122Sgibbs f = open(buf, O_RDWR); 390133122Sgibbs if (f < 0) { 391133122Sgibbs close(g); 392133122Sgibbs return (LIBUSB20_ERROR_NO_DEVICE); 393133122Sgibbs } 394133122Sgibbs if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 395133122Sgibbs error = LIBUSB20_ERROR_OTHER; 396107441Sscottl goto done; 397133122Sgibbs } 39897883Sgibbs /* check that the correct device is still plugged */ 399133122Sgibbs if (pdev->session_data.plugtime != plugtime) { 400133122Sgibbs error = LIBUSB20_ERROR_NO_DEVICE; 401133122Sgibbs goto done; 402133122Sgibbs } 40397883Sgibbs /* need to set this before "tr_renew()" */ 40497883Sgibbs pdev->file = f; 40597883Sgibbs pdev->file_ctrl = g; 406107441Sscottl 40797883Sgibbs /* renew all USB transfers */ 408133122Sgibbs error = ugen20_tr_renew(pdev); 409133122Sgibbs if (error) { 410133122Sgibbs goto done; 411133122Sgibbs } 41297883Sgibbs /* set methods */ 413107441Sscottl pdev->methods = &libusb20_ugen20_device_methods; 414104023Sgibbs 41597883Sgibbsdone: 41697883Sgibbs if (error) { 41797883Sgibbs if (pdev->privBeData) { 418133122Sgibbs /* cleanup after "tr_renew()" */ 419133122Sgibbs free(pdev->privBeData); 420133122Sgibbs pdev->privBeData = NULL; 42197883Sgibbs } 422133122Sgibbs pdev->file = -1; 423133122Sgibbs pdev->file_ctrl = -1; 42497883Sgibbs close(f); 42597883Sgibbs close(g); 426133122Sgibbs } 42797883Sgibbs return (error); 42897883Sgibbs} 42997883Sgibbs 43097883Sgibbsstatic int 43197883Sgibbsugen20_close_device(struct libusb20_device *pdev) 43297883Sgibbs{ 43397883Sgibbs struct usb_fs_uninit fs_uninit; 43497883Sgibbs 43597883Sgibbs if (pdev->privBeData) { 43697883Sgibbs memset(&fs_uninit, 0, sizeof(fs_uninit)); 43797883Sgibbs if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 438129134Sgibbs /* ignore this error */ 43997883Sgibbs } 44097883Sgibbs free(pdev->privBeData); 441125448Sgibbs } 442125448Sgibbs pdev->nTransfer = 0; 443125448Sgibbs pdev->privBeData = NULL; 44497883Sgibbs close(pdev->file); 445115329Sgibbs close(pdev->file_ctrl); 446109588Sgibbs pdev->file = -1; 447109588Sgibbs pdev->file_ctrl = -1; 44897883Sgibbs return (0); /* success */ 44997883Sgibbs} 450107441Sscottl 451129134Sgibbsstatic void 452129134Sgibbsugen20_exit_backend(struct libusb20_backend *pbe) 453129134Sgibbs{ 454129134Sgibbs return; /* nothing to do */ 455129134Sgibbs} 456129134Sgibbs 457129134Sgibbsstatic int 458129134Sgibbsugen20_get_config_desc_full(struct libusb20_device *pdev, 459129134Sgibbs uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 460129134Sgibbs{ 461129134Sgibbs struct usb_gen_descriptor gen_desc; 462129134Sgibbs struct usb_config_descriptor cdesc; 463107441Sscottl uint8_t *ptr; 464107441Sscottl uint16_t len; 46597883Sgibbs int error; 46697883Sgibbs 46797883Sgibbs /* make sure memory is initialised */ 46897883Sgibbs memset(&cdesc, 0, sizeof(cdesc)); 46997883Sgibbs memset(&gen_desc, 0, sizeof(gen_desc)); 47097883Sgibbs 47197883Sgibbs gen_desc.ugd_data = libusb20_pass_ptr(&cdesc); 47297883Sgibbs gen_desc.ugd_maxlen = sizeof(cdesc); 47397883Sgibbs gen_desc.ugd_config_index = cfg_index; 47497883Sgibbs 47597883Sgibbs error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 47697883Sgibbs if (error) { 477114623Sgibbs return (LIBUSB20_ERROR_OTHER); 47897883Sgibbs } 47997883Sgibbs len = UGETW(cdesc.wTotalLength); 48097883Sgibbs if (len < sizeof(cdesc)) { 48197883Sgibbs /* corrupt descriptor */ 48297883Sgibbs return (LIBUSB20_ERROR_OTHER); 48397883Sgibbs } 48497883Sgibbs ptr = malloc(len); 48597883Sgibbs if (!ptr) { 48697883Sgibbs return (LIBUSB20_ERROR_NO_MEM); 48797883Sgibbs } 48897883Sgibbs 48997883Sgibbs /* make sure memory is initialised */ 49097883Sgibbs memset(ptr, 0, len); 49197883Sgibbs 492104023Sgibbs gen_desc.ugd_data = libusb20_pass_ptr(ptr); 49397883Sgibbs gen_desc.ugd_maxlen = len; 49497883Sgibbs 495125448Sgibbs error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 496125448Sgibbs if (error) { 497125448Sgibbs free(ptr); 498125448Sgibbs return (LIBUSB20_ERROR_OTHER); 499125448Sgibbs } 500125448Sgibbs /* make sure that the device doesn't fool us */ 501125448Sgibbs memcpy(ptr, &cdesc, sizeof(cdesc)); 502125448Sgibbs 503125448Sgibbs *ppbuf = ptr; 504125448Sgibbs *plen = len; 505125448Sgibbs 506125448Sgibbs return (0); /* success */ 50797883Sgibbs} 50897883Sgibbs 50997883Sgibbsstatic int 51097883Sgibbsugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 51197883Sgibbs{ 51297883Sgibbs int temp; 513107441Sscottl 51497883Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) { 51597883Sgibbs return (LIBUSB20_ERROR_OTHER); 51697883Sgibbs } 51797883Sgibbs *pindex = temp; 51897883Sgibbs 51997883Sgibbs return (0); 520104023Sgibbs} 52197883Sgibbs 52297883Sgibbsstatic int 52397883Sgibbsugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 52497883Sgibbs{ 525104023Sgibbs int temp = cfg_index; 526104023Sgibbs 527107441Sscottl /* release all active USB transfers */ 528107441Sscottl ugen20_tr_release(pdev); 529107441Sscottl 530107441Sscottl if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) { 531107441Sscottl return (LIBUSB20_ERROR_OTHER); 532107441Sscottl } 533107441Sscottl return (ugen20_tr_renew(pdev)); 534107441Sscottl} 53597883Sgibbs 53697883Sgibbsstatic int 53797883Sgibbsugen20_set_alt_index(struct libusb20_device *pdev, 53897883Sgibbs uint8_t iface_index, uint8_t alt_index) 53997883Sgibbs{ 54097883Sgibbs struct usb_alt_interface alt_iface; 54197883Sgibbs 54297883Sgibbs memset(&alt_iface, 0, sizeof(alt_iface)); 54397883Sgibbs 54497883Sgibbs alt_iface.uai_interface_index = iface_index; 54597883Sgibbs alt_iface.uai_alt_index = alt_index; 546102682Sgibbs 54797883Sgibbs /* release all active USB transfers */ 54897883Sgibbs ugen20_tr_release(pdev); 54997883Sgibbs 55097883Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) { 55197883Sgibbs return (LIBUSB20_ERROR_OTHER); 55297883Sgibbs } 55397883Sgibbs return (ugen20_tr_renew(pdev)); 55497883Sgibbs} 55597883Sgibbs 55697883Sgibbsstatic int 55797883Sgibbsugen20_reset_device(struct libusb20_device *pdev) 55897883Sgibbs{ 55997883Sgibbs int temp = 0; 56097883Sgibbs 56197883Sgibbs /* release all active USB transfers */ 56297883Sgibbs ugen20_tr_release(pdev); 56397883Sgibbs 56497883Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) { 56597883Sgibbs return (LIBUSB20_ERROR_OTHER); 56697883Sgibbs } 56797883Sgibbs return (ugen20_tr_renew(pdev)); 56897883Sgibbs} 56997883Sgibbs 57097883Sgibbsstatic int 57197883Sgibbsugen20_check_connected(struct libusb20_device *pdev) 57297883Sgibbs{ 57397883Sgibbs uint32_t plugtime; 57497883Sgibbs int error = 0; 57597883Sgibbs 57697883Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 57797883Sgibbs error = LIBUSB20_ERROR_NO_DEVICE; 57897883Sgibbs goto done; 57997883Sgibbs } 58097883Sgibbs 58197883Sgibbs if (pdev->session_data.plugtime != plugtime) { 58297883Sgibbs error = LIBUSB20_ERROR_NO_DEVICE; 58397883Sgibbs goto done; 584107441Sscottl } 585107441Sscottldone: 58697883Sgibbs return (error); 58797883Sgibbs} 58897883Sgibbs 58997883Sgibbsstatic int 59097883Sgibbsugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 591107441Sscottl{ 592104023Sgibbs int temp; 59397883Sgibbs 594107441Sscottl switch (power_mode) { 595107441Sscottl case LIBUSB20_POWER_OFF: 596107441Sscottl temp = USB_POWER_MODE_OFF; 597107441Sscottl break; 598107441Sscottl case LIBUSB20_POWER_ON: 599107441Sscottl temp = USB_POWER_MODE_ON; 600107441Sscottl break; 601107441Sscottl case LIBUSB20_POWER_SAVE: 602107441Sscottl temp = USB_POWER_MODE_SAVE; 603107441Sscottl break; 604107441Sscottl case LIBUSB20_POWER_SUSPEND: 605107441Sscottl temp = USB_POWER_MODE_SUSPEND; 606107441Sscottl break; 607107441Sscottl case LIBUSB20_POWER_RESUME: 608104023Sgibbs temp = USB_POWER_MODE_RESUME; 609104023Sgibbs break; 61097883Sgibbs default: 61197883Sgibbs return (LIBUSB20_ERROR_INVALID_PARAM); 61297883Sgibbs } 61397883Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) { 61497883Sgibbs return (LIBUSB20_ERROR_OTHER); 61597883Sgibbs } 61697883Sgibbs return (0); 61797883Sgibbs} 618123579Sgibbs 619123579Sgibbsstatic int 620123579Sgibbsugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 621123579Sgibbs{ 622123579Sgibbs int temp; 623123579Sgibbs 624123579Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) { 625123579Sgibbs return (LIBUSB20_ERROR_OTHER); 626123579Sgibbs } 627123579Sgibbs switch (temp) { 628123579Sgibbs case USB_POWER_MODE_OFF: 629123579Sgibbs temp = LIBUSB20_POWER_OFF; 630123579Sgibbs break; 631123579Sgibbs case USB_POWER_MODE_ON: 632123579Sgibbs temp = LIBUSB20_POWER_ON; 633104023Sgibbs break; 634104023Sgibbs case USB_POWER_MODE_SAVE: 635123579Sgibbs temp = LIBUSB20_POWER_SAVE; 636123579Sgibbs break; 637123579Sgibbs case USB_POWER_MODE_SUSPEND: 638123579Sgibbs temp = LIBUSB20_POWER_SUSPEND; 639123579Sgibbs break; 640104023Sgibbs case USB_POWER_MODE_RESUME: 641123579Sgibbs temp = LIBUSB20_POWER_RESUME; 642104023Sgibbs break; 643104023Sgibbs default: 644104023Sgibbs temp = LIBUSB20_POWER_ON; 64597883Sgibbs break; 64697883Sgibbs } 64797883Sgibbs *power_mode = temp; 64897883Sgibbs return (0); /* success */ 64997883Sgibbs} 65097883Sgibbs 65197883Sgibbsstatic int 65297883Sgibbsugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) 65397883Sgibbs{ 65497883Sgibbs struct usb_device_port_path udpp; 65597883Sgibbs 65697883Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_DEV_PORT_PATH), &udpp)) 65797883Sgibbs return (LIBUSB20_ERROR_OTHER); 65897883Sgibbs 65997883Sgibbs if (udpp.udp_port_level > bufsize) 66097883Sgibbs return (LIBUSB20_ERROR_OVERFLOW); 66197883Sgibbs 66297883Sgibbs memcpy(buf, udpp.udp_port_no, udpp.udp_port_level); 66397883Sgibbs 66497883Sgibbs return (udpp.udp_port_level); /* success */ 66597883Sgibbs} 66697883Sgibbs 66797883Sgibbsstatic int 66897883Sgibbsugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage) 66997883Sgibbs{ 67097883Sgibbs int temp; 671123579Sgibbs 672123579Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) { 673123579Sgibbs return (LIBUSB20_ERROR_OTHER); 674123579Sgibbs } 675123579Sgibbs *power_usage = temp; 676123579Sgibbs return (0); /* success */ 677123579Sgibbs} 678123579Sgibbs 679123579Sgibbsstatic int 680123579Sgibbsugen20_kernel_driver_active(struct libusb20_device *pdev, 681123579Sgibbs uint8_t iface_index) 682123579Sgibbs{ 683123579Sgibbs int temp = iface_index; 684123579Sgibbs 685123579Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) { 68697883Sgibbs return (LIBUSB20_ERROR_OTHER); 68797883Sgibbs } 68897883Sgibbs return (0); /* kernel driver is active */ 68997883Sgibbs} 69097883Sgibbs 691111653Sgibbsstatic int 69297883Sgibbsugen20_detach_kernel_driver(struct libusb20_device *pdev, 69397883Sgibbs uint8_t iface_index) 69497883Sgibbs{ 69597883Sgibbs int temp = iface_index; 69697883Sgibbs 69797883Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) { 69897883Sgibbs return (LIBUSB20_ERROR_OTHER); 69997883Sgibbs } 70097883Sgibbs return (0); /* kernel driver is detached */ 70197883Sgibbs} 70297883Sgibbs 70397883Sgibbsstatic int 70497883Sgibbsugen20_do_request_sync(struct libusb20_device *pdev, 70597883Sgibbs struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 70697883Sgibbs void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 70797883Sgibbs{ 70897883Sgibbs struct usb_ctl_request req; 70997883Sgibbs 71097883Sgibbs memset(&req, 0, sizeof(req)); 71197883Sgibbs 71297883Sgibbs req.ucr_data = libusb20_pass_ptr(data); 71397883Sgibbs if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 71497883Sgibbs req.ucr_flags |= USB_SHORT_XFER_OK; 71597883Sgibbs } 71697883Sgibbs if (libusb20_me_encode(&req.ucr_request, 71797883Sgibbs sizeof(req.ucr_request), setup)) { 71897883Sgibbs /* ignore */ 71997883Sgibbs } 72097883Sgibbs if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) { 72197883Sgibbs return (LIBUSB20_ERROR_OTHER); 72297883Sgibbs } 72397883Sgibbs if (pactlen) { 72497883Sgibbs /* get actual length */ 72597883Sgibbs *pactlen = req.ucr_actlen; 72697883Sgibbs } 72797883Sgibbs return (0); /* request was successful */ 72897883Sgibbs} 72997883Sgibbs 73097883Sgibbsstatic int 73197883Sgibbsugen20_process(struct libusb20_device *pdev) 73297883Sgibbs{ 73397883Sgibbs struct usb_fs_complete temp; 73497883Sgibbs struct usb_fs_endpoint *fsep; 73597883Sgibbs struct libusb20_transfer *xfer; 73697883Sgibbs 73797883Sgibbs while (1) { 73897883Sgibbs 73997883Sgibbs if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) { 74097883Sgibbs if (errno == EBUSY) { 74197883Sgibbs break; 74297883Sgibbs } else { 743107441Sscottl /* device detached */ 74497883Sgibbs return (LIBUSB20_ERROR_OTHER); 745133122Sgibbs } 746133122Sgibbs } 74797883Sgibbs fsep = pdev->privBeData; 748133122Sgibbs xfer = pdev->pTransfer; 74997883Sgibbs fsep += temp.ep_index; 75097883Sgibbs xfer += temp.ep_index; 751133122Sgibbs 75297883Sgibbs /* update transfer status */ 753133122Sgibbs 754133122Sgibbs if (fsep->status == 0) { 755133122Sgibbs xfer->aFrames = fsep->aFrames; 75697883Sgibbs xfer->timeComplete = fsep->isoc_time_complete; 75797883Sgibbs xfer->status = LIBUSB20_TRANSFER_COMPLETED; 758133122Sgibbs } else if (fsep->status == USB_ERR_CANCELLED) { 75997883Sgibbs xfer->aFrames = 0; 76097883Sgibbs xfer->timeComplete = 0; 76197883Sgibbs xfer->status = LIBUSB20_TRANSFER_CANCELLED; 76297883Sgibbs } else if (fsep->status == USB_ERR_STALLED) { 76397883Sgibbs xfer->aFrames = 0; 764133122Sgibbs xfer->timeComplete = 0; 76597883Sgibbs xfer->status = LIBUSB20_TRANSFER_STALL; 766133122Sgibbs } else if (fsep->status == USB_ERR_TIMEOUT) { 767133122Sgibbs xfer->aFrames = 0; 76897883Sgibbs xfer->timeComplete = 0; 769133122Sgibbs xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 770133122Sgibbs } else { 771133122Sgibbs xfer->aFrames = 0; 772133122Sgibbs xfer->timeComplete = 0; 773133122Sgibbs xfer->status = LIBUSB20_TRANSFER_ERROR; 774133122Sgibbs } 775133122Sgibbs libusb20_tr_callback_wrapper(xfer); 776133122Sgibbs } 777133122Sgibbs return (0); /* done */ 778133122Sgibbs} 779133122Sgibbs 78097883Sgibbsstatic int 78197883Sgibbsugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 78297883Sgibbs uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id, 78397883Sgibbs uint8_t pre_scale) 78497883Sgibbs{ 78597883Sgibbs union { 78697883Sgibbs struct usb_fs_open fs_open; 78797883Sgibbs struct usb_fs_open_stream fs_open_stream; 78897883Sgibbs } temp; 78997883Sgibbs struct usb_fs_endpoint *fsep; 79097883Sgibbs 791133122Sgibbs if (pre_scale) 792133122Sgibbs MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE; 79397883Sgibbs 79497883Sgibbs memset(&temp, 0, sizeof(temp)); 79597883Sgibbs 79697883Sgibbs fsep = xfer->pdev->privBeData; 79797883Sgibbs fsep += xfer->trIndex; 798109588Sgibbs 799109588Sgibbs temp.fs_open.max_bufsize = MaxBufSize; 80097883Sgibbs temp.fs_open.max_frames = MaxFrameCount; 80197883Sgibbs temp.fs_open.ep_index = xfer->trIndex; 802109588Sgibbs temp.fs_open.ep_no = ep_no; 803109588Sgibbs 804109588Sgibbs if (stream_id != 0) { 805109588Sgibbs temp.fs_open_stream.stream_id = stream_id; 806109588Sgibbs 80797883Sgibbs if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream)) 80897883Sgibbs return (LIBUSB20_ERROR_INVALID_PARAM); 80997883Sgibbs } else { 81097883Sgibbs if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open)) 811109588Sgibbs return (LIBUSB20_ERROR_INVALID_PARAM); 812109588Sgibbs } 813109588Sgibbs /* maximums might have changed - update */ 814109588Sgibbs xfer->maxFrames = temp.fs_open.max_frames; 81597883Sgibbs 81697883Sgibbs /* "max_bufsize" should be multiple of "max_packet_length" */ 81797883Sgibbs xfer->maxTotalLength = temp.fs_open.max_bufsize; 81897883Sgibbs xfer->maxPacketLen = temp.fs_open.max_packet_length; 819104023Sgibbs 820104023Sgibbs /* setup buffer and length lists using zero copy */ 821123579Sgibbs fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer); 822123579Sgibbs fsep->pLength = libusb20_pass_ptr(xfer->pLength); 823123579Sgibbs 824123579Sgibbs return (0); /* success */ 825123579Sgibbs} 826104023Sgibbs 827123579Sgibbsstatic int 828104023Sgibbsugen20_tr_close(struct libusb20_transfer *xfer) 829104023Sgibbs{ 830104023Sgibbs struct usb_fs_close temp; 83197883Sgibbs 83297883Sgibbs memset(&temp, 0, sizeof(temp)); 833109588Sgibbs 834109588Sgibbs temp.ep_index = xfer->trIndex; 83597883Sgibbs 83697883Sgibbs if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) { 83797883Sgibbs return (LIBUSB20_ERROR_INVALID_PARAM); 83897883Sgibbs } 83997883Sgibbs return (0); /* success */ 84097883Sgibbs} 84197883Sgibbs 84297883Sgibbsstatic int 84397883Sgibbsugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 84497883Sgibbs{ 84597883Sgibbs struct usb_fs_clear_stall_sync temp; 84697883Sgibbs 84797883Sgibbs memset(&temp, 0, sizeof(temp)); 84897883Sgibbs 84997883Sgibbs /* if the transfer is active, an error will be returned */ 85097883Sgibbs 85197883Sgibbs temp.ep_index = xfer->trIndex; 85297883Sgibbs 85397883Sgibbs if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) { 85497883Sgibbs return (LIBUSB20_ERROR_INVALID_PARAM); 85597883Sgibbs } 85697883Sgibbs return (0); /* success */ 85797883Sgibbs} 85897883Sgibbs 85997883Sgibbsstatic void 86097883Sgibbsugen20_tr_submit(struct libusb20_transfer *xfer) 861107441Sscottl{ 86297883Sgibbs struct usb_fs_start temp; 86397883Sgibbs struct usb_fs_endpoint *fsep; 86497883Sgibbs 86597883Sgibbs memset(&temp, 0, sizeof(temp)); 86697883Sgibbs 86797883Sgibbs fsep = xfer->pdev->privBeData; 868107441Sscottl fsep += xfer->trIndex; 869107441Sscottl 870107441Sscottl fsep->nFrames = xfer->nFrames; 87197883Sgibbs fsep->flags = 0; 87297883Sgibbs if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 87397883Sgibbs fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 87497883Sgibbs } 87597883Sgibbs if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 87697883Sgibbs fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 87797883Sgibbs } 878107441Sscottl if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 879107441Sscottl fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 88097883Sgibbs } 881107441Sscottl if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 88297883Sgibbs fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 883104023Sgibbs } 88497883Sgibbs /* NOTE: The "fsep->timeout" variable is 16-bit. */ 885107441Sscottl if (xfer->timeout > 65535) 886107441Sscottl fsep->timeout = 65535; 88797883Sgibbs else 88897883Sgibbs fsep->timeout = xfer->timeout; 88997883Sgibbs 890111653Sgibbs temp.ep_index = xfer->trIndex; 89197883Sgibbs 89297883Sgibbs if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) { 893107441Sscottl /* ignore any errors - should never happen */ 89497883Sgibbs } 89597883Sgibbs return; /* success */ 89697883Sgibbs} 89797883Sgibbs 898107441Sscottlstatic void 899107441Sscottlugen20_tr_cancel_async(struct libusb20_transfer *xfer) 900123579Sgibbs{ 901123579Sgibbs struct usb_fs_stop temp; 902123579Sgibbs 903123579Sgibbs memset(&temp, 0, sizeof(temp)); 904123579Sgibbs 905123579Sgibbs temp.ep_index = xfer->trIndex; 906123579Sgibbs 907123579Sgibbs if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) { 908123579Sgibbs /* ignore any errors - should never happen */ 909123579Sgibbs } 910123579Sgibbs return; 911123579Sgibbs} 912123579Sgibbs 913123579Sgibbsstatic int 914123579Sgibbsugen20_be_ioctl(uint32_t cmd, void *data) 915123579Sgibbs{ 916123579Sgibbs int f; 917123579Sgibbs int error; 918123579Sgibbs 919123579Sgibbs f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 920123579Sgibbs if (f < 0) 921123579Sgibbs return (LIBUSB20_ERROR_OTHER); 922123579Sgibbs error = ioctl(f, cmd, data); 923123579Sgibbs if (error == -1) { 924123579Sgibbs if (errno == EPERM) { 92597883Sgibbs error = LIBUSB20_ERROR_ACCESS; 92697883Sgibbs } else { 92797883Sgibbs error = LIBUSB20_ERROR_OTHER; 928107441Sscottl } 92997883Sgibbs } 93097883Sgibbs close(f); 931123579Sgibbs return (error); 93297883Sgibbs} 93397883Sgibbs 93497883Sgibbsstatic int 93597883Sgibbsugen20_dev_get_iface_desc(struct libusb20_device *pdev, 93697883Sgibbs uint8_t iface_index, char *buf, uint8_t len) 93797883Sgibbs{ 93897883Sgibbs struct usb_gen_descriptor ugd; 93997883Sgibbs 94097883Sgibbs memset(&ugd, 0, sizeof(ugd)); 94197883Sgibbs 94297883Sgibbs ugd.ugd_data = libusb20_pass_ptr(buf); 943107441Sscottl ugd.ugd_maxlen = len; 94497883Sgibbs ugd.ugd_iface_index = iface_index; 94597883Sgibbs 94697883Sgibbs if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) { 94797883Sgibbs return (LIBUSB20_ERROR_INVALID_PARAM); 94897883Sgibbs } 94997883Sgibbs return (0); 95097883Sgibbs} 95197883Sgibbs 95297883Sgibbsstatic int 95397883Sgibbsugen20_dev_get_info(struct libusb20_device *pdev, 95497883Sgibbs struct usb_device_info *pinfo) 95597883Sgibbs{ 95697883Sgibbs if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) { 95797883Sgibbs return (LIBUSB20_ERROR_INVALID_PARAM); 95897883Sgibbs } 95997883Sgibbs return (0); 96097883Sgibbs} 96197883Sgibbs 96297883Sgibbsstatic int 963299375Spfgugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 96497883Sgibbs uint16_t quirk_index, struct libusb20_quirk *pq) 96597883Sgibbs{ 96697883Sgibbs struct usb_gen_quirk q; 96797883Sgibbs int error; 96897883Sgibbs 96997883Sgibbs memset(&q, 0, sizeof(q)); 97097883Sgibbs 97197883Sgibbs q.index = quirk_index; 97297883Sgibbs 97397883Sgibbs error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q); 97497883Sgibbs 97597883Sgibbs if (error) { 97697883Sgibbs if (errno == EINVAL) { 97797883Sgibbs return (LIBUSB20_ERROR_NOT_FOUND); 97897883Sgibbs } 97997883Sgibbs } else { 98097883Sgibbs pq->vid = q.vid; 98197883Sgibbs pq->pid = q.pid; 98297883Sgibbs pq->bcdDeviceLow = q.bcdDeviceLow; 98397883Sgibbs pq->bcdDeviceHigh = q.bcdDeviceHigh; 98497883Sgibbs strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 98597883Sgibbs } 98697883Sgibbs return (error); 98797883Sgibbs} 98897883Sgibbs 98997883Sgibbsstatic int 99097883Sgibbsugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 99197883Sgibbs struct libusb20_quirk *pq) 99297883Sgibbs{ 99397883Sgibbs struct usb_gen_quirk q; 99497883Sgibbs int error; 99597883Sgibbs 996102682Sgibbs memset(&q, 0, sizeof(q)); 99797883Sgibbs 99897883Sgibbs q.index = quirk_index; 99997883Sgibbs 100097883Sgibbs error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q); 100197883Sgibbs 100297883Sgibbs if (error) { 100397883Sgibbs if (errno == EINVAL) { 100497883Sgibbs return (LIBUSB20_ERROR_NOT_FOUND); 100597883Sgibbs } 100697883Sgibbs } else { 100797883Sgibbs strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 100897883Sgibbs } 100997883Sgibbs return (error); 101097883Sgibbs} 101197883Sgibbs 101297883Sgibbsstatic int 101397883Sgibbsugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 101497883Sgibbs struct libusb20_quirk *pq) 101597883Sgibbs{ 101697883Sgibbs struct usb_gen_quirk q; 101797883Sgibbs int error; 101897883Sgibbs 101997883Sgibbs memset(&q, 0, sizeof(q)); 102097883Sgibbs 102197883Sgibbs q.vid = pq->vid; 102297883Sgibbs q.pid = pq->pid; 102397883Sgibbs q.bcdDeviceLow = pq->bcdDeviceLow; 102497883Sgibbs q.bcdDeviceHigh = pq->bcdDeviceHigh; 102597883Sgibbs strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 102697883Sgibbs 102797883Sgibbs error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q); 102897883Sgibbs if (error) { 102997883Sgibbs if (errno == ENOMEM) { 103097883Sgibbs return (LIBUSB20_ERROR_NO_MEM); 103197883Sgibbs } 103297883Sgibbs } 103397883Sgibbs return (error); 103497883Sgibbs} 103597883Sgibbs 103697883Sgibbsstatic int 103797883Sgibbsugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 103897883Sgibbs struct libusb20_quirk *pq) 103997883Sgibbs{ 104097883Sgibbs struct usb_gen_quirk q; 104197883Sgibbs int error; 104297883Sgibbs 104397883Sgibbs memset(&q, 0, sizeof(q)); 104497883Sgibbs 104597883Sgibbs q.vid = pq->vid; 104697883Sgibbs q.pid = pq->pid; 104797883Sgibbs q.bcdDeviceLow = pq->bcdDeviceLow; 1048107441Sscottl q.bcdDeviceHigh = pq->bcdDeviceHigh; 104997883Sgibbs strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 105097883Sgibbs 105197883Sgibbs error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q); 105297883Sgibbs if (error) { 105397883Sgibbs if (errno == EINVAL) { 105497883Sgibbs return (LIBUSB20_ERROR_NOT_FOUND); 105597883Sgibbs } 105697883Sgibbs } 105797883Sgibbs return (error); 1058109588Sgibbs} 1059109588Sgibbs 106097883Sgibbsstatic int 1061109588Sgibbsugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1062109588Sgibbs{ 1063109588Sgibbs return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp)); 106497883Sgibbs} 106597883Sgibbs 106697883Sgibbsstatic int 106797883Sgibbsugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1068115335Sgibbs{ 1069115335Sgibbs return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp)); 107097883Sgibbs} 107197883Sgibbs