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 30 #include "cfga_usb.h" 31 32 33 #define MAX_FORMAT 80 /* for info table */ 34 35 cfga_usb_ret_t usb_rcm_offline(const char *, char **, char *, 36 cfga_flags_t); 37 cfga_usb_ret_t usb_rcm_online(const char *, char **, char *, 38 cfga_flags_t); 39 cfga_usb_ret_t usb_rcm_remove(const char *, char **, char *, 40 cfga_flags_t); 41 static cfga_usb_ret_t usb_rcm_info_table(rcm_info_t *, char **); 42 static cfga_usb_ret_t usb_rcm_init(const char *, cfga_flags_t, char **, 43 uint_t *); 44 45 46 static rcm_handle_t *rcm_handle = NULL; 47 static mutex_t rcm_handle_lock = DEFAULTMUTEX; 48 49 50 /* 51 * usb_rcm_offline: 52 * Offline USB resource consumers. 53 */ 54 cfga_usb_ret_t 55 usb_rcm_offline(const char *rsrc, char **errstring, char *rsrc_fixed, 56 cfga_flags_t flags) 57 { 58 int rret; 59 uint_t rflags = 0; 60 rcm_info_t *rinfo = NULL; 61 cfga_usb_ret_t ret = CFGA_USB_OK; 62 63 DPRINTF("usb_rcm_offline:\n"); 64 65 if ((ret = usb_rcm_init(rsrc, flags, errstring, &rflags)) != 66 CFGA_USB_OK) { 67 68 return (ret); 69 } 70 71 DPRINTF("usb_rcm_offline: rsrc_fixed: %s\n", rsrc_fixed); 72 73 if ((rret = rcm_request_offline(rcm_handle, rsrc_fixed, rflags, &rinfo)) 74 != RCM_SUCCESS) { 75 DPRINTF("usb_rcm_offline: rcm_request_offline failed\n"); 76 77 if (rinfo) { 78 (void) usb_rcm_info_table(rinfo, errstring); 79 rcm_free_info(rinfo); 80 rinfo = NULL; 81 } 82 83 DPRINTF("usb_rcm_offline: table = %s\n", *errstring); 84 85 if (rret == RCM_FAILURE) { 86 (void) usb_rcm_online(rsrc, errstring, 87 rsrc_fixed, flags); 88 } 89 ret = CFGA_USB_RCM_OFFLINE; 90 } 91 92 return (ret); 93 } 94 95 96 /* 97 * usb_rcm_online: 98 * Online USB resource consumers that were previously offlined. 99 */ 100 cfga_usb_ret_t 101 usb_rcm_online(const char *rsrc, char **errstring, char *rsrc_fixed, 102 cfga_flags_t flags) 103 { 104 rcm_info_t *rinfo = NULL; 105 cfga_usb_ret_t ret = CFGA_USB_OK; 106 107 DPRINTF("usb_rcm_online:\n"); 108 109 if ((ret = usb_rcm_init(rsrc, flags, errstring, NULL)) != CFGA_USB_OK) { 110 111 return (ret); 112 } 113 114 if (rcm_notify_online(rcm_handle, rsrc_fixed, 0, &rinfo) != 115 RCM_SUCCESS && (rinfo != NULL)) { 116 DPRINTF("usb_rcm_online: rcm_notify_online failed\n"); 117 118 (void) usb_rcm_info_table(rinfo, errstring); 119 rcm_free_info(rinfo); 120 rinfo = NULL; 121 ret = CFGA_USB_RCM_ONLINE; 122 } 123 124 return (ret); 125 } 126 127 128 /* 129 * usb_rcm_remove: 130 * Remove USB resource consumers after their kernel removal. 131 */ 132 cfga_usb_ret_t 133 usb_rcm_remove(const char *rsrc, char **errstring, char *rsrc_fixed, 134 cfga_flags_t flags) 135 { 136 rcm_info_t *rinfo = NULL; 137 cfga_usb_ret_t ret = CFGA_USB_OK; 138 139 DPRINTF("usb_rcm_remove:\n"); 140 141 if ((ret = usb_rcm_init(rsrc, flags, errstring, NULL)) != CFGA_USB_OK) { 142 143 return (ret); 144 } 145 146 if (rcm_notify_remove(rcm_handle, rsrc_fixed, 0, &rinfo) != 147 RCM_SUCCESS && (rinfo != NULL)) { 148 DPRINTF("usb_rcm_remove: rcm_notify_remove failed\n"); 149 150 (void) usb_rcm_info_table(rinfo, errstring); 151 rcm_free_info(rinfo); 152 rinfo = NULL; 153 ret = CFGA_USB_RCM_ONLINE; 154 } 155 156 return (ret); 157 } 158 159 160 /* 161 * usb_rcm_init: 162 * Contains common initialization code for entering a usb_rcm_xx() routine. 163 */ 164 /* ARGSUSED */ 165 static cfga_usb_ret_t 166 usb_rcm_init(const char *rsrc, cfga_flags_t flags, char **errstring, 167 uint_t *rflags) 168 { 169 DPRINTF("usb_rcm_init:\n"); 170 171 /* Validate the rsrc argument */ 172 if (rsrc == NULL) { 173 DPRINTF("usb_rcm_init: rsrc is NULL\n"); 174 return (CFGA_USB_INTERNAL_ERROR); 175 } 176 177 /* Translate the cfgadm flags to RCM flags */ 178 if (rflags && (flags & CFGA_FLAG_FORCE)) { 179 *rflags |= RCM_FORCE; 180 } 181 182 /* Get a handle for the RCM operations */ 183 (void) mutex_lock(&rcm_handle_lock); 184 if (rcm_handle == NULL) { 185 if (rcm_alloc_handle(NULL, RCM_NOPID, NULL, &rcm_handle) != 186 RCM_SUCCESS) { 187 DPRINTF("usb_rcm_init: alloc_handle failed\n"); 188 (void) mutex_unlock(&rcm_handle_lock); 189 190 return (CFGA_USB_RCM_HANDLE); 191 } 192 } 193 (void) mutex_unlock(&rcm_handle_lock); 194 195 return (CFGA_USB_OK); 196 } 197 198 199 /* 200 * usb_rcm_info_table: 201 * Takes an opaque rcm_info_t pointer and a character pointer, 202 * and appends the rcm_info_t data in the form of a table to the 203 * given character pointer. 204 */ 205 static cfga_usb_ret_t 206 usb_rcm_info_table(rcm_info_t *rinfo, char **table) 207 { 208 int i; 209 size_t w; 210 size_t width = 0; 211 size_t w_rsrc = 0; 212 size_t w_info = 0; 213 size_t table_size = 0; 214 uint_t tuples = 0; 215 rcm_info_tuple_t *tuple = NULL; 216 char *rsrc; 217 char *info; 218 char *newtable; 219 static char format[MAX_FORMAT]; 220 const char *infostr; 221 222 DPRINTF("usb_rcm_info_table:\n"); 223 224 /* Protect against invalid arguments */ 225 if (rinfo == NULL || table == NULL) { 226 return (CFGA_USB_INTERNAL_ERROR); 227 } 228 229 /* Set localized table header strings */ 230 rsrc = dgettext(TEXT_DOMAIN, "Resource"); 231 info = dgettext(TEXT_DOMAIN, "Information"); 232 233 /* A first pass, to size up the RCM information */ 234 while (tuple = rcm_info_next(rinfo, tuple)) { 235 if ((infostr = rcm_info_info(tuple)) != NULL) { 236 tuples++; 237 if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc) 238 w_rsrc = w; 239 if ((w = strlen(infostr)) > w_info) 240 w_info = w; 241 } 242 } 243 244 /* If nothing was sized up above, stop early */ 245 if (tuples == 0) { 246 DPRINTF("usb_rcm_info_table: no tuples\n"); 247 248 return (CFGA_USB_OK); 249 } 250 251 /* Adjust column widths for column headings */ 252 if ((w = strlen(rsrc)) > w_rsrc) { 253 w_rsrc = w; 254 } else if ((w_rsrc - w) % 2) { 255 w_rsrc++; 256 } 257 258 if ((w = strlen(info)) > w_info) { 259 w_info = w; 260 } else if ((w_info - w) % 2) { 261 w_info++; 262 } 263 264 /* 265 * Compute the total line width of each line, 266 * accounting for intercolumn spacing. 267 */ 268 width = w_info + w_rsrc + 4; 269 270 /* Allocate space for the table */ 271 table_size = (2 + tuples) * (width + 1) + 2; 272 if (*table == NULL) { 273 /* zero fill for the strcat() call below */ 274 *table = calloc(table_size, sizeof (char)); 275 if (*table == NULL) { 276 DPRINTF("usb_rcm_info_table: no table\n"); 277 278 return (CFGA_USB_ALLOC_FAIL); 279 } 280 } else { 281 newtable = realloc(*table, strlen(*table) + table_size); 282 if (newtable == NULL) { 283 DPRINTF("usb_rcm_info_table: no new table\n"); 284 285 return (CFGA_USB_ALLOC_FAIL); 286 } else { 287 *table = newtable; 288 } 289 } 290 291 /* Place a table header into the string */ 292 293 /* The resource header */ 294 (void) strcat(*table, "\n"); 295 w = strlen(rsrc); 296 297 for (i = 0; i < ((w_rsrc - w) / 2); i++) { 298 (void) strcat(*table, " "); 299 } 300 (void) strcat(*table, rsrc); 301 302 for (i = 0; i < ((w_rsrc - w) / 2); i++) { 303 (void) strcat(*table, " "); 304 } 305 306 /* The information header */ 307 (void) strcat(*table, " "); 308 w = strlen(info); 309 for (i = 0; i < ((w_info - w) / 2); i++) { 310 (void) strcat(*table, " "); 311 } 312 (void) strcat(*table, info); 313 314 for (i = 0; i < ((w_info - w) / 2); i++) { 315 (void) strcat(*table, " "); 316 } 317 318 (void) strcat(*table, "\n"); 319 320 /* Underline the headers */ 321 for (i = 0; i < w_rsrc; i++) { 322 (void) strcat(*table, "-"); 323 } 324 325 (void) strcat(*table, " "); 326 for (i = 0; i < w_info; i++) { 327 (void) strcat(*table, "-"); 328 } 329 330 (void) strcat(*table, "\n"); 331 332 /* Construct the format string */ 333 (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds", 334 (int)w_rsrc, (int)w_info); 335 336 /* Add the tuples to the table string */ 337 tuple = NULL; 338 while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { 339 if ((infostr = rcm_info_info(tuple)) != NULL) { 340 (void) sprintf(&((*table)[strlen(*table)]), 341 format, rcm_info_rsrc(tuple), infostr); 342 (void) strcat(*table, "\n"); 343 } 344 } 345 346 return (CFGA_USB_OK); 347 } 348