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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * Open Host Controller Driver (OHCI) 29 * 30 * The USB Open Host Controller driver is a software driver which interfaces 31 * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller. 32 * The interface to USB Open Host Controller is defined by the OpenHCI Host 33 * Controller Interface. 34 * 35 * This module contains the code for root hub related functions. 36 * 37 * Note: ONE_XFER is not supported on root hub interrupt polling. 38 */ 39 #include <sys/usb/hcd/openhci/ohcid.h> 40 41 /* static function prototypes */ 42 static int ohci_handle_set_clear_port_feature( 43 ohci_state_t *ohcip, 44 uchar_t bRequest, 45 uint16_t wValue, 46 uint16_t port); 47 static void ohci_handle_port_power(ohci_state_t *ohcip, 48 uint16_t port, 49 uint_t on); 50 static void ohci_handle_port_enable(ohci_state_t *ohcip, 51 uint16_t port, 52 uint_t on); 53 static void ohci_handle_clrchng_port_enable( 54 ohci_state_t *ohcip, 55 uint16_t port); 56 static void ohci_handle_port_suspend(ohci_state_t *ohcip, 57 uint16_t port, 58 uint_t on); 59 static void ohci_handle_clrchng_port_suspend( 60 ohci_state_t *ohcip, 61 uint16_t port); 62 static void ohci_handle_port_reset(ohci_state_t *ohcip, 63 uint16_t port); 64 static void ohci_handle_complete_port_reset( 65 ohci_state_t *ohcip, 66 uint16_t port); 67 static void ohci_handle_clear_port_connection( 68 ohci_state_t *ohcip, 69 uint16_t port); 70 static void ohci_handle_clrchng_port_over_current( 71 ohci_state_t *ohcip, 72 uint16_t port); 73 static void ohci_handle_get_port_status( 74 ohci_state_t *ohcip, 75 uint16_t port); 76 static int ohci_handle_set_clear_hub_feature( 77 ohci_state_t *ohcip, 78 uchar_t bRequest, 79 uint16_t wValue); 80 static void ohci_handle_clrchng_hub_over_current( 81 ohci_state_t *ohcip); 82 static void ohci_handle_get_hub_descriptor( 83 ohci_state_t *ohcip); 84 static void ohci_handle_get_hub_status( 85 ohci_state_t *ohcip); 86 static void ohci_handle_get_device_status( 87 ohci_state_t *ohcip); 88 static int ohci_root_hub_allocate_intr_pipe_resource( 89 ohci_state_t *ohcip, 90 usb_flags_t flags); 91 static void ohci_root_hub_intr_pipe_cleanup( 92 ohci_state_t *ohcip, 93 usb_cr_t completion_reason); 94 static void ohci_root_hub_hcdi_callback( 95 usba_pipe_handle_data_t *ph, 96 usb_cr_t completion_reason); 97 98 99 /* 100 * ohci_init_root_hub: 101 * 102 * Initialize the root hub 103 */ 104 int 105 ohci_init_root_hub(ohci_state_t *ohcip) 106 { 107 usb_hub_descr_t *root_hub_descr = 108 &ohcip->ohci_root_hub.rh_descr; 109 uint_t des_A, des_B, port_state; 110 int i, length; 111 112 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 113 "ohci_init_root_hub:"); 114 115 /* Read the descriptor registers */ 116 des_A = ohcip->ohci_root_hub.rh_des_A = Get_OpReg(hcr_rh_descriptorA); 117 des_B = ohcip->ohci_root_hub.rh_des_B = Get_OpReg(hcr_rh_descriptorB); 118 119 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 120 "root hub descriptor A 0x%x", ohcip->ohci_root_hub.rh_des_A); 121 122 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 123 "root hub descriptor B 0x%x", ohcip->ohci_root_hub.rh_des_B); 124 125 /* Obtain the root hub status */ 126 ohcip->ohci_root_hub.rh_status = Get_OpReg(hcr_rh_status); 127 128 /* 129 * Build the hub descriptor based on HcRhDescriptorA and 130 * HcRhDescriptorB 131 */ 132 root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE; 133 134 if ((des_A & HCR_RHA_NDP) > OHCI_MAX_RH_PORTS) { 135 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 136 "ohci_init_root_hub:" "Invalid no of root hub ports 0x%x", 137 des_A & HCR_RHA_NDP); 138 139 return (USB_FAILURE); 140 } 141 142 /* Obtain the number of downstream ports */ 143 root_hub_descr->bNbrPorts = des_A & HCR_RHA_NDP; 144 145 length = root_hub_descr->bNbrPorts / 8; 146 147 if (length) { 148 root_hub_descr->bDescLength = 7 + (2 * (length + 1)); 149 } else { 150 root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH; 151 } 152 153 /* Determine the Power Switching Mode */ 154 if (!(des_A & HCR_RHA_NPS)) { 155 /* 156 * The ports are power switched. Check for either individual 157 * or gang power switching. 158 */ 159 if ((des_A & HCR_RHA_PSM) && (des_B & HCR_RHB_PPCM)) { 160 /* each port is powered individually */ 161 root_hub_descr->wHubCharacteristics = 162 HUB_CHARS_INDIVIDUAL_PORT_POWER; 163 } else { 164 /* the ports are gang powered */ 165 root_hub_descr-> 166 wHubCharacteristics = HUB_CHARS_GANGED_POWER; 167 } 168 169 /* Each port will start off in the POWERED_OFF mode */ 170 port_state = POWERED_OFF; 171 } else { 172 /* The ports are powered when the ctlr is powered */ 173 root_hub_descr-> 174 wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING; 175 176 port_state = DISCONNECTED; 177 } 178 179 /* The root hub should never be a compound device */ 180 ASSERT((des_A & HCR_RHA_DT) == 0); 181 182 /* Determine the Over-current Protection Mode */ 183 if (des_A & HCR_RHA_NOCP) { 184 /* No over current protection */ 185 root_hub_descr-> 186 wHubCharacteristics |= HUB_CHARS_NO_OVER_CURRENT; 187 } else { 188 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 189 ohcip->ohci_log_hdl, "OCPM =%d, PSM=%d", 190 des_A & HCR_RHA_OCPM, des_A & HCR_RHA_PSM); 191 192 /* See if over current protection is provided */ 193 if (des_A & HCR_RHA_OCPM) { 194 /* reported on a per port basis */ 195 root_hub_descr-> 196 wHubCharacteristics |= HUB_CHARS_INDIV_OVER_CURRENT; 197 } 198 } 199 200 /* Obtain the power on to power good time of the ports */ 201 root_hub_descr->bPwrOn2PwrGood = (uint32_t) 202 ((des_A & HCR_RHA_PTPGT) >> HCR_RHA_PTPGT_SHIFT); 203 204 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_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 = (uchar_t)des_B & HCR_RHB_DR; 209 210 /* 211 * Fill in the port power control mask: 212 * Each bit in the PortPowerControlMask 213 * should be set. Refer to USB 2.0, table 11-13 214 */ 215 root_hub_descr->PortPwrCtrlMask = (uchar_t)(des_B >> 16); 216 217 /* Set the state of each port and initialize the status */ 218 for (i = 0; i < root_hub_descr->bNbrPorts; i++) { 219 ohcip->ohci_root_hub.rh_port_state[i] = port_state; 220 221 /* Turn off the power on each port for now */ 222 Set_OpReg(hcr_rh_portstatus[i], HCR_PORT_CPP); 223 224 /* 225 * Initialize each of the root hub port status 226 * equal to zero. This initialization makes sure 227 * that all devices connected to root hub will 228 * enumerates when the first RHSC interrupt occurs 229 * since definitely there will be changes in 230 * the root hub port status. 231 */ 232 ohcip->ohci_root_hub.rh_port_status[i] = 0; 233 } 234 235 return (USB_SUCCESS); 236 } 237 238 239 /* 240 * ohci_load_root_hub_driver: 241 * 242 * Attach the root hub 243 */ 244 static usb_dev_descr_t ohci_root_hub_device_descriptor = { 245 0x12, /* bLength */ 246 0x01, /* bDescriptorType, Device */ 247 0x110, /* bcdUSB, v1.1 */ 248 0x09, /* bDeviceClass */ 249 0x00, /* bDeviceSubClass */ 250 0x00, /* bDeviceProtocol */ 251 0x08, /* bMaxPacketSize0 */ 252 0x00, /* idVendor */ 253 0x00, /* idProduct */ 254 0x00, /* bcdDevice */ 255 0x00, /* iManufacturer */ 256 0x00, /* iProduct */ 257 0x00, /* iSerialNumber */ 258 0x01 /* bNumConfigurations */ 259 }; 260 261 static uchar_t ohci_root_hub_config_descriptor[] = { 262 /* One configuartion */ 263 0x09, /* bLength */ 264 0x02, /* bDescriptorType, Configuartion */ 265 0x19, 0x00, /* wTotalLength */ 266 0x01, /* bNumInterfaces */ 267 0x01, /* bConfigurationValue */ 268 0x00, /* iConfiguration */ 269 0x40, /* bmAttributes */ 270 0x00, /* MaxPower */ 271 272 /* One Interface */ 273 0x09, /* bLength */ 274 0x04, /* bDescriptorType, Interface */ 275 0x00, /* bInterfaceNumber */ 276 0x00, /* bAlternateSetting */ 277 0x01, /* bNumEndpoints */ 278 0x09, /* bInterfaceClass */ 279 0x01, /* bInterfaceSubClass */ 280 0x00, /* bInterfaceProtocol */ 281 0x00, /* iInterface */ 282 283 /* One Endpoint (status change endpoint) */ 284 0x07, /* bLength */ 285 0x05, /* bDescriptorType, Endpoint */ 286 0x81, /* bEndpointAddress */ 287 0x03, /* bmAttributes */ 288 0x01, 0x00, /* wMaxPacketSize, 1 + (OHCI_MAX_RH_PORTS / 8) */ 289 0xff /* bInterval */ 290 }; 291 292 int 293 ohci_load_root_hub_driver(ohci_state_t *ohcip) 294 { 295 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 296 "ohci_load_root_hub_driver:"); 297 298 return (usba_hubdi_bind_root_hub(ohcip->ohci_dip, 299 ohci_root_hub_config_descriptor, 300 sizeof (ohci_root_hub_config_descriptor), 301 &ohci_root_hub_device_descriptor)); 302 } 303 304 305 /* 306 * ohci_unload_root_hub_driver: 307 */ 308 int 309 ohci_unload_root_hub_driver(ohci_state_t *ohcip) 310 { 311 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 312 "ohci_unload_root_hub_driver:"); 313 314 return (usba_hubdi_unbind_root_hub(ohcip->ohci_dip)); 315 } 316 317 318 /* 319 * ohci_handle_root_hub_pipe_open: 320 * 321 * Handle opening of control and interrupt pipes on root hub. 322 */ 323 /* ARGSUSED */ 324 int 325 ohci_handle_root_hub_pipe_open( 326 usba_pipe_handle_data_t *ph, 327 usb_flags_t usb_flags) 328 { 329 ohci_state_t *ohcip = ohci_obtain_state( 330 ph->p_usba_device->usb_root_hub_dip); 331 usb_ep_descr_t *eptd = &ph->p_ep; 332 333 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 334 "ohci_handle_root_hub_pipe_open: Root hub pipe open"); 335 336 ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 337 338 switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 339 case USB_EP_ATTR_CONTROL: 340 /* Save control pipe handle */ 341 ohcip->ohci_root_hub.rh_ctrl_pipe_handle = ph; 342 343 /* Set state of the root hub control pipe as idle */ 344 ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE; 345 346 ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL; 347 348 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 349 "ohci_handle_root_hub_pipe_open: Root hub control " 350 "pipe open succeeded"); 351 352 break; 353 case USB_EP_ATTR_INTR: 354 /* Save interrupt pipe handle */ 355 ohcip->ohci_root_hub.rh_intr_pipe_handle = ph; 356 357 /* Set state of the root hub interrupt pipe as idle */ 358 ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_IDLE; 359 360 ohcip->ohci_root_hub.rh_client_intr_reqp = NULL; 361 362 ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL; 363 364 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 365 "ohci_handle_root_hub_pipe_open: Root hub interrupt " 366 "pipe open succeeded"); 367 368 break; 369 default: 370 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 371 "ohci_handle_root_hub_pipe_open: Root hub pipe open" 372 "failed"); 373 374 return (USB_FAILURE); 375 } 376 377 ohcip->ohci_open_pipe_count++; 378 379 return (USB_SUCCESS); 380 } 381 382 383 /* 384 * ohci_handle_root_hub_pipe_close: 385 * 386 * Handle closing of control and interrupt pipes on root hub. 387 */ 388 /* ARGSUSED */ 389 int 390 ohci_handle_root_hub_pipe_close(usba_pipe_handle_data_t *ph) 391 { 392 ohci_state_t *ohcip = ohci_obtain_state( 393 ph->p_usba_device->usb_root_hub_dip); 394 usb_ep_descr_t *eptd = &ph->p_ep; 395 396 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 397 "ohci_handle_root_hub_pipe_close: Root hub pipe close"); 398 399 ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 400 401 switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 402 case USB_EP_ATTR_CONTROL: 403 ASSERT(ohcip->ohci_root_hub. 404 rh_ctrl_pipe_state != OHCI_PIPE_STATE_CLOSE); 405 406 /* Set state of the root hub control pipe as close */ 407 ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_CLOSE; 408 409 /* Set root hub control pipe handle to null */ 410 ohcip->ohci_root_hub.rh_ctrl_pipe_handle = NULL; 411 412 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 413 "ohci_handle_root_hub_pipe_close: " 414 "Root hub control pipe close succeeded"); 415 break; 416 case USB_EP_ATTR_INTR: 417 ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1); 418 419 ASSERT(ohcip->ohci_root_hub. 420 rh_intr_pipe_state != OHCI_PIPE_STATE_CLOSE); 421 422 /* Set state of the root hub interrupt pipe as close */ 423 ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_CLOSE; 424 425 /* Do interrupt pipe cleanup */ 426 ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_PIPE_CLOSING); 427 428 /* Set root hub interrupt pipe handle to null */ 429 ohcip->ohci_root_hub.rh_intr_pipe_handle = NULL; 430 431 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 432 "ohci_handle_root_hub_pipe_close: " 433 "Root hub interrupt pipe close succeeded"); 434 435 break; 436 default: 437 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 438 "ohci_handle_root_hub_pipe_close: " 439 "Root hub pipe close failed"); 440 441 return (USB_FAILURE); 442 } 443 444 ohcip->ohci_open_pipe_count--; 445 446 return (USB_SUCCESS); 447 } 448 449 450 /* 451 * ohci_handle_root_hub_pipe_reset: 452 * 453 * Handle resetting of control and interrupt pipes on root hub. 454 */ 455 /* ARGSUSED */ 456 int 457 ohci_handle_root_hub_pipe_reset( 458 usba_pipe_handle_data_t *ph, 459 usb_flags_t usb_flags) 460 { 461 ohci_state_t *ohcip = ohci_obtain_state( 462 ph->p_usba_device->usb_root_hub_dip); 463 usb_ep_descr_t *eptd = &ph->p_ep; 464 int error = USB_SUCCESS; 465 466 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 467 "ohci_handle_root_hub_pipe_reset: Root hub pipe reset"); 468 469 mutex_enter(&ohcip->ohci_int_mutex); 470 471 switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 472 case USB_EP_ATTR_CONTROL: 473 ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE; 474 475 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 476 "ohci_handle_root_hub_pipe_reset: Pipe reset" 477 "for the root hub control pipe successful"); 478 479 break; 480 case USB_EP_ATTR_INTR: 481 ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1); 482 483 if ((ohcip->ohci_root_hub.rh_client_intr_reqp) && 484 (ohcip->ohci_root_hub.rh_intr_pipe_state != 485 OHCI_PIPE_STATE_IDLE)) { 486 487 ohcip->ohci_root_hub. 488 rh_intr_pipe_state = OHCI_PIPE_STATE_RESET; 489 490 /* Do interrupt pipe cleanup */ 491 ohci_root_hub_intr_pipe_cleanup( 492 ohcip, USB_CR_PIPE_RESET); 493 } 494 495 ASSERT(ohcip->ohci_root_hub. 496 rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE); 497 498 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 499 "ohci_handle_root_hub_pipe_reset: " 500 "Pipe reset for root hub interrupt pipe successful"); 501 502 break; 503 default: 504 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 505 "ohci_handle_root_hub_pipe_reset: " 506 "Root hub pipe reset failed"); 507 508 error = USB_FAILURE; 509 break; 510 } 511 512 mutex_exit(&ohcip->ohci_int_mutex); 513 514 return (error); 515 } 516 517 518 /* 519 * ohci_handle_root_hub_request: 520 * 521 * Intercept a root hub request. Handle the root hub request through the 522 * registers 523 */ 524 /* ARGSUSED */ 525 int 526 ohci_handle_root_hub_request( 527 ohci_state_t *ohcip, 528 usba_pipe_handle_data_t *ph, 529 usb_ctrl_req_t *ctrl_reqp) 530 { 531 uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType; 532 uchar_t bRequest = ctrl_reqp->ctrl_bRequest; 533 uint16_t wValue = ctrl_reqp->ctrl_wValue; 534 uint16_t wIndex = ctrl_reqp->ctrl_wIndex; 535 uint16_t wLength = ctrl_reqp->ctrl_wLength; 536 mblk_t *data = ctrl_reqp->ctrl_data; 537 uint16_t port = wIndex - 1; /* Adjust for controller */ 538 usb_cr_t completion_reason; 539 int error = USB_SUCCESS; 540 541 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 542 "ohci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p", 543 bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data); 544 545 mutex_enter(&ohcip->ohci_int_mutex); 546 547 if (ohcip->ohci_root_hub.rh_ctrl_pipe_state != OHCI_PIPE_STATE_IDLE) { 548 549 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 550 "ohci_handle_root_hub_request: Pipe is not idle"); 551 552 mutex_exit(&ohcip->ohci_int_mutex); 553 554 return (USB_FAILURE); 555 } 556 557 /* Save the current control request pointer */ 558 ohcip->ohci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp; 559 560 /* Set pipe state to active */ 561 ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_ACTIVE; 562 563 mutex_exit(&ohcip->ohci_int_mutex); 564 565 switch (bmRequestType) { 566 case HUB_GET_DEVICE_STATUS_TYPE: 567 ohci_handle_get_device_status(ohcip); 568 break; 569 case HUB_HANDLE_PORT_FEATURE_TYPE: 570 error = ohci_handle_set_clear_port_feature(ohcip, 571 bRequest, wValue, port); 572 break; 573 case HUB_GET_PORT_STATUS_TYPE: 574 ohci_handle_get_port_status(ohcip, port); 575 break; 576 case HUB_CLASS_REQ_TYPE: 577 switch (bRequest) { 578 case USB_REQ_GET_STATUS: 579 ohci_handle_get_hub_status(ohcip); 580 break; 581 case USB_REQ_GET_DESCR: 582 ohci_handle_get_hub_descriptor(ohcip); 583 break; 584 default: 585 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 586 "ohci_handle_root_hub_request:" 587 "Unsupported request 0x%x", bRequest); 588 589 error = USB_FAILURE; 590 break; 591 } 592 break; 593 case HUB_HANDLE_HUB_FEATURE_TYPE: 594 error = ohci_handle_set_clear_hub_feature(ohcip, 595 bRequest, wValue); 596 break; 597 default: 598 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 599 "ohci_handle_root_hub_request: " 600 "Unsupported request 0x%x", bmRequestType); 601 602 error = USB_FAILURE; 603 break; 604 } 605 606 completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK; 607 608 mutex_enter(&ohcip->ohci_int_mutex); 609 ohci_root_hub_hcdi_callback(ph, completion_reason); 610 mutex_exit(&ohcip->ohci_int_mutex); 611 612 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 613 "ohci_handle_root_hub_request: error = %d", error); 614 615 return (USB_SUCCESS); 616 } 617 618 619 /* 620 * ohci_handle_set_clear_port_feature: 621 */ 622 static int 623 ohci_handle_set_clear_port_feature( 624 ohci_state_t *ohcip, 625 uchar_t bRequest, 626 uint16_t wValue, 627 uint16_t port) 628 { 629 int error = USB_SUCCESS; 630 631 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 632 "ohci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x", 633 bRequest, wValue, port); 634 635 switch (bRequest) { 636 case USB_REQ_SET_FEATURE: 637 switch (wValue) { 638 case CFS_PORT_ENABLE: 639 ohci_handle_port_enable(ohcip, port, 1); 640 break; 641 case CFS_PORT_SUSPEND: 642 ohci_handle_port_suspend(ohcip, port, 1); 643 break; 644 case CFS_PORT_RESET: 645 ohci_handle_port_reset(ohcip, port); 646 break; 647 case CFS_PORT_POWER: 648 ohci_handle_port_power(ohcip, port, 1); 649 break; 650 default: 651 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 652 "ohci_handle_set_clear_port_feature: " 653 "Unsupported request 0x%x 0x%x", bRequest, wValue); 654 655 error = USB_FAILURE; 656 break; 657 } 658 break; 659 case USB_REQ_CLEAR_FEATURE: 660 switch (wValue) { 661 case CFS_PORT_ENABLE: 662 ohci_handle_port_enable(ohcip, port, 0); 663 break; 664 case CFS_C_PORT_ENABLE: 665 ohci_handle_clrchng_port_enable(ohcip, port); 666 break; 667 case CFS_PORT_SUSPEND: 668 ohci_handle_port_suspend(ohcip, port, 0); 669 break; 670 case CFS_C_PORT_SUSPEND: 671 ohci_handle_clrchng_port_suspend(ohcip, port); 672 break; 673 case CFS_C_PORT_RESET: 674 ohci_handle_complete_port_reset(ohcip, port); 675 break; 676 case CFS_PORT_POWER: 677 ohci_handle_port_power(ohcip, port, 0); 678 break; 679 case CFS_C_PORT_CONNECTION: 680 ohci_handle_clear_port_connection(ohcip, port); 681 break; 682 case CFS_C_PORT_OVER_CURRENT: 683 ohci_handle_clrchng_port_over_current(ohcip, port); 684 break; 685 default: 686 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 687 "ohci_handle_set_clear_port_feature: " 688 "Unsupported request 0x%x 0x%x", bRequest, wValue); 689 690 error = USB_FAILURE; 691 break; 692 } 693 break; 694 default: 695 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 696 "ohci_handle_set_clear_port_feature: " 697 "Unsupported request 0x%x 0x%x", bRequest, wValue); 698 699 error = USB_FAILURE; 700 break; 701 } 702 703 return (error); 704 } 705 706 707 /* 708 * ohci_handle_port_power: 709 * 710 * Turn on a root hub port. 711 */ 712 static void 713 ohci_handle_port_power( 714 ohci_state_t *ohcip, 715 uint16_t port, 716 uint_t on) 717 { 718 usb_hub_descr_t *hub_descr; 719 uint_t port_status; 720 ohci_root_hub_t *rh; 721 uint_t p; 722 723 mutex_enter(&ohcip->ohci_int_mutex); 724 725 port_status = Get_OpReg(hcr_rh_portstatus[port]); 726 rh = &ohcip->ohci_root_hub; 727 hub_descr = &ohcip->ohci_root_hub.rh_descr; 728 729 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 730 "ohci_handle_port_power: port = 0x%x status = 0x%x on = %d", 731 port, port_status, on); 732 733 if (on) { 734 /* 735 * If the port power is ganged, enable the power through 736 * the status registers, else enable the port power. 737 */ 738 if ((hub_descr->wHubCharacteristics & 739 HUB_CHARS_POWER_SWITCHING_MODE) == 740 HUB_CHARS_GANGED_POWER) { 741 742 Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPSC); 743 744 for (p = 0; p < hub_descr->bNbrPorts; p++) { 745 rh->rh_port_status[p] = 0; 746 rh->rh_port_state[p] = DISCONNECTED; 747 } 748 } else { 749 /* See if the port power is already on */ 750 if (!(port_status & HCR_PORT_PPS)) { 751 /* Turn the port on */ 752 Set_OpReg(hcr_rh_portstatus[port], 753 HCR_PORT_PPS); 754 } 755 756 rh->rh_port_status[port] = 0; 757 rh->rh_port_state[port] = DISCONNECTED; 758 } 759 } else { 760 /* 761 * If the port power is ganged, disable the power through 762 * the status registers, else disable the port power. 763 */ 764 if ((hub_descr->wHubCharacteristics & 765 HUB_CHARS_POWER_SWITCHING_MODE) == 766 HUB_CHARS_GANGED_POWER) { 767 768 Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPS); 769 770 for (p = 0; p < hub_descr->bNbrPorts; p++) { 771 rh->rh_port_status[p] = 0; 772 rh->rh_port_state[p] = POWERED_OFF; 773 } 774 } else { 775 /* See if the port power is already OFF */ 776 if ((port_status & HCR_PORT_PPS)) { 777 /* Turn the port OFF by writing LSSA bit */ 778 Set_OpReg(hcr_rh_portstatus[port], 779 HCR_PORT_LSDA); 780 } 781 782 rh->rh_port_status[port] = 0; 783 rh->rh_port_state[port] = POWERED_OFF; 784 } 785 } 786 787 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 788 "ohci_handle_port_power done: " 789 "port = 0x%x status = 0x%x on = %d", 790 port, Get_OpReg(hcr_rh_portstatus[port]), on); 791 792 mutex_exit(&ohcip->ohci_int_mutex); 793 } 794 795 796 /* 797 * ohci_handle_port_enable: 798 * 799 * Handle port enable request. 800 */ 801 static void 802 ohci_handle_port_enable( 803 ohci_state_t *ohcip, 804 uint16_t port, 805 uint_t on) 806 { 807 uint_t port_status; 808 809 mutex_enter(&ohcip->ohci_int_mutex); 810 811 port_status = Get_OpReg(hcr_rh_portstatus[port]); 812 813 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 814 "ohci_handle_port_enable: port = 0x%x, status = 0x%x", 815 port, port_status); 816 817 if (on) { 818 /* See if the port enable is already on */ 819 if (!(port_status & HCR_PORT_PES)) { 820 /* Enable the port */ 821 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PES); 822 } 823 } else { 824 /* See if the port enable is already off */ 825 if (port_status & HCR_PORT_PES) { 826 /* disable the port by writing CCS bit */ 827 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CCS); 828 } 829 } 830 831 mutex_exit(&ohcip->ohci_int_mutex); 832 } 833 834 835 /* 836 * ohci_handle_clrchng_port_enable: 837 * 838 * Handle clear port enable change bit. 839 */ 840 static void 841 ohci_handle_clrchng_port_enable( 842 ohci_state_t *ohcip, 843 uint16_t port) 844 { 845 uint_t port_status; 846 847 mutex_enter(&ohcip->ohci_int_mutex); 848 849 port_status = Get_OpReg(hcr_rh_portstatus[port]); 850 851 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 852 "ohci_handle_port_enable: port = 0x%x, status = 0x%x", 853 port, port_status); 854 855 /* Clear the PortEnableStatusChange Bit */ 856 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PESC); 857 858 mutex_exit(&ohcip->ohci_int_mutex); 859 } 860 861 862 /* 863 * ohci_handle_port_suspend: 864 * 865 * Handle port suspend/resume request. 866 */ 867 static void 868 ohci_handle_port_suspend( 869 ohci_state_t *ohcip, 870 uint16_t port, 871 uint_t on) 872 { 873 uint_t port_status; 874 875 mutex_enter(&ohcip->ohci_int_mutex); 876 877 port_status = Get_OpReg(hcr_rh_portstatus[port]); 878 879 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 880 "ohci_handle_port_suspend: port = 0x%x, status = 0x%x", 881 port, port_status); 882 883 if (on) { 884 /* Suspend the port */ 885 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSS); 886 } else { 887 /* To Resume, we write the POCI bit */ 888 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_POCI); 889 } 890 891 mutex_exit(&ohcip->ohci_int_mutex); 892 } 893 894 895 /* 896 * ohci_handle_clrchng_port_suspend: 897 * 898 * Handle port clear port suspend change bit. 899 */ 900 static void 901 ohci_handle_clrchng_port_suspend( 902 ohci_state_t *ohcip, 903 uint16_t port) 904 { 905 uint_t port_status; 906 907 mutex_enter(&ohcip->ohci_int_mutex); 908 909 port_status = Get_OpReg(hcr_rh_portstatus[port]); 910 911 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 912 "ohci_handle_clrchng_port_suspend: port = 0x%x, status = 0x%x", 913 port, port_status); 914 915 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSSC); 916 917 mutex_exit(&ohcip->ohci_int_mutex); 918 } 919 920 921 /* 922 * ohci_handle_port_reset: 923 * 924 * Perform a port reset. 925 */ 926 static void 927 ohci_handle_port_reset( 928 ohci_state_t *ohcip, 929 uint16_t port) 930 { 931 uint_t port_status; 932 933 mutex_enter(&ohcip->ohci_int_mutex); 934 935 port_status = Get_OpReg(hcr_rh_portstatus[port]); 936 937 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 938 "ohci_handle_port_reset: port = 0x%x status = 0x%x", 939 port, port_status); 940 941 if (!(port_status & HCR_PORT_CCS)) { 942 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 943 "port_status & HCR_PORT_CCS == 0: " 944 "port = 0x%x status = 0x%x", port, port_status); 945 } 946 947 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRS); 948 949 mutex_exit(&ohcip->ohci_int_mutex); 950 } 951 952 953 /* 954 * ohci_handle_complete_port_reset: 955 * 956 * Perform a port reset change. 957 */ 958 static void 959 ohci_handle_complete_port_reset( 960 ohci_state_t *ohcip, 961 uint16_t port) 962 { 963 uint_t port_status; 964 965 mutex_enter(&ohcip->ohci_int_mutex); 966 967 port_status = Get_OpReg(hcr_rh_portstatus[port]); 968 969 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 970 "ohci_handle_complete_port_reset: port = 0x%x status = 0x%x", 971 port, port_status); 972 973 if (!(port_status & HCR_PORT_CCS)) { 974 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 975 "port_status & HCR_PORT_CCS == 0: " 976 "port = 0x%x status = 0x%x", port, port_status); 977 } 978 979 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRSC); 980 981 mutex_exit(&ohcip->ohci_int_mutex); 982 } 983 984 985 /* 986 * ohci_handle_clear_port_connection: 987 * 988 * Perform a clear port connection. 989 */ 990 static void 991 ohci_handle_clear_port_connection( 992 ohci_state_t *ohcip, 993 uint16_t port) 994 { 995 uint_t port_status; 996 997 mutex_enter(&ohcip->ohci_int_mutex); 998 999 port_status = Get_OpReg(hcr_rh_portstatus[port]); 1000 1001 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1002 "ohci_handle_clear_port_connection: port = 0x%x" 1003 "status = 0x%x", port, port_status); 1004 1005 /* Clear CSC bit */ 1006 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CSC); 1007 1008 mutex_exit(&ohcip->ohci_int_mutex); 1009 } 1010 1011 1012 /* 1013 * ohci_handle_clrchng_port_over_current: 1014 * 1015 * Perform a clear over current condition. 1016 */ 1017 static void 1018 ohci_handle_clrchng_port_over_current( 1019 ohci_state_t *ohcip, 1020 uint16_t port) 1021 { 1022 uint_t port_status; 1023 1024 mutex_enter(&ohcip->ohci_int_mutex); 1025 1026 port_status = Get_OpReg(hcr_rh_portstatus[port]); 1027 1028 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1029 "ohci_handle_clrchng_port_over_current: port = 0x%x" 1030 "status = 0x%x", port, port_status); 1031 1032 Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_OCIC); 1033 1034 mutex_exit(&ohcip->ohci_int_mutex); 1035 } 1036 1037 1038 /* 1039 * ohci_handle_get_port_status: 1040 * 1041 * Handle a get port status request. 1042 */ 1043 static void 1044 ohci_handle_get_port_status( 1045 ohci_state_t *ohcip, 1046 uint16_t port) 1047 { 1048 usb_ctrl_req_t *ctrl_reqp; 1049 mblk_t *message; 1050 uint_t new_port_status; 1051 uint_t change_status; 1052 1053 mutex_enter(&ohcip->ohci_int_mutex); 1054 1055 ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp; 1056 1057 /* Read the current port status and return it */ 1058 new_port_status = Get_OpReg(hcr_rh_portstatus[port]); 1059 ohcip->ohci_root_hub.rh_port_status[port] = new_port_status; 1060 1061 change_status = (new_port_status & HCR_PORT_CHNG_MASK) >> 16; 1062 1063 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1064 "ohci_handle_get_port_status: port = %d new status = 0x%x" 1065 "change = 0x%x", port, new_port_status, change_status); 1066 1067 message = ctrl_reqp->ctrl_data; 1068 1069 ASSERT(message != NULL); 1070 1071 *message->b_wptr++ = (uchar_t)new_port_status; 1072 *message->b_wptr++ = (uchar_t)(new_port_status >> 8); 1073 *message->b_wptr++ = (uchar_t)change_status; 1074 *message->b_wptr++ = (uchar_t)(change_status >> 8); 1075 1076 /* Save the data in control request */ 1077 ctrl_reqp->ctrl_data = message; 1078 1079 mutex_exit(&ohcip->ohci_int_mutex); 1080 } 1081 1082 1083 /* 1084 * ohci_handle_set_clear_hub_feature: 1085 * 1086 * OHCI only implements clearing C_HUB_OVER_CURRENT feature now. 1087 * Other hub requests of this bmRequestType are either not 1088 * supported by hardware or never used. 1089 */ 1090 static int 1091 ohci_handle_set_clear_hub_feature( 1092 ohci_state_t *ohcip, 1093 uchar_t bRequest, 1094 uint16_t wValue) 1095 { 1096 int error = USB_SUCCESS; 1097 1098 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1099 "ohci_handle_set_clear_hub_feature: 0x%x 0x%x", 1100 bRequest, wValue); 1101 1102 switch (bRequest) { 1103 case USB_REQ_CLEAR_FEATURE: 1104 if (wValue == CFS_C_HUB_OVER_CURRENT) { 1105 ohci_handle_clrchng_hub_over_current(ohcip); 1106 } else { 1107 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1108 "ohci_handle_set_clear_hub_feature: " 1109 "Unsupported request 0x%x 0x%x", bRequest, wValue); 1110 1111 error = USB_FAILURE; 1112 } 1113 break; 1114 1115 case USB_REQ_SET_FEATURE: 1116 default: 1117 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1118 "ohci_handle_set_clear_hub_feature: " 1119 "Unsupported request 0x%x 0x%x", bRequest, wValue); 1120 1121 error = USB_FAILURE; 1122 break; 1123 } 1124 1125 return (error); 1126 } 1127 1128 1129 /* 1130 * ohci_handle_clrchng_hub_over_current: 1131 * 1132 * Clear over current indicator change bit on the root hub. 1133 */ 1134 static void 1135 ohci_handle_clrchng_hub_over_current( 1136 ohci_state_t *ohcip) 1137 { 1138 uint_t hub_status; 1139 1140 mutex_enter(&ohcip->ohci_int_mutex); 1141 1142 hub_status = Get_OpReg(hcr_rh_status); 1143 1144 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1145 "ohci_handle_clrchng_hub_over_current: " 1146 "status = 0x%x", hub_status); 1147 1148 Set_OpReg(hcr_rh_status, HCR_RH_STATUS_OCIC); 1149 1150 mutex_exit(&ohcip->ohci_int_mutex); 1151 } 1152 1153 1154 /* 1155 * ohci_handle_get_hub_descriptor: 1156 */ 1157 static void 1158 ohci_handle_get_hub_descriptor( 1159 ohci_state_t *ohcip) 1160 { 1161 usb_ctrl_req_t *ctrl_reqp; 1162 mblk_t *message; 1163 usb_hub_descr_t *root_hub_descr; 1164 size_t length; 1165 uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH]; 1166 1167 mutex_enter(&ohcip->ohci_int_mutex); 1168 1169 ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp; 1170 root_hub_descr = &ohcip->ohci_root_hub.rh_descr; 1171 length = ctrl_reqp->ctrl_wLength; 1172 1173 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1174 "ohci_handle_get_hub_descriptor: Ctrl Req = 0x%p", 1175 (void *)ctrl_reqp); 1176 1177 message = ctrl_reqp->ctrl_data; 1178 1179 ASSERT(message != NULL); 1180 1181 bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH); 1182 1183 raw_descr[0] = root_hub_descr->bDescLength; 1184 raw_descr[1] = root_hub_descr->bDescriptorType; 1185 raw_descr[2] = root_hub_descr->bNbrPorts; 1186 raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF; 1187 raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8; 1188 raw_descr[5] = root_hub_descr->bPwrOn2PwrGood; 1189 raw_descr[6] = root_hub_descr->bHubContrCurrent; 1190 raw_descr[7] = root_hub_descr->DeviceRemovable; 1191 raw_descr[8] = root_hub_descr->PortPwrCtrlMask; 1192 1193 bcopy(raw_descr, message->b_wptr, length); 1194 message->b_wptr += length; 1195 1196 /* Save the data in control request */ 1197 ctrl_reqp->ctrl_data = message; 1198 1199 mutex_exit(&ohcip->ohci_int_mutex); 1200 } 1201 1202 1203 /* 1204 * ohci_handle_get_hub_status: 1205 * 1206 * Handle a get hub status request. 1207 */ 1208 static void 1209 ohci_handle_get_hub_status( 1210 ohci_state_t *ohcip) 1211 { 1212 usb_ctrl_req_t *ctrl_reqp; 1213 mblk_t *message; 1214 uint_t new_root_hub_status; 1215 1216 mutex_enter(&ohcip->ohci_int_mutex); 1217 1218 ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp; 1219 new_root_hub_status = Get_OpReg(hcr_rh_status); 1220 1221 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1222 "ohci_handle_get_hub_status: new root hub status = 0x%x", 1223 new_root_hub_status); 1224 1225 message = ctrl_reqp->ctrl_data; 1226 1227 ASSERT(message != NULL); 1228 1229 *message->b_wptr++ = (uchar_t)new_root_hub_status; 1230 *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8); 1231 *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16); 1232 *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24); 1233 1234 /* Save the data in control request */ 1235 ctrl_reqp->ctrl_data = message; 1236 1237 mutex_exit(&ohcip->ohci_int_mutex); 1238 } 1239 1240 1241 /* 1242 * ohci_handle_get_device_status: 1243 * 1244 * Handle a get device status request. 1245 */ 1246 static void 1247 ohci_handle_get_device_status( 1248 ohci_state_t *ohcip) 1249 { 1250 usb_ctrl_req_t *ctrl_reqp; 1251 mblk_t *message; 1252 uint16_t dev_status; 1253 1254 mutex_enter(&ohcip->ohci_int_mutex); 1255 1256 ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp; 1257 1258 /* 1259 * OHCI doesn't have device status information. 1260 * Simply return what is desired for the request. 1261 */ 1262 dev_status = USB_DEV_SLF_PWRD_STATUS; 1263 1264 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1265 "ohci_handle_get_device_status: device status = 0x%x", 1266 dev_status); 1267 1268 message = ctrl_reqp->ctrl_data; 1269 1270 ASSERT(message != NULL); 1271 1272 *message->b_wptr++ = (uchar_t)dev_status; 1273 *message->b_wptr++ = (uchar_t)(dev_status >> 8); 1274 1275 /* Save the data in control request */ 1276 ctrl_reqp->ctrl_data = message; 1277 1278 mutex_exit(&ohcip->ohci_int_mutex); 1279 } 1280 1281 1282 /* 1283 * ohci_handle_root_hub_pipe_start_intr_polling: 1284 * 1285 * Handle start polling on root hub interrupt pipe. 1286 */ 1287 /* ARGSUSED */ 1288 int 1289 ohci_handle_root_hub_pipe_start_intr_polling( 1290 usba_pipe_handle_data_t *ph, 1291 usb_intr_req_t *client_intr_reqp, 1292 usb_flags_t flags) 1293 { 1294 ohci_state_t *ohcip = ohci_obtain_state( 1295 ph->p_usba_device->usb_root_hub_dip); 1296 usb_ep_descr_t *eptd = &ph->p_ep; 1297 int error = USB_SUCCESS; 1298 uint_t pipe_state; 1299 1300 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1301 "ohci_handle_root_hub_pipe_start_intr_polling: " 1302 "Root hub pipe start polling"); 1303 1304 ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 1305 1306 ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1); 1307 1308 /* ONE_XFER not supported for root hub interrupt pipe */ 1309 ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0); 1310 1311 /* Get root hub intr pipe state */ 1312 pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state; 1313 1314 switch (pipe_state) { 1315 case OHCI_PIPE_STATE_IDLE: 1316 ASSERT(ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0); 1317 1318 /* 1319 * Save the Original Client's Interrupt IN request 1320 * information. We use this for final callback 1321 */ 1322 ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp == NULL); 1323 1324 ohcip->ohci_root_hub.rh_client_intr_reqp = client_intr_reqp; 1325 1326 error = ohci_root_hub_allocate_intr_pipe_resource(ohcip, flags); 1327 1328 if (error != USB_SUCCESS) { 1329 /* Reset client interrupt request pointer */ 1330 ohcip->ohci_root_hub.rh_client_intr_reqp = NULL; 1331 1332 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1333 "ohci_handle_root_hub_pipe_start_intr_polling: " 1334 "No Resources"); 1335 1336 return (error); 1337 } 1338 1339 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1340 "ohci_handle_root_hub_pipe_start_intr_polling: " 1341 "Start polling for root hub successful"); 1342 1343 break; 1344 case OHCI_PIPE_STATE_ACTIVE: 1345 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1346 "ohci_handle_root_hub_pipe_start_intr_polling: " 1347 "Polling for root hub is already in progress"); 1348 1349 break; 1350 default: 1351 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1352 "ohci_handle_root_hub_pipe_start_intr_polling: " 1353 "Pipe is in error state 0x%x", pipe_state); 1354 1355 error = USB_FAILURE; 1356 1357 break; 1358 } 1359 1360 return (error); 1361 } 1362 1363 1364 /* 1365 * ohci_handle_root_hub_pipe_stop_intr_polling: 1366 * 1367 * Handle stop polling on root hub intr pipe. 1368 */ 1369 /* ARGSUSED */ 1370 void 1371 ohci_handle_root_hub_pipe_stop_intr_polling( 1372 usba_pipe_handle_data_t *ph, 1373 usb_flags_t flags) 1374 { 1375 ohci_state_t *ohcip = ohci_obtain_state( 1376 ph->p_usba_device->usb_root_hub_dip); 1377 usb_ep_descr_t *eptd = &ph->p_ep; 1378 1379 ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 1380 1381 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1382 "ohci_handle_root_hub_pipe_stop_intr_polling: " 1383 "Root hub pipe stop polling"); 1384 1385 ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1); 1386 1387 if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) { 1388 1389 ohcip->ohci_root_hub.rh_intr_pipe_state = 1390 OHCI_PIPE_STATE_STOP_POLLING; 1391 1392 /* Do interrupt pipe cleanup */ 1393 ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_STOPPED_POLLING); 1394 1395 ASSERT(ohcip->ohci_root_hub. 1396 rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE); 1397 1398 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1399 "ohci_hcdi_pipe_stop_intr_polling: Stop polling for root" 1400 "hub successful"); 1401 } else { 1402 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1403 "ohci_hcdi_pipe_stop_intr_polling: " 1404 "Polling for root hub is already stopped"); 1405 } 1406 } 1407 1408 1409 /* 1410 * ohci_root_hub_allocate_intr_pipe_resource: 1411 * 1412 * Allocate interrupt requests and initialize them. 1413 */ 1414 static int 1415 ohci_root_hub_allocate_intr_pipe_resource( 1416 ohci_state_t *ohcip, 1417 usb_flags_t flags) 1418 { 1419 usba_pipe_handle_data_t *ph; 1420 size_t length; 1421 usb_intr_req_t *curr_intr_reqp; 1422 1423 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1424 "ohci_root_hub_allocate_intr_pipe_resource"); 1425 1426 ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 1427 1428 /* Get the interrupt pipe handle */ 1429 ph = ohcip->ohci_root_hub.rh_intr_pipe_handle; 1430 1431 /* Get the current interrupt request pointer */ 1432 curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp; 1433 1434 /* 1435 * If current interrupt request pointer is null, 1436 * allocate new interrupt request. 1437 */ 1438 if (curr_intr_reqp == NULL) { 1439 ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp); 1440 1441 /* Get the length of interrupt transfer */ 1442 length = ohcip->ohci_root_hub. 1443 rh_client_intr_reqp->intr_len; 1444 1445 curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip, 1446 ohcip->ohci_root_hub.rh_client_intr_reqp, 1447 length, flags); 1448 1449 if (curr_intr_reqp == NULL) { 1450 1451 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1452 "ohci_root_hub_allocate_intr_pipe_resource:" 1453 "Interrupt request structure allocation failed"); 1454 1455 return (USB_NO_RESOURCES); 1456 } 1457 1458 ohcip->ohci_root_hub.rh_curr_intr_reqp = curr_intr_reqp; 1459 1460 mutex_enter(&ph->p_mutex); 1461 ph->p_req_count++; 1462 mutex_exit(&ph->p_mutex); 1463 } 1464 1465 /* Start the timer for the root hub interrupt pipe polling */ 1466 if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0) { 1467 ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 1468 timeout(ohci_handle_root_hub_status_change, 1469 (void *)ohcip, drv_usectohz(OHCI_RH_POLL_TIME)); 1470 1471 ohcip->ohci_root_hub. 1472 rh_intr_pipe_state = OHCI_PIPE_STATE_ACTIVE; 1473 } 1474 1475 return (USB_SUCCESS); 1476 } 1477 1478 1479 /* 1480 * ohci_root_hub_intr_pipe_cleanup: 1481 * 1482 * Deallocate all interrupt requests and do callback 1483 * the original client interrupt request. 1484 */ 1485 static void 1486 ohci_root_hub_intr_pipe_cleanup( 1487 ohci_state_t *ohcip, 1488 usb_cr_t completion_reason) 1489 { 1490 usb_intr_req_t *curr_intr_reqp; 1491 usb_opaque_t client_intr_reqp; 1492 timeout_id_t timer_id; 1493 usba_pipe_handle_data_t *ph; 1494 1495 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1496 "ohci_root_hub_intr_pipe_cleanup"); 1497 1498 ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 1499 1500 /* Get the interrupt pipe handle */ 1501 ph = ohcip->ohci_root_hub.rh_intr_pipe_handle; 1502 1503 /* Get the interrupt timerid */ 1504 timer_id = ohcip->ohci_root_hub.rh_intr_pipe_timer_id; 1505 1506 /* Stop the root hub interrupt timer */ 1507 if (timer_id) { 1508 /* Reset the timer id to zero */ 1509 ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0; 1510 1511 mutex_exit(&ohcip->ohci_int_mutex); 1512 (void) untimeout(timer_id); 1513 mutex_enter(&ohcip->ohci_int_mutex); 1514 } 1515 1516 /* Reset the current interrupt request pointer */ 1517 curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp; 1518 1519 /* Deallocate uncompleted interrupt request */ 1520 if (curr_intr_reqp) { 1521 ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL; 1522 usb_free_intr_req(curr_intr_reqp); 1523 1524 mutex_enter(&ph->p_mutex); 1525 ph->p_req_count--; 1526 mutex_exit(&ph->p_mutex); 1527 } 1528 1529 client_intr_reqp = (usb_opaque_t) 1530 ohcip->ohci_root_hub.rh_client_intr_reqp; 1531 1532 /* Callback for original client interrupt request */ 1533 if (client_intr_reqp) { 1534 ohci_root_hub_hcdi_callback(ph, completion_reason); 1535 } 1536 } 1537 1538 1539 /* 1540 * ohci_handle_root_hub_status_change: 1541 * 1542 * A root hub status change interrupt will occur any time there is a change 1543 * in the root hub status register or one of the port status registers. 1544 */ 1545 void 1546 ohci_handle_root_hub_status_change(void *arg) 1547 { 1548 ohci_state_t *ohcip = (ohci_state_t *)arg; 1549 usb_intr_req_t *curr_intr_reqp; 1550 usb_port_mask_t all_ports_status = 0; 1551 uint_t new_root_hub_status; 1552 uint_t new_port_status; 1553 uint_t change_status; 1554 usb_hub_descr_t *hub_descr; 1555 mblk_t *message; 1556 size_t length; 1557 usb_ep_descr_t *eptd; 1558 usba_pipe_handle_data_t *ph; 1559 int i; 1560 1561 mutex_enter(&ohcip->ohci_int_mutex); 1562 1563 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1564 "ohci_handle_root_hub_status_change: state = %d", 1565 ohcip->ohci_root_hub.rh_intr_pipe_state); 1566 1567 /* Get the pointer to root hub descriptor */ 1568 hub_descr = &ohcip->ohci_root_hub.rh_descr; 1569 1570 /* Get the current interrupt request pointer */ 1571 curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp; 1572 1573 ph = ohcip->ohci_root_hub.rh_intr_pipe_handle; 1574 1575 /* Check whether timeout handler is valid */ 1576 if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id) { 1577 /* Check host controller is in operational state */ 1578 if ((ohci_state_is_operational(ohcip)) != USB_SUCCESS) { 1579 1580 /* Reset the timer id */ 1581 ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0; 1582 1583 /* Do interrupt pipe cleanup */ 1584 ohci_root_hub_intr_pipe_cleanup( 1585 ohcip, USB_CR_HC_HARDWARE_ERR); 1586 1587 mutex_exit(&ohcip->ohci_int_mutex); 1588 1589 return; 1590 } 1591 } else { 1592 mutex_exit(&ohcip->ohci_int_mutex); 1593 1594 return; 1595 } 1596 1597 eptd = &ohcip->ohci_root_hub.rh_intr_pipe_handle->p_ep; 1598 1599 new_root_hub_status = Get_OpReg(hcr_rh_status); 1600 1601 /* See if the root hub status has changed */ 1602 if (new_root_hub_status & HCR_RH_CHNG_MASK) { 1603 1604 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1605 "ohci_handle_root_hub_status_change: " 1606 "Root hub status has changed!"); 1607 1608 all_ports_status = 1; 1609 1610 /* Update root hub status */ 1611 ohcip->ohci_root_hub.rh_status = new_root_hub_status; 1612 } 1613 1614 /* Check each port */ 1615 for (i = 0; i < hub_descr->bNbrPorts; i++) { 1616 new_port_status = Get_OpReg(hcr_rh_portstatus[i]); 1617 change_status = new_port_status & HCR_PORT_CHNG_MASK; 1618 1619 /* 1620 * If there is change in the port status then set 1621 * the bit in the bitmap of changes and inform hub 1622 * driver about these changes. Hub driver will take 1623 * care of these changes. 1624 */ 1625 if (change_status) { 1626 1627 /* See if a device was attached/detached */ 1628 if (change_status & HCR_PORT_CSC) { 1629 /* 1630 * Update the state depending on whether 1631 * the port was attached or detached. 1632 */ 1633 if (new_port_status & HCR_PORT_CCS) { 1634 ohcip->ohci_root_hub. 1635 rh_port_state[i] = DISABLED; 1636 1637 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1638 ohcip->ohci_log_hdl, 1639 "Port %d connected", i+1); 1640 } else { 1641 ohcip->ohci_root_hub. 1642 rh_port_state[i] = DISCONNECTED; 1643 1644 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1645 ohcip->ohci_log_hdl, 1646 "Port %d disconnected", i+1); 1647 } 1648 } 1649 1650 /* See if port enable status changed */ 1651 if (change_status & HCR_PORT_PESC) { 1652 /* 1653 * Update the state depending on whether 1654 * the port was enabled or disabled. 1655 */ 1656 if (new_port_status & HCR_PORT_PES) { 1657 ohcip->ohci_root_hub. 1658 rh_port_state[i] = ENABLED; 1659 1660 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1661 ohcip->ohci_log_hdl, 1662 "Port %d enabled", i+1); 1663 } else { 1664 ohcip->ohci_root_hub. 1665 rh_port_state[i] = DISABLED; 1666 1667 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, 1668 ohcip->ohci_log_hdl, 1669 "Port %d disabled", i+1); 1670 } 1671 } 1672 1673 all_ports_status |= 1 << (i + 1); 1674 1675 /* Update the status */ 1676 ohcip->ohci_root_hub. 1677 rh_port_status[i] = new_port_status; 1678 } 1679 } 1680 1681 if (ph && all_ports_status && curr_intr_reqp) { 1682 1683 length = eptd->wMaxPacketSize; 1684 1685 ASSERT(length != 0); 1686 1687 /* Get the message block */ 1688 message = curr_intr_reqp->intr_data; 1689 1690 ASSERT(message != NULL); 1691 1692 do { 1693 /* 1694 * check that mblk is big enough when we 1695 * are writing bytes into it 1696 */ 1697 if (message->b_wptr >= message->b_datap->db_lim) { 1698 1699 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, 1700 ohcip->ohci_log_hdl, 1701 "ohci_handle_root_hub_status_change: " 1702 "mblk data overflow."); 1703 1704 break; 1705 } 1706 1707 *message->b_wptr++ = (uchar_t)all_ports_status; 1708 all_ports_status >>= 8; 1709 } while (all_ports_status != 0); 1710 1711 ohci_root_hub_hcdi_callback(ph, USB_CR_OK); 1712 } 1713 1714 /* Reset the timer id */ 1715 ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0; 1716 1717 if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) { 1718 /* 1719 * If needed, allocate new interrupt request. Also 1720 * start the timer for the root hub interrupt polling. 1721 */ 1722 if ((ohci_root_hub_allocate_intr_pipe_resource( 1723 ohcip, 0)) != USB_SUCCESS) { 1724 1725 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1726 "ohci_handle_root_hub_status_change: No Resources"); 1727 1728 /* Do interrupt pipe cleanup */ 1729 ohci_root_hub_intr_pipe_cleanup( 1730 ohcip, USB_CR_NO_RESOURCES); 1731 } 1732 } 1733 1734 mutex_exit(&ohcip->ohci_int_mutex); 1735 } 1736 1737 1738 /* 1739 * ohci_root_hub_hcdi_callback() 1740 * 1741 * Convenience wrapper around usba_hcdi_cb() for the root hub. 1742 */ 1743 static void 1744 ohci_root_hub_hcdi_callback( 1745 usba_pipe_handle_data_t *ph, 1746 usb_cr_t completion_reason) 1747 { 1748 ohci_state_t *ohcip = ohci_obtain_state( 1749 ph->p_usba_device->usb_root_hub_dip); 1750 uchar_t attributes = ph->p_ep.bmAttributes & 1751 USB_EP_ATTR_MASK; 1752 usb_opaque_t curr_xfer_reqp; 1753 uint_t pipe_state = 0; 1754 1755 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl, 1756 "ohci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x", 1757 (void *)ph, completion_reason); 1758 1759 ASSERT(mutex_owned(&ohcip->ohci_int_mutex)); 1760 1761 /* Set the pipe state as per completion reason */ 1762 switch (completion_reason) { 1763 case USB_CR_OK: 1764 switch (attributes) { 1765 case USB_EP_ATTR_CONTROL: 1766 pipe_state = OHCI_PIPE_STATE_IDLE; 1767 break; 1768 case USB_EP_ATTR_INTR: 1769 pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state; 1770 break; 1771 } 1772 break; 1773 case USB_CR_NO_RESOURCES: 1774 case USB_CR_NOT_SUPPORTED: 1775 case USB_CR_STOPPED_POLLING: 1776 case USB_CR_PIPE_RESET: 1777 case USB_CR_HC_HARDWARE_ERR: 1778 /* Set pipe state to idle */ 1779 pipe_state = OHCI_PIPE_STATE_IDLE; 1780 break; 1781 case USB_CR_PIPE_CLOSING: 1782 break; 1783 default: 1784 /* Set pipe state to error */ 1785 pipe_state = OHCI_PIPE_STATE_ERROR; 1786 break; 1787 } 1788 1789 switch (attributes) { 1790 case USB_EP_ATTR_CONTROL: 1791 curr_xfer_reqp = (usb_opaque_t) 1792 ohcip->ohci_root_hub.rh_curr_ctrl_reqp; 1793 1794 ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL; 1795 ohcip->ohci_root_hub.rh_ctrl_pipe_state = pipe_state; 1796 break; 1797 case USB_EP_ATTR_INTR: 1798 /* if curr_intr_reqp available then use this request */ 1799 if (ohcip->ohci_root_hub.rh_curr_intr_reqp) { 1800 curr_xfer_reqp = (usb_opaque_t) 1801 ohcip->ohci_root_hub.rh_curr_intr_reqp; 1802 1803 ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL; 1804 } else { 1805 /* no current request, use client's request */ 1806 curr_xfer_reqp = (usb_opaque_t) 1807 ohcip->ohci_root_hub.rh_client_intr_reqp; 1808 1809 ohcip->ohci_root_hub.rh_client_intr_reqp = NULL; 1810 } 1811 1812 ohcip->ohci_root_hub.rh_intr_pipe_state = pipe_state; 1813 break; 1814 } 1815 1816 ASSERT(curr_xfer_reqp != NULL); 1817 1818 mutex_exit(&ohcip->ohci_int_mutex); 1819 usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason); 1820 mutex_enter(&ohcip->ohci_int_mutex); 1821 } 1822