xref: /illumos-gate/usr/src/uts/common/io/usb/usba/usbai_req.c (revision 60405de4d8688d96dd05157c28db3ade5c9bc234)
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  * USBA: Solaris USB Architecture support
30  *
31  * functions that deal with allocation/free/data_xfers
32  * for the  control/bulk/interrupt/isoch pipes:
33  *	usb_alloc_ctrl_req()
34  *	usb_free_ctrl_req()
35  *	usb_pipe_ctrl_xfer()
36  *	usb_pipe_sync_ctrl_xfer()
37  *	usb_pipe_ctrl_xfer_wait()
38  *
39  *	usb_alloc_bulk_req()
40  *	usb_free_bulk_req()
41  *	usb_pipe_bulk_xfer()
42  *	usb_pipe_bulk_transfer_size()
43  *
44  *	usb_alloc_intr_req()
45  *	usb_free_intr_req()
46  *	usb_pipe_intr_xfer()
47  *	usb_pipe_stop_intr_polling()
48  *
49  *	usb_alloc_isoc_req()
50  *	usb_free_isoc_req()
51  *	usb_get_current_frame_number()
52  *	usb_get_max_isoc_pkts()
53  *	usb_pipe_isoc_xfer()
54  *	usb_pipe_stop_isoc_polling()
55  *
56  * XXX to do:
57  *	update return values where needed
58  *	keep track of requests not freed
59  *
60  */
61 #define	USBA_FRAMEWORK
62 #include <sys/usb/usba/usba_impl.h>
63 #include <sys/usb/usba/hcdi_impl.h>
64 #include <sys/strsubr.h>
65 
66 /* prototypes */
67 static int usba_flags_attr_check(usba_pipe_handle_data_t *,
68 			usb_req_attrs_t attrs, usb_flags_t);
69 static int _usba_check_req(usba_pipe_handle_data_t *, usb_opaque_t,
70 			usb_flags_t, uchar_t);
71 
72 /*
73  * usba_check_req:
74  *	check pipe, request structure for validity
75  *
76  * Arguments:
77  *	ph		- pipe handle pointer
78  *	req		- opaque request pointer
79  *	flags		- usb flags
80  *
81  * Returns:
82  *	USB_SUCCESS		- valid request
83  *	USB_INVALID_REQUEST	- request contains some invalid values
84  *	USB_PIPE_ERROR		- pipe is in error state
85  *	USB_INVALID_CONTEXT	- sleep in interrupt context
86  *	USB_INVALID_PIPE	- zero pipe or wrong pipe
87  */
88 static int
89 usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req,
90 		usb_flags_t flags, uchar_t pipe_type)
91 {
92 	int rval = _usba_check_req(ph_data, req, flags, pipe_type);
93 
94 	if (rval != USB_SUCCESS) {
95 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
96 		    "usba_check_req: ph_data=0x%p req=0x%p flags=0%x rval=%d",
97 		    ph_data, req, flags, rval);
98 	}
99 
100 	return (rval);
101 }
102 
103 
104 static int
105 _usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req,
106 		usb_flags_t flags, uchar_t pipe_type)
107 {
108 	usb_ctrl_req_t		*ctrl_req = (usb_ctrl_req_t *)req;
109 	usb_bulk_req_t		*bulk_req = (usb_bulk_req_t *)req;
110 	usb_intr_req_t		*intr_req = (usb_intr_req_t *)req;
111 	usb_isoc_req_t		*isoc_req = (usb_isoc_req_t *)req;
112 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
113 	mblk_t			*data;
114 	usb_cr_t		*cr;
115 	usb_req_attrs_t		attrs;
116 	usb_opaque_t		cb, exc_cb;
117 	uint_t			timeout = 0;
118 	uchar_t			direction = ph_data->p_ep.bEndpointAddress &
119 							USB_EP_DIR_MASK;
120 	uchar_t			ep_attrs = ph_data->p_ep.bmAttributes &
121 							USB_EP_ATTR_MASK;
122 	int			n;
123 
124 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
125 	    "usba_check_req: ph_data=0x%p req=0x%p flags=0x%x",
126 	    ph_data, req, flags);
127 
128 	if (req == NULL) {
129 
130 		return (USB_INVALID_ARGS);
131 	}
132 
133 	/* set completion reason first so it specifies an error */
134 	switch (ep_attrs) {
135 	case USB_EP_ATTR_CONTROL:
136 		cr = &ctrl_req->ctrl_completion_reason;
137 		break;
138 	case USB_EP_ATTR_BULK:
139 		cr = &bulk_req->bulk_completion_reason;
140 		break;
141 	case USB_EP_ATTR_INTR:
142 		cr = &intr_req->intr_completion_reason;
143 		break;
144 	case USB_EP_ATTR_ISOCH:
145 		cr = &isoc_req->isoc_completion_reason;
146 		break;
147 	}
148 
149 	*cr = USB_CR_UNSPECIFIED_ERR;
150 
151 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
152 
153 		return (USB_INVALID_CONTEXT);
154 	}
155 
156 	if (pipe_type != ep_attrs) {
157 
158 		return (USB_INVALID_PIPE);
159 	}
160 
161 	/* we must have usba_device and default ph to do autoclearing */
162 	ASSERT(ph_data->p_usba_device);
163 
164 	if (ph_data->p_usba_device->usb_ph_list[0].usba_ph_data == NULL) {
165 
166 		return (USB_INVALID_PIPE);
167 	}
168 
169 	/* check if this is a valid request packet, ie. not freed */
170 	if (usba_check_in_list(&(ph_data->p_usba_device->usb_allocated),
171 	    &wrp->wr_allocated_list) != USB_SUCCESS) {
172 
173 		return (USB_INVALID_REQUEST);
174 	}
175 
176 	/* copy over some members for easy checking later */
177 	switch (ep_attrs) {
178 	case USB_EP_ATTR_CONTROL:
179 		ctrl_req->ctrl_cb_flags = USB_CB_NO_INFO;
180 		data = ctrl_req->ctrl_data;
181 		attrs = ctrl_req->ctrl_attributes;
182 		timeout = ctrl_req->ctrl_timeout;
183 		cb = (usb_opaque_t)ctrl_req->ctrl_cb;
184 		exc_cb = (usb_opaque_t)ctrl_req->ctrl_exc_cb;
185 		if (flags & USB_FLAGS_SLEEP) {
186 			flags |= USBA_WRP_FLAGS_WAIT;
187 		}
188 		/* force auto clearing on the default pipe */
189 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
190 			attrs |= USB_ATTRS_AUTOCLEARING;
191 		}
192 		break;
193 	case USB_EP_ATTR_BULK:
194 		bulk_req->bulk_cb_flags = USB_CB_NO_INFO;
195 		data = bulk_req->bulk_data;
196 		attrs = bulk_req->bulk_attributes;
197 		timeout = bulk_req->bulk_timeout;
198 		cb = (usb_opaque_t)bulk_req->bulk_cb;
199 		exc_cb = (usb_opaque_t)bulk_req->bulk_exc_cb;
200 		if (flags & USB_FLAGS_SLEEP) {
201 			flags |= USBA_WRP_FLAGS_WAIT;
202 		}
203 		break;
204 	case USB_EP_ATTR_INTR:
205 		intr_req->intr_cb_flags = USB_CB_NO_INFO;
206 		data = intr_req->intr_data;
207 		attrs = intr_req->intr_attributes;
208 		timeout = intr_req->intr_timeout;
209 		cb = (usb_opaque_t)intr_req->intr_cb;
210 		exc_cb = (usb_opaque_t)intr_req->intr_exc_cb;
211 		if ((flags & USB_FLAGS_SLEEP) &&
212 		    (attrs & USB_ATTRS_ONE_XFER)) {
213 			flags |= USBA_WRP_FLAGS_WAIT;
214 		}
215 		break;
216 	case USB_EP_ATTR_ISOCH:
217 		isoc_req->isoc_cb_flags = USB_CB_NO_INFO;
218 		data = isoc_req->isoc_data;
219 		attrs = isoc_req->isoc_attributes;
220 		cb = (usb_opaque_t)isoc_req->isoc_cb;
221 		exc_cb = (usb_opaque_t)isoc_req->isoc_exc_cb;
222 		break;
223 	}
224 
225 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
226 	    "usba_check_req: attrs = 0x%x flags=0x%x", attrs, flags);
227 
228 	/* check flags and attr combinations */
229 	if (usba_flags_attr_check(ph_data, attrs, flags) !=
230 	    USB_SUCCESS) {
231 
232 		return (USB_INVALID_REQUEST);
233 	}
234 
235 	/* if no sleep, there must be callback ptrs */
236 	if ((flags & USB_FLAGS_SLEEP) == 0) {
237 		if (cb == NULL || exc_cb == NULL) {
238 
239 			return (USB_INVALID_REQUEST);
240 		}
241 	}
242 
243 	switch (ep_attrs) {
244 	case USB_EP_ATTR_CONTROL:
245 		if (ctrl_req->ctrl_wLength && (data == NULL)) {
246 
247 			return (USB_INVALID_REQUEST);
248 		}
249 		break;
250 	case USB_EP_ATTR_BULK:
251 		if ((bulk_req->bulk_len) && (data == NULL)) {
252 
253 			return (USB_INVALID_REQUEST);
254 		}
255 		break;
256 	case USB_EP_ATTR_INTR:
257 		if (direction == USB_EP_DIR_OUT) {
258 			if (intr_req->intr_len && data == NULL) {
259 
260 				return (USB_INVALID_REQUEST);
261 			}
262 		}
263 
264 		if (direction == USB_EP_DIR_IN) {
265 			if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER)) {
266 				if (cb == NULL || exc_cb == NULL) {
267 
268 					return (USB_INVALID_REQUEST);
269 				}
270 			}
271 			if (data != NULL) {
272 
273 				return (USB_INVALID_REQUEST);
274 			}
275 			if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER) &&
276 			    (timeout > 0)) {
277 
278 				return (USB_INVALID_REQUEST);
279 			}
280 		}
281 		break;
282 	case USB_EP_ATTR_ISOCH:
283 		if (direction == USB_EP_DIR_IN) {
284 			if (cb == NULL || exc_cb == NULL) {
285 
286 				return (USB_INVALID_REQUEST);
287 			}
288 
289 			if (isoc_req->isoc_pkts_length == 0) {
290 
291 				return (USB_INVALID_REQUEST);
292 			}
293 		}
294 
295 		if (data == NULL) {
296 
297 			return (USB_INVALID_REQUEST);
298 		}
299 
300 		/*
301 		 * Since ehci/ohci/uhci use (data->b_wptr - data->b_rptr) as
302 		 * real isoc_pkts_length, it should be checked.
303 		 */
304 		if (direction == USB_EP_DIR_OUT) {
305 			if ((data->b_wptr - data->b_rptr) <= 0) {
306 
307 				return (USB_INVALID_REQUEST);
308 			}
309 		}
310 
311 		/* special isoc checks */
312 		if ((isoc_req->isoc_pkts_count == 0) ||
313 		    (isoc_req->isoc_pkt_descr == NULL)) {
314 
315 			return (USB_INVALID_REQUEST);
316 		}
317 
318 		/* check attributes for conflicts, one must be specified */
319 		if (!((isoc_req->isoc_attributes &
320 		    USB_ATTRS_ISOC_START_FRAME) ||
321 		    (isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP))) {
322 
323 			return (USB_NO_FRAME_NUMBER);
324 		}
325 
326 		/* both may not be specified */
327 		if ((isoc_req->isoc_attributes &
328 		    (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) ==
329 		    (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) {
330 
331 			return (USB_NO_FRAME_NUMBER);
332 		}
333 
334 		/* no start frame may be specified for ASAP attribute */
335 		if (((isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP)) &&
336 		    isoc_req->isoc_frame_no) {
337 
338 			return (USB_INVALID_REQUEST);
339 		}
340 
341 		/* start frame must be specified for START FRAME attribute */
342 		if (((isoc_req->isoc_attributes &
343 		    USB_ATTRS_ISOC_START_FRAME)) &&
344 		    (isoc_req->isoc_frame_no == 0)) {
345 
346 			return (USB_NO_FRAME_NUMBER);
347 		}
348 
349 		/* each packet must have initialized pkt length */
350 		for (n = 0; n < isoc_req->isoc_pkts_count; n++) {
351 			if (isoc_req->isoc_pkt_descr[n].isoc_pkt_length == 0) {
352 
353 				return (USB_INVALID_REQUEST);
354 			}
355 		}
356 		break;
357 	}
358 
359 	/* save pipe_handle/attrs/timeout/usb_flags */
360 	wrp->wr_ph_data		= ph_data;
361 	wrp->wr_usb_flags	= flags;
362 	wrp->wr_attrs		= attrs;
363 
364 	/* zero some fields in case the request is reused */
365 	wrp->wr_done		= B_FALSE;
366 	wrp->wr_cr		= USB_CR_OK;
367 
368 	/* this request looks good */
369 	*cr = USB_CR_OK;
370 
371 	return (USB_SUCCESS);
372 }
373 
374 
375 /*
376  * Table of invalid flags and attributes values. See "usbai.h"
377  * for a complete table on valid usb_req_attrs_t
378  */
379 #define	X	((uint_t)(-1))
380 #define	OUT	USB_EP_DIR_OUT
381 #define	IN	USB_EP_DIR_IN
382 
383 struct	flags_attr {
384 	uint_t		ep_dir;
385 	uint_t		ep_attr;
386 	uint_t		usb_flags;	/* usb_flags SLEEP or none */
387 	uint_t		attrs;
388 } usb_invalid_flags_attrs[] = {
389 { OUT,	USB_EP_ATTR_BULK,	X,	USB_ATTRS_SHORT_XFER_OK },
390 { OUT,	USB_EP_ATTR_INTR,	X,	USB_ATTRS_SHORT_XFER_OK },
391 { OUT,	USB_EP_ATTR_ISOCH,	X,	USB_ATTRS_SHORT_XFER_OK },
392 
393 { X,	USB_EP_ATTR_CONTROL,	X,	USB_ATTRS_ISOC_START_FRAME },
394 { X,	USB_EP_ATTR_BULK,	X,	USB_ATTRS_ISOC_START_FRAME },
395 { X,	USB_EP_ATTR_INTR,	X,	USB_ATTRS_ISOC_START_FRAME },
396 
397 { X,	USB_EP_ATTR_CONTROL,	X,	USB_ATTRS_ISOC_XFER_ASAP },
398 { X,	USB_EP_ATTR_INTR,	X,	USB_ATTRS_ISOC_XFER_ASAP },
399 { OUT,	USB_EP_ATTR_INTR,	X,	USB_ATTRS_ONE_XFER },
400 { X,	USB_EP_ATTR_BULK,	X,	USB_ATTRS_ISOC_XFER_ASAP },
401 
402 { X,	USB_EP_ATTR_CONTROL,	X,	USB_ATTRS_ONE_XFER },
403 { X,	USB_EP_ATTR_BULK,	X,	USB_ATTRS_ONE_XFER },
404 { X,	USB_EP_ATTR_ISOCH,	X,	USB_ATTRS_ONE_XFER },
405 };
406 
407 #define	N_INVALID_FLAGS_ATTRS	(sizeof (usb_invalid_flags_attrs))/ \
408 					sizeof (struct flags_attr)
409 
410 /*
411  * function to check flags and attribute combinations for a particular pipe
412  * Arguments:
413  *	ph	- pipe handle pointer
414  *	attrs	- attributes of the request
415  *	flags	- usb_flags
416  */
417 static int
418 usba_flags_attr_check(usba_pipe_handle_data_t *ph_data,
419 		usb_req_attrs_t attrs,
420 		usb_flags_t flags)
421 {
422 	uchar_t i;
423 	uchar_t	ep_dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
424 	uchar_t ep_attr = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
425 
426 	flags &= USB_FLAGS_SLEEP; /* ignore other flags */
427 
428 	/*
429 	 * Do some attributes validation checks here.
430 	 */
431 	for (i = 0; i < N_INVALID_FLAGS_ATTRS; i++) {
432 		if (((ep_dir == usb_invalid_flags_attrs[i].ep_dir) ||
433 			(usb_invalid_flags_attrs[i].ep_dir == X)) &&
434 		    ((ep_attr == usb_invalid_flags_attrs[i].ep_attr) ||
435 			(usb_invalid_flags_attrs[i].ep_attr == X)) &&
436 		    ((flags & usb_invalid_flags_attrs[i].usb_flags) ||
437 			(usb_invalid_flags_attrs[i].usb_flags == X)) &&
438 		    ((attrs & usb_invalid_flags_attrs[i].attrs) ||
439 			(usb_invalid_flags_attrs[i].attrs == X))) {
440 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
441 			    "invalid (%d) : flags = 0x%x, attrs = 0x%x",
442 			    i, flags, attrs);
443 
444 			return (USB_INVALID_REQUEST);
445 		}
446 	}
447 
448 	return (USB_SUCCESS);
449 }
450 
451 
452 /*
453  * usba_rval2cr:
454  *	convert rval to meaningful completion reason
455  * XXX extend completion reasons to get better mapping
456  */
457 static struct {
458 	int	rval;
459 	usb_cr_t cr;
460 } rval2cr[] = {
461 	{USB_SUCCESS,		USB_CR_OK},
462 	{USB_FAILURE,		USB_CR_UNSPECIFIED_ERR},
463 	{USB_NO_RESOURCES,	USB_CR_NO_RESOURCES},
464 	{USB_NO_BANDWIDTH,	USB_CR_NO_RESOURCES},
465 	{USB_NOT_SUPPORTED,	USB_CR_UNSPECIFIED_ERR},
466 	{USB_PIPE_ERROR,	USB_CR_UNSPECIFIED_ERR},
467 	{USB_INVALID_PIPE,	USB_CR_UNSPECIFIED_ERR},
468 	{USB_NO_FRAME_NUMBER,	USB_CR_UNSPECIFIED_ERR},
469 	{USB_INVALID_START_FRAME, USB_CR_UNSPECIFIED_ERR},
470 	{USB_HC_HARDWARE_ERROR, USB_CR_UNSPECIFIED_ERR},
471 	{USB_INVALID_REQUEST,	USB_CR_UNSPECIFIED_ERR},
472 	{USB_INVALID_CONTEXT,	USB_CR_UNSPECIFIED_ERR},
473 	{USB_INVALID_VERSION,	USB_CR_UNSPECIFIED_ERR},
474 	{USB_INVALID_ARGS,	USB_CR_UNSPECIFIED_ERR},
475 	{USB_INVALID_PERM,	USB_CR_UNSPECIFIED_ERR},
476 	{USB_BUSY,		USB_CR_UNSPECIFIED_ERR},
477 	{0xffff,		0}
478 };
479 
480 usb_cr_t
481 usba_rval2cr(int rval)
482 {
483 	int i;
484 
485 	for (i = 0; rval2cr[i].rval != 0xffff; i++) {
486 		if (rval2cr[i].rval == rval) {
487 
488 			return (rval2cr[i].cr);
489 		}
490 	}
491 
492 	return (USB_CR_UNSPECIFIED_ERR);
493 }
494 
495 
496 /*
497  * usba_start_next_req:
498  *	Arguments:
499  *	ph_data		- pointer to pipe handle
500  *
501  * Currently, only ctrl/bulk requests can be queued
502  */
503 void
504 usba_start_next_req(usba_pipe_handle_data_t *ph_data)
505 {
506 	usb_ctrl_req_t		*ctrl_req;
507 	usb_bulk_req_t		*bulk_req;
508 	usba_req_wrapper_t	*wrp;
509 	uchar_t			ep_attrs = ph_data->p_ep.bmAttributes &
510 							USB_EP_ATTR_MASK;
511 	int			rval;
512 	usb_pipe_state_t	state;
513 
514 	mutex_enter(&ph_data->p_mutex);
515 	switch (ep_attrs) {
516 	case USB_EP_ATTR_CONTROL:
517 	case USB_EP_ATTR_BULK:
518 		switch (usba_get_ph_state(ph_data)) {
519 		case USB_PIPE_STATE_IDLE:
520 		case USB_PIPE_STATE_CLOSING:
521 
522 			break;
523 
524 		default:
525 			mutex_exit(&ph_data->p_mutex);
526 
527 			return;
528 		}
529 
530 		break;
531 	case USB_EP_ATTR_ISOCH:
532 	case USB_EP_ATTR_INTR:
533 	default:
534 		mutex_exit(&ph_data->p_mutex);
535 
536 		return;
537 	}
538 
539 	while ((wrp = (usba_req_wrapper_t *)
540 	    usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
541 
542 		/* only submit to HCD when idle/active */
543 
544 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
545 		    "usba_start_next_req: ph_data=0x%p state=%d", ph_data,
546 		    usba_get_ph_state(ph_data));
547 
548 		if (ep_attrs == USB_EP_ATTR_CONTROL) {
549 			ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp;
550 		}
551 
552 		if ((state = usba_get_ph_state(ph_data)) ==
553 		    USB_PIPE_STATE_IDLE) {
554 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
555 
556 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
557 			    "starting req = 0x%p", USBA_WRP2CTRL_REQ(wrp));
558 
559 			switch (ep_attrs) {
560 			case USB_EP_ATTR_CONTROL:
561 				mutex_exit(&ph_data->p_mutex);
562 				ctrl_req = USBA_WRP2CTRL_REQ(wrp);
563 				/* submit to hcd */
564 				rval = ph_data->p_usba_device->usb_hcdi_ops->
565 				    usba_hcdi_pipe_ctrl_xfer(ph_data,
566 				    ctrl_req, wrp->wr_usb_flags);
567 				mutex_enter(&ph_data->p_mutex);
568 				break;
569 			case USB_EP_ATTR_BULK:
570 				mutex_exit(&ph_data->p_mutex);
571 				bulk_req = USBA_WRP2BULK_REQ(wrp);
572 				/* submit to hcd */
573 				rval = ph_data->p_usba_device->usb_hcdi_ops->
574 				    usba_hcdi_pipe_bulk_xfer(ph_data,
575 				    bulk_req, wrp->wr_usb_flags);
576 				mutex_enter(&ph_data->p_mutex);
577 				break;
578 			default:
579 				/* there shouldn't be any requests */
580 				rval = USB_FAILURE;
581 				break;
582 			}
583 
584 			if (rval != USB_SUCCESS) {
585 				mutex_exit(&ph_data->p_mutex);
586 				usba_do_req_exc_cb(wrp,
587 				    usba_rval2cr(rval),
588 				    USB_CB_SUBMIT_FAILED);
589 				mutex_enter(&ph_data->p_mutex);
590 			}
591 			/* we are done */
592 			break;
593 
594 		} else {
595 			mutex_exit(&ph_data->p_mutex);
596 			switch (state) {
597 			case USB_PIPE_STATE_CLOSING:
598 				usba_do_req_exc_cb(wrp, USB_CR_PIPE_CLOSING, 0);
599 				break;
600 			case USB_PIPE_STATE_ERROR:
601 			default:
602 				usba_do_req_exc_cb(wrp, USB_CR_FLUSHED, 0);
603 				break;
604 			}
605 			mutex_enter(&ph_data->p_mutex);
606 		}
607 	}
608 
609 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
610 	    "usba_start_next_req done: ph_data=0x%p state=%d", ph_data,
611 	    usba_get_ph_state(ph_data));
612 
613 	mutex_exit(&ph_data->p_mutex);
614 }
615 
616 
617 /*
618  * usba_req_wrapper_alloc:
619  *	Allocate + Initialize a usba_req_wrapper_t
620  *
621  * Arguments:
622  *	dip	-  dev_info_t of the client driver
623  *	req_len	-  sizeof request
624  *	flags	-
625  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
626  *		no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
627  *
628  * Return Values:
629  *	pointer to usba_req_wrapper_t on success; NULL on failure.
630  *
631  */
632 static usba_req_wrapper_t *
633 usba_req_wrapper_alloc(dev_info_t	*dip,
634 			size_t		req_len,
635 			usb_flags_t	flags)
636 {
637 	int		kmflag;
638 	usba_device_t	*usba_device = usba_get_usba_device(dip);
639 	usba_req_wrapper_t *wrp;
640 	size_t		wr_length = sizeof (usba_req_wrapper_t) + req_len;
641 	ddi_iblock_cookie_t iblock_cookie =
642 		usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
643 		hcdi_iblock_cookie;
644 
645 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
646 
647 		return (NULL);
648 	}
649 
650 	kmflag = (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
651 
652 	/* Allocate the usb_{c/b/i/i}_req + usba_req_wrapper_t structure */
653 	if ((wrp = kmem_zalloc(wr_length, kmflag)) != NULL) {
654 		wrp->wr_length	= wr_length;
655 		wrp->wr_dip	= dip;
656 		wrp->wr_req = (usb_opaque_t)USBA_SETREQ_ADDR(wrp);
657 		cv_init(&wrp->wr_cv, NULL, CV_DRIVER, NULL);
658 
659 		/* initialize mutex for the queue */
660 		usba_init_list(&wrp->wr_queue, (usb_opaque_t)wrp,
661 						iblock_cookie);
662 		usba_init_list(&wrp->wr_allocated_list, (usb_opaque_t)wrp,
663 						iblock_cookie);
664 
665 		usba_add_to_list(&usba_device->usb_allocated,
666 		    &wrp->wr_allocated_list);
667 
668 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
669 		    "usba_req_wrapper_alloc: wrp = 0x%p", wrp);
670 	}
671 
672 	return (wrp);
673 }
674 
675 
676 /*
677  * usba_req_wrapper_free:
678  *	Frees a usba_req_wrapper_t. Get rid of lists if any.
679  *
680  * Arguments:
681  *	wrp: request wrapper structure
682  */
683 void
684 usba_req_wrapper_free(usba_req_wrapper_t *wrp)
685 {
686 	usba_device_t		*usba_device;
687 	usba_pipe_handle_data_t	*ph_data;
688 
689 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
690 	    "usba_req_wrapper_free: wrp=0x%p", wrp);
691 
692 	if (wrp) {
693 		/* remove from	queues */
694 		ph_data = USBA_WRP2PH_DATA(wrp);
695 		if (ph_data) {
696 			(void) usba_rm_from_list(&ph_data->p_queue,
697 							&wrp->wr_queue);
698 		}
699 		usba_device = usba_get_usba_device(wrp->wr_dip);
700 		if (usba_rm_from_list(&usba_device->usb_allocated,
701 		    &wrp->wr_allocated_list) != USB_SUCCESS) {
702 			cmn_err(CE_PANIC,
703 			    "usba_req_wrapper_free: data corruption");
704 		}
705 		usba_destroy_list(&wrp->wr_queue);
706 		usba_destroy_list(&wrp->wr_allocated_list);
707 		cv_destroy(&wrp->wr_cv);
708 		kmem_free(wrp, wrp->wr_length);
709 	}
710 }
711 
712 
713 /*
714  * usba_check_intr_context
715  *	Set USB_CB_INTR_CONTEXT callback flag if executing in interrupt context
716  */
717 usb_cb_flags_t
718 usba_check_intr_context(usb_cb_flags_t cb_flags)
719 {
720 	if (servicing_interrupt() != 0) {
721 		cb_flags |= USB_CB_INTR_CONTEXT;
722 	}
723 
724 	return (cb_flags);
725 }
726 
727 
728 /*
729  * usba_req_normal_cb:
730  *	perform normal callback depending on request type
731  */
732 void
733 usba_req_normal_cb(usba_req_wrapper_t *req_wrp)
734 {
735 	usba_pipe_handle_data_t	*ph_data = req_wrp->wr_ph_data;
736 	usb_pipe_handle_t	pipe_handle;
737 	uint_t			direction = ph_data->p_ep.bEndpointAddress &
738 							USB_EP_DIR_MASK;
739 	usb_pipe_state_t	pipe_state;
740 
741 	pipe_handle = usba_get_pipe_handle(ph_data);
742 
743 	mutex_enter(&ph_data->p_mutex);
744 	ASSERT(ph_data->p_req_count >= 0);
745 	pipe_state = usba_get_ph_state(ph_data);
746 
747 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
748 	    "usba_req_normal_cb: "
749 	    "ph_data=0x%p state=%d wrp=0x%p ref=%d req=%d",
750 	    ph_data, pipe_state, req_wrp, usba_get_ph_ref_count(ph_data),
751 	    ph_data->p_req_count);
752 
753 	ASSERT((pipe_state == USB_PIPE_STATE_ACTIVE) ||
754 	    (pipe_state == USB_PIPE_STATE_CLOSING));
755 
756 	/* set done to indicate that we will do callback or cv_signal */
757 	ASSERT(req_wrp->wr_done == B_FALSE);
758 	req_wrp->wr_done = B_TRUE;
759 
760 	/* update the pipe state */
761 	switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
762 	    USB_EP_ATTR_MASK) {
763 	case USB_EP_ATTR_CONTROL:
764 	case USB_EP_ATTR_BULK:
765 		usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
766 		break;
767 	case USB_EP_ATTR_INTR:
768 		if ((direction == USB_EP_DIR_IN) &&
769 		    (USBA_WRP2INTR_REQ(req_wrp)->intr_attributes &
770 		    USB_ATTRS_ONE_XFER)) {
771 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
772 		} else if ((direction == USB_EP_DIR_OUT) &&
773 		    (ph_data->p_req_count == 0)) {
774 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
775 		}
776 		break;
777 	case USB_EP_ATTR_ISOCH:
778 		if ((ph_data->p_req_count == 0) &&
779 		    (direction == USB_EP_DIR_OUT)) {
780 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
781 		}
782 		break;
783 	}
784 
785 
786 	/* now complete the request */
787 	if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) {
788 		ph_data->p_active_cntrl_req_wrp = NULL;
789 		cv_signal(&req_wrp->wr_cv);
790 		mutex_exit(&ph_data->p_mutex);
791 	} else {
792 		mutex_exit(&ph_data->p_mutex);
793 
794 		/* This sets USB_CB_INTR_CONTEXT as needed. */
795 		usba_req_set_cb_flags(req_wrp, USB_CB_NO_INFO);
796 
797 		switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
798 		    USB_EP_ATTR_MASK) {
799 		case USB_EP_ATTR_CONTROL:
800 			USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb(pipe_handle,
801 						USBA_WRP2CTRL_REQ(req_wrp));
802 			mutex_enter(&ph_data->p_mutex);
803 			ph_data->p_active_cntrl_req_wrp = NULL;
804 			mutex_exit(&ph_data->p_mutex);
805 			break;
806 		case USB_EP_ATTR_INTR:
807 			USBA_WRP2INTR_REQ(req_wrp)->intr_cb(pipe_handle,
808 						USBA_WRP2INTR_REQ(req_wrp));
809 			break;
810 		case USB_EP_ATTR_BULK:
811 			USBA_WRP2BULK_REQ(req_wrp)->bulk_cb(pipe_handle,
812 						USBA_WRP2BULK_REQ(req_wrp));
813 			break;
814 		case USB_EP_ATTR_ISOCH:
815 			USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb(pipe_handle,
816 						USBA_WRP2ISOC_REQ(req_wrp));
817 			break;
818 		}
819 	}
820 
821 	/* we are done with this request */
822 	mutex_enter(&ph_data->p_mutex);
823 	ph_data->p_req_count--;
824 	ASSERT(ph_data->p_req_count >= 0);
825 	mutex_exit(&ph_data->p_mutex);
826 }
827 
828 
829 /*
830  * usba_req_exc_cb:
831  *	perform exception cb depending on request type.
832  *	ensure the completion reason is non zero
833  */
834 void
835 usba_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr,
836     usb_cb_flags_t cb_flags)
837 {
838 	usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
839 	usb_pipe_handle_t pipe_handle = usba_get_pipe_handle(ph_data);
840 
841 	mutex_enter(&req_wrp->wr_ph_data->p_mutex);
842 	USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
843 	    "usba_req_exc_cb: %s%d: ph_data=0x%p (ep%x) state=%d wrp=0x%p "
844 	    "ref=%d reqcnt=%d cr=%d",
845 	    ddi_driver_name(req_wrp->wr_dip),
846 	    ddi_get_instance(req_wrp->wr_dip),
847 	    ph_data, ph_data->p_ep.bEndpointAddress,
848 	    usba_get_ph_state(ph_data), req_wrp, usba_get_ph_ref_count(ph_data),
849 	    ph_data->p_req_count, req_wrp->wr_cr);
850 
851 	ASSERT(req_wrp->wr_ph_data->p_req_count >= 0);
852 
853 	usba_req_set_cb_flags(req_wrp, cb_flags);
854 
855 	/* if there was no CR set already, set it now */
856 	if (req_wrp->wr_cr == USB_CR_OK) {
857 		req_wrp->wr_cr = (cr != USB_CR_OK)  ?
858 				cr : USB_CR_UNSPECIFIED_ERR;
859 	}
860 
861 	ASSERT(req_wrp->wr_done == B_FALSE);
862 	req_wrp->wr_done = B_TRUE;
863 
864 	switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
865 	    USB_EP_ATTR_MASK) {
866 	case USB_EP_ATTR_CONTROL:
867 		if (USBA_WRP2CTRL_REQ(req_wrp)->
868 		    ctrl_completion_reason == USB_CR_OK) {
869 			USBA_WRP2CTRL_REQ(req_wrp)->
870 			    ctrl_completion_reason = req_wrp->wr_cr;
871 		}
872 		break;
873 	case USB_EP_ATTR_INTR:
874 		if (USBA_WRP2INTR_REQ(req_wrp)->
875 		    intr_completion_reason == USB_CR_OK) {
876 			USBA_WRP2INTR_REQ(req_wrp)->
877 			    intr_completion_reason = req_wrp->wr_cr;
878 		}
879 		break;
880 	case USB_EP_ATTR_BULK:
881 		if (USBA_WRP2BULK_REQ(req_wrp)->
882 		    bulk_completion_reason == USB_CR_OK) {
883 			USBA_WRP2BULK_REQ(req_wrp)->
884 			    bulk_completion_reason = req_wrp->wr_cr;
885 		}
886 		break;
887 	case USB_EP_ATTR_ISOCH:
888 		if (USBA_WRP2ISOC_REQ(req_wrp)->
889 		    isoc_completion_reason == USB_CR_OK) {
890 			USBA_WRP2ISOC_REQ(req_wrp)->
891 			    isoc_completion_reason = req_wrp->wr_cr;
892 		}
893 		break;
894 	}
895 
896 	if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) {
897 		cv_signal(&req_wrp->wr_cv);
898 		if (ph_data->p_active_cntrl_req_wrp == (usb_opaque_t)req_wrp) {
899 			ph_data->p_active_cntrl_req_wrp = NULL;
900 		}
901 		mutex_exit(&ph_data->p_mutex);
902 	} else {
903 		mutex_exit(&ph_data->p_mutex);
904 		switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
905 		    USB_EP_ATTR_MASK) {
906 		case USB_EP_ATTR_CONTROL:
907 			USBA_WRP2CTRL_REQ(req_wrp)->ctrl_exc_cb(pipe_handle,
908 						USBA_WRP2CTRL_REQ(req_wrp));
909 			mutex_enter(&ph_data->p_mutex);
910 			if (ph_data->p_active_cntrl_req_wrp ==
911 			    (usb_opaque_t)req_wrp) {
912 				ph_data->p_active_cntrl_req_wrp = NULL;
913 			}
914 			mutex_exit(&ph_data->p_mutex);
915 			break;
916 		case USB_EP_ATTR_INTR:
917 			USBA_WRP2INTR_REQ(req_wrp)->intr_exc_cb(pipe_handle,
918 						USBA_WRP2INTR_REQ(req_wrp));
919 			break;
920 		case USB_EP_ATTR_BULK:
921 			USBA_WRP2BULK_REQ(req_wrp)->bulk_exc_cb(pipe_handle,
922 						USBA_WRP2BULK_REQ(req_wrp));
923 			break;
924 		case USB_EP_ATTR_ISOCH:
925 			USBA_WRP2ISOC_REQ(req_wrp)->isoc_exc_cb(pipe_handle,
926 						USBA_WRP2ISOC_REQ(req_wrp));
927 			break;
928 		}
929 	}
930 
931 	/* we are done with this request */
932 	mutex_enter(&ph_data->p_mutex);
933 	ph_data->p_req_count--;
934 	ASSERT(ph_data->p_req_count >= 0);
935 	mutex_exit(&ph_data->p_mutex);
936 }
937 
938 
939 /*
940  * usba_do_req_exc_cb:
941  *	called when flushing requests. rather than calling usba_req_exc_cb()
942  *	directly, this function uses usba_hcdi_cb() which ensures callback
943  *	order is preserved
944  */
945 void
946 usba_do_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr,
947     usb_cb_flags_t cb_flags)
948 {
949 	req_wrp->wr_cb_flags |= cb_flags;
950 	usba_hcdi_cb(req_wrp->wr_ph_data, req_wrp->wr_req, cr);
951 }
952 
953 
954 /*
955  * usba_req_set_cb_flags:
956  * This function sets the request's callback flags to those stored in the
957  * request wrapper ORed with those received as an argument.  Additionally
958  * USB_CB_INTR_CONTEXT is set if called from interrupt context.
959  *
960  * NOTE: The xfer may have succeeded, which client driver can determine
961  * by looking at usb_cr_t
962  */
963 void
964 usba_req_set_cb_flags(usba_req_wrapper_t *req_wrp,
965 		usb_cb_flags_t cb_flags)
966 {
967 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
968 	    "usba_req_set_cb_flags: wrp=0x%p cb-flags=0x%x",
969 	    req_wrp, cb_flags);
970 
971 	cb_flags |= req_wrp->wr_cb_flags;
972 	cb_flags = usba_check_intr_context(cb_flags);
973 
974 	/* do the callback under taskq context */
975 	switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
976 	    USB_EP_ATTR_MASK) {
977 	case USB_EP_ATTR_CONTROL:
978 		USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb_flags |= cb_flags;
979 		break;
980 	case USB_EP_ATTR_INTR:
981 		USBA_WRP2INTR_REQ(req_wrp)->intr_cb_flags |= cb_flags;
982 		break;
983 	case USB_EP_ATTR_BULK:
984 		USBA_WRP2BULK_REQ(req_wrp)->bulk_cb_flags |= cb_flags;
985 		break;
986 	case USB_EP_ATTR_ISOCH:
987 		USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb_flags |= cb_flags;
988 		break;
989 	}
990 }
991 
992 
993 /*
994  * usba_pipe_sync_wait:
995  *	wait for the request to finish.
996  *	usba_hcdi_cb() does a cv_signal thru a soft intr
997  *
998  * Arguments:
999  *	ph_data		- pointer to pipe handle data
1000  *	wrp		- pointer to usba_req_wrapper_structure.
1001  *
1002  * Return Values:
1003  *	USB_SUCCESS	- request successfully executed
1004  *	USB_FAILURE	- request failed
1005  */
1006 static int
1007 usba_pipe_sync_wait(usba_pipe_handle_data_t	*ph_data,
1008 		usba_req_wrapper_t	*wrp)
1009 {
1010 	ASSERT(wrp->wr_usb_flags & USB_FLAGS_SLEEP);
1011 	ASSERT(ph_data == wrp->wr_ph_data);
1012 
1013 	mutex_enter(&ph_data->p_mutex);
1014 	while (wrp->wr_done != B_TRUE) {
1015 		cv_wait(&wrp->wr_cv, &ph_data->p_mutex);
1016 	}
1017 
1018 	mutex_exit(&ph_data->p_mutex);
1019 
1020 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1021 	    "usba_pipe_sync_wait: ph_data=0x%p cr=0x%x", ph_data, wrp->wr_cr);
1022 
1023 	/* XXX return something better than USB_FAILURE?? */
1024 
1025 	return (wrp->wr_cr == USB_CR_OK ? USB_SUCCESS : USB_FAILURE);
1026 }
1027 
1028 
1029 /*
1030  * Allocate usb control request and a USB request wrapper
1031  *
1032  * Arguments:
1033  *	dip	- dev_info_t of the client driver
1034  *	len	- length of "data" for this control request
1035  *	flags:
1036  *		USB_FLAGS_SLEEP	- Sleep if resources are not available
1037  *		no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
1038  *
1039  * Return Values:	usb_ctrl_req_t on success, NULL on failure
1040  */
1041 usb_ctrl_req_t *
1042 usb_alloc_ctrl_req(dev_info_t	*dip,
1043 		size_t		len,
1044 		usb_flags_t	flags)
1045 {
1046 	usb_ctrl_req_t	*ctrl_req = NULL;
1047 	usba_req_wrapper_t	*wrp;
1048 
1049 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1050 	    "usb_alloc_ctrl_req: dip=0x%p, wlen=0x%lx, flags=0x%x",
1051 	    dip, len, flags);
1052 
1053 	/* Allocate + Initialize the usba_req_wrapper_t structure */
1054 	if (dip &&
1055 	    ((wrp = usba_req_wrapper_alloc(dip, sizeof (*ctrl_req), flags)) !=
1056 	    NULL)) {
1057 		ctrl_req = USBA_WRP2CTRL_REQ(wrp);
1058 
1059 		/* Allocate the usb_ctrl_req data mblk */
1060 		if (len) {
1061 			if (flags & USB_FLAGS_SLEEP) {
1062 				ctrl_req->ctrl_data = allocb_wait(len, BPRI_LO,
1063 							STR_NOSIG, NULL);
1064 			} else	if ((ctrl_req->ctrl_data =
1065 			    allocb(len, BPRI_HI)) == NULL) {
1066 				usba_req_wrapper_free(wrp);
1067 				ctrl_req = NULL;
1068 			}
1069 		}
1070 	}
1071 
1072 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1073 	    "usb_alloc_ctrl_req: ctrl_req = 0x%p", ctrl_req);
1074 
1075 	return (ctrl_req);
1076 }
1077 
1078 
1079 /*
1080  * usb_free_ctrl_req:
1081  *	free USB control request + wrapper
1082  *
1083  * Arguments:
1084  *	req - pointer to usb_ctrl_req_t
1085  */
1086 void
1087 usb_free_ctrl_req(usb_ctrl_req_t *req)
1088 {
1089 	if (req) {
1090 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1091 		    "usb_free_ctrl_req: req = 0x%p", req);
1092 
1093 		if (req->ctrl_data) {
1094 			freemsg(req->ctrl_data);
1095 		}
1096 		usba_req_wrapper_free(USBA_REQ2WRP(req));
1097 	}
1098 }
1099 
1100 
1101 /*
1102  * Client driver calls this function to issue the control
1103  * request to the USBA
1104  *
1105  * Arguments:
1106  *	pipe_handle:  control pipe pipehandle (obtained via usb_pipe_open()
1107  *	req: control request
1108  *	usb_flags:
1109  *		USB_FLAGS_SLEEP - wait for the request to complete
1110  *
1111  * Return Values:
1112  *	USB_SUCCESS	- request successfully executed
1113  *	USB_FAILURE	- request failed
1114  */
1115 int
1116 usb_pipe_ctrl_xfer(usb_pipe_handle_t	pipe_handle,
1117 		usb_ctrl_req_t		*req,
1118 		usb_flags_t		usb_flags)
1119 {
1120 	int			rval;
1121 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
1122 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
1123 	usba_device_t		*usba_device;
1124 	usb_flags_t		wrp_usb_flags;
1125 	usb_pipe_state_t	pipe_state;
1126 
1127 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1128 	    "usb_pipe_ctrl_xfer: req=0x%p, wrp=0x%p\n\t"
1129 	    "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf=0x%x",
1130 	    req, wrp, req->ctrl_bmRequestType, req->ctrl_bRequest,
1131 	    req->ctrl_wValue, req->ctrl_wIndex, req->ctrl_wLength, usb_flags);
1132 
1133 	if (ph_data == NULL) {
1134 
1135 		return (USB_INVALID_PIPE);
1136 	}
1137 
1138 	mutex_enter(&ph_data->p_mutex);
1139 	usba_device = ph_data->p_usba_device;
1140 
1141 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
1142 	    USB_EP_ATTR_CONTROL)) != USB_SUCCESS) {
1143 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1144 		    "request rejected: rval=%d", rval);
1145 		mutex_exit(&ph_data->p_mutex);
1146 
1147 		usba_release_ph_data(ph_data->p_ph_impl);
1148 
1149 		return (rval);
1150 	}
1151 
1152 	ASSERT(ph_data == wrp->wr_ph_data);
1153 
1154 	/* we accepted the request, so increment the req count */
1155 	ph_data->p_req_count++;
1156 
1157 	wrp_usb_flags = wrp->wr_usb_flags;
1158 
1159 	/* Get the current bulk pipe state */
1160 	pipe_state = usba_get_ph_state(ph_data);
1161 
1162 	/*
1163 	 * if this is for the default pipe, and the pipe is in error,
1164 	 * just queue the request. autoclearing will start this request
1165 	 *
1166 	 * if there is already an active request in the queue
1167 	 * then just add this request to the queue.
1168 	 */
1169 	switch (pipe_state) {
1170 	case USB_PIPE_STATE_IDLE:
1171 		if (ph_data->p_queue.next ||
1172 		    ph_data->p_active_cntrl_req_wrp) {
1173 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1174 			    "usb_pipe_ctrl_xfer: queue request 0x%p", req);
1175 
1176 			usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1177 			rval = USB_SUCCESS;
1178 			mutex_exit(&ph_data->p_mutex);
1179 		} else {
1180 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
1181 			ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp;
1182 			mutex_exit(&ph_data->p_mutex);
1183 
1184 			/* issue the request to HCD */
1185 			rval = usba_device->usb_hcdi_ops->
1186 			    usba_hcdi_pipe_ctrl_xfer(ph_data, req, usb_flags);
1187 		}
1188 		break;
1189 	case USB_PIPE_STATE_ACTIVE:
1190 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1191 		    "usb_pipe_ctrl_xfer: queue request 0x%p", req);
1192 
1193 		usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1194 		rval = USB_SUCCESS;
1195 		mutex_exit(&ph_data->p_mutex);
1196 		break;
1197 	case USB_PIPE_STATE_ERROR:
1198 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1199 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1200 			    "usb_pipe_ctrl_xfer: queue request 0x%p on "
1201 			    "pending def pipe error", req);
1202 
1203 			usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1204 			rval = USB_SUCCESS;
1205 		} else {
1206 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1207 			    "usb_pipe_ctrl_xfer: pipe is in error state ");
1208 
1209 			rval = USB_PIPE_ERROR;
1210 		}
1211 		mutex_exit(&ph_data->p_mutex);
1212 		break;
1213 	default:
1214 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1215 		    "usb_pipe_ctrl_xfer: pipe state %d", pipe_state);
1216 
1217 		rval = USB_PIPE_ERROR;
1218 		mutex_exit(&ph_data->p_mutex);
1219 		break;
1220 	}
1221 
1222 	/* if there has been a failure, decrement req count */
1223 	if (rval != USB_SUCCESS) {
1224 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1225 		    "usb_pipe_ctrl_xfer: hcd failed req 0x%p", req);
1226 
1227 		if (req->ctrl_completion_reason == USB_CR_OK) {
1228 			req->ctrl_completion_reason = usba_rval2cr(rval);
1229 		}
1230 		mutex_enter(&ph_data->p_mutex);
1231 		ASSERT(wrp->wr_done == B_FALSE);
1232 		ph_data->p_req_count--;
1233 		ASSERT(ph_data->p_req_count >= 0);
1234 		ph_data->p_active_cntrl_req_wrp = NULL;
1235 		if ((ph_data->p_req_count == 0) &&
1236 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
1237 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1238 		}
1239 		mutex_exit(&ph_data->p_mutex);
1240 
1241 	/* if success and sleep specified, wait for completion */
1242 	} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
1243 		rval = usba_pipe_sync_wait(ph_data, wrp);
1244 	}
1245 
1246 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1247 	    "usb_pipe_ctrl_xfer: rval=0x%x", rval);
1248 
1249 	usba_release_ph_data(ph_data->p_ph_impl);
1250 
1251 	return (rval);
1252 }
1253 
1254 
1255 /*
1256  * usb_pipe_sync_ctrl_xfer():
1257  *	for simple synchronous control transactions this wrapper function
1258  *	will perform the allocation, xfer, and deallocation
1259  *	USB_ATTRS_AUTOCLEARING will be enabled
1260  *
1261  * Arguments:
1262  *	dip		- pointer to clients devinfo
1263  *	pipe_handle	- control pipe pipehandle (obtained via usb_pipe_open()
1264  *	bmRequestType	- characteristics of request
1265  *	bRequest	- specific request
1266  *	wValue		- varies according to request
1267  *	wIndex		- index or offset
1268  *	wLength		- number of bytes to xfer
1269  *	data		- pointer to pointer to data and may be NULL if
1270  *			  wLength is 0
1271  *	attrs		- required request attributes
1272  *	completion_reason - completion status
1273  *	cb_flags	- request completions flags
1274  *	flags		- none
1275  *
1276  * Return Values:
1277  *	USB_SUCCESS	- request successfully executed
1278  *	USB_*		- request failed
1279  *
1280  * Notes:
1281  * - in the case of failure, the client should check completion_reason and
1282  *	and cb_flags and determine further recovery action
1283  * - the client should check data and if non-zero, free the data on
1284  *	completion
1285  */
1286 int
1287 usb_pipe_sync_ctrl_xfer(dev_info_t *dip,
1288 		usb_pipe_handle_t pipe_handle,
1289 		uchar_t		bmRequestType,
1290 		uchar_t		bRequest,
1291 		uint16_t	wValue,
1292 		uint16_t	wIndex,
1293 		uint16_t	wLength,
1294 		mblk_t		**data,
1295 		usb_req_attrs_t	attributes,
1296 		usb_cr_t	*completion_reason,
1297 		usb_cb_flags_t	*cb_flags,
1298 		usb_flags_t	flags)
1299 {
1300 	usba_pipe_handle_data_t	*ph_data;
1301 	int			rval;
1302 	usb_ctrl_req_t		*ctrl_req;
1303 	size_t			length;
1304 #ifdef DEBUG
1305 #define	BUFSIZE	256
1306 	char			*buf = kmem_alloc(BUFSIZE, KM_SLEEP);
1307 #endif
1308 
1309 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1310 	    "usb_pipe_sync_ctrl_xfer: ph=0x%p\n\t"
1311 	    "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf = 0x%x", pipe_handle,
1312 	    bmRequestType, bRequest, wValue, wIndex, wLength, flags);
1313 
1314 	if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
1315 		rval = USB_INVALID_PIPE;
1316 
1317 		goto done;
1318 	}
1319 	if (servicing_interrupt()) {
1320 		rval = USB_INVALID_CONTEXT;
1321 
1322 		goto done;
1323 	}
1324 	if (dip == NULL) {
1325 		rval = USB_INVALID_ARGS;
1326 
1327 		goto done;
1328 	}
1329 
1330 	length = ((data) && (*data)) ? 0: wLength;
1331 
1332 	ctrl_req = usb_alloc_ctrl_req(dip,
1333 	    length, flags | USB_FLAGS_SLEEP);
1334 
1335 	/* Initialize the ctrl_req structure */
1336 	ctrl_req->ctrl_bmRequestType	= bmRequestType;
1337 	ctrl_req->ctrl_bRequest 	= bRequest;
1338 	ctrl_req->ctrl_wValue		= wValue;
1339 	ctrl_req->ctrl_wIndex		= wIndex;
1340 	ctrl_req->ctrl_wLength		= wLength;
1341 	ctrl_req->ctrl_data		= ctrl_req->ctrl_data ?
1342 						ctrl_req->ctrl_data :
1343 						((data) ? *data : NULL);
1344 	ctrl_req->ctrl_timeout		= USB_PIPE_TIMEOUT;
1345 	ctrl_req->ctrl_attributes	= attributes | USB_ATTRS_AUTOCLEARING;
1346 
1347 	/* Issue control xfer to the HCD */
1348 	rval = usb_pipe_ctrl_xfer(pipe_handle, ctrl_req,
1349 	    flags | USB_FLAGS_SLEEP);
1350 
1351 #ifdef DEBUG
1352 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1353 	    "req=0x%p, cr=%s cb_flags=%s data=0x%p rval=%s",
1354 	    ctrl_req, usb_str_cr(ctrl_req->ctrl_completion_reason),
1355 	    usb_str_cb_flags(ctrl_req->ctrl_cb_flags, buf, BUFSIZE),
1356 	    ctrl_req->ctrl_data, usb_str_rval(rval));
1357 #endif
1358 
1359 	/* copy back ctrl_req values */
1360 	if (data) {
1361 		*data			= ctrl_req->ctrl_data;
1362 	}
1363 	if (completion_reason) {
1364 		*completion_reason	= ctrl_req->ctrl_completion_reason;
1365 	}
1366 	if (cb_flags) {
1367 		*cb_flags		= ctrl_req->ctrl_cb_flags;
1368 	}
1369 
1370 	/* Free up the control request now */
1371 	ctrl_req->ctrl_data = NULL; /* leave to client to free */
1372 	usb_free_ctrl_req(ctrl_req);
1373 
1374 done:
1375 #ifdef DEBUG
1376 	kmem_free(buf, BUFSIZE);
1377 #endif
1378 	if (ph_data) {
1379 		usba_release_ph_data(ph_data->p_ph_impl);
1380 	}
1381 
1382 	return (rval);
1383 }
1384 
1385 
1386 /*
1387  * usb_pipe_ctrl_xfer_wait():
1388  *	Easy-to-use wrapper around usb_pipe_sync_ctrl_xfer.
1389  *
1390  * ARGUMENTS:
1391  *	pipe_handle	- control pipe pipehandle (obtained via usb_pipe_open())
1392  *	setup		- setup descriptor params, attributes
1393  *	data		- pointer to pointer to data and may be NULL when
1394  *			  wLength is 0
1395  *	completion_reason - completion status.
1396  *	cb_flags	- request completions flags.
1397  *	flags		- none.
1398  *
1399  * RETURN VALUES:
1400  *	USB_SUCCESS	- request successfully executed.
1401  *	USB_*		- failure
1402  */
1403 int
1404 usb_pipe_ctrl_xfer_wait(
1405 		usb_pipe_handle_t	pipe_handle,
1406 		usb_ctrl_setup_t	*setup,
1407 		mblk_t			**data,
1408 		usb_cr_t		*completion_reason,
1409 		usb_cb_flags_t		*cb_flags,
1410 		usb_flags_t		flags)
1411 {
1412 	return (usb_pipe_sync_ctrl_xfer(
1413 				usba_get_dip(pipe_handle),
1414 				pipe_handle,
1415 				setup->bmRequestType,
1416 				setup->bRequest,
1417 				setup->wValue,
1418 				setup->wIndex,
1419 				setup->wLength,
1420 				data,
1421 				setup->attrs,
1422 				completion_reason,
1423 				cb_flags,
1424 				flags));
1425 }
1426 
1427 
1428 /*
1429  * usb_alloc_bulk_req:
1430  *	Allocate a usb bulk request + usba_req_wrapper_t
1431  *
1432  * Arguments:
1433  *	dip	- dev_info_t of the client driver
1434  *	len	- length of "data" for this bulk request
1435  *	flags:
1436  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
1437  *
1438  * Return Values:
1439  *	usb_bulk_req_t on success, NULL on failure
1440  */
1441 usb_bulk_req_t *
1442 usb_alloc_bulk_req(dev_info_t	*dip,
1443 		size_t		len,
1444 		usb_flags_t	flags)
1445 {
1446 	usb_bulk_req_t		*bulk_req = NULL;
1447 	usba_req_wrapper_t	*wrp;
1448 
1449 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1450 	    "usb_alloc_bulk_req: dip=0x%p wlen=0x%lx flags=0x%x",
1451 	    dip, len, flags);
1452 
1453 	/* Allocate + Initialize the usba_req_wrapper_t structure */
1454 	if (dip &&
1455 	    ((wrp = usba_req_wrapper_alloc(dip, sizeof (*bulk_req), flags)) !=
1456 	    NULL)) {
1457 		bulk_req = USBA_WRP2BULK_REQ(wrp);
1458 
1459 		/* Allocate the usb_bulk_req data mblk */
1460 		if (len) {
1461 			if (flags & USB_FLAGS_SLEEP) {
1462 				bulk_req->bulk_data = allocb_wait(len,
1463 				    BPRI_LO, STR_NOSIG, NULL);
1464 			} else	if ((bulk_req->bulk_data =
1465 			    allocb(len, BPRI_HI)) == NULL) {
1466 				usba_req_wrapper_free(wrp);
1467 				bulk_req = NULL;
1468 			}
1469 		}
1470 
1471 	}
1472 
1473 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1474 	    "usb_alloc_bulk_req: bulk_req = 0x%p", bulk_req);
1475 
1476 	return (bulk_req);
1477 }
1478 
1479 
1480 /*
1481  * usb_free_bulk_req:
1482  *	free USB bulk request + wrapper
1483  *
1484  * Arguments:
1485  *	req - pointer to usb_bulk_req_t
1486  */
1487 void
1488 usb_free_bulk_req(usb_bulk_req_t *req)
1489 {
1490 	if (req) {
1491 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1492 		    "usb_free_bulk_req: req=0x%p", req);
1493 
1494 		if (req->bulk_data) {
1495 			freemsg(req->bulk_data);
1496 		}
1497 		usba_req_wrapper_free(USBA_REQ2WRP(req));
1498 	}
1499 }
1500 
1501 
1502 /*
1503  * Client driver calls this function to issue the bulk xfer to the USBA
1504  *
1505  * Arguments:-
1506  *	pipe_handle - bulk pipe handle (obtained via usb_pipe_open()
1507  *	req	    - bulk data xfer request (IN or OUT)
1508  *	usb_flags   - USB_FLAGS_SLEEP - wait for the request to complete
1509  *
1510  * Return Values:
1511  *	USB_SUCCESS - success
1512  *	USB_FAILURE - unspecified failure
1513  */
1514 int
1515 usb_pipe_bulk_xfer(usb_pipe_handle_t	pipe_handle,
1516 		usb_bulk_req_t		*req,
1517 		usb_flags_t		usb_flags)
1518 {
1519 	int			rval;
1520 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
1521 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
1522 	usba_device_t		*usba_device;
1523 	usb_flags_t		wrp_usb_flags;
1524 	usb_pipe_state_t	pipe_state;
1525 
1526 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1527 	    "usb_pipe_bulk_xfer: req=0x%p uf=0x%x", req, usb_flags);
1528 
1529 	if (ph_data == NULL) {
1530 
1531 		return (USB_INVALID_PIPE);
1532 	}
1533 
1534 	mutex_enter(&ph_data->p_mutex);
1535 	usba_device = ph_data->p_usba_device;
1536 
1537 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
1538 	    USB_EP_ATTR_BULK)) != USB_SUCCESS) {
1539 		mutex_exit(&ph_data->p_mutex);
1540 
1541 		usba_release_ph_data(ph_data->p_ph_impl);
1542 
1543 		return (rval);
1544 	}
1545 
1546 	/* we accepted the request */
1547 	ph_data->p_req_count++;
1548 	wrp_usb_flags = wrp->wr_usb_flags;
1549 
1550 	/* Get the current bulk pipe state */
1551 	pipe_state = usba_get_ph_state(ph_data);
1552 
1553 	/*
1554 	 * if there is already an active request in the queue
1555 	 * then just add this request to the queue.
1556 	 */
1557 	switch (pipe_state) {
1558 	case USB_PIPE_STATE_IDLE:
1559 		if (ph_data->p_queue.next) {
1560 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1561 			    "usb_pipe_bulk_xfer: queue request 0x%p", req);
1562 
1563 			usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1564 			rval = USB_SUCCESS;
1565 			mutex_exit(&ph_data->p_mutex);
1566 		} else {
1567 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
1568 			mutex_exit(&ph_data->p_mutex);
1569 
1570 			/* issue the request to HCD */
1571 			rval = usba_device->usb_hcdi_ops->
1572 			    usba_hcdi_pipe_bulk_xfer(ph_data, req, usb_flags);
1573 		}
1574 		break;
1575 	case USB_PIPE_STATE_ACTIVE:
1576 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1577 		    "usb_pipe_bulk_xfer: queue request 0x%p", req);
1578 
1579 		usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1580 		rval = USB_SUCCESS;
1581 		mutex_exit(&ph_data->p_mutex);
1582 		break;
1583 	default:
1584 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1585 		    "usb_pipe_bulk_xfer: pipe state %d", pipe_state);
1586 
1587 		rval = USB_PIPE_ERROR;
1588 		mutex_exit(&ph_data->p_mutex);
1589 		break;
1590 	}
1591 
1592 	if (rval != USB_SUCCESS) {
1593 		if (req->bulk_completion_reason == USB_CR_OK) {
1594 			req->bulk_completion_reason = usba_rval2cr(rval);
1595 		}
1596 		mutex_enter(&ph_data->p_mutex);
1597 		ASSERT(wrp->wr_done == B_FALSE);
1598 		ph_data->p_req_count--;
1599 		ASSERT(ph_data->p_req_count >= 0);
1600 		if ((ph_data->p_req_count == 0) &&
1601 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
1602 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1603 		}
1604 		mutex_exit(&ph_data->p_mutex);
1605 	} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
1606 		rval = usba_pipe_sync_wait(ph_data, wrp);
1607 	}
1608 
1609 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1610 	    "usb_pipe_bulk_xfer: rval=%d", rval);
1611 
1612 	usba_release_ph_data(ph_data->p_ph_impl);
1613 
1614 	return (rval);
1615 }
1616 
1617 
1618 /*
1619  * usb_pipe_bulk_transfer_size:
1620  *	- request HCD to return bulk max transfer data size
1621  *
1622  * Arguments:
1623  *	dip	- pointer to dev_info_t
1624  *	size	- pointer to bulk_transfer_size
1625  *
1626  * Return Values:
1627  *	USB_SUCCESS	- request successfully executed
1628  *	USB_FAILURE	- request failed
1629  */
1630 int
1631 usb_pipe_bulk_transfer_size(dev_info_t	*dip,
1632 			size_t		*size)
1633 {
1634 	return (usb_pipe_get_max_bulk_transfer_size(dip, size));
1635 }
1636 
1637 
1638 int
1639 usb_pipe_get_max_bulk_transfer_size(dev_info_t	*dip,
1640 			size_t		*size)
1641 {
1642 	usba_device_t	*usba_device;
1643 
1644 	if ((dip == NULL) || (size == NULL)) {
1645 
1646 		return (USB_INVALID_ARGS);
1647 	}
1648 	usba_device = usba_get_usba_device(dip);
1649 
1650 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1651 	    "usb_pipe_bulk_transfer_size: usba_device=0x%p", usba_device);
1652 
1653 	if ((usba_device) &&
1654 	    (usba_device->usb_hcdi_ops->usba_hcdi_bulk_transfer_size)) {
1655 
1656 		return (usba_device->usb_hcdi_ops->
1657 		    usba_hcdi_bulk_transfer_size(usba_device, size));
1658 	} else {
1659 		*size = 0;
1660 
1661 		return (USB_FAILURE);
1662 	}
1663 }
1664 
1665 
1666 /*
1667  * usb_alloc_intr_req:
1668  *	Allocate usb interrupt request
1669  *
1670  * Arguments:
1671  *	dip	- dev_info_t of the client driver
1672  *	len	- length of "data" for this interrupt request
1673  *	flags	-
1674  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
1675  *
1676  * Return Values:
1677  *		usb_intr_req_t on success, NULL on failure
1678  */
1679 usb_intr_req_t *
1680 usb_alloc_intr_req(dev_info_t	*dip,
1681 		size_t		len,
1682 		usb_flags_t	flags)
1683 {
1684 	usb_intr_req_t	*intr_req = NULL;
1685 	usba_req_wrapper_t	*wrp;
1686 
1687 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1688 	    "usb_alloc_intr_req: dip=0x%p, len=0x%lx, flags=0x%x",
1689 	    dip, len, flags);
1690 
1691 	/* Allocate + Initialize the usba_req_wrapper_t structure */
1692 	if ((dip &&
1693 	    (wrp = usba_req_wrapper_alloc(dip, sizeof (*intr_req), flags)) !=
1694 	    NULL)) {
1695 		intr_req = (usb_intr_req_t *)USBA_WRP2INTR_REQ(wrp);
1696 
1697 		/* Allocate the usb_intr_req data mblk */
1698 		if (len) {
1699 			if (flags & USB_FLAGS_SLEEP) {
1700 				intr_req->intr_data = allocb_wait(len, BPRI_LO,
1701 							STR_NOSIG, NULL);
1702 			} else	if ((intr_req->intr_data =
1703 			    allocb(len, BPRI_HI)) == NULL) {
1704 				usba_req_wrapper_free(wrp);
1705 				intr_req = NULL;
1706 			}
1707 		}
1708 	}
1709 
1710 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1711 	    "usb_alloc_intr_req: intr_req=0x%p", intr_req);
1712 
1713 	return (intr_req);
1714 }
1715 
1716 
1717 /*
1718  * usba_hcdi_dup_intr_req:
1719  *	create duplicate of interrupt request
1720  *
1721  * Arguments:
1722  *	dip	- devinfo pointer
1723  *	reqp	- original requestp pointer
1724  *	len	- length of "data" for this interrupt request
1725  *	flags	-
1726  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
1727  *
1728  * Return Values:
1729  *		usb_intr_req_t on success, NULL on failure
1730  */
1731 usb_intr_req_t *
1732 usba_hcdi_dup_intr_req(
1733 		dev_info_t	*dip,
1734 		usb_intr_req_t	*reqp,
1735 		size_t		len,
1736 		usb_flags_t	flags)
1737 {
1738 	usb_intr_req_t		*intr_reqp = NULL;
1739 	usba_req_wrapper_t	*intr_wrp, *req_wrp;
1740 
1741 	if (reqp == NULL) {
1742 
1743 		return (NULL);
1744 	}
1745 
1746 	req_wrp	= USBA_REQ2WRP(reqp);
1747 
1748 	if (((intr_reqp = usb_alloc_intr_req(dip, len, flags)) != NULL)) {
1749 		intr_reqp->intr_client_private	= reqp->intr_client_private;
1750 		intr_reqp->intr_timeout		= reqp->intr_timeout;
1751 		intr_reqp->intr_attributes	= reqp->intr_attributes;
1752 		intr_reqp->intr_len		= reqp->intr_len;
1753 		intr_reqp->intr_cb		= reqp->intr_cb;
1754 		intr_reqp->intr_exc_cb		= reqp->intr_exc_cb;
1755 
1756 		intr_wrp		= USBA_REQ2WRP(intr_reqp);
1757 		intr_wrp->wr_dip	= req_wrp->wr_dip;
1758 		intr_wrp->wr_ph_data	= req_wrp->wr_ph_data;
1759 		intr_wrp->wr_attrs	= req_wrp->wr_attrs;
1760 		intr_wrp->wr_usb_flags	= req_wrp->wr_usb_flags;
1761 	}
1762 
1763 	return (intr_reqp);
1764 }
1765 
1766 
1767 /*
1768  * usb_free_intr_req:
1769  *	free USB intr request + wrapper
1770  *
1771  * Arguments:
1772  *	req - pointer to usb_intr_req_t
1773  */
1774 void
1775 usb_free_intr_req(usb_intr_req_t *req)
1776 {
1777 	if (req) {
1778 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1779 		    "usb_free_intr_req: req = 0x%p", req);
1780 
1781 		if (req->intr_data) {
1782 			freemsg(req->intr_data);
1783 		}
1784 
1785 		usba_req_wrapper_free(USBA_REQ2WRP(req));
1786 	}
1787 }
1788 
1789 
1790 /*
1791  * Client driver calls this function to issue the intr xfer to the USBA
1792  *
1793  * Arguments:-
1794  *	pipe_handle	- intr pipe handle (obtained via usb_pipe_open()
1795  *	req		- intr data xfer request (IN or OUT)
1796  *	flags		-
1797  *			   USB_FLAGS_SLEEP - wait for the request to complete
1798  * Return Values
1799  *	USB_SUCCESS	- success
1800  *	USB_FAILURE	- unspecified failure
1801  */
1802 int
1803 usb_pipe_intr_xfer(usb_pipe_handle_t	pipe_handle,
1804 		usb_intr_req_t		*req,
1805 		usb_flags_t		usb_flags)
1806 {
1807 	int			rval;
1808 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
1809 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
1810 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
1811 	usba_device_t		*usba_device;
1812 	uchar_t			direction;
1813 	usb_flags_t		wrp_usb_flags;
1814 	usb_pipe_state_t	pipe_state;
1815 
1816 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1817 	    "usb_pipe_intr_req: req=0x%p uf=0x%x",
1818 	    req, usb_flags);
1819 
1820 	if (ph_data == NULL) {
1821 
1822 		return (USB_INVALID_PIPE);
1823 	}
1824 	usba_device = ph_data->p_usba_device;
1825 	direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
1826 
1827 	mutex_enter(&ph_data->p_mutex);
1828 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
1829 	    USB_EP_ATTR_INTR)) != USB_SUCCESS) {
1830 		mutex_exit(&ph_data->p_mutex);
1831 
1832 		usba_release_ph_data(ph_data->p_ph_impl);
1833 
1834 		return (rval);
1835 	}
1836 
1837 	/* Get the current interrupt pipe state */
1838 	pipe_state = usba_get_ph_state(ph_data);
1839 
1840 	switch (pipe_state) {
1841 	case USB_PIPE_STATE_IDLE:
1842 		/*
1843 		 * if the pipe state is in middle of transition,
1844 		 * i.e. stop polling is in progress, fail any
1845 		 * attempt to do a start polling
1846 		 */
1847 		mutex_enter(&ph_impl->usba_ph_mutex);
1848 		if (ph_impl->usba_ph_state_changing > 0) {
1849 			mutex_exit(&ph_impl->usba_ph_mutex);
1850 
1851 			mutex_exit(&ph_data->p_mutex);
1852 			usba_release_ph_data(ph_data->p_ph_impl);
1853 
1854 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1855 			    "usb_pipe_intr_req: fail request - "
1856 			    "stop polling in progress");
1857 
1858 			return (USB_FAILURE);
1859 		} else {
1860 			mutex_exit(&ph_impl->usba_ph_mutex);
1861 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
1862 		}
1863 
1864 		break;
1865 	case USB_PIPE_STATE_ACTIVE:
1866 		/*
1867 		 * If this is interrupt IN pipe and if we are
1868 		 * already polling, return failure.
1869 		 */
1870 		if (direction == USB_EP_DIR_IN) {
1871 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
1872 			    usbai_log_handle,
1873 			    "usb_pipe_intr_req: already polling");
1874 
1875 			mutex_exit(&ph_data->p_mutex);
1876 			usba_release_ph_data(ph_data->p_ph_impl);
1877 
1878 			return (USB_FAILURE);
1879 		}
1880 
1881 		break;
1882 	default:
1883 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1884 		    "usb_pipe_intr_req: pipe state %d", pipe_state);
1885 
1886 		mutex_exit(&ph_data->p_mutex);
1887 		usba_release_ph_data(ph_data->p_ph_impl);
1888 
1889 		return (USB_PIPE_ERROR);
1890 	}
1891 
1892 	/* we accept the request */
1893 	wrp_usb_flags = wrp->wr_usb_flags;
1894 	ph_data->p_req_count++;
1895 
1896 	mutex_exit(&ph_data->p_mutex);
1897 
1898 	/* issue the request out */
1899 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_intr_xfer(ph_data,
1900 	    req, usb_flags)) != USB_SUCCESS) {
1901 
1902 		/* the request failed, decrement the ref_count */
1903 		if (req->intr_completion_reason == USB_CR_OK) {
1904 			req->intr_completion_reason = usba_rval2cr(rval);
1905 		}
1906 		mutex_enter(&ph_data->p_mutex);
1907 		ASSERT(wrp->wr_done == B_FALSE);
1908 		ph_data->p_req_count--;
1909 		ASSERT(ph_data->p_req_count >= 0);
1910 		if ((ph_data->p_req_count == 0) &&
1911 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
1912 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1913 		}
1914 		mutex_exit(&ph_data->p_mutex);
1915 
1916 	/* if sleep specified, wait for completion */
1917 	} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
1918 		rval = usba_pipe_sync_wait(ph_data, wrp);
1919 	}
1920 
1921 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1922 	    "usb_pipe_intr_req: rval=0x%x", rval);
1923 
1924 	usba_release_ph_data(ph_data->p_ph_impl);
1925 
1926 	return (rval);
1927 }
1928 
1929 
1930 /*
1931  * usba_pipe_sync_stop_intr_polling:
1932  *	- set up for sync transport, if necessary
1933  *	- request HCD to stop polling
1934  *	- wait for draining of all callbacks
1935  */
1936 /*ARGSUSED*/
1937 static int
1938 usba_pipe_sync_stop_intr_polling(dev_info_t	*dip,
1939 		usba_ph_impl_t		*ph_impl,
1940 		usba_pipe_async_req_t	*request,
1941 		usb_flags_t		flags)
1942 {
1943 	int rval;
1944 	usba_pipe_handle_data_t *ph_data;
1945 	usba_device_t	*usba_device;
1946 
1947 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1948 	    "usba_pipe_sync_stop_intr_polling: flags=0x%x", flags);
1949 
1950 	ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_impl);
1951 	if (ph_data == NULL) {
1952 		usba_release_ph_data(ph_impl);
1953 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1954 		    "usba_pipe_sync_stop_intr_polling: pipe closed");
1955 
1956 		return (USB_INVALID_PIPE);
1957 	}
1958 
1959 	usba_device = ph_data->p_usba_device;
1960 
1961 	mutex_enter(&ph_data->p_mutex);
1962 
1963 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
1964 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1965 		    "usba_pipe_sync_stop_intr_polling: pipe error");
1966 		mutex_exit(&ph_data->p_mutex);
1967 
1968 		usba_release_ph_data(ph_impl);
1969 
1970 		return (USB_PIPE_ERROR);
1971 	}
1972 
1973 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
1974 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1975 		    "usba_pipe_sync_stop_intr_polling: already idle");
1976 		mutex_exit(&ph_data->p_mutex);
1977 
1978 		usba_release_ph_data(ph_impl);
1979 
1980 		return (USB_SUCCESS);
1981 	}
1982 	mutex_exit(&ph_data->p_mutex);
1983 
1984 	mutex_enter(&ph_impl->usba_ph_mutex);
1985 	ph_impl->usba_ph_state_changing++;
1986 	mutex_exit(&ph_impl->usba_ph_mutex);
1987 
1988 	flags |= USB_FLAGS_SLEEP;
1989 
1990 	for (;;) {
1991 		rval = usba_device->usb_hcdi_ops->
1992 			usba_hcdi_pipe_stop_intr_polling(ph_data, flags);
1993 
1994 		/*
1995 		 * The host controller has stopped polling of the endpoint.
1996 		 * Now, drain the callbacks if there are any on the callback
1997 		 * queue.
1998 		 */
1999 		if (rval == USB_SUCCESS) {
2000 			mutex_enter(&ph_data->p_mutex);
2001 
2002 			/*
2003 			 * there is a tiny window that the client driver
2004 			 * may still have restarted the polling and we
2005 			 * have to let the stop polling win)
2006 			 */
2007 			rval = usba_drain_cbs(ph_data, 0,
2008 						USB_CR_STOPPED_POLLING);
2009 			mutex_exit(&ph_data->p_mutex);
2010 			if (rval != USB_SUCCESS) {
2011 
2012 				continue;
2013 			}
2014 		}
2015 
2016 		break;
2017 	}
2018 
2019 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2020 	    "usba_pipe_sync_stop_intr_polling: rval=0x%x", rval);
2021 
2022 	mutex_enter(&ph_impl->usba_ph_mutex);
2023 	ph_impl->usba_ph_state_changing--;
2024 	mutex_exit(&ph_impl->usba_ph_mutex);
2025 
2026 	usba_release_ph_data(ph_impl);
2027 
2028 	return (rval);
2029 }
2030 
2031 
2032 /*
2033  * dummy callback function for stop polling
2034  */
2035 static void
2036 usba_dummy_callback(
2037 	usb_pipe_handle_t ph,
2038 	usb_opaque_t arg,
2039 	int rval,
2040 	usb_cb_flags_t flags)
2041 {
2042 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2043 	    "usba_dummy_callback: "
2044 	    "ph=0x%p rval=0x%x flags=0x%x cb_arg=0x%p",
2045 	    ph, rval, flags, arg);
2046 }
2047 
2048 
2049 /*
2050  * usb_pipe_stop_intr_polling:
2051  *	stop polling for interrupt pipe IN data
2052  *	The HCD doesn't do a usba_hcdi_cb().
2053  *	It just returns success/failure
2054  * Arguments:
2055  *	pipe_handle	- pipe handle
2056  *	flags		-
2057  *			USB_FLAGS_SLEEP:	wait for completion
2058  */
2059 void
2060 usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle,
2061 	usb_flags_t	flags)
2062 {
2063 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
2064 
2065 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2066 	    "usba_pipe_stop_intr_polling: flags=0x%x", flags);
2067 
2068 	if (ph_data == NULL) {
2069 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2070 		    "usba_pipe_stop_intr_polling: pipe closed");
2071 
2072 		return;
2073 	}
2074 
2075 	if ((ph_data->p_ep.bmAttributes &
2076 	    USB_EP_ATTR_MASK) != USB_EP_ATTR_INTR) {
2077 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2078 		    "usba_pipe_stop_intr_polling: wrong pipe type");
2079 
2080 		usba_release_ph_data(ph_data->p_ph_impl);
2081 
2082 		return;
2083 	}
2084 
2085 	if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2086 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2087 		    "usba_pipe_stop_intr_polling: wrong pipe direction");
2088 
2089 		usba_release_ph_data(ph_data->p_ph_impl);
2090 
2091 		return;
2092 	}
2093 
2094 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2095 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2096 		    "usba_pipe_stop_intr_polling: invalid context");
2097 
2098 		usba_release_ph_data(ph_data->p_ph_impl);
2099 
2100 		return;
2101 	}
2102 
2103 	(void) usba_pipe_setup_func_call(ph_data->p_dip,
2104 	    usba_pipe_sync_stop_intr_polling,
2105 	    (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
2106 	    flags, usba_dummy_callback, NULL);
2107 }
2108 
2109 
2110 /*
2111  * usb_alloc_isoc_req:
2112  *	- Allocate usb isochronous resources that includes usb isochronous
2113  *	  request and array of packet descriptor structures and wrapper.
2114  *
2115  * Arguments:
2116  *	dip		- dev_info_t of the client driver
2117  *	isoc_pkts_count - number of isoc_pkt_descr_t's
2118  *	len		- length of "data" for this isochronous request
2119  *	flags		-
2120  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
2121  *		no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
2122  *
2123  * Return Values:
2124  *	usb_isoc_req_t on success, NULL on failure
2125  */
2126 /*ARGSUSED*/
2127 usb_isoc_req_t *
2128 usb_alloc_isoc_req(dev_info_t		*dip,
2129 		uint_t			isoc_pkts_count,
2130 		size_t			len,
2131 		usb_flags_t		flags)
2132 {
2133 	usb_isoc_req_t		*isoc_req = NULL;
2134 	usba_req_wrapper_t	*wrp;
2135 	size_t			length = sizeof (*isoc_req) +
2136 			(sizeof (usb_isoc_pkt_descr_t) * isoc_pkts_count);
2137 
2138 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2139 	    "usb_alloc_isoc_req: dip=0x%p pkt_cnt=%d len=%lu flags=0x%x",
2140 	    dip, isoc_pkts_count, len, flags);
2141 
2142 	/* client needs to set isoc_pks_count */
2143 	if (dip && isoc_pkts_count) {
2144 		/* Allocate + Initialize the usba_req_wrapper_t structure */
2145 		if ((wrp = usba_req_wrapper_alloc(dip, length, flags)) !=
2146 		    NULL) {
2147 			isoc_req = (usb_isoc_req_t *)USBA_WRP2ISOC_REQ(wrp);
2148 
2149 			/* Allocate the usb_isoc_req data mblk */
2150 			if (len) {
2151 				if ((isoc_req->isoc_data =
2152 				    allocb(len, BPRI_HI)) == NULL) {
2153 					usba_req_wrapper_free(wrp);
2154 					isoc_req = NULL;
2155 				}
2156 			}
2157 		}
2158 	}
2159 
2160 	if (isoc_req) {
2161 		isoc_req->isoc_pkt_descr = (usb_isoc_pkt_descr_t *)
2162 		    (((intptr_t)isoc_req) + (sizeof (usb_isoc_req_t)));
2163 
2164 		/* Initialize all the fields of usb isochronous request */
2165 		isoc_req->isoc_pkts_count = isoc_pkts_count;
2166 	}
2167 
2168 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2169 	    "usb_alloc_isoc_req: isoc_req = 0x%p", isoc_req);
2170 
2171 	return (isoc_req);
2172 }
2173 
2174 
2175 /*
2176  * usba_hcdi_dup_isoc_req:
2177  *	create duplicate of isoc request
2178  *
2179  * Arguments:
2180  *	dip	- devinfo pointer
2181  *	reqp	- original request pointer
2182  *	len	- length of "data" for this isoc request
2183  *	flags	-
2184  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
2185  *
2186  * Return Values:
2187  *		usb_isoc_req_t on success, NULL on failure
2188  */
2189 usb_isoc_req_t *
2190 usba_hcdi_dup_isoc_req(
2191 		dev_info_t	*dip,
2192 		usb_isoc_req_t	*reqp,
2193 		usb_flags_t	flags)
2194 {
2195 	usb_isoc_req_t		*isoc_reqp = NULL;
2196 	usba_req_wrapper_t	*isoc_wrp, *req_wrp;
2197 	ushort_t		count;
2198 	ushort_t		isoc_pkts_count;
2199 	size_t			length;
2200 
2201 	if (reqp == NULL) {
2202 
2203 		return (isoc_reqp);
2204 	}
2205 
2206 	isoc_pkts_count = reqp->isoc_pkts_count;
2207 
2208 	/* calculate total data length required in original request */
2209 	for (count = length = 0; count < isoc_pkts_count; count++) {
2210 		length += reqp->isoc_pkt_descr[count].isoc_pkt_length;
2211 	}
2212 
2213 	req_wrp	= USBA_REQ2WRP(reqp);
2214 
2215 	if (((isoc_reqp = usb_alloc_isoc_req(dip,
2216 	    isoc_pkts_count, length, flags)) != NULL)) {
2217 		isoc_reqp->isoc_frame_no	= reqp->isoc_frame_no;
2218 		isoc_reqp->isoc_pkts_count	= reqp->isoc_pkts_count;
2219 		isoc_reqp->isoc_pkts_length	= reqp->isoc_pkts_length;
2220 		isoc_reqp->isoc_attributes	= reqp->isoc_attributes;
2221 		isoc_reqp->isoc_client_private	= reqp->isoc_client_private;
2222 		isoc_reqp->isoc_cb		= reqp->isoc_cb;
2223 		isoc_reqp->isoc_exc_cb		= reqp->isoc_exc_cb;
2224 
2225 		isoc_wrp		= USBA_REQ2WRP(isoc_reqp);
2226 		isoc_wrp->wr_dip	= req_wrp->wr_dip;
2227 		isoc_wrp->wr_ph_data	= req_wrp->wr_ph_data;
2228 		isoc_wrp->wr_attrs	= req_wrp->wr_attrs;
2229 		isoc_wrp->wr_usb_flags	= req_wrp->wr_usb_flags;
2230 
2231 		for (count = 0; count < isoc_pkts_count; count++) {
2232 			isoc_reqp->isoc_pkt_descr[count].isoc_pkt_length =
2233 				reqp->isoc_pkt_descr[count].isoc_pkt_length;
2234 		}
2235 	}
2236 
2237 	return (isoc_reqp);
2238 }
2239 
2240 
2241 /*
2242  * usb_free_isoc_req:
2243  *	- Deallocate usb isochronous resources that includes usb isochronous
2244  *	  request and array of packet descriptor strcutures.
2245  *
2246  * Arguments:
2247  *	req - pointer to usb_isoc_req_t
2248  */
2249 void
2250 usb_free_isoc_req(usb_isoc_req_t *req)
2251 {
2252 	if (req) {
2253 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2254 		    "usb_free_isoc_req: req=0x%p", req);
2255 
2256 		if (req->isoc_data) {
2257 			freemsg(req->isoc_data);
2258 		}
2259 
2260 		usba_req_wrapper_free(USBA_REQ2WRP(req));
2261 	}
2262 }
2263 
2264 
2265 /*
2266  * usb_get_current_frame_number:
2267  *	- request HCD to return current usb frame number
2268  *
2269  * Arguments:
2270  *	dip	- pointer to dev_info_t
2271  *
2272  * Return Values:
2273  *	current_frame_number	- request successfully executed
2274  *	0			- request failed
2275  */
2276 usb_frame_number_t
2277 usb_get_current_frame_number(dev_info_t	*dip)
2278 {
2279 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2280 	    "usb_get_current_frame_number: dip=0x%p", dip);
2281 
2282 	if (dip) {
2283 		usba_device_t	*usba_device = usba_get_usba_device(dip);
2284 
2285 		if (usba_device->usb_hcdi_ops->
2286 		    usba_hcdi_get_current_frame_number) {
2287 
2288 			return (usba_device->usb_hcdi_ops->
2289 			    usba_hcdi_get_current_frame_number(usba_device));
2290 		}
2291 	}
2292 
2293 	return (0);
2294 }
2295 
2296 
2297 /*
2298  * usb_get_max_isoc_pkts:
2299  *	- request HCD to return maximum isochronous packets per request
2300  *
2301  * Arguments:
2302  *	dip	- pointer to dev_info_t
2303  *
2304  * Return Values:
2305  *	isoc_pkt - request successfully executed
2306  *	0	 - request failed
2307  */
2308 uint_t
2309 usb_get_max_isoc_pkts(dev_info_t *dip)
2310 {
2311 	return (usb_get_max_pkts_per_isoc_request(dip));
2312 }
2313 
2314 
2315 uint_t
2316 usb_get_max_pkts_per_isoc_request(dev_info_t *dip)
2317 {
2318 	if (dip) {
2319 		usba_device_t	*usba_device = usba_get_usba_device(dip);
2320 
2321 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2322 		    "usb_get_max_isoc_pkts: usba_device=0x%p", usba_device);
2323 
2324 		if (usba_device->usb_hcdi_ops->usba_hcdi_get_max_isoc_pkts) {
2325 
2326 			return (usba_device->usb_hcdi_ops->
2327 			    usba_hcdi_get_max_isoc_pkts(usba_device));
2328 		}
2329 	}
2330 
2331 	return (0);
2332 }
2333 
2334 
2335 /*
2336  * usb_pipe_isoc_xfer:
2337  *	- check for pipe stalled
2338  *	- request HCD to transport isoc data asynchronously
2339  *
2340  * Arguments:
2341  *	pipe_handle	- isoc pipe pipehandle (obtained via usb_pipe_open())
2342  *	req		- isochronous request
2343  *
2344  * Return Values:
2345  *	USB_SUCCESS	- request successfully executed
2346  *	USB_FAILURE	- request failed
2347  */
2348 int
2349 usb_pipe_isoc_xfer(usb_pipe_handle_t	pipe_handle,
2350 		usb_isoc_req_t		*req,
2351 		usb_flags_t		flags)
2352 {
2353 	int			rval;
2354 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
2355 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
2356 	usba_device_t		*usba_device;
2357 	uchar_t			direction;
2358 	usb_pipe_state_t	pipe_state;
2359 
2360 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2361 	    "usb_pipe_isoc_xfer: flags=0x%x", flags);
2362 
2363 	if (ph_data == NULL) {
2364 
2365 		return (USB_INVALID_PIPE);
2366 	}
2367 
2368 	usba_device = ph_data->p_usba_device;
2369 	direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
2370 
2371 	mutex_enter(&ph_data->p_mutex);
2372 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, flags,
2373 	    USB_EP_ATTR_ISOCH)) != USB_SUCCESS) {
2374 		mutex_exit(&ph_data->p_mutex);
2375 
2376 		usba_release_ph_data(ph_data->p_ph_impl);
2377 
2378 		return (rval);
2379 	}
2380 
2381 	req->isoc_error_count = 0;
2382 
2383 	/* Get the current isoch pipe state */
2384 	pipe_state = usba_get_ph_state(ph_data);
2385 
2386 	switch (pipe_state) {
2387 	case USB_PIPE_STATE_IDLE:
2388 		usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
2389 		break;
2390 	case USB_PIPE_STATE_ACTIVE:
2391 		if (direction == USB_EP_DIR_IN) {
2392 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
2393 			    usbai_log_handle,
2394 			    "usb_pipe_isoc_req: already polling");
2395 
2396 			mutex_exit(&ph_data->p_mutex);
2397 			usba_release_ph_data(ph_data->p_ph_impl);
2398 
2399 			return (USB_FAILURE);
2400 		}
2401 		break;
2402 	default:
2403 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2404 		    "usb_pipe_isoc_req: pipe state %d", pipe_state);
2405 
2406 		mutex_exit(&ph_data->p_mutex);
2407 		usba_release_ph_data(ph_data->p_ph_impl);
2408 
2409 		return (USB_PIPE_ERROR);
2410 	}
2411 
2412 	/* we accept the request */
2413 	ph_data->p_req_count++;
2414 	mutex_exit(&ph_data->p_mutex);
2415 
2416 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_isoc_xfer(
2417 	    ph_data, req, flags)) != USB_SUCCESS) {
2418 		if (req->isoc_completion_reason == USB_CR_OK) {
2419 			req->isoc_completion_reason = usba_rval2cr(rval);
2420 		}
2421 		mutex_enter(&ph_data->p_mutex);
2422 		ASSERT(wrp->wr_done == B_FALSE);
2423 		ph_data->p_req_count--;
2424 		if ((ph_data->p_req_count == 0) &&
2425 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
2426 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
2427 		}
2428 		mutex_exit(&ph_data->p_mutex);
2429 	}
2430 
2431 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2432 	    "usb_pipe_isoc_req: rval=%x", rval);
2433 
2434 	usba_release_ph_data(ph_data->p_ph_impl);
2435 
2436 	return (rval);
2437 }
2438 
2439 
2440 /*
2441  * usba_pipe_sync_stop_isoc_polling:
2442  *	- set up for sync transport, if necessary
2443  *	- request HCD to stop polling
2444  *	- wait for draining of all callbacks
2445  *
2446  * Arguments:
2447  *	dip		- dev_info pointer
2448  *	pipe_handle	- pointer to pipe handle
2449  *	flags		- USB_FLAGS_SLEEP:	wait for completion
2450  */
2451 /*ARGSUSED*/
2452 static int
2453 usba_pipe_sync_stop_isoc_polling(dev_info_t	*dip,
2454 		usba_ph_impl_t		*ph_impl,
2455 		usba_pipe_async_req_t	*request,
2456 		usb_flags_t		flags)
2457 {
2458 	int rval;
2459 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
2460 					(usb_pipe_handle_t)ph_impl);
2461 	usba_device_t	*usba_device;
2462 
2463 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2464 	    "usba_pipe_sync_stop_isoc_polling: uf=0x%x", flags);
2465 
2466 	if (ph_data == NULL) {
2467 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2468 		    "usba_pipe_stop_isoc_polling: pipe closed");
2469 
2470 		return (USB_INVALID_PIPE);
2471 	}
2472 
2473 	usba_device = ph_data->p_usba_device;
2474 
2475 	mutex_enter(&ph_data->p_mutex);
2476 
2477 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
2478 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2479 		    "usba_pipe_sync_stop_isoc_polling: pipe error");
2480 		mutex_exit(&ph_data->p_mutex);
2481 
2482 		usba_release_ph_data(ph_impl);
2483 
2484 		return (USB_PIPE_ERROR);
2485 	}
2486 
2487 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
2488 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2489 		    "usba_pipe_sync_stop_isoc_polling: already stopped");
2490 		mutex_exit(&ph_data->p_mutex);
2491 
2492 		usba_release_ph_data(ph_impl);
2493 
2494 		return (USB_SUCCESS);
2495 	}
2496 
2497 
2498 	mutex_exit(&ph_data->p_mutex);
2499 
2500 	flags |= USB_FLAGS_SLEEP;
2501 
2502 	for (;;) {
2503 		rval = usba_device->usb_hcdi_ops->
2504 			usba_hcdi_pipe_stop_isoc_polling(ph_data, flags);
2505 
2506 		/*
2507 		 * The host controller has stopped polling of the endpoint.
2508 		 * Now, drain the callbacks if there are any on the callback
2509 		 * queue.
2510 		 */
2511 		if (rval == USB_SUCCESS) {
2512 			mutex_enter(&ph_data->p_mutex);
2513 
2514 			/*
2515 			 * there is a tiny window that the client driver
2516 			 * may still have restarted the polling and we
2517 			 * let the stop polling win
2518 			 */
2519 			rval = usba_drain_cbs(ph_data, 0,
2520 						USB_CR_STOPPED_POLLING);
2521 			mutex_exit(&ph_data->p_mutex);
2522 			if (rval != USB_SUCCESS) {
2523 
2524 				continue;
2525 			}
2526 		}
2527 
2528 		break;
2529 	}
2530 
2531 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2532 	    "usba_pipe_sync_stop_isoc_polling: rval=0x%x", rval);
2533 
2534 	usba_release_ph_data(ph_impl);
2535 
2536 	return (rval);
2537 }
2538 
2539 
2540 /*
2541  * usb_pipe_stop_isoc_polling:
2542  *	stop polling for isoc IN data
2543  *
2544  * Arguments:
2545  *	pipe_handle	- pipe handle
2546  *	flags		-
2547  *			USB_FLAGS_SLEEP:	wait for completion
2548  */
2549 void
2550 usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle,
2551 		usb_flags_t	flags)
2552 {
2553 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
2554 
2555 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2556 	    "usba_pipe_stop_isoc_polling: uf=0x%x", flags);
2557 
2558 	if (ph_data == NULL) {
2559 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2560 		    "usba_pipe_stop_isoc_polling: pipe closed");
2561 
2562 		return;
2563 	}
2564 
2565 	if ((ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK) !=
2566 	    USB_EP_ATTR_ISOCH) {
2567 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2568 		    "usba_pipe_stop_isoc_polling: wrong pipe type");
2569 
2570 		usba_release_ph_data(ph_data->p_ph_impl);
2571 
2572 		return;
2573 	}
2574 	if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2575 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2576 		    "usba_pipe_stop_isoc_polling: wrong pipe direction");
2577 
2578 		usba_release_ph_data(ph_data->p_ph_impl);
2579 
2580 		return;
2581 	}
2582 
2583 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2584 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2585 		    "usba_pipe_stop_intr_polling: invalid context");
2586 
2587 		usba_release_ph_data(ph_data->p_ph_impl);
2588 
2589 		return;
2590 	}
2591 
2592 	(void) usba_pipe_setup_func_call(ph_data->p_dip,
2593 	    usba_pipe_sync_stop_isoc_polling,
2594 	    (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
2595 	    flags, usba_dummy_callback, NULL);
2596 }
2597