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