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