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