libusb20_ugen20.c revision 203147
171345Sgshapiro/* $FreeBSD: head/lib/libusb/libusb20_ugen20.c 203147 2010-01-29 02:44:06Z thompsa $ */ 271345Sgshapiro/*- 3173340Sgshapiro * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 471345Sgshapiro * 571345Sgshapiro * Redistribution and use in source and binary forms, with or without 671345Sgshapiro * modification, are permitted provided that the following conditions 771345Sgshapiro * are met: 871345Sgshapiro * 1. Redistributions of source code must retain the above copyright 971345Sgshapiro * notice, this list of conditions and the following disclaimer. 1071345Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright 1171345Sgshapiro * notice, this list of conditions and the following disclaimer in the 1271345Sgshapiro * documentation and/or other materials provided with the distribution. 1371345Sgshapiro * 1471345Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1571345Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1671345Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1771345Sgshapiro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1871345Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1971345Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2071345Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2171345Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2271345Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2371345Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2471345Sgshapiro * SUCH DAMAGE. 2571345Sgshapiro */ 2671345Sgshapiro 2771345Sgshapiro#include <sys/queue.h> 2871345Sgshapiro#include <sys/types.h> 2971345Sgshapiro 30266711Sgshapiro#include <stdio.h> 3171345Sgshapiro#include <stdlib.h> 3271345Sgshapiro#include <unistd.h> 3371345Sgshapiro#include <string.h> 3471345Sgshapiro#include <poll.h> 3571345Sgshapiro#include <fcntl.h> 3671345Sgshapiro#include <errno.h> 3771345Sgshapiro 38112810Sgshapiro#include "libusb20.h" 3971345Sgshapiro#include "libusb20_desc.h" 4071345Sgshapiro#include "libusb20_int.h" 4171345Sgshapiro 4271345Sgshapiro#include <dev/usb/usb.h> 4371345Sgshapiro#include <dev/usb/usbdi.h> 4471345Sgshapiro#include <dev/usb/usb_ioctl.h> 4571345Sgshapiro 4671345Sgshapirostatic libusb20_init_backend_t ugen20_init_backend; 4771345Sgshapirostatic libusb20_open_device_t ugen20_open_device; 4873188Sgshapirostatic libusb20_close_device_t ugen20_close_device; 4973188Sgshapirostatic libusb20_get_backend_name_t ugen20_get_backend_name; 5073188Sgshapirostatic libusb20_exit_backend_t ugen20_exit_backend; 5173188Sgshapirostatic libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc; 5271345Sgshapirostatic libusb20_dev_get_info_t ugen20_dev_get_info; 5394334Sgshapirostatic libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk; 5494334Sgshapirostatic libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name; 5594334Sgshapirostatic libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk; 56112810Sgshapirostatic libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk; 57112810Sgshapirostatic libusb20_root_set_template_t ugen20_root_set_template; 58112810Sgshapirostatic libusb20_root_get_template_t ugen20_root_get_template; 5971345Sgshapiro 6071345Sgshapiroconst struct libusb20_backend_methods libusb20_ugen20_backend = { 6171345Sgshapiro LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20) 6271345Sgshapiro}; 6371345Sgshapiro 6471345Sgshapiro/* USB device specific */ 6571345Sgshapirostatic libusb20_get_config_desc_full_t ugen20_get_config_desc_full; 6671345Sgshapirostatic libusb20_get_config_index_t ugen20_get_config_index; 6771345Sgshapirostatic libusb20_set_config_index_t ugen20_set_config_index; 6871345Sgshapirostatic libusb20_set_alt_index_t ugen20_set_alt_index; 6971345Sgshapirostatic libusb20_reset_device_t ugen20_reset_device; 7071345Sgshapirostatic libusb20_check_connected_t ugen20_check_connected; 7171345Sgshapirostatic libusb20_set_power_mode_t ugen20_set_power_mode; 7271345Sgshapirostatic libusb20_get_power_mode_t ugen20_get_power_mode; 73173340Sgshapirostatic libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 7471345Sgshapirostatic libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 75173340Sgshapirostatic libusb20_do_request_sync_t ugen20_do_request_sync; 7671345Sgshapirostatic libusb20_process_t ugen20_process; 7771345Sgshapiro 78173340Sgshapiro/* USB transfer specific */ 79173340Sgshapirostatic libusb20_tr_open_t ugen20_tr_open; 80173340Sgshapirostatic libusb20_tr_close_t ugen20_tr_close; 8171345Sgshapirostatic libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 8271345Sgshapirostatic libusb20_tr_submit_t ugen20_tr_submit; 8371345Sgshapirostatic libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 8471345Sgshapiro 8571345Sgshapirostatic const struct libusb20_device_methods libusb20_ugen20_device_methods = { 86173340Sgshapiro LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 87173340Sgshapiro}; 8871345Sgshapiro 8971345Sgshapirostatic const char * 9071345Sgshapirougen20_get_backend_name(void) 9171345Sgshapiro{ 9271345Sgshapiro return ("FreeBSD UGEN 2.0"); 9371345Sgshapiro} 9471345Sgshapiro 9573188Sgshapirostatic uint32_t 96173340Sgshapirougen20_path_convert_one(const char **pp) 9794334Sgshapiro{ 9873188Sgshapiro const char *ptr; 9971345Sgshapiro uint32_t temp = 0; 10071345Sgshapiro 10171345Sgshapiro ptr = *pp; 10271345Sgshapiro 10371345Sgshapiro while ((*ptr >= '0') && (*ptr <= '9')) { 10471345Sgshapiro temp *= 10; 10571345Sgshapiro temp += (*ptr - '0'); 10671345Sgshapiro if (temp >= 1000000) { 10771345Sgshapiro /* catch overflow early */ 10871345Sgshapiro return (0 - 1); 10973188Sgshapiro } 11094334Sgshapiro ptr++; 11171345Sgshapiro } 112173340Sgshapiro 113173340Sgshapiro if (*ptr == '.') { 114173340Sgshapiro /* skip dot */ 115173340Sgshapiro ptr++; 116173340Sgshapiro } 117173340Sgshapiro *pp = ptr; 118173340Sgshapiro 119173340Sgshapiro return (temp); 120173340Sgshapiro} 121173340Sgshapiro 122173340Sgshapirostatic int 123173340Sgshapirougen20_enumerate(struct libusb20_device *pdev, const char *id) 124112810Sgshapiro{ 12594334Sgshapiro const char *tmp = id; 126112810Sgshapiro struct usb_device_descriptor ddesc; 127112810Sgshapiro struct usb_device_info devinfo; 128112810Sgshapiro uint32_t plugtime; 129112810Sgshapiro char buf[64]; 130112810Sgshapiro int f; 131112810Sgshapiro int error; 13271345Sgshapiro 13371345Sgshapiro pdev->bus_number = ugen20_path_convert_one(&tmp); 13471345Sgshapiro pdev->device_address = ugen20_path_convert_one(&tmp); 13571345Sgshapiro 13671345Sgshapiro snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 13771345Sgshapiro pdev->bus_number, pdev->device_address); 138173340Sgshapiro 13971345Sgshapiro f = open(buf, O_RDWR); 14071345Sgshapiro if (f < 0) { 141173340Sgshapiro return (LIBUSB20_ERROR_OTHER); 142173340Sgshapiro } 143173340Sgshapiro if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 14471345Sgshapiro error = LIBUSB20_ERROR_OTHER; 14571345Sgshapiro goto done; 14671345Sgshapiro } 14771345Sgshapiro /* store when the device was plugged */ 14871345Sgshapiro pdev->session_data.plugtime = plugtime; 14971345Sgshapiro 15071345Sgshapiro if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) { 15171345Sgshapiro error = LIBUSB20_ERROR_OTHER; 15271345Sgshapiro goto done; 15371345Sgshapiro } 15471345Sgshapiro LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 15571345Sgshapiro 15671345Sgshapiro libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 15771345Sgshapiro 15873188Sgshapiro if (pdev->ddesc.bNumConfigurations == 0) { 15971345Sgshapiro error = LIBUSB20_ERROR_OTHER; 16071345Sgshapiro goto done; 16171345Sgshapiro } else if (pdev->ddesc.bNumConfigurations >= 8) { 16271345Sgshapiro error = LIBUSB20_ERROR_OTHER; 16373188Sgshapiro goto done; 16471345Sgshapiro } 16571345Sgshapiro if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) { 16671345Sgshapiro error = LIBUSB20_ERROR_OTHER; 16771345Sgshapiro goto done; 16871345Sgshapiro } 16971345Sgshapiro switch (devinfo.udi_mode) { 170173340Sgshapiro case USB_MODE_DEVICE: 17171345Sgshapiro pdev->usb_mode = LIBUSB20_MODE_DEVICE; 17273188Sgshapiro break; 17373188Sgshapiro default: 17473188Sgshapiro pdev->usb_mode = LIBUSB20_MODE_HOST; 17573188Sgshapiro break; 17673188Sgshapiro } 17771345Sgshapiro 17871345Sgshapiro switch (devinfo.udi_speed) { 17971345Sgshapiro case USB_SPEED_LOW: 18071345Sgshapiro pdev->usb_speed = LIBUSB20_SPEED_LOW; 18171345Sgshapiro break; 182173340Sgshapiro case USB_SPEED_FULL: 183173340Sgshapiro pdev->usb_speed = LIBUSB20_SPEED_FULL; 184173340Sgshapiro break; 18594334Sgshapiro case USB_SPEED_HIGH: 18671345Sgshapiro pdev->usb_speed = LIBUSB20_SPEED_HIGH; 18771345Sgshapiro break; 18871345Sgshapiro case USB_SPEED_VARIABLE: 189112810Sgshapiro pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 190112810Sgshapiro break; 191112810Sgshapiro case USB_SPEED_SUPER: 192112810Sgshapiro pdev->usb_speed = LIBUSB20_SPEED_SUPER; 193112810Sgshapiro break; 194112810Sgshapiro default: 195112810Sgshapiro pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 196112810Sgshapiro break; 197112810Sgshapiro } 19871345Sgshapiro 19971345Sgshapiro /* generate a nice description for printout */ 20071345Sgshapiro 20171345Sgshapiro snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 20271345Sgshapiro USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, 203173340Sgshapiro pdev->device_address, devinfo.udi_product, 20471345Sgshapiro devinfo.udi_vendor, pdev->bus_number); 20571345Sgshapiro 20671345Sgshapiro error = 0; 20771345Sgshapirodone: 20871345Sgshapiro close(f); 209173340Sgshapiro return (error); 21071345Sgshapiro} 21171345Sgshapiro 21271345Sgshapirostruct ugen20_urd_state { 213173340Sgshapiro struct usb_read_dir urd; 21471345Sgshapiro uint32_t nparsed; 21571345Sgshapiro int f; 21671345Sgshapiro uint8_t *ptr; 217 const char *src; 218 const char *dst; 219 uint8_t buf[256]; 220 uint8_t dummy_zero[1]; 221}; 222 223static int 224ugen20_readdir(struct ugen20_urd_state *st) 225{ 226 ; /* style fix */ 227repeat: 228 if (st->ptr == NULL) { 229 st->urd.urd_startentry += st->nparsed; 230 st->urd.urd_data = st->buf; 231 st->urd.urd_maxlen = sizeof(st->buf); 232 st->nparsed = 0; 233 234 if (ioctl(st->f, USB_READ_DIR, &st->urd)) { 235 return (EINVAL); 236 } 237 st->ptr = st->buf; 238 } 239 if (st->ptr[0] == 0) { 240 if (st->nparsed) { 241 st->ptr = NULL; 242 goto repeat; 243 } else { 244 return (ENXIO); 245 } 246 } 247 st->src = (void *)(st->ptr + 1); 248 st->dst = st->src + strlen(st->src) + 1; 249 st->ptr = st->ptr + st->ptr[0]; 250 st->nparsed++; 251 252 if ((st->ptr < st->buf) || 253 (st->ptr > st->dummy_zero)) { 254 /* invalid entry */ 255 return (EINVAL); 256 } 257 return (0); 258} 259 260static int 261ugen20_init_backend(struct libusb20_backend *pbe) 262{ 263 struct ugen20_urd_state state; 264 struct libusb20_device *pdev; 265 266 memset(&state, 0, sizeof(state)); 267 268 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 269 if (state.f < 0) 270 return (LIBUSB20_ERROR_OTHER); 271 272 while (ugen20_readdir(&state) == 0) { 273 274 if ((state.src[0] != 'u') || 275 (state.src[1] != 'g') || 276 (state.src[2] != 'e') || 277 (state.src[3] != 'n')) { 278 continue; 279 } 280 pdev = libusb20_dev_alloc(); 281 if (pdev == NULL) { 282 continue; 283 } 284 if (ugen20_enumerate(pdev, state.src + 4)) { 285 libusb20_dev_free(pdev); 286 continue; 287 } 288 /* put the device on the backend list */ 289 libusb20_be_enqueue_device(pbe, pdev); 290 } 291 close(state.f); 292 return (0); /* success */ 293} 294 295static void 296ugen20_tr_release(struct libusb20_device *pdev) 297{ 298 struct usb_fs_uninit fs_uninit; 299 300 if (pdev->nTransfer == 0) { 301 return; 302 } 303 /* release all pending USB transfers */ 304 if (pdev->privBeData != NULL) { 305 memset(&fs_uninit, 0, sizeof(fs_uninit)); 306 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 307 /* ignore any errors of this kind */ 308 } 309 } 310 return; 311} 312 313static int 314ugen20_tr_renew(struct libusb20_device *pdev) 315{ 316 struct usb_fs_init fs_init; 317 struct usb_fs_endpoint *pfse; 318 int error; 319 uint32_t size; 320 uint16_t nMaxTransfer; 321 322 nMaxTransfer = pdev->nTransfer; 323 error = 0; 324 325 if (nMaxTransfer == 0) { 326 goto done; 327 } 328 size = nMaxTransfer * sizeof(*pfse); 329 330 if (pdev->privBeData == NULL) { 331 pfse = malloc(size); 332 if (pfse == NULL) { 333 error = LIBUSB20_ERROR_NO_MEM; 334 goto done; 335 } 336 pdev->privBeData = pfse; 337 } 338 /* reset endpoint data */ 339 memset(pdev->privBeData, 0, size); 340 341 memset(&fs_init, 0, sizeof(fs_init)); 342 343 fs_init.pEndpoints = pdev->privBeData; 344 fs_init.ep_index_max = nMaxTransfer; 345 346 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) { 347 error = LIBUSB20_ERROR_OTHER; 348 goto done; 349 } 350done: 351 return (error); 352} 353 354static int 355ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 356{ 357 uint32_t plugtime; 358 char buf[64]; 359 int f; 360 int g; 361 int error; 362 363 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 364 pdev->bus_number, pdev->device_address); 365 366 /* 367 * We need two file handles, one for the control endpoint and one 368 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 369 * kernel locking. 370 */ 371 g = open(buf, O_RDWR); 372 if (g < 0) { 373 return (LIBUSB20_ERROR_NO_DEVICE); 374 } 375 f = open(buf, O_RDWR); 376 if (f < 0) { 377 close(g); 378 return (LIBUSB20_ERROR_NO_DEVICE); 379 } 380 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 381 error = LIBUSB20_ERROR_OTHER; 382 goto done; 383 } 384 /* check that the correct device is still plugged */ 385 if (pdev->session_data.plugtime != plugtime) { 386 error = LIBUSB20_ERROR_NO_DEVICE; 387 goto done; 388 } 389 /* need to set this before "tr_renew()" */ 390 pdev->file = f; 391 pdev->file_ctrl = g; 392 393 /* renew all USB transfers */ 394 error = ugen20_tr_renew(pdev); 395 if (error) { 396 goto done; 397 } 398 /* set methods */ 399 pdev->methods = &libusb20_ugen20_device_methods; 400 401done: 402 if (error) { 403 if (pdev->privBeData) { 404 /* cleanup after "tr_renew()" */ 405 free(pdev->privBeData); 406 pdev->privBeData = NULL; 407 } 408 pdev->file = -1; 409 pdev->file_ctrl = -1; 410 close(f); 411 close(g); 412 } 413 return (error); 414} 415 416static int 417ugen20_close_device(struct libusb20_device *pdev) 418{ 419 struct usb_fs_uninit fs_uninit; 420 421 if (pdev->privBeData) { 422 memset(&fs_uninit, 0, sizeof(fs_uninit)); 423 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 424 /* ignore this error */ 425 } 426 free(pdev->privBeData); 427 } 428 pdev->nTransfer = 0; 429 pdev->privBeData = NULL; 430 close(pdev->file); 431 close(pdev->file_ctrl); 432 pdev->file = -1; 433 pdev->file_ctrl = -1; 434 return (0); /* success */ 435} 436 437static void 438ugen20_exit_backend(struct libusb20_backend *pbe) 439{ 440 return; /* nothing to do */ 441} 442 443static int 444ugen20_get_config_desc_full(struct libusb20_device *pdev, 445 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 446{ 447 struct usb_gen_descriptor gen_desc; 448 struct usb_config_descriptor cdesc; 449 uint8_t *ptr; 450 uint16_t len; 451 int error; 452 453 /* make sure memory is initialised */ 454 memset(&cdesc, 0, sizeof(cdesc)); 455 memset(&gen_desc, 0, sizeof(gen_desc)); 456 457 gen_desc.ugd_data = &cdesc; 458 gen_desc.ugd_maxlen = sizeof(cdesc); 459 gen_desc.ugd_config_index = cfg_index; 460 461 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 462 if (error) { 463 return (LIBUSB20_ERROR_OTHER); 464 } 465 len = UGETW(cdesc.wTotalLength); 466 if (len < sizeof(cdesc)) { 467 /* corrupt descriptor */ 468 return (LIBUSB20_ERROR_OTHER); 469 } 470 ptr = malloc(len); 471 if (!ptr) { 472 return (LIBUSB20_ERROR_NO_MEM); 473 } 474 475 /* make sure memory is initialised */ 476 memset(ptr, 0, len); 477 478 gen_desc.ugd_data = ptr; 479 gen_desc.ugd_maxlen = len; 480 481 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 482 if (error) { 483 free(ptr); 484 return (LIBUSB20_ERROR_OTHER); 485 } 486 /* make sure that the device doesn't fool us */ 487 memcpy(ptr, &cdesc, sizeof(cdesc)); 488 489 *ppbuf = ptr; 490 *plen = len; 491 492 return (0); /* success */ 493} 494 495static int 496ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 497{ 498 int temp; 499 500 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) { 501 return (LIBUSB20_ERROR_OTHER); 502 } 503 *pindex = temp; 504 505 return (0); 506} 507 508static int 509ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 510{ 511 int temp = cfg_index; 512 513 /* release all active USB transfers */ 514 ugen20_tr_release(pdev); 515 516 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) { 517 return (LIBUSB20_ERROR_OTHER); 518 } 519 return (ugen20_tr_renew(pdev)); 520} 521 522static int 523ugen20_set_alt_index(struct libusb20_device *pdev, 524 uint8_t iface_index, uint8_t alt_index) 525{ 526 struct usb_alt_interface alt_iface; 527 528 memset(&alt_iface, 0, sizeof(alt_iface)); 529 530 alt_iface.uai_interface_index = iface_index; 531 alt_iface.uai_alt_index = alt_index; 532 533 /* release all active USB transfers */ 534 ugen20_tr_release(pdev); 535 536 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) { 537 return (LIBUSB20_ERROR_OTHER); 538 } 539 return (ugen20_tr_renew(pdev)); 540} 541 542static int 543ugen20_reset_device(struct libusb20_device *pdev) 544{ 545 int temp = 0; 546 547 /* release all active USB transfers */ 548 ugen20_tr_release(pdev); 549 550 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) { 551 return (LIBUSB20_ERROR_OTHER); 552 } 553 return (ugen20_tr_renew(pdev)); 554} 555 556static int 557ugen20_check_connected(struct libusb20_device *pdev) 558{ 559 uint32_t plugtime; 560 int error = 0; 561 562 if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) { 563 error = LIBUSB20_ERROR_NO_DEVICE; 564 goto done; 565 } 566 567 if (pdev->session_data.plugtime != plugtime) { 568 error = LIBUSB20_ERROR_NO_DEVICE; 569 goto done; 570 } 571done: 572 return (error); 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 usb_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 usb_fs_complete temp; 692 struct usb_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 usb_fs_open temp; 743 struct usb_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 usb_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 usb_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 usb_fs_start temp; 808 struct usb_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 /* NOTE: The "fsep->timeout" variable is 16-bit. */ 830 if (xfer->timeout > 65535) 831 fsep->timeout = 65535; 832 else 833 fsep->timeout = xfer->timeout; 834 835 temp.ep_index = xfer->trIndex; 836 837 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) { 838 /* ignore any errors - should never happen */ 839 } 840 return; /* success */ 841} 842 843static void 844ugen20_tr_cancel_async(struct libusb20_transfer *xfer) 845{ 846 struct usb_fs_stop temp; 847 848 memset(&temp, 0, sizeof(temp)); 849 850 temp.ep_index = xfer->trIndex; 851 852 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) { 853 /* ignore any errors - should never happen */ 854 } 855 return; 856} 857 858static int 859ugen20_be_ioctl(uint32_t cmd, void *data) 860{ 861 int f; 862 int error; 863 864 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 865 if (f < 0) 866 return (LIBUSB20_ERROR_OTHER); 867 error = ioctl(f, cmd, data); 868 if (error == -1) { 869 if (errno == EPERM) { 870 error = LIBUSB20_ERROR_ACCESS; 871 } else { 872 error = LIBUSB20_ERROR_OTHER; 873 } 874 } 875 close(f); 876 return (error); 877} 878 879static int 880ugen20_dev_get_iface_desc(struct libusb20_device *pdev, 881 uint8_t iface_index, char *buf, uint8_t len) 882{ 883 struct usb_gen_descriptor ugd; 884 885 memset(&ugd, 0, sizeof(ugd)); 886 887 ugd.ugd_data = buf; 888 ugd.ugd_maxlen = len; 889 ugd.ugd_iface_index = iface_index; 890 891 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) { 892 return (LIBUSB20_ERROR_INVALID_PARAM); 893 } 894 return (0); 895} 896 897static int 898ugen20_dev_get_info(struct libusb20_device *pdev, 899 struct usb_device_info *pinfo) 900{ 901 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) { 902 return (LIBUSB20_ERROR_INVALID_PARAM); 903 } 904 return (0); 905} 906 907static int 908ugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 909 uint16_t quirk_index, struct libusb20_quirk *pq) 910{ 911 struct usb_gen_quirk q; 912 int error; 913 914 memset(&q, 0, sizeof(q)); 915 916 q.index = quirk_index; 917 918 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q); 919 920 if (error) { 921 if (errno == EINVAL) { 922 return (LIBUSB20_ERROR_NOT_FOUND); 923 } 924 } else { 925 pq->vid = q.vid; 926 pq->pid = q.pid; 927 pq->bcdDeviceLow = q.bcdDeviceLow; 928 pq->bcdDeviceHigh = q.bcdDeviceHigh; 929 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 930 } 931 return (error); 932} 933 934static int 935ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 936 struct libusb20_quirk *pq) 937{ 938 struct usb_gen_quirk q; 939 int error; 940 941 memset(&q, 0, sizeof(q)); 942 943 q.index = quirk_index; 944 945 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q); 946 947 if (error) { 948 if (errno == EINVAL) { 949 return (LIBUSB20_ERROR_NOT_FOUND); 950 } 951 } else { 952 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 953 } 954 return (error); 955} 956 957static int 958ugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 959 struct libusb20_quirk *pq) 960{ 961 struct usb_gen_quirk q; 962 int error; 963 964 memset(&q, 0, sizeof(q)); 965 966 q.vid = pq->vid; 967 q.pid = pq->pid; 968 q.bcdDeviceLow = pq->bcdDeviceLow; 969 q.bcdDeviceHigh = pq->bcdDeviceHigh; 970 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 971 972 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q); 973 if (error) { 974 if (errno == ENOMEM) { 975 return (LIBUSB20_ERROR_NO_MEM); 976 } 977 } 978 return (error); 979} 980 981static int 982ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 983 struct libusb20_quirk *pq) 984{ 985 struct usb_gen_quirk q; 986 int error; 987 988 memset(&q, 0, sizeof(q)); 989 990 q.vid = pq->vid; 991 q.pid = pq->pid; 992 q.bcdDeviceLow = pq->bcdDeviceLow; 993 q.bcdDeviceHigh = pq->bcdDeviceHigh; 994 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 995 996 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q); 997 if (error) { 998 if (errno == EINVAL) { 999 return (LIBUSB20_ERROR_NOT_FOUND); 1000 } 1001 } 1002 return (error); 1003} 1004 1005static int 1006ugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1007{ 1008 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp)); 1009} 1010 1011static int 1012ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1013{ 1014 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp)); 1015} 1016