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