1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Universal Serial BUS Host Controller Driver (UHCI) 30 * 31 * The UHCI driver is a driver which interfaces to the Universal 32 * Serial Bus Architecture (USBA) and the Host Controller (HC). The interface to 33 * the Host Controller is defined by the Universal Host Controller Interface. 34 * This file contains the code for root hub related functions. 35 */ 36 #include <sys/usb/hcd/uhci/uhcid.h> 37 #include <sys/usb/hcd/uhci/uhci.h> 38 #include <sys/usb/hcd/uhci/uhcihub.h> 39 40 /* 41 * Function Prototypes 42 */ 43 static int uhci_handle_set_clear_port_feature( 44 uhci_state_t *uhcip, 45 uchar_t bRequest, 46 uint16_t wValue, 47 usb_port_t port); 48 static void uhci_handle_port_power( 49 uhci_state_t *uhcip, 50 usb_port_t port, 51 uint_t on); 52 static void uhci_handle_port_suspend( 53 uhci_state_t *uhcip, 54 usb_port_t port, 55 uint_t on); 56 static void uhci_handle_port_enable_disable( 57 uhci_state_t *uhcip, 58 usb_port_t port, 59 uint_t on); 60 static void uhci_handle_port_reset( 61 uhci_state_t *uhcip, 62 usb_port_t port); 63 static void uhci_handle_complete_port_reset( 64 uhci_state_t *uhcip, 65 usb_port_t port); 66 static void uhci_handle_clear_port_connection( 67 uhci_state_t *uhcip, 68 usb_port_t port); 69 static void uhci_handle_get_port_status( 70 uhci_state_t *uhcip, 71 usb_ctrl_req_t *req, 72 usb_port_t port); 73 static void uhci_handle_get_hub_descriptor( 74 uhci_state_t *uhcip, 75 usb_ctrl_req_t *req); 76 static void uhci_handle_get_hub_status( 77 uhci_state_t *uhcip, 78 usb_ctrl_req_t *req); 79 static void uhci_handle_get_device_status( 80 uhci_state_t *uhcip, 81 usb_ctrl_req_t *req); 82 static uint_t uhci_get_port_status( 83 uhci_state_t *uhcip, 84 usb_port_t port); 85 static void uhci_rh_hcdi_callback( 86 uhci_state_t *uhcip, 87 usba_pipe_handle_data_t *ph, 88 usb_opaque_t req, 89 usb_cr_t cr); 90 91 /* 92 * root hub device descriptor 93 */ 94 static usb_dev_descr_t uhci_rh_dev_descr = { 95 0x12, /* Length */ 96 1, /* Type */ 97 0x110, /* BCD - v1.1 */ 98 9, /* Class */ 99 0, /* Sub class */ 100 0, /* Protocol */ 101 8, /* Max pkt size */ 102 0, /* Vendor */ 103 0, /* Product id */ 104 0, /* Device release */ 105 0, /* Manufacturer */ 106 0, /* Product */ 107 0, /* Sn */ 108 1 /* No of configs */ 109 }; 110 111 /* 112 * root hub config descriptor 113 */ 114 static uchar_t uhci_rh_config_descr[] = { 115 /* config descriptor */ 116 0x09, /* bLength */ 117 0x02, /* bDescriptorType, Configuration */ 118 0x19, 0x00, /* wTotalLength */ 119 0x01, /* bNumInterfaces */ 120 0x01, /* bConfigurationValue */ 121 0x00, /* iConfiguration */ 122 0x40, /* bmAttributes */ 123 0x00, /* MaxPower */ 124 125 /* interface descriptor */ 126 0x09, /* bLength */ 127 0x04, /* bDescriptorType, Interface */ 128 0x00, /* bInterfaceNumber */ 129 0x00, /* bAlternateSetting */ 130 0x01, /* bNumEndpoints */ 131 0x09, /* bInterfaceClass */ 132 0x01, /* bInterfaceSubClass */ 133 0x00, /* bInterfaceProtocol */ 134 0x00, /* iInterface */ 135 136 /* endpoint descriptor */ 137 0x07, /* bLength */ 138 0x05, /* bDescriptorType, Endpoint */ 139 0x81, /* bEndpointAddress */ 140 0x03, /* bmAttributes */ 141 0x01, 0x00, /* wMaxPacketSize, 1 + (OHCI_MAX_RH_PORTS / 8) */ 142 0x20 /* bInterval */ 143 }; 144 145 146 /* 147 * uhci_init_root_hub: 148 * Initialize the root hub 149 */ 150 int 151 uhci_init_root_hub(uhci_state_t *uhcip) 152 { 153 int i, length; 154 usb_hub_descr_t *root_hub_descr = &uhcip->uhci_root_hub.rh_descr; 155 156 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 157 "uhci_init_root_hub:"); 158 159 uhcip->uhci_root_hub.rh_num_ports = MAX_RH_PORTS; 160 161 /* 162 * Build the hub descriptor 163 */ 164 root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE; 165 root_hub_descr->bNbrPorts = MAX_RH_PORTS; 166 167 length = root_hub_descr->bNbrPorts / 8; 168 if (length) { 169 root_hub_descr->bDescLength = 7 + (2 * (length + 1)); 170 } else { 171 root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH; 172 } 173 174 /* Determine the Power Switching Mode */ 175 root_hub_descr->bPwrOn2PwrGood = 10; /* arbitrary number */ 176 root_hub_descr->wHubCharacteristics = 177 HUB_CHARS_NO_POWER_SWITCHING|HUB_CHARS_NO_OVER_CURRENT; 178 179 /* Indicate if the device is removable */ 180 root_hub_descr->DeviceRemovable = 0x0; 181 182 /* Fill in the port power control mask */ 183 root_hub_descr->PortPwrCtrlMask = 0xff; 184 185 for (i = 0; i < uhcip->uhci_root_hub.rh_num_ports; i++) { 186 uhcip->uhci_root_hub.rh_port_state[i] = DISCONNECTED; 187 uhcip->uhci_root_hub.rh_port_status[i] = 0; 188 uhcip->uhci_root_hub.rh_port_changes[i] = 0; 189 } 190 191 /* Finally load the root hub driver */ 192 return (usba_hubdi_bind_root_hub(uhcip->uhci_dip, uhci_rh_config_descr, 193 sizeof (uhci_rh_config_descr), &uhci_rh_dev_descr)); 194 } 195 196 197 /* 198 * uhci_handle_root_hub_request: 199 * Intercept a root hub request. 200 * Handle the root hub request through the registers 201 */ 202 int 203 uhci_handle_root_hub_request( 204 uhci_state_t *uhcip, 205 usba_pipe_handle_data_t *pipe_handle, 206 usb_ctrl_req_t *req) 207 { 208 int error = USB_SUCCESS; 209 uint16_t port = req->ctrl_wIndex - 1; 210 usb_cr_t completion_reason; 211 212 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 213 "uhci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p", 214 req->ctrl_bmRequestType, req->ctrl_bRequest, req->ctrl_wValue, 215 req->ctrl_wIndex, req->ctrl_wLength, (void *)req->ctrl_data); 216 217 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 218 219 switch (req->ctrl_bmRequestType) { 220 case HUB_GET_DEVICE_STATUS_TYPE: 221 uhci_handle_get_device_status(uhcip, req); 222 223 break; 224 case HUB_HANDLE_PORT_FEATURE_TYPE: 225 error = uhci_handle_set_clear_port_feature(uhcip, 226 req->ctrl_bRequest, req->ctrl_wValue, port); 227 228 break; 229 case HUB_GET_PORT_STATUS_TYPE: 230 uhci_handle_get_port_status(uhcip, req, port); 231 232 break; 233 case HUB_CLASS_REQ_TYPE: 234 switch (req->ctrl_bRequest) { 235 case USB_REQ_GET_DESCR: 236 uhci_handle_get_hub_descriptor(uhcip, req); 237 238 break; 239 case USB_REQ_GET_STATUS: 240 uhci_handle_get_hub_status(uhcip, req); 241 242 break; 243 default: 244 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 245 "uhci_handle_root_hub_request: Unsupported " 246 "request 0x%x", req->ctrl_bmRequestType); 247 248 break; 249 } 250 251 break; 252 default: 253 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 254 "uhci_handle_root_hub_request: Unsupported request 0x%x", 255 req->ctrl_bmRequestType); 256 257 break; 258 } 259 260 completion_reason = (error != USB_SUCCESS) ? 261 USB_CR_NOT_SUPPORTED : USB_CR_OK; 262 263 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 264 "uhci_handle_root_hub_request: error = %d", error); 265 266 uhci_rh_hcdi_callback(uhcip, pipe_handle, (usb_opaque_t)req, 267 completion_reason); 268 269 return (USB_SUCCESS); 270 } 271 272 273 /* 274 * uhci_handle_set_clear_port_feature: 275 */ 276 static int 277 uhci_handle_set_clear_port_feature( 278 uhci_state_t *uhcip, 279 uchar_t bRequest, 280 uint16_t wValue, 281 usb_port_t port) 282 { 283 int error = USB_SUCCESS; 284 285 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 286 "uhci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x", 287 bRequest, wValue, port); 288 289 switch (bRequest) { 290 case USB_REQ_SET_FEATURE: 291 switch (wValue) { 292 case CFS_PORT_ENABLE: 293 uhci_handle_port_enable_disable(uhcip, 294 port, UHCI_ENABLE_PORT); 295 break; 296 case CFS_PORT_SUSPEND: 297 uhci_handle_port_suspend(uhcip, port, 1); 298 299 break; 300 case CFS_PORT_RESET: 301 uhci_handle_port_reset(uhcip, port); 302 303 break; 304 case CFS_PORT_POWER: 305 uhci_handle_port_power(uhcip, port, 306 UHCI_ENABLE_PORT_PWR); 307 break; 308 309 default: 310 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 311 "uhci_handle_set_clear_port_feature: " 312 "Unsupported request 0x%x 0x%x", bRequest, wValue); 313 error = USB_FAILURE; 314 315 break; 316 } 317 318 break; 319 case USB_REQ_CLEAR_FEATURE: 320 switch (wValue) { 321 case CFS_PORT_ENABLE: 322 uhci_handle_port_enable_disable(uhcip, 323 port, UHCI_DISABLE_PORT); 324 325 break; 326 case CFS_C_PORT_ENABLE: 327 uhci_handle_port_enable_disable(uhcip, 328 port, UHCI_CLEAR_ENDIS_BIT); 329 330 break; 331 case CFS_PORT_SUSPEND: 332 uhci_handle_port_suspend(uhcip, port, 0); 333 334 break; 335 case CFS_C_PORT_RESET: 336 uhci_handle_complete_port_reset(uhcip, port); 337 338 break; 339 case CFS_PORT_POWER: 340 uhci_handle_port_power(uhcip, port, 341 UHCI_DISABLE_PORT_PWR); 342 343 break; 344 case CFS_C_PORT_CONNECTION: 345 uhci_handle_clear_port_connection(uhcip, port); 346 347 break; 348 default: 349 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 350 "uhci_handle_set_clear_port_feature: " 351 "Unsupported request 0x%x 0x%x", bRequest, wValue); 352 error = USB_FAILURE; 353 354 break; 355 } 356 357 break; 358 default: 359 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 360 "uhci_handle_set_clear_port_feature: " 361 "Unsupported request 0x%x 0x%x", bRequest, wValue); 362 error = USB_FAILURE; 363 } 364 365 366 return (error); 367 } 368 369 370 /* 371 * uhci_handle_port_suspend: 372 */ 373 static void 374 uhci_handle_port_suspend( 375 uhci_state_t *uhcip, 376 usb_port_t port, 377 uint_t on) 378 { 379 uint_t port_status = Get_OpReg16(PORTSC[port]); 380 381 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 382 "uhci_handle_port_suspend: port=%d on=%d", 383 port, on); 384 385 if (on) { 386 /* See if the port suspend is already on */ 387 if (!(port_status & HCR_PORT_SUSPEND)) { 388 /* suspend the port */ 389 Set_OpReg16(PORTSC[port], 390 (port_status | HCR_PORT_SUSPEND)); 391 } 392 } else { 393 /* See if the port suspend is already off */ 394 if ((port_status & HCR_PORT_SUSPEND)) { 395 /* resume the port */ 396 Set_OpReg16(PORTSC[port], 397 (port_status & ~HCR_PORT_SUSPEND)); 398 } 399 } 400 } 401 402 403 /* 404 * uhci_handle_port_power: 405 * Turn on a root hub port. NOTE: Driver does not have any control 406 * over the power status. 407 */ 408 /* ARGSUSED */ 409 static void 410 uhci_handle_port_power( 411 uhci_state_t *uhcip, 412 usb_port_t port, 413 uint_t on) 414 { 415 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 416 "uhci_handle_port_power: nothing to do"); 417 } 418 419 420 /* 421 * uhci_handle_port_enable_disable: 422 * Handle port enable request. 423 */ 424 static void 425 uhci_handle_port_enable_disable( 426 uhci_state_t *uhcip, 427 usb_port_t port, 428 uint_t action) 429 { 430 uint_t port_status = Get_OpReg16(PORTSC[port]); 431 432 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 433 "uhci_handle_port_enable: port = 0x%x, status = 0x%x", 434 port, port_status); 435 436 if (action == UHCI_ENABLE_PORT) { 437 /* See if the port enable is already on */ 438 if (!(port_status & HCR_PORT_ENABLE)) { 439 /* Enable the port */ 440 Set_OpReg16(PORTSC[port], 441 (port_status | HCR_PORT_ENABLE)); 442 } 443 } else if (action == UHCI_DISABLE_PORT) { 444 /* See if the port enable is already off */ 445 if ((port_status & HCR_PORT_ENABLE)) { 446 /* Disable the port */ 447 Set_OpReg16(PORTSC[port], 448 (port_status & ~HCR_PORT_ENABLE)); 449 } 450 } else { 451 /* Clear the Enable/Disable change bit */ 452 Set_OpReg16(PORTSC[port], (port_status | HCR_PORT_ENDIS_CHG)); 453 454 /* Update software port_changes register */ 455 uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_PESC; 456 } 457 } 458 459 460 /* 461 * uhci_root_hub_reset_occurred: 462 * Inform the upper layer that reset has occured on the port. 463 * This is required because the upper layer is expecting an 464 * event immediately after doing a reset. In case of OHCI 465 * the HC gets an interrupt for the change in the root hub 466 * status, but in case of UHCI we don't. So, we send an 467 * event to the upper layer as soon as we complete the reset 468 * as long as the root hub pipe is polling. 469 */ 470 void 471 uhci_root_hub_reset_occurred( 472 uhci_state_t *uhcip, 473 uint16_t port) 474 { 475 usb_intr_req_t *intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp; 476 477 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 478 "uhci_root_hub_reset_occurred: intr_reqp = 0x%p data = 0x%p", 479 (void *)intr_reqp, (void *)intr_reqp->intr_data); 480 481 *intr_reqp->intr_data->b_wptr++ = (1 << (port+1)); 482 483 uhci_rh_hcdi_callback(uhcip, uhcip->uhci_root_hub.rh_intr_pipe_handle, 484 (usb_opaque_t)intr_reqp, USB_CR_OK); 485 } 486 487 488 /* 489 * uhci_handle_port_reset: 490 * Perform a port reset. 491 */ 492 static void 493 uhci_handle_port_reset( 494 uhci_state_t *uhcip, 495 usb_port_t port) 496 { 497 uint_t port_status = Get_OpReg16(PORTSC[port]); 498 499 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 500 "uhci_handle_port_reset: port = 0x%x, status = 0x%x", 501 port, port_status); 502 503 if (!(port_status & HCR_PORT_CCS)) { 504 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 505 "port_status & HCR_PORT_CCS == 0: " 506 "port = 0x%x, status = 0x%x", port, port_status); 507 } 508 509 Set_OpReg16(PORTSC[port], (port_status| HCR_PORT_RESET)); 510 511 drv_usecwait(UHCI_RESET_DELAY); 512 513 Set_OpReg16(PORTSC[port], (port_status & ~HCR_PORT_RESET)); 514 515 drv_usecwait(UHCI_RESET_DELAY/100); 516 517 Set_OpReg16(PORTSC[port], (port_status| HCR_PORT_ENABLE)); 518 519 /* 520 * The next function is only called if the interrupt pipe 521 * is polling and the USBA is ready to receive the 522 * data. If not, we could panic. 523 */ 524 if (uhcip->uhci_root_hub.rh_pipe_state != UHCI_PIPE_STATE_ACTIVE) { 525 /* make a note that we need to send status back */ 526 uhcip->uhci_root_hub.rh_status = port + 1; 527 } else { 528 uhci_root_hub_reset_occurred(uhcip, port); 529 } 530 } 531 532 533 /* 534 * uhci_handle_complete_port_reset: 535 * Perform a port reset change. 536 */ 537 static void 538 uhci_handle_complete_port_reset( 539 uhci_state_t *uhcip, 540 usb_port_t port) 541 { 542 uint_t port_status = Get_OpReg16(PORTSC[port]); 543 544 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 545 "uhci_handle_complete_port_reset: port = 0x%x status = 0x%x", 546 port, port_status); 547 548 if (!(port_status & HCR_PORT_CCS)) { 549 USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 550 "port_status & HCR_PORT_CCS == 0: " 551 "port = 0x%x, status = 0x%x", port, port_status); 552 } 553 554 Set_OpReg16(PORTSC[port], (port_status & (~ HCR_PORT_RESET))); 555 556 /* Update software port_changes register */ 557 uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_PRSC; 558 } 559 560 561 /* 562 * uhci_handle_clear_port_connection: 563 * Perform a clear port connection. 564 */ 565 static void 566 uhci_handle_clear_port_connection( 567 uhci_state_t *uhcip, 568 usb_port_t port) 569 { 570 uint_t port_status = Get_OpReg16(PORTSC[port]); 571 572 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 573 "uhci_handle_clear_port_connection: port = 0x%x status = 0x%x", 574 port, port_status); 575 576 /* Clear CSC bit */ 577 Set_OpReg16(PORTSC[port], port_status | HCR_PORT_CSC); 578 579 /* Update software port_changes register */ 580 uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_CSC; 581 } 582 583 584 /* 585 * uhci_handle_get_port_status: 586 * Handle a get port status request. 587 */ 588 static void 589 uhci_handle_get_port_status( 590 uhci_state_t *uhcip, 591 usb_ctrl_req_t *req, 592 usb_port_t port) 593 { 594 uint_t new_port_status; 595 uint_t old_port_status = 596 uhcip->uhci_root_hub.rh_port_status[port]; 597 uint_t old_port_changes = 598 uhcip->uhci_root_hub.rh_port_changes[port]; 599 uint_t change_status; 600 usb_ctrl_req_t *ctrl_reqp = (usb_ctrl_req_t *)req; 601 uint16_t wLength = req->ctrl_wLength; 602 603 ASSERT(wLength == 4); 604 ASSERT(ctrl_reqp->ctrl_data != NULL); 605 606 /* Read the current port status and return it */ 607 new_port_status = uhci_get_port_status(uhcip, port); 608 change_status = (old_port_status ^ new_port_status) & 0xff; 609 change_status |= old_port_changes; 610 611 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 612 "uhci_handle_get_port_status:\n\t" 613 "port%d: old status = 0x%x new status = 0x%x change = 0x%x", 614 port, old_port_status, new_port_status, change_status); 615 616 *ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)new_port_status; 617 *ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)(new_port_status >> 8); 618 *ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)change_status; 619 *ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)(change_status >> 8); 620 621 /* Update the status */ 622 uhcip->uhci_root_hub.rh_port_status[port] = new_port_status; 623 uhcip->uhci_root_hub.rh_port_changes[port] = change_status; 624 } 625 626 627 /* 628 * uhci_handle_get_hub_descriptor: 629 */ 630 static void 631 uhci_handle_get_hub_descriptor( 632 uhci_state_t *uhcip, 633 usb_ctrl_req_t *req) 634 { 635 uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH]; 636 usb_hub_descr_t *root_hub_descr = &uhcip->uhci_root_hub.rh_descr; 637 638 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 639 "uhci_handle_get_hub_descriptor: wLength = 0x%x", 640 req->ctrl_wLength); 641 642 ASSERT(req->ctrl_wLength != 0); 643 ASSERT(req->ctrl_data != NULL); 644 645 bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH); 646 647 raw_descr[0] = root_hub_descr->bDescLength; 648 raw_descr[1] = root_hub_descr->bDescriptorType; 649 raw_descr[2] = root_hub_descr->bNbrPorts; 650 raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00ff; 651 raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xff00) >> 8; 652 raw_descr[5] = root_hub_descr->bPwrOn2PwrGood; 653 raw_descr[6] = root_hub_descr->bHubContrCurrent; 654 raw_descr[7] = root_hub_descr->DeviceRemovable; 655 raw_descr[8] = root_hub_descr->PortPwrCtrlMask; 656 657 bcopy(raw_descr, req->ctrl_data->b_wptr, req->ctrl_wLength); 658 req->ctrl_data->b_wptr += req->ctrl_wLength; 659 } 660 661 662 /* 663 * uhci_handle_get_hub_status: 664 */ 665 static void 666 uhci_handle_get_hub_status( 667 uhci_state_t *uhcip, 668 usb_ctrl_req_t *req) 669 { 670 671 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 672 "uhci_handle_get_hub_status: wLength = 0x%x", 673 req->ctrl_wLength); 674 ASSERT(req->ctrl_wLength != 0); 675 ASSERT(req->ctrl_data != NULL); 676 677 /* 678 * A good status is always sent because there is no way that 679 * the driver can get to know about the status change of the 680 * over current or power failure of the root hub from the HC. 681 */ 682 bzero(req->ctrl_data->b_wptr, req->ctrl_wLength); 683 req->ctrl_data->b_wptr += req->ctrl_wLength; 684 } 685 686 687 /* 688 * uhci_handle_get_device_status: 689 */ 690 static void 691 uhci_handle_get_device_status( 692 uhci_state_t *uhcip, 693 usb_ctrl_req_t *req) 694 { 695 uint16_t dev_status; 696 697 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 698 "uhci_handle_get_device_status: wLength = 0x%x", 699 req->ctrl_wLength); 700 701 ASSERT(req->ctrl_wLength != 0); 702 ASSERT(req->ctrl_data != NULL); 703 704 /* 705 * UHCI doesn't have device status information. 706 * Simply return what is desired for the request. 707 */ 708 dev_status = USB_DEV_SLF_PWRD_STATUS; 709 710 *req->ctrl_data->b_wptr++ = (uchar_t)dev_status; 711 *req->ctrl_data->b_wptr++ = (uchar_t)(dev_status >> 8); 712 } 713 714 715 /* 716 * uhci_handle_root_hub_status_change: 717 * This function is called every 32 seconds from the time out handler. 718 * It checks for the status change of the root hub and its ports. 719 */ 720 void 721 uhci_handle_root_hub_status_change(void *arg) 722 { 723 usb_port_t port; 724 uint_t old_port_status; 725 uint_t new_port_status; 726 ushort_t port_status; 727 uint_t change_status; 728 uchar_t all_ports_status = 0; 729 uhci_state_t *uhcip = (uhci_state_t *)arg; 730 usb_intr_req_t *curr_intr_reqp; 731 732 mutex_enter(&uhcip->uhci_int_mutex); 733 734 /* reset the timeout id */ 735 uhcip->uhci_timeout_id = 0; 736 737 /* Get the current interrupt request pointer */ 738 curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp; 739 740 /* Check each port */ 741 for (port = 0; port < uhcip->uhci_root_hub.rh_num_ports; port++) { 742 new_port_status = uhci_get_port_status(uhcip, port); 743 old_port_status = uhcip->uhci_root_hub.rh_port_status[port]; 744 745 change_status = (old_port_status ^ new_port_status) & 0xff; 746 change_status |= uhcip->uhci_root_hub.rh_port_changes[port]; 747 748 /* See if a device was attached/detached */ 749 if (change_status & PORT_STATUS_CCS) { 750 all_ports_status |= 1 << (port + 1); 751 } 752 753 port_status = Get_OpReg16(PORTSC[port]); 754 Set_OpReg16(PORTSC[port], port_status | HCR_PORT_ENDIS_CHG); 755 756 uhcip->uhci_root_hub.rh_port_status[port] = new_port_status; 757 uhcip->uhci_root_hub.rh_port_changes[port] = change_status; 758 759 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 760 "port %d old status 0x%x new status 0x%x change 0x%x\n\t" 761 "all_ports_status = 0x%x", port, old_port_status, 762 new_port_status, change_status, all_ports_status); 763 } 764 765 if (uhcip->uhci_root_hub.rh_intr_pipe_handle && 766 all_ports_status && curr_intr_reqp && 767 (uhcip->uhci_root_hub.rh_pipe_state == UHCI_PIPE_STATE_ACTIVE)) { 768 769 ASSERT(curr_intr_reqp->intr_data != NULL); 770 771 *curr_intr_reqp->intr_data->b_wptr++ = all_ports_status; 772 773 uhci_rh_hcdi_callback(uhcip, 774 uhcip->uhci_root_hub.rh_intr_pipe_handle, 775 (usb_opaque_t)curr_intr_reqp, USB_CR_OK); 776 } 777 778 if (uhcip->uhci_root_hub.rh_pipe_state == UHCI_PIPE_STATE_ACTIVE) { 779 /* 780 * If needed, allocate new interrupt request. Also 781 * start the timer for the root hub interrupt polling. 782 */ 783 if (uhci_root_hub_allocate_intr_pipe_resource(uhcip, 0) != 784 USB_SUCCESS) { 785 786 /* Do interrupt pipe cleanup */ 787 uhci_root_hub_intr_pipe_cleanup(uhcip, 788 USB_CR_NO_RESOURCES); 789 } 790 } 791 792 mutex_exit(&uhcip->uhci_int_mutex); 793 } 794 795 796 static uint_t 797 uhci_get_port_status( 798 uhci_state_t *uhcip, 799 usb_port_t port) 800 { 801 uint_t new_port_status = PORT_STATUS_PPS; 802 ushort_t port_status = Get_OpReg16(PORTSC[port]); 803 804 if (port_status & HCR_PORT_CCS) { 805 new_port_status |= PORT_STATUS_CCS; 806 } 807 808 if (port_status & HCR_PORT_LSDA) { 809 new_port_status |= PORT_STATUS_LSDA; 810 } 811 812 if (port_status & HCR_PORT_ENABLE) { 813 new_port_status |= PORT_STATUS_PES; 814 } 815 816 if (port_status & HCR_PORT_SUSPEND) { 817 new_port_status |= PORT_STATUS_PSS; 818 } 819 820 if (port_status & HCR_PORT_RESET) { 821 new_port_status |= PORT_STATUS_PRS; 822 } 823 824 return (new_port_status); 825 } 826 827 828 /* 829 * uhci_root_hub_allocate_intr_pipe_resource: 830 * Allocate interrupt requests and initialize them. 831 */ 832 int 833 uhci_root_hub_allocate_intr_pipe_resource( 834 uhci_state_t *uhcip, 835 usb_flags_t flags) 836 { 837 usb_intr_req_t *curr_intr_reqp; 838 usba_pipe_handle_data_t *ph; 839 840 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 841 "uhci_root_hub_allocate_intr_pipe_resource:"); 842 843 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 844 845 /* Get the interrupt pipe handle */ 846 ph = uhcip->uhci_root_hub.rh_intr_pipe_handle; 847 848 /* Get the current interrupt request pointer */ 849 curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp; 850 851 /* 852 * If current interrupt request pointer is null, 853 * allocate new interrupt request. 854 */ 855 if (curr_intr_reqp == NULL) { 856 ASSERT(uhcip->uhci_root_hub.rh_client_intr_req); 857 858 if ((curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip, 859 uhcip->uhci_root_hub.rh_client_intr_req, 860 uhcip->uhci_root_hub.rh_client_intr_req->intr_len, 861 flags)) == NULL) { 862 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 863 "uhci_root_hub_allocate_intr_pipe_resource:" 864 "Interrupt request structure allocation failed"); 865 866 return (USB_NO_RESOURCES); 867 } 868 869 uhcip->uhci_root_hub.rh_curr_intr_reqp = curr_intr_reqp; 870 871 mutex_enter(&ph->p_mutex); 872 ph->p_req_count++; 873 mutex_exit(&ph->p_mutex); 874 } 875 876 if (uhcip->uhci_timeout_id == 0) { 877 uhcip->uhci_timeout_id = timeout( 878 uhci_handle_root_hub_status_change, 879 (void *)uhcip, UHCI_32_MS); 880 uhcip->uhci_root_hub.rh_pipe_state = 881 UHCI_PIPE_STATE_ACTIVE; 882 } 883 884 return (USB_SUCCESS); 885 } 886 887 888 /* 889 * uhci_root_hub_intr_pipe_cleanup: 890 * Deallocate all interrupt requests and do callback 891 * the original client interrupt request. 892 */ 893 void 894 uhci_root_hub_intr_pipe_cleanup(uhci_state_t *uhcip, usb_cr_t cr) 895 { 896 usb_intr_req_t *curr_intr_reqp; 897 usb_opaque_t client_intr_reqp; 898 usba_pipe_handle_data_t *ph; 899 timeout_id_t timer_id; 900 901 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl, 902 "uhci_root_hub_intr_pipe_cleanup:"); 903 904 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 905 906 /* Get the interrupt pipe handle */ 907 ph = uhcip->uhci_root_hub.rh_intr_pipe_handle; 908 909 /* Get the interrupt timerid */ 910 timer_id = uhcip->uhci_timeout_id; 911 912 /* Stop the root hub interrupt timer */ 913 if (timer_id) { 914 915 /* Reset the timer id to zero */ 916 uhcip->uhci_timeout_id = 0; 917 uhcip->uhci_root_hub.rh_pipe_state = 918 UHCI_PIPE_STATE_IDLE; 919 920 mutex_exit(&uhcip->uhci_int_mutex); 921 (void) untimeout(timer_id); 922 mutex_enter(&uhcip->uhci_int_mutex); 923 } 924 925 /* Reset the current interrupt request pointer */ 926 curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp; 927 928 /* Deallocate uncompleted interrupt request */ 929 if (curr_intr_reqp) { 930 uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL; 931 usb_free_intr_req(curr_intr_reqp); 932 933 mutex_enter(&ph->p_mutex); 934 ph->p_req_count--; 935 mutex_exit(&ph->p_mutex); 936 } 937 938 client_intr_reqp = (usb_opaque_t) 939 uhcip->uhci_root_hub.rh_client_intr_req; 940 941 /* Callback for original client interrupt request */ 942 if (client_intr_reqp) { 943 uhcip->uhci_root_hub.rh_client_intr_req = NULL; 944 uhci_rh_hcdi_callback(uhcip, ph, 945 (usb_opaque_t)client_intr_reqp, cr); 946 } 947 } 948 949 950 /* 951 * uhci_rh_hcdi_callback: 952 * Convenience wrapper around usba_hcdi_cb() for the root hub. 953 */ 954 static void 955 uhci_rh_hcdi_callback( 956 uhci_state_t *uhcip, 957 usba_pipe_handle_data_t *ph, 958 usb_opaque_t req, 959 usb_cr_t cr) 960 { 961 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 962 "uhci_rh_hcdi_callback: ph=0x%p cr=0x%x req=0x%p", 963 (void *)ph, cr, (void *)req); 964 965 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 966 967 switch (UHCI_XFER_TYPE(&ph->p_ep)) { 968 case USB_EP_ATTR_CONTROL: 969 970 break; 971 case USB_EP_ATTR_INTR: 972 if ((usb_intr_req_t *)req == 973 uhcip->uhci_root_hub.rh_curr_intr_reqp) { 974 uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL; 975 976 break; 977 } else if ((usb_intr_req_t *)req == 978 uhcip->uhci_root_hub.rh_client_intr_req) { 979 uhcip->uhci_root_hub.rh_client_intr_req = NULL; 980 981 break; 982 } 983 /*FALLTHRU*/ 984 default: 985 ASSERT(req); 986 break; 987 } 988 989 mutex_exit(&uhcip->uhci_int_mutex); 990 usba_hcdi_cb(ph, req, cr); 991 mutex_enter(&uhcip->uhci_int_mutex); 992 } 993