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