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