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