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