1184610Salfred/* $FreeBSD: stable/11/lib/libusb/libusb20_ugen20.c 356398 2020-01-06 09:21:15Z 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; 80246789Shselaskystatic libusb20_get_power_usage_t ugen20_get_power_usage; 81356398Shselaskystatic libusb20_get_stats_t ugen20_get_stats; 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; 137331771Shselasky struct usb_device_port_path udpp; 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, 218310276Strasz pdev->device_address, devinfo.udi_vendor, 219310276Strasz devinfo.udi_product, pdev->bus_number); 220184610Salfred 221331771Shselasky /* get device port path, if any */ 222331771Shselasky if (ioctl(f, IOUSB(USB_GET_DEV_PORT_PATH), &udpp) == 0 && 223331771Shselasky udpp.udp_port_level < LIBUSB20_DEVICE_PORT_PATH_MAX) { 224331771Shselasky memcpy(pdev->port_path, udpp.udp_port_no, udpp.udp_port_level); 225331771Shselasky pdev->port_level = udpp.udp_port_level; 226331771Shselasky } 227331771Shselasky 228184610Salfred error = 0; 229184610Salfreddone: 230184610Salfred close(f); 231184610Salfred return (error); 232184610Salfred} 233184610Salfred 234184610Salfredstruct ugen20_urd_state { 235192984Sthompsa struct usb_read_dir urd; 236184610Salfred uint32_t nparsed; 237184610Salfred int f; 238184610Salfred uint8_t *ptr; 239184610Salfred const char *src; 240184610Salfred const char *dst; 241184610Salfred uint8_t buf[256]; 242184610Salfred uint8_t dummy_zero[1]; 243184610Salfred}; 244184610Salfred 245184610Salfredstatic int 246184610Salfredugen20_readdir(struct ugen20_urd_state *st) 247184610Salfred{ 248184610Salfred ; /* style fix */ 249184610Salfredrepeat: 250184610Salfred if (st->ptr == NULL) { 251184610Salfred st->urd.urd_startentry += st->nparsed; 252213852Shselasky st->urd.urd_data = libusb20_pass_ptr(st->buf); 253184610Salfred st->urd.urd_maxlen = sizeof(st->buf); 254184610Salfred st->nparsed = 0; 255184610Salfred 256253339Shselasky if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) { 257184610Salfred return (EINVAL); 258184610Salfred } 259184610Salfred st->ptr = st->buf; 260184610Salfred } 261184610Salfred if (st->ptr[0] == 0) { 262184610Salfred if (st->nparsed) { 263184610Salfred st->ptr = NULL; 264184610Salfred goto repeat; 265184610Salfred } else { 266184610Salfred return (ENXIO); 267184610Salfred } 268184610Salfred } 269184610Salfred st->src = (void *)(st->ptr + 1); 270184610Salfred st->dst = st->src + strlen(st->src) + 1; 271184610Salfred st->ptr = st->ptr + st->ptr[0]; 272184610Salfred st->nparsed++; 273184610Salfred 274184610Salfred if ((st->ptr < st->buf) || 275184610Salfred (st->ptr > st->dummy_zero)) { 276184610Salfred /* invalid entry */ 277184610Salfred return (EINVAL); 278184610Salfred } 279184610Salfred return (0); 280184610Salfred} 281184610Salfred 282184610Salfredstatic int 283184610Salfredugen20_init_backend(struct libusb20_backend *pbe) 284184610Salfred{ 285184610Salfred struct ugen20_urd_state state; 286184610Salfred struct libusb20_device *pdev; 287184610Salfred 288184610Salfred memset(&state, 0, sizeof(state)); 289184610Salfred 290189110Sthompsa state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 291184610Salfred if (state.f < 0) 292184610Salfred return (LIBUSB20_ERROR_OTHER); 293184610Salfred 294184610Salfred while (ugen20_readdir(&state) == 0) { 295184610Salfred 296184610Salfred if ((state.src[0] != 'u') || 297184610Salfred (state.src[1] != 'g') || 298184610Salfred (state.src[2] != 'e') || 299184610Salfred (state.src[3] != 'n')) { 300184610Salfred continue; 301184610Salfred } 302184610Salfred pdev = libusb20_dev_alloc(); 303184610Salfred if (pdev == NULL) { 304184610Salfred continue; 305184610Salfred } 306184610Salfred if (ugen20_enumerate(pdev, state.src + 4)) { 307184610Salfred libusb20_dev_free(pdev); 308184610Salfred continue; 309184610Salfred } 310184610Salfred /* put the device on the backend list */ 311184610Salfred libusb20_be_enqueue_device(pbe, pdev); 312184610Salfred } 313184610Salfred close(state.f); 314184610Salfred return (0); /* success */ 315184610Salfred} 316184610Salfred 317185290Salfredstatic void 318185290Salfredugen20_tr_release(struct libusb20_device *pdev) 319185290Salfred{ 320192984Sthompsa struct usb_fs_uninit fs_uninit; 321185290Salfred 322185290Salfred if (pdev->nTransfer == 0) { 323185290Salfred return; 324185290Salfred } 325185290Salfred /* release all pending USB transfers */ 326185290Salfred if (pdev->privBeData != NULL) { 327185290Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 328253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 329185290Salfred /* ignore any errors of this kind */ 330185290Salfred } 331185290Salfred } 332185290Salfred return; 333185290Salfred} 334185290Salfred 335184610Salfredstatic int 336185087Salfredugen20_tr_renew(struct libusb20_device *pdev) 337185087Salfred{ 338192984Sthompsa struct usb_fs_init fs_init; 339192984Sthompsa struct usb_fs_endpoint *pfse; 340185087Salfred int error; 341185087Salfred uint32_t size; 342185087Salfred uint16_t nMaxTransfer; 343185087Salfred 344185087Salfred nMaxTransfer = pdev->nTransfer; 345185087Salfred error = 0; 346185087Salfred 347185087Salfred if (nMaxTransfer == 0) { 348185087Salfred goto done; 349185087Salfred } 350185087Salfred size = nMaxTransfer * sizeof(*pfse); 351185087Salfred 352185290Salfred if (pdev->privBeData == NULL) { 353185087Salfred pfse = malloc(size); 354185087Salfred if (pfse == NULL) { 355185087Salfred error = LIBUSB20_ERROR_NO_MEM; 356185087Salfred goto done; 357185087Salfred } 358185087Salfred pdev->privBeData = pfse; 359185087Salfred } 360185087Salfred /* reset endpoint data */ 361185087Salfred memset(pdev->privBeData, 0, size); 362185087Salfred 363185087Salfred memset(&fs_init, 0, sizeof(fs_init)); 364185087Salfred 365213852Shselasky fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData); 366185087Salfred fs_init.ep_index_max = nMaxTransfer; 367185087Salfred 368253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) { 369185087Salfred error = LIBUSB20_ERROR_OTHER; 370185087Salfred goto done; 371185087Salfred } 372185087Salfreddone: 373185087Salfred return (error); 374185087Salfred} 375185087Salfred 376185087Salfredstatic int 377184610Salfredugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 378184610Salfred{ 379184610Salfred uint32_t plugtime; 380184610Salfred char buf[64]; 381184610Salfred int f; 382184610Salfred int g; 383184610Salfred int error; 384184610Salfred 385189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 386184610Salfred pdev->bus_number, pdev->device_address); 387184610Salfred 388184610Salfred /* 389184610Salfred * We need two file handles, one for the control endpoint and one 390184610Salfred * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 391184610Salfred * kernel locking. 392184610Salfred */ 393184610Salfred g = open(buf, O_RDWR); 394184610Salfred if (g < 0) { 395184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 396184610Salfred } 397184610Salfred f = open(buf, O_RDWR); 398184610Salfred if (f < 0) { 399184610Salfred close(g); 400184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 401184610Salfred } 402253339Shselasky if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 403184610Salfred error = LIBUSB20_ERROR_OTHER; 404184610Salfred goto done; 405184610Salfred } 406184610Salfred /* check that the correct device is still plugged */ 407184610Salfred if (pdev->session_data.plugtime != plugtime) { 408184610Salfred error = LIBUSB20_ERROR_NO_DEVICE; 409184610Salfred goto done; 410184610Salfred } 411185087Salfred /* need to set this before "tr_renew()" */ 412185087Salfred pdev->file = f; 413185087Salfred pdev->file_ctrl = g; 414184610Salfred 415185087Salfred /* renew all USB transfers */ 416185087Salfred error = ugen20_tr_renew(pdev); 417185087Salfred if (error) { 418185087Salfred goto done; 419184610Salfred } 420184610Salfred /* set methods */ 421184610Salfred pdev->methods = &libusb20_ugen20_device_methods; 422185087Salfred 423184610Salfreddone: 424184610Salfred if (error) { 425185087Salfred if (pdev->privBeData) { 426185087Salfred /* cleanup after "tr_renew()" */ 427185087Salfred free(pdev->privBeData); 428185087Salfred pdev->privBeData = NULL; 429184610Salfred } 430185087Salfred pdev->file = -1; 431185087Salfred pdev->file_ctrl = -1; 432184610Salfred close(f); 433184610Salfred close(g); 434184610Salfred } 435184610Salfred return (error); 436184610Salfred} 437184610Salfred 438184610Salfredstatic int 439184610Salfredugen20_close_device(struct libusb20_device *pdev) 440184610Salfred{ 441192984Sthompsa struct usb_fs_uninit fs_uninit; 442184610Salfred 443184610Salfred if (pdev->privBeData) { 444185087Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 445253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 446185290Salfred /* ignore this error */ 447184610Salfred } 448184610Salfred free(pdev->privBeData); 449184610Salfred } 450184610Salfred pdev->nTransfer = 0; 451184610Salfred pdev->privBeData = NULL; 452184610Salfred close(pdev->file); 453184610Salfred close(pdev->file_ctrl); 454184610Salfred pdev->file = -1; 455184610Salfred pdev->file_ctrl = -1; 456185290Salfred return (0); /* success */ 457184610Salfred} 458184610Salfred 459184610Salfredstatic void 460184610Salfredugen20_exit_backend(struct libusb20_backend *pbe) 461184610Salfred{ 462184610Salfred return; /* nothing to do */ 463184610Salfred} 464184610Salfred 465184610Salfredstatic int 466184610Salfredugen20_get_config_desc_full(struct libusb20_device *pdev, 467185087Salfred uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 468184610Salfred{ 469192984Sthompsa struct usb_gen_descriptor gen_desc; 470192984Sthompsa struct usb_config_descriptor cdesc; 471184610Salfred uint8_t *ptr; 472184610Salfred uint16_t len; 473184610Salfred int error; 474184610Salfred 475199055Sthompsa /* make sure memory is initialised */ 476199055Sthompsa memset(&cdesc, 0, sizeof(cdesc)); 477185087Salfred memset(&gen_desc, 0, sizeof(gen_desc)); 478185087Salfred 479213852Shselasky gen_desc.ugd_data = libusb20_pass_ptr(&cdesc); 480184610Salfred gen_desc.ugd_maxlen = sizeof(cdesc); 481185087Salfred gen_desc.ugd_config_index = cfg_index; 482184610Salfred 483253339Shselasky error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 484184610Salfred if (error) { 485184610Salfred return (LIBUSB20_ERROR_OTHER); 486184610Salfred } 487184610Salfred len = UGETW(cdesc.wTotalLength); 488184610Salfred if (len < sizeof(cdesc)) { 489184610Salfred /* corrupt descriptor */ 490184610Salfred return (LIBUSB20_ERROR_OTHER); 491184610Salfred } 492184610Salfred ptr = malloc(len); 493184610Salfred if (!ptr) { 494184610Salfred return (LIBUSB20_ERROR_NO_MEM); 495184610Salfred } 496199055Sthompsa 497199055Sthompsa /* make sure memory is initialised */ 498199055Sthompsa memset(ptr, 0, len); 499199055Sthompsa 500213852Shselasky gen_desc.ugd_data = libusb20_pass_ptr(ptr); 501184610Salfred gen_desc.ugd_maxlen = len; 502184610Salfred 503253339Shselasky error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 504184610Salfred if (error) { 505184610Salfred free(ptr); 506184610Salfred return (LIBUSB20_ERROR_OTHER); 507184610Salfred } 508184610Salfred /* make sure that the device doesn't fool us */ 509184610Salfred memcpy(ptr, &cdesc, sizeof(cdesc)); 510184610Salfred 511184610Salfred *ppbuf = ptr; 512184610Salfred *plen = len; 513184610Salfred 514184610Salfred return (0); /* success */ 515184610Salfred} 516184610Salfred 517184610Salfredstatic int 518184610Salfredugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 519184610Salfred{ 520184610Salfred int temp; 521184610Salfred 522253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) { 523184610Salfred return (LIBUSB20_ERROR_OTHER); 524184610Salfred } 525184610Salfred *pindex = temp; 526184610Salfred 527184610Salfred return (0); 528184610Salfred} 529184610Salfred 530184610Salfredstatic int 531185087Salfredugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 532184610Salfred{ 533185087Salfred int temp = cfg_index; 534184610Salfred 535185290Salfred /* release all active USB transfers */ 536185290Salfred ugen20_tr_release(pdev); 537185290Salfred 538253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) { 539184610Salfred return (LIBUSB20_ERROR_OTHER); 540184610Salfred } 541185087Salfred return (ugen20_tr_renew(pdev)); 542184610Salfred} 543184610Salfred 544184610Salfredstatic int 545184610Salfredugen20_set_alt_index(struct libusb20_device *pdev, 546184610Salfred uint8_t iface_index, uint8_t alt_index) 547184610Salfred{ 548192984Sthompsa struct usb_alt_interface alt_iface; 549184610Salfred 550185087Salfred memset(&alt_iface, 0, sizeof(alt_iface)); 551185087Salfred 552184610Salfred alt_iface.uai_interface_index = iface_index; 553184610Salfred alt_iface.uai_alt_index = alt_index; 554184610Salfred 555185290Salfred /* release all active USB transfers */ 556185290Salfred ugen20_tr_release(pdev); 557185290Salfred 558253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) { 559184610Salfred return (LIBUSB20_ERROR_OTHER); 560184610Salfred } 561185087Salfred return (ugen20_tr_renew(pdev)); 562184610Salfred} 563184610Salfred 564184610Salfredstatic int 565184610Salfredugen20_reset_device(struct libusb20_device *pdev) 566184610Salfred{ 567184610Salfred int temp = 0; 568184610Salfred 569185290Salfred /* release all active USB transfers */ 570185290Salfred ugen20_tr_release(pdev); 571185290Salfred 572253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) { 573184610Salfred return (LIBUSB20_ERROR_OTHER); 574184610Salfred } 575185087Salfred return (ugen20_tr_renew(pdev)); 576184610Salfred} 577184610Salfred 578184610Salfredstatic int 579203147Sthompsaugen20_check_connected(struct libusb20_device *pdev) 580203147Sthompsa{ 581203147Sthompsa uint32_t plugtime; 582203147Sthompsa int error = 0; 583203147Sthompsa 584253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 585203147Sthompsa error = LIBUSB20_ERROR_NO_DEVICE; 586203147Sthompsa goto done; 587203147Sthompsa } 588203147Sthompsa 589203147Sthompsa if (pdev->session_data.plugtime != plugtime) { 590203147Sthompsa error = LIBUSB20_ERROR_NO_DEVICE; 591203147Sthompsa goto done; 592203147Sthompsa } 593203147Sthompsadone: 594203147Sthompsa return (error); 595203147Sthompsa} 596203147Sthompsa 597203147Sthompsastatic int 598184610Salfredugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 599184610Salfred{ 600184610Salfred int temp; 601184610Salfred 602184610Salfred switch (power_mode) { 603184610Salfred case LIBUSB20_POWER_OFF: 604184610Salfred temp = USB_POWER_MODE_OFF; 605184610Salfred break; 606184610Salfred case LIBUSB20_POWER_ON: 607184610Salfred temp = USB_POWER_MODE_ON; 608184610Salfred break; 609184610Salfred case LIBUSB20_POWER_SAVE: 610184610Salfred temp = USB_POWER_MODE_SAVE; 611184610Salfred break; 612184610Salfred case LIBUSB20_POWER_SUSPEND: 613184610Salfred temp = USB_POWER_MODE_SUSPEND; 614184610Salfred break; 615184610Salfred case LIBUSB20_POWER_RESUME: 616184610Salfred temp = USB_POWER_MODE_RESUME; 617184610Salfred break; 618184610Salfred default: 619184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 620184610Salfred } 621253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) { 622184610Salfred return (LIBUSB20_ERROR_OTHER); 623184610Salfred } 624184610Salfred return (0); 625184610Salfred} 626184610Salfred 627184610Salfredstatic int 628184610Salfredugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 629184610Salfred{ 630184610Salfred int temp; 631184610Salfred 632253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) { 633184610Salfred return (LIBUSB20_ERROR_OTHER); 634184610Salfred } 635184610Salfred switch (temp) { 636184610Salfred case USB_POWER_MODE_OFF: 637184610Salfred temp = LIBUSB20_POWER_OFF; 638184610Salfred break; 639184610Salfred case USB_POWER_MODE_ON: 640184610Salfred temp = LIBUSB20_POWER_ON; 641184610Salfred break; 642184610Salfred case USB_POWER_MODE_SAVE: 643184610Salfred temp = LIBUSB20_POWER_SAVE; 644184610Salfred break; 645184610Salfred case USB_POWER_MODE_SUSPEND: 646184610Salfred temp = LIBUSB20_POWER_SUSPEND; 647184610Salfred break; 648184610Salfred case USB_POWER_MODE_RESUME: 649184610Salfred temp = LIBUSB20_POWER_RESUME; 650184610Salfred break; 651184610Salfred default: 652184610Salfred temp = LIBUSB20_POWER_ON; 653184610Salfred break; 654184610Salfred } 655184610Salfred *power_mode = temp; 656184610Salfred return (0); /* success */ 657184610Salfred} 658184610Salfred 659184610Salfredstatic int 660246789Shselaskyugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage) 661246789Shselasky{ 662246789Shselasky int temp; 663246789Shselasky 664253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) { 665246789Shselasky return (LIBUSB20_ERROR_OTHER); 666246789Shselasky } 667246789Shselasky *power_usage = temp; 668246789Shselasky return (0); /* success */ 669246789Shselasky} 670246789Shselasky 671246789Shselaskystatic int 672356398Shselaskyugen20_get_stats(struct libusb20_device *pdev, struct libusb20_device_stats *pstats) 673356398Shselasky{ 674356398Shselasky struct usb_device_stats st; 675356398Shselasky 676356398Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICESTATS), &st)) 677356398Shselasky return (LIBUSB20_ERROR_OTHER); 678356398Shselasky 679356398Shselasky memset(pstats, 0, sizeof(*pstats)); 680356398Shselasky 681356398Shselasky pstats->xfer_ok[0] = st.uds_requests_ok[0]; 682356398Shselasky pstats->xfer_ok[1] = st.uds_requests_ok[1]; 683356398Shselasky pstats->xfer_ok[2] = st.uds_requests_ok[2]; 684356398Shselasky pstats->xfer_ok[3] = st.uds_requests_ok[3]; 685356398Shselasky 686356398Shselasky pstats->xfer_fail[0] = st.uds_requests_fail[0]; 687356398Shselasky pstats->xfer_fail[1] = st.uds_requests_fail[1]; 688356398Shselasky pstats->xfer_fail[2] = st.uds_requests_fail[2]; 689356398Shselasky pstats->xfer_fail[3] = st.uds_requests_fail[3]; 690356398Shselasky 691356398Shselasky return (0); /* success */ 692356398Shselasky} 693356398Shselasky 694356398Shselaskystatic int 695184610Salfredugen20_kernel_driver_active(struct libusb20_device *pdev, 696184610Salfred uint8_t iface_index) 697184610Salfred{ 698184610Salfred int temp = iface_index; 699184610Salfred 700253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) { 701184610Salfred return (LIBUSB20_ERROR_OTHER); 702184610Salfred } 703184610Salfred return (0); /* kernel driver is active */ 704184610Salfred} 705184610Salfred 706184610Salfredstatic int 707184610Salfredugen20_detach_kernel_driver(struct libusb20_device *pdev, 708184610Salfred uint8_t iface_index) 709184610Salfred{ 710184610Salfred int temp = iface_index; 711184610Salfred 712253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) { 713184610Salfred return (LIBUSB20_ERROR_OTHER); 714184610Salfred } 715255242Shselasky return (0); /* kernel driver is detached */ 716184610Salfred} 717184610Salfred 718184610Salfredstatic int 719184610Salfredugen20_do_request_sync(struct libusb20_device *pdev, 720184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 721184610Salfred void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 722184610Salfred{ 723192984Sthompsa struct usb_ctl_request req; 724184610Salfred 725185087Salfred memset(&req, 0, sizeof(req)); 726185087Salfred 727213852Shselasky req.ucr_data = libusb20_pass_ptr(data); 728184610Salfred if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 729184610Salfred req.ucr_flags |= USB_SHORT_XFER_OK; 730184610Salfred } 731184610Salfred if (libusb20_me_encode(&req.ucr_request, 732184610Salfred sizeof(req.ucr_request), setup)) { 733184610Salfred /* ignore */ 734184610Salfred } 735253339Shselasky if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) { 736184610Salfred return (LIBUSB20_ERROR_OTHER); 737184610Salfred } 738184610Salfred if (pactlen) { 739184610Salfred /* get actual length */ 740184610Salfred *pactlen = req.ucr_actlen; 741184610Salfred } 742255242Shselasky return (0); /* request was successful */ 743184610Salfred} 744184610Salfred 745184610Salfredstatic int 746184610Salfredugen20_process(struct libusb20_device *pdev) 747184610Salfred{ 748192984Sthompsa struct usb_fs_complete temp; 749192984Sthompsa struct usb_fs_endpoint *fsep; 750184610Salfred struct libusb20_transfer *xfer; 751184610Salfred 752184610Salfred while (1) { 753184610Salfred 754253339Shselasky if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) { 755184610Salfred if (errno == EBUSY) { 756184610Salfred break; 757184610Salfred } else { 758184610Salfred /* device detached */ 759184610Salfred return (LIBUSB20_ERROR_OTHER); 760184610Salfred } 761184610Salfred } 762184610Salfred fsep = pdev->privBeData; 763184610Salfred xfer = pdev->pTransfer; 764184610Salfred fsep += temp.ep_index; 765184610Salfred xfer += temp.ep_index; 766184610Salfred 767184610Salfred /* update transfer status */ 768184610Salfred 769184610Salfred if (fsep->status == 0) { 770184610Salfred xfer->aFrames = fsep->aFrames; 771184610Salfred xfer->timeComplete = fsep->isoc_time_complete; 772184610Salfred xfer->status = LIBUSB20_TRANSFER_COMPLETED; 773184610Salfred } else if (fsep->status == USB_ERR_CANCELLED) { 774184610Salfred xfer->aFrames = 0; 775184610Salfred xfer->timeComplete = 0; 776184610Salfred xfer->status = LIBUSB20_TRANSFER_CANCELLED; 777184610Salfred } else if (fsep->status == USB_ERR_STALLED) { 778184610Salfred xfer->aFrames = 0; 779184610Salfred xfer->timeComplete = 0; 780184610Salfred xfer->status = LIBUSB20_TRANSFER_STALL; 781184610Salfred } else if (fsep->status == USB_ERR_TIMEOUT) { 782184610Salfred xfer->aFrames = 0; 783184610Salfred xfer->timeComplete = 0; 784184610Salfred xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 785184610Salfred } else { 786184610Salfred xfer->aFrames = 0; 787184610Salfred xfer->timeComplete = 0; 788184610Salfred xfer->status = LIBUSB20_TRANSFER_ERROR; 789184610Salfred } 790184610Salfred libusb20_tr_callback_wrapper(xfer); 791184610Salfred } 792184610Salfred return (0); /* done */ 793184610Salfred} 794184610Salfred 795184610Salfredstatic int 796184610Salfredugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 797239239Shselasky uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id, 798239239Shselasky uint8_t pre_scale) 799184610Salfred{ 800239239Shselasky union { 801239239Shselasky struct usb_fs_open fs_open; 802239239Shselasky struct usb_fs_open_stream fs_open_stream; 803239239Shselasky } temp; 804192984Sthompsa struct usb_fs_endpoint *fsep; 805184610Salfred 806219100Shselasky if (pre_scale) 807219100Shselasky MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE; 808219100Shselasky 809185087Salfred memset(&temp, 0, sizeof(temp)); 810185087Salfred 811184610Salfred fsep = xfer->pdev->privBeData; 812184610Salfred fsep += xfer->trIndex; 813184610Salfred 814239239Shselasky temp.fs_open.max_bufsize = MaxBufSize; 815239239Shselasky temp.fs_open.max_frames = MaxFrameCount; 816239239Shselasky temp.fs_open.ep_index = xfer->trIndex; 817239239Shselasky temp.fs_open.ep_no = ep_no; 818184610Salfred 819239239Shselasky if (stream_id != 0) { 820239239Shselasky temp.fs_open_stream.stream_id = stream_id; 821239239Shselasky 822253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream)) 823239239Shselasky return (LIBUSB20_ERROR_INVALID_PARAM); 824239239Shselasky } else { 825253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open)) 826239239Shselasky return (LIBUSB20_ERROR_INVALID_PARAM); 827184610Salfred } 828184610Salfred /* maximums might have changed - update */ 829239239Shselasky xfer->maxFrames = temp.fs_open.max_frames; 830184610Salfred 831184610Salfred /* "max_bufsize" should be multiple of "max_packet_length" */ 832239239Shselasky xfer->maxTotalLength = temp.fs_open.max_bufsize; 833239239Shselasky xfer->maxPacketLen = temp.fs_open.max_packet_length; 834184610Salfred 835213852Shselasky /* setup buffer and length lists using zero copy */ 836213852Shselasky fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer); 837213852Shselasky fsep->pLength = libusb20_pass_ptr(xfer->pLength); 838184610Salfred 839184610Salfred return (0); /* success */ 840184610Salfred} 841184610Salfred 842184610Salfredstatic int 843184610Salfredugen20_tr_close(struct libusb20_transfer *xfer) 844184610Salfred{ 845192984Sthompsa struct usb_fs_close temp; 846184610Salfred 847185087Salfred memset(&temp, 0, sizeof(temp)); 848185087Salfred 849184610Salfred temp.ep_index = xfer->trIndex; 850184610Salfred 851253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) { 852184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 853184610Salfred } 854184610Salfred return (0); /* success */ 855184610Salfred} 856184610Salfred 857184610Salfredstatic int 858184610Salfredugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 859184610Salfred{ 860192984Sthompsa struct usb_fs_clear_stall_sync temp; 861184610Salfred 862185087Salfred memset(&temp, 0, sizeof(temp)); 863185087Salfred 864184610Salfred /* if the transfer is active, an error will be returned */ 865184610Salfred 866184610Salfred temp.ep_index = xfer->trIndex; 867184610Salfred 868253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) { 869184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 870184610Salfred } 871184610Salfred return (0); /* success */ 872184610Salfred} 873184610Salfred 874184610Salfredstatic void 875184610Salfredugen20_tr_submit(struct libusb20_transfer *xfer) 876184610Salfred{ 877192984Sthompsa struct usb_fs_start temp; 878192984Sthompsa struct usb_fs_endpoint *fsep; 879184610Salfred 880185087Salfred memset(&temp, 0, sizeof(temp)); 881185087Salfred 882184610Salfred fsep = xfer->pdev->privBeData; 883184610Salfred fsep += xfer->trIndex; 884184610Salfred 885184610Salfred fsep->nFrames = xfer->nFrames; 886184610Salfred fsep->flags = 0; 887184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 888184610Salfred fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 889184610Salfred } 890184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 891184610Salfred fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 892184610Salfred } 893184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 894184610Salfred fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 895184610Salfred } 896184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 897184610Salfred fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 898184610Salfred } 899198376Sthompsa /* NOTE: The "fsep->timeout" variable is 16-bit. */ 900198376Sthompsa if (xfer->timeout > 65535) 901198376Sthompsa fsep->timeout = 65535; 902198376Sthompsa else 903198376Sthompsa fsep->timeout = xfer->timeout; 904184610Salfred 905184610Salfred temp.ep_index = xfer->trIndex; 906184610Salfred 907253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) { 908184610Salfred /* ignore any errors - should never happen */ 909184610Salfred } 910184610Salfred return; /* success */ 911184610Salfred} 912184610Salfred 913184610Salfredstatic void 914184610Salfredugen20_tr_cancel_async(struct libusb20_transfer *xfer) 915184610Salfred{ 916192984Sthompsa struct usb_fs_stop temp; 917184610Salfred 918185087Salfred memset(&temp, 0, sizeof(temp)); 919185087Salfred 920184610Salfred temp.ep_index = xfer->trIndex; 921184610Salfred 922253339Shselasky if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) { 923184610Salfred /* ignore any errors - should never happen */ 924184610Salfred } 925184610Salfred return; 926184610Salfred} 927184610Salfred 928184610Salfredstatic int 929184610Salfredugen20_be_ioctl(uint32_t cmd, void *data) 930184610Salfred{ 931184610Salfred int f; 932185087Salfred int error; 933184610Salfred 934189110Sthompsa f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 935184610Salfred if (f < 0) 936184610Salfred return (LIBUSB20_ERROR_OTHER); 937185087Salfred error = ioctl(f, cmd, data); 938185087Salfred if (error == -1) { 939184610Salfred if (errno == EPERM) { 940185087Salfred error = LIBUSB20_ERROR_ACCESS; 941184610Salfred } else { 942185087Salfred error = LIBUSB20_ERROR_OTHER; 943184610Salfred } 944184610Salfred } 945184610Salfred close(f); 946185087Salfred return (error); 947184610Salfred} 948184610Salfred 949184610Salfredstatic int 950188622Sthompsaugen20_dev_get_iface_desc(struct libusb20_device *pdev, 951188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 952188622Sthompsa{ 953192984Sthompsa struct usb_gen_descriptor ugd; 954188622Sthompsa 955188622Sthompsa memset(&ugd, 0, sizeof(ugd)); 956188622Sthompsa 957213852Shselasky ugd.ugd_data = libusb20_pass_ptr(buf); 958188622Sthompsa ugd.ugd_maxlen = len; 959188622Sthompsa ugd.ugd_iface_index = iface_index; 960188622Sthompsa 961253339Shselasky if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) { 962188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 963188622Sthompsa } 964188622Sthompsa return (0); 965188622Sthompsa} 966188622Sthompsa 967188622Sthompsastatic int 968188622Sthompsaugen20_dev_get_info(struct libusb20_device *pdev, 969192984Sthompsa struct usb_device_info *pinfo) 970188622Sthompsa{ 971253339Shselasky if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) { 972188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 973188622Sthompsa } 974188622Sthompsa return (0); 975188622Sthompsa} 976188622Sthompsa 977188622Sthompsastatic int 978184610Salfredugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 979185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 980184610Salfred{ 981192984Sthompsa struct usb_gen_quirk q; 982185087Salfred int error; 983184610Salfred 984184610Salfred memset(&q, 0, sizeof(q)); 985184610Salfred 986185087Salfred q.index = quirk_index; 987184610Salfred 988253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q); 989184610Salfred 990185087Salfred if (error) { 991184610Salfred if (errno == EINVAL) { 992184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 993184610Salfred } 994184610Salfred } else { 995184610Salfred pq->vid = q.vid; 996184610Salfred pq->pid = q.pid; 997184610Salfred pq->bcdDeviceLow = q.bcdDeviceLow; 998184610Salfred pq->bcdDeviceHigh = q.bcdDeviceHigh; 999184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1000184610Salfred } 1001185087Salfred return (error); 1002184610Salfred} 1003184610Salfred 1004184610Salfredstatic int 1005185087Salfredugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 1006184610Salfred struct libusb20_quirk *pq) 1007184610Salfred{ 1008192984Sthompsa struct usb_gen_quirk q; 1009185087Salfred int error; 1010184610Salfred 1011184610Salfred memset(&q, 0, sizeof(q)); 1012184610Salfred 1013185087Salfred q.index = quirk_index; 1014184610Salfred 1015253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q); 1016184610Salfred 1017185087Salfred if (error) { 1018184610Salfred if (errno == EINVAL) { 1019184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1020184610Salfred } 1021184610Salfred } else { 1022184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1023184610Salfred } 1024185087Salfred return (error); 1025184610Salfred} 1026184610Salfred 1027184610Salfredstatic int 1028184610Salfredugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 1029184610Salfred struct libusb20_quirk *pq) 1030184610Salfred{ 1031192984Sthompsa struct usb_gen_quirk q; 1032185087Salfred int error; 1033184610Salfred 1034184610Salfred memset(&q, 0, sizeof(q)); 1035184610Salfred 1036184610Salfred q.vid = pq->vid; 1037184610Salfred q.pid = pq->pid; 1038184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 1039184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 1040184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1041184610Salfred 1042253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q); 1043185087Salfred if (error) { 1044184610Salfred if (errno == ENOMEM) { 1045184610Salfred return (LIBUSB20_ERROR_NO_MEM); 1046184610Salfred } 1047184610Salfred } 1048185087Salfred return (error); 1049184610Salfred} 1050184610Salfred 1051184610Salfredstatic int 1052184610Salfredugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 1053184610Salfred struct libusb20_quirk *pq) 1054184610Salfred{ 1055192984Sthompsa struct usb_gen_quirk q; 1056185087Salfred int error; 1057184610Salfred 1058184610Salfred memset(&q, 0, sizeof(q)); 1059184610Salfred 1060184610Salfred q.vid = pq->vid; 1061184610Salfred q.pid = pq->pid; 1062184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 1063184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 1064184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1065184610Salfred 1066253339Shselasky error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q); 1067185087Salfred if (error) { 1068184610Salfred if (errno == EINVAL) { 1069184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1070184610Salfred } 1071184610Salfred } 1072185087Salfred return (error); 1073184610Salfred} 1074184610Salfred 1075184610Salfredstatic int 1076188987Sthompsaugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1077188987Sthompsa{ 1078253339Shselasky return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp)); 1079188987Sthompsa} 1080188987Sthompsa 1081188987Sthompsastatic int 1082188987Sthompsaugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1083188987Sthompsa{ 1084253339Shselasky return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp)); 1085188987Sthompsa} 1086