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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <regex.h> 29 #include <devfsadm.h> 30 #include <stdio.h> 31 #include <strings.h> 32 #include <stdlib.h> 33 #include <limits.h> 34 #include <sys/mkdev.h> 35 #include <bsm/devalloc.h> 36 37 extern int system_labeled; 38 39 static int node_name(di_minor_t minor, di_node_t node); 40 41 42 static int ddi_other(di_minor_t minor, di_node_t node); 43 static int diskette(di_minor_t minor, di_node_t node); 44 static int ecpp_create(di_minor_t minor, di_node_t node); 45 static int mc_node(di_minor_t minor, di_node_t node); 46 static int ddi_cardreader(di_minor_t minor, di_node_t node); 47 static int starcat_sbbc_node(di_minor_t minor, di_node_t node); 48 static int wrsm(di_minor_t minor, di_node_t node); 49 static int lom(di_minor_t minor, di_node_t node); 50 static int ntwdt_create(di_minor_t minor, di_node_t node); 51 52 static devfsadm_create_t misc_cbt[] = { 53 { "other", "ddi_other", NULL, 54 TYPE_EXACT, ILEVEL_0, ddi_other 55 }, 56 { "memory-controller", "ddi_mem_ctrl", NULL, 57 TYPE_EXACT, ILEVEL_0, mc_node 58 }, 59 { "pseudo", "ddi_pseudo", "sbbc", 60 TYPE_EXACT | DRV_EXACT, ILEVEL_1, starcat_sbbc_node 61 }, 62 { "disk", "ddi_block:diskette", NULL, 63 TYPE_EXACT, ILEVEL_1, diskette 64 }, 65 { "printer", "ddi_printer", NULL, 66 TYPE_EXACT, ILEVEL_1, ecpp_create 67 }, 68 { "card-reader", "ddi_smartcard_reader", NULL, 69 TYPE_EXACT, ILEVEL_0, ddi_cardreader 70 }, 71 { "pseudo", "(^ddi_pseudo$)|(^ddi_ctl:devctl$)", "wrsm", 72 TYPE_RE | DRV_EXACT, ILEVEL_0, wrsm, 73 }, 74 { "network", "ddi_net", "wrsmd", 75 TYPE_EXACT | DRV_EXACT, ILEVEL_0, node_name, 76 }, 77 { "pseudo", "ddi_pseudo", "lw8", 78 TYPE_EXACT | DRV_EXACT, ILEVEL_0, lom 79 }, 80 { "pseudo", "ddi_pseudo", "ntwdt", 81 TYPE_EXACT | DRV_EXACT, ILEVEL_0, ntwdt_create 82 }, 83 }; 84 85 DEVFSADM_CREATE_INIT_V0(misc_cbt); 86 87 /* Smart Card Reader device link */ 88 #define CARDREADER_LINK "^scmi2c[0-9]+$" 89 90 /* Rules for removing links */ 91 static devfsadm_remove_t sparc_remove_cbt[] = { 92 { "card-reader", CARDREADER_LINK, RM_PRE | RM_ALWAYS, 93 ILEVEL_0, devfsadm_rm_all } 94 }; 95 96 DEVFSADM_REMOVE_INIT_V0(sparc_remove_cbt); 97 98 99 /* 100 * Handles minor node type "ddi_other" 101 * type=ddi_other;name=SUNW,pmc pmc 102 * type=ddi_other;name=SUNW,mic mic\M0 103 */ 104 static int 105 ddi_other(di_minor_t minor, di_node_t node) 106 { 107 char path[PATH_MAX + 1]; 108 char *nn = di_node_name(node); 109 char *mn = di_minor_name(minor); 110 111 if (strcmp(nn, "SUNW,pmc") == 0) { 112 (void) devfsadm_mklink("pcm", node, minor, 0); 113 } else if (strcmp(nn, "SUNW,mic") == 0) { 114 (void) strcpy(path, "mic"); 115 (void) strcat(path, mn); 116 (void) devfsadm_mklink(path, node, minor, 0); 117 } 118 119 return (DEVFSADM_CONTINUE); 120 } 121 122 /* 123 * This function is called for diskette nodes 124 */ 125 static int 126 diskette(di_minor_t minor, di_node_t node) 127 { 128 int flags = 0; 129 char *mn = di_minor_name(minor); 130 131 if (system_labeled) 132 flags = DA_ADD|DA_FLOPPY; 133 134 if (strcmp(mn, "c") == 0) { 135 (void) devfsadm_mklink("diskette", node, minor, flags); 136 (void) devfsadm_mklink("diskette0", node, minor, flags); 137 138 } else if (strcmp(mn, "c,raw") == 0) { 139 (void) devfsadm_mklink("rdiskette", node, minor, flags); 140 (void) devfsadm_mklink("rdiskette0", node, minor, flags); 141 142 } 143 return (DEVFSADM_CONTINUE); 144 } 145 146 /* 147 * Handles links of the form: 148 * type=ddi_pseudo;name=xyz \D 149 */ 150 static int 151 node_name(di_minor_t minor, di_node_t node) 152 { 153 (void) devfsadm_mklink(di_node_name(node), node, minor, 0); 154 return (DEVFSADM_CONTINUE); 155 } 156 157 /* 158 * Handles links of the form: 159 * type=ddi_printer;name=ecpp ecpp\N0 160 */ 161 static int 162 ecpp_create(di_minor_t minor, di_node_t node) 163 { 164 char *buf; 165 char path[PATH_MAX + 1]; 166 devfsadm_enumerate_t rules[1] = {"^ecpp([0-9]+)$", 1, MATCH_ALL}; 167 168 if (strcmp(di_driver_name(node), "ecpp") != 0) { 169 return (DEVFSADM_CONTINUE); 170 } 171 172 if ((buf = di_devfs_path(node)) == NULL) { 173 return (DEVFSADM_CONTINUE); 174 } 175 176 (void) snprintf(path, sizeof (path), "%s:%s", 177 buf, di_minor_name(minor)); 178 179 di_devfs_path_free(buf); 180 181 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 182 return (DEVFSADM_CONTINUE); 183 } 184 185 (void) snprintf(path, sizeof (path), "ecpp%s", buf); 186 free(buf); 187 188 (void) devfsadm_mklink(path, node, minor, 0); 189 return (DEVFSADM_CONTINUE); 190 } 191 192 /* Rules for memory controller */ 193 static devfsadm_enumerate_t mc_rules[1] = 194 {"^mc$/^mc([0-9]+)$", 1, MATCH_ALL}; 195 196 197 static int 198 mc_node(di_minor_t minor, di_node_t node) 199 { 200 char path[PATH_MAX], l_path[PATH_MAX], *buf, *devfspath; 201 char *minor_nm; 202 203 minor_nm = di_minor_name(minor); 204 205 if (minor_nm == NULL) { 206 return (DEVFSADM_CONTINUE); 207 } 208 209 devfspath = di_devfs_path(node); 210 211 (void) strcpy(path, devfspath); 212 (void) strcat(path, ":"); 213 (void) strcat(path, minor_nm); 214 di_devfs_path_free(devfspath); 215 216 /* build the physical path from the components */ 217 if (devfsadm_enumerate_int(path, 0, &buf, mc_rules, 1)) { 218 return (DEVFSADM_CONTINUE); 219 } 220 221 (void) strcpy(l_path, "mc/mc"); 222 (void) strcat(l_path, buf); 223 224 free(buf); 225 226 (void) devfsadm_mklink(l_path, node, minor, 0); 227 return (DEVFSADM_CONTINUE); 228 } 229 230 231 /* 232 * This function is called for Smartcard card reader nodes 233 * Handles minor node type "ddi_smartcard_reader" 234 * type=ddi_smartcard_reader;name=card-reader scmi2c\N0 235 * Calls enumerate to assign logical card-reader id and then 236 * devfsadm_mklink to make the link. 237 */ 238 static int 239 ddi_cardreader(di_minor_t minor, di_node_t node) 240 { 241 char p_path[PATH_MAX +1], l_path[PATH_MAX +1]; 242 char *buf; 243 char *ptr; 244 char *nn, *mn; 245 246 devfsadm_enumerate_t rules[1] = {"^scmi2c([0-9]+)$", 1, MATCH_ALL}; 247 248 nn = di_node_name(node); 249 if (strcmp(nn, "card-reader")) { 250 return (DEVFSADM_CONTINUE); 251 } 252 253 if (NULL == (ptr = di_devfs_path(node))) { 254 return (DEVFSADM_CONTINUE); 255 } 256 257 (void) strcpy(p_path, ptr); 258 (void) strcat(p_path, ":"); 259 260 mn = di_minor_name(minor); 261 262 (void) strcat(p_path, mn); 263 di_devfs_path_free(ptr); 264 265 if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) { 266 return (DEVFSADM_CONTINUE); 267 } 268 (void) snprintf(l_path, sizeof (l_path), "scmi2c%s", buf); 269 free(buf); 270 (void) devfsadm_mklink(l_path, node, minor, 0); 271 272 return (DEVFSADM_CONTINUE); 273 } 274 275 276 277 278 279 280 281 282 /* 283 * Starcat sbbc node. We only really care about generating a /dev 284 * link for the lone sbbc on the SC (as opposed to the potentially 285 * numerous sbbcs on the domain), so only operate on instance 0. 286 */ 287 static int 288 starcat_sbbc_node(di_minor_t minor, di_node_t node) 289 { 290 char *mn; 291 292 if (di_instance(node) == 0) { 293 mn = di_minor_name(minor); 294 (void) devfsadm_mklink(mn, node, minor, 0); 295 } 296 return (DEVFSADM_CONTINUE); 297 298 } 299 300 int 301 wrsm(di_minor_t minor, di_node_t node) 302 { 303 const char *node_name = di_node_name(node); 304 const char *minor_name = di_minor_name(minor); 305 char path[PATH_MAX + 1]; 306 307 if (minor_name == NULL || node_name == NULL) { 308 return (DEVFSADM_CONTINUE); 309 } 310 if (strcmp(minor_name, "admin") == 0) { 311 /* admin pseudo device */ 312 (void) snprintf(path, sizeof (path), "%s%s", node_name, 313 minor_name); 314 } else if (strcmp(minor_name, "ctrl") == 0) { 315 /* controller pseudo device */ 316 dev_t dev = di_minor_devt(minor); 317 minor_t dev_minor = minor(dev); 318 (void) snprintf(path, sizeof (path), "%s%u", node_name, 319 (uint_t)dev_minor); 320 } else { 321 /* 322 * For hardware devices, the devlink must be 323 * /dev/<node_name><portid>. devpath is of the format 324 * ".../<node_name>@<portid>,0". Need to extract the 325 * <portid> for use in bulding devlink. 326 */ 327 char devpath[PATH_MAX + 1]; 328 char *devfs_path; 329 int i; 330 331 devfs_path = di_devfs_path(node); 332 if (devfs_path == NULL) { 333 return (DEVFSADM_CONTINUE); 334 } 335 (void) strcpy(devpath, devfs_path); 336 di_devfs_path_free(devfs_path); 337 338 for (i = strlen(devpath); devpath[i] != '@' && i > 0; i--) { 339 if (devpath[i] == ',') { 340 devpath[i] = 0; 341 } 342 } 343 if (i == 0) { 344 return (DEVFSADM_CONTINUE); 345 } 346 (void) snprintf(path, sizeof (path), "wci%s", &devpath[i+1]); 347 } 348 (void) devfsadm_mklink(path, node, minor, 0); 349 350 return (DEVFSADM_CONTINUE); 351 } 352 353 /* 354 * Creates /dev/lom nodes for Platform Specific lom driver 355 */ 356 static int 357 lom(di_minor_t minor, di_node_t node) 358 { 359 (void) devfsadm_mklink("lom", node, minor, 0); 360 return (DEVFSADM_CONTINUE); 361 } 362 363 /* 364 * Creates /dev/ntwdt nodes for Platform Specific ntwdt driver 365 */ 366 static int 367 ntwdt_create(di_minor_t minor, di_node_t node) 368 { 369 (void) devfsadm_mklink("ntwdt", node, minor, 0); 370 return (DEVFSADM_CONTINUE); 371 } 372