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 /*
22112116d8Sfb  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * Utility functions
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
337c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
347c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
35*d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
367c478bd9Sstevel@tonic-gate 
37d73ae94eSgc extern void usba_free_evdata(usba_evdata_t *);
38d73ae94eSgc 
397c478bd9Sstevel@tonic-gate static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int);
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /* local functions */
427c478bd9Sstevel@tonic-gate static	int	usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *,
437c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
447c478bd9Sstevel@tonic-gate static int	usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *,
457c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
467c478bd9Sstevel@tonic-gate static int	usba_sync_clear_feature(dev_info_t *, usba_ph_impl_t *,
477c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Wrapper functions returning parsed standard descriptors without
517c478bd9Sstevel@tonic-gate  * getting the config cloud first but by just providing the dip.
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  * The client can easily retrieve the device and config descriptor from
547c478bd9Sstevel@tonic-gate  * the usb registration and no separate functions are provided
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  * These functions return failure if the full descriptor can not be
577c478bd9Sstevel@tonic-gate  * retrieved.  These functions will not access the device.
587c478bd9Sstevel@tonic-gate  * The caller must allocate the buffer.
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * usb_get_if_descr:
637c478bd9Sstevel@tonic-gate  *	Function to get the cooked interface descriptor
647c478bd9Sstevel@tonic-gate  *	This function will not access the device.
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * Arguments:
677c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
687c478bd9Sstevel@tonic-gate  *	if_index		- interface index
697c478bd9Sstevel@tonic-gate  *	alt_setting	- alt interface setting
707c478bd9Sstevel@tonic-gate  *	descr			- pointer to user allocated interface descr
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  * Return Values:
737c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
747c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
757c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate int
787c478bd9Sstevel@tonic-gate usb_get_if_descr(dev_info_t	*dip,
797c478bd9Sstevel@tonic-gate 		uint_t		if_index,
807c478bd9Sstevel@tonic-gate 		uint_t		alt_setting,
817c478bd9Sstevel@tonic-gate 		usb_if_descr_t	*descr)
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;	/* buf for config descriptor */
847c478bd9Sstevel@tonic-gate 	size_t		size, cfg_length;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
877c478bd9Sstevel@tonic-gate 	    "usb_get_if_descr: %s, index=0x%x, alt#=0x%x",
887c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), if_index, alt_setting);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (descr == NULL)) {
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
967c478bd9Sstevel@tonic-gate 	size = usb_parse_if_descr(usb_cfg, cfg_length,
977c478bd9Sstevel@tonic-gate 	    if_index,	/* interface index */
987c478bd9Sstevel@tonic-gate 	    alt_setting,	/* alt interface index */
997c478bd9Sstevel@tonic-gate 	    descr,
1007c478bd9Sstevel@tonic-gate 	    USB_IF_DESCR_SIZE);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	if (size != USB_IF_DESCR_SIZE) {
1037c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1047c478bd9Sstevel@tonic-gate 		    "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
1057c478bd9Sstevel@tonic-gate 		    size, USB_IF_DESCR_SIZE);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * usb_get_ep_descr:
1167c478bd9Sstevel@tonic-gate  *	Function to get the cooked endpoint descriptor
1177c478bd9Sstevel@tonic-gate  *	This function will not access the device.
1187c478bd9Sstevel@tonic-gate  *
1197c478bd9Sstevel@tonic-gate  * Arguments:
1207c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
1217c478bd9Sstevel@tonic-gate  *	if_index		- interface index
1227c478bd9Sstevel@tonic-gate  *	alt_setting		- alternate interface setting
1237c478bd9Sstevel@tonic-gate  *	endpoint_index		- endpoint index
1247c478bd9Sstevel@tonic-gate  *	descr			- pointer to user allocated interface descr
1257c478bd9Sstevel@tonic-gate  *
1267c478bd9Sstevel@tonic-gate  * Return Values:
1277c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
1287c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
1297c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
1307c478bd9Sstevel@tonic-gate  */
1317c478bd9Sstevel@tonic-gate int
1327c478bd9Sstevel@tonic-gate usb_get_ep_descr(dev_info_t	*dip,
1337c478bd9Sstevel@tonic-gate 		uint_t		if_index,
1347c478bd9Sstevel@tonic-gate 		uint_t		alt_setting,
1357c478bd9Sstevel@tonic-gate 		uint_t		endpoint_index,
1367c478bd9Sstevel@tonic-gate 		usb_ep_descr_t	*descr)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;	/* buf for config descriptor */
1397c478bd9Sstevel@tonic-gate 	size_t		size, cfg_length;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1427c478bd9Sstevel@tonic-gate 	    "usb_get_ep_descr: %s, index=0x%x, alt#=0x%x",
1437c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), if_index, alt_setting);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (descr == NULL)) {
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
1517c478bd9Sstevel@tonic-gate 	size = usb_parse_ep_descr(usb_cfg, cfg_length,
152112116d8Sfb 	    if_index,	/* interface index */
153112116d8Sfb 	    alt_setting,	/* alt interface index */
154112116d8Sfb 	    endpoint_index,		/* ep index */
155112116d8Sfb 	    descr, USB_EP_DESCR_SIZE);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	if (size != USB_EP_DESCR_SIZE) {
1587c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1597c478bd9Sstevel@tonic-gate 		    "parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)",
1607c478bd9Sstevel@tonic-gate 		    size, USB_EP_DESCR_SIZE);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * usb_lookup_ep_data:
1717c478bd9Sstevel@tonic-gate  * usb_get_ep_data (deprecated):
1727c478bd9Sstevel@tonic-gate  *	Function to get specific endpoint descriptor data
1737c478bd9Sstevel@tonic-gate  *	This function will not access the device.
1747c478bd9Sstevel@tonic-gate  *
1757c478bd9Sstevel@tonic-gate  * Arguments:
1767c478bd9Sstevel@tonic-gate  *	dip		- pointer to dev info
1777c478bd9Sstevel@tonic-gate  *	usb_client_dev_data_t - pointer to registration data
1787c478bd9Sstevel@tonic-gate  *	interface	- requested interface
1797c478bd9Sstevel@tonic-gate  *	alternate	- requested alternate
1807c478bd9Sstevel@tonic-gate  *	skip		- how many to skip
1817c478bd9Sstevel@tonic-gate  *	type		- endpoint type
1827c478bd9Sstevel@tonic-gate  *	direction	- endpoint direction or USB_DIR_DONT_CARE
1837c478bd9Sstevel@tonic-gate  *
1847c478bd9Sstevel@tonic-gate  * Return Values:
1857c478bd9Sstevel@tonic-gate  *	NULL or an endpoint descriptor pointer
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate usb_ep_data_t *
1887c478bd9Sstevel@tonic-gate usb_lookup_ep_data(dev_info_t	*dip,
1897c478bd9Sstevel@tonic-gate 		usb_client_dev_data_t *dev_datap,
1907c478bd9Sstevel@tonic-gate 		uint_t		interface,
1917c478bd9Sstevel@tonic-gate 		uint_t		alternate,
1927c478bd9Sstevel@tonic-gate 		uint_t		skip,
1937c478bd9Sstevel@tonic-gate 		uint_t		type,
1947c478bd9Sstevel@tonic-gate 		uint_t		dir)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
1977c478bd9Sstevel@tonic-gate 	int			i;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2007c478bd9Sstevel@tonic-gate 	    "usb_lookup_ep_data: "
2017c478bd9Sstevel@tonic-gate 	    "if=%d alt=%d skip=%d type=%d dir=%d",
2027c478bd9Sstevel@tonic-gate 	    interface, alternate, skip, type, dir);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (dev_datap == NULL)) {
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 		return (NULL);
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	altif_data = &dev_datap->dev_curr_cfg->
210112116d8Sfb 	    cfg_if[interface].if_alt[alternate];
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
213112116d8Sfb 	    "altif=0x%p n_ep=%d", (void *)altif_data, altif_data->altif_n_ep);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	for (i = 0; i < altif_data->altif_n_ep; i++) {
2167c478bd9Sstevel@tonic-gate 		usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
2177c478bd9Sstevel@tonic-gate 		uint8_t	ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
2187c478bd9Sstevel@tonic-gate 		uint8_t ept_dir = ept->bEndpointAddress & USB_EP_DIR_MASK;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		if (ept->bLength == 0) {
2217c478bd9Sstevel@tonic-gate 			continue;
2227c478bd9Sstevel@tonic-gate 		}
2237c478bd9Sstevel@tonic-gate 		if ((ept_type == type) &&
2247c478bd9Sstevel@tonic-gate 		    ((type == USB_EP_ATTR_CONTROL) || (dir == ept_dir))) {
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 			if (skip-- == 0) {
2277c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
2287c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
2297c478bd9Sstevel@tonic-gate 				    "usb_get_ep_data: data=0x%p",
230112116d8Sfb 				    (void *)&altif_data->altif_ep[i]);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 				return (&altif_data->altif_ep[i]);
2337c478bd9Sstevel@tonic-gate 			}
2347c478bd9Sstevel@tonic-gate 		}
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2377c478bd9Sstevel@tonic-gate 	    "usb_get_ep_data: returning NULL");
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	return (NULL);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2447c478bd9Sstevel@tonic-gate usb_ep_data_t *
2457c478bd9Sstevel@tonic-gate usb_get_ep_data(dev_info_t	*dip,
2467c478bd9Sstevel@tonic-gate 		usb_client_dev_data_t *dev_datap,
2477c478bd9Sstevel@tonic-gate 		uint_t		interface,
2487c478bd9Sstevel@tonic-gate 		uint_t		alternate,
2497c478bd9Sstevel@tonic-gate 		uint_t		type,
2507c478bd9Sstevel@tonic-gate 		uint_t		dir)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	return (usb_lookup_ep_data(dip, dev_datap, interface,
2537c478bd9Sstevel@tonic-gate 	    alternate, 0, type, dir));
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * usb_get_string_descr:
2597c478bd9Sstevel@tonic-gate  *	Function to read the string descriptor
2607c478bd9Sstevel@tonic-gate  *	This function will access the device and block.
2617c478bd9Sstevel@tonic-gate  *
2627c478bd9Sstevel@tonic-gate  * Arguments:
2637c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
2647c478bd9Sstevel@tonic-gate  *	langid		- LANGID to read different LOCALEs
2657c478bd9Sstevel@tonic-gate  *	index		- index to the string
2667c478bd9Sstevel@tonic-gate  *	buf		- user provided buffer for string descriptor
2677c478bd9Sstevel@tonic-gate  *	buflen		- user provided length of the buffer
2687c478bd9Sstevel@tonic-gate  *
2697c478bd9Sstevel@tonic-gate  * Return Values:
2707c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- descriptor is valid
2717c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- full descriptor could not be retrieved
2727c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate int
2757c478bd9Sstevel@tonic-gate usb_get_string_descr(dev_info_t *dip,
2767c478bd9Sstevel@tonic-gate 		uint16_t	langid,
2777c478bd9Sstevel@tonic-gate 		uint8_t 	index,
2787c478bd9Sstevel@tonic-gate 		char		*buf,
2797c478bd9Sstevel@tonic-gate 		size_t		buflen)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
2827c478bd9Sstevel@tonic-gate 	uint16_t	length;
2837c478bd9Sstevel@tonic-gate 	int		rval;
2847c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
2857c478bd9Sstevel@tonic-gate 	size_t		len;
2867c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2897c478bd9Sstevel@tonic-gate 	    "usb_get_string_descr: %s, langid=0x%x index=0x%x",
2907c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), langid, index);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (buf == NULL) || (buflen == 0) || (index == 0)) {
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/*
2987c478bd9Sstevel@tonic-gate 	 * determine the length of the descriptor
2997c478bd9Sstevel@tonic-gate 	 */
3007c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip,
301112116d8Sfb 	    usba_get_dflt_pipe_handle(dip),
302112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST,
303112116d8Sfb 	    USB_REQ_GET_DESCR,
304112116d8Sfb 	    USB_DESCR_TYPE_STRING << 8 | index & 0xff,
305112116d8Sfb 	    langid,
306112116d8Sfb 	    4,
307112116d8Sfb 	    &data, USB_ATTRS_SHORT_XFER_OK,
308112116d8Sfb 	    &completion_reason,
309112116d8Sfb 	    &cb_flags, USB_FLAGS_SLEEP);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
3127c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3137c478bd9Sstevel@tonic-gate 		    "rval=%d cr=%d", rval, completion_reason);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 		goto done;
3167c478bd9Sstevel@tonic-gate 	}
317*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	if (MBLKL(data) == 0) {
3187c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3197c478bd9Sstevel@tonic-gate 		    "0 bytes received");
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 		goto done;
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	ASSERT(data);
3257c478bd9Sstevel@tonic-gate 	length = *(data->b_rptr);
3267c478bd9Sstevel@tonic-gate 	freemsg(data);
3277c478bd9Sstevel@tonic-gate 	data = NULL;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
3307c478bd9Sstevel@tonic-gate 	    "rval=%d, cr=%d, length=%d", rval, completion_reason, length);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	/*
3337c478bd9Sstevel@tonic-gate 	 * if length is zero the next control request may fail.
3347c478bd9Sstevel@tonic-gate 	 * the HCD may not support a zero length control request
3357c478bd9Sstevel@tonic-gate 	 * and return an mblk_t which is NULL along with rval
3367c478bd9Sstevel@tonic-gate 	 * being USB_SUCCESS and "cr" being USB_CR_OK
3377c478bd9Sstevel@tonic-gate 	 */
3387c478bd9Sstevel@tonic-gate 	if (length < 2) {
3397c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		goto done;
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip,
345112116d8Sfb 	    usba_get_dflt_pipe_handle(dip),
346112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST,
347112116d8Sfb 	    USB_REQ_GET_DESCR,
348112116d8Sfb 	    USB_DESCR_TYPE_STRING << 8 | index & 0xff,
349112116d8Sfb 	    langid,
350112116d8Sfb 	    length,
351112116d8Sfb 	    &data, USB_ATTRS_SHORT_XFER_OK,
352112116d8Sfb 	    &completion_reason,
353112116d8Sfb 	    &cb_flags, USB_FLAGS_SLEEP);
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
3567c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	if ((data == NULL) || (rval != USB_SUCCESS)) {
3597c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
3607c478bd9Sstevel@tonic-gate 		    "failed to get string descriptor (rval=%d cr=%d)",
3617c478bd9Sstevel@tonic-gate 		    rval, completion_reason);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		goto done;
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
366*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	if ((length = MBLKL(data)) != 0) {
3677c478bd9Sstevel@tonic-gate 		len = usba_ascii_string_descr(data->b_rptr, length, buf,
368112116d8Sfb 		    buflen);
3697c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA,
3707c478bd9Sstevel@tonic-gate 		    usbai_log_handle, "buf=%s buflen=%lu", buf, len);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 		ASSERT(len <= buflen);
3737c478bd9Sstevel@tonic-gate 	} else {
3747c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate done:
3777c478bd9Sstevel@tonic-gate 	freemsg(data);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	return (rval);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate  * usb_get_dev_descr:
3857c478bd9Sstevel@tonic-gate  *	 utility function to get device descriptor from usba_device
3867c478bd9Sstevel@tonic-gate  *
3877c478bd9Sstevel@tonic-gate  * Arguments:
3887c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
3897c478bd9Sstevel@tonic-gate  *
3907c478bd9Sstevel@tonic-gate  * Return Values:
3917c478bd9Sstevel@tonic-gate  *	usb_dev_descr	- device  descriptor or NULL
3927c478bd9Sstevel@tonic-gate  */
3937c478bd9Sstevel@tonic-gate usb_dev_descr_t *
3947c478bd9Sstevel@tonic-gate usb_get_dev_descr(dev_info_t *dip)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
3977c478bd9Sstevel@tonic-gate 	usb_dev_descr_t *usb_dev_descr = NULL;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (dip) {
4007c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4017c478bd9Sstevel@tonic-gate 		    "usb_get_dev_descr: %s", ddi_node_name(dip));
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(dip);
4047c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
4057c478bd9Sstevel@tonic-gate 		usb_dev_descr = usba_device->usb_dev_descr;
4067c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	return (usb_dev_descr);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate /*
4147c478bd9Sstevel@tonic-gate  * usb_get_raw_cfg_data:
4157c478bd9Sstevel@tonic-gate  *	 utility function to get raw config descriptor from usba_device
4167c478bd9Sstevel@tonic-gate  *
4177c478bd9Sstevel@tonic-gate  * Arguments:
4187c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
4197c478bd9Sstevel@tonic-gate  *	length		- pointer to copy the cfg length
4207c478bd9Sstevel@tonic-gate  *
4217c478bd9Sstevel@tonic-gate  * Return Values:
4227c478bd9Sstevel@tonic-gate  *	usb_cfg	- raw config descriptor
4237c478bd9Sstevel@tonic-gate  */
4247c478bd9Sstevel@tonic-gate uchar_t *
4257c478bd9Sstevel@tonic-gate usb_get_raw_cfg_data(dev_info_t *dip, size_t *length)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
4287c478bd9Sstevel@tonic-gate 	uchar_t		*usb_cfg;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4317c478bd9Sstevel@tonic-gate 	    "usb_get_raw_cfg_data: %s", ddi_node_name(dip));
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (length == NULL)) {
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		return (NULL);
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
4417c478bd9Sstevel@tonic-gate 	usb_cfg = usba_device->usb_cfg;
4427c478bd9Sstevel@tonic-gate 	*length = usba_device->usb_cfg_length;
4437c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	return (usb_cfg);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate /*
4507c478bd9Sstevel@tonic-gate  * usb_get_addr:
4517c478bd9Sstevel@tonic-gate  *	utility function to return current usb address, mostly
4527c478bd9Sstevel@tonic-gate  *	for debugging purposes
4537c478bd9Sstevel@tonic-gate  *
4547c478bd9Sstevel@tonic-gate  * Arguments:
4557c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
4567c478bd9Sstevel@tonic-gate  *
4577c478bd9Sstevel@tonic-gate  * Return Values:
4587c478bd9Sstevel@tonic-gate  *	address	- USB Device Address
4597c478bd9Sstevel@tonic-gate  */
4607c478bd9Sstevel@tonic-gate int
4617c478bd9Sstevel@tonic-gate usb_get_addr(dev_info_t *dip)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate 	int address = 0;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
4667c478bd9Sstevel@tonic-gate 	    "usb_get_addr: %s", ddi_node_name(dip));
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	if (dip) {
4697c478bd9Sstevel@tonic-gate 		usba_device_t	*usba_device = usba_get_usba_device(dip);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
4727c478bd9Sstevel@tonic-gate 		address = usba_device->usb_addr;
4737c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	return (address);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate /*
4817c478bd9Sstevel@tonic-gate  * usb_set_cfg():
4827c478bd9Sstevel@tonic-gate  *	set configuration, use with caution (issues USB_REQ_SET_CONFIG)
4837c478bd9Sstevel@tonic-gate  *	Changing configuration will fail if pipes are still open or when
4847c478bd9Sstevel@tonic-gate  *	invoked from a driver bound to an interface on a composite device.
4857c478bd9Sstevel@tonic-gate  *
4867c478bd9Sstevel@tonic-gate  *	This function will access the device and block
4877c478bd9Sstevel@tonic-gate  *
4887c478bd9Sstevel@tonic-gate  * Arguments:
4897c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
4907c478bd9Sstevel@tonic-gate  *	cfg_index	- config index
4917c478bd9Sstevel@tonic-gate  *	cfg_value	- config value to be set
4927c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
4937c478bd9Sstevel@tonic-gate  *				wait for completion
4947c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
4957c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
4967c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
4977c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
4987c478bd9Sstevel@tonic-gate  *			  be provided.
4997c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
5007c478bd9Sstevel@tonic-gate  *
5017c478bd9Sstevel@tonic-gate  * Return Values:
5027c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:	- new configuration was set
5037c478bd9Sstevel@tonic-gate  *	USB_FAILURE:	- new configuration could not be set
5047c478bd9Sstevel@tonic-gate  *	USB_BUSY:	- some pipes were open or there were children
5057c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
5067c478bd9Sstevel@tonic-gate  */
5077c478bd9Sstevel@tonic-gate int
5087c478bd9Sstevel@tonic-gate usb_set_cfg(dev_info_t		*dip,
5097c478bd9Sstevel@tonic-gate 		uint_t		cfg_index,
5107c478bd9Sstevel@tonic-gate 		usb_flags_t	usb_flags,
5117c478bd9Sstevel@tonic-gate 		void		(*cb)(
5127c478bd9Sstevel@tonic-gate 					usb_pipe_handle_t ph,
5137c478bd9Sstevel@tonic-gate 					usb_opaque_t	arg,
5147c478bd9Sstevel@tonic-gate 					int		rval,
5157c478bd9Sstevel@tonic-gate 					usb_cb_flags_t	flags),
5167c478bd9Sstevel@tonic-gate 		usb_opaque_t	cb_arg)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	ph;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
5217c478bd9Sstevel@tonic-gate 	    "usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x",
5227c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), cfg_index,
5237c478bd9Sstevel@tonic-gate 	    usb_flags);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if (!usb_owns_device(dip)) {
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PERM);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
5417c478bd9Sstevel@tonic-gate 	if (usba_hold_ph_data(ph) == NULL) {
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	return (usba_pipe_setup_func_call(dip,
5477c478bd9Sstevel@tonic-gate 	    usba_sync_set_cfg, (usba_ph_impl_t *)ph,
5487c478bd9Sstevel@tonic-gate 	    (usb_opaque_t)((uintptr_t)cfg_index), usb_flags, cb, cb_arg));
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate static int
5537c478bd9Sstevel@tonic-gate usba_sync_set_cfg(dev_info_t	*dip,
5547c478bd9Sstevel@tonic-gate 		usba_ph_impl_t	*ph_impl,
5557c478bd9Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
5567c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate 	int		rval;
5597c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
5607c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
5617c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
5627c478bd9Sstevel@tonic-gate 	int		i, ph_open_cnt;
5637c478bd9Sstevel@tonic-gate 	uint_t		cfg_index = (uint_t)((uintptr_t)(request->arg));
5647c478bd9Sstevel@tonic-gate 	size_t		size;
5657c478bd9Sstevel@tonic-gate 	usb_cfg_descr_t confdescr;
56635f36846Ssl 	dev_info_t	*pdip;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	/*
5717c478bd9Sstevel@tonic-gate 	 * default pipe is still open
5727c478bd9Sstevel@tonic-gate 	 * all other pipes should be closed
5737c478bd9Sstevel@tonic-gate 	 */
5747c478bd9Sstevel@tonic-gate 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
5757c478bd9Sstevel@tonic-gate 		if (usba_device->usb_ph_list[i].usba_ph_data) {
5767c478bd9Sstevel@tonic-gate 			ph_open_cnt++;
5777c478bd9Sstevel@tonic-gate 			break;
5787c478bd9Sstevel@tonic-gate 		}
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	if (ph_open_cnt || ddi_get_child(dip)) {
5827c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 		return (USB_BUSY);
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 
58735f36846Ssl 	/*
58835f36846Ssl 	 * check if the configuration meets the
58935f36846Ssl 	 * power budget requirement
59035f36846Ssl 	 */
59135f36846Ssl 	if (usba_is_root_hub(dip)) {
59235f36846Ssl 		/*
59335f36846Ssl 		 * root hub should never be multi-configured.
59435f36846Ssl 		 * the code is here just to ensure
59535f36846Ssl 		 */
59635f36846Ssl 		usba_release_ph_data(ph_impl);
59735f36846Ssl 
59835f36846Ssl 		return (USB_FAILURE);
59935f36846Ssl 	}
60035f36846Ssl 	pdip = ddi_get_parent(dip);
60135f36846Ssl 
60235f36846Ssl 	/*
60335f36846Ssl 	 * increase the power budget value back to the unconfigured
60435f36846Ssl 	 * state to eliminate the influence of the old configuration
60535f36846Ssl 	 * before checking the new configuration; but remember to
60635f36846Ssl 	 * make a decrement before leaving this routine to restore
60735f36846Ssl 	 * the power consumption state of the device no matter it
60835f36846Ssl 	 * is in the new or old configuration
60935f36846Ssl 	 */
61035f36846Ssl 	usba_hubdi_incr_power_budget(pdip, usba_device);
61135f36846Ssl 
61235f36846Ssl 	if ((usba_hubdi_check_power_budget(pdip, usba_device,
61335f36846Ssl 	    cfg_index)) != USB_SUCCESS) {
61435f36846Ssl 		usba_hubdi_decr_power_budget(pdip, usba_device);
61535f36846Ssl 
61635f36846Ssl 		usba_release_ph_data(ph_impl);
61735f36846Ssl 
61835f36846Ssl 		return (USB_FAILURE);
61935f36846Ssl 	}
62035f36846Ssl 
6217c478bd9Sstevel@tonic-gate 	size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index],
622112116d8Sfb 	    USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	/* hubdi should ensure that this descriptor is correct */
6257c478bd9Sstevel@tonic-gate 	ASSERT(size == USB_CFG_DESCR_SIZE);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	/* set the configuration */
6287c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl,
629112116d8Sfb 	    USB_DEV_REQ_HOST_TO_DEV,
630112116d8Sfb 	    USB_REQ_SET_CFG,
631112116d8Sfb 	    confdescr.bConfigurationValue,
632112116d8Sfb 	    0,
633112116d8Sfb 	    0,
634112116d8Sfb 	    NULL, 0,
635112116d8Sfb 	    &completion_reason,
636112116d8Sfb 	    &cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP);
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	if (rval == USB_SUCCESS) {
6397c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
6407c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg_value = confdescr.bConfigurationValue;
6417c478bd9Sstevel@tonic-gate 		usba_device->usb_active_cfg_ndx = cfg_index;
6427c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index];
6437c478bd9Sstevel@tonic-gate 		usba_device->usb_cfg_length = confdescr.wTotalLength;
6447c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 		/* update the configuration property */
6477c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
648112116d8Sfb 		    "configuration#", usba_device->usb_cfg_value);
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 
65135f36846Ssl 	/*
65235f36846Ssl 	 * usba_device->usb_cfg always stores current configuration
65335f36846Ssl 	 * descriptor no matter SET_CFG request succeeded or not,
65435f36846Ssl 	 * so usba_hubdi_decr_power_budget can be done regardless
65535f36846Ssl 	 * of rval above
65635f36846Ssl 	 */
65735f36846Ssl 	usba_hubdi_decr_power_budget(pdip, usba_device);
65835f36846Ssl 
6597c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
6607c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	return (rval);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate /*
6707c478bd9Sstevel@tonic-gate  * usb_get_cfg():
6717c478bd9Sstevel@tonic-gate  *	get configuration value
6727c478bd9Sstevel@tonic-gate  *
6737c478bd9Sstevel@tonic-gate  * Arguments:
6747c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
6757c478bd9Sstevel@tonic-gate  *	cfg_value	- current config value
6767c478bd9Sstevel@tonic-gate  *	flags		- none, always blocks
6777c478bd9Sstevel@tonic-gate  *
6787c478bd9Sstevel@tonic-gate  * Return Values:
6797c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:	- config value was retrieved
6807c478bd9Sstevel@tonic-gate  *	USB_FAILURE:	- config value could not be retrieved
6817c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
6827c478bd9Sstevel@tonic-gate  */
6837c478bd9Sstevel@tonic-gate int
6847c478bd9Sstevel@tonic-gate usb_get_cfg(dev_info_t		*dip,
6857c478bd9Sstevel@tonic-gate 		uint_t		*cfgval,
6867c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate 	int		rval;
6897c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
6907c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
6917c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
6927c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph;
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
6957c478bd9Sstevel@tonic-gate 	    "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags);
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	if ((cfgval == NULL) || (dip == NULL)) {
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	/*
7057c478bd9Sstevel@tonic-gate 	 * get the cfg value
7067c478bd9Sstevel@tonic-gate 	 */
7077c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
708112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV,
709112116d8Sfb 	    USB_REQ_GET_CFG,
710112116d8Sfb 	    0,
711112116d8Sfb 	    0,
712112116d8Sfb 	    1,		/* returns one byte of data */
713112116d8Sfb 	    &data, 0,
714112116d8Sfb 	    &completion_reason,
715112116d8Sfb 	    &cb_flags, flags);
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
7187c478bd9Sstevel@tonic-gate 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && data &&
721*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (MBLKL(data) == 1)) {
7227c478bd9Sstevel@tonic-gate 		*cfgval = *(data->b_rptr);
7237c478bd9Sstevel@tonic-gate 	} else {
7247c478bd9Sstevel@tonic-gate 		*cfgval = 1;
7257c478bd9Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
7267c478bd9Sstevel@tonic-gate 			rval = USB_FAILURE;
7277c478bd9Sstevel@tonic-gate 		}
7287c478bd9Sstevel@tonic-gate 	}
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
7317c478bd9Sstevel@tonic-gate 	    "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	freemsg(data);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	return (rval);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate /*
7407c478bd9Sstevel@tonic-gate  * usb_get_current_cfgidx:
7417c478bd9Sstevel@tonic-gate  *	get current current config index
7427c478bd9Sstevel@tonic-gate  */
7437c478bd9Sstevel@tonic-gate uint_t
7447c478bd9Sstevel@tonic-gate usb_get_current_cfgidx(dev_info_t *dip)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
7477c478bd9Sstevel@tonic-gate 	uint_t		ndx;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
7507c478bd9Sstevel@tonic-gate 	ndx = usba_device->usb_active_cfg_ndx;
7517c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	return (ndx);
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate /*
7587c478bd9Sstevel@tonic-gate  * usb_get_if_number:
7597c478bd9Sstevel@tonic-gate  *	get usb interface number of current OS device node.
7607c478bd9Sstevel@tonic-gate  *
7617c478bd9Sstevel@tonic-gate  * Arguments:
7627c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
7637c478bd9Sstevel@tonic-gate  *
7647c478bd9Sstevel@tonic-gate  * Return Values:
7657c478bd9Sstevel@tonic-gate  *	USB_COMBINED_NODE if the driver is responsible for the entire
7667c478bd9Sstevel@tonic-gate  *	    device and this dip doesn't correspond to a device node.
7677c478bd9Sstevel@tonic-gate  *	USB_DEVICE_NODE if the driver is responsible for the entire device
7687c478bd9Sstevel@tonic-gate  *	    and this dip corresponds to a device node.
7697c478bd9Sstevel@tonic-gate  *	interface number: otherwise.
7707c478bd9Sstevel@tonic-gate  */
7717c478bd9Sstevel@tonic-gate int
7727c478bd9Sstevel@tonic-gate usb_get_if_number(dev_info_t *dip)
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate 	int interface_num;
7757c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
7767c478bd9Sstevel@tonic-gate 	usb_dev_descr_t	*usb_dev_descr;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
779112116d8Sfb 	    "usb_get_if_number: dip = 0x%p", (void *)dip);
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	/* not quite right but we can't return a negative return value */
7827c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 		return (0);
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	if (usba_device) {
7887c478bd9Sstevel@tonic-gate 		usb_dev_descr = usba_device->usb_dev_descr;
7897c478bd9Sstevel@tonic-gate 	} else {
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 		return (0);
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
7957c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	if (interface_num == USB_COMBINED_NODE) {
7987c478bd9Sstevel@tonic-gate 		if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
7997c478bd9Sstevel@tonic-gate 		    (usb_dev_descr->bDeviceClass == 0)) &&
8007c478bd9Sstevel@tonic-gate 		    (usba_device->usb_n_cfgs == 1) &&
8017c478bd9Sstevel@tonic-gate 		    (usba_device->usb_n_ifs == 1))) {
8027c478bd9Sstevel@tonic-gate 			interface_num = USB_DEVICE_NODE;
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	return (interface_num);
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate boolean_t
8117c478bd9Sstevel@tonic-gate usb_owns_device(dev_info_t *dip)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate 	int interface_num = usb_get_if_number(dip);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	return (interface_num < 0 ? B_TRUE : B_FALSE);
8167c478bd9Sstevel@tonic-gate }
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 
819d73ae94eSgc /* check whether the interface is in this interface association */
820d73ae94eSgc boolean_t
821d73ae94eSgc usba_check_if_in_ia(dev_info_t *dip, int n_if)
822d73ae94eSgc {
823d73ae94eSgc 	int first_if, if_count;
824d73ae94eSgc 
825d73ae94eSgc 	first_if = usb_get_if_number(dip);
826d73ae94eSgc 	if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
827112116d8Sfb 	    DDI_PROP_DONTPASS, "interface-count", -1);
828d73ae94eSgc 	if_count += first_if;
829d73ae94eSgc 
830d73ae94eSgc 	return ((n_if >= first_if && n_if < if_count) ? B_TRUE : B_FALSE);
831d73ae94eSgc }
832d73ae94eSgc 
833d73ae94eSgc 
8347c478bd9Sstevel@tonic-gate uint8_t
8357c478bd9Sstevel@tonic-gate usba_get_ifno(dev_info_t *dip)
8367c478bd9Sstevel@tonic-gate {
8377c478bd9Sstevel@tonic-gate 	int interface_num = usb_get_if_number(dip);
8387c478bd9Sstevel@tonic-gate 
839*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	return (uint8_t)(interface_num < 0 ? 0 : interface_num);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate  * usb_set_alt_if:
8457c478bd9Sstevel@tonic-gate  *	set the alternate interface number. Issues USB_REQ_SET_IF
8467c478bd9Sstevel@tonic-gate  *	This function will access the device
8477c478bd9Sstevel@tonic-gate  *
8487c478bd9Sstevel@tonic-gate  * Arguments:
8497c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
8507c478bd9Sstevel@tonic-gate  *	if_number	- interface number
8517c478bd9Sstevel@tonic-gate  *	alt_number	- alternate interface number
8527c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
8537c478bd9Sstevel@tonic-gate  *				wait for completion
8547c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
8557c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
8567c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
8577c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
8587c478bd9Sstevel@tonic-gate  *			  be provided.
8597c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
8607c478bd9Sstevel@tonic-gate  *
8617c478bd9Sstevel@tonic-gate  *
8627c478bd9Sstevel@tonic-gate  * return values:
8637c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- alternate was set
8647c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- alternate could not be set because pipes
8657c478bd9Sstevel@tonic-gate  *			  were still open or some access error occurred
8667c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
8677c478bd9Sstevel@tonic-gate  *
8687c478bd9Sstevel@tonic-gate  * Note:
8697c478bd9Sstevel@tonic-gate  *	we can't easily check if all pipes to endpoints for this interface
8707c478bd9Sstevel@tonic-gate  *	are closed since we don't have a map of which endpoints belong
8717c478bd9Sstevel@tonic-gate  *	to which interface. If we had this map, we would need to update
8727c478bd9Sstevel@tonic-gate  *	this on each alternative or configuration switch
8737c478bd9Sstevel@tonic-gate  */
8747c478bd9Sstevel@tonic-gate int
8757c478bd9Sstevel@tonic-gate usb_set_alt_if(dev_info_t	*dip,
8767c478bd9Sstevel@tonic-gate 		uint_t		interface,
8777c478bd9Sstevel@tonic-gate 		uint_t		alt_number,
8787c478bd9Sstevel@tonic-gate 		usb_flags_t	usb_flags,
8797c478bd9Sstevel@tonic-gate 		void		(*cb)(
8807c478bd9Sstevel@tonic-gate 					usb_pipe_handle_t ph,
8817c478bd9Sstevel@tonic-gate 					usb_opaque_t	arg,
8827c478bd9Sstevel@tonic-gate 					int		rval,
8837c478bd9Sstevel@tonic-gate 					usb_cb_flags_t	flags),
8847c478bd9Sstevel@tonic-gate 		usb_opaque_t	cb_arg)
8857c478bd9Sstevel@tonic-gate {
8867c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	ph;
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
8897c478bd9Sstevel@tonic-gate 	    "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
8907c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip),
8917c478bd9Sstevel@tonic-gate 	    interface, alt_number, usb_flags);
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
9047c478bd9Sstevel@tonic-gate 	if (usba_hold_ph_data(ph) == NULL) {
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	return (usba_pipe_setup_func_call(dip,
9107c478bd9Sstevel@tonic-gate 	    usba_sync_set_alt_if, (usba_ph_impl_t *)ph,
9117c478bd9Sstevel@tonic-gate 	    (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)),
9127c478bd9Sstevel@tonic-gate 	    usb_flags, cb, cb_arg));
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate static int
9177c478bd9Sstevel@tonic-gate usba_sync_set_alt_if(dev_info_t	*dip,
9187c478bd9Sstevel@tonic-gate 		usba_ph_impl_t	*ph_impl,
9197c478bd9Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
9207c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
9217c478bd9Sstevel@tonic-gate {
9227c478bd9Sstevel@tonic-gate 	int		rval;
9237c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
9247c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
9257c478bd9Sstevel@tonic-gate 	usb_opaque_t	arg = request->arg;
9267c478bd9Sstevel@tonic-gate 	int		interface = ((uintptr_t)arg >> 8) & 0xff;
9277c478bd9Sstevel@tonic-gate 	int		alt_number = (uintptr_t)arg & 0xff;
9287c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
929112116d8Sfb 	    (usb_pipe_handle_t)ph_impl);
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9327c478bd9Sstevel@tonic-gate 	    "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
9337c478bd9Sstevel@tonic-gate 	    "uf=0x%x", ddi_node_name(dip), interface,
9347c478bd9Sstevel@tonic-gate 	    alt_number, flags);
9357c478bd9Sstevel@tonic-gate 
936d73ae94eSgc 	/* if we don't own the device, we must own the interface or ia */
937d73ae94eSgc 	if (!usb_owns_device(dip) && !usba_check_if_in_ia(dip, interface) &&
9387c478bd9Sstevel@tonic-gate 	    (interface != usb_get_if_number(dip))) {
9397c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PERM);
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	/* set the alternate setting */
9457c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip),
946112116d8Sfb 	    USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
947112116d8Sfb 	    USB_REQ_SET_IF,
948112116d8Sfb 	    alt_number,
949112116d8Sfb 	    interface,
950112116d8Sfb 	    0,
951112116d8Sfb 	    NULL, 0,
952112116d8Sfb 	    &completion_reason,
953112116d8Sfb 	    &cb_flags, flags | USB_FLAGS_SLEEP);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9567c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	return (rval);
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate /*
9657c478bd9Sstevel@tonic-gate  * usb_get_alt_if:
9667c478bd9Sstevel@tonic-gate  *	get the alternate interface number. Issues USB_REQ_GET_IF
9677c478bd9Sstevel@tonic-gate  *	This function will access the device and block
9687c478bd9Sstevel@tonic-gate  *
9697c478bd9Sstevel@tonic-gate  * Arguments:
9707c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
9717c478bd9Sstevel@tonic-gate  *	if_number	- interface number
9727c478bd9Sstevel@tonic-gate  *	alt_number	- alternate interface number
9737c478bd9Sstevel@tonic-gate  *	flags			- none but USB_FLAGS_SLEEP may be passed
9747c478bd9Sstevel@tonic-gate  *
9757c478bd9Sstevel@tonic-gate  * return values:
9767c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:		alternate was set
9777c478bd9Sstevel@tonic-gate  *	USB_FAILURE:		alternate could not be set because pipes
9787c478bd9Sstevel@tonic-gate  *				were still open or some access error occurred
9797c478bd9Sstevel@tonic-gate  */
9807c478bd9Sstevel@tonic-gate int
9817c478bd9Sstevel@tonic-gate usb_get_alt_if(dev_info_t	*dip,
9827c478bd9Sstevel@tonic-gate 		uint_t		if_number,
9837c478bd9Sstevel@tonic-gate 		uint_t		*alt_number,
9847c478bd9Sstevel@tonic-gate 		usb_flags_t	flags)
9857c478bd9Sstevel@tonic-gate {
9867c478bd9Sstevel@tonic-gate 	int		rval;
9877c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
9887c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
9897c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
9907c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph;
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
9937c478bd9Sstevel@tonic-gate 	    "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
9947c478bd9Sstevel@tonic-gate 	    "uf = 0x%x", ddi_node_name(dip), if_number,
995112116d8Sfb 	    (void *)alt_number, flags);
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	if ((alt_number == NULL) || (dip == NULL)) {
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	/*
10057c478bd9Sstevel@tonic-gate 	 * get the alternate setting
10067c478bd9Sstevel@tonic-gate 	 */
10077c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1008112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF,
1009112116d8Sfb 	    USB_REQ_GET_IF,
1010112116d8Sfb 	    0,
1011112116d8Sfb 	    if_number,
1012112116d8Sfb 	    1,		/* returns one byte of data */
1013112116d8Sfb 	    &data, 0,
1014112116d8Sfb 	    &completion_reason,
1015112116d8Sfb 	    &cb_flags, flags);
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
10187c478bd9Sstevel@tonic-gate 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && data &&
1021*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (MBLKL(data) == 1)) {
10227c478bd9Sstevel@tonic-gate 		*alt_number = *(data->b_rptr);
10237c478bd9Sstevel@tonic-gate 	} else {
10247c478bd9Sstevel@tonic-gate 		*alt_number = 0;
10257c478bd9Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
10267c478bd9Sstevel@tonic-gate 			rval = USB_FAILURE;
10277c478bd9Sstevel@tonic-gate 		}
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	freemsg(data);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	return (rval);
10337c478bd9Sstevel@tonic-gate }
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate  * usba_get_cfg_cloud:
10387c478bd9Sstevel@tonic-gate  *	Get descriptor cloud for a given configuration.
10397c478bd9Sstevel@tonic-gate  *
10407c478bd9Sstevel@tonic-gate  * Arguments:
10417c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
10427c478bd9Sstevel@tonic-gate  *	default_ph		- default pipe handle
10437c478bd9Sstevel@tonic-gate  *	cfg			- which configuration to retrieve raw cloud of
10447c478bd9Sstevel@tonic-gate  *
10457c478bd9Sstevel@tonic-gate  * Returns:
10467c478bd9Sstevel@tonic-gate  *	on success: mblock containing the raw data.  Caller must free.
10477c478bd9Sstevel@tonic-gate  *	on failure: NULL
10487c478bd9Sstevel@tonic-gate  */
10497c478bd9Sstevel@tonic-gate static mblk_t *
10507c478bd9Sstevel@tonic-gate usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg)
10517c478bd9Sstevel@tonic-gate {
10527c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
10537c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
10547c478bd9Sstevel@tonic-gate 	usb_cfg_descr_t cfg_descr;
10557c478bd9Sstevel@tonic-gate 	mblk_t		*pdata = NULL;
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
10587c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
10597c478bd9Sstevel@tonic-gate 	    USB_REQ_GET_DESCR,
10607c478bd9Sstevel@tonic-gate 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
10617c478bd9Sstevel@tonic-gate 	    0,
10627c478bd9Sstevel@tonic-gate 	    USB_CFG_DESCR_SIZE,
10637c478bd9Sstevel@tonic-gate 	    &pdata,
10647c478bd9Sstevel@tonic-gate 	    0,
10657c478bd9Sstevel@tonic-gate 	    &completion_reason,
10667c478bd9Sstevel@tonic-gate 	    &cb_flags,
10677c478bd9Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 		freemsg(pdata);
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 		return (NULL);
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	(void) usb_parse_cfg_descr(pdata->b_rptr,
1075*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    MBLKL(pdata), &cfg_descr, USB_CFG_DESCR_SIZE);
10767c478bd9Sstevel@tonic-gate 	freemsg(pdata);
10777c478bd9Sstevel@tonic-gate 	pdata = NULL;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
10807c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
10817c478bd9Sstevel@tonic-gate 	    USB_REQ_GET_DESCR,
10827c478bd9Sstevel@tonic-gate 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
10837c478bd9Sstevel@tonic-gate 	    0,
10847c478bd9Sstevel@tonic-gate 	    cfg_descr.wTotalLength,
10857c478bd9Sstevel@tonic-gate 	    &pdata,
10867c478bd9Sstevel@tonic-gate 	    0,
10877c478bd9Sstevel@tonic-gate 	    &completion_reason,
10887c478bd9Sstevel@tonic-gate 	    &cb_flags,
10897c478bd9Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 		freemsg(pdata);
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 		return (NULL);
10947c478bd9Sstevel@tonic-gate 	}
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	return (pdata);
10977c478bd9Sstevel@tonic-gate }
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate /*
11007c478bd9Sstevel@tonic-gate  * usb_check_same_device:
11017c478bd9Sstevel@tonic-gate  *	Check if the device connected to the port is the same as
11027c478bd9Sstevel@tonic-gate  *	the previous device that was in the port.  The previous device is
11037c478bd9Sstevel@tonic-gate  *	represented by the dip on record for the port.	Print a message
11047c478bd9Sstevel@tonic-gate  *	if the device is different.  If device_string arg is not NULL, it is
11057c478bd9Sstevel@tonic-gate  *	included in the message.  Can block.
11067c478bd9Sstevel@tonic-gate  *
11077c478bd9Sstevel@tonic-gate  * Arguments:
11087c478bd9Sstevel@tonic-gate  *	dip			- pointer to devinfo of the client
11097c478bd9Sstevel@tonic-gate  *	log_handle		- handle to which messages are logged
11107c478bd9Sstevel@tonic-gate  *	log_level		- one of USB_LOG_*
11117c478bd9Sstevel@tonic-gate  *	log_mask		- logging mask
11127c478bd9Sstevel@tonic-gate  *	check_mask		- one mask containing things to check:
11137c478bd9Sstevel@tonic-gate  *					USB_CHK_BASIC: empty mask;
11147c478bd9Sstevel@tonic-gate  *						these checks are always done.
11157c478bd9Sstevel@tonic-gate  *					USB_CHK_VIDPID:
11167c478bd9Sstevel@tonic-gate  *						check vid, pid only.
11177c478bd9Sstevel@tonic-gate  *					USB_CHK_SERIAL: check match on device
11187c478bd9Sstevel@tonic-gate  *						serial number.
11197c478bd9Sstevel@tonic-gate  *					USB_CHK_CFG: check all raw config
11207c478bd9Sstevel@tonic-gate  *						clouds for a match.
11217c478bd9Sstevel@tonic-gate  *				NOTE: descr length and content always checked
11227c478bd9Sstevel@tonic-gate  *	device_string		- Device string to appear in error message
11237c478bd9Sstevel@tonic-gate  *
11247c478bd9Sstevel@tonic-gate  * return values:
11257c478bd9Sstevel@tonic-gate  *	USB_SUCCESS:		same device
11267c478bd9Sstevel@tonic-gate  *	USB_INVALID_VERSION	not same device
11277c478bd9Sstevel@tonic-gate  *	USB_FAILURE:		Failure processing request
11287c478bd9Sstevel@tonic-gate  *	USB_INVALID_ARG:	dip is invalid
11297c478bd9Sstevel@tonic-gate  */
11307c478bd9Sstevel@tonic-gate int
11317c478bd9Sstevel@tonic-gate usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle,
11327c478bd9Sstevel@tonic-gate     int log_level, int log_mask, uint_t check_mask, char *device_string)
11337c478bd9Sstevel@tonic-gate {
11347c478bd9Sstevel@tonic-gate 	usb_dev_descr_t		usb_dev_descr;
11357c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
11367c478bd9Sstevel@tonic-gate 	mblk_t			*pdata = NULL;
11377c478bd9Sstevel@tonic-gate 	uint16_t		length;
11387c478bd9Sstevel@tonic-gate 	int			rval;
11397c478bd9Sstevel@tonic-gate 	char			*buf;
11407c478bd9Sstevel@tonic-gate 	usb_cr_t		completion_reason;
11417c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags;
11427c478bd9Sstevel@tonic-gate 	boolean_t		match = B_TRUE;
11437c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	def_ph;
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
11517c478bd9Sstevel@tonic-gate 	length = usba_device->usb_dev_descr->bLength;
11527c478bd9Sstevel@tonic-gate 	def_ph = usba_get_dflt_pipe_handle(dip);
11537c478bd9Sstevel@tonic-gate 	ASSERT(def_ph);
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	/* get the "new" device descriptor */
11567c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
1157112116d8Sfb 	    USB_DEV_REQ_DEV_TO_HOST |
1158112116d8Sfb 	    USB_DEV_REQ_TYPE_STANDARD,
1159112116d8Sfb 	    USB_REQ_GET_DESCR,		/* bRequest */
1160112116d8Sfb 	    USB_DESCR_TYPE_SETUP_DEV,	/* wValue */
1161112116d8Sfb 	    0,				/* wIndex */
1162112116d8Sfb 	    length,				/* wLength */
1163112116d8Sfb 	    &pdata, 0,
1164112116d8Sfb 	    &completion_reason,
1165112116d8Sfb 	    &cb_flags, USB_FLAGS_SLEEP);
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
11687c478bd9Sstevel@tonic-gate 		if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) {
11697c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle,
11707c478bd9Sstevel@tonic-gate 			    "getting device descriptor failed (%d)", rval);
11717c478bd9Sstevel@tonic-gate 			freemsg(pdata);
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
11747c478bd9Sstevel@tonic-gate 		}
11757c478bd9Sstevel@tonic-gate 	}
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	ASSERT(pdata != NULL);
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	(void) usb_parse_dev_descr(pdata->b_rptr,
1180*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    MBLKL(pdata), &usb_dev_descr,
11817c478bd9Sstevel@tonic-gate 	    sizeof (usb_dev_descr_t));
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	freemsg(pdata);
11847c478bd9Sstevel@tonic-gate 	pdata = NULL;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	/* Always check the device descriptor length. */
11877c478bd9Sstevel@tonic-gate 	if (usb_dev_descr.bLength != length) {
11887c478bd9Sstevel@tonic-gate 		match = B_FALSE;
11897c478bd9Sstevel@tonic-gate 	}
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) {
11927c478bd9Sstevel@tonic-gate 		match = (usba_device->usb_dev_descr->idVendor ==
11937c478bd9Sstevel@tonic-gate 		    usb_dev_descr.idVendor) &&
11947c478bd9Sstevel@tonic-gate 		    (usba_device->usb_dev_descr->idProduct ==
11957c478bd9Sstevel@tonic-gate 		    usb_dev_descr.idProduct);
11967c478bd9Sstevel@tonic-gate 	} else if (bcmp((char *)usba_device->usb_dev_descr,
11977c478bd9Sstevel@tonic-gate 	    (char *)&usb_dev_descr, length) != 0) {
11987c478bd9Sstevel@tonic-gate 		match = B_FALSE;
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	/* if requested & this device has a serial number check and compare */
12027c478bd9Sstevel@tonic-gate 	if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) &&
12037c478bd9Sstevel@tonic-gate 	    (usba_device->usb_serialno_str != NULL)) {
12047c478bd9Sstevel@tonic-gate 		buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
12057c478bd9Sstevel@tonic-gate 		if (usb_get_string_descr(dip, USB_LANG_ID,
12067c478bd9Sstevel@tonic-gate 		    usb_dev_descr.iSerialNumber, buf,
12077c478bd9Sstevel@tonic-gate 		    USB_MAXSTRINGLEN) == USB_SUCCESS) {
12087c478bd9Sstevel@tonic-gate 			match =
12097c478bd9Sstevel@tonic-gate 			    (strcmp(buf, usba_device->usb_serialno_str) == 0);
12107c478bd9Sstevel@tonic-gate 		}
12117c478bd9Sstevel@tonic-gate 		kmem_free(buf, USB_MAXSTRINGLEN);
12127c478bd9Sstevel@tonic-gate 	}
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) {
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 		uint8_t num_cfgs = usb_dev_descr.bNumConfigurations;
12177c478bd9Sstevel@tonic-gate 		uint8_t cfg;
12187c478bd9Sstevel@tonic-gate 		mblk_t *cloud;
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 		for (cfg = 0; cfg < num_cfgs; cfg++) {
12217c478bd9Sstevel@tonic-gate 			cloud = usba_get_cfg_cloud(dip, def_ph, cfg);
12227c478bd9Sstevel@tonic-gate 			if (cloud == NULL) {
12237c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(DPRINT_MASK_USBA,
12247c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
12257c478bd9Sstevel@tonic-gate 				    "Could not retrieve config cloud for "
12267c478bd9Sstevel@tonic-gate 				    "comparison");
12277c478bd9Sstevel@tonic-gate 				break;
12287c478bd9Sstevel@tonic-gate 			}
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 			if (bcmp((char *)cloud->b_rptr,
12317c478bd9Sstevel@tonic-gate 			    usba_device->usb_cfg_array[cfg],
1232*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    MBLKL(cloud)) != 0) {
12337c478bd9Sstevel@tonic-gate 				freemsg(cloud);
12347c478bd9Sstevel@tonic-gate 				break;
12357c478bd9Sstevel@tonic-gate 			}
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 			freemsg(cloud);
12387c478bd9Sstevel@tonic-gate 		}
12397c478bd9Sstevel@tonic-gate 		if (cfg != num_cfgs) {
12407c478bd9Sstevel@tonic-gate 			match = B_FALSE;
12417c478bd9Sstevel@tonic-gate 		}
12427c478bd9Sstevel@tonic-gate 	}
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	if (match == B_FALSE) {
12457c478bd9Sstevel@tonic-gate 		boolean_t allocated_here = (device_string == NULL);
12467c478bd9Sstevel@tonic-gate 		if (allocated_here) {
12477c478bd9Sstevel@tonic-gate 			device_string =
12487c478bd9Sstevel@tonic-gate 			    kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP);
12497c478bd9Sstevel@tonic-gate 			(void) usba_get_mfg_prod_sn_str(dip, device_string,
1250112116d8Sfb 			    USB_MAXSTRINGLEN);
12517c478bd9Sstevel@tonic-gate 		}
12527c478bd9Sstevel@tonic-gate 		if (device_string[0] != '\0') {
12537c478bd9Sstevel@tonic-gate 			(void) usb_log(log_handle, log_level, log_mask,
12547c478bd9Sstevel@tonic-gate 			    "Cannot access %s.	Please reconnect.",
12557c478bd9Sstevel@tonic-gate 			    device_string);
12567c478bd9Sstevel@tonic-gate 		} else {
12577c478bd9Sstevel@tonic-gate 			(void) usb_log(log_handle, log_level, log_mask,
12587c478bd9Sstevel@tonic-gate 			    "Device is not identical to the "
12597c478bd9Sstevel@tonic-gate 			    "previous one this port.\n"
12607c478bd9Sstevel@tonic-gate 			    "Please disconnect and reconnect");
12617c478bd9Sstevel@tonic-gate 		}
12627c478bd9Sstevel@tonic-gate 		if (allocated_here) {
12637c478bd9Sstevel@tonic-gate 			kmem_free(device_string, USB_MAXSTRINGLEN);
12647c478bd9Sstevel@tonic-gate 		}
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		return (USB_INVALID_VERSION);
12677c478bd9Sstevel@tonic-gate 	}
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
12707c478bd9Sstevel@tonic-gate }
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate /*
12747c478bd9Sstevel@tonic-gate  * usb_pipe_get_state:
12757c478bd9Sstevel@tonic-gate  *	Return the state of the pipe
12767c478bd9Sstevel@tonic-gate  *
12777c478bd9Sstevel@tonic-gate  * Arguments:
12787c478bd9Sstevel@tonic-gate  *	pipe_handle	- pipe_handle pointer
12797c478bd9Sstevel@tonic-gate  *	pipe_state	- pointer to copy pipe state to
12807c478bd9Sstevel@tonic-gate  *	flags:
12817c478bd9Sstevel@tonic-gate  *		not used other than to check context
12827c478bd9Sstevel@tonic-gate  *
12837c478bd9Sstevel@tonic-gate  * Return Values:
12847c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- port state returned
12857c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
12867c478bd9Sstevel@tonic-gate  */
12877c478bd9Sstevel@tonic-gate int
12887c478bd9Sstevel@tonic-gate usb_pipe_get_state(usb_pipe_handle_t	pipe_handle,
12897c478bd9Sstevel@tonic-gate 	    usb_pipe_state_t	*pipe_state,
12907c478bd9Sstevel@tonic-gate 	    usb_flags_t		usb_flags)
12917c478bd9Sstevel@tonic-gate {
12927c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1295112116d8Sfb 	    "usb_pipe_get_state: ph_data=0x%p uf=0x%x", (void *)ph_data,
1296112116d8Sfb 	    usb_flags);
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	if (pipe_state == NULL) {
12997c478bd9Sstevel@tonic-gate 		if (ph_data) {
13007c478bd9Sstevel@tonic-gate 			usba_release_ph_data(ph_data->p_ph_impl);
13017c478bd9Sstevel@tonic-gate 		}
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
13047c478bd9Sstevel@tonic-gate 	}
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
13077c478bd9Sstevel@tonic-gate 		*pipe_state = USB_PIPE_STATE_CLOSED;
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
13107c478bd9Sstevel@tonic-gate 	}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13137c478bd9Sstevel@tonic-gate 	*pipe_state = usba_get_ph_state(ph_data);
13147c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate /*
13237c478bd9Sstevel@tonic-gate  * usba_pipe_get_policy:
13247c478bd9Sstevel@tonic-gate  *	Return a pipe's policy
13257c478bd9Sstevel@tonic-gate  *
13267c478bd9Sstevel@tonic-gate  * Arguments:
13277c478bd9Sstevel@tonic-gate  *	pipe_handle	- pipe_handle pointer
13287c478bd9Sstevel@tonic-gate  *
13297c478bd9Sstevel@tonic-gate  * Return Values:
13307c478bd9Sstevel@tonic-gate  *	On success: the pipe's policy
13317c478bd9Sstevel@tonic-gate  *	On failure: NULL
13327c478bd9Sstevel@tonic-gate  */
13337c478bd9Sstevel@tonic-gate usb_pipe_policy_t
13347c478bd9Sstevel@tonic-gate *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)
13357c478bd9Sstevel@tonic-gate {
13367c478bd9Sstevel@tonic-gate 	usb_pipe_policy_t *pp = NULL;
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	if (ph_data) {
13417c478bd9Sstevel@tonic-gate 		pp = &ph_data->p_policy;
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
13447c478bd9Sstevel@tonic-gate 	}
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 	return (pp);
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate /*
13517c478bd9Sstevel@tonic-gate  * usb_ep_num:
13527c478bd9Sstevel@tonic-gate  *	Return the endpoint number for a given pipe handle
13537c478bd9Sstevel@tonic-gate  *
13547c478bd9Sstevel@tonic-gate  * Arguments:
13557c478bd9Sstevel@tonic-gate  *	pipe_handle	- pipe_handle pointer
13567c478bd9Sstevel@tonic-gate  *
13577c478bd9Sstevel@tonic-gate  * Return Values:
13587c478bd9Sstevel@tonic-gate  *	endpoint number
13597c478bd9Sstevel@tonic-gate  */
13607c478bd9Sstevel@tonic-gate int
13617c478bd9Sstevel@tonic-gate usb_ep_num(usb_pipe_handle_t pipe_handle)
13627c478bd9Sstevel@tonic-gate {
13637c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
13647c478bd9Sstevel@tonic-gate 	int ep_num;
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
13697c478bd9Sstevel@tonic-gate 	}
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13727c478bd9Sstevel@tonic-gate 	ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK;
13737c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	return (ep_num);
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate /*
13827c478bd9Sstevel@tonic-gate  * usb_get_status
13837c478bd9Sstevel@tonic-gate  *	Issues USB_REQ_GET_STATUS to device/endpoint/interface
13847c478bd9Sstevel@tonic-gate  *	and report in "status" arg.
13857c478bd9Sstevel@tonic-gate  *
13867c478bd9Sstevel@tonic-gate  *	status reported for a "device" is
13877c478bd9Sstevel@tonic-gate  *		RemoteWakeup enabled
13887c478bd9Sstevel@tonic-gate  *		SelfPowered device?
13897c478bd9Sstevel@tonic-gate  *
13907c478bd9Sstevel@tonic-gate  *	status reported for an "interface" is NONE.
13917c478bd9Sstevel@tonic-gate  *	status reported for an "endpoint" is
13927c478bd9Sstevel@tonic-gate  *		HALT set (device STALLED?)
13937c478bd9Sstevel@tonic-gate  *
13947c478bd9Sstevel@tonic-gate  * Arguments:
13957c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo of the client
13967c478bd9Sstevel@tonic-gate  *	ph	- pipe handle
13977c478bd9Sstevel@tonic-gate  *	type	- bmRequestType to be used
13987c478bd9Sstevel@tonic-gate  *	what	- 0 for device, otherwise interface or ep number
13997c478bd9Sstevel@tonic-gate  *	status	- user supplied pointer for storing the status
14007c478bd9Sstevel@tonic-gate  *	flags	- USB_FLAGS_SLEEP (mandatory)
14017c478bd9Sstevel@tonic-gate  *
14027c478bd9Sstevel@tonic-gate  * Return Values:
14037c478bd9Sstevel@tonic-gate  *	valid usb_status_t	or USB_FAILURE
14047c478bd9Sstevel@tonic-gate  */
14057c478bd9Sstevel@tonic-gate int
14067c478bd9Sstevel@tonic-gate usb_get_status(dev_info_t		*dip,
14077c478bd9Sstevel@tonic-gate 		usb_pipe_handle_t	ph,
14087c478bd9Sstevel@tonic-gate 		uint_t			type,	/* bmRequestType */
14097c478bd9Sstevel@tonic-gate 		uint_t			what,	/* 0, interface, ept number */
14107c478bd9Sstevel@tonic-gate 		uint16_t		*status,
14117c478bd9Sstevel@tonic-gate 		usb_flags_t		flags)
14127c478bd9Sstevel@tonic-gate {
14137c478bd9Sstevel@tonic-gate 	int		rval;
14147c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
14157c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
14167c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
14197c478bd9Sstevel@tonic-gate 	    "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x",
14207c478bd9Sstevel@tonic-gate 	    type, what, flags);
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	if ((status == NULL) || (dip == NULL)) {
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
14257c478bd9Sstevel@tonic-gate 	}
14267c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
14297c478bd9Sstevel@tonic-gate 	}
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	type |= USB_DEV_REQ_DEV_TO_HOST;
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	/* get the status */
14347c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1435112116d8Sfb 	    type,
1436112116d8Sfb 	    USB_REQ_GET_STATUS,
1437112116d8Sfb 	    0,
1438112116d8Sfb 	    what,
1439112116d8Sfb 	    USB_GET_STATUS_LEN,	/* status is fixed 2 bytes long */
1440112116d8Sfb 	    &data, 0,
1441112116d8Sfb 	    &completion_reason, &cb_flags, flags);
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
14447c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	if ((rval == USB_SUCCESS) && data &&
1447*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (MBLKL(data) == USB_GET_STATUS_LEN)) {
14487c478bd9Sstevel@tonic-gate 		*status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
14497c478bd9Sstevel@tonic-gate 	} else {
14507c478bd9Sstevel@tonic-gate 		*status = 0;
14517c478bd9Sstevel@tonic-gate 		if (rval == USB_SUCCESS) {
14527c478bd9Sstevel@tonic-gate 			rval = USB_FAILURE;
14537c478bd9Sstevel@tonic-gate 		}
14547c478bd9Sstevel@tonic-gate 	}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	freemsg(data);
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	return (rval);
14597c478bd9Sstevel@tonic-gate }
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate /*
14637c478bd9Sstevel@tonic-gate  * usb_clear_feature:
14647c478bd9Sstevel@tonic-gate  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
14657c478bd9Sstevel@tonic-gate  *
14667c478bd9Sstevel@tonic-gate  * Arguments:
14677c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
14687c478bd9Sstevel@tonic-gate  *	ph		- pipe handle pointer
14697c478bd9Sstevel@tonic-gate  *	type		- bmRequestType to be used
14707c478bd9Sstevel@tonic-gate  *	feature		- feature to be cleared
14717c478bd9Sstevel@tonic-gate  *	what		- 0 for device, otherwise interface or ep number
14727c478bd9Sstevel@tonic-gate  *	flags		- none (but will sleep)
14737c478bd9Sstevel@tonic-gate  *
14747c478bd9Sstevel@tonic-gate  * Return Values:
14757c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- on doing a successful clear feature
14767c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- on failure
14777c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
14787c478bd9Sstevel@tonic-gate  */
14797c478bd9Sstevel@tonic-gate int
14807c478bd9Sstevel@tonic-gate usb_clear_feature(dev_info_t		*dip,
14817c478bd9Sstevel@tonic-gate 		usb_pipe_handle_t	ph,
14827c478bd9Sstevel@tonic-gate 		uint_t			type,	/* bmRequestType */
14837c478bd9Sstevel@tonic-gate 		uint_t			feature,
14847c478bd9Sstevel@tonic-gate 		uint_t			what,	/* 0, interface, ept number */
14857c478bd9Sstevel@tonic-gate 		usb_flags_t		flags)
14867c478bd9Sstevel@tonic-gate {
14877c478bd9Sstevel@tonic-gate 	int		rval;
14887c478bd9Sstevel@tonic-gate 	usb_cr_t	completion_reason;
14897c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
14927c478bd9Sstevel@tonic-gate 	    "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
14937c478bd9Sstevel@tonic-gate 	    "uf = 0x%x", type, feature, what, flags);
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
14987c478bd9Sstevel@tonic-gate 	}
14997c478bd9Sstevel@tonic-gate 	if (ph == NULL) {
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
15027c478bd9Sstevel@tonic-gate 	}
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	/* issue Clear feature */
15057c478bd9Sstevel@tonic-gate 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1506112116d8Sfb 	    type,
1507112116d8Sfb 	    USB_REQ_CLEAR_FEATURE,
1508112116d8Sfb 	    feature,
1509112116d8Sfb 	    what,
1510112116d8Sfb 	    0,
1511112116d8Sfb 	    NULL, 0,
1512112116d8Sfb 	    &completion_reason,
1513112116d8Sfb 	    &cb_flags, flags | USB_FLAGS_SLEEP);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
15167c478bd9Sstevel@tonic-gate 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	return (rval);
15197c478bd9Sstevel@tonic-gate }
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate /*
15237c478bd9Sstevel@tonic-gate  * usb_clr_feature:
15247c478bd9Sstevel@tonic-gate  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
15257c478bd9Sstevel@tonic-gate  *
15267c478bd9Sstevel@tonic-gate  * Arguments:
15277c478bd9Sstevel@tonic-gate  *	dip		- pointer to devinfo of the client
15287c478bd9Sstevel@tonic-gate  *	type		- bmRequestType to be used
15297c478bd9Sstevel@tonic-gate  *	feature		- feature to be cleared
15307c478bd9Sstevel@tonic-gate  *	what		- 0 for device, otherwise interface or ep number
15317c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
15327c478bd9Sstevel@tonic-gate  *				wait for completion
15337c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
15347c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
15357c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
15367c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
15377c478bd9Sstevel@tonic-gate  *			  be provided.
15387c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
15397c478bd9Sstevel@tonic-gate  *
15407c478bd9Sstevel@tonic-gate  *
15417c478bd9Sstevel@tonic-gate  * Return Values:
15427c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- on doing a successful clear feature
15437c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- on failure
15447c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
15457c478bd9Sstevel@tonic-gate  */
15467c478bd9Sstevel@tonic-gate int
15477c478bd9Sstevel@tonic-gate usb_clr_feature(
15487c478bd9Sstevel@tonic-gate 		dev_info_t	*dip,
15497c478bd9Sstevel@tonic-gate 		uint_t		type,	/* bmRequestType */
15507c478bd9Sstevel@tonic-gate 		uint_t		feature,
15517c478bd9Sstevel@tonic-gate 		uint_t		what,	/* 0, interface, ept number */
15527c478bd9Sstevel@tonic-gate 		usb_flags_t	flags,
15537c478bd9Sstevel@tonic-gate 		void		(*cb)(
15547c478bd9Sstevel@tonic-gate 					usb_pipe_handle_t ph,
15557c478bd9Sstevel@tonic-gate 					usb_opaque_t	arg,
15567c478bd9Sstevel@tonic-gate 					int		rval,
15577c478bd9Sstevel@tonic-gate 					usb_cb_flags_t	flags),
15587c478bd9Sstevel@tonic-gate 		usb_opaque_t	cb_arg)
15597c478bd9Sstevel@tonic-gate {
15607c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
15637c478bd9Sstevel@tonic-gate 	    "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
15647c478bd9Sstevel@tonic-gate 	    "uf = 0x%x", type, feature, what, flags);
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
15697c478bd9Sstevel@tonic-gate 	}
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
15747c478bd9Sstevel@tonic-gate 	}
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	ph = usba_get_dflt_pipe_handle(dip);
15777c478bd9Sstevel@tonic-gate 	if (usba_hold_ph_data(ph) == NULL) {
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
15807c478bd9Sstevel@tonic-gate 	}
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	return (usba_pipe_setup_func_call(dip,
15837c478bd9Sstevel@tonic-gate 	    usba_sync_clear_feature, (usba_ph_impl_t *)ph,
15847c478bd9Sstevel@tonic-gate 	    (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))),
15857c478bd9Sstevel@tonic-gate 	    flags, cb, cb_arg));
15867c478bd9Sstevel@tonic-gate }
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate static int
15907c478bd9Sstevel@tonic-gate usba_sync_clear_feature(dev_info_t *dip,
15917c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl,
15927c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t	*req,
1593112116d8Sfb 	usb_flags_t		usb_flags)
15947c478bd9Sstevel@tonic-gate {
15957c478bd9Sstevel@tonic-gate 	uint_t	n = (uint_t)((uintptr_t)(req->arg));
15967c478bd9Sstevel@tonic-gate 	uint_t	type = ((uint_t)n >> 16) & 0xff;
15977c478bd9Sstevel@tonic-gate 	uint_t	feature = ((uint_t)n >> 8) & 0xff;
15987c478bd9Sstevel@tonic-gate 	uint_t	what = (uint_t)n & 0xff;
1599112116d8Sfb 	int	rval;
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
16027c478bd9Sstevel@tonic-gate 	    "usb_sync_clear_feature: "
16037c478bd9Sstevel@tonic-gate 	    "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
1604112116d8Sfb 	    (void *)dip, (void *)ph_impl, type, feature, what, usb_flags);
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type,
1607112116d8Sfb 	    feature, what, usb_flags);
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 	return (rval);
16127c478bd9Sstevel@tonic-gate }
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate /*
16167c478bd9Sstevel@tonic-gate  * usb_async_req:
16177c478bd9Sstevel@tonic-gate  *	function used to dispatch a request to the taskq
16187c478bd9Sstevel@tonic-gate  *
16197c478bd9Sstevel@tonic-gate  * Arguments:
16207c478bd9Sstevel@tonic-gate  *	dip	- pointer to devinfo node
16217c478bd9Sstevel@tonic-gate  *	func	- pointer to function issued by taskq
16227c478bd9Sstevel@tonic-gate  *	flag	- USB_FLAGS_SLEEP mostly
16237c478bd9Sstevel@tonic-gate  *
16247c478bd9Sstevel@tonic-gate  * Return Values:
16257c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- on doing a successful taskq invocation
16267c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- on failure
16277c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
16287c478bd9Sstevel@tonic-gate  */
16297c478bd9Sstevel@tonic-gate int
16307c478bd9Sstevel@tonic-gate usb_async_req(dev_info_t *dip,
16317c478bd9Sstevel@tonic-gate 		void	(*func)(void *),
16327c478bd9Sstevel@tonic-gate 		void	*arg,
16337c478bd9Sstevel@tonic-gate 		usb_flags_t flag)
16347c478bd9Sstevel@tonic-gate {
16357c478bd9Sstevel@tonic-gate 	int tq_flag;
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
16387c478bd9Sstevel@tonic-gate 	    "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
1639112116d8Sfb 	    (void *)dip, (void *)func, arg, flag);
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (func == NULL)) {
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
16467c478bd9Sstevel@tonic-gate 	if (flag & USB_FLAGS_NOQUEUE) {
16477c478bd9Sstevel@tonic-gate 		tq_flag |= TQ_NOQUEUE;
16487c478bd9Sstevel@tonic-gate 	}
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	if (!taskq_dispatch(system_taskq, func, (void *)arg,
16517c478bd9Sstevel@tonic-gate 	    tq_flag)) {
16527c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
16537c478bd9Sstevel@tonic-gate 		    "usb_async_req: failure");
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
16567c478bd9Sstevel@tonic-gate 	}
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
16597c478bd9Sstevel@tonic-gate }
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate /*
16627c478bd9Sstevel@tonic-gate  * usba_async_ph_req:
16637c478bd9Sstevel@tonic-gate  *	function used to dispatch a request to the ph taskq
16647c478bd9Sstevel@tonic-gate  *
16657c478bd9Sstevel@tonic-gate  * Arguments:
16667c478bd9Sstevel@tonic-gate  *	ph_data	- pointer to pipe handle data
16677c478bd9Sstevel@tonic-gate  *	func	- pointer to function issued by taskq
16687c478bd9Sstevel@tonic-gate  *	flag	- USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
16697c478bd9Sstevel@tonic-gate  *
16707c478bd9Sstevel@tonic-gate  * Return Values:
16717c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- on doing a successful taskq invocation
16727c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- on failure
16737c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
16747c478bd9Sstevel@tonic-gate  *
16757c478bd9Sstevel@tonic-gate  * Note:
16767c478bd9Sstevel@tonic-gate  *	If the caller specified  USB_FLAGS_NOSLEEP, it must be
16777c478bd9Sstevel@tonic-gate  *	capable of reliably recovering from a failure return
16787c478bd9Sstevel@tonic-gate  */
16797c478bd9Sstevel@tonic-gate int
16807c478bd9Sstevel@tonic-gate usba_async_ph_req(usba_pipe_handle_data_t *ph_data,
16817c478bd9Sstevel@tonic-gate 		void	(*func)(void *),
16827c478bd9Sstevel@tonic-gate 		void	*arg,
16837c478bd9Sstevel@tonic-gate 		usb_flags_t flag)
16847c478bd9Sstevel@tonic-gate {
16857c478bd9Sstevel@tonic-gate 	int	tq_flag;
16867c478bd9Sstevel@tonic-gate 	taskq_t *taskq;
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
16897c478bd9Sstevel@tonic-gate 	    "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
1690112116d8Sfb 	    (void *)ph_data, (void *)func, arg, flag);
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 	if (func == NULL) {
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
16957c478bd9Sstevel@tonic-gate 	}
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	if (ph_data && ph_data->p_taskq) {
17007c478bd9Sstevel@tonic-gate 		taskq = ph_data->p_taskq;
17017c478bd9Sstevel@tonic-gate 	} else {
17027c478bd9Sstevel@tonic-gate 		taskq = system_taskq;
17037c478bd9Sstevel@tonic-gate 		tq_flag |= TQ_NOQUEUE;
17047c478bd9Sstevel@tonic-gate 	}
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 	if (!taskq_dispatch(taskq, func, (void *)arg, tq_flag)) {
17077c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
17087c478bd9Sstevel@tonic-gate 		    "usba_async_ph_req: failure");
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
17117c478bd9Sstevel@tonic-gate 	}
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
17147c478bd9Sstevel@tonic-gate }
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate /*
17187c478bd9Sstevel@tonic-gate  * utility functions to display CR, CB, return values
17197c478bd9Sstevel@tonic-gate  */
17207c478bd9Sstevel@tonic-gate typedef struct conv_table {
17217c478bd9Sstevel@tonic-gate 	int		what;
17227c478bd9Sstevel@tonic-gate 	const char	*name;
17237c478bd9Sstevel@tonic-gate } conv_table_t;
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate static const char *
17267c478bd9Sstevel@tonic-gate usba_get_name(conv_table_t *conv_table, int value)
17277c478bd9Sstevel@tonic-gate {
17287c478bd9Sstevel@tonic-gate 	int i;
17297c478bd9Sstevel@tonic-gate 	for (i = 0; conv_table[i].name != NULL; i++) {
17307c478bd9Sstevel@tonic-gate 		if (conv_table[i].what == value) {
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 			return (conv_table[i].name);
17337c478bd9Sstevel@tonic-gate 		}
17347c478bd9Sstevel@tonic-gate 	}
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	return ("unknown");
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate static conv_table_t cr_table[] = {
17417c478bd9Sstevel@tonic-gate 	{ USB_CR_OK,		"<no errors detected>" },
17427c478bd9Sstevel@tonic-gate 	{ USB_CR_CRC,		"<crc error detected>" },
17437c478bd9Sstevel@tonic-gate 	{ USB_CR_BITSTUFFING,	"<Bit stuffing violation>" },
17447c478bd9Sstevel@tonic-gate 	{ USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
17457c478bd9Sstevel@tonic-gate 	{ USB_CR_STALL, 	"<Endpoint returned stall PID>" },
17467c478bd9Sstevel@tonic-gate 	{ USB_CR_DEV_NOT_RESP,	"<Device not responding>" },
17477c478bd9Sstevel@tonic-gate 	{ USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
17487c478bd9Sstevel@tonic-gate 	{ USB_CR_UNEXP_PID,	"<Receive PID was not valid>" },
17497c478bd9Sstevel@tonic-gate 	{ USB_CR_DATA_OVERRUN,	"<Data size exceeded>" },
17507c478bd9Sstevel@tonic-gate 	{ USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
17517c478bd9Sstevel@tonic-gate 	{ USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
17527c478bd9Sstevel@tonic-gate 	{ USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
17537c478bd9Sstevel@tonic-gate 	{ USB_CR_TIMEOUT,	"<Command timed out>" },
17547c478bd9Sstevel@tonic-gate 	{ USB_CR_NOT_ACCESSED,	"<Not accessed by hardware>" },
17557c478bd9Sstevel@tonic-gate 	{ USB_CR_NO_RESOURCES,	"<No resources>" },
17567c478bd9Sstevel@tonic-gate 	{ USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
17577c478bd9Sstevel@tonic-gate 	{ USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
17587c478bd9Sstevel@tonic-gate 	{ USB_CR_PIPE_CLOSING,	"<Intr/ISOC IN pipe being closed>" },
17597c478bd9Sstevel@tonic-gate 	{ USB_CR_PIPE_RESET,	"<Intr/ISOC IN pipe reset>" },
17607c478bd9Sstevel@tonic-gate 	{ USB_CR_NOT_SUPPORTED, "<Command not supported>" },
17617c478bd9Sstevel@tonic-gate 	{ USB_CR_FLUSHED,	"<Req was flushed>" },
17627c478bd9Sstevel@tonic-gate 	{ USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
17637c478bd9Sstevel@tonic-gate 	{ 0,			NULL }
17647c478bd9Sstevel@tonic-gate };
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate const char *
17677c478bd9Sstevel@tonic-gate usb_str_cr(usb_cr_t cr)
17687c478bd9Sstevel@tonic-gate {
17697c478bd9Sstevel@tonic-gate 	return (usba_get_name(cr_table, cr));
17707c478bd9Sstevel@tonic-gate }
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate static conv_table_t cb_flags_table[] = {
17747c478bd9Sstevel@tonic-gate 	{ USB_CB_NO_INFO,	"<callback processed>" },
17757c478bd9Sstevel@tonic-gate 	{ USB_CB_STALL_CLEARED, "<stall cleared>" },
17767c478bd9Sstevel@tonic-gate 	{ USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
17777c478bd9Sstevel@tonic-gate 	{ USB_CB_PROTOCOL_STALL, "<protocol stall>" },
17787c478bd9Sstevel@tonic-gate 	{ USB_CB_RESET_PIPE,	"<pipe reset>" },
17797c478bd9Sstevel@tonic-gate 	{ USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
17807c478bd9Sstevel@tonic-gate 	{ USB_CB_NO_RESOURCES,	"<no resources>" },
17817c478bd9Sstevel@tonic-gate 	{ USB_CB_SUBMIT_FAILED, "<submit failed>" },
17827c478bd9Sstevel@tonic-gate 	{ USB_CB_INTR_CONTEXT,	"<Callback executing in interrupt context>" },
17837c478bd9Sstevel@tonic-gate 	{ 0,			NULL }
17847c478bd9Sstevel@tonic-gate };
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17877c478bd9Sstevel@tonic-gate char *
17887c478bd9Sstevel@tonic-gate usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length)
17897c478bd9Sstevel@tonic-gate {
17907c478bd9Sstevel@tonic-gate 	int i;
17917c478bd9Sstevel@tonic-gate 	buffer[0] = '\0';
17927c478bd9Sstevel@tonic-gate 	if (cb_flags == USB_CB_NO_INFO) {
17937c478bd9Sstevel@tonic-gate 		(void) strncpy(buffer, cb_flags_table[0].name, length);
17947c478bd9Sstevel@tonic-gate 	} else {
17957c478bd9Sstevel@tonic-gate 		for (i = 0; cb_flags_table[i].name != NULL; i++) {
17967c478bd9Sstevel@tonic-gate 			if (cb_flags & cb_flags_table[i].what) {
17977c478bd9Sstevel@tonic-gate 				(void) strncpy(&buffer[strlen(buffer)],
17987c478bd9Sstevel@tonic-gate 				    cb_flags_table[0].name,
17997c478bd9Sstevel@tonic-gate 				    length - strlen(buffer) - 1);
18007c478bd9Sstevel@tonic-gate 			}
18017c478bd9Sstevel@tonic-gate 		}
18027c478bd9Sstevel@tonic-gate 	}
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 	return (buffer);
18057c478bd9Sstevel@tonic-gate }
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate static conv_table_t pipe_state_table[] = {
18097c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_CLOSED,	"<closed>" },
18107c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_IDLE,		"<idle>" },
18117c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_ACTIVE,	"<active>" },
18127c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_ERROR,		"<error>" },
18137c478bd9Sstevel@tonic-gate 	{ USB_PIPE_STATE_CLOSING,	"<closing>" },
18147c478bd9Sstevel@tonic-gate 	{ 0,				NULL }
18157c478bd9Sstevel@tonic-gate };
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate const char *
18187c478bd9Sstevel@tonic-gate usb_str_pipe_state(usb_pipe_state_t state)
18197c478bd9Sstevel@tonic-gate {
18207c478bd9Sstevel@tonic-gate 	return (usba_get_name(pipe_state_table, state));
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate static conv_table_t dev_state[] = {
18257c478bd9Sstevel@tonic-gate 	{ USB_DEV_ONLINE,	"<online>" },
18267c478bd9Sstevel@tonic-gate 	{ USB_DEV_DISCONNECTED,	"<disconnected>" },
18277c478bd9Sstevel@tonic-gate 	{ USB_DEV_SUSPENDED,	"<suspended>" },
18287c478bd9Sstevel@tonic-gate 	{ USB_DEV_PWRED_DOWN,	"<powered down>" },
18297c478bd9Sstevel@tonic-gate 	{ 0,			NULL }
18307c478bd9Sstevel@tonic-gate };
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate const char *
18337c478bd9Sstevel@tonic-gate usb_str_dev_state(int state)
18347c478bd9Sstevel@tonic-gate {
18357c478bd9Sstevel@tonic-gate 	return (usba_get_name(dev_state, state));
18367c478bd9Sstevel@tonic-gate }
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate static conv_table_t rval_table[] = {
18407c478bd9Sstevel@tonic-gate 	{ USB_SUCCESS,		"<success>" },
18417c478bd9Sstevel@tonic-gate 	{ USB_FAILURE,		"<failure>" },
18427c478bd9Sstevel@tonic-gate 	{ USB_NO_RESOURCES,	"<no resources>" },
18437c478bd9Sstevel@tonic-gate 	{ USB_NO_BANDWIDTH,	"<no bandwidth>" },
18447c478bd9Sstevel@tonic-gate 	{ USB_NOT_SUPPORTED,	"<not supported>" },
18457c478bd9Sstevel@tonic-gate 	{ USB_PIPE_ERROR,	"<pipe error>" },
18467c478bd9Sstevel@tonic-gate 	{ USB_INVALID_PIPE,	"<invalid pipe>" },
18477c478bd9Sstevel@tonic-gate 	{ USB_NO_FRAME_NUMBER,	"<no frame number>" },
18487c478bd9Sstevel@tonic-gate 	{ USB_INVALID_START_FRAME, "<invalid frame>" },
18497c478bd9Sstevel@tonic-gate 	{ USB_HC_HARDWARE_ERROR, "<hw error>" },
18507c478bd9Sstevel@tonic-gate 	{ USB_INVALID_REQUEST,	"<invalid request>" },
18517c478bd9Sstevel@tonic-gate 	{ USB_INVALID_CONTEXT,	"<invalid context>" },
18527c478bd9Sstevel@tonic-gate 	{ USB_INVALID_VERSION,	"<invalid version>" },
18537c478bd9Sstevel@tonic-gate 	{ USB_INVALID_ARGS,	"<invalid args>" },
18547c478bd9Sstevel@tonic-gate 	{ USB_INVALID_PERM,	"<invalid perms>" },
18557c478bd9Sstevel@tonic-gate 	{ USB_BUSY,		"<busy>" },
18567c478bd9Sstevel@tonic-gate 	{ 0,			NULL }
18577c478bd9Sstevel@tonic-gate };
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate const char *
18607c478bd9Sstevel@tonic-gate usb_str_rval(int rval)
18617c478bd9Sstevel@tonic-gate {
18627c478bd9Sstevel@tonic-gate 	return (usba_get_name(rval_table, rval));
18637c478bd9Sstevel@tonic-gate }
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate /*
18677c478bd9Sstevel@tonic-gate  * function to convert USB return values to close errno
18687c478bd9Sstevel@tonic-gate  */
18697c478bd9Sstevel@tonic-gate static struct usb_rval2errno_entry {
18707c478bd9Sstevel@tonic-gate 	int	rval;
18717c478bd9Sstevel@tonic-gate 	int	Errno;
18727c478bd9Sstevel@tonic-gate } usb_rval2errno_table[] = {
18737c478bd9Sstevel@tonic-gate 	{ USB_SUCCESS,			0	},
18747c478bd9Sstevel@tonic-gate 	{ USB_FAILURE,			EIO	},
18757c478bd9Sstevel@tonic-gate 	{ USB_NO_RESOURCES,		ENOMEM	},
18767c478bd9Sstevel@tonic-gate 	{ USB_NO_BANDWIDTH,		EAGAIN	},
18777c478bd9Sstevel@tonic-gate 	{ USB_NOT_SUPPORTED,		ENOTSUP },
18787c478bd9Sstevel@tonic-gate 	{ USB_PIPE_ERROR,		EIO	},
18797c478bd9Sstevel@tonic-gate 	{ USB_INVALID_PIPE,		EINVAL	},
18807c478bd9Sstevel@tonic-gate 	{ USB_NO_FRAME_NUMBER,		EINVAL	},
18817c478bd9Sstevel@tonic-gate 	{ USB_INVALID_START_FRAME,	EINVAL	},
18827c478bd9Sstevel@tonic-gate 	{ USB_HC_HARDWARE_ERROR,	EIO	},
18837c478bd9Sstevel@tonic-gate 	{ USB_INVALID_REQUEST,		EINVAL	},
18847c478bd9Sstevel@tonic-gate 	{ USB_INVALID_CONTEXT,		EINVAL	},
18857c478bd9Sstevel@tonic-gate 	{ USB_INVALID_VERSION,		EINVAL	},
18867c478bd9Sstevel@tonic-gate 	{ USB_INVALID_ARGS,		EINVAL	},
18877c478bd9Sstevel@tonic-gate 	{ USB_INVALID_PERM,		EACCES	},
18887c478bd9Sstevel@tonic-gate 	{ USB_BUSY,			EBUSY	},
18897c478bd9Sstevel@tonic-gate };
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate #define	USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
18927c478bd9Sstevel@tonic-gate 			sizeof (struct usb_rval2errno_entry))
18937c478bd9Sstevel@tonic-gate int
18947c478bd9Sstevel@tonic-gate usb_rval2errno(int rval)
18957c478bd9Sstevel@tonic-gate {
18967c478bd9Sstevel@tonic-gate 	int i;
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
18997c478bd9Sstevel@tonic-gate 		if (usb_rval2errno_table[i].rval == rval) {
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 			return (usb_rval2errno_table[i].Errno);
19027c478bd9Sstevel@tonic-gate 		}
19037c478bd9Sstevel@tonic-gate 	}
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	return (EIO);
19067c478bd9Sstevel@tonic-gate }
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate /*
19107c478bd9Sstevel@tonic-gate  * serialization
19117c478bd9Sstevel@tonic-gate  */
19127c478bd9Sstevel@tonic-gate usb_serialization_t
19137c478bd9Sstevel@tonic-gate usb_init_serialization(
19147c478bd9Sstevel@tonic-gate 	dev_info_t	*dip,
19157c478bd9Sstevel@tonic-gate 	uint_t		flag)
19167c478bd9Sstevel@tonic-gate {
19177c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp = kmem_zalloc(
1918112116d8Sfb 	    sizeof (usba_serialization_impl_t), KM_SLEEP);
19197c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device;
19207c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t cookie = NULL;
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	if (dip) {
19237c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(dip);
19247c478bd9Sstevel@tonic-gate 		cookie = usba_hcdi_get_hcdi(
19257c478bd9Sstevel@tonic-gate 		    usba_device->usb_root_hub_dip)->hcdi_iblock_cookie;
19267c478bd9Sstevel@tonic-gate 	}
19277c478bd9Sstevel@tonic-gate 	impl_tokenp->s_dip = dip;
19287c478bd9Sstevel@tonic-gate 	impl_tokenp->s_flag = flag;
19297c478bd9Sstevel@tonic-gate 	mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie);
19307c478bd9Sstevel@tonic-gate 	cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL);
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 	return ((usb_serialization_t)impl_tokenp);
19337c478bd9Sstevel@tonic-gate }
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate void
19377c478bd9Sstevel@tonic-gate usb_fini_serialization(
19387c478bd9Sstevel@tonic-gate 	usb_serialization_t tokenp)
19397c478bd9Sstevel@tonic-gate {
19407c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp;
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	if (tokenp) {
19437c478bd9Sstevel@tonic-gate 		impl_tokenp = (usba_serialization_impl_t *)tokenp;
19447c478bd9Sstevel@tonic-gate 		ASSERT(impl_tokenp->s_count == 0);
19457c478bd9Sstevel@tonic-gate 		cv_destroy(&impl_tokenp->s_cv);
19467c478bd9Sstevel@tonic-gate 		mutex_destroy(&impl_tokenp->s_mutex);
19477c478bd9Sstevel@tonic-gate 		kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t));
19487c478bd9Sstevel@tonic-gate 	}
19497c478bd9Sstevel@tonic-gate }
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate /*
19537c478bd9Sstevel@tonic-gate  * usb_serialize_access() permits single threaded access.
19547c478bd9Sstevel@tonic-gate  *
19557c478bd9Sstevel@tonic-gate  * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
19567c478bd9Sstevel@tonic-gate  * it is reentrant with respect to thread. The thread must
19577c478bd9Sstevel@tonic-gate  * hold and release the same number of times.
19587c478bd9Sstevel@tonic-gate  *
19597c478bd9Sstevel@tonic-gate  * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
19607c478bd9Sstevel@tonic-gate  * it is not reentrant by the same thread. It is something like
19617c478bd9Sstevel@tonic-gate  * a semaphore.
19627c478bd9Sstevel@tonic-gate  */
19637c478bd9Sstevel@tonic-gate int
19647c478bd9Sstevel@tonic-gate usb_serialize_access(
19657c478bd9Sstevel@tonic-gate 	usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout)
19667c478bd9Sstevel@tonic-gate {
19677c478bd9Sstevel@tonic-gate 	int			rval = 1;	/* Must be initialized > 0 */
19687c478bd9Sstevel@tonic-gate 	clock_t			abs_timeout;
19697c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp;
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	impl_tokenp = (usba_serialization_impl_t *)tokenp;
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	/*
19747c478bd9Sstevel@tonic-gate 	 * Convert delta timeout in ms to absolute timeout in ticks, if used.
19757c478bd9Sstevel@tonic-gate 	 */
19767c478bd9Sstevel@tonic-gate 	if ((how_to_wait == USB_TIMEDWAIT) ||
19777c478bd9Sstevel@tonic-gate 	    (how_to_wait == USB_TIMEDWAIT_SIG)) {
19787c478bd9Sstevel@tonic-gate 		/* Convert timeout arg (in ms) to hz */
19797c478bd9Sstevel@tonic-gate 		abs_timeout = ddi_get_lbolt() +
19807c478bd9Sstevel@tonic-gate 		    drv_usectohz(delta_timeout * 1000);
19817c478bd9Sstevel@tonic-gate 	}
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	/* Get mutex after calc abs time, to count time waiting for mutex. */
19847c478bd9Sstevel@tonic-gate 	mutex_enter(&impl_tokenp->s_mutex);
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
19877c478bd9Sstevel@tonic-gate 	    "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
19887c478bd9Sstevel@tonic-gate 	    "flg=0x%x, abs_tmo=0x%lx",
1989112116d8Sfb 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
1990112116d8Sfb 	    impl_tokenp->s_count, (void *)impl_tokenp->s_thread,
1991112116d8Sfb 	    how_to_wait, abs_timeout);
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 ||
19947c478bd9Sstevel@tonic-gate 	    impl_tokenp->s_thread != curthread) {
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 		/*
19977c478bd9Sstevel@tonic-gate 		 * There are three ways to break out of the loop:
19987c478bd9Sstevel@tonic-gate 		 * 1) Condition met (s_count == 0) - higher prio test
19997c478bd9Sstevel@tonic-gate 		 * 2) kill(2) signal received (rval == 0)
20007c478bd9Sstevel@tonic-gate 		 * 3) timeout occurred (rval == -1)
20017c478bd9Sstevel@tonic-gate 		 * If condition met, whether or not signal or timeout occurred
20027c478bd9Sstevel@tonic-gate 		 * take access.  If condition not met, check other exit means.
20037c478bd9Sstevel@tonic-gate 		 */
20047c478bd9Sstevel@tonic-gate 		while (impl_tokenp->s_count != 0) {
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 			/* cv_timedwait* returns -1 on timeout. */
20077c478bd9Sstevel@tonic-gate 			/* cv_wait*_sig returns 0 on (kill(2)) signal. */
20087c478bd9Sstevel@tonic-gate 			if (rval <= 0) {
20097c478bd9Sstevel@tonic-gate 				mutex_exit(&impl_tokenp->s_mutex);
20107c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
20117c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
20127c478bd9Sstevel@tonic-gate 				    "usb_serialize_access: "
2013112116d8Sfb 				    "tok=0x%p exit due to %s",
2014112116d8Sfb 				    (void *)impl_tokenp,
20157c478bd9Sstevel@tonic-gate 				    ((rval == 0) ? "signal" : "timeout"));
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 				return (rval);
20187c478bd9Sstevel@tonic-gate 			}
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 			switch (how_to_wait) {
20217c478bd9Sstevel@tonic-gate 			default:
20227c478bd9Sstevel@tonic-gate 				how_to_wait = USB_WAIT;
20237c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
20247c478bd9Sstevel@tonic-gate 			case USB_WAIT:
20257c478bd9Sstevel@tonic-gate 				cv_wait(&impl_tokenp->s_cv,
2026112116d8Sfb 				    &impl_tokenp->s_mutex);
20277c478bd9Sstevel@tonic-gate 				break;
20287c478bd9Sstevel@tonic-gate 			case USB_WAIT_SIG:
20297c478bd9Sstevel@tonic-gate 				rval = cv_wait_sig(&impl_tokenp->s_cv,
2030112116d8Sfb 				    &impl_tokenp->s_mutex);
20317c478bd9Sstevel@tonic-gate 				break;
20327c478bd9Sstevel@tonic-gate 			case USB_TIMEDWAIT:
20337c478bd9Sstevel@tonic-gate 				rval = cv_timedwait(&impl_tokenp->s_cv,
2034112116d8Sfb 				    &impl_tokenp->s_mutex, abs_timeout);
20357c478bd9Sstevel@tonic-gate 				break;
20367c478bd9Sstevel@tonic-gate 			case USB_TIMEDWAIT_SIG:
20377c478bd9Sstevel@tonic-gate 				rval = cv_timedwait_sig(&impl_tokenp->s_cv,
2038112116d8Sfb 				    &impl_tokenp->s_mutex, abs_timeout);
20397c478bd9Sstevel@tonic-gate 				break;
20407c478bd9Sstevel@tonic-gate 			}
20417c478bd9Sstevel@tonic-gate 		}
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate 		impl_tokenp->s_thread = curthread;
20447c478bd9Sstevel@tonic-gate 	}
20457c478bd9Sstevel@tonic-gate 	impl_tokenp->s_count++;
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	ASSERT(!(impl_tokenp->s_count > 1 &&
20487c478bd9Sstevel@tonic-gate 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0));
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate 	mutex_exit(&impl_tokenp->s_mutex);
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2053112116d8Sfb 	    "usb_serialize_access exit: tok=0x%p thr=0x%p", (void *)impl_tokenp,
2054112116d8Sfb 	    (void *)curthread);
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	return (1);
20577c478bd9Sstevel@tonic-gate }
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20617c478bd9Sstevel@tonic-gate int
20627c478bd9Sstevel@tonic-gate usb_try_serialize_access(
20637c478bd9Sstevel@tonic-gate 	usb_serialization_t tokenp, uint_t flag)
20647c478bd9Sstevel@tonic-gate {
20657c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp =
2066112116d8Sfb 	    (usba_serialization_impl_t *)tokenp;
20677c478bd9Sstevel@tonic-gate 	mutex_enter(&impl_tokenp->s_mutex);
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
20707c478bd9Sstevel@tonic-gate 	    "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2071112116d8Sfb 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2072112116d8Sfb 	    impl_tokenp->s_count, (void *)curthread);
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	/*
20757c478bd9Sstevel@tonic-gate 	 * If lock is not taken (s_count is 0), take it.
20767c478bd9Sstevel@tonic-gate 	 * If lock is already taken, the thread is owner and lock
20777c478bd9Sstevel@tonic-gate 	 * is reentrant, take it.
20787c478bd9Sstevel@tonic-gate 	 * Otherwise, fail the access.
20797c478bd9Sstevel@tonic-gate 	 */
20807c478bd9Sstevel@tonic-gate 	if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) &&
20817c478bd9Sstevel@tonic-gate 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) {
20827c478bd9Sstevel@tonic-gate 		impl_tokenp->s_thread = curthread;
20837c478bd9Sstevel@tonic-gate 		impl_tokenp->s_count++;
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2086112116d8Sfb 		    "usb_try_serialize_access success: tok=0x%p",
2087112116d8Sfb 		    (void *)impl_tokenp);
20887c478bd9Sstevel@tonic-gate 		mutex_exit(&impl_tokenp->s_mutex);
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
20917c478bd9Sstevel@tonic-gate 	}
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
20947c478bd9Sstevel@tonic-gate 	    "usb_try_serialize_access failed: "
20957c478bd9Sstevel@tonic-gate 	    "tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2096112116d8Sfb 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2097112116d8Sfb 	    impl_tokenp->s_count, (void *)impl_tokenp->s_thread);
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	mutex_exit(&impl_tokenp->s_mutex);
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate void
21067c478bd9Sstevel@tonic-gate usb_release_access(
21077c478bd9Sstevel@tonic-gate 	usb_serialization_t tokenp)
21087c478bd9Sstevel@tonic-gate {
21097c478bd9Sstevel@tonic-gate 	usba_serialization_impl_t *impl_tokenp =
2110112116d8Sfb 	    (usba_serialization_impl_t *)tokenp;
21117c478bd9Sstevel@tonic-gate 	mutex_enter(&impl_tokenp->s_mutex);
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
21147c478bd9Sstevel@tonic-gate 	    "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
2115112116d8Sfb 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2116112116d8Sfb 	    impl_tokenp->s_count, (void *)curthread);
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	ASSERT(impl_tokenp->s_count > 0);
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) {
21217c478bd9Sstevel@tonic-gate 		if (impl_tokenp->s_thread != curthread) {
2122d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
21237c478bd9Sstevel@tonic-gate 			    "usb_release_access: release from wrong thread");
21247c478bd9Sstevel@tonic-gate 		}
21257c478bd9Sstevel@tonic-gate 		ASSERT(impl_tokenp->s_thread == curthread);
21267c478bd9Sstevel@tonic-gate 	}
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	if (--impl_tokenp->s_count == 0) {
21297c478bd9Sstevel@tonic-gate 		impl_tokenp->s_thread = NULL;
21307c478bd9Sstevel@tonic-gate 		cv_broadcast(&impl_tokenp->s_cv);
21317c478bd9Sstevel@tonic-gate 	}
21327c478bd9Sstevel@tonic-gate 	mutex_exit(&impl_tokenp->s_mutex);
21337c478bd9Sstevel@tonic-gate }
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate /*
21377c478bd9Sstevel@tonic-gate  * usb_fail_checkpoint:
21387c478bd9Sstevel@tonic-gate  *	fail checkpoint as driver/device could not be quiesced
21397c478bd9Sstevel@tonic-gate  */
21407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21417c478bd9Sstevel@tonic-gate void
21427c478bd9Sstevel@tonic-gate usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags)
21437c478bd9Sstevel@tonic-gate {
21447c478bd9Sstevel@tonic-gate 	usba_device_t	*usba_device = usba_get_usba_device(dip);
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
21477c478bd9Sstevel@tonic-gate 	    "usb_fail_checkpoint: %s%d", ddi_driver_name(dip),
21487c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
21517c478bd9Sstevel@tonic-gate 	usba_device->usb_no_cpr++;
21527c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
21537c478bd9Sstevel@tonic-gate }
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
21577c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
21587c478bd9Sstevel@tonic-gate /*
21597c478bd9Sstevel@tonic-gate  * usba_mk_mctl:
21607c478bd9Sstevel@tonic-gate  *	create a USB style M_CTL message, given an iocblk and a buffer
21617c478bd9Sstevel@tonic-gate  *	returns mblk_t * on success, NULL on failure
21627c478bd9Sstevel@tonic-gate  */
21637c478bd9Sstevel@tonic-gate mblk_t *
21647c478bd9Sstevel@tonic-gate usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len)
21657c478bd9Sstevel@tonic-gate {
21667c478bd9Sstevel@tonic-gate 	mblk_t *bp1, *bp2;
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) {
2169*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		/* LINTED E_BAD_PTR_CAST_ALIGN */
21707c478bd9Sstevel@tonic-gate 		*((struct iocblk *)bp1->b_datap->db_base) = mctlmsg;
21717c478bd9Sstevel@tonic-gate 		bp1->b_datap->db_type = M_CTL;
21727c478bd9Sstevel@tonic-gate 		bp1->b_wptr += sizeof (struct iocblk);
21737c478bd9Sstevel@tonic-gate 		if (buf != NULL) {
21747c478bd9Sstevel@tonic-gate 			if ((bp2 = allocb(len, BPRI_HI)) != NULL) {
21757c478bd9Sstevel@tonic-gate 				bp1->b_cont = bp2;
21767c478bd9Sstevel@tonic-gate 				bcopy(buf, bp2->b_datap->db_base, len);
21777c478bd9Sstevel@tonic-gate 				bp2->b_wptr += len;
21787c478bd9Sstevel@tonic-gate 			} else {
21797c478bd9Sstevel@tonic-gate 				freemsg(bp1);
21807c478bd9Sstevel@tonic-gate 				bp1 = NULL;
21817c478bd9Sstevel@tonic-gate 			}
21827c478bd9Sstevel@tonic-gate 		}
21837c478bd9Sstevel@tonic-gate 	}
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	return (bp1);
21867c478bd9Sstevel@tonic-gate }
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate #ifdef ALLOCB_TEST
21907c478bd9Sstevel@tonic-gate #undef	allocb
21917c478bd9Sstevel@tonic-gate mblk_t *
21927c478bd9Sstevel@tonic-gate usba_test_allocb(size_t size, uint_t pri)
21937c478bd9Sstevel@tonic-gate {
21947c478bd9Sstevel@tonic-gate 	if (ddi_get_lbolt() & 0x1) {
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 		return (NULL);
21977c478bd9Sstevel@tonic-gate 	} else {
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 		return (allocb(size, pri));
22007c478bd9Sstevel@tonic-gate 	}
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate #endif
2203d73ae94eSgc 
2204d73ae94eSgc 
2205d73ae94eSgc /*
2206d73ae94eSgc  * usb common power management for usb_mid, usb_ia and maybe other simple
2207d73ae94eSgc  * drivers.
2208d73ae94eSgc  */
2209d73ae94eSgc 
2210d73ae94eSgc /*
2211d73ae94eSgc  * functions to handle power transition for OS levels 0 -> 3
2212d73ae94eSgc  */
2213d73ae94eSgc static int
2214036aa261Sgc usb_common_pwrlvl0(dev_info_t *dip, uint8_t *pm, int *dev_state)
2215d73ae94eSgc {
2216d73ae94eSgc 	int	rval;
2217d73ae94eSgc 
2218d73ae94eSgc 	switch (*dev_state) {
2219d73ae94eSgc 	case USB_DEV_ONLINE:
2220d73ae94eSgc 		/* Issue USB D3 command to the device here */
2221d73ae94eSgc 		rval = usb_set_device_pwrlvl3(dip);
2222d73ae94eSgc 		ASSERT(rval == USB_SUCCESS);
2223d73ae94eSgc 
2224d73ae94eSgc 		*dev_state = USB_DEV_PWRED_DOWN;
2225036aa261Sgc 		*pm = USB_DEV_OS_PWR_OFF;
2226d73ae94eSgc 		/* FALLTHRU */
2227d73ae94eSgc 	case USB_DEV_DISCONNECTED:
2228d73ae94eSgc 	case USB_DEV_SUSPENDED:
2229d73ae94eSgc 		/* allow a disconnected/cpr'ed device to go to low pwr */
2230d73ae94eSgc 
2231d73ae94eSgc 		return (USB_SUCCESS);
2232d73ae94eSgc 	case USB_DEV_PWRED_DOWN:
2233d73ae94eSgc 	default:
2234d73ae94eSgc 		return (USB_FAILURE);
2235d73ae94eSgc 	}
2236d73ae94eSgc }
2237d73ae94eSgc 
2238d73ae94eSgc 
2239d73ae94eSgc /* ARGSUSED */
2240d73ae94eSgc static int
2241036aa261Sgc usb_common_pwrlvl1(dev_info_t *dip, uint8_t *pm, int *dev_state)
2242d73ae94eSgc {
2243d73ae94eSgc 	int	rval;
2244d73ae94eSgc 
2245d73ae94eSgc 	/* Issue USB D2 command to the device here */
2246d73ae94eSgc 	rval = usb_set_device_pwrlvl2(dip);
2247d73ae94eSgc 	ASSERT(rval == USB_SUCCESS);
2248d73ae94eSgc 
2249d73ae94eSgc 	return (USB_FAILURE);
2250d73ae94eSgc }
2251d73ae94eSgc 
2252d73ae94eSgc 
2253d73ae94eSgc /* ARGSUSED */
2254d73ae94eSgc static int
2255036aa261Sgc usb_common_pwrlvl2(dev_info_t *dip, uint8_t *pm, int *dev_state)
2256d73ae94eSgc {
2257d73ae94eSgc 	int	rval;
2258d73ae94eSgc 
2259d73ae94eSgc 	/* Issue USB D1 command to the device here */
2260d73ae94eSgc 	rval = usb_set_device_pwrlvl1(dip);
2261d73ae94eSgc 	ASSERT(rval == USB_SUCCESS);
2262d73ae94eSgc 
2263d73ae94eSgc 	return (USB_FAILURE);
2264d73ae94eSgc }
2265d73ae94eSgc 
2266d73ae94eSgc 
2267d73ae94eSgc static int
2268036aa261Sgc usb_common_pwrlvl3(dev_info_t *dip, uint8_t *pm, int *dev_state)
2269d73ae94eSgc {
2270d73ae94eSgc 	int	rval;
2271d73ae94eSgc 
2272d73ae94eSgc 	switch (*dev_state) {
2273d73ae94eSgc 	case USB_DEV_PWRED_DOWN:
2274d73ae94eSgc 		/* Issue USB D0 command to the device here */
2275d73ae94eSgc 		rval = usb_set_device_pwrlvl0(dip);
2276d73ae94eSgc 		ASSERT(rval == USB_SUCCESS);
2277d73ae94eSgc 
2278d73ae94eSgc 		*dev_state = USB_DEV_ONLINE;
2279036aa261Sgc 		*pm = USB_DEV_OS_FULL_PWR;
2280d73ae94eSgc 
2281d73ae94eSgc 		/* FALLTHRU */
2282d73ae94eSgc 	case USB_DEV_ONLINE:
2283d73ae94eSgc 		/* we are already in full power */
2284d73ae94eSgc 
2285d73ae94eSgc 		/* FALLTHRU */
2286d73ae94eSgc 	case USB_DEV_DISCONNECTED:
2287d73ae94eSgc 	case USB_DEV_SUSPENDED:
2288d73ae94eSgc 		/* allow a disconnected/cpr'ed device to go to low power */
2289d73ae94eSgc 
2290d73ae94eSgc 		return (USB_SUCCESS);
2291d73ae94eSgc 	default:
2292d73ae94eSgc 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2293d73ae94eSgc 		    "usb_common_pwrlvl3: Illegal state (%s)",
2294d73ae94eSgc 		    usb_str_dev_state(*dev_state));
2295d73ae94eSgc 
2296d73ae94eSgc 		return (USB_FAILURE);
2297d73ae94eSgc 	}
2298d73ae94eSgc }
2299d73ae94eSgc 
2300d73ae94eSgc /* power management */
2301d73ae94eSgc int
2302036aa261Sgc usba_common_power(dev_info_t *dip, uint8_t *pm, int *dev_state, int level)
2303d73ae94eSgc {
2304d73ae94eSgc 	int rval = DDI_FAILURE;
2305d73ae94eSgc 
2306d73ae94eSgc 	switch (level) {
2307d73ae94eSgc 	case USB_DEV_OS_PWR_OFF:
2308d73ae94eSgc 		rval = usb_common_pwrlvl0(dip, pm, dev_state);
2309d73ae94eSgc 		break;
2310d73ae94eSgc 	case USB_DEV_OS_PWR_1:
2311d73ae94eSgc 		rval = usb_common_pwrlvl1(dip, pm, dev_state);
2312d73ae94eSgc 		break;
2313d73ae94eSgc 	case USB_DEV_OS_PWR_2:
2314d73ae94eSgc 		rval = usb_common_pwrlvl2(dip, pm, dev_state);
2315d73ae94eSgc 		break;
2316d73ae94eSgc 	case USB_DEV_OS_FULL_PWR:
2317d73ae94eSgc 		rval = usb_common_pwrlvl3(dip, pm, dev_state);
2318d73ae94eSgc 		break;
2319d73ae94eSgc 	}
2320d73ae94eSgc 
2321d73ae94eSgc 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2322d73ae94eSgc }
2323d73ae94eSgc 
2324d73ae94eSgc /*
2325d73ae94eSgc  * register and unregister for events from our parent for usb_mid and usb_ia
2326d73ae94eSgc  * and maybe other nexus driver.
2327d73ae94eSgc  *
2328d73ae94eSgc  * Note: The cookie fields in usba_device structure is not used. They are
2329d73ae94eSgc  * used/shared by children.
2330d73ae94eSgc  */
2331d73ae94eSgc void
2332d73ae94eSgc usba_common_register_events(dev_info_t *dip, uint_t if_num,
2333d73ae94eSgc 	void (*event_cb)(dev_info_t *, ddi_eventcookie_t, void *, void *))
2334d73ae94eSgc {
2335d73ae94eSgc 	int rval;
2336d73ae94eSgc 	usba_evdata_t *evdata;
2337d73ae94eSgc 	ddi_eventcookie_t cookie;
2338d73ae94eSgc 
2339d73ae94eSgc 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2340d73ae94eSgc 	    "usb_common_register_events:");
2341d73ae94eSgc 
2342d73ae94eSgc 	evdata = usba_get_evdata(dip);
2343d73ae94eSgc 
2344d73ae94eSgc 	/* get event cookie, discard level and icookie for now */
2345d73ae94eSgc 	rval = ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
2346112116d8Sfb 	    &cookie);
2347d73ae94eSgc 
2348d73ae94eSgc 	if (rval == DDI_SUCCESS) {
2349d73ae94eSgc 		rval = ddi_add_event_handler(dip,
2350d73ae94eSgc 		    cookie, event_cb, NULL, &evdata->ev_rm_cb_id);
2351d73ae94eSgc 
2352d73ae94eSgc 		if (rval != DDI_SUCCESS) {
2353d73ae94eSgc 
2354d73ae94eSgc 			goto fail;
2355d73ae94eSgc 		}
2356d73ae94eSgc 	}
2357d73ae94eSgc 	rval = ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
2358112116d8Sfb 	    &cookie);
2359d73ae94eSgc 	if (rval == DDI_SUCCESS) {
2360d73ae94eSgc 		rval = ddi_add_event_handler(dip, cookie, event_cb,
2361d73ae94eSgc 		    NULL, &evdata->ev_ins_cb_id);
2362d73ae94eSgc 
2363d73ae94eSgc 		if (rval != DDI_SUCCESS) {
2364d73ae94eSgc 
2365d73ae94eSgc 			goto fail;
2366d73ae94eSgc 		}
2367d73ae94eSgc 	}
2368d73ae94eSgc 	rval = ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, &cookie);
2369d73ae94eSgc 	if (rval == DDI_SUCCESS) {
2370d73ae94eSgc 		rval = ddi_add_event_handler(dip,
2371d73ae94eSgc 		    cookie, event_cb, NULL, &evdata->ev_suspend_cb_id);
2372d73ae94eSgc 
2373d73ae94eSgc 		if (rval != DDI_SUCCESS) {
2374d73ae94eSgc 
2375d73ae94eSgc 			goto fail;
2376d73ae94eSgc 		}
2377d73ae94eSgc 	}
2378d73ae94eSgc 	rval = ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, &cookie);
2379d73ae94eSgc 	if (rval == DDI_SUCCESS) {
2380d73ae94eSgc 		rval = ddi_add_event_handler(dip, cookie, event_cb, NULL,
2381d73ae94eSgc 		    &evdata->ev_resume_cb_id);
2382d73ae94eSgc 
2383d73ae94eSgc 		if (rval != DDI_SUCCESS) {
2384d73ae94eSgc 
2385d73ae94eSgc 			goto fail;
2386d73ae94eSgc 		}
2387d73ae94eSgc 	}
2388d73ae94eSgc 
2389d73ae94eSgc 	return;
2390d73ae94eSgc 
2391d73ae94eSgc 
2392d73ae94eSgc fail:
2393d73ae94eSgc 	usba_common_unregister_events(dip, if_num);
2394d73ae94eSgc 
2395d73ae94eSgc }
2396d73ae94eSgc 
2397d73ae94eSgc void
2398d73ae94eSgc usba_common_unregister_events(dev_info_t *dip, uint_t if_num)
2399d73ae94eSgc {
2400d73ae94eSgc 	usba_evdata_t	*evdata;
2401d73ae94eSgc 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2402d73ae94eSgc 	int i;
2403d73ae94eSgc 
2404d73ae94eSgc 	evdata = usba_get_evdata(dip);
2405d73ae94eSgc 
2406d73ae94eSgc 	if (evdata->ev_rm_cb_id != NULL) {
2407d73ae94eSgc 		(void) ddi_remove_event_handler(evdata->ev_rm_cb_id);
2408d73ae94eSgc 		evdata->ev_rm_cb_id = NULL;
2409d73ae94eSgc 	}
2410d73ae94eSgc 
2411d73ae94eSgc 	if (evdata->ev_ins_cb_id != NULL) {
2412d73ae94eSgc 		(void) ddi_remove_event_handler(evdata->ev_ins_cb_id);
2413d73ae94eSgc 		evdata->ev_ins_cb_id = NULL;
2414d73ae94eSgc 	}
2415d73ae94eSgc 
2416d73ae94eSgc 	if (evdata->ev_suspend_cb_id != NULL) {
2417d73ae94eSgc 		(void) ddi_remove_event_handler(evdata->ev_suspend_cb_id);
2418d73ae94eSgc 		evdata->ev_suspend_cb_id = NULL;
2419d73ae94eSgc 	}
2420d73ae94eSgc 
2421d73ae94eSgc 	if (evdata->ev_resume_cb_id != NULL) {
2422d73ae94eSgc 		(void) ddi_remove_event_handler(evdata->ev_resume_cb_id);
2423d73ae94eSgc 		evdata->ev_resume_cb_id = NULL;
2424d73ae94eSgc 	}
2425d73ae94eSgc 
2426d73ae94eSgc 	/* clear event data for children, required for cfgmadm unconfigure */
2427036aa261Sgc 	mutex_enter(&usba_device->usb_mutex);
2428d73ae94eSgc 	if (usb_owns_device(dip)) {
2429d73ae94eSgc 		usba_free_evdata(usba_device->usb_evdata);
2430d73ae94eSgc 		usba_device->usb_evdata = NULL;
2431d73ae94eSgc 		usba_device->rm_cookie = NULL;
2432d73ae94eSgc 		usba_device->ins_cookie = NULL;
2433d73ae94eSgc 		usba_device->suspend_cookie = NULL;
2434d73ae94eSgc 		usba_device->resume_cookie = NULL;
2435d73ae94eSgc 	} else {
2436d73ae94eSgc 		for (i = 0; i < if_num; i++) {
2437d73ae94eSgc 			usba_device->usb_client_flags[usba_get_ifno(dip) + i]
2438112116d8Sfb 			    &= ~USBA_CLIENT_FLAG_EV_CBS;
2439d73ae94eSgc 		}
2440d73ae94eSgc 	}
2441036aa261Sgc 	mutex_exit(&usba_device->usb_mutex);
2442d73ae94eSgc }
2443