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", 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", 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 ctrl_reqp, 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", 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", frame_number); 804 805 return (rval); 806 } 807 808 809 /* 810 * uhci_hcdi_get_max_isoc_pkts 811 * Get the maximum number of isoc packets per USB Isoch request. 812 * Return whether the request is handled successfully. 813 */ 814 int 815 uhci_hcdi_get_max_isoc_pkts( 816 usba_device_t *usba_device, 817 uint_t *max_isoc_pkts_per_request) 818 { 819 uhci_state_t *uhcip = uhci_obtain_state(usba_device->usb_root_hub_dip); 820 int rval; 821 822 mutex_enter(&uhcip->uhci_int_mutex); 823 rval = uhci_state_is_operational(uhcip); 824 825 if (rval != USB_SUCCESS) { 826 mutex_exit(&uhcip->uhci_int_mutex); 827 828 return (rval); 829 } 830 831 *max_isoc_pkts_per_request = UHCI_MAX_ISOC_PKTS; 832 mutex_exit(&uhcip->uhci_int_mutex); 833 834 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 835 "uhci_hcdi_get_max_isoc_pkts: 0x%x", UHCI_MAX_ISOC_PKTS); 836 837 return (rval); 838 } 839 840 841 /* 842 * uhci_hcdi_pipe_isoc_xfer: 843 */ 844 int 845 uhci_hcdi_pipe_isoc_xfer( 846 usba_pipe_handle_data_t *ph, 847 usb_isoc_req_t *isoc_reqp, 848 usb_flags_t flags) 849 { 850 uhci_state_t *uhcip; 851 852 uhcip = uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 853 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 854 "uhci_hcdi_pipe_isoc_xfer: req=0x%p, uf=0x%x", isoc_reqp, flags); 855 856 if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN) { 857 858 return (uhci_start_periodic_pipe_polling(uhcip, ph, 859 (usb_opaque_t)isoc_reqp, flags)); 860 } else { 861 862 return (uhci_pipe_send_isoc_data(uhcip, ph, isoc_reqp, flags)); 863 } 864 } 865 866 867 /* 868 * uhci_hcdi_pipe_stop_isoc_polling() 869 */ 870 int 871 uhci_hcdi_pipe_stop_isoc_polling( 872 usba_pipe_handle_data_t *ph, 873 usb_flags_t flags) 874 { 875 uhci_state_t *uhcip = 876 uhci_obtain_state(ph->p_usba_device->usb_root_hub_dip); 877 int rval; 878 879 USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl, 880 "uhci_hcdi_pipe_stop_isoc_polling: ph = 0x%p fl = 0x%x", 881 (void *)ph, flags); 882 883 mutex_enter(&uhcip->uhci_int_mutex); 884 rval = uhci_state_is_operational(uhcip); 885 886 if (rval != USB_SUCCESS) { 887 mutex_exit(&uhcip->uhci_int_mutex); 888 889 return (rval); 890 } 891 892 rval = uhci_stop_periodic_pipe_polling(uhcip, ph, flags); 893 894 mutex_exit(&uhcip->uhci_int_mutex); 895 896 return (rval); 897 } 898 899 900 /* 901 * uhci_start_periodic_pipe_polling: 902 */ 903 static int 904 uhci_start_periodic_pipe_polling( 905 uhci_state_t *uhcip, 906 usba_pipe_handle_data_t *ph, 907 usb_opaque_t in_reqp, 908 usb_flags_t flags) 909 { 910 int n, num_tds; 911 int error; 912 usb_intr_req_t *intr_reqp = (usb_intr_req_t *)in_reqp; 913 usb_ep_descr_t *eptd = &ph->p_ep; 914 uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 915 916 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 917 "uhci_start_periodic_pipe_polling: flags: 0x%x, ep%d", 918 flags, eptd->bEndpointAddress); 919 920 mutex_enter(&uhcip->uhci_int_mutex); 921 922 error = uhci_state_is_operational(uhcip); 923 924 if (error != USB_SUCCESS) { 925 mutex_exit(&uhcip->uhci_int_mutex); 926 927 return (error); 928 } 929 930 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 931 uint_t pipe_state = uhcip->uhci_root_hub.rh_pipe_state; 932 933 ASSERT(pipe_state == UHCI_PIPE_STATE_IDLE); 934 ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN); 935 936 /* ONE_XFER not supported */ 937 ASSERT((intr_reqp->intr_attributes & 938 USB_ATTRS_ONE_XFER) == 0); 939 ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL); 940 uhcip->uhci_root_hub.rh_client_intr_req = intr_reqp; 941 942 if ((error = uhci_root_hub_allocate_intr_pipe_resource( 943 uhcip, flags)) != USB_SUCCESS) { 944 /* reset the client interrupt request pointer */ 945 uhcip->uhci_root_hub.rh_client_intr_req = NULL; 946 947 mutex_exit(&uhcip->uhci_int_mutex); 948 949 return (error); 950 } 951 952 uhcip->uhci_root_hub.rh_pipe_state = USB_PIPE_STATE_ACTIVE; 953 954 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 955 "uhci_start_periodic_pipe_polling: " 956 "Start intr polling for root hub successful"); 957 958 /* check if we need to send the reset data up? */ 959 if (uhcip->uhci_root_hub.rh_status) { 960 uhci_root_hub_reset_occurred(uhcip, 961 uhcip->uhci_root_hub.rh_status - 1); 962 963 uhcip->uhci_root_hub.rh_status = 0; 964 } 965 mutex_exit(&uhcip->uhci_int_mutex); 966 967 return (error); 968 } 969 970 /* save the original client's periodic IN request */ 971 pp->pp_client_periodic_in_reqp = in_reqp; 972 973 ASSERT(pp->pp_state != UHCI_PIPE_STATE_ACTIVE); 974 /* 975 * 976 * This pipe is uninitialized. If it is an isoc 977 * receive request, insert four times the same 978 * request so that we do not lose any frames. 979 */ 980 if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) { 981 for (n = 0; n < 5; n++) { 982 if ((error = uhci_start_isoc_receive_polling( 983 uhcip, ph, NULL, flags)) != USB_SUCCESS) { 984 985 USB_DPRINTF_L2(PRINT_MASK_INTR, 986 uhcip->uhci_log_hdl, 987 "uhci_start_periodic_pipe_polling: " 988 "Start isoc polling failed %d", n); 989 990 pp->pp_client_periodic_in_reqp = NULL; 991 mutex_exit(&uhcip->uhci_int_mutex); 992 993 return (error); 994 } 995 } 996 } 997 998 if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_INTR) { 999 if ((pp->pp_node < POLLING_FREQ_7MS) && 1000 (!(intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER))) { 1001 num_tds = 5; 1002 } else { 1003 num_tds = 1; 1004 } 1005 1006 /* 1007 * This pipe is uninitialized. 1008 * Insert a TD on the interrupt ED. 1009 */ 1010 for (n = 0; n < num_tds; n++) { 1011 if ((error = uhci_insert_intr_td(uhcip, ph, NULL, 1012 flags)) != USB_SUCCESS) { 1013 USB_DPRINTF_L2(PRINT_MASK_INTR, 1014 uhcip->uhci_log_hdl, 1015 "uhci_start_periodic_pipe_polling: " 1016 "Start polling failed"); 1017 1018 pp->pp_client_periodic_in_reqp = NULL; 1019 mutex_exit(&uhcip->uhci_int_mutex); 1020 1021 return (error); 1022 } 1023 } 1024 } 1025 1026 pp->pp_state = UHCI_PIPE_STATE_ACTIVE; 1027 1028 mutex_exit(&uhcip->uhci_int_mutex); 1029 1030 return (error); 1031 } 1032 1033 1034 /* 1035 * uhci_hcdi_periodic_pipe_stop_polling: 1036 */ 1037 static int 1038 uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip, 1039 usba_pipe_handle_data_t *ph, usb_flags_t flags) 1040 { 1041 uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private; 1042 usb_ep_descr_t *eptd = &ph->p_ep; 1043 1044 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1045 "uhci_stop_periodic_pipe_polling: flags = 0x%x", flags); 1046 1047 ASSERT(mutex_owned(&uhcip->uhci_int_mutex)); 1048 if (ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) { 1049 ASSERT(UHCI_XFER_DIR(eptd) == USB_EP_DIR_IN); 1050 1051 if (uhcip->uhci_root_hub.rh_pipe_state == 1052 UHCI_PIPE_STATE_ACTIVE) { 1053 uhcip->uhci_root_hub.rh_pipe_state = 1054 UHCI_PIPE_STATE_IDLE; 1055 1056 /* Do interrupt pipe cleanup */ 1057 uhci_root_hub_intr_pipe_cleanup(uhcip, 1058 USB_CR_STOPPED_POLLING); 1059 1060 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1061 "uhci_stop_periodic_pipe_polling: Stop intr " 1062 "polling for root hub successful"); 1063 1064 } else { 1065 USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1066 "uhci_stop_periodic_pipe_polling: " 1067 "Intr polling for root hub is already stopped"); 1068 } 1069 1070 return (USB_SUCCESS); 1071 } 1072 1073 if (pp->pp_state != UHCI_PIPE_STATE_ACTIVE) { 1074 USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl, 1075 "uhci_stop_periodic_pipe_polling: Polling already stopped"); 1076 1077 return (USB_SUCCESS); 1078 } 1079 1080 /* 1081 * Set the terminate bits in all the tds in the queue and 1082 * in the element_ptr. 1083 * Do not deallocate the bandwidth or tear down the DMA 1084 */ 1085 uhci_modify_td_active_bits(uhcip, pp); 1086 (void) uhci_wait_for_sof(uhcip); 1087 1088 if (UHCI_XFER_TYPE(eptd) == USB_EP_ATTR_ISOCH) { 1089 uhci_remove_isoc_tds_tws(uhcip, pp); 1090 pp->pp_state = UHCI_PIPE_STATE_IDLE; 1091 } else { 1092 UHCI_SET_TERMINATE_BIT(pp->pp_qh->element_ptr); 1093 uhci_update_intr_td_data_toggle(uhcip, pp); 1094 SetQH32(uhcip, pp->pp_qh->element_ptr, 1095 TD_PADDR(pp->pp_qh->td_tailp)); 1096 uhci_remove_tds_tws(uhcip, ph); 1097 } 1098 1099 pp->pp_state = UHCI_PIPE_STATE_IDLE; 1100 1101 if (pp->pp_client_periodic_in_reqp) { 1102 uhci_hcdi_callback(uhcip, pp, ph, NULL, USB_CR_STOPPED_POLLING); 1103 } 1104 1105 return (USB_SUCCESS); 1106 } 1107 1108 1109 /* 1110 * uhci_hcdi_pipe_send_isoc_data: 1111 * Handles the isoc write request. 1112 */ 1113 static int 1114 uhci_pipe_send_isoc_data( 1115 uhci_state_t *uhcip, 1116 usba_pipe_handle_data_t *ph, 1117 usb_isoc_req_t *isoc_req, 1118 usb_flags_t usb_flags) 1119 { 1120 int error; 1121 size_t max_isoc_xfer_sz, length; 1122 1123 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1124 "uhci_pipe_send_isoc_data: isoc_req = %p flags = %x", 1125 isoc_req, usb_flags); 1126 1127 ASSERT(isoc_req->isoc_pkts_count < UHCI_MAX_ISOC_PKTS); 1128 1129 /* Calculate the maximum isochronous transfer size */ 1130 max_isoc_xfer_sz = UHCI_MAX_ISOC_PKTS * ph->p_ep.wMaxPacketSize; 1131 1132 /* Check the size of isochronous request */ 1133 ASSERT(isoc_req->isoc_data != NULL); 1134 length = isoc_req->isoc_data->b_wptr - isoc_req->isoc_data->b_rptr; 1135 1136 if (length > max_isoc_xfer_sz) { 1137 USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1138 "uhci_pipe_send_isoc_data: Maximum isoc request size %lx " 1139 "Given isoc request size %lx", max_isoc_xfer_sz, length); 1140 1141 return (USB_INVALID_REQUEST); 1142 } 1143 1144 1145 /* 1146 * Check whether we can insert these tds? 1147 * At any point of time, we can insert maximum of 1024 isoc td's, 1148 * size of frame list table. 1149 */ 1150 if (isoc_req->isoc_pkts_count > UHCI_MAX_ISOC_PKTS) { 1151 1152 USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl, 1153 "uhci_pipe_send_isoc_data: request too big"); 1154 1155 return (USB_INVALID_REQUEST); 1156 } 1157 1158 /* Add the TD into the Host Controller's isoc list */ 1159 mutex_enter(&uhcip->uhci_int_mutex); 1160 1161 error = uhci_state_is_operational(uhcip); 1162 1163 if (error != USB_SUCCESS) { 1164 mutex_exit(&uhcip->uhci_int_mutex); 1165 1166 return (error); 1167 } 1168 1169 if ((error = uhci_insert_isoc_td(uhcip, ph, isoc_req, 1170 length, usb_flags)) != USB_SUCCESS) { 1171 1172 USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl, 1173 "uhci_pipe_send_isoc_data: Unable to insert the isoc_req," 1174 "Error = %d", error); 1175 } 1176 mutex_exit(&uhcip->uhci_int_mutex); 1177 1178 return (error); 1179 } 1180 1181 1182 /* 1183 * uhci_update_intr_td_data_toggle 1184 * Update the data toggle and save in the usba_device structure 1185 */ 1186 static void 1187 uhci_update_intr_td_data_toggle(uhci_state_t *uhcip, uhci_pipe_private_t *pp) 1188 { 1189 uint32_t paddr_tail, element_ptr; 1190 uhci_td_t *next_td; 1191 1192 /* Find the next td that would have been executed */ 1193 element_ptr = GetQH32(uhcip, pp->pp_qh->element_ptr) & 1194 QH_ELEMENT_PTR_MASK; 1195 next_td = TD_VADDR(element_ptr); 1196 paddr_tail = TD_PADDR(pp->pp_qh->td_tailp); 1197 1198 /* 1199 * If element_ptr points to the dummy td, then the data toggle in 1200 * pp_data_toggle is correct. Otherwise update the data toggle in 1201 * the pipe private 1202 */ 1203 if (element_ptr != paddr_tail) { 1204 pp->pp_data_toggle = GetTD_dtogg(uhcip, next_td); 1205 } 1206 1207 USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl, 1208 "uhci_update_intr_td_data_toggle: " 1209 "pp %p toggle %x element ptr %x ptail %x", 1210 pp, pp->pp_data_toggle, element_ptr, paddr_tail); 1211 1212 uhci_save_data_toggle(pp); 1213 } 1214