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
5d29f5a71Szhigang lu - Sun Microsystems - Beijing China  * Common Development and Distribution License (the "License").
6d29f5a71Szhigang lu - Sun Microsystems - Beijing China  * 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 /*
22d29f5a71Szhigang lu - Sun Microsystems - Beijing China  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*cf252232SAndy Fiddaman  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include "cfga_usb.h"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /* function prototypes */
327c478bd9Sstevel@tonic-gate cfga_err_t		usb_err_msg(char **, cfga_usb_ret_t, const char *, int);
337c478bd9Sstevel@tonic-gate extern cfga_usb_ret_t	usb_rcm_offline(const char *, char **, char *,
347c478bd9Sstevel@tonic-gate 			    cfga_flags_t);
357c478bd9Sstevel@tonic-gate extern cfga_usb_ret_t	usb_rcm_online(const char *, char **, char *,
367c478bd9Sstevel@tonic-gate 			    cfga_flags_t);
377c478bd9Sstevel@tonic-gate extern cfga_usb_ret_t	usb_rcm_remove(const char *, char **, char *,
387c478bd9Sstevel@tonic-gate 			    cfga_flags_t);
397c478bd9Sstevel@tonic-gate static int		usb_confirm(struct cfga_confirm *, char *);
40*cf252232SAndy Fiddaman static char		*usb_get_devicepath(const char *);
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * This file contains the entry points to the plugin as defined in the
447c478bd9Sstevel@tonic-gate  * config_admin(3X) man page.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * Set the version number for the cfgadm library's use.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate int cfga_version = CFGA_HSL_V2;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define	HELP_HEADER		1
537c478bd9Sstevel@tonic-gate #define	HELP_CONFIG		2
547c478bd9Sstevel@tonic-gate #define	HELP_RESET_SLOT		3
557c478bd9Sstevel@tonic-gate #define	HELP_CONFIG_SLOT	4
567c478bd9Sstevel@tonic-gate #define	HELP_UNKNOWN		5
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* Help messages */
597c478bd9Sstevel@tonic-gate static char *
607c478bd9Sstevel@tonic-gate usb_help[] = {
617c478bd9Sstevel@tonic-gate NULL,
627c478bd9Sstevel@tonic-gate "USB specific commands:\n",
637c478bd9Sstevel@tonic-gate " cfgadm -c [configure|unconfigure|disconnect] ap_id [ap_id...]\n",
647c478bd9Sstevel@tonic-gate " cfgadm -x usb_reset ap_id [ap_id...]\n",
657c478bd9Sstevel@tonic-gate " cfgadm -x usb_config -o config=<index of desired configuration>  ap_id\n",
667c478bd9Sstevel@tonic-gate "\tunknown command or option: ",
677c478bd9Sstevel@tonic-gate NULL
687c478bd9Sstevel@tonic-gate };	/* End help messages */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* Error messages */
717c478bd9Sstevel@tonic-gate static msgcvt_t
727c478bd9Sstevel@tonic-gate usb_error_msgs[] = {
737c478bd9Sstevel@tonic-gate 	/* CFGA_USB_OK	*/
747c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_OK, "ok" },
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	/* CFGA_USB_UNKNOWN	*/
777c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	/* CFGA_USB_INTERNAL_ERROR	*/
807c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_LIB_ERROR, "Internal error" },
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	/* CFGA_USB_OPTIONS	*/
837c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR, "Hardware specific options not supported" },
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	/* CFGA_USB_DYNAMIC_AP	*/
867c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_INVAL, "Dynamic attachment points not supported" },
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	/* CFGA_USB_AP	*/
897c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_APID_NOEXIST, "" },
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	/* CFGA_USB_PORT	*/
927c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_LIB_ERROR, "Cannot determine hub port number for " },
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	/* CFGA_USB_DEVCTL	*/
957c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR, "Cannot issue devctl to " },
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	/* CFGA_USB_NOT_CONNECTED	*/
987c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_INVAL, "No device connected to " },
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	/* CFGA_USB_NOT_CONFIGURED	*/
1017c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_INVAL, "No device configured to " },
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	/* CFGA_USB_ALREADY_CONNECTED	*/
1047c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_INSUFFICENT_CONDITION,
1057c478bd9Sstevel@tonic-gate 		"Device already connected; cannot connect again " },
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/* CFGA_USB_ALREADY_CONFIGURED	*/
1087c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_INVAL, "device already configured for " },
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	/* CFGA_USB_OPEN	*/
1117c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_LIB_ERROR, "Cannot open " },
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/* CFGA_USB_IOCTL	*/
1147c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR, "Driver ioctl failed " },
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/* CFGA_USB_BUSY	*/
1177c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_SYSTEM_BUSY, "" },
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	/* CFGA_USB_ALLOC_FAIL	*/
1207c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/* CFGA_USB_OPNOTSUPP	*/
1237c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_OPNOTSUPP, "Operation not supported" },
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	/* CFGA_USB_DEVLINK	*/
1267c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	/* CFGA_USB_STATE	*/
1297c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	/* CFGA_USB_CONFIG_INVAL	*/
1327c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR,
1337c478bd9Sstevel@tonic-gate 		"Specified configuration index unrecognized or exceeds "
1347c478bd9Sstevel@tonic-gate 		"maximum available" },
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	/* CFGA_USB_PRIV	*/
1377c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_PRIV, "" },
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	/* CFGA_USB_NVLIST	*/
1407c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR, "Internal error (nvlist)" },
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	/* CFGA_USB_ZEROLEN	*/
1437c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR, "Internal error (zerolength string)" },
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	/* CFGA_USB_CONFIG_FILE	*/
1467c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR,
1477c478bd9Sstevel@tonic-gate 	"Cannot open/fstat/read USB system configuration file" },
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	/* CFGA_USB_LOCK_FILE */
1507c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR, "Cannot lock USB system configuration file" },
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/* CFGA_USB_UNLOCK_FILE */
1537c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR, "Cannot unlock USB system configuration file" },
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* CFGA_USB_ONE_CONFIG	*/
1567c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR,
1577c478bd9Sstevel@tonic-gate 	"Operation not supported for devices with one configuration" },
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/* CFGA_USB_RCM_HANDLE Errors */
1607c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR, "cannot get RCM handle"},
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/* CFGA_USB_RCM_ONLINE */
1637c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_SYSTEM_BUSY,   "failed to online: "},
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/* CFGA_USB_RCM_OFFLINE */
1667c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_SYSTEM_BUSY,   "failed to offline: "},
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	/* CFGA_USB_RCM_INFO */
1697c478bd9Sstevel@tonic-gate 	{ CVT, CFGA_ERROR,   "failed to query: "}
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate };	/* End error messages */
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /* ========================================================================= */
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate  * The next two funcs imported verbatim from cfgadm_scsi.
1777c478bd9Sstevel@tonic-gate  * physpath_to_devlink is the only func directly used by cfgadm_usb.
1787c478bd9Sstevel@tonic-gate  * get_link supports it.
1797c478bd9Sstevel@tonic-gate  */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * Routine to search the /dev directory or a subtree of /dev.
1837c478bd9Sstevel@tonic-gate  */
1847c478bd9Sstevel@tonic-gate static int
1857c478bd9Sstevel@tonic-gate get_link(di_devlink_t devlink, void *arg)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate 	walk_link_t *larg = (walk_link_t *)arg;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	/*
1907c478bd9Sstevel@tonic-gate 	 * When path is specified, it's the node path without minor
1917c478bd9Sstevel@tonic-gate 	 * name. Therefore, the ../.. prefixes needs to be stripped.
1927c478bd9Sstevel@tonic-gate 	 */
1937c478bd9Sstevel@tonic-gate 	if (larg->path) {
1947c478bd9Sstevel@tonic-gate 		char *content = (char *)di_devlink_content(devlink);
1957c478bd9Sstevel@tonic-gate 		char *start = strstr(content, "/devices/");
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		/* line content must have minor node */
1987c478bd9Sstevel@tonic-gate 		if (start == NULL ||
1997c478bd9Sstevel@tonic-gate 		    strncmp(start, larg->path, larg->len) != 0 ||
2007c478bd9Sstevel@tonic-gate 		    start[larg->len] != ':') {
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 			return (DI_WALK_CONTINUE);
2037c478bd9Sstevel@tonic-gate 		}
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	*(larg->linkpp) = strdup(di_devlink_path(devlink));
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	return (DI_WALK_TERMINATE);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /* ARGSUSED */
2137c478bd9Sstevel@tonic-gate static ucfga_ret_t
2147c478bd9Sstevel@tonic-gate physpath_to_devlink(
2157c478bd9Sstevel@tonic-gate 	const char *basedir,
2167c478bd9Sstevel@tonic-gate 	const char *node_path,
2177c478bd9Sstevel@tonic-gate 	char **logpp,
2187c478bd9Sstevel@tonic-gate 	int *l_errnop,
2197c478bd9Sstevel@tonic-gate 	int match_minor)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	walk_link_t larg;
2227c478bd9Sstevel@tonic-gate 	di_devlink_handle_t hdl;
2237c478bd9Sstevel@tonic-gate 	char *minor_path;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
2267c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
2277c478bd9Sstevel@tonic-gate 		return (UCFGA_LIB_ERR);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	*logpp = NULL;
2317c478bd9Sstevel@tonic-gate 	larg.linkpp = logpp;
2327c478bd9Sstevel@tonic-gate 	if (match_minor) {
2337c478bd9Sstevel@tonic-gate 		minor_path = (char *)node_path + strlen("/devices");
2347c478bd9Sstevel@tonic-gate 		larg.path = NULL;
2357c478bd9Sstevel@tonic-gate 	} else {
2367c478bd9Sstevel@tonic-gate 		minor_path = NULL;
2377c478bd9Sstevel@tonic-gate 		larg.len = strlen(node_path);
2387c478bd9Sstevel@tonic-gate 		larg.path = (char *)node_path;
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	(void) di_devlink_walk(hdl, "^cfg/", minor_path, DI_PRIMARY_LINK,
2427c478bd9Sstevel@tonic-gate 	    (void *)&larg, get_link);
2437c478bd9Sstevel@tonic-gate 
244d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	(void) di_devlink_fini(&hdl);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	if (*logpp == NULL) {
2477c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
2487c478bd9Sstevel@tonic-gate 		return (UCFGA_LIB_ERR);
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	return (UCFGA_OK);
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate /* ========================================================================= */
2567c478bd9Sstevel@tonic-gate /* Utilities */
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * Given the index into a table (msgcvt_t) of messages, get the message
2607c478bd9Sstevel@tonic-gate  * string, converting it to the proper locale if necessary.
2617c478bd9Sstevel@tonic-gate  * NOTE: See cfga_usb.h
2627c478bd9Sstevel@tonic-gate  */
2637c478bd9Sstevel@tonic-gate static const char *
2647c478bd9Sstevel@tonic-gate get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	if (msg_index >= tbl_size) {
2677c478bd9Sstevel@tonic-gate 		DPRINTF("get_error_msg: bad error msg index: %d\n", msg_index);
2687c478bd9Sstevel@tonic-gate 		msg_index = CFGA_USB_UNKNOWN;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	return ((msg_tbl[msg_index].intl) ?
2727c478bd9Sstevel@tonic-gate 	    dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
2737c478bd9Sstevel@tonic-gate 	    msg_tbl[msg_index].msgstr);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate  * Allocates and creates a message string (in *ret_str),
2797c478bd9Sstevel@tonic-gate  * by concatenating all the (char *) args together, in order.
2807c478bd9Sstevel@tonic-gate  * Last arg MUST be NULL.
2817c478bd9Sstevel@tonic-gate  */
2827c478bd9Sstevel@tonic-gate static void
2837c478bd9Sstevel@tonic-gate set_msg(char **ret_str, ...)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	char	*str;
2867c478bd9Sstevel@tonic-gate 	size_t	total_len;
2877c478bd9Sstevel@tonic-gate 	va_list	valist;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	va_start(valist, ret_str);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	while ((str = va_arg(valist, char *)) != NULL) {
2947c478bd9Sstevel@tonic-gate 		size_t	len = strlen(str);
2957c478bd9Sstevel@tonic-gate 		char	*old_str = *ret_str;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 		*ret_str = (char *)realloc(*ret_str, total_len + len + 1);
2987c478bd9Sstevel@tonic-gate 		if (*ret_str == NULL) {
2997c478bd9Sstevel@tonic-gate 			/* We're screwed */
3007c478bd9Sstevel@tonic-gate 			free(old_str);
3017c478bd9Sstevel@tonic-gate 			DPRINTF("set_msg: realloc failed.\n");
3027c478bd9Sstevel@tonic-gate 			va_end(valist);
3037c478bd9Sstevel@tonic-gate 			return;
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 
306d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		(void) strcpy(*ret_str + total_len, str);
3077c478bd9Sstevel@tonic-gate 		total_len += len;
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	va_end(valist);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate  * Error message handling.
3167c478bd9Sstevel@tonic-gate  * For the rv passed in, looks up the corresponding error message string(s),
3177c478bd9Sstevel@tonic-gate  * internationalized it if necessary, and concatenates it into a new
3187c478bd9Sstevel@tonic-gate  * memory buffer, and points *errstring to it.
3197c478bd9Sstevel@tonic-gate  * Note not all rvs will result in an error message return, as not all
3207c478bd9Sstevel@tonic-gate  * error conditions warrant a USB-specific error message.
3217c478bd9Sstevel@tonic-gate  *
3227c478bd9Sstevel@tonic-gate  * Some messages may display ap_id or errno, which is why they are passed
3237c478bd9Sstevel@tonic-gate  * in.
3247c478bd9Sstevel@tonic-gate  */
3257c478bd9Sstevel@tonic-gate cfga_err_t
3267c478bd9Sstevel@tonic-gate usb_err_msg(char **errstring, cfga_usb_ret_t rv, const char *ap_id, int l_errno)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	if (errstring == NULL) {
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 		return (usb_error_msgs[rv].cfga_err);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/*
3347c478bd9Sstevel@tonic-gate 	 * Generate the appropriate USB-specific error message(s) (if any).
3357c478bd9Sstevel@tonic-gate 	 */
3367c478bd9Sstevel@tonic-gate 	switch (rv) {
3377c478bd9Sstevel@tonic-gate 	case CFGA_USB_OK:
3387c478bd9Sstevel@tonic-gate 	/* Special case - do nothing.  */
3397c478bd9Sstevel@tonic-gate 		break;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	case CFGA_USB_UNKNOWN:
3427c478bd9Sstevel@tonic-gate 	case CFGA_USB_DYNAMIC_AP:
3437c478bd9Sstevel@tonic-gate 	case CFGA_USB_INTERNAL_ERROR:
3447c478bd9Sstevel@tonic-gate 	case CFGA_USB_OPTIONS:
3457c478bd9Sstevel@tonic-gate 	case CFGA_USB_ALLOC_FAIL:
3467c478bd9Sstevel@tonic-gate 	case CFGA_USB_STATE:
3477c478bd9Sstevel@tonic-gate 	case CFGA_USB_CONFIG_INVAL:
3487c478bd9Sstevel@tonic-gate 	case CFGA_USB_PRIV:
3497c478bd9Sstevel@tonic-gate 	case CFGA_USB_OPNOTSUPP:
3507c478bd9Sstevel@tonic-gate 	/* These messages require no additional strings passed. */
3517c478bd9Sstevel@tonic-gate 		set_msg(errstring, ERR_STR(rv), NULL);
3527c478bd9Sstevel@tonic-gate 		break;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	case CFGA_USB_AP:
3557c478bd9Sstevel@tonic-gate 	case CFGA_USB_PORT:
3567c478bd9Sstevel@tonic-gate 	case CFGA_USB_NOT_CONNECTED:
3577c478bd9Sstevel@tonic-gate 	case CFGA_USB_NOT_CONFIGURED:
3587c478bd9Sstevel@tonic-gate 	case CFGA_USB_ALREADY_CONNECTED:
3597c478bd9Sstevel@tonic-gate 	case CFGA_USB_ALREADY_CONFIGURED:
3607c478bd9Sstevel@tonic-gate 	case CFGA_USB_BUSY:
3617c478bd9Sstevel@tonic-gate 	case CFGA_USB_DEVLINK:
3627c478bd9Sstevel@tonic-gate 	case CFGA_USB_RCM_HANDLE:
3637c478bd9Sstevel@tonic-gate 	case CFGA_USB_RCM_ONLINE:
3647c478bd9Sstevel@tonic-gate 	case CFGA_USB_RCM_OFFLINE:
3657c478bd9Sstevel@tonic-gate 	case CFGA_USB_RCM_INFO:
3667c478bd9Sstevel@tonic-gate 	case CFGA_USB_DEVCTL:
3677c478bd9Sstevel@tonic-gate 	/* These messages also print ap_id.  */
368d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		(void) set_msg(errstring, ERR_STR(rv),
369d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    "ap_id: ", ap_id, "", NULL);
3707c478bd9Sstevel@tonic-gate 		break;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	case CFGA_USB_IOCTL:
3737c478bd9Sstevel@tonic-gate 	case CFGA_USB_NVLIST:
3747c478bd9Sstevel@tonic-gate 	case CFGA_USB_CONFIG_FILE:
3757c478bd9Sstevel@tonic-gate 	case CFGA_USB_ONE_CONFIG:
3767c478bd9Sstevel@tonic-gate 	/* These messages also print errno.  */
3777c478bd9Sstevel@tonic-gate 	{
3787c478bd9Sstevel@tonic-gate 		char *errno_str = l_errno ? strerror(l_errno) : "";
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		set_msg(errstring, ERR_STR(rv), errno_str,
3817c478bd9Sstevel@tonic-gate 		    l_errno ? "\n" : "", NULL);
3827c478bd9Sstevel@tonic-gate 		break;
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	case CFGA_USB_OPEN:
3867c478bd9Sstevel@tonic-gate 	/* These messages also apid and errno.  */
3877c478bd9Sstevel@tonic-gate 	{
3887c478bd9Sstevel@tonic-gate 		char *errno_str = l_errno ? strerror(l_errno) : "";
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
3917c478bd9Sstevel@tonic-gate 		    errno_str, l_errno ? "\n" : "", NULL);
3927c478bd9Sstevel@tonic-gate 		break;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	default:
3967c478bd9Sstevel@tonic-gate 		DPRINTF("usb_err_msg: Unrecognized message index: %d\n", rv);
3977c478bd9Sstevel@tonic-gate 		set_msg(errstring, ERR_STR(CFGA_USB_INTERNAL_ERROR), NULL);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	}	/* end switch */
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/*
4027c478bd9Sstevel@tonic-gate 	 * Determine the proper error code to send back to the cfgadm library.
4037c478bd9Sstevel@tonic-gate 	 */
4047c478bd9Sstevel@tonic-gate 	return (usb_error_msgs[rv].cfga_err);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate  * Ensure the ap_id passed is in the correct (physical ap_id) form:
4107c478bd9Sstevel@tonic-gate  *     path/device:xx[.xx]+
4117c478bd9Sstevel@tonic-gate  * where xx is a one or two-digit number.
4127c478bd9Sstevel@tonic-gate  *
4137c478bd9Sstevel@tonic-gate  * Note the library always calls the plugin with a physical ap_id.
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate static int
4167c478bd9Sstevel@tonic-gate verify_valid_apid(const char *ap_id)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	char	*l_ap_id;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (ap_id == NULL) {
4217c478bd9Sstevel@tonic-gate 		return (-1);
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	l_ap_id = strrchr(ap_id, *MINOR_SEP);
4257c478bd9Sstevel@tonic-gate 	l_ap_id++;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) {
4287c478bd9Sstevel@tonic-gate 		/* Bad characters in the ap_id. */
4297c478bd9Sstevel@tonic-gate 		return (-1);
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if (strstr(l_ap_id, "..") != NULL) {
4337c478bd9Sstevel@tonic-gate 		/* ap_id has 1..2 or more than 2 dots */
4347c478bd9Sstevel@tonic-gate 		return (-1);
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	return (0);
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate  * Verify the params passed in are valid.
4437c478bd9Sstevel@tonic-gate  */
4447c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
4457c478bd9Sstevel@tonic-gate verify_params(
4467c478bd9Sstevel@tonic-gate 	const char *ap_id,
4477c478bd9Sstevel@tonic-gate 	const char *options,
4487c478bd9Sstevel@tonic-gate 	char **errstring)
4497c478bd9Sstevel@tonic-gate {
4507c478bd9Sstevel@tonic-gate 	if (errstring != NULL) {
4517c478bd9Sstevel@tonic-gate 		*errstring = NULL;
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (options != NULL) {
4557c478bd9Sstevel@tonic-gate 		DPRINTF("verify_params: hardware-specific options not "
4567c478bd9Sstevel@tonic-gate 		    "supported.\n");
4577c478bd9Sstevel@tonic-gate 		return (CFGA_USB_OPTIONS);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/* Dynamic attachment points not supported (yet). */
4617c478bd9Sstevel@tonic-gate 	if (GET_DYN(ap_id) != NULL) {
4627c478bd9Sstevel@tonic-gate 		DPRINTF("verify_params: dynamic ap_id passed\n");
4637c478bd9Sstevel@tonic-gate 		return (CFGA_USB_DYNAMIC_AP);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if (verify_valid_apid(ap_id) != 0) {
4677c478bd9Sstevel@tonic-gate 		DPRINTF("verify_params: not a USB ap_id.\n");
4687c478bd9Sstevel@tonic-gate 		return (CFGA_USB_AP);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	return (CFGA_USB_OK);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate /*
4767c478bd9Sstevel@tonic-gate  * Takes a validated ap_id and extracts the port number.
4777c478bd9Sstevel@tonic-gate  */
4787c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
4797c478bd9Sstevel@tonic-gate get_port_num(const char *ap_id, uint_t *port)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	char *port_nbr_str;
4827c478bd9Sstevel@tonic-gate 	char *temp;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	port_nbr_str = strrchr(ap_id, *MINOR_SEP) + strlen(MINOR_SEP);
4857c478bd9Sstevel@tonic-gate 	if ((temp = strrchr(ap_id, (int)*PORT_SEPERATOR)) != 0) {
4867c478bd9Sstevel@tonic-gate 		port_nbr_str = temp + strlen(PORT_SEPERATOR);
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	errno = 0;
4907c478bd9Sstevel@tonic-gate 	*port = strtol(port_nbr_str, NULL, 10);
4917c478bd9Sstevel@tonic-gate 	if (errno) {
4927c478bd9Sstevel@tonic-gate 		DPRINTF("get_port_num: conversion of port str failed\n");
4937c478bd9Sstevel@tonic-gate 		return (CFGA_USB_PORT);
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	return (CFGA_USB_OK);
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate  * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
5027c478bd9Sstevel@tonic-gate  */
5037c478bd9Sstevel@tonic-gate static void
5047c478bd9Sstevel@tonic-gate cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	if (user_nvlist != NULL) {
5077c478bd9Sstevel@tonic-gate 		nvlist_free(user_nvlist);
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 	if (devctl_hdl != NULL) {
5107c478bd9Sstevel@tonic-gate 		devctl_release(devctl_hdl);
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
5167c478bd9Sstevel@tonic-gate setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl,
5177c478bd9Sstevel@tonic-gate     nvlist_t **user_nvlistp, uint_t oflag)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	uint32_t	port;
5207c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t	rv = CFGA_USB_OK;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	DPRINTF("setup_for_devctl_cmd: oflag=%d\n", oflag);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/* Get a handle to the ap */
5257c478bd9Sstevel@tonic-gate 	if ((*devctl_hdl = devctl_ap_acquire((char *)ap_id, oflag)) == NULL) {
5267c478bd9Sstevel@tonic-gate 		DPRINTF("setup_for_devctl_cmd: devctl_ap_acquire failed with "
5277c478bd9Sstevel@tonic-gate 		    "errno: %d\n", errno);
5287c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_DEVCTL;
5297c478bd9Sstevel@tonic-gate 		goto bailout;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	/* Set up to pass port number down to driver */
5337c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) {
5347c478bd9Sstevel@tonic-gate 		DPRINTF("setup_for_devctl: nvlist_alloc failed, errno: %d\n",
5357c478bd9Sstevel@tonic-gate 		    errno);
5367c478bd9Sstevel@tonic-gate 		*user_nvlistp = NULL;	/* Prevent possible incorrect free in */
5377c478bd9Sstevel@tonic-gate 					/* cleanup_after_devctl_cmd */
5387c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_NVLIST;
5397c478bd9Sstevel@tonic-gate 		goto bailout;
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if ((rv = get_port_num(ap_id, &port)) != CFGA_USB_OK) {
5437c478bd9Sstevel@tonic-gate 		DPRINTF("setup_for_devctl_cmd: get_port_num, errno: %d\n",
5447c478bd9Sstevel@tonic-gate 		    errno);
5457c478bd9Sstevel@tonic-gate 		goto bailout;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	/* creates an int32_t entry */
5497c478bd9Sstevel@tonic-gate 	if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) {
5507c478bd9Sstevel@tonic-gate 		DPRINTF("setup_for_devctl_cmd: nvlist_add_int32 failed. "
5517c478bd9Sstevel@tonic-gate 		    "errno: %d\n", errno);
5527c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_NVLIST;
5537c478bd9Sstevel@tonic-gate 		goto bailout;
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	return (rv);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate bailout:
5597c478bd9Sstevel@tonic-gate 	cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	return (rv);
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate /*
5667c478bd9Sstevel@tonic-gate  * Ensure that there's a device actually connected to the ap
5677c478bd9Sstevel@tonic-gate  */
5687c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
5697c478bd9Sstevel@tonic-gate device_configured(devctl_hdl_t hdl, nvlist_t *nvl, ap_rstate_t *rstate)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t		rv;
5727c478bd9Sstevel@tonic-gate 	devctl_ap_state_t	devctl_ap_state;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	DPRINTF("device_configured:\n");
5757c478bd9Sstevel@tonic-gate 	if (devctl_ap_getstate(hdl, nvl, &devctl_ap_state) == -1) {
5767c478bd9Sstevel@tonic-gate 		DPRINTF("devctl_ap_getstate failed, errno: %d\n", errno);
5777c478bd9Sstevel@tonic-gate 		return (CFGA_USB_DEVCTL);
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	rv = CFGA_USB_ALREADY_CONFIGURED;
5817c478bd9Sstevel@tonic-gate 	*rstate = devctl_ap_state.ap_rstate;
5827c478bd9Sstevel@tonic-gate 	if (devctl_ap_state.ap_ostate != AP_OSTATE_CONFIGURED) {
5837c478bd9Sstevel@tonic-gate 		return (CFGA_USB_NOT_CONFIGURED);
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	return (rv);
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate  * Ensure that there's a device actually connected to the ap
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
5947c478bd9Sstevel@tonic-gate device_connected(devctl_hdl_t hdl, nvlist_t *list, ap_ostate_t *ostate)
5957c478bd9Sstevel@tonic-gate {
5967c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t		rv = CFGA_USB_ALREADY_CONNECTED;
5977c478bd9Sstevel@tonic-gate 	devctl_ap_state_t	devctl_ap_state;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	DPRINTF("device_connected:\n");
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
6027c478bd9Sstevel@tonic-gate 		DPRINTF("devctl_ap_getstate failed, errno: %d\n", errno);
6037c478bd9Sstevel@tonic-gate 		return (CFGA_USB_DEVCTL);
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	*ostate =  devctl_ap_state.ap_ostate;
6077c478bd9Sstevel@tonic-gate 	if (devctl_ap_state.ap_rstate != AP_RSTATE_CONNECTED) {
6087c478bd9Sstevel@tonic-gate 		return (CFGA_USB_NOT_CONNECTED);
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	return (rv);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate /*
6167c478bd9Sstevel@tonic-gate  * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
6177c478bd9Sstevel@tonic-gate  * the data to be returned, allocate a buffer, then get the data.
6187c478bd9Sstevel@tonic-gate  * Returns *descrp (which must be freed) and size.
6197c478bd9Sstevel@tonic-gate  *
6207c478bd9Sstevel@tonic-gate  * Note USB_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
6217c478bd9Sstevel@tonic-gate  * not a string descr.
6227c478bd9Sstevel@tonic-gate  */
6237c478bd9Sstevel@tonic-gate cfga_usb_ret_t
6247c478bd9Sstevel@tonic-gate do_control_ioctl(const char *ap_id, uint_t subcommand, uint_t arg,
625*cf252232SAndy Fiddaman     void **descrp, size_t *sizep)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	int			fd = -1;
6287c478bd9Sstevel@tonic-gate 	uint_t			port;
6297c478bd9Sstevel@tonic-gate 	uint32_t		local_size;
6307c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t		rv = CFGA_USB_OK;
6317c478bd9Sstevel@tonic-gate 	struct hubd_ioctl_data	ioctl_data;
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	assert(descrp != NULL);
6347c478bd9Sstevel@tonic-gate 	*descrp = NULL;
6357c478bd9Sstevel@tonic-gate 	assert(sizep != NULL);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if ((rv = get_port_num(ap_id, &port)) != CFGA_USB_OK) {
6387c478bd9Sstevel@tonic-gate 		goto bailout;
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	if ((fd = open(ap_id, O_RDONLY)) == -1) {
6427c478bd9Sstevel@tonic-gate 		DPRINTF("do_control_ioctl: open failed: errno:%d\n", errno);
6437c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_OPEN;
6447c478bd9Sstevel@tonic-gate 		if (errno == EBUSY) {
6457c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_BUSY;
6467c478bd9Sstevel@tonic-gate 		}
6477c478bd9Sstevel@tonic-gate 		goto bailout;
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	ioctl_data.cmd = subcommand;
6517c478bd9Sstevel@tonic-gate 	ioctl_data.port = port;
6527c478bd9Sstevel@tonic-gate 	ioctl_data.misc_arg = (uint_t)arg;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	/*
6557c478bd9Sstevel@tonic-gate 	 * Find out how large a buf we need to get the data.
6567c478bd9Sstevel@tonic-gate 	 *
6577c478bd9Sstevel@tonic-gate 	 * Note the ioctls only accept/return a 32-bit int for a get_size
6587c478bd9Sstevel@tonic-gate 	 * to avoid 32/64 and BE/LE issues.
6597c478bd9Sstevel@tonic-gate 	 */
6607c478bd9Sstevel@tonic-gate 	ioctl_data.get_size = B_TRUE;
6617c478bd9Sstevel@tonic-gate 	ioctl_data.buf = (caddr_t)&local_size;
6627c478bd9Sstevel@tonic-gate 	ioctl_data.bufsiz = sizeof (local_size);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
6657c478bd9Sstevel@tonic-gate 		DPRINTF("do_control_ioctl: size ioctl failed: errno:%d\n",
6667c478bd9Sstevel@tonic-gate 		    errno);
6677c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_IOCTL;
6687c478bd9Sstevel@tonic-gate 		goto bailout;
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 	*sizep = local_size;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if (subcommand == USB_DESCR_TYPE_STRING &&
6737c478bd9Sstevel@tonic-gate 	    arg == HUBD_CFG_DESCR_STR && local_size == 0) {
6747c478bd9Sstevel@tonic-gate 		/* Zero-length data - nothing to do.  */
6757c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_ZEROLEN;
6767c478bd9Sstevel@tonic-gate 		goto bailout;
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 	if (subcommand == HUBD_REFRESH_DEVDB) {
6797c478bd9Sstevel@tonic-gate 		/* Already done - no data transfer; nothing left to do. */
6807c478bd9Sstevel@tonic-gate 		goto bailout;
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	if ((*descrp = malloc(*sizep)) == NULL) {
6847c478bd9Sstevel@tonic-gate 		DPRINTF("do_control_ioctl: malloc failed\n");
6857c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_ALLOC_FAIL;
6867c478bd9Sstevel@tonic-gate 		goto bailout;
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	/* Get the data */
6907c478bd9Sstevel@tonic-gate 	ioctl_data.get_size = B_FALSE;
6917c478bd9Sstevel@tonic-gate 	ioctl_data.buf = *descrp;
6927c478bd9Sstevel@tonic-gate 	ioctl_data.bufsiz = *sizep;
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
6957c478bd9Sstevel@tonic-gate 		DPRINTF("do_control_ioctl: ioctl failed: errno:%d\n",
6967c478bd9Sstevel@tonic-gate 		    errno);
6977c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_IOCTL;
6987c478bd9Sstevel@tonic-gate 		goto bailout;
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	(void) close(fd);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	return (rv);
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate bailout:
7077c478bd9Sstevel@tonic-gate 	if (fd != -1) {
7087c478bd9Sstevel@tonic-gate 		(void) close(fd);
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 	if (*descrp != NULL) {
7117c478bd9Sstevel@tonic-gate 		free(*descrp);
7127c478bd9Sstevel@tonic-gate 		*descrp = NULL;
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	if (rv == CFGA_USB_IOCTL && errno == EBUSY) {
7167c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_BUSY;	/* Provide more useful msg */
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	return (rv);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /* ========================================================================= */
7247c478bd9Sstevel@tonic-gate /*
7257c478bd9Sstevel@tonic-gate  * Support funcs called directly from cfga_* entry points.
7267c478bd9Sstevel@tonic-gate  */
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate /*
7307c478bd9Sstevel@tonic-gate  * Invoked from cfga_private_func.
7317c478bd9Sstevel@tonic-gate  * Modify the USB persistant configuration file so that the device
7327c478bd9Sstevel@tonic-gate  * represented by ap_id will henceforth be initialized to the desired
7337c478bd9Sstevel@tonic-gate  * configuration setting (configuration index).
7347c478bd9Sstevel@tonic-gate  */
7357c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
7367c478bd9Sstevel@tonic-gate set_configuration(const char *ap_id, uint_t config, char *driver,
7377c478bd9Sstevel@tonic-gate     usb_dev_descr_t *descrp, char **errstring)
7387c478bd9Sstevel@tonic-gate {
7397c478bd9Sstevel@tonic-gate 	char		*serial_no = NULL;
7407c478bd9Sstevel@tonic-gate 	char		*dev_path = NULL;
7417c478bd9Sstevel@tonic-gate 	char		*tmp;
7427c478bd9Sstevel@tonic-gate 	size_t		size;
7437c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t	rv = CFGA_USB_OK;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	DPRINTF("set_configuration: ap_id: %s, config:%d\n", ap_id, config);
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	/* Only one bNumConfigurations, don't allow this operation */
7487c478bd9Sstevel@tonic-gate 	if (descrp->bNumConfigurations == 1) {
7497c478bd9Sstevel@tonic-gate 		DPRINTF("device supports %d configurations\n",
7507c478bd9Sstevel@tonic-gate 		    descrp->bNumConfigurations);
7517c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_ONE_CONFIG;
7527c478bd9Sstevel@tonic-gate 		goto bailout;
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	/* get the serial number string if it exists */
7567c478bd9Sstevel@tonic-gate 	if (descrp->iSerialNumber != 0) {
7577c478bd9Sstevel@tonic-gate 		if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
7587c478bd9Sstevel@tonic-gate 		    HUBD_SERIALNO_STR, (void **)&serial_no, &size)) !=
7597c478bd9Sstevel@tonic-gate 		    CFGA_USB_OK) {
7607c478bd9Sstevel@tonic-gate 			if (rv != CFGA_USB_ZEROLEN) {
7617c478bd9Sstevel@tonic-gate 				DPRINTF("set_configuration: get serial "
7627c478bd9Sstevel@tonic-gate 				    "no string failed\n");
7637c478bd9Sstevel@tonic-gate 				goto bailout;
7647c478bd9Sstevel@tonic-gate 			}
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	dev_path = usb_get_devicepath(ap_id);
7697c478bd9Sstevel@tonic-gate 	if (dev_path == NULL) {
7707c478bd9Sstevel@tonic-gate 		DPRINTF("get device path failed\n");
7717c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_DEVCTL;
7727c478bd9Sstevel@tonic-gate 		goto bailout;
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	DPRINTF("calling add_entry: vid: 0x%x pid:0x%x config:0x%x,",
7767c478bd9Sstevel@tonic-gate 	    descrp->idVendor, descrp->idProduct, config);
7777c478bd9Sstevel@tonic-gate 	DPRINTF("serial_no: %s\n\tdev_path: %s\n\tdriver: %s\n", serial_no ?
7787c478bd9Sstevel@tonic-gate 	    serial_no : "", dev_path ? dev_path : "", driver ? driver : "");
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	/*
7817c478bd9Sstevel@tonic-gate 	 * the devicepath should be an absolute path.
7827c478bd9Sstevel@tonic-gate 	 * So, if path has leading "/devices" - nuke it.
7837c478bd9Sstevel@tonic-gate 	 */
7847c478bd9Sstevel@tonic-gate 	if (strncmp(dev_path, "/devices/", 9) == 0) {
7857c478bd9Sstevel@tonic-gate 		tmp = dev_path + 8;
7867c478bd9Sstevel@tonic-gate 	} else {
7877c478bd9Sstevel@tonic-gate 		tmp = dev_path;
7887c478bd9Sstevel@tonic-gate 	}
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	/* Save an entry in the USBCONF_FILE  */
7917c478bd9Sstevel@tonic-gate 	if ((rv = add_entry(
7927c478bd9Sstevel@tonic-gate 	    "enable",		/* Always to "enable" */
7937c478bd9Sstevel@tonic-gate 	    descrp->idVendor,	/* vendorId */
7947c478bd9Sstevel@tonic-gate 	    descrp->idProduct,	/* ProductId */
7957c478bd9Sstevel@tonic-gate 	    config,		/* new cfgndx */
7967c478bd9Sstevel@tonic-gate 	    serial_no,		/* serial no string */
7977c478bd9Sstevel@tonic-gate 	    tmp,		/* device path */
7987c478bd9Sstevel@tonic-gate 	    driver,		/* Driver (optional) */
7997c478bd9Sstevel@tonic-gate 	    errstring))
8007c478bd9Sstevel@tonic-gate 	    != CFGA_USB_OK) {
8017c478bd9Sstevel@tonic-gate 		DPRINTF("set_configuration: add_entry failed\n");
8027c478bd9Sstevel@tonic-gate 		goto bailout;
8037c478bd9Sstevel@tonic-gate 	}
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	/* Notify hubd that it needs to refresh its db.  */
8067c478bd9Sstevel@tonic-gate 	if ((rv = do_control_ioctl(ap_id, HUBD_REFRESH_DEVDB, NULL,
8077c478bd9Sstevel@tonic-gate 	    (void **)&dev_path, &size)) != CFGA_USB_OK) {
8087c478bd9Sstevel@tonic-gate 		DPRINTF("set_configuration: HUBD_REFRESH_DEVDB failed\n");
8097c478bd9Sstevel@tonic-gate 		goto bailout;
8107c478bd9Sstevel@tonic-gate 	}
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate bailout:
8137c478bd9Sstevel@tonic-gate 	if (dev_path) {
8147c478bd9Sstevel@tonic-gate 		free(dev_path);
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 	if (serial_no) {
8177c478bd9Sstevel@tonic-gate 		free(serial_no);
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	return (rv);
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate /*
8257c478bd9Sstevel@tonic-gate  * Invoked from cfga_private_func() and fill_in_ap_info().
8267c478bd9Sstevel@tonic-gate  * Call into USBA and get the current configuration setting for this device,
8277c478bd9Sstevel@tonic-gate  */
8287c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
8297c478bd9Sstevel@tonic-gate get_config(const char *ap_id, uint_t *config)
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate 	size_t		size;
8327c478bd9Sstevel@tonic-gate 	uint_t		*config_val = NULL;
8337c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t	rv;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	if ((rv = do_control_ioctl(ap_id, HUBD_GET_CURRENT_CONFIG, NULL,
8367c478bd9Sstevel@tonic-gate 	    (void **)&config_val, &size)) != CFGA_USB_OK) {
8377c478bd9Sstevel@tonic-gate 		DPRINTF("get_config: get current config descr failed\n");
8387c478bd9Sstevel@tonic-gate 		goto bailout;
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 	*config = *config_val;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate bailout:
8437c478bd9Sstevel@tonic-gate 	free(config_val);
8447c478bd9Sstevel@tonic-gate 	return (rv);
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate /*
8497c478bd9Sstevel@tonic-gate  * Invoked from cfga_private_func.
8507c478bd9Sstevel@tonic-gate  * it does an unconfigure of the device followed by a configure,
8517c478bd9Sstevel@tonic-gate  * thus essentially resetting the device.
8527c478bd9Sstevel@tonic-gate  */
8537c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
8547c478bd9Sstevel@tonic-gate reset_device(devctl_hdl_t devctl_hdl, nvlist_t *nvl)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t	rv;
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	DPRINTF("reset_device: \n");
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/*
8617c478bd9Sstevel@tonic-gate 	 * Disconnect and reconfigure the device.
8627c478bd9Sstevel@tonic-gate 	 * Note this forces the new default config to take effect.
8637c478bd9Sstevel@tonic-gate 	 */
8647c478bd9Sstevel@tonic-gate 	if (devctl_ap_disconnect(devctl_hdl, nvl) != 0) {
8657c478bd9Sstevel@tonic-gate 		DPRINTF("devctl_ap_unconfigure failed, errno: %d\n", errno);
8667c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_DEVCTL;
8677c478bd9Sstevel@tonic-gate 		if (errno == EBUSY) {
8687c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_BUSY;	/* Provide more useful msg */
8697c478bd9Sstevel@tonic-gate 		}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 		return (rv);
8727c478bd9Sstevel@tonic-gate 	}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	if (devctl_ap_configure(devctl_hdl, nvl) != 0) {
8757c478bd9Sstevel@tonic-gate 		DPRINTF(" devctl_ap_configure failed, errno = %d\n", errno);
8767c478bd9Sstevel@tonic-gate 		return (CFGA_USB_DEVCTL);
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	return (CFGA_USB_OK);
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate /*
8847c478bd9Sstevel@tonic-gate  * Called from cfga_list_ext.
8857c478bd9Sstevel@tonic-gate  * Fills in the 'misc_info' field in the cfga buffer (displayed with -lv).
8867c478bd9Sstevel@tonic-gate  */
8877c478bd9Sstevel@tonic-gate static cfga_usb_ret_t
8887c478bd9Sstevel@tonic-gate fill_in_ap_info(const char *ap_id, char *info_buf, size_t info_size)
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	char			*mfg_str = NULL;	/* iManufacturer */
8917c478bd9Sstevel@tonic-gate 	char			*prod_str = NULL;	/* iProduct */
8927c478bd9Sstevel@tonic-gate 	char			*cfg_descr = NULL;	/* iConfiguration */
8937c478bd9Sstevel@tonic-gate 	uint_t			config;			/* curr cfg index */
8947c478bd9Sstevel@tonic-gate 	size_t			size;			/* tmp stuff */
8957c478bd9Sstevel@tonic-gate 	boolean_t		flag;		/* wether to print ":" or not */
8967c478bd9Sstevel@tonic-gate 	boolean_t		free_mfg_str = B_FALSE;
8977c478bd9Sstevel@tonic-gate 	boolean_t		free_prod_str = B_FALSE;
8987c478bd9Sstevel@tonic-gate 	boolean_t		free_cfg_str = B_FALSE;
8997c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t		rv = CFGA_USB_OK;
9007c478bd9Sstevel@tonic-gate 	usb_dev_descr_t		*dev_descrp = NULL;	/* device descriptor */
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	DPRINTF("fill_in_ap_info:\n");
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_DEV, NULL,
9057c478bd9Sstevel@tonic-gate 	    (void **)&dev_descrp, &size)) != CFGA_USB_OK) {
9067c478bd9Sstevel@tonic-gate 		DPRINTF("fill_in_ap_info: get dev descr failed\n");
9077c478bd9Sstevel@tonic-gate 		return (rv);
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	/* iManufacturer */
9117c478bd9Sstevel@tonic-gate 	mfg_str = USB_UNDEF_STR;
9127c478bd9Sstevel@tonic-gate 	if (dev_descrp->iManufacturer != 0) {
9137c478bd9Sstevel@tonic-gate 		if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
9147c478bd9Sstevel@tonic-gate 		    HUBD_MFG_STR, (void **)&mfg_str, &size)) != CFGA_USB_OK) {
9157c478bd9Sstevel@tonic-gate 			if (rv == CFGA_USB_ZEROLEN) {
9167c478bd9Sstevel@tonic-gate 				rv = CFGA_USB_OK;
9177c478bd9Sstevel@tonic-gate 			} else {
9187c478bd9Sstevel@tonic-gate 				DPRINTF("get iManufacturer failed\n");
9197c478bd9Sstevel@tonic-gate 				goto bailout;
9207c478bd9Sstevel@tonic-gate 			}
9217c478bd9Sstevel@tonic-gate 		}
9227c478bd9Sstevel@tonic-gate 		free_mfg_str = B_TRUE;
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	/* iProduct */
9267c478bd9Sstevel@tonic-gate 	prod_str = USB_UNDEF_STR;
9277c478bd9Sstevel@tonic-gate 	if (dev_descrp->iProduct != 0) {
9287c478bd9Sstevel@tonic-gate 		if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
9297c478bd9Sstevel@tonic-gate 		    HUBD_PRODUCT_STR, (void **)&prod_str,
9307c478bd9Sstevel@tonic-gate 		    &size)) != CFGA_USB_OK) {
9317c478bd9Sstevel@tonic-gate 			if (rv == CFGA_USB_ZEROLEN) {
9327c478bd9Sstevel@tonic-gate 				rv = CFGA_USB_OK;
9337c478bd9Sstevel@tonic-gate 			} else {
9347c478bd9Sstevel@tonic-gate 				DPRINTF("getting iProduct failed\n");
9357c478bd9Sstevel@tonic-gate 				goto bailout;
9367c478bd9Sstevel@tonic-gate 			}
9377c478bd9Sstevel@tonic-gate 		}
9387c478bd9Sstevel@tonic-gate 		free_prod_str = B_TRUE;
9397c478bd9Sstevel@tonic-gate 	}
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	/* Current conifguration */
9427c478bd9Sstevel@tonic-gate 	if ((rv = get_config(ap_id, &config)) != CFGA_USB_OK) {
9437c478bd9Sstevel@tonic-gate 		DPRINTF("get_config failed\n");
9447c478bd9Sstevel@tonic-gate 		goto bailout;
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	/* Configuration string descriptor */
9487c478bd9Sstevel@tonic-gate 	cfg_descr = USB_NO_CFG_STR;
9497c478bd9Sstevel@tonic-gate 	if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
9507c478bd9Sstevel@tonic-gate 	    HUBD_CFG_DESCR_STR, (void **)&cfg_descr, &size)) != CFGA_USB_OK) {
9517c478bd9Sstevel@tonic-gate 		if (rv == CFGA_USB_ZEROLEN) {
9527c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_OK;
9537c478bd9Sstevel@tonic-gate 			flag = B_TRUE;
9547c478bd9Sstevel@tonic-gate 		} else {
9557c478bd9Sstevel@tonic-gate 			DPRINTF("HUBD_CFG_DESCR_STR failed\n");
9567c478bd9Sstevel@tonic-gate 			goto bailout;
9577c478bd9Sstevel@tonic-gate 		}
9587c478bd9Sstevel@tonic-gate 	}
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	/* add ": " to output coz PSARC case says so */
9617c478bd9Sstevel@tonic-gate 	if ((cfg_descr != (char *)NULL) && rv != CFGA_USB_ZEROLEN) {
9627c478bd9Sstevel@tonic-gate 		flag = B_TRUE;
9637c478bd9Sstevel@tonic-gate 		free_cfg_str = B_TRUE;
9647c478bd9Sstevel@tonic-gate 	} else {
9657c478bd9Sstevel@tonic-gate 		flag = B_FALSE;
9667c478bd9Sstevel@tonic-gate 		cfg_descr = USB_NO_CFG_STR;
9677c478bd9Sstevel@tonic-gate 	}
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	/* Dump local buf into passed-in buf. */
9707c478bd9Sstevel@tonic-gate 	(void) snprintf(info_buf, info_size,
9717c478bd9Sstevel@tonic-gate 	    "Mfg: %s  Product: %s  NConfigs: %d  Config: %d  %s%s", mfg_str,
9727c478bd9Sstevel@tonic-gate 	    prod_str, dev_descrp->bNumConfigurations, config,
9737c478bd9Sstevel@tonic-gate 	    (flag == B_TRUE) ? ": " : "", cfg_descr);
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate bailout:
9767c478bd9Sstevel@tonic-gate 	if (dev_descrp) {
9777c478bd9Sstevel@tonic-gate 		free(dev_descrp);
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	if ((free_mfg_str == B_TRUE) && mfg_str) {
9817c478bd9Sstevel@tonic-gate 		free(mfg_str);
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	if ((free_prod_str == B_TRUE) && prod_str) {
9857c478bd9Sstevel@tonic-gate 		free(prod_str);
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	if ((free_cfg_str == B_TRUE) && cfg_descr) {
9897c478bd9Sstevel@tonic-gate 		free(cfg_descr);
9907c478bd9Sstevel@tonic-gate 	}
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	return (rv);
9937c478bd9Sstevel@tonic-gate }
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate /* ========================================================================== */
9977c478bd9Sstevel@tonic-gate /* Entry points */
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10017c478bd9Sstevel@tonic-gate cfga_err_t
10027c478bd9Sstevel@tonic-gate cfga_change_state(
10037c478bd9Sstevel@tonic-gate 	cfga_cmd_t state_change_cmd,
10047c478bd9Sstevel@tonic-gate 	const char *ap_id,
10057c478bd9Sstevel@tonic-gate 	const char *options,
10067c478bd9Sstevel@tonic-gate 	struct cfga_confirm *confp,
10077c478bd9Sstevel@tonic-gate 	struct cfga_msg *msgp,
10087c478bd9Sstevel@tonic-gate 	char **errstring,
10097c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
10107c478bd9Sstevel@tonic-gate {
10117c478bd9Sstevel@tonic-gate 	int		ret;
10127c478bd9Sstevel@tonic-gate 	int		len;
10137c478bd9Sstevel@tonic-gate 	char		*msg;
10147c478bd9Sstevel@tonic-gate 	char		*devpath;
10157c478bd9Sstevel@tonic-gate 	nvlist_t	*nvl = NULL;
10167c478bd9Sstevel@tonic-gate 	ap_rstate_t	rstate;
10177c478bd9Sstevel@tonic-gate 	ap_ostate_t	ostate;
10187c478bd9Sstevel@tonic-gate 	devctl_hdl_t	hdl = NULL;
10197c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t	rv = CFGA_USB_OK;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	DPRINTF("cfga_change_state:\n");
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 	if ((rv = verify_params(ap_id, options, errstring)) != CFGA_USB_OK) {
10247c478bd9Sstevel@tonic-gate 		(void) cfga_help(msgp, options, flags);
10257c478bd9Sstevel@tonic-gate 		goto bailout;
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	/*
10297c478bd9Sstevel@tonic-gate 	 * All subcommands which can change state of device require
10307c478bd9Sstevel@tonic-gate 	 * root privileges.
10317c478bd9Sstevel@tonic-gate 	 */
10327c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
10337c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_PRIV;
10347c478bd9Sstevel@tonic-gate 		goto bailout;
10357c478bd9Sstevel@tonic-gate 	}
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl, 0)) !=
10387c478bd9Sstevel@tonic-gate 	    CFGA_USB_OK) {
10397c478bd9Sstevel@tonic-gate 		goto bailout;
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	switch (state_change_cmd) {
10437c478bd9Sstevel@tonic-gate 	case CFGA_CMD_CONFIGURE:
10447c478bd9Sstevel@tonic-gate 		if ((rv = device_configured(hdl, nvl, &rstate)) !=
10457c478bd9Sstevel@tonic-gate 		    CFGA_USB_NOT_CONFIGURED) {
10467c478bd9Sstevel@tonic-gate 			goto bailout;
10477c478bd9Sstevel@tonic-gate 		}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 		if (rstate == AP_RSTATE_EMPTY) {
10507c478bd9Sstevel@tonic-gate 			goto bailout;
10517c478bd9Sstevel@tonic-gate 		}
10527c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_OK;	/* Other statuses don't matter */
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 		if (devctl_ap_configure(hdl, nvl) != 0) {
10557c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_change_state: devctl_ap_configure "
10567c478bd9Sstevel@tonic-gate 			    "failed.  errno: %d\n", errno);
10577c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_DEVCTL;
10587c478bd9Sstevel@tonic-gate 		}
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 		devpath = usb_get_devicepath(ap_id);
10617c478bd9Sstevel@tonic-gate 		if (devpath == NULL) {
10627c478bd9Sstevel@tonic-gate 			int i;
10637c478bd9Sstevel@tonic-gate 			/*
10647c478bd9Sstevel@tonic-gate 			 * try for some time as USB hotplug thread
10657c478bd9Sstevel@tonic-gate 			 * takes a while to create the path
10667c478bd9Sstevel@tonic-gate 			 * and then eventually give up
10677c478bd9Sstevel@tonic-gate 			 */
10687c478bd9Sstevel@tonic-gate 			for (i = 0; i < 12 && (devpath == NULL); i++) {
1069d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				(void) sleep(6);
10707c478bd9Sstevel@tonic-gate 				devpath = usb_get_devicepath(ap_id);
10717c478bd9Sstevel@tonic-gate 			}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 			if (devpath == NULL) {
10747c478bd9Sstevel@tonic-gate 				DPRINTF("cfga_change_state: get device "
10757c478bd9Sstevel@tonic-gate 				    "path failed i = %d\n", i);
10767c478bd9Sstevel@tonic-gate 				rv = CFGA_USB_DEVCTL;
10777c478bd9Sstevel@tonic-gate 				break;
10787c478bd9Sstevel@tonic-gate 			}
10797c478bd9Sstevel@tonic-gate 		}
10807c478bd9Sstevel@tonic-gate 		S_FREE(devpath);
10817c478bd9Sstevel@tonic-gate 		break;
10827c478bd9Sstevel@tonic-gate 	case CFGA_CMD_UNCONFIGURE:
10837c478bd9Sstevel@tonic-gate 		if ((rv = device_connected(hdl, nvl, &ostate)) !=
10847c478bd9Sstevel@tonic-gate 		    CFGA_USB_ALREADY_CONNECTED) {
10857c478bd9Sstevel@tonic-gate 			goto bailout;
10867c478bd9Sstevel@tonic-gate 		}
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 		/* check if it is already unconfigured */
10897c478bd9Sstevel@tonic-gate 		if ((rv = device_configured(hdl, nvl, &rstate)) ==
10907c478bd9Sstevel@tonic-gate 		    CFGA_USB_NOT_CONFIGURED) {
10917c478bd9Sstevel@tonic-gate 			goto bailout;
10927c478bd9Sstevel@tonic-gate 		}
10937c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_OK;	/* Other statuses don't matter */
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 		len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1096d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    strlen("Unconfigure") + strlen(ap_id);
10977c478bd9Sstevel@tonic-gate 		if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
10987c478bd9Sstevel@tonic-gate 			(void) snprintf(msg, len + 3, "Unconfigure %s%s\n%s",
10997c478bd9Sstevel@tonic-gate 			    USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
11007c478bd9Sstevel@tonic-gate 		}
11017c478bd9Sstevel@tonic-gate 		if (!usb_confirm(confp, msg)) {
11027c478bd9Sstevel@tonic-gate 			free(msg);
11037c478bd9Sstevel@tonic-gate 			cleanup_after_devctl_cmd(hdl, nvl);
11047c478bd9Sstevel@tonic-gate 			return (CFGA_NACK);
11057c478bd9Sstevel@tonic-gate 		}
11067c478bd9Sstevel@tonic-gate 		free(msg);
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 		devpath = usb_get_devicepath(ap_id);
11097c478bd9Sstevel@tonic-gate 		if (devpath == NULL) {
11107c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_change_state: get device path failed\n");
11117c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_DEVCTL;
11127c478bd9Sstevel@tonic-gate 			break;
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 		if ((rv = usb_rcm_offline(ap_id, errstring, devpath, flags)) !=
11167c478bd9Sstevel@tonic-gate 		    CFGA_USB_OK) {
11177c478bd9Sstevel@tonic-gate 			break;
11187c478bd9Sstevel@tonic-gate 		}
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 		ret = devctl_ap_unconfigure(hdl, nvl);
11217c478bd9Sstevel@tonic-gate 		if (ret != 0) {
11227c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_change_state: devctl_ap_unconfigure "
11237c478bd9Sstevel@tonic-gate 			    "failed with errno: %d\n", errno);
11247c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_DEVCTL;
11257c478bd9Sstevel@tonic-gate 			if (errno == EBUSY) {
11267c478bd9Sstevel@tonic-gate 				rv = CFGA_USB_BUSY;
11277c478bd9Sstevel@tonic-gate 			}
11287c478bd9Sstevel@tonic-gate 			(void) usb_rcm_online(ap_id, errstring, devpath, flags);
11297c478bd9Sstevel@tonic-gate 		} else {
11307c478bd9Sstevel@tonic-gate 			(void) usb_rcm_remove(ap_id, errstring, devpath, flags);
11317c478bd9Sstevel@tonic-gate 		}
11327c478bd9Sstevel@tonic-gate 		S_FREE(devpath);
11337c478bd9Sstevel@tonic-gate 		break;
11347c478bd9Sstevel@tonic-gate 	case CFGA_CMD_DISCONNECT:
11357c478bd9Sstevel@tonic-gate 		if ((rv = device_connected(hdl, nvl, &ostate)) !=
11367c478bd9Sstevel@tonic-gate 		    CFGA_USB_ALREADY_CONNECTED) {
11377c478bd9Sstevel@tonic-gate 			/*
11387c478bd9Sstevel@tonic-gate 			 * special case handling for
11397c478bd9Sstevel@tonic-gate 			 * SLM based cfgadm disconnects
11407c478bd9Sstevel@tonic-gate 			 */
11417c478bd9Sstevel@tonic-gate 			if (ostate == AP_OSTATE_UNCONFIGURED)
11427c478bd9Sstevel@tonic-gate 				goto bailout;
11437c478bd9Sstevel@tonic-gate 		}
11447c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_OK;	/* Other statuses don't matter */
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 		len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1147d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    strlen("Disconnect") + strlen(ap_id);
11487c478bd9Sstevel@tonic-gate 		if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
11497c478bd9Sstevel@tonic-gate 			(void) snprintf(msg, len + 3, "Disconnect %s%s\n%s",
11507c478bd9Sstevel@tonic-gate 			    USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
11517c478bd9Sstevel@tonic-gate 		}
11527c478bd9Sstevel@tonic-gate 		if (!usb_confirm(confp, msg)) {
11537c478bd9Sstevel@tonic-gate 			free(msg);
11547c478bd9Sstevel@tonic-gate 			cleanup_after_devctl_cmd(hdl, nvl);
11557c478bd9Sstevel@tonic-gate 			return (CFGA_NACK);
11567c478bd9Sstevel@tonic-gate 		}
11577c478bd9Sstevel@tonic-gate 		free(msg);
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 		devpath = usb_get_devicepath(ap_id);
11607c478bd9Sstevel@tonic-gate 		if (devpath == NULL) {
11617c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_change_state: get device path failed\n");
11627c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_DEVCTL;
11637c478bd9Sstevel@tonic-gate 			break;
11647c478bd9Sstevel@tonic-gate 		}
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 		/* only call rcm_offline iff the state was CONFIGURED */
11677c478bd9Sstevel@tonic-gate 		if (ostate == AP_OSTATE_CONFIGURED) {
11687c478bd9Sstevel@tonic-gate 			if ((rv = usb_rcm_offline(ap_id, errstring,
11697c478bd9Sstevel@tonic-gate 			    devpath, flags)) != CFGA_USB_OK) {
11707c478bd9Sstevel@tonic-gate 				break;
11717c478bd9Sstevel@tonic-gate 			}
11727c478bd9Sstevel@tonic-gate 		}
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 		ret = devctl_ap_disconnect(hdl, nvl);
11757c478bd9Sstevel@tonic-gate 		if (ret != 0) {
11767c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_change_state: devctl_ap_disconnect "
11777c478bd9Sstevel@tonic-gate 			    "failed with errno: %d\n", errno);
11787c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_DEVCTL;
11797c478bd9Sstevel@tonic-gate 			if (errno == EBUSY) {
11807c478bd9Sstevel@tonic-gate 				rv = CFGA_USB_BUSY;
11817c478bd9Sstevel@tonic-gate 			}
11827c478bd9Sstevel@tonic-gate 			if (ostate == AP_OSTATE_CONFIGURED) {
11837c478bd9Sstevel@tonic-gate 				(void) usb_rcm_online(ap_id, errstring,
11847c478bd9Sstevel@tonic-gate 				    devpath, flags);
11857c478bd9Sstevel@tonic-gate 			}
11867c478bd9Sstevel@tonic-gate 		} else {
11877c478bd9Sstevel@tonic-gate 			if (ostate == AP_OSTATE_CONFIGURED) {
11887c478bd9Sstevel@tonic-gate 				(void) usb_rcm_remove(ap_id, errstring,
11897c478bd9Sstevel@tonic-gate 				    devpath, flags);
11907c478bd9Sstevel@tonic-gate 			}
11917c478bd9Sstevel@tonic-gate 		}
11927c478bd9Sstevel@tonic-gate 		S_FREE(devpath);
11937c478bd9Sstevel@tonic-gate 		break;
11947c478bd9Sstevel@tonic-gate 	case CFGA_CMD_CONNECT:
11957c478bd9Sstevel@tonic-gate 	case CFGA_CMD_LOAD:
11967c478bd9Sstevel@tonic-gate 	case CFGA_CMD_UNLOAD:
11977c478bd9Sstevel@tonic-gate 		(void) cfga_help(msgp, options, flags);
11987c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_OPNOTSUPP;
11997c478bd9Sstevel@tonic-gate 		break;
12007c478bd9Sstevel@tonic-gate 	case CFGA_CMD_NONE:
12017c478bd9Sstevel@tonic-gate 	default:
12027c478bd9Sstevel@tonic-gate 		(void) cfga_help(msgp, options, flags);
12037c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_INTERNAL_ERROR;
12047c478bd9Sstevel@tonic-gate 	}
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate bailout:
12077c478bd9Sstevel@tonic-gate 	cleanup_after_devctl_cmd(hdl, nvl);
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	return (usb_err_msg(errstring, rv, ap_id, errno));
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12147c478bd9Sstevel@tonic-gate cfga_err_t
12157c478bd9Sstevel@tonic-gate cfga_private_func(
12167c478bd9Sstevel@tonic-gate 	const char *func,
12177c478bd9Sstevel@tonic-gate 	const char *ap_id,
12187c478bd9Sstevel@tonic-gate 	const char *options,
12197c478bd9Sstevel@tonic-gate 	struct cfga_confirm *confp,
12207c478bd9Sstevel@tonic-gate 	struct cfga_msg *msgp,
12217c478bd9Sstevel@tonic-gate 	char **errstring,
12227c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
12237c478bd9Sstevel@tonic-gate {
12247c478bd9Sstevel@tonic-gate 	int			len;
12257c478bd9Sstevel@tonic-gate 	char			*msg;
12267c478bd9Sstevel@tonic-gate 	nvlist_t		*list = NULL;
12277c478bd9Sstevel@tonic-gate 	ap_ostate_t		ostate;
1228*cf252232SAndy Fiddaman 	devctl_hdl_t		hdl = NULL;
12297c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t		rv;
12307c478bd9Sstevel@tonic-gate 	usb_dev_descr_t		*dev_descrp = NULL;
12317c478bd9Sstevel@tonic-gate 	char			*driver = NULL;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	DPRINTF("cfga_private_func:\n");
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_USB_OK) {
12367c478bd9Sstevel@tonic-gate 		(void) cfga_help(msgp, options, flags);
12377c478bd9Sstevel@tonic-gate 		return (usb_err_msg(errstring, rv, ap_id, errno));
12387c478bd9Sstevel@tonic-gate 	}
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	/*
12417c478bd9Sstevel@tonic-gate 	 * All subcommands which can change state of device require
12427c478bd9Sstevel@tonic-gate 	 * root privileges.
12437c478bd9Sstevel@tonic-gate 	 */
12447c478bd9Sstevel@tonic-gate 	if (geteuid() != 0) {
12457c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_PRIV;
12467c478bd9Sstevel@tonic-gate 		goto bailout;
12477c478bd9Sstevel@tonic-gate 	}
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	if (func == NULL) {
12507c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_INTERNAL_ERROR;
12517c478bd9Sstevel@tonic-gate 		goto bailout;
12527c478bd9Sstevel@tonic-gate 	}
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) !=
12557c478bd9Sstevel@tonic-gate 	    CFGA_USB_OK) {
12567c478bd9Sstevel@tonic-gate 		goto bailout;
12577c478bd9Sstevel@tonic-gate 	}
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	if ((rv = device_connected(hdl, list, &ostate)) !=
12607c478bd9Sstevel@tonic-gate 	    CFGA_USB_ALREADY_CONNECTED) {
12617c478bd9Sstevel@tonic-gate 		goto bailout;
12627c478bd9Sstevel@tonic-gate 	}
12637c478bd9Sstevel@tonic-gate 	rv = CFGA_USB_OK;
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	if (strcmp(func, RESET_DEVICE) == 0) {	/* usb_reset? */
12667c478bd9Sstevel@tonic-gate 		len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1267d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    strlen("Reset") + strlen(ap_id);
12687c478bd9Sstevel@tonic-gate 		if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
12697c478bd9Sstevel@tonic-gate 			(void) snprintf(msg, len + 3, "Reset %s%s\n%s",
12707c478bd9Sstevel@tonic-gate 			    USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
12717c478bd9Sstevel@tonic-gate 		} else {
12727c478bd9Sstevel@tonic-gate 			cleanup_after_devctl_cmd(hdl, list);
12737c478bd9Sstevel@tonic-gate 			return (CFGA_NACK);
12747c478bd9Sstevel@tonic-gate 		}
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 		if (!usb_confirm(confp, msg)) {
12777c478bd9Sstevel@tonic-gate 			cleanup_after_devctl_cmd(hdl, list);
12787c478bd9Sstevel@tonic-gate 			return (CFGA_NACK);
12797c478bd9Sstevel@tonic-gate 		}
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 		if ((rv = reset_device(hdl, list)) != CFGA_USB_OK) {
12827c478bd9Sstevel@tonic-gate 			goto bailout;
12837c478bd9Sstevel@tonic-gate 		}
12847c478bd9Sstevel@tonic-gate 	} else if (strncmp(func, USB_CONFIG, sizeof (USB_CONFIG)) == 0) {
12857c478bd9Sstevel@tonic-gate 		uint_t	config = 0;
12867c478bd9Sstevel@tonic-gate 		uint_t	actual_config;
12877c478bd9Sstevel@tonic-gate 		size_t	size;
12887c478bd9Sstevel@tonic-gate 		char	*subopts, *value;
12897c478bd9Sstevel@tonic-gate 		uint_t	cfg_opt_flag = B_FALSE;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 		/* these are the only valid options */
12927c478bd9Sstevel@tonic-gate 		char *cfg_opts[] = {
12937c478bd9Sstevel@tonic-gate 			"config",	/* 0 */
12947c478bd9Sstevel@tonic-gate 			"drv",		/* 1 */
12957c478bd9Sstevel@tonic-gate 			NULL
12967c478bd9Sstevel@tonic-gate 		};
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 		/* return error if no options are specified */
12997c478bd9Sstevel@tonic-gate 		subopts = (char *)options;
13007c478bd9Sstevel@tonic-gate 		if (subopts == (char *)NULL) {
13017c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_private_func: no options\n");
13027c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_OPNOTSUPP;
13037c478bd9Sstevel@tonic-gate 			(void) cfga_help(msgp, options, flags);
13047c478bd9Sstevel@tonic-gate 			goto bailout;
13057c478bd9Sstevel@tonic-gate 		}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 		/* parse options specified */
13087c478bd9Sstevel@tonic-gate 		while (*subopts != '\0') {
13097c478bd9Sstevel@tonic-gate 			switch (getsubopt(&subopts, cfg_opts, &value)) {
1310d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			case 0: /* config */
1311d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				if (value == NULL) {
1312d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					rv = CFGA_USB_OPNOTSUPP;
1313d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					(void) cfga_help(msgp,
1314d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					    options, flags);
1315d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					goto bailout;
1316d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				} else {
1317d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					errno = 0;
1318d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					config = strtol(value,
1319d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					    (char **)NULL, 10);
1320d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					if (errno) {
1321d29f5a71Szhigang lu - Sun Microsystems - Beijing China 						DPRINTF(
1322d29f5a71Szhigang lu - Sun Microsystems - Beijing China 						    "config conversion"
1323d29f5a71Szhigang lu - Sun Microsystems - Beijing China 						    "failed\n");
1324d29f5a71Szhigang lu - Sun Microsystems - Beijing China 						rv =
1325d29f5a71Szhigang lu - Sun Microsystems - Beijing China 						    CFGA_USB_CONFIG_INVAL;
13267c478bd9Sstevel@tonic-gate 						goto bailout;
13277c478bd9Sstevel@tonic-gate 					}
1328d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				}
1329d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				cfg_opt_flag = B_TRUE;
1330d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				break;
13317c478bd9Sstevel@tonic-gate 
1332d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			case 1: /* drv */
1333d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				if (value == NULL) {
13347c478bd9Sstevel@tonic-gate 					rv = CFGA_USB_OPNOTSUPP;
1335d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					(void) cfga_help(msgp,
1336d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					    options, flags);
13377c478bd9Sstevel@tonic-gate 					goto bailout;
1338d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				} else {
1339d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					S_FREE(driver);
1340d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					driver = strdup(value);
1341d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					if (driver == NULL) {
1342d29f5a71Szhigang lu - Sun Microsystems - Beijing China 						rv =
1343d29f5a71Szhigang lu - Sun Microsystems - Beijing China 						    CFGA_USB_INTERNAL_ERROR;
1344d29f5a71Szhigang lu - Sun Microsystems - Beijing China 						goto bailout;
1345d29f5a71Szhigang lu - Sun Microsystems - Beijing China 					}
1346d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				}
1347d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				break;
1348d29f5a71Szhigang lu - Sun Microsystems - Beijing China 
1349d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			default:
1350d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				rv = CFGA_USB_OPNOTSUPP;
1351d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				(void) cfga_help(msgp, options, flags);
1352d29f5a71Szhigang lu - Sun Microsystems - Beijing China 				goto bailout;
13537c478bd9Sstevel@tonic-gate 			}
13547c478bd9Sstevel@tonic-gate 		}
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 		/* config is mandatory */
13577c478bd9Sstevel@tonic-gate 		if (cfg_opt_flag != B_TRUE) {
13587c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_OPNOTSUPP;
13597c478bd9Sstevel@tonic-gate 			(void) cfga_help(msgp, options, flags);
13607c478bd9Sstevel@tonic-gate 			goto bailout;
13617c478bd9Sstevel@tonic-gate 		}
13627c478bd9Sstevel@tonic-gate 		DPRINTF("config = %x\n", config);
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 		len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1365d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    strlen("Setting") + strlen(ap_id) +
1366d29f5a71Szhigang lu - Sun Microsystems - Beijing China 		    strlen("to USB configuration");
13677c478bd9Sstevel@tonic-gate 		/* len + 8 to account for config, \n and white space */
13687c478bd9Sstevel@tonic-gate 		if ((msg = (char *)calloc(len + 8, 1)) != NULL) {
13697c478bd9Sstevel@tonic-gate 			(void) snprintf(msg, len + 8,
13707c478bd9Sstevel@tonic-gate 			    "Setting %s%s\nto USB configuration %d\n%s",
13717c478bd9Sstevel@tonic-gate 			    USB_CONFIRM_0, ap_id, config, USB_CONFIRM_1);
13727c478bd9Sstevel@tonic-gate 		} else {
13737c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_INTERNAL_ERROR;
13747c478bd9Sstevel@tonic-gate 			goto bailout;
13757c478bd9Sstevel@tonic-gate 		}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 		if (!usb_confirm(confp, msg)) {
13787c478bd9Sstevel@tonic-gate 			S_FREE(driver);
13797c478bd9Sstevel@tonic-gate 			cleanup_after_devctl_cmd(hdl, list);
13807c478bd9Sstevel@tonic-gate 			return (CFGA_NACK);
13817c478bd9Sstevel@tonic-gate 		}
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 		/*
13847c478bd9Sstevel@tonic-gate 		 * Check that the option setting selected is in range.
13857c478bd9Sstevel@tonic-gate 		 */
13867c478bd9Sstevel@tonic-gate 		if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_DEV, NULL,
13877c478bd9Sstevel@tonic-gate 		    (void **)&dev_descrp, &size)) != CFGA_USB_OK) {
13887c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_private_func: get dev descr failed\n");
13897c478bd9Sstevel@tonic-gate 			goto bailout;
13907c478bd9Sstevel@tonic-gate 		}
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 		if (config > dev_descrp->bNumConfigurations - 1) {
13937c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_private_func: config index requested "
13947c478bd9Sstevel@tonic-gate 			    "(%d) exceeds bNumConfigurations - 1 (%d)\n",
13957c478bd9Sstevel@tonic-gate 			    config, dev_descrp->bNumConfigurations - 1);
13967c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_CONFIG_INVAL;
13977c478bd9Sstevel@tonic-gate 			goto bailout;
13987c478bd9Sstevel@tonic-gate 		}
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 		/* Pass current setting to set_configuration */
14017c478bd9Sstevel@tonic-gate 		if ((rv = get_config(ap_id, &actual_config)) != CFGA_USB_OK) {
14027c478bd9Sstevel@tonic-gate 			goto bailout;
14037c478bd9Sstevel@tonic-gate 		}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		/* check if they match - yes, then nothing to do */
14067c478bd9Sstevel@tonic-gate 		if (actual_config == config) {
14077c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_private_func: config index requested "
14087c478bd9Sstevel@tonic-gate 			    "(%d)  matches the actual config value %d\n",
14097c478bd9Sstevel@tonic-gate 			    config, actual_config);
14107c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_OK;
14117c478bd9Sstevel@tonic-gate 			goto bailout;
14127c478bd9Sstevel@tonic-gate 		}
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 		/* Save the configuration settings  */
14157c478bd9Sstevel@tonic-gate 		if ((rv = set_configuration(ap_id, config, driver,
14167c478bd9Sstevel@tonic-gate 		    dev_descrp, errstring)) != CFGA_USB_OK) {
14177c478bd9Sstevel@tonic-gate 			goto bailout;
14187c478bd9Sstevel@tonic-gate 		}
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 		/* Reset device to force new config to take effect */
14217c478bd9Sstevel@tonic-gate 		if ((rv = reset_device(hdl, list)) != CFGA_USB_OK) {
14227c478bd9Sstevel@tonic-gate 			goto bailout;
14237c478bd9Sstevel@tonic-gate 		}
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	} else {
14267c478bd9Sstevel@tonic-gate 		DPRINTF("cfga_private_func: unrecognized command.\n");
14277c478bd9Sstevel@tonic-gate 		(void) cfga_help(msgp, options, flags);
14287c478bd9Sstevel@tonic-gate 		errno = EINVAL;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 		return (CFGA_INVAL);
14317c478bd9Sstevel@tonic-gate 	}
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate bailout:
14347c478bd9Sstevel@tonic-gate 	S_FREE(dev_descrp);
14357c478bd9Sstevel@tonic-gate 	S_FREE(driver);
14367c478bd9Sstevel@tonic-gate 	cleanup_after_devctl_cmd(hdl, list);
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 	return (usb_err_msg(errstring, rv, ap_id, errno));
14397c478bd9Sstevel@tonic-gate }
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14437c478bd9Sstevel@tonic-gate cfga_err_t
14447c478bd9Sstevel@tonic-gate cfga_test(
14457c478bd9Sstevel@tonic-gate 	const char *ap_id,
14467c478bd9Sstevel@tonic-gate 	const char *options,
14477c478bd9Sstevel@tonic-gate 	struct cfga_msg *msgp,
14487c478bd9Sstevel@tonic-gate 	char **errstring,
14497c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
14507c478bd9Sstevel@tonic-gate {
14517c478bd9Sstevel@tonic-gate 	(void) cfga_help(msgp, options, flags);
14527c478bd9Sstevel@tonic-gate 	return (CFGA_OPNOTSUPP);
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14577c478bd9Sstevel@tonic-gate cfga_err_t
14587c478bd9Sstevel@tonic-gate cfga_list_ext(
14597c478bd9Sstevel@tonic-gate 	const char *ap_id,
14607c478bd9Sstevel@tonic-gate 	cfga_list_data_t **ap_id_list,
14617c478bd9Sstevel@tonic-gate 	int *nlistp,
14627c478bd9Sstevel@tonic-gate 	const char *options,
14637c478bd9Sstevel@tonic-gate 	const char *listopts,
14647c478bd9Sstevel@tonic-gate 	char **errstring,
14657c478bd9Sstevel@tonic-gate 	cfga_flags_t flags)
14667c478bd9Sstevel@tonic-gate {
14677c478bd9Sstevel@tonic-gate 	int			l_errno;
14687c478bd9Sstevel@tonic-gate 	char			*ap_id_log = NULL;
14697c478bd9Sstevel@tonic-gate 	size_t			size;
14707c478bd9Sstevel@tonic-gate 	nvlist_t		*user_nvlist = NULL;
14717c478bd9Sstevel@tonic-gate 	devctl_hdl_t		devctl_hdl = NULL;
14727c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t		rv = CFGA_USB_OK;
14737c478bd9Sstevel@tonic-gate 	devctl_ap_state_t	devctl_ap_state;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	DPRINTF("cfga_list_ext:\n");
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	if ((rv = verify_params(ap_id, options, errstring)) != CFGA_USB_OK) {
14787c478bd9Sstevel@tonic-gate 		goto bailout;
14797c478bd9Sstevel@tonic-gate 	}
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	if (ap_id_list == NULL || nlistp == NULL) {
14827c478bd9Sstevel@tonic-gate 		DPRINTF("cfga_list_ext: list = NULL or nlistp = NULL\n");
14837c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_INTERNAL_ERROR;
14847c478bd9Sstevel@tonic-gate 		goto bailout;
14857c478bd9Sstevel@tonic-gate 	}
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 	/* Get ap status */
14887c478bd9Sstevel@tonic-gate 	if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
14897c478bd9Sstevel@tonic-gate 	    DC_RDONLY)) != CFGA_USB_OK) {
14907c478bd9Sstevel@tonic-gate 		goto bailout;
14917c478bd9Sstevel@tonic-gate 	}
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	if (devctl_ap_getstate(devctl_hdl, user_nvlist, &devctl_ap_state) ==
14947c478bd9Sstevel@tonic-gate 	    -1) {
14957c478bd9Sstevel@tonic-gate 		DPRINTF("cfga_list_ext: devctl_ap_getstate failed. errno: %d\n",
14967c478bd9Sstevel@tonic-gate 		    errno);
14977c478bd9Sstevel@tonic-gate 		cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
14987c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_DEVCTL;
14997c478bd9Sstevel@tonic-gate 		goto bailout;
15007c478bd9Sstevel@tonic-gate 	}
15017c478bd9Sstevel@tonic-gate 	cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	/*
15047c478bd9Sstevel@tonic-gate 	 * Create cfga_list_data_t struct.
15057c478bd9Sstevel@tonic-gate 	 */
15067c478bd9Sstevel@tonic-gate 	if ((*ap_id_list =
15077c478bd9Sstevel@tonic-gate 	    (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
15087c478bd9Sstevel@tonic-gate 		DPRINTF("cfga_list_ext: malloc for cfga_list_data_t failed. "
15097c478bd9Sstevel@tonic-gate 		    "errno: %d\n", errno);
15107c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_ALLOC_FAIL;
15117c478bd9Sstevel@tonic-gate 		goto bailout;
15127c478bd9Sstevel@tonic-gate 	}
15137c478bd9Sstevel@tonic-gate 	*nlistp = 1;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 	/*
15177c478bd9Sstevel@tonic-gate 	 * Rest of the code fills in the cfga_list_data_t struct.
15187c478bd9Sstevel@tonic-gate 	 */
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	/* Get /dev/cfg path to corresponding to the physical ap_id */
15217c478bd9Sstevel@tonic-gate 	/* Remember ap_id_log must be freed */
15227c478bd9Sstevel@tonic-gate 	rv = (cfga_usb_ret_t)physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
15237c478bd9Sstevel@tonic-gate 	    &ap_id_log, &l_errno, MATCH_MINOR_NAME);
15247c478bd9Sstevel@tonic-gate 	if (rv != 0) {
15257c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_DEVLINK;
15267c478bd9Sstevel@tonic-gate 		goto bailout;
15277c478bd9Sstevel@tonic-gate 	}
15287c478bd9Sstevel@tonic-gate 	assert(ap_id_log != NULL);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	/* Get logical ap-id corresponding to the physical */
15317c478bd9Sstevel@tonic-gate 	if (strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
15327c478bd9Sstevel@tonic-gate 		DPRINTF("cfga_list_ext: devlink doesn't contain /dev/cfg\n");
15337c478bd9Sstevel@tonic-gate 		rv = CFGA_USB_DEVLINK;
15347c478bd9Sstevel@tonic-gate 		goto bailout;
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 	(void) strlcpy((*ap_id_list)->ap_log_id,
15377c478bd9Sstevel@tonic-gate 	    /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
15387c478bd9Sstevel@tonic-gate 	    sizeof ((*ap_id_list)->ap_log_id));
15397c478bd9Sstevel@tonic-gate 	free(ap_id_log);
15407c478bd9Sstevel@tonic-gate 	ap_id_log = NULL;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	(void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
15437c478bd9Sstevel@tonic-gate 	    sizeof ((*ap_id_list)->ap_phys_id));
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	switch (devctl_ap_state.ap_rstate) {
15467c478bd9Sstevel@tonic-gate 		case AP_RSTATE_EMPTY:
15477c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
15487c478bd9Sstevel@tonic-gate 			break;
15497c478bd9Sstevel@tonic-gate 		case AP_RSTATE_DISCONNECTED:
15507c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
15517c478bd9Sstevel@tonic-gate 			break;
15527c478bd9Sstevel@tonic-gate 		case AP_RSTATE_CONNECTED:
15537c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
15547c478bd9Sstevel@tonic-gate 			break;
15557c478bd9Sstevel@tonic-gate 		default:
15567c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_STATE;
15577c478bd9Sstevel@tonic-gate 			goto bailout;
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	switch (devctl_ap_state.ap_ostate) {
15617c478bd9Sstevel@tonic-gate 		case AP_OSTATE_CONFIGURED:
15627c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
15637c478bd9Sstevel@tonic-gate 			break;
15647c478bd9Sstevel@tonic-gate 		case AP_OSTATE_UNCONFIGURED:
15657c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
15667c478bd9Sstevel@tonic-gate 			break;
15677c478bd9Sstevel@tonic-gate 		default:
15687c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_STATE;
15697c478bd9Sstevel@tonic-gate 			goto bailout;
15707c478bd9Sstevel@tonic-gate 	}
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	switch (devctl_ap_state.ap_condition) {
15737c478bd9Sstevel@tonic-gate 		case AP_COND_OK:
15747c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_cond = CFGA_COND_OK;
15757c478bd9Sstevel@tonic-gate 			break;
15767c478bd9Sstevel@tonic-gate 		case AP_COND_FAILING:
15777c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_cond = CFGA_COND_FAILING;
15787c478bd9Sstevel@tonic-gate 			break;
15797c478bd9Sstevel@tonic-gate 		case AP_COND_FAILED:
15807c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_cond = CFGA_COND_FAILED;
15817c478bd9Sstevel@tonic-gate 			break;
15827c478bd9Sstevel@tonic-gate 		case AP_COND_UNUSABLE:
15837c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
15847c478bd9Sstevel@tonic-gate 			break;
15857c478bd9Sstevel@tonic-gate 		case AP_COND_UNKNOWN:
15867c478bd9Sstevel@tonic-gate 			(*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
15877c478bd9Sstevel@tonic-gate 			break;
15887c478bd9Sstevel@tonic-gate 		default:
15897c478bd9Sstevel@tonic-gate 			rv = CFGA_USB_STATE;
15907c478bd9Sstevel@tonic-gate 			goto bailout;
15917c478bd9Sstevel@tonic-gate 	}
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	(*ap_id_list)->ap_class[0] = '\0';	/* Filled by libcfgadm */
15947c478bd9Sstevel@tonic-gate 	(*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
15957c478bd9Sstevel@tonic-gate 	(*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
15967c478bd9Sstevel@tonic-gate 	(*ap_id_list)->ap_info[0] = NULL;
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
15997c478bd9Sstevel@tonic-gate 		char *str_p;
16007c478bd9Sstevel@tonic-gate 		size_t	str_len;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 		/* Fill in the info for the -v option display.  */
16037c478bd9Sstevel@tonic-gate 		if ((rv = fill_in_ap_info(ap_id, (*ap_id_list)->ap_info,
16047c478bd9Sstevel@tonic-gate 		    sizeof ((*ap_id_list)->ap_info))) != CFGA_USB_OK) {
16057c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_list_ext: fill_in_ap_info failed\n");
16067c478bd9Sstevel@tonic-gate 			goto bailout;
16077c478bd9Sstevel@tonic-gate 		}
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 		/* Fill in ap_type */
16107c478bd9Sstevel@tonic-gate 		if ((rv = do_control_ioctl(ap_id, HUBD_GET_CFGADM_NAME, NULL,
16117c478bd9Sstevel@tonic-gate 		    (void **)&str_p, &size)) != CFGA_USB_OK) {
16127c478bd9Sstevel@tonic-gate 			DPRINTF("cfga_list_ext: do_control_ioctl failed\n");
16137c478bd9Sstevel@tonic-gate 			goto bailout;
16147c478bd9Sstevel@tonic-gate 		}
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 		(void) strcpy((*ap_id_list)->ap_type, "usb-");
16177c478bd9Sstevel@tonic-gate 		str_len = strlen((*ap_id_list)->ap_type);
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 		/*
16207c478bd9Sstevel@tonic-gate 		 * NOTE: In the cfgadm display the "Type" column is only 12
16217c478bd9Sstevel@tonic-gate 		 * chars long. Most USB devices can be displayed here with a
16227c478bd9Sstevel@tonic-gate 		 * "usb-" prefix. Only USB keyboard cannot be displayed in
16237c478bd9Sstevel@tonic-gate 		 * its entirety as "usb-keybaord" is 13 chars in length.
16247c478bd9Sstevel@tonic-gate 		 * It will show up as "usb-kbd".
16257c478bd9Sstevel@tonic-gate 		 */
16267c478bd9Sstevel@tonic-gate 		if (strncasecmp(str_p, "keyboard", 8) != 0) {
16277c478bd9Sstevel@tonic-gate 			(void) strlcpy((*ap_id_list)->ap_type + str_len, str_p,
16287c478bd9Sstevel@tonic-gate 			    sizeof ((*ap_id_list)->ap_type) - str_len);
16297c478bd9Sstevel@tonic-gate 		} else {
16307c478bd9Sstevel@tonic-gate 			(void) strlcpy((*ap_id_list)->ap_type + str_len, "kbd",
16317c478bd9Sstevel@tonic-gate 			    sizeof ((*ap_id_list)->ap_type) - str_len);
16327c478bd9Sstevel@tonic-gate 		}
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 		free(str_p);
16357c478bd9Sstevel@tonic-gate 	} else {
16367c478bd9Sstevel@tonic-gate 		(void) strcpy((*ap_id_list)->ap_type,
16377c478bd9Sstevel@tonic-gate 		    USB_CFGADM_DEFAULT_AP_TYPE);
16387c478bd9Sstevel@tonic-gate 	}
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	return (usb_err_msg(errstring, rv, ap_id, errno));
16417c478bd9Sstevel@tonic-gate bailout:
16427c478bd9Sstevel@tonic-gate 	if (*ap_id_list != NULL) {
16437c478bd9Sstevel@tonic-gate 		free(*ap_id_list);
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate 	if (ap_id_log != NULL) {
16467c478bd9Sstevel@tonic-gate 		free(ap_id_log);
16477c478bd9Sstevel@tonic-gate 	}
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	return (usb_err_msg(errstring, rv, ap_id, errno));
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate /*
16547c478bd9Sstevel@tonic-gate  * This routine accepts a variable number of message IDs and constructs
16557c478bd9Sstevel@tonic-gate  * a corresponding error string which is printed via the message print routine
16567c478bd9Sstevel@tonic-gate  * argument.
16577c478bd9Sstevel@tonic-gate  */
16587c478bd9Sstevel@tonic-gate static void
16597c478bd9Sstevel@tonic-gate cfga_msg(struct cfga_msg *msgp, const char *str)
16607c478bd9Sstevel@tonic-gate {
16617c478bd9Sstevel@tonic-gate 	int len;
16627c478bd9Sstevel@tonic-gate 	char *q;
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate 	if (msgp == NULL || msgp->message_routine == NULL) {
16657c478bd9Sstevel@tonic-gate 		DPRINTF("cfga_msg: msg\n");
16667c478bd9Sstevel@tonic-gate 		return;
16677c478bd9Sstevel@tonic-gate 	}
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	if ((len = strlen(str)) == 0) {
16707c478bd9Sstevel@tonic-gate 		DPRINTF("cfga_msg: null str\n");
16717c478bd9Sstevel@tonic-gate 		return;
16727c478bd9Sstevel@tonic-gate 	}
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	if ((q = (char *)calloc(len + 1, 1)) == NULL) {
16757c478bd9Sstevel@tonic-gate 		DPRINTF("cfga_msg: null q\n");
16767c478bd9Sstevel@tonic-gate 		return;
16777c478bd9Sstevel@tonic-gate 	}
16787c478bd9Sstevel@tonic-gate 
1679d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	(void) strcpy(q, str);
16807c478bd9Sstevel@tonic-gate 	(*msgp->message_routine)(msgp->appdata_ptr, q);
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	free(q);
16837c478bd9Sstevel@tonic-gate }
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate /* ARGSUSED */
16877c478bd9Sstevel@tonic-gate cfga_err_t
16887c478bd9Sstevel@tonic-gate cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
16897c478bd9Sstevel@tonic-gate {
16907c478bd9Sstevel@tonic-gate 	DPRINTF("cfga_help:\n");
16917c478bd9Sstevel@tonic-gate 	if (options) {
16927c478bd9Sstevel@tonic-gate 		cfga_msg(msgp, dgettext(TEXT_DOMAIN, usb_help[HELP_UNKNOWN]));
16937c478bd9Sstevel@tonic-gate 		cfga_msg(msgp, options);
16947c478bd9Sstevel@tonic-gate 	}
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 	cfga_msg(msgp, dgettext(TEXT_DOMAIN, usb_help[HELP_HEADER]));
16977c478bd9Sstevel@tonic-gate 	cfga_msg(msgp, usb_help[HELP_CONFIG]);
16987c478bd9Sstevel@tonic-gate 	cfga_msg(msgp, usb_help[HELP_RESET_SLOT]);
16997c478bd9Sstevel@tonic-gate 	cfga_msg(msgp, usb_help[HELP_CONFIG_SLOT]);
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	return (CFGA_OK);
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate static int
17067c478bd9Sstevel@tonic-gate usb_confirm(struct cfga_confirm *confp, char *msg)
17077c478bd9Sstevel@tonic-gate {
17087c478bd9Sstevel@tonic-gate 	int rval;
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	if (confp == NULL || confp->confirm == NULL) {
17117c478bd9Sstevel@tonic-gate 		return (0);
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	rval = (*confp->confirm)(confp->appdata_ptr, msg);
17157c478bd9Sstevel@tonic-gate 	DPRINTF("usb_confirm: %d\n", rval);
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 	return (rval);
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate static char *
17227c478bd9Sstevel@tonic-gate usb_get_devicepath(const char *ap_id)
17237c478bd9Sstevel@tonic-gate {
17247c478bd9Sstevel@tonic-gate 	char		*devpath = NULL;
17257c478bd9Sstevel@tonic-gate 	size_t		size;
17267c478bd9Sstevel@tonic-gate 	cfga_usb_ret_t	rv;
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	rv = do_control_ioctl(ap_id, HUBD_GET_DEVICE_PATH, NULL,
17297c478bd9Sstevel@tonic-gate 	    (void **)&devpath, &size);
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	if (rv == CFGA_USB_OK) {
17327c478bd9Sstevel@tonic-gate 		DPRINTF("usb_get_devicepath: get device path ioctl ok\n");
17337c478bd9Sstevel@tonic-gate 		return (devpath);
17347c478bd9Sstevel@tonic-gate 	} else {
17357c478bd9Sstevel@tonic-gate 		DPRINTF("usb_get_devicepath: get device path ioctl failed\n");
17367c478bd9Sstevel@tonic-gate 		return ((char *)NULL);
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate }
1739