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