1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "cfga_usb.h" 30 31 32 /* function prototypes */ 33 cfga_err_t usb_err_msg(char **, cfga_usb_ret_t, const char *, int); 34 extern cfga_usb_ret_t usb_rcm_offline(const char *, char **, char *, 35 cfga_flags_t); 36 extern cfga_usb_ret_t usb_rcm_online(const char *, char **, char *, 37 cfga_flags_t); 38 extern cfga_usb_ret_t usb_rcm_remove(const char *, char **, char *, 39 cfga_flags_t); 40 static int usb_confirm(struct cfga_confirm *, char *); 41 static char *usb_get_devicepath(const char *); 42 43 /* 44 * This file contains the entry points to the plugin as defined in the 45 * config_admin(3X) man page. 46 */ 47 48 /* 49 * Set the version number for the cfgadm library's use. 50 */ 51 int cfga_version = CFGA_HSL_V2; 52 53 #define HELP_HEADER 1 54 #define HELP_CONFIG 2 55 #define HELP_RESET_SLOT 3 56 #define HELP_CONFIG_SLOT 4 57 #define HELP_UNKNOWN 5 58 59 /* Help messages */ 60 static char * 61 usb_help[] = { 62 NULL, 63 "USB specific commands:\n", 64 " cfgadm -c [configure|unconfigure|disconnect] ap_id [ap_id...]\n", 65 " cfgadm -x usb_reset ap_id [ap_id...]\n", 66 " cfgadm -x usb_config -o config=<index of desired configuration> ap_id\n", 67 "\tunknown command or option: ", 68 NULL 69 }; /* End help messages */ 70 71 /* Error messages */ 72 static msgcvt_t 73 usb_error_msgs[] = { 74 /* CFGA_USB_OK */ 75 { CVT, CFGA_OK, "ok" }, 76 77 /* CFGA_USB_UNKNOWN */ 78 { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" }, 79 80 /* CFGA_USB_INTERNAL_ERROR */ 81 { CVT, CFGA_LIB_ERROR, "Internal error" }, 82 83 /* CFGA_USB_OPTIONS */ 84 { CVT, CFGA_ERROR, "Hardware specific options not supported" }, 85 86 /* CFGA_USB_DYNAMIC_AP */ 87 { CVT, CFGA_INVAL, "Dynamic attachment points not supported" }, 88 89 /* CFGA_USB_AP */ 90 { CVT, CFGA_APID_NOEXIST, "" }, 91 92 /* CFGA_USB_PORT */ 93 { CVT, CFGA_LIB_ERROR, "Cannot determine hub port number for " }, 94 95 /* CFGA_USB_DEVCTL */ 96 { CVT, CFGA_ERROR, "Cannot issue devctl to " }, 97 98 /* CFGA_USB_NOT_CONNECTED */ 99 { CVT, CFGA_INVAL, "No device connected to " }, 100 101 /* CFGA_USB_NOT_CONFIGURED */ 102 { CVT, CFGA_INVAL, "No device configured to " }, 103 104 /* CFGA_USB_ALREADY_CONNECTED */ 105 { CVT, CFGA_INSUFFICENT_CONDITION, 106 "Device already connected; cannot connect again " }, 107 108 /* CFGA_USB_ALREADY_CONFIGURED */ 109 { CVT, CFGA_INVAL, "device already configured for " }, 110 111 /* CFGA_USB_OPEN */ 112 { CVT, CFGA_LIB_ERROR, "Cannot open " }, 113 114 /* CFGA_USB_IOCTL */ 115 { CVT, CFGA_ERROR, "Driver ioctl failed " }, 116 117 /* CFGA_USB_BUSY */ 118 { CVT, CFGA_SYSTEM_BUSY, "" }, 119 120 /* CFGA_USB_ALLOC_FAIL */ 121 { CVT, CFGA_LIB_ERROR, "Memory allocation failure" }, 122 123 /* CFGA_USB_OPNOTSUPP */ 124 { CVT, CFGA_OPNOTSUPP, "Operation not supported" }, 125 126 /* CFGA_USB_DEVLINK */ 127 { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " }, 128 129 /* CFGA_USB_STATE */ 130 { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" }, 131 132 /* CFGA_USB_CONFIG_INVAL */ 133 { CVT, CFGA_ERROR, 134 "Specified configuration index unrecognized or exceeds " 135 "maximum available" }, 136 137 /* CFGA_USB_PRIV */ 138 { CVT, CFGA_PRIV, "" }, 139 140 /* CFGA_USB_NVLIST */ 141 { CVT, CFGA_ERROR, "Internal error (nvlist)" }, 142 143 /* CFGA_USB_ZEROLEN */ 144 { CVT, CFGA_ERROR, "Internal error (zerolength string)" }, 145 146 /* CFGA_USB_CONFIG_FILE */ 147 { CVT, CFGA_ERROR, 148 "Cannot open/fstat/read USB system configuration file" }, 149 150 /* CFGA_USB_LOCK_FILE */ 151 { CVT, CFGA_ERROR, "Cannot lock USB system configuration file" }, 152 153 /* CFGA_USB_UNLOCK_FILE */ 154 { CVT, CFGA_ERROR, "Cannot unlock USB system configuration file" }, 155 156 /* CFGA_USB_ONE_CONFIG */ 157 { CVT, CFGA_ERROR, 158 "Operation not supported for devices with one configuration" }, 159 160 /* CFGA_USB_RCM_HANDLE Errors */ 161 { CVT, CFGA_ERROR, "cannot get RCM handle"}, 162 163 /* CFGA_USB_RCM_ONLINE */ 164 { CVT, CFGA_SYSTEM_BUSY, "failed to online: "}, 165 166 /* CFGA_USB_RCM_OFFLINE */ 167 { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "}, 168 169 /* CFGA_USB_RCM_INFO */ 170 { CVT, CFGA_ERROR, "failed to query: "} 171 172 }; /* End error messages */ 173 174 175 /* ========================================================================= */ 176 /* 177 * The next two funcs imported verbatim from cfgadm_scsi. 178 * physpath_to_devlink is the only func directly used by cfgadm_usb. 179 * get_link supports it. 180 */ 181 182 /* 183 * Routine to search the /dev directory or a subtree of /dev. 184 */ 185 static int 186 get_link(di_devlink_t devlink, void *arg) 187 { 188 walk_link_t *larg = (walk_link_t *)arg; 189 190 /* 191 * When path is specified, it's the node path without minor 192 * name. Therefore, the ../.. prefixes needs to be stripped. 193 */ 194 if (larg->path) { 195 char *content = (char *)di_devlink_content(devlink); 196 char *start = strstr(content, "/devices/"); 197 198 /* line content must have minor node */ 199 if (start == NULL || 200 strncmp(start, larg->path, larg->len) != 0 || 201 start[larg->len] != ':') { 202 203 return (DI_WALK_CONTINUE); 204 } 205 } 206 207 *(larg->linkpp) = strdup(di_devlink_path(devlink)); 208 209 return (DI_WALK_TERMINATE); 210 } 211 212 213 /* ARGSUSED */ 214 static ucfga_ret_t 215 physpath_to_devlink( 216 const char *basedir, 217 const char *node_path, 218 char **logpp, 219 int *l_errnop, 220 int match_minor) 221 { 222 walk_link_t larg; 223 di_devlink_handle_t hdl; 224 char *minor_path; 225 226 if ((hdl = di_devlink_init(NULL, 0)) == NULL) { 227 *l_errnop = errno; 228 return (UCFGA_LIB_ERR); 229 } 230 231 *logpp = NULL; 232 larg.linkpp = logpp; 233 if (match_minor) { 234 minor_path = (char *)node_path + strlen("/devices"); 235 larg.path = NULL; 236 } else { 237 minor_path = NULL; 238 larg.len = strlen(node_path); 239 larg.path = (char *)node_path; 240 } 241 242 (void) di_devlink_walk(hdl, "^cfg/", minor_path, DI_PRIMARY_LINK, 243 (void *)&larg, get_link); 244 245 di_devlink_fini(&hdl); 246 247 if (*logpp == NULL) { 248 *l_errnop = errno; 249 return (UCFGA_LIB_ERR); 250 } 251 252 return (UCFGA_OK); 253 } 254 255 256 /* ========================================================================= */ 257 /* Utilities */ 258 259 /* 260 * Given the index into a table (msgcvt_t) of messages, get the message 261 * string, converting it to the proper locale if necessary. 262 * NOTE: See cfga_usb.h 263 */ 264 static const char * 265 get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size) 266 { 267 if (msg_index >= tbl_size) { 268 DPRINTF("get_error_msg: bad error msg index: %d\n", msg_index); 269 msg_index = CFGA_USB_UNKNOWN; 270 } 271 272 return ((msg_tbl[msg_index].intl) ? 273 dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) : 274 msg_tbl[msg_index].msgstr); 275 } 276 277 278 /* 279 * Allocates and creates a message string (in *ret_str), 280 * by concatenating all the (char *) args together, in order. 281 * Last arg MUST be NULL. 282 */ 283 static void 284 set_msg(char **ret_str, ...) 285 { 286 char *str; 287 size_t total_len; 288 va_list valist; 289 290 va_start(valist, ret_str); 291 292 total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str); 293 294 while ((str = va_arg(valist, char *)) != NULL) { 295 size_t len = strlen(str); 296 char *old_str = *ret_str; 297 298 *ret_str = (char *)realloc(*ret_str, total_len + len + 1); 299 if (*ret_str == NULL) { 300 /* We're screwed */ 301 free(old_str); 302 DPRINTF("set_msg: realloc failed.\n"); 303 va_end(valist); 304 return; 305 } 306 307 strcpy(*ret_str + total_len, str); 308 total_len += len; 309 } 310 311 va_end(valist); 312 } 313 314 315 /* 316 * Error message handling. 317 * For the rv passed in, looks up the corresponding error message string(s), 318 * internationalized it if necessary, and concatenates it into a new 319 * memory buffer, and points *errstring to it. 320 * Note not all rvs will result in an error message return, as not all 321 * error conditions warrant a USB-specific error message. 322 * 323 * Some messages may display ap_id or errno, which is why they are passed 324 * in. 325 */ 326 cfga_err_t 327 usb_err_msg(char **errstring, cfga_usb_ret_t rv, const char *ap_id, int l_errno) 328 { 329 if (errstring == NULL) { 330 331 return (usb_error_msgs[rv].cfga_err); 332 } 333 334 /* 335 * Generate the appropriate USB-specific error message(s) (if any). 336 */ 337 switch (rv) { 338 case CFGA_USB_OK: 339 /* Special case - do nothing. */ 340 break; 341 342 case CFGA_USB_UNKNOWN: 343 case CFGA_USB_DYNAMIC_AP: 344 case CFGA_USB_INTERNAL_ERROR: 345 case CFGA_USB_OPTIONS: 346 case CFGA_USB_ALLOC_FAIL: 347 case CFGA_USB_STATE: 348 case CFGA_USB_CONFIG_INVAL: 349 case CFGA_USB_PRIV: 350 case CFGA_USB_OPNOTSUPP: 351 /* These messages require no additional strings passed. */ 352 set_msg(errstring, ERR_STR(rv), NULL); 353 break; 354 355 case CFGA_USB_AP: 356 case CFGA_USB_PORT: 357 case CFGA_USB_NOT_CONNECTED: 358 case CFGA_USB_NOT_CONFIGURED: 359 case CFGA_USB_ALREADY_CONNECTED: 360 case CFGA_USB_ALREADY_CONFIGURED: 361 case CFGA_USB_BUSY: 362 case CFGA_USB_DEVLINK: 363 case CFGA_USB_RCM_HANDLE: 364 case CFGA_USB_RCM_ONLINE: 365 case CFGA_USB_RCM_OFFLINE: 366 case CFGA_USB_RCM_INFO: 367 case CFGA_USB_DEVCTL: 368 /* These messages also print ap_id. */ 369 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL); 370 break; 371 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. */ 377 { 378 char *errno_str = l_errno ? strerror(l_errno) : ""; 379 380 set_msg(errstring, ERR_STR(rv), errno_str, 381 l_errno ? "\n" : "", NULL); 382 break; 383 } 384 385 case CFGA_USB_OPEN: 386 /* These messages also apid and errno. */ 387 { 388 char *errno_str = l_errno ? strerror(l_errno) : ""; 389 390 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n", 391 errno_str, l_errno ? "\n" : "", NULL); 392 break; 393 } 394 395 default: 396 DPRINTF("usb_err_msg: Unrecognized message index: %d\n", rv); 397 set_msg(errstring, ERR_STR(CFGA_USB_INTERNAL_ERROR), NULL); 398 399 } /* end switch */ 400 401 /* 402 * Determine the proper error code to send back to the cfgadm library. 403 */ 404 return (usb_error_msgs[rv].cfga_err); 405 } 406 407 408 /* 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. 412 * 413 * Note the library always calls the plugin with a physical ap_id. 414 */ 415 static int 416 verify_valid_apid(const char *ap_id) 417 { 418 char *l_ap_id; 419 420 if (ap_id == NULL) { 421 return (-1); 422 } 423 424 l_ap_id = strrchr(ap_id, *MINOR_SEP); 425 l_ap_id++; 426 427 if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) { 428 /* Bad characters in the ap_id. */ 429 return (-1); 430 } 431 432 if (strstr(l_ap_id, "..") != NULL) { 433 /* ap_id has 1..2 or more than 2 dots */ 434 return (-1); 435 } 436 437 return (0); 438 } 439 440 441 /* 442 * Verify the params passed in are valid. 443 */ 444 static cfga_usb_ret_t 445 verify_params( 446 const char *ap_id, 447 const char *options, 448 char **errstring) 449 { 450 if (errstring != NULL) { 451 *errstring = NULL; 452 } 453 454 if (options != NULL) { 455 DPRINTF("verify_params: hardware-specific options not " 456 "supported.\n"); 457 return (CFGA_USB_OPTIONS); 458 } 459 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); 464 } 465 466 if (verify_valid_apid(ap_id) != 0) { 467 DPRINTF("verify_params: not a USB ap_id.\n"); 468 return (CFGA_USB_AP); 469 } 470 471 return (CFGA_USB_OK); 472 } 473 474 475 /* 476 * Takes a validated ap_id and extracts the port number. 477 */ 478 static cfga_usb_ret_t 479 get_port_num(const char *ap_id, uint_t *port) 480 { 481 char *port_nbr_str; 482 char *temp; 483 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); 487 } 488 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); 494 } 495 496 return (CFGA_USB_OK); 497 } 498 499 500 /* 501 * Pair of routines to set up for/clean up after a devctl_ap_* lib call. 502 */ 503 static void 504 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist) 505 { 506 if (user_nvlist != NULL) { 507 nvlist_free(user_nvlist); 508 } 509 if (devctl_hdl != NULL) { 510 devctl_release(devctl_hdl); 511 } 512 } 513 514 515 static cfga_usb_ret_t 516 setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl, 517 nvlist_t **user_nvlistp, uint_t oflag) 518 { 519 uint32_t port; 520 cfga_usb_ret_t rv = CFGA_USB_OK; 521 522 DPRINTF("setup_for_devctl_cmd: oflag=%d\n", oflag); 523 524 /* Get a handle to the ap */ 525 if ((*devctl_hdl = devctl_ap_acquire((char *)ap_id, oflag)) == NULL) { 526 DPRINTF("setup_for_devctl_cmd: devctl_ap_acquire failed with " 527 "errno: %d\n", errno); 528 rv = CFGA_USB_DEVCTL; 529 goto bailout; 530 } 531 532 /* Set up to pass port number down to driver */ 533 if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) { 534 DPRINTF("setup_for_devctl: nvlist_alloc failed, errno: %d\n", 535 errno); 536 *user_nvlistp = NULL; /* Prevent possible incorrect free in */ 537 /* cleanup_after_devctl_cmd */ 538 rv = CFGA_USB_NVLIST; 539 goto bailout; 540 } 541 542 if ((rv = get_port_num(ap_id, &port)) != CFGA_USB_OK) { 543 DPRINTF("setup_for_devctl_cmd: get_port_num, errno: %d\n", 544 errno); 545 goto bailout; 546 } 547 548 /* creates an int32_t entry */ 549 if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) { 550 DPRINTF("setup_for_devctl_cmd: nvlist_add_int32 failed. " 551 "errno: %d\n", errno); 552 rv = CFGA_USB_NVLIST; 553 goto bailout; 554 } 555 556 return (rv); 557 558 bailout: 559 cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp); 560 561 return (rv); 562 } 563 564 565 /* 566 * Ensure that there's a device actually connected to the ap 567 */ 568 static cfga_usb_ret_t 569 device_configured(devctl_hdl_t hdl, nvlist_t *nvl, ap_rstate_t *rstate) 570 { 571 cfga_usb_ret_t rv; 572 devctl_ap_state_t devctl_ap_state; 573 574 DPRINTF("device_configured:\n"); 575 if (devctl_ap_getstate(hdl, nvl, &devctl_ap_state) == -1) { 576 DPRINTF("devctl_ap_getstate failed, errno: %d\n", errno); 577 return (CFGA_USB_DEVCTL); 578 } 579 580 rv = CFGA_USB_ALREADY_CONFIGURED; 581 *rstate = devctl_ap_state.ap_rstate; 582 if (devctl_ap_state.ap_ostate != AP_OSTATE_CONFIGURED) { 583 return (CFGA_USB_NOT_CONFIGURED); 584 } 585 586 return (rv); 587 } 588 589 590 /* 591 * Ensure that there's a device actually connected to the ap 592 */ 593 static cfga_usb_ret_t 594 device_connected(devctl_hdl_t hdl, nvlist_t *list, ap_ostate_t *ostate) 595 { 596 cfga_usb_ret_t rv = CFGA_USB_ALREADY_CONNECTED; 597 devctl_ap_state_t devctl_ap_state; 598 599 DPRINTF("device_connected:\n"); 600 601 if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) { 602 DPRINTF("devctl_ap_getstate failed, errno: %d\n", errno); 603 return (CFGA_USB_DEVCTL); 604 } 605 606 *ostate = devctl_ap_state.ap_ostate; 607 if (devctl_ap_state.ap_rstate != AP_RSTATE_CONNECTED) { 608 return (CFGA_USB_NOT_CONNECTED); 609 } 610 611 return (rv); 612 } 613 614 615 /* 616 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of 617 * the data to be returned, allocate a buffer, then get the data. 618 * Returns *descrp (which must be freed) and size. 619 * 620 * Note USB_DESCR_TYPE_STRING returns an ASCII NULL-terminated string, 621 * not a string descr. 622 */ 623 cfga_usb_ret_t 624 do_control_ioctl(const char *ap_id, uint_t subcommand, uint_t arg, 625 void **descrp, size_t *sizep) 626 { 627 int fd = -1; 628 uint_t port; 629 uint32_t local_size; 630 cfga_usb_ret_t rv = CFGA_USB_OK; 631 struct hubd_ioctl_data ioctl_data; 632 633 assert(descrp != NULL); 634 *descrp = NULL; 635 assert(sizep != NULL); 636 637 if ((rv = get_port_num(ap_id, &port)) != CFGA_USB_OK) { 638 goto bailout; 639 } 640 641 if ((fd = open(ap_id, O_RDONLY)) == -1) { 642 DPRINTF("do_control_ioctl: open failed: errno:%d\n", errno); 643 rv = CFGA_USB_OPEN; 644 if (errno == EBUSY) { 645 rv = CFGA_USB_BUSY; 646 } 647 goto bailout; 648 } 649 650 ioctl_data.cmd = subcommand; 651 ioctl_data.port = port; 652 ioctl_data.misc_arg = (uint_t)arg; 653 654 /* 655 * Find out how large a buf we need to get the data. 656 * 657 * Note the ioctls only accept/return a 32-bit int for a get_size 658 * to avoid 32/64 and BE/LE issues. 659 */ 660 ioctl_data.get_size = B_TRUE; 661 ioctl_data.buf = (caddr_t)&local_size; 662 ioctl_data.bufsiz = sizeof (local_size); 663 664 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) { 665 DPRINTF("do_control_ioctl: size ioctl failed: errno:%d\n", 666 errno); 667 rv = CFGA_USB_IOCTL; 668 goto bailout; 669 } 670 *sizep = local_size; 671 672 if (subcommand == USB_DESCR_TYPE_STRING && 673 arg == HUBD_CFG_DESCR_STR && local_size == 0) { 674 /* Zero-length data - nothing to do. */ 675 rv = CFGA_USB_ZEROLEN; 676 goto bailout; 677 } 678 if (subcommand == HUBD_REFRESH_DEVDB) { 679 /* Already done - no data transfer; nothing left to do. */ 680 goto bailout; 681 } 682 683 if ((*descrp = malloc(*sizep)) == NULL) { 684 DPRINTF("do_control_ioctl: malloc failed\n"); 685 rv = CFGA_USB_ALLOC_FAIL; 686 goto bailout; 687 } 688 689 /* Get the data */ 690 ioctl_data.get_size = B_FALSE; 691 ioctl_data.buf = *descrp; 692 ioctl_data.bufsiz = *sizep; 693 694 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) { 695 DPRINTF("do_control_ioctl: ioctl failed: errno:%d\n", 696 errno); 697 rv = CFGA_USB_IOCTL; 698 goto bailout; 699 } 700 701 (void) close(fd); 702 703 return (rv); 704 705 706 bailout: 707 if (fd != -1) { 708 (void) close(fd); 709 } 710 if (*descrp != NULL) { 711 free(*descrp); 712 *descrp = NULL; 713 } 714 715 if (rv == CFGA_USB_IOCTL && errno == EBUSY) { 716 rv = CFGA_USB_BUSY; /* Provide more useful msg */ 717 } 718 719 return (rv); 720 } 721 722 723 /* ========================================================================= */ 724 /* 725 * Support funcs called directly from cfga_* entry points. 726 */ 727 728 729 /* 730 * Invoked from cfga_private_func. 731 * Modify the USB persistant configuration file so that the device 732 * represented by ap_id will henceforth be initialized to the desired 733 * configuration setting (configuration index). 734 */ 735 static cfga_usb_ret_t 736 set_configuration(const char *ap_id, uint_t config, char *driver, 737 usb_dev_descr_t *descrp, char **errstring) 738 { 739 char *serial_no = NULL; 740 char *dev_path = NULL; 741 char *tmp; 742 size_t size; 743 cfga_usb_ret_t rv = CFGA_USB_OK; 744 745 DPRINTF("set_configuration: ap_id: %s, config:%d\n", ap_id, config); 746 747 /* Only one bNumConfigurations, don't allow this operation */ 748 if (descrp->bNumConfigurations == 1) { 749 DPRINTF("device supports %d configurations\n", 750 descrp->bNumConfigurations); 751 rv = CFGA_USB_ONE_CONFIG; 752 goto bailout; 753 } 754 755 /* get the serial number string if it exists */ 756 if (descrp->iSerialNumber != 0) { 757 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING, 758 HUBD_SERIALNO_STR, (void **)&serial_no, &size)) != 759 CFGA_USB_OK) { 760 if (rv != CFGA_USB_ZEROLEN) { 761 DPRINTF("set_configuration: get serial " 762 "no string failed\n"); 763 goto bailout; 764 } 765 } 766 } 767 768 dev_path = usb_get_devicepath(ap_id); 769 if (dev_path == NULL) { 770 DPRINTF("get device path failed\n"); 771 rv = CFGA_USB_DEVCTL; 772 goto bailout; 773 } 774 775 DPRINTF("calling add_entry: vid: 0x%x pid:0x%x config:0x%x,", 776 descrp->idVendor, descrp->idProduct, config); 777 DPRINTF("serial_no: %s\n\tdev_path: %s\n\tdriver: %s\n", serial_no ? 778 serial_no : "", dev_path ? dev_path : "", driver ? driver : ""); 779 780 /* 781 * the devicepath should be an absolute path. 782 * So, if path has leading "/devices" - nuke it. 783 */ 784 if (strncmp(dev_path, "/devices/", 9) == 0) { 785 tmp = dev_path + 8; 786 } else { 787 tmp = dev_path; 788 } 789 790 /* Save an entry in the USBCONF_FILE */ 791 if ((rv = add_entry( 792 "enable", /* Always to "enable" */ 793 descrp->idVendor, /* vendorId */ 794 descrp->idProduct, /* ProductId */ 795 config, /* new cfgndx */ 796 serial_no, /* serial no string */ 797 tmp, /* device path */ 798 driver, /* Driver (optional) */ 799 errstring)) 800 != CFGA_USB_OK) { 801 DPRINTF("set_configuration: add_entry failed\n"); 802 goto bailout; 803 } 804 805 /* Notify hubd that it needs to refresh its db. */ 806 if ((rv = do_control_ioctl(ap_id, HUBD_REFRESH_DEVDB, NULL, 807 (void **)&dev_path, &size)) != CFGA_USB_OK) { 808 DPRINTF("set_configuration: HUBD_REFRESH_DEVDB failed\n"); 809 goto bailout; 810 } 811 812 bailout: 813 if (dev_path) { 814 free(dev_path); 815 } 816 if (serial_no) { 817 free(serial_no); 818 } 819 820 return (rv); 821 } 822 823 824 /* 825 * Invoked from cfga_private_func() and fill_in_ap_info(). 826 * Call into USBA and get the current configuration setting for this device, 827 */ 828 static cfga_usb_ret_t 829 get_config(const char *ap_id, uint_t *config) 830 { 831 size_t size; 832 uint_t *config_val = NULL; 833 cfga_usb_ret_t rv; 834 835 if ((rv = do_control_ioctl(ap_id, HUBD_GET_CURRENT_CONFIG, NULL, 836 (void **)&config_val, &size)) != CFGA_USB_OK) { 837 DPRINTF("get_config: get current config descr failed\n"); 838 goto bailout; 839 } 840 *config = *config_val; 841 842 bailout: 843 free(config_val); 844 return (rv); 845 } 846 847 848 /* 849 * Invoked from cfga_private_func. 850 * it does an unconfigure of the device followed by a configure, 851 * thus essentially resetting the device. 852 */ 853 static cfga_usb_ret_t 854 reset_device(devctl_hdl_t devctl_hdl, nvlist_t *nvl) 855 { 856 cfga_usb_ret_t rv; 857 858 DPRINTF("reset_device: \n"); 859 860 /* 861 * Disconnect and reconfigure the device. 862 * Note this forces the new default config to take effect. 863 */ 864 if (devctl_ap_disconnect(devctl_hdl, nvl) != 0) { 865 DPRINTF("devctl_ap_unconfigure failed, errno: %d\n", errno); 866 rv = CFGA_USB_DEVCTL; 867 if (errno == EBUSY) { 868 rv = CFGA_USB_BUSY; /* Provide more useful msg */ 869 } 870 871 return (rv); 872 } 873 874 if (devctl_ap_configure(devctl_hdl, nvl) != 0) { 875 DPRINTF(" devctl_ap_configure failed, errno = %d\n", errno); 876 return (CFGA_USB_DEVCTL); 877 } 878 879 return (CFGA_USB_OK); 880 } 881 882 883 /* 884 * Called from cfga_list_ext. 885 * Fills in the 'misc_info' field in the cfga buffer (displayed with -lv). 886 */ 887 static cfga_usb_ret_t 888 fill_in_ap_info(const char *ap_id, char *info_buf, size_t info_size) 889 { 890 char *mfg_str = NULL; /* iManufacturer */ 891 char *prod_str = NULL; /* iProduct */ 892 char *cfg_descr = NULL; /* iConfiguration */ 893 uint_t config; /* curr cfg index */ 894 size_t size; /* tmp stuff */ 895 boolean_t flag; /* wether to print ":" or not */ 896 boolean_t free_mfg_str = B_FALSE; 897 boolean_t free_prod_str = B_FALSE; 898 boolean_t free_cfg_str = B_FALSE; 899 cfga_usb_ret_t rv = CFGA_USB_OK; 900 usb_dev_descr_t *dev_descrp = NULL; /* device descriptor */ 901 902 DPRINTF("fill_in_ap_info:\n"); 903 904 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_DEV, NULL, 905 (void **)&dev_descrp, &size)) != CFGA_USB_OK) { 906 DPRINTF("fill_in_ap_info: get dev descr failed\n"); 907 return (rv); 908 } 909 910 /* iManufacturer */ 911 mfg_str = USB_UNDEF_STR; 912 if (dev_descrp->iManufacturer != 0) { 913 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING, 914 HUBD_MFG_STR, (void **)&mfg_str, &size)) != CFGA_USB_OK) { 915 if (rv == CFGA_USB_ZEROLEN) { 916 rv = CFGA_USB_OK; 917 } else { 918 DPRINTF("get iManufacturer failed\n"); 919 goto bailout; 920 } 921 } 922 free_mfg_str = B_TRUE; 923 } 924 925 /* iProduct */ 926 prod_str = USB_UNDEF_STR; 927 if (dev_descrp->iProduct != 0) { 928 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING, 929 HUBD_PRODUCT_STR, (void **)&prod_str, 930 &size)) != CFGA_USB_OK) { 931 if (rv == CFGA_USB_ZEROLEN) { 932 rv = CFGA_USB_OK; 933 } else { 934 DPRINTF("getting iProduct failed\n"); 935 goto bailout; 936 } 937 } 938 free_prod_str = B_TRUE; 939 } 940 941 /* Current conifguration */ 942 if ((rv = get_config(ap_id, &config)) != CFGA_USB_OK) { 943 DPRINTF("get_config failed\n"); 944 goto bailout; 945 } 946 947 /* Configuration string descriptor */ 948 cfg_descr = USB_NO_CFG_STR; 949 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_STRING, 950 HUBD_CFG_DESCR_STR, (void **)&cfg_descr, &size)) != CFGA_USB_OK) { 951 if (rv == CFGA_USB_ZEROLEN) { 952 rv = CFGA_USB_OK; 953 flag = B_TRUE; 954 } else { 955 DPRINTF("HUBD_CFG_DESCR_STR failed\n"); 956 goto bailout; 957 } 958 } 959 960 /* add ": " to output coz PSARC case says so */ 961 if ((cfg_descr != (char *)NULL) && rv != CFGA_USB_ZEROLEN) { 962 flag = B_TRUE; 963 free_cfg_str = B_TRUE; 964 } else { 965 flag = B_FALSE; 966 cfg_descr = USB_NO_CFG_STR; 967 } 968 969 /* Dump local buf into passed-in buf. */ 970 (void) snprintf(info_buf, info_size, 971 "Mfg: %s Product: %s NConfigs: %d Config: %d %s%s", mfg_str, 972 prod_str, dev_descrp->bNumConfigurations, config, 973 (flag == B_TRUE) ? ": " : "", cfg_descr); 974 975 bailout: 976 if (dev_descrp) { 977 free(dev_descrp); 978 } 979 980 if ((free_mfg_str == B_TRUE) && mfg_str) { 981 free(mfg_str); 982 } 983 984 if ((free_prod_str == B_TRUE) && prod_str) { 985 free(prod_str); 986 } 987 988 if ((free_cfg_str == B_TRUE) && cfg_descr) { 989 free(cfg_descr); 990 } 991 992 return (rv); 993 } 994 995 996 /* ========================================================================== */ 997 /* Entry points */ 998 999 1000 /*ARGSUSED*/ 1001 cfga_err_t 1002 cfga_change_state( 1003 cfga_cmd_t state_change_cmd, 1004 const char *ap_id, 1005 const char *options, 1006 struct cfga_confirm *confp, 1007 struct cfga_msg *msgp, 1008 char **errstring, 1009 cfga_flags_t flags) 1010 { 1011 int ret; 1012 int len; 1013 char *msg; 1014 char *devpath; 1015 nvlist_t *nvl = NULL; 1016 ap_rstate_t rstate; 1017 ap_ostate_t ostate; 1018 devctl_hdl_t hdl = NULL; 1019 cfga_usb_ret_t rv = CFGA_USB_OK; 1020 1021 DPRINTF("cfga_change_state:\n"); 1022 1023 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_USB_OK) { 1024 (void) cfga_help(msgp, options, flags); 1025 goto bailout; 1026 } 1027 1028 /* 1029 * All subcommands which can change state of device require 1030 * root privileges. 1031 */ 1032 if (geteuid() != 0) { 1033 rv = CFGA_USB_PRIV; 1034 goto bailout; 1035 } 1036 1037 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl, 0)) != 1038 CFGA_USB_OK) { 1039 goto bailout; 1040 } 1041 1042 switch (state_change_cmd) { 1043 case CFGA_CMD_CONFIGURE: 1044 if ((rv = device_configured(hdl, nvl, &rstate)) != 1045 CFGA_USB_NOT_CONFIGURED) { 1046 goto bailout; 1047 } 1048 1049 if (rstate == AP_RSTATE_EMPTY) { 1050 goto bailout; 1051 } 1052 rv = CFGA_USB_OK; /* Other statuses don't matter */ 1053 1054 if (devctl_ap_configure(hdl, nvl) != 0) { 1055 DPRINTF("cfga_change_state: devctl_ap_configure " 1056 "failed. errno: %d\n", errno); 1057 rv = CFGA_USB_DEVCTL; 1058 } 1059 1060 devpath = usb_get_devicepath(ap_id); 1061 if (devpath == NULL) { 1062 int i; 1063 /* 1064 * try for some time as USB hotplug thread 1065 * takes a while to create the path 1066 * and then eventually give up 1067 */ 1068 for (i = 0; i < 12 && (devpath == NULL); i++) { 1069 sleep(6); 1070 devpath = usb_get_devicepath(ap_id); 1071 } 1072 1073 if (devpath == NULL) { 1074 DPRINTF("cfga_change_state: get device " 1075 "path failed i = %d\n", i); 1076 rv = CFGA_USB_DEVCTL; 1077 break; 1078 } 1079 } 1080 S_FREE(devpath); 1081 break; 1082 case CFGA_CMD_UNCONFIGURE: 1083 if ((rv = device_connected(hdl, nvl, &ostate)) != 1084 CFGA_USB_ALREADY_CONNECTED) { 1085 goto bailout; 1086 } 1087 1088 /* check if it is already unconfigured */ 1089 if ((rv = device_configured(hdl, nvl, &rstate)) == 1090 CFGA_USB_NOT_CONFIGURED) { 1091 goto bailout; 1092 } 1093 rv = CFGA_USB_OK; /* Other statuses don't matter */ 1094 1095 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) + 1096 strlen("Unconfigure") + strlen(ap_id); 1097 if ((msg = (char *)calloc(len + 3, 1)) != NULL) { 1098 (void) snprintf(msg, len + 3, "Unconfigure %s%s\n%s", 1099 USB_CONFIRM_0, ap_id, USB_CONFIRM_1); 1100 } 1101 if (!usb_confirm(confp, msg)) { 1102 free(msg); 1103 cleanup_after_devctl_cmd(hdl, nvl); 1104 return (CFGA_NACK); 1105 } 1106 free(msg); 1107 1108 devpath = usb_get_devicepath(ap_id); 1109 if (devpath == NULL) { 1110 DPRINTF("cfga_change_state: get device path failed\n"); 1111 rv = CFGA_USB_DEVCTL; 1112 break; 1113 } 1114 1115 if ((rv = usb_rcm_offline(ap_id, errstring, devpath, flags)) != 1116 CFGA_USB_OK) { 1117 break; 1118 } 1119 1120 ret = devctl_ap_unconfigure(hdl, nvl); 1121 if (ret != 0) { 1122 DPRINTF("cfga_change_state: devctl_ap_unconfigure " 1123 "failed with errno: %d\n", errno); 1124 rv = CFGA_USB_DEVCTL; 1125 if (errno == EBUSY) { 1126 rv = CFGA_USB_BUSY; 1127 } 1128 (void) usb_rcm_online(ap_id, errstring, devpath, flags); 1129 } else { 1130 (void) usb_rcm_remove(ap_id, errstring, devpath, flags); 1131 } 1132 S_FREE(devpath); 1133 break; 1134 case CFGA_CMD_DISCONNECT: 1135 if ((rv = device_connected(hdl, nvl, &ostate)) != 1136 CFGA_USB_ALREADY_CONNECTED) { 1137 /* 1138 * special case handling for 1139 * SLM based cfgadm disconnects 1140 */ 1141 if (ostate == AP_OSTATE_UNCONFIGURED) 1142 goto bailout; 1143 } 1144 rv = CFGA_USB_OK; /* Other statuses don't matter */ 1145 1146 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) + 1147 strlen("Disconnect") + strlen(ap_id); 1148 if ((msg = (char *)calloc(len + 3, 1)) != NULL) { 1149 (void) snprintf(msg, len + 3, "Disconnect %s%s\n%s", 1150 USB_CONFIRM_0, ap_id, USB_CONFIRM_1); 1151 } 1152 if (!usb_confirm(confp, msg)) { 1153 free(msg); 1154 cleanup_after_devctl_cmd(hdl, nvl); 1155 return (CFGA_NACK); 1156 } 1157 free(msg); 1158 1159 devpath = usb_get_devicepath(ap_id); 1160 if (devpath == NULL) { 1161 DPRINTF("cfga_change_state: get device path failed\n"); 1162 rv = CFGA_USB_DEVCTL; 1163 break; 1164 } 1165 1166 /* only call rcm_offline iff the state was CONFIGURED */ 1167 if (ostate == AP_OSTATE_CONFIGURED) { 1168 if ((rv = usb_rcm_offline(ap_id, errstring, 1169 devpath, flags)) != CFGA_USB_OK) { 1170 break; 1171 } 1172 } 1173 1174 ret = devctl_ap_disconnect(hdl, nvl); 1175 if (ret != 0) { 1176 DPRINTF("cfga_change_state: devctl_ap_disconnect " 1177 "failed with errno: %d\n", errno); 1178 rv = CFGA_USB_DEVCTL; 1179 if (errno == EBUSY) { 1180 rv = CFGA_USB_BUSY; 1181 } 1182 if (ostate == AP_OSTATE_CONFIGURED) { 1183 (void) usb_rcm_online(ap_id, errstring, 1184 devpath, flags); 1185 } 1186 } else { 1187 if (ostate == AP_OSTATE_CONFIGURED) { 1188 (void) usb_rcm_remove(ap_id, errstring, 1189 devpath, flags); 1190 } 1191 } 1192 S_FREE(devpath); 1193 break; 1194 case CFGA_CMD_CONNECT: 1195 case CFGA_CMD_LOAD: 1196 case CFGA_CMD_UNLOAD: 1197 (void) cfga_help(msgp, options, flags); 1198 rv = CFGA_USB_OPNOTSUPP; 1199 break; 1200 case CFGA_CMD_NONE: 1201 default: 1202 (void) cfga_help(msgp, options, flags); 1203 rv = CFGA_USB_INTERNAL_ERROR; 1204 } 1205 1206 bailout: 1207 cleanup_after_devctl_cmd(hdl, nvl); 1208 1209 return (usb_err_msg(errstring, rv, ap_id, errno)); 1210 } 1211 1212 1213 /*ARGSUSED*/ 1214 cfga_err_t 1215 cfga_private_func( 1216 const char *func, 1217 const char *ap_id, 1218 const char *options, 1219 struct cfga_confirm *confp, 1220 struct cfga_msg *msgp, 1221 char **errstring, 1222 cfga_flags_t flags) 1223 { 1224 int len; 1225 char *msg; 1226 nvlist_t *list = NULL; 1227 ap_ostate_t ostate; 1228 devctl_hdl_t hdl = NULL; 1229 cfga_usb_ret_t rv; 1230 usb_dev_descr_t *dev_descrp = NULL; 1231 char *driver = NULL; 1232 1233 DPRINTF("cfga_private_func:\n"); 1234 1235 if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_USB_OK) { 1236 (void) cfga_help(msgp, options, flags); 1237 return (usb_err_msg(errstring, rv, ap_id, errno)); 1238 } 1239 1240 /* 1241 * All subcommands which can change state of device require 1242 * root privileges. 1243 */ 1244 if (geteuid() != 0) { 1245 rv = CFGA_USB_PRIV; 1246 goto bailout; 1247 } 1248 1249 if (func == NULL) { 1250 rv = CFGA_USB_INTERNAL_ERROR; 1251 goto bailout; 1252 } 1253 1254 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) != 1255 CFGA_USB_OK) { 1256 goto bailout; 1257 } 1258 1259 if ((rv = device_connected(hdl, list, &ostate)) != 1260 CFGA_USB_ALREADY_CONNECTED) { 1261 goto bailout; 1262 } 1263 rv = CFGA_USB_OK; 1264 1265 if (strcmp(func, RESET_DEVICE) == 0) { /* usb_reset? */ 1266 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) + 1267 strlen("Reset") + strlen(ap_id); 1268 if ((msg = (char *)calloc(len + 3, 1)) != NULL) { 1269 (void) snprintf(msg, len + 3, "Reset %s%s\n%s", 1270 USB_CONFIRM_0, ap_id, USB_CONFIRM_1); 1271 } else { 1272 cleanup_after_devctl_cmd(hdl, list); 1273 return (CFGA_NACK); 1274 } 1275 1276 if (!usb_confirm(confp, msg)) { 1277 cleanup_after_devctl_cmd(hdl, list); 1278 return (CFGA_NACK); 1279 } 1280 1281 if ((rv = reset_device(hdl, list)) != CFGA_USB_OK) { 1282 goto bailout; 1283 } 1284 } else if (strncmp(func, USB_CONFIG, sizeof (USB_CONFIG)) == 0) { 1285 uint_t config = 0; 1286 uint_t actual_config; 1287 size_t size; 1288 char *subopts, *value; 1289 uint_t cfg_opt_flag = B_FALSE; 1290 1291 /* these are the only valid options */ 1292 char *cfg_opts[] = { 1293 "config", /* 0 */ 1294 "drv", /* 1 */ 1295 NULL 1296 }; 1297 1298 /* return error if no options are specified */ 1299 subopts = (char *)options; 1300 if (subopts == (char *)NULL) { 1301 DPRINTF("cfga_private_func: no options\n"); 1302 rv = CFGA_USB_OPNOTSUPP; 1303 (void) cfga_help(msgp, options, flags); 1304 goto bailout; 1305 } 1306 1307 /* parse options specified */ 1308 while (*subopts != '\0') { 1309 switch (getsubopt(&subopts, cfg_opts, &value)) { 1310 case 0: /* config */ 1311 if (value == NULL) { 1312 rv = CFGA_USB_OPNOTSUPP; 1313 (void) cfga_help(msgp, 1314 options, flags); 1315 goto bailout; 1316 } else { 1317 errno = 0; 1318 config = strtol(value, 1319 (char **)NULL, 10); 1320 if (errno) { 1321 DPRINTF( 1322 "config conversion" 1323 "failed\n"); 1324 rv = 1325 CFGA_USB_CONFIG_INVAL; 1326 goto bailout; 1327 } 1328 } 1329 cfg_opt_flag = B_TRUE; 1330 break; 1331 1332 case 1: /* drv */ 1333 if (value == NULL) { 1334 rv = CFGA_USB_OPNOTSUPP; 1335 (void) cfga_help(msgp, 1336 options, flags); 1337 goto bailout; 1338 } else { 1339 S_FREE(driver); 1340 driver = strdup(value); 1341 if (driver == NULL) { 1342 rv = 1343 CFGA_USB_INTERNAL_ERROR; 1344 goto bailout; 1345 } 1346 } 1347 break; 1348 1349 default: 1350 rv = CFGA_USB_OPNOTSUPP; 1351 (void) cfga_help(msgp, options, flags); 1352 goto bailout; 1353 } 1354 } 1355 1356 /* config is mandatory */ 1357 if (cfg_opt_flag != B_TRUE) { 1358 rv = CFGA_USB_OPNOTSUPP; 1359 (void) cfga_help(msgp, options, flags); 1360 goto bailout; 1361 } 1362 DPRINTF("config = %x\n", config); 1363 1364 len = strlen(USB_CONFIRM_0) + strlen(USB_CONFIRM_1) + 1365 strlen("Setting") + strlen(ap_id) + 1366 strlen("to USB configuration"); 1367 /* len + 8 to account for config, \n and white space */ 1368 if ((msg = (char *)calloc(len + 8, 1)) != NULL) { 1369 (void) snprintf(msg, len + 8, 1370 "Setting %s%s\nto USB configuration %d\n%s", 1371 USB_CONFIRM_0, ap_id, config, USB_CONFIRM_1); 1372 } else { 1373 rv = CFGA_USB_INTERNAL_ERROR; 1374 goto bailout; 1375 } 1376 1377 if (!usb_confirm(confp, msg)) { 1378 S_FREE(driver); 1379 cleanup_after_devctl_cmd(hdl, list); 1380 return (CFGA_NACK); 1381 } 1382 1383 /* 1384 * Check that the option setting selected is in range. 1385 */ 1386 if ((rv = do_control_ioctl(ap_id, USB_DESCR_TYPE_DEV, NULL, 1387 (void **)&dev_descrp, &size)) != CFGA_USB_OK) { 1388 DPRINTF("cfga_private_func: get dev descr failed\n"); 1389 goto bailout; 1390 } 1391 1392 if (config > dev_descrp->bNumConfigurations - 1) { 1393 DPRINTF("cfga_private_func: config index requested " 1394 "(%d) exceeds bNumConfigurations - 1 (%d)\n", 1395 config, dev_descrp->bNumConfigurations - 1); 1396 rv = CFGA_USB_CONFIG_INVAL; 1397 goto bailout; 1398 } 1399 1400 /* Pass current setting to set_configuration */ 1401 if ((rv = get_config(ap_id, &actual_config)) != CFGA_USB_OK) { 1402 goto bailout; 1403 } 1404 1405 /* check if they match - yes, then nothing to do */ 1406 if (actual_config == config) { 1407 DPRINTF("cfga_private_func: config index requested " 1408 "(%d) matches the actual config value %d\n", 1409 config, actual_config); 1410 rv = CFGA_USB_OK; 1411 goto bailout; 1412 } 1413 1414 /* Save the configuration settings */ 1415 if ((rv = set_configuration(ap_id, config, driver, 1416 dev_descrp, errstring)) != CFGA_USB_OK) { 1417 goto bailout; 1418 } 1419 1420 /* Reset device to force new config to take effect */ 1421 if ((rv = reset_device(hdl, list)) != CFGA_USB_OK) { 1422 goto bailout; 1423 } 1424 1425 } else { 1426 DPRINTF("cfga_private_func: unrecognized command.\n"); 1427 (void) cfga_help(msgp, options, flags); 1428 errno = EINVAL; 1429 1430 return (CFGA_INVAL); 1431 } 1432 1433 bailout: 1434 S_FREE(dev_descrp); 1435 S_FREE(driver); 1436 cleanup_after_devctl_cmd(hdl, list); 1437 1438 return (usb_err_msg(errstring, rv, ap_id, errno)); 1439 } 1440 1441 1442 /*ARGSUSED*/ 1443 cfga_err_t 1444 cfga_test( 1445 const char *ap_id, 1446 const char *options, 1447 struct cfga_msg *msgp, 1448 char **errstring, 1449 cfga_flags_t flags) 1450 { 1451 (void) cfga_help(msgp, options, flags); 1452 return (CFGA_OPNOTSUPP); 1453 } 1454 1455 1456 /*ARGSUSED*/ 1457 cfga_err_t 1458 cfga_list_ext( 1459 const char *ap_id, 1460 cfga_list_data_t **ap_id_list, 1461 int *nlistp, 1462 const char *options, 1463 const char *listopts, 1464 char **errstring, 1465 cfga_flags_t flags) 1466 { 1467 int l_errno; 1468 char *ap_id_log = NULL; 1469 size_t size; 1470 nvlist_t *user_nvlist = NULL; 1471 devctl_hdl_t devctl_hdl = NULL; 1472 cfga_usb_ret_t rv = CFGA_USB_OK; 1473 devctl_ap_state_t devctl_ap_state; 1474 1475 DPRINTF("cfga_list_ext:\n"); 1476 1477 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_USB_OK) { 1478 (void) cfga_help(NULL, options, flags); 1479 goto bailout; 1480 } 1481 1482 if (ap_id_list == NULL || nlistp == NULL) { 1483 DPRINTF("cfga_list_ext: list = NULL or nlistp = NULL\n"); 1484 rv = CFGA_USB_INTERNAL_ERROR; 1485 (void) cfga_help(NULL, options, flags); 1486 goto bailout; 1487 } 1488 1489 /* Get ap status */ 1490 if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist, 1491 DC_RDONLY)) != CFGA_USB_OK) { 1492 goto bailout; 1493 } 1494 1495 if (devctl_ap_getstate(devctl_hdl, user_nvlist, &devctl_ap_state) == 1496 -1) { 1497 DPRINTF("cfga_list_ext: devctl_ap_getstate failed. errno: %d\n", 1498 errno); 1499 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist); 1500 rv = CFGA_USB_DEVCTL; 1501 goto bailout; 1502 } 1503 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist); 1504 1505 /* 1506 * Create cfga_list_data_t struct. 1507 */ 1508 if ((*ap_id_list = 1509 (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) { 1510 DPRINTF("cfga_list_ext: malloc for cfga_list_data_t failed. " 1511 "errno: %d\n", errno); 1512 rv = CFGA_USB_ALLOC_FAIL; 1513 goto bailout; 1514 } 1515 *nlistp = 1; 1516 1517 1518 /* 1519 * Rest of the code fills in the cfga_list_data_t struct. 1520 */ 1521 1522 /* Get /dev/cfg path to corresponding to the physical ap_id */ 1523 /* Remember ap_id_log must be freed */ 1524 rv = (cfga_usb_ret_t)physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id, 1525 &ap_id_log, &l_errno, MATCH_MINOR_NAME); 1526 if (rv != 0) { 1527 rv = CFGA_USB_DEVLINK; 1528 goto bailout; 1529 } 1530 assert(ap_id_log != NULL); 1531 1532 /* Get logical ap-id corresponding to the physical */ 1533 if (strstr(ap_id_log, CFGA_DEV_DIR) == NULL) { 1534 DPRINTF("cfga_list_ext: devlink doesn't contain /dev/cfg\n"); 1535 rv = CFGA_USB_DEVLINK; 1536 goto bailout; 1537 } 1538 (void) strlcpy((*ap_id_list)->ap_log_id, 1539 /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1, 1540 sizeof ((*ap_id_list)->ap_log_id)); 1541 free(ap_id_log); 1542 ap_id_log = NULL; 1543 1544 (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id, 1545 sizeof ((*ap_id_list)->ap_phys_id)); 1546 1547 switch (devctl_ap_state.ap_rstate) { 1548 case AP_RSTATE_EMPTY: 1549 (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY; 1550 break; 1551 case AP_RSTATE_DISCONNECTED: 1552 (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED; 1553 break; 1554 case AP_RSTATE_CONNECTED: 1555 (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED; 1556 break; 1557 default: 1558 rv = CFGA_USB_STATE; 1559 goto bailout; 1560 } 1561 1562 switch (devctl_ap_state.ap_ostate) { 1563 case AP_OSTATE_CONFIGURED: 1564 (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED; 1565 break; 1566 case AP_OSTATE_UNCONFIGURED: 1567 (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED; 1568 break; 1569 default: 1570 rv = CFGA_USB_STATE; 1571 goto bailout; 1572 } 1573 1574 switch (devctl_ap_state.ap_condition) { 1575 case AP_COND_OK: 1576 (*ap_id_list)->ap_cond = CFGA_COND_OK; 1577 break; 1578 case AP_COND_FAILING: 1579 (*ap_id_list)->ap_cond = CFGA_COND_FAILING; 1580 break; 1581 case AP_COND_FAILED: 1582 (*ap_id_list)->ap_cond = CFGA_COND_FAILED; 1583 break; 1584 case AP_COND_UNUSABLE: 1585 (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE; 1586 break; 1587 case AP_COND_UNKNOWN: 1588 (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN; 1589 break; 1590 default: 1591 rv = CFGA_USB_STATE; 1592 goto bailout; 1593 } 1594 1595 (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */ 1596 (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition; 1597 (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change; 1598 (*ap_id_list)->ap_info[0] = NULL; 1599 1600 if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) { 1601 char *str_p; 1602 size_t str_len; 1603 1604 /* Fill in the info for the -v option display. */ 1605 if ((rv = fill_in_ap_info(ap_id, (*ap_id_list)->ap_info, 1606 sizeof ((*ap_id_list)->ap_info))) != CFGA_USB_OK) { 1607 DPRINTF("cfga_list_ext: fill_in_ap_info failed\n"); 1608 goto bailout; 1609 } 1610 1611 /* Fill in ap_type */ 1612 if ((rv = do_control_ioctl(ap_id, HUBD_GET_CFGADM_NAME, NULL, 1613 (void **)&str_p, &size)) != CFGA_USB_OK) { 1614 DPRINTF("cfga_list_ext: do_control_ioctl failed\n"); 1615 goto bailout; 1616 } 1617 1618 (void) strcpy((*ap_id_list)->ap_type, "usb-"); 1619 str_len = strlen((*ap_id_list)->ap_type); 1620 1621 /* 1622 * NOTE: In the cfgadm display the "Type" column is only 12 1623 * chars long. Most USB devices can be displayed here with a 1624 * "usb-" prefix. Only USB keyboard cannot be displayed in 1625 * its entirety as "usb-keybaord" is 13 chars in length. 1626 * It will show up as "usb-kbd". 1627 */ 1628 if (strncasecmp(str_p, "keyboard", 8) != 0) { 1629 (void) strlcpy((*ap_id_list)->ap_type + str_len, str_p, 1630 sizeof ((*ap_id_list)->ap_type) - str_len); 1631 } else { 1632 (void) strlcpy((*ap_id_list)->ap_type + str_len, "kbd", 1633 sizeof ((*ap_id_list)->ap_type) - str_len); 1634 } 1635 1636 free(str_p); 1637 } else { 1638 (void) strcpy((*ap_id_list)->ap_type, 1639 USB_CFGADM_DEFAULT_AP_TYPE); 1640 } 1641 1642 return (usb_err_msg(errstring, rv, ap_id, errno)); 1643 bailout: 1644 if (*ap_id_list != NULL) { 1645 free(*ap_id_list); 1646 } 1647 if (ap_id_log != NULL) { 1648 free(ap_id_log); 1649 } 1650 1651 return (usb_err_msg(errstring, rv, ap_id, errno)); 1652 } 1653 1654 1655 /* 1656 * This routine accepts a variable number of message IDs and constructs 1657 * a corresponding error string which is printed via the message print routine 1658 * argument. 1659 */ 1660 static void 1661 cfga_msg(struct cfga_msg *msgp, const char *str) 1662 { 1663 int len; 1664 char *q; 1665 1666 if (msgp == NULL || msgp->message_routine == NULL) { 1667 DPRINTF("cfga_msg: msg\n"); 1668 return; 1669 } 1670 1671 if ((len = strlen(str)) == 0) { 1672 DPRINTF("cfga_msg: null str\n"); 1673 return; 1674 } 1675 1676 if ((q = (char *)calloc(len + 1, 1)) == NULL) { 1677 DPRINTF("cfga_msg: null q\n"); 1678 return; 1679 } 1680 1681 strcpy(q, str); 1682 (*msgp->message_routine)(msgp->appdata_ptr, q); 1683 1684 free(q); 1685 } 1686 1687 1688 /* ARGSUSED */ 1689 cfga_err_t 1690 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 1691 { 1692 DPRINTF("cfga_help:\n"); 1693 if (options) { 1694 cfga_msg(msgp, dgettext(TEXT_DOMAIN, usb_help[HELP_UNKNOWN])); 1695 cfga_msg(msgp, options); 1696 } 1697 1698 cfga_msg(msgp, dgettext(TEXT_DOMAIN, usb_help[HELP_HEADER])); 1699 cfga_msg(msgp, usb_help[HELP_CONFIG]); 1700 cfga_msg(msgp, usb_help[HELP_RESET_SLOT]); 1701 cfga_msg(msgp, usb_help[HELP_CONFIG_SLOT]); 1702 1703 return (CFGA_OK); 1704 } 1705 1706 1707 static int 1708 usb_confirm(struct cfga_confirm *confp, char *msg) 1709 { 1710 int rval; 1711 1712 if (confp == NULL || confp->confirm == NULL) { 1713 return (0); 1714 } 1715 1716 rval = (*confp->confirm)(confp->appdata_ptr, msg); 1717 DPRINTF("usb_confirm: %d\n", rval); 1718 1719 return (rval); 1720 } 1721 1722 1723 static char * 1724 usb_get_devicepath(const char *ap_id) 1725 { 1726 char *devpath = NULL; 1727 size_t size; 1728 cfga_usb_ret_t rv; 1729 1730 rv = do_control_ioctl(ap_id, HUBD_GET_DEVICE_PATH, NULL, 1731 (void **)&devpath, &size); 1732 1733 if (rv == CFGA_USB_OK) { 1734 DPRINTF("usb_get_devicepath: get device path ioctl ok\n"); 1735 return (devpath); 1736 } else { 1737 DPRINTF("usb_get_devicepath: get device path ioctl failed\n"); 1738 return ((char *)NULL); 1739 } 1740 } 1741