1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * Utility functions
33*7c478bd9Sstevel@tonic-gate  */
34*7c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
35*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int);
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate /* local functions */
41*7c478bd9Sstevel@tonic-gate static	int	usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *,
42*7c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
43*7c478bd9Sstevel@tonic-gate static int	usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *,
44*7c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
45*7c478bd9Sstevel@tonic-gate static int	usba_sync_clear_feature(dev_info_t *, usba_ph_impl_t *,
46*7c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * Wrapper functions returning parsed standard descriptors without
50*7c478bd9Sstevel@tonic-gate  * getting the config cloud first but by just providing the dip.
51*7c478bd9Sstevel@tonic-gate  *
52*7c478bd9Sstevel@tonic-gate  * The client can easily retrieve the device and config descriptor from
53*7c478bd9Sstevel@tonic-gate  * the usb registration and no separate functions are provided
54*7c478bd9Sstevel@tonic-gate  *
55*7c478bd9Sstevel@tonic-gate  * These functions return failure if the full descriptor can not be
56*7c478bd9Sstevel@tonic-gate  * retrieved.  These functions will not access the device.
57*7c478bd9Sstevel@tonic-gate  * The caller must allocate the buffer.
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /*
61*7c478bd9Sstevel@tonic-gate  * usb_get_if_descr:
62*7c478bd9Sstevel@tonic-gate  *	Function to get the cooked interface descriptor
63*7c478bd9Sstevel@tonic-gate  *	This function will not access the device.
64*7c478bd9Sstevel@tonic-gate  *
65*7c478bd9Sstevel@tonic-gate  * Arguments:
66*7c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
67*7c478bd9Sstevel@tonic-gate  *	if_index		- interface index
68*7c478bd9Sstevel@tonic-gate  *	alt_setting	- alt interface setting
69*7c478bd9Sstevel@tonic-gate  *	descr			- pointer to user allocated interface descr
70*7c478bd9Sstevel@tonic-gate  *
71*7c478bd9Sstevel@tonic-gate  * Return Values:
72*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
73*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
74*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate int
77*7c478bd9Sstevel@tonic-gate usb_get_if_descr(dev_info_t	*dip,
78*7c478bd9Sstevel@tonic-gate 		uint_t		if_index,
79*7c478bd9Sstevel@tonic-gate 		uint_t		alt_setting,
80*7c478bd9Sstevel@tonic-gate 		usb_if_descr_t	*descr)
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;	/* buf for config descriptor */
83*7c478bd9Sstevel@tonic-gate 	size_t		size, cfg_length;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
86*7c478bd9Sstevel@tonic-gate 	    "usb_get_if_descr: %s, index=0x%x, alt#=0x%x",
87*7c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), if_index, alt_setting);
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (descr == NULL)) {
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
92*7c478bd9Sstevel@tonic-gate 	}
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
95*7c478bd9Sstevel@tonic-gate 	size = usb_parse_if_descr(usb_cfg, cfg_length,
96*7c478bd9Sstevel@tonic-gate 	    if_index,	/* interface index */
97*7c478bd9Sstevel@tonic-gate 	    alt_setting,	/* alt interface index */
98*7c478bd9Sstevel@tonic-gate 	    descr,
99*7c478bd9Sstevel@tonic-gate 	    USB_IF_DESCR_SIZE);
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	if (size != USB_IF_DESCR_SIZE) {
102*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
103*7c478bd9Sstevel@tonic-gate 		    "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
104*7c478bd9Sstevel@tonic-gate 		    size, USB_IF_DESCR_SIZE);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
107*7c478bd9Sstevel@tonic-gate 	}
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
110*7c478bd9Sstevel@tonic-gate }
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate /*
114*7c478bd9Sstevel@tonic-gate  * usb_get_ep_descr:
115*7c478bd9Sstevel@tonic-gate  *	Function to get the cooked endpoint descriptor
116*7c478bd9Sstevel@tonic-gate  *	This function will not access the device.
117*7c478bd9Sstevel@tonic-gate  *
118*7c478bd9Sstevel@tonic-gate  * Arguments:
119*7c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
120*7c478bd9Sstevel@tonic-gate  *	if_index		- interface index
121*7c478bd9Sstevel@tonic-gate  *	alt_setting		- alternate interface setting
122*7c478bd9Sstevel@tonic-gate  *	endpoint_index		- endpoint index
123*7c478bd9Sstevel@tonic-gate  *	descr			- pointer to user allocated interface descr
124*7c478bd9Sstevel@tonic-gate  *
125*7c478bd9Sstevel@tonic-gate  * Return Values:
126*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
127*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
128*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
129*7c478bd9Sstevel@tonic-gate  */
130*7c478bd9Sstevel@tonic-gate int
131*7c478bd9Sstevel@tonic-gate usb_get_ep_descr(dev_info_t	*dip,
132*7c478bd9Sstevel@tonic-gate 		uint_t		if_index,
133*7c478bd9Sstevel@tonic-gate 		uint_t		alt_setting,
134*7c478bd9Sstevel@tonic-gate 		uint_t		endpoint_index,
135*7c478bd9Sstevel@tonic-gate 		usb_ep_descr_t	*descr)
136*7c478bd9Sstevel@tonic-gate {
137*7c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;	/* buf for config descriptor */
138*7c478bd9Sstevel@tonic-gate 	size_t		size, cfg_length;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
141*7c478bd9Sstevel@tonic-gate 	    "usb_get_ep_descr: %s, index=0x%x, alt#=0x%x",
142*7c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), if_index, alt_setting);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (descr == NULL)) {
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
147*7c478bd9Sstevel@tonic-gate 	}
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
150*7c478bd9Sstevel@tonic-gate 	size = usb_parse_ep_descr(usb_cfg, cfg_length,
151*7c478bd9Sstevel@tonic-gate 		if_index,	/* interface index */
152*7c478bd9Sstevel@tonic-gate 		alt_setting,	/* alt interface index */
153*7c478bd9Sstevel@tonic-gate 		endpoint_index,		/* ep index */
154*7c478bd9Sstevel@tonic-gate 		descr, USB_EP_DESCR_SIZE);
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	if (size != USB_EP_DESCR_SIZE) {
157*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
158*7c478bd9Sstevel@tonic-gate 		    "parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)",
159*7c478bd9Sstevel@tonic-gate 		    size, USB_EP_DESCR_SIZE);
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
162*7c478bd9Sstevel@tonic-gate 	}
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
165*7c478bd9Sstevel@tonic-gate }
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate /*
169*7c478bd9Sstevel@tonic-gate  * usb_lookup_ep_data:
170*7c478bd9Sstevel@tonic-gate  * usb_get_ep_data (deprecated):
171*7c478bd9Sstevel@tonic-gate  *	Function to get specific endpoint descriptor data
172*7c478bd9Sstevel@tonic-gate  *	This function will not access the device.
173*7c478bd9Sstevel@tonic-gate  *
174*7c478bd9Sstevel@tonic-gate  * Arguments:
175*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to dev info
176*7c478bd9Sstevel@tonic-gate  *	usb_client_dev_data_t - pointer to registration data
177*7c478bd9Sstevel@tonic-gate  *	interface	- requested interface
178*7c478bd9Sstevel@tonic-gate  *	alternate	- requested alternate
179*7c478bd9Sstevel@tonic-gate  *	skip		- how many to skip
180*7c478bd9Sstevel@tonic-gate  *	type		- endpoint type
181*7c478bd9Sstevel@tonic-gate  *	direction	- endpoint direction or USB_DIR_DONT_CARE
182*7c478bd9Sstevel@tonic-gate  *
183*7c478bd9Sstevel@tonic-gate  * Return Values:
184*7c478bd9Sstevel@tonic-gate  *	NULL or an endpoint descriptor pointer
185*7c478bd9Sstevel@tonic-gate  */
186*7c478bd9Sstevel@tonic-gate usb_ep_data_t *
187*7c478bd9Sstevel@tonic-gate usb_lookup_ep_data(dev_info_t	*dip,
188*7c478bd9Sstevel@tonic-gate 		usb_client_dev_data_t *dev_datap,
189*7c478bd9Sstevel@tonic-gate 		uint_t		interface,
190*7c478bd9Sstevel@tonic-gate 		uint_t		alternate,
191*7c478bd9Sstevel@tonic-gate 		uint_t		skip,
192*7c478bd9Sstevel@tonic-gate 		uint_t		type,
193*7c478bd9Sstevel@tonic-gate 		uint_t		dir)
194*7c478bd9Sstevel@tonic-gate {
195*7c478bd9Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
196*7c478bd9Sstevel@tonic-gate 	int			i;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
199*7c478bd9Sstevel@tonic-gate 	    "usb_lookup_ep_data: "
200*7c478bd9Sstevel@tonic-gate 	    "if=%d alt=%d skip=%d type=%d dir=%d",
201*7c478bd9Sstevel@tonic-gate 	    interface, alternate, skip, type, dir);
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (dev_datap == NULL)) {
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 		return (NULL);
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	altif_data = &dev_datap->dev_curr_cfg->
209*7c478bd9Sstevel@tonic-gate 					cfg_if[interface].if_alt[alternate];
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
212*7c478bd9Sstevel@tonic-gate 	    "altif=0x%p n_ep=%d", altif_data, altif_data->altif_n_ep);
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < altif_data->altif_n_ep; i++) {
215*7c478bd9Sstevel@tonic-gate 		usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
216*7c478bd9Sstevel@tonic-gate 		uint8_t	ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
217*7c478bd9Sstevel@tonic-gate 		uint8_t ept_dir = ept->bEndpointAddress & USB_EP_DIR_MASK;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 		if (ept->bLength == 0) {
220*7c478bd9Sstevel@tonic-gate 			continue;
221*7c478bd9Sstevel@tonic-gate 		}
222*7c478bd9Sstevel@tonic-gate 		if ((ept_type == type) &&
223*7c478bd9Sstevel@tonic-gate 		    ((type == USB_EP_ATTR_CONTROL) || (dir == ept_dir))) {
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 			if (skip-- == 0) {
226*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
227*7c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
228*7c478bd9Sstevel@tonic-gate 				    "usb_get_ep_data: data=0x%p",
229*7c478bd9Sstevel@tonic-gate 				    &altif_data->altif_ep[i]);
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 				return (&altif_data->altif_ep[i]);
232*7c478bd9Sstevel@tonic-gate 			}
233*7c478bd9Sstevel@tonic-gate 		}
234*7c478bd9Sstevel@tonic-gate 	}
235*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
236*7c478bd9Sstevel@tonic-gate 	    "usb_get_ep_data: returning NULL");
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	return (NULL);
239*7c478bd9Sstevel@tonic-gate }
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
243*7c478bd9Sstevel@tonic-gate usb_ep_data_t *
244*7c478bd9Sstevel@tonic-gate usb_get_ep_data(dev_info_t	*dip,
245*7c478bd9Sstevel@tonic-gate 		usb_client_dev_data_t *dev_datap,
246*7c478bd9Sstevel@tonic-gate 		uint_t		interface,
247*7c478bd9Sstevel@tonic-gate 		uint_t		alternate,
248*7c478bd9Sstevel@tonic-gate 		uint_t		type,
249*7c478bd9Sstevel@tonic-gate 		uint_t		dir)
250*7c478bd9Sstevel@tonic-gate {
251*7c478bd9Sstevel@tonic-gate 	return (usb_lookup_ep_data(dip, dev_datap, interface,
252*7c478bd9Sstevel@tonic-gate 	    alternate, 0, type, dir));
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate /*
257*7c478bd9Sstevel@tonic-gate  * usb_get_string_descr:
258*7c478bd9Sstevel@tonic-gate  *	Function to read the string descriptor
259*7c478bd9Sstevel@tonic-gate  *	This function will access the device and block.
260*7c478bd9Sstevel@tonic-gate  *
261*7c478bd9Sstevel@tonic-gate  * Arguments:
262*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
263*7c478bd9Sstevel@tonic-gate  *	langid		- LANGID to read different LOCALEs
264*7c478bd9Sstevel@tonic-gate  *	index		- index to the string
265*7c478bd9Sstevel@tonic-gate  *	buf		- user provided buffer for string descriptor
266*7c478bd9Sstevel@tonic-gate  *	buflen		- user provided length of the buffer
267*7c478bd9Sstevel@tonic-gate  *
268*7c478bd9Sstevel@tonic-gate  * Return Values:
269*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
270*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
271*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
272*7c478bd9Sstevel@tonic-gate  */
273*7c478bd9Sstevel@tonic-gate int
274*7c478bd9Sstevel@tonic-gate usb_get_string_descr(dev_info_t *dip,
275*7c478bd9Sstevel@tonic-gate 		uint16_t	langid,
276*7c478bd9Sstevel@tonic-gate 		uint8_t 	index,
277*7c478bd9Sstevel@tonic-gate 		char		*buf,
278*7c478bd9Sstevel@tonic-gate 		size_t		buflen)
279*7c478bd9Sstevel@tonic-gate {
280*7c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
281*7c478bd9Sstevel@tonic-gate 	uint16_t	length;
282*7c478bd9Sstevel@tonic-gate 	int		rval;
283*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
284*7c478bd9Sstevel@tonic-gate 	size_t		len;
285*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
288*7c478bd9Sstevel@tonic-gate 	    "usb_get_string_descr: %s, langid=0x%x index=0x%x",
289*7c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), langid, index);
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (buf == NULL) || (buflen == 0) || (index == 0)) {
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
294*7c478bd9Sstevel@tonic-gate 	}
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	/*
297*7c478bd9Sstevel@tonic-gate 	 * determine the length of the descriptor
298*7c478bd9Sstevel@tonic-gate 	 */
299*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip,
300*7c478bd9Sstevel@tonic-gate 		usba_get_dflt_pipe_handle(dip),
301*7c478bd9Sstevel@tonic-gate 		USB_DEV_REQ_DEV_TO_HOST,
302*7c478bd9Sstevel@tonic-gate 		USB_REQ_GET_DESCR,
303*7c478bd9Sstevel@tonic-gate 		USB_DESCR_TYPE_STRING << 8 | index & 0xff,
304*7c478bd9Sstevel@tonic-gate 		langid,
305*7c478bd9Sstevel@tonic-gate 		4,
306*7c478bd9Sstevel@tonic-gate 		&data, USB_ATTRS_SHORT_XFER_OK,
307*7c478bd9Sstevel@tonic-gate 		&completion_reason,
308*7c478bd9Sstevel@tonic-gate 		&cb_flags, USB_FLAGS_SLEEP);
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
311*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
312*7c478bd9Sstevel@tonic-gate 		    "rval=%d cr=%d", rval, completion_reason);
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 		goto done;
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 	if (data->b_wptr - data->b_rptr == 0) {
317*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
318*7c478bd9Sstevel@tonic-gate 		    "0 bytes received");
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 		goto done;
321*7c478bd9Sstevel@tonic-gate 	}
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	ASSERT(data);
324*7c478bd9Sstevel@tonic-gate 	length = *(data->b_rptr);
325*7c478bd9Sstevel@tonic-gate 	freemsg(data);
326*7c478bd9Sstevel@tonic-gate 	data = NULL;
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
329*7c478bd9Sstevel@tonic-gate 	    "rval=%d, cr=%d, length=%d", rval, completion_reason, length);
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	/*
332*7c478bd9Sstevel@tonic-gate 	 * if length is zero the next control request may fail.
333*7c478bd9Sstevel@tonic-gate 	 * the HCD may not support a zero length control request
334*7c478bd9Sstevel@tonic-gate 	 * and return an mblk_t which is NULL along with rval
335*7c478bd9Sstevel@tonic-gate 	 * being USB_SUCCESS and "cr" being USB_CR_OK
336*7c478bd9Sstevel@tonic-gate 	 */
337*7c478bd9Sstevel@tonic-gate 	if (length < 2) {
338*7c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 		goto done;
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip,
344*7c478bd9Sstevel@tonic-gate 		usba_get_dflt_pipe_handle(dip),
345*7c478bd9Sstevel@tonic-gate 		USB_DEV_REQ_DEV_TO_HOST,
346*7c478bd9Sstevel@tonic-gate 		USB_REQ_GET_DESCR,
347*7c478bd9Sstevel@tonic-gate 		USB_DESCR_TYPE_STRING << 8 | index & 0xff,
348*7c478bd9Sstevel@tonic-gate 		langid,
349*7c478bd9Sstevel@tonic-gate 		length,
350*7c478bd9Sstevel@tonic-gate 		&data, USB_ATTRS_SHORT_XFER_OK,
351*7c478bd9Sstevel@tonic-gate 		&completion_reason,
352*7c478bd9Sstevel@tonic-gate 		&cb_flags, USB_FLAGS_SLEEP);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
355*7c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	if ((data == NULL) || (rval != USB_SUCCESS)) {
358*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
359*7c478bd9Sstevel@tonic-gate 		    "failed to get string descriptor (rval=%d cr=%d)",
360*7c478bd9Sstevel@tonic-gate 		    rval, completion_reason);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 		goto done;
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	if ((length = data->b_wptr - data->b_rptr) != 0) {
366*7c478bd9Sstevel@tonic-gate 		len = usba_ascii_string_descr(data->b_rptr, length, buf,
367*7c478bd9Sstevel@tonic-gate 								buflen);
368*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA,
369*7c478bd9Sstevel@tonic-gate 		    usbai_log_handle, "buf=%s buflen=%lu", buf, len);
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 		ASSERT(len <= buflen);
372*7c478bd9Sstevel@tonic-gate 	} else {
373*7c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
374*7c478bd9Sstevel@tonic-gate 	}
375*7c478bd9Sstevel@tonic-gate done:
376*7c478bd9Sstevel@tonic-gate 	freemsg(data);
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	return (rval);
379*7c478bd9Sstevel@tonic-gate }
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate /*
383*7c478bd9Sstevel@tonic-gate  * usb_get_dev_descr:
384*7c478bd9Sstevel@tonic-gate  *	 utility function to get device descriptor from usba_device
385*7c478bd9Sstevel@tonic-gate  *
386*7c478bd9Sstevel@tonic-gate  * Arguments:
387*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
388*7c478bd9Sstevel@tonic-gate  *
389*7c478bd9Sstevel@tonic-gate  * Return Values:
390*7c478bd9Sstevel@tonic-gate  *	usb_dev_descr	- device  descriptor or NULL
391*7c478bd9Sstevel@tonic-gate  */
392*7c478bd9Sstevel@tonic-gate usb_dev_descr_t *
393*7c478bd9Sstevel@tonic-gate usb_get_dev_descr(dev_info_t *dip)
394*7c478bd9Sstevel@tonic-gate {
395*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
396*7c478bd9Sstevel@tonic-gate 	usb_dev_descr_t *usb_dev_descr = NULL;
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	if (dip) {
399*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
400*7c478bd9Sstevel@tonic-gate 		    "usb_get_dev_descr: %s", ddi_node_name(dip));
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(dip);
403*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
404*7c478bd9Sstevel@tonic-gate 		usb_dev_descr = usba_device->usb_dev_descr;
405*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	return (usb_dev_descr);
409*7c478bd9Sstevel@tonic-gate }
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate /*
413*7c478bd9Sstevel@tonic-gate  * usb_get_raw_cfg_data:
414*7c478bd9Sstevel@tonic-gate  *	 utility function to get raw config descriptor from usba_device
415*7c478bd9Sstevel@tonic-gate  *
416*7c478bd9Sstevel@tonic-gate  * Arguments:
417*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
418*7c478bd9Sstevel@tonic-gate  *	length		- pointer to copy the cfg length
419*7c478bd9Sstevel@tonic-gate  *
420*7c478bd9Sstevel@tonic-gate  * Return Values:
421*7c478bd9Sstevel@tonic-gate  *	usb_cfg	- raw config descriptor
422*7c478bd9Sstevel@tonic-gate  */
423*7c478bd9Sstevel@tonic-gate uchar_t *
424*7c478bd9Sstevel@tonic-gate usb_get_raw_cfg_data(dev_info_t *dip, size_t *length)
425*7c478bd9Sstevel@tonic-gate {
426*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
427*7c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
430*7c478bd9Sstevel@tonic-gate 	    "usb_get_raw_cfg_data: %s", ddi_node_name(dip));
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (length == NULL)) {
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 		return (NULL);
435*7c478bd9Sstevel@tonic-gate 	}
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
440*7c478bd9Sstevel@tonic-gate 	usb_cfg = usba_device->usb_cfg;
441*7c478bd9Sstevel@tonic-gate 	*length = usba_device->usb_cfg_length;
442*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	return (usb_cfg);
445*7c478bd9Sstevel@tonic-gate }
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate /*
449*7c478bd9Sstevel@tonic-gate  * usb_get_addr:
450*7c478bd9Sstevel@tonic-gate  *	utility function to return current usb address, mostly
451*7c478bd9Sstevel@tonic-gate  *	for debugging purposes
452*7c478bd9Sstevel@tonic-gate  *
453*7c478bd9Sstevel@tonic-gate  * Arguments:
454*7c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
455*7c478bd9Sstevel@tonic-gate  *
456*7c478bd9Sstevel@tonic-gate  * Return Values:
457*7c478bd9Sstevel@tonic-gate  *	address	- USB Device Address
458*7c478bd9Sstevel@tonic-gate  */
459*7c478bd9Sstevel@tonic-gate int
460*7c478bd9Sstevel@tonic-gate usb_get_addr(dev_info_t *dip)
461*7c478bd9Sstevel@tonic-gate {
462*7c478bd9Sstevel@tonic-gate 	int address = 0;
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
465*7c478bd9Sstevel@tonic-gate 	    "usb_get_addr: %s", ddi_node_name(dip));
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	if (dip) {
468*7c478bd9Sstevel@tonic-gate 		usba_device_t	*usba_device = usba_get_usba_device(dip);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
471*7c478bd9Sstevel@tonic-gate 		address = usba_device->usb_addr;
472*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
473*7c478bd9Sstevel@tonic-gate 	}
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	return (address);
476*7c478bd9Sstevel@tonic-gate }
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate /*
480*7c478bd9Sstevel@tonic-gate  * usb_set_cfg():
481*7c478bd9Sstevel@tonic-gate  *	set configuration, use with caution (issues USB_REQ_SET_CONFIG)
482*7c478bd9Sstevel@tonic-gate  *	Changing configuration will fail if pipes are still open or when
483*7c478bd9Sstevel@tonic-gate  *	invoked from a driver bound to an interface on a composite device.
484*7c478bd9Sstevel@tonic-gate  *
485*7c478bd9Sstevel@tonic-gate  *	This function will access the device and block
486*7c478bd9Sstevel@tonic-gate  *
487*7c478bd9Sstevel@tonic-gate  * Arguments:
488*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
489*7c478bd9Sstevel@tonic-gate  *	cfg_index	- config index
490*7c478bd9Sstevel@tonic-gate  *	cfg_value	- config value to be set
491*7c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
492*7c478bd9Sstevel@tonic-gate  *				wait for completion
493*7c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
494*7c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
495*7c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
496*7c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
497*7c478bd9Sstevel@tonic-gate  *			  be provided.
498*7c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
499*7c478bd9Sstevel@tonic-gate  *
500*7c478bd9Sstevel@tonic-gate  * Return Values:
501*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:	- new configuration was set
502*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE:	- new configuration could not be set
503*7c478bd9Sstevel@tonic-gate  *	USB_BUSY:	- some pipes were open or there were children
504*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
505*7c478bd9Sstevel@tonic-gate  */
506*7c478bd9Sstevel@tonic-gate int
507*7c478bd9Sstevel@tonic-gate usb_set_cfg(dev_info_t		*dip,
508*7c478bd9Sstevel@tonic-gate 		uint_t		cfg_index,
509*7c478bd9Sstevel@tonic-gate 		usb_flags_t	usb_flags,
510*7c478bd9Sstevel@tonic-gate 		void		(*cb)(
511*7c478bd9Sstevel@tonic-gate 					usb_pipe_handle_t ph,
512*7c478bd9Sstevel@tonic-gate 					usb_opaque_t	arg,
513*7c478bd9Sstevel@tonic-gate 					int		rval,
514*7c478bd9Sstevel@tonic-gate 					usb_cb_flags_t	flags),
515*7c478bd9Sstevel@tonic-gate 		usb_opaque_t	cb_arg)
516*7c478bd9Sstevel@tonic-gate {
517*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	ph;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
520*7c478bd9Sstevel@tonic-gate 	    "usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x",
521*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), cfg_index,
522*7c478bd9Sstevel@tonic-gate 	    usb_flags);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
527*7c478bd9Sstevel@tonic-gate 	}
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	if (!usb_owns_device(dip)) {
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PERM);
537*7c478bd9Sstevel@tonic-gate 	}
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
540*7c478bd9Sstevel@tonic-gate 	if (usba_hold_ph_data(ph) == NULL) {
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
543*7c478bd9Sstevel@tonic-gate 	}
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	return (usba_pipe_setup_func_call(dip,
546*7c478bd9Sstevel@tonic-gate 	    usba_sync_set_cfg, (usba_ph_impl_t *)ph,
547*7c478bd9Sstevel@tonic-gate 	    (usb_opaque_t)((uintptr_t)cfg_index), usb_flags, cb, cb_arg));
548*7c478bd9Sstevel@tonic-gate }
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate static int
552*7c478bd9Sstevel@tonic-gate usba_sync_set_cfg(dev_info_t	*dip,
553*7c478bd9Sstevel@tonic-gate 		usba_ph_impl_t	*ph_impl,
554*7c478bd9Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
555*7c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
556*7c478bd9Sstevel@tonic-gate {
557*7c478bd9Sstevel@tonic-gate 	int		rval;
558*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
559*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
560*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
561*7c478bd9Sstevel@tonic-gate 	int		i, ph_open_cnt;
562*7c478bd9Sstevel@tonic-gate 	uint_t		cfg_index = (uint_t)((uintptr_t)(request->arg));
563*7c478bd9Sstevel@tonic-gate 	size_t		size;
564*7c478bd9Sstevel@tonic-gate 	usb_cfg_descr_t confdescr;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	/*
569*7c478bd9Sstevel@tonic-gate 	 * default pipe is still open
570*7c478bd9Sstevel@tonic-gate 	 * all other pipes should be closed
571*7c478bd9Sstevel@tonic-gate 	 */
572*7c478bd9Sstevel@tonic-gate 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
573*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_ph_list[i].usba_ph_data) {
574*7c478bd9Sstevel@tonic-gate 			ph_open_cnt++;
575*7c478bd9Sstevel@tonic-gate 			break;
576*7c478bd9Sstevel@tonic-gate 		}
577*7c478bd9Sstevel@tonic-gate 	}
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	if (ph_open_cnt || ddi_get_child(dip)) {
580*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 		return (USB_BUSY);
583*7c478bd9Sstevel@tonic-gate 	}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index],
586*7c478bd9Sstevel@tonic-gate 			USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE);
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	/* hubdi should ensure that this descriptor is correct */
589*7c478bd9Sstevel@tonic-gate 	ASSERT(size == USB_CFG_DESCR_SIZE);
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	/* set the configuration */
592*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl,
593*7c478bd9Sstevel@tonic-gate 		USB_DEV_REQ_HOST_TO_DEV,
594*7c478bd9Sstevel@tonic-gate 		USB_REQ_SET_CFG,
595*7c478bd9Sstevel@tonic-gate 		confdescr.bConfigurationValue,
596*7c478bd9Sstevel@tonic-gate 		0,
597*7c478bd9Sstevel@tonic-gate 		0,
598*7c478bd9Sstevel@tonic-gate 		NULL, 0,
599*7c478bd9Sstevel@tonic-gate 		&completion_reason,
600*7c478bd9Sstevel@tonic-gate 		&cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	if (rval == USB_SUCCESS) {
603*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
604*7c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg_value = confdescr.bConfigurationValue;
605*7c478bd9Sstevel@tonic-gate 		usba_device->usb_active_cfg_ndx = cfg_index;
606*7c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index];
607*7c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg_length = confdescr.wTotalLength;
608*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 		/* update the configuration property */
611*7c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
612*7c478bd9Sstevel@tonic-gate 			"configuration#", usba_device->usb_cfg_value);
613*7c478bd9Sstevel@tonic-gate 	}
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
616*7c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 	return (rval);
621*7c478bd9Sstevel@tonic-gate }
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate /*
626*7c478bd9Sstevel@tonic-gate  * usb_get_cfg():
627*7c478bd9Sstevel@tonic-gate  *	get configuration value
628*7c478bd9Sstevel@tonic-gate  *
629*7c478bd9Sstevel@tonic-gate  * Arguments:
630*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
631*7c478bd9Sstevel@tonic-gate  *	cfg_value	- current config value
632*7c478bd9Sstevel@tonic-gate  *	flags		- none, always blocks
633*7c478bd9Sstevel@tonic-gate  *
634*7c478bd9Sstevel@tonic-gate  * Return Values:
635*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:	- config value was retrieved
636*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE:	- config value could not be retrieved
637*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
638*7c478bd9Sstevel@tonic-gate  */
639*7c478bd9Sstevel@tonic-gate int
640*7c478bd9Sstevel@tonic-gate usb_get_cfg(dev_info_t		*dip,
641*7c478bd9Sstevel@tonic-gate 		uint_t		*cfgval,
642*7c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
643*7c478bd9Sstevel@tonic-gate {
644*7c478bd9Sstevel@tonic-gate 	int		rval;
645*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
646*7c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
647*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
648*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph;
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
651*7c478bd9Sstevel@tonic-gate 	    "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags);
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	if ((cfgval == NULL) || (dip == NULL)) {
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
656*7c478bd9Sstevel@tonic-gate 	}
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	/*
661*7c478bd9Sstevel@tonic-gate 	 * get the cfg value
662*7c478bd9Sstevel@tonic-gate 	 */
663*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
664*7c478bd9Sstevel@tonic-gate 		USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV,
665*7c478bd9Sstevel@tonic-gate 		USB_REQ_GET_CFG,
666*7c478bd9Sstevel@tonic-gate 		0,
667*7c478bd9Sstevel@tonic-gate 		0,
668*7c478bd9Sstevel@tonic-gate 		1,		/* returns one byte of data */
669*7c478bd9Sstevel@tonic-gate 		&data, 0,
670*7c478bd9Sstevel@tonic-gate 		&completion_reason,
671*7c478bd9Sstevel@tonic-gate 		&cb_flags, flags);
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
674*7c478bd9Sstevel@tonic-gate 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && data &&
677*7c478bd9Sstevel@tonic-gate 	    ((data->b_wptr - data->b_rptr) == 1)) {
678*7c478bd9Sstevel@tonic-gate 		*cfgval = *(data->b_rptr);
679*7c478bd9Sstevel@tonic-gate 	} else {
680*7c478bd9Sstevel@tonic-gate 		*cfgval = 1;
681*7c478bd9Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
682*7c478bd9Sstevel@tonic-gate 			rval = USB_FAILURE;
683*7c478bd9Sstevel@tonic-gate 		}
684*7c478bd9Sstevel@tonic-gate 	}
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
687*7c478bd9Sstevel@tonic-gate 	    "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval);
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 	freemsg(data);
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	return (rval);
692*7c478bd9Sstevel@tonic-gate }
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate /*
696*7c478bd9Sstevel@tonic-gate  * usb_get_current_cfgidx:
697*7c478bd9Sstevel@tonic-gate  *	get current current config index
698*7c478bd9Sstevel@tonic-gate  */
699*7c478bd9Sstevel@tonic-gate uint_t
700*7c478bd9Sstevel@tonic-gate usb_get_current_cfgidx(dev_info_t *dip)
701*7c478bd9Sstevel@tonic-gate {
702*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
703*7c478bd9Sstevel@tonic-gate 	uint_t		ndx;
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
706*7c478bd9Sstevel@tonic-gate 	ndx = usba_device->usb_active_cfg_ndx;
707*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	return (ndx);
710*7c478bd9Sstevel@tonic-gate }
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate /*
714*7c478bd9Sstevel@tonic-gate  * usb_get_if_number:
715*7c478bd9Sstevel@tonic-gate  *	get usb interface number of current OS device node.
716*7c478bd9Sstevel@tonic-gate  *
717*7c478bd9Sstevel@tonic-gate  * Arguments:
718*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
719*7c478bd9Sstevel@tonic-gate  *
720*7c478bd9Sstevel@tonic-gate  * Return Values:
721*7c478bd9Sstevel@tonic-gate  *	USB_COMBINED_NODE if the driver is responsible for the entire
722*7c478bd9Sstevel@tonic-gate  *	    device and this dip doesn't correspond to a device node.
723*7c478bd9Sstevel@tonic-gate  *	USB_DEVICE_NODE if the driver is responsible for the entire device
724*7c478bd9Sstevel@tonic-gate  *	    and this dip corresponds to a device node.
725*7c478bd9Sstevel@tonic-gate  *	interface number: otherwise.
726*7c478bd9Sstevel@tonic-gate  */
727*7c478bd9Sstevel@tonic-gate int
728*7c478bd9Sstevel@tonic-gate usb_get_if_number(dev_info_t *dip)
729*7c478bd9Sstevel@tonic-gate {
730*7c478bd9Sstevel@tonic-gate 	int interface_num;
731*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
732*7c478bd9Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
735*7c478bd9Sstevel@tonic-gate 	    "usb_get_if_number: dip = 0x%p", dip);
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	/* not quite right but we can't return a negative return value */
738*7c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 		return (0);
741*7c478bd9Sstevel@tonic-gate 	}
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	if (usba_device) {
744*7c478bd9Sstevel@tonic-gate 		usb_dev_descr = usba_device->usb_dev_descr;
745*7c478bd9Sstevel@tonic-gate 	} else {
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 		return (0);
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
751*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE);
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 	if (interface_num == USB_COMBINED_NODE) {
754*7c478bd9Sstevel@tonic-gate 		if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
755*7c478bd9Sstevel@tonic-gate 		    (usb_dev_descr->bDeviceClass == 0)) &&
756*7c478bd9Sstevel@tonic-gate 		    (usba_device->usb_n_cfgs == 1) &&
757*7c478bd9Sstevel@tonic-gate 		    (usba_device->usb_n_ifs == 1))) {
758*7c478bd9Sstevel@tonic-gate 			interface_num = USB_DEVICE_NODE;
759*7c478bd9Sstevel@tonic-gate 		}
760*7c478bd9Sstevel@tonic-gate 	}
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	return (interface_num);
763*7c478bd9Sstevel@tonic-gate }
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate boolean_t
767*7c478bd9Sstevel@tonic-gate usb_owns_device(dev_info_t *dip)
768*7c478bd9Sstevel@tonic-gate {
769*7c478bd9Sstevel@tonic-gate 	int interface_num = usb_get_if_number(dip);
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	return (interface_num < 0 ? B_TRUE : B_FALSE);
772*7c478bd9Sstevel@tonic-gate }
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate uint8_t
776*7c478bd9Sstevel@tonic-gate usba_get_ifno(dev_info_t *dip)
777*7c478bd9Sstevel@tonic-gate {
778*7c478bd9Sstevel@tonic-gate 	int interface_num = usb_get_if_number(dip);
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	return (interface_num < 0 ? 0 : interface_num);
781*7c478bd9Sstevel@tonic-gate }
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate /*
785*7c478bd9Sstevel@tonic-gate  * usb_set_alt_if:
786*7c478bd9Sstevel@tonic-gate  *	set the alternate interface number. Issues USB_REQ_SET_IF
787*7c478bd9Sstevel@tonic-gate  *	This function will access the device
788*7c478bd9Sstevel@tonic-gate  *
789*7c478bd9Sstevel@tonic-gate  * Arguments:
790*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
791*7c478bd9Sstevel@tonic-gate  *	if_number	- interface number
792*7c478bd9Sstevel@tonic-gate  *	alt_number	- alternate interface number
793*7c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
794*7c478bd9Sstevel@tonic-gate  *				wait for completion
795*7c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
796*7c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
797*7c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
798*7c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
799*7c478bd9Sstevel@tonic-gate  *			  be provided.
800*7c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
801*7c478bd9Sstevel@tonic-gate  *
802*7c478bd9Sstevel@tonic-gate  *
803*7c478bd9Sstevel@tonic-gate  * return values:
804*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- alternate was set
805*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- alternate could not be set because pipes
806*7c478bd9Sstevel@tonic-gate  *			  were still open or some access error occurred
807*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
808*7c478bd9Sstevel@tonic-gate  *
809*7c478bd9Sstevel@tonic-gate  * Note:
810*7c478bd9Sstevel@tonic-gate  *	we can't easily check if all pipes to endpoints for this interface
811*7c478bd9Sstevel@tonic-gate  *	are closed since we don't have a map of which endpoints belong
812*7c478bd9Sstevel@tonic-gate  *	to which interface. If we had this map, we would need to update
813*7c478bd9Sstevel@tonic-gate  *	this on each alternative or configuration switch
814*7c478bd9Sstevel@tonic-gate  */
815*7c478bd9Sstevel@tonic-gate int
816*7c478bd9Sstevel@tonic-gate usb_set_alt_if(dev_info_t	*dip,
817*7c478bd9Sstevel@tonic-gate 		uint_t		interface,
818*7c478bd9Sstevel@tonic-gate 		uint_t		alt_number,
819*7c478bd9Sstevel@tonic-gate 		usb_flags_t	usb_flags,
820*7c478bd9Sstevel@tonic-gate 		void		(*cb)(
821*7c478bd9Sstevel@tonic-gate 					usb_pipe_handle_t ph,
822*7c478bd9Sstevel@tonic-gate 					usb_opaque_t	arg,
823*7c478bd9Sstevel@tonic-gate 					int		rval,
824*7c478bd9Sstevel@tonic-gate 					usb_cb_flags_t	flags),
825*7c478bd9Sstevel@tonic-gate 		usb_opaque_t	cb_arg)
826*7c478bd9Sstevel@tonic-gate {
827*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	ph;
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
830*7c478bd9Sstevel@tonic-gate 	    "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
831*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip),
832*7c478bd9Sstevel@tonic-gate 	    interface, alt_number, usb_flags);
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
837*7c478bd9Sstevel@tonic-gate 	}
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
842*7c478bd9Sstevel@tonic-gate 	}
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
845*7c478bd9Sstevel@tonic-gate 	if (usba_hold_ph_data(ph) == NULL) {
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
848*7c478bd9Sstevel@tonic-gate 	}
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	return (usba_pipe_setup_func_call(dip,
851*7c478bd9Sstevel@tonic-gate 	    usba_sync_set_alt_if, (usba_ph_impl_t *)ph,
852*7c478bd9Sstevel@tonic-gate 	    (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)),
853*7c478bd9Sstevel@tonic-gate 	    usb_flags, cb, cb_arg));
854*7c478bd9Sstevel@tonic-gate }
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate static int
858*7c478bd9Sstevel@tonic-gate usba_sync_set_alt_if(dev_info_t	*dip,
859*7c478bd9Sstevel@tonic-gate 		usba_ph_impl_t	*ph_impl,
860*7c478bd9Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
861*7c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
862*7c478bd9Sstevel@tonic-gate {
863*7c478bd9Sstevel@tonic-gate 	int		rval;
864*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
865*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
866*7c478bd9Sstevel@tonic-gate 	usb_opaque_t	arg = request->arg;
867*7c478bd9Sstevel@tonic-gate 	int		interface = ((uintptr_t)arg >> 8) & 0xff;
868*7c478bd9Sstevel@tonic-gate 	int		alt_number = (uintptr_t)arg & 0xff;
869*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
870*7c478bd9Sstevel@tonic-gate 				(usb_pipe_handle_t)ph_impl);
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
873*7c478bd9Sstevel@tonic-gate 	    "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
874*7c478bd9Sstevel@tonic-gate 	    "uf=0x%x", ddi_node_name(dip), interface,
875*7c478bd9Sstevel@tonic-gate 	    alt_number, flags);
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 	/* if we don't own the device, we must own the interface */
878*7c478bd9Sstevel@tonic-gate 	if (!usb_owns_device(dip) &&
879*7c478bd9Sstevel@tonic-gate 	    (interface != usb_get_if_number(dip))) {
880*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PERM);
883*7c478bd9Sstevel@tonic-gate 	}
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	/* set the alternate setting */
886*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip),
887*7c478bd9Sstevel@tonic-gate 		USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
888*7c478bd9Sstevel@tonic-gate 		USB_REQ_SET_IF,
889*7c478bd9Sstevel@tonic-gate 		alt_number,
890*7c478bd9Sstevel@tonic-gate 		interface,
891*7c478bd9Sstevel@tonic-gate 		0,
892*7c478bd9Sstevel@tonic-gate 		NULL, 0,
893*7c478bd9Sstevel@tonic-gate 		&completion_reason,
894*7c478bd9Sstevel@tonic-gate 		&cb_flags, flags | USB_FLAGS_SLEEP);
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
897*7c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 	return (rval);
902*7c478bd9Sstevel@tonic-gate }
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate /*
906*7c478bd9Sstevel@tonic-gate  * usb_get_alt_if:
907*7c478bd9Sstevel@tonic-gate  *	get the alternate interface number. Issues USB_REQ_GET_IF
908*7c478bd9Sstevel@tonic-gate  *	This function will access the device and block
909*7c478bd9Sstevel@tonic-gate  *
910*7c478bd9Sstevel@tonic-gate  * Arguments:
911*7c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
912*7c478bd9Sstevel@tonic-gate  *	if_number	- interface number
913*7c478bd9Sstevel@tonic-gate  *	alt_number	- alternate interface number
914*7c478bd9Sstevel@tonic-gate  *	flags			- none but USB_FLAGS_SLEEP may be passed
915*7c478bd9Sstevel@tonic-gate  *
916*7c478bd9Sstevel@tonic-gate  * return values:
917*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:		alternate was set
918*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE:		alternate could not be set because pipes
919*7c478bd9Sstevel@tonic-gate  *				were still open or some access error occurred
920*7c478bd9Sstevel@tonic-gate  */
921*7c478bd9Sstevel@tonic-gate int
922*7c478bd9Sstevel@tonic-gate usb_get_alt_if(dev_info_t	*dip,
923*7c478bd9Sstevel@tonic-gate 		uint_t		if_number,
924*7c478bd9Sstevel@tonic-gate 		uint_t		*alt_number,
925*7c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
926*7c478bd9Sstevel@tonic-gate {
927*7c478bd9Sstevel@tonic-gate 	int		rval;
928*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
929*7c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
930*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
931*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph;
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
934*7c478bd9Sstevel@tonic-gate 	    "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
935*7c478bd9Sstevel@tonic-gate 	    "uf = 0x%x", ddi_node_name(dip), if_number,
936*7c478bd9Sstevel@tonic-gate 	    alt_number, flags);
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	if ((alt_number == NULL) || (dip == NULL)) {
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
941*7c478bd9Sstevel@tonic-gate 	}
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 	/*
946*7c478bd9Sstevel@tonic-gate 	 * get the alternate setting
947*7c478bd9Sstevel@tonic-gate 	 */
948*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
949*7c478bd9Sstevel@tonic-gate 		USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF,
950*7c478bd9Sstevel@tonic-gate 		USB_REQ_GET_IF,
951*7c478bd9Sstevel@tonic-gate 		0,
952*7c478bd9Sstevel@tonic-gate 		if_number,
953*7c478bd9Sstevel@tonic-gate 		1,		/* returns one byte of data */
954*7c478bd9Sstevel@tonic-gate 		&data, 0,
955*7c478bd9Sstevel@tonic-gate 		&completion_reason,
956*7c478bd9Sstevel@tonic-gate 		&cb_flags, flags);
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
959*7c478bd9Sstevel@tonic-gate 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && data &&
962*7c478bd9Sstevel@tonic-gate 	    ((data->b_wptr - data->b_rptr) == 1)) {
963*7c478bd9Sstevel@tonic-gate 		*alt_number = *(data->b_rptr);
964*7c478bd9Sstevel@tonic-gate 	} else {
965*7c478bd9Sstevel@tonic-gate 		*alt_number = 0;
966*7c478bd9Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
967*7c478bd9Sstevel@tonic-gate 			rval = USB_FAILURE;
968*7c478bd9Sstevel@tonic-gate 		}
969*7c478bd9Sstevel@tonic-gate 	}
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate 	freemsg(data);
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	return (rval);
974*7c478bd9Sstevel@tonic-gate }
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate /*
978*7c478bd9Sstevel@tonic-gate  * usba_get_cfg_cloud:
979*7c478bd9Sstevel@tonic-gate  *	Get descriptor cloud for a given configuration.
980*7c478bd9Sstevel@tonic-gate  *
981*7c478bd9Sstevel@tonic-gate  * Arguments:
982*7c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
983*7c478bd9Sstevel@tonic-gate  *	default_ph		- default pipe handle
984*7c478bd9Sstevel@tonic-gate  *	cfg			- which configuration to retrieve raw cloud of
985*7c478bd9Sstevel@tonic-gate  *
986*7c478bd9Sstevel@tonic-gate  * Returns:
987*7c478bd9Sstevel@tonic-gate  *	on success: mblock containing the raw data.  Caller must free.
988*7c478bd9Sstevel@tonic-gate  *	on failure: NULL
989*7c478bd9Sstevel@tonic-gate  */
990*7c478bd9Sstevel@tonic-gate static mblk_t *
991*7c478bd9Sstevel@tonic-gate usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg)
992*7c478bd9Sstevel@tonic-gate {
993*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
994*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
995*7c478bd9Sstevel@tonic-gate 	usb_cfg_descr_t cfg_descr;
996*7c478bd9Sstevel@tonic-gate 	mblk_t		*pdata = NULL;
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
999*7c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1000*7c478bd9Sstevel@tonic-gate 	    USB_REQ_GET_DESCR,
1001*7c478bd9Sstevel@tonic-gate 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
1002*7c478bd9Sstevel@tonic-gate 	    0,
1003*7c478bd9Sstevel@tonic-gate 	    USB_CFG_DESCR_SIZE,
1004*7c478bd9Sstevel@tonic-gate 	    &pdata,
1005*7c478bd9Sstevel@tonic-gate 	    0,
1006*7c478bd9Sstevel@tonic-gate 	    &completion_reason,
1007*7c478bd9Sstevel@tonic-gate 	    &cb_flags,
1008*7c478bd9Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 		freemsg(pdata);
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 		return (NULL);
1013*7c478bd9Sstevel@tonic-gate 	}
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	(void) usb_parse_cfg_descr(pdata->b_rptr,
1016*7c478bd9Sstevel@tonic-gate 	    pdata->b_wptr - pdata->b_rptr, &cfg_descr, USB_CFG_DESCR_SIZE);
1017*7c478bd9Sstevel@tonic-gate 	freemsg(pdata);
1018*7c478bd9Sstevel@tonic-gate 	pdata = NULL;
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
1021*7c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1022*7c478bd9Sstevel@tonic-gate 	    USB_REQ_GET_DESCR,
1023*7c478bd9Sstevel@tonic-gate 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
1024*7c478bd9Sstevel@tonic-gate 	    0,
1025*7c478bd9Sstevel@tonic-gate 	    cfg_descr.wTotalLength,
1026*7c478bd9Sstevel@tonic-gate 	    &pdata,
1027*7c478bd9Sstevel@tonic-gate 	    0,
1028*7c478bd9Sstevel@tonic-gate 	    &completion_reason,
1029*7c478bd9Sstevel@tonic-gate 	    &cb_flags,
1030*7c478bd9Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 		freemsg(pdata);
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 		return (NULL);
1035*7c478bd9Sstevel@tonic-gate 	}
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	return (pdata);
1038*7c478bd9Sstevel@tonic-gate }
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate /*
1041*7c478bd9Sstevel@tonic-gate  * usb_check_same_device:
1042*7c478bd9Sstevel@tonic-gate  *	Check if the device connected to the port is the same as
1043*7c478bd9Sstevel@tonic-gate  *	the previous device that was in the port.  The previous device is
1044*7c478bd9Sstevel@tonic-gate  *	represented by the dip on record for the port.	Print a message
1045*7c478bd9Sstevel@tonic-gate  *	if the device is different.  If device_string arg is not NULL, it is
1046*7c478bd9Sstevel@tonic-gate  *	included in the message.  Can block.
1047*7c478bd9Sstevel@tonic-gate  *
1048*7c478bd9Sstevel@tonic-gate  * Arguments:
1049*7c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
1050*7c478bd9Sstevel@tonic-gate  *	log_handle		- handle to which messages are logged
1051*7c478bd9Sstevel@tonic-gate  *	log_level		- one of USB_LOG_*
1052*7c478bd9Sstevel@tonic-gate  *	log_mask		- logging mask
1053*7c478bd9Sstevel@tonic-gate  *	check_mask		- one mask containing things to check:
1054*7c478bd9Sstevel@tonic-gate  *					USB_CHK_BASIC: empty mask;
1055*7c478bd9Sstevel@tonic-gate  *						these checks are always done.
1056*7c478bd9Sstevel@tonic-gate  *					USB_CHK_VIDPID:
1057*7c478bd9Sstevel@tonic-gate  *						check vid, pid only.
1058*7c478bd9Sstevel@tonic-gate  *					USB_CHK_SERIAL: check match on device
1059*7c478bd9Sstevel@tonic-gate  *						serial number.
1060*7c478bd9Sstevel@tonic-gate  *					USB_CHK_CFG: check all raw config
1061*7c478bd9Sstevel@tonic-gate  *						clouds for a match.
1062*7c478bd9Sstevel@tonic-gate  *				NOTE: descr length and content always checked
1063*7c478bd9Sstevel@tonic-gate  *	device_string		- Device string to appear in error message
1064*7c478bd9Sstevel@tonic-gate  *
1065*7c478bd9Sstevel@tonic-gate  * return values:
1066*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:		same device
1067*7c478bd9Sstevel@tonic-gate  *	USB_INVALID_VERSION	not same device
1068*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE:		Failure processing request
1069*7c478bd9Sstevel@tonic-gate  *	USB_INVALID_ARG:	dip is invalid
1070*7c478bd9Sstevel@tonic-gate  */
1071*7c478bd9Sstevel@tonic-gate int
1072*7c478bd9Sstevel@tonic-gate usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle,
1073*7c478bd9Sstevel@tonic-gate     int log_level, int log_mask, uint_t check_mask, char *device_string)
1074*7c478bd9Sstevel@tonic-gate {
1075*7c478bd9Sstevel@tonic-gate 	usb_dev_descr_t		usb_dev_descr;
1076*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
1077*7c478bd9Sstevel@tonic-gate 	mblk_t			*pdata = NULL;
1078*7c478bd9Sstevel@tonic-gate 	uint16_t		length;
1079*7c478bd9Sstevel@tonic-gate 	int			rval;
1080*7c478bd9Sstevel@tonic-gate 	char			*buf;
1081*7c478bd9Sstevel@tonic-gate 	usb_cr_t		completion_reason;
1082*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags;
1083*7c478bd9Sstevel@tonic-gate 	boolean_t		match = B_TRUE;
1084*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	def_ph;
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1089*7c478bd9Sstevel@tonic-gate 	}
1090*7c478bd9Sstevel@tonic-gate 
1091*7c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
1092*7c478bd9Sstevel@tonic-gate 	length = usba_device->usb_dev_descr->bLength;
1093*7c478bd9Sstevel@tonic-gate 	def_ph = usba_get_dflt_pipe_handle(dip);
1094*7c478bd9Sstevel@tonic-gate 	ASSERT(def_ph);
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 	/* get the "new" device descriptor */
1097*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
1098*7c478bd9Sstevel@tonic-gate 			USB_DEV_REQ_DEV_TO_HOST |
1099*7c478bd9Sstevel@tonic-gate 				USB_DEV_REQ_TYPE_STANDARD,
1100*7c478bd9Sstevel@tonic-gate 			USB_REQ_GET_DESCR,		/* bRequest */
1101*7c478bd9Sstevel@tonic-gate 			USB_DESCR_TYPE_SETUP_DEV,	/* wValue */
1102*7c478bd9Sstevel@tonic-gate 			0,				/* wIndex */
1103*7c478bd9Sstevel@tonic-gate 			length,				/* wLength */
1104*7c478bd9Sstevel@tonic-gate 			&pdata, 0,
1105*7c478bd9Sstevel@tonic-gate 			&completion_reason,
1106*7c478bd9Sstevel@tonic-gate 			&cb_flags, USB_FLAGS_SLEEP);
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
1109*7c478bd9Sstevel@tonic-gate 		if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) {
1110*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle,
1111*7c478bd9Sstevel@tonic-gate 			    "getting device descriptor failed (%d)", rval);
1112*7c478bd9Sstevel@tonic-gate 			freemsg(pdata);
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
1115*7c478bd9Sstevel@tonic-gate 		}
1116*7c478bd9Sstevel@tonic-gate 	}
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	ASSERT(pdata != NULL);
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	(void) usb_parse_dev_descr(pdata->b_rptr,
1121*7c478bd9Sstevel@tonic-gate 	    pdata->b_wptr - pdata->b_rptr, &usb_dev_descr,
1122*7c478bd9Sstevel@tonic-gate 	    sizeof (usb_dev_descr_t));
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 	freemsg(pdata);
1125*7c478bd9Sstevel@tonic-gate 	pdata = NULL;
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate 	/* Always check the device descriptor length. */
1128*7c478bd9Sstevel@tonic-gate 	if (usb_dev_descr.bLength != length) {
1129*7c478bd9Sstevel@tonic-gate 		match = B_FALSE;
1130*7c478bd9Sstevel@tonic-gate 	}
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) {
1133*7c478bd9Sstevel@tonic-gate 		match = (usba_device->usb_dev_descr->idVendor ==
1134*7c478bd9Sstevel@tonic-gate 		    usb_dev_descr.idVendor) &&
1135*7c478bd9Sstevel@tonic-gate 		    (usba_device->usb_dev_descr->idProduct ==
1136*7c478bd9Sstevel@tonic-gate 		    usb_dev_descr.idProduct);
1137*7c478bd9Sstevel@tonic-gate 	} else if (bcmp((char *)usba_device->usb_dev_descr,
1138*7c478bd9Sstevel@tonic-gate 	    (char *)&usb_dev_descr, length) != 0) {
1139*7c478bd9Sstevel@tonic-gate 		match = B_FALSE;
1140*7c478bd9Sstevel@tonic-gate 	}
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	/* if requested & this device has a serial number check and compare */
1143*7c478bd9Sstevel@tonic-gate 	if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) &&
1144*7c478bd9Sstevel@tonic-gate 	    (usba_device->usb_serialno_str != NULL)) {
1145*7c478bd9Sstevel@tonic-gate 		buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
1146*7c478bd9Sstevel@tonic-gate 		if (usb_get_string_descr(dip, USB_LANG_ID,
1147*7c478bd9Sstevel@tonic-gate 		    usb_dev_descr.iSerialNumber, buf,
1148*7c478bd9Sstevel@tonic-gate 		    USB_MAXSTRINGLEN) == USB_SUCCESS) {
1149*7c478bd9Sstevel@tonic-gate 			match =
1150*7c478bd9Sstevel@tonic-gate 			    (strcmp(buf, usba_device->usb_serialno_str) == 0);
1151*7c478bd9Sstevel@tonic-gate 		}
1152*7c478bd9Sstevel@tonic-gate 		kmem_free(buf, USB_MAXSTRINGLEN);
1153*7c478bd9Sstevel@tonic-gate 	}
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) {
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 		uint8_t num_cfgs = usb_dev_descr.bNumConfigurations;
1158*7c478bd9Sstevel@tonic-gate 		uint8_t cfg;
1159*7c478bd9Sstevel@tonic-gate 		mblk_t *cloud;
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 		for (cfg = 0; cfg < num_cfgs; cfg++) {
1162*7c478bd9Sstevel@tonic-gate 			cloud = usba_get_cfg_cloud(dip, def_ph, cfg);
1163*7c478bd9Sstevel@tonic-gate 			if (cloud == NULL) {
1164*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(DPRINT_MASK_USBA,
1165*7c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
1166*7c478bd9Sstevel@tonic-gate 				    "Could not retrieve config cloud for "
1167*7c478bd9Sstevel@tonic-gate 				    "comparison");
1168*7c478bd9Sstevel@tonic-gate 				break;
1169*7c478bd9Sstevel@tonic-gate 			}
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 			if (bcmp((char *)cloud->b_rptr,
1172*7c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_array[cfg],
1173*7c478bd9Sstevel@tonic-gate 			    cloud->b_wptr - cloud->b_rptr) != 0) {
1174*7c478bd9Sstevel@tonic-gate 				freemsg(cloud);
1175*7c478bd9Sstevel@tonic-gate 				break;
1176*7c478bd9Sstevel@tonic-gate 			}
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 			freemsg(cloud);
1179*7c478bd9Sstevel@tonic-gate 		}
1180*7c478bd9Sstevel@tonic-gate 		if (cfg != num_cfgs) {
1181*7c478bd9Sstevel@tonic-gate 			match = B_FALSE;
1182*7c478bd9Sstevel@tonic-gate 		}
1183*7c478bd9Sstevel@tonic-gate 	}
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	if (match == B_FALSE) {
1186*7c478bd9Sstevel@tonic-gate 		boolean_t allocated_here = (device_string == NULL);
1187*7c478bd9Sstevel@tonic-gate 		if (allocated_here) {
1188*7c478bd9Sstevel@tonic-gate 			device_string =
1189*7c478bd9Sstevel@tonic-gate 			    kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP);
1190*7c478bd9Sstevel@tonic-gate 			(void) usba_get_mfg_prod_sn_str(dip, device_string,
1191*7c478bd9Sstevel@tonic-gate 						USB_MAXSTRINGLEN);
1192*7c478bd9Sstevel@tonic-gate 		}
1193*7c478bd9Sstevel@tonic-gate 		if (device_string[0] != '\0') {
1194*7c478bd9Sstevel@tonic-gate 			(void) usb_log(log_handle, log_level, log_mask,
1195*7c478bd9Sstevel@tonic-gate 			    "Cannot access %s.	Please reconnect.",
1196*7c478bd9Sstevel@tonic-gate 			    device_string);
1197*7c478bd9Sstevel@tonic-gate 		} else {
1198*7c478bd9Sstevel@tonic-gate 			(void) usb_log(log_handle, log_level, log_mask,
1199*7c478bd9Sstevel@tonic-gate 			    "Device is not identical to the "
1200*7c478bd9Sstevel@tonic-gate 			    "previous one this port.\n"
1201*7c478bd9Sstevel@tonic-gate 			    "Please disconnect and reconnect");
1202*7c478bd9Sstevel@tonic-gate 		}
1203*7c478bd9Sstevel@tonic-gate 		if (allocated_here) {
1204*7c478bd9Sstevel@tonic-gate 			kmem_free(device_string, USB_MAXSTRINGLEN);
1205*7c478bd9Sstevel@tonic-gate 		}
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_VERSION);
1208*7c478bd9Sstevel@tonic-gate 	}
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1211*7c478bd9Sstevel@tonic-gate }
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate /*
1215*7c478bd9Sstevel@tonic-gate  * usb_pipe_get_state:
1216*7c478bd9Sstevel@tonic-gate  *	Return the state of the pipe
1217*7c478bd9Sstevel@tonic-gate  *
1218*7c478bd9Sstevel@tonic-gate  * Arguments:
1219*7c478bd9Sstevel@tonic-gate  *	pipe_handle	- pipe_handle pointer
1220*7c478bd9Sstevel@tonic-gate  *	pipe_state	- pointer to copy pipe state to
1221*7c478bd9Sstevel@tonic-gate  *	flags:
1222*7c478bd9Sstevel@tonic-gate  *		not used other than to check context
1223*7c478bd9Sstevel@tonic-gate  *
1224*7c478bd9Sstevel@tonic-gate  * Return Values:
1225*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- port state returned
1226*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
1227*7c478bd9Sstevel@tonic-gate  */
1228*7c478bd9Sstevel@tonic-gate int
1229*7c478bd9Sstevel@tonic-gate usb_pipe_get_state(usb_pipe_handle_t	pipe_handle,
1230*7c478bd9Sstevel@tonic-gate 	    usb_pipe_state_t	*pipe_state,
1231*7c478bd9Sstevel@tonic-gate 	    usb_flags_t		usb_flags)
1232*7c478bd9Sstevel@tonic-gate {
1233*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1236*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_get_state: ph_data=0x%p uf=0x%x", ph_data, usb_flags);
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	if (pipe_state == NULL) {
1239*7c478bd9Sstevel@tonic-gate 		if (ph_data) {
1240*7c478bd9Sstevel@tonic-gate 			usba_release_ph_data(ph_data->p_ph_impl);
1241*7c478bd9Sstevel@tonic-gate 		}
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1244*7c478bd9Sstevel@tonic-gate 	}
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
1247*7c478bd9Sstevel@tonic-gate 		*pipe_state = USB_PIPE_STATE_CLOSED;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
1250*7c478bd9Sstevel@tonic-gate 	}
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1253*7c478bd9Sstevel@tonic-gate 	*pipe_state = usba_get_ph_state(ph_data);
1254*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1259*7c478bd9Sstevel@tonic-gate }
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 
1262*7c478bd9Sstevel@tonic-gate /*
1263*7c478bd9Sstevel@tonic-gate  * usba_pipe_get_policy:
1264*7c478bd9Sstevel@tonic-gate  *	Return a pipe's policy
1265*7c478bd9Sstevel@tonic-gate  *
1266*7c478bd9Sstevel@tonic-gate  * Arguments:
1267*7c478bd9Sstevel@tonic-gate  *	pipe_handle	- pipe_handle pointer
1268*7c478bd9Sstevel@tonic-gate  *
1269*7c478bd9Sstevel@tonic-gate  * Return Values:
1270*7c478bd9Sstevel@tonic-gate  *	On success: the pipe's policy
1271*7c478bd9Sstevel@tonic-gate  *	On failure: NULL
1272*7c478bd9Sstevel@tonic-gate  */
1273*7c478bd9Sstevel@tonic-gate usb_pipe_policy_t
1274*7c478bd9Sstevel@tonic-gate *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)
1275*7c478bd9Sstevel@tonic-gate {
1276*7c478bd9Sstevel@tonic-gate 	usb_pipe_policy_t *pp = NULL;
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 	if (ph_data) {
1281*7c478bd9Sstevel@tonic-gate 		pp = &ph_data->p_policy;
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
1284*7c478bd9Sstevel@tonic-gate 	}
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 	return (pp);
1287*7c478bd9Sstevel@tonic-gate }
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate /*
1291*7c478bd9Sstevel@tonic-gate  * usb_ep_num:
1292*7c478bd9Sstevel@tonic-gate  *	Return the endpoint number for a given pipe handle
1293*7c478bd9Sstevel@tonic-gate  *
1294*7c478bd9Sstevel@tonic-gate  * Arguments:
1295*7c478bd9Sstevel@tonic-gate  *	pipe_handle	- pipe_handle pointer
1296*7c478bd9Sstevel@tonic-gate  *
1297*7c478bd9Sstevel@tonic-gate  * Return Values:
1298*7c478bd9Sstevel@tonic-gate  *	endpoint number
1299*7c478bd9Sstevel@tonic-gate  */
1300*7c478bd9Sstevel@tonic-gate int
1301*7c478bd9Sstevel@tonic-gate usb_ep_num(usb_pipe_handle_t pipe_handle)
1302*7c478bd9Sstevel@tonic-gate {
1303*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1304*7c478bd9Sstevel@tonic-gate 	int ep_num;
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
1309*7c478bd9Sstevel@tonic-gate 	}
1310*7c478bd9Sstevel@tonic-gate 
1311*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1312*7c478bd9Sstevel@tonic-gate 	ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK;
1313*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1314*7c478bd9Sstevel@tonic-gate 
1315*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate 	return (ep_num);
1318*7c478bd9Sstevel@tonic-gate }
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate 
1321*7c478bd9Sstevel@tonic-gate /*
1322*7c478bd9Sstevel@tonic-gate  * usb_get_status
1323*7c478bd9Sstevel@tonic-gate  *	Issues USB_REQ_GET_STATUS to device/endpoint/interface
1324*7c478bd9Sstevel@tonic-gate  *	and report in "status" arg.
1325*7c478bd9Sstevel@tonic-gate  *
1326*7c478bd9Sstevel@tonic-gate  *	status reported for a "device" is
1327*7c478bd9Sstevel@tonic-gate  *		RemoteWakeup enabled
1328*7c478bd9Sstevel@tonic-gate  *		SelfPowered device?
1329*7c478bd9Sstevel@tonic-gate  *
1330*7c478bd9Sstevel@tonic-gate  *	status reported for an "interface" is NONE.
1331*7c478bd9Sstevel@tonic-gate  *	status reported for an "endpoint" is
1332*7c478bd9Sstevel@tonic-gate  *		HALT set (device STALLED?)
1333*7c478bd9Sstevel@tonic-gate  *
1334*7c478bd9Sstevel@tonic-gate  * Arguments:
1335*7c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
1336*7c478bd9Sstevel@tonic-gate  *	ph	- pipe handle
1337*7c478bd9Sstevel@tonic-gate  *	type	- bmRequestType to be used
1338*7c478bd9Sstevel@tonic-gate  *	what	- 0 for device, otherwise interface or ep number
1339*7c478bd9Sstevel@tonic-gate  *	status	- user supplied pointer for storing the status
1340*7c478bd9Sstevel@tonic-gate  *	flags	- USB_FLAGS_SLEEP (mandatory)
1341*7c478bd9Sstevel@tonic-gate  *
1342*7c478bd9Sstevel@tonic-gate  * Return Values:
1343*7c478bd9Sstevel@tonic-gate  *	valid usb_status_t	or USB_FAILURE
1344*7c478bd9Sstevel@tonic-gate  */
1345*7c478bd9Sstevel@tonic-gate int
1346*7c478bd9Sstevel@tonic-gate usb_get_status(dev_info_t		*dip,
1347*7c478bd9Sstevel@tonic-gate 		usb_pipe_handle_t	ph,
1348*7c478bd9Sstevel@tonic-gate 		uint_t			type,	/* bmRequestType */
1349*7c478bd9Sstevel@tonic-gate 		uint_t			what,	/* 0, interface, ept number */
1350*7c478bd9Sstevel@tonic-gate 		uint16_t		*status,
1351*7c478bd9Sstevel@tonic-gate 		usb_flags_t		flags)
1352*7c478bd9Sstevel@tonic-gate {
1353*7c478bd9Sstevel@tonic-gate 	int		rval;
1354*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
1355*7c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
1356*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1359*7c478bd9Sstevel@tonic-gate 	    "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x",
1360*7c478bd9Sstevel@tonic-gate 	    type, what, flags);
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate 	if ((status == NULL) || (dip == NULL)) {
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1365*7c478bd9Sstevel@tonic-gate 	}
1366*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
1369*7c478bd9Sstevel@tonic-gate 	}
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 	type |= USB_DEV_REQ_DEV_TO_HOST;
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate 	/* get the status */
1374*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1375*7c478bd9Sstevel@tonic-gate 		type,
1376*7c478bd9Sstevel@tonic-gate 		USB_REQ_GET_STATUS,
1377*7c478bd9Sstevel@tonic-gate 		0,
1378*7c478bd9Sstevel@tonic-gate 		what,
1379*7c478bd9Sstevel@tonic-gate 		USB_GET_STATUS_LEN,	/* status is fixed 2 bytes long */
1380*7c478bd9Sstevel@tonic-gate 		&data, 0,
1381*7c478bd9Sstevel@tonic-gate 		&completion_reason, &cb_flags, flags);
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1384*7c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1385*7c478bd9Sstevel@tonic-gate 
1386*7c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && data &&
1387*7c478bd9Sstevel@tonic-gate 	    ((data->b_wptr - data->b_rptr) == USB_GET_STATUS_LEN)) {
1388*7c478bd9Sstevel@tonic-gate 		*status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
1389*7c478bd9Sstevel@tonic-gate 	} else {
1390*7c478bd9Sstevel@tonic-gate 		*status = 0;
1391*7c478bd9Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
1392*7c478bd9Sstevel@tonic-gate 			rval = USB_FAILURE;
1393*7c478bd9Sstevel@tonic-gate 		}
1394*7c478bd9Sstevel@tonic-gate 	}
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 	freemsg(data);
1397*7c478bd9Sstevel@tonic-gate 
1398*7c478bd9Sstevel@tonic-gate 	return (rval);
1399*7c478bd9Sstevel@tonic-gate }
1400*7c478bd9Sstevel@tonic-gate 
1401*7c478bd9Sstevel@tonic-gate 
1402*7c478bd9Sstevel@tonic-gate /*
1403*7c478bd9Sstevel@tonic-gate  * usb_clear_feature:
1404*7c478bd9Sstevel@tonic-gate  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1405*7c478bd9Sstevel@tonic-gate  *
1406*7c478bd9Sstevel@tonic-gate  * Arguments:
1407*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
1408*7c478bd9Sstevel@tonic-gate  *	ph		- pipe handle pointer
1409*7c478bd9Sstevel@tonic-gate  *	type		- bmRequestType to be used
1410*7c478bd9Sstevel@tonic-gate  *	feature		- feature to be cleared
1411*7c478bd9Sstevel@tonic-gate  *	what		- 0 for device, otherwise interface or ep number
1412*7c478bd9Sstevel@tonic-gate  *	flags		- none (but will sleep)
1413*7c478bd9Sstevel@tonic-gate  *
1414*7c478bd9Sstevel@tonic-gate  * Return Values:
1415*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- on doing a successful clear feature
1416*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- on failure
1417*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
1418*7c478bd9Sstevel@tonic-gate  */
1419*7c478bd9Sstevel@tonic-gate int
1420*7c478bd9Sstevel@tonic-gate usb_clear_feature(dev_info_t		*dip,
1421*7c478bd9Sstevel@tonic-gate 		usb_pipe_handle_t	ph,
1422*7c478bd9Sstevel@tonic-gate 		uint_t			type,	/* bmRequestType */
1423*7c478bd9Sstevel@tonic-gate 		uint_t			feature,
1424*7c478bd9Sstevel@tonic-gate 		uint_t			what,	/* 0, interface, ept number */
1425*7c478bd9Sstevel@tonic-gate 		usb_flags_t		flags)
1426*7c478bd9Sstevel@tonic-gate {
1427*7c478bd9Sstevel@tonic-gate 	int		rval;
1428*7c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
1429*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1432*7c478bd9Sstevel@tonic-gate 	    "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1433*7c478bd9Sstevel@tonic-gate 	    "uf = 0x%x", type, feature, what, flags);
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1438*7c478bd9Sstevel@tonic-gate 	}
1439*7c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
1440*7c478bd9Sstevel@tonic-gate 
1441*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
1442*7c478bd9Sstevel@tonic-gate 	}
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate 	/* issue Clear feature */
1445*7c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1446*7c478bd9Sstevel@tonic-gate 		type,
1447*7c478bd9Sstevel@tonic-gate 		USB_REQ_CLEAR_FEATURE,
1448*7c478bd9Sstevel@tonic-gate 		feature,
1449*7c478bd9Sstevel@tonic-gate 		what,
1450*7c478bd9Sstevel@tonic-gate 		0,
1451*7c478bd9Sstevel@tonic-gate 		NULL, 0,
1452*7c478bd9Sstevel@tonic-gate 		&completion_reason,
1453*7c478bd9Sstevel@tonic-gate 		&cb_flags, flags | USB_FLAGS_SLEEP);
1454*7c478bd9Sstevel@tonic-gate 
1455*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1456*7c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate 	return (rval);
1459*7c478bd9Sstevel@tonic-gate }
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 
1462*7c478bd9Sstevel@tonic-gate /*
1463*7c478bd9Sstevel@tonic-gate  * usb_clr_feature:
1464*7c478bd9Sstevel@tonic-gate  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1465*7c478bd9Sstevel@tonic-gate  *
1466*7c478bd9Sstevel@tonic-gate  * Arguments:
1467*7c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
1468*7c478bd9Sstevel@tonic-gate  *	type		- bmRequestType to be used
1469*7c478bd9Sstevel@tonic-gate  *	feature		- feature to be cleared
1470*7c478bd9Sstevel@tonic-gate  *	what		- 0 for device, otherwise interface or ep number
1471*7c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
1472*7c478bd9Sstevel@tonic-gate  *				wait for completion
1473*7c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
1474*7c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
1475*7c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
1476*7c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
1477*7c478bd9Sstevel@tonic-gate  *			  be provided.
1478*7c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
1479*7c478bd9Sstevel@tonic-gate  *
1480*7c478bd9Sstevel@tonic-gate  *
1481*7c478bd9Sstevel@tonic-gate  * Return Values:
1482*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- on doing a successful clear feature
1483*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- on failure
1484*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
1485*7c478bd9Sstevel@tonic-gate  */
1486*7c478bd9Sstevel@tonic-gate int
1487*7c478bd9Sstevel@tonic-gate usb_clr_feature(
1488*7c478bd9Sstevel@tonic-gate 		dev_info_t	*dip,
1489*7c478bd9Sstevel@tonic-gate 		uint_t		type,	/* bmRequestType */
1490*7c478bd9Sstevel@tonic-gate 		uint_t		feature,
1491*7c478bd9Sstevel@tonic-gate 		uint_t		what,	/* 0, interface, ept number */
1492*7c478bd9Sstevel@tonic-gate 		usb_flags_t	flags,
1493*7c478bd9Sstevel@tonic-gate 		void		(*cb)(
1494*7c478bd9Sstevel@tonic-gate 					usb_pipe_handle_t ph,
1495*7c478bd9Sstevel@tonic-gate 					usb_opaque_t	arg,
1496*7c478bd9Sstevel@tonic-gate 					int		rval,
1497*7c478bd9Sstevel@tonic-gate 					usb_cb_flags_t	flags),
1498*7c478bd9Sstevel@tonic-gate 		usb_opaque_t	cb_arg)
1499*7c478bd9Sstevel@tonic-gate {
1500*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph;
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1503*7c478bd9Sstevel@tonic-gate 	    "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1504*7c478bd9Sstevel@tonic-gate 	    "uf = 0x%x", type, feature, what, flags);
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1509*7c478bd9Sstevel@tonic-gate 	}
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 	if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
1514*7c478bd9Sstevel@tonic-gate 	}
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
1517*7c478bd9Sstevel@tonic-gate 	if (usba_hold_ph_data(ph) == NULL) {
1518*7c478bd9Sstevel@tonic-gate 
1519*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
1520*7c478bd9Sstevel@tonic-gate 	}
1521*7c478bd9Sstevel@tonic-gate 
1522*7c478bd9Sstevel@tonic-gate 	return (usba_pipe_setup_func_call(dip,
1523*7c478bd9Sstevel@tonic-gate 	    usba_sync_clear_feature, (usba_ph_impl_t *)ph,
1524*7c478bd9Sstevel@tonic-gate 	    (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))),
1525*7c478bd9Sstevel@tonic-gate 	    flags, cb, cb_arg));
1526*7c478bd9Sstevel@tonic-gate }
1527*7c478bd9Sstevel@tonic-gate 
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate static int
1530*7c478bd9Sstevel@tonic-gate usba_sync_clear_feature(dev_info_t *dip,
1531*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl,
1532*7c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t	*req,
1533*7c478bd9Sstevel@tonic-gate 	usb_flags_t 		usb_flags)
1534*7c478bd9Sstevel@tonic-gate {
1535*7c478bd9Sstevel@tonic-gate 	uint_t	n = (uint_t)((uintptr_t)(req->arg));
1536*7c478bd9Sstevel@tonic-gate 	uint_t	type = ((uint_t)n >> 16) & 0xff;
1537*7c478bd9Sstevel@tonic-gate 	uint_t	feature = ((uint_t)n >> 8) & 0xff;
1538*7c478bd9Sstevel@tonic-gate 	uint_t	what = (uint_t)n & 0xff;
1539*7c478bd9Sstevel@tonic-gate 	int 	rval;
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1542*7c478bd9Sstevel@tonic-gate 	    "usb_sync_clear_feature: "
1543*7c478bd9Sstevel@tonic-gate 	    "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
1544*7c478bd9Sstevel@tonic-gate 	    dip, ph_impl, type, feature, what, usb_flags);
1545*7c478bd9Sstevel@tonic-gate 
1546*7c478bd9Sstevel@tonic-gate 	rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type,
1547*7c478bd9Sstevel@tonic-gate 					feature, what, usb_flags);
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate 	return (rval);
1552*7c478bd9Sstevel@tonic-gate }
1553*7c478bd9Sstevel@tonic-gate 
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate /*
1556*7c478bd9Sstevel@tonic-gate  * usb_async_req:
1557*7c478bd9Sstevel@tonic-gate  *	function used to dispatch a request to the taskq
1558*7c478bd9Sstevel@tonic-gate  *
1559*7c478bd9Sstevel@tonic-gate  * Arguments:
1560*7c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo node
1561*7c478bd9Sstevel@tonic-gate  *	func	- pointer to function issued by taskq
1562*7c478bd9Sstevel@tonic-gate  *	flag	- USB_FLAGS_SLEEP mostly
1563*7c478bd9Sstevel@tonic-gate  *
1564*7c478bd9Sstevel@tonic-gate  * Return Values:
1565*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- on doing a successful taskq invocation
1566*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- on failure
1567*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
1568*7c478bd9Sstevel@tonic-gate  */
1569*7c478bd9Sstevel@tonic-gate int
1570*7c478bd9Sstevel@tonic-gate usb_async_req(dev_info_t *dip,
1571*7c478bd9Sstevel@tonic-gate 		void	(*func)(void *),
1572*7c478bd9Sstevel@tonic-gate 		void	*arg,
1573*7c478bd9Sstevel@tonic-gate 		usb_flags_t flag)
1574*7c478bd9Sstevel@tonic-gate {
1575*7c478bd9Sstevel@tonic-gate 	int tq_flag;
1576*7c478bd9Sstevel@tonic-gate 
1577*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1578*7c478bd9Sstevel@tonic-gate 	    "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
1579*7c478bd9Sstevel@tonic-gate 	    dip, func, arg, flag);
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (func == NULL)) {
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1584*7c478bd9Sstevel@tonic-gate 	}
1585*7c478bd9Sstevel@tonic-gate 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1586*7c478bd9Sstevel@tonic-gate 	if (flag & USB_FLAGS_NOQUEUE) {
1587*7c478bd9Sstevel@tonic-gate 		tq_flag |= TQ_NOQUEUE;
1588*7c478bd9Sstevel@tonic-gate 	}
1589*7c478bd9Sstevel@tonic-gate 
1590*7c478bd9Sstevel@tonic-gate 	if (!taskq_dispatch(system_taskq, func, (void *)arg,
1591*7c478bd9Sstevel@tonic-gate 	    tq_flag)) {
1592*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1593*7c478bd9Sstevel@tonic-gate 		    "usb_async_req: failure");
1594*7c478bd9Sstevel@tonic-gate 
1595*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1596*7c478bd9Sstevel@tonic-gate 	}
1597*7c478bd9Sstevel@tonic-gate 
1598*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1599*7c478bd9Sstevel@tonic-gate }
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate /*
1602*7c478bd9Sstevel@tonic-gate  * usba_async_ph_req:
1603*7c478bd9Sstevel@tonic-gate  *	function used to dispatch a request to the ph taskq
1604*7c478bd9Sstevel@tonic-gate  *
1605*7c478bd9Sstevel@tonic-gate  * Arguments:
1606*7c478bd9Sstevel@tonic-gate  *	ph_data	- pointer to pipe handle data
1607*7c478bd9Sstevel@tonic-gate  *	func	- pointer to function issued by taskq
1608*7c478bd9Sstevel@tonic-gate  *	flag	- USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
1609*7c478bd9Sstevel@tonic-gate  *
1610*7c478bd9Sstevel@tonic-gate  * Return Values:
1611*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- on doing a successful taskq invocation
1612*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- on failure
1613*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
1614*7c478bd9Sstevel@tonic-gate  *
1615*7c478bd9Sstevel@tonic-gate  * Note:
1616*7c478bd9Sstevel@tonic-gate  *	If the caller specified  USB_FLAGS_NOSLEEP, it must be
1617*7c478bd9Sstevel@tonic-gate  *	capable of reliably recovering from a failure return
1618*7c478bd9Sstevel@tonic-gate  */
1619*7c478bd9Sstevel@tonic-gate int
1620*7c478bd9Sstevel@tonic-gate usba_async_ph_req(usba_pipe_handle_data_t *ph_data,
1621*7c478bd9Sstevel@tonic-gate 		void	(*func)(void *),
1622*7c478bd9Sstevel@tonic-gate 		void	*arg,
1623*7c478bd9Sstevel@tonic-gate 		usb_flags_t flag)
1624*7c478bd9Sstevel@tonic-gate {
1625*7c478bd9Sstevel@tonic-gate 	int	tq_flag;
1626*7c478bd9Sstevel@tonic-gate 	taskq_t *taskq;
1627*7c478bd9Sstevel@tonic-gate 
1628*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1629*7c478bd9Sstevel@tonic-gate 	    "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
1630*7c478bd9Sstevel@tonic-gate 	    ph_data, func, arg, flag);
1631*7c478bd9Sstevel@tonic-gate 
1632*7c478bd9Sstevel@tonic-gate 	if (func == NULL) {
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1635*7c478bd9Sstevel@tonic-gate 	}
1636*7c478bd9Sstevel@tonic-gate 
1637*7c478bd9Sstevel@tonic-gate 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 	if (ph_data && ph_data->p_taskq) {
1640*7c478bd9Sstevel@tonic-gate 		taskq = ph_data->p_taskq;
1641*7c478bd9Sstevel@tonic-gate 	} else {
1642*7c478bd9Sstevel@tonic-gate 		taskq = system_taskq;
1643*7c478bd9Sstevel@tonic-gate 		tq_flag |= TQ_NOQUEUE;
1644*7c478bd9Sstevel@tonic-gate 	}
1645*7c478bd9Sstevel@tonic-gate 
1646*7c478bd9Sstevel@tonic-gate 	if (!taskq_dispatch(taskq, func, (void *)arg, tq_flag)) {
1647*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1648*7c478bd9Sstevel@tonic-gate 		    "usba_async_ph_req: failure");
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1651*7c478bd9Sstevel@tonic-gate 	}
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1654*7c478bd9Sstevel@tonic-gate }
1655*7c478bd9Sstevel@tonic-gate 
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate /*
1658*7c478bd9Sstevel@tonic-gate  * utility functions to display CR, CB, return values
1659*7c478bd9Sstevel@tonic-gate  */
1660*7c478bd9Sstevel@tonic-gate typedef struct conv_table {
1661*7c478bd9Sstevel@tonic-gate 	int		what;
1662*7c478bd9Sstevel@tonic-gate 	const char	*name;
1663*7c478bd9Sstevel@tonic-gate } conv_table_t;
1664*7c478bd9Sstevel@tonic-gate 
1665*7c478bd9Sstevel@tonic-gate static const char *
1666*7c478bd9Sstevel@tonic-gate usba_get_name(conv_table_t *conv_table, int value)
1667*7c478bd9Sstevel@tonic-gate {
1668*7c478bd9Sstevel@tonic-gate 	int i;
1669*7c478bd9Sstevel@tonic-gate 	for (i = 0; conv_table[i].name != NULL; i++) {
1670*7c478bd9Sstevel@tonic-gate 		if (conv_table[i].what == value) {
1671*7c478bd9Sstevel@tonic-gate 
1672*7c478bd9Sstevel@tonic-gate 			return (conv_table[i].name);
1673*7c478bd9Sstevel@tonic-gate 		}
1674*7c478bd9Sstevel@tonic-gate 	}
1675*7c478bd9Sstevel@tonic-gate 
1676*7c478bd9Sstevel@tonic-gate 	return ("unknown");
1677*7c478bd9Sstevel@tonic-gate }
1678*7c478bd9Sstevel@tonic-gate 
1679*7c478bd9Sstevel@tonic-gate 
1680*7c478bd9Sstevel@tonic-gate static conv_table_t cr_table[] = {
1681*7c478bd9Sstevel@tonic-gate 	{ USB_CR_OK,		"<no errors detected>" },
1682*7c478bd9Sstevel@tonic-gate 	{ USB_CR_CRC,		"<crc error detected>" },
1683*7c478bd9Sstevel@tonic-gate 	{ USB_CR_BITSTUFFING,	"<Bit stuffing violation>" },
1684*7c478bd9Sstevel@tonic-gate 	{ USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
1685*7c478bd9Sstevel@tonic-gate 	{ USB_CR_STALL, 	"<Endpoint returned stall PID>" },
1686*7c478bd9Sstevel@tonic-gate 	{ USB_CR_DEV_NOT_RESP,	"<Device not responding>" },
1687*7c478bd9Sstevel@tonic-gate 	{ USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
1688*7c478bd9Sstevel@tonic-gate 	{ USB_CR_UNEXP_PID,	"<Receive PID was not valid>" },
1689*7c478bd9Sstevel@tonic-gate 	{ USB_CR_DATA_OVERRUN,	"<Data size exceeded>" },
1690*7c478bd9Sstevel@tonic-gate 	{ USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
1691*7c478bd9Sstevel@tonic-gate 	{ USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
1692*7c478bd9Sstevel@tonic-gate 	{ USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
1693*7c478bd9Sstevel@tonic-gate 	{ USB_CR_TIMEOUT,	"<Command timed out>" },
1694*7c478bd9Sstevel@tonic-gate 	{ USB_CR_NOT_ACCESSED,	"<Not accessed by hardware>" },
1695*7c478bd9Sstevel@tonic-gate 	{ USB_CR_NO_RESOURCES,	"<No resources>" },
1696*7c478bd9Sstevel@tonic-gate 	{ USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
1697*7c478bd9Sstevel@tonic-gate 	{ USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
1698*7c478bd9Sstevel@tonic-gate 	{ USB_CR_PIPE_CLOSING,	"<Intr/ISOC IN pipe being closed>" },
1699*7c478bd9Sstevel@tonic-gate 	{ USB_CR_PIPE_RESET,	"<Intr/ISOC IN pipe reset>" },
1700*7c478bd9Sstevel@tonic-gate 	{ USB_CR_NOT_SUPPORTED, "<Command not supported>" },
1701*7c478bd9Sstevel@tonic-gate 	{ USB_CR_FLUSHED,	"<Req was flushed>" },
1702*7c478bd9Sstevel@tonic-gate 	{ USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
1703*7c478bd9Sstevel@tonic-gate 	{ 0,			NULL }
1704*7c478bd9Sstevel@tonic-gate };
1705*7c478bd9Sstevel@tonic-gate 
1706*7c478bd9Sstevel@tonic-gate const char *
1707*7c478bd9Sstevel@tonic-gate usb_str_cr(usb_cr_t cr)
1708*7c478bd9Sstevel@tonic-gate {
1709*7c478bd9Sstevel@tonic-gate 	return (usba_get_name(cr_table, cr));
1710*7c478bd9Sstevel@tonic-gate }
1711*7c478bd9Sstevel@tonic-gate 
1712*7c478bd9Sstevel@tonic-gate 
1713*7c478bd9Sstevel@tonic-gate static conv_table_t cb_flags_table[] = {
1714*7c478bd9Sstevel@tonic-gate 	{ USB_CB_NO_INFO,	"<callback processed>" },
1715*7c478bd9Sstevel@tonic-gate 	{ USB_CB_STALL_CLEARED, "<stall cleared>" },
1716*7c478bd9Sstevel@tonic-gate 	{ USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
1717*7c478bd9Sstevel@tonic-gate 	{ USB_CB_PROTOCOL_STALL, "<protocol stall>" },
1718*7c478bd9Sstevel@tonic-gate 	{ USB_CB_RESET_PIPE,	"<pipe reset>" },
1719*7c478bd9Sstevel@tonic-gate 	{ USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
1720*7c478bd9Sstevel@tonic-gate 	{ USB_CB_NO_RESOURCES,	"<no resources>" },
1721*7c478bd9Sstevel@tonic-gate 	{ USB_CB_SUBMIT_FAILED, "<submit failed>" },
1722*7c478bd9Sstevel@tonic-gate 	{ USB_CB_INTR_CONTEXT,	"<Callback executing in interrupt context>" },
1723*7c478bd9Sstevel@tonic-gate 	{ 0,			NULL }
1724*7c478bd9Sstevel@tonic-gate };
1725*7c478bd9Sstevel@tonic-gate 
1726*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1727*7c478bd9Sstevel@tonic-gate char *
1728*7c478bd9Sstevel@tonic-gate usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length)
1729*7c478bd9Sstevel@tonic-gate {
1730*7c478bd9Sstevel@tonic-gate 	int i;
1731*7c478bd9Sstevel@tonic-gate 	buffer[0] = '\0';
1732*7c478bd9Sstevel@tonic-gate 	if (cb_flags == USB_CB_NO_INFO) {
1733*7c478bd9Sstevel@tonic-gate 		(void) strncpy(buffer, cb_flags_table[0].name, length);
1734*7c478bd9Sstevel@tonic-gate 	} else {
1735*7c478bd9Sstevel@tonic-gate 		for (i = 0; cb_flags_table[i].name != NULL; i++) {
1736*7c478bd9Sstevel@tonic-gate 			if (cb_flags & cb_flags_table[i].what) {
1737*7c478bd9Sstevel@tonic-gate 				(void) strncpy(&buffer[strlen(buffer)],
1738*7c478bd9Sstevel@tonic-gate 				    cb_flags_table[0].name,
1739*7c478bd9Sstevel@tonic-gate 				    length - strlen(buffer) - 1);
1740*7c478bd9Sstevel@tonic-gate 			}
1741*7c478bd9Sstevel@tonic-gate 		}
1742*7c478bd9Sstevel@tonic-gate 	}
1743*7c478bd9Sstevel@tonic-gate 
1744*7c478bd9Sstevel@tonic-gate 	return (buffer);
1745*7c478bd9Sstevel@tonic-gate }
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 
1748*7c478bd9Sstevel@tonic-gate static conv_table_t pipe_state_table[] = {
1749*7c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_CLOSED,	"<closed>" },
1750*7c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_IDLE,		"<idle>" },
1751*7c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_ACTIVE,	"<active>" },
1752*7c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_ERROR,		"<error>" },
1753*7c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_CLOSING,	"<closing>" },
1754*7c478bd9Sstevel@tonic-gate 	{ 0,				NULL }
1755*7c478bd9Sstevel@tonic-gate };
1756*7c478bd9Sstevel@tonic-gate 
1757*7c478bd9Sstevel@tonic-gate const char *
1758*7c478bd9Sstevel@tonic-gate usb_str_pipe_state(usb_pipe_state_t state)
1759*7c478bd9Sstevel@tonic-gate {
1760*7c478bd9Sstevel@tonic-gate 	return (usba_get_name(pipe_state_table, state));
1761*7c478bd9Sstevel@tonic-gate }
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate static conv_table_t dev_state[] = {
1765*7c478bd9Sstevel@tonic-gate 	{ USB_DEV_ONLINE,	"<online>" },
1766*7c478bd9Sstevel@tonic-gate 	{ USB_DEV_DISCONNECTED,	"<disconnected>" },
1767*7c478bd9Sstevel@tonic-gate 	{ USB_DEV_SUSPENDED,	"<suspended>" },
1768*7c478bd9Sstevel@tonic-gate 	{ USB_DEV_PWRED_DOWN,	"<powered down>" },
1769*7c478bd9Sstevel@tonic-gate 	{ 0,			NULL }
1770*7c478bd9Sstevel@tonic-gate };
1771*7c478bd9Sstevel@tonic-gate 
1772*7c478bd9Sstevel@tonic-gate const char *
1773*7c478bd9Sstevel@tonic-gate usb_str_dev_state(int state)
1774*7c478bd9Sstevel@tonic-gate {
1775*7c478bd9Sstevel@tonic-gate 	return (usba_get_name(dev_state, state));
1776*7c478bd9Sstevel@tonic-gate }
1777*7c478bd9Sstevel@tonic-gate 
1778*7c478bd9Sstevel@tonic-gate 
1779*7c478bd9Sstevel@tonic-gate static conv_table_t rval_table[] = {
1780*7c478bd9Sstevel@tonic-gate 	{ USB_SUCCESS,		"<success>" },
1781*7c478bd9Sstevel@tonic-gate 	{ USB_FAILURE,		"<failure>" },
1782*7c478bd9Sstevel@tonic-gate 	{ USB_NO_RESOURCES,	"<no resources>" },
1783*7c478bd9Sstevel@tonic-gate 	{ USB_NO_BANDWIDTH,	"<no bandwidth>" },
1784*7c478bd9Sstevel@tonic-gate 	{ USB_NOT_SUPPORTED,	"<not supported>" },
1785*7c478bd9Sstevel@tonic-gate 	{ USB_PIPE_ERROR,	"<pipe error>" },
1786*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_PIPE,	"<invalid pipe>" },
1787*7c478bd9Sstevel@tonic-gate 	{ USB_NO_FRAME_NUMBER,	"<no frame number>" },
1788*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_START_FRAME, "<invalid frame>" },
1789*7c478bd9Sstevel@tonic-gate 	{ USB_HC_HARDWARE_ERROR, "<hw error>" },
1790*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_REQUEST,	"<invalid request>" },
1791*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_CONTEXT,	"<invalid context>" },
1792*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_VERSION,	"<invalid version>" },
1793*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_ARGS,	"<invalid args>" },
1794*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_PERM,	"<invalid perms>" },
1795*7c478bd9Sstevel@tonic-gate 	{ USB_BUSY,		"<busy>" },
1796*7c478bd9Sstevel@tonic-gate 	{ 0,			NULL }
1797*7c478bd9Sstevel@tonic-gate };
1798*7c478bd9Sstevel@tonic-gate 
1799*7c478bd9Sstevel@tonic-gate const char *
1800*7c478bd9Sstevel@tonic-gate usb_str_rval(int rval)
1801*7c478bd9Sstevel@tonic-gate {
1802*7c478bd9Sstevel@tonic-gate 	return (usba_get_name(rval_table, rval));
1803*7c478bd9Sstevel@tonic-gate }
1804*7c478bd9Sstevel@tonic-gate 
1805*7c478bd9Sstevel@tonic-gate 
1806*7c478bd9Sstevel@tonic-gate /*
1807*7c478bd9Sstevel@tonic-gate  * function to convert USB return values to close errno
1808*7c478bd9Sstevel@tonic-gate  */
1809*7c478bd9Sstevel@tonic-gate static struct usb_rval2errno_entry {
1810*7c478bd9Sstevel@tonic-gate 	int	rval;
1811*7c478bd9Sstevel@tonic-gate 	int	Errno;
1812*7c478bd9Sstevel@tonic-gate } usb_rval2errno_table[] = {
1813*7c478bd9Sstevel@tonic-gate 	{ USB_SUCCESS,			0	},
1814*7c478bd9Sstevel@tonic-gate 	{ USB_FAILURE,			EIO	},
1815*7c478bd9Sstevel@tonic-gate 	{ USB_NO_RESOURCES,		ENOMEM	},
1816*7c478bd9Sstevel@tonic-gate 	{ USB_NO_BANDWIDTH,		EAGAIN	},
1817*7c478bd9Sstevel@tonic-gate 	{ USB_NOT_SUPPORTED,		ENOTSUP },
1818*7c478bd9Sstevel@tonic-gate 	{ USB_PIPE_ERROR,		EIO	},
1819*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_PIPE,		EINVAL	},
1820*7c478bd9Sstevel@tonic-gate 	{ USB_NO_FRAME_NUMBER,		EINVAL	},
1821*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_START_FRAME,	EINVAL	},
1822*7c478bd9Sstevel@tonic-gate 	{ USB_HC_HARDWARE_ERROR,	EIO	},
1823*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_REQUEST,		EINVAL	},
1824*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_CONTEXT,		EINVAL	},
1825*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_VERSION,		EINVAL	},
1826*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_ARGS,		EINVAL	},
1827*7c478bd9Sstevel@tonic-gate 	{ USB_INVALID_PERM,		EACCES	},
1828*7c478bd9Sstevel@tonic-gate 	{ USB_BUSY,			EBUSY	},
1829*7c478bd9Sstevel@tonic-gate };
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate #define	USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
1832*7c478bd9Sstevel@tonic-gate 			sizeof (struct usb_rval2errno_entry))
1833*7c478bd9Sstevel@tonic-gate int
1834*7c478bd9Sstevel@tonic-gate usb_rval2errno(int rval)
1835*7c478bd9Sstevel@tonic-gate {
1836*7c478bd9Sstevel@tonic-gate 	int i;
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
1839*7c478bd9Sstevel@tonic-gate 		if (usb_rval2errno_table[i].rval == rval) {
1840*7c478bd9Sstevel@tonic-gate 
1841*7c478bd9Sstevel@tonic-gate 			return (usb_rval2errno_table[i].Errno);
1842*7c478bd9Sstevel@tonic-gate 		}
1843*7c478bd9Sstevel@tonic-gate 	}
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 	return (EIO);
1846*7c478bd9Sstevel@tonic-gate }
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate 
1849*7c478bd9Sstevel@tonic-gate /*
1850*7c478bd9Sstevel@tonic-gate  * serialization
1851*7c478bd9Sstevel@tonic-gate  */
1852*7c478bd9Sstevel@tonic-gate usb_serialization_t
1853*7c478bd9Sstevel@tonic-gate usb_init_serialization(
1854*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip,
1855*7c478bd9Sstevel@tonic-gate 	uint_t		flag)
1856*7c478bd9Sstevel@tonic-gate {
1857*7c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp = kmem_zalloc(
1858*7c478bd9Sstevel@tonic-gate 				sizeof (usba_serialization_impl_t), KM_SLEEP);
1859*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
1860*7c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t cookie = NULL;
1861*7c478bd9Sstevel@tonic-gate 
1862*7c478bd9Sstevel@tonic-gate 	if (dip) {
1863*7c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(dip);
1864*7c478bd9Sstevel@tonic-gate 		cookie = usba_hcdi_get_hcdi(
1865*7c478bd9Sstevel@tonic-gate 		    usba_device->usb_root_hub_dip)->hcdi_iblock_cookie;
1866*7c478bd9Sstevel@tonic-gate 	}
1867*7c478bd9Sstevel@tonic-gate 	impl_tokenp->s_dip = dip;
1868*7c478bd9Sstevel@tonic-gate 	impl_tokenp->s_flag = flag;
1869*7c478bd9Sstevel@tonic-gate 	mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie);
1870*7c478bd9Sstevel@tonic-gate 	cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL);
1871*7c478bd9Sstevel@tonic-gate 
1872*7c478bd9Sstevel@tonic-gate 	return ((usb_serialization_t)impl_tokenp);
1873*7c478bd9Sstevel@tonic-gate }
1874*7c478bd9Sstevel@tonic-gate 
1875*7c478bd9Sstevel@tonic-gate 
1876*7c478bd9Sstevel@tonic-gate void
1877*7c478bd9Sstevel@tonic-gate usb_fini_serialization(
1878*7c478bd9Sstevel@tonic-gate 	usb_serialization_t tokenp)
1879*7c478bd9Sstevel@tonic-gate {
1880*7c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp;
1881*7c478bd9Sstevel@tonic-gate 
1882*7c478bd9Sstevel@tonic-gate 	if (tokenp) {
1883*7c478bd9Sstevel@tonic-gate 		impl_tokenp = (usba_serialization_impl_t *)tokenp;
1884*7c478bd9Sstevel@tonic-gate 		ASSERT(impl_tokenp->s_count == 0);
1885*7c478bd9Sstevel@tonic-gate 		cv_destroy(&impl_tokenp->s_cv);
1886*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&impl_tokenp->s_mutex);
1887*7c478bd9Sstevel@tonic-gate 		kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t));
1888*7c478bd9Sstevel@tonic-gate 	}
1889*7c478bd9Sstevel@tonic-gate }
1890*7c478bd9Sstevel@tonic-gate 
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate /*
1893*7c478bd9Sstevel@tonic-gate  * usb_serialize_access() permits single threaded access.
1894*7c478bd9Sstevel@tonic-gate  *
1895*7c478bd9Sstevel@tonic-gate  * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
1896*7c478bd9Sstevel@tonic-gate  * it is reentrant with respect to thread. The thread must
1897*7c478bd9Sstevel@tonic-gate  * hold and release the same number of times.
1898*7c478bd9Sstevel@tonic-gate  *
1899*7c478bd9Sstevel@tonic-gate  * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
1900*7c478bd9Sstevel@tonic-gate  * it is not reentrant by the same thread. It is something like
1901*7c478bd9Sstevel@tonic-gate  * a semaphore.
1902*7c478bd9Sstevel@tonic-gate  */
1903*7c478bd9Sstevel@tonic-gate int
1904*7c478bd9Sstevel@tonic-gate usb_serialize_access(
1905*7c478bd9Sstevel@tonic-gate 	usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout)
1906*7c478bd9Sstevel@tonic-gate {
1907*7c478bd9Sstevel@tonic-gate 	int			rval = 1;	/* Must be initialized > 0 */
1908*7c478bd9Sstevel@tonic-gate 	clock_t			abs_timeout;
1909*7c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp;
1910*7c478bd9Sstevel@tonic-gate 
1911*7c478bd9Sstevel@tonic-gate 	impl_tokenp = (usba_serialization_impl_t *)tokenp;
1912*7c478bd9Sstevel@tonic-gate 
1913*7c478bd9Sstevel@tonic-gate 	/*
1914*7c478bd9Sstevel@tonic-gate 	 * Convert delta timeout in ms to absolute timeout in ticks, if used.
1915*7c478bd9Sstevel@tonic-gate 	 */
1916*7c478bd9Sstevel@tonic-gate 	if ((how_to_wait == USB_TIMEDWAIT) ||
1917*7c478bd9Sstevel@tonic-gate 	    (how_to_wait == USB_TIMEDWAIT_SIG)) {
1918*7c478bd9Sstevel@tonic-gate 		/* Convert timeout arg (in ms) to hz */
1919*7c478bd9Sstevel@tonic-gate 		abs_timeout = ddi_get_lbolt() +
1920*7c478bd9Sstevel@tonic-gate 		    drv_usectohz(delta_timeout * 1000);
1921*7c478bd9Sstevel@tonic-gate 	}
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate 	/* Get mutex after calc abs time, to count time waiting for mutex. */
1924*7c478bd9Sstevel@tonic-gate 	mutex_enter(&impl_tokenp->s_mutex);
1925*7c478bd9Sstevel@tonic-gate 
1926*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1927*7c478bd9Sstevel@tonic-gate 	    "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
1928*7c478bd9Sstevel@tonic-gate 	    "flg=0x%x, abs_tmo=0x%lx",
1929*7c478bd9Sstevel@tonic-gate 	    impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count,
1930*7c478bd9Sstevel@tonic-gate 	    impl_tokenp->s_thread, how_to_wait, abs_timeout);
1931*7c478bd9Sstevel@tonic-gate 
1932*7c478bd9Sstevel@tonic-gate 	if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 ||
1933*7c478bd9Sstevel@tonic-gate 	    impl_tokenp->s_thread != curthread) {
1934*7c478bd9Sstevel@tonic-gate 
1935*7c478bd9Sstevel@tonic-gate 		/*
1936*7c478bd9Sstevel@tonic-gate 		 * There are three ways to break out of the loop:
1937*7c478bd9Sstevel@tonic-gate 		 * 1) Condition met (s_count == 0) - higher prio test
1938*7c478bd9Sstevel@tonic-gate 		 * 2) kill(2) signal received (rval == 0)
1939*7c478bd9Sstevel@tonic-gate 		 * 3) timeout occurred (rval == -1)
1940*7c478bd9Sstevel@tonic-gate 		 * If condition met, whether or not signal or timeout occurred
1941*7c478bd9Sstevel@tonic-gate 		 * take access.  If condition not met, check other exit means.
1942*7c478bd9Sstevel@tonic-gate 		 */
1943*7c478bd9Sstevel@tonic-gate 		while (impl_tokenp->s_count != 0) {
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate 			/* cv_timedwait* returns -1 on timeout. */
1946*7c478bd9Sstevel@tonic-gate 			/* cv_wait*_sig returns 0 on (kill(2)) signal. */
1947*7c478bd9Sstevel@tonic-gate 			if (rval <= 0) {
1948*7c478bd9Sstevel@tonic-gate 				mutex_exit(&impl_tokenp->s_mutex);
1949*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
1950*7c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
1951*7c478bd9Sstevel@tonic-gate 				    "usb_serialize_access: "
1952*7c478bd9Sstevel@tonic-gate 				    "tok=0x%p exit due to %s", impl_tokenp,
1953*7c478bd9Sstevel@tonic-gate 				    ((rval == 0) ? "signal" : "timeout"));
1954*7c478bd9Sstevel@tonic-gate 
1955*7c478bd9Sstevel@tonic-gate 				return (rval);
1956*7c478bd9Sstevel@tonic-gate 			}
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 			switch (how_to_wait) {
1959*7c478bd9Sstevel@tonic-gate 			default:
1960*7c478bd9Sstevel@tonic-gate 				how_to_wait = USB_WAIT;
1961*7c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
1962*7c478bd9Sstevel@tonic-gate 			case USB_WAIT:
1963*7c478bd9Sstevel@tonic-gate 				cv_wait(&impl_tokenp->s_cv,
1964*7c478bd9Sstevel@tonic-gate 					&impl_tokenp->s_mutex);
1965*7c478bd9Sstevel@tonic-gate 				break;
1966*7c478bd9Sstevel@tonic-gate 			case USB_WAIT_SIG:
1967*7c478bd9Sstevel@tonic-gate 				rval = cv_wait_sig(&impl_tokenp->s_cv,
1968*7c478bd9Sstevel@tonic-gate 						&impl_tokenp->s_mutex);
1969*7c478bd9Sstevel@tonic-gate 				break;
1970*7c478bd9Sstevel@tonic-gate 			case USB_TIMEDWAIT:
1971*7c478bd9Sstevel@tonic-gate 				rval = cv_timedwait(&impl_tokenp->s_cv,
1972*7c478bd9Sstevel@tonic-gate 					&impl_tokenp->s_mutex, abs_timeout);
1973*7c478bd9Sstevel@tonic-gate 				break;
1974*7c478bd9Sstevel@tonic-gate 			case USB_TIMEDWAIT_SIG:
1975*7c478bd9Sstevel@tonic-gate 				rval = cv_timedwait_sig(&impl_tokenp->s_cv,
1976*7c478bd9Sstevel@tonic-gate 					&impl_tokenp->s_mutex, abs_timeout);
1977*7c478bd9Sstevel@tonic-gate 				break;
1978*7c478bd9Sstevel@tonic-gate 			}
1979*7c478bd9Sstevel@tonic-gate 		}
1980*7c478bd9Sstevel@tonic-gate 
1981*7c478bd9Sstevel@tonic-gate 		impl_tokenp->s_thread = curthread;
1982*7c478bd9Sstevel@tonic-gate 	}
1983*7c478bd9Sstevel@tonic-gate 	impl_tokenp->s_count++;
1984*7c478bd9Sstevel@tonic-gate 
1985*7c478bd9Sstevel@tonic-gate 	ASSERT(!(impl_tokenp->s_count > 1 &&
1986*7c478bd9Sstevel@tonic-gate 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0));
1987*7c478bd9Sstevel@tonic-gate 
1988*7c478bd9Sstevel@tonic-gate 	mutex_exit(&impl_tokenp->s_mutex);
1989*7c478bd9Sstevel@tonic-gate 
1990*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1991*7c478bd9Sstevel@tonic-gate 	    "usb_serialize_access exit: tok=0x%p thr=0x%p", impl_tokenp,
1992*7c478bd9Sstevel@tonic-gate 	    curthread);
1993*7c478bd9Sstevel@tonic-gate 
1994*7c478bd9Sstevel@tonic-gate 	return (1);
1995*7c478bd9Sstevel@tonic-gate }
1996*7c478bd9Sstevel@tonic-gate 
1997*7c478bd9Sstevel@tonic-gate 
1998*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1999*7c478bd9Sstevel@tonic-gate int
2000*7c478bd9Sstevel@tonic-gate usb_try_serialize_access(
2001*7c478bd9Sstevel@tonic-gate 	usb_serialization_t tokenp, uint_t flag)
2002*7c478bd9Sstevel@tonic-gate {
2003*7c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp =
2004*7c478bd9Sstevel@tonic-gate 					(usba_serialization_impl_t *)tokenp;
2005*7c478bd9Sstevel@tonic-gate 	mutex_enter(&impl_tokenp->s_mutex);
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2008*7c478bd9Sstevel@tonic-gate 	    "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2009*7c478bd9Sstevel@tonic-gate 	    impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count, curthread);
2010*7c478bd9Sstevel@tonic-gate 
2011*7c478bd9Sstevel@tonic-gate 	/*
2012*7c478bd9Sstevel@tonic-gate 	 * If lock is not taken (s_count is 0), take it.
2013*7c478bd9Sstevel@tonic-gate 	 * If lock is already taken, the thread is owner and lock
2014*7c478bd9Sstevel@tonic-gate 	 * is reentrant, take it.
2015*7c478bd9Sstevel@tonic-gate 	 * Otherwise, fail the access.
2016*7c478bd9Sstevel@tonic-gate 	 */
2017*7c478bd9Sstevel@tonic-gate 	if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) &&
2018*7c478bd9Sstevel@tonic-gate 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) {
2019*7c478bd9Sstevel@tonic-gate 		impl_tokenp->s_thread = curthread;
2020*7c478bd9Sstevel@tonic-gate 		impl_tokenp->s_count++;
2021*7c478bd9Sstevel@tonic-gate 
2022*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2023*7c478bd9Sstevel@tonic-gate 		    "usb_try_serialize_access success: tok=0x%p", impl_tokenp);
2024*7c478bd9Sstevel@tonic-gate 		mutex_exit(&impl_tokenp->s_mutex);
2025*7c478bd9Sstevel@tonic-gate 
2026*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
2027*7c478bd9Sstevel@tonic-gate 	}
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2030*7c478bd9Sstevel@tonic-gate 	    "usb_try_serialize_access failed: "
2031*7c478bd9Sstevel@tonic-gate 	    "tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2032*7c478bd9Sstevel@tonic-gate 	    impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count,
2033*7c478bd9Sstevel@tonic-gate 	    impl_tokenp->s_thread);
2034*7c478bd9Sstevel@tonic-gate 
2035*7c478bd9Sstevel@tonic-gate 	mutex_exit(&impl_tokenp->s_mutex);
2036*7c478bd9Sstevel@tonic-gate 
2037*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
2038*7c478bd9Sstevel@tonic-gate }
2039*7c478bd9Sstevel@tonic-gate 
2040*7c478bd9Sstevel@tonic-gate 
2041*7c478bd9Sstevel@tonic-gate void
2042*7c478bd9Sstevel@tonic-gate usb_release_access(
2043*7c478bd9Sstevel@tonic-gate 	usb_serialization_t tokenp)
2044*7c478bd9Sstevel@tonic-gate {
2045*7c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp =
2046*7c478bd9Sstevel@tonic-gate 					(usba_serialization_impl_t *)tokenp;
2047*7c478bd9Sstevel@tonic-gate 	mutex_enter(&impl_tokenp->s_mutex);
2048*7c478bd9Sstevel@tonic-gate 
2049*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2050*7c478bd9Sstevel@tonic-gate 	    "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
2051*7c478bd9Sstevel@tonic-gate 	    impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count, curthread);
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate 	ASSERT(impl_tokenp->s_count > 0);
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 	if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) {
2056*7c478bd9Sstevel@tonic-gate 		if (impl_tokenp->s_thread != curthread) {
2057*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usbai_log_handle,
2058*7c478bd9Sstevel@tonic-gate 			    "usb_release_access: release from wrong thread");
2059*7c478bd9Sstevel@tonic-gate 		}
2060*7c478bd9Sstevel@tonic-gate 		ASSERT(impl_tokenp->s_thread == curthread);
2061*7c478bd9Sstevel@tonic-gate 	}
2062*7c478bd9Sstevel@tonic-gate 
2063*7c478bd9Sstevel@tonic-gate 	if (--impl_tokenp->s_count == 0) {
2064*7c478bd9Sstevel@tonic-gate 		impl_tokenp->s_thread = NULL;
2065*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&impl_tokenp->s_cv);
2066*7c478bd9Sstevel@tonic-gate 	}
2067*7c478bd9Sstevel@tonic-gate 	mutex_exit(&impl_tokenp->s_mutex);
2068*7c478bd9Sstevel@tonic-gate }
2069*7c478bd9Sstevel@tonic-gate 
2070*7c478bd9Sstevel@tonic-gate 
2071*7c478bd9Sstevel@tonic-gate /*
2072*7c478bd9Sstevel@tonic-gate  * usb_fail_checkpoint:
2073*7c478bd9Sstevel@tonic-gate  *	fail checkpoint as driver/device could not be quiesced
2074*7c478bd9Sstevel@tonic-gate  */
2075*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2076*7c478bd9Sstevel@tonic-gate void
2077*7c478bd9Sstevel@tonic-gate usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags)
2078*7c478bd9Sstevel@tonic-gate {
2079*7c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2080*7c478bd9Sstevel@tonic-gate 
2081*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2082*7c478bd9Sstevel@tonic-gate 	    "usb_fail_checkpoint: %s%d", ddi_driver_name(dip),
2083*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
2084*7c478bd9Sstevel@tonic-gate 
2085*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
2086*7c478bd9Sstevel@tonic-gate 	usba_device->usb_no_cpr++;
2087*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
2088*7c478bd9Sstevel@tonic-gate }
2089*7c478bd9Sstevel@tonic-gate 
2090*7c478bd9Sstevel@tonic-gate 
2091*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
2092*7c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
2093*7c478bd9Sstevel@tonic-gate /*
2094*7c478bd9Sstevel@tonic-gate  * usba_mk_mctl:
2095*7c478bd9Sstevel@tonic-gate  *	create a USB style M_CTL message, given an iocblk and a buffer
2096*7c478bd9Sstevel@tonic-gate  *	returns mblk_t * on success, NULL on failure
2097*7c478bd9Sstevel@tonic-gate  */
2098*7c478bd9Sstevel@tonic-gate mblk_t *
2099*7c478bd9Sstevel@tonic-gate usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len)
2100*7c478bd9Sstevel@tonic-gate {
2101*7c478bd9Sstevel@tonic-gate 	mblk_t *bp1, *bp2;
2102*7c478bd9Sstevel@tonic-gate 
2103*7c478bd9Sstevel@tonic-gate 	if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) {
2104*7c478bd9Sstevel@tonic-gate 		*((struct iocblk *)bp1->b_datap->db_base) = mctlmsg;
2105*7c478bd9Sstevel@tonic-gate 		bp1->b_datap->db_type = M_CTL;
2106*7c478bd9Sstevel@tonic-gate 		bp1->b_wptr += sizeof (struct iocblk);
2107*7c478bd9Sstevel@tonic-gate 		if (buf != NULL) {
2108*7c478bd9Sstevel@tonic-gate 			if ((bp2 = allocb(len, BPRI_HI)) != NULL) {
2109*7c478bd9Sstevel@tonic-gate 				bp1->b_cont = bp2;
2110*7c478bd9Sstevel@tonic-gate 				bcopy(buf, bp2->b_datap->db_base, len);
2111*7c478bd9Sstevel@tonic-gate 				bp2->b_wptr += len;
2112*7c478bd9Sstevel@tonic-gate 			} else {
2113*7c478bd9Sstevel@tonic-gate 				freemsg(bp1);
2114*7c478bd9Sstevel@tonic-gate 				bp1 = NULL;
2115*7c478bd9Sstevel@tonic-gate 			}
2116*7c478bd9Sstevel@tonic-gate 		}
2117*7c478bd9Sstevel@tonic-gate 	}
2118*7c478bd9Sstevel@tonic-gate 
2119*7c478bd9Sstevel@tonic-gate 	return (bp1);
2120*7c478bd9Sstevel@tonic-gate }
2121*7c478bd9Sstevel@tonic-gate 
2122*7c478bd9Sstevel@tonic-gate 
2123*7c478bd9Sstevel@tonic-gate #ifdef ALLOCB_TEST
2124*7c478bd9Sstevel@tonic-gate #undef	allocb
2125*7c478bd9Sstevel@tonic-gate mblk_t *
2126*7c478bd9Sstevel@tonic-gate usba_test_allocb(size_t size, uint_t pri)
2127*7c478bd9Sstevel@tonic-gate {
2128*7c478bd9Sstevel@tonic-gate 	if (ddi_get_lbolt() & 0x1) {
2129*7c478bd9Sstevel@tonic-gate 
2130*7c478bd9Sstevel@tonic-gate 		return (NULL);
2131*7c478bd9Sstevel@tonic-gate 	} else {
2132*7c478bd9Sstevel@tonic-gate 
2133*7c478bd9Sstevel@tonic-gate 		return (allocb(size, pri));
2134*7c478bd9Sstevel@tonic-gate 	}
2135*7c478bd9Sstevel@tonic-gate }
2136*7c478bd9Sstevel@tonic-gate #endif
2137