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 Host Controller Driver (UHCI) 30 * 31 * The UHCI driver is a driver which interfaces to the Universal 32 * Serial Bus Driver (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 HCDI entry points. 35 */ 36 #include <sys/usb/hcd/uhci/uhcid.h> 37 #include <sys/usb/hcd/uhci/uhcitgt.h> 38 #include <sys/usb/hcd/uhci/uhciutil.h> 39 #include <sys/strsun.h> 40 41 /* function prototypes */ 42 static int uhci_pipe_send_isoc_data(uhci_state_t *uhcip, 43 usba_pipe_handle_data_t *ph, usb_isoc_req_t *isoc_req, 44 usb_flags_t usb_flags); 45 static int uhci_send_intr_data(uhci_state_t *uhcip, 46 usba_pipe_handle_data_t *pipe_handle, 47 usb_intr_req_t *req, 48 usb_flags_t flags); 49 static int uhci_start_periodic_pipe_polling(uhci_state_t *uhcip, 50 usba_pipe_handle_data_t *ph, 51 usb_opaque_t reqp, 52 usb_flags_t flags); 53 static int uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip, 54 usba_pipe_handle_data_t *ph, 55 usb_flags_t flags); 56 static void uhci_update_intr_td_data_toggle(uhci_state_t *uhcip, 57 uhci_pipe_private_t *pp); 58 59 60 /* Maximum bulk transfer size */ 61 int uhci_bulk_transfer_size = UHCI_BULK_MAX_XFER_SIZE; 62 63 /* 64 * uhci_hcdi_pipe_open: 65 * Member of HCD Ops structure and called during client specific pipe open 66 * Add the pipe to the data structure representing the device and allocate 67 * bandwidth for the pipe if it is a interrupt or isochronous endpoint. 68 */ 69 int 70 uhci_hcdi_pipe_open(usba_pipe_handle_data_t *ph, usb_flags_t flags) 71 { 72 uint_t node = 0; 73 usb_addr_t usb_addr; 74 uhci_state_t *uhcip; 75 uhci_pipe_private_t *pp; 76 int rval, error = USB_SUCCESS; 77 78 ASSERT(ph); 79 80 usb_addr = ph->p_usba_device->usb_addr; 81 uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 82 83 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 84 "uhci_hcdi_pipe_open: addr = 0x%x, ep%d", usb_addr, 85 ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK); 86 87 sema_p(&uhcip->uhci_ocsem); 88 89 mutex_enter(&uhcip->uhci_int_mutex); 90 rval = uhci_state_is_operational(uhcip); 91 mutex_exit(&uhcip->uhci_int_mutex); 92 93 if (rval != USB_SUCCESS) { 94 sema_v(&uhcip->uhci_ocsem); 95 96 return (rval); 97 } 98 99 /* 100 * Return failure immediately for any other pipe open on the root hub 101 * except control or interrupt pipe. 102 */ 103 if (usb_addr == ROOT_HUB_ADDR) { 104 switch (UHCI_XFER_TYPE(&ph->p_ep)) { 105 case USB_EP_ATTR_CONTROL: 106 USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 107 "uhci_hcdi_pipe_open: Root hub control pipe"); 108 break; 109 case USB_EP_ATTR_INTR: 110 ASSERT(UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN); 111 112 mutex_enter(&uhcip->uhci_int_mutex); 113 uhcip->uhci_root_hub.rh_intr_pipe_handle = ph; 114 115 /* 116 * Set the state of the root hub interrupt 117 * pipe as IDLE. 118 */ 119 uhcip->uhci_root_hub.rh_pipe_state = 120 UHCI_PIPE_STATE_IDLE; 121 122 ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL); 123 uhcip->uhci_root_hub.rh_client_intr_req = NULL; 124 125 ASSERT(uhcip->uhci_root_hub.rh_curr_intr_reqp == NULL); 126 uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL; 127 128 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 129 "uhci_hcdi_pipe_open: Root hub interrupt " 130 "pipe open succeeded"); 131 mutex_exit(&uhcip->uhci_int_mutex); 132 sema_v(&uhcip->uhci_ocsem); 133 134 return (USB_SUCCESS); 135 default: 136 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 137 "uhci_hcdi_pipe_open: Root hub pipe open failed"); 138 sema_v(&uhcip->uhci_ocsem); 139 140 return (USB_FAILURE); 141 } 142 } 143 144 /* 145 * A portion of the bandwidth is reserved for the non-periodic 146 * transfers i.e control and bulk transfers in each of one 147 * mill second frame period & usually it will be 10% of frame 148 * period. Hence there is no need to check for the available 149 * bandwidth before adding the control or bulk endpoints. 150 * 151 * There is a need to check for the available bandwidth before 152 * adding the periodic transfers i.e interrupt & isochronous, since 153 * all these periodic transfers are guaranteed transfers. Usually, 154 * 90% of the total frame time is reserved for periodic transfers. 155 */ 156 if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) { 157 /* Zero Max Packet size endpoints are not supported */ 158 if (ph->p_ep.wMaxPacketSize == 0) { 159 USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 160 "uhci_hcdi_pipe_open: Zero length packet"); 161 sema_v(&uhcip->uhci_ocsem); 162 163 return (USB_FAILURE); 164 } 165 166 mutex_enter(&uhcip->uhci_int_mutex); 167 mutex_enter(&ph->p_mutex); 168 169 error = uhci_allocate_bandwidth(uhcip, ph, &node); 170 if (error != USB_SUCCESS) { 171 172 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 173 "uhci_hcdi_pipe_open: Bandwidth allocation failed"); 174 mutex_exit(&ph->p_mutex); 175 mutex_exit(&uhcip->uhci_int_mutex); 176 sema_v(&uhcip->uhci_ocsem); 177 178 return (error); 179 } 180 181 mutex_exit(&ph->p_mutex); 182 mutex_exit(&uhcip->uhci_int_mutex); 183 } 184 185 /* Create the HCD pipe private structure */ 186 pp = kmem_zalloc(sizeof (uhci_pipe_private_t), 187 (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 188 if (pp == NULL) { 189 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 190 "uhci_hcdi_pipe_open: pp allocation failure"); 191 192 if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) { 193 mutex_enter(&uhcip->uhci_int_mutex); 194 uhci_deallocate_bandwidth(uhcip, ph); 195 mutex_exit(&uhcip->uhci_int_mutex); 196 } 197 sema_v(&uhcip->uhci_ocsem); 198 199 return (USB_NO_RESOURCES); 200 } 201 202 mutex_enter(&uhcip->uhci_int_mutex); 203 rval = uhci_state_is_operational(uhcip); 204 205 if (rval != USB_SUCCESS) { 206 kmem_free(ph, sizeof (uhci_pipe_private_t)); 207 mutex_exit(&uhcip->uhci_int_mutex); 208 sema_v(&uhcip->uhci_ocsem); 209 210 return (rval); 211 } 212 pp->pp_node = node; /* Store the node in the interrupt lattice */ 213 214 /* Initialize frame number */ 215 pp->pp_frame_num = INVALID_FRNUM; 216 217 /* Set the state of pipe as IDLE */ 218 pp->pp_state = UHCI_PIPE_STATE_IDLE; 219 220 /* Store a pointer to the pipe handle */ 221 pp->pp_pipe_handle = ph; 222 223 /* Store the pointer in the pipe handle */ 224 mutex_enter(&ph->p_mutex); 225 ph->p_hcd_private = (usb_opaque_t)pp; 226 227 /* Store a copy of the pipe policy */ 228 bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t)); 229 mutex_exit(&ph->p_mutex); 230 231 /* don't check for ROOT_HUB here anymore */ 232 if (UHCI_XFER_TYPE(&ph->p_ep) != USB_EP_ATTR_ISOCH) { 233 /* Allocate the host controller endpoint descriptor */ 234 pp->pp_qh = uhci_alloc_queue_head(uhcip); 235 236 if (pp->pp_qh == NULL) { 237 USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 238 "uhci_hcdi_pipe_open: QH allocation failed"); 239 240 if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) { 241 uhci_deallocate_bandwidth(uhcip, ph); 242 } 243 244 mutex_enter(&ph->p_mutex); 245 246 /* 247 * Deallocate the hcd private portion 248 * of the pipe handle. 249 */ 250 kmem_free(ph->p_hcd_private, 251 sizeof (uhci_pipe_private_t)); 252 253 /* 254 * Set the private structure in the 255 * pipe handle equal to NULL. 256 */ 257 ph->p_hcd_private = NULL; 258 mutex_exit(&ph->p_mutex); 259 mutex_exit(&uhcip->uhci_int_mutex); 260 261 sema_v(&uhcip->uhci_ocsem); 262 263 return (USB_NO_RESOURCES); 264 } 265 266 /* 267 * Insert the endpoint onto the host controller's 268 * appropriate endpoint list. The host controller 269 * will not schedule this endpoint until there are 270 * any TD's to process. 271 */ 272 uhci_insert_qh(uhcip, ph); 273 } 274 275 /* 276 * Restore the data toggle from usb device structure. 277 */ 278 if (((ph->p_ep.bmAttributes) & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR || 279 ((ph->p_ep.bmAttributes) & USB_EP_ATTR_MASK) == USB_EP_ATTR_BULK) { 280 mutex_enter(&ph->p_mutex); 281 282 pp->pp_data_toggle = usba_hcdi_get_data_toggle( 283 ph->p_usba_device, ph->p_ep.bEndpointAddress); 284 mutex_exit(&ph->p_mutex); 285 } 286 287 mutex_exit(&uhcip->uhci_int_mutex); 288 sema_v(&uhcip->uhci_ocsem); 289 290 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 291 "uhci_hcdi_pipe_open: ph = 0x%p", (void *)ph); 292 293 return (USB_SUCCESS); 294 } 295 296 297 /* 298 * uhci_hcdi_pipe_close: 299 * Member of HCD Ops structure and called during the client specific pipe 300 * close. Remove the pipe to the data structure representing the device 301 * deallocate bandwidth for the pipe if it is an intr or isoch endpoint. 302 */ 303 int 304 uhci_hcdi_pipe_close(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) 305 { 306 usb_addr_t usb_addr; 307 uhci_state_t *uhcip; 308 usb_ep_descr_t *eptd = &ph->p_ep; 309 uhci_pipe_private_t *pp; 310 311 uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 312 pp = (uhci_pipe_private_t *)ph->p_hcd_private; 313 usb_addr = ph->p_usba_device->usb_addr; 314 315 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 316 "uhci_hcdi_pipe_close: addr = 0x%x, ep%d, flags = 0x%x", usb_addr, 317 eptd->bEndpointAddress, usb_flags); 318 319 sema_p(&uhcip->uhci_ocsem); 320 321 mutex_enter(&uhcip->uhci_int_mutex); 322 323 /* 324 * Check whether the pipe is a root hub 325 */ 326 if (usb_addr == ROOT_HUB_ADDR) { 327 switch (UHCI_XFER_TYPE(eptd)) { 328 case USB_EP_ATTR_CONTROL: 329 USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 330 "uhci_hcdi_pipe_close: Root hub control pipe " 331 "close succeeded"); 332 333 break; 334 case USB_EP_ATTR_INTR: 335 ASSERT((eptd->bEndpointAddress & 336 USB_EP_NUM_MASK) == 1); 337 338 /* Do interrupt pipe cleanup */ 339 uhci_root_hub_intr_pipe_cleanup(uhcip, 340 USB_CR_PIPE_CLOSING); 341 342 ASSERT(uhcip->uhci_root_hub.rh_pipe_state == 343 UHCI_PIPE_STATE_IDLE); 344 345 uhcip->uhci_root_hub.rh_intr_pipe_handle = NULL; 346 347 USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 348 "uhci_hcdi_pipe_close: Root hub interrupt " 349 "pipe close succeeded"); 350 351 uhcip->uhci_root_hub.rh_pipe_state = 352 UHCI_PIPE_STATE_IDLE; 353 354 mutex_exit(&uhcip->uhci_int_mutex); 355 sema_v(&uhcip->uhci_ocsem); 356 return (USB_SUCCESS); 357 } 358 } else { 359 /* 360 * Stop all the transactions if it is not the root hub. 361 */ 362 if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) { 363 /* 364 * Stop polling on the pipe to prevent any subsequently 365 * queued tds (while we're waiting for SOF, below) 366 * from being executed 367 */ 368 pp->pp_state = UHCI_PIPE_STATE_IDLE; 369 } 370 371 /* Disable all outstanding tds */ 372 uhci_modify_td_active_bits(uhcip, pp); 373 374 /* Prevent this queue from being executed */ 375 if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) { 376 UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr); 377 } 378 379 /* Wait for the next start of frame */ 380 (void) uhci_wait_for_sof(uhcip); 381 382 ASSERT(eptd != NULL); 383 384 switch (UHCI_XFER_TYPE(eptd)) { 385 case USB_EP_ATTR_INTR: 386 uhci_update_intr_td_data_toggle(uhcip, pp); 387 /* FALLTHROUGH */ 388 case USB_EP_ATTR_CONTROL: 389 uhci_remove_tds_tws(uhcip, ph); 390 break; 391 case USB_EP_ATTR_BULK: 392 SetQH32(uhcip, pp->pp_qh->element_ptr, 393 TD_PADDR(pp->pp_qh->td_tailp)); 394 uhci_remove_bulk_tds_tws(uhcip, pp, UHCI_IN_CLOSE); 395 uhci_save_data_toggle(pp); 396 break; 397 case USB_EP_ATTR_ISOCH: 398 uhci_remove_isoc_tds_tws(uhcip, pp); 399 break; 400 default: 401 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 402 "uhci_hcdi_pipe_close: Unknown xfer type"); 403 break; 404 } 405 406 /* 407 * Remove the endoint descriptor from Host Controller's 408 * appropriate endpoint list. Isochronous pipes dont have 409 * any queue heads attached to it. 410 */ 411 if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) { 412 uhci_remove_qh(uhcip, pp); 413 } 414 415 /* 416 * Do the callback for the original client 417 * periodic IN request. 418 */ 419 if (pp->pp_client_periodic_in_reqp) { 420 uhci_hcdi_callback(uhcip, pp, ph, NULL, 421 USB_CR_PIPE_CLOSING); 422 } 423 424 /* Deallocate bandwidth */ 425 if (UHCI_PERIODIC_ENDPOINT(eptd)) { 426 mutex_enter(&ph->p_mutex); 427 uhci_deallocate_bandwidth(uhcip, ph); 428 mutex_exit(&ph->p_mutex); 429 } 430 } 431 432 /* Deallocate the hcd private portion of the pipe handle. */ 433 434 mutex_enter(&ph->p_mutex); 435 kmem_free(ph->p_hcd_private, sizeof (uhci_pipe_private_t)); 436 ph->p_hcd_private = NULL; 437 mutex_exit(&ph->p_mutex); 438 439 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 440 "uhci_hcdi_pipe_close: ph = 0x%p", (void *)ph); 441 442 mutex_exit(&uhcip->uhci_int_mutex); 443 sema_v(&uhcip->uhci_ocsem); 444 445 return (USB_SUCCESS); 446 } 447 448 449 /* 450 * uhci_hcdi_pipe_reset: 451 */ 452 int 453 uhci_hcdi_pipe_reset(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) 454 { 455 uhci_state_t *uhcip = uhci_obtain_state( 456 ph->p_usba_device->usb_root_hub_dip); 457 uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 458 usb_ep_descr_t *eptd = &ph->p_ep; 459 460 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 461 "uhci_hcdi_pipe_reset: usb_flags = 0x%x", usb_flags); 462 463 /* 464 * Return failure immediately for any other pipe reset on the root 465 * hub except control or interrupt pipe. 466 */ 467 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 468 switch (UHCI_XFER_TYPE(&ph->p_ep)) { 469 case USB_EP_ATTR_CONTROL: 470 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 471 "uhci_hcdi_pipe_reset: Pipe reset for root" 472 "hub control pipe successful"); 473 474 break; 475 case USB_EP_ATTR_INTR: 476 mutex_enter(&uhcip->uhci_int_mutex); 477 uhcip->uhci_root_hub.rh_pipe_state = 478 UHCI_PIPE_STATE_IDLE; 479 480 /* Do interrupt pipe cleanup */ 481 uhci_root_hub_intr_pipe_cleanup(uhcip, 482 USB_CR_PIPE_RESET); 483 484 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 485 "uhci_hcdi_pipe_reset: Pipe reset for " 486 "root hub interrupt pipe successful"); 487 mutex_exit(&uhcip->uhci_int_mutex); 488 489 break; 490 default: 491 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 492 "uhci_hcdi_pipe_reset: Root hub pipe reset failed"); 493 494 return (USB_FAILURE); 495 } 496 497 return (USB_SUCCESS); 498 } 499 500 mutex_enter(&uhcip->uhci_int_mutex); 501 502 /* 503 * Set the active bit in to INACTIVE for all the remaining TD's of 504 * this end point. Set the active bit for the dummy td. This will 505 * generate an interrupt at the end of the frame. After receiving 506 * the interrupt, it is safe to to manipulate the lattice. 507 */ 508 uhci_modify_td_active_bits(uhcip, pp); 509 510 /* Initialize the element pointer */ 511 if (UHCI_XFER_TYPE(eptd) != USB_EP_ATTR_ISOCH) { 512 UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr); 513 SetQH32(uhcip, pp->pp_qh->element_ptr, 514 TD_PADDR(pp->pp_qh->td_tailp)); 515 } 516 517 (void) uhci_wait_for_sof(uhcip); 518 519 /* 520 * Save the data toggle and clear the pipe. 521 */ 522 switch (UHCI_XFER_TYPE(eptd)) { 523 case USB_EP_ATTR_CONTROL: 524 case USB_EP_ATTR_INTR: 525 uhci_remove_tds_tws(uhcip, ph); 526 break; 527 case USB_EP_ATTR_BULK: 528 SetQH32(uhcip, pp->pp_qh->element_ptr, 529 TD_PADDR(pp->pp_qh->td_tailp)); 530 uhci_remove_bulk_tds_tws(uhcip, pp, UHCI_IN_RESET); 531 break; 532 case USB_EP_ATTR_ISOCH: 533 uhci_remove_isoc_tds_tws(uhcip, pp); 534 break; 535 default: 536 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 537 "uhci_hcdi_pipe_reset: Unknown xfer type"); 538 break; 539 } 540 541 /* 542 * Do the callback for the original client 543 * periodic IN request. 544 */ 545 if (pp->pp_client_periodic_in_reqp) { 546 uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_PIPE_RESET); 547 } 548 549 /* 550 * Since the endpoint is stripped of Transfer Descriptors (TD), 551 * reset the state of the periodic pipe to IDLE. 552 */ 553 pp->pp_state = UHCI_PIPE_STATE_IDLE; 554 555 mutex_exit(&uhcip->uhci_int_mutex); 556 557 return (USB_SUCCESS); 558 } 559 560 561 /* 562 * uhci_hcdi_pipe_ctrl_xfer: 563 */ 564 int 565 uhci_hcdi_pipe_ctrl_xfer( 566 usba_pipe_handle_data_t *ph, 567 usb_ctrl_req_t *ctrl_reqp, 568 usb_flags_t flags) 569 { 570 uhci_state_t *uhcip = uhci_obtain_state( 571 ph->p_usba_device->usb_root_hub_dip); 572 uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 573 int error; 574 575 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 576 "uhci_hcdi_pipe_ctrl_xfer: req=0x%p, ph=0x%p, flags=0x%x", 577 (void *)ctrl_reqp, (void *)ph, flags); 578 579 mutex_enter(&uhcip->uhci_int_mutex); 580 error = uhci_state_is_operational(uhcip); 581 582 if (error != USB_SUCCESS) { 583 mutex_exit(&uhcip->uhci_int_mutex); 584 585 return (error); 586 } 587 588 ASSERT(pp->pp_state == UHCI_PIPE_STATE_IDLE); 589 590 /* 591 * Check and handle root hub control request. 592 */ 593 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 594 error = uhci_handle_root_hub_request(uhcip, ph, ctrl_reqp); 595 mutex_exit(&uhcip->uhci_int_mutex); 596 597 return (error); 598 } 599 600 /* Insert the td's on the endpoint */ 601 if ((error = uhci_insert_ctrl_td(uhcip, ph, ctrl_reqp, flags)) != 602 USB_SUCCESS) { 603 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 604 "uhci_hcdi_pipe_ctrl_xfer: No resources"); 605 } 606 mutex_exit(&uhcip->uhci_int_mutex); 607 608 return (error); 609 } 610 611 612 /* 613 * uhci_hcdi_pipe_bulk_xfer: 614 */ 615 int 616 uhci_hcdi_pipe_bulk_xfer(usba_pipe_handle_data_t *pipe_handle, 617 usb_bulk_req_t *bulk_reqp, usb_flags_t usb_flags) 618 { 619 int error; 620 uhci_state_t *uhcip; 621 622 uhcip = uhci_obtain_state(pipe_handle->p_usba_device->usb_root_hub_dip); 623 624 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 625 "uhci_hcdi_pipe_bulk_xfer: Flags = 0x%x", usb_flags); 626 627 /* Check the size of bulk request */ 628 if (bulk_reqp->bulk_len > UHCI_BULK_MAX_XFER_SIZE) { 629 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 630 "uhci_hcdi_pipe_bulk_xfer: req size 0x%x is more than 0x%x", 631 bulk_reqp->bulk_len, UHCI_BULK_MAX_XFER_SIZE); 632 633 return (USB_FAILURE); 634 } 635 636 mutex_enter(&uhcip->uhci_int_mutex); 637 638 error = uhci_state_is_operational(uhcip); 639 640 if (error != USB_SUCCESS) { 641 mutex_exit(&uhcip->uhci_int_mutex); 642 643 return (error); 644 } 645 /* Add the TD into the Host Controller's bulk list */ 646 if ((error = uhci_insert_bulk_td(uhcip, pipe_handle, bulk_reqp, 647 usb_flags)) != USB_SUCCESS) { 648 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 649 "uhci_hcdi_pipe_bulk_xfer: uhci_insert_bulk_td failed"); 650 } 651 mutex_exit(&uhcip->uhci_int_mutex); 652 653 return (error); 654 } 655 656 657 /* 658 * uhci_hcdi_bulk_transfer_size: 659 * Return maximum bulk transfer size 660 */ 661 int 662 uhci_hcdi_bulk_transfer_size( 663 usba_device_t *usba_device, 664 size_t *size) 665 { 666 uhci_state_t *uhcip = uhci_obtain_state( 667 usba_device->usb_root_hub_dip); 668 int rval; 669 670 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 671 "uhci_hcdi_bulk_transfer_size:"); 672 673 mutex_enter(&uhcip->uhci_int_mutex); 674 rval = uhci_state_is_operational(uhcip); 675 676 if (rval != USB_SUCCESS) { 677 mutex_exit(&uhcip->uhci_int_mutex); 678 679 return (rval); 680 } 681 682 *size = uhci_bulk_transfer_size; 683 mutex_exit(&uhcip->uhci_int_mutex); 684 685 return (USB_SUCCESS); 686 } 687 688 689 /* 690 * uhci_hcdi_pipe_intr_xfer: 691 */ 692 int 693 uhci_hcdi_pipe_intr_xfer( 694 usba_pipe_handle_data_t *ph, 695 usb_intr_req_t *req, 696 usb_flags_t flags) 697 { 698 uhci_state_t *uhcip = uhci_obtain_state( 699 ph->p_usba_device->usb_root_hub_dip); 700 701 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 702 "uhci_hcdi_pipe_intr_xfer: req=0x%p, uf=0x%x", (void *)req, flags); 703 704 if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) { 705 706 return (uhci_start_periodic_pipe_polling(uhcip, ph, 707 (usb_opaque_t)req, flags)); 708 } else { 709 710 return (uhci_send_intr_data(uhcip, ph, req, flags)); 711 } 712 } 713 714 715 /* 716 * uhci_send_intr_data(): 717 * send data to interrupt out pipe 718 */ 719 static int 720 uhci_send_intr_data( 721 uhci_state_t *uhcip, 722 usba_pipe_handle_data_t *pipe_handle, 723 usb_intr_req_t *req, 724 usb_flags_t flags) 725 { 726 int rval; 727 728 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 729 "uhci_send_intr_data:"); 730 731 mutex_enter(&uhcip->uhci_int_mutex); 732 733 rval = uhci_state_is_operational(uhcip); 734 735 if (rval != USB_SUCCESS) { 736 mutex_exit(&uhcip->uhci_int_mutex); 737 738 return (rval); 739 } 740 741 /* Add the TD into the Host Controller's interrupt list */ 742 if ((rval = uhci_insert_intr_td(uhcip, pipe_handle, req, flags)) != 743 USB_SUCCESS) { 744 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 745 "uhci_send_intr_data: No resources"); 746 } 747 mutex_exit(&uhcip->uhci_int_mutex); 748 749 return (rval); 750 } 751 752 753 /* 754 * uhci_hcdi_pipe_stop_intr_polling() 755 */ 756 int 757 uhci_hcdi_pipe_stop_intr_polling( 758 usba_pipe_handle_data_t *pipe_handle, 759 usb_flags_t flags) 760 { 761 uhci_state_t *uhcip = 762 uhci_obtain_state(pipe_handle->p_usba_device->usb_root_hub_dip); 763 int rval; 764 765 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 766 "uhci_hcdi_pipe_stop_intr_polling: ph = 0x%p fl = 0x%x", 767 (void *)pipe_handle, flags); 768 mutex_enter(&uhcip->uhci_int_mutex); 769 770 rval = uhci_stop_periodic_pipe_polling(uhcip, pipe_handle, flags); 771 772 mutex_exit(&uhcip->uhci_int_mutex); 773 774 return (rval); 775 } 776 777 778 /* 779 * uhci_hcdi_get_current_frame_number 780 * Get the current frame number. 781 * Return whether the request is handled successfully. 782 */ 783 int 784 uhci_hcdi_get_current_frame_number( 785 usba_device_t *usba_device, 786 usb_frame_number_t *frame_number) 787 { 788 uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip); 789 int rval; 790 791 mutex_enter(&uhcip->uhci_int_mutex); 792 rval = uhci_state_is_operational(uhcip); 793 794 if (rval != USB_SUCCESS) { 795 mutex_exit(&uhcip->uhci_int_mutex); 796 797 return (rval); 798 } 799 800 *frame_number = uhci_get_sw_frame_number(uhcip); 801 mutex_exit(&uhcip->uhci_int_mutex); 802 803 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 804 "uhci_hcdi_get_current_frame_number: %llx", 805 (unsigned long long)(*frame_number)); 806 807 return (rval); 808 } 809 810 811 /* 812 * uhci_hcdi_get_max_isoc_pkts 813 * Get the maximum number of isoc packets per USB Isoch request. 814 * Return whether the request is handled successfully. 815 */ 816 int 817 uhci_hcdi_get_max_isoc_pkts( 818 usba_device_t *usba_device, 819 uint_t *max_isoc_pkts_per_request) 820 { 821 uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip); 822 int rval; 823 824 mutex_enter(&uhcip->uhci_int_mutex); 825 rval = uhci_state_is_operational(uhcip); 826 827 if (rval != USB_SUCCESS) { 828 mutex_exit(&uhcip->uhci_int_mutex); 829 830 return (rval); 831 } 832 833 *max_isoc_pkts_per_request = UHCI_MAX_ISOC_PKTS; 834 mutex_exit(&uhcip->uhci_int_mutex); 835 836 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 837 "uhci_hcdi_get_max_isoc_pkts: 0x%x", UHCI_MAX_ISOC_PKTS); 838 839 return (rval); 840 } 841 842 843 /* 844 * uhci_hcdi_pipe_isoc_xfer: 845 */ 846 int 847 uhci_hcdi_pipe_isoc_xfer( 848 usba_pipe_handle_data_t *ph, 849 usb_isoc_req_t *isoc_reqp, 850 usb_flags_t flags) 851 { 852 uhci_state_t *uhcip; 853 854 uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 855 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 856 "uhci_hcdi_pipe_isoc_xfer: req=0x%p, uf=0x%x", 857 (void *)isoc_reqp, flags); 858 859 if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) { 860 861 return (uhci_start_periodic_pipe_polling(uhcip, ph, 862 (usb_opaque_t)isoc_reqp, flags)); 863 } else { 864 865 return (uhci_pipe_send_isoc_data(uhcip, ph, isoc_reqp, flags)); 866 } 867 } 868 869 870 /* 871 * uhci_hcdi_pipe_stop_isoc_polling() 872 */ 873 int 874 uhci_hcdi_pipe_stop_isoc_polling( 875 usba_pipe_handle_data_t *ph, 876 usb_flags_t flags) 877 { 878 uhci_state_t *uhcip = 879 uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 880 int rval; 881 882 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 883 "uhci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x", 884 (void *)ph, flags); 885 886 mutex_enter(&uhcip->uhci_int_mutex); 887 rval = uhci_state_is_operational(uhcip); 888 889 if (rval != USB_SUCCESS) { 890 mutex_exit(&uhcip->uhci_int_mutex); 891 892 return (rval); 893 } 894 895 rval = uhci_stop_periodic_pipe_polling(uhcip, ph, flags); 896 897 mutex_exit(&uhcip->uhci_int_mutex); 898 899 return (rval); 900 } 901 902 903 /* 904 * uhci_start_periodic_pipe_polling: 905 */ 906 static int 907 uhci_start_periodic_pipe_polling( 908 uhci_state_t *uhcip, 909 usba_pipe_handle_data_t *ph, 910 usb_opaque_t in_reqp, 911 usb_flags_t flags) 912 { 913 int n, num_tds; 914 int error; 915 usb_intr_req_t *intr_reqp = (usb_intr_req_t *)in_reqp; 916 usb_ep_descr_t *eptd = &ph->p_ep; 917 uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 918 919 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 920 "uhci_start_periodic_pipe_polling: flags: 0x%x, ep%d", 921 flags, eptd->bEndpointAddress); 922 923 mutex_enter(&uhcip->uhci_int_mutex); 924 925 error = uhci_state_is_operational(uhcip); 926 927 if (error != USB_SUCCESS) { 928 mutex_exit(&uhcip->uhci_int_mutex); 929 930 return (error); 931 } 932 933 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 934 uint_t pipe_state = uhcip->uhci_root_hub.rh_pipe_state; 935 936 ASSERT(pipe_state == UHCI_PIPE_STATE_IDLE); 937 ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN); 938 939 /* ONE_XFER not supported */ 940 ASSERT((intr_reqp->intr_attributes & 941 USB_ATTRS_ONE_XFER) == 0); 942 ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL); 943 uhcip->uhci_root_hub.rh_client_intr_req = intr_reqp; 944 945 if ((error = uhci_root_hub_allocate_intr_pipe_resource( 946 uhcip, flags)) != USB_SUCCESS) { 947 /* reset the client interrupt request pointer */ 948 uhcip->uhci_root_hub.rh_client_intr_req = NULL; 949 950 mutex_exit(&uhcip->uhci_int_mutex); 951 952 return (error); 953 } 954 955 uhcip->uhci_root_hub.rh_pipe_state = USB_PIPE_STATE_ACTIVE; 956 957 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 958 "uhci_start_periodic_pipe_polling: " 959 "Start intr polling for root hub successful"); 960 961 /* check if we need to send the reset data up? */ 962 if (uhcip->uhci_root_hub.rh_status) { 963 uhci_root_hub_reset_occurred(uhcip, 964 uhcip->uhci_root_hub.rh_status - 1); 965 966 uhcip->uhci_root_hub.rh_status = 0; 967 } 968 mutex_exit(&uhcip->uhci_int_mutex); 969 970 return (error); 971 } 972 973 /* save the original client's periodic IN request */ 974 pp->pp_client_periodic_in_reqp = in_reqp; 975 976 ASSERT(pp->pp_state != UHCI_PIPE_STATE_ACTIVE); 977 /* 978 * 979 * This pipe is uninitialized. If it is an isoc 980 * receive request, insert four times the same 981 * request so that we do not lose any frames. 982 */ 983 if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) { 984 for (n = 0; n < 5; n++) { 985 if ((error = uhci_start_isoc_receive_polling( 986 uhcip, ph, NULL, flags)) != USB_SUCCESS) { 987 988 USB_DPRINTF_L2(PRINT_MASK_INTR, 989 uhcip->uhci_log_hdl, 990 "uhci_start_periodic_pipe_polling: " 991 "Start isoc polling failed %d", n); 992 993 pp->pp_client_periodic_in_reqp = NULL; 994 mutex_exit(&uhcip->uhci_int_mutex); 995 996 return (error); 997 } 998 } 999 } 1000 1001 if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) { 1002 if ((pp->pp_node < POLLING_FREQ_7MS) && 1003 (!(intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER))) { 1004 num_tds = 5; 1005 } else { 1006 num_tds = 1; 1007 } 1008 1009 /* 1010 * This pipe is uninitialized. 1011 * Insert a TD on the interrupt ED. 1012 */ 1013 for (n = 0; n < num_tds; n++) { 1014 if ((error = uhci_insert_intr_td(uhcip, ph, NULL, 1015 flags)) != USB_SUCCESS) { 1016 USB_DPRINTF_L2(PRINT_MASK_INTR, 1017 uhcip->uhci_log_hdl, 1018 "uhci_start_periodic_pipe_polling: " 1019 "Start polling failed"); 1020 1021 pp->pp_client_periodic_in_reqp = NULL; 1022 mutex_exit(&uhcip->uhci_int_mutex); 1023 1024 return (error); 1025 } 1026 } 1027 } 1028 1029 pp->pp_state = UHCI_PIPE_STATE_ACTIVE; 1030 1031 mutex_exit(&uhcip->uhci_int_mutex); 1032 1033 return (error); 1034 } 1035 1036 1037 /* 1038 * uhci_hcdi_periodic_pipe_stop_polling: 1039 */ 1040 static int 1041 uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip, 1042 usba_pipe_handle_data_t *ph, usb_flags_t flags) 1043 { 1044 uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 1045 usb_ep_descr_t *eptd = &ph->p_ep; 1046 1047 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1048 "uhci_stop_periodic_pipe_polling: flags = 0x%x", flags); 1049 1050 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 1051 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 1052 ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN); 1053 1054 if (uhcip->uhci_root_hub.rh_pipe_state == 1055 UHCI_PIPE_STATE_ACTIVE) { 1056 uhcip->uhci_root_hub.rh_pipe_state = 1057 UHCI_PIPE_STATE_IDLE; 1058 1059 /* Do interrupt pipe cleanup */ 1060 uhci_root_hub_intr_pipe_cleanup(uhcip, 1061 USB_CR_STOPPED_POLLING); 1062 1063 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1064 "uhci_stop_periodic_pipe_polling: Stop intr " 1065 "polling for root hub successful"); 1066 1067 } else { 1068 USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1069 "uhci_stop_periodic_pipe_polling: " 1070 "Intr polling for root hub is already stopped"); 1071 } 1072 1073 return (USB_SUCCESS); 1074 } 1075 1076 if (pp->pp_state != UHCI_PIPE_STATE_ACTIVE) { 1077 USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1078 "uhci_stop_periodic_pipe_polling: Polling already stopped"); 1079 1080 return (USB_SUCCESS); 1081 } 1082 1083 /* 1084 * Set the terminate bits in all the tds in the queue and 1085 * in the element_ptr. 1086 * Do not deallocate the bandwidth or tear down the DMA 1087 */ 1088 uhci_modify_td_active_bits(uhcip, pp); 1089 (void) uhci_wait_for_sof(uhcip); 1090 1091 if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) { 1092 uhci_remove_isoc_tds_tws(uhcip, pp); 1093 pp->pp_state = UHCI_PIPE_STATE_IDLE; 1094 } else { 1095 UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr); 1096 uhci_update_intr_td_data_toggle(uhcip, pp); 1097 SetQH32(uhcip, pp->pp_qh->element_ptr, 1098 TD_PADDR(pp->pp_qh->td_tailp)); 1099 uhci_remove_tds_tws(uhcip, ph); 1100 } 1101 1102 pp->pp_state = UHCI_PIPE_STATE_IDLE; 1103 1104 if (pp->pp_client_periodic_in_reqp) { 1105 uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_STOPPED_POLLING); 1106 } 1107 1108 return (USB_SUCCESS); 1109 } 1110 1111 1112 /* 1113 * uhci_hcdi_pipe_send_isoc_data: 1114 * Handles the isoc write request. 1115 */ 1116 static int 1117 uhci_pipe_send_isoc_data( 1118 uhci_state_t *uhcip, 1119 usba_pipe_handle_data_t *ph, 1120 usb_isoc_req_t *isoc_req, 1121 usb_flags_t usb_flags) 1122 { 1123 int error; 1124 size_t max_isoc_xfer_sz, length; 1125 1126 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1127 "uhci_pipe_send_isoc_data: isoc_req = %p flags = %x", 1128 (void *)isoc_req, usb_flags); 1129 1130 ASSERT(isoc_req->isoc_pkts_count < UHCI_MAX_ISOC_PKTS); 1131 1132 /* Calculate the maximum isochronous transfer size */ 1133 max_isoc_xfer_sz = UHCI_MAX_ISOC_PKTS * ph->p_ep.wMaxPacketSize; 1134 1135 /* Check the size of isochronous request */ 1136 ASSERT(isoc_req->isoc_data != NULL); 1137 length = MBLKL(isoc_req->isoc_data); 1138 1139 if (length > max_isoc_xfer_sz) { 1140 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1141 "uhci_pipe_send_isoc_data: Maximum isoc request size %lx " 1142 "Given isoc request size %lx", max_isoc_xfer_sz, length); 1143 1144 return (USB_INVALID_REQUEST); 1145 } 1146 1147 1148 /* 1149 * Check whether we can insert these tds? 1150 * At any point of time, we can insert maximum of 1024 isoc td's, 1151 * size of frame list table. 1152 */ 1153 if (isoc_req->isoc_pkts_count > UHCI_MAX_ISOC_PKTS) { 1154 1155 USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl, 1156 "uhci_pipe_send_isoc_data: request too big"); 1157 1158 return (USB_INVALID_REQUEST); 1159 } 1160 1161 /* Add the TD into the Host Controller's isoc list */ 1162 mutex_enter(&uhcip->uhci_int_mutex); 1163 1164 error = uhci_state_is_operational(uhcip); 1165 1166 if (error != USB_SUCCESS) { 1167 mutex_exit(&uhcip->uhci_int_mutex); 1168 1169 return (error); 1170 } 1171 1172 if ((error = uhci_insert_isoc_td(uhcip, ph, isoc_req, 1173 length, usb_flags)) != USB_SUCCESS) { 1174 1175 USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl, 1176 "uhci_pipe_send_isoc_data: Unable to insert the isoc_req," 1177 "Error = %d", error); 1178 } 1179 mutex_exit(&uhcip->uhci_int_mutex); 1180 1181 return (error); 1182 } 1183 1184 1185 /* 1186 * uhci_update_intr_td_data_toggle 1187 * Update the data toggle and save in the usba_device structure 1188 */ 1189 static void 1190 uhci_update_intr_td_data_toggle(uhci_state_t *uhcip, uhci_pipe_private_t *pp) 1191 { 1192 uint32_t paddr_tail, element_ptr; 1193 uhci_td_t *next_td; 1194 1195 /* Find the next td that would have been executed */ 1196 element_ptr = GetQH32(uhcip, pp->pp_qh->element_ptr) & 1197 QH_ELEMENT_PTR_MASK; 1198 next_td = TD_VADDR(element_ptr); 1199 paddr_tail = TD_PADDR(pp->pp_qh->td_tailp); 1200 1201 /* 1202 * If element_ptr points to the dummy td, then the data toggle in 1203 * pp_data_toggle is correct. Otherwise update the data toggle in 1204 * the pipe private 1205 */ 1206 if (element_ptr != paddr_tail) { 1207 pp->pp_data_toggle = GetTD_dtogg(uhcip, next_td); 1208 } 1209 1210 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1211 "uhci_update_intr_td_data_toggle: " 1212 "pp %p toggle %x element ptr %x ptail %x", 1213 (void *)pp, pp->pp_data_toggle, element_ptr, paddr_tail); 1214 1215 uhci_save_data_toggle(pp); 1216 } 1217