1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * Universal Host Controller Driver (UHCI) 29 * 30 * The UHCI driver is a driver which interfaces to the Universal 31 * Serial Bus Architecture (USBA) and the Host Controller (HC). The interface to 32 * the Host Controller is defined by the Universal Host Controller Interface. 33 * This file contains code for auto-configuration entry points and interrupt 34 * handling. 35 */ 36 #include <sys/usb/hcd/uhci/uhcid.h> 37 #include <sys/usb/hcd/uhci/uhcihub.h> 38 #include <sys/usb/hcd/uhci/uhciutil.h> 39 40 /* 41 * Prototype Declarations for cb_ops and dev_ops 42 */ 43 static int uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 44 static int uhci_add_intrs(uhci_state_t *uhcip, int intr_type); 45 static int uhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 46 static void uhci_rem_intrs(uhci_state_t *uhcip); 47 static int uhci_open(dev_t *devp, int flags, int otyp, cred_t *credp); 48 static int uhci_close(dev_t dev, int flag, int otyp, cred_t *credp); 49 static int uhci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 50 cred_t *credp, int *rvalp); 51 static int uhci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd); 52 static int uhci_quiesce(dev_info_t *dip); 53 static int uhci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 54 void **result); 55 56 /* extern */ 57 int usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level); 58 59 static struct cb_ops uhci_cb_ops = { 60 uhci_open, /* Open */ 61 uhci_close, /* Close */ 62 nodev, /* Strategy */ 63 nodev, /* Print */ 64 nodev, /* Dump */ 65 nodev, /* Read */ 66 nodev, /* Write */ 67 uhci_ioctl, /* Ioctl */ 68 nodev, /* Devmap */ 69 nodev, /* Mmap */ 70 nodev, /* Segmap */ 71 nochpoll, /* Poll */ 72 ddi_prop_op, /* cb_prop_op */ 73 NULL, /* Streamtab */ 74 D_MP /* Driver compatibility flag */ 75 }; 76 77 static struct dev_ops uhci_ops = { 78 DEVO_REV, /* Devo_rev */ 79 0, /* Refcnt */ 80 uhci_info, /* Info */ 81 nulldev, /* Identify */ 82 nulldev, /* Probe */ 83 uhci_attach, /* Attach */ 84 uhci_detach, /* Detach */ 85 uhci_reset, /* Reset */ 86 &uhci_cb_ops, /* Driver operations */ 87 &usba_hubdi_busops, /* Bus operations */ 88 usba_hubdi_root_hub_power, /* Power */ 89 uhci_quiesce /* quiesce */ 90 }; 91 92 static struct modldrv modldrv = { 93 &mod_driverops, /* Type of module. This one is a driver */ 94 "USB UHCI Controller Driver", /* Name of the module. */ 95 &uhci_ops, /* Driver ops */ 96 }; 97 98 static struct modlinkage modlinkage = { 99 MODREV_1, (void *)&modldrv, NULL 100 }; 101 102 /* 103 * Globals 104 */ 105 void *uhci_statep; 106 uint_t uhci_errlevel = USB_LOG_L2; 107 uint_t uhci_errmask = PRINT_MASK_ALL; 108 uint_t uhci_instance_debug = (uint_t)-1; 109 110 uint_t uhci_td_pool_size = 256; /* Num TDs */ 111 uint_t uhci_qh_pool_size = 130; /* Num QHs */ 112 ushort_t uhci_tree_bottom_nodes[NUM_FRAME_LST_ENTRIES]; 113 114 115 /* 116 * UHCI MSI tunable: 117 * 118 * By default MSI is enabled on all supported platforms. 119 */ 120 boolean_t uhci_enable_msi = B_TRUE; 121 122 /* 123 * tunable, delay during attach in seconds 124 */ 125 int uhci_attach_wait = 0; 126 127 /* function prototypes */ 128 static void uhci_handle_intr_td_errors(uhci_state_t *uhcip, uhci_td_t *td, 129 uhci_trans_wrapper_t *tw, uhci_pipe_private_t *pp); 130 static void uhci_handle_one_xfer_completion(uhci_state_t *uhcip, 131 usb_cr_t usb_err, uhci_td_t *td); 132 static uint_t uhci_intr(caddr_t arg1, caddr_t arg2); 133 static int uhci_cleanup(uhci_state_t *uhcip); 134 static int uhci_cpr_suspend(uhci_state_t *uhcip); 135 static int uhci_cpr_resume(uhci_state_t *uhcip); 136 137 138 int 139 _init(void) 140 { 141 int error; 142 ushort_t i, j, k, *temp, num_of_nodes; 143 144 /* Initialize the soft state structures */ 145 if ((error = ddi_soft_state_init(&uhci_statep, sizeof (uhci_state_t), 146 UHCI_MAX_INSTS)) != 0) { 147 148 return (error); 149 } 150 151 /* Install the loadable module */ 152 if ((error = mod_install(&modlinkage)) != 0) { 153 ddi_soft_state_fini(&uhci_statep); 154 155 return (error); 156 } 157 158 /* 159 * Build the tree bottom shared by all instances 160 */ 161 temp = kmem_zalloc(NUM_FRAME_LST_ENTRIES * 2, KM_SLEEP); 162 163 num_of_nodes = 1; 164 for (i = 0; i < log_2(NUM_FRAME_LST_ENTRIES); i++) { 165 for (j = 0, k = 0; k < num_of_nodes; k++, j++) { 166 uhci_tree_bottom_nodes[j++] = temp[k]; 167 uhci_tree_bottom_nodes[j] = temp[k] + pow_2(i); 168 } 169 170 num_of_nodes *= 2; 171 for (k = 0; k < num_of_nodes; k++) 172 temp[k] = uhci_tree_bottom_nodes[k]; 173 174 } 175 kmem_free(temp, (NUM_FRAME_LST_ENTRIES*2)); 176 177 178 return (error); 179 } 180 181 182 int 183 _info(struct modinfo *modinfop) 184 { 185 return (mod_info(&modlinkage, modinfop)); 186 } 187 188 189 int 190 _fini(void) 191 { 192 int error; 193 194 error = mod_remove(&modlinkage); 195 196 if (error == 0) { 197 /* Release per module resources */ 198 ddi_soft_state_fini(&uhci_statep); 199 } 200 201 return (error); 202 } 203 204 /* 205 * The following simulated polling is for debugging purposes only. 206 * It is activated on x86 by setting usb-polling=true in GRUB or uhci.conf. 207 */ 208 static int 209 uhci_is_polled(dev_info_t *dip) 210 { 211 int ret; 212 char *propval; 213 214 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 215 "usb-polling", &propval) != DDI_SUCCESS) 216 217 return (0); 218 219 ret = (strcmp(propval, "true") == 0); 220 ddi_prop_free(propval); 221 222 return (ret); 223 } 224 225 static void 226 uhci_poll_intr(void *arg) 227 { 228 /* poll every msec */ 229 for (;;) { 230 (void) uhci_intr(arg, NULL); 231 delay(drv_usectohz(1000)); 232 } 233 } 234 235 /* 236 * Host Controller Driver (HCD) Auto configuration entry points 237 */ 238 239 /* 240 * Function Name : uhci_attach: 241 * Description : Attach entry point - called by the Kernel. 242 * Allocates of per controller data structure. 243 * Initializes the controller. 244 * Output : DDI_SUCCESS / DDI_FAILURE 245 */ 246 static int 247 uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 248 { 249 int instance, polled; 250 int i, intr_types; 251 uhci_state_t *uhcip = NULL; 252 usba_hcdi_register_args_t hcdi_args; 253 254 USB_DPRINTF_L4(PRINT_MASK_ATTA, NULL, "uhci_attach:"); 255 256 switch (cmd) { 257 case DDI_ATTACH: 258 break; 259 case DDI_RESUME: 260 uhcip = uhci_obtain_state(dip); 261 262 return (uhci_cpr_resume(uhcip)); 263 default: 264 265 return (DDI_FAILURE); 266 } 267 268 /* Get the instance and create soft state */ 269 instance = ddi_get_instance(dip); 270 271 /* Allocate the soft state structure for this instance of the driver */ 272 if (ddi_soft_state_zalloc(uhci_statep, instance) != 0) { 273 274 return (DDI_FAILURE); 275 } 276 277 if ((uhcip = ddi_get_soft_state(uhci_statep, instance)) == NULL) { 278 279 return (DDI_FAILURE); 280 } 281 282 uhcip->uhci_log_hdl = usb_alloc_log_hdl(dip, "uhci", &uhci_errlevel, 283 &uhci_errmask, &uhci_instance_debug, 0); 284 285 /* Set host controller soft state to initialization */ 286 uhcip->uhci_hc_soft_state = UHCI_CTLR_INIT_STATE; 287 288 /* Save the dip and instance */ 289 uhcip->uhci_dip = dip; 290 uhcip->uhci_instance = instance; 291 292 polled = uhci_is_polled(dip); 293 if (polled) 294 295 goto skip_intr; 296 297 /* Get supported interrupt types */ 298 if (ddi_intr_get_supported_types(uhcip->uhci_dip, 299 &intr_types) != DDI_SUCCESS) { 300 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 301 "uhci_attach: ddi_intr_get_supported_types failed"); 302 303 usb_free_log_hdl(uhcip->uhci_log_hdl); 304 ddi_soft_state_free(uhci_statep, instance); 305 306 return (DDI_FAILURE); 307 } 308 309 USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 310 "uhci_attach: supported interrupt types 0x%x", intr_types); 311 312 if ((intr_types & DDI_INTR_TYPE_MSI) && uhci_enable_msi) { 313 if (uhci_add_intrs(uhcip, DDI_INTR_TYPE_MSI) 314 != DDI_SUCCESS) { 315 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 316 "uhci_attach: MSI registration failed, " 317 "trying FIXED interrupt \n"); 318 } else { 319 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 320 "uhci_attach: Using MSI interrupt type\n"); 321 322 uhcip->uhci_intr_type = DDI_INTR_TYPE_MSI; 323 } 324 } 325 326 if (!(uhcip->uhci_htable) && (intr_types & DDI_INTR_TYPE_FIXED)) { 327 if (uhci_add_intrs(uhcip, DDI_INTR_TYPE_FIXED) 328 != DDI_SUCCESS) { 329 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 330 "uhci_attach: FIXED interrupt registration " 331 "failed\n"); 332 333 usb_free_log_hdl(uhcip->uhci_log_hdl); 334 ddi_soft_state_free(uhci_statep, instance); 335 336 return (DDI_FAILURE); 337 } 338 339 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 340 "uhci_attach: Using FIXED interrupt type\n"); 341 342 uhcip->uhci_intr_type = DDI_INTR_TYPE_FIXED; 343 } 344 345 skip_intr: 346 /* Semaphore to serialize opens and closes */ 347 sema_init(&uhcip->uhci_ocsem, 1, NULL, SEMA_DRIVER, NULL); 348 349 /* Create prototype condition variable */ 350 cv_init(&uhcip->uhci_cv_SOF, NULL, CV_DRIVER, NULL); 351 352 /* Initialize the DMA attributes */ 353 uhci_set_dma_attributes(uhcip); 354 355 /* Initialize the kstat structures */ 356 uhci_create_stats(uhcip); 357 358 /* Create the td and ed pools */ 359 if (uhci_allocate_pools(uhcip) != USB_SUCCESS) { 360 361 goto fail; 362 } 363 364 /* Map the registers */ 365 if (uhci_map_regs(uhcip) != USB_SUCCESS) { 366 367 goto fail; 368 } 369 370 /* Enable all interrupts */ 371 if (polled) { 372 extern pri_t maxclsyspri; 373 374 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 375 "uhci_attach: running in simulated polled mode."); 376 377 /* create thread to poll */ 378 (void) thread_create(NULL, 0, uhci_poll_intr, uhcip, 0, &p0, 379 TS_RUN, maxclsyspri); 380 } else if (uhcip->uhci_intr_cap & DDI_INTR_FLAG_BLOCK) { 381 /* Call ddi_intr_block_enable() for MSI interrupts */ 382 (void) ddi_intr_block_enable(uhcip->uhci_htable, 383 uhcip->uhci_intr_cnt); 384 } else { 385 /* Call ddi_intr_enable for MSI or FIXED interrupts */ 386 for (i = 0; i < uhcip->uhci_intr_cnt; i++) 387 (void) ddi_intr_enable(uhcip->uhci_htable[i]); 388 } 389 390 391 /* Initialize the controller */ 392 if (uhci_init_ctlr(uhcip) != USB_SUCCESS) { 393 394 goto fail; 395 } 396 397 /* 398 * At this point, the hardware will be okay. 399 * Initialize the usba_hcdi structure 400 */ 401 uhcip->uhci_hcdi_ops = uhci_alloc_hcdi_ops(uhcip); 402 403 /* 404 * Make this HCD instance known to USBA 405 * (dma_attr must be passed for USBA busctl's) 406 */ 407 hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION; 408 hcdi_args.usba_hcdi_register_dip = dip; 409 hcdi_args.usba_hcdi_register_ops = uhcip->uhci_hcdi_ops; 410 hcdi_args.usba_hcdi_register_dma_attr = &uhcip->uhci_dma_attr; 411 hcdi_args.usba_hcdi_register_iblock_cookie = 412 (ddi_iblock_cookie_t)(uintptr_t)uhcip->uhci_intr_pri; 413 414 if (usba_hcdi_register(&hcdi_args, 0) != USB_SUCCESS) { 415 416 goto fail; 417 } 418 419 #ifndef __sparc 420 /* 421 * On NCR system, the driver seen failure of some commands 422 * while booting. This delay mysteriously solved the problem. 423 */ 424 delay(drv_usectohz(uhci_attach_wait*1000000)); 425 #endif 426 427 /* 428 * Create another timeout handler to check whether any 429 * control/bulk/interrupt commands failed. 430 * This gets called every second. 431 */ 432 uhcip->uhci_cmd_timeout_id = timeout(uhci_cmd_timeout_hdlr, 433 (void *)uhcip, UHCI_ONE_SECOND); 434 435 mutex_enter(&uhcip->uhci_int_mutex); 436 437 /* 438 * Set HcInterruptEnable to enable all interrupts except Root 439 * Hub Status change and SOF interrupts. 440 */ 441 Set_OpReg16(USBINTR, ENABLE_ALL_INTRS); 442 443 /* Test the SOF interrupt */ 444 if (uhci_wait_for_sof(uhcip) != USB_SUCCESS) { 445 USB_DPRINTF_L0(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 446 "No SOF interrupts have been received, this USB UHCI host" 447 " controller is unusable"); 448 mutex_exit(&uhcip->uhci_int_mutex); 449 450 goto fail; 451 } 452 453 mutex_exit(&uhcip->uhci_int_mutex); 454 455 /* This should be the last step which might fail during attaching */ 456 if (uhci_init_root_hub(uhcip) != USB_SUCCESS) { 457 458 goto fail; 459 } 460 461 /* Display information in the banner */ 462 ddi_report_dev(dip); 463 464 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 465 "uhci_attach successful"); 466 467 return (DDI_SUCCESS); 468 469 fail: 470 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 471 "failed to attach"); 472 473 (void) uhci_cleanup(uhcip); 474 475 return (DDI_FAILURE); 476 } 477 478 479 /* 480 * uhci_add_intrs: 481 * 482 * Register FIXED or MSI interrupts. 483 */ 484 static int 485 uhci_add_intrs(uhci_state_t *uhcip, 486 int intr_type) 487 { 488 int actual, avail, intr_size, count = 0; 489 int i, flag, ret; 490 491 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 492 "uhci_add_intrs: interrupt type 0x%x", intr_type); 493 494 /* Get number of interrupts */ 495 ret = ddi_intr_get_nintrs(uhcip->uhci_dip, intr_type, &count); 496 if ((ret != DDI_SUCCESS) || (count == 0)) { 497 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 498 "uhci_add_intrs: ddi_intr_get_nintrs() failure, " 499 "ret: %d, count: %d", ret, count); 500 501 return (DDI_FAILURE); 502 } 503 504 /* Get number of available interrupts */ 505 ret = ddi_intr_get_navail(uhcip->uhci_dip, intr_type, &avail); 506 if ((ret != DDI_SUCCESS) || (avail == 0)) { 507 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 508 "uhci_add_intrs: ddi_intr_get_navail() failure, " 509 "ret: %d, count: %d", ret, count); 510 511 return (DDI_FAILURE); 512 } 513 514 if (avail < count) { 515 USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 516 "uhci_add_intrs: uhci_add_intrs: nintrs () " 517 "returned %d, navail returned %d\n", count, avail); 518 } 519 520 /* Allocate an array of interrupt handles */ 521 intr_size = count * sizeof (ddi_intr_handle_t); 522 uhcip->uhci_htable = kmem_zalloc(intr_size, KM_SLEEP); 523 524 flag = (intr_type == DDI_INTR_TYPE_MSI) ? 525 DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL; 526 527 /* call ddi_intr_alloc() */ 528 ret = ddi_intr_alloc(uhcip->uhci_dip, uhcip->uhci_htable, 529 intr_type, 0, count, &actual, flag); 530 531 if ((ret != DDI_SUCCESS) || (actual == 0)) { 532 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 533 "uhci_add_intrs: ddi_intr_alloc() failed %d", ret); 534 535 kmem_free(uhcip->uhci_htable, intr_size); 536 537 return (DDI_FAILURE); 538 } 539 540 if (actual < count) { 541 USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 542 "uhci_add_intrs: Requested: %d, Received: %d\n", 543 count, actual); 544 545 for (i = 0; i < actual; i++) 546 (void) ddi_intr_free(uhcip->uhci_htable[i]); 547 548 kmem_free(uhcip->uhci_htable, intr_size); 549 550 return (DDI_FAILURE); 551 } 552 553 uhcip->uhci_intr_cnt = actual; 554 555 if ((ret = ddi_intr_get_pri(uhcip->uhci_htable[0], 556 &uhcip->uhci_intr_pri)) != DDI_SUCCESS) { 557 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 558 "uhci_add_intrs: ddi_intr_get_pri() failed %d", ret); 559 560 for (i = 0; i < actual; i++) 561 (void) ddi_intr_free(uhcip->uhci_htable[i]); 562 563 kmem_free(uhcip->uhci_htable, intr_size); 564 565 return (DDI_FAILURE); 566 } 567 568 USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 569 "uhci_add_intrs: Supported Interrupt priority 0x%x", 570 uhcip->uhci_intr_pri); 571 572 /* Test for high level mutex */ 573 if (uhcip->uhci_intr_pri >= ddi_intr_get_hilevel_pri()) { 574 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 575 "uhci_add_intrs: Hi level interrupt not supported"); 576 577 for (i = 0; i < actual; i++) 578 (void) ddi_intr_free(uhcip->uhci_htable[i]); 579 580 kmem_free(uhcip->uhci_htable, intr_size); 581 582 return (DDI_FAILURE); 583 } 584 585 /* Initialize the mutex */ 586 mutex_init(&uhcip->uhci_int_mutex, NULL, MUTEX_DRIVER, 587 DDI_INTR_PRI(uhcip->uhci_intr_pri)); 588 589 /* Call ddi_intr_add_handler() */ 590 for (i = 0; i < actual; i++) { 591 if ((ret = ddi_intr_add_handler(uhcip->uhci_htable[i], 592 uhci_intr, (caddr_t)uhcip, 593 (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 594 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 595 "uhci_add_intrs: ddi_intr_add_handler() " 596 "failed %d", ret); 597 598 for (i = 0; i < actual; i++) 599 (void) ddi_intr_free(uhcip->uhci_htable[i]); 600 601 mutex_destroy(&uhcip->uhci_int_mutex); 602 kmem_free(uhcip->uhci_htable, intr_size); 603 604 return (DDI_FAILURE); 605 } 606 } 607 608 if ((ret = ddi_intr_get_cap(uhcip->uhci_htable[0], 609 &uhcip->uhci_intr_cap)) != DDI_SUCCESS) { 610 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 611 "uhci_add_intrs: ddi_intr_get_cap() failed %d", ret); 612 613 for (i = 0; i < actual; i++) { 614 (void) ddi_intr_remove_handler(uhcip->uhci_htable[i]); 615 (void) ddi_intr_free(uhcip->uhci_htable[i]); 616 } 617 618 mutex_destroy(&uhcip->uhci_int_mutex); 619 kmem_free(uhcip->uhci_htable, intr_size); 620 621 return (DDI_FAILURE); 622 } 623 624 return (DDI_SUCCESS); 625 } 626 627 628 /* 629 * Function Name: uhci_detach 630 * Description: Detach entry point - called by the Kernel. 631 * Deallocates all the memory 632 * Unregisters the interrupt handle and other resources. 633 * Output: DDI_SUCCESS / DDI_FAILURE 634 */ 635 static int 636 uhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 637 { 638 uhci_state_t *uhcip = uhci_obtain_state(dip); 639 640 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 641 "uhci_detach:"); 642 643 switch (cmd) { 644 case DDI_DETACH: 645 646 return (uhci_cleanup(uhcip) == USB_SUCCESS ? 647 DDI_SUCCESS : DDI_FAILURE); 648 case DDI_SUSPEND: 649 650 return (uhci_cpr_suspend(uhcip)); 651 default: 652 653 return (DDI_FAILURE); 654 } 655 } 656 657 658 /* 659 * uhci_rem_intrs: 660 * 661 * Unregister FIXED or MSI interrupts 662 */ 663 static void 664 uhci_rem_intrs(uhci_state_t *uhcip) 665 { 666 int i; 667 668 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 669 "uhci_rem_intrs: interrupt type 0x%x", uhcip->uhci_intr_type); 670 671 /* Disable all interrupts */ 672 if (uhcip->uhci_intr_cap & DDI_INTR_FLAG_BLOCK) { 673 (void) ddi_intr_block_disable(uhcip->uhci_htable, 674 uhcip->uhci_intr_cnt); 675 } else { 676 for (i = 0; i < uhcip->uhci_intr_cnt; i++) { 677 (void) ddi_intr_disable(uhcip->uhci_htable[i]); 678 } 679 } 680 681 /* Call ddi_intr_remove_handler() */ 682 for (i = 0; i < uhcip->uhci_intr_cnt; i++) { 683 (void) ddi_intr_remove_handler(uhcip->uhci_htable[i]); 684 (void) ddi_intr_free(uhcip->uhci_htable[i]); 685 } 686 687 kmem_free(uhcip->uhci_htable, 688 uhcip->uhci_intr_cnt * sizeof (ddi_intr_handle_t)); 689 } 690 691 692 /* 693 * Function Name: uhci_reset 694 * Description: Reset entry point - called by the Kernel 695 * on the way down. 696 * The Toshiba laptop has been observed to hang 697 * on reboot when BIOS is set to suspend/resume. 698 * The resetting uhci on the way down solves the 699 * problem. 700 * Output: DDI_SUCCESS / DDI_FAILURE 701 */ 702 /* ARGSUSED */ 703 static int 704 uhci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 705 { 706 uhci_state_t *uhcip = uhci_obtain_state(dip); 707 708 /* Disable all HC ED list processing */ 709 Set_OpReg16(USBINTR, DISABLE_ALL_INTRS); 710 Set_OpReg16(USBCMD, 0); 711 712 return (DDI_SUCCESS); 713 } 714 715 /* 716 * quiesce(9E) entry point. 717 * 718 * This function is called when the system is single-threaded at high 719 * PIL with preemption disabled. Therefore, this function must not be 720 * blocked. 721 * 722 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 723 * DDI_FAILURE indicates an error condition and should almost never happen. 724 */ 725 static int 726 uhci_quiesce(dev_info_t *dip) 727 { 728 uhci_state_t *uhcip = uhci_obtain_state(dip); 729 730 if (uhcip == NULL) 731 return (DDI_FAILURE); 732 733 /* Disable interrupts */ 734 Set_OpReg16(USBINTR, DISABLE_ALL_INTRS); 735 736 /* Stop the Host Controller */ 737 Set_OpReg16(USBCMD, 0); 738 739 /* Clear all status bits */ 740 Set_OpReg16(USBSTS, Get_OpReg16(USBSTS) & UHCI_INTR_MASK); 741 742 return (DDI_SUCCESS); 743 } 744 745 746 /* 747 * uhci_info: 748 */ 749 /* ARGSUSED */ 750 static int 751 uhci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 752 { 753 dev_t dev; 754 int instance; 755 int error = DDI_FAILURE; 756 uhci_state_t *uhcip; 757 758 switch (infocmd) { 759 case DDI_INFO_DEVT2DEVINFO: 760 dev = (dev_t)arg; 761 instance = UHCI_UNIT(dev); 762 uhcip = ddi_get_soft_state(uhci_statep, instance); 763 if (uhcip != NULL) { 764 *result = (void *)uhcip->uhci_dip; 765 if (*result != NULL) { 766 error = DDI_SUCCESS; 767 } 768 } else { 769 *result = NULL; 770 } 771 772 break; 773 case DDI_INFO_DEVT2INSTANCE: 774 dev = (dev_t)arg; 775 instance = UHCI_UNIT(dev); 776 *result = (void *)(uintptr_t)instance; 777 error = DDI_SUCCESS; 778 779 break; 780 default: 781 break; 782 } 783 784 return (error); 785 } 786 787 788 /* 789 * uhci_cleanup: 790 * Cleanup on attach failure or detach 791 */ 792 static int 793 uhci_cleanup(uhci_state_t *uhcip) 794 { 795 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, "uhci_cleanup:"); 796 797 if (usba_hubdi_unbind_root_hub(uhcip->uhci_dip) != USB_SUCCESS) { 798 799 return (USB_FAILURE); 800 } 801 802 mutex_enter(&uhcip->uhci_int_mutex); 803 804 if (uhcip->uhci_cmd_timeout_id) { 805 timeout_id_t timeout_id = uhcip->uhci_cmd_timeout_id; 806 uhcip->uhci_cmd_timeout_id = 0; 807 mutex_exit(&uhcip->uhci_int_mutex); 808 (void) untimeout(timeout_id); 809 mutex_enter(&uhcip->uhci_int_mutex); 810 } 811 812 uhci_uninit_ctlr(uhcip); 813 814 mutex_exit(&uhcip->uhci_int_mutex); 815 816 /* do interrupt cleanup */ 817 if (uhcip->uhci_htable) { 818 uhci_rem_intrs(uhcip); 819 } 820 821 mutex_enter(&uhcip->uhci_int_mutex); 822 823 usba_hcdi_unregister(uhcip->uhci_dip); 824 825 uhci_unmap_regs(uhcip); 826 827 uhci_free_pools(uhcip); 828 829 mutex_exit(&uhcip->uhci_int_mutex); 830 831 mutex_destroy(&uhcip->uhci_int_mutex); 832 cv_destroy(&uhcip->uhci_cv_SOF); 833 sema_destroy(&uhcip->uhci_ocsem); 834 835 /* cleanup kstat structures */ 836 uhci_destroy_stats(uhcip); 837 838 usba_free_hcdi_ops(uhcip->uhci_hcdi_ops); 839 usb_free_log_hdl(uhcip->uhci_log_hdl); 840 ddi_prop_remove_all(uhcip->uhci_dip); 841 ddi_soft_state_free(uhci_statep, uhcip->uhci_instance); 842 843 return (USB_SUCCESS); 844 } 845 846 847 /* 848 * uhci_cpr_suspend 849 */ 850 static int 851 uhci_cpr_suspend(uhci_state_t *uhcip) 852 { 853 uint16_t cmd_reg; 854 int i; 855 856 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 857 "uhci_cpr_suspend:"); 858 859 /* Call into the root hub and suspend it */ 860 if (usba_hubdi_detach(uhcip->uhci_dip, DDI_SUSPEND) != DDI_SUCCESS) { 861 862 return (DDI_FAILURE); 863 } 864 865 mutex_enter(&uhcip->uhci_int_mutex); 866 867 /* Stop the Host Controller */ 868 cmd_reg = Get_OpReg16(USBCMD); 869 cmd_reg &= ~USBCMD_REG_HC_RUN; 870 Set_OpReg16(USBCMD, cmd_reg); 871 872 /* 873 * Wait for the duration of an SOF period until the host controller 874 * reaches the stopped state, indicated by the HCHalted bit in the 875 * USB status register. 876 */ 877 for (i = 0; i <= UHCI_TIMEWAIT / 1000; i++) { 878 if (Get_OpReg16(USBSTS) & USBSTS_REG_HC_HALTED) 879 break; 880 drv_usecwait(1000); 881 } 882 883 USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 884 "uhci_cpr_suspend: waited %d milliseconds for hc to halt", i); 885 886 /* Disable interrupts */ 887 Set_OpReg16(USBINTR, DISABLE_ALL_INTRS); 888 889 /* Clear any scheduled pending interrupts */ 890 Set_OpReg16(USBSTS, USBSTS_REG_HC_HALTED | 891 USBSTS_REG_HC_PROCESS_ERR | USBSTS_REG_HOST_SYS_ERR | 892 USBSTS_REG_RESUME_DETECT | USBSTS_REG_USB_ERR_INTR | 893 USBSTS_REG_USB_INTR); 894 895 /* Set Global Suspend bit */ 896 Set_OpReg16(USBCMD, USBCMD_REG_ENTER_GBL_SUSPEND); 897 898 /* Set host controller soft state to suspend */ 899 uhcip->uhci_hc_soft_state = UHCI_CTLR_SUSPEND_STATE; 900 901 mutex_exit(&uhcip->uhci_int_mutex); 902 903 return (USB_SUCCESS); 904 } 905 906 907 /* 908 * uhci_cpr_cleanup: 909 * 910 * Cleanup uhci specific information across resuming. 911 */ 912 static void 913 uhci_cpr_cleanup(uhci_state_t *uhcip) 914 { 915 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 916 917 /* Reset software part of usb frame number */ 918 uhcip->uhci_sw_frnum = 0; 919 } 920 921 922 /* 923 * uhci_cpr_resume 924 */ 925 static int 926 uhci_cpr_resume(uhci_state_t *uhcip) 927 { 928 USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 929 "uhci_cpr_resume: Restart the controller"); 930 931 mutex_enter(&uhcip->uhci_int_mutex); 932 933 /* Cleanup uhci specific information across cpr */ 934 uhci_cpr_cleanup(uhcip); 935 936 mutex_exit(&uhcip->uhci_int_mutex); 937 938 /* Restart the controller */ 939 if (uhci_init_ctlr(uhcip) != DDI_SUCCESS) { 940 941 USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, 942 "uhci_cpr_resume: uhci host controller resume failed "); 943 944 return (DDI_FAILURE); 945 } 946 947 mutex_enter(&uhcip->uhci_int_mutex); 948 949 /* 950 * Set HcInterruptEnable to enable all interrupts except Root 951 * Hub Status change and SOF interrupts. 952 */ 953 Set_OpReg16(USBINTR, ENABLE_ALL_INTRS); 954 955 mutex_exit(&uhcip->uhci_int_mutex); 956 957 /* Now resume the root hub */ 958 if (usba_hubdi_attach(uhcip->uhci_dip, DDI_RESUME) != DDI_SUCCESS) { 959 960 return (DDI_FAILURE); 961 } 962 963 return (DDI_SUCCESS); 964 } 965 966 967 /* 968 * uhci_intr: 969 * uhci interrupt handling routine. 970 */ 971 static uint_t 972 uhci_intr(caddr_t arg1, caddr_t arg2) 973 { 974 ushort_t intr_status, cmd_reg, intr_reg; 975 uhci_state_t *uhcip = (uhci_state_t *)arg1; 976 977 USB_DPRINTF_L4(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 978 "uhci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p", 979 (void *)arg1, (void *)arg2); 980 981 mutex_enter(&uhcip->uhci_int_mutex); 982 983 /* Any interrupt is not handled for the suspended device. */ 984 if (uhcip->uhci_hc_soft_state == UHCI_CTLR_SUSPEND_STATE) { 985 mutex_exit(&uhcip->uhci_int_mutex); 986 987 return (DDI_INTR_UNCLAIMED); 988 } 989 990 /* Get the status of the interrupts */ 991 intr_status = Get_OpReg16(USBSTS); 992 intr_reg = Get_OpReg16(USBINTR); 993 994 USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 995 "uhci_intr: intr_status = %x, intr_reg = %x", 996 intr_status, intr_reg); 997 998 /* 999 * If uhci interrupts are all disabled, the driver should return 1000 * unclaimed. 1001 * HC Process Error and Host System Error interrupts cannot be 1002 * disabled by intr register, and need to be judged separately. 1003 */ 1004 if (((intr_reg & ENABLE_ALL_INTRS) == 0) && 1005 ((intr_status & USBSTS_REG_HC_PROCESS_ERR) == 0) && 1006 ((intr_status & USBSTS_REG_HOST_SYS_ERR) == 0)) { 1007 1008 USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1009 "uhci_intr: interrupts disabled, unclaim"); 1010 mutex_exit(&uhcip->uhci_int_mutex); 1011 1012 return (DDI_INTR_UNCLAIMED); 1013 } 1014 1015 /* 1016 * If the intr is not from our controller, just return unclaimed. 1017 * HCHalted status bit cannot generate interrupts and should be 1018 * ignored. 1019 */ 1020 if (!(intr_status & UHCI_INTR_MASK)) { 1021 1022 USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1023 "uhci_intr: no interrupt status set, unclaim"); 1024 mutex_exit(&uhcip->uhci_int_mutex); 1025 1026 return (DDI_INTR_UNCLAIMED); 1027 } 1028 1029 /* Update kstat values */ 1030 uhci_do_intrs_stats(uhcip, intr_status); 1031 1032 /* Acknowledge the interrupt */ 1033 Set_OpReg16(USBSTS, intr_status); 1034 1035 /* 1036 * If uhci controller has not been initialized, just clear the 1037 * interrupter status and return claimed. 1038 */ 1039 if (uhcip->uhci_hc_soft_state != UHCI_CTLR_OPERATIONAL_STATE) { 1040 1041 USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1042 "uhci_intr: uhci controller is not in the operational " 1043 "state"); 1044 mutex_exit(&uhcip->uhci_int_mutex); 1045 1046 return (DDI_INTR_CLAIMED); 1047 } 1048 1049 /* 1050 * We configured the hw incorrectly, disable future interrupts. 1051 */ 1052 if ((intr_status & USBSTS_REG_HOST_SYS_ERR)) { 1053 USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1054 "uhci_intr: Sys Err Disabling Interrupt"); 1055 Set_OpReg16(USBINTR, DISABLE_ALL_INTRS); 1056 uhcip->uhci_hc_soft_state = UHCI_CTLR_ERROR_STATE; 1057 1058 mutex_exit(&uhcip->uhci_int_mutex); 1059 1060 return (DDI_INTR_CLAIMED); 1061 } 1062 1063 /* 1064 * Check whether a frame number overflow occurred. 1065 * if so, update the sw frame number. 1066 */ 1067 uhci_isoc_update_sw_frame_number(uhcip); 1068 1069 /* 1070 * Check whether any commands got completed. If so, process them. 1071 */ 1072 uhci_process_submitted_td_queue(uhcip); 1073 1074 /* 1075 * This should not occur. It occurs only if a HC controller 1076 * experiences internal problem. 1077 */ 1078 if (intr_status & USBSTS_REG_HC_HALTED) { 1079 USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1080 "uhci_intr: Controller halted"); 1081 cmd_reg = Get_OpReg16(USBCMD); 1082 Set_OpReg16(USBCMD, (cmd_reg | USBCMD_REG_HC_RUN)); 1083 } 1084 1085 /* 1086 * Wake up all the threads which are waiting for the Start of Frame 1087 */ 1088 if (uhcip->uhci_cv_signal == B_TRUE) { 1089 cv_broadcast(&uhcip->uhci_cv_SOF); 1090 uhcip->uhci_cv_signal = B_FALSE; 1091 } 1092 1093 mutex_exit(&uhcip->uhci_int_mutex); 1094 1095 return (DDI_INTR_CLAIMED); 1096 } 1097 1098 1099 /* 1100 * uhci_process_submitted_td_queue: 1101 * Traverse thru the submitted queue and process the completed ones. 1102 */ 1103 void 1104 uhci_process_submitted_td_queue(uhci_state_t *uhcip) 1105 { 1106 uhci_td_t *head = uhcip->uhci_outst_tds_head; 1107 uhci_trans_wrapper_t *tw; 1108 1109 while (head != NULL) { 1110 if ((!(GetTD_status(uhcip, head) & UHCI_TD_ACTIVE)) && 1111 (head->tw->tw_claim == UHCI_NOT_CLAIMED)) { 1112 tw = head->tw; 1113 1114 /* 1115 * Call the corresponding handle_td routine 1116 */ 1117 (*tw->tw_handle_td)(uhcip, head); 1118 1119 /* restart at the beginning again */ 1120 head = uhcip->uhci_outst_tds_head; 1121 } else { 1122 head = head->outst_td_next; 1123 } 1124 } 1125 } 1126 1127 1128 /* 1129 * uhci_handle_intr_td: 1130 * handles the completed interrupt transfer TD's. 1131 */ 1132 void 1133 uhci_handle_intr_td(uhci_state_t *uhcip, uhci_td_t *td) 1134 { 1135 usb_req_attrs_t attrs; 1136 uint_t bytes_xfered; 1137 usb_cr_t usb_err; 1138 uhci_trans_wrapper_t *tw = td->tw; 1139 uhci_pipe_private_t *pp = tw->tw_pipe_private; 1140 usb_intr_req_t *intr_reqp = 1141 (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 1142 usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 1143 1144 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1145 "uhci_handle_intr_td: intr_reqp = 0x%p", (void *)intr_reqp); 1146 1147 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 1148 1149 /* set tw->tw_claim flag, so that nobody else works on this td. */ 1150 tw->tw_claim = UHCI_INTR_HDLR_CLAIMED; 1151 1152 /* Interrupt OUT */ 1153 if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_OUT) { 1154 1155 /* process errors first */ 1156 usb_err = uhci_parse_td_error(uhcip, pp, td); 1157 1158 /* get the actual xfered data size */ 1159 bytes_xfered = GetTD_alen(uhcip, td); 1160 1161 /* check data underrun error */ 1162 if ((usb_err == USB_CR_OK) && (bytes_xfered != 1163 GetTD_mlen(uhcip, td))) { 1164 1165 USB_DPRINTF_L2(PRINT_MASK_LISTS, 1166 uhcip->uhci_log_hdl, "uhci_handle_intr_td:" 1167 " Intr out pipe, data underrun occurred"); 1168 1169 usb_err = USB_CR_DATA_UNDERRUN; 1170 1171 } 1172 1173 bytes_xfered = (bytes_xfered == ZERO_LENGTH) ? 1174 0 : bytes_xfered+1; 1175 tw->tw_bytes_xfered += bytes_xfered; 1176 uhci_do_byte_stats(uhcip, tw->tw_bytes_xfered, 1177 ph->p_ep.bmAttributes, ph->p_ep.bEndpointAddress); 1178 1179 1180 /* 1181 * If error occurred or all data xfered, delete the current td, 1182 * free tw, do the callback. Otherwise wait for the next td. 1183 */ 1184 if (usb_err != USB_CR_OK) { 1185 1186 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1187 "uhci_handle_intr_td: Intr out pipe error"); 1188 1189 /* update the element pointer */ 1190 SetQH32(uhcip, pp->pp_qh->element_ptr, GetTD32( 1191 uhcip, tw->tw_hctd_tail->link_ptr)); 1192 1193 1194 } else if (tw->tw_bytes_xfered == tw->tw_length) { 1195 1196 /* all data xfered */ 1197 USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1198 "uhci_handle_intr_td: Intr out pipe," 1199 " all data xfered"); 1200 1201 } else { 1202 1203 /* remove the current td and wait for the next one. */ 1204 uhci_delete_td(uhcip, td); 1205 tw->tw_claim = UHCI_NOT_CLAIMED; 1206 1207 return; 1208 } 1209 1210 uhci_delete_td(uhcip, td); 1211 uhci_hcdi_callback(uhcip, pp, ph, tw, usb_err); 1212 uhci_deallocate_tw(uhcip, tw->tw_pipe_private, tw); 1213 1214 return; 1215 } 1216 1217 /* Interrupt IN */ 1218 1219 /* Get the actual received data size */ 1220 tw->tw_bytes_xfered = GetTD_alen(uhcip, td); 1221 if (tw->tw_bytes_xfered == ZERO_LENGTH) { 1222 tw->tw_bytes_xfered = 0; 1223 } else { 1224 tw->tw_bytes_xfered++; 1225 } 1226 1227 /* process errors first */ 1228 if (GetTD_status(uhcip, td) & TD_STATUS_MASK) { 1229 SetQH32(uhcip, pp->pp_qh->element_ptr, 1230 GetTD32(uhcip, td->link_ptr)); 1231 1232 uhci_handle_intr_td_errors(uhcip, td, tw, pp); 1233 1234 return; 1235 } 1236 1237 /* 1238 * Check for data underruns. 1239 * For data underrun case, the host controller does not update 1240 * element pointer. So, we update here. 1241 */ 1242 if (GetTD_alen(uhcip, td) != GetTD_mlen(uhcip, td)) { 1243 SetQH32(uhcip, pp->pp_qh->element_ptr, 1244 GetTD32(uhcip, td->link_ptr)); 1245 } 1246 1247 /* 1248 * Call uhci_sendup_td_message to send message upstream. 1249 * The function uhci_sendup_td_message returns USB_NO_RESOURCES 1250 * if allocb fails and also sends error message to upstream by 1251 * calling USBA callback function. Under error conditions just 1252 * drop the current message. 1253 */ 1254 1255 /* Get the interrupt xfer attributes */ 1256 attrs = intr_reqp->intr_attributes; 1257 1258 /* 1259 * Check usb flag whether USB_FLAGS_ONE_XFER flag is set 1260 * and if so, free duplicate request. 1261 */ 1262 if (attrs & USB_ATTRS_ONE_XFER) { 1263 uhci_handle_one_xfer_completion(uhcip, USB_CR_OK, td); 1264 1265 return; 1266 } 1267 1268 /* save it temporarily */ 1269 if (tw->tw_bytes_xfered != 0) { 1270 uhci_sendup_td_message(uhcip, USB_CR_OK, tw); 1271 } 1272 1273 /* Clear the tw->tw_claim flag */ 1274 tw->tw_claim = UHCI_NOT_CLAIMED; 1275 1276 uhci_delete_td(uhcip, td); 1277 1278 /* allocate another interrupt periodic resource */ 1279 if (pp->pp_state == UHCI_PIPE_STATE_ACTIVE) { 1280 if (uhci_allocate_periodic_in_resource(uhcip, pp, tw, 0) != 1281 USB_SUCCESS) { 1282 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1283 "uhci_insert_intr_req: Interrupt request structure" 1284 "allocation failed"); 1285 1286 uhci_hcdi_callback(uhcip, pp, ph, 1287 tw, USB_CR_NO_RESOURCES); 1288 1289 return; 1290 } 1291 1292 /* Insert another interrupt TD */ 1293 if (uhci_insert_hc_td(uhcip, 0, 1294 tw->tw_length, pp, tw, PID_IN, attrs) != USB_SUCCESS) { 1295 1296 uhci_deallocate_periodic_in_resource(uhcip, pp, tw); 1297 1298 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1299 "uhci_handle_intr_td: TD exhausted"); 1300 1301 uhci_hcdi_callback(uhcip, pp, ph, 1302 tw, USB_CR_NO_RESOURCES); 1303 } 1304 } 1305 } 1306 1307 1308 /* 1309 * uhci_sendup_td_message: 1310 * 1311 * Get a message block and send the received message upstream. 1312 */ 1313 void 1314 uhci_sendup_td_message( 1315 uhci_state_t *uhcip, 1316 usb_cr_t usb_err, 1317 uhci_trans_wrapper_t *tw) 1318 { 1319 mblk_t *mp = NULL; 1320 size_t length = 0; 1321 size_t skip_len = 0; 1322 uchar_t *buf; 1323 usb_opaque_t curr_xfer_reqp = tw->tw_curr_xfer_reqp; 1324 uhci_pipe_private_t *pp = tw->tw_pipe_private; 1325 usb_ep_descr_t *ept = &pp->pp_pipe_handle->p_ep; 1326 1327 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 1328 1329 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1330 "uhci_sendup_td_message: bytes transferred=0x%x, " 1331 "bytes pending=0x%x", 1332 tw->tw_bytes_xfered, tw->tw_bytes_pending); 1333 1334 length = tw->tw_bytes_xfered; 1335 1336 switch (UHCI_XFER_TYPE(ept)) { 1337 case USB_EP_ATTR_CONTROL: 1338 skip_len = UHCI_CTRL_EPT_MAX_SIZE; /* length to skip */ 1339 mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data; 1340 break; 1341 case USB_EP_ATTR_INTR: 1342 mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data; 1343 break; 1344 case USB_EP_ATTR_BULK: 1345 mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data; 1346 break; 1347 case USB_EP_ATTR_ISOCH: 1348 length = tw->tw_length; 1349 mp = ((usb_isoc_req_t *)curr_xfer_reqp)->isoc_data; 1350 break; 1351 default: 1352 break; 1353 } 1354 1355 /* Copy the data into the mblk_t */ 1356 buf = (uchar_t *)tw->tw_buf + skip_len; 1357 1358 ASSERT(mp != NULL); 1359 1360 /* 1361 * Update kstat byte counts 1362 * The control endpoints don't have direction bits so in 1363 * order for control stats to be counted correctly an IN 1364 * bit must be faked on a control read. 1365 */ 1366 uhci_do_byte_stats(uhcip, length, ept->bmAttributes, 1367 (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_CONTROL) ? 1368 USB_EP_DIR_IN : ept->bEndpointAddress); 1369 1370 if (length) { 1371 int rval, i; 1372 uchar_t *p = mp->b_rptr; 1373 1374 if (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_ISOCH) { 1375 /* Deal with isoc data by packets */ 1376 for (i = 0; i < tw->tw_ncookies; i++) { 1377 rval = ddi_dma_sync( 1378 tw->tw_isoc_bufs[i].dma_handle, 0, 1379 tw->tw_isoc_bufs[i].length, 1380 DDI_DMA_SYNC_FORCPU); 1381 ASSERT(rval == DDI_SUCCESS); 1382 1383 ddi_rep_get8(tw->tw_isoc_bufs[i].mem_handle, 1384 p, (uint8_t *)tw->tw_isoc_bufs[i].buf_addr, 1385 tw->tw_isoc_bufs[i].length, 1386 DDI_DEV_AUTOINCR); 1387 p += tw->tw_isoc_bufs[i].length; 1388 } 1389 } else { 1390 /* Sync the streaming buffer */ 1391 rval = ddi_dma_sync(tw->tw_dmahandle, 0, 1392 (skip_len + length), DDI_DMA_SYNC_FORCPU); 1393 ASSERT(rval == DDI_SUCCESS); 1394 1395 /* Copy the data into the message */ 1396 ddi_rep_get8(tw->tw_accesshandle, 1397 mp->b_rptr, buf, length, DDI_DEV_AUTOINCR); 1398 } 1399 1400 /* Increment the write pointer */ 1401 mp->b_wptr += length; 1402 } else { 1403 USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1404 "uhci_sendup_td_message: Zero length packet"); 1405 } 1406 1407 /* Do the callback */ 1408 uhci_hcdi_callback(uhcip, pp, pp->pp_pipe_handle, tw, usb_err); 1409 } 1410 1411 1412 /* 1413 * uhci_handle_ctrl_td: 1414 * Handle a control Transfer Descriptor (TD). 1415 */ 1416 void 1417 uhci_handle_ctrl_td(uhci_state_t *uhcip, uhci_td_t *td) 1418 { 1419 ushort_t direction; 1420 ushort_t bytes_for_xfer; 1421 ushort_t bytes_xfered; 1422 ushort_t MaxPacketSize; 1423 usb_cr_t error; 1424 uhci_trans_wrapper_t *tw = td->tw; 1425 uhci_pipe_private_t *pp = tw->tw_pipe_private; 1426 usba_pipe_handle_data_t *usb_pp = pp->pp_pipe_handle; 1427 usb_ep_descr_t *eptd = &usb_pp->p_ep; 1428 usb_ctrl_req_t *reqp = (usb_ctrl_req_t *)tw->tw_curr_xfer_reqp; 1429 1430 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1431 "uhci_handle_ctrl_td: pp = 0x%p tw = 0x%p td = 0x%p " 1432 "state = 0x%x len = 0x%lx", (void *)pp, (void *)tw, 1433 (void *)td, tw->tw_ctrl_state, tw->tw_length); 1434 1435 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 1436 1437 error = uhci_parse_td_error(uhcip, pp, td); 1438 1439 /* 1440 * In case of control transfers, the device can send NAK when it 1441 * is busy. If a NAK is received, then send the status TD again. 1442 */ 1443 if (error != USB_CR_OK) { 1444 USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1445 "uhci_handle_ctrl_td: Ctrl cmd failed, error = %x", error); 1446 1447 SetQH32(uhcip, pp->pp_qh->element_ptr, 1448 GetTD32(uhcip, td->link_ptr)); 1449 uhci_delete_td(uhcip, td); 1450 1451 /* Return number of bytes xfered */ 1452 if (GetTD_alen(uhcip, td) != ZERO_LENGTH) { 1453 tw->tw_bytes_xfered = GetTD_alen(uhcip, td) + 1; 1454 } 1455 1456 USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1457 "uhci_handle_ctrl_td: Bytes transferred = %x", 1458 tw->tw_bytes_xfered); 1459 1460 if ((tw->tw_ctrl_state == DATA) && 1461 (tw->tw_direction == PID_IN)) { 1462 uhci_sendup_td_message(uhcip, error, tw); 1463 } else { 1464 uhci_hcdi_callback(uhcip, pp, usb_pp, tw, error); 1465 1466 uhci_deallocate_tw(uhcip, pp, tw); 1467 } 1468 1469 return; 1470 } 1471 1472 /* 1473 * A control transfer consists of three phases: 1474 * - Setup 1475 * - Data (optional) 1476 * - Status 1477 * 1478 * There is a TD per phase. A TD for a given phase isn't 1479 * enqueued until the previous phase is finished. 1480 */ 1481 switch (tw->tw_ctrl_state) { 1482 case SETUP: 1483 /* 1484 * Enqueue either the data or the status 1485 * phase depending on the length. 1486 */ 1487 pp->pp_data_toggle = 1; 1488 uhci_delete_td(uhcip, td); 1489 1490 /* 1491 * If the length is 0, move to the status. 1492 * If length is not 0, then we have some data 1493 * to move on the bus to device either IN or OUT. 1494 */ 1495 if ((tw->tw_length - SETUP_SIZE) == 0) { 1496 /* 1497 * There is no data stage, then 1498 * initiate status phase from the host. 1499 */ 1500 if ((uhci_insert_hc_td(uhcip, 0, 0, pp, tw, PID_IN, 1501 reqp->ctrl_attributes)) != USB_SUCCESS) { 1502 USB_DPRINTF_L2(PRINT_MASK_LISTS, 1503 uhcip->uhci_log_hdl, 1504 "uhci_handle_ctrl_td: No resources"); 1505 1506 uhci_hcdi_callback(uhcip, pp, usb_pp, tw, 1507 USB_CR_NO_RESOURCES); 1508 1509 return; 1510 } 1511 1512 tw->tw_ctrl_state = STATUS; 1513 } else { 1514 uint_t xx; 1515 1516 /* 1517 * Each USB device can send/receive 8/16/32/64 1518 * depending on wMaxPacketSize's implementation. 1519 * We need to insert 'N = Number of byte/ 1520 * MaxpktSize" TD's in the lattice to send/ 1521 * receive the data. Though the USB protocol 1522 * allows to insert more than one TD in the same 1523 * frame, we are inserting only one TD in one 1524 * frame. This is bcos OHCI has seen some problem 1525 * when multiple TD's are inserted at the same time. 1526 */ 1527 tw->tw_length -= UHCI_CTRL_EPT_MAX_SIZE; 1528 MaxPacketSize = eptd->wMaxPacketSize; 1529 1530 /* 1531 * We dont know the maximum packet size that 1532 * the device can handle(MaxPAcketSize=0). 1533 * In that case insert a data phase with 1534 * eight bytes or less. 1535 */ 1536 if (MaxPacketSize == 0) { 1537 xx = (tw->tw_length > 8) ? 8 : tw->tw_length; 1538 } else { 1539 xx = (tw->tw_length > MaxPacketSize) ? 1540 MaxPacketSize : tw->tw_length; 1541 } 1542 1543 tw->tw_tmp = xx; 1544 1545 /* 1546 * Create the TD. If this is an OUT 1547 * transaction, the data is already 1548 * in the buffer of the TW. 1549 * Get first 8 bytes of the command only. 1550 */ 1551 if ((uhci_insert_hc_td(uhcip, 1552 UHCI_CTRL_EPT_MAX_SIZE, xx, 1553 pp, tw, tw->tw_direction, 1554 reqp->ctrl_attributes)) != USB_SUCCESS) { 1555 1556 USB_DPRINTF_L2(PRINT_MASK_LISTS, 1557 uhcip->uhci_log_hdl, 1558 "uhci_handle_ctrl_td: No resources"); 1559 1560 uhci_hcdi_callback(uhcip, pp, usb_pp, tw, 1561 USB_CR_NO_RESOURCES); 1562 1563 return; 1564 } 1565 1566 tw->tw_ctrl_state = DATA; 1567 } 1568 1569 USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1570 "Setup complete: pp 0x%p td 0x%p", (void *)pp, (void *)td); 1571 1572 break; 1573 case DATA: 1574 uhci_delete_td(uhcip, td); 1575 1576 MaxPacketSize = eptd->wMaxPacketSize; 1577 1578 /* 1579 * Decrement pending bytes and increment the total 1580 * number bytes transferred by the actual number of bytes 1581 * transferred in this TD. If the number of bytes transferred 1582 * is less than requested, that means an underrun has 1583 * occurred. Set the tw_tmp varible to indicate UNDER run. 1584 */ 1585 bytes_xfered = GetTD_alen(uhcip, td); 1586 if (bytes_xfered == ZERO_LENGTH) { 1587 bytes_xfered = 0; 1588 } else { 1589 bytes_xfered++; 1590 } 1591 1592 tw->tw_bytes_pending -= bytes_xfered; 1593 tw->tw_bytes_xfered += bytes_xfered; 1594 1595 if (bytes_xfered < tw->tw_tmp) { 1596 tw->tw_bytes_pending = 0; 1597 tw->tw_tmp = UHCI_UNDERRUN_OCCURRED; 1598 1599 /* 1600 * Controller does not update the queue head 1601 * element pointer when a data underrun occurs. 1602 */ 1603 SetQH32(uhcip, pp->pp_qh->element_ptr, 1604 GetTD32(uhcip, td->link_ptr)); 1605 } 1606 1607 if (bytes_xfered > tw->tw_tmp) { 1608 tw->tw_bytes_pending = 0; 1609 tw->tw_tmp = UHCI_OVERRUN_OCCURRED; 1610 } 1611 1612 /* 1613 * If no more bytes are pending, insert status 1614 * phase. Otherwise insert data phase. 1615 */ 1616 if (tw->tw_bytes_pending) { 1617 bytes_for_xfer = (tw->tw_bytes_pending > 1618 MaxPacketSize) ? MaxPacketSize : 1619 tw->tw_bytes_pending; 1620 1621 tw->tw_tmp = bytes_for_xfer; 1622 1623 if ((uhci_insert_hc_td(uhcip, 1624 UHCI_CTRL_EPT_MAX_SIZE + tw->tw_bytes_xfered, 1625 bytes_for_xfer, pp, tw, 1626 tw->tw_direction, 1627 reqp->ctrl_attributes)) != USB_SUCCESS) { 1628 USB_DPRINTF_L2(PRINT_MASK_LISTS, 1629 uhcip->uhci_log_hdl, 1630 "uhci_handle_ctrl_td: No TD"); 1631 1632 uhci_hcdi_callback(uhcip, pp, usb_pp, 1633 tw, USB_NO_RESOURCES); 1634 1635 return; 1636 } 1637 1638 tw->tw_ctrl_state = DATA; 1639 1640 break; 1641 } 1642 1643 pp->pp_data_toggle = 1; 1644 direction = (tw->tw_direction == PID_IN) ? PID_OUT : PID_IN; 1645 1646 if ((uhci_insert_hc_td(uhcip, 0, 0, pp, tw, direction, 1647 reqp->ctrl_attributes)) != USB_SUCCESS) { 1648 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1649 "uhci_handle_ctrl_td: TD exhausted"); 1650 1651 uhci_hcdi_callback(uhcip, pp, usb_pp, tw, 1652 USB_NO_RESOURCES); 1653 1654 return; 1655 } 1656 1657 tw->tw_ctrl_state = STATUS; 1658 USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1659 "Data complete: pp 0x%p td 0x%p", (void *)pp, (void *)td); 1660 1661 break; 1662 case STATUS: 1663 /* 1664 * Send the data to the client if it is a DATA IN, 1665 * else send just return status for DATA OUT commnads. 1666 * And set the tw_claim flag. 1667 */ 1668 tw->tw_claim = UHCI_INTR_HDLR_CLAIMED; 1669 1670 if ((tw->tw_length != 0) && (tw->tw_direction == PID_IN)) { 1671 usb_req_attrs_t attrs = ((usb_ctrl_req_t *) 1672 tw->tw_curr_xfer_reqp)->ctrl_attributes; 1673 /* 1674 * Call uhci_sendup_td_message to send message 1675 * upstream. The function uhci_sendup_td_message 1676 * returns USB_NO_RESOURCES if allocb fails and 1677 * also sends error message to upstream by calling 1678 * USBA callback function. 1679 * 1680 * Under error conditions just drop the current msg. 1681 */ 1682 if ((tw->tw_tmp == UHCI_UNDERRUN_OCCURRED) && 1683 (!(attrs & USB_ATTRS_SHORT_XFER_OK))) { 1684 error = USB_CR_DATA_UNDERRUN; 1685 } else if (tw->tw_tmp == UHCI_OVERRUN_OCCURRED) { 1686 error = USB_CR_DATA_OVERRUN; 1687 } 1688 uhci_sendup_td_message(uhcip, error, tw); 1689 1690 } else { 1691 uhci_do_byte_stats(uhcip, tw->tw_length, 1692 eptd->bmAttributes, eptd->bEndpointAddress); 1693 1694 uhci_hcdi_callback(uhcip, pp, usb_pp, tw, USB_CR_OK); 1695 } 1696 1697 USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1698 "Status complete: pp 0x%p td 0x%p", (void *)pp, (void *)td); 1699 1700 uhci_delete_td(uhcip, td); 1701 uhci_deallocate_tw(uhcip, pp, tw); 1702 1703 break; 1704 default: 1705 USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1706 "uhci_handle_ctrl_td: Bad control state"); 1707 1708 uhci_hcdi_callback(uhcip, pp, usb_pp, tw, 1709 USB_CR_UNSPECIFIED_ERR); 1710 } 1711 } 1712 1713 1714 /* 1715 * uhci_handle_intr_td_errors: 1716 * Handles the errors encountered for the interrupt transfers. 1717 */ 1718 static void 1719 uhci_handle_intr_td_errors(uhci_state_t *uhcip, uhci_td_t *td, 1720 uhci_trans_wrapper_t *tw, uhci_pipe_private_t *pp) 1721 { 1722 usb_cr_t usb_err; 1723 usb_intr_req_t *intr_reqp = 1724 (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 1725 1726 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1727 "uhci_handle_intr_td_errors: td = 0x%p tw = 0x%p", 1728 (void *)td, (void *)tw); 1729 1730 usb_err = uhci_parse_td_error(uhcip, pp, td); 1731 1732 if (intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) { 1733 uhci_handle_one_xfer_completion(uhcip, usb_err, td); 1734 1735 return; 1736 } 1737 1738 uhci_delete_td(uhcip, td); 1739 uhci_sendup_td_message(uhcip, usb_err, tw); 1740 uhci_deallocate_tw(uhcip, tw->tw_pipe_private, tw); 1741 } 1742 1743 1744 /* 1745 * uhci_handle_one_xfer_completion: 1746 */ 1747 static void 1748 uhci_handle_one_xfer_completion( 1749 uhci_state_t *uhcip, 1750 usb_cr_t usb_err, 1751 uhci_td_t *td) 1752 { 1753 uhci_trans_wrapper_t *tw = td->tw; 1754 uhci_pipe_private_t *pp = tw->tw_pipe_private; 1755 usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 1756 usb_intr_req_t *intr_reqp = 1757 (usb_intr_req_t *)tw->tw_curr_xfer_reqp; 1758 1759 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1760 "uhci_handle_one_xfer_completion: td = 0x%p", (void *)td); 1761 1762 ASSERT(intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER); 1763 1764 /* set state to idle */ 1765 pp->pp_state = UHCI_PIPE_STATE_IDLE; 1766 1767 ((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))-> 1768 intr_data = ((usb_intr_req_t *)(tw->tw_curr_xfer_reqp))->intr_data; 1769 1770 ((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL; 1771 1772 /* now free duplicate current request */ 1773 usb_free_intr_req((usb_intr_req_t *)tw->tw_curr_xfer_reqp); 1774 mutex_enter(&ph->p_mutex); 1775 ph->p_req_count--; 1776 mutex_exit(&ph->p_mutex); 1777 1778 /* make client's request the current request */ 1779 tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 1780 pp->pp_client_periodic_in_reqp = NULL; 1781 1782 uhci_sendup_td_message(uhcip, usb_err, tw); 1783 /* Clear the tw->tw_claim flag */ 1784 tw->tw_claim = UHCI_NOT_CLAIMED; 1785 1786 uhci_delete_td(uhcip, td); 1787 uhci_deallocate_tw(uhcip, pp, tw); 1788 } 1789 1790 1791 /* 1792 * uhci_parse_td_error 1793 * Parses the Transfer Descriptors error 1794 */ 1795 usb_cr_t 1796 uhci_parse_td_error(uhci_state_t *uhcip, uhci_pipe_private_t *pp, uhci_td_t *td) 1797 { 1798 uint_t status; 1799 1800 status = GetTD_status(uhcip, td) & TD_STATUS_MASK; 1801 1802 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1803 "uhci_parse_td_error: status_bits=0x%x", status); 1804 1805 if (UHCI_XFER_TYPE(&pp->pp_pipe_handle->p_ep) == USB_EP_ATTR_ISOCH) { 1806 1807 return (USB_CR_OK); 1808 } 1809 1810 if (!status) { 1811 1812 return (USB_CR_OK); 1813 } 1814 1815 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1816 "uhci_parse_td_error: status_bits=0x%x", status); 1817 1818 1819 if (status & UHCI_TD_BITSTUFF_ERR) { 1820 1821 return (USB_CR_BITSTUFFING); 1822 } 1823 1824 if (status & UHCI_TD_CRC_TIMEOUT) { 1825 pp->pp_data_toggle = GetTD_dtogg(uhcip, td); 1826 1827 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1828 "uhci_parse_td_error: timeout & data toggle reset; " 1829 "data toggle: %x", pp->pp_data_toggle); 1830 1831 return ((GetTD_PID(uhcip, td) == PID_IN) ? USB_CR_DEV_NOT_RESP : 1832 USB_CR_TIMEOUT); 1833 } 1834 1835 if (status & UHCI_TD_BABBLE_ERR) { 1836 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1837 "babble error"); 1838 1839 return (USB_CR_UNSPECIFIED_ERR); 1840 } 1841 1842 if (status & UHCI_TD_DATA_BUFFER_ERR) { 1843 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1844 "buffer error"); 1845 1846 return ((GetTD_PID(uhcip, td) == PID_IN) ? 1847 USB_CR_BUFFER_OVERRUN : USB_CR_BUFFER_UNDERRUN); 1848 } 1849 1850 if (status & UHCI_TD_STALLED) { 1851 pp->pp_data_toggle = 0; 1852 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1853 "uhci_parse_td_error: stall; data toggle reset; " 1854 "data toggle: %x", pp->pp_data_toggle); 1855 1856 return (USB_CR_STALL); 1857 } 1858 1859 if (status) { 1860 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 1861 "unspecified error=0x%x", status); 1862 } 1863 1864 return (USB_CR_OK); 1865 } 1866 1867 1868 static dev_info_t * 1869 uhci_get_dip(dev_t dev) 1870 { 1871 int instance = UHCI_UNIT(dev); 1872 uhci_state_t *uhcip = ddi_get_soft_state(uhci_statep, instance); 1873 1874 return (uhcip ? uhcip->uhci_dip : NULL); 1875 } 1876 1877 1878 /* 1879 * cb_ops entry points 1880 */ 1881 static int 1882 uhci_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1883 { 1884 dev_info_t *dip = uhci_get_dip(*devp); 1885 1886 return (usba_hubdi_open(dip, devp, flags, otyp, credp)); 1887 } 1888 1889 1890 static int 1891 uhci_close(dev_t dev, int flag, int otyp, cred_t *credp) 1892 { 1893 dev_info_t *dip = uhci_get_dip(dev); 1894 1895 return (usba_hubdi_close(dip, dev, flag, otyp, credp)); 1896 } 1897 1898 1899 static int 1900 uhci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 1901 cred_t *credp, int *rvalp) 1902 { 1903 dev_info_t *dip = uhci_get_dip(dev); 1904 1905 return (usba_hubdi_ioctl(dip, dev, cmd, arg, mode, credp, rvalp)); 1906 } 1907