libusb20_ugen20.c revision 250201
1184610Salfred/* $FreeBSD: head/lib/libusb/libusb20_ugen20.c 250201 2013-05-03 07:44:58Z 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 49184610Salfredstatic libusb20_init_backend_t ugen20_init_backend; 50184610Salfredstatic libusb20_open_device_t ugen20_open_device; 51184610Salfredstatic libusb20_close_device_t ugen20_close_device; 52184610Salfredstatic libusb20_get_backend_name_t ugen20_get_backend_name; 53184610Salfredstatic libusb20_exit_backend_t ugen20_exit_backend; 54188622Sthompsastatic libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc; 55188622Sthompsastatic libusb20_dev_get_info_t ugen20_dev_get_info; 56184610Salfredstatic libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk; 57184610Salfredstatic libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name; 58184610Salfredstatic libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk; 59184610Salfredstatic libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk; 60188987Sthompsastatic libusb20_root_set_template_t ugen20_root_set_template; 61188987Sthompsastatic libusb20_root_get_template_t ugen20_root_get_template; 62184610Salfred 63184610Salfredconst struct libusb20_backend_methods libusb20_ugen20_backend = { 64184610Salfred LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20) 65184610Salfred}; 66184610Salfred 67184610Salfred/* USB device specific */ 68184610Salfredstatic libusb20_get_config_desc_full_t ugen20_get_config_desc_full; 69184610Salfredstatic libusb20_get_config_index_t ugen20_get_config_index; 70184610Salfredstatic libusb20_set_config_index_t ugen20_set_config_index; 71184610Salfredstatic libusb20_set_alt_index_t ugen20_set_alt_index; 72184610Salfredstatic libusb20_reset_device_t ugen20_reset_device; 73203147Sthompsastatic libusb20_check_connected_t ugen20_check_connected; 74184610Salfredstatic libusb20_set_power_mode_t ugen20_set_power_mode; 75184610Salfredstatic libusb20_get_power_mode_t ugen20_get_power_mode; 76250201Shselaskystatic libusb20_get_port_path_t ugen20_get_port_path; 77246789Shselaskystatic libusb20_get_power_usage_t ugen20_get_power_usage; 78184610Salfredstatic libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 79184610Salfredstatic libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 80184610Salfredstatic libusb20_do_request_sync_t ugen20_do_request_sync; 81184610Salfredstatic libusb20_process_t ugen20_process; 82184610Salfred 83184610Salfred/* USB transfer specific */ 84184610Salfredstatic libusb20_tr_open_t ugen20_tr_open; 85184610Salfredstatic libusb20_tr_close_t ugen20_tr_close; 86184610Salfredstatic libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 87184610Salfredstatic libusb20_tr_submit_t ugen20_tr_submit; 88184610Salfredstatic libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 89184610Salfred 90184610Salfredstatic const struct libusb20_device_methods libusb20_ugen20_device_methods = { 91184610Salfred LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 92184610Salfred}; 93184610Salfred 94184610Salfredstatic const char * 95184610Salfredugen20_get_backend_name(void) 96184610Salfred{ 97184610Salfred return ("FreeBSD UGEN 2.0"); 98184610Salfred} 99184610Salfred 100184610Salfredstatic uint32_t 101184610Salfredugen20_path_convert_one(const char **pp) 102184610Salfred{ 103184610Salfred const char *ptr; 104184610Salfred uint32_t temp = 0; 105184610Salfred 106184610Salfred ptr = *pp; 107184610Salfred 108184610Salfred while ((*ptr >= '0') && (*ptr <= '9')) { 109184610Salfred temp *= 10; 110184610Salfred temp += (*ptr - '0'); 111184610Salfred if (temp >= 1000000) { 112184610Salfred /* catch overflow early */ 113234491Shselasky return (0xFFFFFFFF); 114184610Salfred } 115184610Salfred ptr++; 116184610Salfred } 117184610Salfred 118184610Salfred if (*ptr == '.') { 119184610Salfred /* skip dot */ 120184610Salfred ptr++; 121184610Salfred } 122184610Salfred *pp = ptr; 123184610Salfred 124184610Salfred return (temp); 125184610Salfred} 126184610Salfred 127184610Salfredstatic int 128184610Salfredugen20_enumerate(struct libusb20_device *pdev, const char *id) 129184610Salfred{ 130184610Salfred const char *tmp = id; 131192984Sthompsa struct usb_device_descriptor ddesc; 132192984Sthompsa struct usb_device_info devinfo; 133184610Salfred uint32_t plugtime; 134184610Salfred char buf[64]; 135184610Salfred int f; 136184610Salfred int error; 137184610Salfred 138184610Salfred pdev->bus_number = ugen20_path_convert_one(&tmp); 139184610Salfred pdev->device_address = ugen20_path_convert_one(&tmp); 140184610Salfred 141189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 142184610Salfred pdev->bus_number, pdev->device_address); 143184610Salfred 144184610Salfred f = open(buf, O_RDWR); 145184610Salfred if (f < 0) { 146184610Salfred return (LIBUSB20_ERROR_OTHER); 147184610Salfred } 148184610Salfred if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 149184610Salfred error = LIBUSB20_ERROR_OTHER; 150184610Salfred goto done; 151184610Salfred } 152184610Salfred /* store when the device was plugged */ 153184610Salfred pdev->session_data.plugtime = plugtime; 154184610Salfred 155184610Salfred if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) { 156184610Salfred error = LIBUSB20_ERROR_OTHER; 157184610Salfred goto done; 158184610Salfred } 159184610Salfred LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 160184610Salfred 161184610Salfred libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 162184610Salfred 163184610Salfred if (pdev->ddesc.bNumConfigurations == 0) { 164184610Salfred error = LIBUSB20_ERROR_OTHER; 165184610Salfred goto done; 166184610Salfred } else if (pdev->ddesc.bNumConfigurations >= 8) { 167184610Salfred error = LIBUSB20_ERROR_OTHER; 168184610Salfred goto done; 169184610Salfred } 170184610Salfred if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) { 171184610Salfred error = LIBUSB20_ERROR_OTHER; 172184610Salfred goto done; 173184610Salfred } 174184610Salfred switch (devinfo.udi_mode) { 175184610Salfred case USB_MODE_DEVICE: 176184610Salfred pdev->usb_mode = LIBUSB20_MODE_DEVICE; 177184610Salfred break; 178184610Salfred default: 179184610Salfred pdev->usb_mode = LIBUSB20_MODE_HOST; 180184610Salfred break; 181184610Salfred } 182184610Salfred 183184610Salfred switch (devinfo.udi_speed) { 184184610Salfred case USB_SPEED_LOW: 185184610Salfred pdev->usb_speed = LIBUSB20_SPEED_LOW; 186184610Salfred break; 187184610Salfred case USB_SPEED_FULL: 188184610Salfred pdev->usb_speed = LIBUSB20_SPEED_FULL; 189184610Salfred break; 190184610Salfred case USB_SPEED_HIGH: 191184610Salfred pdev->usb_speed = LIBUSB20_SPEED_HIGH; 192184610Salfred break; 193184610Salfred case USB_SPEED_VARIABLE: 194184610Salfred pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 195184610Salfred break; 196184610Salfred case USB_SPEED_SUPER: 197184610Salfred pdev->usb_speed = LIBUSB20_SPEED_SUPER; 198184610Salfred break; 199184610Salfred default: 200184610Salfred pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 201184610Salfred break; 202184610Salfred } 203184610Salfred 204223495Shselasky /* get parent HUB index and port */ 205223495Shselasky 206223495Shselasky pdev->parent_address = devinfo.udi_hubindex; 207223495Shselasky pdev->parent_port = devinfo.udi_hubport; 208223495Shselasky 209184610Salfred /* generate a nice description for printout */ 210184610Salfred 211184610Salfred snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 212189110Sthompsa USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, 213184610Salfred pdev->device_address, devinfo.udi_product, 214184610Salfred devinfo.udi_vendor, pdev->bus_number); 215184610Salfred 216184610Salfred error = 0; 217184610Salfreddone: 218184610Salfred close(f); 219184610Salfred return (error); 220184610Salfred} 221184610Salfred 222184610Salfredstruct ugen20_urd_state { 223192984Sthompsa struct usb_read_dir urd; 224184610Salfred uint32_t nparsed; 225184610Salfred int f; 226184610Salfred uint8_t *ptr; 227184610Salfred const char *src; 228184610Salfred const char *dst; 229184610Salfred uint8_t buf[256]; 230184610Salfred uint8_t dummy_zero[1]; 231184610Salfred}; 232184610Salfred 233184610Salfredstatic int 234184610Salfredugen20_readdir(struct ugen20_urd_state *st) 235184610Salfred{ 236184610Salfred ; /* style fix */ 237184610Salfredrepeat: 238184610Salfred if (st->ptr == NULL) { 239184610Salfred st->urd.urd_startentry += st->nparsed; 240213852Shselasky st->urd.urd_data = libusb20_pass_ptr(st->buf); 241184610Salfred st->urd.urd_maxlen = sizeof(st->buf); 242184610Salfred st->nparsed = 0; 243184610Salfred 244184610Salfred if (ioctl(st->f, USB_READ_DIR, &st->urd)) { 245184610Salfred return (EINVAL); 246184610Salfred } 247184610Salfred st->ptr = st->buf; 248184610Salfred } 249184610Salfred if (st->ptr[0] == 0) { 250184610Salfred if (st->nparsed) { 251184610Salfred st->ptr = NULL; 252184610Salfred goto repeat; 253184610Salfred } else { 254184610Salfred return (ENXIO); 255184610Salfred } 256184610Salfred } 257184610Salfred st->src = (void *)(st->ptr + 1); 258184610Salfred st->dst = st->src + strlen(st->src) + 1; 259184610Salfred st->ptr = st->ptr + st->ptr[0]; 260184610Salfred st->nparsed++; 261184610Salfred 262184610Salfred if ((st->ptr < st->buf) || 263184610Salfred (st->ptr > st->dummy_zero)) { 264184610Salfred /* invalid entry */ 265184610Salfred return (EINVAL); 266184610Salfred } 267184610Salfred return (0); 268184610Salfred} 269184610Salfred 270184610Salfredstatic int 271184610Salfredugen20_init_backend(struct libusb20_backend *pbe) 272184610Salfred{ 273184610Salfred struct ugen20_urd_state state; 274184610Salfred struct libusb20_device *pdev; 275184610Salfred 276184610Salfred memset(&state, 0, sizeof(state)); 277184610Salfred 278189110Sthompsa state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 279184610Salfred if (state.f < 0) 280184610Salfred return (LIBUSB20_ERROR_OTHER); 281184610Salfred 282184610Salfred while (ugen20_readdir(&state) == 0) { 283184610Salfred 284184610Salfred if ((state.src[0] != 'u') || 285184610Salfred (state.src[1] != 'g') || 286184610Salfred (state.src[2] != 'e') || 287184610Salfred (state.src[3] != 'n')) { 288184610Salfred continue; 289184610Salfred } 290184610Salfred pdev = libusb20_dev_alloc(); 291184610Salfred if (pdev == NULL) { 292184610Salfred continue; 293184610Salfred } 294184610Salfred if (ugen20_enumerate(pdev, state.src + 4)) { 295184610Salfred libusb20_dev_free(pdev); 296184610Salfred continue; 297184610Salfred } 298184610Salfred /* put the device on the backend list */ 299184610Salfred libusb20_be_enqueue_device(pbe, pdev); 300184610Salfred } 301184610Salfred close(state.f); 302184610Salfred return (0); /* success */ 303184610Salfred} 304184610Salfred 305185290Salfredstatic void 306185290Salfredugen20_tr_release(struct libusb20_device *pdev) 307185290Salfred{ 308192984Sthompsa struct usb_fs_uninit fs_uninit; 309185290Salfred 310185290Salfred if (pdev->nTransfer == 0) { 311185290Salfred return; 312185290Salfred } 313185290Salfred /* release all pending USB transfers */ 314185290Salfred if (pdev->privBeData != NULL) { 315185290Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 316185290Salfred if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 317185290Salfred /* ignore any errors of this kind */ 318185290Salfred } 319185290Salfred } 320185290Salfred return; 321185290Salfred} 322185290Salfred 323184610Salfredstatic int 324185087Salfredugen20_tr_renew(struct libusb20_device *pdev) 325185087Salfred{ 326192984Sthompsa struct usb_fs_init fs_init; 327192984Sthompsa struct usb_fs_endpoint *pfse; 328185087Salfred int error; 329185087Salfred uint32_t size; 330185087Salfred uint16_t nMaxTransfer; 331185087Salfred 332185087Salfred nMaxTransfer = pdev->nTransfer; 333185087Salfred error = 0; 334185087Salfred 335185087Salfred if (nMaxTransfer == 0) { 336185087Salfred goto done; 337185087Salfred } 338185087Salfred size = nMaxTransfer * sizeof(*pfse); 339185087Salfred 340185290Salfred if (pdev->privBeData == NULL) { 341185087Salfred pfse = malloc(size); 342185087Salfred if (pfse == NULL) { 343185087Salfred error = LIBUSB20_ERROR_NO_MEM; 344185087Salfred goto done; 345185087Salfred } 346185087Salfred pdev->privBeData = pfse; 347185087Salfred } 348185087Salfred /* reset endpoint data */ 349185087Salfred memset(pdev->privBeData, 0, size); 350185087Salfred 351185087Salfred memset(&fs_init, 0, sizeof(fs_init)); 352185087Salfred 353213852Shselasky fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData); 354185087Salfred fs_init.ep_index_max = nMaxTransfer; 355185087Salfred 356185087Salfred if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) { 357185087Salfred error = LIBUSB20_ERROR_OTHER; 358185087Salfred goto done; 359185087Salfred } 360185087Salfreddone: 361185087Salfred return (error); 362185087Salfred} 363185087Salfred 364185087Salfredstatic int 365184610Salfredugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 366184610Salfred{ 367184610Salfred uint32_t plugtime; 368184610Salfred char buf[64]; 369184610Salfred int f; 370184610Salfred int g; 371184610Salfred int error; 372184610Salfred 373189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 374184610Salfred pdev->bus_number, pdev->device_address); 375184610Salfred 376184610Salfred /* 377184610Salfred * We need two file handles, one for the control endpoint and one 378184610Salfred * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 379184610Salfred * kernel locking. 380184610Salfred */ 381184610Salfred g = open(buf, O_RDWR); 382184610Salfred if (g < 0) { 383184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 384184610Salfred } 385184610Salfred f = open(buf, O_RDWR); 386184610Salfred if (f < 0) { 387184610Salfred close(g); 388184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 389184610Salfred } 390184610Salfred if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 391184610Salfred error = LIBUSB20_ERROR_OTHER; 392184610Salfred goto done; 393184610Salfred } 394184610Salfred /* check that the correct device is still plugged */ 395184610Salfred if (pdev->session_data.plugtime != plugtime) { 396184610Salfred error = LIBUSB20_ERROR_NO_DEVICE; 397184610Salfred goto done; 398184610Salfred } 399185087Salfred /* need to set this before "tr_renew()" */ 400185087Salfred pdev->file = f; 401185087Salfred pdev->file_ctrl = g; 402184610Salfred 403185087Salfred /* renew all USB transfers */ 404185087Salfred error = ugen20_tr_renew(pdev); 405185087Salfred if (error) { 406185087Salfred goto done; 407184610Salfred } 408184610Salfred /* set methods */ 409184610Salfred pdev->methods = &libusb20_ugen20_device_methods; 410185087Salfred 411184610Salfreddone: 412184610Salfred if (error) { 413185087Salfred if (pdev->privBeData) { 414185087Salfred /* cleanup after "tr_renew()" */ 415185087Salfred free(pdev->privBeData); 416185087Salfred pdev->privBeData = NULL; 417184610Salfred } 418185087Salfred pdev->file = -1; 419185087Salfred pdev->file_ctrl = -1; 420184610Salfred close(f); 421184610Salfred close(g); 422184610Salfred } 423184610Salfred return (error); 424184610Salfred} 425184610Salfred 426184610Salfredstatic int 427184610Salfredugen20_close_device(struct libusb20_device *pdev) 428184610Salfred{ 429192984Sthompsa struct usb_fs_uninit fs_uninit; 430184610Salfred 431184610Salfred if (pdev->privBeData) { 432185087Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 433184610Salfred if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 434185290Salfred /* ignore this error */ 435184610Salfred } 436184610Salfred free(pdev->privBeData); 437184610Salfred } 438184610Salfred pdev->nTransfer = 0; 439184610Salfred pdev->privBeData = NULL; 440184610Salfred close(pdev->file); 441184610Salfred close(pdev->file_ctrl); 442184610Salfred pdev->file = -1; 443184610Salfred pdev->file_ctrl = -1; 444185290Salfred return (0); /* success */ 445184610Salfred} 446184610Salfred 447184610Salfredstatic void 448184610Salfredugen20_exit_backend(struct libusb20_backend *pbe) 449184610Salfred{ 450184610Salfred return; /* nothing to do */ 451184610Salfred} 452184610Salfred 453184610Salfredstatic int 454184610Salfredugen20_get_config_desc_full(struct libusb20_device *pdev, 455185087Salfred uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 456184610Salfred{ 457192984Sthompsa struct usb_gen_descriptor gen_desc; 458192984Sthompsa struct usb_config_descriptor cdesc; 459184610Salfred uint8_t *ptr; 460184610Salfred uint16_t len; 461184610Salfred int error; 462184610Salfred 463199055Sthompsa /* make sure memory is initialised */ 464199055Sthompsa memset(&cdesc, 0, sizeof(cdesc)); 465185087Salfred memset(&gen_desc, 0, sizeof(gen_desc)); 466185087Salfred 467213852Shselasky gen_desc.ugd_data = libusb20_pass_ptr(&cdesc); 468184610Salfred gen_desc.ugd_maxlen = sizeof(cdesc); 469185087Salfred gen_desc.ugd_config_index = cfg_index; 470184610Salfred 471184610Salfred error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 472184610Salfred if (error) { 473184610Salfred return (LIBUSB20_ERROR_OTHER); 474184610Salfred } 475184610Salfred len = UGETW(cdesc.wTotalLength); 476184610Salfred if (len < sizeof(cdesc)) { 477184610Salfred /* corrupt descriptor */ 478184610Salfred return (LIBUSB20_ERROR_OTHER); 479184610Salfred } 480184610Salfred ptr = malloc(len); 481184610Salfred if (!ptr) { 482184610Salfred return (LIBUSB20_ERROR_NO_MEM); 483184610Salfred } 484199055Sthompsa 485199055Sthompsa /* make sure memory is initialised */ 486199055Sthompsa memset(ptr, 0, len); 487199055Sthompsa 488213852Shselasky gen_desc.ugd_data = libusb20_pass_ptr(ptr); 489184610Salfred gen_desc.ugd_maxlen = len; 490184610Salfred 491184610Salfred error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 492184610Salfred if (error) { 493184610Salfred free(ptr); 494184610Salfred return (LIBUSB20_ERROR_OTHER); 495184610Salfred } 496184610Salfred /* make sure that the device doesn't fool us */ 497184610Salfred memcpy(ptr, &cdesc, sizeof(cdesc)); 498184610Salfred 499184610Salfred *ppbuf = ptr; 500184610Salfred *plen = len; 501184610Salfred 502184610Salfred return (0); /* success */ 503184610Salfred} 504184610Salfred 505184610Salfredstatic int 506184610Salfredugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 507184610Salfred{ 508184610Salfred int temp; 509184610Salfred 510184610Salfred if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) { 511184610Salfred return (LIBUSB20_ERROR_OTHER); 512184610Salfred } 513184610Salfred *pindex = temp; 514184610Salfred 515184610Salfred return (0); 516184610Salfred} 517184610Salfred 518184610Salfredstatic int 519185087Salfredugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 520184610Salfred{ 521185087Salfred int temp = cfg_index; 522184610Salfred 523185290Salfred /* release all active USB transfers */ 524185290Salfred ugen20_tr_release(pdev); 525185290Salfred 526184610Salfred if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) { 527184610Salfred return (LIBUSB20_ERROR_OTHER); 528184610Salfred } 529185087Salfred return (ugen20_tr_renew(pdev)); 530184610Salfred} 531184610Salfred 532184610Salfredstatic int 533184610Salfredugen20_set_alt_index(struct libusb20_device *pdev, 534184610Salfred uint8_t iface_index, uint8_t alt_index) 535184610Salfred{ 536192984Sthompsa struct usb_alt_interface alt_iface; 537184610Salfred 538185087Salfred memset(&alt_iface, 0, sizeof(alt_iface)); 539185087Salfred 540184610Salfred alt_iface.uai_interface_index = iface_index; 541184610Salfred alt_iface.uai_alt_index = alt_index; 542184610Salfred 543185290Salfred /* release all active USB transfers */ 544185290Salfred ugen20_tr_release(pdev); 545185290Salfred 546184610Salfred if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) { 547184610Salfred return (LIBUSB20_ERROR_OTHER); 548184610Salfred } 549185087Salfred return (ugen20_tr_renew(pdev)); 550184610Salfred} 551184610Salfred 552184610Salfredstatic int 553184610Salfredugen20_reset_device(struct libusb20_device *pdev) 554184610Salfred{ 555184610Salfred int temp = 0; 556184610Salfred 557185290Salfred /* release all active USB transfers */ 558185290Salfred ugen20_tr_release(pdev); 559185290Salfred 560184610Salfred if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) { 561184610Salfred return (LIBUSB20_ERROR_OTHER); 562184610Salfred } 563185087Salfred return (ugen20_tr_renew(pdev)); 564184610Salfred} 565184610Salfred 566184610Salfredstatic int 567203147Sthompsaugen20_check_connected(struct libusb20_device *pdev) 568203147Sthompsa{ 569203147Sthompsa uint32_t plugtime; 570203147Sthompsa int error = 0; 571203147Sthompsa 572203147Sthompsa if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) { 573203147Sthompsa error = LIBUSB20_ERROR_NO_DEVICE; 574203147Sthompsa goto done; 575203147Sthompsa } 576203147Sthompsa 577203147Sthompsa if (pdev->session_data.plugtime != plugtime) { 578203147Sthompsa error = LIBUSB20_ERROR_NO_DEVICE; 579203147Sthompsa goto done; 580203147Sthompsa } 581203147Sthompsadone: 582203147Sthompsa return (error); 583203147Sthompsa} 584203147Sthompsa 585203147Sthompsastatic int 586184610Salfredugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 587184610Salfred{ 588184610Salfred int temp; 589184610Salfred 590184610Salfred switch (power_mode) { 591184610Salfred case LIBUSB20_POWER_OFF: 592184610Salfred temp = USB_POWER_MODE_OFF; 593184610Salfred break; 594184610Salfred case LIBUSB20_POWER_ON: 595184610Salfred temp = USB_POWER_MODE_ON; 596184610Salfred break; 597184610Salfred case LIBUSB20_POWER_SAVE: 598184610Salfred temp = USB_POWER_MODE_SAVE; 599184610Salfred break; 600184610Salfred case LIBUSB20_POWER_SUSPEND: 601184610Salfred temp = USB_POWER_MODE_SUSPEND; 602184610Salfred break; 603184610Salfred case LIBUSB20_POWER_RESUME: 604184610Salfred temp = USB_POWER_MODE_RESUME; 605184610Salfred break; 606184610Salfred default: 607184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 608184610Salfred } 609184610Salfred if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) { 610184610Salfred return (LIBUSB20_ERROR_OTHER); 611184610Salfred } 612184610Salfred return (0); 613184610Salfred} 614184610Salfred 615184610Salfredstatic int 616184610Salfredugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 617184610Salfred{ 618184610Salfred int temp; 619184610Salfred 620184610Salfred if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) { 621184610Salfred return (LIBUSB20_ERROR_OTHER); 622184610Salfred } 623184610Salfred switch (temp) { 624184610Salfred case USB_POWER_MODE_OFF: 625184610Salfred temp = LIBUSB20_POWER_OFF; 626184610Salfred break; 627184610Salfred case USB_POWER_MODE_ON: 628184610Salfred temp = LIBUSB20_POWER_ON; 629184610Salfred break; 630184610Salfred case USB_POWER_MODE_SAVE: 631184610Salfred temp = LIBUSB20_POWER_SAVE; 632184610Salfred break; 633184610Salfred case USB_POWER_MODE_SUSPEND: 634184610Salfred temp = LIBUSB20_POWER_SUSPEND; 635184610Salfred break; 636184610Salfred case USB_POWER_MODE_RESUME: 637184610Salfred temp = LIBUSB20_POWER_RESUME; 638184610Salfred break; 639184610Salfred default: 640184610Salfred temp = LIBUSB20_POWER_ON; 641184610Salfred break; 642184610Salfred } 643184610Salfred *power_mode = temp; 644184610Salfred return (0); /* success */ 645184610Salfred} 646184610Salfred 647184610Salfredstatic int 648250201Shselaskyugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) 649250201Shselasky{ 650250201Shselasky struct usb_device_port_path udpp; 651250201Shselasky 652250201Shselasky if (ioctl(pdev->file_ctrl, USB_GET_DEV_PORT_PATH, &udpp)) 653250201Shselasky return (LIBUSB20_ERROR_OTHER); 654250201Shselasky 655250201Shselasky if (udpp.udp_port_level > bufsize) 656250201Shselasky return (LIBUSB20_ERROR_OVERFLOW); 657250201Shselasky 658250201Shselasky memcpy(buf, udpp.udp_port_no, udpp.udp_port_level); 659250201Shselasky 660250201Shselasky return (udpp.udp_port_level); /* success */ 661250201Shselasky} 662250201Shselasky 663250201Shselaskystatic int 664246789Shselaskyugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage) 665246789Shselasky{ 666246789Shselasky int temp; 667246789Shselasky 668246789Shselasky if (ioctl(pdev->file_ctrl, USB_GET_POWER_USAGE, &temp)) { 669246789Shselasky return (LIBUSB20_ERROR_OTHER); 670246789Shselasky } 671246789Shselasky *power_usage = temp; 672246789Shselasky return (0); /* success */ 673246789Shselasky} 674246789Shselasky 675246789Shselaskystatic int 676184610Salfredugen20_kernel_driver_active(struct libusb20_device *pdev, 677184610Salfred uint8_t iface_index) 678184610Salfred{ 679184610Salfred int temp = iface_index; 680184610Salfred 681184610Salfred if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) { 682184610Salfred return (LIBUSB20_ERROR_OTHER); 683184610Salfred } 684184610Salfred return (0); /* kernel driver is active */ 685184610Salfred} 686184610Salfred 687184610Salfredstatic int 688184610Salfredugen20_detach_kernel_driver(struct libusb20_device *pdev, 689184610Salfred uint8_t iface_index) 690184610Salfred{ 691184610Salfred int temp = iface_index; 692184610Salfred 693184610Salfred if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) { 694184610Salfred return (LIBUSB20_ERROR_OTHER); 695184610Salfred } 696184610Salfred return (0); /* kernel driver is active */ 697184610Salfred} 698184610Salfred 699184610Salfredstatic int 700184610Salfredugen20_do_request_sync(struct libusb20_device *pdev, 701184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 702184610Salfred void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 703184610Salfred{ 704192984Sthompsa struct usb_ctl_request req; 705184610Salfred 706185087Salfred memset(&req, 0, sizeof(req)); 707185087Salfred 708213852Shselasky req.ucr_data = libusb20_pass_ptr(data); 709184610Salfred if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 710184610Salfred req.ucr_flags |= USB_SHORT_XFER_OK; 711184610Salfred } 712184610Salfred if (libusb20_me_encode(&req.ucr_request, 713184610Salfred sizeof(req.ucr_request), setup)) { 714184610Salfred /* ignore */ 715184610Salfred } 716184610Salfred if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) { 717184610Salfred return (LIBUSB20_ERROR_OTHER); 718184610Salfred } 719184610Salfred if (pactlen) { 720184610Salfred /* get actual length */ 721184610Salfred *pactlen = req.ucr_actlen; 722184610Salfred } 723184610Salfred return (0); /* kernel driver is active */ 724184610Salfred} 725184610Salfred 726184610Salfredstatic int 727184610Salfredugen20_process(struct libusb20_device *pdev) 728184610Salfred{ 729192984Sthompsa struct usb_fs_complete temp; 730192984Sthompsa struct usb_fs_endpoint *fsep; 731184610Salfred struct libusb20_transfer *xfer; 732184610Salfred 733184610Salfred while (1) { 734184610Salfred 735184610Salfred if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) { 736184610Salfred if (errno == EBUSY) { 737184610Salfred break; 738184610Salfred } else { 739184610Salfred /* device detached */ 740184610Salfred return (LIBUSB20_ERROR_OTHER); 741184610Salfred } 742184610Salfred } 743184610Salfred fsep = pdev->privBeData; 744184610Salfred xfer = pdev->pTransfer; 745184610Salfred fsep += temp.ep_index; 746184610Salfred xfer += temp.ep_index; 747184610Salfred 748184610Salfred /* update transfer status */ 749184610Salfred 750184610Salfred if (fsep->status == 0) { 751184610Salfred xfer->aFrames = fsep->aFrames; 752184610Salfred xfer->timeComplete = fsep->isoc_time_complete; 753184610Salfred xfer->status = LIBUSB20_TRANSFER_COMPLETED; 754184610Salfred } else if (fsep->status == USB_ERR_CANCELLED) { 755184610Salfred xfer->aFrames = 0; 756184610Salfred xfer->timeComplete = 0; 757184610Salfred xfer->status = LIBUSB20_TRANSFER_CANCELLED; 758184610Salfred } else if (fsep->status == USB_ERR_STALLED) { 759184610Salfred xfer->aFrames = 0; 760184610Salfred xfer->timeComplete = 0; 761184610Salfred xfer->status = LIBUSB20_TRANSFER_STALL; 762184610Salfred } else if (fsep->status == USB_ERR_TIMEOUT) { 763184610Salfred xfer->aFrames = 0; 764184610Salfred xfer->timeComplete = 0; 765184610Salfred xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 766184610Salfred } else { 767184610Salfred xfer->aFrames = 0; 768184610Salfred xfer->timeComplete = 0; 769184610Salfred xfer->status = LIBUSB20_TRANSFER_ERROR; 770184610Salfred } 771184610Salfred libusb20_tr_callback_wrapper(xfer); 772184610Salfred } 773184610Salfred return (0); /* done */ 774184610Salfred} 775184610Salfred 776184610Salfredstatic int 777184610Salfredugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 778239239Shselasky uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id, 779239239Shselasky uint8_t pre_scale) 780184610Salfred{ 781239239Shselasky union { 782239239Shselasky struct usb_fs_open fs_open; 783239239Shselasky struct usb_fs_open_stream fs_open_stream; 784239239Shselasky } temp; 785192984Sthompsa struct usb_fs_endpoint *fsep; 786184610Salfred 787219100Shselasky if (pre_scale) 788219100Shselasky MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE; 789219100Shselasky 790185087Salfred memset(&temp, 0, sizeof(temp)); 791185087Salfred 792184610Salfred fsep = xfer->pdev->privBeData; 793184610Salfred fsep += xfer->trIndex; 794184610Salfred 795239239Shselasky temp.fs_open.max_bufsize = MaxBufSize; 796239239Shselasky temp.fs_open.max_frames = MaxFrameCount; 797239239Shselasky temp.fs_open.ep_index = xfer->trIndex; 798239239Shselasky temp.fs_open.ep_no = ep_no; 799184610Salfred 800239239Shselasky if (stream_id != 0) { 801239239Shselasky temp.fs_open_stream.stream_id = stream_id; 802239239Shselasky 803239239Shselasky if (ioctl(xfer->pdev->file, USB_FS_OPEN_STREAM, &temp.fs_open_stream)) 804239239Shselasky return (LIBUSB20_ERROR_INVALID_PARAM); 805239239Shselasky } else { 806239239Shselasky if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp.fs_open)) 807239239Shselasky return (LIBUSB20_ERROR_INVALID_PARAM); 808184610Salfred } 809184610Salfred /* maximums might have changed - update */ 810239239Shselasky xfer->maxFrames = temp.fs_open.max_frames; 811184610Salfred 812184610Salfred /* "max_bufsize" should be multiple of "max_packet_length" */ 813239239Shselasky xfer->maxTotalLength = temp.fs_open.max_bufsize; 814239239Shselasky xfer->maxPacketLen = temp.fs_open.max_packet_length; 815184610Salfred 816213852Shselasky /* setup buffer and length lists using zero copy */ 817213852Shselasky fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer); 818213852Shselasky fsep->pLength = libusb20_pass_ptr(xfer->pLength); 819184610Salfred 820184610Salfred return (0); /* success */ 821184610Salfred} 822184610Salfred 823184610Salfredstatic int 824184610Salfredugen20_tr_close(struct libusb20_transfer *xfer) 825184610Salfred{ 826192984Sthompsa struct usb_fs_close temp; 827184610Salfred 828185087Salfred memset(&temp, 0, sizeof(temp)); 829185087Salfred 830184610Salfred temp.ep_index = xfer->trIndex; 831184610Salfred 832184610Salfred if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) { 833184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 834184610Salfred } 835184610Salfred return (0); /* success */ 836184610Salfred} 837184610Salfred 838184610Salfredstatic int 839184610Salfredugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 840184610Salfred{ 841192984Sthompsa struct usb_fs_clear_stall_sync temp; 842184610Salfred 843185087Salfred memset(&temp, 0, sizeof(temp)); 844185087Salfred 845184610Salfred /* if the transfer is active, an error will be returned */ 846184610Salfred 847184610Salfred temp.ep_index = xfer->trIndex; 848184610Salfred 849184610Salfred if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) { 850184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 851184610Salfred } 852184610Salfred return (0); /* success */ 853184610Salfred} 854184610Salfred 855184610Salfredstatic void 856184610Salfredugen20_tr_submit(struct libusb20_transfer *xfer) 857184610Salfred{ 858192984Sthompsa struct usb_fs_start temp; 859192984Sthompsa struct usb_fs_endpoint *fsep; 860184610Salfred 861185087Salfred memset(&temp, 0, sizeof(temp)); 862185087Salfred 863184610Salfred fsep = xfer->pdev->privBeData; 864184610Salfred fsep += xfer->trIndex; 865184610Salfred 866184610Salfred fsep->nFrames = xfer->nFrames; 867184610Salfred fsep->flags = 0; 868184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 869184610Salfred fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 870184610Salfred } 871184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 872184610Salfred fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 873184610Salfred } 874184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 875184610Salfred fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 876184610Salfred } 877184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 878184610Salfred fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 879184610Salfred } 880198376Sthompsa /* NOTE: The "fsep->timeout" variable is 16-bit. */ 881198376Sthompsa if (xfer->timeout > 65535) 882198376Sthompsa fsep->timeout = 65535; 883198376Sthompsa else 884198376Sthompsa fsep->timeout = xfer->timeout; 885184610Salfred 886184610Salfred temp.ep_index = xfer->trIndex; 887184610Salfred 888184610Salfred if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) { 889184610Salfred /* ignore any errors - should never happen */ 890184610Salfred } 891184610Salfred return; /* success */ 892184610Salfred} 893184610Salfred 894184610Salfredstatic void 895184610Salfredugen20_tr_cancel_async(struct libusb20_transfer *xfer) 896184610Salfred{ 897192984Sthompsa struct usb_fs_stop temp; 898184610Salfred 899185087Salfred memset(&temp, 0, sizeof(temp)); 900185087Salfred 901184610Salfred temp.ep_index = xfer->trIndex; 902184610Salfred 903184610Salfred if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) { 904184610Salfred /* ignore any errors - should never happen */ 905184610Salfred } 906184610Salfred return; 907184610Salfred} 908184610Salfred 909184610Salfredstatic int 910184610Salfredugen20_be_ioctl(uint32_t cmd, void *data) 911184610Salfred{ 912184610Salfred int f; 913185087Salfred int error; 914184610Salfred 915189110Sthompsa f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 916184610Salfred if (f < 0) 917184610Salfred return (LIBUSB20_ERROR_OTHER); 918185087Salfred error = ioctl(f, cmd, data); 919185087Salfred if (error == -1) { 920184610Salfred if (errno == EPERM) { 921185087Salfred error = LIBUSB20_ERROR_ACCESS; 922184610Salfred } else { 923185087Salfred error = LIBUSB20_ERROR_OTHER; 924184610Salfred } 925184610Salfred } 926184610Salfred close(f); 927185087Salfred return (error); 928184610Salfred} 929184610Salfred 930184610Salfredstatic int 931188622Sthompsaugen20_dev_get_iface_desc(struct libusb20_device *pdev, 932188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 933188622Sthompsa{ 934192984Sthompsa struct usb_gen_descriptor ugd; 935188622Sthompsa 936188622Sthompsa memset(&ugd, 0, sizeof(ugd)); 937188622Sthompsa 938213852Shselasky ugd.ugd_data = libusb20_pass_ptr(buf); 939188622Sthompsa ugd.ugd_maxlen = len; 940188622Sthompsa ugd.ugd_iface_index = iface_index; 941188622Sthompsa 942188622Sthompsa if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) { 943188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 944188622Sthompsa } 945188622Sthompsa return (0); 946188622Sthompsa} 947188622Sthompsa 948188622Sthompsastatic int 949188622Sthompsaugen20_dev_get_info(struct libusb20_device *pdev, 950192984Sthompsa struct usb_device_info *pinfo) 951188622Sthompsa{ 952188622Sthompsa if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) { 953188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 954188622Sthompsa } 955188622Sthompsa return (0); 956188622Sthompsa} 957188622Sthompsa 958188622Sthompsastatic int 959184610Salfredugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 960185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 961184610Salfred{ 962192984Sthompsa struct usb_gen_quirk q; 963185087Salfred int error; 964184610Salfred 965184610Salfred memset(&q, 0, sizeof(q)); 966184610Salfred 967185087Salfred q.index = quirk_index; 968184610Salfred 969185087Salfred error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q); 970184610Salfred 971185087Salfred if (error) { 972184610Salfred if (errno == EINVAL) { 973184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 974184610Salfred } 975184610Salfred } else { 976184610Salfred pq->vid = q.vid; 977184610Salfred pq->pid = q.pid; 978184610Salfred pq->bcdDeviceLow = q.bcdDeviceLow; 979184610Salfred pq->bcdDeviceHigh = q.bcdDeviceHigh; 980184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 981184610Salfred } 982185087Salfred return (error); 983184610Salfred} 984184610Salfred 985184610Salfredstatic int 986185087Salfredugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 987184610Salfred struct libusb20_quirk *pq) 988184610Salfred{ 989192984Sthompsa struct usb_gen_quirk q; 990185087Salfred int error; 991184610Salfred 992184610Salfred memset(&q, 0, sizeof(q)); 993184610Salfred 994185087Salfred q.index = quirk_index; 995184610Salfred 996185087Salfred error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q); 997184610Salfred 998185087Salfred if (error) { 999184610Salfred if (errno == EINVAL) { 1000184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1001184610Salfred } 1002184610Salfred } else { 1003184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1004184610Salfred } 1005185087Salfred return (error); 1006184610Salfred} 1007184610Salfred 1008184610Salfredstatic int 1009184610Salfredugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 1010184610Salfred struct libusb20_quirk *pq) 1011184610Salfred{ 1012192984Sthompsa struct usb_gen_quirk q; 1013185087Salfred int error; 1014184610Salfred 1015184610Salfred memset(&q, 0, sizeof(q)); 1016184610Salfred 1017184610Salfred q.vid = pq->vid; 1018184610Salfred q.pid = pq->pid; 1019184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 1020184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 1021184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1022184610Salfred 1023185087Salfred error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q); 1024185087Salfred if (error) { 1025184610Salfred if (errno == ENOMEM) { 1026184610Salfred return (LIBUSB20_ERROR_NO_MEM); 1027184610Salfred } 1028184610Salfred } 1029185087Salfred return (error); 1030184610Salfred} 1031184610Salfred 1032184610Salfredstatic int 1033184610Salfredugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 1034184610Salfred struct libusb20_quirk *pq) 1035184610Salfred{ 1036192984Sthompsa struct usb_gen_quirk q; 1037185087Salfred int error; 1038184610Salfred 1039184610Salfred memset(&q, 0, sizeof(q)); 1040184610Salfred 1041184610Salfred q.vid = pq->vid; 1042184610Salfred q.pid = pq->pid; 1043184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 1044184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 1045184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1046184610Salfred 1047185087Salfred error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q); 1048185087Salfred if (error) { 1049184610Salfred if (errno == EINVAL) { 1050184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 1051184610Salfred } 1052184610Salfred } 1053185087Salfred return (error); 1054184610Salfred} 1055184610Salfred 1056184610Salfredstatic int 1057188987Sthompsaugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1058188987Sthompsa{ 1059188987Sthompsa return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp)); 1060188987Sthompsa} 1061188987Sthompsa 1062188987Sthompsastatic int 1063188987Sthompsaugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1064188987Sthompsa{ 1065188987Sthompsa return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp)); 1066188987Sthompsa} 1067