libusb20_ugen20.c revision 255242
1184610Salfred/* $FreeBSD: head/lib/libusb/libusb20_ugen20.c 255242 2013-09-05 12:21:11Z 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; 82184610Salfredstatic libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 83184610Salfredstatic libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 84184610Salfredstatic libusb20_do_request_sync_t ugen20_do_request_sync; 85184610Salfredstatic libusb20_process_t ugen20_process; 86184610Salfred 87184610Salfred/* USB transfer specific */ 88184610Salfredstatic libusb20_tr_open_t ugen20_tr_open; 89184610Salfredstatic libusb20_tr_close_t ugen20_tr_close; 90184610Salfredstatic libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 91184610Salfredstatic libusb20_tr_submit_t ugen20_tr_submit; 92184610Salfredstatic libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 93184610Salfred 94184610Salfredstatic const struct libusb20_device_methods libusb20_ugen20_device_methods = { 95184610Salfred LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 96184610Salfred}; 97184610Salfred 98184610Salfredstatic const char * 99184610Salfredugen20_get_backend_name(void) 100184610Salfred{ 101184610Salfred return ("FreeBSD UGEN 2.0"); 102184610Salfred} 103184610Salfred 104184610Salfredstatic uint32_t 105184610Salfredugen20_path_convert_one(const char **pp) 106184610Salfred{ 107184610Salfred const char *ptr; 108184610Salfred uint32_t temp = 0; 109184610Salfred 110184610Salfred ptr = *pp; 111184610Salfred 112184610Salfred while ((*ptr >= '0') && (*ptr <= '9')) { 113184610Salfred temp *= 10; 114184610Salfred temp += (*ptr - '0'); 115184610Salfred if (temp >= 1000000) { 116184610Salfred /* catch overflow early */ 117234491Shselasky return (0xFFFFFFFF); 118184610Salfred } 119184610Salfred ptr++; 120184610Salfred } 121184610Salfred 122184610Salfred if (*ptr == '.') { 123184610Salfred /* skip dot */ 124184610Salfred ptr++; 125184610Salfred } 126184610Salfred *pp = ptr; 127184610Salfred 128184610Salfred return (temp); 129184610Salfred} 130184610Salfred 131184610Salfredstatic int 132184610Salfredugen20_enumerate(struct libusb20_device *pdev, const char *id) 133184610Salfred{ 134184610Salfred const char *tmp = id; 135192984Sthompsa struct usb_device_descriptor ddesc; 136192984Sthompsa struct usb_device_info devinfo; 137184610Salfred uint32_t plugtime; 138184610Salfred char buf[64]; 139184610Salfred int f; 140184610Salfred int error; 141184610Salfred 142184610Salfred pdev->bus_number = ugen20_path_convert_one(&tmp); 143184610Salfred pdev->device_address = ugen20_path_convert_one(&tmp); 144184610Salfred 145189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 146184610Salfred pdev->bus_number, pdev->device_address); 147184610Salfred 148184610Salfred f = open(buf, O_RDWR); 149184610Salfred if (f < 0) { 150184610Salfred return (LIBUSB20_ERROR_OTHER); 151184610Salfred } 152253339Shselasky if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 153184610Salfred error = LIBUSB20_ERROR_OTHER; 154184610Salfred goto done; 155184610Salfred } 156184610Salfred /* store when the device was plugged */ 157184610Salfred pdev->session_data.plugtime = plugtime; 158184610Salfred 159253339Shselasky if (ioctl(f, IOUSB(USB_GET_DEVICE_DESC), &ddesc)) { 160184610Salfred error = LIBUSB20_ERROR_OTHER; 161184610Salfred goto done; 162184610Salfred } 163184610Salfred LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 164184610Salfred 165184610Salfred libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 166184610Salfred 167184610Salfred if (pdev->ddesc.bNumConfigurations == 0) { 168184610Salfred error = LIBUSB20_ERROR_OTHER; 169184610Salfred goto done; 170184610Salfred } else if (pdev->ddesc.bNumConfigurations >= 8) { 171184610Salfred error = LIBUSB20_ERROR_OTHER; 172184610Salfred goto done; 173184610Salfred } 174253339Shselasky if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo)) { 175184610Salfred error = LIBUSB20_ERROR_OTHER; 176184610Salfred goto done; 177184610Salfred } 178184610Salfred switch (devinfo.udi_mode) { 179184610Salfred case USB_MODE_DEVICE: 180184610Salfred pdev->usb_mode = LIBUSB20_MODE_DEVICE; 181184610Salfred break; 182184610Salfred default: 183184610Salfred pdev->usb_mode = LIBUSB20_MODE_HOST; 184184610Salfred break; 185184610Salfred } 186184610Salfred 187184610Salfred switch (devinfo.udi_speed) { 188184610Salfred case USB_SPEED_LOW: 189184610Salfred pdev->usb_speed = LIBUSB20_SPEED_LOW; 190184610Salfred break; 191184610Salfred case USB_SPEED_FULL: 192184610Salfred pdev->usb_speed = LIBUSB20_SPEED_FULL; 193184610Salfred break; 194184610Salfred case USB_SPEED_HIGH: 195184610Salfred pdev->usb_speed = LIBUSB20_SPEED_HIGH; 196184610Salfred break; 197184610Salfred case USB_SPEED_VARIABLE: 198184610Salfred pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 199184610Salfred break; 200184610Salfred case USB_SPEED_SUPER: 201184610Salfred pdev->usb_speed = LIBUSB20_SPEED_SUPER; 202184610Salfred break; 203184610Salfred default: 204184610Salfred pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 205184610Salfred break; 206184610Salfred } 207184610Salfred 208223495Shselasky /* get parent HUB index and port */ 209223495Shselasky 210223495Shselasky pdev->parent_address = devinfo.udi_hubindex; 211223495Shselasky pdev->parent_port = devinfo.udi_hubport; 212223495Shselasky 213184610Salfred /* generate a nice description for printout */ 214184610Salfred 215184610Salfred snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 216189110Sthompsa USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, 217184610Salfred pdev->device_address, devinfo.udi_product, 218184610Salfred devinfo.udi_vendor, pdev->bus_number); 219184610Salfred 220184610Salfred error = 0; 221184610Salfreddone: 222184610Salfred close(f); 223184610Salfred return (error); 224184610Salfred} 225184610Salfred 226184610Salfredstruct ugen20_urd_state { 227192984Sthompsa struct usb_read_dir urd; 228184610Salfred uint32_t nparsed; 229184610Salfred int f; 230184610Salfred uint8_t *ptr; 231184610Salfred const char *src; 232184610Salfred const char *dst; 233184610Salfred uint8_t buf[256]; 234184610Salfred uint8_t dummy_zero[1]; 235184610Salfred}; 236184610Salfred 237184610Salfredstatic int 238184610Salfredugen20_readdir(struct ugen20_urd_state *st) 239184610Salfred{ 240184610Salfred ; /* style fix */ 241184610Salfredrepeat: 242184610Salfred if (st->ptr == NULL) { 243184610Salfred st->urd.urd_startentry += st->nparsed; 244213852Shselasky st->urd.urd_data = libusb20_pass_ptr(st->buf); 245184610Salfred st->urd.urd_maxlen = sizeof(st->buf); 246184610Salfred st->nparsed = 0; 247184610Salfred 248253339Shselasky if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) { 249184610Salfred return (EINVAL); 250184610Salfred } 251184610Salfred st->ptr = st->buf; 252184610Salfred } 253184610Salfred if (st->ptr[0] == 0) { 254184610Salfred if (st->nparsed) { 255184610Salfred st->ptr = NULL; 256184610Salfred goto repeat; 257184610Salfred } else { 258184610Salfred return (ENXIO); 259184610Salfred } 260184610Salfred } 261184610Salfred st->src = (void *)(st->ptr + 1); 262184610Salfred st->dst = st->src + strlen(st->src) + 1; 263184610Salfred st->ptr = st->ptr + st->ptr[0]; 264184610Salfred st->nparsed++; 265184610Salfred 266184610Salfred if ((st->ptr < st->buf) || 267184610Salfred (st->ptr > st->dummy_zero)) { 268184610Salfred /* invalid entry */ 269184610Salfred return (EINVAL); 270184610Salfred } 271184610Salfred return (0); 272184610Salfred} 273184610Salfred 274184610Salfredstatic int 275184610Salfredugen20_init_backend(struct libusb20_backend *pbe) 276184610Salfred{ 277184610Salfred struct ugen20_urd_state state; 278184610Salfred struct libusb20_device *pdev; 279184610Salfred 280184610Salfred memset(&state, 0, sizeof(state)); 281184610Salfred 282189110Sthompsa state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 283184610Salfred if (state.f < 0) 284184610Salfred return (LIBUSB20_ERROR_OTHER); 285184610Salfred 286184610Salfred while (ugen20_readdir(&state) == 0) { 287184610Salfred 288184610Salfred if ((state.src[0] != 'u') || 289184610Salfred (state.src[1] != 'g') || 290184610Salfred (state.src[2] != 'e') || 291184610Salfred (state.src[3] != 'n')) { 292184610Salfred continue; 293184610Salfred } 294184610Salfred pdev = libusb20_dev_alloc(); 295184610Salfred if (pdev == NULL) { 296184610Salfred continue; 297184610Salfred } 298184610Salfred if (ugen20_enumerate(pdev, state.src + 4)) { 299184610Salfred libusb20_dev_free(pdev); 300184610Salfred continue; 301184610Salfred } 302184610Salfred /* put the device on the backend list */ 303184610Salfred libusb20_be_enqueue_device(pbe, pdev); 304184610Salfred } 305184610Salfred close(state.f); 306184610Salfred return (0); /* success */ 307184610Salfred} 308184610Salfred 309185290Salfredstatic void 310185290Salfredugen20_tr_release(struct libusb20_device *pdev) 311185290Salfred{ 312192984Sthompsa struct usb_fs_uninit fs_uninit; 313185290Salfred 314185290Salfred if (pdev->nTransfer == 0) { 315185290Salfred return; 316185290Salfred } 317185290Salfred /* release all pending USB transfers */ 318185290Salfred if (pdev->privBeData != NULL) { 319185290Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 320253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 321185290Salfred /* ignore any errors of this kind */ 322185290Salfred } 323185290Salfred } 324185290Salfred return; 325185290Salfred} 326185290Salfred 327184610Salfredstatic int 328185087Salfredugen20_tr_renew(struct libusb20_device *pdev) 329185087Salfred{ 330192984Sthompsa struct usb_fs_init fs_init; 331192984Sthompsa struct usb_fs_endpoint *pfse; 332185087Salfred int error; 333185087Salfred uint32_t size; 334185087Salfred uint16_t nMaxTransfer; 335185087Salfred 336185087Salfred nMaxTransfer = pdev->nTransfer; 337185087Salfred error = 0; 338185087Salfred 339185087Salfred if (nMaxTransfer == 0) { 340185087Salfred goto done; 341185087Salfred } 342185087Salfred size = nMaxTransfer * sizeof(*pfse); 343185087Salfred 344185290Salfred if (pdev->privBeData == NULL) { 345185087Salfred pfse = malloc(size); 346185087Salfred if (pfse == NULL) { 347185087Salfred error = LIBUSB20_ERROR_NO_MEM; 348185087Salfred goto done; 349185087Salfred } 350185087Salfred pdev->privBeData = pfse; 351185087Salfred } 352185087Salfred /* reset endpoint data */ 353185087Salfred memset(pdev->privBeData, 0, size); 354185087Salfred 355185087Salfred memset(&fs_init, 0, sizeof(fs_init)); 356185087Salfred 357213852Shselasky fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData); 358185087Salfred fs_init.ep_index_max = nMaxTransfer; 359185087Salfred 360253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) { 361185087Salfred error = LIBUSB20_ERROR_OTHER; 362185087Salfred goto done; 363185087Salfred } 364185087Salfreddone: 365185087Salfred return (error); 366185087Salfred} 367185087Salfred 368185087Salfredstatic int 369184610Salfredugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 370184610Salfred{ 371184610Salfred uint32_t plugtime; 372184610Salfred char buf[64]; 373184610Salfred int f; 374184610Salfred int g; 375184610Salfred int error; 376184610Salfred 377189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 378184610Salfred pdev->bus_number, pdev->device_address); 379184610Salfred 380184610Salfred /* 381184610Salfred * We need two file handles, one for the control endpoint and one 382184610Salfred * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 383184610Salfred * kernel locking. 384184610Salfred */ 385184610Salfred g = open(buf, O_RDWR); 386184610Salfred if (g < 0) { 387184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 388184610Salfred } 389184610Salfred f = open(buf, O_RDWR); 390184610Salfred if (f < 0) { 391184610Salfred close(g); 392184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 393184610Salfred } 394253339Shselasky if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 395184610Salfred error = LIBUSB20_ERROR_OTHER; 396184610Salfred goto done; 397184610Salfred } 398184610Salfred /* check that the correct device is still plugged */ 399184610Salfred if (pdev->session_data.plugtime != plugtime) { 400184610Salfred error = LIBUSB20_ERROR_NO_DEVICE; 401184610Salfred goto done; 402184610Salfred } 403185087Salfred /* need to set this before "tr_renew()" */ 404185087Salfred pdev->file = f; 405185087Salfred pdev->file_ctrl = g; 406184610Salfred 407185087Salfred /* renew all USB transfers */ 408185087Salfred error = ugen20_tr_renew(pdev); 409185087Salfred if (error) { 410185087Salfred goto done; 411184610Salfred } 412184610Salfred /* set methods */ 413184610Salfred pdev->methods = &libusb20_ugen20_device_methods; 414185087Salfred 415184610Salfreddone: 416184610Salfred if (error) { 417185087Salfred if (pdev->privBeData) { 418185087Salfred /* cleanup after "tr_renew()" */ 419185087Salfred free(pdev->privBeData); 420185087Salfred pdev->privBeData = NULL; 421184610Salfred } 422185087Salfred pdev->file = -1; 423185087Salfred pdev->file_ctrl = -1; 424184610Salfred close(f); 425184610Salfred close(g); 426184610Salfred } 427184610Salfred return (error); 428184610Salfred} 429184610Salfred 430184610Salfredstatic int 431184610Salfredugen20_close_device(struct libusb20_device *pdev) 432184610Salfred{ 433192984Sthompsa struct usb_fs_uninit fs_uninit; 434184610Salfred 435184610Salfred if (pdev->privBeData) { 436185087Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 437253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 438185290Salfred /* ignore this error */ 439184610Salfred } 440184610Salfred free(pdev->privBeData); 441184610Salfred } 442184610Salfred pdev->nTransfer = 0; 443184610Salfred pdev->privBeData = NULL; 444184610Salfred close(pdev->file); 445184610Salfred close(pdev->file_ctrl); 446184610Salfred pdev->file = -1; 447184610Salfred pdev->file_ctrl = -1; 448185290Salfred return (0); /* success */ 449184610Salfred} 450184610Salfred 451184610Salfredstatic void 452184610Salfredugen20_exit_backend(struct libusb20_backend *pbe) 453184610Salfred{ 454184610Salfred return; /* nothing to do */ 455184610Salfred} 456184610Salfred 457184610Salfredstatic int 458184610Salfredugen20_get_config_desc_full(struct libusb20_device *pdev, 459185087Salfred uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 460184610Salfred{ 461192984Sthompsa struct usb_gen_descriptor gen_desc; 462192984Sthompsa struct usb_config_descriptor cdesc; 463184610Salfred uint8_t *ptr; 464184610Salfred uint16_t len; 465184610Salfred int error; 466184610Salfred 467199055Sthompsa /* make sure memory is initialised */ 468199055Sthompsa memset(&cdesc, 0, sizeof(cdesc)); 469185087Salfred memset(&gen_desc, 0, sizeof(gen_desc)); 470185087Salfred 471213852Shselasky gen_desc.ugd_data = libusb20_pass_ptr(&cdesc); 472184610Salfred gen_desc.ugd_maxlen = sizeof(cdesc); 473185087Salfred gen_desc.ugd_config_index = cfg_index; 474184610Salfred 475253339Shselasky error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 476184610Salfred if (error) { 477184610Salfred return (LIBUSB20_ERROR_OTHER); 478184610Salfred } 479184610Salfred len = UGETW(cdesc.wTotalLength); 480184610Salfred if (len < sizeof(cdesc)) { 481184610Salfred /* corrupt descriptor */ 482184610Salfred return (LIBUSB20_ERROR_OTHER); 483184610Salfred } 484184610Salfred ptr = malloc(len); 485184610Salfred if (!ptr) { 486184610Salfred return (LIBUSB20_ERROR_NO_MEM); 487184610Salfred } 488199055Sthompsa 489199055Sthompsa /* make sure memory is initialised */ 490199055Sthompsa memset(ptr, 0, len); 491199055Sthompsa 492213852Shselasky gen_desc.ugd_data = libusb20_pass_ptr(ptr); 493184610Salfred gen_desc.ugd_maxlen = len; 494184610Salfred 495253339Shselasky error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 496184610Salfred if (error) { 497184610Salfred free(ptr); 498184610Salfred return (LIBUSB20_ERROR_OTHER); 499184610Salfred } 500184610Salfred /* make sure that the device doesn't fool us */ 501184610Salfred memcpy(ptr, &cdesc, sizeof(cdesc)); 502184610Salfred 503184610Salfred *ppbuf = ptr; 504184610Salfred *plen = len; 505184610Salfred 506184610Salfred return (0); /* success */ 507184610Salfred} 508184610Salfred 509184610Salfredstatic int 510184610Salfredugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 511184610Salfred{ 512184610Salfred int temp; 513184610Salfred 514253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) { 515184610Salfred return (LIBUSB20_ERROR_OTHER); 516184610Salfred } 517184610Salfred *pindex = temp; 518184610Salfred 519184610Salfred return (0); 520184610Salfred} 521184610Salfred 522184610Salfredstatic int 523185087Salfredugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 524184610Salfred{ 525185087Salfred int temp = cfg_index; 526184610Salfred 527185290Salfred /* release all active USB transfers */ 528185290Salfred ugen20_tr_release(pdev); 529185290Salfred 530253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) { 531184610Salfred return (LIBUSB20_ERROR_OTHER); 532184610Salfred } 533185087Salfred return (ugen20_tr_renew(pdev)); 534184610Salfred} 535184610Salfred 536184610Salfredstatic int 537184610Salfredugen20_set_alt_index(struct libusb20_device *pdev, 538184610Salfred uint8_t iface_index, uint8_t alt_index) 539184610Salfred{ 540192984Sthompsa struct usb_alt_interface alt_iface; 541184610Salfred 542185087Salfred memset(&alt_iface, 0, sizeof(alt_iface)); 543185087Salfred 544184610Salfred alt_iface.uai_interface_index = iface_index; 545184610Salfred alt_iface.uai_alt_index = alt_index; 546184610Salfred 547185290Salfred /* release all active USB transfers */ 548185290Salfred ugen20_tr_release(pdev); 549185290Salfred 550253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) { 551184610Salfred return (LIBUSB20_ERROR_OTHER); 552184610Salfred } 553185087Salfred return (ugen20_tr_renew(pdev)); 554184610Salfred} 555184610Salfred 556184610Salfredstatic int 557184610Salfredugen20_reset_device(struct libusb20_device *pdev) 558184610Salfred{ 559184610Salfred int temp = 0; 560184610Salfred 561185290Salfred /* release all active USB transfers */ 562185290Salfred ugen20_tr_release(pdev); 563185290Salfred 564253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) { 565184610Salfred return (LIBUSB20_ERROR_OTHER); 566184610Salfred } 567185087Salfred return (ugen20_tr_renew(pdev)); 568184610Salfred} 569184610Salfred 570184610Salfredstatic int 571203147Sthompsaugen20_check_connected(struct libusb20_device *pdev) 572203147Sthompsa{ 573203147Sthompsa uint32_t plugtime; 574203147Sthompsa int error = 0; 575203147Sthompsa 576253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 577203147Sthompsa error = LIBUSB20_ERROR_NO_DEVICE; 578203147Sthompsa goto done; 579203147Sthompsa } 580203147Sthompsa 581203147Sthompsa if (pdev->session_data.plugtime != plugtime) { 582203147Sthompsa error = LIBUSB20_ERROR_NO_DEVICE; 583203147Sthompsa goto done; 584203147Sthompsa } 585203147Sthompsadone: 586203147Sthompsa return (error); 587203147Sthompsa} 588203147Sthompsa 589203147Sthompsastatic int 590184610Salfredugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 591184610Salfred{ 592184610Salfred int temp; 593184610Salfred 594184610Salfred switch (power_mode) { 595184610Salfred case LIBUSB20_POWER_OFF: 596184610Salfred temp = USB_POWER_MODE_OFF; 597184610Salfred break; 598184610Salfred case LIBUSB20_POWER_ON: 599184610Salfred temp = USB_POWER_MODE_ON; 600184610Salfred break; 601184610Salfred case LIBUSB20_POWER_SAVE: 602184610Salfred temp = USB_POWER_MODE_SAVE; 603184610Salfred break; 604184610Salfred case LIBUSB20_POWER_SUSPEND: 605184610Salfred temp = USB_POWER_MODE_SUSPEND; 606184610Salfred break; 607184610Salfred case LIBUSB20_POWER_RESUME: 608184610Salfred temp = USB_POWER_MODE_RESUME; 609184610Salfred break; 610184610Salfred default: 611184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 612184610Salfred } 613253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) { 614184610Salfred return (LIBUSB20_ERROR_OTHER); 615184610Salfred } 616184610Salfred return (0); 617184610Salfred} 618184610Salfred 619184610Salfredstatic int 620184610Salfredugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 621184610Salfred{ 622184610Salfred int temp; 623184610Salfred 624253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) { 625184610Salfred return (LIBUSB20_ERROR_OTHER); 626184610Salfred } 627184610Salfred switch (temp) { 628184610Salfred case USB_POWER_MODE_OFF: 629184610Salfred temp = LIBUSB20_POWER_OFF; 630184610Salfred break; 631184610Salfred case USB_POWER_MODE_ON: 632184610Salfred temp = LIBUSB20_POWER_ON; 633184610Salfred break; 634184610Salfred case USB_POWER_MODE_SAVE: 635184610Salfred temp = LIBUSB20_POWER_SAVE; 636184610Salfred break; 637184610Salfred case USB_POWER_MODE_SUSPEND: 638184610Salfred temp = LIBUSB20_POWER_SUSPEND; 639184610Salfred break; 640184610Salfred case USB_POWER_MODE_RESUME: 641184610Salfred temp = LIBUSB20_POWER_RESUME; 642184610Salfred break; 643184610Salfred default: 644184610Salfred temp = LIBUSB20_POWER_ON; 645184610Salfred break; 646184610Salfred } 647184610Salfred *power_mode = temp; 648184610Salfred return (0); /* success */ 649184610Salfred} 650184610Salfred 651184610Salfredstatic int 652250201Shselaskyugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) 653250201Shselasky{ 654250201Shselasky struct usb_device_port_path udpp; 655250201Shselasky 656253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_DEV_PORT_PATH), &udpp)) 657250201Shselasky return (LIBUSB20_ERROR_OTHER); 658250201Shselasky 659250201Shselasky if (udpp.udp_port_level > bufsize) 660250201Shselasky return (LIBUSB20_ERROR_OVERFLOW); 661250201Shselasky 662250201Shselasky memcpy(buf, udpp.udp_port_no, udpp.udp_port_level); 663250201Shselasky 664250201Shselasky return (udpp.udp_port_level); /* success */ 665250201Shselasky} 666250201Shselasky 667250201Shselaskystatic int 668246789Shselaskyugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage) 669246789Shselasky{ 670246789Shselasky int temp; 671246789Shselasky 672253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) { 673246789Shselasky return (LIBUSB20_ERROR_OTHER); 674246789Shselasky } 675246789Shselasky *power_usage = temp; 676246789Shselasky return (0); /* success */ 677246789Shselasky} 678246789Shselasky 679246789Shselaskystatic int 680184610Salfredugen20_kernel_driver_active(struct libusb20_device *pdev, 681184610Salfred uint8_t iface_index) 682184610Salfred{ 683184610Salfred int temp = iface_index; 684184610Salfred 685253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) { 686184610Salfred return (LIBUSB20_ERROR_OTHER); 687184610Salfred } 688184610Salfred return (0); /* kernel driver is active */ 689184610Salfred} 690184610Salfred 691184610Salfredstatic int 692184610Salfredugen20_detach_kernel_driver(struct libusb20_device *pdev, 693184610Salfred uint8_t iface_index) 694184610Salfred{ 695184610Salfred int temp = iface_index; 696184610Salfred 697253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) { 698184610Salfred return (LIBUSB20_ERROR_OTHER); 699184610Salfred } 700255242Shselasky return (0); /* kernel driver is detached */ 701184610Salfred} 702184610Salfred 703184610Salfredstatic int 704184610Salfredugen20_do_request_sync(struct libusb20_device *pdev, 705184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 706184610Salfred void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 707184610Salfred{ 708192984Sthompsa struct usb_ctl_request req; 709184610Salfred 710185087Salfred memset(&req, 0, sizeof(req)); 711185087Salfred 712213852Shselasky req.ucr_data = libusb20_pass_ptr(data); 713184610Salfred if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 714184610Salfred req.ucr_flags |= USB_SHORT_XFER_OK; 715184610Salfred } 716184610Salfred if (libusb20_me_encode(&req.ucr_request, 717184610Salfred sizeof(req.ucr_request), setup)) { 718184610Salfred /* ignore */ 719184610Salfred } 720253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) { 721184610Salfred return (LIBUSB20_ERROR_OTHER); 722184610Salfred } 723184610Salfred if (pactlen) { 724184610Salfred /* get actual length */ 725184610Salfred *pactlen = req.ucr_actlen; 726184610Salfred } 727255242Shselasky return (0); /* request was successful */ 728184610Salfred} 729184610Salfred 730184610Salfredstatic int 731184610Salfredugen20_process(struct libusb20_device *pdev) 732184610Salfred{ 733192984Sthompsa struct usb_fs_complete temp; 734192984Sthompsa struct usb_fs_endpoint *fsep; 735184610Salfred struct libusb20_transfer *xfer; 736184610Salfred 737184610Salfred while (1) { 738184610Salfred 739253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) { 740184610Salfred if (errno == EBUSY) { 741184610Salfred break; 742184610Salfred } else { 743184610Salfred /* device detached */ 744184610Salfred return (LIBUSB20_ERROR_OTHER); 745184610Salfred } 746184610Salfred } 747184610Salfred fsep = pdev->privBeData; 748184610Salfred xfer = pdev->pTransfer; 749184610Salfred fsep += temp.ep_index; 750184610Salfred xfer += temp.ep_index; 751184610Salfred 752184610Salfred /* update transfer status */ 753184610Salfred 754184610Salfred if (fsep->status == 0) { 755184610Salfred xfer->aFrames = fsep->aFrames; 756184610Salfred xfer->timeComplete = fsep->isoc_time_complete; 757184610Salfred xfer->status = LIBUSB20_TRANSFER_COMPLETED; 758184610Salfred } else if (fsep->status == USB_ERR_CANCELLED) { 759184610Salfred xfer->aFrames = 0; 760184610Salfred xfer->timeComplete = 0; 761184610Salfred xfer->status = LIBUSB20_TRANSFER_CANCELLED; 762184610Salfred } else if (fsep->status == USB_ERR_STALLED) { 763184610Salfred xfer->aFrames = 0; 764184610Salfred xfer->timeComplete = 0; 765184610Salfred xfer->status = LIBUSB20_TRANSFER_STALL; 766184610Salfred } else if (fsep->status == USB_ERR_TIMEOUT) { 767184610Salfred xfer->aFrames = 0; 768184610Salfred xfer->timeComplete = 0; 769184610Salfred xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 770184610Salfred } else { 771184610Salfred xfer->aFrames = 0; 772184610Salfred xfer->timeComplete = 0; 773184610Salfred xfer->status = LIBUSB20_TRANSFER_ERROR; 774184610Salfred } 775184610Salfred libusb20_tr_callback_wrapper(xfer); 776184610Salfred } 777184610Salfred return (0); /* done */ 778184610Salfred} 779184610Salfred 780184610Salfredstatic int 781184610Salfredugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 782239239Shselasky uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id, 783239239Shselasky uint8_t pre_scale) 784184610Salfred{ 785239239Shselasky union { 786239239Shselasky struct usb_fs_open fs_open; 787239239Shselasky struct usb_fs_open_stream fs_open_stream; 788239239Shselasky } temp; 789192984Sthompsa struct usb_fs_endpoint *fsep; 790184610Salfred 791219100Shselasky if (pre_scale) 792219100Shselasky MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE; 793219100Shselasky 794185087Salfred memset(&temp, 0, sizeof(temp)); 795185087Salfred 796184610Salfred fsep = xfer->pdev->privBeData; 797184610Salfred fsep += xfer->trIndex; 798184610Salfred 799239239Shselasky temp.fs_open.max_bufsize = MaxBufSize; 800239239Shselasky temp.fs_open.max_frames = MaxFrameCount; 801239239Shselasky temp.fs_open.ep_index = xfer->trIndex; 802239239Shselasky temp.fs_open.ep_no = ep_no; 803184610Salfred 804239239Shselasky if (stream_id != 0) { 805239239Shselasky temp.fs_open_stream.stream_id = stream_id; 806239239Shselasky 807253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream)) 808239239Shselasky return (LIBUSB20_ERROR_INVALID_PARAM); 809239239Shselasky } else { 810253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open)) 811239239Shselasky return (LIBUSB20_ERROR_INVALID_PARAM); 812184610Salfred } 813184610Salfred /* maximums might have changed - update */ 814239239Shselasky xfer->maxFrames = temp.fs_open.max_frames; 815184610Salfred 816184610Salfred /* "max_bufsize" should be multiple of "max_packet_length" */ 817239239Shselasky xfer->maxTotalLength = temp.fs_open.max_bufsize; 818239239Shselasky xfer->maxPacketLen = temp.fs_open.max_packet_length; 819184610Salfred 820213852Shselasky /* setup buffer and length lists using zero copy */ 821213852Shselasky fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer); 822213852Shselasky fsep->pLength = libusb20_pass_ptr(xfer->pLength); 823184610Salfred 824184610Salfred return (0); /* success */ 825184610Salfred} 826184610Salfred 827184610Salfredstatic int 828184610Salfredugen20_tr_close(struct libusb20_transfer *xfer) 829184610Salfred{ 830192984Sthompsa struct usb_fs_close temp; 831184610Salfred 832185087Salfred memset(&temp, 0, sizeof(temp)); 833185087Salfred 834184610Salfred temp.ep_index = xfer->trIndex; 835184610Salfred 836253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) { 837184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 838184610Salfred } 839184610Salfred return (0); /* success */ 840184610Salfred} 841184610Salfred 842184610Salfredstatic int 843184610Salfredugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 844184610Salfred{ 845192984Sthompsa struct usb_fs_clear_stall_sync temp; 846184610Salfred 847185087Salfred memset(&temp, 0, sizeof(temp)); 848185087Salfred 849184610Salfred /* if the transfer is active, an error will be returned */ 850184610Salfred 851184610Salfred temp.ep_index = xfer->trIndex; 852184610Salfred 853253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) { 854184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 855184610Salfred } 856184610Salfred return (0); /* success */ 857184610Salfred} 858184610Salfred 859184610Salfredstatic void 860184610Salfredugen20_tr_submit(struct libusb20_transfer *xfer) 861184610Salfred{ 862192984Sthompsa struct usb_fs_start temp; 863192984Sthompsa struct usb_fs_endpoint *fsep; 864184610Salfred 865185087Salfred memset(&temp, 0, sizeof(temp)); 866185087Salfred 867184610Salfred fsep = xfer->pdev->privBeData; 868184610Salfred fsep += xfer->trIndex; 869184610Salfred 870184610Salfred fsep->nFrames = xfer->nFrames; 871184610Salfred fsep->flags = 0; 872184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 873184610Salfred fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 874184610Salfred } 875184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 876184610Salfred fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 877184610Salfred } 878184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 879184610Salfred fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 880184610Salfred } 881184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 882184610Salfred fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 883184610Salfred } 884198376Sthompsa /* NOTE: The "fsep->timeout" variable is 16-bit. */ 885198376Sthompsa if (xfer->timeout > 65535) 886198376Sthompsa fsep->timeout = 65535; 887198376Sthompsa else 888198376Sthompsa fsep->timeout = xfer->timeout; 889184610Salfred 890184610Salfred temp.ep_index = xfer->trIndex; 891184610Salfred 892253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) { 893184610Salfred /* ignore any errors - should never happen */ 894184610Salfred } 895184610Salfred return; /* success */ 896184610Salfred} 897184610Salfred 898184610Salfredstatic void 899184610Salfredugen20_tr_cancel_async(struct libusb20_transfer *xfer) 900184610Salfred{ 901192984Sthompsa struct usb_fs_stop temp; 902184610Salfred 903185087Salfred memset(&temp, 0, sizeof(temp)); 904185087Salfred 905184610Salfred temp.ep_index = xfer->trIndex; 906184610Salfred 907253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) { 908184610Salfred /* ignore any errors - should never happen */ 909184610Salfred } 910184610Salfred return; 911184610Salfred} 912184610Salfred 913184610Salfredstatic int 914184610Salfredugen20_be_ioctl(uint32_t cmd, void *data) 915184610Salfred{ 916184610Salfred int f; 917185087Salfred int error; 918184610Salfred 919189110Sthompsa f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 920184610Salfred if (f < 0) 921184610Salfred return (LIBUSB20_ERROR_OTHER); 922185087Salfred error = ioctl(f, cmd, data); 923185087Salfred if (error == -1) { 924184610Salfred if (errno == EPERM) { 925185087Salfred error = LIBUSB20_ERROR_ACCESS; 926184610Salfred } else { 927185087Salfred error = LIBUSB20_ERROR_OTHER; 928184610Salfred } 929184610Salfred } 930184610Salfred close(f); 931185087Salfred return (error); 932184610Salfred} 933184610Salfred 934184610Salfredstatic int 935188622Sthompsaugen20_dev_get_iface_desc(struct libusb20_device *pdev, 936188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 937188622Sthompsa{ 938192984Sthompsa struct usb_gen_descriptor ugd; 939188622Sthompsa 940188622Sthompsa memset(&ugd, 0, sizeof(ugd)); 941188622Sthompsa 942213852Shselasky ugd.ugd_data = libusb20_pass_ptr(buf); 943188622Sthompsa ugd.ugd_maxlen = len; 944188622Sthompsa ugd.ugd_iface_index = iface_index; 945188622Sthompsa 946253339Shselasky if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) { 947188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 948188622Sthompsa } 949188622Sthompsa return (0); 950188622Sthompsa} 951188622Sthompsa 952188622Sthompsastatic int 953188622Sthompsaugen20_dev_get_info(struct libusb20_device *pdev, 954192984Sthompsa struct usb_device_info *pinfo) 955188622Sthompsa{ 956253339Shselasky if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) { 957188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 958188622Sthompsa } 959188622Sthompsa return (0); 960188622Sthompsa} 961188622Sthompsa 962188622Sthompsastatic int 963184610Salfredugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 964185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 965184610Salfred{ 966192984Sthompsa struct usb_gen_quirk q; 967185087Salfred int error; 968184610Salfred 969184610Salfred memset(&q, 0, sizeof(q)); 970184610Salfred 971185087Salfred q.index = quirk_index; 972184610Salfred 973253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q); 974184610Salfred 975185087Salfred if (error) { 976184610Salfred if (errno == EINVAL) { 977184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 978184610Salfred } 979184610Salfred } else { 980184610Salfred pq->vid = q.vid; 981184610Salfred pq->pid = q.pid; 982184610Salfred pq->bcdDeviceLow = q.bcdDeviceLow; 983184610Salfred pq->bcdDeviceHigh = q.bcdDeviceHigh; 984184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 985184610Salfred } 986185087Salfred return (error); 987184610Salfred} 988184610Salfred 989184610Salfredstatic int 990185087Salfredugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 991184610Salfred struct libusb20_quirk *pq) 992184610Salfred{ 993192984Sthompsa struct usb_gen_quirk q; 994185087Salfred int error; 995184610Salfred 996184610Salfred memset(&q, 0, sizeof(q)); 997184610Salfred 998185087Salfred q.index = quirk_index; 999184610Salfred 1000253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q); 1001184610Salfred 1002185087Salfred if (error) { 1003184610Salfred if (errno == EINVAL) { 1004184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1005184610Salfred } 1006184610Salfred } else { 1007184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1008184610Salfred } 1009185087Salfred return (error); 1010184610Salfred} 1011184610Salfred 1012184610Salfredstatic int 1013184610Salfredugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 1014184610Salfred struct libusb20_quirk *pq) 1015184610Salfred{ 1016192984Sthompsa struct usb_gen_quirk q; 1017185087Salfred int error; 1018184610Salfred 1019184610Salfred memset(&q, 0, sizeof(q)); 1020184610Salfred 1021184610Salfred q.vid = pq->vid; 1022184610Salfred q.pid = pq->pid; 1023184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 1024184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 1025184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1026184610Salfred 1027253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q); 1028185087Salfred if (error) { 1029184610Salfred if (errno == ENOMEM) { 1030184610Salfred return (LIBUSB20_ERROR_NO_MEM); 1031184610Salfred } 1032184610Salfred } 1033185087Salfred return (error); 1034184610Salfred} 1035184610Salfred 1036184610Salfredstatic int 1037184610Salfredugen20_root_remove_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_REMOVE), &q); 1052185087Salfred if (error) { 1053184610Salfred if (errno == EINVAL) { 1054184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1055184610Salfred } 1056184610Salfred } 1057185087Salfred return (error); 1058184610Salfred} 1059184610Salfred 1060184610Salfredstatic int 1061188987Sthompsaugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1062188987Sthompsa{ 1063253339Shselasky return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp)); 1064188987Sthompsa} 1065188987Sthompsa 1066188987Sthompsastatic int 1067188987Sthompsaugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1068188987Sthompsa{ 1069253339Shselasky return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp)); 1070188987Sthompsa} 1071