1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * EHCI Host Controller Driver (EHCI) 29 * 30 * The EHCI driver is a software driver which interfaces to the Universal 31 * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 32 * the Host Controller is defined by the EHCI Host Controller Interface. 33 * 34 * This module contains the code for root hub related functions. 35 * 36 * NOTE: 37 * 38 * ONE_XFER is not supported on root hub interrupt polling 39 */ 40 41 #include <sys/usb/hcd/ehci/ehcid.h> 42 #include <sys/usb/hcd/ehci/ehci_util.h> 43 #include <sys/usb/usba/usba_types.h> 44 45 /* Static function prototypes */ 46 static int ehci_handle_set_clear_port_feature( 47 ehci_state_t *ehcip, 48 uchar_t bRequest, 49 uint16_t wValue, 50 uint16_t port); 51 static void ehci_handle_port_power( 52 ehci_state_t *ehcip, 53 uint16_t port, 54 uint_t on); 55 static void ehci_handle_port_enable( 56 ehci_state_t *ehcip, 57 uint16_t port, 58 uint_t on); 59 static void ehci_handle_clrchng_port_enable( 60 ehci_state_t *ehcip, 61 uint16_t port); 62 static void ehci_handle_port_suspend( 63 ehci_state_t *ehcip, 64 uint16_t port, 65 uint_t on); 66 static void ehci_handle_clrchng_port_suspend( 67 ehci_state_t *ehcip, 68 uint16_t port); 69 static void ehci_handle_port_reset( 70 ehci_state_t *ehcip, 71 uint16_t port); 72 static void ehci_root_hub_reset_occured( 73 ehci_state_t *ehcip); 74 static void ehci_handle_complete_port_reset( 75 ehci_state_t *ehcip, 76 uint16_t port); 77 static void ehci_handle_clear_port_connection( 78 ehci_state_t *ehcip, 79 uint16_t port); 80 static void ehci_handle_clrchng_port_over_current( 81 ehci_state_t *ehcip, 82 uint16_t port); 83 static void ehci_handle_get_port_status( 84 ehci_state_t *ehcip, 85 uint16_t port); 86 static void ehci_handle_get_hub_descriptor( 87 ehci_state_t *ehcip); 88 static void ehci_handle_get_hub_status( 89 ehci_state_t *ehcip); 90 static void ehci_handle_get_device_status( 91 ehci_state_t *ehcip); 92 static uint_t ehci_get_root_hub_port_status( 93 ehci_state_t *ehcip, 94 uint16_t port); 95 static int ehci_is_port_owner( 96 ehci_state_t *ehcip, 97 uint16_t port); 98 static int ehci_root_hub_allocate_intr_pipe_resource( 99 ehci_state_t *ehcip, 100 usb_flags_t flags); 101 static void ehci_root_hub_intr_pipe_cleanup( 102 ehci_state_t *ehcip, 103 usb_cr_t completion_reason); 104 static void ehci_handle_root_hub_status_change(void *arg); 105 static void ehci_root_hub_hcdi_callback( 106 usba_pipe_handle_data_t *ph, 107 usb_cr_t completion_reason); 108 109 110 /* 111 * ehci_init_root_hub: 112 * 113 * Initialize the root hub 114 */ 115 int 116 ehci_init_root_hub(ehci_state_t *ehcip) 117 { 118 usb_hub_descr_t *root_hub_descr = 119 &ehcip->ehci_root_hub.rh_descr; 120 uint_t i, length, port_state; 121 uint32_t capability; 122 123 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 124 "ehci_init_root_hub:"); 125 126 /* Read the EHCI capability register */ 127 capability = Get_Cap(ehci_hcs_params); 128 129 /* 130 * Build the Root hub descriptor by looking EHCI capability 131 * and operational registers. 132 */ 133 root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE; 134 135 if ((capability & EHCI_HCS_NUM_PORTS) > EHCI_MAX_RH_PORTS) { 136 137 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 138 "ehci_init_root_hub: Invalid no of root hub ports 0x%x", 139 capability & EHCI_HCS_NUM_PORTS); 140 141 return (USB_FAILURE); 142 } 143 144 /* Obtain the number of downstream ports */ 145 root_hub_descr->bNbrPorts = capability & EHCI_HCS_NUM_PORTS; 146 147 length = root_hub_descr->bNbrPorts / 8; 148 149 if (length) { 150 root_hub_descr->bDescLength = 7 + (2 * (length + 1)); 151 } else { 152 root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH; 153 } 154 155 /* 156 * Obtain the number of Classic or Companion USB 1.1 (OHCI/UHCI) 157 * Host Controllers information. 158 */ 159 ehcip->ehci_root_hub.rh_companion_controllers = (capability & 160 EHCI_HCS_NUM_COMP_CTRLS) >> EHCI_HCS_NUM_COMP_CTRL_SHIFT; 161 162 /* 163 * Determine the Power Switching Mode 164 * 165 * EHCI Specification, root hub supports either no power switching 166 * individual port power switching. Also determine the Over-current 167 * Protection Mode. 168 */ 169 if (capability & EHCI_HCS_PORT_POWER_CONTROL) { 170 /* Each port is powered individually */ 171 root_hub_descr-> wHubCharacteristics = 172 HUB_CHARS_INDIVIDUAL_PORT_POWER; 173 174 /* Assume individual overcurrent reporting */ 175 root_hub_descr->wHubCharacteristics |= 176 HUB_CHARS_INDIV_OVER_CURRENT; 177 178 /* Each port will start off in the POWERED_OFF mode */ 179 port_state = POWERED_OFF; 180 } else { 181 /* The ports are powered when the ctlr is powered */ 182 root_hub_descr-> 183 wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING; 184 185 /* Assume no overcurrent reporting */ 186 root_hub_descr->wHubCharacteristics |= 187 HUB_CHARS_NO_OVER_CURRENT; 188 189 port_state = DISCONNECTED; 190 } 191 192 /* Look at the port indicator information */ 193 if (capability & EHCI_HCS_PORT_INDICATOR) { 194 root_hub_descr->wHubCharacteristics |= HUB_CHARS_PORT_INDICATOR; 195 } 196 197 /* 198 * Obtain the power on to power good time of the ports. 199 * 200 * Assume: Zero for this field. 201 */ 202 root_hub_descr->bPwrOn2PwrGood = 2; 203 204 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 205 "Power on to power good %d", root_hub_descr->bPwrOn2PwrGood); 206 207 /* Indicate if the device is removable */ 208 root_hub_descr->DeviceRemovable = 0; 209 210 /* Set PortPowerControlMask to zero */ 211 root_hub_descr->PortPwrCtrlMask = 0; 212 213 /* Set the state of each port and initialize the status */ 214 for (i = 0; i < root_hub_descr->bNbrPorts; i++) { 215 216 /* Initilize state/status of each root hub port */ 217 ehcip->ehci_root_hub.rh_port_state[i] = port_state; 218 ehcip->ehci_root_hub.rh_port_status[i] = 0; 219 } 220 221 return (USB_SUCCESS); 222 } 223 224 225 /* 226 * ehci_load_root_hub_driver: 227 * 228 * Attach the root hub 229 */ 230 static usb_dev_descr_t ehci_root_hub_device_descriptor = { 231 0x12, /* bLength */ 232 0x01, /* bDescriptorType, Device */ 233 0x200, /* bcdUSB, v2.0 */ 234 0x09, /* bDeviceClass */ 235 0x00, /* bDeviceSubClass */ 236 0x01, /* bDeviceProtocol */ 237 0x40, /* bMaxPacketSize0 */ 238 0x00, /* idVendor */ 239 0x00, /* idProduct */ 240 0x00, /* bcdDevice */ 241 0x00, /* iManufacturer */ 242 0x00, /* iProduct */ 243 0x00, /* iSerialNumber */ 244 0x01 /* bNumConfigurations */ 245 }; 246 247 static uchar_t ehci_root_hub_config_descriptor[] = { 248 /* One configuartion */ 249 0x09, /* bLength */ 250 0x02, /* bDescriptorType, Configuartion */ 251 0x19, 0x00, /* wTotalLength */ 252 0x01, /* bNumInterfaces */ 253 0x01, /* bConfigurationValue */ 254 0x00, /* iConfiguration */ 255 0x40, /* bmAttributes */ 256 0x00, /* MaxPower */ 257 258 /* One Interface */ 259 0x09, /* bLength */ 260 0x04, /* bDescriptorType, Interface */ 261 0x00, /* bInterfaceNumber */ 262 0x00, /* bAlternateSetting */ 263 0x01, /* bNumEndpoints */ 264 0x09, /* bInterfaceClass */ 265 0x01, /* bInterfaceSubClass */ 266 0x00, /* bInterfaceProtocol */ 267 0x00, /* iInterface */ 268 269 /* One Endpoint (status change endpoint) */ 270 0x07, /* bLength */ 271 0x05, /* bDescriptorType, Endpoint */ 272 0x81, /* bEndpointAddress */ 273 0x03, /* bmAttributes */ 274 0x01, 0x00, /* wMaxPacketSize, 1 + (EHCI_MAX_RH_PORTS / 8) */ 275 0xff /* bInterval */ 276 }; 277 278 int 279 ehci_load_root_hub_driver(ehci_state_t *ehcip) 280 { 281 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 282 "ehci_load_root_hub_driver:"); 283 284 return (usba_hubdi_bind_root_hub(ehcip->ehci_dip, 285 ehci_root_hub_config_descriptor, 286 sizeof (ehci_root_hub_config_descriptor), 287 &ehci_root_hub_device_descriptor)); 288 } 289 290 291 /* 292 * ehci_unload_root_hub_driver: 293 */ 294 int 295 ehci_unload_root_hub_driver(ehci_state_t *ehcip) 296 { 297 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 298 "ehci_unload_root_hub_driver:"); 299 300 return (usba_hubdi_unbind_root_hub(ehcip->ehci_dip)); 301 } 302 303 304 /* 305 * ehci_handle_root_hub_pipe_open: 306 * 307 * Handle opening of control and interrupt pipes on root hub. 308 */ 309 /* ARGSUSED */ 310 int 311 ehci_handle_root_hub_pipe_open( 312 usba_pipe_handle_data_t *ph, 313 usb_flags_t usb_flags) 314 { 315 ehci_state_t *ehcip = ehci_obtain_state( 316 ph->p_usba_device->usb_root_hub_dip); 317 usb_ep_descr_t *eptd = &ph->p_ep; 318 319 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 320 "ehci_handle_root_hub_pipe_open: Root hub pipe open"); 321 322 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 323 324 switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 325 case USB_EP_ATTR_CONTROL: 326 /* Save control pipe handle */ 327 ehcip->ehci_root_hub.rh_ctrl_pipe_handle = ph; 328 329 /* Set state of the root hub control pipe as idle */ 330 ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_IDLE; 331 332 ehcip->ehci_root_hub.rh_curr_ctrl_reqp = NULL; 333 334 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 335 "ehci_handle_root_hub_pipe_open: Root hub control " 336 "pipe open succeeded"); 337 338 break; 339 case USB_EP_ATTR_INTR: 340 /* Save interrupt pipe handle */ 341 ehcip->ehci_root_hub.rh_intr_pipe_handle = ph; 342 343 /* Set state of the root hub interrupt pipe as idle */ 344 ehcip->ehci_root_hub.rh_intr_pipe_state = EHCI_PIPE_STATE_IDLE; 345 346 ehcip->ehci_root_hub.rh_client_intr_reqp = NULL; 347 348 ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL; 349 350 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 351 "ehci_handle_root_hub_pipe_open: Root hub interrupt " 352 "pipe open succeeded"); 353 354 break; 355 default: 356 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 357 "ehci_handle_root_hub_pipe_open: Root hub pipe open" 358 "failed"); 359 360 return (USB_FAILURE); 361 } 362 363 ehcip->ehci_open_pipe_count++; 364 365 return (USB_SUCCESS); 366 } 367 368 369 /* 370 * ehci_handle_root_hub_pipe_close: 371 * 372 * Handle closing of control and interrupt pipes on root hub. 373 */ 374 /* ARGSUSED */ 375 int 376 ehci_handle_root_hub_pipe_close(usba_pipe_handle_data_t *ph) 377 { 378 ehci_state_t *ehcip = ehci_obtain_state( 379 ph->p_usba_device->usb_root_hub_dip); 380 usb_ep_descr_t *eptd = &ph->p_ep; 381 382 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 383 "ehci_handle_root_hub_pipe_close: Root hub pipe close"); 384 385 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 386 387 switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 388 case USB_EP_ATTR_CONTROL: 389 ASSERT(ehcip->ehci_root_hub. 390 rh_ctrl_pipe_state != EHCI_PIPE_STATE_CLOSE); 391 392 /* Set state of the root hub control pipe as close */ 393 ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_CLOSE; 394 395 /* Set root hub control pipe handle to null */ 396 ehcip->ehci_root_hub.rh_ctrl_pipe_handle = NULL; 397 398 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 399 "ehci_handle_root_hub_pipe_close: " 400 "Root hub control pipe close succeeded"); 401 break; 402 case USB_EP_ATTR_INTR: 403 ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1); 404 405 ASSERT(ehcip->ehci_root_hub. 406 rh_intr_pipe_state != EHCI_PIPE_STATE_CLOSE); 407 408 /* Set state of the root hub interrupt pipe as close */ 409 ehcip->ehci_root_hub.rh_intr_pipe_state = EHCI_PIPE_STATE_CLOSE; 410 411 /* Do interrupt pipe cleanup */ 412 ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_PIPE_CLOSING); 413 414 /* Set root hub interrupt pipe handle to null */ 415 ehcip->ehci_root_hub.rh_intr_pipe_handle = NULL; 416 417 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 418 "ehci_handle_root_hub_pipe_close: " 419 "Root hub interrupt pipe close succeeded"); 420 421 break; 422 default: 423 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 424 "ehci_handle_root_hub_pipe_close: " 425 "Root hub pipe close failed"); 426 427 return (USB_FAILURE); 428 } 429 430 ehcip->ehci_open_pipe_count--; 431 432 return (USB_SUCCESS); 433 } 434 435 436 /* 437 * ehci_handle_root_hub_pipe_reset: 438 * 439 * Handle resetting of control and interrupt pipes on root hub. 440 */ 441 /* ARGSUSED */ 442 int 443 ehci_handle_root_hub_pipe_reset( 444 usba_pipe_handle_data_t *ph, 445 usb_flags_t usb_flags) 446 { 447 ehci_state_t *ehcip = ehci_obtain_state( 448 ph->p_usba_device->usb_root_hub_dip); 449 usb_ep_descr_t *eptd = &ph->p_ep; 450 int error = USB_SUCCESS; 451 452 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 453 "ehci_handle_root_hub_pipe_reset: Root hub pipe reset"); 454 455 mutex_enter(&ehcip->ehci_int_mutex); 456 457 switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 458 case USB_EP_ATTR_CONTROL: 459 ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_IDLE; 460 461 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 462 "ehci_handle_root_hub_pipe_reset: Pipe reset" 463 "for the root hub control pipe successful"); 464 465 break; 466 case USB_EP_ATTR_INTR: 467 ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1); 468 469 if ((ehcip->ehci_root_hub.rh_client_intr_reqp) && 470 (ehcip->ehci_root_hub.rh_intr_pipe_state != 471 EHCI_PIPE_STATE_IDLE)) { 472 473 ehcip->ehci_root_hub. 474 rh_intr_pipe_state = EHCI_PIPE_STATE_RESET; 475 476 /* Do interrupt pipe cleanup */ 477 ehci_root_hub_intr_pipe_cleanup( 478 ehcip, USB_CR_PIPE_RESET); 479 } 480 481 ASSERT(ehcip->ehci_root_hub. 482 rh_intr_pipe_state == EHCI_PIPE_STATE_IDLE); 483 484 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 485 "ehci_handle_root_hub_pipe_reset: " 486 "Pipe reset for root hub interrupt pipe successful"); 487 488 break; 489 default: 490 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 491 "ehci_handle_root_hub_pipe_reset: " 492 "Root hub pipe reset failed"); 493 494 error = USB_FAILURE; 495 break; 496 } 497 498 mutex_exit(&ehcip->ehci_int_mutex); 499 500 return (error); 501 } 502 503 504 /* 505 * ehci_handle_root_hub_request: 506 * 507 * Intercept a root hub request. Handle the root hub request through the 508 * registers 509 */ 510 /* ARGSUSED */ 511 int 512 ehci_handle_root_hub_request( 513 ehci_state_t *ehcip, 514 usba_pipe_handle_data_t *ph, 515 usb_ctrl_req_t *ctrl_reqp) 516 { 517 uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType; 518 uchar_t bRequest = ctrl_reqp->ctrl_bRequest; 519 uint16_t wValue = ctrl_reqp->ctrl_wValue; 520 uint16_t wIndex = ctrl_reqp->ctrl_wIndex; 521 uint16_t wLength = ctrl_reqp->ctrl_wLength; 522 mblk_t *data = ctrl_reqp->ctrl_data; 523 uint16_t port = wIndex - 1; 524 usb_cr_t completion_reason; 525 int error = USB_SUCCESS; 526 527 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 528 "ehci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p", 529 bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data); 530 531 mutex_enter(&ehcip->ehci_int_mutex); 532 533 if (ehcip->ehci_root_hub. 534 rh_ctrl_pipe_state != EHCI_PIPE_STATE_IDLE) { 535 536 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 537 "ehci_handle_root_hub_request: Pipe is not idle"); 538 539 mutex_exit(&ehcip->ehci_int_mutex); 540 541 return (USB_FAILURE); 542 } 543 544 /* Save the current control request pointer */ 545 ehcip->ehci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp; 546 547 /* Set pipe state to active */ 548 ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_ACTIVE; 549 550 mutex_exit(&ehcip->ehci_int_mutex); 551 552 switch (bmRequestType) { 553 case HUB_GET_DEVICE_STATUS_TYPE: 554 ehci_handle_get_device_status(ehcip); 555 break; 556 case HUB_HANDLE_PORT_FEATURE_TYPE: 557 error = ehci_handle_set_clear_port_feature(ehcip, 558 bRequest, wValue, port); 559 break; 560 case HUB_GET_PORT_STATUS_TYPE: 561 ehci_handle_get_port_status(ehcip, port); 562 break; 563 case HUB_CLASS_REQ_TYPE: 564 switch (bRequest) { 565 case USB_REQ_GET_STATUS: 566 ehci_handle_get_hub_status(ehcip); 567 break; 568 case USB_REQ_GET_DESCR: 569 ehci_handle_get_hub_descriptor(ehcip); 570 break; 571 default: 572 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 573 "ehci_handle_root_hub_request:" 574 "Unsupported request 0x%x", bRequest); 575 576 error = USB_FAILURE; 577 break; 578 } 579 break; 580 default: 581 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 582 "ehci_handle_root_hub_request: " 583 "Unsupported request 0x%x", bmRequestType); 584 585 error = USB_FAILURE; 586 break; 587 } 588 589 completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK; 590 591 mutex_enter(&ehcip->ehci_int_mutex); 592 ehci_root_hub_hcdi_callback(ph, completion_reason); 593 mutex_exit(&ehcip->ehci_int_mutex); 594 595 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 596 "ehci_handle_root_hub_request: error = %d", error); 597 598 return (USB_SUCCESS); 599 } 600 601 602 /* 603 * ehci_handle_set_clear_port_feature: 604 */ 605 static int 606 ehci_handle_set_clear_port_feature( 607 ehci_state_t *ehcip, 608 uchar_t bRequest, 609 uint16_t wValue, 610 uint16_t port) 611 { 612 int error = USB_SUCCESS; 613 614 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 615 "ehci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x", 616 bRequest, wValue, port); 617 618 switch (bRequest) { 619 case USB_REQ_SET_FEATURE: 620 switch (wValue) { 621 case CFS_PORT_ENABLE: 622 ehci_handle_port_enable(ehcip, port, 1); 623 break; 624 case CFS_PORT_SUSPEND: 625 ehci_handle_port_suspend(ehcip, port, 1); 626 break; 627 case CFS_PORT_RESET: 628 ehci_handle_port_reset(ehcip, port); 629 break; 630 case CFS_PORT_POWER: 631 ehci_handle_port_power(ehcip, port, 1); 632 break; 633 default: 634 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 635 "ehci_handle_set_clear_port_feature: " 636 "Unsupported request 0x%x 0x%x", bRequest, wValue); 637 638 error = USB_FAILURE; 639 break; 640 } 641 break; 642 case USB_REQ_CLEAR_FEATURE: 643 switch (wValue) { 644 case CFS_PORT_ENABLE: 645 ehci_handle_port_enable(ehcip, port, 0); 646 break; 647 case CFS_C_PORT_ENABLE: 648 ehci_handle_clrchng_port_enable(ehcip, port); 649 break; 650 case CFS_PORT_SUSPEND: 651 ehci_handle_port_suspend(ehcip, port, 0); 652 break; 653 case CFS_C_PORT_SUSPEND: 654 ehci_handle_clrchng_port_suspend(ehcip, port); 655 break; 656 case CFS_C_PORT_RESET: 657 ehci_handle_complete_port_reset(ehcip, port); 658 break; 659 case CFS_PORT_POWER: 660 ehci_handle_port_power(ehcip, port, 0); 661 break; 662 case CFS_C_PORT_CONNECTION: 663 ehci_handle_clear_port_connection(ehcip, port); 664 break; 665 case CFS_C_PORT_OVER_CURRENT: 666 ehci_handle_clrchng_port_over_current(ehcip, port); 667 break; 668 default: 669 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 670 "ehci_handle_set_clear_port_feature: " 671 "Unsupported request 0x%x 0x%x", bRequest, wValue); 672 673 error = USB_FAILURE; 674 break; 675 } 676 break; 677 default: 678 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 679 "ehci_handle_set_clear_port_feature: " 680 "Unsupported request 0x%x 0x%x", bRequest, wValue); 681 682 error = USB_FAILURE; 683 break; 684 } 685 686 return (error); 687 } 688 689 690 /* 691 * ehci_handle_port_power: 692 * 693 * Turn on a root hub port. 694 */ 695 static void 696 ehci_handle_port_power( 697 ehci_state_t *ehcip, 698 uint16_t port, 699 uint_t on) 700 { 701 uint_t port_status; 702 ehci_root_hub_t *rh; 703 704 mutex_enter(&ehcip->ehci_int_mutex); 705 706 port_status = Get_OpReg(ehci_rh_port_status[port]) & 707 ~EHCI_RH_PORT_CLEAR_MASK; 708 709 rh = &ehcip->ehci_root_hub; 710 711 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 712 "ehci_handle_port_power: port = 0x%x status = 0x%x on = %d", 713 port, port_status, on); 714 715 /* Check port is owned by ehci */ 716 if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) { 717 mutex_exit(&ehcip->ehci_int_mutex); 718 719 return; 720 } 721 722 if (on) { 723 /* See if the port power is already on */ 724 if (!(port_status & EHCI_RH_PORT_POWER)) { 725 /* Turn the port on */ 726 Set_OpReg(ehci_rh_port_status[port], 727 port_status | EHCI_RH_PORT_POWER); 728 } 729 730 rh->rh_port_status[port] = 0; 731 rh->rh_port_state[port] = DISCONNECTED; 732 } else { 733 /* See if the port power is already OFF */ 734 if (port_status & EHCI_RH_PORT_POWER) { 735 /* Turn-off the port */ 736 Set_OpReg(ehci_rh_port_status[port], 737 port_status & ~EHCI_RH_PORT_POWER); 738 } 739 740 rh->rh_port_status[port] = 0; 741 rh->rh_port_state[port] = POWERED_OFF; 742 } 743 744 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 745 "ehci_handle_port_power done: port = 0x%x status = 0x%x on = %d", 746 port, Get_OpReg(ehci_rh_port_status[port]), on); 747 748 mutex_exit(&ehcip->ehci_int_mutex); 749 } 750 751 752 /* 753 * ehci_handle_port_enable: 754 * 755 * Handle port enable request. 756 */ 757 static void 758 ehci_handle_port_enable( 759 ehci_state_t *ehcip, 760 uint16_t port, 761 uint_t on) 762 { 763 uint_t port_status; 764 765 mutex_enter(&ehcip->ehci_int_mutex); 766 767 port_status = Get_OpReg(ehci_rh_port_status[port]) & 768 ~EHCI_RH_PORT_CLEAR_MASK; 769 770 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 771 "ehci_handle_port_enable: port = 0x%x, status = 0x%x", 772 port, port_status); 773 774 /* Check port is owned by ehci */ 775 if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) { 776 mutex_exit(&ehcip->ehci_int_mutex); 777 778 return; 779 } 780 781 if (on) { 782 /* See if the port enable is already on */ 783 if (!(port_status & EHCI_RH_PORT_ENABLE)) { 784 /* Enable the port */ 785 Set_OpReg(ehci_rh_port_status[port], 786 port_status | EHCI_RH_PORT_ENABLE); 787 } 788 } else { 789 /* See if the port enable is already off */ 790 if (port_status & EHCI_RH_PORT_ENABLE) { 791 /* Disable the port */ 792 Set_OpReg(ehci_rh_port_status[port], 793 port_status & ~EHCI_RH_PORT_ENABLE); 794 } 795 } 796 797 mutex_exit(&ehcip->ehci_int_mutex); 798 } 799 800 801 /* 802 * ehci_handle_clrchng_port_enable: 803 * 804 * Handle clear port enable change bit. 805 */ 806 static void 807 ehci_handle_clrchng_port_enable( 808 ehci_state_t *ehcip, 809 uint16_t port) 810 { 811 uint_t port_status; 812 813 mutex_enter(&ehcip->ehci_int_mutex); 814 815 port_status = Get_OpReg(ehci_rh_port_status[port]) & 816 ~EHCI_RH_PORT_CLEAR_MASK; 817 818 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 819 "ehci_handle_port_enable: port = 0x%x, status = 0x%x", 820 port, port_status); 821 822 /* Check port is owned by ehci */ 823 if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) { 824 mutex_exit(&ehcip->ehci_int_mutex); 825 826 return; 827 } 828 829 /* Clear the PortEnableStatusChange Bit */ 830 Set_OpReg(ehci_rh_port_status[port], 831 port_status | EHCI_RH_PORT_ENABLE_CHANGE); 832 833 mutex_exit(&ehcip->ehci_int_mutex); 834 } 835 836 837 /* 838 * ehci_handle_port_suspend: 839 * 840 * Handle port suspend/resume request. 841 */ 842 static void 843 ehci_handle_port_suspend( 844 ehci_state_t *ehcip, 845 uint16_t port, 846 uint_t on) 847 { 848 uint_t port_status; 849 850 mutex_enter(&ehcip->ehci_int_mutex); 851 852 port_status = Get_OpReg(ehci_rh_port_status[port]) & 853 ~EHCI_RH_PORT_CLEAR_MASK; 854 855 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 856 "ehci_handle_port_suspend: port = 0x%x, status = 0x%x", 857 port, port_status); 858 859 /* Check port is owned by ehci */ 860 if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) { 861 mutex_exit(&ehcip->ehci_int_mutex); 862 863 return; 864 } 865 866 if (on) { 867 /* 868 * Suspend port only if port is enabled and 869 * it is not already in suspend state. 870 */ 871 if ((port_status & EHCI_RH_PORT_ENABLE) && 872 (!(port_status & EHCI_RH_PORT_SUSPEND))) { 873 /* Suspend the port */ 874 Set_OpReg(ehci_rh_port_status[port], 875 port_status | EHCI_RH_PORT_SUSPEND); 876 877 mutex_exit(&ehcip->ehci_int_mutex); 878 879 /* Wait 10ms for port move to suspend state */ 880 delay(drv_usectohz(EHCI_PORT_SUSPEND_TIMEWAIT)); 881 882 return; 883 } 884 } else { 885 /* Perform resume only if port is in suspend state */ 886 if (port_status & EHCI_RH_PORT_SUSPEND) { 887 /* Resume the port */ 888 Set_OpReg(ehci_rh_port_status[port], 889 port_status | EHCI_RH_PORT_RESUME); 890 } 891 } 892 893 mutex_exit(&ehcip->ehci_int_mutex); 894 } 895 896 897 /* 898 * ehci_handle_clrchng_port_suspend: 899 * 900 * Handle port clear port suspend change bit. 901 */ 902 static void 903 ehci_handle_clrchng_port_suspend( 904 ehci_state_t *ehcip, 905 uint16_t port) 906 { 907 uint_t port_status; 908 int i; 909 910 mutex_enter(&ehcip->ehci_int_mutex); 911 912 port_status = Get_OpReg(ehci_rh_port_status[port]) & 913 ~EHCI_RH_PORT_CLEAR_MASK; 914 915 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 916 "ehci_handle_clrchng_port_suspend: port = 0x%x, " 917 "status = 0x%x", port, port_status); 918 919 /* Check port is owned by ehci */ 920 if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) { 921 mutex_exit(&ehcip->ehci_int_mutex); 922 923 return; 924 } 925 926 /* Return if port is not in resume state */ 927 if (!(port_status & EHCI_RH_PORT_RESUME)) { 928 mutex_exit(&ehcip->ehci_int_mutex); 929 930 return; 931 } 932 933 mutex_exit(&ehcip->ehci_int_mutex); 934 935 /* Wait for 20ms to terminate resume */ 936 delay(drv_usectohz(EHCI_PORT_RESUME_TIMEWAIT)); 937 938 mutex_enter(&ehcip->ehci_int_mutex); 939 940 Set_OpReg(ehci_rh_port_status[port], 941 port_status & ~EHCI_RH_PORT_RESUME); 942 943 mutex_exit(&ehcip->ehci_int_mutex); 944 945 /* 946 * Wait for port to return to high speed mode. It's necessary to poll 947 * for resume completion for some high-speed devices to work correctly. 948 */ 949 for (i = 0; i < EHCI_PORT_RESUME_RETRY_MAX; i++) { 950 delay(drv_usectohz(EHCI_PORT_RESUME_COMP_TIMEWAIT)); 951 952 mutex_enter(&ehcip->ehci_int_mutex); 953 port_status = Get_OpReg(ehci_rh_port_status[port]) & 954 ~EHCI_RH_PORT_CLEAR_MASK; 955 mutex_exit(&ehcip->ehci_int_mutex); 956 957 if (!(port_status & EHCI_RH_PORT_RESUME)) { 958 break; 959 } 960 } 961 } 962 963 964 /* 965 * ehci_handle_port_reset: 966 * 967 * Perform a port reset. 968 */ 969 static void 970 ehci_handle_port_reset( 971 ehci_state_t *ehcip, 972 uint16_t port) 973 { 974 ehci_root_hub_t *rh; 975 uint_t port_status; 976 int i; 977 978 mutex_enter(&ehcip->ehci_int_mutex); 979 980 /* Get the root hub structure */ 981 rh = &ehcip->ehci_root_hub; 982 983 /* Get the port status information */ 984 port_status = Get_OpReg(ehci_rh_port_status[port]) & 985 ~EHCI_RH_PORT_CLEAR_MASK; 986 987 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 988 "ehci_handle_port_reset: port = 0x%x status = 0x%x", 989 port, port_status); 990 991 /* Check port is owned by ehci */ 992 if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) { 993 mutex_exit(&ehcip->ehci_int_mutex); 994 995 return; 996 } 997 998 if (port_status & EHCI_RH_PORT_LOW_SPEED) { 999 /* Check for classic or companion host controllers */ 1000 if (rh->rh_companion_controllers) { 1001 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1002 "ehci_handle_port_reset: Low speed device " 1003 "and handover this port to Companion controller"); 1004 1005 Set_OpReg(ehci_rh_port_status[port], 1006 port_status | EHCI_RH_PORT_OWNER_CLASSIC); 1007 } else { 1008 USB_DPRINTF_L1(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1009 "Low speed device is not supported"); 1010 } 1011 } else { 1012 Set_OpReg(ehci_rh_port_status[port], 1013 ((port_status | EHCI_RH_PORT_RESET) & 1014 ~EHCI_RH_PORT_ENABLE)); 1015 1016 mutex_exit(&ehcip->ehci_int_mutex); 1017 1018 /* Wait 50ms for reset to complete */ 1019 delay(drv_usectohz(EHCI_PORT_RESET_TIMEWAIT)); 1020 1021 mutex_enter(&ehcip->ehci_int_mutex); 1022 1023 port_status = Get_OpReg(ehci_rh_port_status[port]) & 1024 ~EHCI_RH_PORT_CLEAR_MASK; 1025 1026 Set_OpReg(ehci_rh_port_status[port], 1027 (port_status & ~EHCI_RH_PORT_RESET)); 1028 1029 mutex_exit(&ehcip->ehci_int_mutex); 1030 1031 /* 1032 * Wait for hardware to enable this port, if the connected 1033 * usb device is high speed. It's necessary to poll for reset 1034 * completion for some high-speed devices to recognized 1035 * correctly. 1036 */ 1037 for (i = 0; i < EHCI_PORT_RESET_RETRY_MAX; i++) { 1038 delay(drv_usectohz(EHCI_PORT_RESET_COMP_TIMEWAIT)); 1039 1040 mutex_enter(&ehcip->ehci_int_mutex); 1041 port_status = Get_OpReg(ehci_rh_port_status[port]) & 1042 ~EHCI_RH_PORT_CLEAR_MASK; 1043 mutex_exit(&ehcip->ehci_int_mutex); 1044 1045 if (!(port_status & EHCI_RH_PORT_RESET)) { 1046 break; 1047 } 1048 } 1049 1050 mutex_enter(&ehcip->ehci_int_mutex); 1051 1052 port_status = Get_OpReg(ehci_rh_port_status[port]) & 1053 ~EHCI_RH_PORT_CLEAR_MASK; 1054 1055 /* 1056 * If port is not enabled, connected device is a 1057 * Full-speed usb device. 1058 */ 1059 if (!(port_status & EHCI_RH_PORT_ENABLE)) { 1060 /* Check for classic or companion host controllers */ 1061 if (rh->rh_companion_controllers) { 1062 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1063 ehcip->ehci_log_hdl, 1064 "ehci_handle_port_reset: Full speed device " 1065 "and handover this port to Companion host " 1066 "controller"); 1067 1068 Set_OpReg(ehci_rh_port_status[port], 1069 port_status | EHCI_RH_PORT_OWNER_CLASSIC); 1070 } else { 1071 USB_DPRINTF_L1(PRINT_MASK_ROOT_HUB, 1072 ehcip->ehci_log_hdl, 1073 "Full speed device is not supported"); 1074 } 1075 } else { 1076 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1077 "ehci_handle_port_reset: High speed device "); 1078 1079 port_status = Get_OpReg(ehci_rh_port_status[port]) & 1080 ~EHCI_RH_PORT_CLEAR_MASK; 1081 1082 /* 1083 * Enable over-current, connect, and disconnect 1084 * wakeup bits. 1085 */ 1086 Set_OpReg(ehci_rh_port_status[port], (port_status | 1087 EHCI_RH_PORT_OVER_CURENT_ENABLE | 1088 EHCI_RH_PORT_DISCONNECT_ENABLE | 1089 EHCI_RH_PORT_CONNECT_ENABLE)); 1090 1091 /* 1092 * The next function is only called if the interrupt 1093 * pipe is polling and the USBA is ready to receive 1094 * the data. 1095 */ 1096 ehcip->ehci_root_hub. 1097 rh_intr_pending_status |= (1 << port); 1098 1099 if (ehcip->ehci_root_hub. 1100 rh_intr_pipe_state == EHCI_PIPE_STATE_ACTIVE) { 1101 1102 ehci_root_hub_reset_occured(ehcip); 1103 } 1104 } 1105 } 1106 1107 mutex_exit(&ehcip->ehci_int_mutex); 1108 } 1109 1110 1111 /* 1112 * ehci_root_hub_reset_occured: 1113 * 1114 * Inform the upper layer that reset has occured on the port. This is 1115 * required because the upper layer is expecting a an evernt immidiately 1116 * after doing reset. In case of OHCI, the controller gets an interrupt 1117 * for the change in the root hub status but in case of EHCI, we dont. 1118 * So, send a event to the upper layer as soon as we complete the reset. 1119 */ 1120 void 1121 ehci_root_hub_reset_occured( 1122 ehci_state_t *ehcip) 1123 { 1124 usb_intr_req_t *curr_intr_reqp = 1125 ehcip->ehci_root_hub.rh_curr_intr_reqp; 1126 usb_port_mask_t port_mask; 1127 usba_pipe_handle_data_t *ph; 1128 1129 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1130 "ehci_root_hub_reset_occured: curr_intr_reqp = 0x%p data = 0x%p", 1131 (void *)curr_intr_reqp, (void *)curr_intr_reqp->intr_data); 1132 1133 /* Get the interrupt pipe handle */ 1134 ph = ehcip->ehci_root_hub.rh_intr_pipe_handle; 1135 1136 /* Get the pending status */ 1137 port_mask = ehcip->ehci_root_hub.rh_intr_pending_status << 1; 1138 1139 do { 1140 *curr_intr_reqp->intr_data->b_wptr++ = (uchar_t)port_mask; 1141 port_mask >>= 8; 1142 } while (port_mask != 0); 1143 1144 ehci_root_hub_hcdi_callback(ph, USB_CR_OK); 1145 1146 /* Reset pending status */ 1147 ehcip->ehci_root_hub.rh_intr_pending_status = 0; 1148 1149 /* If needed, allocate new interrupt request */ 1150 if ((ehci_root_hub_allocate_intr_pipe_resource( 1151 ehcip, 0)) != USB_SUCCESS) { 1152 1153 /* Do interrupt pipe cleanup */ 1154 ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_NO_RESOURCES); 1155 } 1156 } 1157 1158 1159 /* 1160 * ehci_handle_complete_port_reset: 1161 * 1162 * Perform a port reset change. 1163 */ 1164 static void 1165 ehci_handle_complete_port_reset( 1166 ehci_state_t *ehcip, 1167 uint16_t port) 1168 { 1169 uint_t port_status; 1170 1171 mutex_enter(&ehcip->ehci_int_mutex); 1172 1173 port_status = Get_OpReg(ehci_rh_port_status[port]) & 1174 ~EHCI_RH_PORT_CLEAR_MASK; 1175 1176 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1177 "ehci_handle_complete_port_reset: port = 0x%x status = 0x%x", 1178 port, port_status); 1179 1180 /* Check port is owned by ehci */ 1181 if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) { 1182 mutex_exit(&ehcip->ehci_int_mutex); 1183 1184 return; 1185 } 1186 1187 if (port_status & EHCI_RH_PORT_RESET) { 1188 Set_OpReg(ehci_rh_port_status[port], 1189 port_status & ~EHCI_RH_PORT_RESET); 1190 1191 } 1192 1193 mutex_exit(&ehcip->ehci_int_mutex); 1194 } 1195 1196 1197 /* 1198 * ehci_handle_clear_port_connection: 1199 * 1200 * Perform a clear port connection. 1201 */ 1202 static void 1203 ehci_handle_clear_port_connection( 1204 ehci_state_t *ehcip, 1205 uint16_t port) 1206 { 1207 uint_t port_status; 1208 1209 mutex_enter(&ehcip->ehci_int_mutex); 1210 1211 port_status = Get_OpReg(ehci_rh_port_status[port]) & 1212 ~EHCI_RH_PORT_CLEAR_MASK; 1213 1214 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1215 "ehci_handle_clear_port_connection: port = 0x%x" 1216 "status = 0x%x", port, port_status); 1217 1218 Set_OpReg(ehci_rh_port_status[port], 1219 port_status | EHCI_RH_PORT_CONNECT_STS_CHANGE); 1220 1221 mutex_exit(&ehcip->ehci_int_mutex); 1222 } 1223 1224 1225 /* 1226 * ehci_handle_clrchng_port_over_current: 1227 * 1228 * Perform a clear port connection. 1229 */ 1230 static void 1231 ehci_handle_clrchng_port_over_current( 1232 ehci_state_t *ehcip, 1233 uint16_t port) 1234 { 1235 uint_t port_status; 1236 1237 mutex_enter(&ehcip->ehci_int_mutex); 1238 1239 port_status = Get_OpReg(ehci_rh_port_status[port]) & 1240 ~EHCI_RH_PORT_CLEAR_MASK; 1241 1242 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1243 "ehci_handle_clrchng_port_over_current: port = 0x%x" 1244 "status = 0x%x", port, port_status); 1245 1246 Set_OpReg(ehci_rh_port_status[port], 1247 port_status | EHCI_RH_PORT_OVER_CURR_CHANGE); 1248 1249 mutex_exit(&ehcip->ehci_int_mutex); 1250 } 1251 1252 1253 /* 1254 * ehci_handle_get_port_status: 1255 * 1256 * Handle a get port status request. 1257 */ 1258 static void 1259 ehci_handle_get_port_status( 1260 ehci_state_t *ehcip, 1261 uint16_t port) 1262 { 1263 usb_ctrl_req_t *ctrl_reqp; 1264 mblk_t *message; 1265 uint_t new_port_status = 0; 1266 uint_t change_status = 0; 1267 uint_t port_status; 1268 1269 mutex_enter(&ehcip->ehci_int_mutex); 1270 1271 ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp; 1272 1273 /* Get the root hub port status information */ 1274 port_status = ehci_get_root_hub_port_status(ehcip, port); 1275 1276 new_port_status = port_status & PORT_STATUS_MASK; 1277 change_status = (port_status >> 16) & PORT_CHANGE_MASK; 1278 1279 ehcip->ehci_root_hub.rh_port_status[port] = new_port_status; 1280 1281 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1282 "ehci_handle_get_port_status: port = %d new status = 0x%x" 1283 "change = 0x%x", port, new_port_status, change_status); 1284 1285 message = ctrl_reqp->ctrl_data; 1286 1287 ASSERT(message != NULL); 1288 1289 *message->b_wptr++ = (uchar_t)new_port_status; 1290 *message->b_wptr++ = (uchar_t)(new_port_status >> 8); 1291 *message->b_wptr++ = (uchar_t)change_status; 1292 *message->b_wptr++ = (uchar_t)(change_status >> 8); 1293 1294 /* Save the data in control request */ 1295 ctrl_reqp->ctrl_data = message; 1296 1297 mutex_exit(&ehcip->ehci_int_mutex); 1298 } 1299 1300 1301 /* 1302 * ehci_handle_get_hub_descriptor: 1303 */ 1304 static void 1305 ehci_handle_get_hub_descriptor( 1306 ehci_state_t *ehcip) 1307 { 1308 usb_ctrl_req_t *ctrl_reqp; 1309 mblk_t *message; 1310 usb_hub_descr_t *root_hub_descr; 1311 size_t length; 1312 uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH]; 1313 1314 mutex_enter(&ehcip->ehci_int_mutex); 1315 1316 ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp; 1317 root_hub_descr = &ehcip->ehci_root_hub.rh_descr; 1318 length = ctrl_reqp->ctrl_wLength; 1319 1320 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1321 "ehci_handle_get_hub_descriptor: Ctrl Req = 0x%p", 1322 (void *)ctrl_reqp); 1323 1324 message = ctrl_reqp->ctrl_data; 1325 1326 ASSERT(message != NULL); 1327 1328 bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH); 1329 1330 raw_descr[0] = root_hub_descr->bDescLength; 1331 raw_descr[1] = root_hub_descr->bDescriptorType; 1332 raw_descr[2] = root_hub_descr->bNbrPorts; 1333 raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF; 1334 raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8; 1335 raw_descr[5] = root_hub_descr->bPwrOn2PwrGood; 1336 raw_descr[6] = root_hub_descr->bHubContrCurrent; 1337 raw_descr[7] = root_hub_descr->DeviceRemovable; 1338 raw_descr[8] = root_hub_descr->PortPwrCtrlMask; 1339 1340 bcopy(raw_descr, message->b_wptr, length); 1341 message->b_wptr += length; 1342 1343 /* Save the data in control request */ 1344 ctrl_reqp->ctrl_data = message; 1345 1346 mutex_exit(&ehcip->ehci_int_mutex); 1347 } 1348 1349 1350 /* 1351 * ehci_handle_get_hub_status: 1352 * 1353 * Handle a get hub status request. 1354 */ 1355 static void 1356 ehci_handle_get_hub_status( 1357 ehci_state_t *ehcip) 1358 { 1359 usb_ctrl_req_t *ctrl_reqp; 1360 mblk_t *message; 1361 uint_t new_root_hub_status; 1362 1363 mutex_enter(&ehcip->ehci_int_mutex); 1364 1365 ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp; 1366 1367 /* 1368 * For EHCI, there is no overall hub status information. 1369 * Only individual root hub port status information is 1370 * available. So return zero for the root hub status 1371 * request. 1372 */ 1373 new_root_hub_status = 0; 1374 1375 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1376 "ehci_handle_get_hub_status: new root hub status = 0x%x", 1377 new_root_hub_status); 1378 1379 message = ctrl_reqp->ctrl_data; 1380 1381 ASSERT(message != NULL); 1382 1383 *message->b_wptr++ = (uchar_t)new_root_hub_status; 1384 *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8); 1385 *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16); 1386 *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24); 1387 1388 /* Save the data in control request */ 1389 ctrl_reqp->ctrl_data = message; 1390 1391 mutex_exit(&ehcip->ehci_int_mutex); 1392 } 1393 1394 1395 /* 1396 * ehci_handle_get_device_status: 1397 * 1398 * Handle a get device status request. 1399 */ 1400 static void 1401 ehci_handle_get_device_status( 1402 ehci_state_t *ehcip) 1403 { 1404 usb_ctrl_req_t *ctrl_reqp; 1405 mblk_t *message; 1406 uint16_t dev_status; 1407 1408 mutex_enter(&ehcip->ehci_int_mutex); 1409 1410 ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp; 1411 1412 /* 1413 * For EHCI, there is no device status information. 1414 * Simply return what is desired for the request. 1415 */ 1416 dev_status = USB_DEV_SLF_PWRD_STATUS; 1417 1418 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1419 "ehci_handle_get_device_status: device status = 0x%x", 1420 dev_status); 1421 1422 message = ctrl_reqp->ctrl_data; 1423 1424 ASSERT(message != NULL); 1425 1426 *message->b_wptr++ = (uchar_t)dev_status; 1427 *message->b_wptr++ = (uchar_t)(dev_status >> 8); 1428 1429 /* Save the data in control request */ 1430 ctrl_reqp->ctrl_data = message; 1431 1432 mutex_exit(&ehcip->ehci_int_mutex); 1433 } 1434 1435 1436 /* 1437 * ehci_handle_root_hub_pipe_start_intr_polling: 1438 * 1439 * Handle start polling on root hub interrupt pipe. 1440 */ 1441 /* ARGSUSED */ 1442 int 1443 ehci_handle_root_hub_pipe_start_intr_polling( 1444 usba_pipe_handle_data_t *ph, 1445 usb_intr_req_t *client_intr_reqp, 1446 usb_flags_t flags) 1447 { 1448 ehci_state_t *ehcip = ehci_obtain_state( 1449 ph->p_usba_device->usb_root_hub_dip); 1450 usb_ep_descr_t *eptd = &ph->p_ep; 1451 int error = USB_SUCCESS; 1452 uint_t pipe_state; 1453 1454 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1455 "ehci_handle_root_hub_pipe_start_intr_polling: " 1456 "Root hub pipe start polling"); 1457 1458 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1459 1460 ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1); 1461 1462 ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0); 1463 1464 pipe_state = ehcip->ehci_root_hub.rh_intr_pipe_state; 1465 1466 switch (pipe_state) { 1467 case EHCI_PIPE_STATE_IDLE: 1468 ASSERT(ehcip->ehci_root_hub.rh_intr_pipe_timer_id == 0); 1469 1470 /* 1471 * Save the Original Client's Interrupt IN request 1472 * information. We use this for final callback 1473 */ 1474 ASSERT(ehcip->ehci_root_hub.rh_client_intr_reqp == NULL); 1475 ehcip->ehci_root_hub.rh_client_intr_reqp = client_intr_reqp; 1476 1477 error = ehci_root_hub_allocate_intr_pipe_resource(ehcip, flags); 1478 1479 if (error != USB_SUCCESS) { 1480 /* Reset client interrupt request pointer */ 1481 ehcip->ehci_root_hub.rh_client_intr_reqp = NULL; 1482 1483 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1484 "ehci_handle_root_hub_pipe_start_intr_polling: " 1485 "No Resources"); 1486 1487 return (error); 1488 } 1489 1490 /* Check whether we need to send the reset data up */ 1491 if (ehcip->ehci_root_hub.rh_intr_pending_status) { 1492 ehci_root_hub_reset_occured(ehcip); 1493 } 1494 1495 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1496 "ehci_handle_root_hub_pipe_start_intr_polling: " 1497 "Start polling for root hub successful"); 1498 1499 break; 1500 case EHCI_PIPE_STATE_ACTIVE: 1501 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1502 "ehci_handle_root_hub_pipe_start_intr_polling: " 1503 "Polling for root hub is already in progress"); 1504 1505 break; 1506 default: 1507 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1508 "ehci_handle_root_hub_pipe_start_intr_polling: " 1509 "Pipe is in error state 0x%x", pipe_state); 1510 1511 error = USB_FAILURE; 1512 1513 break; 1514 } 1515 1516 return (error); 1517 } 1518 1519 1520 /* 1521 * ehci_handle_root_hub_pipe_stop_intr_polling: 1522 * 1523 * Handle stop polling on root hub intr pipe. 1524 */ 1525 /* ARGSUSED */ 1526 void 1527 ehci_handle_root_hub_pipe_stop_intr_polling( 1528 usba_pipe_handle_data_t *ph, 1529 usb_flags_t flags) 1530 { 1531 ehci_state_t *ehcip = ehci_obtain_state( 1532 ph->p_usba_device->usb_root_hub_dip); 1533 usb_ep_descr_t *eptd = &ph->p_ep; 1534 1535 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1536 1537 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1538 "ehci_handle_root_hub_pipe_stop_intr_polling: " 1539 "Root hub pipe stop polling"); 1540 1541 ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1); 1542 1543 if (ehcip->ehci_root_hub.rh_intr_pipe_state == 1544 EHCI_PIPE_STATE_ACTIVE) { 1545 1546 ehcip->ehci_root_hub.rh_intr_pipe_state = 1547 EHCI_PIPE_STATE_STOP_POLLING; 1548 1549 /* Do interrupt pipe cleanup */ 1550 ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_STOPPED_POLLING); 1551 1552 ASSERT(ehcip->ehci_root_hub. 1553 rh_intr_pipe_state == EHCI_PIPE_STATE_IDLE); 1554 1555 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1556 "ehci_hcdi_pipe_stop_intr_polling: Stop polling for root" 1557 "hub successful"); 1558 } else { 1559 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, 1560 ehcip->ehci_log_hdl, "ehci_hcdi_pipe_stop_intr_polling: " 1561 "Polling for root hub is already stopped"); 1562 } 1563 } 1564 1565 1566 /* 1567 * ehci_get_root_hub_port_status: 1568 * 1569 * Construct root hub port status and change information 1570 */ 1571 static uint_t 1572 ehci_get_root_hub_port_status( 1573 ehci_state_t *ehcip, 1574 uint16_t port) 1575 { 1576 uint_t new_port_status = 0; 1577 uint_t change_status = 0; 1578 uint_t port_status; 1579 1580 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1581 1582 /* Read the current port status */ 1583 port_status = Get_OpReg(ehci_rh_port_status[port]); 1584 1585 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1586 "ehci_get_root_hub_port_status: port %d " 1587 "port status = 0x%x", port, port_status); 1588 1589 /* 1590 * EHCI root hub port status and control register information 1591 * format is different what Hub driver wants. So EHCI driver 1592 * needs to contruct the proper root hub port status information. 1593 * 1594 * Send all port status information only if port is owned by EHCI 1595 * host controller. 1596 */ 1597 if ((port_status & EHCI_RH_PORT_OWNER) == EHCI_RH_PORT_OWNER_EHCI) { 1598 1599 /* First construct port change information */ 1600 if (port_status & EHCI_RH_PORT_ENABLE_CHANGE) { 1601 change_status |= PORT_CHANGE_PESC; 1602 } 1603 1604 if (port_status & EHCI_RH_PORT_RESUME) { 1605 change_status |= PORT_CHANGE_PSSC; 1606 } 1607 1608 if (port_status & EHCI_RH_PORT_OVER_CURR_CHANGE) { 1609 change_status |= PORT_CHANGE_OCIC; 1610 } 1611 1612 /* Now construct port status information */ 1613 if (port_status & EHCI_RH_PORT_CONNECT_STATUS) { 1614 new_port_status |= PORT_STATUS_CCS; 1615 } 1616 1617 if (port_status & EHCI_RH_PORT_ENABLE) { 1618 new_port_status |= 1619 (PORT_STATUS_PES | PORT_STATUS_HSDA); 1620 } 1621 1622 if (port_status & EHCI_RH_PORT_SUSPEND) { 1623 new_port_status |= PORT_STATUS_PSS; 1624 } 1625 1626 if (port_status & EHCI_RH_PORT_OVER_CURR_ACTIVE) { 1627 new_port_status |= PORT_STATUS_POCI; 1628 } 1629 1630 if (port_status & EHCI_RH_PORT_RESET) { 1631 new_port_status |= PORT_STATUS_PRS; 1632 } 1633 1634 if (port_status & EHCI_RH_PORT_INDICATOR) { 1635 new_port_status |= PORT_STATUS_PIC; 1636 } 1637 } 1638 1639 /* 1640 * Send the following port status and change information 1641 * even if port is not owned by EHCI. 1642 * 1643 * Additional port change information. 1644 */ 1645 if (port_status & EHCI_RH_PORT_CONNECT_STS_CHANGE) { 1646 change_status |= PORT_CHANGE_CSC; 1647 } 1648 1649 /* Additional port status information */ 1650 if (port_status & EHCI_RH_PORT_POWER) { 1651 new_port_status |= PORT_STATUS_PPS; 1652 } 1653 1654 if ((!(port_status & EHCI_RH_PORT_ENABLE)) && 1655 (port_status & EHCI_RH_PORT_LOW_SPEED)) { 1656 new_port_status |= PORT_STATUS_LSDA; 1657 } 1658 1659 /* 1660 * Construct complete root hub port status and change information. 1661 */ 1662 port_status = ((change_status << 16) | new_port_status); 1663 1664 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1665 "ehci_get_root_hub_port_status: port = %d new status = 0x%x " 1666 "change status = 0x%x complete port status 0x%x", port, 1667 new_port_status, change_status, port_status); 1668 1669 return (port_status); 1670 } 1671 1672 1673 /* 1674 * ehci_is_port_owner: 1675 * 1676 * Check whether given port is owned by ehci. 1677 */ 1678 static int 1679 ehci_is_port_owner( 1680 ehci_state_t *ehcip, 1681 uint16_t port) 1682 { 1683 uint_t port_status; 1684 1685 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1686 1687 port_status = Get_OpReg(ehci_rh_port_status[port]) & 1688 ~EHCI_RH_PORT_CLEAR_MASK; 1689 1690 /* 1691 * Don't perform anything if port is owned by classis host 1692 * controller and return success. 1693 */ 1694 if ((port_status & EHCI_RH_PORT_OWNER) == EHCI_RH_PORT_OWNER_CLASSIC) { 1695 1696 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1697 "ehci_handle_set_clear_port_feature: " 1698 "Port %d is owned by classic host controller", port); 1699 1700 return (USB_FAILURE); 1701 } 1702 1703 return (USB_SUCCESS); 1704 } 1705 1706 1707 /* 1708 * ehci_root_hub_allocate_intr_pipe_resource: 1709 * 1710 * Allocate interrupt requests and initialize them. 1711 */ 1712 static int 1713 ehci_root_hub_allocate_intr_pipe_resource( 1714 ehci_state_t *ehcip, 1715 usb_flags_t flags) 1716 { 1717 usba_pipe_handle_data_t *ph; 1718 size_t length; 1719 usb_intr_req_t *curr_intr_reqp; 1720 1721 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1722 "ehci_root_hub_allocate_intr_pipe_resource"); 1723 1724 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1725 1726 /* Get the interrupt pipe handle */ 1727 ph = ehcip->ehci_root_hub.rh_intr_pipe_handle; 1728 1729 /* Get the current interrupt request pointer */ 1730 curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp; 1731 1732 /* 1733 * If current interrupt request pointer is null, 1734 * allocate new interrupt request. 1735 */ 1736 if (curr_intr_reqp == NULL) { 1737 ASSERT(ehcip->ehci_root_hub.rh_client_intr_reqp); 1738 1739 /* Get the length of interrupt transfer */ 1740 length = ehcip->ehci_root_hub. 1741 rh_client_intr_reqp->intr_len; 1742 1743 curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip, 1744 ehcip->ehci_root_hub.rh_client_intr_reqp, 1745 length, flags); 1746 1747 if (curr_intr_reqp == NULL) { 1748 1749 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1750 "ehci_root_hub_allocate_intr_pipe_resource:" 1751 "Interrupt request structure allocation failed"); 1752 1753 return (USB_NO_RESOURCES); 1754 } 1755 1756 ehcip->ehci_root_hub.rh_curr_intr_reqp = curr_intr_reqp; 1757 mutex_enter(&ph->p_mutex); 1758 ph->p_req_count++; 1759 mutex_exit(&ph->p_mutex); 1760 } 1761 1762 /* Start the timer for the root hub interrupt pipe polling */ 1763 if (ehcip->ehci_root_hub.rh_intr_pipe_timer_id == 0) { 1764 ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 1765 timeout(ehci_handle_root_hub_status_change, 1766 (void *)ehcip, drv_usectohz(EHCI_RH_POLL_TIME)); 1767 1768 ehcip->ehci_root_hub. 1769 rh_intr_pipe_state = EHCI_PIPE_STATE_ACTIVE; 1770 } 1771 1772 return (USB_SUCCESS); 1773 } 1774 1775 1776 /* 1777 * ehci_root_hub_intr_pipe_cleanup: 1778 * 1779 * Deallocate all interrupt requests and do callback 1780 * the original client interrupt request. 1781 */ 1782 static void 1783 ehci_root_hub_intr_pipe_cleanup( 1784 ehci_state_t *ehcip, 1785 usb_cr_t completion_reason) 1786 { 1787 usb_intr_req_t *curr_intr_reqp; 1788 usb_opaque_t client_intr_reqp; 1789 timeout_id_t timer_id; 1790 usba_pipe_handle_data_t *ph; 1791 1792 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1793 "ehci_root_hub_intr_pipe_cleanup"); 1794 1795 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1796 1797 /* Get the interrupt pipe handle */ 1798 ph = ehcip->ehci_root_hub.rh_intr_pipe_handle; 1799 1800 /* Get the interrupt timerid */ 1801 timer_id = ehcip->ehci_root_hub.rh_intr_pipe_timer_id; 1802 1803 /* Stop the root hub interrupt timer */ 1804 if (timer_id) { 1805 /* Reset the timer id to zero */ 1806 ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0; 1807 1808 mutex_exit(&ehcip->ehci_int_mutex); 1809 (void) untimeout(timer_id); 1810 mutex_enter(&ehcip->ehci_int_mutex); 1811 } 1812 1813 /* Reset the current interrupt request pointer */ 1814 curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp; 1815 1816 /* Deallocate uncompleted interrupt request */ 1817 if (curr_intr_reqp) { 1818 ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL; 1819 usb_free_intr_req(curr_intr_reqp); 1820 1821 mutex_enter(&ph->p_mutex); 1822 ph->p_req_count--; 1823 mutex_exit(&ph->p_mutex); 1824 } 1825 1826 client_intr_reqp = (usb_opaque_t) 1827 ehcip->ehci_root_hub.rh_client_intr_reqp; 1828 1829 /* Callback for original client interrupt request */ 1830 if (client_intr_reqp) { 1831 ehci_root_hub_hcdi_callback(ph, completion_reason); 1832 } 1833 } 1834 1835 1836 /* 1837 * ehci_handle_root_hub_status_change: 1838 * 1839 * A root hub status change interrupt will occur any time there is a change 1840 * in the root hub status register or one of the port status registers. 1841 */ 1842 static void 1843 ehci_handle_root_hub_status_change(void *arg) 1844 { 1845 ehci_state_t *ehcip = (ehci_state_t *)arg; 1846 usb_hub_descr_t *root_hub_descr = 1847 &ehcip->ehci_root_hub.rh_descr; 1848 usb_intr_req_t *curr_intr_reqp; 1849 usb_port_mask_t port_mask = 0; 1850 uint_t new_port_status; 1851 uint_t change_status; 1852 uint_t port_status; 1853 mblk_t *message; 1854 size_t length; 1855 usb_ep_descr_t *eptd; 1856 usba_pipe_handle_data_t *ph; 1857 int i; 1858 1859 mutex_enter(&ehcip->ehci_int_mutex); 1860 1861 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 1862 "ehci_handle_root_hub_status_change: state = %d", 1863 ehcip->ehci_root_hub.rh_intr_pipe_state); 1864 1865 #if defined(__x86) 1866 /* 1867 * When ohci are attached in ferrari 4000, SMI will reset ehci 1868 * registers. If ehci registers have been reset, we must re-initialize 1869 * them. During booting, this function will be called 2~3 times. When 1870 * this function is called 16 times, ohci drivers have been attached 1871 * and stop checking the ehci registers. 1872 */ 1873 if (ehcip->ehci_polled_root_hub_count < 16) { 1874 1875 if (Get_OpReg(ehci_config_flag) == 0) { 1876 1877 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, 1878 ehcip->ehci_log_hdl, 1879 "ehci_handle_root_hub_status_change:" 1880 " EHCI have been reset"); 1881 1882 /* Reinitialize the controller */ 1883 if (ehci_init_ctlr(ehcip, EHCI_REINITIALIZATION) != 1884 DDI_SUCCESS) { 1885 mutex_exit(&ehcip->ehci_int_mutex); 1886 1887 return; 1888 } 1889 } 1890 1891 ehcip->ehci_polled_root_hub_count++; 1892 } 1893 #endif /* __x86 */ 1894 1895 /* Get the current interrupt request pointer */ 1896 curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp; 1897 1898 ph = ehcip->ehci_root_hub.rh_intr_pipe_handle; 1899 1900 /* Check whether timeout handler is valid */ 1901 if (ehcip->ehci_root_hub.rh_intr_pipe_timer_id) { 1902 /* Check host controller is in operational state */ 1903 if ((ehci_state_is_operational(ehcip)) != USB_SUCCESS) { 1904 /* Reset the timer id */ 1905 ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0; 1906 1907 /* Do interrupt pipe cleanup */ 1908 ehci_root_hub_intr_pipe_cleanup( 1909 ehcip, USB_CR_HC_HARDWARE_ERR); 1910 1911 mutex_exit(&ehcip->ehci_int_mutex); 1912 1913 return; 1914 } 1915 } else { 1916 mutex_exit(&ehcip->ehci_int_mutex); 1917 1918 return; 1919 } 1920 1921 eptd = &ehcip->ehci_root_hub.rh_intr_pipe_handle->p_ep; 1922 1923 /* Check each port */ 1924 for (i = 0; i < root_hub_descr->bNbrPorts; i++) { 1925 1926 port_status = ehci_get_root_hub_port_status(ehcip, i); 1927 1928 new_port_status = port_status & PORT_STATUS_MASK; 1929 change_status = (port_status >> 16) & PORT_CHANGE_MASK; 1930 1931 /* 1932 * If there is change in the port status then set the bit in the 1933 * bitmap of changes and inform hub driver about these changes. 1934 * Hub driver will take care of these changes. 1935 */ 1936 if (change_status) { 1937 1938 /* See if a device was attached/detached */ 1939 if (change_status & PORT_CHANGE_CSC) { 1940 /* 1941 * Update the state depending on whether 1942 * the port was attached or detached. 1943 */ 1944 if (new_port_status & PORT_STATUS_CCS) { 1945 ehcip->ehci_root_hub. 1946 rh_port_state[i] = DISABLED; 1947 1948 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1949 ehcip->ehci_log_hdl, 1950 "Port %d connected", i+1); 1951 } else { 1952 ehcip->ehci_root_hub. 1953 rh_port_state[i] = DISCONNECTED; 1954 1955 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1956 ehcip->ehci_log_hdl, 1957 "Port %d disconnected", i+1); 1958 } 1959 } 1960 1961 /* See if port enable status changed */ 1962 if (change_status & PORT_CHANGE_PESC) { 1963 /* 1964 * Update the state depending on whether 1965 * the port was enabled or disabled. 1966 */ 1967 if (new_port_status & PORT_STATUS_PES) { 1968 ehcip->ehci_root_hub. 1969 rh_port_state[i] = ENABLED; 1970 1971 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1972 ehcip->ehci_log_hdl, 1973 "Port %d enabled", i+1); 1974 } else { 1975 ehcip->ehci_root_hub. 1976 rh_port_state[i] = DISABLED; 1977 1978 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1979 ehcip->ehci_log_hdl, 1980 "Port %d disabled", i+1); 1981 } 1982 } 1983 1984 port_mask |= 1 << (i + 1); 1985 1986 /* Update the status */ 1987 ehcip->ehci_root_hub. 1988 rh_port_status[i] = new_port_status; 1989 } 1990 } 1991 1992 if (ph && port_mask && curr_intr_reqp) { 1993 length = eptd->wMaxPacketSize; 1994 1995 ASSERT(length != 0); 1996 1997 /* Get the message block */ 1998 message = curr_intr_reqp->intr_data; 1999 2000 ASSERT(message != NULL); 2001 2002 do { 2003 /* 2004 * check that the mblk is big enough when we 2005 * are writing bytes into it 2006 */ 2007 if (message->b_wptr >= message->b_datap->db_lim) { 2008 2009 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, 2010 ehcip->ehci_log_hdl, 2011 "ehci_handle_root_hub_status_change" 2012 "mblk data overflow."); 2013 2014 break; 2015 } 2016 *message->b_wptr++ = (uchar_t)port_mask; 2017 port_mask >>= 8; 2018 } while (port_mask != 0); 2019 2020 ehci_root_hub_hcdi_callback(ph, USB_CR_OK); 2021 } 2022 2023 /* Reset the timer id */ 2024 ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0; 2025 2026 if (ehcip->ehci_root_hub.rh_intr_pipe_state == 2027 EHCI_PIPE_STATE_ACTIVE) { 2028 /* 2029 * If needed, allocate new interrupt request. Also 2030 * start the timer for the root hub interrupt polling. 2031 */ 2032 if ((ehci_root_hub_allocate_intr_pipe_resource( 2033 ehcip, 0)) != USB_SUCCESS) { 2034 2035 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 2036 "ehci_handle_root_hub_status_change: No Resources"); 2037 2038 /* Do interrupt pipe cleanup */ 2039 ehci_root_hub_intr_pipe_cleanup( 2040 ehcip, USB_CR_NO_RESOURCES); 2041 } 2042 } 2043 2044 mutex_exit(&ehcip->ehci_int_mutex); 2045 } 2046 2047 2048 /* 2049 * ehci_root_hub_hcdi_callback() 2050 * 2051 * Convenience wrapper around usba_hcdi_cb() for the root hub. 2052 */ 2053 static void 2054 ehci_root_hub_hcdi_callback( 2055 usba_pipe_handle_data_t *ph, 2056 usb_cr_t completion_reason) 2057 { 2058 ehci_state_t *ehcip = ehci_obtain_state( 2059 ph->p_usba_device->usb_root_hub_dip); 2060 uchar_t attributes = ph->p_ep.bmAttributes & 2061 USB_EP_ATTR_MASK; 2062 usb_opaque_t curr_xfer_reqp; 2063 uint_t pipe_state = 0; 2064 2065 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl, 2066 "ehci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x", 2067 (void *)ph, completion_reason); 2068 2069 ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 2070 2071 /* Set the pipe state as per completion reason */ 2072 switch (completion_reason) { 2073 case USB_CR_OK: 2074 switch (attributes) { 2075 case USB_EP_ATTR_CONTROL: 2076 pipe_state = EHCI_PIPE_STATE_IDLE; 2077 break; 2078 case USB_EP_ATTR_INTR: 2079 pipe_state = ehcip->ehci_root_hub. 2080 rh_intr_pipe_state; 2081 break; 2082 } 2083 break; 2084 case USB_CR_NO_RESOURCES: 2085 case USB_CR_NOT_SUPPORTED: 2086 case USB_CR_STOPPED_POLLING: 2087 case USB_CR_PIPE_RESET: 2088 case USB_CR_HC_HARDWARE_ERR: 2089 /* Set pipe state to idle */ 2090 pipe_state = EHCI_PIPE_STATE_IDLE; 2091 break; 2092 case USB_CR_PIPE_CLOSING: 2093 break; 2094 default: 2095 /* Set pipe state to error */ 2096 pipe_state = EHCI_PIPE_STATE_ERROR; 2097 break; 2098 } 2099 2100 switch (attributes) { 2101 case USB_EP_ATTR_CONTROL: 2102 curr_xfer_reqp = (usb_opaque_t) 2103 ehcip->ehci_root_hub.rh_curr_ctrl_reqp; 2104 2105 ehcip->ehci_root_hub.rh_curr_ctrl_reqp = NULL; 2106 ehcip->ehci_root_hub.rh_ctrl_pipe_state = pipe_state; 2107 break; 2108 case USB_EP_ATTR_INTR: 2109 /* if curr_intr_reqp available then use this request */ 2110 if (ehcip->ehci_root_hub.rh_curr_intr_reqp) { 2111 curr_xfer_reqp = (usb_opaque_t)ehcip-> 2112 ehci_root_hub.rh_curr_intr_reqp; 2113 2114 ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL; 2115 } else { 2116 /* no current request, use client's request */ 2117 curr_xfer_reqp = (usb_opaque_t) 2118 ehcip->ehci_root_hub.rh_client_intr_reqp; 2119 2120 ehcip->ehci_root_hub.rh_client_intr_reqp = NULL; 2121 } 2122 ehcip->ehci_root_hub.rh_intr_pipe_state = pipe_state; 2123 break; 2124 } 2125 2126 ASSERT(curr_xfer_reqp != NULL); 2127 2128 mutex_exit(&ehcip->ehci_int_mutex); 2129 usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason); 2130 mutex_enter(&ehcip->ehci_int_mutex); 2131 } 2132