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