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