xref: /illumos-gate/usr/src/uts/common/io/usb/hcd/uhci/uhcitgt.c (revision 4e9cfc9a015e8ca7d41f7d018c74dc8a692305b3)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Universal Host Controller Driver (UHCI)
30  *
31  * The UHCI driver is a driver which interfaces to the Universal
32  * Serial Bus Driver (USBA) and the Host Controller (HC). The interface to
33  * the Host Controller is defined by the Universal Host Controller Interface.
34  * This file contains the code for HCDI entry points.
35  */
36 #include <sys/usb/hcd/uhci/uhcid.h>
37 #include <sys/usb/hcd/uhci/uhcitgt.h>
38 #include <sys/usb/hcd/uhci/uhciutil.h>
39 
40 /* function prototypes */
41 static int	uhci_pipe_send_isoc_data(uhci_state_t *uhcip,
42 			usba_pipe_handle_data_t *ph, usb_isoc_req_t *isoc_req,
43 			usb_flags_t usb_flags);
44 static int	uhci_send_intr_data(uhci_state_t *uhcip,
45 			usba_pipe_handle_data_t	*pipe_handle,
46 			usb_intr_req_t		*req,
47 			usb_flags_t		flags);
48 static int	uhci_start_periodic_pipe_polling(uhci_state_t *uhcip,
49 			usba_pipe_handle_data_t	*ph,
50 			usb_opaque_t		reqp,
51 			usb_flags_t		flags);
52 static int	uhci_stop_periodic_pipe_polling(uhci_state_t *uhcip,
53 			usba_pipe_handle_data_t	*ph,
54 			usb_flags_t		flags);
55 static void	uhci_update_intr_td_data_toggle(uhci_state_t *uhcip,
56 			uhci_pipe_private_t *pp);
57 
58 
59 /* Maximum bulk transfer size */
60 int uhci_bulk_transfer_size = UHCI_BULK_MAX_XFER_SIZE;
61 
62 /*
63  * uhci_hcdi_pipe_open:
64  *	Member of HCD Ops structure and called during client specific pipe open
65  *	Add the pipe to the data structure representing the device and allocate
66  *	bandwidth for the pipe if it is a interrupt or isochronous endpoint.
67  */
68 int
69 uhci_hcdi_pipe_open(usba_pipe_handle_data_t *ph, usb_flags_t flags)
70 {
71 	uint_t			node = 0;
72 	usb_addr_t		usb_addr;
73 	uhci_state_t		*uhcip;
74 	uhci_pipe_private_t	*pp;
75 	int			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 	/*
89 	 * Return failure immediately for any other pipe open on the root hub
90 	 * except control or interrupt pipe.
91 	 */
92 	if (usb_addr == ROOT_HUB_ADDR) {
93 		switch (UHCI_XFER_TYPE(&ph->p_ep)) {
94 		case USB_EP_ATTR_CONTROL:
95 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
96 			    "uhci_hcdi_pipe_open: Root hub control pipe");
97 			break;
98 		case USB_EP_ATTR_INTR:
99 			ASSERT(UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_IN);
100 
101 			mutex_enter(&uhcip->uhci_int_mutex);
102 			uhcip->uhci_root_hub.rh_intr_pipe_handle = ph;
103 
104 			/*
105 			 * Set the state of the root hub interrupt
106 			 * pipe as IDLE.
107 			 */
108 			uhcip->uhci_root_hub.rh_pipe_state =
109 						UHCI_PIPE_STATE_IDLE;
110 
111 			ASSERT(uhcip->uhci_root_hub.rh_client_intr_req == NULL);
112 			uhcip->uhci_root_hub.rh_client_intr_req = NULL;
113 
114 			ASSERT(uhcip->uhci_root_hub.rh_curr_intr_reqp == NULL);
115 			uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL;
116 
117 			USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
118 			    "uhci_hcdi_pipe_open: Root hub interrupt "
119 			    "pipe open succeeded");
120 			mutex_exit(&uhcip->uhci_int_mutex);
121 			sema_v(&uhcip->uhci_ocsem);
122 
123 			return (USB_SUCCESS);
124 		default:
125 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
126 			    "uhci_hcdi_pipe_open: Root hub pipe open failed");
127 			sema_v(&uhcip->uhci_ocsem);
128 
129 			return (USB_FAILURE);
130 		}
131 	}
132 
133 	/*
134 	 * A portion of the bandwidth is reserved for the non-periodic
135 	 * transfers  i.e control and bulk transfers in each  of one
136 	 * mill second frame period & usually it will be 10% of frame
137 	 * period. Hence there is no need to check for the available
138 	 * bandwidth before adding the control or bulk endpoints.
139 	 *
140 	 * There is a need to check for the available bandwidth before
141 	 * adding the periodic transfers i.e interrupt & isochronous, since
142 	 * all these periodic transfers are guaranteed transfers. Usually,
143 	 * 90% of the total frame time is reserved for periodic transfers.
144 	 */
145 	if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
146 		/* Zero Max Packet size endpoints are not supported */
147 		if (ph->p_ep.wMaxPacketSize == 0) {
148 			USB_DPRINTF_L3(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
149 			    "uhci_hcdi_pipe_open: Zero length packet");
150 			sema_v(&uhcip->uhci_ocsem);
151 
152 			return (USB_FAILURE);
153 		}
154 
155 		mutex_enter(&uhcip->uhci_int_mutex);
156 		mutex_enter(&ph->p_mutex);
157 
158 		error = uhci_allocate_bandwidth(uhcip, ph, &node);
159 		if (error != USB_SUCCESS) {
160 
161 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
162 			    "uhci_hcdi_pipe_open: Bandwidth allocation failed");
163 			mutex_exit(&ph->p_mutex);
164 			mutex_exit(&uhcip->uhci_int_mutex);
165 			sema_v(&uhcip->uhci_ocsem);
166 
167 			return (error);
168 		}
169 
170 		mutex_exit(&ph->p_mutex);
171 		mutex_exit(&uhcip->uhci_int_mutex);
172 	}
173 
174 	/* Create the HCD pipe private structure */
175 	pp = kmem_zalloc(sizeof (uhci_pipe_private_t),
176 	    (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
177 	if (pp == NULL) {
178 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
179 		    "uhci_hcdi_pipe_open: pp allocation failure");
180 
181 		if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
182 			mutex_enter(&uhcip->uhci_int_mutex);
183 			uhci_deallocate_bandwidth(uhcip, ph);
184 			mutex_exit(&uhcip->uhci_int_mutex);
185 		}
186 		sema_v(&uhcip->uhci_ocsem);
187 
188 		return (USB_NO_RESOURCES);
189 	}
190 
191 	mutex_enter(&uhcip->uhci_int_mutex);
192 	pp->pp_node = node;	/* Store the node in the interrupt lattice */
193 
194 	/* Initialize frame number */
195 	pp->pp_frame_num = INVALID_FRNUM;
196 
197 	/* Set the state of pipe as IDLE */
198 	pp->pp_state = UHCI_PIPE_STATE_IDLE;
199 
200 	/* Store a pointer to the pipe handle */
201 	pp->pp_pipe_handle = ph;
202 
203 	/* Store the pointer in the pipe handle */
204 	mutex_enter(&ph->p_mutex);
205 	ph->p_hcd_private = (usb_opaque_t)pp;
206 
207 	/* Store a copy of the pipe policy */
208 	bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
209 	mutex_exit(&ph->p_mutex);
210 
211 	/* don't check for ROOT_HUB here anymore */
212 	if (UHCI_XFER_TYPE(&ph->p_ep) != USB_EP_ATTR_ISOCH) {
213 		/* Allocate the host controller endpoint descriptor */
214 		pp->pp_qh = uhci_alloc_queue_head(uhcip);
215 
216 		if (pp->pp_qh == NULL) {
217 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
218 			    "uhci_hcdi_pipe_open: QH allocation failed");
219 
220 			if (UHCI_PERIODIC_ENDPOINT(&ph->p_ep)) {
221 				uhci_deallocate_bandwidth(uhcip, ph);
222 			}
223 
224 			mutex_enter(&ph->p_mutex);
225 
226 			/*
227 			 * Deallocate the hcd private portion
228 			 * of the pipe handle.
229 			 */
230 			kmem_free(ph->p_hcd_private,
231 				sizeof (uhci_pipe_private_t));
232 
233 			/*
234 			 * Set the private structure in the
235 			 * pipe handle equal to NULL.
236 			 */
237 			ph->p_hcd_private = NULL;
238 			mutex_exit(&ph->p_mutex);
239 			mutex_exit(&uhcip->uhci_int_mutex);
240 
241 			sema_v(&uhcip->uhci_ocsem);
242 
243 			return (USB_NO_RESOURCES);
244 		}
245 
246 		/*
247 		 * Insert the endpoint onto the host controller's
248 		 * appropriate endpoint list. The host controller
249 		 * will not schedule this endpoint until there are
250 		 * any TD's to process.
251 		 */
252 		uhci_insert_qh(uhcip, ph);
253 	}
254 
255 	/*
256 	 * Restore the data toggle from usb device structure.
257 	 */
258 	if (((ph->p_ep.bmAttributes) & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR ||
259 	    ((ph->p_ep.bmAttributes) & USB_EP_ATTR_MASK) == USB_EP_ATTR_BULK) {
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