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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * EHCI Host Controller Driver (EHCI) 30 * 31 * The EHCI driver is a software driver which interfaces to the Universal 32 * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 33 * the Host Controller is defined by the EHCI Host Controller Interface. 34 * 35 * This file contains code for Auto-configuration and HCDI entry points. 36 * 37 * NOTE: 38 * 39 * Currently EHCI driver does not support the following features 40 * 41 * - Alternate QTD for short xfer condition is only used in Bulk xfers. 42 * - Frame Span Traversal Nodes (FSTN). 43 * - Bandwidth allocation scheme needs to be updated for FSTN and USB2.0 44 * or High speed hub with multiple TT implementation. Currently bandwidth 45 * allocation scheme assumes one TT per USB2.0 or High speed hub. 46 * - 64 bit addressing capability. 47 * - Programmable periodic frame list size like 256, 512, 1024. 48 * It supports only 1024 periodic frame list size. 49 */ 50 51 #include <sys/usb/hcd/ehci/ehcid.h> 52 #include <sys/usb/hcd/ehci/ehci_xfer.h> 53 #include <sys/usb/hcd/ehci/ehci_intr.h> 54 #include <sys/usb/hcd/ehci/ehci_util.h> 55 #include <sys/usb/hcd/ehci/ehci_isoch.h> 56 57 /* Pointer to the state structure */ 58 void *ehci_statep; 59 60 /* Number of instances */ 61 #define EHCI_INSTS 1 62 63 /* Debugging information */ 64 uint_t ehci_errmask = (uint_t)PRINT_MASK_ALL; 65 uint_t ehci_errlevel = USB_LOG_L2; 66 uint_t ehci_instance_debug = (uint_t)-1; 67 68 /* Enable all workarounds for VIA VT62x2 */ 69 uint_t ehci_vt62x2_workaround = EHCI_VIA_WORKAROUNDS; 70 71 /* 72 * EHCI Auto-configuration entry points. 73 * 74 * Device operations (dev_ops) entries function prototypes. 75 * 76 * We use the hub cbops since all nexus ioctl operations defined so far will 77 * be executed by the root hub. The following are the Host Controller Driver 78 * (HCD) entry points. 79 * 80 * the open/close/ioctl functions call the corresponding usba_hubdi_* 81 * calls after looking up the dip thru the dev_t. 82 */ 83 static int ehci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 84 static int ehci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 85 static int ehci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd); 86 static int ehci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 87 void *arg, void **result); 88 89 static int ehci_open(dev_t *devp, int flags, int otyp, cred_t *credp); 90 static int ehci_close(dev_t dev, int flag, int otyp, cred_t *credp); 91 static int ehci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 92 cred_t *credp, int *rvalp); 93 94 int usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level); 95 96 static struct cb_ops ehci_cb_ops = { 97 ehci_open, /* EHCI */ 98 ehci_close, /* Close */ 99 nodev, /* Strategy */ 100 nodev, /* Print */ 101 nodev, /* Dump */ 102 nodev, /* Read */ 103 nodev, /* Write */ 104 ehci_ioctl, /* Ioctl */ 105 nodev, /* Devmap */ 106 nodev, /* Mmap */ 107 nodev, /* Segmap */ 108 nochpoll, /* Poll */ 109 ddi_prop_op, /* cb_prop_op */ 110 NULL, /* Streamtab */ 111 D_NEW | D_MP | D_HOTPLUG /* Driver compatibility flag */ 112 }; 113 114 static struct dev_ops ehci_ops = { 115 DEVO_REV, /* Devo_rev */ 116 0, /* Refcnt */ 117 ehci_info, /* Info */ 118 nulldev, /* Identify */ 119 nulldev, /* Probe */ 120 ehci_attach, /* Attach */ 121 ehci_detach, /* Detach */ 122 ehci_reset, /* Reset */ 123 &ehci_cb_ops, /* Driver operations */ 124 &usba_hubdi_busops, /* Bus operations */ 125 usba_hubdi_root_hub_power /* Power */ 126 }; 127 128 /* 129 * The USBA library must be loaded for this driver. 130 */ 131 static struct modldrv modldrv = { 132 &mod_driverops, /* Type of module. This one is a driver */ 133 "USB EHCI Driver %I%", /* Name of the module. */ 134 &ehci_ops, /* Driver ops */ 135 }; 136 137 static struct modlinkage modlinkage = { 138 MODREV_1, (void *)&modldrv, NULL 139 }; 140 141 142 int 143 _init(void) 144 { 145 int error; 146 147 /* Initialize the soft state structures */ 148 if ((error = ddi_soft_state_init(&ehci_statep, sizeof (ehci_state_t), 149 EHCI_INSTS)) != 0) { 150 return (error); 151 } 152 153 /* Install the loadable module */ 154 if ((error = mod_install(&modlinkage)) != 0) { 155 ddi_soft_state_fini(&ehci_statep); 156 } 157 158 return (error); 159 } 160 161 162 int 163 _info(struct modinfo *modinfop) 164 { 165 return (mod_info(&modlinkage, modinfop)); 166 } 167 168 169 int 170 _fini(void) 171 { 172 int error; 173 174 if ((error = mod_remove(&modlinkage)) == 0) { 175 176 /* Release per module resources */ 177 ddi_soft_state_fini(&ehci_statep); 178 } 179 180 return (error); 181 } 182 183 184 /* 185 * EHCI Auto configuration entry points. 186 */ 187 188 /* 189 * ehci_attach: 190 * 191 * Description: Attach entry point is called by the Kernel. 192 * Allocates resources for each EHCI host controller instance. 193 * Initializes the EHCI Host Controller. 194 * 195 * Return : DDI_SUCCESS / DDI_FAILURE. 196 */ 197 static int 198 ehci_attach(dev_info_t *dip, 199 ddi_attach_cmd_t cmd) 200 { 201 int instance; 202 ehci_state_t *ehcip = NULL; 203 usba_hcdi_register_args_t hcdi_args; 204 205 switch (cmd) { 206 case DDI_ATTACH: 207 break; 208 case DDI_RESUME: 209 ehcip = ehci_obtain_state(dip); 210 211 return (ehci_cpr_resume(ehcip)); 212 default: 213 return (DDI_FAILURE); 214 } 215 216 /* Get the instance and create soft state */ 217 instance = ddi_get_instance(dip); 218 219 if (ddi_soft_state_zalloc(ehci_statep, instance) != 0) { 220 221 return (DDI_FAILURE); 222 } 223 224 ehcip = ddi_get_soft_state(ehci_statep, instance); 225 if (ehcip == NULL) { 226 227 return (DDI_FAILURE); 228 } 229 230 ehcip->ehci_flags = EHCI_ATTACH; 231 232 ehcip->ehci_log_hdl = usb_alloc_log_hdl(dip, "ehci", &ehci_errlevel, 233 &ehci_errmask, &ehci_instance_debug, 0); 234 235 ehcip->ehci_flags |= EHCI_ZALLOC; 236 237 /* Set host controller soft state to initialization */ 238 ehcip->ehci_hc_soft_state = EHCI_CTLR_INIT_STATE; 239 240 USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 241 "ehcip = 0x%p", (void *)ehcip); 242 243 /* Initialize the DMA attributes */ 244 ehci_set_dma_attributes(ehcip); 245 246 /* Save the dip and instance */ 247 ehcip->ehci_dip = dip; 248 ehcip->ehci_instance = instance; 249 250 /* Initialize the DMA attributes */ 251 ehci_create_stats(ehcip); 252 253 /* Create the qtd and qh pools */ 254 if (ehci_allocate_pools(ehcip) != DDI_SUCCESS) { 255 (void) ehci_cleanup(ehcip); 256 257 return (DDI_FAILURE); 258 } 259 260 /* Initialize the isochronous resources */ 261 if (ehci_isoc_init(ehcip) != DDI_SUCCESS) { 262 (void) ehci_cleanup(ehcip); 263 264 return (DDI_FAILURE); 265 } 266 267 /* Map the registers */ 268 if (ehci_map_regs(ehcip) != DDI_SUCCESS) { 269 (void) ehci_cleanup(ehcip); 270 271 return (DDI_FAILURE); 272 } 273 274 /* Get the ehci chip vendor and device id */ 275 ehcip->ehci_vendor_id = pci_config_get16( 276 ehcip->ehci_config_handle, PCI_CONF_VENID); 277 ehcip->ehci_device_id = pci_config_get16( 278 ehcip->ehci_config_handle, PCI_CONF_DEVID); 279 ehcip->ehci_rev_id = pci_config_get8( 280 ehcip->ehci_config_handle, PCI_CONF_REVID); 281 282 /* Register interrupts */ 283 if (ehci_register_intrs_and_init_mutex(ehcip) != DDI_SUCCESS) { 284 (void) ehci_cleanup(ehcip); 285 286 return (DDI_FAILURE); 287 } 288 289 mutex_enter(&ehcip->ehci_int_mutex); 290 291 /* Initialize the controller */ 292 if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) { 293 mutex_exit(&ehcip->ehci_int_mutex); 294 (void) ehci_cleanup(ehcip); 295 296 return (DDI_FAILURE); 297 } 298 299 /* 300 * At this point, the hardware will be okay. 301 * Initialize the usba_hcdi structure 302 */ 303 ehcip->ehci_hcdi_ops = ehci_alloc_hcdi_ops(ehcip); 304 305 mutex_exit(&ehcip->ehci_int_mutex); 306 307 /* 308 * Make this HCD instance known to USBA 309 * (dma_attr must be passed for USBA busctl's) 310 */ 311 hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION; 312 hcdi_args.usba_hcdi_register_dip = dip; 313 hcdi_args.usba_hcdi_register_ops = ehcip->ehci_hcdi_ops; 314 hcdi_args.usba_hcdi_register_dma_attr = &ehcip->ehci_dma_attr; 315 316 /* 317 * Priority and iblock_cookie are one and the same 318 * (However, retaining hcdi_soft_iblock_cookie for now 319 * assigning it w/ priority. In future all iblock_cookie 320 * could just go) 321 */ 322 hcdi_args.usba_hcdi_register_iblock_cookie = 323 (ddi_iblock_cookie_t)(uintptr_t)ehcip->ehci_intr_pri; 324 325 if (usba_hcdi_register(&hcdi_args, 0) != DDI_SUCCESS) { 326 (void) ehci_cleanup(ehcip); 327 328 return (DDI_FAILURE); 329 } 330 331 ehcip->ehci_flags |= EHCI_USBAREG; 332 333 mutex_enter(&ehcip->ehci_int_mutex); 334 335 if ((ehci_init_root_hub(ehcip)) != USB_SUCCESS) { 336 mutex_exit(&ehcip->ehci_int_mutex); 337 (void) ehci_cleanup(ehcip); 338 339 return (DDI_FAILURE); 340 } 341 342 mutex_exit(&ehcip->ehci_int_mutex); 343 344 /* Finally load the root hub driver */ 345 if (ehci_load_root_hub_driver(ehcip) != USB_SUCCESS) { 346 (void) ehci_cleanup(ehcip); 347 348 return (DDI_FAILURE); 349 } 350 ehcip->ehci_flags |= EHCI_RHREG; 351 352 /* Display information in the banner */ 353 ddi_report_dev(dip); 354 355 mutex_enter(&ehcip->ehci_int_mutex); 356 357 /* Reset the ehci initialization flag */ 358 ehcip->ehci_flags &= ~EHCI_ATTACH; 359 360 /* Print the Host Control's Operational registers */ 361 ehci_print_caps(ehcip); 362 ehci_print_regs(ehcip); 363 364 (void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000); 365 366 mutex_exit(&ehcip->ehci_int_mutex); 367 368 USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 369 "ehci_attach: dip = 0x%p done", (void *)dip); 370 371 return (DDI_SUCCESS); 372 } 373 374 375 /* 376 * ehci_detach: 377 * 378 * Description: Detach entry point is called by the Kernel. 379 * Deallocates all resource allocated. 380 * Unregisters the interrupt handler. 381 * 382 * Return : DDI_SUCCESS / DDI_FAILURE 383 */ 384 int 385 ehci_detach(dev_info_t *dip, 386 ddi_detach_cmd_t cmd) 387 { 388 ehci_state_t *ehcip = ehci_obtain_state(dip); 389 390 USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_detach:"); 391 392 switch (cmd) { 393 case DDI_DETACH: 394 395 return (ehci_cleanup(ehcip)); 396 case DDI_SUSPEND: 397 398 return (ehci_cpr_suspend(ehcip)); 399 default: 400 401 return (DDI_FAILURE); 402 } 403 } 404 405 /* 406 * ehci_reset: 407 * 408 * Description: Reset entry point - called by the Kernel 409 * on the way down. 410 * Toshiba Tecra laptop has been observed to hang 411 * on soft reboot. The resetting ehci on the way 412 * down solves the problem. 413 * 414 * Return : DDI_SUCCESS / DDI_FAILURE 415 */ 416 /* ARGSUSED */ 417 static int 418 ehci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 419 { 420 #if defined(__sparc) 421 /* 422 * Don't reset the host controller on SPARC, for OBP needs Solaris 423 * to continue to provide keyboard support after shutdown of SPARC, 424 * or the keyboard connected to a USB 2.0 port will not work after 425 * that. The incomplete reset problem on Toshiba Tecra laptop is 426 * specific to Tecra laptop or BIOS, not present on SPARC. The SPARC 427 * OBP guarantees good reset behavior during startup. 428 */ 429 return (DDI_SUCCESS); 430 #else 431 ehci_state_t *ehcip = ehci_obtain_state(dip); 432 433 mutex_enter(&ehcip->ehci_int_mutex); 434 435 /* 436 * To reset the host controller, the HCRESET bit should be set to one. 437 * Software should not set this bit to a one when the HCHalted bit in 438 * the USBSTS register is a zero. Attempting to reset an actively 439 * running host controller will result in undefined behavior. 440 * see EHCI SPEC. for more information. 441 */ 442 if (!(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 443 444 /* Stop the EHCI host controller */ 445 Set_OpReg(ehci_command, 446 Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 447 /* 448 * When this bit is set to 0, the Host Controller completes the 449 * current and any actively pipelined transactions on the USB 450 * and then halts. The Host Controller must halt within 16 451 * micro-frames after software clears the Run bit. 452 * The HC Halted bit in the status register indicates when the 453 * Host Controller has finished its pending pipelined 454 * transactions and has entered the stopped state. 455 */ 456 drv_usecwait(EHCI_RESET_TIMEWAIT); 457 } 458 459 /* Reset the EHCI host controller */ 460 Set_OpReg(ehci_command, 461 Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET); 462 463 mutex_exit(&ehcip->ehci_int_mutex); 464 465 return (DDI_SUCCESS); 466 #endif 467 } 468 469 /* 470 * ehci_info: 471 */ 472 /* ARGSUSED */ 473 static int 474 ehci_info(dev_info_t *dip, 475 ddi_info_cmd_t infocmd, 476 void *arg, 477 void **result) 478 { 479 dev_t dev; 480 ehci_state_t *ehcip; 481 int instance; 482 int error = DDI_FAILURE; 483 484 switch (infocmd) { 485 case DDI_INFO_DEVT2DEVINFO: 486 dev = (dev_t)arg; 487 instance = EHCI_UNIT(dev); 488 ehcip = ddi_get_soft_state(ehci_statep, instance); 489 if (ehcip != NULL) { 490 *result = (void *)ehcip->ehci_dip; 491 if (*result != NULL) { 492 error = DDI_SUCCESS; 493 } 494 } else { 495 *result = NULL; 496 } 497 498 break; 499 case DDI_INFO_DEVT2INSTANCE: 500 dev = (dev_t)arg; 501 instance = EHCI_UNIT(dev); 502 *result = (void *)(uintptr_t)instance; 503 error = DDI_SUCCESS; 504 break; 505 default: 506 break; 507 } 508 509 return (error); 510 } 511 512 513 /* 514 * EHCI CB_OPS entry points. 515 */ 516 static dev_info_t * 517 ehci_get_dip(dev_t dev) 518 { 519 int instance = EHCI_UNIT(dev); 520 ehci_state_t *ehcip = ddi_get_soft_state(ehci_statep, instance); 521 522 if (ehcip) { 523 524 return (ehcip->ehci_dip); 525 } else { 526 527 return (NULL); 528 } 529 } 530 531 532 static int 533 ehci_open(dev_t *devp, 534 int flags, 535 int otyp, 536 cred_t *credp) 537 { 538 dev_info_t *dip = ehci_get_dip(*devp); 539 540 return (usba_hubdi_open(dip, devp, flags, otyp, credp)); 541 } 542 543 544 static int 545 ehci_close(dev_t dev, 546 int flag, 547 int otyp, 548 cred_t *credp) 549 { 550 dev_info_t *dip = ehci_get_dip(dev); 551 552 return (usba_hubdi_close(dip, dev, flag, otyp, credp)); 553 } 554 555 556 static int 557 ehci_ioctl(dev_t dev, 558 int cmd, 559 intptr_t arg, 560 int mode, 561 cred_t *credp, 562 int *rvalp) 563 { 564 dev_info_t *dip = ehci_get_dip(dev); 565 566 return (usba_hubdi_ioctl(dip, 567 dev, cmd, arg, mode, credp, rvalp)); 568 } 569 570 /* 571 * EHCI Interrupt Handler entry point. 572 */ 573 574 /* 575 * ehci_intr: 576 * 577 * EHCI (EHCI) interrupt handling routine. 578 */ 579 uint_t 580 ehci_intr(caddr_t arg1, caddr_t arg2) 581 { 582 uint_t intr; 583 ehci_state_t *ehcip = (ehci_state_t *)arg1; 584 585 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 586 "ehci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p", arg1, arg2); 587 588 /* Get the ehci global mutex */ 589 mutex_enter(&ehcip->ehci_int_mutex); 590 591 /* 592 * Now process the actual ehci interrupt events that caused 593 * invocation of this ehci interrupt handler. 594 */ 595 intr = (Get_OpReg(ehci_status) & Get_OpReg(ehci_interrupt)); 596 597 /* Update kstat values */ 598 ehci_do_intrs_stats(ehcip, intr); 599 600 /* 601 * We could have gotten a spurious interrupts. If so, do not 602 * claim it. This is quite possible on some architectures 603 * where more than one PCI slots share the IRQs. If so, the 604 * associated driver's interrupt routine may get called even 605 * if the interrupt is not meant for them. 606 * 607 * By unclaiming the interrupt, the other driver gets chance 608 * to service its interrupt. 609 */ 610 if (!intr) { 611 mutex_exit(&ehcip->ehci_int_mutex); 612 613 return (DDI_INTR_UNCLAIMED); 614 } 615 616 /* Acknowledge the interrupt */ 617 Set_OpReg(ehci_status, intr); 618 619 if (ehcip->ehci_hc_soft_state == EHCI_CTLR_ERROR_STATE) { 620 mutex_exit(&ehcip->ehci_int_mutex); 621 622 return (DDI_INTR_CLAIMED); 623 } 624 625 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 626 "Interrupt status 0x%x", intr); 627 628 /* 629 * If necessary broadcast that an interrupt has occured. This 630 * is only necessary during controller init. 631 */ 632 if (ehcip->ehci_flags & EHCI_CV_INTR) { 633 ehcip->ehci_flags &= ~EHCI_CV_INTR; 634 cv_broadcast(&ehcip->ehci_async_schedule_advance_cv); 635 } 636 637 /* Check for Frame List Rollover */ 638 if (intr & EHCI_INTR_FRAME_LIST_ROLLOVER) { 639 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 640 "ehci_intr: Frame List Rollover"); 641 642 ehci_handle_frame_list_rollover(ehcip); 643 644 /* VIA VT6202 looses EHCI_INTR_USB interrupts, workaround. */ 645 if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 646 (ehci_vt62x2_workaround & EHCI_VIA_LOST_INTERRUPTS)) { 647 ehcip->ehci_missed_intr_sts |= EHCI_INTR_USB; 648 } 649 } 650 651 /* Check for Advance on Asynchronous Schedule */ 652 if (intr & EHCI_INTR_ASYNC_ADVANCE) { 653 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 654 "ehci_intr: Asynchronous Schedule Advance Notification"); 655 656 /* Disable async list advance interrupt */ 657 Set_OpReg(ehci_interrupt, 658 (Get_OpReg(ehci_interrupt) & ~EHCI_INTR_ASYNC_ADVANCE)); 659 660 /* 661 * Call cv_broadcast on every this interrupt to wakeup 662 * all the threads that are waiting the async list advance 663 * event. 664 */ 665 cv_broadcast(&ehcip->ehci_async_schedule_advance_cv); 666 } 667 668 /* Always process completed itds */ 669 ehci_traverse_active_isoc_list(ehcip); 670 671 /* 672 * Check for any USB transaction completion notification. Also 673 * process any missed USB transaction completion interrupts. 674 */ 675 if ((intr & EHCI_INTR_USB) || (intr & EHCI_INTR_USB_ERROR) || 676 (ehcip->ehci_missed_intr_sts & EHCI_INTR_USB) || 677 (ehcip->ehci_missed_intr_sts & EHCI_INTR_USB_ERROR)) { 678 679 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 680 "ehci_intr: USB Transaction Completion Notification"); 681 682 /* Clear missed interrupts */ 683 if (ehcip->ehci_missed_intr_sts) { 684 ehcip->ehci_missed_intr_sts = 0; 685 } 686 687 /* Process completed qtds */ 688 ehci_traverse_active_qtd_list(ehcip); 689 } 690 691 /* Process endpoint reclamation list */ 692 if (ehcip->ehci_reclaim_list) { 693 ehci_handle_endpoint_reclaimation(ehcip); 694 } 695 696 /* Check for Host System Error */ 697 if (intr & EHCI_INTR_HOST_SYSTEM_ERROR) { 698 USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 699 "ehci_intr: Unrecoverable error"); 700 701 ehci_handle_ue(ehcip); 702 } 703 704 /* 705 * Read interrupt status register to make sure that any PIO 706 * store to clear the ISR has made it on the PCI bus before 707 * returning from its interrupt handler. 708 */ 709 (void) Get_OpReg(ehci_status); 710 711 /* Release the ehci global mutex */ 712 mutex_exit(&ehcip->ehci_int_mutex); 713 714 USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 715 "Interrupt handling completed"); 716 717 return (DDI_INTR_CLAIMED); 718 } 719 720 721 /* 722 * EHCI HCDI entry points 723 * 724 * The Host Controller Driver Interfaces (HCDI) are the software interfaces 725 * between the Universal Serial Bus Layer (USBA) and the Host Controller 726 * Driver (HCD). The HCDI interfaces or entry points are subject to change. 727 */ 728 729 /* 730 * ehci_hcdi_pipe_open: 731 * 732 * Member of HCD Ops structure and called during client specific pipe open 733 * Add the pipe to the data structure representing the device and allocate 734 * bandwidth for the pipe if it is a interrupt or isochronous endpoint. 735 */ 736 int 737 ehci_hcdi_pipe_open( 738 usba_pipe_handle_data_t *ph, 739 usb_flags_t flags) 740 { 741 ehci_state_t *ehcip = ehci_obtain_state( 742 ph->p_usba_device->usb_root_hub_dip); 743 usb_ep_descr_t *epdt = &ph->p_ep; 744 int rval, error = USB_SUCCESS; 745 int kmflag = (flags & USB_FLAGS_SLEEP) ? 746 KM_SLEEP : KM_NOSLEEP; 747 uchar_t smask = 0; 748 uchar_t cmask = 0; 749 uint_t pnode = 0; 750 ehci_pipe_private_t *pp; 751 752 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 753 "ehci_hcdi_pipe_open: addr = 0x%x, ep%d", 754 ph->p_usba_device->usb_addr, 755 epdt->bEndpointAddress & USB_EP_NUM_MASK); 756 757 mutex_enter(&ehcip->ehci_int_mutex); 758 rval = ehci_state_is_operational(ehcip); 759 mutex_exit(&ehcip->ehci_int_mutex); 760 761 if (rval != USB_SUCCESS) { 762 763 return (rval); 764 } 765 766 /* 767 * Check and handle root hub pipe open. 768 */ 769 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 770 771 mutex_enter(&ehcip->ehci_int_mutex); 772 error = ehci_handle_root_hub_pipe_open(ph, flags); 773 mutex_exit(&ehcip->ehci_int_mutex); 774 775 return (error); 776 } 777 778 /* 779 * Opening of other pipes excluding root hub pipe are 780 * handled below. Check whether pipe is already opened. 781 */ 782 if (ph->p_hcd_private) { 783 USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 784 "ehci_hcdi_pipe_open: Pipe is already opened"); 785 786 return (USB_FAILURE); 787 } 788 789 /* 790 * A portion of the bandwidth is reserved for the non-periodic 791 * transfers, i.e control and bulk transfers in each of one 792 * millisecond frame period & usually it will be 20% of frame 793 * period. Hence there is no need to check for the available 794 * bandwidth before adding the control or bulk endpoints. 795 * 796 * There is a need to check for the available bandwidth before 797 * adding the periodic transfers, i.e interrupt & isochronous, 798 * since all these periodic transfers are guaranteed transfers. 799 * Usually 80% of the total frame time is reserved for periodic 800 * transfers. 801 */ 802 if (EHCI_PERIODIC_ENDPOINT(epdt)) { 803 804 mutex_enter(&ehcip->ehci_int_mutex); 805 mutex_enter(&ph->p_mutex); 806 807 error = ehci_allocate_bandwidth(ehcip, 808 ph, &pnode, &smask, &cmask); 809 810 if (error != USB_SUCCESS) { 811 812 USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 813 "ehci_hcdi_pipe_open: Bandwidth allocation failed"); 814 815 mutex_exit(&ph->p_mutex); 816 mutex_exit(&ehcip->ehci_int_mutex); 817 818 return (error); 819 } 820 821 mutex_exit(&ph->p_mutex); 822 mutex_exit(&ehcip->ehci_int_mutex); 823 } 824 825 /* Create the HCD pipe private structure */ 826 pp = kmem_zalloc(sizeof (ehci_pipe_private_t), kmflag); 827 828 /* 829 * Return failure if ehci pipe private 830 * structure allocation fails. 831 */ 832 if (pp == NULL) { 833 834 mutex_enter(&ehcip->ehci_int_mutex); 835 836 /* Deallocate bandwidth */ 837 if (EHCI_PERIODIC_ENDPOINT(epdt)) { 838 839 mutex_enter(&ph->p_mutex); 840 ehci_deallocate_bandwidth(ehcip, 841 ph, pnode, smask, cmask); 842 mutex_exit(&ph->p_mutex); 843 } 844 845 mutex_exit(&ehcip->ehci_int_mutex); 846 847 return (USB_NO_RESOURCES); 848 } 849 850 mutex_enter(&ehcip->ehci_int_mutex); 851 852 /* Save periodic nodes */ 853 pp->pp_pnode = pnode; 854 855 /* Save start and complete split mask values */ 856 pp->pp_smask = smask; 857 pp->pp_cmask = cmask; 858 859 /* Create prototype for xfer completion condition variable */ 860 cv_init(&pp->pp_xfer_cmpl_cv, NULL, CV_DRIVER, NULL); 861 862 /* Set the state of pipe as idle */ 863 pp->pp_state = EHCI_PIPE_STATE_IDLE; 864 865 /* Store a pointer to the pipe handle */ 866 pp->pp_pipe_handle = ph; 867 868 mutex_enter(&ph->p_mutex); 869 870 /* Store the pointer in the pipe handle */ 871 ph->p_hcd_private = (usb_opaque_t)pp; 872 873 /* Store a copy of the pipe policy */ 874 bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t)); 875 876 mutex_exit(&ph->p_mutex); 877 878 /* Allocate the host controller endpoint descriptor */ 879 pp->pp_qh = ehci_alloc_qh(ehcip, ph, NULL); 880 881 /* Initialize the halting flag */ 882 pp->pp_halt_state = EHCI_HALT_STATE_FREE; 883 884 /* Create prototype for halt completion condition variable */ 885 cv_init(&pp->pp_halt_cmpl_cv, NULL, CV_DRIVER, NULL); 886 887 /* Isoch does not use QH, so ignore this */ 888 if ((pp->pp_qh == NULL) && !(EHCI_ISOC_ENDPOINT(epdt))) { 889 ASSERT(pp->pp_qh == NULL); 890 891 USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 892 "ehci_hcdi_pipe_open: QH allocation failed"); 893 894 mutex_enter(&ph->p_mutex); 895 896 /* Deallocate bandwidth */ 897 if (EHCI_PERIODIC_ENDPOINT(epdt)) { 898 899 ehci_deallocate_bandwidth(ehcip, 900 ph, pnode, smask, cmask); 901 } 902 903 /* Destroy the xfer completion condition variable */ 904 cv_destroy(&pp->pp_xfer_cmpl_cv); 905 906 /* 907 * Deallocate the hcd private portion 908 * of the pipe handle. 909 */ 910 kmem_free(ph->p_hcd_private, sizeof (ehci_pipe_private_t)); 911 912 /* 913 * Set the private structure in the 914 * pipe handle equal to NULL. 915 */ 916 ph->p_hcd_private = NULL; 917 918 mutex_exit(&ph->p_mutex); 919 mutex_exit(&ehcip->ehci_int_mutex); 920 921 return (USB_NO_RESOURCES); 922 } 923 924 /* 925 * Isoch does not use QH so no need to 926 * restore data toggle or insert QH 927 */ 928 if (!(EHCI_ISOC_ENDPOINT(epdt))) { 929 /* Restore the data toggle information */ 930 ehci_restore_data_toggle(ehcip, ph); 931 } 932 933 /* 934 * Insert the endpoint onto the host controller's 935 * appropriate endpoint list. The host controller 936 * will not schedule this endpoint and will not have 937 * any QTD's to process. It will also update the pipe count. 938 */ 939 ehci_insert_qh(ehcip, ph); 940 941 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 942 "ehci_hcdi_pipe_open: ph = 0x%p", (void *)ph); 943 944 ehcip->ehci_open_pipe_count++; 945 946 mutex_exit(&ehcip->ehci_int_mutex); 947 948 return (USB_SUCCESS); 949 } 950 951 952 /* 953 * ehci_hcdi_pipe_close: 954 * 955 * Member of HCD Ops structure and called during the client specific pipe 956 * close. Remove the pipe and the data structure representing the device. 957 * Deallocate bandwidth for the pipe if it is a interrupt or isochronous 958 * endpoint. 959 */ 960 /* ARGSUSED */ 961 int 962 ehci_hcdi_pipe_close( 963 usba_pipe_handle_data_t *ph, 964 usb_flags_t flags) 965 { 966 ehci_state_t *ehcip = ehci_obtain_state( 967 ph->p_usba_device->usb_root_hub_dip); 968 ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 969 usb_ep_descr_t *eptd = &ph->p_ep; 970 int error = USB_SUCCESS; 971 972 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 973 "ehci_hcdi_pipe_close: addr = 0x%x, ep%d", 974 ph->p_usba_device->usb_addr, 975 eptd->bEndpointAddress & USB_EP_NUM_MASK); 976 977 /* Check and handle root hub pipe close */ 978 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 979 980 mutex_enter(&ehcip->ehci_int_mutex); 981 error = ehci_handle_root_hub_pipe_close(ph); 982 mutex_exit(&ehcip->ehci_int_mutex); 983 984 return (error); 985 } 986 987 ASSERT(ph->p_hcd_private != NULL); 988 989 mutex_enter(&ehcip->ehci_int_mutex); 990 991 /* Set pipe state to pipe close */ 992 pp->pp_state = EHCI_PIPE_STATE_CLOSE; 993 994 ehci_pipe_cleanup(ehcip, ph); 995 996 /* 997 * Remove the endpoint descriptor from Host 998 * Controller's appropriate endpoint list. 999 */ 1000 ehci_remove_qh(ehcip, pp, B_TRUE); 1001 1002 /* Deallocate bandwidth */ 1003 if (EHCI_PERIODIC_ENDPOINT(eptd)) { 1004 1005 mutex_enter(&ph->p_mutex); 1006 ehci_deallocate_bandwidth(ehcip, ph, pp->pp_pnode, 1007 pp->pp_smask, pp->pp_cmask); 1008 mutex_exit(&ph->p_mutex); 1009 } 1010 1011 mutex_enter(&ph->p_mutex); 1012 1013 /* Destroy the xfer completion condition variable */ 1014 cv_destroy(&pp->pp_xfer_cmpl_cv); 1015 1016 1017 /* Destory halt completion condition variable */ 1018 cv_destroy(&pp->pp_halt_cmpl_cv); 1019 1020 /* 1021 * Deallocate the hcd private portion 1022 * of the pipe handle. 1023 */ 1024 kmem_free(ph->p_hcd_private, sizeof (ehci_pipe_private_t)); 1025 ph->p_hcd_private = NULL; 1026 1027 mutex_exit(&ph->p_mutex); 1028 1029 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1030 "ehci_hcdi_pipe_close: ph = 0x%p", (void *)ph); 1031 1032 ehcip->ehci_open_pipe_count--; 1033 1034 mutex_exit(&ehcip->ehci_int_mutex); 1035 1036 return (error); 1037 } 1038 1039 1040 /* 1041 * ehci_hcdi_pipe_reset: 1042 */ 1043 /* ARGSUSED */ 1044 int 1045 ehci_hcdi_pipe_reset( 1046 usba_pipe_handle_data_t *ph, 1047 usb_flags_t usb_flags) 1048 { 1049 ehci_state_t *ehcip = ehci_obtain_state( 1050 ph->p_usba_device->usb_root_hub_dip); 1051 ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 1052 int error = USB_SUCCESS; 1053 1054 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1055 "ehci_hcdi_pipe_reset:"); 1056 1057 /* 1058 * Check and handle root hub pipe reset. 1059 */ 1060 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 1061 1062 error = ehci_handle_root_hub_pipe_reset(ph, usb_flags); 1063 return (error); 1064 } 1065 1066 mutex_enter(&ehcip->ehci_int_mutex); 1067 1068 /* Set pipe state to pipe reset */ 1069 pp->pp_state = EHCI_PIPE_STATE_RESET; 1070 1071 ehci_pipe_cleanup(ehcip, ph); 1072 1073 mutex_exit(&ehcip->ehci_int_mutex); 1074 1075 return (error); 1076 } 1077 1078 /* 1079 * ehci_hcdi_pipe_ctrl_xfer: 1080 */ 1081 int 1082 ehci_hcdi_pipe_ctrl_xfer( 1083 usba_pipe_handle_data_t *ph, 1084 usb_ctrl_req_t *ctrl_reqp, 1085 usb_flags_t usb_flags) 1086 { 1087 ehci_state_t *ehcip = ehci_obtain_state( 1088 ph->p_usba_device->usb_root_hub_dip); 1089 ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 1090 int rval; 1091 int error = USB_SUCCESS; 1092 ehci_trans_wrapper_t *tw; 1093 1094 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1095 "ehci_hcdi_pipe_ctrl_xfer: ph = 0x%p reqp = 0x%p flags = %x", 1096 (void *)ph, ctrl_reqp, usb_flags); 1097 1098 mutex_enter(&ehcip->ehci_int_mutex); 1099 rval = ehci_state_is_operational(ehcip); 1100 mutex_exit(&ehcip->ehci_int_mutex); 1101 1102 if (rval != USB_SUCCESS) { 1103 1104 return (rval); 1105 } 1106 1107 /* 1108 * Check and handle root hub control request. 1109 */ 1110 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 1111 1112 error = ehci_handle_root_hub_request(ehcip, ph, ctrl_reqp); 1113 1114 return (error); 1115 } 1116 1117 mutex_enter(&ehcip->ehci_int_mutex); 1118 1119 /* 1120 * Check whether pipe is in halted state. 1121 */ 1122 if (pp->pp_state == EHCI_PIPE_STATE_ERROR) { 1123 1124 USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1125 "ehci_hcdi_pipe_ctrl_xfer: " 1126 "Pipe is in error state, need pipe reset to continue"); 1127 1128 mutex_exit(&ehcip->ehci_int_mutex); 1129 1130 return (USB_FAILURE); 1131 } 1132 1133 /* Allocate a transfer wrapper */ 1134 if ((tw = ehci_allocate_ctrl_resources(ehcip, pp, ctrl_reqp, 1135 usb_flags)) == NULL) { 1136 1137 error = USB_NO_RESOURCES; 1138 } else { 1139 /* Insert the qtd's on the endpoint */ 1140 ehci_insert_ctrl_req(ehcip, ph, ctrl_reqp, tw, usb_flags); 1141 } 1142 1143 mutex_exit(&ehcip->ehci_int_mutex); 1144 1145 return (error); 1146 } 1147 1148 1149 /* 1150 * ehci_hcdi_bulk_transfer_size: 1151 * 1152 * Return maximum bulk transfer size 1153 */ 1154 1155 /* ARGSUSED */ 1156 int 1157 ehci_hcdi_bulk_transfer_size( 1158 usba_device_t *usba_device, 1159 size_t *size) 1160 { 1161 ehci_state_t *ehcip = ehci_obtain_state( 1162 usba_device->usb_root_hub_dip); 1163 int rval; 1164 1165 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1166 "ehci_hcdi_bulk_transfer_size:"); 1167 1168 mutex_enter(&ehcip->ehci_int_mutex); 1169 rval = ehci_state_is_operational(ehcip); 1170 mutex_exit(&ehcip->ehci_int_mutex); 1171 1172 if (rval != USB_SUCCESS) { 1173 1174 return (rval); 1175 } 1176 1177 /* VIA VT6202 may not handle bigger xfers well, workaround. */ 1178 if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 1179 (ehci_vt62x2_workaround & EHCI_VIA_REDUCED_MAX_BULK_XFER_SIZE)) { 1180 *size = EHCI_VIA_MAX_BULK_XFER_SIZE; 1181 } else { 1182 *size = EHCI_MAX_BULK_XFER_SIZE; 1183 } 1184 1185 return (USB_SUCCESS); 1186 } 1187 1188 1189 /* 1190 * ehci_hcdi_pipe_bulk_xfer: 1191 */ 1192 int 1193 ehci_hcdi_pipe_bulk_xfer( 1194 usba_pipe_handle_data_t *ph, 1195 usb_bulk_req_t *bulk_reqp, 1196 usb_flags_t usb_flags) 1197 { 1198 ehci_state_t *ehcip = ehci_obtain_state( 1199 ph->p_usba_device->usb_root_hub_dip); 1200 ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 1201 int rval, error = USB_SUCCESS; 1202 ehci_trans_wrapper_t *tw; 1203 1204 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1205 "ehci_hcdi_pipe_bulk_xfer: ph = 0x%p reqp = 0x%p flags = %x", 1206 (void *)ph, bulk_reqp, usb_flags); 1207 1208 mutex_enter(&ehcip->ehci_int_mutex); 1209 rval = ehci_state_is_operational(ehcip); 1210 1211 if (rval != USB_SUCCESS) { 1212 mutex_exit(&ehcip->ehci_int_mutex); 1213 1214 return (rval); 1215 } 1216 1217 /* 1218 * Check whether pipe is in halted state. 1219 */ 1220 if (pp->pp_state == EHCI_PIPE_STATE_ERROR) { 1221 1222 USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1223 "ehci_hcdi_pipe_bulk_xfer:" 1224 "Pipe is in error state, need pipe reset to continue"); 1225 1226 mutex_exit(&ehcip->ehci_int_mutex); 1227 1228 return (USB_FAILURE); 1229 } 1230 1231 /* Allocate a transfer wrapper */ 1232 if ((tw = ehci_allocate_bulk_resources(ehcip, pp, bulk_reqp, 1233 usb_flags)) == NULL) { 1234 1235 error = USB_NO_RESOURCES; 1236 } else { 1237 /* Add the QTD into the Host Controller's bulk list */ 1238 ehci_insert_bulk_req(ehcip, ph, bulk_reqp, tw, usb_flags); 1239 } 1240 1241 mutex_exit(&ehcip->ehci_int_mutex); 1242 1243 return (error); 1244 } 1245 1246 1247 /* 1248 * ehci_hcdi_pipe_intr_xfer: 1249 */ 1250 int 1251 ehci_hcdi_pipe_intr_xfer( 1252 usba_pipe_handle_data_t *ph, 1253 usb_intr_req_t *intr_reqp, 1254 usb_flags_t usb_flags) 1255 { 1256 ehci_state_t *ehcip = ehci_obtain_state( 1257 ph->p_usba_device->usb_root_hub_dip); 1258 int pipe_dir, rval, error = USB_SUCCESS; 1259 ehci_trans_wrapper_t *tw; 1260 1261 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1262 "ehci_hcdi_pipe_intr_xfer: ph = 0x%p reqp = 0x%p flags = %x", 1263 (void *)ph, intr_reqp, usb_flags); 1264 1265 mutex_enter(&ehcip->ehci_int_mutex); 1266 rval = ehci_state_is_operational(ehcip); 1267 1268 if (rval != USB_SUCCESS) { 1269 mutex_exit(&ehcip->ehci_int_mutex); 1270 1271 return (rval); 1272 } 1273 1274 /* Get the pipe direction */ 1275 pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 1276 1277 if (pipe_dir == USB_EP_DIR_IN) { 1278 error = ehci_start_periodic_pipe_polling(ehcip, ph, 1279 (usb_opaque_t)intr_reqp, usb_flags); 1280 } else { 1281 /* Allocate transaction resources */ 1282 if ((tw = ehci_allocate_intr_resources(ehcip, ph, 1283 intr_reqp, usb_flags)) == NULL) { 1284 1285 error = USB_NO_RESOURCES; 1286 } else { 1287 ehci_insert_intr_req(ehcip, 1288 (ehci_pipe_private_t *)ph->p_hcd_private, 1289 tw, usb_flags); 1290 } 1291 } 1292 1293 mutex_exit(&ehcip->ehci_int_mutex); 1294 1295 return (error); 1296 } 1297 1298 /* 1299 * ehci_hcdi_pipe_stop_intr_polling() 1300 */ 1301 int 1302 ehci_hcdi_pipe_stop_intr_polling( 1303 usba_pipe_handle_data_t *ph, 1304 usb_flags_t flags) 1305 { 1306 ehci_state_t *ehcip = ehci_obtain_state( 1307 ph->p_usba_device->usb_root_hub_dip); 1308 int error = USB_SUCCESS; 1309 1310 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1311 "ehci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x", 1312 (void *)ph, flags); 1313 1314 mutex_enter(&ehcip->ehci_int_mutex); 1315 1316 error = ehci_stop_periodic_pipe_polling(ehcip, ph, flags); 1317 1318 mutex_exit(&ehcip->ehci_int_mutex); 1319 1320 return (error); 1321 } 1322 1323 1324 /* 1325 * ehci_hcdi_get_current_frame_number: 1326 * 1327 * Return the current usb frame number 1328 */ 1329 usb_frame_number_t 1330 ehci_hcdi_get_current_frame_number(usba_device_t *usba_device) 1331 { 1332 ehci_state_t *ehcip = ehci_obtain_state( 1333 usba_device->usb_root_hub_dip); 1334 usb_frame_number_t frame_number; 1335 int rval; 1336 1337 ehcip = ehci_obtain_state(usba_device->usb_root_hub_dip); 1338 1339 mutex_enter(&ehcip->ehci_int_mutex); 1340 rval = ehci_state_is_operational(ehcip); 1341 1342 if (rval != USB_SUCCESS) { 1343 mutex_exit(&ehcip->ehci_int_mutex); 1344 1345 return (rval); 1346 } 1347 1348 frame_number = ehci_get_current_frame_number(ehcip); 1349 1350 mutex_exit(&ehcip->ehci_int_mutex); 1351 1352 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1353 "ehci_hcdi_get_current_frame_number: " 1354 "Current frame number 0x%llx", frame_number); 1355 1356 return (frame_number); 1357 } 1358 1359 1360 /* 1361 * ehci_hcdi_get_max_isoc_pkts: 1362 * 1363 * Return maximum isochronous packets per usb isochronous request 1364 */ 1365 uint_t 1366 ehci_hcdi_get_max_isoc_pkts(usba_device_t *usba_device) 1367 { 1368 ehci_state_t *ehcip = ehci_obtain_state( 1369 usba_device->usb_root_hub_dip); 1370 uint_t max_isoc_pkts_per_request; 1371 int rval; 1372 1373 mutex_enter(&ehcip->ehci_int_mutex); 1374 rval = ehci_state_is_operational(ehcip); 1375 mutex_exit(&ehcip->ehci_int_mutex); 1376 1377 if (rval != USB_SUCCESS) { 1378 1379 return (rval); 1380 } 1381 1382 max_isoc_pkts_per_request = EHCI_MAX_ISOC_PKTS_PER_XFER; 1383 1384 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1385 "ehci_hcdi_get_max_isoc_pkts: maximum isochronous" 1386 "packets per usb isochronous request = 0x%x", 1387 max_isoc_pkts_per_request); 1388 1389 return (max_isoc_pkts_per_request); 1390 } 1391 1392 1393 /* 1394 * ehci_hcdi_pipe_isoc_xfer: 1395 */ 1396 int 1397 ehci_hcdi_pipe_isoc_xfer( 1398 usba_pipe_handle_data_t *ph, 1399 usb_isoc_req_t *isoc_reqp, 1400 usb_flags_t usb_flags) 1401 { 1402 ehci_state_t *ehcip = ehci_obtain_state( 1403 ph->p_usba_device->usb_root_hub_dip); 1404 1405 int pipe_dir, rval; 1406 ehci_isoc_xwrapper_t *itw; 1407 1408 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1409 "ehci_hcdi_pipe_isoc_xfer: ph = 0x%p reqp = 0x%p flags = 0x%x", 1410 (void *)ph, isoc_reqp, usb_flags); 1411 1412 mutex_enter(&ehcip->ehci_int_mutex); 1413 rval = ehci_state_is_operational(ehcip); 1414 1415 if (rval != USB_SUCCESS) { 1416 mutex_exit(&ehcip->ehci_int_mutex); 1417 1418 return (rval); 1419 } 1420 1421 /* Get the isochronous pipe direction */ 1422 pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 1423 1424 if (pipe_dir == USB_EP_DIR_IN) { 1425 rval = ehci_start_periodic_pipe_polling(ehcip, ph, 1426 (usb_opaque_t)isoc_reqp, usb_flags); 1427 } else { 1428 /* Allocate transaction resources */ 1429 if ((itw = ehci_allocate_isoc_resources(ehcip, ph, 1430 isoc_reqp, usb_flags)) == NULL) { 1431 rval = USB_NO_RESOURCES; 1432 } else { 1433 rval = ehci_insert_isoc_req(ehcip, 1434 (ehci_pipe_private_t *)ph->p_hcd_private, 1435 itw, usb_flags); 1436 } 1437 } 1438 1439 mutex_exit(&ehcip->ehci_int_mutex); 1440 1441 return (rval); 1442 } 1443 1444 1445 /* 1446 * ehci_hcdi_pipe_stop_isoc_polling() 1447 */ 1448 /*ARGSUSED*/ 1449 int 1450 ehci_hcdi_pipe_stop_isoc_polling( 1451 usba_pipe_handle_data_t *ph, 1452 usb_flags_t flags) 1453 { 1454 ehci_state_t *ehcip = ehci_obtain_state( 1455 ph->p_usba_device->usb_root_hub_dip); 1456 int rval; 1457 1458 USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 1459 "ehci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x", 1460 (void *)ph, flags); 1461 1462 mutex_enter(&ehcip->ehci_int_mutex); 1463 rval = ehci_state_is_operational(ehcip); 1464 1465 if (rval != USB_SUCCESS) { 1466 mutex_exit(&ehcip->ehci_int_mutex); 1467 1468 return (rval); 1469 } 1470 1471 rval = ehci_stop_periodic_pipe_polling(ehcip, ph, flags); 1472 1473 mutex_exit(&ehcip->ehci_int_mutex); 1474 1475 return (rval); 1476 } 1477