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