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