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  * EHCI Host Controller Driver (EHCI)
30  *
31  * The EHCI driver is a software driver which interfaces to the Universal
32  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
33  * the Host Controller is defined by the EHCI Host Controller Interface.
34  *
35  * This module contains the EHCI driver isochronous code, which handles all
36  * Checking of status of USB transfers, error recovery and callbacks.
37  */
38 #include <sys/usb/hcd/ehci/ehcid.h>
39 #include <sys/usb/hcd/ehci/ehci_xfer.h>
40 #include <sys/usb/hcd/ehci/ehci_util.h>
41 #include <sys/usb/hcd/ehci/ehci_isoch.h>
42 #include <sys/usb/hcd/ehci/ehci_isoch_util.h>
43 
44 /*
45  * Isochronous initialization functions
46  */
47 int ehci_isoc_init(
48 	ehci_state_t		*ehcip);
49 void ehci_isoc_cleanup(
50 	ehci_state_t		*ehcip);
51 void ehci_isoc_pipe_cleanup(
52 	ehci_state_t		*ehcip,
53 	usba_pipe_handle_data_t *ph);
54 static void ehci_wait_for_isoc_completion(
55 	ehci_state_t		*ehcip,
56 	ehci_pipe_private_t	*pp);
57 
58 /*
59  * Isochronous request functions
60  */
61 ehci_isoc_xwrapper_t *ehci_allocate_isoc_resources(
62 	ehci_state_t		*ehcip,
63 	usba_pipe_handle_data_t *ph,
64 	usb_isoc_req_t		*isoc_reqp,
65 	usb_flags_t		usb_flags);
66 int ehci_insert_isoc_req(
67 	ehci_state_t		*ehcip,
68 	ehci_pipe_private_t	*pp,
69 	ehci_isoc_xwrapper_t	*itw,
70 	usb_flags_t		usb_flags);
71 static int ehci_insert_itd_req(
72 	ehci_state_t		*ehcip,
73 	ehci_pipe_private_t	*pp,
74 	ehci_isoc_xwrapper_t	*itw,
75 	usb_flags_t		usb_flags);
76 static int ehci_insert_sitd_req(
77 	ehci_state_t		*ehcip,
78 	ehci_pipe_private_t	*pp,
79 	ehci_isoc_xwrapper_t	*itw,
80 	usb_flags_t		usb_flags);
81 static int ehci_insert_isoc_with_frame_number(
82 	ehci_state_t		*ehcip,
83 	ehci_pipe_private_t	*pp,
84 	ehci_isoc_xwrapper_t	*itw,
85 	ehci_itd_t		*current_sitd);
86 static void ehci_remove_isoc_itds(
87 	ehci_state_t		*ehcip,
88 	ehci_pipe_private_t	*pp);
89 static void ehci_mark_reclaim_isoc(
90 	ehci_state_t		*ehcip,
91 	ehci_pipe_private_t	*pp);
92 static void ehci_reclaim_isoc(
93 	ehci_state_t		*ehcip,
94 	ehci_isoc_xwrapper_t	*itw,
95 	ehci_itd_t		*itd,
96 	ehci_pipe_private_t	*pp);
97 int	ehci_start_isoc_polling(
98 	ehci_state_t		*ehcip,
99 	usba_pipe_handle_data_t	*ph,
100 	usb_flags_t		flags);
101 
102 /*
103  * Isochronronous handling functions.
104  */
105 void ehci_traverse_active_isoc_list(
106 	ehci_state_t		*ehcip);
107 static void ehci_handle_isoc(
108 	ehci_state_t		*ehcip,
109 	ehci_isoc_xwrapper_t	*itw,
110 	ehci_itd_t		*itd);
111 static void ehci_handle_itd(
112 	ehci_state_t		*ehcip,
113 	ehci_pipe_private_t	*pp,
114 	ehci_isoc_xwrapper_t	*itw,
115 	ehci_itd_t		*itd,
116 	void			*tw_handle_callback_value);
117 static void ehci_sendup_itd_message(
118 	ehci_state_t		*ehcip,
119 	ehci_pipe_private_t	*pp,
120 	ehci_isoc_xwrapper_t	*itw,
121 	ehci_itd_t		*td,
122 	usb_cr_t		error);
123 void ehci_hcdi_isoc_callback(
124 	usba_pipe_handle_data_t	*ph,
125 	ehci_isoc_xwrapper_t	*itw,
126 	usb_cr_t		completion_reason);
127 
128 
129 /*
130  * Isochronous initialization functions
131  */
132 /*
133  * Initialize all the needed resources needed by isochronous pipes.
134  */
135 int
136 ehci_isoc_init(
137 	ehci_state_t		*ehcip)
138 {
139 	return (ehci_allocate_isoc_pools(ehcip));
140 }
141 
142 
143 /*
144  * Cleanup isochronous resources.
145  */
146 void
147 ehci_isoc_cleanup(
148 	ehci_state_t		*ehcip)
149 {
150 	ehci_isoc_xwrapper_t	*itw;
151 	ehci_pipe_private_t	*pp;
152 	ehci_itd_t		*itd;
153 	int			i, ctrl, rval;
154 
155 	/* Free all the buffers */
156 	if (ehcip->ehci_itd_pool_addr && ehcip->ehci_itd_pool_mem_handle) {
157 		for (i = 0; i < ehci_get_itd_pool_size(); i ++) {
158 			itd = &ehcip->ehci_itd_pool_addr[i];
159 			ctrl = Get_ITD(ehcip->
160 			    ehci_itd_pool_addr[i].itd_state);
161 
162 			if ((ctrl != EHCI_ITD_FREE) &&
163 			    (ctrl != EHCI_ITD_DUMMY) &&
164 			    (itd->itd_trans_wrapper)) {
165 
166 				mutex_enter(&ehcip->ehci_int_mutex);
167 
168 				itw = (ehci_isoc_xwrapper_t *)
169 					EHCI_LOOKUP_ID((uint32_t)
170 					Get_ITD(itd->itd_trans_wrapper));
171 
172 				/* Obtain the pipe private structure */
173 				pp = itw->itw_pipe_private;
174 
175 				ehci_deallocate_itd(ehcip, itw, itd);
176 				ehci_deallocate_itw(ehcip, pp, itw);
177 
178 				mutex_exit(&ehcip->ehci_int_mutex);
179 			}
180 		}
181 
182 		/*
183 		 * If EHCI_ITD_POOL_BOUND flag is set, then unbind
184 		 * the handle for ITD pools.
185 		 */
186 		if ((ehcip->ehci_dma_addr_bind_flag &
187 		    EHCI_ITD_POOL_BOUND) == EHCI_ITD_POOL_BOUND) {
188 
189 			rval = ddi_dma_unbind_handle(
190 			    ehcip->ehci_itd_pool_dma_handle);
191 
192 			ASSERT(rval == DDI_SUCCESS);
193 		}
194 		ddi_dma_mem_free(&ehcip->ehci_itd_pool_mem_handle);
195 	}
196 
197 	/* Free the ITD pool */
198 	if (ehcip->ehci_itd_pool_dma_handle) {
199 		ddi_dma_free_handle(&ehcip->ehci_itd_pool_dma_handle);
200 	}
201 }
202 
203 
204 /*
205  * ehci_isoc_pipe_cleanup
206  *
207  * Cleanup ehci isoc pipes.
208  */
209 void ehci_isoc_pipe_cleanup(
210 	ehci_state_t		*ehcip,
211 	usba_pipe_handle_data_t *ph) {
212 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
213 	uint_t			pipe_state = pp->pp_state;
214 	usb_cr_t		completion_reason;
215 
216 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
217 	    "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph);
218 
219 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
220 
221 	/* Stop all further processing */
222 	ehci_mark_reclaim_isoc(ehcip, pp);
223 
224 	/*
225 	 * Wait for processing all completed transfers
226 	 * and send result upstream/
227 	 */
228 	ehci_wait_for_isoc_completion(ehcip, pp);
229 
230 	/* Go ahead and remove all remaining itds if there are any */
231 	ehci_remove_isoc_itds(ehcip, pp);
232 
233 	switch (pipe_state) {
234 	case EHCI_PIPE_STATE_CLOSE:
235 		completion_reason = USB_CR_PIPE_CLOSING;
236 		break;
237 	case EHCI_PIPE_STATE_RESET:
238 	case EHCI_PIPE_STATE_STOP_POLLING:
239 		/* Set completion reason */
240 		completion_reason = (pipe_state ==
241 		    EHCI_PIPE_STATE_RESET) ?
242 		    USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING;
243 
244 		/* Set pipe state to idle */
245 		pp->pp_state = EHCI_PIPE_STATE_IDLE;
246 
247 		break;
248 	}
249 
250 	/*
251 	 * Do the callback for the original client
252 	 * periodic IN request.
253 	 */
254 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
255 	    USB_EP_DIR_IN) {
256 
257 		ehci_do_client_periodic_in_req_callback(
258 		    ehcip, pp, completion_reason);
259 	}
260 }
261 
262 
263 /*
264  * ehci_wait_for_transfers_completion:
265  *
266  * Wait for processing all completed transfers and to send results
267  * to upstream.
268  */
269 static void
270 ehci_wait_for_isoc_completion(
271 	ehci_state_t		*ehcip,
272 	ehci_pipe_private_t	*pp)
273 {
274 	clock_t			xfer_cmpl_time_wait;
275 
276 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
277 
278 	if (pp->pp_itw_head == NULL) {
279 
280 		return;
281 	}
282 
283 	/* Get the number of clock ticks to wait */
284 	xfer_cmpl_time_wait = drv_usectohz(EHCI_XFER_CMPL_TIMEWAIT * 1000000);
285 
286 	(void) cv_timedwait(&pp->pp_xfer_cmpl_cv,
287 	    &ehcip->ehci_int_mutex,
288 	    ddi_get_lbolt() + xfer_cmpl_time_wait);
289 
290 	if (pp->pp_itw_head) {
291 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
292 		    "ehci_wait_for_isoc_completion: "
293 		    "No transfers completion confirmation received");
294 	}
295 }
296 
297 
298 /*
299  *  Isochronous request functions
300  */
301 /*
302  * ehci_allocate_isoc_resources:
303  *
304  * Calculates the number of tds necessary for a isoch transfer, and
305  * allocates all the necessary resources.
306  *
307  * Returns NULL if there is insufficient resources otherwise ITW.
308  */
309 ehci_isoc_xwrapper_t *
310 ehci_allocate_isoc_resources(
311 	ehci_state_t		*ehcip,
312 	usba_pipe_handle_data_t *ph,
313 	usb_isoc_req_t		*isoc_reqp,
314 	usb_flags_t		usb_flags)
315 {
316 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
317 	int			pipe_dir, i;
318 	uint_t			max_ep_pkt_size, max_isoc_xfer_size;
319 	usb_isoc_pkt_descr_t	*isoc_pkt_descr;
320 	size_t			isoc_pkt_count, isoc_pkts_length;
321 	size_t 			itw_xfer_size = 0;
322 	ehci_isoc_xwrapper_t	*itw;
323 
324 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
325 	    "ehci_allocate_isoc_resources: flags = 0x%x", usb_flags);
326 
327 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
328 
329 	/*
330 	 * Check whether pipe is in halted state.
331 	 */
332 	if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
333 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
334 		    "ehci_allocate_isoc_resources:"
335 		    "Pipe is in error state, need pipe reset to continue");
336 
337 		return (NULL);
338 	}
339 
340 	/* Calculate the maximum isochronous transfer size we allow */
341 	max_ep_pkt_size = ph->p_ep.wMaxPacketSize;
342 	max_isoc_xfer_size = EHCI_MAX_ISOC_PKTS_PER_XFER * max_ep_pkt_size;
343 
344 	/* Get the packet descriptor and number of packets to send */
345 	if (isoc_reqp) {
346 		isoc_pkt_descr = isoc_reqp->isoc_pkt_descr;
347 		isoc_pkt_count = isoc_reqp->isoc_pkts_count;
348 		isoc_pkts_length = isoc_reqp->isoc_pkts_length;
349 	} else {
350 		isoc_pkt_descr = ((usb_isoc_req_t *)
351 		    pp->pp_client_periodic_in_reqp)->isoc_pkt_descr;
352 
353 		isoc_pkt_count = ((usb_isoc_req_t *)
354 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_count;
355 
356 		isoc_pkts_length = ((usb_isoc_req_t *)
357 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_length;
358 	}
359 
360 	/* Calculate the size of the transfer. */
361 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
362 	if (pipe_dir == USB_EP_DIR_IN) {
363 		for (i = 0; i < isoc_pkt_count; i++) {
364 			itw_xfer_size += isoc_pkt_descr->isoc_pkt_length;
365 			isoc_pkt_descr++;
366 		}
367 
368 		if ((isoc_pkts_length) &&
369 			(isoc_pkts_length != itw_xfer_size)) {
370 
371 			USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
372 			    "ehci_allocate_isoc_resources: "
373 			    "isoc_pkts_length 0x%x is not equal to the sum of "
374 			    "all pkt lengths 0x%x in an isoc request",
375 			    isoc_pkts_length, itw_xfer_size);
376 
377 			return (NULL);
378 		}
379 
380 	} else {
381 		ASSERT(isoc_reqp != NULL);
382 		itw_xfer_size = isoc_reqp->isoc_data->b_wptr -
383 		    isoc_reqp->isoc_data->b_rptr;
384 	}
385 
386 	/* Check the size of isochronous request */
387 	if (itw_xfer_size > max_isoc_xfer_size) {
388 
389 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
390 		    "ehci_allocate_isoc_resources: Maximum isoc request "
391 		    "size 0x%x Given isoc request size 0x%x",
392 		    max_isoc_xfer_size, itw_xfer_size);
393 
394 		return (NULL);
395 	}
396 
397 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
398 	    "ehci_allocate_isoc_resources: length = 0x%x", itw_xfer_size);
399 
400 	/* Allocate the itw for this request */
401 	if ((itw = ehci_allocate_itw_resources(ehcip, pp, itw_xfer_size,
402 	    usb_flags, isoc_pkt_count)) == NULL) {
403 
404 		return (NULL);
405 	}
406 
407 	itw->itw_handle_callback_value = NULL;
408 
409 	if (pipe_dir == USB_EP_DIR_IN) {
410 		if (ehci_allocate_isoc_in_resource(ehcip, pp, itw, usb_flags) !=
411 		    USB_SUCCESS) {
412 
413 			ehci_deallocate_itw(ehcip, pp, itw);
414 
415 			return (NULL);
416 		}
417 	} else {
418 		if (itw->itw_length) {
419 			ASSERT(isoc_reqp->isoc_data != NULL);
420 
421 			/* Copy the data into the buffer */
422 			bcopy(isoc_reqp->isoc_data->b_rptr,
423 			    itw->itw_buf, itw->itw_length);
424 
425 			Sync_IO_Buffer_for_device(itw->itw_dmahandle,
426 			    itw->itw_length);
427 		}
428 		itw->itw_curr_xfer_reqp = isoc_reqp;
429 	}
430 
431 	return (itw);
432 }
433 
434 
435 /*
436  * ehci_insert_isoc_req:
437  *
438  * Insert an isochronous request into the Host Controller's
439  * isochronous list.
440  */
441 int
442 ehci_insert_isoc_req(
443 	ehci_state_t			*ehcip,
444 	ehci_pipe_private_t		*pp,
445 	ehci_isoc_xwrapper_t		*itw,
446 	usb_flags_t			usb_flags)
447 {
448 	int			error;
449 	ehci_itd_t		*new_itd, *temp_itd;
450 
451 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
452 	    "ehci_insert_isoc_req: flags = 0x%x port status = 0x%x",
453 	    usb_flags, itw->itw_port_status);
454 
455 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
456 
457 	ASSERT(itw->itw_curr_xfer_reqp != NULL);
458 	ASSERT(itw->itw_curr_xfer_reqp->isoc_pkt_descr != NULL);
459 
460 	/*
461 	 * Save address of first usb isochronous packet descriptor.
462 	 */
463 	itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
464 
465 	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
466 		error = ehci_insert_itd_req(ehcip, pp, itw, usb_flags);
467 	} else {
468 		error = ehci_insert_sitd_req(ehcip, pp, itw, usb_flags);
469 	}
470 
471 	/* Either all the isocs will be added or none of them will */
472 	error = ehci_insert_isoc_to_pfl(ehcip, pp, itw);
473 
474 	if (error != USB_SUCCESS) {
475 		/*
476 		 * Deallocate all the ITDs, otherwise they will be
477 		 * lost forever.
478 		 */
479 		new_itd = itw->itw_itd_head;
480 		while (new_itd) {
481 			temp_itd = ehci_itd_iommu_to_cpu(ehcip,
482 			    Get_ITD(new_itd->itd_itw_next_itd));
483 			ehci_deallocate_itd(ehcip, itw, new_itd);
484 			new_itd = temp_itd;
485 		}
486 		if ((itw->itw_direction == USB_EP_DIR_IN)) {
487 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
488 
489 			if (pp->pp_cur_periodic_req_cnt) {
490 				/*
491 				 * Set pipe state to stop polling and
492 				 * error to no resource. Don't insert
493 				 * any more isoch polling requests.
494 				 */
495 				pp->pp_state =
496 				    EHCI_PIPE_STATE_STOP_POLLING;
497 				pp->pp_error = error;
498 			} else {
499 				/* Set periodic in pipe state to idle */
500 				pp->pp_state = EHCI_PIPE_STATE_IDLE;
501 			}
502 
503 			return (error);
504 		}
505 
506 		/* Save how many packets and data actually went */
507 		itw->itw_num_itds = 0;
508 		itw->itw_length  = 0;
509 	}
510 
511 	/*
512 	 * Reset back to the address of first usb isochronous
513 	 * packet descriptor.
514 	 */
515 	itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
516 
517 	/* Reset the CONTINUE flag */
518 	pp->pp_flag &= ~EHCI_ISOC_XFER_CONTINUE;
519 
520 	return (error);
521 }
522 
523 
524 /*
525  * ehci_insert_itd_req:
526  *
527  * Insert an ITD request into the Host Controller's isochronous list.
528  */
529 /* ARGSUSED */
530 static int
531 ehci_insert_itd_req(
532 	ehci_state_t		*ehcip,
533 	ehci_pipe_private_t	*pp,
534 	ehci_isoc_xwrapper_t	*itw,
535 	usb_flags_t		usb_flags)
536 {
537 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
538 	usb_isoc_req_t		*curr_isoc_reqp;
539 	usb_isoc_pkt_descr_t	*curr_isoc_pkt_descr;
540 	size_t			curr_isoc_xfer_offset;
541 	size_t			isoc_pkt_length;
542 	uint_t			count, xactcount;
543 	uint32_t		xact_status;
544 	uint32_t		page, pageselected;
545 	uint32_t		buf[EHCI_ITD_BUFFER_LIST_SIZE];
546 	uint16_t		index = 0;
547 	uint16_t		multi = 0;
548 	ehci_itd_t		*new_itd;
549 
550 	/*
551 	 * Get the current isochronous request and packet
552 	 * descriptor pointers.
553 	 */
554 	curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
555 
556 	page = itw->itw_cookie.dmac_address;
557 	ASSERT((page % EHCI_4K_ALIGN) == 0);
558 
559 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
560 	    "ehci_insert_itd_req: itw_curr_xfer_reqp = 0x%p page = 0x%p",
561 	    itw->itw_curr_xfer_reqp, page);
562 
563 	/* Insert all the isochronous TDs */
564 	count = 0;
565 	curr_isoc_xfer_offset = 0;
566 
567 	while (count < curr_isoc_reqp->isoc_pkts_count) {
568 
569 		/* Grab a new itd */
570 		new_itd = itw->itw_itd_free_list;
571 
572 		ASSERT(new_itd != NULL);
573 
574 		itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
575 		    Get_ITD(new_itd->itd_link_ptr));
576 		Set_ITD(new_itd->itd_link_ptr, NULL);
577 
578 		bzero(buf, EHCI_ITD_BUFFER_LIST_SIZE * sizeof (uint32_t));
579 
580 		multi = CalculateITDMultiField(ph->p_ep.wMaxPacketSize);
581 
582 		if (multi > EHCI_ITD_CTRL_MULTI_MASK) {
583 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
584 			    "ehci_insert_itd_req: Wrong multi value.");
585 
586 			return (USB_FAILURE);
587 		}
588 
589 		/* Fill 8 transaction for every iTD */
590 		for (xactcount = 0, pageselected = 0;
591 		    xactcount < EHCI_ITD_CTRL_LIST_SIZE; xactcount++) {
592 
593 			curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
594 
595 			isoc_pkt_length = ph->p_ep.wMaxPacketSize &
596 			    EHCI_ITD_CTRL_MAX_PACKET_MASK;
597 
598 			curr_isoc_pkt_descr->isoc_pkt_actual_length
599 			    = isoc_pkt_length;
600 
601 			xact_status = 0;
602 
603 			if (pageselected < EHCI_ITD_BUFFER_LIST_SIZE) {
604 
605 				buf[pageselected] |= page;
606 			} else {
607 				USB_DPRINTF_L2(PRINT_MASK_INTR,
608 				    ehcip->ehci_log_hdl,
609 				    "ehci_insert_itd_req: "
610 				    "Error in buffer pointer.");
611 
612 				return (USB_FAILURE);
613 			}
614 
615 			xact_status = curr_isoc_xfer_offset;
616 			xact_status |= (pageselected << 12);
617 			xact_status |= (isoc_pkt_length * multi) << 16;
618 			xact_status |= EHCI_ITD_XFER_ACTIVE;
619 
620 			/* Set IOC on the last TD. */
621 			if (count == (curr_isoc_reqp->isoc_pkts_count - 1)) {
622 				xact_status |= EHCI_ITD_XFER_IOC_ON;
623 			}
624 
625 			USB_DPRINTF_L3(PRINT_MASK_INTR,
626 			    ehcip->ehci_log_hdl,
627 			    "ehci_insert_itd_req: count = 0x%x multi = %d"
628 			    "status = 0x%x page = 0x%x index = %d "
629 			    "pageselected = %d isoc_pkt_length = 0x%x",
630 			    xactcount, multi, xact_status, page,
631 			    index, pageselected, isoc_pkt_length);
632 
633 			/* Fill in the new itd */
634 			Set_ITD_BODY(new_itd, xactcount, xact_status);
635 
636 			itw->itw_curr_isoc_pktp++;
637 			Set_ITD_INDEX(new_itd, xactcount, index++);
638 
639 			curr_isoc_xfer_offset += isoc_pkt_length * multi;
640 
641 			if (curr_isoc_xfer_offset >= EHCI_4K_ALIGN) {
642 				pageselected ++;
643 				page += EHCI_4K_ALIGN;
644 				curr_isoc_xfer_offset -= EHCI_4K_ALIGN;
645 			}
646 
647 			count ++;
648 			if (count >= curr_isoc_reqp->isoc_pkts_count) {
649 
650 			    break;
651 			}
652 		}
653 
654 		buf[0] |= (itw->itw_endpoint_num << 8);
655 		buf[0] |= itw->itw_device_addr;
656 		buf[1] |= isoc_pkt_length;
657 		if (itw->itw_direction == USB_EP_DIR_IN) {
658 			buf[1] |= EHCI_ITD_CTRL_DIR_IN;
659 		}
660 		buf[2] |= multi;
661 
662 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER0, buf[0]);
663 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER1, buf[1]);
664 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER2, buf[2]);
665 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER3, buf[3]);
666 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER4, buf[4]);
667 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER5, buf[5]);
668 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER6, buf[6]);
669 
670 		Set_ITD(new_itd->itd_state, EHCI_ITD_ACTIVE);
671 		ehci_print_itd(ehcip, new_itd);
672 
673 		/*
674 		 * Add this itd to the itw before we add it in the PFL
675 		 * If adding it to the PFL fails, we will have to cleanup.
676 		 */
677 		ehci_insert_itd_on_itw(ehcip, itw, new_itd);
678 
679 	}
680 
681 	return (USB_SUCCESS);
682 }
683 
684 
685 /*
686  * ehci_insert_sitd_req:
687  *
688  * Insert an SITD request into the Host Controller's isochronous list.
689  */
690 /* ARGSUSED */
691 static int
692 ehci_insert_sitd_req(
693 	ehci_state_t		*ehcip,
694 	ehci_pipe_private_t	*pp,
695 	ehci_isoc_xwrapper_t	*itw,
696 	usb_flags_t		usb_flags)
697 {
698 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
699 	usb_isoc_req_t		*curr_isoc_reqp;
700 	usb_isoc_pkt_descr_t	*curr_isoc_pkt_descr;
701 	size_t			curr_isoc_xfer_offset;
702 	size_t			isoc_pkt_length;
703 	uint_t			count;
704 	uint32_t		ctrl, uframe_sched, xfer_state;
705 	uint32_t		page0, page1, prev_sitd;
706 	uint32_t		ssplit_count;
707 	ehci_itd_t		*new_sitd;
708 
709 	/*
710 	 * Get the current isochronous request and packet
711 	 * descriptor pointers.
712 	 */
713 	curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
714 
715 	/* Set the ctrl field */
716 	ctrl = 0;
717 	if (itw->itw_direction == USB_EP_DIR_IN) {
718 		ctrl |= EHCI_SITD_CTRL_DIR_IN;
719 	} else {
720 		ctrl |= EHCI_SITD_CTRL_DIR_OUT;
721 	}
722 
723 	ctrl |= (itw->itw_hub_port << EHCI_SITD_CTRL_PORT_SHIFT) &
724 	    EHCI_SITD_CTRL_PORT_MASK;
725 	ctrl |= (itw->itw_hub_addr << EHCI_SITD_CTRL_HUB_SHIFT) &
726 	    EHCI_SITD_CTRL_HUB_MASK;
727 	ctrl |= (itw->itw_endpoint_num << EHCI_SITD_CTRL_END_PT_SHIFT) &
728 	    EHCI_SITD_CTRL_END_PT_MASK;
729 	ctrl |= (itw->itw_device_addr << EHCI_SITD_CTRL_DEVICE_SHIFT) &
730 	    EHCI_SITD_CTRL_DEVICE_MASK;
731 
732 	/* Set the micro frame schedule */
733 	uframe_sched = 0;
734 	uframe_sched |= (pp->pp_smask << EHCI_SITD_UFRAME_SMASK_SHIFT) &
735 	    EHCI_SITD_UFRAME_SMASK_MASK;
736 	uframe_sched |= (pp->pp_cmask << EHCI_SITD_UFRAME_CMASK_SHIFT) &
737 	    EHCI_SITD_UFRAME_CMASK_MASK;
738 
739 	/* Set the default page information */
740 	page0 = itw->itw_cookie.dmac_address;
741 	page1 = 0;
742 
743 	prev_sitd = EHCI_ITD_LINK_PTR_INVALID;
744 
745 	/*
746 	 * Save the number of isochronous TDs needs
747 	 * to be insert to complete current isochronous request.
748 	 */
749 	itw->itw_num_itds = curr_isoc_reqp->isoc_pkts_count;
750 
751 	/* Insert all the isochronous TDs */
752 	for (count = 0, curr_isoc_xfer_offset = 0;
753 		count < itw->itw_num_itds; count++) {
754 
755 		curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
756 
757 		isoc_pkt_length = curr_isoc_pkt_descr->isoc_pkt_length;
758 		curr_isoc_pkt_descr->isoc_pkt_actual_length = isoc_pkt_length;
759 
760 		/* Set the transfer state information */
761 		xfer_state = 0;
762 
763 		if (itw->itw_direction == USB_EP_DIR_IN) {
764 			/* Set the size to the max packet size */
765 			xfer_state |= (ph->p_ep.wMaxPacketSize <<
766 			    EHCI_SITD_XFER_TOTAL_SHIFT) &
767 			    EHCI_SITD_XFER_TOTAL_MASK;
768 		} else {
769 			/* Set the size to the packet length */
770 			xfer_state |= (isoc_pkt_length <<
771 			    EHCI_SITD_XFER_TOTAL_SHIFT) &
772 			    EHCI_SITD_XFER_TOTAL_MASK;
773 		}
774 		xfer_state |=  EHCI_SITD_XFER_ACTIVE;
775 
776 		/* Set IOC on the last TD. */
777 		if (count == (itw->itw_num_itds - 1)) {
778 			xfer_state |= EHCI_SITD_XFER_IOC_ON;
779 		}
780 
781 		ssplit_count = isoc_pkt_length / MAX_UFRAME_SITD_XFER;
782 		if (isoc_pkt_length % MAX_UFRAME_SITD_XFER) {
783 			ssplit_count++;
784 		}
785 
786 		page1 = (ssplit_count & EHCI_SITD_XFER_TCOUNT_MASK) <<
787 		    EHCI_SITD_XFER_TCOUNT_SHIFT;
788 		if (ssplit_count > 1) {
789 			page1 |= EHCI_SITD_XFER_TP_BEGIN;
790 		} else {
791 			page1 |= EHCI_SITD_XFER_TP_ALL;
792 		}
793 
794 		/* Grab a new sitd */
795 		new_sitd = itw->itw_itd_free_list;
796 
797 		ASSERT(new_sitd != NULL);
798 
799 		itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
800 		    Get_ITD(new_sitd->itd_link_ptr));
801 		Set_ITD(new_sitd->itd_link_ptr, NULL);
802 
803 		/* Fill in the new sitd */
804 		Set_ITD_BODY(new_sitd, EHCI_SITD_CTRL, ctrl);
805 		Set_ITD_BODY(new_sitd, EHCI_SITD_UFRAME_SCHED, uframe_sched);
806 		Set_ITD_BODY(new_sitd, EHCI_SITD_XFER_STATE, xfer_state);
807 		Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER0,
808 		    page0 + curr_isoc_xfer_offset);
809 		Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER1, page1);
810 		Set_ITD_BODY(new_sitd, EHCI_SITD_PREV_SITD, prev_sitd);
811 
812 		Set_ITD(new_sitd->itd_state, EHCI_ITD_ACTIVE);
813 
814 		/*
815 		 * Add this itd to the itw before we add it in the PFL
816 		 * If adding it to the PFL fails, we will have to cleanup.
817 		 */
818 		ehci_insert_itd_on_itw(ehcip, itw, new_sitd);
819 
820 		itw->itw_curr_isoc_pktp++;
821 		curr_isoc_xfer_offset += isoc_pkt_length;
822 	}
823 
824 	return (USB_SUCCESS);
825 }
826 
827 
828 /*
829  * ehci_remove_isoc_itds:
830  *
831  * Remove all itds from the PFL.
832  */
833 static void
834 ehci_remove_isoc_itds(
835 	ehci_state_t		*ehcip,
836 	ehci_pipe_private_t	*pp)
837 {
838 	ehci_isoc_xwrapper_t	*curr_itw, *next_itw;
839 	ehci_itd_t		*curr_itd, *next_itd;
840 
841 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
842 	    "ehci_remove_isoc_itds: pp = 0x%p", pp);
843 
844 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
845 
846 	curr_itw = pp->pp_itw_head;
847 	while (curr_itw) {
848 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
849 		    "ehci_remove_isoc_itds: itw = 0x%p num itds = %d",
850 		    curr_itw, curr_itw->itw_num_itds);
851 
852 		next_itw = curr_itw->itw_next;
853 
854 		curr_itd = curr_itw->itw_itd_head;
855 		while (curr_itd) {
856 			next_itd = ehci_itd_iommu_to_cpu(ehcip,
857 			    Get_ITD(curr_itd->itd_itw_next_itd));
858 
859 			ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
860 
861 			curr_itd = next_itd;
862 		}
863 
864 		ehci_deallocate_itw(ehcip, pp, curr_itw);
865 
866 		curr_itw = next_itw;
867 	}
868 }
869 
870 
871 /*
872  * ehci_mark_reclaim_isoc:
873  *
874  * Set active ITDs to RECLAIM.
875  * Return number of ITD that need to be processed.
876  */
877 static void
878 ehci_mark_reclaim_isoc(
879 	ehci_state_t		*ehcip,
880 	ehci_pipe_private_t	*pp)
881 {
882 	usb_frame_number_t	current_frame_number;
883 	ehci_isoc_xwrapper_t	*curr_itw, *next_itw;
884 	ehci_itd_t		*curr_itd, *next_itd;
885 	uint_t			ctrl;
886 	uint_t			isActive;
887 	int			i;
888 
889 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
890 	    "ehci_mark_reclaim_isoc: pp = 0x%p", pp);
891 
892 	if (pp->pp_itw_head == NULL) {
893 
894 		return;
895 	}
896 
897 	/* Get the current frame number. */
898 	current_frame_number = ehci_get_current_frame_number(ehcip);
899 
900 	/* Traverse the list of transfer descriptors */
901 	curr_itw = pp->pp_itw_head;
902 	while (curr_itw) {
903 		next_itw = curr_itw->itw_next;
904 
905 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
906 		    "ehci_mark_reclaim_isoc: itw = 0x%p num itds = %d",
907 		    curr_itw, curr_itw->itw_num_itds);
908 
909 		curr_itd = curr_itw->itw_itd_head;
910 		while (curr_itd) {
911 			next_itd = ehci_itd_iommu_to_cpu(ehcip,
912 			    Get_ITD(curr_itd->itd_itw_next_itd));
913 
914 			if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
915 
916 				for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
917 					ctrl = Get_ITD_BODY(curr_itd,
918 					    EHCI_ITD_CTRL0 + i);
919 					isActive = ctrl & EHCI_ITD_XFER_ACTIVE;
920 					/* If still active, deactivate it */
921 					if (isActive) {
922 						ctrl &= ~EHCI_ITD_XFER_ACTIVE;
923 						Set_ITD_BODY(curr_itd,
924 						    EHCI_ITD_CTRL0 + i,
925 						    ctrl);
926 						break;
927 					}
928 				}
929 			} else {
930 				ctrl = Get_ITD_BODY(curr_itd,
931 				    EHCI_SITD_XFER_STATE);
932 				isActive = ctrl & EHCI_SITD_XFER_ACTIVE;
933 				/* If it is still active deactivate it */
934 				if (isActive) {
935 					ctrl &= ~EHCI_SITD_XFER_ACTIVE;
936 					Set_ITD_BODY(curr_itd,
937 					    EHCI_SITD_XFER_STATE,
938 					    ctrl);
939 				}
940 			}
941 
942 			/*
943 			 * If the itd was active put it on the reclaim status,
944 			 * so the interrupt handler will know not to process it.
945 			 * Otherwise leave it alone and let the interrupt
946 			 * handler process it normally.
947 			 */
948 			if (isActive) {
949 				Set_ITD(curr_itd->itd_state, EHCI_ITD_RECLAIM);
950 				Set_ITD_FRAME(curr_itd->itd_reclaim_number,
951 				    current_frame_number);
952 				ehci_remove_isoc_from_pfl(ehcip, curr_itd);
953 			}
954 			curr_itd = next_itd;
955 		}
956 		curr_itw = next_itw;
957 	}
958 }
959 
960 
961 /*
962  * ehci_reclaim_isoc:
963  *
964  * "Reclaim" itds that were marked as RECLAIM.
965  */
966 static void
967 ehci_reclaim_isoc(
968 	ehci_state_t		*ehcip,
969 	ehci_isoc_xwrapper_t	*itw,
970 	ehci_itd_t		*itd,
971 	ehci_pipe_private_t	*pp)
972 {
973 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
974 	    "ehci_reclaim_isoc: itd = 0x%p", itd);
975 
976 	/*
977 	 * These are itds that were marked "RECLAIM"
978 	 * by the pipe cleanup.
979 	 *
980 	 * Decrement the num_itds and the periodic in
981 	 * request count if necessary.
982 	 */
983 	if ((--itw->itw_num_itds == 0) && (itw->itw_curr_xfer_reqp)) {
984 		if (itw->itw_direction == USB_EP_DIR_IN) {
985 
986 			pp->pp_cur_periodic_req_cnt--;
987 
988 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
989 		} else {
990 			ehci_hcdi_isoc_callback(pp->pp_pipe_handle, itw,
991 			    USB_CR_FLUSHED);
992 		}
993 	}
994 
995 	/* Deallocate this transfer descriptor */
996 	ehci_deallocate_itd(ehcip, itw, itd);
997 }
998 
999 
1000 /*
1001  * ehci_start_isoc_polling:
1002  *
1003  * Insert the number of periodic requests corresponding to polling
1004  * interval as calculated during pipe open.
1005  */
1006 int
1007 ehci_start_isoc_polling(
1008 	ehci_state_t		*ehcip,
1009 	usba_pipe_handle_data_t	*ph,
1010 	usb_flags_t		flags)
1011 {
1012 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
1013 	ehci_isoc_xwrapper_t	*itw_list, *itw;
1014 	int			i, total_itws;
1015 	int			error = USB_SUCCESS;
1016 
1017 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1018 		"ehci_start_isoc_polling:");
1019 
1020 	/* Allocate all the necessary resources for the IN transfer */
1021 	itw_list = NULL;
1022 	total_itws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt;
1023 	for (i = 0; i < total_itws; i += 1) {
1024 		itw = ehci_allocate_isoc_resources(ehcip, ph, NULL, flags);
1025 		if (itw == NULL) {
1026 			error = USB_NO_RESOURCES;
1027 			/* There are not enough resources deallocate the ITWs */
1028 			itw = itw_list;
1029 			while (itw != NULL) {
1030 				itw_list = itw->itw_next;
1031 				ehci_deallocate_isoc_in_resource(
1032 					ehcip, pp, itw);
1033 				ehci_deallocate_itw(ehcip, pp, itw);
1034 				itw = itw_list;
1035 			}
1036 
1037 			return (error);
1038 		} else {
1039 			if (itw_list == NULL) {
1040 				itw_list = itw;
1041 			}
1042 		}
1043 	}
1044 
1045 	i = 0;
1046 	while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) {
1047 
1048 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1049 		    "ehci_start_isoc_polling: max = %d curr = %d itw = %p:",
1050 		    pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt,
1051 		    itw_list);
1052 
1053 		itw = itw_list;
1054 		itw_list = itw->itw_next;
1055 
1056 		error = ehci_insert_isoc_req(ehcip, pp, itw, flags);
1057 
1058 		if (error == USB_SUCCESS) {
1059 			pp->pp_cur_periodic_req_cnt++;
1060 		} else {
1061 			/*
1062 			 * Deallocate the remaining tw
1063 			 * The current tw should have already been deallocated
1064 			 */
1065 			itw = itw_list;
1066 			while (itw != NULL) {
1067 				itw_list = itw->itw_next;
1068 				ehci_deallocate_isoc_in_resource(
1069 					ehcip, pp, itw);
1070 				ehci_deallocate_itw(ehcip, pp, itw);
1071 				itw = itw_list;
1072 			}
1073 			/*
1074 			 * If this is the first req return an error.
1075 			 * Otherwise return success.
1076 			 */
1077 			if (i != 0) {
1078 				error = USB_SUCCESS;
1079 			}
1080 
1081 			break;
1082 		}
1083 		i++;
1084 	}
1085 
1086 	return (error);
1087 }
1088 
1089 
1090 /*
1091  * Isochronronous handling functions.
1092  */
1093 /*
1094  * ehci_traverse_active_isoc_list:
1095  */
1096 void
1097 ehci_traverse_active_isoc_list(
1098 	ehci_state_t		*ehcip)
1099 {
1100 	ehci_isoc_xwrapper_t	*curr_itw;
1101 	ehci_itd_t		*curr_itd, *next_itd;
1102 	uint_t			state;
1103 	ehci_pipe_private_t	*pp;
1104 
1105 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1106 	    "ehci_traverse_active_isoc_list:");
1107 
1108 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1109 
1110 	/* Sync ITD pool */
1111 	Sync_ITD_Pool(ehcip);
1112 
1113 	/* Traverse the list of done itds */
1114 	curr_itd = ehci_create_done_itd_list(ehcip);
1115 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1116 	    "ehci_traverse_active_isoc_list: current itd = 0x%p", curr_itd);
1117 
1118 	while (curr_itd) {
1119 		/* Save the next_itd */
1120 		next_itd = ehci_itd_iommu_to_cpu(ehcip,
1121 		    Get_ITD(curr_itd->itd_next_active_itd));
1122 
1123 		/* Get the transfer wrapper and the pp */
1124 		curr_itw = (ehci_isoc_xwrapper_t *)EHCI_LOOKUP_ID(
1125 			(uint32_t)Get_ITD(curr_itd->itd_trans_wrapper));
1126 		pp = curr_itw->itw_pipe_private;
1127 
1128 		if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
1129 			ehci_print_itd(ehcip, curr_itd);
1130 		} else {
1131 			ehci_print_sitd(ehcip, curr_itd);
1132 		}
1133 
1134 		/* Get the ITD state */
1135 		state = Get_ITD(curr_itd->itd_state);
1136 
1137 		/* Only process the ITDs marked as active. */
1138 		if (state == EHCI_ITD_ACTIVE) {
1139 			ehci_parse_isoc_error(ehcip, curr_itw, curr_itd);
1140 			ehci_handle_isoc(ehcip, curr_itw, curr_itd);
1141 		} else {
1142 			ASSERT(state == EHCI_ITD_RECLAIM);
1143 			ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
1144 		}
1145 
1146 		/*
1147 		 * Deallocate the transfer wrapper if there are no more
1148 		 * ITD's for the transfer wrapper.  ehci_deallocate_itw()
1149 		 * will  not deallocate the tw for a periodic in endpoint
1150 		 * since it will always have a ITD attached to it.
1151 		 */
1152 		ehci_deallocate_itw(ehcip, pp, curr_itw);
1153 
1154 		/* Check any ISOC is waiting for transfers completion event */
1155 		if (pp->pp_itw_head == NULL) {
1156 			USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1157 			    "ehci_traverse_active_isoc_list: "
1158 			    "Sent transfers completion event pp = 0x%p", pp);
1159 			cv_signal(&pp->pp_xfer_cmpl_cv);
1160 		}
1161 
1162 		curr_itd = next_itd;
1163 
1164 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1165 		    "ehci_traverse_active_isoc_list: state = 0x%x "
1166 		    "pp = 0x%p itw = 0x%p itd = 0x%p next_itd = 0x%p",
1167 		    state, pp, curr_itw, curr_itd, next_itd);
1168 	}
1169 }
1170 
1171 
1172 static void
1173 ehci_handle_isoc(
1174 	ehci_state_t		*ehcip,
1175 	ehci_isoc_xwrapper_t	*itw,
1176 	ehci_itd_t		*itd)
1177 {
1178 	ehci_pipe_private_t	*pp;	/* Pipe private field */
1179 
1180 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1181 
1182 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1183 	    "ehci_handle_isoc:");
1184 
1185 	/* Obtain the pipe private structure */
1186 	pp = itw->itw_pipe_private;
1187 
1188 	ehci_handle_itd(ehcip, pp, itw, itd, itw->itw_handle_callback_value);
1189 }
1190 
1191 
1192 /*
1193  * ehci_handle_itd:
1194  *
1195  * Handle an (split) isochronous transfer descriptor.
1196  * This function will deallocate the itd from the list as well.
1197  */
1198 /* ARGSUSED */
1199 static void
1200 ehci_handle_itd(
1201 	ehci_state_t		*ehcip,
1202 	ehci_pipe_private_t	*pp,
1203 	ehci_isoc_xwrapper_t	*itw,
1204 	ehci_itd_t		*itd,
1205 	void			*tw_handle_callback_value)
1206 {
1207 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1208 	usb_isoc_req_t		*curr_isoc_reqp =
1209 				    (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
1210 	int			error = USB_SUCCESS;
1211 	int			i, index;
1212 
1213 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1214 	    "ehci_handle_itd: pp=0x%p itw=0x%p itd=0x%p "
1215 	    "isoc_reqp=0%p data=0x%p", pp, itw, itd, curr_isoc_reqp,
1216 	    curr_isoc_reqp->isoc_data);
1217 
1218 	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV &&
1219 	    curr_isoc_reqp != NULL) {
1220 
1221 	    for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
1222 
1223 		index = Get_ITD_INDEX(itd, i);
1224 		if (index == EHCI_ITD_UNUSED_INDEX) {
1225 
1226 			continue;
1227 		}
1228 		curr_isoc_reqp->isoc_pkt_descr[index].isoc_pkt_actual_length =
1229 			(Get_ITD_BODY(itd, i) & EHCI_ITD_XFER_LENGTH) >> 16;
1230 	    }
1231 	}
1232 
1233 	/*
1234 	 * Decrement the ITDs counter and check whether all the isoc
1235 	 * data has been send or received. If ITDs counter reaches
1236 	 * zero then inform client driver about completion current
1237 	 * isoc request. Otherwise wait for completion of other isoc
1238 	 * ITDs or transactions on this pipe.
1239 	 */
1240 	if (--itw->itw_num_itds != 0) {
1241 		/* Deallocate this transfer descriptor */
1242 		ehci_deallocate_itd(ehcip, itw, itd);
1243 
1244 		return;
1245 	}
1246 
1247 	/*
1248 	 * If this is a isoc in pipe, return the data to the client.
1249 	 * For a isoc out pipe, there is no need to do anything.
1250 	 */
1251 	if (itw->itw_direction == USB_EP_DIR_OUT) {
1252 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1253 		    "ehci_handle_itd: Isoc out pipe, isoc_reqp=0x%p,"
1254 		    "data=0x%p", curr_isoc_reqp, curr_isoc_reqp->isoc_data);
1255 
1256 		/* Do the callback */
1257 		ehci_hcdi_isoc_callback(ph, itw, USB_CR_OK);
1258 
1259 		/* Deallocate this transfer descriptor */
1260 		ehci_deallocate_itd(ehcip, itw, itd);
1261 
1262 		return;
1263 	}
1264 
1265 	/* Decrement number of IN isochronous request count */
1266 	pp->pp_cur_periodic_req_cnt--;
1267 
1268 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1269 	    "ehci_handle_itd: pp_cur_periodic_req_cnt = 0x%x ",
1270 	    pp->pp_cur_periodic_req_cnt);
1271 
1272 	/* Call ehci_sendup_itd_message to send message to upstream */
1273 	ehci_sendup_itd_message(ehcip, pp, itw, itd, USB_CR_OK);
1274 
1275 	/* Deallocate this transfer descriptor */
1276 	ehci_deallocate_itd(ehcip, itw, itd);
1277 
1278 	/*
1279 	 * If isochronous pipe state is still active, insert next isochronous
1280 	 * request into the Host Controller's isochronous list.
1281 	 */
1282 	if (pp->pp_state != EHCI_PIPE_STATE_ACTIVE) {
1283 
1284 		return;
1285 	}
1286 
1287 	if ((error = ehci_allocate_isoc_in_resource(ehcip, pp, itw, 0)) ==
1288 	    USB_SUCCESS) {
1289 		curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
1290 
1291 		ASSERT(curr_isoc_reqp != NULL);
1292 
1293 		itw->itw_num_itds = ehci_calc_num_itds(itw,
1294 		    curr_isoc_reqp->isoc_pkts_count);
1295 
1296 		if (ehci_allocate_itds_for_itw(ehcip, itw, itw->itw_num_itds) !=
1297 		    USB_SUCCESS) {
1298 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
1299 			itw->itw_num_itds = 0;
1300 			error = USB_FAILURE;
1301 		}
1302 	}
1303 
1304 	if ((error != USB_SUCCESS) ||
1305 	    (ehci_insert_isoc_req(ehcip, pp, itw, 0) != USB_SUCCESS)) {
1306 		/*
1307 		 * Set pipe state to stop polling and error to no
1308 		 * resource. Don't insert any more isoch polling
1309 		 * requests.
1310 		 */
1311 		pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING;
1312 		pp->pp_error = USB_CR_NO_RESOURCES;
1313 
1314 	} else {
1315 		/* Increment number of IN isochronous request count */
1316 		pp->pp_cur_periodic_req_cnt++;
1317 
1318 		ASSERT(pp->pp_cur_periodic_req_cnt ==
1319 		    pp->pp_max_periodic_req_cnt);
1320 	}
1321 }
1322 
1323 
1324 /*
1325  * ehci_sendup_qtd_message:
1326  *	copy data, if necessary and do callback
1327  */
1328 /* ARGSUSED */
1329 static void
1330 ehci_sendup_itd_message(
1331 	ehci_state_t		*ehcip,
1332 	ehci_pipe_private_t	*pp,
1333 	ehci_isoc_xwrapper_t	*itw,
1334 	ehci_itd_t		*td,
1335 	usb_cr_t		error)
1336 {
1337 	usb_isoc_req_t		*isoc_reqp = itw->itw_curr_xfer_reqp;
1338 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1339 	size_t			length;
1340 	uchar_t			*buf;
1341 	mblk_t			*mp;
1342 
1343 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1344 
1345 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1346 	    "ehci_sendup_itd_message:");
1347 
1348 	ASSERT(itw != NULL);
1349 
1350 	length = itw->itw_length;
1351 
1352 	/* Copy the data into the mblk_t */
1353 	buf = (uchar_t *)itw->itw_buf;
1354 
1355 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1356 	    "ehci_sendup_itd_message: length %d error %d", length, error);
1357 
1358 	/* Get the message block */
1359 	mp = isoc_reqp->isoc_data;
1360 
1361 	ASSERT(mp != NULL);
1362 
1363 	if (length) {
1364 		/* Sync IO buffer */
1365 		Sync_IO_Buffer(itw->itw_dmahandle, length);
1366 
1367 		/* Copy the data into the message */
1368 		ddi_rep_get8(itw->itw_accesshandle,
1369 		    mp->b_rptr, buf, length, DDI_DEV_AUTOINCR);
1370 
1371 		/* Increment the write pointer */
1372 		mp->b_wptr = mp->b_wptr + length;
1373 	} else {
1374 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1375 		    "ehci_sendup_itd_message: Zero length packet");
1376 	}
1377 
1378 	ehci_hcdi_isoc_callback(ph, itw, error);
1379 }
1380 
1381 
1382 /*
1383  * ehci_hcdi_isoc_callback:
1384  *
1385  * Convenience wrapper around usba_hcdi_cb() other than root hub.
1386  */
1387 void
1388 ehci_hcdi_isoc_callback(
1389 	usba_pipe_handle_data_t	*ph,
1390 	ehci_isoc_xwrapper_t	*itw,
1391 	usb_cr_t		completion_reason)
1392 {
1393 	ehci_state_t		*ehcip = ehci_obtain_state(
1394 				    ph->p_usba_device->usb_root_hub_dip);
1395 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
1396 	usb_opaque_t		curr_xfer_reqp;
1397 	uint_t			pipe_state = 0;
1398 
1399 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
1400 	    "ehci_hcdi_isoc_callback: ph = 0x%p, itw = 0x%p, cr = 0x%x",
1401 	    (void *)ph, itw, completion_reason);
1402 
1403 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1404 
1405 	/* Set the pipe state as per completion reason */
1406 	switch (completion_reason) {
1407 	case USB_CR_OK:
1408 		pipe_state = pp->pp_state;
1409 		break;
1410 	case USB_CR_NO_RESOURCES:
1411 	case USB_CR_NOT_SUPPORTED:
1412 	case USB_CR_PIPE_RESET:
1413 	case USB_CR_STOPPED_POLLING:
1414 		pipe_state = EHCI_PIPE_STATE_IDLE;
1415 		break;
1416 	case USB_CR_PIPE_CLOSING:
1417 		break;
1418 	}
1419 
1420 	pp->pp_state = pipe_state;
1421 
1422 	if (itw && itw->itw_curr_xfer_reqp) {
1423 		curr_xfer_reqp = (usb_opaque_t)itw->itw_curr_xfer_reqp;
1424 		itw->itw_curr_xfer_reqp = NULL;
1425 	} else {
1426 		ASSERT(pp->pp_client_periodic_in_reqp != NULL);
1427 
1428 		curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
1429 		pp->pp_client_periodic_in_reqp = NULL;
1430 	}
1431 
1432 	ASSERT(curr_xfer_reqp != NULL);
1433 
1434 	mutex_exit(&ehcip->ehci_int_mutex);
1435 
1436 	usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
1437 
1438 	mutex_enter(&ehcip->ehci_int_mutex);
1439 }
1440