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