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