libusb20_ugen20.c revision 188945
1/* $FreeBSD: head/lib/libusb20/libusb20_ugen20.c 188945 2009-02-23 18:36:54Z thompsa $ */ 2/*- 3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/queue.h> 28#include <sys/types.h> 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <unistd.h> 33#include <string.h> 34#include <poll.h> 35#include <fcntl.h> 36#include <errno.h> 37 38#include "libusb20.h" 39#include "libusb20_desc.h" 40#include "libusb20_int.h" 41 42#include <dev/usb/usb.h> 43#include <dev/usb/usb_ioctl.h> 44#include <dev/usb/usb_mfunc.h> 45#include <dev/usb/usb_error.h> 46#include <dev/usb/usb_revision.h> 47 48static libusb20_init_backend_t ugen20_init_backend; 49static libusb20_open_device_t ugen20_open_device; 50static libusb20_close_device_t ugen20_close_device; 51static libusb20_get_backend_name_t ugen20_get_backend_name; 52static libusb20_exit_backend_t ugen20_exit_backend; 53static libusb20_bus_set_owner_t ugen20_bus_set_owner; 54static libusb20_bus_get_owner_t ugen20_bus_get_owner; 55static libusb20_bus_set_perm_t ugen20_bus_set_perm; 56static libusb20_bus_get_perm_t ugen20_bus_get_perm; 57static libusb20_dev_get_iface_owner_t ugen20_dev_get_iface_owner; 58static libusb20_dev_get_iface_perm_t ugen20_dev_get_iface_perm; 59static libusb20_dev_get_owner_t ugen20_dev_get_owner; 60static libusb20_dev_get_perm_t ugen20_dev_get_perm; 61static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc; 62static libusb20_dev_get_info_t ugen20_dev_get_info; 63static libusb20_dev_set_iface_owner_t ugen20_dev_set_iface_owner; 64static libusb20_dev_set_iface_perm_t ugen20_dev_set_iface_perm; 65static libusb20_dev_set_owner_t ugen20_dev_set_owner; 66static libusb20_dev_set_perm_t ugen20_dev_set_perm; 67static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk; 68static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name; 69static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk; 70static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk; 71static libusb20_root_set_owner_t ugen20_root_set_owner; 72static libusb20_root_get_owner_t ugen20_root_get_owner; 73static libusb20_root_set_perm_t ugen20_root_set_perm; 74static libusb20_root_get_perm_t ugen20_root_get_perm; 75 76const struct libusb20_backend_methods libusb20_ugen20_backend = { 77 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20) 78}; 79 80/* USB device specific */ 81static libusb20_get_config_desc_full_t ugen20_get_config_desc_full; 82static libusb20_get_config_index_t ugen20_get_config_index; 83static libusb20_set_config_index_t ugen20_set_config_index; 84static libusb20_claim_interface_t ugen20_claim_interface; 85static libusb20_release_interface_t ugen20_release_interface; 86static libusb20_set_alt_index_t ugen20_set_alt_index; 87static libusb20_reset_device_t ugen20_reset_device; 88static libusb20_set_power_mode_t ugen20_set_power_mode; 89static libusb20_get_power_mode_t ugen20_get_power_mode; 90static libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 91static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 92static libusb20_do_request_sync_t ugen20_do_request_sync; 93static libusb20_process_t ugen20_process; 94 95/* USB transfer specific */ 96static libusb20_tr_open_t ugen20_tr_open; 97static libusb20_tr_close_t ugen20_tr_close; 98static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 99static libusb20_tr_submit_t ugen20_tr_submit; 100static libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 101 102static const struct libusb20_device_methods libusb20_ugen20_device_methods = { 103 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 104}; 105 106static const char * 107ugen20_get_backend_name(void) 108{ 109 return ("FreeBSD UGEN 2.0"); 110} 111 112static uint32_t 113ugen20_path_convert_one(const char **pp) 114{ 115 const char *ptr; 116 uint32_t temp = 0; 117 118 ptr = *pp; 119 120 while ((*ptr >= '0') && (*ptr <= '9')) { 121 temp *= 10; 122 temp += (*ptr - '0'); 123 if (temp >= 1000000) { 124 /* catch overflow early */ 125 return (0 - 1); 126 } 127 ptr++; 128 } 129 130 if (*ptr == '.') { 131 /* skip dot */ 132 ptr++; 133 } 134 *pp = ptr; 135 136 return (temp); 137} 138 139static int 140ugen20_enumerate(struct libusb20_device *pdev, const char *id) 141{ 142 const char *tmp = id; 143 struct usb2_device_descriptor ddesc; 144 struct usb2_device_info devinfo; 145 uint32_t plugtime; 146 char buf[64]; 147 int f; 148 int error; 149 150 pdev->bus_number = ugen20_path_convert_one(&tmp); 151 pdev->device_address = ugen20_path_convert_one(&tmp); 152 153 snprintf(buf, sizeof(buf), "/dev/ugen%u.%u", 154 pdev->bus_number, pdev->device_address); 155 156 f = open(buf, O_RDWR); 157 if (f < 0) { 158 return (LIBUSB20_ERROR_OTHER); 159 } 160 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 161 error = LIBUSB20_ERROR_OTHER; 162 goto done; 163 } 164 /* store when the device was plugged */ 165 pdev->session_data.plugtime = plugtime; 166 167 if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) { 168 error = LIBUSB20_ERROR_OTHER; 169 goto done; 170 } 171 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 172 173 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 174 175 if (pdev->ddesc.bNumConfigurations == 0) { 176 error = LIBUSB20_ERROR_OTHER; 177 goto done; 178 } else if (pdev->ddesc.bNumConfigurations >= 8) { 179 error = LIBUSB20_ERROR_OTHER; 180 goto done; 181 } 182 if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) { 183 error = LIBUSB20_ERROR_OTHER; 184 goto done; 185 } 186 switch (devinfo.udi_mode) { 187 case USB_MODE_DEVICE: 188 pdev->usb_mode = LIBUSB20_MODE_DEVICE; 189 break; 190 default: 191 pdev->usb_mode = LIBUSB20_MODE_HOST; 192 break; 193 } 194 195 switch (devinfo.udi_speed) { 196 case USB_SPEED_LOW: 197 pdev->usb_speed = LIBUSB20_SPEED_LOW; 198 break; 199 case USB_SPEED_FULL: 200 pdev->usb_speed = LIBUSB20_SPEED_FULL; 201 break; 202 case USB_SPEED_HIGH: 203 pdev->usb_speed = LIBUSB20_SPEED_HIGH; 204 break; 205 case USB_SPEED_VARIABLE: 206 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 207 break; 208 case USB_SPEED_SUPER: 209 pdev->usb_speed = LIBUSB20_SPEED_SUPER; 210 break; 211 default: 212 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 213 break; 214 } 215 216 /* generate a nice description for printout */ 217 218 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 219 "ugen%u.%u: <%s %s> at usbus%u", pdev->bus_number, 220 pdev->device_address, devinfo.udi_product, 221 devinfo.udi_vendor, pdev->bus_number); 222 223 error = 0; 224done: 225 close(f); 226 return (error); 227} 228 229struct ugen20_urd_state { 230 struct usb2_read_dir urd; 231 uint32_t nparsed; 232 int f; 233 uint8_t *ptr; 234 const char *src; 235 const char *dst; 236 uint8_t buf[256]; 237 uint8_t dummy_zero[1]; 238}; 239 240static int 241ugen20_readdir(struct ugen20_urd_state *st) 242{ 243 ; /* style fix */ 244repeat: 245 if (st->ptr == NULL) { 246 st->urd.urd_startentry += st->nparsed; 247 st->urd.urd_data = st->buf; 248 st->urd.urd_maxlen = sizeof(st->buf); 249 st->nparsed = 0; 250 251 if (ioctl(st->f, USB_READ_DIR, &st->urd)) { 252 return (EINVAL); 253 } 254 st->ptr = st->buf; 255 } 256 if (st->ptr[0] == 0) { 257 if (st->nparsed) { 258 st->ptr = NULL; 259 goto repeat; 260 } else { 261 return (ENXIO); 262 } 263 } 264 st->src = (void *)(st->ptr + 1); 265 st->dst = st->src + strlen(st->src) + 1; 266 st->ptr = st->ptr + st->ptr[0]; 267 st->nparsed++; 268 269 if ((st->ptr < st->buf) || 270 (st->ptr > st->dummy_zero)) { 271 /* invalid entry */ 272 return (EINVAL); 273 } 274 return (0); 275} 276 277static int 278ugen20_init_backend(struct libusb20_backend *pbe) 279{ 280 struct ugen20_urd_state state; 281 struct libusb20_device *pdev; 282 283 memset(&state, 0, sizeof(state)); 284 285 state.f = open("/dev/usb", O_RDONLY); 286 if (state.f < 0) 287 return (LIBUSB20_ERROR_OTHER); 288 289 while (ugen20_readdir(&state) == 0) { 290 291 if ((state.src[0] != 'u') || 292 (state.src[1] != 'g') || 293 (state.src[2] != 'e') || 294 (state.src[3] != 'n')) { 295 continue; 296 } 297 pdev = libusb20_dev_alloc(); 298 if (pdev == NULL) { 299 continue; 300 } 301 if (ugen20_enumerate(pdev, state.src + 4)) { 302 libusb20_dev_free(pdev); 303 continue; 304 } 305 /* put the device on the backend list */ 306 libusb20_be_enqueue_device(pbe, pdev); 307 } 308 close(state.f); 309 return (0); /* success */ 310} 311 312static void 313ugen20_tr_release(struct libusb20_device *pdev) 314{ 315 struct usb2_fs_uninit fs_uninit; 316 317 if (pdev->nTransfer == 0) { 318 return; 319 } 320 /* release all pending USB transfers */ 321 if (pdev->privBeData != NULL) { 322 memset(&fs_uninit, 0, sizeof(fs_uninit)); 323 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 324 /* ignore any errors of this kind */ 325 } 326 } 327 return; 328} 329 330static int 331ugen20_tr_renew(struct libusb20_device *pdev) 332{ 333 struct usb2_fs_init fs_init; 334 struct usb2_fs_endpoint *pfse; 335 int error; 336 uint32_t size; 337 uint16_t nMaxTransfer; 338 339 nMaxTransfer = pdev->nTransfer; 340 error = 0; 341 342 if (nMaxTransfer == 0) { 343 goto done; 344 } 345 size = nMaxTransfer * sizeof(*pfse); 346 347 if (pdev->privBeData == NULL) { 348 pfse = malloc(size); 349 if (pfse == NULL) { 350 error = LIBUSB20_ERROR_NO_MEM; 351 goto done; 352 } 353 pdev->privBeData = pfse; 354 } 355 /* reset endpoint data */ 356 memset(pdev->privBeData, 0, size); 357 358 memset(&fs_init, 0, sizeof(fs_init)); 359 360 fs_init.pEndpoints = pdev->privBeData; 361 fs_init.ep_index_max = nMaxTransfer; 362 363 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) { 364 error = LIBUSB20_ERROR_OTHER; 365 goto done; 366 } 367done: 368 return (error); 369} 370 371static int 372ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 373{ 374 uint32_t plugtime; 375 char buf[64]; 376 int f; 377 int g; 378 int error; 379 380 snprintf(buf, sizeof(buf), "/dev/ugen%u.%u", 381 pdev->bus_number, pdev->device_address); 382 383 /* 384 * We need two file handles, one for the control endpoint and one 385 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 386 * kernel locking. 387 */ 388 g = open(buf, O_RDWR); 389 if (g < 0) { 390 return (LIBUSB20_ERROR_NO_DEVICE); 391 } 392 f = open(buf, O_RDWR); 393 if (f < 0) { 394 close(g); 395 return (LIBUSB20_ERROR_NO_DEVICE); 396 } 397 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 398 error = LIBUSB20_ERROR_OTHER; 399 goto done; 400 } 401 /* check that the correct device is still plugged */ 402 if (pdev->session_data.plugtime != plugtime) { 403 error = LIBUSB20_ERROR_NO_DEVICE; 404 goto done; 405 } 406 /* need to set this before "tr_renew()" */ 407 pdev->file = f; 408 pdev->file_ctrl = g; 409 410 /* renew all USB transfers */ 411 error = ugen20_tr_renew(pdev); 412 if (error) { 413 goto done; 414 } 415 /* set methods */ 416 pdev->methods = &libusb20_ugen20_device_methods; 417 418done: 419 if (error) { 420 if (pdev->privBeData) { 421 /* cleanup after "tr_renew()" */ 422 free(pdev->privBeData); 423 pdev->privBeData = NULL; 424 } 425 pdev->file = -1; 426 pdev->file_ctrl = -1; 427 close(f); 428 close(g); 429 } 430 return (error); 431} 432 433static int 434ugen20_close_device(struct libusb20_device *pdev) 435{ 436 struct usb2_fs_uninit fs_uninit; 437 438 if (pdev->privBeData) { 439 memset(&fs_uninit, 0, sizeof(fs_uninit)); 440 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 441 /* ignore this error */ 442 } 443 free(pdev->privBeData); 444 } 445 pdev->nTransfer = 0; 446 pdev->privBeData = NULL; 447 close(pdev->file); 448 close(pdev->file_ctrl); 449 pdev->file = -1; 450 pdev->file_ctrl = -1; 451 return (0); /* success */ 452} 453 454static void 455ugen20_exit_backend(struct libusb20_backend *pbe) 456{ 457 return; /* nothing to do */ 458} 459 460static int 461ugen20_get_config_desc_full(struct libusb20_device *pdev, 462 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 463{ 464 struct usb2_gen_descriptor gen_desc; 465 struct usb2_config_descriptor cdesc; 466 uint8_t *ptr; 467 uint16_t len; 468 int error; 469 470 memset(&gen_desc, 0, sizeof(gen_desc)); 471 472 gen_desc.ugd_data = &cdesc; 473 gen_desc.ugd_maxlen = sizeof(cdesc); 474 gen_desc.ugd_config_index = cfg_index; 475 476 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 477 if (error) { 478 return (LIBUSB20_ERROR_OTHER); 479 } 480 len = UGETW(cdesc.wTotalLength); 481 if (len < sizeof(cdesc)) { 482 /* corrupt descriptor */ 483 return (LIBUSB20_ERROR_OTHER); 484 } 485 ptr = malloc(len); 486 if (!ptr) { 487 return (LIBUSB20_ERROR_NO_MEM); 488 } 489 gen_desc.ugd_data = ptr; 490 gen_desc.ugd_maxlen = len; 491 492 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 493 if (error) { 494 free(ptr); 495 return (LIBUSB20_ERROR_OTHER); 496 } 497 /* make sure that the device doesn't fool us */ 498 memcpy(ptr, &cdesc, sizeof(cdesc)); 499 500 *ppbuf = ptr; 501 *plen = len; 502 503 return (0); /* success */ 504} 505 506static int 507ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 508{ 509 int temp; 510 511 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) { 512 return (LIBUSB20_ERROR_OTHER); 513 } 514 *pindex = temp; 515 516 return (0); 517} 518 519static int 520ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 521{ 522 int temp = cfg_index; 523 524 /* release all active USB transfers */ 525 ugen20_tr_release(pdev); 526 527 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) { 528 return (LIBUSB20_ERROR_OTHER); 529 } 530 return (ugen20_tr_renew(pdev)); 531} 532 533static int 534ugen20_claim_interface(struct libusb20_device *pdev, uint8_t iface_index) 535{ 536 int temp = iface_index; 537 538 if (ioctl(pdev->file_ctrl, USB_CLAIM_INTERFACE, &temp)) { 539 return (LIBUSB20_ERROR_OTHER); 540 } 541 return (0); 542} 543 544static int 545ugen20_release_interface(struct libusb20_device *pdev, uint8_t iface_index) 546{ 547 int temp = iface_index; 548 549 if (ioctl(pdev->file_ctrl, USB_RELEASE_INTERFACE, &temp)) { 550 return (LIBUSB20_ERROR_OTHER); 551 } 552 return (0); 553} 554 555static int 556ugen20_set_alt_index(struct libusb20_device *pdev, 557 uint8_t iface_index, uint8_t alt_index) 558{ 559 struct usb2_alt_interface alt_iface; 560 561 memset(&alt_iface, 0, sizeof(alt_iface)); 562 563 alt_iface.uai_interface_index = iface_index; 564 alt_iface.uai_alt_index = alt_index; 565 566 /* release all active USB transfers */ 567 ugen20_tr_release(pdev); 568 569 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) { 570 return (LIBUSB20_ERROR_OTHER); 571 } 572 return (ugen20_tr_renew(pdev)); 573} 574 575static int 576ugen20_reset_device(struct libusb20_device *pdev) 577{ 578 int temp = 0; 579 580 /* release all active USB transfers */ 581 ugen20_tr_release(pdev); 582 583 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) { 584 return (LIBUSB20_ERROR_OTHER); 585 } 586 return (ugen20_tr_renew(pdev)); 587} 588 589static int 590ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 591{ 592 int temp; 593 594 switch (power_mode) { 595 case LIBUSB20_POWER_OFF: 596 temp = USB_POWER_MODE_OFF; 597 break; 598 case LIBUSB20_POWER_ON: 599 temp = USB_POWER_MODE_ON; 600 break; 601 case LIBUSB20_POWER_SAVE: 602 temp = USB_POWER_MODE_SAVE; 603 break; 604 case LIBUSB20_POWER_SUSPEND: 605 temp = USB_POWER_MODE_SUSPEND; 606 break; 607 case LIBUSB20_POWER_RESUME: 608 temp = USB_POWER_MODE_RESUME; 609 break; 610 default: 611 return (LIBUSB20_ERROR_INVALID_PARAM); 612 } 613 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) { 614 return (LIBUSB20_ERROR_OTHER); 615 } 616 return (0); 617} 618 619static int 620ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 621{ 622 int temp; 623 624 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) { 625 return (LIBUSB20_ERROR_OTHER); 626 } 627 switch (temp) { 628 case USB_POWER_MODE_OFF: 629 temp = LIBUSB20_POWER_OFF; 630 break; 631 case USB_POWER_MODE_ON: 632 temp = LIBUSB20_POWER_ON; 633 break; 634 case USB_POWER_MODE_SAVE: 635 temp = LIBUSB20_POWER_SAVE; 636 break; 637 case USB_POWER_MODE_SUSPEND: 638 temp = LIBUSB20_POWER_SUSPEND; 639 break; 640 case USB_POWER_MODE_RESUME: 641 temp = LIBUSB20_POWER_RESUME; 642 break; 643 default: 644 temp = LIBUSB20_POWER_ON; 645 break; 646 } 647 *power_mode = temp; 648 return (0); /* success */ 649} 650 651static int 652ugen20_kernel_driver_active(struct libusb20_device *pdev, 653 uint8_t iface_index) 654{ 655 int temp = iface_index; 656 657 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) { 658 return (LIBUSB20_ERROR_OTHER); 659 } 660 return (0); /* kernel driver is active */ 661} 662 663static int 664ugen20_detach_kernel_driver(struct libusb20_device *pdev, 665 uint8_t iface_index) 666{ 667 int temp = iface_index; 668 669 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) { 670 return (LIBUSB20_ERROR_OTHER); 671 } 672 return (0); /* kernel driver is active */ 673} 674 675static int 676ugen20_do_request_sync(struct libusb20_device *pdev, 677 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 678 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 679{ 680 struct usb2_ctl_request req; 681 682 memset(&req, 0, sizeof(req)); 683 684 req.ucr_data = data; 685 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 686 req.ucr_flags |= USB_SHORT_XFER_OK; 687 } 688 if (libusb20_me_encode(&req.ucr_request, 689 sizeof(req.ucr_request), setup)) { 690 /* ignore */ 691 } 692 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) { 693 return (LIBUSB20_ERROR_OTHER); 694 } 695 if (pactlen) { 696 /* get actual length */ 697 *pactlen = req.ucr_actlen; 698 } 699 return (0); /* kernel driver is active */ 700} 701 702static int 703ugen20_process(struct libusb20_device *pdev) 704{ 705 struct usb2_fs_complete temp; 706 struct usb2_fs_endpoint *fsep; 707 struct libusb20_transfer *xfer; 708 709 while (1) { 710 711 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) { 712 if (errno == EBUSY) { 713 break; 714 } else { 715 /* device detached */ 716 return (LIBUSB20_ERROR_OTHER); 717 } 718 } 719 fsep = pdev->privBeData; 720 xfer = pdev->pTransfer; 721 fsep += temp.ep_index; 722 xfer += temp.ep_index; 723 724 /* update transfer status */ 725 726 if (fsep->status == 0) { 727 xfer->aFrames = fsep->aFrames; 728 xfer->timeComplete = fsep->isoc_time_complete; 729 xfer->status = LIBUSB20_TRANSFER_COMPLETED; 730 } else if (fsep->status == USB_ERR_CANCELLED) { 731 xfer->aFrames = 0; 732 xfer->timeComplete = 0; 733 xfer->status = LIBUSB20_TRANSFER_CANCELLED; 734 } else if (fsep->status == USB_ERR_STALLED) { 735 xfer->aFrames = 0; 736 xfer->timeComplete = 0; 737 xfer->status = LIBUSB20_TRANSFER_STALL; 738 } else if (fsep->status == USB_ERR_TIMEOUT) { 739 xfer->aFrames = 0; 740 xfer->timeComplete = 0; 741 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 742 } else { 743 xfer->aFrames = 0; 744 xfer->timeComplete = 0; 745 xfer->status = LIBUSB20_TRANSFER_ERROR; 746 } 747 libusb20_tr_callback_wrapper(xfer); 748 } 749 return (0); /* done */ 750} 751 752static int 753ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 754 uint32_t MaxFrameCount, uint8_t ep_no) 755{ 756 struct usb2_fs_open temp; 757 struct usb2_fs_endpoint *fsep; 758 759 memset(&temp, 0, sizeof(temp)); 760 761 fsep = xfer->pdev->privBeData; 762 fsep += xfer->trIndex; 763 764 temp.max_bufsize = MaxBufSize; 765 temp.max_frames = MaxFrameCount; 766 temp.ep_index = xfer->trIndex; 767 temp.ep_no = ep_no; 768 769 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) { 770 return (LIBUSB20_ERROR_INVALID_PARAM); 771 } 772 /* maximums might have changed - update */ 773 xfer->maxFrames = temp.max_frames; 774 775 /* "max_bufsize" should be multiple of "max_packet_length" */ 776 xfer->maxTotalLength = temp.max_bufsize; 777 xfer->maxPacketLen = temp.max_packet_length; 778 779 /* setup buffer and length lists */ 780 fsep->ppBuffer = xfer->ppBuffer;/* zero copy */ 781 fsep->pLength = xfer->pLength; /* zero copy */ 782 783 return (0); /* success */ 784} 785 786static int 787ugen20_tr_close(struct libusb20_transfer *xfer) 788{ 789 struct usb2_fs_close temp; 790 791 memset(&temp, 0, sizeof(temp)); 792 793 temp.ep_index = xfer->trIndex; 794 795 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) { 796 return (LIBUSB20_ERROR_INVALID_PARAM); 797 } 798 return (0); /* success */ 799} 800 801static int 802ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 803{ 804 struct usb2_fs_clear_stall_sync temp; 805 806 memset(&temp, 0, sizeof(temp)); 807 808 /* if the transfer is active, an error will be returned */ 809 810 temp.ep_index = xfer->trIndex; 811 812 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) { 813 return (LIBUSB20_ERROR_INVALID_PARAM); 814 } 815 return (0); /* success */ 816} 817 818static void 819ugen20_tr_submit(struct libusb20_transfer *xfer) 820{ 821 struct usb2_fs_start temp; 822 struct usb2_fs_endpoint *fsep; 823 824 memset(&temp, 0, sizeof(temp)); 825 826 fsep = xfer->pdev->privBeData; 827 fsep += xfer->trIndex; 828 829 fsep->nFrames = xfer->nFrames; 830 fsep->flags = 0; 831 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 832 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 833 } 834 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 835 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 836 } 837 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 838 fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 839 } 840 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 841 fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 842 } 843 fsep->timeout = xfer->timeout; 844 845 temp.ep_index = xfer->trIndex; 846 847 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) { 848 /* ignore any errors - should never happen */ 849 } 850 return; /* success */ 851} 852 853static void 854ugen20_tr_cancel_async(struct libusb20_transfer *xfer) 855{ 856 struct usb2_fs_stop temp; 857 858 memset(&temp, 0, sizeof(temp)); 859 860 temp.ep_index = xfer->trIndex; 861 862 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) { 863 /* ignore any errors - should never happen */ 864 } 865 return; 866} 867 868static int 869ugen20_be_ioctl(uint32_t cmd, void *data) 870{ 871 int f; 872 int error; 873 874 f = open("/dev/usb", O_RDONLY); 875 if (f < 0) 876 return (LIBUSB20_ERROR_OTHER); 877 error = ioctl(f, cmd, data); 878 if (error == -1) { 879 if (errno == EPERM) { 880 error = LIBUSB20_ERROR_ACCESS; 881 } else { 882 error = LIBUSB20_ERROR_OTHER; 883 } 884 } 885 close(f); 886 return (error); 887} 888 889static int 890ugen20_be_do_perm(uint32_t get_cmd, uint32_t set_cmd, uint8_t bus, 891 uint8_t dev, uint8_t iface, uid_t *uid, 892 gid_t *gid, mode_t *mode) 893{ 894 struct usb2_dev_perm perm; 895 int error; 896 897 memset(&perm, 0, sizeof(perm)); 898 899 perm.bus_index = bus; 900 perm.dev_index = dev; 901 perm.iface_index = iface; 902 903 error = ugen20_be_ioctl(get_cmd, &perm); 904 if (error) 905 return (error); 906 907 if (set_cmd == 0) { 908 if (uid) 909 *uid = perm.user_id; 910 if (gid) 911 *gid = perm.group_id; 912 if (mode) 913 *mode = perm.mode; 914 return (0); 915 } 916 if (uid) 917 perm.user_id = *uid; 918 if (gid) 919 perm.group_id = *gid; 920 if (mode) 921 perm.mode = *mode; 922 923 return (ugen20_be_ioctl(set_cmd, &perm)); 924} 925 926static int 927ugen20_bus_set_owner(struct libusb20_backend *pbe, 928 uint8_t bus, uid_t user, gid_t group) 929{ 930 return (ugen20_be_do_perm(USB_GET_BUS_PERM, USB_SET_BUS_PERM, 931 bus, 0, 0, &user, &group, NULL)); 932} 933 934static int 935ugen20_bus_get_owner(struct libusb20_backend *pbe, uint8_t bus, 936 uid_t *user, gid_t *group) 937{ 938 return (ugen20_be_do_perm(USB_GET_BUS_PERM, 0, 939 bus, 0, 0, user, group, NULL)); 940} 941 942static int 943ugen20_bus_set_perm(struct libusb20_backend *pbe, 944 uint8_t bus, mode_t mode) 945{ 946 return (ugen20_be_do_perm(USB_GET_BUS_PERM, USB_SET_BUS_PERM, 947 bus, 0, 0, NULL, NULL, &mode)); 948} 949 950static int 951ugen20_bus_get_perm(struct libusb20_backend *pbe, 952 uint8_t bus, mode_t *mode) 953{ 954 return (ugen20_be_do_perm(USB_GET_BUS_PERM, 0, 955 bus, 0, 0, NULL, NULL, mode)); 956} 957 958static int 959ugen20_dev_get_iface_desc(struct libusb20_device *pdev, 960 uint8_t iface_index, char *buf, uint8_t len) 961{ 962 struct usb2_gen_descriptor ugd; 963 964 memset(&ugd, 0, sizeof(ugd)); 965 966 ugd.ugd_data = buf; 967 ugd.ugd_maxlen = len; 968 ugd.ugd_iface_index = iface_index; 969 970 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) { 971 return (LIBUSB20_ERROR_INVALID_PARAM); 972 } 973 return (0); 974} 975 976static int 977ugen20_dev_get_info(struct libusb20_device *pdev, 978 struct usb2_device_info *pinfo) 979{ 980 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) { 981 return (LIBUSB20_ERROR_INVALID_PARAM); 982 } 983 return (0); 984} 985 986static int 987ugen20_dev_get_iface_owner(struct libusb20_device *pdev, 988 uint8_t iface_index, uid_t *user, gid_t *group) 989{ 990 return (ugen20_be_do_perm(USB_GET_IFACE_PERM, 0, 991 pdev->bus_number, pdev->device_address, iface_index, 992 user, group, NULL)); 993} 994 995static int 996ugen20_dev_get_iface_perm(struct libusb20_device *pdev, 997 uint8_t iface_index, mode_t *mode) 998{ 999 return (ugen20_be_do_perm(USB_GET_IFACE_PERM, 0, 1000 pdev->bus_number, pdev->device_address, iface_index, 1001 NULL, NULL, mode)); 1002} 1003 1004static int 1005ugen20_dev_get_owner(struct libusb20_device *pdev, 1006 uid_t *user, gid_t *group) 1007{ 1008 return (ugen20_be_do_perm(USB_GET_DEVICE_PERM, 0, 1009 pdev->bus_number, pdev->device_address, 0, 1010 user, group, NULL)); 1011} 1012 1013static int 1014ugen20_dev_get_perm(struct libusb20_device *pdev, mode_t *mode) 1015{ 1016 return (ugen20_be_do_perm(USB_GET_DEVICE_PERM, 0, 1017 pdev->bus_number, pdev->device_address, 0, 1018 NULL, NULL, mode)); 1019} 1020 1021static int 1022ugen20_dev_set_iface_owner(struct libusb20_device *pdev, 1023 uint8_t iface_index, uid_t user, gid_t group) 1024{ 1025 return (ugen20_be_do_perm(USB_GET_IFACE_PERM, USB_SET_IFACE_PERM, 1026 pdev->bus_number, pdev->device_address, iface_index, 1027 &user, &group, NULL)); 1028} 1029 1030static int 1031ugen20_dev_set_iface_perm(struct libusb20_device *pdev, 1032 uint8_t iface_index, mode_t mode) 1033{ 1034 return (ugen20_be_do_perm(USB_GET_IFACE_PERM, USB_SET_IFACE_PERM, 1035 pdev->bus_number, pdev->device_address, iface_index, 1036 NULL, NULL, &mode)); 1037} 1038 1039static int 1040ugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 1041 uint16_t quirk_index, struct libusb20_quirk *pq) 1042{ 1043 struct usb2_gen_quirk q; 1044 int error; 1045 1046 memset(&q, 0, sizeof(q)); 1047 1048 q.index = quirk_index; 1049 1050 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q); 1051 1052 if (error) { 1053 if (errno == EINVAL) { 1054 return (LIBUSB20_ERROR_NOT_FOUND); 1055 } 1056 } else { 1057 pq->vid = q.vid; 1058 pq->pid = q.pid; 1059 pq->bcdDeviceLow = q.bcdDeviceLow; 1060 pq->bcdDeviceHigh = q.bcdDeviceHigh; 1061 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1062 } 1063 return (error); 1064} 1065 1066static int 1067ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 1068 struct libusb20_quirk *pq) 1069{ 1070 struct usb2_gen_quirk q; 1071 int error; 1072 1073 memset(&q, 0, sizeof(q)); 1074 1075 q.index = quirk_index; 1076 1077 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q); 1078 1079 if (error) { 1080 if (errno == EINVAL) { 1081 return (LIBUSB20_ERROR_NOT_FOUND); 1082 } 1083 } else { 1084 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1085 } 1086 return (error); 1087} 1088 1089static int 1090ugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 1091 struct libusb20_quirk *pq) 1092{ 1093 struct usb2_gen_quirk q; 1094 int error; 1095 1096 memset(&q, 0, sizeof(q)); 1097 1098 q.vid = pq->vid; 1099 q.pid = pq->pid; 1100 q.bcdDeviceLow = pq->bcdDeviceLow; 1101 q.bcdDeviceHigh = pq->bcdDeviceHigh; 1102 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1103 1104 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q); 1105 if (error) { 1106 if (errno == ENOMEM) { 1107 return (LIBUSB20_ERROR_NO_MEM); 1108 } 1109 } 1110 return (error); 1111} 1112 1113static int 1114ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 1115 struct libusb20_quirk *pq) 1116{ 1117 struct usb2_gen_quirk q; 1118 int error; 1119 1120 memset(&q, 0, sizeof(q)); 1121 1122 q.vid = pq->vid; 1123 q.pid = pq->pid; 1124 q.bcdDeviceLow = pq->bcdDeviceLow; 1125 q.bcdDeviceHigh = pq->bcdDeviceHigh; 1126 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1127 1128 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q); 1129 if (error) { 1130 if (errno == EINVAL) { 1131 return (LIBUSB20_ERROR_NOT_FOUND); 1132 } 1133 } 1134 return (error); 1135} 1136 1137static int 1138ugen20_dev_set_owner(struct libusb20_device *pdev, 1139 uid_t user, gid_t group) 1140{ 1141 return (ugen20_be_do_perm(USB_GET_DEVICE_PERM, USB_SET_DEVICE_PERM, 1142 pdev->bus_number, pdev->device_address, 0, 1143 &user, &group, NULL)); 1144} 1145 1146static int 1147ugen20_dev_set_perm(struct libusb20_device *pdev, mode_t mode) 1148{ 1149 return (ugen20_be_do_perm(USB_GET_DEVICE_PERM, USB_SET_DEVICE_PERM, 1150 pdev->bus_number, pdev->device_address, 0, 1151 NULL, NULL, &mode)); 1152} 1153 1154static int 1155ugen20_root_set_owner(struct libusb20_backend *pbe, 1156 uid_t user, gid_t group) 1157{ 1158 return (ugen20_be_do_perm(USB_GET_ROOT_PERM, USB_SET_ROOT_PERM, 0, 0, 0, 1159 &user, &group, NULL)); 1160} 1161 1162static int 1163ugen20_root_get_owner(struct libusb20_backend *pbe, uid_t *user, gid_t *group) 1164{ 1165 return (ugen20_be_do_perm(USB_GET_ROOT_PERM, 0, 0, 0, 0, 1166 user, group, NULL)); 1167} 1168 1169static int 1170ugen20_root_set_perm(struct libusb20_backend *pbe, mode_t mode) 1171{ 1172 return (ugen20_be_do_perm(USB_GET_ROOT_PERM, USB_SET_ROOT_PERM, 0, 0, 0, 1173 NULL, NULL, &mode)); 1174} 1175 1176static int 1177ugen20_root_get_perm(struct libusb20_backend *pbe, mode_t *mode) 1178{ 1179 return (ugen20_be_do_perm(USB_GET_ROOT_PERM, 0, 0, 0, 0, 1180 NULL, NULL, mode)); 1181} 1182