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