1184610Salfred/* $FreeBSD: stable/10/lib/libusb/libusb20_ugen20.c 356399 2020-01-06 09:22:33Z hselasky $ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27248236Shselasky#ifdef LIBUSB_GLOBAL_INCLUDE_FILE 28248236Shselasky#include LIBUSB_GLOBAL_INCLUDE_FILE 29248236Shselasky#else 30203815Swkoszek#include <errno.h> 31203815Swkoszek#include <fcntl.h> 32184610Salfred#include <stdio.h> 33184610Salfred#include <stdlib.h> 34203815Swkoszek#include <string.h> 35184610Salfred#include <unistd.h> 36248236Shselasky#include <time.h> 37248236Shselasky#include <sys/queue.h> 38248236Shselasky#include <sys/types.h> 39248236Shselasky#endif 40184610Salfred 41248236Shselasky#include <dev/usb/usb.h> 42248236Shselasky#include <dev/usb/usbdi.h> 43248236Shselasky#include <dev/usb/usb_ioctl.h> 44248236Shselasky 45184610Salfred#include "libusb20.h" 46184610Salfred#include "libusb20_desc.h" 47184610Salfred#include "libusb20_int.h" 48184610Salfred 49253339Shselasky#ifndef IOUSB 50253339Shselasky#define IOUSB(a) a 51253339Shselasky#endif 52253339Shselasky 53184610Salfredstatic libusb20_init_backend_t ugen20_init_backend; 54184610Salfredstatic libusb20_open_device_t ugen20_open_device; 55184610Salfredstatic libusb20_close_device_t ugen20_close_device; 56184610Salfredstatic libusb20_get_backend_name_t ugen20_get_backend_name; 57184610Salfredstatic libusb20_exit_backend_t ugen20_exit_backend; 58188622Sthompsastatic libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc; 59188622Sthompsastatic libusb20_dev_get_info_t ugen20_dev_get_info; 60184610Salfredstatic libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk; 61184610Salfredstatic libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name; 62184610Salfredstatic libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk; 63184610Salfredstatic libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk; 64188987Sthompsastatic libusb20_root_set_template_t ugen20_root_set_template; 65188987Sthompsastatic libusb20_root_get_template_t ugen20_root_get_template; 66184610Salfred 67184610Salfredconst struct libusb20_backend_methods libusb20_ugen20_backend = { 68184610Salfred LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20) 69184610Salfred}; 70184610Salfred 71184610Salfred/* USB device specific */ 72184610Salfredstatic libusb20_get_config_desc_full_t ugen20_get_config_desc_full; 73184610Salfredstatic libusb20_get_config_index_t ugen20_get_config_index; 74184610Salfredstatic libusb20_set_config_index_t ugen20_set_config_index; 75184610Salfredstatic libusb20_set_alt_index_t ugen20_set_alt_index; 76184610Salfredstatic libusb20_reset_device_t ugen20_reset_device; 77203147Sthompsastatic libusb20_check_connected_t ugen20_check_connected; 78184610Salfredstatic libusb20_set_power_mode_t ugen20_set_power_mode; 79184610Salfredstatic libusb20_get_power_mode_t ugen20_get_power_mode; 80250201Shselaskystatic libusb20_get_port_path_t ugen20_get_port_path; 81246789Shselaskystatic libusb20_get_power_usage_t ugen20_get_power_usage; 82356399Shselaskystatic libusb20_get_stats_t ugen20_get_stats; 83184610Salfredstatic libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 84184610Salfredstatic libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 85184610Salfredstatic libusb20_do_request_sync_t ugen20_do_request_sync; 86184610Salfredstatic libusb20_process_t ugen20_process; 87184610Salfred 88184610Salfred/* USB transfer specific */ 89184610Salfredstatic libusb20_tr_open_t ugen20_tr_open; 90184610Salfredstatic libusb20_tr_close_t ugen20_tr_close; 91184610Salfredstatic libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 92184610Salfredstatic libusb20_tr_submit_t ugen20_tr_submit; 93184610Salfredstatic libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 94184610Salfred 95184610Salfredstatic const struct libusb20_device_methods libusb20_ugen20_device_methods = { 96184610Salfred LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 97184610Salfred}; 98184610Salfred 99184610Salfredstatic const char * 100184610Salfredugen20_get_backend_name(void) 101184610Salfred{ 102184610Salfred return ("FreeBSD UGEN 2.0"); 103184610Salfred} 104184610Salfred 105184610Salfredstatic uint32_t 106184610Salfredugen20_path_convert_one(const char **pp) 107184610Salfred{ 108184610Salfred const char *ptr; 109184610Salfred uint32_t temp = 0; 110184610Salfred 111184610Salfred ptr = *pp; 112184610Salfred 113184610Salfred while ((*ptr >= '0') && (*ptr <= '9')) { 114184610Salfred temp *= 10; 115184610Salfred temp += (*ptr - '0'); 116184610Salfred if (temp >= 1000000) { 117184610Salfred /* catch overflow early */ 118234491Shselasky return (0xFFFFFFFF); 119184610Salfred } 120184610Salfred ptr++; 121184610Salfred } 122184610Salfred 123184610Salfred if (*ptr == '.') { 124184610Salfred /* skip dot */ 125184610Salfred ptr++; 126184610Salfred } 127184610Salfred *pp = ptr; 128184610Salfred 129184610Salfred return (temp); 130184610Salfred} 131184610Salfred 132184610Salfredstatic int 133184610Salfredugen20_enumerate(struct libusb20_device *pdev, const char *id) 134184610Salfred{ 135184610Salfred const char *tmp = id; 136192984Sthompsa struct usb_device_descriptor ddesc; 137192984Sthompsa struct usb_device_info devinfo; 138184610Salfred uint32_t plugtime; 139184610Salfred char buf[64]; 140184610Salfred int f; 141184610Salfred int error; 142184610Salfred 143184610Salfred pdev->bus_number = ugen20_path_convert_one(&tmp); 144184610Salfred pdev->device_address = ugen20_path_convert_one(&tmp); 145184610Salfred 146189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 147184610Salfred pdev->bus_number, pdev->device_address); 148184610Salfred 149184610Salfred f = open(buf, O_RDWR); 150184610Salfred if (f < 0) { 151184610Salfred return (LIBUSB20_ERROR_OTHER); 152184610Salfred } 153253339Shselasky if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 154184610Salfred error = LIBUSB20_ERROR_OTHER; 155184610Salfred goto done; 156184610Salfred } 157184610Salfred /* store when the device was plugged */ 158184610Salfred pdev->session_data.plugtime = plugtime; 159184610Salfred 160253339Shselasky if (ioctl(f, IOUSB(USB_GET_DEVICE_DESC), &ddesc)) { 161184610Salfred error = LIBUSB20_ERROR_OTHER; 162184610Salfred goto done; 163184610Salfred } 164184610Salfred LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 165184610Salfred 166184610Salfred libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 167184610Salfred 168184610Salfred if (pdev->ddesc.bNumConfigurations == 0) { 169184610Salfred error = LIBUSB20_ERROR_OTHER; 170184610Salfred goto done; 171184610Salfred } else if (pdev->ddesc.bNumConfigurations >= 8) { 172184610Salfred error = LIBUSB20_ERROR_OTHER; 173184610Salfred goto done; 174184610Salfred } 175253339Shselasky if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo)) { 176184610Salfred error = LIBUSB20_ERROR_OTHER; 177184610Salfred goto done; 178184610Salfred } 179184610Salfred switch (devinfo.udi_mode) { 180184610Salfred case USB_MODE_DEVICE: 181184610Salfred pdev->usb_mode = LIBUSB20_MODE_DEVICE; 182184610Salfred break; 183184610Salfred default: 184184610Salfred pdev->usb_mode = LIBUSB20_MODE_HOST; 185184610Salfred break; 186184610Salfred } 187184610Salfred 188184610Salfred switch (devinfo.udi_speed) { 189184610Salfred case USB_SPEED_LOW: 190184610Salfred pdev->usb_speed = LIBUSB20_SPEED_LOW; 191184610Salfred break; 192184610Salfred case USB_SPEED_FULL: 193184610Salfred pdev->usb_speed = LIBUSB20_SPEED_FULL; 194184610Salfred break; 195184610Salfred case USB_SPEED_HIGH: 196184610Salfred pdev->usb_speed = LIBUSB20_SPEED_HIGH; 197184610Salfred break; 198184610Salfred case USB_SPEED_VARIABLE: 199184610Salfred pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 200184610Salfred break; 201184610Salfred case USB_SPEED_SUPER: 202184610Salfred pdev->usb_speed = LIBUSB20_SPEED_SUPER; 203184610Salfred break; 204184610Salfred default: 205184610Salfred pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 206184610Salfred break; 207184610Salfred } 208184610Salfred 209223495Shselasky /* get parent HUB index and port */ 210223495Shselasky 211223495Shselasky pdev->parent_address = devinfo.udi_hubindex; 212223495Shselasky pdev->parent_port = devinfo.udi_hubport; 213223495Shselasky 214184610Salfred /* generate a nice description for printout */ 215184610Salfred 216184610Salfred snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 217189110Sthompsa USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, 218310280Strasz pdev->device_address, devinfo.udi_vendor, 219310280Strasz devinfo.udi_product, pdev->bus_number); 220184610Salfred 221184610Salfred error = 0; 222184610Salfreddone: 223184610Salfred close(f); 224184610Salfred return (error); 225184610Salfred} 226184610Salfred 227184610Salfredstruct ugen20_urd_state { 228192984Sthompsa struct usb_read_dir urd; 229184610Salfred uint32_t nparsed; 230184610Salfred int f; 231184610Salfred uint8_t *ptr; 232184610Salfred const char *src; 233184610Salfred const char *dst; 234184610Salfred uint8_t buf[256]; 235184610Salfred uint8_t dummy_zero[1]; 236184610Salfred}; 237184610Salfred 238184610Salfredstatic int 239184610Salfredugen20_readdir(struct ugen20_urd_state *st) 240184610Salfred{ 241184610Salfred ; /* style fix */ 242184610Salfredrepeat: 243184610Salfred if (st->ptr == NULL) { 244184610Salfred st->urd.urd_startentry += st->nparsed; 245213852Shselasky st->urd.urd_data = libusb20_pass_ptr(st->buf); 246184610Salfred st->urd.urd_maxlen = sizeof(st->buf); 247184610Salfred st->nparsed = 0; 248184610Salfred 249253339Shselasky if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) { 250184610Salfred return (EINVAL); 251184610Salfred } 252184610Salfred st->ptr = st->buf; 253184610Salfred } 254184610Salfred if (st->ptr[0] == 0) { 255184610Salfred if (st->nparsed) { 256184610Salfred st->ptr = NULL; 257184610Salfred goto repeat; 258184610Salfred } else { 259184610Salfred return (ENXIO); 260184610Salfred } 261184610Salfred } 262184610Salfred st->src = (void *)(st->ptr + 1); 263184610Salfred st->dst = st->src + strlen(st->src) + 1; 264184610Salfred st->ptr = st->ptr + st->ptr[0]; 265184610Salfred st->nparsed++; 266184610Salfred 267184610Salfred if ((st->ptr < st->buf) || 268184610Salfred (st->ptr > st->dummy_zero)) { 269184610Salfred /* invalid entry */ 270184610Salfred return (EINVAL); 271184610Salfred } 272184610Salfred return (0); 273184610Salfred} 274184610Salfred 275184610Salfredstatic int 276184610Salfredugen20_init_backend(struct libusb20_backend *pbe) 277184610Salfred{ 278184610Salfred struct ugen20_urd_state state; 279184610Salfred struct libusb20_device *pdev; 280184610Salfred 281184610Salfred memset(&state, 0, sizeof(state)); 282184610Salfred 283189110Sthompsa state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 284184610Salfred if (state.f < 0) 285184610Salfred return (LIBUSB20_ERROR_OTHER); 286184610Salfred 287184610Salfred while (ugen20_readdir(&state) == 0) { 288184610Salfred 289184610Salfred if ((state.src[0] != 'u') || 290184610Salfred (state.src[1] != 'g') || 291184610Salfred (state.src[2] != 'e') || 292184610Salfred (state.src[3] != 'n')) { 293184610Salfred continue; 294184610Salfred } 295184610Salfred pdev = libusb20_dev_alloc(); 296184610Salfred if (pdev == NULL) { 297184610Salfred continue; 298184610Salfred } 299184610Salfred if (ugen20_enumerate(pdev, state.src + 4)) { 300184610Salfred libusb20_dev_free(pdev); 301184610Salfred continue; 302184610Salfred } 303184610Salfred /* put the device on the backend list */ 304184610Salfred libusb20_be_enqueue_device(pbe, pdev); 305184610Salfred } 306184610Salfred close(state.f); 307184610Salfred return (0); /* success */ 308184610Salfred} 309184610Salfred 310185290Salfredstatic void 311185290Salfredugen20_tr_release(struct libusb20_device *pdev) 312185290Salfred{ 313192984Sthompsa struct usb_fs_uninit fs_uninit; 314185290Salfred 315185290Salfred if (pdev->nTransfer == 0) { 316185290Salfred return; 317185290Salfred } 318185290Salfred /* release all pending USB transfers */ 319185290Salfred if (pdev->privBeData != NULL) { 320185290Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 321253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 322185290Salfred /* ignore any errors of this kind */ 323185290Salfred } 324185290Salfred } 325185290Salfred return; 326185290Salfred} 327185290Salfred 328184610Salfredstatic int 329185087Salfredugen20_tr_renew(struct libusb20_device *pdev) 330185087Salfred{ 331192984Sthompsa struct usb_fs_init fs_init; 332192984Sthompsa struct usb_fs_endpoint *pfse; 333185087Salfred int error; 334185087Salfred uint32_t size; 335185087Salfred uint16_t nMaxTransfer; 336185087Salfred 337185087Salfred nMaxTransfer = pdev->nTransfer; 338185087Salfred error = 0; 339185087Salfred 340185087Salfred if (nMaxTransfer == 0) { 341185087Salfred goto done; 342185087Salfred } 343185087Salfred size = nMaxTransfer * sizeof(*pfse); 344185087Salfred 345185290Salfred if (pdev->privBeData == NULL) { 346185087Salfred pfse = malloc(size); 347185087Salfred if (pfse == NULL) { 348185087Salfred error = LIBUSB20_ERROR_NO_MEM; 349185087Salfred goto done; 350185087Salfred } 351185087Salfred pdev->privBeData = pfse; 352185087Salfred } 353185087Salfred /* reset endpoint data */ 354185087Salfred memset(pdev->privBeData, 0, size); 355185087Salfred 356185087Salfred memset(&fs_init, 0, sizeof(fs_init)); 357185087Salfred 358213852Shselasky fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData); 359185087Salfred fs_init.ep_index_max = nMaxTransfer; 360185087Salfred 361253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) { 362185087Salfred error = LIBUSB20_ERROR_OTHER; 363185087Salfred goto done; 364185087Salfred } 365185087Salfreddone: 366185087Salfred return (error); 367185087Salfred} 368185087Salfred 369185087Salfredstatic int 370184610Salfredugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 371184610Salfred{ 372184610Salfred uint32_t plugtime; 373184610Salfred char buf[64]; 374184610Salfred int f; 375184610Salfred int g; 376184610Salfred int error; 377184610Salfred 378189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 379184610Salfred pdev->bus_number, pdev->device_address); 380184610Salfred 381184610Salfred /* 382184610Salfred * We need two file handles, one for the control endpoint and one 383184610Salfred * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 384184610Salfred * kernel locking. 385184610Salfred */ 386184610Salfred g = open(buf, O_RDWR); 387184610Salfred if (g < 0) { 388184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 389184610Salfred } 390184610Salfred f = open(buf, O_RDWR); 391184610Salfred if (f < 0) { 392184610Salfred close(g); 393184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 394184610Salfred } 395253339Shselasky if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 396184610Salfred error = LIBUSB20_ERROR_OTHER; 397184610Salfred goto done; 398184610Salfred } 399184610Salfred /* check that the correct device is still plugged */ 400184610Salfred if (pdev->session_data.plugtime != plugtime) { 401184610Salfred error = LIBUSB20_ERROR_NO_DEVICE; 402184610Salfred goto done; 403184610Salfred } 404185087Salfred /* need to set this before "tr_renew()" */ 405185087Salfred pdev->file = f; 406185087Salfred pdev->file_ctrl = g; 407184610Salfred 408185087Salfred /* renew all USB transfers */ 409185087Salfred error = ugen20_tr_renew(pdev); 410185087Salfred if (error) { 411185087Salfred goto done; 412184610Salfred } 413184610Salfred /* set methods */ 414184610Salfred pdev->methods = &libusb20_ugen20_device_methods; 415185087Salfred 416184610Salfreddone: 417184610Salfred if (error) { 418185087Salfred if (pdev->privBeData) { 419185087Salfred /* cleanup after "tr_renew()" */ 420185087Salfred free(pdev->privBeData); 421185087Salfred pdev->privBeData = NULL; 422184610Salfred } 423185087Salfred pdev->file = -1; 424185087Salfred pdev->file_ctrl = -1; 425184610Salfred close(f); 426184610Salfred close(g); 427184610Salfred } 428184610Salfred return (error); 429184610Salfred} 430184610Salfred 431184610Salfredstatic int 432184610Salfredugen20_close_device(struct libusb20_device *pdev) 433184610Salfred{ 434192984Sthompsa struct usb_fs_uninit fs_uninit; 435184610Salfred 436184610Salfred if (pdev->privBeData) { 437185087Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 438253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 439185290Salfred /* ignore this error */ 440184610Salfred } 441184610Salfred free(pdev->privBeData); 442184610Salfred } 443184610Salfred pdev->nTransfer = 0; 444184610Salfred pdev->privBeData = NULL; 445184610Salfred close(pdev->file); 446184610Salfred close(pdev->file_ctrl); 447184610Salfred pdev->file = -1; 448184610Salfred pdev->file_ctrl = -1; 449185290Salfred return (0); /* success */ 450184610Salfred} 451184610Salfred 452184610Salfredstatic void 453184610Salfredugen20_exit_backend(struct libusb20_backend *pbe) 454184610Salfred{ 455184610Salfred return; /* nothing to do */ 456184610Salfred} 457184610Salfred 458184610Salfredstatic int 459184610Salfredugen20_get_config_desc_full(struct libusb20_device *pdev, 460185087Salfred uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 461184610Salfred{ 462192984Sthompsa struct usb_gen_descriptor gen_desc; 463192984Sthompsa struct usb_config_descriptor cdesc; 464184610Salfred uint8_t *ptr; 465184610Salfred uint16_t len; 466184610Salfred int error; 467184610Salfred 468199055Sthompsa /* make sure memory is initialised */ 469199055Sthompsa memset(&cdesc, 0, sizeof(cdesc)); 470185087Salfred memset(&gen_desc, 0, sizeof(gen_desc)); 471185087Salfred 472213852Shselasky gen_desc.ugd_data = libusb20_pass_ptr(&cdesc); 473184610Salfred gen_desc.ugd_maxlen = sizeof(cdesc); 474185087Salfred gen_desc.ugd_config_index = cfg_index; 475184610Salfred 476253339Shselasky error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 477184610Salfred if (error) { 478184610Salfred return (LIBUSB20_ERROR_OTHER); 479184610Salfred } 480184610Salfred len = UGETW(cdesc.wTotalLength); 481184610Salfred if (len < sizeof(cdesc)) { 482184610Salfred /* corrupt descriptor */ 483184610Salfred return (LIBUSB20_ERROR_OTHER); 484184610Salfred } 485184610Salfred ptr = malloc(len); 486184610Salfred if (!ptr) { 487184610Salfred return (LIBUSB20_ERROR_NO_MEM); 488184610Salfred } 489199055Sthompsa 490199055Sthompsa /* make sure memory is initialised */ 491199055Sthompsa memset(ptr, 0, len); 492199055Sthompsa 493213852Shselasky gen_desc.ugd_data = libusb20_pass_ptr(ptr); 494184610Salfred gen_desc.ugd_maxlen = len; 495184610Salfred 496253339Shselasky error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 497184610Salfred if (error) { 498184610Salfred free(ptr); 499184610Salfred return (LIBUSB20_ERROR_OTHER); 500184610Salfred } 501184610Salfred /* make sure that the device doesn't fool us */ 502184610Salfred memcpy(ptr, &cdesc, sizeof(cdesc)); 503184610Salfred 504184610Salfred *ppbuf = ptr; 505184610Salfred *plen = len; 506184610Salfred 507184610Salfred return (0); /* success */ 508184610Salfred} 509184610Salfred 510184610Salfredstatic int 511184610Salfredugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 512184610Salfred{ 513184610Salfred int temp; 514184610Salfred 515253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) { 516184610Salfred return (LIBUSB20_ERROR_OTHER); 517184610Salfred } 518184610Salfred *pindex = temp; 519184610Salfred 520184610Salfred return (0); 521184610Salfred} 522184610Salfred 523184610Salfredstatic int 524185087Salfredugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 525184610Salfred{ 526185087Salfred int temp = cfg_index; 527184610Salfred 528185290Salfred /* release all active USB transfers */ 529185290Salfred ugen20_tr_release(pdev); 530185290Salfred 531253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) { 532184610Salfred return (LIBUSB20_ERROR_OTHER); 533184610Salfred } 534185087Salfred return (ugen20_tr_renew(pdev)); 535184610Salfred} 536184610Salfred 537184610Salfredstatic int 538184610Salfredugen20_set_alt_index(struct libusb20_device *pdev, 539184610Salfred uint8_t iface_index, uint8_t alt_index) 540184610Salfred{ 541192984Sthompsa struct usb_alt_interface alt_iface; 542184610Salfred 543185087Salfred memset(&alt_iface, 0, sizeof(alt_iface)); 544185087Salfred 545184610Salfred alt_iface.uai_interface_index = iface_index; 546184610Salfred alt_iface.uai_alt_index = alt_index; 547184610Salfred 548185290Salfred /* release all active USB transfers */ 549185290Salfred ugen20_tr_release(pdev); 550185290Salfred 551253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) { 552184610Salfred return (LIBUSB20_ERROR_OTHER); 553184610Salfred } 554185087Salfred return (ugen20_tr_renew(pdev)); 555184610Salfred} 556184610Salfred 557184610Salfredstatic int 558184610Salfredugen20_reset_device(struct libusb20_device *pdev) 559184610Salfred{ 560184610Salfred int temp = 0; 561184610Salfred 562185290Salfred /* release all active USB transfers */ 563185290Salfred ugen20_tr_release(pdev); 564185290Salfred 565253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) { 566184610Salfred return (LIBUSB20_ERROR_OTHER); 567184610Salfred } 568185087Salfred return (ugen20_tr_renew(pdev)); 569184610Salfred} 570184610Salfred 571184610Salfredstatic int 572203147Sthompsaugen20_check_connected(struct libusb20_device *pdev) 573203147Sthompsa{ 574203147Sthompsa uint32_t plugtime; 575203147Sthompsa int error = 0; 576203147Sthompsa 577253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 578203147Sthompsa error = LIBUSB20_ERROR_NO_DEVICE; 579203147Sthompsa goto done; 580203147Sthompsa } 581203147Sthompsa 582203147Sthompsa if (pdev->session_data.plugtime != plugtime) { 583203147Sthompsa error = LIBUSB20_ERROR_NO_DEVICE; 584203147Sthompsa goto done; 585203147Sthompsa } 586203147Sthompsadone: 587203147Sthompsa return (error); 588203147Sthompsa} 589203147Sthompsa 590203147Sthompsastatic int 591184610Salfredugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 592184610Salfred{ 593184610Salfred int temp; 594184610Salfred 595184610Salfred switch (power_mode) { 596184610Salfred case LIBUSB20_POWER_OFF: 597184610Salfred temp = USB_POWER_MODE_OFF; 598184610Salfred break; 599184610Salfred case LIBUSB20_POWER_ON: 600184610Salfred temp = USB_POWER_MODE_ON; 601184610Salfred break; 602184610Salfred case LIBUSB20_POWER_SAVE: 603184610Salfred temp = USB_POWER_MODE_SAVE; 604184610Salfred break; 605184610Salfred case LIBUSB20_POWER_SUSPEND: 606184610Salfred temp = USB_POWER_MODE_SUSPEND; 607184610Salfred break; 608184610Salfred case LIBUSB20_POWER_RESUME: 609184610Salfred temp = USB_POWER_MODE_RESUME; 610184610Salfred break; 611184610Salfred default: 612184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 613184610Salfred } 614253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) { 615184610Salfred return (LIBUSB20_ERROR_OTHER); 616184610Salfred } 617184610Salfred return (0); 618184610Salfred} 619184610Salfred 620184610Salfredstatic int 621184610Salfredugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 622184610Salfred{ 623184610Salfred int temp; 624184610Salfred 625253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) { 626184610Salfred return (LIBUSB20_ERROR_OTHER); 627184610Salfred } 628184610Salfred switch (temp) { 629184610Salfred case USB_POWER_MODE_OFF: 630184610Salfred temp = LIBUSB20_POWER_OFF; 631184610Salfred break; 632184610Salfred case USB_POWER_MODE_ON: 633184610Salfred temp = LIBUSB20_POWER_ON; 634184610Salfred break; 635184610Salfred case USB_POWER_MODE_SAVE: 636184610Salfred temp = LIBUSB20_POWER_SAVE; 637184610Salfred break; 638184610Salfred case USB_POWER_MODE_SUSPEND: 639184610Salfred temp = LIBUSB20_POWER_SUSPEND; 640184610Salfred break; 641184610Salfred case USB_POWER_MODE_RESUME: 642184610Salfred temp = LIBUSB20_POWER_RESUME; 643184610Salfred break; 644184610Salfred default: 645184610Salfred temp = LIBUSB20_POWER_ON; 646184610Salfred break; 647184610Salfred } 648184610Salfred *power_mode = temp; 649184610Salfred return (0); /* success */ 650184610Salfred} 651184610Salfred 652184610Salfredstatic int 653250201Shselaskyugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) 654250201Shselasky{ 655250201Shselasky struct usb_device_port_path udpp; 656250201Shselasky 657253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_DEV_PORT_PATH), &udpp)) 658250201Shselasky return (LIBUSB20_ERROR_OTHER); 659250201Shselasky 660250201Shselasky if (udpp.udp_port_level > bufsize) 661250201Shselasky return (LIBUSB20_ERROR_OVERFLOW); 662250201Shselasky 663250201Shselasky memcpy(buf, udpp.udp_port_no, udpp.udp_port_level); 664250201Shselasky 665250201Shselasky return (udpp.udp_port_level); /* success */ 666250201Shselasky} 667250201Shselasky 668250201Shselaskystatic int 669246789Shselaskyugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage) 670246789Shselasky{ 671246789Shselasky int temp; 672246789Shselasky 673253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) { 674246789Shselasky return (LIBUSB20_ERROR_OTHER); 675246789Shselasky } 676246789Shselasky *power_usage = temp; 677246789Shselasky return (0); /* success */ 678246789Shselasky} 679246789Shselasky 680246789Shselaskystatic int 681356399Shselaskyugen20_get_stats(struct libusb20_device *pdev, struct libusb20_device_stats *pstats) 682356399Shselasky{ 683356399Shselasky struct usb_device_stats st; 684356399Shselasky 685356399Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICESTATS), &st)) 686356399Shselasky return (LIBUSB20_ERROR_OTHER); 687356399Shselasky 688356399Shselasky memset(pstats, 0, sizeof(*pstats)); 689356399Shselasky 690356399Shselasky pstats->xfer_ok[0] = st.uds_requests_ok[0]; 691356399Shselasky pstats->xfer_ok[1] = st.uds_requests_ok[1]; 692356399Shselasky pstats->xfer_ok[2] = st.uds_requests_ok[2]; 693356399Shselasky pstats->xfer_ok[3] = st.uds_requests_ok[3]; 694356399Shselasky 695356399Shselasky pstats->xfer_fail[0] = st.uds_requests_fail[0]; 696356399Shselasky pstats->xfer_fail[1] = st.uds_requests_fail[1]; 697356399Shselasky pstats->xfer_fail[2] = st.uds_requests_fail[2]; 698356399Shselasky pstats->xfer_fail[3] = st.uds_requests_fail[3]; 699356399Shselasky 700356399Shselasky return (0); /* success */ 701356399Shselasky} 702356399Shselasky 703356399Shselaskystatic int 704184610Salfredugen20_kernel_driver_active(struct libusb20_device *pdev, 705184610Salfred uint8_t iface_index) 706184610Salfred{ 707184610Salfred int temp = iface_index; 708184610Salfred 709253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) { 710184610Salfred return (LIBUSB20_ERROR_OTHER); 711184610Salfred } 712184610Salfred return (0); /* kernel driver is active */ 713184610Salfred} 714184610Salfred 715184610Salfredstatic int 716184610Salfredugen20_detach_kernel_driver(struct libusb20_device *pdev, 717184610Salfred uint8_t iface_index) 718184610Salfred{ 719184610Salfred int temp = iface_index; 720184610Salfred 721253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) { 722184610Salfred return (LIBUSB20_ERROR_OTHER); 723184610Salfred } 724255242Shselasky return (0); /* kernel driver is detached */ 725184610Salfred} 726184610Salfred 727184610Salfredstatic int 728184610Salfredugen20_do_request_sync(struct libusb20_device *pdev, 729184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 730184610Salfred void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 731184610Salfred{ 732192984Sthompsa struct usb_ctl_request req; 733184610Salfred 734185087Salfred memset(&req, 0, sizeof(req)); 735185087Salfred 736213852Shselasky req.ucr_data = libusb20_pass_ptr(data); 737184610Salfred if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 738184610Salfred req.ucr_flags |= USB_SHORT_XFER_OK; 739184610Salfred } 740184610Salfred if (libusb20_me_encode(&req.ucr_request, 741184610Salfred sizeof(req.ucr_request), setup)) { 742184610Salfred /* ignore */ 743184610Salfred } 744253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) { 745184610Salfred return (LIBUSB20_ERROR_OTHER); 746184610Salfred } 747184610Salfred if (pactlen) { 748184610Salfred /* get actual length */ 749184610Salfred *pactlen = req.ucr_actlen; 750184610Salfred } 751255242Shselasky return (0); /* request was successful */ 752184610Salfred} 753184610Salfred 754184610Salfredstatic int 755184610Salfredugen20_process(struct libusb20_device *pdev) 756184610Salfred{ 757192984Sthompsa struct usb_fs_complete temp; 758192984Sthompsa struct usb_fs_endpoint *fsep; 759184610Salfred struct libusb20_transfer *xfer; 760184610Salfred 761184610Salfred while (1) { 762184610Salfred 763253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) { 764184610Salfred if (errno == EBUSY) { 765184610Salfred break; 766184610Salfred } else { 767184610Salfred /* device detached */ 768184610Salfred return (LIBUSB20_ERROR_OTHER); 769184610Salfred } 770184610Salfred } 771184610Salfred fsep = pdev->privBeData; 772184610Salfred xfer = pdev->pTransfer; 773184610Salfred fsep += temp.ep_index; 774184610Salfred xfer += temp.ep_index; 775184610Salfred 776184610Salfred /* update transfer status */ 777184610Salfred 778184610Salfred if (fsep->status == 0) { 779184610Salfred xfer->aFrames = fsep->aFrames; 780184610Salfred xfer->timeComplete = fsep->isoc_time_complete; 781184610Salfred xfer->status = LIBUSB20_TRANSFER_COMPLETED; 782184610Salfred } else if (fsep->status == USB_ERR_CANCELLED) { 783184610Salfred xfer->aFrames = 0; 784184610Salfred xfer->timeComplete = 0; 785184610Salfred xfer->status = LIBUSB20_TRANSFER_CANCELLED; 786184610Salfred } else if (fsep->status == USB_ERR_STALLED) { 787184610Salfred xfer->aFrames = 0; 788184610Salfred xfer->timeComplete = 0; 789184610Salfred xfer->status = LIBUSB20_TRANSFER_STALL; 790184610Salfred } else if (fsep->status == USB_ERR_TIMEOUT) { 791184610Salfred xfer->aFrames = 0; 792184610Salfred xfer->timeComplete = 0; 793184610Salfred xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 794184610Salfred } else { 795184610Salfred xfer->aFrames = 0; 796184610Salfred xfer->timeComplete = 0; 797184610Salfred xfer->status = LIBUSB20_TRANSFER_ERROR; 798184610Salfred } 799184610Salfred libusb20_tr_callback_wrapper(xfer); 800184610Salfred } 801184610Salfred return (0); /* done */ 802184610Salfred} 803184610Salfred 804184610Salfredstatic int 805184610Salfredugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 806239239Shselasky uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id, 807239239Shselasky uint8_t pre_scale) 808184610Salfred{ 809239239Shselasky union { 810239239Shselasky struct usb_fs_open fs_open; 811239239Shselasky struct usb_fs_open_stream fs_open_stream; 812239239Shselasky } temp; 813192984Sthompsa struct usb_fs_endpoint *fsep; 814184610Salfred 815219100Shselasky if (pre_scale) 816219100Shselasky MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE; 817219100Shselasky 818185087Salfred memset(&temp, 0, sizeof(temp)); 819185087Salfred 820184610Salfred fsep = xfer->pdev->privBeData; 821184610Salfred fsep += xfer->trIndex; 822184610Salfred 823239239Shselasky temp.fs_open.max_bufsize = MaxBufSize; 824239239Shselasky temp.fs_open.max_frames = MaxFrameCount; 825239239Shselasky temp.fs_open.ep_index = xfer->trIndex; 826239239Shselasky temp.fs_open.ep_no = ep_no; 827184610Salfred 828239239Shselasky if (stream_id != 0) { 829239239Shselasky temp.fs_open_stream.stream_id = stream_id; 830239239Shselasky 831253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream)) 832239239Shselasky return (LIBUSB20_ERROR_INVALID_PARAM); 833239239Shselasky } else { 834253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open)) 835239239Shselasky return (LIBUSB20_ERROR_INVALID_PARAM); 836184610Salfred } 837184610Salfred /* maximums might have changed - update */ 838239239Shselasky xfer->maxFrames = temp.fs_open.max_frames; 839184610Salfred 840184610Salfred /* "max_bufsize" should be multiple of "max_packet_length" */ 841239239Shselasky xfer->maxTotalLength = temp.fs_open.max_bufsize; 842239239Shselasky xfer->maxPacketLen = temp.fs_open.max_packet_length; 843184610Salfred 844213852Shselasky /* setup buffer and length lists using zero copy */ 845213852Shselasky fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer); 846213852Shselasky fsep->pLength = libusb20_pass_ptr(xfer->pLength); 847184610Salfred 848184610Salfred return (0); /* success */ 849184610Salfred} 850184610Salfred 851184610Salfredstatic int 852184610Salfredugen20_tr_close(struct libusb20_transfer *xfer) 853184610Salfred{ 854192984Sthompsa struct usb_fs_close temp; 855184610Salfred 856185087Salfred memset(&temp, 0, sizeof(temp)); 857185087Salfred 858184610Salfred temp.ep_index = xfer->trIndex; 859184610Salfred 860253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) { 861184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 862184610Salfred } 863184610Salfred return (0); /* success */ 864184610Salfred} 865184610Salfred 866184610Salfredstatic int 867184610Salfredugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 868184610Salfred{ 869192984Sthompsa struct usb_fs_clear_stall_sync temp; 870184610Salfred 871185087Salfred memset(&temp, 0, sizeof(temp)); 872185087Salfred 873184610Salfred /* if the transfer is active, an error will be returned */ 874184610Salfred 875184610Salfred temp.ep_index = xfer->trIndex; 876184610Salfred 877253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) { 878184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 879184610Salfred } 880184610Salfred return (0); /* success */ 881184610Salfred} 882184610Salfred 883184610Salfredstatic void 884184610Salfredugen20_tr_submit(struct libusb20_transfer *xfer) 885184610Salfred{ 886192984Sthompsa struct usb_fs_start temp; 887192984Sthompsa struct usb_fs_endpoint *fsep; 888184610Salfred 889185087Salfred memset(&temp, 0, sizeof(temp)); 890185087Salfred 891184610Salfred fsep = xfer->pdev->privBeData; 892184610Salfred fsep += xfer->trIndex; 893184610Salfred 894184610Salfred fsep->nFrames = xfer->nFrames; 895184610Salfred fsep->flags = 0; 896184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 897184610Salfred fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 898184610Salfred } 899184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 900184610Salfred fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 901184610Salfred } 902184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 903184610Salfred fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 904184610Salfred } 905184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 906184610Salfred fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 907184610Salfred } 908198376Sthompsa /* NOTE: The "fsep->timeout" variable is 16-bit. */ 909198376Sthompsa if (xfer->timeout > 65535) 910198376Sthompsa fsep->timeout = 65535; 911198376Sthompsa else 912198376Sthompsa fsep->timeout = xfer->timeout; 913184610Salfred 914184610Salfred temp.ep_index = xfer->trIndex; 915184610Salfred 916253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) { 917184610Salfred /* ignore any errors - should never happen */ 918184610Salfred } 919184610Salfred return; /* success */ 920184610Salfred} 921184610Salfred 922184610Salfredstatic void 923184610Salfredugen20_tr_cancel_async(struct libusb20_transfer *xfer) 924184610Salfred{ 925192984Sthompsa struct usb_fs_stop temp; 926184610Salfred 927185087Salfred memset(&temp, 0, sizeof(temp)); 928185087Salfred 929184610Salfred temp.ep_index = xfer->trIndex; 930184610Salfred 931253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) { 932184610Salfred /* ignore any errors - should never happen */ 933184610Salfred } 934184610Salfred return; 935184610Salfred} 936184610Salfred 937184610Salfredstatic int 938184610Salfredugen20_be_ioctl(uint32_t cmd, void *data) 939184610Salfred{ 940184610Salfred int f; 941185087Salfred int error; 942184610Salfred 943189110Sthompsa f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 944184610Salfred if (f < 0) 945184610Salfred return (LIBUSB20_ERROR_OTHER); 946185087Salfred error = ioctl(f, cmd, data); 947185087Salfred if (error == -1) { 948184610Salfred if (errno == EPERM) { 949185087Salfred error = LIBUSB20_ERROR_ACCESS; 950184610Salfred } else { 951185087Salfred error = LIBUSB20_ERROR_OTHER; 952184610Salfred } 953184610Salfred } 954184610Salfred close(f); 955185087Salfred return (error); 956184610Salfred} 957184610Salfred 958184610Salfredstatic int 959188622Sthompsaugen20_dev_get_iface_desc(struct libusb20_device *pdev, 960188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 961188622Sthompsa{ 962192984Sthompsa struct usb_gen_descriptor ugd; 963188622Sthompsa 964188622Sthompsa memset(&ugd, 0, sizeof(ugd)); 965188622Sthompsa 966213852Shselasky ugd.ugd_data = libusb20_pass_ptr(buf); 967188622Sthompsa ugd.ugd_maxlen = len; 968188622Sthompsa ugd.ugd_iface_index = iface_index; 969188622Sthompsa 970253339Shselasky if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) { 971188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 972188622Sthompsa } 973188622Sthompsa return (0); 974188622Sthompsa} 975188622Sthompsa 976188622Sthompsastatic int 977188622Sthompsaugen20_dev_get_info(struct libusb20_device *pdev, 978192984Sthompsa struct usb_device_info *pinfo) 979188622Sthompsa{ 980253339Shselasky if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) { 981188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 982188622Sthompsa } 983188622Sthompsa return (0); 984188622Sthompsa} 985188622Sthompsa 986188622Sthompsastatic int 987184610Salfredugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 988185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 989184610Salfred{ 990192984Sthompsa struct usb_gen_quirk q; 991185087Salfred int error; 992184610Salfred 993184610Salfred memset(&q, 0, sizeof(q)); 994184610Salfred 995185087Salfred q.index = quirk_index; 996184610Salfred 997253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q); 998184610Salfred 999185087Salfred if (error) { 1000184610Salfred if (errno == EINVAL) { 1001184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1002184610Salfred } 1003184610Salfred } else { 1004184610Salfred pq->vid = q.vid; 1005184610Salfred pq->pid = q.pid; 1006184610Salfred pq->bcdDeviceLow = q.bcdDeviceLow; 1007184610Salfred pq->bcdDeviceHigh = q.bcdDeviceHigh; 1008184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1009184610Salfred } 1010185087Salfred return (error); 1011184610Salfred} 1012184610Salfred 1013184610Salfredstatic int 1014185087Salfredugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 1015184610Salfred struct libusb20_quirk *pq) 1016184610Salfred{ 1017192984Sthompsa struct usb_gen_quirk q; 1018185087Salfred int error; 1019184610Salfred 1020184610Salfred memset(&q, 0, sizeof(q)); 1021184610Salfred 1022185087Salfred q.index = quirk_index; 1023184610Salfred 1024253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q); 1025184610Salfred 1026185087Salfred if (error) { 1027184610Salfred if (errno == EINVAL) { 1028184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1029184610Salfred } 1030184610Salfred } else { 1031184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1032184610Salfred } 1033185087Salfred return (error); 1034184610Salfred} 1035184610Salfred 1036184610Salfredstatic int 1037184610Salfredugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 1038184610Salfred struct libusb20_quirk *pq) 1039184610Salfred{ 1040192984Sthompsa struct usb_gen_quirk q; 1041185087Salfred int error; 1042184610Salfred 1043184610Salfred memset(&q, 0, sizeof(q)); 1044184610Salfred 1045184610Salfred q.vid = pq->vid; 1046184610Salfred q.pid = pq->pid; 1047184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 1048184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 1049184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1050184610Salfred 1051253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q); 1052185087Salfred if (error) { 1053184610Salfred if (errno == ENOMEM) { 1054184610Salfred return (LIBUSB20_ERROR_NO_MEM); 1055184610Salfred } 1056184610Salfred } 1057185087Salfred return (error); 1058184610Salfred} 1059184610Salfred 1060184610Salfredstatic int 1061184610Salfredugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 1062184610Salfred struct libusb20_quirk *pq) 1063184610Salfred{ 1064192984Sthompsa struct usb_gen_quirk q; 1065185087Salfred int error; 1066184610Salfred 1067184610Salfred memset(&q, 0, sizeof(q)); 1068184610Salfred 1069184610Salfred q.vid = pq->vid; 1070184610Salfred q.pid = pq->pid; 1071184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 1072184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 1073184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1074184610Salfred 1075253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q); 1076185087Salfred if (error) { 1077184610Salfred if (errno == EINVAL) { 1078184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1079184610Salfred } 1080184610Salfred } 1081185087Salfred return (error); 1082184610Salfred} 1083184610Salfred 1084184610Salfredstatic int 1085188987Sthompsaugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1086188987Sthompsa{ 1087253339Shselasky return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp)); 1088188987Sthompsa} 1089188987Sthompsa 1090188987Sthompsastatic int 1091188987Sthompsaugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1092188987Sthompsa{ 1093253339Shselasky return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp)); 1094188987Sthompsa} 1095