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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2012 Joyent, Inc. All rights reserved. 25 */ 26 27 #include <regex.h> 28 #include <devfsadm.h> 29 #include <stdio.h> 30 #include <strings.h> 31 #include <stdlib.h> 32 #include <limits.h> 33 #include <ctype.h> 34 #include <sys/mc_amd.h> 35 #include <bsm/devalloc.h> 36 37 extern int system_labeled; 38 39 static int lp(di_minor_t minor, di_node_t node); 40 static int serial_dialout(di_minor_t minor, di_node_t node); 41 static int serial(di_minor_t minor, di_node_t node); 42 static int diskette(di_minor_t minor, di_node_t node); 43 static int vt00(di_minor_t minor, di_node_t node); 44 static int kdmouse(di_minor_t minor, di_node_t node); 45 static int ipmi(di_minor_t minor, di_node_t node); 46 static int smbios(di_minor_t minor, di_node_t node); 47 static int mc_node(di_minor_t minor, di_node_t node); 48 static int xsvc(di_minor_t minor, di_node_t node); 49 static int srn(di_minor_t minor, di_node_t node); 50 static int ucode(di_minor_t minor, di_node_t node); 51 static int heci(di_minor_t minor, di_node_t node); 52 53 54 static devfsadm_create_t misc_cbt[] = { 55 { "vt00", "ddi_display", NULL, 56 TYPE_EXACT, ILEVEL_0, vt00 57 }, 58 { "mouse", "ddi_mouse", "mouse8042", 59 TYPE_EXACT | DRV_EXACT, ILEVEL_0, kdmouse 60 }, 61 { "pseudo", "ddi_pseudo", "ipmi", 62 TYPE_EXACT | DRV_EXACT, ILEVEL_0, ipmi, 63 }, 64 { "pseudo", "ddi_pseudo", "smbios", 65 TYPE_EXACT | DRV_EXACT, ILEVEL_1, smbios, 66 }, 67 /* floppies share the same class, but not link regex, as hard disks */ 68 { "disk", "ddi_block:diskette", NULL, 69 TYPE_EXACT, ILEVEL_1, diskette 70 }, 71 { "parallel", "ddi_printer", NULL, 72 TYPE_EXACT, ILEVEL_1, lp 73 }, 74 { "serial", "ddi_serial:mb", NULL, 75 TYPE_EXACT, ILEVEL_1, serial 76 }, 77 { "serial", "ddi_serial:dialout,mb", NULL, 78 TYPE_EXACT, ILEVEL_1, serial_dialout 79 }, 80 { "pseudo", "ddi_pseudo", NULL, 81 TYPE_EXACT, ILEVEL_0, xsvc 82 }, 83 { "pseudo", "ddi_pseudo", NULL, 84 TYPE_EXACT, ILEVEL_0, srn 85 }, 86 { "memory-controller", "ddi_mem_ctrl", NULL, 87 TYPE_EXACT, ILEVEL_0, mc_node 88 }, 89 { "pseudo", "ddi_pseudo", "ucode", 90 TYPE_EXACT | DRV_EXACT, ILEVEL_0, ucode, 91 }, 92 { "pseudo", "ddi_pseudo", "heci", 93 TYPE_EXACT | DRV_EXACT, ILEVEL_0, heci, 94 } 95 }; 96 97 DEVFSADM_CREATE_INIT_V0(misc_cbt); 98 99 static devfsadm_remove_t misc_remove_cbt[] = { 100 { "vt", "vt[0-9][0-9]", RM_PRE|RM_ALWAYS, 101 ILEVEL_0, devfsadm_rm_all 102 }, 103 { "pseudo", "^ucode$", RM_ALWAYS | RM_PRE | RM_HOT, 104 ILEVEL_0, devfsadm_rm_all 105 }, 106 { "mouse", "^kdmouse$", RM_ALWAYS | RM_PRE, 107 ILEVEL_0, devfsadm_rm_all 108 }, 109 { "disk", "^(diskette|rdiskette)([0-9]*)$", 110 RM_ALWAYS | RM_PRE, ILEVEL_1, devfsadm_rm_all 111 }, 112 { "parallel", "^(lp|ecpp)([0-9]+)$", RM_ALWAYS | RM_PRE, 113 ILEVEL_1, devfsadm_rm_all 114 }, 115 { "serial", "^(tty|ttyd)([0-9]+)$", RM_ALWAYS | RM_PRE, 116 ILEVEL_1, devfsadm_rm_all 117 }, 118 { "serial", "^tty[a-z]$", RM_ALWAYS | RM_PRE, 119 ILEVEL_1, devfsadm_rm_all 120 } 121 }; 122 123 DEVFSADM_REMOVE_INIT_V0(misc_remove_cbt); 124 125 /* 126 * Handles minor node type "ddi_display", in addition to generic processing 127 * done by display(). 128 * 129 * This creates a /dev/vt00 link to /dev/fb, for backwards compatibility. 130 */ 131 /* ARGSUSED */ 132 int 133 vt00(di_minor_t minor, di_node_t node) 134 { 135 (void) devfsadm_secondary_link("vt00", "fb", 0); 136 return (DEVFSADM_CONTINUE); 137 } 138 139 /* 140 * type=ddi_block:diskette;addr=0,0;minor=c diskette 141 * type=ddi_block:diskette;addr=0,0;minor=c,raw rdiskette 142 * type=ddi_block:diskette;addr1=0;minor=c diskette\A2 143 * type=ddi_block:diskette;addr1=0;minor=c,raw rdiskette\A2 144 */ 145 static int 146 diskette(di_minor_t minor, di_node_t node) 147 { 148 int flags = 0; 149 char *a2; 150 char link[PATH_MAX]; 151 char *addr = di_bus_addr(node); 152 char *mn = di_minor_name(minor); 153 154 if (system_labeled) 155 flags = DA_ADD|DA_FLOPPY; 156 157 if (strcmp(addr, "0,0") == 0) { 158 if (strcmp(mn, "c") == 0) { 159 (void) devfsadm_mklink("diskette", node, minor, flags); 160 } else if (strcmp(mn, "c,raw") == 0) { 161 (void) devfsadm_mklink("rdiskette", node, minor, flags); 162 } 163 164 } 165 166 if (addr[0] == '0') { 167 if ((a2 = strchr(addr, ',')) != NULL) { 168 a2++; 169 if (strcmp(mn, "c") == 0) { 170 (void) strcpy(link, "diskette"); 171 (void) strcat(link, a2); 172 (void) devfsadm_mklink(link, node, minor, 173 flags); 174 } else if (strcmp(mn, "c,raw") == 0) { 175 (void) strcpy(link, "rdiskette"); 176 (void) strcat(link, a2); 177 (void) devfsadm_mklink(link, node, minor, 178 flags); 179 } 180 } 181 } 182 183 return (DEVFSADM_CONTINUE); 184 } 185 186 /* 187 * type=ddi_printer;name=lp;addr=1,3bc lp0 188 * type=ddi_printer;name=lp;addr=1,378 lp1 189 * type=ddi_printer;name=lp;addr=1,278 lp2 190 */ 191 static int 192 lp(di_minor_t minor, di_node_t node) 193 { 194 char *addr = di_bus_addr(node); 195 char *buf; 196 char path[PATH_MAX + 1]; 197 devfsadm_enumerate_t rules[1] = {"^ecpp([0-9]+)$", 1, MATCH_ALL}; 198 199 if (strcmp(addr, "1,3bc") == 0) { 200 (void) devfsadm_mklink("lp0", node, minor, 0); 201 202 } else if (strcmp(addr, "1,378") == 0) { 203 (void) devfsadm_mklink("lp1", node, minor, 0); 204 205 } else if (strcmp(addr, "1,278") == 0) { 206 (void) devfsadm_mklink("lp2", node, minor, 0); 207 } 208 209 if (strcmp(di_driver_name(node), "ecpp") != 0) { 210 return (DEVFSADM_CONTINUE); 211 } 212 213 if ((buf = di_devfs_path(node)) == NULL) { 214 return (DEVFSADM_CONTINUE); 215 } 216 217 (void) snprintf(path, sizeof (path), "%s:%s", 218 buf, di_minor_name(minor)); 219 220 di_devfs_path_free(buf); 221 222 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 223 return (DEVFSADM_CONTINUE); 224 } 225 226 (void) snprintf(path, sizeof (path), "ecpp%s", buf); 227 free(buf); 228 (void) devfsadm_mklink(path, node, minor, 0); 229 return (DEVFSADM_CONTINUE); 230 } 231 232 /* 233 * type=ddi_serial:mb;minor=a tty00 234 * type=ddi_serial:mb;minor=b tty01 235 * type=ddi_serial:mb;minor=c tty02 236 * type=ddi_serial:mb;minor=d tty03 237 */ 238 static int 239 serial(di_minor_t minor, di_node_t node) 240 { 241 242 char *mn = di_minor_name(minor); 243 char link[PATH_MAX]; 244 245 (void) strcpy(link, "tty"); 246 (void) strcat(link, mn); 247 (void) devfsadm_mklink(link, node, minor, 0); 248 249 if (strcmp(mn, "a") == 0) { 250 (void) devfsadm_mklink("tty00", node, minor, 0); 251 252 } else if (strcmp(mn, "b") == 0) { 253 (void) devfsadm_mklink("tty01", node, minor, 0); 254 255 } else if (strcmp(mn, "c") == 0) { 256 (void) devfsadm_mklink("tty02", node, minor, 0); 257 258 } else if (strcmp(mn, "d") == 0) { 259 (void) devfsadm_mklink("tty03", node, minor, 0); 260 } 261 return (DEVFSADM_CONTINUE); 262 } 263 264 /* 265 * type=ddi_serial:dialout,mb;minor=a,cu ttyd0 266 * type=ddi_serial:dialout,mb;minor=b,cu ttyd1 267 * type=ddi_serial:dialout,mb;minor=c,cu ttyd2 268 * type=ddi_serial:dialout,mb;minor=d,cu ttyd3 269 */ 270 static int 271 serial_dialout(di_minor_t minor, di_node_t node) 272 { 273 char *mn = di_minor_name(minor); 274 275 if (strcmp(mn, "a,cu") == 0) { 276 (void) devfsadm_mklink("ttyd0", node, minor, 0); 277 (void) devfsadm_mklink("cua0", node, minor, 0); 278 279 } else if (strcmp(mn, "b,cu") == 0) { 280 (void) devfsadm_mklink("ttyd1", node, minor, 0); 281 (void) devfsadm_mklink("cua1", node, minor, 0); 282 283 } else if (strcmp(mn, "c,cu") == 0) { 284 (void) devfsadm_mklink("ttyd2", node, minor, 0); 285 (void) devfsadm_mklink("cua2", node, minor, 0); 286 287 } else if (strcmp(mn, "d,cu") == 0) { 288 (void) devfsadm_mklink("ttyd3", node, minor, 0); 289 (void) devfsadm_mklink("cua3", node, minor, 0); 290 } 291 return (DEVFSADM_CONTINUE); 292 } 293 294 static int 295 kdmouse(di_minor_t minor, di_node_t node) 296 { 297 (void) devfsadm_mklink("kdmouse", node, minor, 0); 298 return (DEVFSADM_CONTINUE); 299 } 300 301 static int 302 ipmi(di_minor_t minor, di_node_t node) 303 { 304 /* 305 * Follow convention from other systems, and include an instance#, 306 * even though there will only be one. 307 */ 308 (void) devfsadm_mklink("ipmi0", node, minor, 0); 309 return (DEVFSADM_CONTINUE); 310 } 311 312 static int 313 smbios(di_minor_t minor, di_node_t node) 314 { 315 (void) devfsadm_mklink("smbios", node, minor, 0); 316 return (DEVFSADM_CONTINUE); 317 } 318 319 /* 320 * /dev/mc/mc<chipid> -> /devices/.../pci1022,1102@<chipid+24>,2:mc-amd 321 */ 322 static int 323 mc_node(di_minor_t minor, di_node_t node) 324 { 325 const char *minorname = di_minor_name(minor); 326 const char *busaddr = di_bus_addr(node); 327 char linkpath[PATH_MAX]; 328 int unitaddr; 329 char *c; 330 331 if (minorname == NULL || busaddr == NULL) 332 return (DEVFSADM_CONTINUE); 333 334 errno = 0; 335 unitaddr = strtol(busaddr, &c, 16); 336 337 if (errno != 0) 338 return (DEVFSADM_CONTINUE); 339 340 if (unitaddr == 0) { 341 (void) snprintf(linkpath, sizeof (linkpath), "mc/mc"); 342 } else if (unitaddr >= MC_AMD_DEV_OFFSET) { 343 (void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u", 344 unitaddr - MC_AMD_DEV_OFFSET); 345 } else { 346 (void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u", 347 minor->dev_minor); 348 } 349 (void) devfsadm_mklink(linkpath, node, minor, 0); 350 return (DEVFSADM_CONTINUE); 351 } 352 353 /* 354 * Creates \M0 devlink for xsvc node 355 */ 356 static int 357 xsvc(di_minor_t minor, di_node_t node) 358 { 359 char *mn; 360 361 if (strcmp(di_node_name(node), "xsvc") != 0) 362 return (DEVFSADM_CONTINUE); 363 364 mn = di_minor_name(minor); 365 if (mn == NULL) 366 return (DEVFSADM_CONTINUE); 367 368 (void) devfsadm_mklink(mn, node, minor, 0); 369 return (DEVFSADM_CONTINUE); 370 } 371 372 /* 373 * Creates \M0 devlink for srn device 374 */ 375 static int 376 srn(di_minor_t minor, di_node_t node) 377 { 378 char *mn; 379 380 if (strcmp(di_node_name(node), "srn") != 0) 381 return (DEVFSADM_CONTINUE); 382 383 mn = di_minor_name(minor); 384 if (mn == NULL) 385 return (DEVFSADM_CONTINUE); 386 387 (void) devfsadm_mklink(mn, node, minor, 0); 388 return (DEVFSADM_CONTINUE); 389 } 390 391 /* 392 * /dev/ucode -> /devices/pseudo/ucode@0:ucode 393 */ 394 static int 395 ucode(di_minor_t minor, di_node_t node) 396 { 397 (void) devfsadm_mklink("ucode", node, minor, 0); 398 return (DEVFSADM_CONTINUE); 399 } 400 401 static int 402 heci(di_minor_t minor, di_node_t node) 403 { 404 if (strcmp(di_minor_name(minor), "AMT") == 0) { 405 (void) devfsadm_mklink("heci", node, minor, 0); 406 } 407 return (DEVFSADM_CONTINUE); 408 } 409