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