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