xref: /onnv-gate/usr/src/uts/common/io/usb/usba/usbai_req.c (revision 7492:2387323b838f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52495Sgc161489  * Common Development and Distribution License (the "License").
62495Sgc161489  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
225773Sqz150045  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * functions that deal with allocation/free/data_xfers
310Sstevel@tonic-gate  * for the  control/bulk/interrupt/isoch pipes:
320Sstevel@tonic-gate  *	usb_alloc_ctrl_req()
330Sstevel@tonic-gate  *	usb_free_ctrl_req()
340Sstevel@tonic-gate  *	usb_pipe_ctrl_xfer()
350Sstevel@tonic-gate  *	usb_pipe_sync_ctrl_xfer()
360Sstevel@tonic-gate  *	usb_pipe_ctrl_xfer_wait()
370Sstevel@tonic-gate  *
380Sstevel@tonic-gate  *	usb_alloc_bulk_req()
390Sstevel@tonic-gate  *	usb_free_bulk_req()
400Sstevel@tonic-gate  *	usb_pipe_bulk_xfer()
410Sstevel@tonic-gate  *	usb_pipe_bulk_transfer_size()
420Sstevel@tonic-gate  *
430Sstevel@tonic-gate  *	usb_alloc_intr_req()
440Sstevel@tonic-gate  *	usb_free_intr_req()
450Sstevel@tonic-gate  *	usb_pipe_intr_xfer()
460Sstevel@tonic-gate  *	usb_pipe_stop_intr_polling()
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  *	usb_alloc_isoc_req()
490Sstevel@tonic-gate  *	usb_free_isoc_req()
500Sstevel@tonic-gate  *	usb_get_current_frame_number()
510Sstevel@tonic-gate  *	usb_get_max_isoc_pkts()
520Sstevel@tonic-gate  *	usb_pipe_isoc_xfer()
530Sstevel@tonic-gate  *	usb_pipe_stop_isoc_polling()
540Sstevel@tonic-gate  *
550Sstevel@tonic-gate  * XXX to do:
560Sstevel@tonic-gate  *	update return values where needed
570Sstevel@tonic-gate  *	keep track of requests not freed
580Sstevel@tonic-gate  *
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate #define	USBA_FRAMEWORK
610Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
620Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
630Sstevel@tonic-gate #include <sys/strsubr.h>
64*7492SZhigang.Lu@Sun.COM #include <sys/strsun.h>
650Sstevel@tonic-gate 
660Sstevel@tonic-gate /* prototypes */
670Sstevel@tonic-gate static int usba_flags_attr_check(usba_pipe_handle_data_t *,
680Sstevel@tonic-gate 			usb_req_attrs_t attrs, usb_flags_t);
690Sstevel@tonic-gate static int _usba_check_req(usba_pipe_handle_data_t *, usb_opaque_t,
700Sstevel@tonic-gate 			usb_flags_t, uchar_t);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * usba_check_req:
740Sstevel@tonic-gate  *	check pipe, request structure for validity
750Sstevel@tonic-gate  *
760Sstevel@tonic-gate  * Arguments:
770Sstevel@tonic-gate  *	ph		- pipe handle pointer
780Sstevel@tonic-gate  *	req		- opaque request pointer
790Sstevel@tonic-gate  *	flags		- usb flags
800Sstevel@tonic-gate  *
810Sstevel@tonic-gate  * Returns:
820Sstevel@tonic-gate  *	USB_SUCCESS		- valid request
830Sstevel@tonic-gate  *	USB_INVALID_REQUEST	- request contains some invalid values
840Sstevel@tonic-gate  *	USB_PIPE_ERROR		- pipe is in error state
850Sstevel@tonic-gate  *	USB_INVALID_CONTEXT	- sleep in interrupt context
860Sstevel@tonic-gate  *	USB_INVALID_PIPE	- zero pipe or wrong pipe
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate static int
usba_check_req(usba_pipe_handle_data_t * ph_data,usb_opaque_t req,usb_flags_t flags,uchar_t pipe_type)890Sstevel@tonic-gate usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req,
900Sstevel@tonic-gate 		usb_flags_t flags, uchar_t pipe_type)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	int rval = _usba_check_req(ph_data, req, flags, pipe_type);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
950Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
960Sstevel@tonic-gate 		    "usba_check_req: ph_data=0x%p req=0x%p flags=0%x rval=%d",
976898Sfb209375 		    (void *)ph_data, (void *)req, flags, rval);
980Sstevel@tonic-gate 	}
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	return (rval);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate static int
_usba_check_req(usba_pipe_handle_data_t * ph_data,usb_opaque_t req,usb_flags_t flags,uchar_t pipe_type)1050Sstevel@tonic-gate _usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req,
1060Sstevel@tonic-gate 		usb_flags_t flags, uchar_t pipe_type)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_req = (usb_ctrl_req_t *)req;
1090Sstevel@tonic-gate 	usb_bulk_req_t		*bulk_req = (usb_bulk_req_t *)req;
1100Sstevel@tonic-gate 	usb_intr_req_t		*intr_req = (usb_intr_req_t *)req;
1110Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_req = (usb_isoc_req_t *)req;
1120Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
1130Sstevel@tonic-gate 	mblk_t			*data;
1140Sstevel@tonic-gate 	usb_cr_t		*cr;
1150Sstevel@tonic-gate 	usb_req_attrs_t		attrs;
1160Sstevel@tonic-gate 	usb_opaque_t		cb, exc_cb;
1170Sstevel@tonic-gate 	uint_t			timeout = 0;
1180Sstevel@tonic-gate 	uchar_t			direction = ph_data->p_ep.bEndpointAddress &
1195773Sqz150045 	    USB_EP_DIR_MASK;
1200Sstevel@tonic-gate 	uchar_t			ep_attrs = ph_data->p_ep.bmAttributes &
1215773Sqz150045 	    USB_EP_ATTR_MASK;
1220Sstevel@tonic-gate 	int			n;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1250Sstevel@tonic-gate 	    "usba_check_req: ph_data=0x%p req=0x%p flags=0x%x",
1266898Sfb209375 	    (void *)ph_data, (void *)req, flags);
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	if (req == NULL) {
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	/* set completion reason first so it specifies an error */
1340Sstevel@tonic-gate 	switch (ep_attrs) {
1350Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
1360Sstevel@tonic-gate 		cr = &ctrl_req->ctrl_completion_reason;
1370Sstevel@tonic-gate 		break;
1380Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
1390Sstevel@tonic-gate 		cr = &bulk_req->bulk_completion_reason;
1400Sstevel@tonic-gate 		break;
1410Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
1420Sstevel@tonic-gate 		cr = &intr_req->intr_completion_reason;
1430Sstevel@tonic-gate 		break;
1440Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
1450Sstevel@tonic-gate 		cr = &isoc_req->isoc_completion_reason;
1460Sstevel@tonic-gate 		break;
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	*cr = USB_CR_UNSPECIFIED_ERR;
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	if (pipe_type != ep_attrs) {
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	/* we must have usba_device and default ph to do autoclearing */
1620Sstevel@tonic-gate 	ASSERT(ph_data->p_usba_device);
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	if (ph_data->p_usba_device->usb_ph_list[0].usba_ph_data == NULL) {
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	/* check if this is a valid request packet, ie. not freed */
1700Sstevel@tonic-gate 	if (usba_check_in_list(&(ph_data->p_usba_device->usb_allocated),
1710Sstevel@tonic-gate 	    &wrp->wr_allocated_list) != USB_SUCCESS) {
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 		return (USB_INVALID_REQUEST);
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	/* copy over some members for easy checking later */
1770Sstevel@tonic-gate 	switch (ep_attrs) {
1780Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
1790Sstevel@tonic-gate 		ctrl_req->ctrl_cb_flags = USB_CB_NO_INFO;
1800Sstevel@tonic-gate 		data = ctrl_req->ctrl_data;
1810Sstevel@tonic-gate 		attrs = ctrl_req->ctrl_attributes;
1820Sstevel@tonic-gate 		timeout = ctrl_req->ctrl_timeout;
1830Sstevel@tonic-gate 		cb = (usb_opaque_t)ctrl_req->ctrl_cb;
1840Sstevel@tonic-gate 		exc_cb = (usb_opaque_t)ctrl_req->ctrl_exc_cb;
1850Sstevel@tonic-gate 		if (flags & USB_FLAGS_SLEEP) {
1860Sstevel@tonic-gate 			flags |= USBA_WRP_FLAGS_WAIT;
1870Sstevel@tonic-gate 		}
1880Sstevel@tonic-gate 		/* force auto clearing on the default pipe */
1890Sstevel@tonic-gate 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1900Sstevel@tonic-gate 			attrs |= USB_ATTRS_AUTOCLEARING;
1910Sstevel@tonic-gate 		}
1920Sstevel@tonic-gate 		break;
1930Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
1940Sstevel@tonic-gate 		bulk_req->bulk_cb_flags = USB_CB_NO_INFO;
1950Sstevel@tonic-gate 		data = bulk_req->bulk_data;
1960Sstevel@tonic-gate 		attrs = bulk_req->bulk_attributes;
1970Sstevel@tonic-gate 		timeout = bulk_req->bulk_timeout;
1980Sstevel@tonic-gate 		cb = (usb_opaque_t)bulk_req->bulk_cb;
1990Sstevel@tonic-gate 		exc_cb = (usb_opaque_t)bulk_req->bulk_exc_cb;
2000Sstevel@tonic-gate 		if (flags & USB_FLAGS_SLEEP) {
2010Sstevel@tonic-gate 			flags |= USBA_WRP_FLAGS_WAIT;
2020Sstevel@tonic-gate 		}
2030Sstevel@tonic-gate 		break;
2040Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
2050Sstevel@tonic-gate 		intr_req->intr_cb_flags = USB_CB_NO_INFO;
2060Sstevel@tonic-gate 		data = intr_req->intr_data;
2070Sstevel@tonic-gate 		attrs = intr_req->intr_attributes;
2080Sstevel@tonic-gate 		timeout = intr_req->intr_timeout;
2090Sstevel@tonic-gate 		cb = (usb_opaque_t)intr_req->intr_cb;
2100Sstevel@tonic-gate 		exc_cb = (usb_opaque_t)intr_req->intr_exc_cb;
2110Sstevel@tonic-gate 		if ((flags & USB_FLAGS_SLEEP) &&
2120Sstevel@tonic-gate 		    (attrs & USB_ATTRS_ONE_XFER)) {
2130Sstevel@tonic-gate 			flags |= USBA_WRP_FLAGS_WAIT;
2140Sstevel@tonic-gate 		}
2150Sstevel@tonic-gate 		break;
2160Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
2170Sstevel@tonic-gate 		isoc_req->isoc_cb_flags = USB_CB_NO_INFO;
2180Sstevel@tonic-gate 		data = isoc_req->isoc_data;
2190Sstevel@tonic-gate 		attrs = isoc_req->isoc_attributes;
2200Sstevel@tonic-gate 		cb = (usb_opaque_t)isoc_req->isoc_cb;
2210Sstevel@tonic-gate 		exc_cb = (usb_opaque_t)isoc_req->isoc_exc_cb;
2220Sstevel@tonic-gate 		break;
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2260Sstevel@tonic-gate 	    "usba_check_req: attrs = 0x%x flags=0x%x", attrs, flags);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	/* check flags and attr combinations */
2290Sstevel@tonic-gate 	if (usba_flags_attr_check(ph_data, attrs, flags) !=
2300Sstevel@tonic-gate 	    USB_SUCCESS) {
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 		return (USB_INVALID_REQUEST);
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/* if no sleep, there must be callback ptrs */
2360Sstevel@tonic-gate 	if ((flags & USB_FLAGS_SLEEP) == 0) {
2370Sstevel@tonic-gate 		if (cb == NULL || exc_cb == NULL) {
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 			return (USB_INVALID_REQUEST);
2400Sstevel@tonic-gate 		}
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	switch (ep_attrs) {
2440Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
2450Sstevel@tonic-gate 		if (ctrl_req->ctrl_wLength && (data == NULL)) {
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 			return (USB_INVALID_REQUEST);
2480Sstevel@tonic-gate 		}
2490Sstevel@tonic-gate 		break;
2500Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
2512495Sgc161489 		if ((bulk_req->bulk_len) && (data == NULL)) {
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 			return (USB_INVALID_REQUEST);
2540Sstevel@tonic-gate 		}
2550Sstevel@tonic-gate 		break;
2560Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
2570Sstevel@tonic-gate 		if (direction == USB_EP_DIR_OUT) {
2582495Sgc161489 			if (intr_req->intr_len && data == NULL) {
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 				return (USB_INVALID_REQUEST);
2610Sstevel@tonic-gate 			}
2620Sstevel@tonic-gate 		}
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		if (direction == USB_EP_DIR_IN) {
2650Sstevel@tonic-gate 			if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER)) {
2660Sstevel@tonic-gate 				if (cb == NULL || exc_cb == NULL) {
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 					return (USB_INVALID_REQUEST);
2690Sstevel@tonic-gate 				}
2700Sstevel@tonic-gate 			}
2710Sstevel@tonic-gate 			if (data != NULL) {
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 				return (USB_INVALID_REQUEST);
2740Sstevel@tonic-gate 			}
2750Sstevel@tonic-gate 			if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER) &&
2760Sstevel@tonic-gate 			    (timeout > 0)) {
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 				return (USB_INVALID_REQUEST);
2790Sstevel@tonic-gate 			}
2800Sstevel@tonic-gate 		}
2810Sstevel@tonic-gate 		break;
2820Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
2830Sstevel@tonic-gate 		if (direction == USB_EP_DIR_IN) {
2840Sstevel@tonic-gate 			if (cb == NULL || exc_cb == NULL) {
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 				return (USB_INVALID_REQUEST);
2870Sstevel@tonic-gate 			}
2880Sstevel@tonic-gate 		}
2890Sstevel@tonic-gate 
2902735Sgc161489 		if (data == NULL) {
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 			return (USB_INVALID_REQUEST);
2930Sstevel@tonic-gate 		}
2940Sstevel@tonic-gate 
2952735Sgc161489 		/*
2962735Sgc161489 		 * Since ehci/ohci/uhci use (data->b_wptr - data->b_rptr) as
2972735Sgc161489 		 * real isoc_pkts_length, it should be checked.
2982735Sgc161489 		 */
2992735Sgc161489 		if (direction == USB_EP_DIR_OUT) {
300*7492SZhigang.Lu@Sun.COM 			if (MBLKL(data) <= 0) {
3012735Sgc161489 
3022735Sgc161489 				return (USB_INVALID_REQUEST);
3032735Sgc161489 			}
3042735Sgc161489 		}
3052735Sgc161489 
3060Sstevel@tonic-gate 		/* special isoc checks */
3070Sstevel@tonic-gate 		if ((isoc_req->isoc_pkts_count == 0) ||
3080Sstevel@tonic-gate 		    (isoc_req->isoc_pkt_descr == NULL)) {
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 			return (USB_INVALID_REQUEST);
3110Sstevel@tonic-gate 		}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 		/* check attributes for conflicts, one must be specified */
3140Sstevel@tonic-gate 		if (!((isoc_req->isoc_attributes &
3150Sstevel@tonic-gate 		    USB_ATTRS_ISOC_START_FRAME) ||
3160Sstevel@tonic-gate 		    (isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP))) {
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 			return (USB_NO_FRAME_NUMBER);
3190Sstevel@tonic-gate 		}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 		/* both may not be specified */
3220Sstevel@tonic-gate 		if ((isoc_req->isoc_attributes &
3230Sstevel@tonic-gate 		    (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) ==
3240Sstevel@tonic-gate 		    (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) {
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 			return (USB_NO_FRAME_NUMBER);
3270Sstevel@tonic-gate 		}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		/* no start frame may be specified for ASAP attribute */
3300Sstevel@tonic-gate 		if (((isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP)) &&
3310Sstevel@tonic-gate 		    isoc_req->isoc_frame_no) {
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 			return (USB_INVALID_REQUEST);
3340Sstevel@tonic-gate 		}
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 		/* start frame must be specified for START FRAME attribute */
3370Sstevel@tonic-gate 		if (((isoc_req->isoc_attributes &
3380Sstevel@tonic-gate 		    USB_ATTRS_ISOC_START_FRAME)) &&
3390Sstevel@tonic-gate 		    (isoc_req->isoc_frame_no == 0)) {
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 			return (USB_NO_FRAME_NUMBER);
3420Sstevel@tonic-gate 		}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 		/* each packet must have initialized pkt length */
3450Sstevel@tonic-gate 		for (n = 0; n < isoc_req->isoc_pkts_count; n++) {
3460Sstevel@tonic-gate 			if (isoc_req->isoc_pkt_descr[n].isoc_pkt_length == 0) {
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 				return (USB_INVALID_REQUEST);
3490Sstevel@tonic-gate 			}
3500Sstevel@tonic-gate 		}
3510Sstevel@tonic-gate 		break;
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/* save pipe_handle/attrs/timeout/usb_flags */
3550Sstevel@tonic-gate 	wrp->wr_ph_data		= ph_data;
3560Sstevel@tonic-gate 	wrp->wr_usb_flags	= flags;
3570Sstevel@tonic-gate 	wrp->wr_attrs		= attrs;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/* zero some fields in case the request is reused */
3600Sstevel@tonic-gate 	wrp->wr_done		= B_FALSE;
3610Sstevel@tonic-gate 	wrp->wr_cr		= USB_CR_OK;
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/* this request looks good */
3640Sstevel@tonic-gate 	*cr = USB_CR_OK;
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	return (USB_SUCCESS);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate /*
3710Sstevel@tonic-gate  * Table of invalid flags and attributes values. See "usbai.h"
3720Sstevel@tonic-gate  * for a complete table on valid usb_req_attrs_t
3730Sstevel@tonic-gate  */
3740Sstevel@tonic-gate #define	X	((uint_t)(-1))
3750Sstevel@tonic-gate #define	OUT	USB_EP_DIR_OUT
3760Sstevel@tonic-gate #define	IN	USB_EP_DIR_IN
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate struct	flags_attr {
3790Sstevel@tonic-gate 	uint_t		ep_dir;
3800Sstevel@tonic-gate 	uint_t		ep_attr;
3810Sstevel@tonic-gate 	uint_t		usb_flags;	/* usb_flags SLEEP or none */
3820Sstevel@tonic-gate 	uint_t		attrs;
3830Sstevel@tonic-gate } usb_invalid_flags_attrs[] = {
3840Sstevel@tonic-gate { OUT,	USB_EP_ATTR_BULK,	X,	USB_ATTRS_SHORT_XFER_OK },
3850Sstevel@tonic-gate { OUT,	USB_EP_ATTR_INTR,	X,	USB_ATTRS_SHORT_XFER_OK },
3860Sstevel@tonic-gate { OUT,	USB_EP_ATTR_ISOCH,	X,	USB_ATTRS_SHORT_XFER_OK },
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate { X,	USB_EP_ATTR_CONTROL,	X,	USB_ATTRS_ISOC_START_FRAME },
3890Sstevel@tonic-gate { X,	USB_EP_ATTR_BULK,	X,	USB_ATTRS_ISOC_START_FRAME },
3900Sstevel@tonic-gate { X,	USB_EP_ATTR_INTR,	X,	USB_ATTRS_ISOC_START_FRAME },
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate { X,	USB_EP_ATTR_CONTROL,	X,	USB_ATTRS_ISOC_XFER_ASAP },
3930Sstevel@tonic-gate { X,	USB_EP_ATTR_INTR,	X,	USB_ATTRS_ISOC_XFER_ASAP },
3940Sstevel@tonic-gate { OUT,	USB_EP_ATTR_INTR,	X,	USB_ATTRS_ONE_XFER },
3950Sstevel@tonic-gate { X,	USB_EP_ATTR_BULK,	X,	USB_ATTRS_ISOC_XFER_ASAP },
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate { X,	USB_EP_ATTR_CONTROL,	X,	USB_ATTRS_ONE_XFER },
3980Sstevel@tonic-gate { X,	USB_EP_ATTR_BULK,	X,	USB_ATTRS_ONE_XFER },
3990Sstevel@tonic-gate { X,	USB_EP_ATTR_ISOCH,	X,	USB_ATTRS_ONE_XFER },
4000Sstevel@tonic-gate };
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate #define	N_INVALID_FLAGS_ATTRS	(sizeof (usb_invalid_flags_attrs))/ \
4030Sstevel@tonic-gate 					sizeof (struct flags_attr)
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate  * function to check flags and attribute combinations for a particular pipe
4070Sstevel@tonic-gate  * Arguments:
4080Sstevel@tonic-gate  *	ph	- pipe handle pointer
4090Sstevel@tonic-gate  *	attrs	- attributes of the request
4100Sstevel@tonic-gate  *	flags	- usb_flags
4110Sstevel@tonic-gate  */
4120Sstevel@tonic-gate static int
usba_flags_attr_check(usba_pipe_handle_data_t * ph_data,usb_req_attrs_t attrs,usb_flags_t flags)4130Sstevel@tonic-gate usba_flags_attr_check(usba_pipe_handle_data_t *ph_data,
4140Sstevel@tonic-gate 		usb_req_attrs_t attrs,
4150Sstevel@tonic-gate 		usb_flags_t flags)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate 	uchar_t i;
4180Sstevel@tonic-gate 	uchar_t	ep_dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
4190Sstevel@tonic-gate 	uchar_t ep_attr = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	flags &= USB_FLAGS_SLEEP; /* ignore other flags */
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	/*
4240Sstevel@tonic-gate 	 * Do some attributes validation checks here.
4250Sstevel@tonic-gate 	 */
4260Sstevel@tonic-gate 	for (i = 0; i < N_INVALID_FLAGS_ATTRS; i++) {
4270Sstevel@tonic-gate 		if (((ep_dir == usb_invalid_flags_attrs[i].ep_dir) ||
4285773Sqz150045 		    (usb_invalid_flags_attrs[i].ep_dir == X)) &&
4290Sstevel@tonic-gate 		    ((ep_attr == usb_invalid_flags_attrs[i].ep_attr) ||
4305773Sqz150045 		    (usb_invalid_flags_attrs[i].ep_attr == X)) &&
4310Sstevel@tonic-gate 		    ((flags & usb_invalid_flags_attrs[i].usb_flags) ||
4325773Sqz150045 		    (usb_invalid_flags_attrs[i].usb_flags == X)) &&
4330Sstevel@tonic-gate 		    ((attrs & usb_invalid_flags_attrs[i].attrs) ||
4345773Sqz150045 		    (usb_invalid_flags_attrs[i].attrs == X))) {
4350Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
4360Sstevel@tonic-gate 			    "invalid (%d) : flags = 0x%x, attrs = 0x%x",
4370Sstevel@tonic-gate 			    i, flags, attrs);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 			return (USB_INVALID_REQUEST);
4400Sstevel@tonic-gate 		}
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	return (USB_SUCCESS);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate  * usba_rval2cr:
4490Sstevel@tonic-gate  *	convert rval to meaningful completion reason
4500Sstevel@tonic-gate  * XXX extend completion reasons to get better mapping
4510Sstevel@tonic-gate  */
4520Sstevel@tonic-gate static struct {
4530Sstevel@tonic-gate 	int	rval;
4540Sstevel@tonic-gate 	usb_cr_t cr;
4550Sstevel@tonic-gate } rval2cr[] = {
4560Sstevel@tonic-gate 	{USB_SUCCESS,		USB_CR_OK},
4570Sstevel@tonic-gate 	{USB_FAILURE,		USB_CR_UNSPECIFIED_ERR},
4580Sstevel@tonic-gate 	{USB_NO_RESOURCES,	USB_CR_NO_RESOURCES},
4590Sstevel@tonic-gate 	{USB_NO_BANDWIDTH,	USB_CR_NO_RESOURCES},
4600Sstevel@tonic-gate 	{USB_NOT_SUPPORTED,	USB_CR_UNSPECIFIED_ERR},
4610Sstevel@tonic-gate 	{USB_PIPE_ERROR,	USB_CR_UNSPECIFIED_ERR},
4620Sstevel@tonic-gate 	{USB_INVALID_PIPE,	USB_CR_UNSPECIFIED_ERR},
4630Sstevel@tonic-gate 	{USB_NO_FRAME_NUMBER,	USB_CR_UNSPECIFIED_ERR},
4640Sstevel@tonic-gate 	{USB_INVALID_START_FRAME, USB_CR_UNSPECIFIED_ERR},
4650Sstevel@tonic-gate 	{USB_HC_HARDWARE_ERROR, USB_CR_UNSPECIFIED_ERR},
4660Sstevel@tonic-gate 	{USB_INVALID_REQUEST,	USB_CR_UNSPECIFIED_ERR},
4670Sstevel@tonic-gate 	{USB_INVALID_CONTEXT,	USB_CR_UNSPECIFIED_ERR},
4680Sstevel@tonic-gate 	{USB_INVALID_VERSION,	USB_CR_UNSPECIFIED_ERR},
4690Sstevel@tonic-gate 	{USB_INVALID_ARGS,	USB_CR_UNSPECIFIED_ERR},
4700Sstevel@tonic-gate 	{USB_INVALID_PERM,	USB_CR_UNSPECIFIED_ERR},
4710Sstevel@tonic-gate 	{USB_BUSY,		USB_CR_UNSPECIFIED_ERR},
4720Sstevel@tonic-gate 	{0xffff,		0}
4730Sstevel@tonic-gate };
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate usb_cr_t
usba_rval2cr(int rval)4760Sstevel@tonic-gate usba_rval2cr(int rval)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate 	int i;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	for (i = 0; rval2cr[i].rval != 0xffff; i++) {
4810Sstevel@tonic-gate 		if (rval2cr[i].rval == rval) {
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 			return (rval2cr[i].cr);
4840Sstevel@tonic-gate 		}
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	return (USB_CR_UNSPECIFIED_ERR);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate /*
4920Sstevel@tonic-gate  * usba_start_next_req:
4930Sstevel@tonic-gate  *	Arguments:
4940Sstevel@tonic-gate  *	ph_data		- pointer to pipe handle
4950Sstevel@tonic-gate  *
4960Sstevel@tonic-gate  * Currently, only ctrl/bulk requests can be queued
4970Sstevel@tonic-gate  */
4980Sstevel@tonic-gate void
usba_start_next_req(usba_pipe_handle_data_t * ph_data)4990Sstevel@tonic-gate usba_start_next_req(usba_pipe_handle_data_t *ph_data)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_req;
5020Sstevel@tonic-gate 	usb_bulk_req_t		*bulk_req;
5030Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp;
5040Sstevel@tonic-gate 	uchar_t			ep_attrs = ph_data->p_ep.bmAttributes &
5055773Sqz150045 	    USB_EP_ATTR_MASK;
5060Sstevel@tonic-gate 	int			rval;
5070Sstevel@tonic-gate 	usb_pipe_state_t	state;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
5100Sstevel@tonic-gate 	switch (ep_attrs) {
5110Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
5120Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
5130Sstevel@tonic-gate 		switch (usba_get_ph_state(ph_data)) {
5140Sstevel@tonic-gate 		case USB_PIPE_STATE_IDLE:
5150Sstevel@tonic-gate 		case USB_PIPE_STATE_CLOSING:
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 			break;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		default:
5200Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 			return;
5230Sstevel@tonic-gate 		}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		break;
5260Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
5270Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
5280Sstevel@tonic-gate 	default:
5290Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 		return;
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	while ((wrp = (usba_req_wrapper_t *)
5350Sstevel@tonic-gate 	    usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 		/* only submit to HCD when idle/active */
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
5406898Sfb209375 		    "usba_start_next_req: ph_data=0x%p state=%d",
5416898Sfb209375 		    (void *)ph_data, usba_get_ph_state(ph_data));
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 		if (ep_attrs == USB_EP_ATTR_CONTROL) {
5440Sstevel@tonic-gate 			ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp;
5450Sstevel@tonic-gate 		}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		if ((state = usba_get_ph_state(ph_data)) ==
5480Sstevel@tonic-gate 		    USB_PIPE_STATE_IDLE) {
5490Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
5526898Sfb209375 			    "starting req = 0x%p",
5536898Sfb209375 			    (void *)USBA_WRP2CTRL_REQ(wrp));
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 			switch (ep_attrs) {
5560Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
5570Sstevel@tonic-gate 				mutex_exit(&ph_data->p_mutex);
5580Sstevel@tonic-gate 				ctrl_req = USBA_WRP2CTRL_REQ(wrp);
5590Sstevel@tonic-gate 				/* submit to hcd */
5600Sstevel@tonic-gate 				rval = ph_data->p_usba_device->usb_hcdi_ops->
5610Sstevel@tonic-gate 				    usba_hcdi_pipe_ctrl_xfer(ph_data,
5620Sstevel@tonic-gate 				    ctrl_req, wrp->wr_usb_flags);
5630Sstevel@tonic-gate 				mutex_enter(&ph_data->p_mutex);
5640Sstevel@tonic-gate 				break;
5650Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
5660Sstevel@tonic-gate 				mutex_exit(&ph_data->p_mutex);
5670Sstevel@tonic-gate 				bulk_req = USBA_WRP2BULK_REQ(wrp);
5680Sstevel@tonic-gate 				/* submit to hcd */
5690Sstevel@tonic-gate 				rval = ph_data->p_usba_device->usb_hcdi_ops->
5700Sstevel@tonic-gate 				    usba_hcdi_pipe_bulk_xfer(ph_data,
5710Sstevel@tonic-gate 				    bulk_req, wrp->wr_usb_flags);
5720Sstevel@tonic-gate 				mutex_enter(&ph_data->p_mutex);
5730Sstevel@tonic-gate 				break;
5740Sstevel@tonic-gate 			default:
5750Sstevel@tonic-gate 				/* there shouldn't be any requests */
5760Sstevel@tonic-gate 				rval = USB_FAILURE;
5770Sstevel@tonic-gate 				break;
5780Sstevel@tonic-gate 			}
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 			if (rval != USB_SUCCESS) {
5810Sstevel@tonic-gate 				mutex_exit(&ph_data->p_mutex);
5820Sstevel@tonic-gate 				usba_do_req_exc_cb(wrp,
5830Sstevel@tonic-gate 				    usba_rval2cr(rval),
5840Sstevel@tonic-gate 				    USB_CB_SUBMIT_FAILED);
5850Sstevel@tonic-gate 				mutex_enter(&ph_data->p_mutex);
5860Sstevel@tonic-gate 			}
5870Sstevel@tonic-gate 			/* we are done */
5880Sstevel@tonic-gate 			break;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		} else {
5910Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
5920Sstevel@tonic-gate 			switch (state) {
5930Sstevel@tonic-gate 			case USB_PIPE_STATE_CLOSING:
5940Sstevel@tonic-gate 				usba_do_req_exc_cb(wrp, USB_CR_PIPE_CLOSING, 0);
5950Sstevel@tonic-gate 				break;
5960Sstevel@tonic-gate 			case USB_PIPE_STATE_ERROR:
5970Sstevel@tonic-gate 			default:
5980Sstevel@tonic-gate 				usba_do_req_exc_cb(wrp, USB_CR_FLUSHED, 0);
5990Sstevel@tonic-gate 				break;
6000Sstevel@tonic-gate 			}
6010Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
6020Sstevel@tonic-gate 		}
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6066898Sfb209375 	    "usba_start_next_req done: ph_data=0x%p state=%d", (void *)ph_data,
6070Sstevel@tonic-gate 	    usba_get_ph_state(ph_data));
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate  * usba_req_wrapper_alloc:
6150Sstevel@tonic-gate  *	Allocate + Initialize a usba_req_wrapper_t
6160Sstevel@tonic-gate  *
6170Sstevel@tonic-gate  * Arguments:
6180Sstevel@tonic-gate  *	dip	-  dev_info_t of the client driver
6190Sstevel@tonic-gate  *	req_len	-  sizeof request
6200Sstevel@tonic-gate  *	flags	-
6210Sstevel@tonic-gate  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
6220Sstevel@tonic-gate  *		no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
6230Sstevel@tonic-gate  *
6240Sstevel@tonic-gate  * Return Values:
6250Sstevel@tonic-gate  *	pointer to usba_req_wrapper_t on success; NULL on failure.
6260Sstevel@tonic-gate  *
6270Sstevel@tonic-gate  */
6280Sstevel@tonic-gate static usba_req_wrapper_t *
usba_req_wrapper_alloc(dev_info_t * dip,size_t req_len,usb_flags_t flags)6290Sstevel@tonic-gate usba_req_wrapper_alloc(dev_info_t	*dip,
6300Sstevel@tonic-gate 			size_t		req_len,
6310Sstevel@tonic-gate 			usb_flags_t	flags)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate 	int		kmflag;
6340Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
6350Sstevel@tonic-gate 	usba_req_wrapper_t *wrp;
6360Sstevel@tonic-gate 	size_t		wr_length = sizeof (usba_req_wrapper_t) + req_len;
6370Sstevel@tonic-gate 	ddi_iblock_cookie_t iblock_cookie =
6385773Sqz150045 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
6395773Sqz150045 	    hcdi_iblock_cookie;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 		return (NULL);
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	kmflag = (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	/* Allocate the usb_{c/b/i/i}_req + usba_req_wrapper_t structure */
6490Sstevel@tonic-gate 	if ((wrp = kmem_zalloc(wr_length, kmflag)) != NULL) {
6500Sstevel@tonic-gate 		wrp->wr_length	= wr_length;
6510Sstevel@tonic-gate 		wrp->wr_dip	= dip;
6520Sstevel@tonic-gate 		wrp->wr_req = (usb_opaque_t)USBA_SETREQ_ADDR(wrp);
6530Sstevel@tonic-gate 		cv_init(&wrp->wr_cv, NULL, CV_DRIVER, NULL);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		/* initialize mutex for the queue */
6560Sstevel@tonic-gate 		usba_init_list(&wrp->wr_queue, (usb_opaque_t)wrp,
6575773Sqz150045 		    iblock_cookie);
6580Sstevel@tonic-gate 		usba_init_list(&wrp->wr_allocated_list, (usb_opaque_t)wrp,
6595773Sqz150045 		    iblock_cookie);
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 		usba_add_to_list(&usba_device->usb_allocated,
6620Sstevel@tonic-gate 		    &wrp->wr_allocated_list);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6656898Sfb209375 		    "usba_req_wrapper_alloc: wrp = 0x%p", (void *)wrp);
6660Sstevel@tonic-gate 	}
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	return (wrp);
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate /*
6730Sstevel@tonic-gate  * usba_req_wrapper_free:
6740Sstevel@tonic-gate  *	Frees a usba_req_wrapper_t. Get rid of lists if any.
6750Sstevel@tonic-gate  *
6760Sstevel@tonic-gate  * Arguments:
6770Sstevel@tonic-gate  *	wrp: request wrapper structure
6780Sstevel@tonic-gate  */
6790Sstevel@tonic-gate void
usba_req_wrapper_free(usba_req_wrapper_t * wrp)6800Sstevel@tonic-gate usba_req_wrapper_free(usba_req_wrapper_t *wrp)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate 	usba_device_t		*usba_device;
6830Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph_data;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6866898Sfb209375 	    "usba_req_wrapper_free: wrp=0x%p", (void *)wrp);
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	if (wrp) {
6890Sstevel@tonic-gate 		/* remove from	queues */
6900Sstevel@tonic-gate 		ph_data = USBA_WRP2PH_DATA(wrp);
6910Sstevel@tonic-gate 		if (ph_data) {
6920Sstevel@tonic-gate 			(void) usba_rm_from_list(&ph_data->p_queue,
6935773Sqz150045 			    &wrp->wr_queue);
6940Sstevel@tonic-gate 		}
6950Sstevel@tonic-gate 		usba_device = usba_get_usba_device(wrp->wr_dip);
6960Sstevel@tonic-gate 		if (usba_rm_from_list(&usba_device->usb_allocated,
6970Sstevel@tonic-gate 		    &wrp->wr_allocated_list) != USB_SUCCESS) {
6980Sstevel@tonic-gate 			cmn_err(CE_PANIC,
6990Sstevel@tonic-gate 			    "usba_req_wrapper_free: data corruption");
7000Sstevel@tonic-gate 		}
7010Sstevel@tonic-gate 		usba_destroy_list(&wrp->wr_queue);
7020Sstevel@tonic-gate 		usba_destroy_list(&wrp->wr_allocated_list);
7030Sstevel@tonic-gate 		cv_destroy(&wrp->wr_cv);
7040Sstevel@tonic-gate 		kmem_free(wrp, wrp->wr_length);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate /*
7100Sstevel@tonic-gate  * usba_check_intr_context
7110Sstevel@tonic-gate  *	Set USB_CB_INTR_CONTEXT callback flag if executing in interrupt context
7120Sstevel@tonic-gate  */
7130Sstevel@tonic-gate usb_cb_flags_t
usba_check_intr_context(usb_cb_flags_t cb_flags)7140Sstevel@tonic-gate usba_check_intr_context(usb_cb_flags_t cb_flags)
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate 	if (servicing_interrupt() != 0) {
7170Sstevel@tonic-gate 		cb_flags |= USB_CB_INTR_CONTEXT;
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	return (cb_flags);
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate /*
7250Sstevel@tonic-gate  * usba_req_normal_cb:
7260Sstevel@tonic-gate  *	perform normal callback depending on request type
7270Sstevel@tonic-gate  */
7280Sstevel@tonic-gate void
usba_req_normal_cb(usba_req_wrapper_t * req_wrp)7290Sstevel@tonic-gate usba_req_normal_cb(usba_req_wrapper_t *req_wrp)
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph_data = req_wrp->wr_ph_data;
7320Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle;
7330Sstevel@tonic-gate 	uint_t			direction = ph_data->p_ep.bEndpointAddress &
7345773Sqz150045 	    USB_EP_DIR_MASK;
7350Sstevel@tonic-gate 	usb_pipe_state_t	pipe_state;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	pipe_handle = usba_get_pipe_handle(ph_data);
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
7400Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
7410Sstevel@tonic-gate 	pipe_state = usba_get_ph_state(ph_data);
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
7440Sstevel@tonic-gate 	    "usba_req_normal_cb: "
7450Sstevel@tonic-gate 	    "ph_data=0x%p state=%d wrp=0x%p ref=%d req=%d",
7466898Sfb209375 	    (void *)ph_data, pipe_state, (void *)req_wrp,
7476898Sfb209375 	    usba_get_ph_ref_count(ph_data), ph_data->p_req_count);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	ASSERT((pipe_state == USB_PIPE_STATE_ACTIVE) ||
7500Sstevel@tonic-gate 	    (pipe_state == USB_PIPE_STATE_CLOSING));
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	/* set done to indicate that we will do callback or cv_signal */
7530Sstevel@tonic-gate 	ASSERT(req_wrp->wr_done == B_FALSE);
7540Sstevel@tonic-gate 	req_wrp->wr_done = B_TRUE;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	/* update the pipe state */
7570Sstevel@tonic-gate 	switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
7580Sstevel@tonic-gate 	    USB_EP_ATTR_MASK) {
7590Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
7600Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
7610Sstevel@tonic-gate 		usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
7620Sstevel@tonic-gate 		break;
7630Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
7640Sstevel@tonic-gate 		if ((direction == USB_EP_DIR_IN) &&
7650Sstevel@tonic-gate 		    (USBA_WRP2INTR_REQ(req_wrp)->intr_attributes &
7660Sstevel@tonic-gate 		    USB_ATTRS_ONE_XFER)) {
7670Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
7680Sstevel@tonic-gate 		} else if ((direction == USB_EP_DIR_OUT) &&
7690Sstevel@tonic-gate 		    (ph_data->p_req_count == 0)) {
7700Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
7710Sstevel@tonic-gate 		}
7720Sstevel@tonic-gate 		break;
7730Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
7740Sstevel@tonic-gate 		if ((ph_data->p_req_count == 0) &&
7750Sstevel@tonic-gate 		    (direction == USB_EP_DIR_OUT)) {
7760Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
7770Sstevel@tonic-gate 		}
7780Sstevel@tonic-gate 		break;
7790Sstevel@tonic-gate 	}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	/* now complete the request */
7830Sstevel@tonic-gate 	if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) {
7840Sstevel@tonic-gate 		ph_data->p_active_cntrl_req_wrp = NULL;
7850Sstevel@tonic-gate 		cv_signal(&req_wrp->wr_cv);
7860Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
7870Sstevel@tonic-gate 	} else {
7880Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		/* This sets USB_CB_INTR_CONTEXT as needed. */
7910Sstevel@tonic-gate 		usba_req_set_cb_flags(req_wrp, USB_CB_NO_INFO);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 		switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
7940Sstevel@tonic-gate 		    USB_EP_ATTR_MASK) {
7950Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
7960Sstevel@tonic-gate 			USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb(pipe_handle,
7975773Sqz150045 			    USBA_WRP2CTRL_REQ(req_wrp));
7980Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
7990Sstevel@tonic-gate 			ph_data->p_active_cntrl_req_wrp = NULL;
8000Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
8010Sstevel@tonic-gate 			break;
8020Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
8030Sstevel@tonic-gate 			USBA_WRP2INTR_REQ(req_wrp)->intr_cb(pipe_handle,
8045773Sqz150045 			    USBA_WRP2INTR_REQ(req_wrp));
8050Sstevel@tonic-gate 			break;
8060Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
8070Sstevel@tonic-gate 			USBA_WRP2BULK_REQ(req_wrp)->bulk_cb(pipe_handle,
8085773Sqz150045 			    USBA_WRP2BULK_REQ(req_wrp));
8090Sstevel@tonic-gate 			break;
8100Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
8110Sstevel@tonic-gate 			USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb(pipe_handle,
8125773Sqz150045 			    USBA_WRP2ISOC_REQ(req_wrp));
8130Sstevel@tonic-gate 			break;
8140Sstevel@tonic-gate 		}
8150Sstevel@tonic-gate 	}
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	/* we are done with this request */
8180Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
8190Sstevel@tonic-gate 	ph_data->p_req_count--;
8200Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
8210Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate /*
8260Sstevel@tonic-gate  * usba_req_exc_cb:
8270Sstevel@tonic-gate  *	perform exception cb depending on request type.
8280Sstevel@tonic-gate  *	ensure the completion reason is non zero
8290Sstevel@tonic-gate  */
8300Sstevel@tonic-gate void
usba_req_exc_cb(usba_req_wrapper_t * req_wrp,usb_cr_t cr,usb_cb_flags_t cb_flags)8310Sstevel@tonic-gate usba_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr,
8320Sstevel@tonic-gate     usb_cb_flags_t cb_flags)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
8350Sstevel@tonic-gate 	usb_pipe_handle_t pipe_handle = usba_get_pipe_handle(ph_data);
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	mutex_enter(&req_wrp->wr_ph_data->p_mutex);
8380Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8390Sstevel@tonic-gate 	    "usba_req_exc_cb: %s%d: ph_data=0x%p (ep%x) state=%d wrp=0x%p "
8400Sstevel@tonic-gate 	    "ref=%d reqcnt=%d cr=%d",
8410Sstevel@tonic-gate 	    ddi_driver_name(req_wrp->wr_dip),
8420Sstevel@tonic-gate 	    ddi_get_instance(req_wrp->wr_dip),
8436898Sfb209375 	    (void *)ph_data, ph_data->p_ep.bEndpointAddress,
8446898Sfb209375 	    usba_get_ph_state(ph_data), (void *)req_wrp,
8456898Sfb209375 	    usba_get_ph_ref_count(ph_data), ph_data->p_req_count,
8466898Sfb209375 	    req_wrp->wr_cr);
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	ASSERT(req_wrp->wr_ph_data->p_req_count >= 0);
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	usba_req_set_cb_flags(req_wrp, cb_flags);
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	/* if there was no CR set already, set it now */
8530Sstevel@tonic-gate 	if (req_wrp->wr_cr == USB_CR_OK) {
8540Sstevel@tonic-gate 		req_wrp->wr_cr = (cr != USB_CR_OK)  ?
8555773Sqz150045 		    cr : USB_CR_UNSPECIFIED_ERR;
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	ASSERT(req_wrp->wr_done == B_FALSE);
8590Sstevel@tonic-gate 	req_wrp->wr_done = B_TRUE;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
8620Sstevel@tonic-gate 	    USB_EP_ATTR_MASK) {
8630Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
8640Sstevel@tonic-gate 		if (USBA_WRP2CTRL_REQ(req_wrp)->
8650Sstevel@tonic-gate 		    ctrl_completion_reason == USB_CR_OK) {
8660Sstevel@tonic-gate 			USBA_WRP2CTRL_REQ(req_wrp)->
8670Sstevel@tonic-gate 			    ctrl_completion_reason = req_wrp->wr_cr;
8680Sstevel@tonic-gate 		}
8690Sstevel@tonic-gate 		break;
8700Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
8710Sstevel@tonic-gate 		if (USBA_WRP2INTR_REQ(req_wrp)->
8720Sstevel@tonic-gate 		    intr_completion_reason == USB_CR_OK) {
8730Sstevel@tonic-gate 			USBA_WRP2INTR_REQ(req_wrp)->
8740Sstevel@tonic-gate 			    intr_completion_reason = req_wrp->wr_cr;
8750Sstevel@tonic-gate 		}
8760Sstevel@tonic-gate 		break;
8770Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
8780Sstevel@tonic-gate 		if (USBA_WRP2BULK_REQ(req_wrp)->
8790Sstevel@tonic-gate 		    bulk_completion_reason == USB_CR_OK) {
8800Sstevel@tonic-gate 			USBA_WRP2BULK_REQ(req_wrp)->
8810Sstevel@tonic-gate 			    bulk_completion_reason = req_wrp->wr_cr;
8820Sstevel@tonic-gate 		}
8830Sstevel@tonic-gate 		break;
8840Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
8850Sstevel@tonic-gate 		if (USBA_WRP2ISOC_REQ(req_wrp)->
8860Sstevel@tonic-gate 		    isoc_completion_reason == USB_CR_OK) {
8870Sstevel@tonic-gate 			USBA_WRP2ISOC_REQ(req_wrp)->
8880Sstevel@tonic-gate 			    isoc_completion_reason = req_wrp->wr_cr;
8890Sstevel@tonic-gate 		}
8900Sstevel@tonic-gate 		break;
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) {
8940Sstevel@tonic-gate 		cv_signal(&req_wrp->wr_cv);
8950Sstevel@tonic-gate 		if (ph_data->p_active_cntrl_req_wrp == (usb_opaque_t)req_wrp) {
8960Sstevel@tonic-gate 			ph_data->p_active_cntrl_req_wrp = NULL;
8970Sstevel@tonic-gate 		}
8980Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
8990Sstevel@tonic-gate 	} else {
9000Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
9010Sstevel@tonic-gate 		switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
9020Sstevel@tonic-gate 		    USB_EP_ATTR_MASK) {
9030Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
9040Sstevel@tonic-gate 			USBA_WRP2CTRL_REQ(req_wrp)->ctrl_exc_cb(pipe_handle,
9055773Sqz150045 			    USBA_WRP2CTRL_REQ(req_wrp));
9060Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
9070Sstevel@tonic-gate 			if (ph_data->p_active_cntrl_req_wrp ==
9080Sstevel@tonic-gate 			    (usb_opaque_t)req_wrp) {
9090Sstevel@tonic-gate 				ph_data->p_active_cntrl_req_wrp = NULL;
9100Sstevel@tonic-gate 			}
9110Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
9120Sstevel@tonic-gate 			break;
9130Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
9140Sstevel@tonic-gate 			USBA_WRP2INTR_REQ(req_wrp)->intr_exc_cb(pipe_handle,
9155773Sqz150045 			    USBA_WRP2INTR_REQ(req_wrp));
9160Sstevel@tonic-gate 			break;
9170Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
9180Sstevel@tonic-gate 			USBA_WRP2BULK_REQ(req_wrp)->bulk_exc_cb(pipe_handle,
9195773Sqz150045 			    USBA_WRP2BULK_REQ(req_wrp));
9200Sstevel@tonic-gate 			break;
9210Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
9220Sstevel@tonic-gate 			USBA_WRP2ISOC_REQ(req_wrp)->isoc_exc_cb(pipe_handle,
9235773Sqz150045 			    USBA_WRP2ISOC_REQ(req_wrp));
9240Sstevel@tonic-gate 			break;
9250Sstevel@tonic-gate 		}
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	/* we are done with this request */
9290Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
9300Sstevel@tonic-gate 	ph_data->p_req_count--;
9310Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
9320Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate  * usba_do_req_exc_cb:
9380Sstevel@tonic-gate  *	called when flushing requests. rather than calling usba_req_exc_cb()
9390Sstevel@tonic-gate  *	directly, this function uses usba_hcdi_cb() which ensures callback
9400Sstevel@tonic-gate  *	order is preserved
9410Sstevel@tonic-gate  */
9420Sstevel@tonic-gate void
usba_do_req_exc_cb(usba_req_wrapper_t * req_wrp,usb_cr_t cr,usb_cb_flags_t cb_flags)9430Sstevel@tonic-gate usba_do_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr,
9440Sstevel@tonic-gate     usb_cb_flags_t cb_flags)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate 	req_wrp->wr_cb_flags |= cb_flags;
9470Sstevel@tonic-gate 	usba_hcdi_cb(req_wrp->wr_ph_data, req_wrp->wr_req, cr);
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate /*
9520Sstevel@tonic-gate  * usba_req_set_cb_flags:
9530Sstevel@tonic-gate  * This function sets the request's callback flags to those stored in the
9540Sstevel@tonic-gate  * request wrapper ORed with those received as an argument.  Additionally
9550Sstevel@tonic-gate  * USB_CB_INTR_CONTEXT is set if called from interrupt context.
9560Sstevel@tonic-gate  *
9570Sstevel@tonic-gate  * NOTE: The xfer may have succeeded, which client driver can determine
9580Sstevel@tonic-gate  * by looking at usb_cr_t
9590Sstevel@tonic-gate  */
9600Sstevel@tonic-gate void
usba_req_set_cb_flags(usba_req_wrapper_t * req_wrp,usb_cb_flags_t cb_flags)9610Sstevel@tonic-gate usba_req_set_cb_flags(usba_req_wrapper_t *req_wrp,
9620Sstevel@tonic-gate 		usb_cb_flags_t cb_flags)
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
9650Sstevel@tonic-gate 	    "usba_req_set_cb_flags: wrp=0x%p cb-flags=0x%x",
9666898Sfb209375 	    (void *)req_wrp, cb_flags);
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	cb_flags |= req_wrp->wr_cb_flags;
9690Sstevel@tonic-gate 	cb_flags = usba_check_intr_context(cb_flags);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	/* do the callback under taskq context */
9720Sstevel@tonic-gate 	switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
9730Sstevel@tonic-gate 	    USB_EP_ATTR_MASK) {
9740Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
9750Sstevel@tonic-gate 		USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb_flags |= cb_flags;
9760Sstevel@tonic-gate 		break;
9770Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
9780Sstevel@tonic-gate 		USBA_WRP2INTR_REQ(req_wrp)->intr_cb_flags |= cb_flags;
9790Sstevel@tonic-gate 		break;
9800Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
9810Sstevel@tonic-gate 		USBA_WRP2BULK_REQ(req_wrp)->bulk_cb_flags |= cb_flags;
9820Sstevel@tonic-gate 		break;
9830Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
9840Sstevel@tonic-gate 		USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb_flags |= cb_flags;
9850Sstevel@tonic-gate 		break;
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate /*
9910Sstevel@tonic-gate  * usba_pipe_sync_wait:
9920Sstevel@tonic-gate  *	wait for the request to finish.
9930Sstevel@tonic-gate  *	usba_hcdi_cb() does a cv_signal thru a soft intr
9940Sstevel@tonic-gate  *
9950Sstevel@tonic-gate  * Arguments:
9960Sstevel@tonic-gate  *	ph_data		- pointer to pipe handle data
9970Sstevel@tonic-gate  *	wrp		- pointer to usba_req_wrapper_structure.
9980Sstevel@tonic-gate  *
9990Sstevel@tonic-gate  * Return Values:
10000Sstevel@tonic-gate  *	USB_SUCCESS	- request successfully executed
10010Sstevel@tonic-gate  *	USB_FAILURE	- request failed
10020Sstevel@tonic-gate  */
10030Sstevel@tonic-gate static int
usba_pipe_sync_wait(usba_pipe_handle_data_t * ph_data,usba_req_wrapper_t * wrp)10040Sstevel@tonic-gate usba_pipe_sync_wait(usba_pipe_handle_data_t	*ph_data,
10050Sstevel@tonic-gate 		usba_req_wrapper_t	*wrp)
10060Sstevel@tonic-gate {
10070Sstevel@tonic-gate 	ASSERT(wrp->wr_usb_flags & USB_FLAGS_SLEEP);
10080Sstevel@tonic-gate 	ASSERT(ph_data == wrp->wr_ph_data);
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
10110Sstevel@tonic-gate 	while (wrp->wr_done != B_TRUE) {
10120Sstevel@tonic-gate 		cv_wait(&wrp->wr_cv, &ph_data->p_mutex);
10130Sstevel@tonic-gate 	}
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10186898Sfb209375 	    "usba_pipe_sync_wait: ph_data=0x%p cr=0x%x", (void *)ph_data,
10196898Sfb209375 	    wrp->wr_cr);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	/* XXX return something better than USB_FAILURE?? */
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	return (wrp->wr_cr == USB_CR_OK ? USB_SUCCESS : USB_FAILURE);
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate /*
10280Sstevel@tonic-gate  * Allocate usb control request and a USB request wrapper
10290Sstevel@tonic-gate  *
10300Sstevel@tonic-gate  * Arguments:
10310Sstevel@tonic-gate  *	dip	- dev_info_t of the client driver
10320Sstevel@tonic-gate  *	len	- length of "data" for this control request
10330Sstevel@tonic-gate  *	flags:
10340Sstevel@tonic-gate  *		USB_FLAGS_SLEEP	- Sleep if resources are not available
10350Sstevel@tonic-gate  *		no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
10360Sstevel@tonic-gate  *
10370Sstevel@tonic-gate  * Return Values:	usb_ctrl_req_t on success, NULL on failure
10380Sstevel@tonic-gate  */
10390Sstevel@tonic-gate usb_ctrl_req_t *
usb_alloc_ctrl_req(dev_info_t * dip,size_t len,usb_flags_t flags)10400Sstevel@tonic-gate usb_alloc_ctrl_req(dev_info_t	*dip,
10410Sstevel@tonic-gate 		size_t		len,
10420Sstevel@tonic-gate 		usb_flags_t	flags)
10430Sstevel@tonic-gate {
10440Sstevel@tonic-gate 	usb_ctrl_req_t	*ctrl_req = NULL;
10450Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp;
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10480Sstevel@tonic-gate 	    "usb_alloc_ctrl_req: dip=0x%p, wlen=0x%lx, flags=0x%x",
10496898Sfb209375 	    (void *)dip, len, flags);
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/* Allocate + Initialize the usba_req_wrapper_t structure */
10520Sstevel@tonic-gate 	if (dip &&
10530Sstevel@tonic-gate 	    ((wrp = usba_req_wrapper_alloc(dip, sizeof (*ctrl_req), flags)) !=
10540Sstevel@tonic-gate 	    NULL)) {
10550Sstevel@tonic-gate 		ctrl_req = USBA_WRP2CTRL_REQ(wrp);
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 		/* Allocate the usb_ctrl_req data mblk */
10580Sstevel@tonic-gate 		if (len) {
10590Sstevel@tonic-gate 			if (flags & USB_FLAGS_SLEEP) {
10600Sstevel@tonic-gate 				ctrl_req->ctrl_data = allocb_wait(len, BPRI_LO,
10615773Sqz150045 				    STR_NOSIG, NULL);
10620Sstevel@tonic-gate 			} else	if ((ctrl_req->ctrl_data =
10630Sstevel@tonic-gate 			    allocb(len, BPRI_HI)) == NULL) {
10640Sstevel@tonic-gate 				usba_req_wrapper_free(wrp);
10650Sstevel@tonic-gate 				ctrl_req = NULL;
10660Sstevel@tonic-gate 			}
10670Sstevel@tonic-gate 		}
10680Sstevel@tonic-gate 	}
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10716898Sfb209375 	    "usb_alloc_ctrl_req: ctrl_req = 0x%p", (void *)ctrl_req);
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	return (ctrl_req);
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate /*
10780Sstevel@tonic-gate  * usb_free_ctrl_req:
10790Sstevel@tonic-gate  *	free USB control request + wrapper
10800Sstevel@tonic-gate  *
10810Sstevel@tonic-gate  * Arguments:
10820Sstevel@tonic-gate  *	req - pointer to usb_ctrl_req_t
10830Sstevel@tonic-gate  */
10840Sstevel@tonic-gate void
usb_free_ctrl_req(usb_ctrl_req_t * req)10850Sstevel@tonic-gate usb_free_ctrl_req(usb_ctrl_req_t *req)
10860Sstevel@tonic-gate {
10870Sstevel@tonic-gate 	if (req) {
10880Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10896898Sfb209375 		    "usb_free_ctrl_req: req = 0x%p", (void *)req);
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 		if (req->ctrl_data) {
10920Sstevel@tonic-gate 			freemsg(req->ctrl_data);
10930Sstevel@tonic-gate 		}
10940Sstevel@tonic-gate 		usba_req_wrapper_free(USBA_REQ2WRP(req));
10950Sstevel@tonic-gate 	}
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate /*
11000Sstevel@tonic-gate  * Client driver calls this function to issue the control
11010Sstevel@tonic-gate  * request to the USBA
11020Sstevel@tonic-gate  *
11030Sstevel@tonic-gate  * Arguments:
11040Sstevel@tonic-gate  *	pipe_handle:  control pipe pipehandle (obtained via usb_pipe_open()
11050Sstevel@tonic-gate  *	req: control request
11060Sstevel@tonic-gate  *	usb_flags:
11070Sstevel@tonic-gate  *		USB_FLAGS_SLEEP - wait for the request to complete
11080Sstevel@tonic-gate  *
11090Sstevel@tonic-gate  * Return Values:
11100Sstevel@tonic-gate  *	USB_SUCCESS	- request successfully executed
11110Sstevel@tonic-gate  *	USB_FAILURE	- request failed
11120Sstevel@tonic-gate  */
11130Sstevel@tonic-gate int
usb_pipe_ctrl_xfer(usb_pipe_handle_t pipe_handle,usb_ctrl_req_t * req,usb_flags_t usb_flags)11140Sstevel@tonic-gate usb_pipe_ctrl_xfer(usb_pipe_handle_t	pipe_handle,
11150Sstevel@tonic-gate 		usb_ctrl_req_t		*req,
11160Sstevel@tonic-gate 		usb_flags_t		usb_flags)
11170Sstevel@tonic-gate {
11180Sstevel@tonic-gate 	int			rval;
11190Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
11200Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
11210Sstevel@tonic-gate 	usba_device_t		*usba_device;
11220Sstevel@tonic-gate 	usb_flags_t		wrp_usb_flags;
11230Sstevel@tonic-gate 	usb_pipe_state_t	pipe_state;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11260Sstevel@tonic-gate 	    "usb_pipe_ctrl_xfer: req=0x%p, wrp=0x%p\n\t"
11270Sstevel@tonic-gate 	    "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf=0x%x",
11286898Sfb209375 	    (void *)req, (void *)wrp, req->ctrl_bmRequestType,
11296898Sfb209375 	    req->ctrl_bRequest, req->ctrl_wValue, req->ctrl_wIndex,
11306898Sfb209375 	    req->ctrl_wLength, usb_flags);
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	if (ph_data == NULL) {
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
11350Sstevel@tonic-gate 	}
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
11380Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
11410Sstevel@tonic-gate 	    USB_EP_ATTR_CONTROL)) != USB_SUCCESS) {
11420Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11430Sstevel@tonic-gate 		    "request rejected: rval=%d", rval);
11440Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 		return (rval);
11490Sstevel@tonic-gate 	}
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	ASSERT(ph_data == wrp->wr_ph_data);
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	/* we accepted the request, so increment the req count */
11540Sstevel@tonic-gate 	ph_data->p_req_count++;
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	wrp_usb_flags = wrp->wr_usb_flags;
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	/* Get the current bulk pipe state */
11590Sstevel@tonic-gate 	pipe_state = usba_get_ph_state(ph_data);
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	/*
11620Sstevel@tonic-gate 	 * if this is for the default pipe, and the pipe is in error,
11630Sstevel@tonic-gate 	 * just queue the request. autoclearing will start this request
11640Sstevel@tonic-gate 	 *
11650Sstevel@tonic-gate 	 * if there is already an active request in the queue
11660Sstevel@tonic-gate 	 * then just add this request to the queue.
11670Sstevel@tonic-gate 	 */
11680Sstevel@tonic-gate 	switch (pipe_state) {
11690Sstevel@tonic-gate 	case USB_PIPE_STATE_IDLE:
11700Sstevel@tonic-gate 		if (ph_data->p_queue.next ||
11710Sstevel@tonic-gate 		    ph_data->p_active_cntrl_req_wrp) {
11720Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11736898Sfb209375 			    "usb_pipe_ctrl_xfer: queue request 0x%p",
11746898Sfb209375 			    (void *)req);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 			usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
11770Sstevel@tonic-gate 			rval = USB_SUCCESS;
11780Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
11790Sstevel@tonic-gate 		} else {
11800Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
11810Sstevel@tonic-gate 			ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp;
11820Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 			/* issue the request to HCD */
11850Sstevel@tonic-gate 			rval = usba_device->usb_hcdi_ops->
11860Sstevel@tonic-gate 			    usba_hcdi_pipe_ctrl_xfer(ph_data, req, usb_flags);
11870Sstevel@tonic-gate 		}
11880Sstevel@tonic-gate 		break;
11890Sstevel@tonic-gate 	case USB_PIPE_STATE_ACTIVE:
11900Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11916898Sfb209375 		    "usb_pipe_ctrl_xfer: queue request 0x%p", (void *)req);
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 		usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
11940Sstevel@tonic-gate 		rval = USB_SUCCESS;
11950Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
11960Sstevel@tonic-gate 		break;
11970Sstevel@tonic-gate 	case USB_PIPE_STATE_ERROR:
11980Sstevel@tonic-gate 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
11990Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12000Sstevel@tonic-gate 			    "usb_pipe_ctrl_xfer: queue request 0x%p on "
12016898Sfb209375 			    "pending def pipe error", (void *)req);
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 			usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
12040Sstevel@tonic-gate 			rval = USB_SUCCESS;
12050Sstevel@tonic-gate 		} else {
12060Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12070Sstevel@tonic-gate 			    "usb_pipe_ctrl_xfer: pipe is in error state ");
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 			rval = USB_PIPE_ERROR;
12100Sstevel@tonic-gate 		}
12110Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
12120Sstevel@tonic-gate 		break;
12130Sstevel@tonic-gate 	default:
12140Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12150Sstevel@tonic-gate 		    "usb_pipe_ctrl_xfer: pipe state %d", pipe_state);
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 		rval = USB_PIPE_ERROR;
12180Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
12190Sstevel@tonic-gate 		break;
12200Sstevel@tonic-gate 	}
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	/* if there has been a failure, decrement req count */
12230Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
12240Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
12256898Sfb209375 		    "usb_pipe_ctrl_xfer: hcd failed req 0x%p", (void *)req);
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 		if (req->ctrl_completion_reason == USB_CR_OK) {
12280Sstevel@tonic-gate 			req->ctrl_completion_reason = usba_rval2cr(rval);
12290Sstevel@tonic-gate 		}
12300Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
12310Sstevel@tonic-gate 		ASSERT(wrp->wr_done == B_FALSE);
12320Sstevel@tonic-gate 		ph_data->p_req_count--;
12330Sstevel@tonic-gate 		ASSERT(ph_data->p_req_count >= 0);
12340Sstevel@tonic-gate 		ph_data->p_active_cntrl_req_wrp = NULL;
12350Sstevel@tonic-gate 		if ((ph_data->p_req_count == 0) &&
12360Sstevel@tonic-gate 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
12370Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
12380Sstevel@tonic-gate 		}
12390Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	/* if success and sleep specified, wait for completion */
12420Sstevel@tonic-gate 	} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
12430Sstevel@tonic-gate 		rval = usba_pipe_sync_wait(ph_data, wrp);
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12470Sstevel@tonic-gate 	    "usb_pipe_ctrl_xfer: rval=0x%x", rval);
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	return (rval);
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate /*
12560Sstevel@tonic-gate  * usb_pipe_sync_ctrl_xfer():
12570Sstevel@tonic-gate  *	for simple synchronous control transactions this wrapper function
12580Sstevel@tonic-gate  *	will perform the allocation, xfer, and deallocation
12590Sstevel@tonic-gate  *	USB_ATTRS_AUTOCLEARING will be enabled
12600Sstevel@tonic-gate  *
12610Sstevel@tonic-gate  * Arguments:
12620Sstevel@tonic-gate  *	dip		- pointer to clients devinfo
12630Sstevel@tonic-gate  *	pipe_handle	- control pipe pipehandle (obtained via usb_pipe_open()
12640Sstevel@tonic-gate  *	bmRequestType	- characteristics of request
12650Sstevel@tonic-gate  *	bRequest	- specific request
12660Sstevel@tonic-gate  *	wValue		- varies according to request
12670Sstevel@tonic-gate  *	wIndex		- index or offset
12680Sstevel@tonic-gate  *	wLength		- number of bytes to xfer
12690Sstevel@tonic-gate  *	data		- pointer to pointer to data and may be NULL if
12700Sstevel@tonic-gate  *			  wLength is 0
12710Sstevel@tonic-gate  *	attrs		- required request attributes
12720Sstevel@tonic-gate  *	completion_reason - completion status
12730Sstevel@tonic-gate  *	cb_flags	- request completions flags
12740Sstevel@tonic-gate  *	flags		- none
12750Sstevel@tonic-gate  *
12760Sstevel@tonic-gate  * Return Values:
12770Sstevel@tonic-gate  *	USB_SUCCESS	- request successfully executed
12780Sstevel@tonic-gate  *	USB_*		- request failed
12790Sstevel@tonic-gate  *
12800Sstevel@tonic-gate  * Notes:
12810Sstevel@tonic-gate  * - in the case of failure, the client should check completion_reason and
12820Sstevel@tonic-gate  *	and cb_flags and determine further recovery action
12830Sstevel@tonic-gate  * - the client should check data and if non-zero, free the data on
12840Sstevel@tonic-gate  *	completion
12850Sstevel@tonic-gate  */
12860Sstevel@tonic-gate 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)12870Sstevel@tonic-gate usb_pipe_sync_ctrl_xfer(dev_info_t *dip,
12880Sstevel@tonic-gate 		usb_pipe_handle_t pipe_handle,
12890Sstevel@tonic-gate 		uchar_t		bmRequestType,
12900Sstevel@tonic-gate 		uchar_t		bRequest,
12910Sstevel@tonic-gate 		uint16_t	wValue,
12920Sstevel@tonic-gate 		uint16_t	wIndex,
12930Sstevel@tonic-gate 		uint16_t	wLength,
12940Sstevel@tonic-gate 		mblk_t		**data,
12950Sstevel@tonic-gate 		usb_req_attrs_t	attributes,
12960Sstevel@tonic-gate 		usb_cr_t	*completion_reason,
12970Sstevel@tonic-gate 		usb_cb_flags_t	*cb_flags,
12980Sstevel@tonic-gate 		usb_flags_t	flags)
12990Sstevel@tonic-gate {
13000Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph_data;
13010Sstevel@tonic-gate 	int			rval;
13020Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_req;
13030Sstevel@tonic-gate 	size_t			length;
13040Sstevel@tonic-gate #ifdef DEBUG
13050Sstevel@tonic-gate #define	BUFSIZE	256
13060Sstevel@tonic-gate 	char			*buf = kmem_alloc(BUFSIZE, KM_SLEEP);
13070Sstevel@tonic-gate #endif
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13100Sstevel@tonic-gate 	    "usb_pipe_sync_ctrl_xfer: ph=0x%p\n\t"
13116898Sfb209375 	    "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf = 0x%x", (void *)pipe_handle,
13120Sstevel@tonic-gate 	    bmRequestType, bRequest, wValue, wIndex, wLength, flags);
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
13150Sstevel@tonic-gate 		rval = USB_INVALID_PIPE;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 		goto done;
13180Sstevel@tonic-gate 	}
13190Sstevel@tonic-gate 	if (servicing_interrupt()) {
13200Sstevel@tonic-gate 		rval = USB_INVALID_CONTEXT;
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 		goto done;
13230Sstevel@tonic-gate 	}
13240Sstevel@tonic-gate 	if (dip == NULL) {
13250Sstevel@tonic-gate 		rval = USB_INVALID_ARGS;
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 		goto done;
13280Sstevel@tonic-gate 	}
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	length = ((data) && (*data)) ? 0: wLength;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	ctrl_req = usb_alloc_ctrl_req(dip,
13330Sstevel@tonic-gate 	    length, flags | USB_FLAGS_SLEEP);
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	/* Initialize the ctrl_req structure */
13360Sstevel@tonic-gate 	ctrl_req->ctrl_bmRequestType	= bmRequestType;
13370Sstevel@tonic-gate 	ctrl_req->ctrl_bRequest 	= bRequest;
13380Sstevel@tonic-gate 	ctrl_req->ctrl_wValue		= wValue;
13390Sstevel@tonic-gate 	ctrl_req->ctrl_wIndex		= wIndex;
13400Sstevel@tonic-gate 	ctrl_req->ctrl_wLength		= wLength;
13410Sstevel@tonic-gate 	ctrl_req->ctrl_data		= ctrl_req->ctrl_data ?
13425773Sqz150045 	    ctrl_req->ctrl_data : ((data) ? *data : NULL);
13430Sstevel@tonic-gate 	ctrl_req->ctrl_timeout		= USB_PIPE_TIMEOUT;
13440Sstevel@tonic-gate 	ctrl_req->ctrl_attributes	= attributes | USB_ATTRS_AUTOCLEARING;
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	/* Issue control xfer to the HCD */
13470Sstevel@tonic-gate 	rval = usb_pipe_ctrl_xfer(pipe_handle, ctrl_req,
13480Sstevel@tonic-gate 	    flags | USB_FLAGS_SLEEP);
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate #ifdef DEBUG
13510Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13520Sstevel@tonic-gate 	    "req=0x%p, cr=%s cb_flags=%s data=0x%p rval=%s",
13536898Sfb209375 	    (void *)ctrl_req, usb_str_cr(ctrl_req->ctrl_completion_reason),
13540Sstevel@tonic-gate 	    usb_str_cb_flags(ctrl_req->ctrl_cb_flags, buf, BUFSIZE),
13556898Sfb209375 	    (void *)ctrl_req->ctrl_data, usb_str_rval(rval));
13560Sstevel@tonic-gate #endif
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	/* copy back ctrl_req values */
13590Sstevel@tonic-gate 	if (data) {
13600Sstevel@tonic-gate 		*data			= ctrl_req->ctrl_data;
13610Sstevel@tonic-gate 	}
13620Sstevel@tonic-gate 	if (completion_reason) {
13630Sstevel@tonic-gate 		*completion_reason	= ctrl_req->ctrl_completion_reason;
13640Sstevel@tonic-gate 	}
13650Sstevel@tonic-gate 	if (cb_flags) {
13660Sstevel@tonic-gate 		*cb_flags		= ctrl_req->ctrl_cb_flags;
13670Sstevel@tonic-gate 	}
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	/* Free up the control request now */
13700Sstevel@tonic-gate 	ctrl_req->ctrl_data = NULL; /* leave to client to free */
13710Sstevel@tonic-gate 	usb_free_ctrl_req(ctrl_req);
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate done:
13740Sstevel@tonic-gate #ifdef DEBUG
13750Sstevel@tonic-gate 	kmem_free(buf, BUFSIZE);
13760Sstevel@tonic-gate #endif
13770Sstevel@tonic-gate 	if (ph_data) {
13780Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
13790Sstevel@tonic-gate 	}
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	return (rval);
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate /*
13860Sstevel@tonic-gate  * usb_pipe_ctrl_xfer_wait():
13870Sstevel@tonic-gate  *	Easy-to-use wrapper around usb_pipe_sync_ctrl_xfer.
13880Sstevel@tonic-gate  *
13890Sstevel@tonic-gate  * ARGUMENTS:
13900Sstevel@tonic-gate  *	pipe_handle	- control pipe pipehandle (obtained via usb_pipe_open())
13910Sstevel@tonic-gate  *	setup		- setup descriptor params, attributes
13920Sstevel@tonic-gate  *	data		- pointer to pointer to data and may be NULL when
13930Sstevel@tonic-gate  *			  wLength is 0
13940Sstevel@tonic-gate  *	completion_reason - completion status.
13950Sstevel@tonic-gate  *	cb_flags	- request completions flags.
13960Sstevel@tonic-gate  *	flags		- none.
13970Sstevel@tonic-gate  *
13980Sstevel@tonic-gate  * RETURN VALUES:
13990Sstevel@tonic-gate  *	USB_SUCCESS	- request successfully executed.
14000Sstevel@tonic-gate  *	USB_*		- failure
14010Sstevel@tonic-gate  */
14020Sstevel@tonic-gate 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)14030Sstevel@tonic-gate usb_pipe_ctrl_xfer_wait(
14040Sstevel@tonic-gate 		usb_pipe_handle_t	pipe_handle,
14050Sstevel@tonic-gate 		usb_ctrl_setup_t	*setup,
14060Sstevel@tonic-gate 		mblk_t			**data,
14070Sstevel@tonic-gate 		usb_cr_t		*completion_reason,
14080Sstevel@tonic-gate 		usb_cb_flags_t		*cb_flags,
14090Sstevel@tonic-gate 		usb_flags_t		flags)
14100Sstevel@tonic-gate {
14110Sstevel@tonic-gate 	return (usb_pipe_sync_ctrl_xfer(
14125773Sqz150045 	    usba_get_dip(pipe_handle),
14135773Sqz150045 	    pipe_handle,
14145773Sqz150045 	    setup->bmRequestType,
14155773Sqz150045 	    setup->bRequest,
14165773Sqz150045 	    setup->wValue,
14175773Sqz150045 	    setup->wIndex,
14185773Sqz150045 	    setup->wLength,
14195773Sqz150045 	    data,
14205773Sqz150045 	    setup->attrs,
14215773Sqz150045 	    completion_reason,
14225773Sqz150045 	    cb_flags,
14235773Sqz150045 	    flags));
14240Sstevel@tonic-gate }
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate /*
14280Sstevel@tonic-gate  * usb_alloc_bulk_req:
14290Sstevel@tonic-gate  *	Allocate a usb bulk request + usba_req_wrapper_t
14300Sstevel@tonic-gate  *
14310Sstevel@tonic-gate  * Arguments:
14320Sstevel@tonic-gate  *	dip	- dev_info_t of the client driver
14330Sstevel@tonic-gate  *	len	- length of "data" for this bulk request
14340Sstevel@tonic-gate  *	flags:
14350Sstevel@tonic-gate  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
14360Sstevel@tonic-gate  *
14370Sstevel@tonic-gate  * Return Values:
14380Sstevel@tonic-gate  *	usb_bulk_req_t on success, NULL on failure
14390Sstevel@tonic-gate  */
14400Sstevel@tonic-gate usb_bulk_req_t *
usb_alloc_bulk_req(dev_info_t * dip,size_t len,usb_flags_t flags)14410Sstevel@tonic-gate usb_alloc_bulk_req(dev_info_t	*dip,
14420Sstevel@tonic-gate 		size_t		len,
14430Sstevel@tonic-gate 		usb_flags_t	flags)
14440Sstevel@tonic-gate {
14450Sstevel@tonic-gate 	usb_bulk_req_t		*bulk_req = NULL;
14460Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp;
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14490Sstevel@tonic-gate 	    "usb_alloc_bulk_req: dip=0x%p wlen=0x%lx flags=0x%x",
14506898Sfb209375 	    (void *)dip, len, flags);
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 	/* Allocate + Initialize the usba_req_wrapper_t structure */
14530Sstevel@tonic-gate 	if (dip &&
14540Sstevel@tonic-gate 	    ((wrp = usba_req_wrapper_alloc(dip, sizeof (*bulk_req), flags)) !=
14550Sstevel@tonic-gate 	    NULL)) {
14560Sstevel@tonic-gate 		bulk_req = USBA_WRP2BULK_REQ(wrp);
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 		/* Allocate the usb_bulk_req data mblk */
14590Sstevel@tonic-gate 		if (len) {
14600Sstevel@tonic-gate 			if (flags & USB_FLAGS_SLEEP) {
14610Sstevel@tonic-gate 				bulk_req->bulk_data = allocb_wait(len,
14620Sstevel@tonic-gate 				    BPRI_LO, STR_NOSIG, NULL);
14630Sstevel@tonic-gate 			} else	if ((bulk_req->bulk_data =
14640Sstevel@tonic-gate 			    allocb(len, BPRI_HI)) == NULL) {
14650Sstevel@tonic-gate 				usba_req_wrapper_free(wrp);
14660Sstevel@tonic-gate 				bulk_req = NULL;
14670Sstevel@tonic-gate 			}
14680Sstevel@tonic-gate 		}
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	}
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14736898Sfb209375 	    "usb_alloc_bulk_req: bulk_req = 0x%p", (void *)bulk_req);
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 	return (bulk_req);
14760Sstevel@tonic-gate }
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate  * usb_free_bulk_req:
14810Sstevel@tonic-gate  *	free USB bulk request + wrapper
14820Sstevel@tonic-gate  *
14830Sstevel@tonic-gate  * Arguments:
14840Sstevel@tonic-gate  *	req - pointer to usb_bulk_req_t
14850Sstevel@tonic-gate  */
14860Sstevel@tonic-gate void
usb_free_bulk_req(usb_bulk_req_t * req)14870Sstevel@tonic-gate usb_free_bulk_req(usb_bulk_req_t *req)
14880Sstevel@tonic-gate {
14890Sstevel@tonic-gate 	if (req) {
14900Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14916898Sfb209375 		    "usb_free_bulk_req: req=0x%p", (void *)req);
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 		if (req->bulk_data) {
14940Sstevel@tonic-gate 			freemsg(req->bulk_data);
14950Sstevel@tonic-gate 		}
14960Sstevel@tonic-gate 		usba_req_wrapper_free(USBA_REQ2WRP(req));
14970Sstevel@tonic-gate 	}
14980Sstevel@tonic-gate }
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate /*
15020Sstevel@tonic-gate  * Client driver calls this function to issue the bulk xfer to the USBA
15030Sstevel@tonic-gate  *
15040Sstevel@tonic-gate  * Arguments:-
15050Sstevel@tonic-gate  *	pipe_handle - bulk pipe handle (obtained via usb_pipe_open()
15060Sstevel@tonic-gate  *	req	    - bulk data xfer request (IN or OUT)
15070Sstevel@tonic-gate  *	usb_flags   - USB_FLAGS_SLEEP - wait for the request to complete
15080Sstevel@tonic-gate  *
15090Sstevel@tonic-gate  * Return Values:
15100Sstevel@tonic-gate  *	USB_SUCCESS - success
15110Sstevel@tonic-gate  *	USB_FAILURE - unspecified failure
15120Sstevel@tonic-gate  */
15130Sstevel@tonic-gate int
usb_pipe_bulk_xfer(usb_pipe_handle_t pipe_handle,usb_bulk_req_t * req,usb_flags_t usb_flags)15140Sstevel@tonic-gate usb_pipe_bulk_xfer(usb_pipe_handle_t	pipe_handle,
15150Sstevel@tonic-gate 		usb_bulk_req_t		*req,
15160Sstevel@tonic-gate 		usb_flags_t		usb_flags)
15170Sstevel@tonic-gate {
15180Sstevel@tonic-gate 	int			rval;
15190Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
15200Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
15210Sstevel@tonic-gate 	usba_device_t		*usba_device;
15220Sstevel@tonic-gate 	usb_flags_t		wrp_usb_flags;
15230Sstevel@tonic-gate 	usb_pipe_state_t	pipe_state;
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15266898Sfb209375 	    "usb_pipe_bulk_xfer: req=0x%p uf=0x%x", (void *)req, usb_flags);
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 	if (ph_data == NULL) {
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
15310Sstevel@tonic-gate 	}
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
15340Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
15370Sstevel@tonic-gate 	    USB_EP_ATTR_BULK)) != USB_SUCCESS) {
15380Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 		return (rval);
15430Sstevel@tonic-gate 	}
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	/* we accepted the request */
15460Sstevel@tonic-gate 	ph_data->p_req_count++;
15470Sstevel@tonic-gate 	wrp_usb_flags = wrp->wr_usb_flags;
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 	/* Get the current bulk pipe state */
15500Sstevel@tonic-gate 	pipe_state = usba_get_ph_state(ph_data);
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	/*
15530Sstevel@tonic-gate 	 * if there is already an active request in the queue
15540Sstevel@tonic-gate 	 * then just add this request to the queue.
15550Sstevel@tonic-gate 	 */
15560Sstevel@tonic-gate 	switch (pipe_state) {
15570Sstevel@tonic-gate 	case USB_PIPE_STATE_IDLE:
15580Sstevel@tonic-gate 		if (ph_data->p_queue.next) {
15590Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15606898Sfb209375 			    "usb_pipe_bulk_xfer: queue request 0x%p",
15616898Sfb209375 			    (void *)req);
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 			usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
15640Sstevel@tonic-gate 			rval = USB_SUCCESS;
15650Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
15660Sstevel@tonic-gate 		} else {
15670Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
15680Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 			/* issue the request to HCD */
15710Sstevel@tonic-gate 			rval = usba_device->usb_hcdi_ops->
15720Sstevel@tonic-gate 			    usba_hcdi_pipe_bulk_xfer(ph_data, req, usb_flags);
15730Sstevel@tonic-gate 		}
15740Sstevel@tonic-gate 		break;
15750Sstevel@tonic-gate 	case USB_PIPE_STATE_ACTIVE:
15760Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15776898Sfb209375 		    "usb_pipe_bulk_xfer: queue request 0x%p", (void *)req);
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 		usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
15800Sstevel@tonic-gate 		rval = USB_SUCCESS;
15810Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
15820Sstevel@tonic-gate 		break;
15830Sstevel@tonic-gate 	default:
15840Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15850Sstevel@tonic-gate 		    "usb_pipe_bulk_xfer: pipe state %d", pipe_state);
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 		rval = USB_PIPE_ERROR;
15880Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
15890Sstevel@tonic-gate 		break;
15900Sstevel@tonic-gate 	}
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
15930Sstevel@tonic-gate 		if (req->bulk_completion_reason == USB_CR_OK) {
15940Sstevel@tonic-gate 			req->bulk_completion_reason = usba_rval2cr(rval);
15950Sstevel@tonic-gate 		}
15960Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
15970Sstevel@tonic-gate 		ASSERT(wrp->wr_done == B_FALSE);
15980Sstevel@tonic-gate 		ph_data->p_req_count--;
15990Sstevel@tonic-gate 		ASSERT(ph_data->p_req_count >= 0);
16000Sstevel@tonic-gate 		if ((ph_data->p_req_count == 0) &&
16010Sstevel@tonic-gate 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
16020Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
16030Sstevel@tonic-gate 		}
16040Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
16050Sstevel@tonic-gate 	} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
16060Sstevel@tonic-gate 		rval = usba_pipe_sync_wait(ph_data, wrp);
16070Sstevel@tonic-gate 	}
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16100Sstevel@tonic-gate 	    "usb_pipe_bulk_xfer: rval=%d", rval);
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	return (rval);
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate /*
16190Sstevel@tonic-gate  * usb_pipe_bulk_transfer_size:
16200Sstevel@tonic-gate  *	- request HCD to return bulk max transfer data size
16210Sstevel@tonic-gate  *
16220Sstevel@tonic-gate  * Arguments:
16230Sstevel@tonic-gate  *	dip	- pointer to dev_info_t
16240Sstevel@tonic-gate  *	size	- pointer to bulk_transfer_size
16250Sstevel@tonic-gate  *
16260Sstevel@tonic-gate  * Return Values:
16270Sstevel@tonic-gate  *	USB_SUCCESS	- request successfully executed
16280Sstevel@tonic-gate  *	USB_FAILURE	- request failed
16290Sstevel@tonic-gate  */
16300Sstevel@tonic-gate int
usb_pipe_bulk_transfer_size(dev_info_t * dip,size_t * size)16310Sstevel@tonic-gate usb_pipe_bulk_transfer_size(dev_info_t	*dip,
16320Sstevel@tonic-gate 			size_t		*size)
16330Sstevel@tonic-gate {
16340Sstevel@tonic-gate 	return (usb_pipe_get_max_bulk_transfer_size(dip, size));
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate int
usb_pipe_get_max_bulk_transfer_size(dev_info_t * dip,size_t * size)16390Sstevel@tonic-gate usb_pipe_get_max_bulk_transfer_size(dev_info_t	*dip,
16400Sstevel@tonic-gate 			size_t		*size)
16410Sstevel@tonic-gate {
16420Sstevel@tonic-gate 	usba_device_t	*usba_device;
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	if ((dip == NULL) || (size == NULL)) {
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
16470Sstevel@tonic-gate 	}
16480Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16516898Sfb209375 	    "usb_pipe_bulk_transfer_size: usba_device=0x%p",
16526898Sfb209375 	    (void *)usba_device);
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	if ((usba_device) &&
16550Sstevel@tonic-gate 	    (usba_device->usb_hcdi_ops->usba_hcdi_bulk_transfer_size)) {
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 		return (usba_device->usb_hcdi_ops->
16580Sstevel@tonic-gate 		    usba_hcdi_bulk_transfer_size(usba_device, size));
16590Sstevel@tonic-gate 	} else {
16600Sstevel@tonic-gate 		*size = 0;
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 		return (USB_FAILURE);
16630Sstevel@tonic-gate 	}
16640Sstevel@tonic-gate }
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate /*
16680Sstevel@tonic-gate  * usb_alloc_intr_req:
16690Sstevel@tonic-gate  *	Allocate usb interrupt request
16700Sstevel@tonic-gate  *
16710Sstevel@tonic-gate  * Arguments:
16720Sstevel@tonic-gate  *	dip	- dev_info_t of the client driver
16730Sstevel@tonic-gate  *	len	- length of "data" for this interrupt request
16740Sstevel@tonic-gate  *	flags	-
16750Sstevel@tonic-gate  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
16760Sstevel@tonic-gate  *
16770Sstevel@tonic-gate  * Return Values:
16780Sstevel@tonic-gate  *		usb_intr_req_t on success, NULL on failure
16790Sstevel@tonic-gate  */
16800Sstevel@tonic-gate usb_intr_req_t *
usb_alloc_intr_req(dev_info_t * dip,size_t len,usb_flags_t flags)16810Sstevel@tonic-gate usb_alloc_intr_req(dev_info_t	*dip,
16820Sstevel@tonic-gate 		size_t		len,
16830Sstevel@tonic-gate 		usb_flags_t	flags)
16840Sstevel@tonic-gate {
16850Sstevel@tonic-gate 	usb_intr_req_t	*intr_req = NULL;
16860Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp;
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16890Sstevel@tonic-gate 	    "usb_alloc_intr_req: dip=0x%p, len=0x%lx, flags=0x%x",
16906898Sfb209375 	    (void *)dip, len, flags);
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	/* Allocate + Initialize the usba_req_wrapper_t structure */
16930Sstevel@tonic-gate 	if ((dip &&
16940Sstevel@tonic-gate 	    (wrp = usba_req_wrapper_alloc(dip, sizeof (*intr_req), flags)) !=
16950Sstevel@tonic-gate 	    NULL)) {
16960Sstevel@tonic-gate 		intr_req = (usb_intr_req_t *)USBA_WRP2INTR_REQ(wrp);
16970Sstevel@tonic-gate 
16980Sstevel@tonic-gate 		/* Allocate the usb_intr_req data mblk */
16990Sstevel@tonic-gate 		if (len) {
17000Sstevel@tonic-gate 			if (flags & USB_FLAGS_SLEEP) {
17010Sstevel@tonic-gate 				intr_req->intr_data = allocb_wait(len, BPRI_LO,
17025773Sqz150045 				    STR_NOSIG, NULL);
17030Sstevel@tonic-gate 			} else	if ((intr_req->intr_data =
17040Sstevel@tonic-gate 			    allocb(len, BPRI_HI)) == NULL) {
17050Sstevel@tonic-gate 				usba_req_wrapper_free(wrp);
17060Sstevel@tonic-gate 				intr_req = NULL;
17070Sstevel@tonic-gate 			}
17080Sstevel@tonic-gate 		}
17090Sstevel@tonic-gate 	}
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
17126898Sfb209375 	    "usb_alloc_intr_req: intr_req=0x%p", (void *)intr_req);
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	return (intr_req);
17150Sstevel@tonic-gate }
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 
17180Sstevel@tonic-gate /*
17190Sstevel@tonic-gate  * usba_hcdi_dup_intr_req:
17200Sstevel@tonic-gate  *	create duplicate of interrupt request
17210Sstevel@tonic-gate  *
17220Sstevel@tonic-gate  * Arguments:
17230Sstevel@tonic-gate  *	dip	- devinfo pointer
17240Sstevel@tonic-gate  *	reqp	- original requestp pointer
17250Sstevel@tonic-gate  *	len	- length of "data" for this interrupt request
17260Sstevel@tonic-gate  *	flags	-
17270Sstevel@tonic-gate  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
17280Sstevel@tonic-gate  *
17290Sstevel@tonic-gate  * Return Values:
17300Sstevel@tonic-gate  *		usb_intr_req_t on success, NULL on failure
17310Sstevel@tonic-gate  */
17320Sstevel@tonic-gate 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)17330Sstevel@tonic-gate usba_hcdi_dup_intr_req(
17340Sstevel@tonic-gate 		dev_info_t	*dip,
17350Sstevel@tonic-gate 		usb_intr_req_t	*reqp,
17360Sstevel@tonic-gate 		size_t		len,
17370Sstevel@tonic-gate 		usb_flags_t	flags)
17380Sstevel@tonic-gate {
17390Sstevel@tonic-gate 	usb_intr_req_t		*intr_reqp = NULL;
17400Sstevel@tonic-gate 	usba_req_wrapper_t	*intr_wrp, *req_wrp;
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	if (reqp == NULL) {
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 		return (NULL);
17450Sstevel@tonic-gate 	}
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	req_wrp	= USBA_REQ2WRP(reqp);
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	if (((intr_reqp = usb_alloc_intr_req(dip, len, flags)) != NULL)) {
17500Sstevel@tonic-gate 		intr_reqp->intr_client_private	= reqp->intr_client_private;
17510Sstevel@tonic-gate 		intr_reqp->intr_timeout		= reqp->intr_timeout;
17520Sstevel@tonic-gate 		intr_reqp->intr_attributes	= reqp->intr_attributes;
17530Sstevel@tonic-gate 		intr_reqp->intr_len		= reqp->intr_len;
17540Sstevel@tonic-gate 		intr_reqp->intr_cb		= reqp->intr_cb;
17550Sstevel@tonic-gate 		intr_reqp->intr_exc_cb		= reqp->intr_exc_cb;
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 		intr_wrp		= USBA_REQ2WRP(intr_reqp);
17580Sstevel@tonic-gate 		intr_wrp->wr_dip	= req_wrp->wr_dip;
17590Sstevel@tonic-gate 		intr_wrp->wr_ph_data	= req_wrp->wr_ph_data;
17600Sstevel@tonic-gate 		intr_wrp->wr_attrs	= req_wrp->wr_attrs;
17610Sstevel@tonic-gate 		intr_wrp->wr_usb_flags	= req_wrp->wr_usb_flags;
17620Sstevel@tonic-gate 	}
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 	return (intr_reqp);
17650Sstevel@tonic-gate }
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate /*
17690Sstevel@tonic-gate  * usb_free_intr_req:
17700Sstevel@tonic-gate  *	free USB intr request + wrapper
17710Sstevel@tonic-gate  *
17720Sstevel@tonic-gate  * Arguments:
17730Sstevel@tonic-gate  *	req - pointer to usb_intr_req_t
17740Sstevel@tonic-gate  */
17750Sstevel@tonic-gate void
usb_free_intr_req(usb_intr_req_t * req)17760Sstevel@tonic-gate usb_free_intr_req(usb_intr_req_t *req)
17770Sstevel@tonic-gate {
17780Sstevel@tonic-gate 	if (req) {
17790Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
17806898Sfb209375 		    "usb_free_intr_req: req = 0x%p", (void *)req);
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 		if (req->intr_data) {
17830Sstevel@tonic-gate 			freemsg(req->intr_data);
17840Sstevel@tonic-gate 		}
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 		usba_req_wrapper_free(USBA_REQ2WRP(req));
17870Sstevel@tonic-gate 	}
17880Sstevel@tonic-gate }
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate /*
17920Sstevel@tonic-gate  * Client driver calls this function to issue the intr xfer to the USBA
17930Sstevel@tonic-gate  *
17940Sstevel@tonic-gate  * Arguments:-
17950Sstevel@tonic-gate  *	pipe_handle	- intr pipe handle (obtained via usb_pipe_open()
17960Sstevel@tonic-gate  *	req		- intr data xfer request (IN or OUT)
17970Sstevel@tonic-gate  *	flags		-
17980Sstevel@tonic-gate  *			   USB_FLAGS_SLEEP - wait for the request to complete
17990Sstevel@tonic-gate  * Return Values
18000Sstevel@tonic-gate  *	USB_SUCCESS	- success
18010Sstevel@tonic-gate  *	USB_FAILURE	- unspecified failure
18020Sstevel@tonic-gate  */
18030Sstevel@tonic-gate int
usb_pipe_intr_xfer(usb_pipe_handle_t pipe_handle,usb_intr_req_t * req,usb_flags_t usb_flags)18040Sstevel@tonic-gate usb_pipe_intr_xfer(usb_pipe_handle_t	pipe_handle,
18050Sstevel@tonic-gate 		usb_intr_req_t		*req,
18060Sstevel@tonic-gate 		usb_flags_t		usb_flags)
18070Sstevel@tonic-gate {
18080Sstevel@tonic-gate 	int			rval;
18090Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
18100Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
18110Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
18120Sstevel@tonic-gate 	usba_device_t		*usba_device;
18130Sstevel@tonic-gate 	uchar_t			direction;
18140Sstevel@tonic-gate 	usb_flags_t		wrp_usb_flags;
18150Sstevel@tonic-gate 	usb_pipe_state_t	pipe_state;
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
18180Sstevel@tonic-gate 	    "usb_pipe_intr_req: req=0x%p uf=0x%x",
18196898Sfb209375 	    (void *)req, usb_flags);
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 	if (ph_data == NULL) {
18220Sstevel@tonic-gate 
18230Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
18240Sstevel@tonic-gate 	}
18250Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
18260Sstevel@tonic-gate 	direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
18290Sstevel@tonic-gate 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
18300Sstevel@tonic-gate 	    USB_EP_ATTR_INTR)) != USB_SUCCESS) {
18310Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 		return (rval);
18360Sstevel@tonic-gate 	}
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 	/* Get the current interrupt pipe state */
18390Sstevel@tonic-gate 	pipe_state = usba_get_ph_state(ph_data);
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 	switch (pipe_state) {
18420Sstevel@tonic-gate 	case USB_PIPE_STATE_IDLE:
18430Sstevel@tonic-gate 		/*
18440Sstevel@tonic-gate 		 * if the pipe state is in middle of transition,
18450Sstevel@tonic-gate 		 * i.e. stop polling is in progress, fail any
18460Sstevel@tonic-gate 		 * attempt to do a start polling
18470Sstevel@tonic-gate 		 */
18480Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
18490Sstevel@tonic-gate 		if (ph_impl->usba_ph_state_changing > 0) {
18500Sstevel@tonic-gate 			mutex_exit(&ph_impl->usba_ph_mutex);
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
18530Sstevel@tonic-gate 			usba_release_ph_data(ph_data->p_ph_impl);
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
18560Sstevel@tonic-gate 			    "usb_pipe_intr_req: fail request - "
18570Sstevel@tonic-gate 			    "stop polling in progress");
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 			return (USB_FAILURE);
18600Sstevel@tonic-gate 		} else {
18610Sstevel@tonic-gate 			mutex_exit(&ph_impl->usba_ph_mutex);
18620Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
18630Sstevel@tonic-gate 		}
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 		break;
18660Sstevel@tonic-gate 	case USB_PIPE_STATE_ACTIVE:
18670Sstevel@tonic-gate 		/*
18680Sstevel@tonic-gate 		 * If this is interrupt IN pipe and if we are
18690Sstevel@tonic-gate 		 * already polling, return failure.
18700Sstevel@tonic-gate 		 */
18710Sstevel@tonic-gate 		if (direction == USB_EP_DIR_IN) {
18720Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
18730Sstevel@tonic-gate 			    usbai_log_handle,
18740Sstevel@tonic-gate 			    "usb_pipe_intr_req: already polling");
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
18770Sstevel@tonic-gate 			usba_release_ph_data(ph_data->p_ph_impl);
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 			return (USB_FAILURE);
18800Sstevel@tonic-gate 		}
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 		break;
18830Sstevel@tonic-gate 	default:
18840Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
18850Sstevel@tonic-gate 		    "usb_pipe_intr_req: pipe state %d", pipe_state);
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
18880Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 		return (USB_PIPE_ERROR);
18910Sstevel@tonic-gate 	}
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 	/* we accept the request */
18940Sstevel@tonic-gate 	wrp_usb_flags = wrp->wr_usb_flags;
18950Sstevel@tonic-gate 	ph_data->p_req_count++;
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	/* issue the request out */
19000Sstevel@tonic-gate 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_intr_xfer(ph_data,
19010Sstevel@tonic-gate 	    req, usb_flags)) != USB_SUCCESS) {
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 		/* the request failed, decrement the ref_count */
19040Sstevel@tonic-gate 		if (req->intr_completion_reason == USB_CR_OK) {
19050Sstevel@tonic-gate 			req->intr_completion_reason = usba_rval2cr(rval);
19060Sstevel@tonic-gate 		}
19070Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
19080Sstevel@tonic-gate 		ASSERT(wrp->wr_done == B_FALSE);
19090Sstevel@tonic-gate 		ph_data->p_req_count--;
19100Sstevel@tonic-gate 		ASSERT(ph_data->p_req_count >= 0);
19110Sstevel@tonic-gate 		if ((ph_data->p_req_count == 0) &&
19120Sstevel@tonic-gate 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
19130Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
19140Sstevel@tonic-gate 		}
19150Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	/* if sleep specified, wait for completion */
19180Sstevel@tonic-gate 	} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
19190Sstevel@tonic-gate 		rval = usba_pipe_sync_wait(ph_data, wrp);
19200Sstevel@tonic-gate 	}
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
19230Sstevel@tonic-gate 	    "usb_pipe_intr_req: rval=0x%x", rval);
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 	return (rval);
19280Sstevel@tonic-gate }
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate /*
19320Sstevel@tonic-gate  * usba_pipe_sync_stop_intr_polling:
19330Sstevel@tonic-gate  *	- set up for sync transport, if necessary
19340Sstevel@tonic-gate  *	- request HCD to stop polling
19350Sstevel@tonic-gate  *	- wait for draining of all callbacks
19360Sstevel@tonic-gate  */
19370Sstevel@tonic-gate /*ARGSUSED*/
19380Sstevel@tonic-gate 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)19390Sstevel@tonic-gate usba_pipe_sync_stop_intr_polling(dev_info_t	*dip,
19400Sstevel@tonic-gate 		usba_ph_impl_t		*ph_impl,
19410Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
19420Sstevel@tonic-gate 		usb_flags_t		flags)
19430Sstevel@tonic-gate {
19440Sstevel@tonic-gate 	int rval;
19450Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data;
19460Sstevel@tonic-gate 	usba_device_t	*usba_device;
19470Sstevel@tonic-gate 
19480Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
19490Sstevel@tonic-gate 	    "usba_pipe_sync_stop_intr_polling: flags=0x%x", flags);
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 	ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_impl);
19520Sstevel@tonic-gate 	if (ph_data == NULL) {
19530Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
19540Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
19550Sstevel@tonic-gate 		    "usba_pipe_sync_stop_intr_polling: pipe closed");
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
19580Sstevel@tonic-gate 	}
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
19650Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
19660Sstevel@tonic-gate 		    "usba_pipe_sync_stop_intr_polling: pipe error");
19670Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 		return (USB_PIPE_ERROR);
19720Sstevel@tonic-gate 	}
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
19750Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
19760Sstevel@tonic-gate 		    "usba_pipe_sync_stop_intr_polling: already idle");
19770Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate 		return (USB_SUCCESS);
19820Sstevel@tonic-gate 	}
19830Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
19860Sstevel@tonic-gate 	ph_impl->usba_ph_state_changing++;
19870Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 	flags |= USB_FLAGS_SLEEP;
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate 	for (;;) {
19920Sstevel@tonic-gate 		rval = usba_device->usb_hcdi_ops->
19935773Sqz150045 		    usba_hcdi_pipe_stop_intr_polling(ph_data, flags);
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 		/*
19960Sstevel@tonic-gate 		 * The host controller has stopped polling of the endpoint.
19970Sstevel@tonic-gate 		 * Now, drain the callbacks if there are any on the callback
19980Sstevel@tonic-gate 		 * queue.
19990Sstevel@tonic-gate 		 */
20000Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
20010Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 			/*
20040Sstevel@tonic-gate 			 * there is a tiny window that the client driver
20050Sstevel@tonic-gate 			 * may still have restarted the polling and we
20060Sstevel@tonic-gate 			 * have to let the stop polling win)
20070Sstevel@tonic-gate 			 */
20080Sstevel@tonic-gate 			rval = usba_drain_cbs(ph_data, 0,
20095773Sqz150045 			    USB_CR_STOPPED_POLLING);
20100Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
20110Sstevel@tonic-gate 			if (rval != USB_SUCCESS) {
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate 				continue;
20140Sstevel@tonic-gate 			}
20150Sstevel@tonic-gate 		}
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 		break;
20180Sstevel@tonic-gate 	}
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
20210Sstevel@tonic-gate 	    "usba_pipe_sync_stop_intr_polling: rval=0x%x", rval);
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
20240Sstevel@tonic-gate 	ph_impl->usba_ph_state_changing--;
20250Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
20280Sstevel@tonic-gate 
20290Sstevel@tonic-gate 	return (rval);
20300Sstevel@tonic-gate }
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate /*
20340Sstevel@tonic-gate  * dummy callback function for stop polling
20350Sstevel@tonic-gate  */
20360Sstevel@tonic-gate static void
usba_dummy_callback(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags)20370Sstevel@tonic-gate usba_dummy_callback(
20380Sstevel@tonic-gate 	usb_pipe_handle_t ph,
20390Sstevel@tonic-gate 	usb_opaque_t arg,
20400Sstevel@tonic-gate 	int rval,
20410Sstevel@tonic-gate 	usb_cb_flags_t flags)
20420Sstevel@tonic-gate {
20430Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
20440Sstevel@tonic-gate 	    "usba_dummy_callback: "
20450Sstevel@tonic-gate 	    "ph=0x%p rval=0x%x flags=0x%x cb_arg=0x%p",
20466898Sfb209375 	    (void *)ph, rval, flags, (void *)arg);
20470Sstevel@tonic-gate }
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 
20500Sstevel@tonic-gate /*
20510Sstevel@tonic-gate  * usb_pipe_stop_intr_polling:
20520Sstevel@tonic-gate  *	stop polling for interrupt pipe IN data
20530Sstevel@tonic-gate  *	The HCD doesn't do a usba_hcdi_cb().
20540Sstevel@tonic-gate  *	It just returns success/failure
20550Sstevel@tonic-gate  * Arguments:
20560Sstevel@tonic-gate  *	pipe_handle	- pipe handle
20570Sstevel@tonic-gate  *	flags		-
20580Sstevel@tonic-gate  *			USB_FLAGS_SLEEP:	wait for completion
20590Sstevel@tonic-gate  */
20600Sstevel@tonic-gate void
usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle,usb_flags_t flags)20610Sstevel@tonic-gate usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle,
20620Sstevel@tonic-gate 	usb_flags_t	flags)
20630Sstevel@tonic-gate {
20640Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
20670Sstevel@tonic-gate 	    "usba_pipe_stop_intr_polling: flags=0x%x", flags);
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 	if (ph_data == NULL) {
20700Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
20710Sstevel@tonic-gate 		    "usba_pipe_stop_intr_polling: pipe closed");
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 		return;
20740Sstevel@tonic-gate 	}
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate 	if ((ph_data->p_ep.bmAttributes &
20770Sstevel@tonic-gate 	    USB_EP_ATTR_MASK) != USB_EP_ATTR_INTR) {
2078978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
20790Sstevel@tonic-gate 		    "usba_pipe_stop_intr_polling: wrong pipe type");
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
20820Sstevel@tonic-gate 
20830Sstevel@tonic-gate 		return;
20840Sstevel@tonic-gate 	}
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2087978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
20880Sstevel@tonic-gate 		    "usba_pipe_stop_intr_polling: wrong pipe direction");
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate 		return;
20930Sstevel@tonic-gate 	}
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2096978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
20970Sstevel@tonic-gate 		    "usba_pipe_stop_intr_polling: invalid context");
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 		return;
21020Sstevel@tonic-gate 	}
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(ph_data->p_dip,
21050Sstevel@tonic-gate 	    usba_pipe_sync_stop_intr_polling,
21060Sstevel@tonic-gate 	    (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
21070Sstevel@tonic-gate 	    flags, usba_dummy_callback, NULL);
21080Sstevel@tonic-gate }
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate /*
21120Sstevel@tonic-gate  * usb_alloc_isoc_req:
21130Sstevel@tonic-gate  *	- Allocate usb isochronous resources that includes usb isochronous
21140Sstevel@tonic-gate  *	  request and array of packet descriptor structures and wrapper.
21150Sstevel@tonic-gate  *
21160Sstevel@tonic-gate  * Arguments:
21170Sstevel@tonic-gate  *	dip		- dev_info_t of the client driver
21180Sstevel@tonic-gate  *	isoc_pkts_count - number of isoc_pkt_descr_t's
21190Sstevel@tonic-gate  *	len		- length of "data" for this isochronous request
21200Sstevel@tonic-gate  *	flags		-
21210Sstevel@tonic-gate  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
21220Sstevel@tonic-gate  *		no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
21230Sstevel@tonic-gate  *
21240Sstevel@tonic-gate  * Return Values:
21250Sstevel@tonic-gate  *	usb_isoc_req_t on success, NULL on failure
21260Sstevel@tonic-gate  */
21270Sstevel@tonic-gate /*ARGSUSED*/
21280Sstevel@tonic-gate usb_isoc_req_t *
usb_alloc_isoc_req(dev_info_t * dip,uint_t isoc_pkts_count,size_t len,usb_flags_t flags)21290Sstevel@tonic-gate usb_alloc_isoc_req(dev_info_t		*dip,
21300Sstevel@tonic-gate 		uint_t			isoc_pkts_count,
21310Sstevel@tonic-gate 		size_t			len,
21320Sstevel@tonic-gate 		usb_flags_t		flags)
21330Sstevel@tonic-gate {
21340Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_req = NULL;
21350Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp;
21360Sstevel@tonic-gate 	size_t			length = sizeof (*isoc_req) +
21375773Sqz150045 	    (sizeof (usb_isoc_pkt_descr_t) * isoc_pkts_count);
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
21400Sstevel@tonic-gate 	    "usb_alloc_isoc_req: dip=0x%p pkt_cnt=%d len=%lu flags=0x%x",
21416898Sfb209375 	    (void *)dip, isoc_pkts_count, len, flags);
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 	/* client needs to set isoc_pks_count */
21440Sstevel@tonic-gate 	if (dip && isoc_pkts_count) {
21450Sstevel@tonic-gate 		/* Allocate + Initialize the usba_req_wrapper_t structure */
21460Sstevel@tonic-gate 		if ((wrp = usba_req_wrapper_alloc(dip, length, flags)) !=
21470Sstevel@tonic-gate 		    NULL) {
21480Sstevel@tonic-gate 			isoc_req = (usb_isoc_req_t *)USBA_WRP2ISOC_REQ(wrp);
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 			/* Allocate the usb_isoc_req data mblk */
21510Sstevel@tonic-gate 			if (len) {
21520Sstevel@tonic-gate 				if ((isoc_req->isoc_data =
21530Sstevel@tonic-gate 				    allocb(len, BPRI_HI)) == NULL) {
21540Sstevel@tonic-gate 					usba_req_wrapper_free(wrp);
21550Sstevel@tonic-gate 					isoc_req = NULL;
21560Sstevel@tonic-gate 				}
21570Sstevel@tonic-gate 			}
21580Sstevel@tonic-gate 		}
21590Sstevel@tonic-gate 	}
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	if (isoc_req) {
21620Sstevel@tonic-gate 		isoc_req->isoc_pkt_descr = (usb_isoc_pkt_descr_t *)
21630Sstevel@tonic-gate 		    (((intptr_t)isoc_req) + (sizeof (usb_isoc_req_t)));
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 		/* Initialize all the fields of usb isochronous request */
2166*7492SZhigang.Lu@Sun.COM 		isoc_req->isoc_pkts_count = (ushort_t)isoc_pkts_count;
21670Sstevel@tonic-gate 	}
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
21706898Sfb209375 	    "usb_alloc_isoc_req: isoc_req = 0x%p", (void *)isoc_req);
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate 	return (isoc_req);
21730Sstevel@tonic-gate }
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate /*
21770Sstevel@tonic-gate  * usba_hcdi_dup_isoc_req:
21780Sstevel@tonic-gate  *	create duplicate of isoc request
21790Sstevel@tonic-gate  *
21800Sstevel@tonic-gate  * Arguments:
21810Sstevel@tonic-gate  *	dip	- devinfo pointer
21820Sstevel@tonic-gate  *	reqp	- original request pointer
21830Sstevel@tonic-gate  *	len	- length of "data" for this isoc request
21840Sstevel@tonic-gate  *	flags	-
21850Sstevel@tonic-gate  *		USB_FLAGS_SLEEP    - Sleep if resources are not available
21860Sstevel@tonic-gate  *
21870Sstevel@tonic-gate  * Return Values:
21880Sstevel@tonic-gate  *		usb_isoc_req_t on success, NULL on failure
21890Sstevel@tonic-gate  */
21900Sstevel@tonic-gate usb_isoc_req_t *
usba_hcdi_dup_isoc_req(dev_info_t * dip,usb_isoc_req_t * reqp,usb_flags_t flags)21910Sstevel@tonic-gate usba_hcdi_dup_isoc_req(
21920Sstevel@tonic-gate 		dev_info_t	*dip,
21930Sstevel@tonic-gate 		usb_isoc_req_t	*reqp,
21940Sstevel@tonic-gate 		usb_flags_t	flags)
21950Sstevel@tonic-gate {
21960Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_reqp = NULL;
21970Sstevel@tonic-gate 	usba_req_wrapper_t	*isoc_wrp, *req_wrp;
21980Sstevel@tonic-gate 	ushort_t		count;
21990Sstevel@tonic-gate 	ushort_t		isoc_pkts_count;
22000Sstevel@tonic-gate 	size_t			length;
22010Sstevel@tonic-gate 
22020Sstevel@tonic-gate 	if (reqp == NULL) {
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 		return (isoc_reqp);
22050Sstevel@tonic-gate 	}
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 	isoc_pkts_count = reqp->isoc_pkts_count;
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 	/* calculate total data length required in original request */
22100Sstevel@tonic-gate 	for (count = length = 0; count < isoc_pkts_count; count++) {
22110Sstevel@tonic-gate 		length += reqp->isoc_pkt_descr[count].isoc_pkt_length;
22120Sstevel@tonic-gate 	}
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate 	req_wrp	= USBA_REQ2WRP(reqp);
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	if (((isoc_reqp = usb_alloc_isoc_req(dip,
22170Sstevel@tonic-gate 	    isoc_pkts_count, length, flags)) != NULL)) {
22180Sstevel@tonic-gate 		isoc_reqp->isoc_frame_no	= reqp->isoc_frame_no;
22190Sstevel@tonic-gate 		isoc_reqp->isoc_pkts_count	= reqp->isoc_pkts_count;
22200Sstevel@tonic-gate 		isoc_reqp->isoc_pkts_length	= reqp->isoc_pkts_length;
22210Sstevel@tonic-gate 		isoc_reqp->isoc_attributes	= reqp->isoc_attributes;
22220Sstevel@tonic-gate 		isoc_reqp->isoc_client_private	= reqp->isoc_client_private;
22230Sstevel@tonic-gate 		isoc_reqp->isoc_cb		= reqp->isoc_cb;
22240Sstevel@tonic-gate 		isoc_reqp->isoc_exc_cb		= reqp->isoc_exc_cb;
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 		isoc_wrp		= USBA_REQ2WRP(isoc_reqp);
22270Sstevel@tonic-gate 		isoc_wrp->wr_dip	= req_wrp->wr_dip;
22280Sstevel@tonic-gate 		isoc_wrp->wr_ph_data	= req_wrp->wr_ph_data;
22290Sstevel@tonic-gate 		isoc_wrp->wr_attrs	= req_wrp->wr_attrs;
22300Sstevel@tonic-gate 		isoc_wrp->wr_usb_flags	= req_wrp->wr_usb_flags;
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 		for (count = 0; count < isoc_pkts_count; count++) {
22330Sstevel@tonic-gate 			isoc_reqp->isoc_pkt_descr[count].isoc_pkt_length =
22345773Sqz150045 			    reqp->isoc_pkt_descr[count].isoc_pkt_length;
22350Sstevel@tonic-gate 		}
22360Sstevel@tonic-gate 	}
22370Sstevel@tonic-gate 
22380Sstevel@tonic-gate 	return (isoc_reqp);
22390Sstevel@tonic-gate }
22400Sstevel@tonic-gate 
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate /*
22430Sstevel@tonic-gate  * usb_free_isoc_req:
22440Sstevel@tonic-gate  *	- Deallocate usb isochronous resources that includes usb isochronous
22450Sstevel@tonic-gate  *	  request and array of packet descriptor strcutures.
22460Sstevel@tonic-gate  *
22470Sstevel@tonic-gate  * Arguments:
22480Sstevel@tonic-gate  *	req - pointer to usb_isoc_req_t
22490Sstevel@tonic-gate  */
22500Sstevel@tonic-gate void
usb_free_isoc_req(usb_isoc_req_t * req)22510Sstevel@tonic-gate usb_free_isoc_req(usb_isoc_req_t *req)
22520Sstevel@tonic-gate {
22530Sstevel@tonic-gate 	if (req) {
22540Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
22556898Sfb209375 		    "usb_free_isoc_req: req=0x%p", (void *)req);
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate 		if (req->isoc_data) {
22580Sstevel@tonic-gate 			freemsg(req->isoc_data);
22590Sstevel@tonic-gate 		}
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 		usba_req_wrapper_free(USBA_REQ2WRP(req));
22620Sstevel@tonic-gate 	}
22630Sstevel@tonic-gate }
22640Sstevel@tonic-gate 
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate /*
22670Sstevel@tonic-gate  * usb_get_current_frame_number:
22680Sstevel@tonic-gate  *	- request HCD to return current usb frame number
22690Sstevel@tonic-gate  *
22700Sstevel@tonic-gate  * Arguments:
22710Sstevel@tonic-gate  *	dip	- pointer to dev_info_t
22720Sstevel@tonic-gate  *
22730Sstevel@tonic-gate  * Return Values:
22740Sstevel@tonic-gate  *	current_frame_number	- request successfully executed
22750Sstevel@tonic-gate  *	0			- request failed
22760Sstevel@tonic-gate  */
22770Sstevel@tonic-gate usb_frame_number_t
usb_get_current_frame_number(dev_info_t * dip)22780Sstevel@tonic-gate usb_get_current_frame_number(dev_info_t	*dip)
22790Sstevel@tonic-gate {
22800Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
22816898Sfb209375 	    "usb_get_current_frame_number: dip=0x%p", (void *)dip);
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 	if (dip) {
22840Sstevel@tonic-gate 		usba_device_t	*usba_device = usba_get_usba_device(dip);
22855773Sqz150045 		usb_frame_number_t	frame_number;
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate 		if (usba_device->usb_hcdi_ops->
22880Sstevel@tonic-gate 		    usba_hcdi_get_current_frame_number) {
22890Sstevel@tonic-gate 
22905773Sqz150045 			if (usba_device->usb_hcdi_ops->
22915773Sqz150045 			    usba_hcdi_get_current_frame_number(usba_device,
22925773Sqz150045 			    &frame_number) == USB_SUCCESS) {
22935773Sqz150045 
22945773Sqz150045 				return (frame_number);
22955773Sqz150045 			}
22960Sstevel@tonic-gate 		}
22970Sstevel@tonic-gate 	}
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 	return (0);
23000Sstevel@tonic-gate }
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate /*
23040Sstevel@tonic-gate  * usb_get_max_isoc_pkts:
23050Sstevel@tonic-gate  *	- request HCD to return maximum isochronous packets per request
23060Sstevel@tonic-gate  *
23070Sstevel@tonic-gate  * Arguments:
23080Sstevel@tonic-gate  *	dip	- pointer to dev_info_t
23090Sstevel@tonic-gate  *
23100Sstevel@tonic-gate  * Return Values:
23110Sstevel@tonic-gate  *	isoc_pkt - request successfully executed
23120Sstevel@tonic-gate  *	0	 - request failed
23130Sstevel@tonic-gate  */
23140Sstevel@tonic-gate uint_t
usb_get_max_isoc_pkts(dev_info_t * dip)23150Sstevel@tonic-gate usb_get_max_isoc_pkts(dev_info_t *dip)
23160Sstevel@tonic-gate {
23170Sstevel@tonic-gate 	return (usb_get_max_pkts_per_isoc_request(dip));
23180Sstevel@tonic-gate }
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate uint_t
usb_get_max_pkts_per_isoc_request(dev_info_t * dip)23220Sstevel@tonic-gate usb_get_max_pkts_per_isoc_request(dev_info_t *dip)
23230Sstevel@tonic-gate {
23240Sstevel@tonic-gate 	if (dip) {
23250Sstevel@tonic-gate 		usba_device_t	*usba_device = usba_get_usba_device(dip);
23265773Sqz150045 		uint_t		max_isoc_pkts_per_request;
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
23296898Sfb209375 		    "usb_get_max_isoc_pkts: usba_device=0x%p",
23306898Sfb209375 		    (void *)usba_device);
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 		if (usba_device->usb_hcdi_ops->usba_hcdi_get_max_isoc_pkts) {
23330Sstevel@tonic-gate 
23345773Sqz150045 			if (usba_device->usb_hcdi_ops->
23355773Sqz150045 			    usba_hcdi_get_max_isoc_pkts(usba_device,
23365773Sqz150045 			    &max_isoc_pkts_per_request) == USB_SUCCESS) {
23375773Sqz150045 
23385773Sqz150045 				return (max_isoc_pkts_per_request);
23395773Sqz150045 			}
23400Sstevel@tonic-gate 		}
23410Sstevel@tonic-gate 	}
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 	return (0);
23440Sstevel@tonic-gate }
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate /*
23480Sstevel@tonic-gate  * usb_pipe_isoc_xfer:
23490Sstevel@tonic-gate  *	- check for pipe stalled
23500Sstevel@tonic-gate  *	- request HCD to transport isoc data asynchronously
23510Sstevel@tonic-gate  *
23520Sstevel@tonic-gate  * Arguments:
23530Sstevel@tonic-gate  *	pipe_handle	- isoc pipe pipehandle (obtained via usb_pipe_open())
23540Sstevel@tonic-gate  *	req		- isochronous request
23550Sstevel@tonic-gate  *
23560Sstevel@tonic-gate  * Return Values:
23570Sstevel@tonic-gate  *	USB_SUCCESS	- request successfully executed
23580Sstevel@tonic-gate  *	USB_FAILURE	- request failed
23590Sstevel@tonic-gate  */
23600Sstevel@tonic-gate int
usb_pipe_isoc_xfer(usb_pipe_handle_t pipe_handle,usb_isoc_req_t * req,usb_flags_t flags)23610Sstevel@tonic-gate usb_pipe_isoc_xfer(usb_pipe_handle_t	pipe_handle,
23620Sstevel@tonic-gate 		usb_isoc_req_t		*req,
23630Sstevel@tonic-gate 		usb_flags_t		flags)
23640Sstevel@tonic-gate {
23650Sstevel@tonic-gate 	int			rval;
23660Sstevel@tonic-gate 	usba_req_wrapper_t	*wrp = USBA_REQ2WRP(req);
23670Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph_data = usba_hold_ph_data(pipe_handle);
23680Sstevel@tonic-gate 	usba_device_t		*usba_device;
23690Sstevel@tonic-gate 	uchar_t			direction;
23700Sstevel@tonic-gate 	usb_pipe_state_t	pipe_state;
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
23730Sstevel@tonic-gate 	    "usb_pipe_isoc_xfer: flags=0x%x", flags);
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate 	if (ph_data == NULL) {
23760Sstevel@tonic-gate 
23770Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
23780Sstevel@tonic-gate 	}
23790Sstevel@tonic-gate 
23800Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
23810Sstevel@tonic-gate 	direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
23820Sstevel@tonic-gate 
23830Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
23840Sstevel@tonic-gate 	if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, flags,
23850Sstevel@tonic-gate 	    USB_EP_ATTR_ISOCH)) != USB_SUCCESS) {
23860Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
23890Sstevel@tonic-gate 
23900Sstevel@tonic-gate 		return (rval);
23910Sstevel@tonic-gate 	}
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	req->isoc_error_count = 0;
23940Sstevel@tonic-gate 
23950Sstevel@tonic-gate 	/* Get the current isoch pipe state */
23960Sstevel@tonic-gate 	pipe_state = usba_get_ph_state(ph_data);
23970Sstevel@tonic-gate 
23980Sstevel@tonic-gate 	switch (pipe_state) {
23990Sstevel@tonic-gate 	case USB_PIPE_STATE_IDLE:
24000Sstevel@tonic-gate 		usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
24010Sstevel@tonic-gate 		break;
24020Sstevel@tonic-gate 	case USB_PIPE_STATE_ACTIVE:
24030Sstevel@tonic-gate 		if (direction == USB_EP_DIR_IN) {
24040Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
24050Sstevel@tonic-gate 			    usbai_log_handle,
24060Sstevel@tonic-gate 			    "usb_pipe_isoc_req: already polling");
24070Sstevel@tonic-gate 
24080Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
24090Sstevel@tonic-gate 			usba_release_ph_data(ph_data->p_ph_impl);
24100Sstevel@tonic-gate 
24110Sstevel@tonic-gate 			return (USB_FAILURE);
24120Sstevel@tonic-gate 		}
24130Sstevel@tonic-gate 		break;
24140Sstevel@tonic-gate 	default:
24150Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
24160Sstevel@tonic-gate 		    "usb_pipe_isoc_req: pipe state %d", pipe_state);
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
24190Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate 		return (USB_PIPE_ERROR);
24220Sstevel@tonic-gate 	}
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate 	/* we accept the request */
24250Sstevel@tonic-gate 	ph_data->p_req_count++;
24260Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_isoc_xfer(
24290Sstevel@tonic-gate 	    ph_data, req, flags)) != USB_SUCCESS) {
24300Sstevel@tonic-gate 		if (req->isoc_completion_reason == USB_CR_OK) {
24310Sstevel@tonic-gate 			req->isoc_completion_reason = usba_rval2cr(rval);
24320Sstevel@tonic-gate 		}
24330Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
24340Sstevel@tonic-gate 		ASSERT(wrp->wr_done == B_FALSE);
24350Sstevel@tonic-gate 		ph_data->p_req_count--;
24360Sstevel@tonic-gate 		if ((ph_data->p_req_count == 0) &&
24370Sstevel@tonic-gate 		    (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
24380Sstevel@tonic-gate 			usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
24390Sstevel@tonic-gate 		}
24400Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
24410Sstevel@tonic-gate 	}
24420Sstevel@tonic-gate 
24430Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
24440Sstevel@tonic-gate 	    "usb_pipe_isoc_req: rval=%x", rval);
24450Sstevel@tonic-gate 
24460Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
24470Sstevel@tonic-gate 
24480Sstevel@tonic-gate 	return (rval);
24490Sstevel@tonic-gate }
24500Sstevel@tonic-gate 
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate /*
24530Sstevel@tonic-gate  * usba_pipe_sync_stop_isoc_polling:
24540Sstevel@tonic-gate  *	- set up for sync transport, if necessary
24550Sstevel@tonic-gate  *	- request HCD to stop polling
24560Sstevel@tonic-gate  *	- wait for draining of all callbacks
24570Sstevel@tonic-gate  *
24580Sstevel@tonic-gate  * Arguments:
24590Sstevel@tonic-gate  *	dip		- dev_info pointer
24600Sstevel@tonic-gate  *	pipe_handle	- pointer to pipe handle
24610Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:	wait for completion
24620Sstevel@tonic-gate  */
24630Sstevel@tonic-gate /*ARGSUSED*/
24640Sstevel@tonic-gate 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)24650Sstevel@tonic-gate usba_pipe_sync_stop_isoc_polling(dev_info_t	*dip,
24660Sstevel@tonic-gate 		usba_ph_impl_t		*ph_impl,
24670Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
24680Sstevel@tonic-gate 		usb_flags_t		flags)
24690Sstevel@tonic-gate {
24700Sstevel@tonic-gate 	int rval;
24710Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
24725773Sqz150045 	    (usb_pipe_handle_t)ph_impl);
24730Sstevel@tonic-gate 	usba_device_t	*usba_device;
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
24760Sstevel@tonic-gate 	    "usba_pipe_sync_stop_isoc_polling: uf=0x%x", flags);
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate 	if (ph_data == NULL) {
24790Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
24800Sstevel@tonic-gate 		    "usba_pipe_stop_isoc_polling: pipe closed");
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
24830Sstevel@tonic-gate 	}
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
24860Sstevel@tonic-gate 
24870Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
24900Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
24910Sstevel@tonic-gate 		    "usba_pipe_sync_stop_isoc_polling: pipe error");
24920Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
24950Sstevel@tonic-gate 
24960Sstevel@tonic-gate 		return (USB_PIPE_ERROR);
24970Sstevel@tonic-gate 	}
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
25000Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25010Sstevel@tonic-gate 		    "usba_pipe_sync_stop_isoc_polling: already stopped");
25020Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
25030Sstevel@tonic-gate 
25040Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate 		return (USB_SUCCESS);
25070Sstevel@tonic-gate 	}
25080Sstevel@tonic-gate 
25090Sstevel@tonic-gate 
25100Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 	flags |= USB_FLAGS_SLEEP;
25130Sstevel@tonic-gate 
25140Sstevel@tonic-gate 	for (;;) {
25150Sstevel@tonic-gate 		rval = usba_device->usb_hcdi_ops->
25165773Sqz150045 		    usba_hcdi_pipe_stop_isoc_polling(ph_data, flags);
25170Sstevel@tonic-gate 
25180Sstevel@tonic-gate 		/*
25190Sstevel@tonic-gate 		 * The host controller has stopped polling of the endpoint.
25200Sstevel@tonic-gate 		 * Now, drain the callbacks if there are any on the callback
25210Sstevel@tonic-gate 		 * queue.
25220Sstevel@tonic-gate 		 */
25230Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
25240Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
25250Sstevel@tonic-gate 
25260Sstevel@tonic-gate 			/*
25270Sstevel@tonic-gate 			 * there is a tiny window that the client driver
25280Sstevel@tonic-gate 			 * may still have restarted the polling and we
25290Sstevel@tonic-gate 			 * let the stop polling win
25300Sstevel@tonic-gate 			 */
25310Sstevel@tonic-gate 			rval = usba_drain_cbs(ph_data, 0,
25325773Sqz150045 			    USB_CR_STOPPED_POLLING);
25330Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
25340Sstevel@tonic-gate 			if (rval != USB_SUCCESS) {
25350Sstevel@tonic-gate 
25360Sstevel@tonic-gate 				continue;
25370Sstevel@tonic-gate 			}
25380Sstevel@tonic-gate 		}
25390Sstevel@tonic-gate 
25400Sstevel@tonic-gate 		break;
25410Sstevel@tonic-gate 	}
25420Sstevel@tonic-gate 
25430Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
25440Sstevel@tonic-gate 	    "usba_pipe_sync_stop_isoc_polling: rval=0x%x", rval);
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 	return (rval);
25490Sstevel@tonic-gate }
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate /*
25530Sstevel@tonic-gate  * usb_pipe_stop_isoc_polling:
25540Sstevel@tonic-gate  *	stop polling for isoc IN data
25550Sstevel@tonic-gate  *
25560Sstevel@tonic-gate  * Arguments:
25570Sstevel@tonic-gate  *	pipe_handle	- pipe handle
25580Sstevel@tonic-gate  *	flags		-
25590Sstevel@tonic-gate  *			USB_FLAGS_SLEEP:	wait for completion
25600Sstevel@tonic-gate  */
25610Sstevel@tonic-gate void
usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle,usb_flags_t flags)25620Sstevel@tonic-gate usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle,
25630Sstevel@tonic-gate 		usb_flags_t	flags)
25640Sstevel@tonic-gate {
25650Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
25660Sstevel@tonic-gate 
25670Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
25680Sstevel@tonic-gate 	    "usba_pipe_stop_isoc_polling: uf=0x%x", flags);
25690Sstevel@tonic-gate 
25700Sstevel@tonic-gate 	if (ph_data == NULL) {
25710Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25720Sstevel@tonic-gate 		    "usba_pipe_stop_isoc_polling: pipe closed");
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 		return;
25750Sstevel@tonic-gate 	}
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate 	if ((ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK) !=
25780Sstevel@tonic-gate 	    USB_EP_ATTR_ISOCH) {
2579978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25800Sstevel@tonic-gate 		    "usba_pipe_stop_isoc_polling: wrong pipe type");
25810Sstevel@tonic-gate 
25820Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate 		return;
25850Sstevel@tonic-gate 	}
25860Sstevel@tonic-gate 	if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2587978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25880Sstevel@tonic-gate 		    "usba_pipe_stop_isoc_polling: wrong pipe direction");
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate 		return;
25930Sstevel@tonic-gate 	}
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate 	if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2596978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25970Sstevel@tonic-gate 		    "usba_pipe_stop_intr_polling: invalid context");
25980Sstevel@tonic-gate 
25990Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate 		return;
26020Sstevel@tonic-gate 	}
26030Sstevel@tonic-gate 
26040Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(ph_data->p_dip,
26050Sstevel@tonic-gate 	    usba_pipe_sync_stop_isoc_polling,
26060Sstevel@tonic-gate 	    (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
26070Sstevel@tonic-gate 	    flags, usba_dummy_callback, NULL);
26080Sstevel@tonic-gate }
2609