xref: /illumos-gate/usr/src/uts/common/io/usb/usba/usbai_req.c (revision d321a33cdd896e6b211d113a33698dd76e89b861)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #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 : ((data) ? *data : NULL);
1338 	ctrl_req->ctrl_timeout		= USB_PIPE_TIMEOUT;
1339 	ctrl_req->ctrl_attributes	= attributes | USB_ATTRS_AUTOCLEARING;
1340 
1341 	/* Issue control xfer to the HCD */
1342 	rval = usb_pipe_ctrl_xfer(pipe_handle, ctrl_req,
1343 	    flags | USB_FLAGS_SLEEP);
1344 
1345 #ifdef DEBUG
1346 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1347 	    "req=0x%p, cr=%s cb_flags=%s data=0x%p rval=%s",
1348 	    ctrl_req, usb_str_cr(ctrl_req->ctrl_completion_reason),
1349 	    usb_str_cb_flags(ctrl_req->ctrl_cb_flags, buf, BUFSIZE),
1350 	    ctrl_req->ctrl_data, usb_str_rval(rval));
1351 #endif
1352 
1353 	/* copy back ctrl_req values */
1354 	if (data) {
1355 		*data			= ctrl_req->ctrl_data;
1356 	}
1357 	if (completion_reason) {
1358 		*completion_reason	= ctrl_req->ctrl_completion_reason;
1359 	}
1360 	if (cb_flags) {
1361 		*cb_flags		= ctrl_req->ctrl_cb_flags;
1362 	}
1363 
1364 	/* Free up the control request now */
1365 	ctrl_req->ctrl_data = NULL; /* leave to client to free */
1366 	usb_free_ctrl_req(ctrl_req);
1367 
1368 done:
1369 #ifdef DEBUG
1370 	kmem_free(buf, BUFSIZE);
1371 #endif
1372 	if (ph_data) {
1373 		usba_release_ph_data(ph_data->p_ph_impl);
1374 	}
1375 
1376 	return (rval);
1377 }
1378 
1379 
1380 /*
1381  * usb_pipe_ctrl_xfer_wait():
1382  *	Easy-to-use wrapper around usb_pipe_sync_ctrl_xfer.
1383  *
1384  * ARGUMENTS:
1385  *	pipe_handle	- control pipe pipehandle (obtained via usb_pipe_open())
1386  *	setup		- setup descriptor params, attributes
1387  *	data		- pointer to pointer to data and may be NULL when
1388  *			  wLength is 0
1389  *	completion_reason - completion status.
1390  *	cb_flags	- request completions flags.
1391  *	flags		- none.
1392  *
1393  * RETURN VALUES:
1394  *	USB_SUCCESS	- request successfully executed.
1395  *	USB_*		- failure
1396  */
1397 int
1398 usb_pipe_ctrl_xfer_wait(
1399 		usb_pipe_handle_t	pipe_handle,
1400 		usb_ctrl_setup_t	*setup,
1401 		mblk_t			**data,
1402 		usb_cr_t		*completion_reason,
1403 		usb_cb_flags_t		*cb_flags,
1404 		usb_flags_t		flags)
1405 {
1406 	return (usb_pipe_sync_ctrl_xfer(
1407 	    usba_get_dip(pipe_handle),
1408 	    pipe_handle,
1409 	    setup->bmRequestType,
1410 	    setup->bRequest,
1411 	    setup->wValue,
1412 	    setup->wIndex,
1413 	    setup->wLength,
1414 	    data,
1415 	    setup->attrs,
1416 	    completion_reason,
1417 	    cb_flags,
1418 	    flags));
1419 }
1420 
1421 
1422 /*
1423  * usb_alloc_bulk_req:
1424  *	Allocate a usb bulk request + usba_req_wrapper_t
1425  *
1426  * Arguments:
1427  *	dip	- dev_info_t of the client driver
1428  *	len	- length of "data" for this bulk request
1429  *	flags:
1430  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
1431  *
1432  * Return Values:
1433  *	usb_bulk_req_t on success, NULL on failure
1434  */
1435 usb_bulk_req_t *
1436 usb_alloc_bulk_req(dev_info_t	*dip,
1437 		size_t		len,
1438 		usb_flags_t	flags)
1439 {
1440 	usb_bulk_req_t		*bulk_req = NULL;
1441 	usba_req_wrapper_t	*wrp;
1442 
1443 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1444 	    "usb_alloc_bulk_req: dip=0x%p wlen=0x%lx flags=0x%x",
1445 	    dip, len, flags);
1446 
1447 	/* Allocate + Initialize the usba_req_wrapper_t structure */
1448 	if (dip &&
1449 	    ((wrp = usba_req_wrapper_alloc(dip, sizeof (*bulk_req), flags)) !=
1450 	    NULL)) {
1451 		bulk_req = USBA_WRP2BULK_REQ(wrp);
1452 
1453 		/* Allocate the usb_bulk_req data mblk */
1454 		if (len) {
1455 			if (flags & USB_FLAGS_SLEEP) {
1456 				bulk_req->bulk_data = allocb_wait(len,
1457 				    BPRI_LO, STR_NOSIG, NULL);
1458 			} else	if ((bulk_req->bulk_data =
1459 			    allocb(len, BPRI_HI)) == NULL) {
1460 				usba_req_wrapper_free(wrp);
1461 				bulk_req = NULL;
1462 			}
1463 		}
1464 
1465 	}
1466 
1467 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1468 	    "usb_alloc_bulk_req: bulk_req = 0x%p", bulk_req);
1469 
1470 	return (bulk_req);
1471 }
1472 
1473 
1474 /*
1475  * usb_free_bulk_req:
1476  *	free USB bulk request + wrapper
1477  *
1478  * Arguments:
1479  *	req - pointer to usb_bulk_req_t
1480  */
1481 void
1482 usb_free_bulk_req(usb_bulk_req_t *req)
1483 {
1484 	if (req) {
1485 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1486 		    "usb_free_bulk_req: req=0x%p", req);
1487 
1488 		if (req->bulk_data) {
1489 			freemsg(req->bulk_data);
1490 		}
1491 		usba_req_wrapper_free(USBA_REQ2WRP(req));
1492 	}
1493 }
1494 
1495 
1496 /*
1497  * Client driver calls this function to issue the bulk xfer to the USBA
1498  *
1499  * Arguments:-
1500  *	pipe_handle - bulk pipe handle (obtained via usb_pipe_open()
1501  *	req	    - bulk data xfer request (IN or OUT)
1502  *	usb_flags   - USB_FLAGS_SLEEP - wait for the request to complete
1503  *
1504  * Return Values:
1505  *	USB_SUCCESS - success
1506  *	USB_FAILURE - unspecified failure
1507  */
1508 int
1509 usb_pipe_bulk_xfer(usb_pipe_handle_t	pipe_handle,
1510 		usb_bulk_req_t		*req,
1511 		usb_flags_t		usb_flags)
1512 {
1513 	int			rval;
1514 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
1515 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
1516 	usba_device_t		*usba_device;
1517 	usb_flags_t		wrp_usb_flags;
1518 	usb_pipe_state_t	pipe_state;
1519 
1520 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1521 	    "usb_pipe_bulk_xfer: req=0x%p uf=0x%x", req, usb_flags);
1522 
1523 	if (ph_data == NULL) {
1524 
1525 		return (USB_INVALID_PIPE);
1526 	}
1527 
1528 	mutex_enter(&ph_data->p_mutex);
1529 	usba_device = ph_data->p_usba_device;
1530 
1531 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
1532 	    USB_EP_ATTR_BULK)) != USB_SUCCESS) {
1533 		mutex_exit(&ph_data->p_mutex);
1534 
1535 		usba_release_ph_data(ph_data->p_ph_impl);
1536 
1537 		return (rval);
1538 	}
1539 
1540 	/* we accepted the request */
1541 	ph_data->p_req_count++;
1542 	wrp_usb_flags = wrp->wr_usb_flags;
1543 
1544 	/* Get the current bulk pipe state */
1545 	pipe_state = usba_get_ph_state(ph_data);
1546 
1547 	/*
1548 	 * if there is already an active request in the queue
1549 	 * then just add this request to the queue.
1550 	 */
1551 	switch (pipe_state) {
1552 	case USB_PIPE_STATE_IDLE:
1553 		if (ph_data->p_queue.next) {
1554 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1555 			    "usb_pipe_bulk_xfer: queue request 0x%p", req);
1556 
1557 			usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1558 			rval = USB_SUCCESS;
1559 			mutex_exit(&ph_data->p_mutex);
1560 		} else {
1561 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
1562 			mutex_exit(&ph_data->p_mutex);
1563 
1564 			/* issue the request to HCD */
1565 			rval = usba_device->usb_hcdi_ops->
1566 			    usba_hcdi_pipe_bulk_xfer(ph_data, req, usb_flags);
1567 		}
1568 		break;
1569 	case USB_PIPE_STATE_ACTIVE:
1570 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1571 		    "usb_pipe_bulk_xfer: queue request 0x%p", req);
1572 
1573 		usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
1574 		rval = USB_SUCCESS;
1575 		mutex_exit(&ph_data->p_mutex);
1576 		break;
1577 	default:
1578 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1579 		    "usb_pipe_bulk_xfer: pipe state %d", pipe_state);
1580 
1581 		rval = USB_PIPE_ERROR;
1582 		mutex_exit(&ph_data->p_mutex);
1583 		break;
1584 	}
1585 
1586 	if (rval != USB_SUCCESS) {
1587 		if (req->bulk_completion_reason == USB_CR_OK) {
1588 			req->bulk_completion_reason = usba_rval2cr(rval);
1589 		}
1590 		mutex_enter(&ph_data->p_mutex);
1591 		ASSERT(wrp->wr_done == B_FALSE);
1592 		ph_data->p_req_count--;
1593 		ASSERT(ph_data->p_req_count >= 0);
1594 		if ((ph_data->p_req_count == 0) &&
1595 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
1596 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1597 		}
1598 		mutex_exit(&ph_data->p_mutex);
1599 	} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
1600 		rval = usba_pipe_sync_wait(ph_data, wrp);
1601 	}
1602 
1603 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1604 	    "usb_pipe_bulk_xfer: rval=%d", rval);
1605 
1606 	usba_release_ph_data(ph_data->p_ph_impl);
1607 
1608 	return (rval);
1609 }
1610 
1611 
1612 /*
1613  * usb_pipe_bulk_transfer_size:
1614  *	- request HCD to return bulk max transfer data size
1615  *
1616  * Arguments:
1617  *	dip	- pointer to dev_info_t
1618  *	size	- pointer to bulk_transfer_size
1619  *
1620  * Return Values:
1621  *	USB_SUCCESS	- request successfully executed
1622  *	USB_FAILURE	- request failed
1623  */
1624 int
1625 usb_pipe_bulk_transfer_size(dev_info_t	*dip,
1626 			size_t		*size)
1627 {
1628 	return (usb_pipe_get_max_bulk_transfer_size(dip, size));
1629 }
1630 
1631 
1632 int
1633 usb_pipe_get_max_bulk_transfer_size(dev_info_t	*dip,
1634 			size_t		*size)
1635 {
1636 	usba_device_t	*usba_device;
1637 
1638 	if ((dip == NULL) || (size == NULL)) {
1639 
1640 		return (USB_INVALID_ARGS);
1641 	}
1642 	usba_device = usba_get_usba_device(dip);
1643 
1644 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1645 	    "usb_pipe_bulk_transfer_size: usba_device=0x%p", usba_device);
1646 
1647 	if ((usba_device) &&
1648 	    (usba_device->usb_hcdi_ops->usba_hcdi_bulk_transfer_size)) {
1649 
1650 		return (usba_device->usb_hcdi_ops->
1651 		    usba_hcdi_bulk_transfer_size(usba_device, size));
1652 	} else {
1653 		*size = 0;
1654 
1655 		return (USB_FAILURE);
1656 	}
1657 }
1658 
1659 
1660 /*
1661  * usb_alloc_intr_req:
1662  *	Allocate usb interrupt request
1663  *
1664  * Arguments:
1665  *	dip	- dev_info_t of the client driver
1666  *	len	- length of "data" for this interrupt request
1667  *	flags	-
1668  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
1669  *
1670  * Return Values:
1671  *		usb_intr_req_t on success, NULL on failure
1672  */
1673 usb_intr_req_t *
1674 usb_alloc_intr_req(dev_info_t	*dip,
1675 		size_t		len,
1676 		usb_flags_t	flags)
1677 {
1678 	usb_intr_req_t	*intr_req = NULL;
1679 	usba_req_wrapper_t	*wrp;
1680 
1681 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1682 	    "usb_alloc_intr_req: dip=0x%p, len=0x%lx, flags=0x%x",
1683 	    dip, len, flags);
1684 
1685 	/* Allocate + Initialize the usba_req_wrapper_t structure */
1686 	if ((dip &&
1687 	    (wrp = usba_req_wrapper_alloc(dip, sizeof (*intr_req), flags)) !=
1688 	    NULL)) {
1689 		intr_req = (usb_intr_req_t *)USBA_WRP2INTR_REQ(wrp);
1690 
1691 		/* Allocate the usb_intr_req data mblk */
1692 		if (len) {
1693 			if (flags & USB_FLAGS_SLEEP) {
1694 				intr_req->intr_data = allocb_wait(len, BPRI_LO,
1695 				    STR_NOSIG, NULL);
1696 			} else	if ((intr_req->intr_data =
1697 			    allocb(len, BPRI_HI)) == NULL) {
1698 				usba_req_wrapper_free(wrp);
1699 				intr_req = NULL;
1700 			}
1701 		}
1702 	}
1703 
1704 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1705 	    "usb_alloc_intr_req: intr_req=0x%p", intr_req);
1706 
1707 	return (intr_req);
1708 }
1709 
1710 
1711 /*
1712  * usba_hcdi_dup_intr_req:
1713  *	create duplicate of interrupt request
1714  *
1715  * Arguments:
1716  *	dip	- devinfo pointer
1717  *	reqp	- original requestp pointer
1718  *	len	- length of "data" for this interrupt request
1719  *	flags	-
1720  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
1721  *
1722  * Return Values:
1723  *		usb_intr_req_t on success, NULL on failure
1724  */
1725 usb_intr_req_t *
1726 usba_hcdi_dup_intr_req(
1727 		dev_info_t	*dip,
1728 		usb_intr_req_t	*reqp,
1729 		size_t		len,
1730 		usb_flags_t	flags)
1731 {
1732 	usb_intr_req_t		*intr_reqp = NULL;
1733 	usba_req_wrapper_t	*intr_wrp, *req_wrp;
1734 
1735 	if (reqp == NULL) {
1736 
1737 		return (NULL);
1738 	}
1739 
1740 	req_wrp	= USBA_REQ2WRP(reqp);
1741 
1742 	if (((intr_reqp = usb_alloc_intr_req(dip, len, flags)) != NULL)) {
1743 		intr_reqp->intr_client_private	= reqp->intr_client_private;
1744 		intr_reqp->intr_timeout		= reqp->intr_timeout;
1745 		intr_reqp->intr_attributes	= reqp->intr_attributes;
1746 		intr_reqp->intr_len		= reqp->intr_len;
1747 		intr_reqp->intr_cb		= reqp->intr_cb;
1748 		intr_reqp->intr_exc_cb		= reqp->intr_exc_cb;
1749 
1750 		intr_wrp		= USBA_REQ2WRP(intr_reqp);
1751 		intr_wrp->wr_dip	= req_wrp->wr_dip;
1752 		intr_wrp->wr_ph_data	= req_wrp->wr_ph_data;
1753 		intr_wrp->wr_attrs	= req_wrp->wr_attrs;
1754 		intr_wrp->wr_usb_flags	= req_wrp->wr_usb_flags;
1755 	}
1756 
1757 	return (intr_reqp);
1758 }
1759 
1760 
1761 /*
1762  * usb_free_intr_req:
1763  *	free USB intr request + wrapper
1764  *
1765  * Arguments:
1766  *	req - pointer to usb_intr_req_t
1767  */
1768 void
1769 usb_free_intr_req(usb_intr_req_t *req)
1770 {
1771 	if (req) {
1772 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1773 		    "usb_free_intr_req: req = 0x%p", req);
1774 
1775 		if (req->intr_data) {
1776 			freemsg(req->intr_data);
1777 		}
1778 
1779 		usba_req_wrapper_free(USBA_REQ2WRP(req));
1780 	}
1781 }
1782 
1783 
1784 /*
1785  * Client driver calls this function to issue the intr xfer to the USBA
1786  *
1787  * Arguments:-
1788  *	pipe_handle	- intr pipe handle (obtained via usb_pipe_open()
1789  *	req		- intr data xfer request (IN or OUT)
1790  *	flags		-
1791  *			   USB_FLAGS_SLEEP - wait for the request to complete
1792  * Return Values
1793  *	USB_SUCCESS	- success
1794  *	USB_FAILURE	- unspecified failure
1795  */
1796 int
1797 usb_pipe_intr_xfer(usb_pipe_handle_t	pipe_handle,
1798 		usb_intr_req_t		*req,
1799 		usb_flags_t		usb_flags)
1800 {
1801 	int			rval;
1802 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
1803 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
1804 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
1805 	usba_device_t		*usba_device;
1806 	uchar_t			direction;
1807 	usb_flags_t		wrp_usb_flags;
1808 	usb_pipe_state_t	pipe_state;
1809 
1810 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1811 	    "usb_pipe_intr_req: req=0x%p uf=0x%x",
1812 	    req, usb_flags);
1813 
1814 	if (ph_data == NULL) {
1815 
1816 		return (USB_INVALID_PIPE);
1817 	}
1818 	usba_device = ph_data->p_usba_device;
1819 	direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
1820 
1821 	mutex_enter(&ph_data->p_mutex);
1822 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
1823 	    USB_EP_ATTR_INTR)) != USB_SUCCESS) {
1824 		mutex_exit(&ph_data->p_mutex);
1825 
1826 		usba_release_ph_data(ph_data->p_ph_impl);
1827 
1828 		return (rval);
1829 	}
1830 
1831 	/* Get the current interrupt pipe state */
1832 	pipe_state = usba_get_ph_state(ph_data);
1833 
1834 	switch (pipe_state) {
1835 	case USB_PIPE_STATE_IDLE:
1836 		/*
1837 		 * if the pipe state is in middle of transition,
1838 		 * i.e. stop polling is in progress, fail any
1839 		 * attempt to do a start polling
1840 		 */
1841 		mutex_enter(&ph_impl->usba_ph_mutex);
1842 		if (ph_impl->usba_ph_state_changing > 0) {
1843 			mutex_exit(&ph_impl->usba_ph_mutex);
1844 
1845 			mutex_exit(&ph_data->p_mutex);
1846 			usba_release_ph_data(ph_data->p_ph_impl);
1847 
1848 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1849 			    "usb_pipe_intr_req: fail request - "
1850 			    "stop polling in progress");
1851 
1852 			return (USB_FAILURE);
1853 		} else {
1854 			mutex_exit(&ph_impl->usba_ph_mutex);
1855 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
1856 		}
1857 
1858 		break;
1859 	case USB_PIPE_STATE_ACTIVE:
1860 		/*
1861 		 * If this is interrupt IN pipe and if we are
1862 		 * already polling, return failure.
1863 		 */
1864 		if (direction == USB_EP_DIR_IN) {
1865 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
1866 			    usbai_log_handle,
1867 			    "usb_pipe_intr_req: already polling");
1868 
1869 			mutex_exit(&ph_data->p_mutex);
1870 			usba_release_ph_data(ph_data->p_ph_impl);
1871 
1872 			return (USB_FAILURE);
1873 		}
1874 
1875 		break;
1876 	default:
1877 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1878 		    "usb_pipe_intr_req: pipe state %d", pipe_state);
1879 
1880 		mutex_exit(&ph_data->p_mutex);
1881 		usba_release_ph_data(ph_data->p_ph_impl);
1882 
1883 		return (USB_PIPE_ERROR);
1884 	}
1885 
1886 	/* we accept the request */
1887 	wrp_usb_flags = wrp->wr_usb_flags;
1888 	ph_data->p_req_count++;
1889 
1890 	mutex_exit(&ph_data->p_mutex);
1891 
1892 	/* issue the request out */
1893 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_intr_xfer(ph_data,
1894 	    req, usb_flags)) != USB_SUCCESS) {
1895 
1896 		/* the request failed, decrement the ref_count */
1897 		if (req->intr_completion_reason == USB_CR_OK) {
1898 			req->intr_completion_reason = usba_rval2cr(rval);
1899 		}
1900 		mutex_enter(&ph_data->p_mutex);
1901 		ASSERT(wrp->wr_done == B_FALSE);
1902 		ph_data->p_req_count--;
1903 		ASSERT(ph_data->p_req_count >= 0);
1904 		if ((ph_data->p_req_count == 0) &&
1905 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
1906 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1907 		}
1908 		mutex_exit(&ph_data->p_mutex);
1909 
1910 	/* if sleep specified, wait for completion */
1911 	} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
1912 		rval = usba_pipe_sync_wait(ph_data, wrp);
1913 	}
1914 
1915 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1916 	    "usb_pipe_intr_req: rval=0x%x", rval);
1917 
1918 	usba_release_ph_data(ph_data->p_ph_impl);
1919 
1920 	return (rval);
1921 }
1922 
1923 
1924 /*
1925  * usba_pipe_sync_stop_intr_polling:
1926  *	- set up for sync transport, if necessary
1927  *	- request HCD to stop polling
1928  *	- wait for draining of all callbacks
1929  */
1930 /*ARGSUSED*/
1931 static int
1932 usba_pipe_sync_stop_intr_polling(dev_info_t	*dip,
1933 		usba_ph_impl_t		*ph_impl,
1934 		usba_pipe_async_req_t	*request,
1935 		usb_flags_t		flags)
1936 {
1937 	int rval;
1938 	usba_pipe_handle_data_t *ph_data;
1939 	usba_device_t	*usba_device;
1940 
1941 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1942 	    "usba_pipe_sync_stop_intr_polling: flags=0x%x", flags);
1943 
1944 	ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_impl);
1945 	if (ph_data == NULL) {
1946 		usba_release_ph_data(ph_impl);
1947 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1948 		    "usba_pipe_sync_stop_intr_polling: pipe closed");
1949 
1950 		return (USB_INVALID_PIPE);
1951 	}
1952 
1953 	usba_device = ph_data->p_usba_device;
1954 
1955 	mutex_enter(&ph_data->p_mutex);
1956 
1957 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
1958 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1959 		    "usba_pipe_sync_stop_intr_polling: pipe error");
1960 		mutex_exit(&ph_data->p_mutex);
1961 
1962 		usba_release_ph_data(ph_impl);
1963 
1964 		return (USB_PIPE_ERROR);
1965 	}
1966 
1967 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
1968 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1969 		    "usba_pipe_sync_stop_intr_polling: already idle");
1970 		mutex_exit(&ph_data->p_mutex);
1971 
1972 		usba_release_ph_data(ph_impl);
1973 
1974 		return (USB_SUCCESS);
1975 	}
1976 	mutex_exit(&ph_data->p_mutex);
1977 
1978 	mutex_enter(&ph_impl->usba_ph_mutex);
1979 	ph_impl->usba_ph_state_changing++;
1980 	mutex_exit(&ph_impl->usba_ph_mutex);
1981 
1982 	flags |= USB_FLAGS_SLEEP;
1983 
1984 	for (;;) {
1985 		rval = usba_device->usb_hcdi_ops->
1986 		    usba_hcdi_pipe_stop_intr_polling(ph_data, flags);
1987 
1988 		/*
1989 		 * The host controller has stopped polling of the endpoint.
1990 		 * Now, drain the callbacks if there are any on the callback
1991 		 * queue.
1992 		 */
1993 		if (rval == USB_SUCCESS) {
1994 			mutex_enter(&ph_data->p_mutex);
1995 
1996 			/*
1997 			 * there is a tiny window that the client driver
1998 			 * may still have restarted the polling and we
1999 			 * have to let the stop polling win)
2000 			 */
2001 			rval = usba_drain_cbs(ph_data, 0,
2002 			    USB_CR_STOPPED_POLLING);
2003 			mutex_exit(&ph_data->p_mutex);
2004 			if (rval != USB_SUCCESS) {
2005 
2006 				continue;
2007 			}
2008 		}
2009 
2010 		break;
2011 	}
2012 
2013 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2014 	    "usba_pipe_sync_stop_intr_polling: rval=0x%x", rval);
2015 
2016 	mutex_enter(&ph_impl->usba_ph_mutex);
2017 	ph_impl->usba_ph_state_changing--;
2018 	mutex_exit(&ph_impl->usba_ph_mutex);
2019 
2020 	usba_release_ph_data(ph_impl);
2021 
2022 	return (rval);
2023 }
2024 
2025 
2026 /*
2027  * dummy callback function for stop polling
2028  */
2029 static void
2030 usba_dummy_callback(
2031 	usb_pipe_handle_t ph,
2032 	usb_opaque_t arg,
2033 	int rval,
2034 	usb_cb_flags_t flags)
2035 {
2036 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2037 	    "usba_dummy_callback: "
2038 	    "ph=0x%p rval=0x%x flags=0x%x cb_arg=0x%p",
2039 	    ph, rval, flags, arg);
2040 }
2041 
2042 
2043 /*
2044  * usb_pipe_stop_intr_polling:
2045  *	stop polling for interrupt pipe IN data
2046  *	The HCD doesn't do a usba_hcdi_cb().
2047  *	It just returns success/failure
2048  * Arguments:
2049  *	pipe_handle	- pipe handle
2050  *	flags		-
2051  *			USB_FLAGS_SLEEP:	wait for completion
2052  */
2053 void
2054 usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle,
2055 	usb_flags_t	flags)
2056 {
2057 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
2058 
2059 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2060 	    "usba_pipe_stop_intr_polling: flags=0x%x", flags);
2061 
2062 	if (ph_data == NULL) {
2063 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2064 		    "usba_pipe_stop_intr_polling: pipe closed");
2065 
2066 		return;
2067 	}
2068 
2069 	if ((ph_data->p_ep.bmAttributes &
2070 	    USB_EP_ATTR_MASK) != USB_EP_ATTR_INTR) {
2071 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2072 		    "usba_pipe_stop_intr_polling: wrong pipe type");
2073 
2074 		usba_release_ph_data(ph_data->p_ph_impl);
2075 
2076 		return;
2077 	}
2078 
2079 	if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2080 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2081 		    "usba_pipe_stop_intr_polling: wrong pipe direction");
2082 
2083 		usba_release_ph_data(ph_data->p_ph_impl);
2084 
2085 		return;
2086 	}
2087 
2088 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2089 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2090 		    "usba_pipe_stop_intr_polling: invalid context");
2091 
2092 		usba_release_ph_data(ph_data->p_ph_impl);
2093 
2094 		return;
2095 	}
2096 
2097 	(void) usba_pipe_setup_func_call(ph_data->p_dip,
2098 	    usba_pipe_sync_stop_intr_polling,
2099 	    (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
2100 	    flags, usba_dummy_callback, NULL);
2101 }
2102 
2103 
2104 /*
2105  * usb_alloc_isoc_req:
2106  *	- Allocate usb isochronous resources that includes usb isochronous
2107  *	  request and array of packet descriptor structures and wrapper.
2108  *
2109  * Arguments:
2110  *	dip		- dev_info_t of the client driver
2111  *	isoc_pkts_count - number of isoc_pkt_descr_t's
2112  *	len		- length of "data" for this isochronous request
2113  *	flags		-
2114  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
2115  *		no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
2116  *
2117  * Return Values:
2118  *	usb_isoc_req_t on success, NULL on failure
2119  */
2120 /*ARGSUSED*/
2121 usb_isoc_req_t *
2122 usb_alloc_isoc_req(dev_info_t		*dip,
2123 		uint_t			isoc_pkts_count,
2124 		size_t			len,
2125 		usb_flags_t		flags)
2126 {
2127 	usb_isoc_req_t		*isoc_req = NULL;
2128 	usba_req_wrapper_t	*wrp;
2129 	size_t			length = sizeof (*isoc_req) +
2130 	    (sizeof (usb_isoc_pkt_descr_t) * isoc_pkts_count);
2131 
2132 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2133 	    "usb_alloc_isoc_req: dip=0x%p pkt_cnt=%d len=%lu flags=0x%x",
2134 	    dip, isoc_pkts_count, len, flags);
2135 
2136 	/* client needs to set isoc_pks_count */
2137 	if (dip && isoc_pkts_count) {
2138 		/* Allocate + Initialize the usba_req_wrapper_t structure */
2139 		if ((wrp = usba_req_wrapper_alloc(dip, length, flags)) !=
2140 		    NULL) {
2141 			isoc_req = (usb_isoc_req_t *)USBA_WRP2ISOC_REQ(wrp);
2142 
2143 			/* Allocate the usb_isoc_req data mblk */
2144 			if (len) {
2145 				if ((isoc_req->isoc_data =
2146 				    allocb(len, BPRI_HI)) == NULL) {
2147 					usba_req_wrapper_free(wrp);
2148 					isoc_req = NULL;
2149 				}
2150 			}
2151 		}
2152 	}
2153 
2154 	if (isoc_req) {
2155 		isoc_req->isoc_pkt_descr = (usb_isoc_pkt_descr_t *)
2156 		    (((intptr_t)isoc_req) + (sizeof (usb_isoc_req_t)));
2157 
2158 		/* Initialize all the fields of usb isochronous request */
2159 		isoc_req->isoc_pkts_count = isoc_pkts_count;
2160 	}
2161 
2162 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2163 	    "usb_alloc_isoc_req: isoc_req = 0x%p", isoc_req);
2164 
2165 	return (isoc_req);
2166 }
2167 
2168 
2169 /*
2170  * usba_hcdi_dup_isoc_req:
2171  *	create duplicate of isoc request
2172  *
2173  * Arguments:
2174  *	dip	- devinfo pointer
2175  *	reqp	- original request pointer
2176  *	len	- length of "data" for this isoc request
2177  *	flags	-
2178  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
2179  *
2180  * Return Values:
2181  *		usb_isoc_req_t on success, NULL on failure
2182  */
2183 usb_isoc_req_t *
2184 usba_hcdi_dup_isoc_req(
2185 		dev_info_t	*dip,
2186 		usb_isoc_req_t	*reqp,
2187 		usb_flags_t	flags)
2188 {
2189 	usb_isoc_req_t		*isoc_reqp = NULL;
2190 	usba_req_wrapper_t	*isoc_wrp, *req_wrp;
2191 	ushort_t		count;
2192 	ushort_t		isoc_pkts_count;
2193 	size_t			length;
2194 
2195 	if (reqp == NULL) {
2196 
2197 		return (isoc_reqp);
2198 	}
2199 
2200 	isoc_pkts_count = reqp->isoc_pkts_count;
2201 
2202 	/* calculate total data length required in original request */
2203 	for (count = length = 0; count < isoc_pkts_count; count++) {
2204 		length += reqp->isoc_pkt_descr[count].isoc_pkt_length;
2205 	}
2206 
2207 	req_wrp	= USBA_REQ2WRP(reqp);
2208 
2209 	if (((isoc_reqp = usb_alloc_isoc_req(dip,
2210 	    isoc_pkts_count, length, flags)) != NULL)) {
2211 		isoc_reqp->isoc_frame_no	= reqp->isoc_frame_no;
2212 		isoc_reqp->isoc_pkts_count	= reqp->isoc_pkts_count;
2213 		isoc_reqp->isoc_pkts_length	= reqp->isoc_pkts_length;
2214 		isoc_reqp->isoc_attributes	= reqp->isoc_attributes;
2215 		isoc_reqp->isoc_client_private	= reqp->isoc_client_private;
2216 		isoc_reqp->isoc_cb		= reqp->isoc_cb;
2217 		isoc_reqp->isoc_exc_cb		= reqp->isoc_exc_cb;
2218 
2219 		isoc_wrp		= USBA_REQ2WRP(isoc_reqp);
2220 		isoc_wrp->wr_dip	= req_wrp->wr_dip;
2221 		isoc_wrp->wr_ph_data	= req_wrp->wr_ph_data;
2222 		isoc_wrp->wr_attrs	= req_wrp->wr_attrs;
2223 		isoc_wrp->wr_usb_flags	= req_wrp->wr_usb_flags;
2224 
2225 		for (count = 0; count < isoc_pkts_count; count++) {
2226 			isoc_reqp->isoc_pkt_descr[count].isoc_pkt_length =
2227 			    reqp->isoc_pkt_descr[count].isoc_pkt_length;
2228 		}
2229 	}
2230 
2231 	return (isoc_reqp);
2232 }
2233 
2234 
2235 /*
2236  * usb_free_isoc_req:
2237  *	- Deallocate usb isochronous resources that includes usb isochronous
2238  *	  request and array of packet descriptor strcutures.
2239  *
2240  * Arguments:
2241  *	req - pointer to usb_isoc_req_t
2242  */
2243 void
2244 usb_free_isoc_req(usb_isoc_req_t *req)
2245 {
2246 	if (req) {
2247 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2248 		    "usb_free_isoc_req: req=0x%p", req);
2249 
2250 		if (req->isoc_data) {
2251 			freemsg(req->isoc_data);
2252 		}
2253 
2254 		usba_req_wrapper_free(USBA_REQ2WRP(req));
2255 	}
2256 }
2257 
2258 
2259 /*
2260  * usb_get_current_frame_number:
2261  *	- request HCD to return current usb frame number
2262  *
2263  * Arguments:
2264  *	dip	- pointer to dev_info_t
2265  *
2266  * Return Values:
2267  *	current_frame_number	- request successfully executed
2268  *	0			- request failed
2269  */
2270 usb_frame_number_t
2271 usb_get_current_frame_number(dev_info_t	*dip)
2272 {
2273 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2274 	    "usb_get_current_frame_number: dip=0x%p", dip);
2275 
2276 	if (dip) {
2277 		usba_device_t	*usba_device = usba_get_usba_device(dip);
2278 		usb_frame_number_t	frame_number;
2279 
2280 		if (usba_device->usb_hcdi_ops->
2281 		    usba_hcdi_get_current_frame_number) {
2282 
2283 			if (usba_device->usb_hcdi_ops->
2284 			    usba_hcdi_get_current_frame_number(usba_device,
2285 			    &frame_number) == USB_SUCCESS) {
2286 
2287 				return (frame_number);
2288 			}
2289 		}
2290 	}
2291 
2292 	return (0);
2293 }
2294 
2295 
2296 /*
2297  * usb_get_max_isoc_pkts:
2298  *	- request HCD to return maximum isochronous packets per request
2299  *
2300  * Arguments:
2301  *	dip	- pointer to dev_info_t
2302  *
2303  * Return Values:
2304  *	isoc_pkt - request successfully executed
2305  *	0	 - request failed
2306  */
2307 uint_t
2308 usb_get_max_isoc_pkts(dev_info_t *dip)
2309 {
2310 	return (usb_get_max_pkts_per_isoc_request(dip));
2311 }
2312 
2313 
2314 uint_t
2315 usb_get_max_pkts_per_isoc_request(dev_info_t *dip)
2316 {
2317 	if (dip) {
2318 		usba_device_t	*usba_device = usba_get_usba_device(dip);
2319 		uint_t		max_isoc_pkts_per_request;
2320 
2321 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2322 		    "usb_get_max_isoc_pkts: usba_device=0x%p", usba_device);
2323 
2324 		if (usba_device->usb_hcdi_ops->usba_hcdi_get_max_isoc_pkts) {
2325 
2326 			if (usba_device->usb_hcdi_ops->
2327 			    usba_hcdi_get_max_isoc_pkts(usba_device,
2328 			    &max_isoc_pkts_per_request) == USB_SUCCESS) {
2329 
2330 				return (max_isoc_pkts_per_request);
2331 			}
2332 		}
2333 	}
2334 
2335 	return (0);
2336 }
2337 
2338 
2339 /*
2340  * usb_pipe_isoc_xfer:
2341  *	- check for pipe stalled
2342  *	- request HCD to transport isoc data asynchronously
2343  *
2344  * Arguments:
2345  *	pipe_handle	- isoc pipe pipehandle (obtained via usb_pipe_open())
2346  *	req		- isochronous request
2347  *
2348  * Return Values:
2349  *	USB_SUCCESS	- request successfully executed
2350  *	USB_FAILURE	- request failed
2351  */
2352 int
2353 usb_pipe_isoc_xfer(usb_pipe_handle_t	pipe_handle,
2354 		usb_isoc_req_t		*req,
2355 		usb_flags_t		flags)
2356 {
2357 	int			rval;
2358 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
2359 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
2360 	usba_device_t		*usba_device;
2361 	uchar_t			direction;
2362 	usb_pipe_state_t	pipe_state;
2363 
2364 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2365 	    "usb_pipe_isoc_xfer: flags=0x%x", flags);
2366 
2367 	if (ph_data == NULL) {
2368 
2369 		return (USB_INVALID_PIPE);
2370 	}
2371 
2372 	usba_device = ph_data->p_usba_device;
2373 	direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
2374 
2375 	mutex_enter(&ph_data->p_mutex);
2376 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, flags,
2377 	    USB_EP_ATTR_ISOCH)) != USB_SUCCESS) {
2378 		mutex_exit(&ph_data->p_mutex);
2379 
2380 		usba_release_ph_data(ph_data->p_ph_impl);
2381 
2382 		return (rval);
2383 	}
2384 
2385 	req->isoc_error_count = 0;
2386 
2387 	/* Get the current isoch pipe state */
2388 	pipe_state = usba_get_ph_state(ph_data);
2389 
2390 	switch (pipe_state) {
2391 	case USB_PIPE_STATE_IDLE:
2392 		usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
2393 		break;
2394 	case USB_PIPE_STATE_ACTIVE:
2395 		if (direction == USB_EP_DIR_IN) {
2396 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
2397 			    usbai_log_handle,
2398 			    "usb_pipe_isoc_req: already polling");
2399 
2400 			mutex_exit(&ph_data->p_mutex);
2401 			usba_release_ph_data(ph_data->p_ph_impl);
2402 
2403 			return (USB_FAILURE);
2404 		}
2405 		break;
2406 	default:
2407 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2408 		    "usb_pipe_isoc_req: pipe state %d", pipe_state);
2409 
2410 		mutex_exit(&ph_data->p_mutex);
2411 		usba_release_ph_data(ph_data->p_ph_impl);
2412 
2413 		return (USB_PIPE_ERROR);
2414 	}
2415 
2416 	/* we accept the request */
2417 	ph_data->p_req_count++;
2418 	mutex_exit(&ph_data->p_mutex);
2419 
2420 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_isoc_xfer(
2421 	    ph_data, req, flags)) != USB_SUCCESS) {
2422 		if (req->isoc_completion_reason == USB_CR_OK) {
2423 			req->isoc_completion_reason = usba_rval2cr(rval);
2424 		}
2425 		mutex_enter(&ph_data->p_mutex);
2426 		ASSERT(wrp->wr_done == B_FALSE);
2427 		ph_data->p_req_count--;
2428 		if ((ph_data->p_req_count == 0) &&
2429 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
2430 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
2431 		}
2432 		mutex_exit(&ph_data->p_mutex);
2433 	}
2434 
2435 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2436 	    "usb_pipe_isoc_req: rval=%x", rval);
2437 
2438 	usba_release_ph_data(ph_data->p_ph_impl);
2439 
2440 	return (rval);
2441 }
2442 
2443 
2444 /*
2445  * usba_pipe_sync_stop_isoc_polling:
2446  *	- set up for sync transport, if necessary
2447  *	- request HCD to stop polling
2448  *	- wait for draining of all callbacks
2449  *
2450  * Arguments:
2451  *	dip		- dev_info pointer
2452  *	pipe_handle	- pointer to pipe handle
2453  *	flags		- USB_FLAGS_SLEEP:	wait for completion
2454  */
2455 /*ARGSUSED*/
2456 static int
2457 usba_pipe_sync_stop_isoc_polling(dev_info_t	*dip,
2458 		usba_ph_impl_t		*ph_impl,
2459 		usba_pipe_async_req_t	*request,
2460 		usb_flags_t		flags)
2461 {
2462 	int rval;
2463 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
2464 	    (usb_pipe_handle_t)ph_impl);
2465 	usba_device_t	*usba_device;
2466 
2467 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2468 	    "usba_pipe_sync_stop_isoc_polling: uf=0x%x", flags);
2469 
2470 	if (ph_data == NULL) {
2471 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2472 		    "usba_pipe_stop_isoc_polling: pipe closed");
2473 
2474 		return (USB_INVALID_PIPE);
2475 	}
2476 
2477 	usba_device = ph_data->p_usba_device;
2478 
2479 	mutex_enter(&ph_data->p_mutex);
2480 
2481 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
2482 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2483 		    "usba_pipe_sync_stop_isoc_polling: pipe error");
2484 		mutex_exit(&ph_data->p_mutex);
2485 
2486 		usba_release_ph_data(ph_impl);
2487 
2488 		return (USB_PIPE_ERROR);
2489 	}
2490 
2491 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
2492 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2493 		    "usba_pipe_sync_stop_isoc_polling: already stopped");
2494 		mutex_exit(&ph_data->p_mutex);
2495 
2496 		usba_release_ph_data(ph_impl);
2497 
2498 		return (USB_SUCCESS);
2499 	}
2500 
2501 
2502 	mutex_exit(&ph_data->p_mutex);
2503 
2504 	flags |= USB_FLAGS_SLEEP;
2505 
2506 	for (;;) {
2507 		rval = usba_device->usb_hcdi_ops->
2508 		    usba_hcdi_pipe_stop_isoc_polling(ph_data, flags);
2509 
2510 		/*
2511 		 * The host controller has stopped polling of the endpoint.
2512 		 * Now, drain the callbacks if there are any on the callback
2513 		 * queue.
2514 		 */
2515 		if (rval == USB_SUCCESS) {
2516 			mutex_enter(&ph_data->p_mutex);
2517 
2518 			/*
2519 			 * there is a tiny window that the client driver
2520 			 * may still have restarted the polling and we
2521 			 * let the stop polling win
2522 			 */
2523 			rval = usba_drain_cbs(ph_data, 0,
2524 			    USB_CR_STOPPED_POLLING);
2525 			mutex_exit(&ph_data->p_mutex);
2526 			if (rval != USB_SUCCESS) {
2527 
2528 				continue;
2529 			}
2530 		}
2531 
2532 		break;
2533 	}
2534 
2535 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2536 	    "usba_pipe_sync_stop_isoc_polling: rval=0x%x", rval);
2537 
2538 	usba_release_ph_data(ph_impl);
2539 
2540 	return (rval);
2541 }
2542 
2543 
2544 /*
2545  * usb_pipe_stop_isoc_polling:
2546  *	stop polling for isoc IN data
2547  *
2548  * Arguments:
2549  *	pipe_handle	- pipe handle
2550  *	flags		-
2551  *			USB_FLAGS_SLEEP:	wait for completion
2552  */
2553 void
2554 usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle,
2555 		usb_flags_t	flags)
2556 {
2557 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
2558 
2559 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2560 	    "usba_pipe_stop_isoc_polling: uf=0x%x", flags);
2561 
2562 	if (ph_data == NULL) {
2563 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2564 		    "usba_pipe_stop_isoc_polling: pipe closed");
2565 
2566 		return;
2567 	}
2568 
2569 	if ((ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK) !=
2570 	    USB_EP_ATTR_ISOCH) {
2571 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2572 		    "usba_pipe_stop_isoc_polling: wrong pipe type");
2573 
2574 		usba_release_ph_data(ph_data->p_ph_impl);
2575 
2576 		return;
2577 	}
2578 	if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2579 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2580 		    "usba_pipe_stop_isoc_polling: wrong pipe direction");
2581 
2582 		usba_release_ph_data(ph_data->p_ph_impl);
2583 
2584 		return;
2585 	}
2586 
2587 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2588 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
2589 		    "usba_pipe_stop_intr_polling: invalid context");
2590 
2591 		usba_release_ph_data(ph_data->p_ph_impl);
2592 
2593 		return;
2594 	}
2595 
2596 	(void) usba_pipe_setup_func_call(ph_data->p_dip,
2597 	    usba_pipe_sync_stop_isoc_polling,
2598 	    (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
2599 	    flags, usba_dummy_callback, NULL);
2600 }
2601