libusb20_ugen20.c revision 189110
1184610Salfred/* $FreeBSD: head/lib/libusb20/libusb20_ugen20.c 189110 2009-02-27 17:27:16Z thompsa $ */ 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 27184610Salfred#include <sys/queue.h> 28184610Salfred#include <sys/types.h> 29184610Salfred 30184610Salfred#include <stdio.h> 31184610Salfred#include <stdlib.h> 32184610Salfred#include <unistd.h> 33184610Salfred#include <string.h> 34184610Salfred#include <poll.h> 35184610Salfred#include <fcntl.h> 36184610Salfred#include <errno.h> 37184610Salfred 38184610Salfred#include "libusb20.h" 39184610Salfred#include "libusb20_desc.h" 40184610Salfred#include "libusb20_int.h" 41184610Salfred 42188945Sthompsa#include <dev/usb/usb.h> 43188945Sthompsa#include <dev/usb/usb_ioctl.h> 44188945Sthompsa#include <dev/usb/usb_mfunc.h> 45188945Sthompsa#include <dev/usb/usb_error.h> 46188945Sthompsa#include <dev/usb/usb_revision.h> 47184610Salfred 48184610Salfredstatic libusb20_init_backend_t ugen20_init_backend; 49184610Salfredstatic libusb20_open_device_t ugen20_open_device; 50184610Salfredstatic libusb20_close_device_t ugen20_close_device; 51184610Salfredstatic libusb20_get_backend_name_t ugen20_get_backend_name; 52184610Salfredstatic libusb20_exit_backend_t ugen20_exit_backend; 53188622Sthompsastatic libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc; 54188622Sthompsastatic libusb20_dev_get_info_t ugen20_dev_get_info; 55184610Salfredstatic libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk; 56184610Salfredstatic libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name; 57184610Salfredstatic libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk; 58184610Salfredstatic libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk; 59188987Sthompsastatic libusb20_root_set_template_t ugen20_root_set_template; 60188987Sthompsastatic libusb20_root_get_template_t ugen20_root_get_template; 61184610Salfred 62184610Salfredconst struct libusb20_backend_methods libusb20_ugen20_backend = { 63184610Salfred LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20) 64184610Salfred}; 65184610Salfred 66184610Salfred/* USB device specific */ 67184610Salfredstatic libusb20_get_config_desc_full_t ugen20_get_config_desc_full; 68184610Salfredstatic libusb20_get_config_index_t ugen20_get_config_index; 69184610Salfredstatic libusb20_set_config_index_t ugen20_set_config_index; 70184610Salfredstatic libusb20_claim_interface_t ugen20_claim_interface; 71184610Salfredstatic libusb20_release_interface_t ugen20_release_interface; 72184610Salfredstatic libusb20_set_alt_index_t ugen20_set_alt_index; 73184610Salfredstatic libusb20_reset_device_t ugen20_reset_device; 74184610Salfredstatic libusb20_set_power_mode_t ugen20_set_power_mode; 75184610Salfredstatic libusb20_get_power_mode_t ugen20_get_power_mode; 76184610Salfredstatic libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 77184610Salfredstatic libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 78184610Salfredstatic libusb20_do_request_sync_t ugen20_do_request_sync; 79184610Salfredstatic libusb20_process_t ugen20_process; 80184610Salfred 81184610Salfred/* USB transfer specific */ 82184610Salfredstatic libusb20_tr_open_t ugen20_tr_open; 83184610Salfredstatic libusb20_tr_close_t ugen20_tr_close; 84184610Salfredstatic libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 85184610Salfredstatic libusb20_tr_submit_t ugen20_tr_submit; 86184610Salfredstatic libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 87184610Salfred 88184610Salfredstatic const struct libusb20_device_methods libusb20_ugen20_device_methods = { 89184610Salfred LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 90184610Salfred}; 91184610Salfred 92184610Salfredstatic const char * 93184610Salfredugen20_get_backend_name(void) 94184610Salfred{ 95184610Salfred return ("FreeBSD UGEN 2.0"); 96184610Salfred} 97184610Salfred 98184610Salfredstatic uint32_t 99184610Salfredugen20_path_convert_one(const char **pp) 100184610Salfred{ 101184610Salfred const char *ptr; 102184610Salfred uint32_t temp = 0; 103184610Salfred 104184610Salfred ptr = *pp; 105184610Salfred 106184610Salfred while ((*ptr >= '0') && (*ptr <= '9')) { 107184610Salfred temp *= 10; 108184610Salfred temp += (*ptr - '0'); 109184610Salfred if (temp >= 1000000) { 110184610Salfred /* catch overflow early */ 111184610Salfred return (0 - 1); 112184610Salfred } 113184610Salfred ptr++; 114184610Salfred } 115184610Salfred 116184610Salfred if (*ptr == '.') { 117184610Salfred /* skip dot */ 118184610Salfred ptr++; 119184610Salfred } 120184610Salfred *pp = ptr; 121184610Salfred 122184610Salfred return (temp); 123184610Salfred} 124184610Salfred 125184610Salfredstatic int 126184610Salfredugen20_enumerate(struct libusb20_device *pdev, const char *id) 127184610Salfred{ 128184610Salfred const char *tmp = id; 129184610Salfred struct usb2_device_descriptor ddesc; 130184610Salfred struct usb2_device_info devinfo; 131184610Salfred uint32_t plugtime; 132184610Salfred char buf[64]; 133184610Salfred int f; 134184610Salfred int error; 135184610Salfred 136184610Salfred pdev->bus_number = ugen20_path_convert_one(&tmp); 137184610Salfred pdev->device_address = ugen20_path_convert_one(&tmp); 138184610Salfred 139189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 140184610Salfred pdev->bus_number, pdev->device_address); 141184610Salfred 142184610Salfred f = open(buf, O_RDWR); 143184610Salfred if (f < 0) { 144184610Salfred return (LIBUSB20_ERROR_OTHER); 145184610Salfred } 146184610Salfred if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 147184610Salfred error = LIBUSB20_ERROR_OTHER; 148184610Salfred goto done; 149184610Salfred } 150184610Salfred /* store when the device was plugged */ 151184610Salfred pdev->session_data.plugtime = plugtime; 152184610Salfred 153184610Salfred if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) { 154184610Salfred error = LIBUSB20_ERROR_OTHER; 155184610Salfred goto done; 156184610Salfred } 157184610Salfred LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 158184610Salfred 159184610Salfred libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 160184610Salfred 161184610Salfred if (pdev->ddesc.bNumConfigurations == 0) { 162184610Salfred error = LIBUSB20_ERROR_OTHER; 163184610Salfred goto done; 164184610Salfred } else if (pdev->ddesc.bNumConfigurations >= 8) { 165184610Salfred error = LIBUSB20_ERROR_OTHER; 166184610Salfred goto done; 167184610Salfred } 168184610Salfred if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) { 169184610Salfred error = LIBUSB20_ERROR_OTHER; 170184610Salfred goto done; 171184610Salfred } 172184610Salfred switch (devinfo.udi_mode) { 173184610Salfred case USB_MODE_DEVICE: 174184610Salfred pdev->usb_mode = LIBUSB20_MODE_DEVICE; 175184610Salfred break; 176184610Salfred default: 177184610Salfred pdev->usb_mode = LIBUSB20_MODE_HOST; 178184610Salfred break; 179184610Salfred } 180184610Salfred 181184610Salfred switch (devinfo.udi_speed) { 182184610Salfred case USB_SPEED_LOW: 183184610Salfred pdev->usb_speed = LIBUSB20_SPEED_LOW; 184184610Salfred break; 185184610Salfred case USB_SPEED_FULL: 186184610Salfred pdev->usb_speed = LIBUSB20_SPEED_FULL; 187184610Salfred break; 188184610Salfred case USB_SPEED_HIGH: 189184610Salfred pdev->usb_speed = LIBUSB20_SPEED_HIGH; 190184610Salfred break; 191184610Salfred case USB_SPEED_VARIABLE: 192184610Salfred pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 193184610Salfred break; 194184610Salfred case USB_SPEED_SUPER: 195184610Salfred pdev->usb_speed = LIBUSB20_SPEED_SUPER; 196184610Salfred break; 197184610Salfred default: 198184610Salfred pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 199184610Salfred break; 200184610Salfred } 201184610Salfred 202184610Salfred /* generate a nice description for printout */ 203184610Salfred 204184610Salfred snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 205189110Sthompsa USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, 206184610Salfred pdev->device_address, devinfo.udi_product, 207184610Salfred devinfo.udi_vendor, pdev->bus_number); 208184610Salfred 209184610Salfred error = 0; 210184610Salfreddone: 211184610Salfred close(f); 212184610Salfred return (error); 213184610Salfred} 214184610Salfred 215184610Salfredstruct ugen20_urd_state { 216184610Salfred struct usb2_read_dir urd; 217184610Salfred uint32_t nparsed; 218184610Salfred int f; 219184610Salfred uint8_t *ptr; 220184610Salfred const char *src; 221184610Salfred const char *dst; 222184610Salfred uint8_t buf[256]; 223184610Salfred uint8_t dummy_zero[1]; 224184610Salfred}; 225184610Salfred 226184610Salfredstatic int 227184610Salfredugen20_readdir(struct ugen20_urd_state *st) 228184610Salfred{ 229184610Salfred ; /* style fix */ 230184610Salfredrepeat: 231184610Salfred if (st->ptr == NULL) { 232184610Salfred st->urd.urd_startentry += st->nparsed; 233184610Salfred st->urd.urd_data = st->buf; 234184610Salfred st->urd.urd_maxlen = sizeof(st->buf); 235184610Salfred st->nparsed = 0; 236184610Salfred 237184610Salfred if (ioctl(st->f, USB_READ_DIR, &st->urd)) { 238184610Salfred return (EINVAL); 239184610Salfred } 240184610Salfred st->ptr = st->buf; 241184610Salfred } 242184610Salfred if (st->ptr[0] == 0) { 243184610Salfred if (st->nparsed) { 244184610Salfred st->ptr = NULL; 245184610Salfred goto repeat; 246184610Salfred } else { 247184610Salfred return (ENXIO); 248184610Salfred } 249184610Salfred } 250184610Salfred st->src = (void *)(st->ptr + 1); 251184610Salfred st->dst = st->src + strlen(st->src) + 1; 252184610Salfred st->ptr = st->ptr + st->ptr[0]; 253184610Salfred st->nparsed++; 254184610Salfred 255184610Salfred if ((st->ptr < st->buf) || 256184610Salfred (st->ptr > st->dummy_zero)) { 257184610Salfred /* invalid entry */ 258184610Salfred return (EINVAL); 259184610Salfred } 260184610Salfred return (0); 261184610Salfred} 262184610Salfred 263184610Salfredstatic int 264184610Salfredugen20_init_backend(struct libusb20_backend *pbe) 265184610Salfred{ 266184610Salfred struct ugen20_urd_state state; 267184610Salfred struct libusb20_device *pdev; 268184610Salfred 269184610Salfred memset(&state, 0, sizeof(state)); 270184610Salfred 271189110Sthompsa state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 272184610Salfred if (state.f < 0) 273184610Salfred return (LIBUSB20_ERROR_OTHER); 274184610Salfred 275184610Salfred while (ugen20_readdir(&state) == 0) { 276184610Salfred 277184610Salfred if ((state.src[0] != 'u') || 278184610Salfred (state.src[1] != 'g') || 279184610Salfred (state.src[2] != 'e') || 280184610Salfred (state.src[3] != 'n')) { 281184610Salfred continue; 282184610Salfred } 283184610Salfred pdev = libusb20_dev_alloc(); 284184610Salfred if (pdev == NULL) { 285184610Salfred continue; 286184610Salfred } 287184610Salfred if (ugen20_enumerate(pdev, state.src + 4)) { 288184610Salfred libusb20_dev_free(pdev); 289184610Salfred continue; 290184610Salfred } 291184610Salfred /* put the device on the backend list */ 292184610Salfred libusb20_be_enqueue_device(pbe, pdev); 293184610Salfred } 294184610Salfred close(state.f); 295184610Salfred return (0); /* success */ 296184610Salfred} 297184610Salfred 298185290Salfredstatic void 299185290Salfredugen20_tr_release(struct libusb20_device *pdev) 300185290Salfred{ 301185290Salfred struct usb2_fs_uninit fs_uninit; 302185290Salfred 303185290Salfred if (pdev->nTransfer == 0) { 304185290Salfred return; 305185290Salfred } 306185290Salfred /* release all pending USB transfers */ 307185290Salfred if (pdev->privBeData != NULL) { 308185290Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 309185290Salfred if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 310185290Salfred /* ignore any errors of this kind */ 311185290Salfred } 312185290Salfred } 313185290Salfred return; 314185290Salfred} 315185290Salfred 316184610Salfredstatic int 317185087Salfredugen20_tr_renew(struct libusb20_device *pdev) 318185087Salfred{ 319185087Salfred struct usb2_fs_init fs_init; 320185087Salfred struct usb2_fs_endpoint *pfse; 321185087Salfred int error; 322185087Salfred uint32_t size; 323185087Salfred uint16_t nMaxTransfer; 324185087Salfred 325185087Salfred nMaxTransfer = pdev->nTransfer; 326185087Salfred error = 0; 327185087Salfred 328185087Salfred if (nMaxTransfer == 0) { 329185087Salfred goto done; 330185087Salfred } 331185087Salfred size = nMaxTransfer * sizeof(*pfse); 332185087Salfred 333185290Salfred if (pdev->privBeData == NULL) { 334185087Salfred pfse = malloc(size); 335185087Salfred if (pfse == NULL) { 336185087Salfred error = LIBUSB20_ERROR_NO_MEM; 337185087Salfred goto done; 338185087Salfred } 339185087Salfred pdev->privBeData = pfse; 340185087Salfred } 341185087Salfred /* reset endpoint data */ 342185087Salfred memset(pdev->privBeData, 0, size); 343185087Salfred 344185087Salfred memset(&fs_init, 0, sizeof(fs_init)); 345185087Salfred 346185087Salfred fs_init.pEndpoints = pdev->privBeData; 347185087Salfred fs_init.ep_index_max = nMaxTransfer; 348185087Salfred 349185087Salfred if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) { 350185087Salfred error = LIBUSB20_ERROR_OTHER; 351185087Salfred goto done; 352185087Salfred } 353185087Salfreddone: 354185087Salfred return (error); 355185087Salfred} 356185087Salfred 357185087Salfredstatic int 358184610Salfredugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 359184610Salfred{ 360184610Salfred uint32_t plugtime; 361184610Salfred char buf[64]; 362184610Salfred int f; 363184610Salfred int g; 364184610Salfred int error; 365184610Salfred 366189110Sthompsa snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 367184610Salfred pdev->bus_number, pdev->device_address); 368184610Salfred 369184610Salfred /* 370184610Salfred * We need two file handles, one for the control endpoint and one 371184610Salfred * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 372184610Salfred * kernel locking. 373184610Salfred */ 374184610Salfred g = open(buf, O_RDWR); 375184610Salfred if (g < 0) { 376184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 377184610Salfred } 378184610Salfred f = open(buf, O_RDWR); 379184610Salfred if (f < 0) { 380184610Salfred close(g); 381184610Salfred return (LIBUSB20_ERROR_NO_DEVICE); 382184610Salfred } 383184610Salfred if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 384184610Salfred error = LIBUSB20_ERROR_OTHER; 385184610Salfred goto done; 386184610Salfred } 387184610Salfred /* check that the correct device is still plugged */ 388184610Salfred if (pdev->session_data.plugtime != plugtime) { 389184610Salfred error = LIBUSB20_ERROR_NO_DEVICE; 390184610Salfred goto done; 391184610Salfred } 392185087Salfred /* need to set this before "tr_renew()" */ 393185087Salfred pdev->file = f; 394185087Salfred pdev->file_ctrl = g; 395184610Salfred 396185087Salfred /* renew all USB transfers */ 397185087Salfred error = ugen20_tr_renew(pdev); 398185087Salfred if (error) { 399185087Salfred goto done; 400184610Salfred } 401184610Salfred /* set methods */ 402184610Salfred pdev->methods = &libusb20_ugen20_device_methods; 403185087Salfred 404184610Salfreddone: 405184610Salfred if (error) { 406185087Salfred if (pdev->privBeData) { 407185087Salfred /* cleanup after "tr_renew()" */ 408185087Salfred free(pdev->privBeData); 409185087Salfred pdev->privBeData = NULL; 410184610Salfred } 411185087Salfred pdev->file = -1; 412185087Salfred pdev->file_ctrl = -1; 413184610Salfred close(f); 414184610Salfred close(g); 415184610Salfred } 416184610Salfred return (error); 417184610Salfred} 418184610Salfred 419184610Salfredstatic int 420184610Salfredugen20_close_device(struct libusb20_device *pdev) 421184610Salfred{ 422185087Salfred struct usb2_fs_uninit fs_uninit; 423184610Salfred 424184610Salfred if (pdev->privBeData) { 425185087Salfred memset(&fs_uninit, 0, sizeof(fs_uninit)); 426184610Salfred if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 427185290Salfred /* ignore this error */ 428184610Salfred } 429184610Salfred free(pdev->privBeData); 430184610Salfred } 431184610Salfred pdev->nTransfer = 0; 432184610Salfred pdev->privBeData = NULL; 433184610Salfred close(pdev->file); 434184610Salfred close(pdev->file_ctrl); 435184610Salfred pdev->file = -1; 436184610Salfred pdev->file_ctrl = -1; 437185290Salfred return (0); /* success */ 438184610Salfred} 439184610Salfred 440184610Salfredstatic void 441184610Salfredugen20_exit_backend(struct libusb20_backend *pbe) 442184610Salfred{ 443184610Salfred return; /* nothing to do */ 444184610Salfred} 445184610Salfred 446184610Salfredstatic int 447184610Salfredugen20_get_config_desc_full(struct libusb20_device *pdev, 448185087Salfred uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 449184610Salfred{ 450185087Salfred struct usb2_gen_descriptor gen_desc; 451184610Salfred struct usb2_config_descriptor cdesc; 452184610Salfred uint8_t *ptr; 453184610Salfred uint16_t len; 454184610Salfred int error; 455184610Salfred 456185087Salfred memset(&gen_desc, 0, sizeof(gen_desc)); 457185087Salfred 458184610Salfred gen_desc.ugd_data = &cdesc; 459184610Salfred gen_desc.ugd_maxlen = sizeof(cdesc); 460185087Salfred gen_desc.ugd_config_index = cfg_index; 461184610Salfred 462184610Salfred error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 463184610Salfred if (error) { 464184610Salfred return (LIBUSB20_ERROR_OTHER); 465184610Salfred } 466184610Salfred len = UGETW(cdesc.wTotalLength); 467184610Salfred if (len < sizeof(cdesc)) { 468184610Salfred /* corrupt descriptor */ 469184610Salfred return (LIBUSB20_ERROR_OTHER); 470184610Salfred } 471184610Salfred ptr = malloc(len); 472184610Salfred if (!ptr) { 473184610Salfred return (LIBUSB20_ERROR_NO_MEM); 474184610Salfred } 475184610Salfred gen_desc.ugd_data = ptr; 476184610Salfred gen_desc.ugd_maxlen = len; 477184610Salfred 478184610Salfred error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 479184610Salfred if (error) { 480184610Salfred free(ptr); 481184610Salfred return (LIBUSB20_ERROR_OTHER); 482184610Salfred } 483184610Salfred /* make sure that the device doesn't fool us */ 484184610Salfred memcpy(ptr, &cdesc, sizeof(cdesc)); 485184610Salfred 486184610Salfred *ppbuf = ptr; 487184610Salfred *plen = len; 488184610Salfred 489184610Salfred return (0); /* success */ 490184610Salfred} 491184610Salfred 492184610Salfredstatic int 493184610Salfredugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 494184610Salfred{ 495184610Salfred int temp; 496184610Salfred 497184610Salfred if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) { 498184610Salfred return (LIBUSB20_ERROR_OTHER); 499184610Salfred } 500184610Salfred *pindex = temp; 501184610Salfred 502184610Salfred return (0); 503184610Salfred} 504184610Salfred 505184610Salfredstatic int 506185087Salfredugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 507184610Salfred{ 508185087Salfred int temp = cfg_index; 509184610Salfred 510185290Salfred /* release all active USB transfers */ 511185290Salfred ugen20_tr_release(pdev); 512185290Salfred 513184610Salfred if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) { 514184610Salfred return (LIBUSB20_ERROR_OTHER); 515184610Salfred } 516185087Salfred return (ugen20_tr_renew(pdev)); 517184610Salfred} 518184610Salfred 519184610Salfredstatic int 520184610Salfredugen20_claim_interface(struct libusb20_device *pdev, uint8_t iface_index) 521184610Salfred{ 522184610Salfred int temp = iface_index; 523184610Salfred 524184610Salfred if (ioctl(pdev->file_ctrl, USB_CLAIM_INTERFACE, &temp)) { 525184610Salfred return (LIBUSB20_ERROR_OTHER); 526184610Salfred } 527184610Salfred return (0); 528184610Salfred} 529184610Salfred 530184610Salfredstatic int 531184610Salfredugen20_release_interface(struct libusb20_device *pdev, uint8_t iface_index) 532184610Salfred{ 533184610Salfred int temp = iface_index; 534184610Salfred 535184610Salfred if (ioctl(pdev->file_ctrl, USB_RELEASE_INTERFACE, &temp)) { 536184610Salfred return (LIBUSB20_ERROR_OTHER); 537184610Salfred } 538184610Salfred return (0); 539184610Salfred} 540184610Salfred 541184610Salfredstatic int 542184610Salfredugen20_set_alt_index(struct libusb20_device *pdev, 543184610Salfred uint8_t iface_index, uint8_t alt_index) 544184610Salfred{ 545185087Salfred struct usb2_alt_interface alt_iface; 546184610Salfred 547185087Salfred memset(&alt_iface, 0, sizeof(alt_iface)); 548185087Salfred 549184610Salfred alt_iface.uai_interface_index = iface_index; 550184610Salfred alt_iface.uai_alt_index = alt_index; 551184610Salfred 552185290Salfred /* release all active USB transfers */ 553185290Salfred ugen20_tr_release(pdev); 554185290Salfred 555184610Salfred if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) { 556184610Salfred return (LIBUSB20_ERROR_OTHER); 557184610Salfred } 558185087Salfred return (ugen20_tr_renew(pdev)); 559184610Salfred} 560184610Salfred 561184610Salfredstatic int 562184610Salfredugen20_reset_device(struct libusb20_device *pdev) 563184610Salfred{ 564184610Salfred int temp = 0; 565184610Salfred 566185290Salfred /* release all active USB transfers */ 567185290Salfred ugen20_tr_release(pdev); 568185290Salfred 569184610Salfred if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) { 570184610Salfred return (LIBUSB20_ERROR_OTHER); 571184610Salfred } 572185087Salfred return (ugen20_tr_renew(pdev)); 573184610Salfred} 574184610Salfred 575184610Salfredstatic int 576184610Salfredugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 577184610Salfred{ 578184610Salfred int temp; 579184610Salfred 580184610Salfred switch (power_mode) { 581184610Salfred case LIBUSB20_POWER_OFF: 582184610Salfred temp = USB_POWER_MODE_OFF; 583184610Salfred break; 584184610Salfred case LIBUSB20_POWER_ON: 585184610Salfred temp = USB_POWER_MODE_ON; 586184610Salfred break; 587184610Salfred case LIBUSB20_POWER_SAVE: 588184610Salfred temp = USB_POWER_MODE_SAVE; 589184610Salfred break; 590184610Salfred case LIBUSB20_POWER_SUSPEND: 591184610Salfred temp = USB_POWER_MODE_SUSPEND; 592184610Salfred break; 593184610Salfred case LIBUSB20_POWER_RESUME: 594184610Salfred temp = USB_POWER_MODE_RESUME; 595184610Salfred break; 596184610Salfred default: 597184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 598184610Salfred } 599184610Salfred if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) { 600184610Salfred return (LIBUSB20_ERROR_OTHER); 601184610Salfred } 602184610Salfred return (0); 603184610Salfred} 604184610Salfred 605184610Salfredstatic int 606184610Salfredugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 607184610Salfred{ 608184610Salfred int temp; 609184610Salfred 610184610Salfred if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) { 611184610Salfred return (LIBUSB20_ERROR_OTHER); 612184610Salfred } 613184610Salfred switch (temp) { 614184610Salfred case USB_POWER_MODE_OFF: 615184610Salfred temp = LIBUSB20_POWER_OFF; 616184610Salfred break; 617184610Salfred case USB_POWER_MODE_ON: 618184610Salfred temp = LIBUSB20_POWER_ON; 619184610Salfred break; 620184610Salfred case USB_POWER_MODE_SAVE: 621184610Salfred temp = LIBUSB20_POWER_SAVE; 622184610Salfred break; 623184610Salfred case USB_POWER_MODE_SUSPEND: 624184610Salfred temp = LIBUSB20_POWER_SUSPEND; 625184610Salfred break; 626184610Salfred case USB_POWER_MODE_RESUME: 627184610Salfred temp = LIBUSB20_POWER_RESUME; 628184610Salfred break; 629184610Salfred default: 630184610Salfred temp = LIBUSB20_POWER_ON; 631184610Salfred break; 632184610Salfred } 633184610Salfred *power_mode = temp; 634184610Salfred return (0); /* success */ 635184610Salfred} 636184610Salfred 637184610Salfredstatic int 638184610Salfredugen20_kernel_driver_active(struct libusb20_device *pdev, 639184610Salfred uint8_t iface_index) 640184610Salfred{ 641184610Salfred int temp = iface_index; 642184610Salfred 643184610Salfred if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) { 644184610Salfred return (LIBUSB20_ERROR_OTHER); 645184610Salfred } 646184610Salfred return (0); /* kernel driver is active */ 647184610Salfred} 648184610Salfred 649184610Salfredstatic int 650184610Salfredugen20_detach_kernel_driver(struct libusb20_device *pdev, 651184610Salfred uint8_t iface_index) 652184610Salfred{ 653184610Salfred int temp = iface_index; 654184610Salfred 655184610Salfred if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) { 656184610Salfred return (LIBUSB20_ERROR_OTHER); 657184610Salfred } 658184610Salfred return (0); /* kernel driver is active */ 659184610Salfred} 660184610Salfred 661184610Salfredstatic int 662184610Salfredugen20_do_request_sync(struct libusb20_device *pdev, 663184610Salfred struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 664184610Salfred void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 665184610Salfred{ 666185087Salfred struct usb2_ctl_request req; 667184610Salfred 668185087Salfred memset(&req, 0, sizeof(req)); 669185087Salfred 670184610Salfred req.ucr_data = data; 671184610Salfred if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 672184610Salfred req.ucr_flags |= USB_SHORT_XFER_OK; 673184610Salfred } 674184610Salfred if (libusb20_me_encode(&req.ucr_request, 675184610Salfred sizeof(req.ucr_request), setup)) { 676184610Salfred /* ignore */ 677184610Salfred } 678184610Salfred if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) { 679184610Salfred return (LIBUSB20_ERROR_OTHER); 680184610Salfred } 681184610Salfred if (pactlen) { 682184610Salfred /* get actual length */ 683184610Salfred *pactlen = req.ucr_actlen; 684184610Salfred } 685184610Salfred return (0); /* kernel driver is active */ 686184610Salfred} 687184610Salfred 688184610Salfredstatic int 689184610Salfredugen20_process(struct libusb20_device *pdev) 690184610Salfred{ 691184610Salfred struct usb2_fs_complete temp; 692184610Salfred struct usb2_fs_endpoint *fsep; 693184610Salfred struct libusb20_transfer *xfer; 694184610Salfred 695184610Salfred while (1) { 696184610Salfred 697184610Salfred if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) { 698184610Salfred if (errno == EBUSY) { 699184610Salfred break; 700184610Salfred } else { 701184610Salfred /* device detached */ 702184610Salfred return (LIBUSB20_ERROR_OTHER); 703184610Salfred } 704184610Salfred } 705184610Salfred fsep = pdev->privBeData; 706184610Salfred xfer = pdev->pTransfer; 707184610Salfred fsep += temp.ep_index; 708184610Salfred xfer += temp.ep_index; 709184610Salfred 710184610Salfred /* update transfer status */ 711184610Salfred 712184610Salfred if (fsep->status == 0) { 713184610Salfred xfer->aFrames = fsep->aFrames; 714184610Salfred xfer->timeComplete = fsep->isoc_time_complete; 715184610Salfred xfer->status = LIBUSB20_TRANSFER_COMPLETED; 716184610Salfred } else if (fsep->status == USB_ERR_CANCELLED) { 717184610Salfred xfer->aFrames = 0; 718184610Salfred xfer->timeComplete = 0; 719184610Salfred xfer->status = LIBUSB20_TRANSFER_CANCELLED; 720184610Salfred } else if (fsep->status == USB_ERR_STALLED) { 721184610Salfred xfer->aFrames = 0; 722184610Salfred xfer->timeComplete = 0; 723184610Salfred xfer->status = LIBUSB20_TRANSFER_STALL; 724184610Salfred } else if (fsep->status == USB_ERR_TIMEOUT) { 725184610Salfred xfer->aFrames = 0; 726184610Salfred xfer->timeComplete = 0; 727184610Salfred xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 728184610Salfred } else { 729184610Salfred xfer->aFrames = 0; 730184610Salfred xfer->timeComplete = 0; 731184610Salfred xfer->status = LIBUSB20_TRANSFER_ERROR; 732184610Salfred } 733184610Salfred libusb20_tr_callback_wrapper(xfer); 734184610Salfred } 735184610Salfred return (0); /* done */ 736184610Salfred} 737184610Salfred 738184610Salfredstatic int 739184610Salfredugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 740184610Salfred uint32_t MaxFrameCount, uint8_t ep_no) 741184610Salfred{ 742185087Salfred struct usb2_fs_open temp; 743184610Salfred struct usb2_fs_endpoint *fsep; 744184610Salfred 745185087Salfred memset(&temp, 0, sizeof(temp)); 746185087Salfred 747184610Salfred fsep = xfer->pdev->privBeData; 748184610Salfred fsep += xfer->trIndex; 749184610Salfred 750184610Salfred temp.max_bufsize = MaxBufSize; 751184610Salfred temp.max_frames = MaxFrameCount; 752184610Salfred temp.ep_index = xfer->trIndex; 753184610Salfred temp.ep_no = ep_no; 754184610Salfred 755184610Salfred if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) { 756184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 757184610Salfred } 758184610Salfred /* maximums might have changed - update */ 759184610Salfred xfer->maxFrames = temp.max_frames; 760184610Salfred 761184610Salfred /* "max_bufsize" should be multiple of "max_packet_length" */ 762184610Salfred xfer->maxTotalLength = temp.max_bufsize; 763184610Salfred xfer->maxPacketLen = temp.max_packet_length; 764184610Salfred 765184610Salfred /* setup buffer and length lists */ 766184610Salfred fsep->ppBuffer = xfer->ppBuffer;/* zero copy */ 767184610Salfred fsep->pLength = xfer->pLength; /* zero copy */ 768184610Salfred 769184610Salfred return (0); /* success */ 770184610Salfred} 771184610Salfred 772184610Salfredstatic int 773184610Salfredugen20_tr_close(struct libusb20_transfer *xfer) 774184610Salfred{ 775185087Salfred struct usb2_fs_close temp; 776184610Salfred 777185087Salfred memset(&temp, 0, sizeof(temp)); 778185087Salfred 779184610Salfred temp.ep_index = xfer->trIndex; 780184610Salfred 781184610Salfred if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) { 782184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 783184610Salfred } 784184610Salfred return (0); /* success */ 785184610Salfred} 786184610Salfred 787184610Salfredstatic int 788184610Salfredugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 789184610Salfred{ 790185087Salfred struct usb2_fs_clear_stall_sync temp; 791184610Salfred 792185087Salfred memset(&temp, 0, sizeof(temp)); 793185087Salfred 794184610Salfred /* if the transfer is active, an error will be returned */ 795184610Salfred 796184610Salfred temp.ep_index = xfer->trIndex; 797184610Salfred 798184610Salfred if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) { 799184610Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 800184610Salfred } 801184610Salfred return (0); /* success */ 802184610Salfred} 803184610Salfred 804184610Salfredstatic void 805184610Salfredugen20_tr_submit(struct libusb20_transfer *xfer) 806184610Salfred{ 807185087Salfred struct usb2_fs_start temp; 808184610Salfred struct usb2_fs_endpoint *fsep; 809184610Salfred 810185087Salfred memset(&temp, 0, sizeof(temp)); 811185087Salfred 812184610Salfred fsep = xfer->pdev->privBeData; 813184610Salfred fsep += xfer->trIndex; 814184610Salfred 815184610Salfred fsep->nFrames = xfer->nFrames; 816184610Salfred fsep->flags = 0; 817184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 818184610Salfred fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 819184610Salfred } 820184610Salfred if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 821184610Salfred fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 822184610Salfred } 823184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 824184610Salfred fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 825184610Salfred } 826184610Salfred if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 827184610Salfred fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 828184610Salfred } 829184610Salfred fsep->timeout = xfer->timeout; 830184610Salfred 831184610Salfred temp.ep_index = xfer->trIndex; 832184610Salfred 833184610Salfred if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) { 834184610Salfred /* ignore any errors - should never happen */ 835184610Salfred } 836184610Salfred return; /* success */ 837184610Salfred} 838184610Salfred 839184610Salfredstatic void 840184610Salfredugen20_tr_cancel_async(struct libusb20_transfer *xfer) 841184610Salfred{ 842185087Salfred struct usb2_fs_stop temp; 843184610Salfred 844185087Salfred memset(&temp, 0, sizeof(temp)); 845185087Salfred 846184610Salfred temp.ep_index = xfer->trIndex; 847184610Salfred 848184610Salfred if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) { 849184610Salfred /* ignore any errors - should never happen */ 850184610Salfred } 851184610Salfred return; 852184610Salfred} 853184610Salfred 854184610Salfredstatic int 855184610Salfredugen20_be_ioctl(uint32_t cmd, void *data) 856184610Salfred{ 857184610Salfred int f; 858185087Salfred int error; 859184610Salfred 860189110Sthompsa f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 861184610Salfred if (f < 0) 862184610Salfred return (LIBUSB20_ERROR_OTHER); 863185087Salfred error = ioctl(f, cmd, data); 864185087Salfred if (error == -1) { 865184610Salfred if (errno == EPERM) { 866185087Salfred error = LIBUSB20_ERROR_ACCESS; 867184610Salfred } else { 868185087Salfred error = LIBUSB20_ERROR_OTHER; 869184610Salfred } 870184610Salfred } 871184610Salfred close(f); 872185087Salfred return (error); 873184610Salfred} 874184610Salfred 875184610Salfredstatic int 876188622Sthompsaugen20_dev_get_iface_desc(struct libusb20_device *pdev, 877188622Sthompsa uint8_t iface_index, char *buf, uint8_t len) 878188622Sthompsa{ 879188622Sthompsa struct usb2_gen_descriptor ugd; 880188622Sthompsa 881188622Sthompsa memset(&ugd, 0, sizeof(ugd)); 882188622Sthompsa 883188622Sthompsa ugd.ugd_data = buf; 884188622Sthompsa ugd.ugd_maxlen = len; 885188622Sthompsa ugd.ugd_iface_index = iface_index; 886188622Sthompsa 887188622Sthompsa if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) { 888188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 889188622Sthompsa } 890188622Sthompsa return (0); 891188622Sthompsa} 892188622Sthompsa 893188622Sthompsastatic int 894188622Sthompsaugen20_dev_get_info(struct libusb20_device *pdev, 895188622Sthompsa struct usb2_device_info *pinfo) 896188622Sthompsa{ 897188622Sthompsa if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) { 898188622Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 899188622Sthompsa } 900188622Sthompsa return (0); 901188622Sthompsa} 902188622Sthompsa 903188622Sthompsastatic int 904184610Salfredugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 905185087Salfred uint16_t quirk_index, struct libusb20_quirk *pq) 906184610Salfred{ 907184610Salfred struct usb2_gen_quirk q; 908185087Salfred int error; 909184610Salfred 910184610Salfred memset(&q, 0, sizeof(q)); 911184610Salfred 912185087Salfred q.index = quirk_index; 913184610Salfred 914185087Salfred error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q); 915184610Salfred 916185087Salfred if (error) { 917184610Salfred if (errno == EINVAL) { 918184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 919184610Salfred } 920184610Salfred } else { 921184610Salfred pq->vid = q.vid; 922184610Salfred pq->pid = q.pid; 923184610Salfred pq->bcdDeviceLow = q.bcdDeviceLow; 924184610Salfred pq->bcdDeviceHigh = q.bcdDeviceHigh; 925184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 926184610Salfred } 927185087Salfred return (error); 928184610Salfred} 929184610Salfred 930184610Salfredstatic int 931185087Salfredugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 932184610Salfred struct libusb20_quirk *pq) 933184610Salfred{ 934184610Salfred struct usb2_gen_quirk q; 935185087Salfred int error; 936184610Salfred 937184610Salfred memset(&q, 0, sizeof(q)); 938184610Salfred 939185087Salfred q.index = quirk_index; 940184610Salfred 941185087Salfred error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q); 942184610Salfred 943185087Salfred if (error) { 944184610Salfred if (errno == EINVAL) { 945184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 946184610Salfred } 947184610Salfred } else { 948184610Salfred strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 949184610Salfred } 950185087Salfred return (error); 951184610Salfred} 952184610Salfred 953184610Salfredstatic int 954184610Salfredugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 955184610Salfred struct libusb20_quirk *pq) 956184610Salfred{ 957184610Salfred struct usb2_gen_quirk q; 958185087Salfred int error; 959184610Salfred 960184610Salfred memset(&q, 0, sizeof(q)); 961184610Salfred 962184610Salfred q.vid = pq->vid; 963184610Salfred q.pid = pq->pid; 964184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 965184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 966184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 967184610Salfred 968185087Salfred error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q); 969185087Salfred if (error) { 970184610Salfred if (errno == ENOMEM) { 971184610Salfred return (LIBUSB20_ERROR_NO_MEM); 972184610Salfred } 973184610Salfred } 974185087Salfred return (error); 975184610Salfred} 976184610Salfred 977184610Salfredstatic int 978184610Salfredugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 979184610Salfred struct libusb20_quirk *pq) 980184610Salfred{ 981184610Salfred struct usb2_gen_quirk q; 982185087Salfred int error; 983184610Salfred 984184610Salfred memset(&q, 0, sizeof(q)); 985184610Salfred 986184610Salfred q.vid = pq->vid; 987184610Salfred q.pid = pq->pid; 988184610Salfred q.bcdDeviceLow = pq->bcdDeviceLow; 989184610Salfred q.bcdDeviceHigh = pq->bcdDeviceHigh; 990184610Salfred strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 991184610Salfred 992185087Salfred error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q); 993185087Salfred if (error) { 994184610Salfred if (errno == EINVAL) { 995184610Salfred return (LIBUSB20_ERROR_NOT_FOUND); 996184610Salfred } 997184610Salfred } 998185087Salfred return (error); 999184610Salfred} 1000184610Salfred 1001184610Salfredstatic int 1002188987Sthompsaugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1003188987Sthompsa{ 1004188987Sthompsa return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp)); 1005188987Sthompsa} 1006188987Sthompsa 1007188987Sthompsastatic int 1008188987Sthompsaugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1009188987Sthompsa{ 1010188987Sthompsa return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp)); 1011188987Sthompsa} 1012