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