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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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 *,
34 extern cfga_usb_ret_t
usb_rcm_online(const char *, char **, char *,
36 extern cfga_usb_ret_t
usb_rcm_remove(const char *, char **, char *,
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
;
53 #define HELP_RESET_SLOT 3
54 #define HELP_CONFIG_SLOT 4
55 #define HELP_UNKNOWN 5
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: ",
67 }; /* End help messages */
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" },
88 { CVT
, CFGA_APID_NOEXIST
, "" },
91 { CVT
, CFGA_LIB_ERROR
, "Cannot determine hub port number for " },
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 " },
110 { CVT
, CFGA_LIB_ERROR
, "Cannot open " },
113 { CVT
, CFGA_ERROR
, "Driver ioctl failed " },
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 " },
128 { CVT
, CFGA_LIB_ERROR
, "Internal error: Unrecognized ap state" },
130 /* CFGA_USB_CONFIG_INVAL */
132 "Specified configuration index unrecognized or exceeds "
133 "maximum available" },
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 */
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 */
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.
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.
193 char *content
= (char *)di_devlink_content(devlink
);
194 char *start
= strstr(content
, "/devices/");
196 /* line content must have minor node */
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
);
215 const char *node_path
,
221 di_devlink_handle_t hdl
;
224 if ((hdl
= di_devlink_init(NULL
, 0)) == NULL
) {
226 return (UCFGA_LIB_ERR
);
232 minor_path
= (char *)node_path
+ strlen("/devices");
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
) {
247 return (UCFGA_LIB_ERR
);
254 /* ========================================================================= */
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
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.
282 set_msg(char **ret_str
, ...)
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
) {
300 DPRINTF("set_msg: realloc failed.\n");
305 (void) strcpy(*ret_str
+ total_len
, str
);
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
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).
337 /* Special case - do nothing. */
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
:
346 case CFGA_USB_CONFIG_INVAL
:
348 case CFGA_USB_OPNOTSUPP
:
349 /* These messages require no additional strings passed. */
350 set_msg(errstring
, ERR_STR(rv
), NULL
);
355 case CFGA_USB_NOT_CONNECTED
:
356 case CFGA_USB_NOT_CONFIGURED
:
357 case CFGA_USB_ALREADY_CONNECTED
:
358 case CFGA_USB_ALREADY_CONFIGURED
:
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
);
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
);
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
);
395 DPRINTF("usb_err_msg: Unrecognized message index: %d\n", rv
);
396 set_msg(errstring
, ERR_STR(CFGA_USB_INTERNAL_ERROR
), NULL
);
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.
415 verify_valid_apid(const char *ap_id
)
423 l_ap_id
= strrchr(ap_id
, *MINOR_SEP
);
426 if (strspn(l_ap_id
, "0123456789.") != strlen(l_ap_id
)) {
427 /* Bad characters in the ap_id. */
431 if (strstr(l_ap_id
, "..") != NULL
) {
432 /* ap_id has 1..2 or more than 2 dots */
441 * Verify the params passed in are valid.
443 static cfga_usb_ret_t
449 if (errstring
!= NULL
) {
453 if (options
!= NULL
) {
454 DPRINTF("verify_params: hardware-specific options not "
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
)
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
);
489 *port
= strtol(port_nbr_str
, NULL
, 10);
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.
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
)
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
;
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",
531 *user_nvlistp
= NULL
; /* Prevent possible incorrect free in */
532 /* cleanup_after_devctl_cmd */
533 rv
= CFGA_USB_NVLIST
;
537 if ((rv
= get_port_num(ap_id
, &port
)) != CFGA_USB_OK
) {
538 DPRINTF("setup_for_devctl_cmd: get_port_num, errno: %d\n",
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
;
554 cleanup_after_devctl_cmd(*devctl_hdl
, *user_nvlistp
);
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
)
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
);
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
);
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.
619 do_control_ioctl(const char *ap_id
, uint_t subcommand
, uint_t arg
,
620 void **descrp
, size_t *sizep
)
625 cfga_usb_ret_t rv
= CFGA_USB_OK
;
626 struct hubd_ioctl_data ioctl_data
;
628 assert(descrp
!= NULL
);
630 assert(sizep
!= NULL
);
632 if ((rv
= get_port_num(ap_id
, &port
)) != CFGA_USB_OK
) {
636 if ((fd
= open(ap_id
, O_RDONLY
)) == -1) {
637 DPRINTF("do_control_ioctl: open failed: errno:%d\n", errno
);
639 if (errno
== EBUSY
) {
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",
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
;
673 if (subcommand
== HUBD_REFRESH_DEVDB
) {
674 /* Already done - no data transfer; nothing left to do. */
678 if ((*descrp
= malloc(*sizep
)) == NULL
) {
679 DPRINTF("do_control_ioctl: malloc failed\n");
680 rv
= CFGA_USB_ALLOC_FAIL
;
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",
705 if (*descrp
!= NULL
) {
710 if (rv
== CFGA_USB_IOCTL
&& errno
== EBUSY
) {
711 rv
= CFGA_USB_BUSY
; /* Provide more useful msg */
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
;
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
;
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
)) !=
755 if (rv
!= CFGA_USB_ZEROLEN
) {
756 DPRINTF("set_configuration: get serial "
757 "no string failed\n");
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
;
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) {
785 /* Save an entry in the USBCONF_FILE */
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) */
796 DPRINTF("set_configuration: add_entry failed\n");
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");
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
)
827 uint_t
*config_val
= NULL
;
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");
835 *config
= *config_val
;
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
)
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 */
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");
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
) {
913 DPRINTF("get iManufacturer failed\n");
917 free_mfg_str
= B_TRUE
;
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
) {
929 DPRINTF("getting iProduct failed\n");
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");
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
) {
950 DPRINTF("HUBD_CFG_DESCR_STR failed\n");
955 /* add ": " to output coz PSARC case says so */
956 if ((cfg_descr
!= NULL
) && rv
!= CFGA_USB_ZEROLEN
) {
958 free_cfg_str
= B_TRUE
;
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
);
975 if ((free_mfg_str
== B_TRUE
) && mfg_str
) {
979 if ((free_prod_str
== B_TRUE
) && prod_str
) {
983 if ((free_cfg_str
== B_TRUE
) && cfg_descr
) {
991 /* ========================================================================== */
998 cfga_cmd_t state_change_cmd
,
1000 const char *options
,
1001 struct cfga_confirm
*confp
,
1002 struct cfga_msg
*msgp
,
1010 nvlist_t
*nvl
= NULL
;
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
);
1024 * All subcommands which can change state of device require
1027 if (geteuid() != 0) {
1032 if ((rv
= setup_for_devctl_cmd(ap_id
, &hdl
, &nvl
, 0)) !=
1037 switch (state_change_cmd
) {
1038 case CFGA_CMD_CONFIGURE
:
1039 if ((rv
= device_configured(hdl
, nvl
, &rstate
)) !=
1040 CFGA_USB_NOT_CONFIGURED
) {
1044 if (rstate
== AP_RSTATE_EMPTY
) {
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
) {
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
++) {
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
;
1077 case CFGA_CMD_UNCONFIGURE
:
1078 if ((rv
= device_connected(hdl
, nvl
, &ostate
)) !=
1079 CFGA_USB_ALREADY_CONNECTED
) {
1083 /* check if it is already unconfigured */
1084 if ((rv
= device_configured(hdl
, nvl
, &rstate
)) ==
1085 CFGA_USB_NOT_CONFIGURED
) {
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
)) {
1098 cleanup_after_devctl_cmd(hdl
, nvl
);
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
;
1110 if ((rv
= usb_rcm_offline(ap_id
, errstring
, devpath
, flags
)) !=
1115 ret
= devctl_ap_unconfigure(hdl
, nvl
);
1117 DPRINTF("cfga_change_state: devctl_ap_unconfigure "
1118 "failed with errno: %d\n", errno
);
1119 rv
= CFGA_USB_DEVCTL
;
1120 if (errno
== EBUSY
) {
1123 (void) usb_rcm_online(ap_id
, errstring
, devpath
, flags
);
1125 (void) usb_rcm_remove(ap_id
, errstring
, devpath
, flags
);
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
)
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
)) {
1149 cleanup_after_devctl_cmd(hdl
, nvl
);
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
;
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
) {
1169 ret
= devctl_ap_disconnect(hdl
, nvl
);
1171 DPRINTF("cfga_change_state: devctl_ap_disconnect "
1172 "failed with errno: %d\n", errno
);
1173 rv
= CFGA_USB_DEVCTL
;
1174 if (errno
== EBUSY
) {
1177 if (ostate
== AP_OSTATE_CONFIGURED
) {
1178 (void) usb_rcm_online(ap_id
, errstring
,
1182 if (ostate
== AP_OSTATE_CONFIGURED
) {
1183 (void) usb_rcm_remove(ap_id
, errstring
,
1189 case CFGA_CMD_CONNECT
:
1191 case CFGA_CMD_UNLOAD
:
1192 (void) cfga_help(msgp
, options
, flags
);
1193 rv
= CFGA_USB_OPNOTSUPP
;
1197 (void) cfga_help(msgp
, options
, flags
);
1198 rv
= CFGA_USB_INTERNAL_ERROR
;
1202 cleanup_after_devctl_cmd(hdl
, nvl
);
1204 return (usb_err_msg(errstring
, rv
, ap_id
, errno
));
1213 const char *options
,
1214 struct cfga_confirm
*confp
,
1215 struct cfga_msg
*msgp
,
1221 nvlist_t
*list
= NULL
;
1223 devctl_hdl_t hdl
= NULL
;
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
1239 if (geteuid() != 0) {
1245 rv
= CFGA_USB_INTERNAL_ERROR
;
1249 if ((rv
= setup_for_devctl_cmd(ap_id
, &hdl
, &list
, 0)) !=
1254 if ((rv
= device_connected(hdl
, list
, &ostate
)) !=
1255 CFGA_USB_ALREADY_CONNECTED
) {
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
);
1267 cleanup_after_devctl_cmd(hdl
, list
);
1271 if (!usb_confirm(confp
, msg
)) {
1272 cleanup_after_devctl_cmd(hdl
, list
);
1276 if ((rv
= reset_device(hdl
, list
)) != CFGA_USB_OK
) {
1279 } else if (strncmp(func
, USB_CONFIG
, sizeof (USB_CONFIG
)) == 0) {
1281 uint_t actual_config
;
1283 char *subopts
, *value
;
1284 uint_t cfg_opt_flag
= B_FALSE
;
1286 /* these are the only valid options */
1287 char *cfg_opts
[] = {
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
);
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
,
1313 config
= strtol(value
,
1320 CFGA_USB_CONFIG_INVAL
;
1324 cfg_opt_flag
= B_TRUE
;
1328 if (value
== NULL
) {
1329 rv
= CFGA_USB_OPNOTSUPP
;
1330 (void) cfga_help(msgp
,
1335 driver
= strdup(value
);
1336 if (driver
== NULL
) {
1338 CFGA_USB_INTERNAL_ERROR
;
1345 rv
= CFGA_USB_OPNOTSUPP
;
1346 (void) cfga_help(msgp
, options
, flags
);
1351 /* config is mandatory */
1352 if (cfg_opt_flag
!= B_TRUE
) {
1353 rv
= CFGA_USB_OPNOTSUPP
;
1354 (void) cfga_help(msgp
, options
, flags
);
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
);
1368 rv
= CFGA_USB_INTERNAL_ERROR
;
1372 if (!usb_confirm(confp
, msg
)) {
1374 cleanup_after_devctl_cmd(hdl
, list
);
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");
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
;
1395 /* Pass current setting to set_configuration */
1396 if ((rv
= get_config(ap_id
, &actual_config
)) != CFGA_USB_OK
) {
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
);
1409 /* Save the configuration settings */
1410 if ((rv
= set_configuration(ap_id
, config
, driver
,
1411 dev_descrp
, errstring
)) != CFGA_USB_OK
) {
1415 /* Reset device to force new config to take effect */
1416 if ((rv
= reset_device(hdl
, list
)) != CFGA_USB_OK
) {
1421 DPRINTF("cfga_private_func: unrecognized command.\n");
1422 (void) cfga_help(msgp
, options
, flags
);
1425 return (CFGA_INVAL
);
1431 cleanup_after_devctl_cmd(hdl
, list
);
1433 return (usb_err_msg(errstring
, rv
, ap_id
, errno
));
1441 const char *options
,
1442 struct cfga_msg
*msgp
,
1446 (void) cfga_help(msgp
, options
, flags
);
1447 return (CFGA_OPNOTSUPP
);
1455 cfga_list_data_t
**ap_id_list
,
1457 const char *options
,
1458 const char *listopts
,
1463 char *ap_id_log
= NULL
;
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
);
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
);
1485 if ((rv
= setup_for_devctl_cmd(ap_id
, &devctl_hdl
, &user_nvlist
,
1486 DC_RDONLY
)) != CFGA_USB_OK
) {
1490 if (devctl_ap_getstate(devctl_hdl
, user_nvlist
, &devctl_ap_state
) ==
1492 DPRINTF("cfga_list_ext: devctl_ap_getstate failed. errno: %d\n",
1494 cleanup_after_devctl_cmd(devctl_hdl
, user_nvlist
);
1495 rv
= CFGA_USB_DEVCTL
;
1498 cleanup_after_devctl_cmd(devctl_hdl
, user_nvlist
);
1501 * Create cfga_list_data_t struct.
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
;
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
);
1522 rv
= CFGA_USB_DEVLINK
;
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
;
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
));
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
;
1546 case AP_RSTATE_DISCONNECTED
:
1547 (*ap_id_list
)->ap_r_state
= CFGA_STAT_DISCONNECTED
;
1549 case AP_RSTATE_CONNECTED
:
1550 (*ap_id_list
)->ap_r_state
= CFGA_STAT_CONNECTED
;
1553 rv
= CFGA_USB_STATE
;
1557 switch (devctl_ap_state
.ap_ostate
) {
1558 case AP_OSTATE_CONFIGURED
:
1559 (*ap_id_list
)->ap_o_state
= CFGA_STAT_CONFIGURED
;
1561 case AP_OSTATE_UNCONFIGURED
:
1562 (*ap_id_list
)->ap_o_state
= CFGA_STAT_UNCONFIGURED
;
1565 rv
= CFGA_USB_STATE
;
1569 switch (devctl_ap_state
.ap_condition
) {
1571 (*ap_id_list
)->ap_cond
= CFGA_COND_OK
;
1573 case AP_COND_FAILING
:
1574 (*ap_id_list
)->ap_cond
= CFGA_COND_FAILING
;
1576 case AP_COND_FAILED
:
1577 (*ap_id_list
)->ap_cond
= CFGA_COND_FAILED
;
1579 case AP_COND_UNUSABLE
:
1580 (*ap_id_list
)->ap_cond
= CFGA_COND_UNUSABLE
;
1582 case AP_COND_UNKNOWN
:
1583 (*ap_id_list
)->ap_cond
= CFGA_COND_UNKNOWN
;
1586 rv
= CFGA_USB_STATE
;
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
) {
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");
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");
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
);
1627 (void) strlcpy((*ap_id_list
)->ap_type
+ str_len
, "kbd",
1628 sizeof ((*ap_id_list
)->ap_type
) - str_len
);
1633 (void) strcpy((*ap_id_list
)->ap_type
,
1634 USB_CFGADM_DEFAULT_AP_TYPE
);
1637 return (usb_err_msg(errstring
, rv
, ap_id
, errno
));
1639 if (*ap_id_list
!= NULL
) {
1642 if (ap_id_log
!= NULL
) {
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
1656 cfga_msg(struct cfga_msg
*msgp
, const char *str
)
1661 if (msgp
== NULL
|| msgp
->message_routine
== NULL
) {
1662 DPRINTF("cfga_msg: msg\n");
1666 if ((len
= strlen(str
)) == 0) {
1667 DPRINTF("cfga_msg: null str\n");
1671 if ((q
= (char *)calloc(len
+ 1, 1)) == NULL
) {
1672 DPRINTF("cfga_msg: null q\n");
1676 (void) strcpy(q
, str
);
1677 (*msgp
->message_routine
)(msgp
->appdata_ptr
, q
);
1685 cfga_help(struct cfga_msg
*msgp
, const char *options
, cfga_flags_t flags
)
1687 DPRINTF("cfga_help:\n");
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
]);
1703 usb_confirm(struct cfga_confirm
*confp
, char *msg
)
1707 if (confp
== NULL
|| confp
->confirm
== NULL
) {
1711 rval
= (*confp
->confirm
)(confp
->appdata_ptr
, msg
);
1712 DPRINTF("usb_confirm: %d\n", rval
);
1719 usb_get_devicepath(const char *ap_id
)
1721 char *devpath
= NULL
;
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");
1732 DPRINTF("usb_get_devicepath: get device path ioctl failed\n");