17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d73ae94eSgc  * Common Development and Distribution License (the "License").
6d73ae94eSgc  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22269552cdSguoqing zhu - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*0d2006e4SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * Utility functions
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
347c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
357c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
36d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
377c478bd9Sstevel@tonic-gate 
38d73ae94eSgc extern void usba_free_evdata(usba_evdata_t *);
39d73ae94eSgc 
407c478bd9Sstevel@tonic-gate static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int);
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /* local functions */
437c478bd9Sstevel@tonic-gate static	int	usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *,
447c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
457c478bd9Sstevel@tonic-gate static int	usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *,
467c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
477c478bd9Sstevel@tonic-gate static int	usba_sync_clear_feature(dev_info_t *, usba_ph_impl_t *,
487c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Wrapper functions returning parsed standard descriptors without
527c478bd9Sstevel@tonic-gate  * getting the config cloud first but by just providing the dip.
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * The client can easily retrieve the device and config descriptor from
557c478bd9Sstevel@tonic-gate  * the usb registration and no separate functions are provided
567c478bd9Sstevel@tonic-gate  *
577c478bd9Sstevel@tonic-gate  * These functions return failure if the full descriptor can not be
587c478bd9Sstevel@tonic-gate  * retrieved.  These functions will not access the device.
597c478bd9Sstevel@tonic-gate  * The caller must allocate the buffer.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * usb_get_if_descr:
647c478bd9Sstevel@tonic-gate  *	Function to get the cooked interface descriptor
657c478bd9Sstevel@tonic-gate  *	This function will not access the device.
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  * Arguments:
687c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
697c478bd9Sstevel@tonic-gate  *	if_index		- interface index
707c478bd9Sstevel@tonic-gate  *	alt_setting	- alt interface setting
717c478bd9Sstevel@tonic-gate  *	descr			- pointer to user allocated interface descr
727c478bd9Sstevel@tonic-gate  *
737c478bd9Sstevel@tonic-gate  * Return Values:
747c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
757c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
767c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate int
usb_get_if_descr(dev_info_t * dip,uint_t if_index,uint_t alt_setting,usb_if_descr_t * descr)797c478bd9Sstevel@tonic-gate usb_get_if_descr(dev_info_t	*dip,
807c478bd9Sstevel@tonic-gate 		uint_t		if_index,
817c478bd9Sstevel@tonic-gate 		uint_t		alt_setting,
827c478bd9Sstevel@tonic-gate 		usb_if_descr_t	*descr)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;	/* buf for config descriptor */
857c478bd9Sstevel@tonic-gate 	size_t		size, cfg_length;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
887c478bd9Sstevel@tonic-gate 	    "usb_get_if_descr: %s, index=0x%x, alt#=0x%x",
897c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), if_index, alt_setting);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (descr == NULL)) {
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
977c478bd9Sstevel@tonic-gate 	size = usb_parse_if_descr(usb_cfg, cfg_length,
987c478bd9Sstevel@tonic-gate 	    if_index,	/* interface index */
997c478bd9Sstevel@tonic-gate 	    alt_setting,	/* alt interface index */
1007c478bd9Sstevel@tonic-gate 	    descr,
1017c478bd9Sstevel@tonic-gate 	    USB_IF_DESCR_SIZE);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if (size != USB_IF_DESCR_SIZE) {
1047c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1057c478bd9Sstevel@tonic-gate 		    "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
1067c478bd9Sstevel@tonic-gate 		    size, USB_IF_DESCR_SIZE);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * usb_get_ep_descr:
1177c478bd9Sstevel@tonic-gate  *	Function to get the cooked endpoint descriptor
1187c478bd9Sstevel@tonic-gate  *	This function will not access the device.
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * Arguments:
1217c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
1227c478bd9Sstevel@tonic-gate  *	if_index		- interface index
1237c478bd9Sstevel@tonic-gate  *	alt_setting		- alternate interface setting
1247c478bd9Sstevel@tonic-gate  *	endpoint_index		- endpoint index
1257c478bd9Sstevel@tonic-gate  *	descr			- pointer to user allocated interface descr
1267c478bd9Sstevel@tonic-gate  *
1277c478bd9Sstevel@tonic-gate  * Return Values:
1287c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
1297c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
1307c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate int
usb_get_ep_descr(dev_info_t * dip,uint_t if_index,uint_t alt_setting,uint_t endpoint_index,usb_ep_descr_t * descr)1337c478bd9Sstevel@tonic-gate usb_get_ep_descr(dev_info_t	*dip,
1347c478bd9Sstevel@tonic-gate 		uint_t		if_index,
1357c478bd9Sstevel@tonic-gate 		uint_t		alt_setting,
1367c478bd9Sstevel@tonic-gate 		uint_t		endpoint_index,
1377c478bd9Sstevel@tonic-gate 		usb_ep_descr_t	*descr)
1387c478bd9Sstevel@tonic-gate {
1397c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;	/* buf for config descriptor */
1407c478bd9Sstevel@tonic-gate 	size_t		size, cfg_length;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1437c478bd9Sstevel@tonic-gate 	    "usb_get_ep_descr: %s, index=0x%x, alt#=0x%x",
1447c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), if_index, alt_setting);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (descr == NULL)) {
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
1527c478bd9Sstevel@tonic-gate 	size = usb_parse_ep_descr(usb_cfg, cfg_length,
153112116d8Sfb 	    if_index,	/* interface index */
154112116d8Sfb 	    alt_setting,	/* alt interface index */
155112116d8Sfb 	    endpoint_index,		/* ep index */
156112116d8Sfb 	    descr, USB_EP_DESCR_SIZE);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if (size != USB_EP_DESCR_SIZE) {
1597c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1607c478bd9Sstevel@tonic-gate 		    "parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)",
1617c478bd9Sstevel@tonic-gate 		    size, USB_EP_DESCR_SIZE);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * usb_lookup_ep_data:
1727c478bd9Sstevel@tonic-gate  * usb_get_ep_data (deprecated):
1737c478bd9Sstevel@tonic-gate  *	Function to get specific endpoint descriptor data
1747c478bd9Sstevel@tonic-gate  *	This function will not access the device.
1757c478bd9Sstevel@tonic-gate  *
1767c478bd9Sstevel@tonic-gate  * Arguments:
1777c478bd9Sstevel@tonic-gate  *	dip		- pointer to dev info
1787c478bd9Sstevel@tonic-gate  *	usb_client_dev_data_t - pointer to registration data
1797c478bd9Sstevel@tonic-gate  *	interface	- requested interface
1807c478bd9Sstevel@tonic-gate  *	alternate	- requested alternate
1817c478bd9Sstevel@tonic-gate  *	skip		- how many to skip
1827c478bd9Sstevel@tonic-gate  *	type		- endpoint type
1837c478bd9Sstevel@tonic-gate  *	direction	- endpoint direction or USB_DIR_DONT_CARE
1847c478bd9Sstevel@tonic-gate  *
1857c478bd9Sstevel@tonic-gate  * Return Values:
1867c478bd9Sstevel@tonic-gate  *	NULL or an endpoint descriptor pointer
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate usb_ep_data_t *
usb_lookup_ep_data(dev_info_t * dip,usb_client_dev_data_t * dev_datap,uint_t interface,uint_t alternate,uint_t skip,uint_t type,uint_t dir)1897c478bd9Sstevel@tonic-gate usb_lookup_ep_data(dev_info_t	*dip,
1907c478bd9Sstevel@tonic-gate 		usb_client_dev_data_t *dev_datap,
1917c478bd9Sstevel@tonic-gate 		uint_t		interface,
1927c478bd9Sstevel@tonic-gate 		uint_t		alternate,
1937c478bd9Sstevel@tonic-gate 		uint_t		skip,
1947c478bd9Sstevel@tonic-gate 		uint_t		type,
1957c478bd9Sstevel@tonic-gate 		uint_t		dir)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
1987c478bd9Sstevel@tonic-gate 	int			i;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2017c478bd9Sstevel@tonic-gate 	    "usb_lookup_ep_data: "
2027c478bd9Sstevel@tonic-gate 	    "if=%d alt=%d skip=%d type=%d dir=%d",
2037c478bd9Sstevel@tonic-gate 	    interface, alternate, skip, type, dir);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (dev_datap == NULL)) {
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 		return (NULL);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	altif_data = &dev_datap->dev_curr_cfg->
211112116d8Sfb 	    cfg_if[interface].if_alt[alternate];
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
214112116d8Sfb 	    "altif=0x%p n_ep=%d", (void *)altif_data, altif_data->altif_n_ep);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	for (i = 0; i < altif_data->altif_n_ep; i++) {
2177c478bd9Sstevel@tonic-gate 		usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
2187c478bd9Sstevel@tonic-gate 		uint8_t	ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
2197c478bd9Sstevel@tonic-gate 		uint8_t ept_dir = ept->bEndpointAddress & USB_EP_DIR_MASK;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 		if (ept->bLength == 0) {
2227c478bd9Sstevel@tonic-gate 			continue;
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 		if ((ept_type == type) &&
2257c478bd9Sstevel@tonic-gate 		    ((type == USB_EP_ATTR_CONTROL) || (dir == ept_dir))) {
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 			if (skip-- == 0) {
2287c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
2297c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
2307c478bd9Sstevel@tonic-gate 				    "usb_get_ep_data: data=0x%p",
231112116d8Sfb 				    (void *)&altif_data->altif_ep[i]);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 				return (&altif_data->altif_ep[i]);
2347c478bd9Sstevel@tonic-gate 			}
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2387c478bd9Sstevel@tonic-gate 	    "usb_get_ep_data: returning NULL");
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	return (NULL);
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2457c478bd9Sstevel@tonic-gate usb_ep_data_t *
usb_get_ep_data(dev_info_t * dip,usb_client_dev_data_t * dev_datap,uint_t interface,uint_t alternate,uint_t type,uint_t dir)2467c478bd9Sstevel@tonic-gate usb_get_ep_data(dev_info_t	*dip,
2477c478bd9Sstevel@tonic-gate 		usb_client_dev_data_t *dev_datap,
2487c478bd9Sstevel@tonic-gate 		uint_t		interface,
2497c478bd9Sstevel@tonic-gate 		uint_t		alternate,
2507c478bd9Sstevel@tonic-gate 		uint_t		type,
2517c478bd9Sstevel@tonic-gate 		uint_t		dir)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	return (usb_lookup_ep_data(dip, dev_datap, interface,
2547c478bd9Sstevel@tonic-gate 	    alternate, 0, type, dir));
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * usb_get_string_descr:
2607c478bd9Sstevel@tonic-gate  *	Function to read the string descriptor
2617c478bd9Sstevel@tonic-gate  *	This function will access the device and block.
2627c478bd9Sstevel@tonic-gate  *
2637c478bd9Sstevel@tonic-gate  * Arguments:
2647c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
2657c478bd9Sstevel@tonic-gate  *	langid		- LANGID to read different LOCALEs
2667c478bd9Sstevel@tonic-gate  *	index		- index to the string
2677c478bd9Sstevel@tonic-gate  *	buf		- user provided buffer for string descriptor
2687c478bd9Sstevel@tonic-gate  *	buflen		- user provided length of the buffer
2697c478bd9Sstevel@tonic-gate  *
2707c478bd9Sstevel@tonic-gate  * Return Values:
2717c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
2727c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
2737c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
2747c478bd9Sstevel@tonic-gate  */
2757c478bd9Sstevel@tonic-gate int
usb_get_string_descr(dev_info_t * dip,uint16_t langid,uint8_t index,char * buf,size_t buflen)2767c478bd9Sstevel@tonic-gate usb_get_string_descr(dev_info_t *dip,
2777c478bd9Sstevel@tonic-gate 		uint16_t	langid,
2787c478bd9Sstevel@tonic-gate 		uint8_t 	index,
2797c478bd9Sstevel@tonic-gate 		char		*buf,
2807c478bd9Sstevel@tonic-gate 		size_t		buflen)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
2837c478bd9Sstevel@tonic-gate 	uint16_t	length;
2847c478bd9Sstevel@tonic-gate 	int		rval;
2857c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
2867c478bd9Sstevel@tonic-gate 	size_t		len;
2877c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2907c478bd9Sstevel@tonic-gate 	    "usb_get_string_descr: %s, langid=0x%x index=0x%x",
2917c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), langid, index);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (buf == NULL) || (buflen == 0) || (index == 0)) {
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/*
2997c478bd9Sstevel@tonic-gate 	 * determine the length of the descriptor
3007c478bd9Sstevel@tonic-gate 	 */
3017c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip,
302112116d8Sfb 	    usba_get_dflt_pipe_handle(dip),
303112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST,
304112116d8Sfb 	    USB_REQ_GET_DESCR,
305*0d2006e4SRobert Mustacchi 	    (USB_DESCR_TYPE_STRING << 8) | (index & 0xff),
306112116d8Sfb 	    langid,
307112116d8Sfb 	    4,
308112116d8Sfb 	    &data, USB_ATTRS_SHORT_XFER_OK,
309112116d8Sfb 	    &completion_reason,
310112116d8Sfb 	    &cb_flags, USB_FLAGS_SLEEP);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
3137c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3147c478bd9Sstevel@tonic-gate 		    "rval=%d cr=%d", rval, completion_reason);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 		goto done;
3177c478bd9Sstevel@tonic-gate 	}
318d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	if (MBLKL(data) == 0) {
3197c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3207c478bd9Sstevel@tonic-gate 		    "0 bytes received");
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 		goto done;
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	ASSERT(data);
3267c478bd9Sstevel@tonic-gate 	length = *(data->b_rptr);
3277c478bd9Sstevel@tonic-gate 	freemsg(data);
3287c478bd9Sstevel@tonic-gate 	data = NULL;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
3317c478bd9Sstevel@tonic-gate 	    "rval=%d, cr=%d, length=%d", rval, completion_reason, length);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/*
3347c478bd9Sstevel@tonic-gate 	 * if length is zero the next control request may fail.
3357c478bd9Sstevel@tonic-gate 	 * the HCD may not support a zero length control request
3367c478bd9Sstevel@tonic-gate 	 * and return an mblk_t which is NULL along with rval
3377c478bd9Sstevel@tonic-gate 	 * being USB_SUCCESS and "cr" being USB_CR_OK
3387c478bd9Sstevel@tonic-gate 	 */
3397c478bd9Sstevel@tonic-gate 	if (length < 2) {
3407c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 		goto done;
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip,
346112116d8Sfb 	    usba_get_dflt_pipe_handle(dip),
347112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST,
348112116d8Sfb 	    USB_REQ_GET_DESCR,
349*0d2006e4SRobert Mustacchi 	    (USB_DESCR_TYPE_STRING << 8) | (index & 0xff),
350112116d8Sfb 	    langid,
351112116d8Sfb 	    length,
352112116d8Sfb 	    &data, USB_ATTRS_SHORT_XFER_OK,
353112116d8Sfb 	    &completion_reason,
354112116d8Sfb 	    &cb_flags, USB_FLAGS_SLEEP);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
3577c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	if ((data == NULL) || (rval != USB_SUCCESS)) {
3607c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3617c478bd9Sstevel@tonic-gate 		    "failed to get string descriptor (rval=%d cr=%d)",
3627c478bd9Sstevel@tonic-gate 		    rval, completion_reason);
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 		goto done;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
367d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	if ((length = MBLKL(data)) != 0) {
3687c478bd9Sstevel@tonic-gate 		len = usba_ascii_string_descr(data->b_rptr, length, buf,
369112116d8Sfb 		    buflen);
3707c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA,
3717c478bd9Sstevel@tonic-gate 		    usbai_log_handle, "buf=%s buflen=%lu", buf, len);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		ASSERT(len <= buflen);
3747c478bd9Sstevel@tonic-gate 	} else {
3757c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate done:
3787c478bd9Sstevel@tonic-gate 	freemsg(data);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	return (rval);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  * usb_get_dev_descr:
3867c478bd9Sstevel@tonic-gate  *	 utility function to get device descriptor from usba_device
3877c478bd9Sstevel@tonic-gate  *
3887c478bd9Sstevel@tonic-gate  * Arguments:
3897c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
3907c478bd9Sstevel@tonic-gate  *
3917c478bd9Sstevel@tonic-gate  * Return Values:
3927c478bd9Sstevel@tonic-gate  *	usb_dev_descr	- device  descriptor or NULL
3937c478bd9Sstevel@tonic-gate  */
3947c478bd9Sstevel@tonic-gate usb_dev_descr_t *
usb_get_dev_descr(dev_info_t * dip)3957c478bd9Sstevel@tonic-gate usb_get_dev_descr(dev_info_t *dip)
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
3987c478bd9Sstevel@tonic-gate 	usb_dev_descr_t *usb_dev_descr = NULL;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	if (dip) {
4017c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4027c478bd9Sstevel@tonic-gate 		    "usb_get_dev_descr: %s", ddi_node_name(dip));
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(dip);
4057c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
4067c478bd9Sstevel@tonic-gate 		usb_dev_descr = usba_device->usb_dev_descr;
4077c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	return (usb_dev_descr);
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate  * usb_get_raw_cfg_data:
4167c478bd9Sstevel@tonic-gate  *	 utility function to get raw config descriptor from usba_device
4177c478bd9Sstevel@tonic-gate  *
4187c478bd9Sstevel@tonic-gate  * Arguments:
4197c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
4207c478bd9Sstevel@tonic-gate  *	length		- pointer to copy the cfg length
4217c478bd9Sstevel@tonic-gate  *
4227c478bd9Sstevel@tonic-gate  * Return Values:
4237c478bd9Sstevel@tonic-gate  *	usb_cfg	- raw config descriptor
4247c478bd9Sstevel@tonic-gate  */
4257c478bd9Sstevel@tonic-gate uchar_t *
usb_get_raw_cfg_data(dev_info_t * dip,size_t * length)4267c478bd9Sstevel@tonic-gate usb_get_raw_cfg_data(dev_info_t *dip, size_t *length)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
4297c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4327c478bd9Sstevel@tonic-gate 	    "usb_get_raw_cfg_data: %s", ddi_node_name(dip));
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (length == NULL)) {
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 		return (NULL);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
4427c478bd9Sstevel@tonic-gate 	usb_cfg = usba_device->usb_cfg;
4437c478bd9Sstevel@tonic-gate 	*length = usba_device->usb_cfg_length;
4447c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	return (usb_cfg);
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate  * usb_get_addr:
4527c478bd9Sstevel@tonic-gate  *	utility function to return current usb address, mostly
4537c478bd9Sstevel@tonic-gate  *	for debugging purposes
4547c478bd9Sstevel@tonic-gate  *
4557c478bd9Sstevel@tonic-gate  * Arguments:
4567c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
4577c478bd9Sstevel@tonic-gate  *
4587c478bd9Sstevel@tonic-gate  * Return Values:
4597c478bd9Sstevel@tonic-gate  *	address	- USB Device Address
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate int
usb_get_addr(dev_info_t * dip)4627c478bd9Sstevel@tonic-gate usb_get_addr(dev_info_t *dip)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate 	int address = 0;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4677c478bd9Sstevel@tonic-gate 	    "usb_get_addr: %s", ddi_node_name(dip));
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (dip) {
4707c478bd9Sstevel@tonic-gate 		usba_device_t	*usba_device = usba_get_usba_device(dip);
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
4737c478bd9Sstevel@tonic-gate 		address = usba_device->usb_addr;
4747c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	return (address);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate  * usb_set_cfg():
4837c478bd9Sstevel@tonic-gate  *	set configuration, use with caution (issues USB_REQ_SET_CONFIG)
4847c478bd9Sstevel@tonic-gate  *	Changing configuration will fail if pipes are still open or when
4857c478bd9Sstevel@tonic-gate  *	invoked from a driver bound to an interface on a composite device.
4867c478bd9Sstevel@tonic-gate  *
4877c478bd9Sstevel@tonic-gate  *	This function will access the device and block
4887c478bd9Sstevel@tonic-gate  *
4897c478bd9Sstevel@tonic-gate  * Arguments:
4907c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
4917c478bd9Sstevel@tonic-gate  *	cfg_index	- config index
4927c478bd9Sstevel@tonic-gate  *	cfg_value	- config value to be set
4937c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
4947c478bd9Sstevel@tonic-gate  *				wait for completion
4957c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
4967c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
4977c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
4987c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
4997c478bd9Sstevel@tonic-gate  *			  be provided.
5007c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
5017c478bd9Sstevel@tonic-gate  *
5027c478bd9Sstevel@tonic-gate  * Return Values:
5037c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:	- new configuration was set
5047c478bd9Sstevel@tonic-gate  *	USB_FAILURE:	- new configuration could not be set
5057c478bd9Sstevel@tonic-gate  *	USB_BUSY:	- some pipes were open or there were children
5067c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
5077c478bd9Sstevel@tonic-gate  */
5087c478bd9Sstevel@tonic-gate int
usb_set_cfg(dev_info_t * dip,uint_t cfg_index,usb_flags_t usb_flags,void (* cb)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t cb_arg)5097c478bd9Sstevel@tonic-gate usb_set_cfg(dev_info_t		*dip,
5107c478bd9Sstevel@tonic-gate 		uint_t		cfg_index,
5117c478bd9Sstevel@tonic-gate 		usb_flags_t	usb_flags,
5127c478bd9Sstevel@tonic-gate 		void		(*cb)(
5137c478bd9Sstevel@tonic-gate 					usb_pipe_handle_t ph,
5147c478bd9Sstevel@tonic-gate 					usb_opaque_t	arg,
5157c478bd9Sstevel@tonic-gate 					int		rval,
5167c478bd9Sstevel@tonic-gate 					usb_cb_flags_t	flags),
5177c478bd9Sstevel@tonic-gate 		usb_opaque_t	cb_arg)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	ph;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
5227c478bd9Sstevel@tonic-gate 	    "usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x",
5237c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), cfg_index,
5247c478bd9Sstevel@tonic-gate 	    usb_flags);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (!usb_owns_device(dip)) {
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PERM);
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
5427c478bd9Sstevel@tonic-gate 	if (usba_hold_ph_data(ph) == NULL) {
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	return (usba_pipe_setup_func_call(dip,
5487c478bd9Sstevel@tonic-gate 	    usba_sync_set_cfg, (usba_ph_impl_t *)ph,
5497c478bd9Sstevel@tonic-gate 	    (usb_opaque_t)((uintptr_t)cfg_index), usb_flags, cb, cb_arg));
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate static int
usba_sync_set_cfg(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t flags)5547c478bd9Sstevel@tonic-gate usba_sync_set_cfg(dev_info_t	*dip,
5557c478bd9Sstevel@tonic-gate 		usba_ph_impl_t	*ph_impl,
5567c478bd9Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
5577c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	int		rval;
5607c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
5617c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
5627c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
5637c478bd9Sstevel@tonic-gate 	int		i, ph_open_cnt;
5647c478bd9Sstevel@tonic-gate 	uint_t		cfg_index = (uint_t)((uintptr_t)(request->arg));
5657c478bd9Sstevel@tonic-gate 	size_t		size;
5667c478bd9Sstevel@tonic-gate 	usb_cfg_descr_t confdescr;
56735f36846Ssl 	dev_info_t	*pdip;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	/*
5727c478bd9Sstevel@tonic-gate 	 * default pipe is still open
5737c478bd9Sstevel@tonic-gate 	 * all other pipes should be closed
5747c478bd9Sstevel@tonic-gate 	 */
5757c478bd9Sstevel@tonic-gate 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
5767c478bd9Sstevel@tonic-gate 		if (usba_device->usb_ph_list[i].usba_ph_data) {
5777c478bd9Sstevel@tonic-gate 			ph_open_cnt++;
5787c478bd9Sstevel@tonic-gate 			break;
5797c478bd9Sstevel@tonic-gate 		}
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if (ph_open_cnt || ddi_get_child(dip)) {
5837c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 		return (USB_BUSY);
5867c478bd9Sstevel@tonic-gate 	}
5877c478bd9Sstevel@tonic-gate 
58835f36846Ssl 	/*
58935f36846Ssl 	 * check if the configuration meets the
59035f36846Ssl 	 * power budget requirement
59135f36846Ssl 	 */
59235f36846Ssl 	if (usba_is_root_hub(dip)) {
59335f36846Ssl 		/*
59435f36846Ssl 		 * root hub should never be multi-configured.
59535f36846Ssl 		 * the code is here just to ensure
59635f36846Ssl 		 */
59735f36846Ssl 		usba_release_ph_data(ph_impl);
59835f36846Ssl 
59935f36846Ssl 		return (USB_FAILURE);
60035f36846Ssl 	}
60135f36846Ssl 	pdip = ddi_get_parent(dip);
60235f36846Ssl 
60335f36846Ssl 	/*
60435f36846Ssl 	 * increase the power budget value back to the unconfigured
60535f36846Ssl 	 * state to eliminate the influence of the old configuration
60635f36846Ssl 	 * before checking the new configuration; but remember to
60735f36846Ssl 	 * make a decrement before leaving this routine to restore
60835f36846Ssl 	 * the power consumption state of the device no matter it
60935f36846Ssl 	 * is in the new or old configuration
61035f36846Ssl 	 */
61135f36846Ssl 	usba_hubdi_incr_power_budget(pdip, usba_device);
61235f36846Ssl 
61335f36846Ssl 	if ((usba_hubdi_check_power_budget(pdip, usba_device,
61435f36846Ssl 	    cfg_index)) != USB_SUCCESS) {
61535f36846Ssl 		usba_hubdi_decr_power_budget(pdip, usba_device);
61635f36846Ssl 
61735f36846Ssl 		usba_release_ph_data(ph_impl);
61835f36846Ssl 
61935f36846Ssl 		return (USB_FAILURE);
62035f36846Ssl 	}
62135f36846Ssl 
6227c478bd9Sstevel@tonic-gate 	size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index],
623112116d8Sfb 	    USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	/* hubdi should ensure that this descriptor is correct */
6267c478bd9Sstevel@tonic-gate 	ASSERT(size == USB_CFG_DESCR_SIZE);
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	/* set the configuration */
6297c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl,
630112116d8Sfb 	    USB_DEV_REQ_HOST_TO_DEV,
631112116d8Sfb 	    USB_REQ_SET_CFG,
632112116d8Sfb 	    confdescr.bConfigurationValue,
633112116d8Sfb 	    0,
634112116d8Sfb 	    0,
635112116d8Sfb 	    NULL, 0,
636112116d8Sfb 	    &completion_reason,
637112116d8Sfb 	    &cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP);
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	if (rval == USB_SUCCESS) {
6407c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
6417c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg_value = confdescr.bConfigurationValue;
6427c478bd9Sstevel@tonic-gate 		usba_device->usb_active_cfg_ndx = cfg_index;
6437c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index];
6447c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg_length = confdescr.wTotalLength;
6457c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		/* update the configuration property */
6487c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
649112116d8Sfb 		    "configuration#", usba_device->usb_cfg_value);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 
65235f36846Ssl 	/*
65335f36846Ssl 	 * usba_device->usb_cfg always stores current configuration
65435f36846Ssl 	 * descriptor no matter SET_CFG request succeeded or not,
65535f36846Ssl 	 * so usba_hubdi_decr_power_budget can be done regardless
65635f36846Ssl 	 * of rval above
65735f36846Ssl 	 */
65835f36846Ssl 	usba_hubdi_decr_power_budget(pdip, usba_device);
65935f36846Ssl 
6607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
6617c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	return (rval);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate  * usb_get_cfg():
6727c478bd9Sstevel@tonic-gate  *	get configuration value
6737c478bd9Sstevel@tonic-gate  *
6747c478bd9Sstevel@tonic-gate  * Arguments:
6757c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
6767c478bd9Sstevel@tonic-gate  *	cfg_value	- current config value
6777c478bd9Sstevel@tonic-gate  *	flags		- none, always blocks
6787c478bd9Sstevel@tonic-gate  *
6797c478bd9Sstevel@tonic-gate  * Return Values:
6807c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:	- config value was retrieved
6817c478bd9Sstevel@tonic-gate  *	USB_FAILURE:	- config value could not be retrieved
6827c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
6837c478bd9Sstevel@tonic-gate  */
6847c478bd9Sstevel@tonic-gate int
usb_get_cfg(dev_info_t * dip,uint_t * cfgval,usb_flags_t flags)6857c478bd9Sstevel@tonic-gate usb_get_cfg(dev_info_t		*dip,
6867c478bd9Sstevel@tonic-gate 		uint_t		*cfgval,
6877c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
6887c478bd9Sstevel@tonic-gate {
6897c478bd9Sstevel@tonic-gate 	int		rval;
6907c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
6917c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
6927c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
6937c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
6967c478bd9Sstevel@tonic-gate 	    "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	if ((cfgval == NULL) || (dip == NULL)) {
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	/*
7067c478bd9Sstevel@tonic-gate 	 * get the cfg value
7077c478bd9Sstevel@tonic-gate 	 */
7087c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
709112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV,
710112116d8Sfb 	    USB_REQ_GET_CFG,
711112116d8Sfb 	    0,
712112116d8Sfb 	    0,
713112116d8Sfb 	    1,		/* returns one byte of data */
714112116d8Sfb 	    &data, 0,
715112116d8Sfb 	    &completion_reason,
716112116d8Sfb 	    &cb_flags, flags);
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
7197c478bd9Sstevel@tonic-gate 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && data &&
722d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (MBLKL(data) == 1)) {
7237c478bd9Sstevel@tonic-gate 		*cfgval = *(data->b_rptr);
7247c478bd9Sstevel@tonic-gate 	} else {
7257c478bd9Sstevel@tonic-gate 		*cfgval = 1;
7267c478bd9Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
7277c478bd9Sstevel@tonic-gate 			rval = USB_FAILURE;
7287c478bd9Sstevel@tonic-gate 		}
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
7327c478bd9Sstevel@tonic-gate 	    "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	freemsg(data);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	return (rval);
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate  * usb_get_current_cfgidx:
7427c478bd9Sstevel@tonic-gate  *	get current current config index
7437c478bd9Sstevel@tonic-gate  */
7447c478bd9Sstevel@tonic-gate uint_t
usb_get_current_cfgidx(dev_info_t * dip)7457c478bd9Sstevel@tonic-gate usb_get_current_cfgidx(dev_info_t *dip)
7467c478bd9Sstevel@tonic-gate {
7477c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
7487c478bd9Sstevel@tonic-gate 	uint_t		ndx;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
7517c478bd9Sstevel@tonic-gate 	ndx = usba_device->usb_active_cfg_ndx;
7527c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	return (ndx);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate /*
7597c478bd9Sstevel@tonic-gate  * usb_get_if_number:
7607c478bd9Sstevel@tonic-gate  *	get usb interface number of current OS device node.
7617c478bd9Sstevel@tonic-gate  *
7627c478bd9Sstevel@tonic-gate  * Arguments:
7637c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
7647c478bd9Sstevel@tonic-gate  *
7657c478bd9Sstevel@tonic-gate  * Return Values:
7667c478bd9Sstevel@tonic-gate  *	USB_COMBINED_NODE if the driver is responsible for the entire
7677c478bd9Sstevel@tonic-gate  *	    device and this dip doesn't correspond to a device node.
7687c478bd9Sstevel@tonic-gate  *	USB_DEVICE_NODE if the driver is responsible for the entire device
7697c478bd9Sstevel@tonic-gate  *	    and this dip corresponds to a device node.
7707c478bd9Sstevel@tonic-gate  *	interface number: otherwise.
7717c478bd9Sstevel@tonic-gate  */
7727c478bd9Sstevel@tonic-gate int
usb_get_if_number(dev_info_t * dip)7737c478bd9Sstevel@tonic-gate usb_get_if_number(dev_info_t *dip)
7747c478bd9Sstevel@tonic-gate {
7757c478bd9Sstevel@tonic-gate 	int interface_num;
7767c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
7777c478bd9Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
780112116d8Sfb 	    "usb_get_if_number: dip = 0x%p", (void *)dip);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	/* not quite right but we can't return a negative return value */
7837c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 		return (0);
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	if (usba_device) {
7897c478bd9Sstevel@tonic-gate 		usb_dev_descr = usba_device->usb_dev_descr;
7907c478bd9Sstevel@tonic-gate 	} else {
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 		return (0);
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
7967c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	if (interface_num == USB_COMBINED_NODE) {
7997c478bd9Sstevel@tonic-gate 		if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
8007c478bd9Sstevel@tonic-gate 		    (usb_dev_descr->bDeviceClass == 0)) &&
8017c478bd9Sstevel@tonic-gate 		    (usba_device->usb_n_cfgs == 1) &&
8027c478bd9Sstevel@tonic-gate 		    (usba_device->usb_n_ifs == 1))) {
8037c478bd9Sstevel@tonic-gate 			interface_num = USB_DEVICE_NODE;
8047c478bd9Sstevel@tonic-gate 		}
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	return (interface_num);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate boolean_t
usb_owns_device(dev_info_t * dip)8127c478bd9Sstevel@tonic-gate usb_owns_device(dev_info_t *dip)
8137c478bd9Sstevel@tonic-gate {
8147c478bd9Sstevel@tonic-gate 	int interface_num = usb_get_if_number(dip);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	return (interface_num < 0 ? B_TRUE : B_FALSE);
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 
820d73ae94eSgc /* check whether the interface is in this interface association */
821d73ae94eSgc boolean_t
usba_check_if_in_ia(dev_info_t * dip,int n_if)822d73ae94eSgc usba_check_if_in_ia(dev_info_t *dip, int n_if)
823d73ae94eSgc {
824d73ae94eSgc 	int first_if, if_count;
825d73ae94eSgc 
826d73ae94eSgc 	first_if = usb_get_if_number(dip);
827d73ae94eSgc 	if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
828112116d8Sfb 	    DDI_PROP_DONTPASS, "interface-count", -1);
829d73ae94eSgc 	if_count += first_if;
830d73ae94eSgc 
831d73ae94eSgc 	return ((n_if >= first_if && n_if < if_count) ? B_TRUE : B_FALSE);
832d73ae94eSgc }
833d73ae94eSgc 
834d73ae94eSgc 
8357c478bd9Sstevel@tonic-gate uint8_t
usba_get_ifno(dev_info_t * dip)8367c478bd9Sstevel@tonic-gate usba_get_ifno(dev_info_t *dip)
8377c478bd9Sstevel@tonic-gate {
8387c478bd9Sstevel@tonic-gate 	int interface_num = usb_get_if_number(dip);
8397c478bd9Sstevel@tonic-gate 
840d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	return (uint8_t)(interface_num < 0 ? 0 : interface_num);
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate /*
8457c478bd9Sstevel@tonic-gate  * usb_set_alt_if:
8467c478bd9Sstevel@tonic-gate  *	set the alternate interface number. Issues USB_REQ_SET_IF
8477c478bd9Sstevel@tonic-gate  *	This function will access the device
8487c478bd9Sstevel@tonic-gate  *
8497c478bd9Sstevel@tonic-gate  * Arguments:
8507c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
8517c478bd9Sstevel@tonic-gate  *	if_number	- interface number
8527c478bd9Sstevel@tonic-gate  *	alt_number	- alternate interface number
8537c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
8547c478bd9Sstevel@tonic-gate  *				wait for completion
8557c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
8567c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
8577c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
8587c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
8597c478bd9Sstevel@tonic-gate  *			  be provided.
8607c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
8617c478bd9Sstevel@tonic-gate  *
8627c478bd9Sstevel@tonic-gate  *
8637c478bd9Sstevel@tonic-gate  * return values:
8647c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- alternate was set
8657c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- alternate could not be set because pipes
8667c478bd9Sstevel@tonic-gate  *			  were still open or some access error occurred
8677c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
8687c478bd9Sstevel@tonic-gate  *
8697c478bd9Sstevel@tonic-gate  * Note:
8707c478bd9Sstevel@tonic-gate  *	we can't easily check if all pipes to endpoints for this interface
8717c478bd9Sstevel@tonic-gate  *	are closed since we don't have a map of which endpoints belong
8727c478bd9Sstevel@tonic-gate  *	to which interface. If we had this map, we would need to update
8737c478bd9Sstevel@tonic-gate  *	this on each alternative or configuration switch
8747c478bd9Sstevel@tonic-gate  */
8757c478bd9Sstevel@tonic-gate int
usb_set_alt_if(dev_info_t * dip,uint_t interface,uint_t alt_number,usb_flags_t usb_flags,void (* cb)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t cb_arg)8767c478bd9Sstevel@tonic-gate usb_set_alt_if(dev_info_t	*dip,
8777c478bd9Sstevel@tonic-gate 		uint_t		interface,
8787c478bd9Sstevel@tonic-gate 		uint_t		alt_number,
8797c478bd9Sstevel@tonic-gate 		usb_flags_t	usb_flags,
8807c478bd9Sstevel@tonic-gate 		void		(*cb)(
8817c478bd9Sstevel@tonic-gate 					usb_pipe_handle_t ph,
8827c478bd9Sstevel@tonic-gate 					usb_opaque_t	arg,
8837c478bd9Sstevel@tonic-gate 					int		rval,
8847c478bd9Sstevel@tonic-gate 					usb_cb_flags_t	flags),
8857c478bd9Sstevel@tonic-gate 		usb_opaque_t	cb_arg)
8867c478bd9Sstevel@tonic-gate {
8877c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	ph;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
8907c478bd9Sstevel@tonic-gate 	    "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
8917c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip),
8927c478bd9Sstevel@tonic-gate 	    interface, alt_number, usb_flags);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
9057c478bd9Sstevel@tonic-gate 	if (usba_hold_ph_data(ph) == NULL) {
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	return (usba_pipe_setup_func_call(dip,
9117c478bd9Sstevel@tonic-gate 	    usba_sync_set_alt_if, (usba_ph_impl_t *)ph,
9127c478bd9Sstevel@tonic-gate 	    (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)),
9137c478bd9Sstevel@tonic-gate 	    usb_flags, cb, cb_arg));
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate static int
usba_sync_set_alt_if(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t flags)9187c478bd9Sstevel@tonic-gate usba_sync_set_alt_if(dev_info_t	*dip,
9197c478bd9Sstevel@tonic-gate 		usba_ph_impl_t	*ph_impl,
9207c478bd9Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
9217c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	int		rval;
9247c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
9257c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
9267c478bd9Sstevel@tonic-gate 	usb_opaque_t	arg = request->arg;
9277c478bd9Sstevel@tonic-gate 	int		interface = ((uintptr_t)arg >> 8) & 0xff;
9287c478bd9Sstevel@tonic-gate 	int		alt_number = (uintptr_t)arg & 0xff;
9297c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
930112116d8Sfb 	    (usb_pipe_handle_t)ph_impl);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9337c478bd9Sstevel@tonic-gate 	    "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
9347c478bd9Sstevel@tonic-gate 	    "uf=0x%x", ddi_node_name(dip), interface,
9357c478bd9Sstevel@tonic-gate 	    alt_number, flags);
9367c478bd9Sstevel@tonic-gate 
937d73ae94eSgc 	/* if we don't own the device, we must own the interface or ia */
938d73ae94eSgc 	if (!usb_owns_device(dip) && !usba_check_if_in_ia(dip, interface) &&
9397c478bd9Sstevel@tonic-gate 	    (interface != usb_get_if_number(dip))) {
9407c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PERM);
9437c478bd9Sstevel@tonic-gate 	}
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	/* set the alternate setting */
9467c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip),
947112116d8Sfb 	    USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
948112116d8Sfb 	    USB_REQ_SET_IF,
949112116d8Sfb 	    alt_number,
950112116d8Sfb 	    interface,
951112116d8Sfb 	    0,
952112116d8Sfb 	    NULL, 0,
953112116d8Sfb 	    &completion_reason,
954112116d8Sfb 	    &cb_flags, flags | USB_FLAGS_SLEEP);
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9577c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	return (rval);
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate /*
9667c478bd9Sstevel@tonic-gate  * usb_get_alt_if:
9677c478bd9Sstevel@tonic-gate  *	get the alternate interface number. Issues USB_REQ_GET_IF
9687c478bd9Sstevel@tonic-gate  *	This function will access the device and block
9697c478bd9Sstevel@tonic-gate  *
9707c478bd9Sstevel@tonic-gate  * Arguments:
9717c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
9727c478bd9Sstevel@tonic-gate  *	if_number	- interface number
9737c478bd9Sstevel@tonic-gate  *	alt_number	- alternate interface number
9747c478bd9Sstevel@tonic-gate  *	flags			- none but USB_FLAGS_SLEEP may be passed
9757c478bd9Sstevel@tonic-gate  *
9767c478bd9Sstevel@tonic-gate  * return values:
9777c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:		alternate was set
9787c478bd9Sstevel@tonic-gate  *	USB_FAILURE:		alternate could not be set because pipes
9797c478bd9Sstevel@tonic-gate  *				were still open or some access error occurred
9807c478bd9Sstevel@tonic-gate  */
9817c478bd9Sstevel@tonic-gate int
usb_get_alt_if(dev_info_t * dip,uint_t if_number,uint_t * alt_number,usb_flags_t flags)9827c478bd9Sstevel@tonic-gate usb_get_alt_if(dev_info_t	*dip,
9837c478bd9Sstevel@tonic-gate 		uint_t		if_number,
9847c478bd9Sstevel@tonic-gate 		uint_t		*alt_number,
9857c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
9867c478bd9Sstevel@tonic-gate {
9877c478bd9Sstevel@tonic-gate 	int		rval;
9887c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
9897c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
9907c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
9917c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph;
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9947c478bd9Sstevel@tonic-gate 	    "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
9957c478bd9Sstevel@tonic-gate 	    "uf = 0x%x", ddi_node_name(dip), if_number,
996112116d8Sfb 	    (void *)alt_number, flags);
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	if ((alt_number == NULL) || (dip == NULL)) {
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	/*
10067c478bd9Sstevel@tonic-gate 	 * get the alternate setting
10077c478bd9Sstevel@tonic-gate 	 */
10087c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1009112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF,
1010112116d8Sfb 	    USB_REQ_GET_IF,
1011112116d8Sfb 	    0,
1012112116d8Sfb 	    if_number,
1013112116d8Sfb 	    1,		/* returns one byte of data */
1014112116d8Sfb 	    &data, 0,
1015112116d8Sfb 	    &completion_reason,
1016112116d8Sfb 	    &cb_flags, flags);
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
10197c478bd9Sstevel@tonic-gate 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && data &&
1022d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (MBLKL(data) == 1)) {
10237c478bd9Sstevel@tonic-gate 		*alt_number = *(data->b_rptr);
10247c478bd9Sstevel@tonic-gate 	} else {
10257c478bd9Sstevel@tonic-gate 		*alt_number = 0;
10267c478bd9Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
10277c478bd9Sstevel@tonic-gate 			rval = USB_FAILURE;
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 	}
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	freemsg(data);
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	return (rval);
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate /*
10387c478bd9Sstevel@tonic-gate  * usba_get_cfg_cloud:
10397c478bd9Sstevel@tonic-gate  *	Get descriptor cloud for a given configuration.
10407c478bd9Sstevel@tonic-gate  *
10417c478bd9Sstevel@tonic-gate  * Arguments:
10427c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
10437c478bd9Sstevel@tonic-gate  *	default_ph		- default pipe handle
10447c478bd9Sstevel@tonic-gate  *	cfg			- which configuration to retrieve raw cloud of
10457c478bd9Sstevel@tonic-gate  *
10467c478bd9Sstevel@tonic-gate  * Returns:
10477c478bd9Sstevel@tonic-gate  *	on success: mblock containing the raw data.  Caller must free.
10487c478bd9Sstevel@tonic-gate  *	on failure: NULL
10497c478bd9Sstevel@tonic-gate  */
10507c478bd9Sstevel@tonic-gate static mblk_t *
usba_get_cfg_cloud(dev_info_t * dip,usb_pipe_handle_t default_ph,int cfg)10517c478bd9Sstevel@tonic-gate usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg)
10527c478bd9Sstevel@tonic-gate {
10537c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
10547c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
10557c478bd9Sstevel@tonic-gate 	usb_cfg_descr_t cfg_descr;
10567c478bd9Sstevel@tonic-gate 	mblk_t		*pdata = NULL;
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
10597c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
10607c478bd9Sstevel@tonic-gate 	    USB_REQ_GET_DESCR,
10617c478bd9Sstevel@tonic-gate 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
10627c478bd9Sstevel@tonic-gate 	    0,
10637c478bd9Sstevel@tonic-gate 	    USB_CFG_DESCR_SIZE,
10647c478bd9Sstevel@tonic-gate 	    &pdata,
10657c478bd9Sstevel@tonic-gate 	    0,
10667c478bd9Sstevel@tonic-gate 	    &completion_reason,
10677c478bd9Sstevel@tonic-gate 	    &cb_flags,
10687c478bd9Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 		freemsg(pdata);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 		return (NULL);
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	(void) usb_parse_cfg_descr(pdata->b_rptr,
1076d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    MBLKL(pdata), &cfg_descr, USB_CFG_DESCR_SIZE);
10777c478bd9Sstevel@tonic-gate 	freemsg(pdata);
10787c478bd9Sstevel@tonic-gate 	pdata = NULL;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
10817c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
10827c478bd9Sstevel@tonic-gate 	    USB_REQ_GET_DESCR,
10837c478bd9Sstevel@tonic-gate 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
10847c478bd9Sstevel@tonic-gate 	    0,
10857c478bd9Sstevel@tonic-gate 	    cfg_descr.wTotalLength,
10867c478bd9Sstevel@tonic-gate 	    &pdata,
10877c478bd9Sstevel@tonic-gate 	    0,
10887c478bd9Sstevel@tonic-gate 	    &completion_reason,
10897c478bd9Sstevel@tonic-gate 	    &cb_flags,
10907c478bd9Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 		freemsg(pdata);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 		return (NULL);
10957c478bd9Sstevel@tonic-gate 	}
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	return (pdata);
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate /*
11017c478bd9Sstevel@tonic-gate  * usb_check_same_device:
11027c478bd9Sstevel@tonic-gate  *	Check if the device connected to the port is the same as
11037c478bd9Sstevel@tonic-gate  *	the previous device that was in the port.  The previous device is
11047c478bd9Sstevel@tonic-gate  *	represented by the dip on record for the port.	Print a message
11057c478bd9Sstevel@tonic-gate  *	if the device is different.  If device_string arg is not NULL, it is
11067c478bd9Sstevel@tonic-gate  *	included in the message.  Can block.
11077c478bd9Sstevel@tonic-gate  *
11087c478bd9Sstevel@tonic-gate  * Arguments:
11097c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
11107c478bd9Sstevel@tonic-gate  *	log_handle		- handle to which messages are logged
11117c478bd9Sstevel@tonic-gate  *	log_level		- one of USB_LOG_*
11127c478bd9Sstevel@tonic-gate  *	log_mask		- logging mask
11137c478bd9Sstevel@tonic-gate  *	check_mask		- one mask containing things to check:
11147c478bd9Sstevel@tonic-gate  *					USB_CHK_BASIC: empty mask;
11157c478bd9Sstevel@tonic-gate  *						these checks are always done.
11167c478bd9Sstevel@tonic-gate  *					USB_CHK_VIDPID:
11177c478bd9Sstevel@tonic-gate  *						check vid, pid only.
11187c478bd9Sstevel@tonic-gate  *					USB_CHK_SERIAL: check match on device
11197c478bd9Sstevel@tonic-gate  *						serial number.
11207c478bd9Sstevel@tonic-gate  *					USB_CHK_CFG: check all raw config
11217c478bd9Sstevel@tonic-gate  *						clouds for a match.
11227c478bd9Sstevel@tonic-gate  *				NOTE: descr length and content always checked
11237c478bd9Sstevel@tonic-gate  *	device_string		- Device string to appear in error message
11247c478bd9Sstevel@tonic-gate  *
11257c478bd9Sstevel@tonic-gate  * return values:
11267c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:		same device
11277c478bd9Sstevel@tonic-gate  *	USB_INVALID_VERSION	not same device
11287c478bd9Sstevel@tonic-gate  *	USB_FAILURE:		Failure processing request
11297c478bd9Sstevel@tonic-gate  *	USB_INVALID_ARG:	dip is invalid
11307c478bd9Sstevel@tonic-gate  */
11317c478bd9Sstevel@tonic-gate int
usb_check_same_device(dev_info_t * dip,usb_log_handle_t log_handle,int log_level,int log_mask,uint_t check_mask,char * device_string)11327c478bd9Sstevel@tonic-gate usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle,
11337c478bd9Sstevel@tonic-gate     int log_level, int log_mask, uint_t check_mask, char *device_string)
11347c478bd9Sstevel@tonic-gate {
11357c478bd9Sstevel@tonic-gate 	usb_dev_descr_t		usb_dev_descr;
11367c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
11377c478bd9Sstevel@tonic-gate 	mblk_t			*pdata = NULL;
11387c478bd9Sstevel@tonic-gate 	uint16_t		length;
11397c478bd9Sstevel@tonic-gate 	int			rval;
11407c478bd9Sstevel@tonic-gate 	char			*buf;
11417c478bd9Sstevel@tonic-gate 	usb_cr_t		completion_reason;
11427c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags;
11437c478bd9Sstevel@tonic-gate 	boolean_t		match = B_TRUE;
11447c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	def_ph;
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
11527c478bd9Sstevel@tonic-gate 	length = usba_device->usb_dev_descr->bLength;
11537c478bd9Sstevel@tonic-gate 	def_ph = usba_get_dflt_pipe_handle(dip);
11547c478bd9Sstevel@tonic-gate 	ASSERT(def_ph);
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	/* get the "new" device descriptor */
11577c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
1158112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST |
1159112116d8Sfb 	    USB_DEV_REQ_TYPE_STANDARD,
1160112116d8Sfb 	    USB_REQ_GET_DESCR,		/* bRequest */
1161112116d8Sfb 	    USB_DESCR_TYPE_SETUP_DEV,	/* wValue */
1162112116d8Sfb 	    0,				/* wIndex */
1163112116d8Sfb 	    length,				/* wLength */
1164112116d8Sfb 	    &pdata, 0,
1165112116d8Sfb 	    &completion_reason,
1166112116d8Sfb 	    &cb_flags, USB_FLAGS_SLEEP);
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
11697c478bd9Sstevel@tonic-gate 		if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) {
11707c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle,
11717c478bd9Sstevel@tonic-gate 			    "getting device descriptor failed (%d)", rval);
11727c478bd9Sstevel@tonic-gate 			freemsg(pdata);
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
11757c478bd9Sstevel@tonic-gate 		}
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	ASSERT(pdata != NULL);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	(void) usb_parse_dev_descr(pdata->b_rptr,
1181d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    MBLKL(pdata), &usb_dev_descr,
11827c478bd9Sstevel@tonic-gate 	    sizeof (usb_dev_descr_t));
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	freemsg(pdata);
11857c478bd9Sstevel@tonic-gate 	pdata = NULL;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	/* Always check the device descriptor length. */
11887c478bd9Sstevel@tonic-gate 	if (usb_dev_descr.bLength != length) {
11897c478bd9Sstevel@tonic-gate 		match = B_FALSE;
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) {
11937c478bd9Sstevel@tonic-gate 		match = (usba_device->usb_dev_descr->idVendor ==
11947c478bd9Sstevel@tonic-gate 		    usb_dev_descr.idVendor) &&
11957c478bd9Sstevel@tonic-gate 		    (usba_device->usb_dev_descr->idProduct ==
11967c478bd9Sstevel@tonic-gate 		    usb_dev_descr.idProduct);
11977c478bd9Sstevel@tonic-gate 	} else if (bcmp((char *)usba_device->usb_dev_descr,
11987c478bd9Sstevel@tonic-gate 	    (char *)&usb_dev_descr, length) != 0) {
11997c478bd9Sstevel@tonic-gate 		match = B_FALSE;
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	/* if requested & this device has a serial number check and compare */
12037c478bd9Sstevel@tonic-gate 	if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) &&
12047c478bd9Sstevel@tonic-gate 	    (