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