Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / lib / cfgadm_plugins / usb / common / cfga_usb.c
blobc874e8784c44677acadc5b18c873614cce02977b
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28 #include "cfga_usb.h"
31 /* function prototypes */
32 cfga_err_t usb_err_msg(char **, cfga_usb_ret_t, const char *, int);
33 extern cfga_usb_ret_t usb_rcm_offline(const char *, char **, char *,
34 cfga_flags_t);
35 extern cfga_usb_ret_t usb_rcm_online(const char *, char **, char *,
36 cfga_flags_t);
37 extern cfga_usb_ret_t usb_rcm_remove(const char *, char **, char *,
38 cfga_flags_t);
39 static int usb_confirm(struct cfga_confirm *, char *);
40 static char *usb_get_devicepath(const char *);
43 * This file contains the entry points to the plugin as defined in the
44 * config_admin(3X) man page.
48 * Set the version number for the cfgadm library's use.
50 int cfga_version = CFGA_HSL_V2;
52 #define HELP_HEADER 1
53 #define HELP_CONFIG 2
54 #define HELP_RESET_SLOT 3
55 #define HELP_CONFIG_SLOT 4
56 #define HELP_UNKNOWN 5
58 /* Help messages */
59 static char *
60 usb_help[] = {
61 NULL,
62 "USB specific commands:\n",
63 " cfgadm -c [configure|unconfigure|disconnect] ap_id [ap_id...]\n",
64 " cfgadm -x usb_reset ap_id [ap_id...]\n",
65 " cfgadm -x usb_config -o config=<index of desired configuration> ap_id\n",
66 "\tunknown command or option: ",
67 NULL
68 }; /* End help messages */
70 /* Error messages */
71 static msgcvt_t
72 usb_error_msgs[] = {
73 /* CFGA_USB_OK */
74 { CVT, CFGA_OK, "ok" },
76 /* CFGA_USB_UNKNOWN */
77 { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
79 /* CFGA_USB_INTERNAL_ERROR */
80 { CVT, CFGA_LIB_ERROR, "Internal error" },
82 /* CFGA_USB_OPTIONS */
83 { CVT, CFGA_ERROR, "Hardware specific options not supported" },
85 /* CFGA_USB_DYNAMIC_AP */
86 { CVT, CFGA_INVAL, "Dynamic attachment points not supported" },
88 /* CFGA_USB_AP */
89 { CVT, CFGA_APID_NOEXIST, "" },
91 /* CFGA_USB_PORT */
92 { CVT, CFGA_LIB_ERROR, "Cannot determine hub port number for " },
94 /* CFGA_USB_DEVCTL */
95 { CVT, CFGA_ERROR, "Cannot issue devctl to " },
97 /* CFGA_USB_NOT_CONNECTED */
98 { CVT, CFGA_INVAL, "No device connected to " },
100 /* CFGA_USB_NOT_CONFIGURED */
101 { CVT, CFGA_INVAL, "No device configured to " },
103 /* CFGA_USB_ALREADY_CONNECTED */
104 { CVT, CFGA_INSUFFICENT_CONDITION,
105 "Device already connected; cannot connect again " },
107 /* CFGA_USB_ALREADY_CONFIGURED */
108 { CVT, CFGA_INVAL, "device already configured for " },
110 /* CFGA_USB_OPEN */
111 { CVT, CFGA_LIB_ERROR, "Cannot open " },
113 /* CFGA_USB_IOCTL */
114 { CVT, CFGA_ERROR, "Driver ioctl failed " },
116 /* CFGA_USB_BUSY */
117 { CVT, CFGA_SYSTEM_BUSY, "" },
119 /* CFGA_USB_ALLOC_FAIL */
120 { CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
122 /* CFGA_USB_OPNOTSUPP */
123 { CVT, CFGA_OPNOTSUPP, "Operation not supported" },
125 /* CFGA_USB_DEVLINK */
126 { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
128 /* CFGA_USB_STATE */
129 { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
131 /* CFGA_USB_CONFIG_INVAL */
132 { CVT, CFGA_ERROR,
133 "Specified configuration index unrecognized or exceeds "
134 "maximum available" },
136 /* CFGA_USB_PRIV */
137 { CVT, CFGA_PRIV, "" },
139 /* CFGA_USB_NVLIST */
140 { CVT, CFGA_ERROR, "Internal error (nvlist)" },
142 /* CFGA_USB_ZEROLEN */
143 { CVT, CFGA_ERROR, "Internal error (zerolength string)" },
145 /* CFGA_USB_CONFIG_FILE */
146 { CVT, CFGA_ERROR,
147 "Cannot open/fstat/read USB system configuration file" },
149 /* CFGA_USB_LOCK_FILE */
150 { CVT, CFGA_ERROR, "Cannot lock USB system configuration file" },
152 /* CFGA_USB_UNLOCK_FILE */
153 { CVT, CFGA_ERROR, "Cannot unlock USB system configuration file" },
155 /* CFGA_USB_ONE_CONFIG */
156 { CVT, CFGA_ERROR,
157 "Operation not supported for devices with one configuration" },
159 /* CFGA_USB_RCM_HANDLE Errors */
160 { CVT, CFGA_ERROR, "cannot get RCM handle"},
162 /* CFGA_USB_RCM_ONLINE */
163 { CVT, CFGA_SYSTEM_BUSY, "failed to online: "},
165 /* CFGA_USB_RCM_OFFLINE */
166 { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "},
168 /* CFGA_USB_RCM_INFO */
169 { CVT, CFGA_ERROR, "failed to query: "}
171 }; /* End error messages */
174 /* ========================================================================= */
176 * The next two funcs imported verbatim from cfgadm_scsi.
177 * physpath_to_devlink is the only func directly used by cfgadm_usb.
178 * get_link supports it.
182 * Routine to search the /dev directory or a subtree of /dev.
184 static int
185 get_link(di_devlink_t devlink, void *arg)
187 walk_link_t *larg = (walk_link_t *)arg;
190 * When path is specified, it's the node path without minor
191 * name. Therefore, the ../.. prefixes needs to be stripped.
193 if (larg->path) {
194 char *content = (char *)di_devlink_content(devlink);
195 char *start = strstr(content, "/devices/");
197 /* line content must have minor node */
198 if (start == NULL ||
199 strncmp(start, larg->path, larg->len) != 0 ||
200 start[larg->len] != ':') {
202 return (DI_WALK_CONTINUE);
206 *(larg->linkpp) = strdup(di_devlink_path(devlink));
208 return (DI_WALK_TERMINATE);
212 /* ARGSUSED */
213 static ucfga_ret_t
214 physpath_to_devlink(
215 const char *basedir,
216 const char *node_path,
217 char **logpp,
218 int *l_errnop,
219 int match_minor)
221 walk_link_t larg;
222 di_devlink_handle_t hdl;
223 char *minor_path;
225 if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
226 *l_errnop = errno;
227 return (UCFGA_LIB_ERR);
230 *logpp = NULL;
231 larg.linkpp = logpp;
232 if (match_minor) {
233 minor_path = (char *)node_path + strlen("/devices");
234 larg.path = NULL;
235 } else {
236 minor_path = NULL;
237 larg.len = strlen(node_path);
238 larg.path = (char *)node_path;
241 (void) di_devlink_walk(hdl, "^cfg/", minor_path, DI_PRIMARY_LINK,
242 (void *)&larg, get_link);
244 (void) di_devlink_fini(&hdl);
246 if (*logpp == NULL) {
247 *l_errnop = errno;
248 return (UCFGA_LIB_ERR);
251 return (UCFGA_OK);
255 /* ========================================================================= */
256 /* Utilities */
259 * Given the index into a table (msgcvt_t) of messages, get the message
260 * string, converting it to the proper locale if necessary.
261 * NOTE: See cfga_usb.h
263 static const char *
264 get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
266 if (msg_index >= tbl_size) {
267 DPRINTF("get_error_msg: bad error msg index: %d\n", msg_index);
268 msg_index = CFGA_USB_UNKNOWN;
271 return ((msg_tbl[msg_index].intl) ?
272 dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
273 msg_tbl[msg_index].msgstr);
278 * Allocates and creates a message string (in *ret_str),
279 * by concatenating all the (char *) args together, in order.
280 * Last arg MUST be NULL.
282 static void
283 set_msg(char **ret_str, ...)
285 char *str;
286 size_t total_len;
287 va_list valist;
289 va_start(valist, ret_str);
291 total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
293 while ((str = va_arg(valist, char *)) != NULL) {
294 size_t len = strlen(str);
295 char *old_str = *ret_str;
297 *ret_str = (char *)realloc(*ret_str, total_len + len + 1);
298 if (*ret_str == NULL) {
299 /* We're screwed */
300 free(old_str);
301 DPRINTF("set_msg: realloc failed.\n");
302 va_end(valist);
303 return;
306 (void) strcpy(*ret_str + total_len, str);
307 total_len += len;
310 va_end(valist);
315 * Error message handling.
316 * For the rv passed in, looks up the corresponding error message string(s),
317 * internationalized it if necessary, and concatenates it into a new
318 * memory buffer, and points *errstring to it.
319 * Note not all rvs will result in an error message return, as not all
320 * error conditions warrant a USB-specific error message.
322 * Some messages may display ap_id or errno, which is why they are passed
323 * in.
325 cfga_err_t
326 usb_err_msg(char **errstring, cfga_usb_ret_t rv, const char *ap_id, int l_errno)
328 if (errstring == NULL) {
330 return (usb_error_msgs[rv].cfga_err);
334 * Generate the appropriate USB-specific error message(s) (if any).
336 switch (rv) {
337 case CFGA_USB_OK:
338 /* Special case - do nothing. */
339 break;
341 case CFGA_USB_UNKNOWN:
342 case CFGA_USB_DYNAMIC_AP:
343 case CFGA_USB_INTERNAL_ERROR:
344 case CFGA_USB_OPTIONS:
345 case CFGA_USB_ALLOC_FAIL:
346 case CFGA_USB_STATE:
347 case CFGA_USB_CONFIG_INVAL:
348 case CFGA_USB_PRIV:
349 case CFGA_USB_OPNOTSUPP:
350 /* These messages require no additional strings passed. */
351 set_msg(errstring, ERR_STR(rv), NULL);
352 break;
354 case CFGA_USB_AP:
355 case CFGA_USB_PORT:
356 case CFGA_USB_NOT_CONNECTED:
357 case CFGA_USB_NOT_CONFIGURED:
358 case CFGA_USB_ALREADY_CONNECTED:
359 case CFGA_USB_ALREADY_CONFIGURED:
360 case CFGA_USB_BUSY:
361 case CFGA_USB_DEVLINK:
362 case CFGA_USB_RCM_HANDLE:
363 case CFGA_USB_RCM_ONLINE:
364 case CFGA_USB_RCM_OFFLINE:
365 case CFGA_USB_RCM_INFO:
366 case CFGA_USB_DEVCTL:
367 /* These messages also print ap_id. */
368 (void) set_msg(errstring, ERR_STR(rv),
369 "ap_id: ", ap_id, "", NULL);
370 break;
372 case CFGA_USB_IOCTL:
373 case CFGA_USB_NVLIST:
374 case CFGA_USB_CONFIG_FILE:
375 case CFGA_USB_ONE_CONFIG:
376 /* These messages also print errno. */
378 char *errno_str = l_errno ? strerror(l_errno) : "";
380 set_msg(errstring, ERR_STR(rv), errno_str,
381 l_errno ? "\n" : "", NULL);
382 break;
385 case CFGA_USB_OPEN:
386 /* These messages also apid and errno. */
388 char *errno_str = l_errno ? strerror(l_errno) : "";
390 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
391 errno_str, l_errno ? "\n" : "", NULL);
392 break;
395 default:
396 DPRINTF("usb_err_msg: Unrecognized message index: %d\n", rv);
397 set_msg(errstring, ERR_STR(CFGA_USB_INTERNAL_ERROR), NULL);
399 } /* end switch */
402 * Determine the proper error code to send back to the cfgadm library.
404 return (usb_error_msgs[rv].cfga_err);
409 * Ensure the ap_id passed is in the correct (physical ap_id) form:
410 * path/device:xx[.xx]+
411 * where xx is a one or two-digit number.
413 * Note the library always calls the plugin with a physical ap_id.
415 static int
416 verify_valid_apid(const char *ap_id)
418 char *l_ap_id;
420 if (ap_id == NULL) {
421 return (-1);
424 l_ap_id = strrchr(ap_id, *MINOR_SEP);
425 l_ap_id++;
427 if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) {
428 /* Bad characters in the ap_id. */
429 return (-1);
432 if (strstr(l_ap_id, "..") != NULL) {
433 /* ap_id has 1..2 or more than 2 dots */
434 return (-1);
437 return (0);
442 * Verify the params passed in are valid.
444 static cfga_usb_ret_t
445 verify_params(
446 const char *ap_id,
447 const char *options,
448 char **errstring)
450 if (errstring != NULL) {
451 *errstring = NULL;
454 if (options != NULL) {
455 DPRINTF("verify_params: hardware-specific options not "
456 "supported.\n");
457 return (CFGA_USB_OPTIONS);
460 /* Dynamic attachment points not supported (yet). */
461 if (GET_DYN(ap_id) != NULL) {
462 DPRINTF("verify_params: dynamic ap_id passed\n");
463 return (CFGA_USB_DYNAMIC_AP);
466 if (verify_valid_apid(ap_id) != 0) {
467 DPRINTF("verify_params: not a USB ap_id.\n");
468 return (CFGA_USB_AP);
471 return (CFGA_USB_OK);
476 * Takes a validated ap_id and extracts the port number.
478 static cfga_usb_ret_t
479 get_port_num(const char *ap_id, uint_t *port)
481 char *port_nbr_str;
482 char *temp;
484 port_nbr_str = strrchr(ap_id, *MINOR_SEP) + strlen(MINOR_SEP);
485 if ((temp = strrchr(ap_id, (int)*PORT_SEPERATOR)) != 0) {
486 port_nbr_str = temp + strlen(PORT_SEPERATOR);
489 errno = 0;
490 *port = strtol(port_nbr_str, NULL, 10);
491 if (errno) {
492 DPRINTF("get_port_num: conversion of port str failed\n");
493 return (CFGA_USB_PORT);
496 return (CFGA_USB_OK);
501 * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
503 static void
504 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
506 nvlist_free(user_nvlist);
507 devctl_release(devctl_hdl);
511 static cfga_usb_ret_t
512 setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl,
513 nvlist_t **user_nvlistp, uint_t oflag)
515 uint32_t port;
516 cfga_usb_ret_t rv = CFGA_USB_OK;
518 DPRINTF("setup_for_devctl_cmd: oflag=%d\n", oflag);
520 /* Get a handle to the ap */
521 if ((*devctl_hdl = devctl_ap_acquire((char *)ap_id, oflag)) == NULL) {
522 DPRINTF("setup_for_devctl_cmd: devctl_ap_acquire failed with "
523 "errno: %d\n", errno);
524 rv = CFGA_USB_DEVCTL;
525 goto bailout;
528 /* Set up to pass port number down to driver */
529 if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, 0) != 0) {
530 DPRINTF("setup_for_devctl: nvlist_alloc failed, errno: %d\n",
531 errno);
532 *user_nvlistp = NULL; /* Prevent possible incorrect free in */
533 /* cleanup_after_devctl_cmd */
534 rv = CFGA_USB_NVLIST;
535 goto bailout;
538 if ((rv = get_port_num(ap_id, &port)) != CFGA_USB_OK) {
539 DPRINTF("setup_for_devctl_cmd: get_port_num, errno: %d\n",
540 errno);
541 goto bailout;
544 /* creates an int32_t entry */
545 if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) {
546 DPRINTF("setup_for_devctl_cmd: nvlist_add_int32 failed. "
547 "errno: %d\n", errno);
548 rv = CFGA_USB_NVLIST;
549 goto bailout;
552 return (rv);
554 bailout:
555 cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
557 return (rv);
562 * Ensure that there's a device actually connected to the ap
564 static cfga_usb_ret_t
565 device_configured(devctl_hdl_t hdl, nvlist_t *nvl, ap_rstate_t *rstate)
567 cfga_usb_ret_t rv;
568 devctl_ap_state_t devctl_ap_state;
570 DPRINTF("device_configured:\n");
571 if (devctl_ap_getstate(hdl, nvl, &devctl_ap_state) == -1) {
572 DPRINTF("devctl_ap_getstate failed, errno: %d\n", errno);
573 return (CFGA_USB_DEVCTL);
576 rv = CFGA_USB_ALREADY_CONFIGURED;
577 *rstate = devctl_ap_state.ap_rstate;
578 if (devctl_ap_state.ap_ostate != AP_OSTATE_CONFIGURED) {
579 return (CFGA_USB_NOT_CONFIGURED);
582 return (rv);
587 * Ensure that there's a device actually connected to the ap
589 static cfga_usb_ret_t
590 device_connected(devctl_hdl_t hdl, nvlist_t *list, ap_ostate_t *ostate)
592 cfga_usb_ret_t rv = CFGA_USB_ALREADY_CONNECTED;
593 devctl_ap_state_t devctl_ap_state;
595 DPRINTF("device_connected:\n");
597 if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
598 DPRINTF("devctl_ap_getstate failed, errno: %d\n", errno);
599 return (CFGA_USB_DEVCTL);
602 *ostate = devctl_ap_state.ap_ostate;
603 if (devctl_ap_state.ap_rstate != AP_RSTATE_CONNECTED) {
604 return (CFGA_USB_NOT_CONNECTED);
607 return (rv);
612 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
613 * the data to be returned, allocate a buffer, then get the data.
614 * Returns *descrp (which must be freed) and size.
616 * Note USB_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
617 * not a string descr.
619 cfga_usb_ret_t
620 do_control_ioctl(const char *ap_id, uint_t subcommand, uint_t arg,
621 void **descrp, size_t *sizep)
623 int fd = -1;
624 uint_t port;
625 uint32_t local_size;
626 cfga_usb_ret_t rv = CFGA_USB_OK;
627 struct hubd_ioctl_data ioctl_data;
629 assert(descrp != NULL);
630 *descrp = NULL;
631 assert(sizep != NULL);
633 if ((rv = get_port_num(ap_id, &port)) != CFGA_USB_OK) {
634 goto bailout;
637 if ((fd = open(ap_id, O_RDONLY)) == -1) {
638 DPRINTF("do_control_ioctl: open failed: errno:%d\n", errno);
639 rv = CFGA_USB_OPEN;
640 if (errno == EBUSY) {
641 rv = CFGA_USB_BUSY;
643 goto bailout;
646 ioctl_data.cmd = subcommand;
647 ioctl_data.port = port;
648 ioctl_data.misc_arg = (uint_t)arg;
651 * Find out how large a buf we need to get the data.
653 * Note the ioctls only accept/return a 32-bit int for a get_size
654 * to avoid 32/64 and BE/LE issues.
656 ioctl_data.get_size = B_TRUE;
657 ioctl_data.buf = (caddr_t)&local_size;
658 ioctl_data.bufsiz = sizeof (local_size);
660 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
661 DPRINTF("do_control_ioctl: size ioctl failed: errno:%d\n",
662 errno);
663 rv = CFGA_USB_IOCTL;
664 goto bailout;
666 *sizep = local_size;
668 if (subcommand == USB_DESCR_TYPE_STRING &&
669 arg == HUBD_CFG_DESCR_STR && local_size == 0) {
670 /* Zero-length data - nothing to do. */
671 rv = CFGA_USB_ZEROLEN;
672 goto bailout;
674 if (subcommand == HUBD_REFRESH_DEVDB) {
675 /* Already done - no data transfer; nothing left to do. */
676 goto bailout;
679 if ((*descrp = malloc(*sizep)) == NULL) {
680 DPRINTF("do_control_ioctl: malloc failed\n");
681 rv = CFGA_USB_ALLOC_FAIL;
682 goto bailout;
685 /* Get the data */
686 ioctl_data.get_size = B_FALSE;
687 ioctl_data.buf = *descrp;
688 ioctl_data.bufsiz = *sizep;
690 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
691 DPRINTF("do_control_ioctl: ioctl failed: errno:%d\n",
692 errno);
693 rv = CFGA_USB_IOCTL;
694 goto bailout;
697 (void) close(fd);
699 return (rv);
702 bailout:
703 if (fd != -1) {
704 (void) close(fd);
706 if (*descrp != NULL) {
707 free(*descrp);
708 *descrp = NULL;
711 if (rv == CFGA_USB_IOCTL && errno == EBUSY) {
712 rv = CFGA_USB_BUSY; /* Provide more useful msg */
715 return (rv);
719 /* ========================================================================= */
721 * Support funcs called directly from cfga_* entry points.
726 * Invoked from cfga_private_func.
727 * Modify the USB persistant configuration file so that the device
728 * represented by ap_id will henceforth be initialized to the desired
729 * configuration setting (configuration index).
731 static cfga_usb_ret_t
732 set_configuration(const char *ap_id, uint_t config, char *driver,
733 usb_dev_descr_t *descrp, char **errstring)
735 char *serial_no = NULL;
736 char *dev_path = NULL;
737 char *tmp;
738 size_t size;
739 cfga_usb_ret_t rv = CFGA_USB_OK;
741 DPRINTF("set_configuration: ap_id: %s, config:%d\n", ap_id, config);
743 /* Only one bNumConfigurations, don't allow this operation */
744 if (descrp->bNumConfigurations == 1) {
745 DPRINTF("device supports %d configurations\n",
746 descrp->bNumConfigurations);
747 rv = CFGA_USB_ONE_CONFIG;
748 goto bailout;
751 /* get the serial number string if it exists */
752 if (descrp->iSerialNumber != 0) {
753 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
754 HUBD_SERIALNO_STR, (void **)&serial_no, &size)) !=
755 CFGA_USB_OK) {
756 if (rv != CFGA_USB_ZEROLEN) {
757 DPRINTF("set_configuration: get serial "
758 "no string failed\n");
759 goto bailout;
764 dev_path = usb_get_devicepath(ap_id);
765 if (dev_path == NULL) {
766 DPRINTF("get device path failed\n");
767 rv = CFGA_USB_DEVCTL;
768 goto bailout;
771 DPRINTF("calling add_entry: vid: 0x%x pid:0x%x config:0x%x,",
772 descrp->idVendor, descrp->idProduct, config);
773 DPRINTF("serial_no: %s\n\tdev_path: %s\n\tdriver: %s\n", serial_no ?
774 serial_no : "", dev_path ? dev_path : "", driver ? driver : "");
777 * the devicepath should be an absolute path.
778 * So, if path has leading "/devices" - nuke it.
780 if (strncmp(dev_path, "/devices/", 9) == 0) {
781 tmp = dev_path + 8;
782 } else {
783 tmp = dev_path;
786 /* Save an entry in the USBCONF_FILE */
787 if ((rv = add_entry(
788 "enable", /* Always to "enable" */
789 descrp->idVendor, /* vendorId */
790 descrp->idProduct, /* ProductId */
791 config, /* new cfgndx */
792 serial_no, /* serial no string */
793 tmp, /* device path */
794 driver, /* Driver (optional) */
795 errstring))
796 != CFGA_USB_OK) {
797 DPRINTF("set_configuration: add_entry failed\n");
798 goto bailout;
801 /* Notify hubd that it needs to refresh its db. */
802 if ((rv = do_control_ioctl(ap_id, HUBD_REFRESH_DEVDB, 0,
803 (void **)&dev_path, &size)) != CFGA_USB_OK) {
804 DPRINTF("set_configuration: HUBD_REFRESH_DEVDB failed\n");
805 goto bailout;
808 bailout:
809 if (dev_path) {
810 free(dev_path);
812 if (serial_no) {
813 free(serial_no);
816 return (rv);
821 * Invoked from cfga_private_func() and fill_in_ap_info().
822 * Call into USBA and get the current configuration setting for this device,
824 static cfga_usb_ret_t
825 get_config(const char *ap_id, uint_t *config)
827 size_t size;
828 uint_t *config_val = NULL;
829 cfga_usb_ret_t rv;
831 if ((rv = do_control_ioctl(ap_id, HUBD_GET_CURRENT_CONFIG, 0,
832 (void **)&config_val, &size)) != CFGA_USB_OK) {
833 DPRINTF("get_config: get current config descr failed\n");
834 goto bailout;
836 *config = *config_val;
838 bailout:
839 free(config_val);
840 return (rv);
845 * Invoked from cfga_private_func.
846 * it does an unconfigure of the device followed by a configure,
847 * thus essentially resetting the device.
849 static cfga_usb_ret_t
850 reset_device(devctl_hdl_t devctl_hdl, nvlist_t *nvl)
852 cfga_usb_ret_t rv;
854 DPRINTF("reset_device: \n");
857 * Disconnect and reconfigure the device.
858 * Note this forces the new default config to take effect.
860 if (devctl_ap_disconnect(devctl_hdl, nvl) != 0) {
861 DPRINTF("devctl_ap_unconfigure failed, errno: %d\n", errno);
862 rv = CFGA_USB_DEVCTL;
863 if (errno == EBUSY) {
864 rv = CFGA_USB_BUSY; /* Provide more useful msg */
867 return (rv);
870 if (devctl_ap_configure(devctl_hdl, nvl) != 0) {
871 DPRINTF(" devctl_ap_configure failed, errno = %d\n", errno);
872 return (CFGA_USB_DEVCTL);
875 return (CFGA_USB_OK);
880 * Called from cfga_list_ext.
881 * Fills in the 'misc_info' field in the cfga buffer (displayed with -lv).
883 static cfga_usb_ret_t
884 fill_in_ap_info(const char *ap_id, char *info_buf, size_t info_size)
886 char *mfg_str = NULL; /* iManufacturer */
887 char *prod_str = NULL; /* iProduct */
888 char *cfg_descr = NULL; /* iConfiguration */
889 uint_t config; /* curr cfg index */
890 size_t size; /* tmp stuff */
891 boolean_t flag; /* wether to print ":" or not */
892 boolean_t free_mfg_str = B_FALSE;
893 boolean_t free_prod_str = B_FALSE;
894 boolean_t free_cfg_str = B_FALSE;
895 cfga_usb_ret_t rv = CFGA_USB_OK;
896 usb_dev_descr_t *dev_descrp = NULL; /* device descriptor */
898 DPRINTF("fill_in_ap_info:\n");
900 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_DEV, 0,
901 (void **)&dev_descrp, &size)) != CFGA_USB_OK) {
902 DPRINTF("fill_in_ap_info: get dev descr failed\n");
903 return (rv);
906 /* iManufacturer */
907 mfg_str = USB_UNDEF_STR;
908 if (dev_descrp->iManufacturer != 0) {
909 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
910 HUBD_MFG_STR, (void **)&mfg_str, &size)) != CFGA_USB_OK) {
911 if (rv == CFGA_USB_ZEROLEN) {
912 rv = CFGA_USB_OK;
913 } else {
914 DPRINTF("get iManufacturer failed\n");
915 goto bailout;
918 free_mfg_str = B_TRUE;
921 /* iProduct */
922 prod_str = USB_UNDEF_STR;
923 if (dev_descrp->iProduct != 0) {
924 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
925 HUBD_PRODUCT_STR, (void **)&prod_str,
926 &size)) != CFGA_USB_OK) {
927 if (rv == CFGA_USB_ZEROLEN) {
928 rv = CFGA_USB_OK;
929 } else {
930 DPRINTF("getting iProduct failed\n");
931 goto bailout;
934 free_prod_str = B_TRUE;
937 /* Current conifguration */
938 if ((rv = get_config(ap_id, &config)) != CFGA_USB_OK) {
939 DPRINTF("get_config failed\n");
940 goto bailout;
943 /* Configuration string descriptor */
944 cfg_descr = USB_NO_CFG_STR;
945 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
946 HUBD_CFG_DESCR_STR, (void **)&cfg_descr, &size)) != CFGA_USB_OK) {
947 if (rv == CFGA_USB_ZEROLEN) {
948 rv = CFGA_USB_OK;
949 flag = B_TRUE;
950 } else {
951 DPRINTF("HUBD_CFG_DESCR_STR failed\n");
952 goto bailout;
956 /* add ": " to output coz PSARC case says so */
957 if ((cfg_descr != NULL) && rv != CFGA_USB_ZEROLEN) {
958 flag = B_TRUE;
959 free_cfg_str = B_TRUE;
960 } else {
961 flag = B_FALSE;
962 cfg_descr = USB_NO_CFG_STR;
965 /* Dump local buf into passed-in buf. */
966 (void) snprintf(info_buf, info_size,
967 "Mfg: %s Product: %s NConfigs: %d Config: %d %s%s", mfg_str,
968 prod_str, dev_descrp->bNumConfigurations, config,
969 (flag == B_TRUE) ? ": " : "", cfg_descr);
971 bailout:
972 if (dev_descrp) {
973 free(dev_descrp);
976 if ((free_mfg_str == B_TRUE) && mfg_str) {
977 free(mfg_str);
980 if ((free_prod_str == B_TRUE) && prod_str) {
981 free(prod_str);
984 if ((free_cfg_str == B_TRUE) && cfg_descr) {
985 free(cfg_descr);
988 return (rv);
992 /* ========================================================================== */
993 /* Entry points */
996 /*ARGSUSED*/
997 cfga_err_t
998 cfga_change_state(
999 cfga_cmd_t state_change_cmd,
1000 const char *ap_id,
1001 const char *options,
1002 struct cfga_confirm *confp,
1003 struct cfga_msg *msgp,
1004 char **errstring,
1005 cfga_flags_t flags)
1007 int ret;
1008 int len;
1009 char *msg;
1010 char *devpath;
1011 nvlist_t *nvl = NULL;
1012 ap_rstate_t rstate;
1013 ap_ostate_t ostate;
1014 devctl_hdl_t hdl = NULL;
1015 cfga_usb_ret_t rv = CFGA_USB_OK;
1017 DPRINTF("cfga_change_state:\n");
1019 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_USB_OK) {
1020 (void) cfga_help(msgp, options, flags);
1021 goto bailout;
1025 * All subcommands which can change state of device require
1026 * root privileges.
1028 if (geteuid() != 0) {
1029 rv = CFGA_USB_PRIV;
1030 goto bailout;
1033 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl, 0)) !=
1034 CFGA_USB_OK) {
1035 goto bailout;
1038 switch (state_change_cmd) {
1039 case CFGA_CMD_CONFIGURE:
1040 if ((rv = device_configured(hdl, nvl, &rstate)) !=
1041 CFGA_USB_NOT_CONFIGURED) {
1042 goto bailout;
1045 if (rstate == AP_RSTATE_EMPTY) {
1046 goto bailout;
1048 rv = CFGA_USB_OK; /* Other statuses don't matter */
1050 if (devctl_ap_configure(hdl, nvl) != 0) {
1051 DPRINTF("cfga_change_state: devctl_ap_configure "
1052 "failed. errno: %d\n", errno);
1053 rv = CFGA_USB_DEVCTL;
1056 devpath = usb_get_devicepath(ap_id);
1057 if (devpath == NULL) {
1058 int i;
1060 * try for some time as USB hotplug thread
1061 * takes a while to create the path
1062 * and then eventually give up
1064 for (i = 0; i < 12 && (devpath == NULL); i++) {
1065 (void) sleep(6);
1066 devpath = usb_get_devicepath(ap_id);
1069 if (devpath == NULL) {
1070 DPRINTF("cfga_change_state: get device "
1071 "path failed i = %d\n", i);
1072 rv = CFGA_USB_DEVCTL;
1073 break;
1076 S_FREE(devpath);
1077 break;
1078 case CFGA_CMD_UNCONFIGURE:
1079 if ((rv = device_connected(hdl, nvl, &ostate)) !=
1080 CFGA_USB_ALREADY_CONNECTED) {
1081 goto bailout;
1084 /* check if it is already unconfigured */
1085 if ((rv = device_configured(hdl, nvl, &rstate)) ==
1086 CFGA_USB_NOT_CONFIGURED) {
1087 goto bailout;
1089 rv = CFGA_USB_OK; /* Other statuses don't matter */
1091 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1092 strlen("Unconfigure") + strlen(ap_id);
1093 if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
1094 (void) snprintf(msg, len + 3, "Unconfigure %s%s\n%s",
1095 USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
1097 if (!usb_confirm(confp, msg)) {
1098 free(msg);
1099 cleanup_after_devctl_cmd(hdl, nvl);
1100 return (CFGA_NACK);
1102 free(msg);
1104 devpath = usb_get_devicepath(ap_id);
1105 if (devpath == NULL) {
1106 DPRINTF("cfga_change_state: get device path failed\n");
1107 rv = CFGA_USB_DEVCTL;
1108 break;
1111 if ((rv = usb_rcm_offline(ap_id, errstring, devpath, flags)) !=
1112 CFGA_USB_OK) {
1113 break;
1116 ret = devctl_ap_unconfigure(hdl, nvl);
1117 if (ret != 0) {
1118 DPRINTF("cfga_change_state: devctl_ap_unconfigure "
1119 "failed with errno: %d\n", errno);
1120 rv = CFGA_USB_DEVCTL;
1121 if (errno == EBUSY) {
1122 rv = CFGA_USB_BUSY;
1124 (void) usb_rcm_online(ap_id, errstring, devpath, flags);
1125 } else {
1126 (void) usb_rcm_remove(ap_id, errstring, devpath, flags);
1128 S_FREE(devpath);
1129 break;
1130 case CFGA_CMD_DISCONNECT:
1131 if ((rv = device_connected(hdl, nvl, &ostate)) !=
1132 CFGA_USB_ALREADY_CONNECTED) {
1134 * special case handling for
1135 * SLM based cfgadm disconnects
1137 if (ostate == AP_OSTATE_UNCONFIGURED)
1138 goto bailout;
1140 rv = CFGA_USB_OK; /* Other statuses don't matter */
1142 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1143 strlen("Disconnect") + strlen(ap_id);
1144 if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
1145 (void) snprintf(msg, len + 3, "Disconnect %s%s\n%s",
1146 USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
1148 if (!usb_confirm(confp, msg)) {
1149 free(msg);
1150 cleanup_after_devctl_cmd(hdl, nvl);
1151 return (CFGA_NACK);
1153 free(msg);
1155 devpath = usb_get_devicepath(ap_id);
1156 if (devpath == NULL) {
1157 DPRINTF("cfga_change_state: get device path failed\n");
1158 rv = CFGA_USB_DEVCTL;
1159 break;
1162 /* only call rcm_offline iff the state was CONFIGURED */
1163 if (ostate == AP_OSTATE_CONFIGURED) {
1164 if ((rv = usb_rcm_offline(ap_id, errstring,
1165 devpath, flags)) != CFGA_USB_OK) {
1166 break;
1170 ret = devctl_ap_disconnect(hdl, nvl);
1171 if (ret != 0) {
1172 DPRINTF("cfga_change_state: devctl_ap_disconnect "
1173 "failed with errno: %d\n", errno);
1174 rv = CFGA_USB_DEVCTL;
1175 if (errno == EBUSY) {
1176 rv = CFGA_USB_BUSY;
1178 if (ostate == AP_OSTATE_CONFIGURED) {
1179 (void) usb_rcm_online(ap_id, errstring,
1180 devpath, flags);
1182 } else {
1183 if (ostate == AP_OSTATE_CONFIGURED) {
1184 (void) usb_rcm_remove(ap_id, errstring,
1185 devpath, flags);
1188 S_FREE(devpath);
1189 break;
1190 case CFGA_CMD_CONNECT:
1191 case CFGA_CMD_LOAD:
1192 case CFGA_CMD_UNLOAD:
1193 (void) cfga_help(msgp, options, flags);
1194 rv = CFGA_USB_OPNOTSUPP;
1195 break;
1196 case CFGA_CMD_NONE:
1197 default:
1198 (void) cfga_help(msgp, options, flags);
1199 rv = CFGA_USB_INTERNAL_ERROR;
1202 bailout:
1203 cleanup_after_devctl_cmd(hdl, nvl);
1205 return (usb_err_msg(errstring, rv, ap_id, errno));
1209 /*ARGSUSED*/
1210 cfga_err_t
1211 cfga_private_func(
1212 const char *func,
1213 const char *ap_id,
1214 const char *options,
1215 struct cfga_confirm *confp,
1216 struct cfga_msg *msgp,
1217 char **errstring,
1218 cfga_flags_t flags)
1220 int len;
1221 char *msg;
1222 nvlist_t *list = NULL;
1223 ap_ostate_t ostate;
1224 devctl_hdl_t hdl = NULL;
1225 cfga_usb_ret_t rv;
1226 usb_dev_descr_t *dev_descrp = NULL;
1227 char *driver = NULL;
1229 DPRINTF("cfga_private_func:\n");
1231 if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_USB_OK) {
1232 (void) cfga_help(msgp, options, flags);
1233 return (usb_err_msg(errstring, rv, ap_id, errno));
1237 * All subcommands which can change state of device require
1238 * root privileges.
1240 if (geteuid() != 0) {
1241 rv = CFGA_USB_PRIV;
1242 goto bailout;
1245 if (func == NULL) {
1246 rv = CFGA_USB_INTERNAL_ERROR;
1247 goto bailout;
1250 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) !=
1251 CFGA_USB_OK) {
1252 goto bailout;
1255 if ((rv = device_connected(hdl, list, &ostate)) !=
1256 CFGA_USB_ALREADY_CONNECTED) {
1257 goto bailout;
1259 rv = CFGA_USB_OK;
1261 if (strcmp(func, RESET_DEVICE) == 0) { /* usb_reset? */
1262 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1263 strlen("Reset") + strlen(ap_id);
1264 if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
1265 (void) snprintf(msg, len + 3, "Reset %s%s\n%s",
1266 USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
1267 } else {
1268 cleanup_after_devctl_cmd(hdl, list);
1269 return (CFGA_NACK);
1272 if (!usb_confirm(confp, msg)) {
1273 cleanup_after_devctl_cmd(hdl, list);
1274 return (CFGA_NACK);
1277 if ((rv = reset_device(hdl, list)) != CFGA_USB_OK) {
1278 goto bailout;
1280 } else if (strncmp(func, USB_CONFIG, sizeof (USB_CONFIG)) == 0) {
1281 uint_t config = 0;
1282 uint_t actual_config;
1283 size_t size;
1284 char *subopts, *value;
1285 uint_t cfg_opt_flag = B_FALSE;
1287 /* these are the only valid options */
1288 char *cfg_opts[] = {
1289 "config", /* 0 */
1290 "drv", /* 1 */
1291 NULL
1294 /* return error if no options are specified */
1295 subopts = (char *)options;
1296 if (subopts == NULL) {
1297 DPRINTF("cfga_private_func: no options\n");
1298 rv = CFGA_USB_OPNOTSUPP;
1299 (void) cfga_help(msgp, options, flags);
1300 goto bailout;
1303 /* parse options specified */
1304 while (*subopts != '\0') {
1305 switch (getsubopt(&subopts, cfg_opts, &value)) {
1306 case 0: /* config */
1307 if (value == NULL) {
1308 rv = CFGA_USB_OPNOTSUPP;
1309 (void) cfga_help(msgp,
1310 options, flags);
1311 goto bailout;
1312 } else {
1313 errno = 0;
1314 config = strtol(value,
1315 (char **)NULL, 10);
1316 if (errno) {
1317 DPRINTF(
1318 "config conversion"
1319 "failed\n");
1320 rv =
1321 CFGA_USB_CONFIG_INVAL;
1322 goto bailout;
1325 cfg_opt_flag = B_TRUE;
1326 break;
1328 case 1: /* drv */
1329 if (value == NULL) {
1330 rv = CFGA_USB_OPNOTSUPP;
1331 (void) cfga_help(msgp,
1332 options, flags);
1333 goto bailout;
1334 } else {
1335 S_FREE(driver);
1336 driver = strdup(value);
1337 if (driver == NULL) {
1338 rv =
1339 CFGA_USB_INTERNAL_ERROR;
1340 goto bailout;
1343 break;
1345 default:
1346 rv = CFGA_USB_OPNOTSUPP;
1347 (void) cfga_help(msgp, options, flags);
1348 goto bailout;
1352 /* config is mandatory */
1353 if (cfg_opt_flag != B_TRUE) {
1354 rv = CFGA_USB_OPNOTSUPP;
1355 (void) cfga_help(msgp, options, flags);
1356 goto bailout;
1358 DPRINTF("config = %x\n", config);
1360 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1361 strlen("Setting") + strlen(ap_id) +
1362 strlen("to USB configuration");
1363 /* len + 8 to account for config, \n and white space */
1364 if ((msg = (char *)calloc(len + 8, 1)) != NULL) {
1365 (void) snprintf(msg, len + 8,
1366 "Setting %s%s\nto USB configuration %d\n%s",
1367 USB_CONFIRM_0, ap_id, config, USB_CONFIRM_1);
1368 } else {
1369 rv = CFGA_USB_INTERNAL_ERROR;
1370 goto bailout;
1373 if (!usb_confirm(confp, msg)) {
1374 S_FREE(driver);
1375 cleanup_after_devctl_cmd(hdl, list);
1376 return (CFGA_NACK);
1380 * Check that the option setting selected is in range.
1382 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_DEV, 0,
1383 (void **)&dev_descrp, &size)) != CFGA_USB_OK) {
1384 DPRINTF("cfga_private_func: get dev descr failed\n");
1385 goto bailout;
1388 if (config > dev_descrp->bNumConfigurations - 1) {
1389 DPRINTF("cfga_private_func: config index requested "
1390 "(%d) exceeds bNumConfigurations - 1 (%d)\n",
1391 config, dev_descrp->bNumConfigurations - 1);
1392 rv = CFGA_USB_CONFIG_INVAL;
1393 goto bailout;
1396 /* Pass current setting to set_configuration */
1397 if ((rv = get_config(ap_id, &actual_config)) != CFGA_USB_OK) {
1398 goto bailout;
1401 /* check if they match - yes, then nothing to do */
1402 if (actual_config == config) {
1403 DPRINTF("cfga_private_func: config index requested "
1404 "(%d) matches the actual config value %d\n",
1405 config, actual_config);
1406 rv = CFGA_USB_OK;
1407 goto bailout;
1410 /* Save the configuration settings */
1411 if ((rv = set_configuration(ap_id, config, driver,
1412 dev_descrp, errstring)) != CFGA_USB_OK) {
1413 goto bailout;
1416 /* Reset device to force new config to take effect */
1417 if ((rv = reset_device(hdl, list)) != CFGA_USB_OK) {
1418 goto bailout;
1421 } else {
1422 DPRINTF("cfga_private_func: unrecognized command.\n");
1423 (void) cfga_help(msgp, options, flags);
1424 errno = EINVAL;
1426 return (CFGA_INVAL);
1429 bailout:
1430 S_FREE(dev_descrp);
1431 S_FREE(driver);
1432 cleanup_after_devctl_cmd(hdl, list);
1434 return (usb_err_msg(errstring, rv, ap_id, errno));
1438 /*ARGSUSED*/
1439 cfga_err_t
1440 cfga_test(
1441 const char *ap_id,
1442 const char *options,
1443 struct cfga_msg *msgp,
1444 char **errstring,
1445 cfga_flags_t flags)
1447 (void) cfga_help(msgp, options, flags);
1448 return (CFGA_OPNOTSUPP);
1452 /*ARGSUSED*/
1453 cfga_err_t
1454 cfga_list_ext(
1455 const char *ap_id,
1456 cfga_list_data_t **ap_id_list,
1457 int *nlistp,
1458 const char *options,
1459 const char *listopts,
1460 char **errstring,
1461 cfga_flags_t flags)
1463 int l_errno;
1464 char *ap_id_log = NULL;
1465 size_t size;
1466 nvlist_t *user_nvlist = NULL;
1467 devctl_hdl_t devctl_hdl = NULL;
1468 cfga_usb_ret_t rv = CFGA_USB_OK;
1469 devctl_ap_state_t devctl_ap_state;
1471 DPRINTF("cfga_list_ext:\n");
1473 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_USB_OK) {
1474 goto bailout;
1477 if (ap_id_list == NULL || nlistp == NULL) {
1478 DPRINTF("cfga_list_ext: list = NULL or nlistp = NULL\n");
1479 rv = CFGA_USB_INTERNAL_ERROR;
1480 goto bailout;
1483 /* Get ap status */
1484 if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
1485 DC_RDONLY)) != CFGA_USB_OK) {
1486 goto bailout;
1489 if (devctl_ap_getstate(devctl_hdl, user_nvlist, &devctl_ap_state) ==
1490 -1) {
1491 DPRINTF("cfga_list_ext: devctl_ap_getstate failed. errno: %d\n",
1492 errno);
1493 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1494 rv = CFGA_USB_DEVCTL;
1495 goto bailout;
1497 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1500 * Create cfga_list_data_t struct.
1502 if ((*ap_id_list =
1503 (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
1504 DPRINTF("cfga_list_ext: malloc for cfga_list_data_t failed. "
1505 "errno: %d\n", errno);
1506 rv = CFGA_USB_ALLOC_FAIL;
1507 goto bailout;
1509 *nlistp = 1;
1513 * Rest of the code fills in the cfga_list_data_t struct.
1516 /* Get /dev/cfg path to corresponding to the physical ap_id */
1517 /* Remember ap_id_log must be freed */
1518 rv = (cfga_usb_ret_t)physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
1519 &ap_id_log, &l_errno, MATCH_MINOR_NAME);
1520 if (rv != 0) {
1521 rv = CFGA_USB_DEVLINK;
1522 goto bailout;
1524 assert(ap_id_log != NULL);
1526 /* Get logical ap-id corresponding to the physical */
1527 if (strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
1528 DPRINTF("cfga_list_ext: devlink doesn't contain /dev/cfg\n");
1529 rv = CFGA_USB_DEVLINK;
1530 goto bailout;
1532 (void) strlcpy((*ap_id_list)->ap_log_id,
1533 /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
1534 sizeof ((*ap_id_list)->ap_log_id));
1535 free(ap_id_log);
1536 ap_id_log = NULL;
1538 (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
1539 sizeof ((*ap_id_list)->ap_phys_id));
1541 switch (devctl_ap_state.ap_rstate) {
1542 case AP_RSTATE_EMPTY:
1543 (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
1544 break;
1545 case AP_RSTATE_DISCONNECTED:
1546 (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
1547 break;
1548 case AP_RSTATE_CONNECTED:
1549 (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
1550 break;
1551 default:
1552 rv = CFGA_USB_STATE;
1553 goto bailout;
1556 switch (devctl_ap_state.ap_ostate) {
1557 case AP_OSTATE_CONFIGURED:
1558 (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
1559 break;
1560 case AP_OSTATE_UNCONFIGURED:
1561 (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
1562 break;
1563 default:
1564 rv = CFGA_USB_STATE;
1565 goto bailout;
1568 switch (devctl_ap_state.ap_condition) {
1569 case AP_COND_OK:
1570 (*ap_id_list)->ap_cond = CFGA_COND_OK;
1571 break;
1572 case AP_COND_FAILING:
1573 (*ap_id_list)->ap_cond = CFGA_COND_FAILING;
1574 break;
1575 case AP_COND_FAILED:
1576 (*ap_id_list)->ap_cond = CFGA_COND_FAILED;
1577 break;
1578 case AP_COND_UNUSABLE:
1579 (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
1580 break;
1581 case AP_COND_UNKNOWN:
1582 (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
1583 break;
1584 default:
1585 rv = CFGA_USB_STATE;
1586 goto bailout;
1589 (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */
1590 (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
1591 (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
1592 (*ap_id_list)->ap_info[0] = '\0';
1594 if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
1595 char *str_p;
1596 size_t str_len;
1598 /* Fill in the info for the -v option display. */
1599 if ((rv = fill_in_ap_info(ap_id, (*ap_id_list)->ap_info,
1600 sizeof ((*ap_id_list)->ap_info))) != CFGA_USB_OK) {
1601 DPRINTF("cfga_list_ext: fill_in_ap_info failed\n");
1602 goto bailout;
1605 /* Fill in ap_type */
1606 if ((rv = do_control_ioctl(ap_id, HUBD_GET_CFGADM_NAME, 0,
1607 (void **)&str_p, &size)) != CFGA_USB_OK) {
1608 DPRINTF("cfga_list_ext: do_control_ioctl failed\n");
1609 goto bailout;
1612 (void) strcpy((*ap_id_list)->ap_type, "usb-");
1613 str_len = strlen((*ap_id_list)->ap_type);
1616 * NOTE: In the cfgadm display the "Type" column is only 12
1617 * chars long. Most USB devices can be displayed here with a
1618 * "usb-" prefix. Only USB keyboard cannot be displayed in
1619 * its entirety as "usb-keybaord" is 13 chars in length.
1620 * It will show up as "usb-kbd".
1622 if (strncasecmp(str_p, "keyboard", 8) != 0) {
1623 (void) strlcpy((*ap_id_list)->ap_type + str_len, str_p,
1624 sizeof ((*ap_id_list)->ap_type) - str_len);
1625 } else {
1626 (void) strlcpy((*ap_id_list)->ap_type + str_len, "kbd",
1627 sizeof ((*ap_id_list)->ap_type) - str_len);
1630 free(str_p);
1631 } else {
1632 (void) strcpy((*ap_id_list)->ap_type,
1633 USB_CFGADM_DEFAULT_AP_TYPE);
1636 return (usb_err_msg(errstring, rv, ap_id, errno));
1637 bailout:
1638 if (*ap_id_list != NULL) {
1639 free(*ap_id_list);
1641 if (ap_id_log != NULL) {
1642 free(ap_id_log);
1645 return (usb_err_msg(errstring, rv, ap_id, errno));
1650 * This routine accepts a variable number of message IDs and constructs
1651 * a corresponding error string which is printed via the message print routine
1652 * argument.
1654 static void
1655 cfga_msg(struct cfga_msg *msgp, const char *str)
1657 int len;
1658 char *q;
1660 if (msgp == NULL || msgp->message_routine == NULL) {
1661 DPRINTF("cfga_msg: msg\n");
1662 return;
1665 if ((len = strlen(str)) == 0) {
1666 DPRINTF("cfga_msg: null str\n");
1667 return;
1670 if ((q = (char *)calloc(len + 1, 1)) == NULL) {
1671 DPRINTF("cfga_msg: null q\n");
1672 return;
1675 (void) strcpy(q, str);
1676 (*msgp->message_routine)(msgp->appdata_ptr, q);
1678 free(q);
1682 /* ARGSUSED */
1683 cfga_err_t
1684 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
1686 DPRINTF("cfga_help:\n");
1687 if (options) {
1688 cfga_msg(msgp, dgettext(TEXT_DOMAIN, usb_help[HELP_UNKNOWN]));
1689 cfga_msg(msgp, options);
1692 cfga_msg(msgp, dgettext(TEXT_DOMAIN, usb_help[HELP_HEADER]));
1693 cfga_msg(msgp, usb_help[HELP_CONFIG]);
1694 cfga_msg(msgp, usb_help[HELP_RESET_SLOT]);
1695 cfga_msg(msgp, usb_help[HELP_CONFIG_SLOT]);
1697 return (CFGA_OK);
1701 static int
1702 usb_confirm(struct cfga_confirm *confp, char *msg)
1704 int rval;
1706 if (confp == NULL || confp->confirm == NULL) {
1707 return (0);
1710 rval = (*confp->confirm)(confp->appdata_ptr, msg);
1711 DPRINTF("usb_confirm: %d\n", rval);
1713 return (rval);
1717 static char *
1718 usb_get_devicepath(const char *ap_id)
1720 char *devpath = NULL;
1721 size_t size;
1722 cfga_usb_ret_t rv;
1724 rv = do_control_ioctl(ap_id, HUBD_GET_DEVICE_PATH, 0,
1725 (void **)&devpath, &size);
1727 if (rv == CFGA_USB_OK) {
1728 DPRINTF("usb_get_devicepath: get device path ioctl ok\n");
1729 return (devpath);
1730 } else {
1731 DPRINTF("usb_get_devicepath: get device path ioctl failed\n");
1732 return (NULL);