dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / cfgadm_plugins / usb / common / cfga_usb.c
blob3663ca072cf01a4605a6f89d233adcaff5a75777
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.
27 #include "cfga_usb.h"
30 /* function prototypes */
31 cfga_err_t usb_err_msg(char **, cfga_usb_ret_t, const char *, int);
32 extern cfga_usb_ret_t usb_rcm_offline(const char *, char **, char *,
33 cfga_flags_t);
34 extern cfga_usb_ret_t usb_rcm_online(const char *, char **, char *,
35 cfga_flags_t);
36 extern cfga_usb_ret_t usb_rcm_remove(const char *, char **, char *,
37 cfga_flags_t);
38 static int usb_confirm(struct cfga_confirm *, char *);
39 static char *usb_get_devicepath(const char *);
42 * This file contains the entry points to the plugin as defined in the
43 * config_admin(3X) man page.
47 * Set the version number for the cfgadm library's use.
49 int cfga_version = CFGA_HSL_V2;
51 #define HELP_HEADER 1
52 #define HELP_CONFIG 2
53 #define HELP_RESET_SLOT 3
54 #define HELP_CONFIG_SLOT 4
55 #define HELP_UNKNOWN 5
57 /* Help messages */
58 static char *
59 usb_help[] = {
60 NULL,
61 "USB specific commands:\n",
62 " cfgadm -c [configure|unconfigure|disconnect] ap_id [ap_id...]\n",
63 " cfgadm -x usb_reset ap_id [ap_id...]\n",
64 " cfgadm -x usb_config -o config=<index of desired configuration> ap_id\n",
65 "\tunknown command or option: ",
66 NULL
67 }; /* End help messages */
69 /* Error messages */
70 static msgcvt_t
71 usb_error_msgs[] = {
72 /* CFGA_USB_OK */
73 { CVT, CFGA_OK, "ok" },
75 /* CFGA_USB_UNKNOWN */
76 { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
78 /* CFGA_USB_INTERNAL_ERROR */
79 { CVT, CFGA_LIB_ERROR, "Internal error" },
81 /* CFGA_USB_OPTIONS */
82 { CVT, CFGA_ERROR, "Hardware specific options not supported" },
84 /* CFGA_USB_DYNAMIC_AP */
85 { CVT, CFGA_INVAL, "Dynamic attachment points not supported" },
87 /* CFGA_USB_AP */
88 { CVT, CFGA_APID_NOEXIST, "" },
90 /* CFGA_USB_PORT */
91 { CVT, CFGA_LIB_ERROR, "Cannot determine hub port number for " },
93 /* CFGA_USB_DEVCTL */
94 { CVT, CFGA_ERROR, "Cannot issue devctl to " },
96 /* CFGA_USB_NOT_CONNECTED */
97 { CVT, CFGA_INVAL, "No device connected to " },
99 /* CFGA_USB_NOT_CONFIGURED */
100 { CVT, CFGA_INVAL, "No device configured to " },
102 /* CFGA_USB_ALREADY_CONNECTED */
103 { CVT, CFGA_INSUFFICENT_CONDITION,
104 "Device already connected; cannot connect again " },
106 /* CFGA_USB_ALREADY_CONFIGURED */
107 { CVT, CFGA_INVAL, "device already configured for " },
109 /* CFGA_USB_OPEN */
110 { CVT, CFGA_LIB_ERROR, "Cannot open " },
112 /* CFGA_USB_IOCTL */
113 { CVT, CFGA_ERROR, "Driver ioctl failed " },
115 /* CFGA_USB_BUSY */
116 { CVT, CFGA_SYSTEM_BUSY, "" },
118 /* CFGA_USB_ALLOC_FAIL */
119 { CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
121 /* CFGA_USB_OPNOTSUPP */
122 { CVT, CFGA_OPNOTSUPP, "Operation not supported" },
124 /* CFGA_USB_DEVLINK */
125 { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
127 /* CFGA_USB_STATE */
128 { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
130 /* CFGA_USB_CONFIG_INVAL */
131 { CVT, CFGA_ERROR,
132 "Specified configuration index unrecognized or exceeds "
133 "maximum available" },
135 /* CFGA_USB_PRIV */
136 { CVT, CFGA_PRIV, "" },
138 /* CFGA_USB_NVLIST */
139 { CVT, CFGA_ERROR, "Internal error (nvlist)" },
141 /* CFGA_USB_ZEROLEN */
142 { CVT, CFGA_ERROR, "Internal error (zerolength string)" },
144 /* CFGA_USB_CONFIG_FILE */
145 { CVT, CFGA_ERROR,
146 "Cannot open/fstat/read USB system configuration file" },
148 /* CFGA_USB_LOCK_FILE */
149 { CVT, CFGA_ERROR, "Cannot lock USB system configuration file" },
151 /* CFGA_USB_UNLOCK_FILE */
152 { CVT, CFGA_ERROR, "Cannot unlock USB system configuration file" },
154 /* CFGA_USB_ONE_CONFIG */
155 { CVT, CFGA_ERROR,
156 "Operation not supported for devices with one configuration" },
158 /* CFGA_USB_RCM_HANDLE Errors */
159 { CVT, CFGA_ERROR, "cannot get RCM handle"},
161 /* CFGA_USB_RCM_ONLINE */
162 { CVT, CFGA_SYSTEM_BUSY, "failed to online: "},
164 /* CFGA_USB_RCM_OFFLINE */
165 { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "},
167 /* CFGA_USB_RCM_INFO */
168 { CVT, CFGA_ERROR, "failed to query: "}
170 }; /* End error messages */
173 /* ========================================================================= */
175 * The next two funcs imported verbatim from cfgadm_scsi.
176 * physpath_to_devlink is the only func directly used by cfgadm_usb.
177 * get_link supports it.
181 * Routine to search the /dev directory or a subtree of /dev.
183 static int
184 get_link(di_devlink_t devlink, void *arg)
186 walk_link_t *larg = (walk_link_t *)arg;
189 * When path is specified, it's the node path without minor
190 * name. Therefore, the ../.. prefixes needs to be stripped.
192 if (larg->path) {
193 char *content = (char *)di_devlink_content(devlink);
194 char *start = strstr(content, "/devices/");
196 /* line content must have minor node */
197 if (start == NULL ||
198 strncmp(start, larg->path, larg->len) != 0 ||
199 start[larg->len] != ':') {
201 return (DI_WALK_CONTINUE);
205 *(larg->linkpp) = strdup(di_devlink_path(devlink));
207 return (DI_WALK_TERMINATE);
211 /* ARGSUSED */
212 static ucfga_ret_t
213 physpath_to_devlink(
214 const char *basedir,
215 const char *node_path,
216 char **logpp,
217 int *l_errnop,
218 int match_minor)
220 walk_link_t larg;
221 di_devlink_handle_t hdl;
222 char *minor_path;
224 if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
225 *l_errnop = errno;
226 return (UCFGA_LIB_ERR);
229 *logpp = NULL;
230 larg.linkpp = logpp;
231 if (match_minor) {
232 minor_path = (char *)node_path + strlen("/devices");
233 larg.path = NULL;
234 } else {
235 minor_path = NULL;
236 larg.len = strlen(node_path);
237 larg.path = (char *)node_path;
240 (void) di_devlink_walk(hdl, "^cfg/", minor_path, DI_PRIMARY_LINK,
241 (void *)&larg, get_link);
243 (void) di_devlink_fini(&hdl);
245 if (*logpp == NULL) {
246 *l_errnop = errno;
247 return (UCFGA_LIB_ERR);
250 return (UCFGA_OK);
254 /* ========================================================================= */
255 /* Utilities */
258 * Given the index into a table (msgcvt_t) of messages, get the message
259 * string, converting it to the proper locale if necessary.
260 * NOTE: See cfga_usb.h
262 static const char *
263 get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
265 if (msg_index >= tbl_size) {
266 DPRINTF("get_error_msg: bad error msg index: %d\n", msg_index);
267 msg_index = CFGA_USB_UNKNOWN;
270 return ((msg_tbl[msg_index].intl) ?
271 dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
272 msg_tbl[msg_index].msgstr);
277 * Allocates and creates a message string (in *ret_str),
278 * by concatenating all the (char *) args together, in order.
279 * Last arg MUST be NULL.
281 static void
282 set_msg(char **ret_str, ...)
284 char *str;
285 size_t total_len;
286 va_list valist;
288 va_start(valist, ret_str);
290 total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
292 while ((str = va_arg(valist, char *)) != NULL) {
293 size_t len = strlen(str);
294 char *old_str = *ret_str;
296 *ret_str = (char *)realloc(*ret_str, total_len + len + 1);
297 if (*ret_str == NULL) {
298 /* We're screwed */
299 free(old_str);
300 DPRINTF("set_msg: realloc failed.\n");
301 va_end(valist);
302 return;
305 (void) strcpy(*ret_str + total_len, str);
306 total_len += len;
309 va_end(valist);
314 * Error message handling.
315 * For the rv passed in, looks up the corresponding error message string(s),
316 * internationalized it if necessary, and concatenates it into a new
317 * memory buffer, and points *errstring to it.
318 * Note not all rvs will result in an error message return, as not all
319 * error conditions warrant a USB-specific error message.
321 * Some messages may display ap_id or errno, which is why they are passed
322 * in.
324 cfga_err_t
325 usb_err_msg(char **errstring, cfga_usb_ret_t rv, const char *ap_id, int l_errno)
327 if (errstring == NULL) {
329 return (usb_error_msgs[rv].cfga_err);
333 * Generate the appropriate USB-specific error message(s) (if any).
335 switch (rv) {
336 case CFGA_USB_OK:
337 /* Special case - do nothing. */
338 break;
340 case CFGA_USB_UNKNOWN:
341 case CFGA_USB_DYNAMIC_AP:
342 case CFGA_USB_INTERNAL_ERROR:
343 case CFGA_USB_OPTIONS:
344 case CFGA_USB_ALLOC_FAIL:
345 case CFGA_USB_STATE:
346 case CFGA_USB_CONFIG_INVAL:
347 case CFGA_USB_PRIV:
348 case CFGA_USB_OPNOTSUPP:
349 /* These messages require no additional strings passed. */
350 set_msg(errstring, ERR_STR(rv), NULL);
351 break;
353 case CFGA_USB_AP:
354 case CFGA_USB_PORT:
355 case CFGA_USB_NOT_CONNECTED:
356 case CFGA_USB_NOT_CONFIGURED:
357 case CFGA_USB_ALREADY_CONNECTED:
358 case CFGA_USB_ALREADY_CONFIGURED:
359 case CFGA_USB_BUSY:
360 case CFGA_USB_DEVLINK:
361 case CFGA_USB_RCM_HANDLE:
362 case CFGA_USB_RCM_ONLINE:
363 case CFGA_USB_RCM_OFFLINE:
364 case CFGA_USB_RCM_INFO:
365 case CFGA_USB_DEVCTL:
366 /* These messages also print ap_id. */
367 (void) set_msg(errstring, ERR_STR(rv),
368 "ap_id: ", ap_id, "", NULL);
369 break;
371 case CFGA_USB_IOCTL:
372 case CFGA_USB_NVLIST:
373 case CFGA_USB_CONFIG_FILE:
374 case CFGA_USB_ONE_CONFIG:
375 /* These messages also print errno. */
377 char *errno_str = l_errno ? strerror(l_errno) : "";
379 set_msg(errstring, ERR_STR(rv), errno_str,
380 l_errno ? "\n" : "", NULL);
381 break;
384 case CFGA_USB_OPEN:
385 /* These messages also apid and errno. */
387 char *errno_str = l_errno ? strerror(l_errno) : "";
389 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
390 errno_str, l_errno ? "\n" : "", NULL);
391 break;
394 default:
395 DPRINTF("usb_err_msg: Unrecognized message index: %d\n", rv);
396 set_msg(errstring, ERR_STR(CFGA_USB_INTERNAL_ERROR), NULL);
398 } /* end switch */
401 * Determine the proper error code to send back to the cfgadm library.
403 return (usb_error_msgs[rv].cfga_err);
408 * Ensure the ap_id passed is in the correct (physical ap_id) form:
409 * path/device:xx[.xx]+
410 * where xx is a one or two-digit number.
412 * Note the library always calls the plugin with a physical ap_id.
414 static int
415 verify_valid_apid(const char *ap_id)
417 char *l_ap_id;
419 if (ap_id == NULL) {
420 return (-1);
423 l_ap_id = strrchr(ap_id, *MINOR_SEP);
424 l_ap_id++;
426 if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) {
427 /* Bad characters in the ap_id. */
428 return (-1);
431 if (strstr(l_ap_id, "..") != NULL) {
432 /* ap_id has 1..2 or more than 2 dots */
433 return (-1);
436 return (0);
441 * Verify the params passed in are valid.
443 static cfga_usb_ret_t
444 verify_params(
445 const char *ap_id,
446 const char *options,
447 char **errstring)
449 if (errstring != NULL) {
450 *errstring = NULL;
453 if (options != NULL) {
454 DPRINTF("verify_params: hardware-specific options not "
455 "supported.\n");
456 return (CFGA_USB_OPTIONS);
459 /* Dynamic attachment points not supported (yet). */
460 if (GET_DYN(ap_id) != NULL) {
461 DPRINTF("verify_params: dynamic ap_id passed\n");
462 return (CFGA_USB_DYNAMIC_AP);
465 if (verify_valid_apid(ap_id) != 0) {
466 DPRINTF("verify_params: not a USB ap_id.\n");
467 return (CFGA_USB_AP);
470 return (CFGA_USB_OK);
475 * Takes a validated ap_id and extracts the port number.
477 static cfga_usb_ret_t
478 get_port_num(const char *ap_id, uint_t *port)
480 char *port_nbr_str;
481 char *temp;
483 port_nbr_str = strrchr(ap_id, *MINOR_SEP) + strlen(MINOR_SEP);
484 if ((temp = strrchr(ap_id, (int)*PORT_SEPERATOR)) != 0) {
485 port_nbr_str = temp + strlen(PORT_SEPERATOR);
488 errno = 0;
489 *port = strtol(port_nbr_str, NULL, 10);
490 if (errno) {
491 DPRINTF("get_port_num: conversion of port str failed\n");
492 return (CFGA_USB_PORT);
495 return (CFGA_USB_OK);
500 * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
502 static void
503 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
505 nvlist_free(user_nvlist);
506 devctl_release(devctl_hdl);
510 static cfga_usb_ret_t
511 setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl,
512 nvlist_t **user_nvlistp, uint_t oflag)
514 uint32_t port;
515 cfga_usb_ret_t rv = CFGA_USB_OK;
517 DPRINTF("setup_for_devctl_cmd: oflag=%d\n", oflag);
519 /* Get a handle to the ap */
520 if ((*devctl_hdl = devctl_ap_acquire((char *)ap_id, oflag)) == NULL) {
521 DPRINTF("setup_for_devctl_cmd: devctl_ap_acquire failed with "
522 "errno: %d\n", errno);
523 rv = CFGA_USB_DEVCTL;
524 goto bailout;
527 /* Set up to pass port number down to driver */
528 if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, 0) != 0) {
529 DPRINTF("setup_for_devctl: nvlist_alloc failed, errno: %d\n",
530 errno);
531 *user_nvlistp = NULL; /* Prevent possible incorrect free in */
532 /* cleanup_after_devctl_cmd */
533 rv = CFGA_USB_NVLIST;
534 goto bailout;
537 if ((rv = get_port_num(ap_id, &port)) != CFGA_USB_OK) {
538 DPRINTF("setup_for_devctl_cmd: get_port_num, errno: %d\n",
539 errno);
540 goto bailout;
543 /* creates an int32_t entry */
544 if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) {
545 DPRINTF("setup_for_devctl_cmd: nvlist_add_int32 failed. "
546 "errno: %d\n", errno);
547 rv = CFGA_USB_NVLIST;
548 goto bailout;
551 return (rv);
553 bailout:
554 cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
556 return (rv);
561 * Ensure that there's a device actually connected to the ap
563 static cfga_usb_ret_t
564 device_configured(devctl_hdl_t hdl, nvlist_t *nvl, ap_rstate_t *rstate)
566 cfga_usb_ret_t rv;
567 devctl_ap_state_t devctl_ap_state;
569 DPRINTF("device_configured:\n");
570 if (devctl_ap_getstate(hdl, nvl, &devctl_ap_state) == -1) {
571 DPRINTF("devctl_ap_getstate failed, errno: %d\n", errno);
572 return (CFGA_USB_DEVCTL);
575 rv = CFGA_USB_ALREADY_CONFIGURED;
576 *rstate = devctl_ap_state.ap_rstate;
577 if (devctl_ap_state.ap_ostate != AP_OSTATE_CONFIGURED) {
578 return (CFGA_USB_NOT_CONFIGURED);
581 return (rv);
586 * Ensure that there's a device actually connected to the ap
588 static cfga_usb_ret_t
589 device_connected(devctl_hdl_t hdl, nvlist_t *list, ap_ostate_t *ostate)
591 cfga_usb_ret_t rv = CFGA_USB_ALREADY_CONNECTED;
592 devctl_ap_state_t devctl_ap_state;
594 DPRINTF("device_connected:\n");
596 if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
597 DPRINTF("devctl_ap_getstate failed, errno: %d\n", errno);
598 return (CFGA_USB_DEVCTL);
601 *ostate = devctl_ap_state.ap_ostate;
602 if (devctl_ap_state.ap_rstate != AP_RSTATE_CONNECTED) {
603 return (CFGA_USB_NOT_CONNECTED);
606 return (rv);
611 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
612 * the data to be returned, allocate a buffer, then get the data.
613 * Returns *descrp (which must be freed) and size.
615 * Note USB_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
616 * not a string descr.
618 cfga_usb_ret_t
619 do_control_ioctl(const char *ap_id, uint_t subcommand, uint_t arg,
620 void **descrp, size_t *sizep)
622 int fd = -1;
623 uint_t port;
624 uint32_t local_size;
625 cfga_usb_ret_t rv = CFGA_USB_OK;
626 struct hubd_ioctl_data ioctl_data;
628 assert(descrp != NULL);
629 *descrp = NULL;
630 assert(sizep != NULL);
632 if ((rv = get_port_num(ap_id, &port)) != CFGA_USB_OK) {
633 goto bailout;
636 if ((fd = open(ap_id, O_RDONLY)) == -1) {
637 DPRINTF("do_control_ioctl: open failed: errno:%d\n", errno);
638 rv = CFGA_USB_OPEN;
639 if (errno == EBUSY) {
640 rv = CFGA_USB_BUSY;
642 goto bailout;
645 ioctl_data.cmd = subcommand;
646 ioctl_data.port = port;
647 ioctl_data.misc_arg = (uint_t)arg;
650 * Find out how large a buf we need to get the data.
652 * Note the ioctls only accept/return a 32-bit int for a get_size
653 * to avoid 32/64 and BE/LE issues.
655 ioctl_data.get_size = B_TRUE;
656 ioctl_data.buf = (caddr_t)&local_size;
657 ioctl_data.bufsiz = sizeof (local_size);
659 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
660 DPRINTF("do_control_ioctl: size ioctl failed: errno:%d\n",
661 errno);
662 rv = CFGA_USB_IOCTL;
663 goto bailout;
665 *sizep = local_size;
667 if (subcommand == USB_DESCR_TYPE_STRING &&
668 arg == HUBD_CFG_DESCR_STR && local_size == 0) {
669 /* Zero-length data - nothing to do. */
670 rv = CFGA_USB_ZEROLEN;
671 goto bailout;
673 if (subcommand == HUBD_REFRESH_DEVDB) {
674 /* Already done - no data transfer; nothing left to do. */
675 goto bailout;
678 if ((*descrp = malloc(*sizep)) == NULL) {
679 DPRINTF("do_control_ioctl: malloc failed\n");
680 rv = CFGA_USB_ALLOC_FAIL;
681 goto bailout;
684 /* Get the data */
685 ioctl_data.get_size = B_FALSE;
686 ioctl_data.buf = *descrp;
687 ioctl_data.bufsiz = *sizep;
689 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
690 DPRINTF("do_control_ioctl: ioctl failed: errno:%d\n",
691 errno);
692 rv = CFGA_USB_IOCTL;
693 goto bailout;
696 (void) close(fd);
698 return (rv);
701 bailout:
702 if (fd != -1) {
703 (void) close(fd);
705 if (*descrp != NULL) {
706 free(*descrp);
707 *descrp = NULL;
710 if (rv == CFGA_USB_IOCTL && errno == EBUSY) {
711 rv = CFGA_USB_BUSY; /* Provide more useful msg */
714 return (rv);
718 /* ========================================================================= */
720 * Support funcs called directly from cfga_* entry points.
725 * Invoked from cfga_private_func.
726 * Modify the USB persistant configuration file so that the device
727 * represented by ap_id will henceforth be initialized to the desired
728 * configuration setting (configuration index).
730 static cfga_usb_ret_t
731 set_configuration(const char *ap_id, uint_t config, char *driver,
732 usb_dev_descr_t *descrp, char **errstring)
734 char *serial_no = NULL;
735 char *dev_path = NULL;
736 char *tmp;
737 size_t size;
738 cfga_usb_ret_t rv = CFGA_USB_OK;
740 DPRINTF("set_configuration: ap_id: %s, config:%d\n", ap_id, config);
742 /* Only one bNumConfigurations, don't allow this operation */
743 if (descrp->bNumConfigurations == 1) {
744 DPRINTF("device supports %d configurations\n",
745 descrp->bNumConfigurations);
746 rv = CFGA_USB_ONE_CONFIG;
747 goto bailout;
750 /* get the serial number string if it exists */
751 if (descrp->iSerialNumber != 0) {
752 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
753 HUBD_SERIALNO_STR, (void **)&serial_no, &size)) !=
754 CFGA_USB_OK) {
755 if (rv != CFGA_USB_ZEROLEN) {
756 DPRINTF("set_configuration: get serial "
757 "no string failed\n");
758 goto bailout;
763 dev_path = usb_get_devicepath(ap_id);
764 if (dev_path == NULL) {
765 DPRINTF("get device path failed\n");
766 rv = CFGA_USB_DEVCTL;
767 goto bailout;
770 DPRINTF("calling add_entry: vid: 0x%x pid:0x%x config:0x%x,",
771 descrp->idVendor, descrp->idProduct, config);
772 DPRINTF("serial_no: %s\n\tdev_path: %s\n\tdriver: %s\n", serial_no ?
773 serial_no : "", dev_path ? dev_path : "", driver ? driver : "");
776 * the devicepath should be an absolute path.
777 * So, if path has leading "/devices" - nuke it.
779 if (strncmp(dev_path, "/devices/", 9) == 0) {
780 tmp = dev_path + 8;
781 } else {
782 tmp = dev_path;
785 /* Save an entry in the USBCONF_FILE */
786 if ((rv = add_entry(
787 "enable", /* Always to "enable" */
788 descrp->idVendor, /* vendorId */
789 descrp->idProduct, /* ProductId */
790 config, /* new cfgndx */
791 serial_no, /* serial no string */
792 tmp, /* device path */
793 driver, /* Driver (optional) */
794 errstring))
795 != CFGA_USB_OK) {
796 DPRINTF("set_configuration: add_entry failed\n");
797 goto bailout;
800 /* Notify hubd that it needs to refresh its db. */
801 if ((rv = do_control_ioctl(ap_id, HUBD_REFRESH_DEVDB, 0,
802 (void **)&dev_path, &size)) != CFGA_USB_OK) {
803 DPRINTF("set_configuration: HUBD_REFRESH_DEVDB failed\n");
804 goto bailout;
807 bailout:
808 if (dev_path) {
809 free(dev_path);
811 if (serial_no) {
812 free(serial_no);
815 return (rv);
820 * Invoked from cfga_private_func() and fill_in_ap_info().
821 * Call into USBA and get the current configuration setting for this device,
823 static cfga_usb_ret_t
824 get_config(const char *ap_id, uint_t *config)
826 size_t size;
827 uint_t *config_val = NULL;
828 cfga_usb_ret_t rv;
830 if ((rv = do_control_ioctl(ap_id, HUBD_GET_CURRENT_CONFIG, 0,
831 (void **)&config_val, &size)) != CFGA_USB_OK) {
832 DPRINTF("get_config: get current config descr failed\n");
833 goto bailout;
835 *config = *config_val;
837 bailout:
838 free(config_val);
839 return (rv);
844 * Invoked from cfga_private_func.
845 * it does an unconfigure of the device followed by a configure,
846 * thus essentially resetting the device.
848 static cfga_usb_ret_t
849 reset_device(devctl_hdl_t devctl_hdl, nvlist_t *nvl)
851 cfga_usb_ret_t rv;
853 DPRINTF("reset_device: \n");
856 * Disconnect and reconfigure the device.
857 * Note this forces the new default config to take effect.
859 if (devctl_ap_disconnect(devctl_hdl, nvl) != 0) {
860 DPRINTF("devctl_ap_unconfigure failed, errno: %d\n", errno);
861 rv = CFGA_USB_DEVCTL;
862 if (errno == EBUSY) {
863 rv = CFGA_USB_BUSY; /* Provide more useful msg */
866 return (rv);
869 if (devctl_ap_configure(devctl_hdl, nvl) != 0) {
870 DPRINTF(" devctl_ap_configure failed, errno = %d\n", errno);
871 return (CFGA_USB_DEVCTL);
874 return (CFGA_USB_OK);
879 * Called from cfga_list_ext.
880 * Fills in the 'misc_info' field in the cfga buffer (displayed with -lv).
882 static cfga_usb_ret_t
883 fill_in_ap_info(const char *ap_id, char *info_buf, size_t info_size)
885 char *mfg_str = NULL; /* iManufacturer */
886 char *prod_str = NULL; /* iProduct */
887 char *cfg_descr = NULL; /* iConfiguration */
888 uint_t config; /* curr cfg index */
889 size_t size; /* tmp stuff */
890 boolean_t flag; /* wether to print ":" or not */
891 boolean_t free_mfg_str = B_FALSE;
892 boolean_t free_prod_str = B_FALSE;
893 boolean_t free_cfg_str = B_FALSE;
894 cfga_usb_ret_t rv = CFGA_USB_OK;
895 usb_dev_descr_t *dev_descrp = NULL; /* device descriptor */
897 DPRINTF("fill_in_ap_info:\n");
899 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_DEV, 0,
900 (void **)&dev_descrp, &size)) != CFGA_USB_OK) {
901 DPRINTF("fill_in_ap_info: get dev descr failed\n");
902 return (rv);
905 /* iManufacturer */
906 mfg_str = USB_UNDEF_STR;
907 if (dev_descrp->iManufacturer != 0) {
908 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
909 HUBD_MFG_STR, (void **)&mfg_str, &size)) != CFGA_USB_OK) {
910 if (rv == CFGA_USB_ZEROLEN) {
911 rv = CFGA_USB_OK;
912 } else {
913 DPRINTF("get iManufacturer failed\n");
914 goto bailout;
917 free_mfg_str = B_TRUE;
920 /* iProduct */
921 prod_str = USB_UNDEF_STR;
922 if (dev_descrp->iProduct != 0) {
923 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
924 HUBD_PRODUCT_STR, (void **)&prod_str,
925 &size)) != CFGA_USB_OK) {
926 if (rv == CFGA_USB_ZEROLEN) {
927 rv = CFGA_USB_OK;
928 } else {
929 DPRINTF("getting iProduct failed\n");
930 goto bailout;
933 free_prod_str = B_TRUE;
936 /* Current conifguration */
937 if ((rv = get_config(ap_id, &config)) != CFGA_USB_OK) {
938 DPRINTF("get_config failed\n");
939 goto bailout;
942 /* Configuration string descriptor */
943 cfg_descr = USB_NO_CFG_STR;
944 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING,
945 HUBD_CFG_DESCR_STR, (void **)&cfg_descr, &size)) != CFGA_USB_OK) {
946 if (rv == CFGA_USB_ZEROLEN) {
947 rv = CFGA_USB_OK;
948 flag = B_TRUE;
949 } else {
950 DPRINTF("HUBD_CFG_DESCR_STR failed\n");
951 goto bailout;
955 /* add ": " to output coz PSARC case says so */
956 if ((cfg_descr != NULL) && rv != CFGA_USB_ZEROLEN) {
957 flag = B_TRUE;
958 free_cfg_str = B_TRUE;
959 } else {
960 flag = B_FALSE;
961 cfg_descr = USB_NO_CFG_STR;
964 /* Dump local buf into passed-in buf. */
965 (void) snprintf(info_buf, info_size,
966 "Mfg: %s Product: %s NConfigs: %d Config: %d %s%s", mfg_str,
967 prod_str, dev_descrp->bNumConfigurations, config,
968 (flag == B_TRUE) ? ": " : "", cfg_descr);
970 bailout:
971 if (dev_descrp) {
972 free(dev_descrp);
975 if ((free_mfg_str == B_TRUE) && mfg_str) {
976 free(mfg_str);
979 if ((free_prod_str == B_TRUE) && prod_str) {
980 free(prod_str);
983 if ((free_cfg_str == B_TRUE) && cfg_descr) {
984 free(cfg_descr);
987 return (rv);
991 /* ========================================================================== */
992 /* Entry points */
995 /*ARGSUSED*/
996 cfga_err_t
997 cfga_change_state(
998 cfga_cmd_t state_change_cmd,
999 const char *ap_id,
1000 const char *options,
1001 struct cfga_confirm *confp,
1002 struct cfga_msg *msgp,
1003 char **errstring,
1004 cfga_flags_t flags)
1006 int ret;
1007 int len;
1008 char *msg;
1009 char *devpath;
1010 nvlist_t *nvl = NULL;
1011 ap_rstate_t rstate;
1012 ap_ostate_t ostate;
1013 devctl_hdl_t hdl = NULL;
1014 cfga_usb_ret_t rv = CFGA_USB_OK;
1016 DPRINTF("cfga_change_state:\n");
1018 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_USB_OK) {
1019 (void) cfga_help(msgp, options, flags);
1020 goto bailout;
1024 * All subcommands which can change state of device require
1025 * root privileges.
1027 if (geteuid() != 0) {
1028 rv = CFGA_USB_PRIV;
1029 goto bailout;
1032 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl, 0)) !=
1033 CFGA_USB_OK) {
1034 goto bailout;
1037 switch (state_change_cmd) {
1038 case CFGA_CMD_CONFIGURE:
1039 if ((rv = device_configured(hdl, nvl, &rstate)) !=
1040 CFGA_USB_NOT_CONFIGURED) {
1041 goto bailout;
1044 if (rstate == AP_RSTATE_EMPTY) {
1045 goto bailout;
1047 rv = CFGA_USB_OK; /* Other statuses don't matter */
1049 if (devctl_ap_configure(hdl, nvl) != 0) {
1050 DPRINTF("cfga_change_state: devctl_ap_configure "
1051 "failed. errno: %d\n", errno);
1052 rv = CFGA_USB_DEVCTL;
1055 devpath = usb_get_devicepath(ap_id);
1056 if (devpath == NULL) {
1057 int i;
1059 * try for some time as USB hotplug thread
1060 * takes a while to create the path
1061 * and then eventually give up
1063 for (i = 0; i < 12 && (devpath == NULL); i++) {
1064 (void) sleep(6);
1065 devpath = usb_get_devicepath(ap_id);
1068 if (devpath == NULL) {
1069 DPRINTF("cfga_change_state: get device "
1070 "path failed i = %d\n", i);
1071 rv = CFGA_USB_DEVCTL;
1072 break;
1075 S_FREE(devpath);
1076 break;
1077 case CFGA_CMD_UNCONFIGURE:
1078 if ((rv = device_connected(hdl, nvl, &ostate)) !=
1079 CFGA_USB_ALREADY_CONNECTED) {
1080 goto bailout;
1083 /* check if it is already unconfigured */
1084 if ((rv = device_configured(hdl, nvl, &rstate)) ==
1085 CFGA_USB_NOT_CONFIGURED) {
1086 goto bailout;
1088 rv = CFGA_USB_OK; /* Other statuses don't matter */
1090 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1091 strlen("Unconfigure") + strlen(ap_id);
1092 if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
1093 (void) snprintf(msg, len + 3, "Unconfigure %s%s\n%s",
1094 USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
1096 if (!usb_confirm(confp, msg)) {
1097 free(msg);
1098 cleanup_after_devctl_cmd(hdl, nvl);
1099 return (CFGA_NACK);
1101 free(msg);
1103 devpath = usb_get_devicepath(ap_id);
1104 if (devpath == NULL) {
1105 DPRINTF("cfga_change_state: get device path failed\n");
1106 rv = CFGA_USB_DEVCTL;
1107 break;
1110 if ((rv = usb_rcm_offline(ap_id, errstring, devpath, flags)) !=
1111 CFGA_USB_OK) {
1112 break;
1115 ret = devctl_ap_unconfigure(hdl, nvl);
1116 if (ret != 0) {
1117 DPRINTF("cfga_change_state: devctl_ap_unconfigure "
1118 "failed with errno: %d\n", errno);
1119 rv = CFGA_USB_DEVCTL;
1120 if (errno == EBUSY) {
1121 rv = CFGA_USB_BUSY;
1123 (void) usb_rcm_online(ap_id, errstring, devpath, flags);
1124 } else {
1125 (void) usb_rcm_remove(ap_id, errstring, devpath, flags);
1127 S_FREE(devpath);
1128 break;
1129 case CFGA_CMD_DISCONNECT:
1130 if ((rv = device_connected(hdl, nvl, &ostate)) !=
1131 CFGA_USB_ALREADY_CONNECTED) {
1133 * special case handling for
1134 * SLM based cfgadm disconnects
1136 if (ostate == AP_OSTATE_UNCONFIGURED)
1137 goto bailout;
1139 rv = CFGA_USB_OK; /* Other statuses don't matter */
1141 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1142 strlen("Disconnect") + strlen(ap_id);
1143 if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
1144 (void) snprintf(msg, len + 3, "Disconnect %s%s\n%s",
1145 USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
1147 if (!usb_confirm(confp, msg)) {
1148 free(msg);
1149 cleanup_after_devctl_cmd(hdl, nvl);
1150 return (CFGA_NACK);
1152 free(msg);
1154 devpath = usb_get_devicepath(ap_id);
1155 if (devpath == NULL) {
1156 DPRINTF("cfga_change_state: get device path failed\n");
1157 rv = CFGA_USB_DEVCTL;
1158 break;
1161 /* only call rcm_offline iff the state was CONFIGURED */
1162 if (ostate == AP_OSTATE_CONFIGURED) {
1163 if ((rv = usb_rcm_offline(ap_id, errstring,
1164 devpath, flags)) != CFGA_USB_OK) {
1165 break;
1169 ret = devctl_ap_disconnect(hdl, nvl);
1170 if (ret != 0) {
1171 DPRINTF("cfga_change_state: devctl_ap_disconnect "
1172 "failed with errno: %d\n", errno);
1173 rv = CFGA_USB_DEVCTL;
1174 if (errno == EBUSY) {
1175 rv = CFGA_USB_BUSY;
1177 if (ostate == AP_OSTATE_CONFIGURED) {
1178 (void) usb_rcm_online(ap_id, errstring,
1179 devpath, flags);
1181 } else {
1182 if (ostate == AP_OSTATE_CONFIGURED) {
1183 (void) usb_rcm_remove(ap_id, errstring,
1184 devpath, flags);
1187 S_FREE(devpath);
1188 break;
1189 case CFGA_CMD_CONNECT:
1190 case CFGA_CMD_LOAD:
1191 case CFGA_CMD_UNLOAD:
1192 (void) cfga_help(msgp, options, flags);
1193 rv = CFGA_USB_OPNOTSUPP;
1194 break;
1195 case CFGA_CMD_NONE:
1196 default:
1197 (void) cfga_help(msgp, options, flags);
1198 rv = CFGA_USB_INTERNAL_ERROR;
1201 bailout:
1202 cleanup_after_devctl_cmd(hdl, nvl);
1204 return (usb_err_msg(errstring, rv, ap_id, errno));
1208 /*ARGSUSED*/
1209 cfga_err_t
1210 cfga_private_func(
1211 const char *func,
1212 const char *ap_id,
1213 const char *options,
1214 struct cfga_confirm *confp,
1215 struct cfga_msg *msgp,
1216 char **errstring,
1217 cfga_flags_t flags)
1219 int len;
1220 char *msg;
1221 nvlist_t *list = NULL;
1222 ap_ostate_t ostate;
1223 devctl_hdl_t hdl = NULL;
1224 cfga_usb_ret_t rv;
1225 usb_dev_descr_t *dev_descrp = NULL;
1226 char *driver = NULL;
1228 DPRINTF("cfga_private_func:\n");
1230 if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_USB_OK) {
1231 (void) cfga_help(msgp, options, flags);
1232 return (usb_err_msg(errstring, rv, ap_id, errno));
1236 * All subcommands which can change state of device require
1237 * root privileges.
1239 if (geteuid() != 0) {
1240 rv = CFGA_USB_PRIV;
1241 goto bailout;
1244 if (func == NULL) {
1245 rv = CFGA_USB_INTERNAL_ERROR;
1246 goto bailout;
1249 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) !=
1250 CFGA_USB_OK) {
1251 goto bailout;
1254 if ((rv = device_connected(hdl, list, &ostate)) !=
1255 CFGA_USB_ALREADY_CONNECTED) {
1256 goto bailout;
1258 rv = CFGA_USB_OK;
1260 if (strcmp(func, RESET_DEVICE) == 0) { /* usb_reset? */
1261 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1262 strlen("Reset") + strlen(ap_id);
1263 if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
1264 (void) snprintf(msg, len + 3, "Reset %s%s\n%s",
1265 USB_CONFIRM_0, ap_id, USB_CONFIRM_1);
1266 } else {
1267 cleanup_after_devctl_cmd(hdl, list);
1268 return (CFGA_NACK);
1271 if (!usb_confirm(confp, msg)) {
1272 cleanup_after_devctl_cmd(hdl, list);
1273 return (CFGA_NACK);
1276 if ((rv = reset_device(hdl, list)) != CFGA_USB_OK) {
1277 goto bailout;
1279 } else if (strncmp(func, USB_CONFIG, sizeof (USB_CONFIG)) == 0) {
1280 uint_t config = 0;
1281 uint_t actual_config;
1282 size_t size;
1283 char *subopts, *value;
1284 uint_t cfg_opt_flag = B_FALSE;
1286 /* these are the only valid options */
1287 char *cfg_opts[] = {
1288 "config", /* 0 */
1289 "drv", /* 1 */
1290 NULL
1293 /* return error if no options are specified */
1294 subopts = (char *)options;
1295 if (subopts == NULL) {
1296 DPRINTF("cfga_private_func: no options\n");
1297 rv = CFGA_USB_OPNOTSUPP;
1298 (void) cfga_help(msgp, options, flags);
1299 goto bailout;
1302 /* parse options specified */
1303 while (*subopts != '\0') {
1304 switch (getsubopt(&subopts, cfg_opts, &value)) {
1305 case 0: /* config */
1306 if (value == NULL) {
1307 rv = CFGA_USB_OPNOTSUPP;
1308 (void) cfga_help(msgp,
1309 options, flags);
1310 goto bailout;
1311 } else {
1312 errno = 0;
1313 config = strtol(value,
1314 (char **)NULL, 10);
1315 if (errno) {
1316 DPRINTF(
1317 "config conversion"
1318 "failed\n");
1319 rv =
1320 CFGA_USB_CONFIG_INVAL;
1321 goto bailout;
1324 cfg_opt_flag = B_TRUE;
1325 break;
1327 case 1: /* drv */
1328 if (value == NULL) {
1329 rv = CFGA_USB_OPNOTSUPP;
1330 (void) cfga_help(msgp,
1331 options, flags);
1332 goto bailout;
1333 } else {
1334 S_FREE(driver);
1335 driver = strdup(value);
1336 if (driver == NULL) {
1337 rv =
1338 CFGA_USB_INTERNAL_ERROR;
1339 goto bailout;
1342 break;
1344 default:
1345 rv = CFGA_USB_OPNOTSUPP;
1346 (void) cfga_help(msgp, options, flags);
1347 goto bailout;
1351 /* config is mandatory */
1352 if (cfg_opt_flag != B_TRUE) {
1353 rv = CFGA_USB_OPNOTSUPP;
1354 (void) cfga_help(msgp, options, flags);
1355 goto bailout;
1357 DPRINTF("config = %x\n", config);
1359 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) +
1360 strlen("Setting") + strlen(ap_id) +
1361 strlen("to USB configuration");
1362 /* len + 8 to account for config, \n and white space */
1363 if ((msg = (char *)calloc(len + 8, 1)) != NULL) {
1364 (void) snprintf(msg, len + 8,
1365 "Setting %s%s\nto USB configuration %d\n%s",
1366 USB_CONFIRM_0, ap_id, config, USB_CONFIRM_1);
1367 } else {
1368 rv = CFGA_USB_INTERNAL_ERROR;
1369 goto bailout;
1372 if (!usb_confirm(confp, msg)) {
1373 S_FREE(driver);
1374 cleanup_after_devctl_cmd(hdl, list);
1375 return (CFGA_NACK);
1379 * Check that the option setting selected is in range.
1381 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_DEV, 0,
1382 (void **)&dev_descrp, &size)) != CFGA_USB_OK) {
1383 DPRINTF("cfga_private_func: get dev descr failed\n");
1384 goto bailout;
1387 if (config > dev_descrp->bNumConfigurations - 1) {
1388 DPRINTF("cfga_private_func: config index requested "
1389 "(%d) exceeds bNumConfigurations - 1 (%d)\n",
1390 config, dev_descrp->bNumConfigurations - 1);
1391 rv = CFGA_USB_CONFIG_INVAL;
1392 goto bailout;
1395 /* Pass current setting to set_configuration */
1396 if ((rv = get_config(ap_id, &actual_config)) != CFGA_USB_OK) {
1397 goto bailout;
1400 /* check if they match - yes, then nothing to do */
1401 if (actual_config == config) {
1402 DPRINTF("cfga_private_func: config index requested "
1403 "(%d) matches the actual config value %d\n",
1404 config, actual_config);
1405 rv = CFGA_USB_OK;
1406 goto bailout;
1409 /* Save the configuration settings */
1410 if ((rv = set_configuration(ap_id, config, driver,
1411 dev_descrp, errstring)) != CFGA_USB_OK) {
1412 goto bailout;
1415 /* Reset device to force new config to take effect */
1416 if ((rv = reset_device(hdl, list)) != CFGA_USB_OK) {
1417 goto bailout;
1420 } else {
1421 DPRINTF("cfga_private_func: unrecognized command.\n");
1422 (void) cfga_help(msgp, options, flags);
1423 errno = EINVAL;
1425 return (CFGA_INVAL);
1428 bailout:
1429 S_FREE(dev_descrp);
1430 S_FREE(driver);
1431 cleanup_after_devctl_cmd(hdl, list);
1433 return (usb_err_msg(errstring, rv, ap_id, errno));
1437 /*ARGSUSED*/
1438 cfga_err_t
1439 cfga_test(
1440 const char *ap_id,
1441 const char *options,
1442 struct cfga_msg *msgp,
1443 char **errstring,
1444 cfga_flags_t flags)
1446 (void) cfga_help(msgp, options, flags);
1447 return (CFGA_OPNOTSUPP);
1451 /*ARGSUSED*/
1452 cfga_err_t
1453 cfga_list_ext(
1454 const char *ap_id,
1455 cfga_list_data_t **ap_id_list,
1456 int *nlistp,
1457 const char *options,
1458 const char *listopts,
1459 char **errstring,
1460 cfga_flags_t flags)
1462 int l_errno;
1463 char *ap_id_log = NULL;
1464 size_t size;
1465 nvlist_t *user_nvlist = NULL;
1466 devctl_hdl_t devctl_hdl = NULL;
1467 cfga_usb_ret_t rv = CFGA_USB_OK;
1468 devctl_ap_state_t devctl_ap_state;
1470 DPRINTF("cfga_list_ext:\n");
1472 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_USB_OK) {
1473 (void) cfga_help(NULL, options, flags);
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 (void) cfga_help(NULL, options, flags);
1481 goto bailout;
1484 /* Get ap status */
1485 if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
1486 DC_RDONLY)) != CFGA_USB_OK) {
1487 goto bailout;
1490 if (devctl_ap_getstate(devctl_hdl, user_nvlist, &devctl_ap_state) ==
1491 -1) {
1492 DPRINTF("cfga_list_ext: devctl_ap_getstate failed. errno: %d\n",
1493 errno);
1494 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1495 rv = CFGA_USB_DEVCTL;
1496 goto bailout;
1498 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1501 * Create cfga_list_data_t struct.
1503 if ((*ap_id_list =
1504 (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
1505 DPRINTF("cfga_list_ext: malloc for cfga_list_data_t failed. "
1506 "errno: %d\n", errno);
1507 rv = CFGA_USB_ALLOC_FAIL;
1508 goto bailout;
1510 *nlistp = 1;
1514 * Rest of the code fills in the cfga_list_data_t struct.
1517 /* Get /dev/cfg path to corresponding to the physical ap_id */
1518 /* Remember ap_id_log must be freed */
1519 rv = (cfga_usb_ret_t)physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
1520 &ap_id_log, &l_errno, MATCH_MINOR_NAME);
1521 if (rv != 0) {
1522 rv = CFGA_USB_DEVLINK;
1523 goto bailout;
1525 assert(ap_id_log != NULL);
1527 /* Get logical ap-id corresponding to the physical */
1528 if (strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
1529 DPRINTF("cfga_list_ext: devlink doesn't contain /dev/cfg\n");
1530 rv = CFGA_USB_DEVLINK;
1531 goto bailout;
1533 (void) strlcpy((*ap_id_list)->ap_log_id,
1534 /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
1535 sizeof ((*ap_id_list)->ap_log_id));
1536 free(ap_id_log);
1537 ap_id_log = NULL;
1539 (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
1540 sizeof ((*ap_id_list)->ap_phys_id));
1542 switch (devctl_ap_state.ap_rstate) {
1543 case AP_RSTATE_EMPTY:
1544 (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
1545 break;
1546 case AP_RSTATE_DISCONNECTED:
1547 (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
1548 break;
1549 case AP_RSTATE_CONNECTED:
1550 (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
1551 break;
1552 default:
1553 rv = CFGA_USB_STATE;
1554 goto bailout;
1557 switch (devctl_ap_state.ap_ostate) {
1558 case AP_OSTATE_CONFIGURED:
1559 (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
1560 break;
1561 case AP_OSTATE_UNCONFIGURED:
1562 (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
1563 break;
1564 default:
1565 rv = CFGA_USB_STATE;
1566 goto bailout;
1569 switch (devctl_ap_state.ap_condition) {
1570 case AP_COND_OK:
1571 (*ap_id_list)->ap_cond = CFGA_COND_OK;
1572 break;
1573 case AP_COND_FAILING:
1574 (*ap_id_list)->ap_cond = CFGA_COND_FAILING;
1575 break;
1576 case AP_COND_FAILED:
1577 (*ap_id_list)->ap_cond = CFGA_COND_FAILED;
1578 break;
1579 case AP_COND_UNUSABLE:
1580 (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
1581 break;
1582 case AP_COND_UNKNOWN:
1583 (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
1584 break;
1585 default:
1586 rv = CFGA_USB_STATE;
1587 goto bailout;
1590 (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */
1591 (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
1592 (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
1593 (*ap_id_list)->ap_info[0] = '\0';
1595 if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
1596 char *str_p;
1597 size_t str_len;
1599 /* Fill in the info for the -v option display. */
1600 if ((rv = fill_in_ap_info(ap_id, (*ap_id_list)->ap_info,
1601 sizeof ((*ap_id_list)->ap_info))) != CFGA_USB_OK) {
1602 DPRINTF("cfga_list_ext: fill_in_ap_info failed\n");
1603 goto bailout;
1606 /* Fill in ap_type */
1607 if ((rv = do_control_ioctl(ap_id, HUBD_GET_CFGADM_NAME, 0,
1608 (void **)&str_p, &size)) != CFGA_USB_OK) {
1609 DPRINTF("cfga_list_ext: do_control_ioctl failed\n");
1610 goto bailout;
1613 (void) strcpy((*ap_id_list)->ap_type, "usb-");
1614 str_len = strlen((*ap_id_list)->ap_type);
1617 * NOTE: In the cfgadm display the "Type" column is only 12
1618 * chars long. Most USB devices can be displayed here with a
1619 * "usb-" prefix. Only USB keyboard cannot be displayed in
1620 * its entirety as "usb-keybaord" is 13 chars in length.
1621 * It will show up as "usb-kbd".
1623 if (strncasecmp(str_p, "keyboard", 8) != 0) {
1624 (void) strlcpy((*ap_id_list)->ap_type + str_len, str_p,
1625 sizeof ((*ap_id_list)->ap_type) - str_len);
1626 } else {
1627 (void) strlcpy((*ap_id_list)->ap_type + str_len, "kbd",
1628 sizeof ((*ap_id_list)->ap_type) - str_len);
1631 free(str_p);
1632 } else {
1633 (void) strcpy((*ap_id_list)->ap_type,
1634 USB_CFGADM_DEFAULT_AP_TYPE);
1637 return (usb_err_msg(errstring, rv, ap_id, errno));
1638 bailout:
1639 if (*ap_id_list != NULL) {
1640 free(*ap_id_list);
1642 if (ap_id_log != NULL) {
1643 free(ap_id_log);
1646 return (usb_err_msg(errstring, rv, ap_id, errno));
1651 * This routine accepts a variable number of message IDs and constructs
1652 * a corresponding error string which is printed via the message print routine
1653 * argument.
1655 static void
1656 cfga_msg(struct cfga_msg *msgp, const char *str)
1658 int len;
1659 char *q;
1661 if (msgp == NULL || msgp->message_routine == NULL) {
1662 DPRINTF("cfga_msg: msg\n");
1663 return;
1666 if ((len = strlen(str)) == 0) {
1667 DPRINTF("cfga_msg: null str\n");
1668 return;
1671 if ((q = (char *)calloc(len + 1, 1)) == NULL) {
1672 DPRINTF("cfga_msg: null q\n");
1673 return;
1676 (void) strcpy(q, str);
1677 (*msgp->message_routine)(msgp->appdata_ptr, q);
1679 free(q);
1683 /* ARGSUSED */
1684 cfga_err_t
1685 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
1687 DPRINTF("cfga_help:\n");
1688 if (options) {
1689 cfga_msg(msgp, dgettext(TEXT_DOMAIN, usb_help[HELP_UNKNOWN]));
1690 cfga_msg(msgp, options);
1693 cfga_msg(msgp, dgettext(TEXT_DOMAIN, usb_help[HELP_HEADER]));
1694 cfga_msg(msgp, usb_help[HELP_CONFIG]);
1695 cfga_msg(msgp, usb_help[HELP_RESET_SLOT]);
1696 cfga_msg(msgp, usb_help[HELP_CONFIG_SLOT]);
1698 return (CFGA_OK);
1702 static int
1703 usb_confirm(struct cfga_confirm *confp, char *msg)
1705 int rval;
1707 if (confp == NULL || confp->confirm == NULL) {
1708 return (0);
1711 rval = (*confp->confirm)(confp->appdata_ptr, msg);
1712 DPRINTF("usb_confirm: %d\n", rval);
1714 return (rval);
1718 static char *
1719 usb_get_devicepath(const char *ap_id)
1721 char *devpath = NULL;
1722 size_t size;
1723 cfga_usb_ret_t rv;
1725 rv = do_control_ioctl(ap_id, HUBD_GET_DEVICE_PATH, 0,
1726 (void **)&devpath, &size);
1728 if (rv == CFGA_USB_OK) {
1729 DPRINTF("usb_get_devicepath: get device path ioctl ok\n");
1730 return (devpath);
1731 } else {
1732 DPRINTF("usb_get_devicepath: get device path ioctl failed\n");
1733 return (NULL);