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