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