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 <ctype.h> 35 #include <sys/mc.h> 36 #include <bsm/devalloc.h> 37 38 extern int system_labeled; 39 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 bmc(di_minor_t minor, di_node_t node); 47 static int smbios(di_minor_t minor, di_node_t node); 48 static int agp_process(di_minor_t minor, di_node_t node); 49 static int mc_node(di_minor_t minor, di_node_t node); 50 51 static devfsadm_create_t misc_cbt[] = { 52 { "vt00", "ddi_display", NULL, 53 TYPE_EXACT, ILEVEL_0, vt00 54 }, 55 { "mouse", "ddi_mouse", "mouse8042", 56 TYPE_EXACT | DRV_EXACT, ILEVEL_0, kdmouse 57 }, 58 { "pseudo", "ddi_pseudo", "bmc", 59 TYPE_EXACT | DRV_EXACT, ILEVEL_0, bmc, 60 }, 61 { "pseudo", "ddi_pseudo", "smbios", 62 TYPE_EXACT | DRV_EXACT, ILEVEL_1, smbios, 63 }, 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 { "agp", "ddi_agp:pseudo", NULL, 77 TYPE_EXACT, ILEVEL_0, agp_process 78 }, 79 { "agp", "ddi_agp:target", NULL, 80 TYPE_EXACT, ILEVEL_0, agp_process 81 }, 82 { "agp", "ddi_agp:cpugart", NULL, 83 TYPE_EXACT, ILEVEL_0, agp_process 84 }, 85 { "agp", "ddi_agp:master", NULL, 86 TYPE_EXACT, ILEVEL_0, agp_process 87 }, 88 { "memory-controller", "ddi_mem_ctrl", NULL, 89 TYPE_EXACT, ILEVEL_0, mc_node 90 } 91 }; 92 93 DEVFSADM_CREATE_INIT_V0(misc_cbt); 94 95 static char *debug_mid = "agp_mid"; 96 97 typedef enum { 98 DRIVER_AGPPSEUDO = 0, 99 DRIVER_AGPTARGET, 100 DRIVER_CPUGART, 101 DRIVER_AGPMASTER, 102 DRIVER_UNKNOWN 103 } driver_defs_t; 104 105 typedef struct { 106 char *driver_name; 107 int index; 108 } driver_name_table_entry_t; 109 110 static driver_name_table_entry_t driver_name_table[] = { 111 { "agpgart", DRIVER_AGPPSEUDO }, 112 { "agptarget", DRIVER_AGPTARGET }, 113 { "amd64_gart", DRIVER_CPUGART }, 114 { "vgatext", DRIVER_AGPMASTER }, 115 { NULL, DRIVER_UNKNOWN } 116 }; 117 118 static devfsadm_enumerate_t agptarget_rules[1] = 119 { "^agp$/^agptarget([0-9]+)$", 1, MATCH_ALL }; 120 static devfsadm_enumerate_t cpugart_rules[1] = 121 { "^agp$/^cpugart([0-9]+)$", 1, MATCH_ALL }; 122 static devfsadm_enumerate_t agpmaster_rules[1] = 123 { "^agp$/^agpmaster([0-9]+)$", 1, MATCH_ALL }; 124 125 static devfsadm_remove_t misc_remove_cbt[] = { 126 { "vt", "vt[0-9][0-9]", RM_PRE|RM_ALWAYS, 127 ILEVEL_0, devfsadm_rm_all 128 } 129 }; 130 131 DEVFSADM_REMOVE_INIT_V0(misc_remove_cbt); 132 133 /* 134 * Handles minor node type "ddi_display", in addition to generic processing 135 * done by display(). 136 * 137 * This creates a /dev/vt00 link to /dev/fb, for backwards compatibility. 138 */ 139 /* ARGSUSED */ 140 int 141 vt00(di_minor_t minor, di_node_t node) 142 { 143 (void) devfsadm_secondary_link("vt00", "fb", 0); 144 return (DEVFSADM_CONTINUE); 145 } 146 147 /* 148 * type=ddi_block:diskette;addr=0,0;minor=c diskette 149 * type=ddi_block:diskette;addr=0,0;minor=c,raw rdiskette 150 * type=ddi_block:diskette;addr1=0;minor=c diskette\A2 151 * type=ddi_block:diskette;addr1=0;minor=c,raw rdiskette\A2 152 */ 153 static int 154 diskette(di_minor_t minor, di_node_t node) 155 { 156 int flags = 0; 157 char *a2; 158 char link[PATH_MAX]; 159 char *addr = di_bus_addr(node); 160 char *mn = di_minor_name(minor); 161 162 if (system_labeled) 163 flags = DA_ADD|DA_FLOPPY; 164 165 if (strcmp(addr, "0,0") == 0) { 166 if (strcmp(mn, "c") == 0) { 167 (void) devfsadm_mklink("diskette", node, minor, flags); 168 } else if (strcmp(mn, "c,raw") == 0) { 169 (void) devfsadm_mklink("rdiskette", node, minor, flags); 170 } 171 172 } 173 174 if (addr[0] == '0') { 175 if ((a2 = strchr(addr, ',')) != NULL) { 176 a2++; 177 if (strcmp(mn, "c") == 0) { 178 (void) strcpy(link, "diskette"); 179 (void) strcat(link, a2); 180 (void) devfsadm_mklink(link, node, minor, 181 flags); 182 } else if (strcmp(mn, "c,raw") == 0) { 183 (void) strcpy(link, "rdiskette"); 184 (void) strcat(link, a2); 185 (void) devfsadm_mklink(link, node, minor, 186 flags); 187 } 188 } 189 } 190 191 return (DEVFSADM_CONTINUE); 192 } 193 194 /* 195 * type=ddi_printer;name=lp;addr=1,3bc lp0 196 * type=ddi_printer;name=lp;addr=1,378 lp1 197 * type=ddi_printer;name=lp;addr=1,278 lp2 198 */ 199 static int 200 lp(di_minor_t minor, di_node_t node) 201 { 202 char *addr = di_bus_addr(node); 203 char *buf; 204 char path[PATH_MAX + 1]; 205 devfsadm_enumerate_t rules[1] = {"^ecpp([0-9]+)$", 1, MATCH_ALL}; 206 207 if (strcmp(addr, "1,3bc") == 0) { 208 (void) devfsadm_mklink("lp0", node, minor, 0); 209 210 } else if (strcmp(addr, "1,378") == 0) { 211 (void) devfsadm_mklink("lp1", node, minor, 0); 212 213 } else if (strcmp(addr, "1,278") == 0) { 214 (void) devfsadm_mklink("lp2", node, minor, 0); 215 } 216 217 if (strcmp(di_driver_name(node), "ecpp") != 0) { 218 return (DEVFSADM_CONTINUE); 219 } 220 221 if ((buf = di_devfs_path(node)) == NULL) { 222 return (DEVFSADM_CONTINUE); 223 } 224 225 (void) snprintf(path, sizeof (path), "%s:%s", 226 buf, di_minor_name(minor)); 227 228 di_devfs_path_free(buf); 229 230 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 231 return (DEVFSADM_CONTINUE); 232 } 233 234 (void) snprintf(path, sizeof (path), "ecpp%s", buf); 235 free(buf); 236 (void) devfsadm_mklink(path, node, minor, 0); 237 return (DEVFSADM_CONTINUE); 238 } 239 240 /* 241 * type=ddi_serial:mb;minor=a tty00 242 * type=ddi_serial:mb;minor=b tty01 243 * type=ddi_serial:mb;minor=c tty02 244 * type=ddi_serial:mb;minor=d tty03 245 */ 246 static int 247 serial(di_minor_t minor, di_node_t node) 248 { 249 250 char *mn = di_minor_name(minor); 251 char link[PATH_MAX]; 252 253 (void) strcpy(link, "tty"); 254 (void) strcat(link, mn); 255 (void) devfsadm_mklink(link, node, minor, 0); 256 257 if (strcmp(mn, "a") == 0) { 258 (void) devfsadm_mklink("tty00", node, minor, 0); 259 260 } else if (strcmp(mn, "b") == 0) { 261 (void) devfsadm_mklink("tty01", node, minor, 0); 262 263 } else if (strcmp(mn, "c") == 0) { 264 (void) devfsadm_mklink("tty02", node, minor, 0); 265 266 } else if (strcmp(mn, "d") == 0) { 267 (void) devfsadm_mklink("tty03", node, minor, 0); 268 } 269 return (DEVFSADM_CONTINUE); 270 } 271 272 /* 273 * type=ddi_serial:dialout,mb;minor=a,cu ttyd0 274 * type=ddi_serial:dialout,mb;minor=b,cu ttyd1 275 * type=ddi_serial:dialout,mb;minor=c,cu ttyd2 276 * type=ddi_serial:dialout,mb;minor=d,cu ttyd3 277 */ 278 static int 279 serial_dialout(di_minor_t minor, di_node_t node) 280 { 281 char *mn = di_minor_name(minor); 282 283 if (strcmp(mn, "a,cu") == 0) { 284 (void) devfsadm_mklink("ttyd0", node, minor, 0); 285 (void) devfsadm_mklink("cua0", node, minor, 0); 286 287 } else if (strcmp(mn, "b,cu") == 0) { 288 (void) devfsadm_mklink("ttyd1", node, minor, 0); 289 (void) devfsadm_mklink("cua1", node, minor, 0); 290 291 } else if (strcmp(mn, "c,cu") == 0) { 292 (void) devfsadm_mklink("ttyd2", node, minor, 0); 293 (void) devfsadm_mklink("cua2", node, minor, 0); 294 295 } else if (strcmp(mn, "d,cu") == 0) { 296 (void) devfsadm_mklink("ttyd3", node, minor, 0); 297 (void) devfsadm_mklink("cua3", node, minor, 0); 298 } 299 return (DEVFSADM_CONTINUE); 300 } 301 302 static int 303 kdmouse(di_minor_t minor, di_node_t node) 304 { 305 (void) devfsadm_mklink("kdmouse", node, minor, 0); 306 return (DEVFSADM_CONTINUE); 307 } 308 309 static int 310 bmc(di_minor_t minor, di_node_t node) 311 { 312 (void) devfsadm_mklink("bmc", node, minor, 0); 313 return (DEVFSADM_CONTINUE); 314 } 315 316 static int 317 smbios(di_minor_t minor, di_node_t node) 318 { 319 (void) devfsadm_mklink("smbios", node, minor, 0); 320 return (DEVFSADM_CONTINUE); 321 } 322 323 static int 324 agp_process(di_minor_t minor, di_node_t node) 325 { 326 char *minor_nm, *drv_nm; 327 char *devfspath; 328 char *I_path, *p_path, *buf; 329 char *name = (char *)NULL; 330 int i, index; 331 devfsadm_enumerate_t rules[1]; 332 333 minor_nm = di_minor_name(minor); 334 drv_nm = di_driver_name(node); 335 336 if ((minor_nm == NULL) || (drv_nm == NULL)) { 337 return (DEVFSADM_CONTINUE); 338 } 339 340 devfsadm_print(debug_mid, "agp_process: minor=%s node=%s\n", 341 minor_nm, di_node_name(node)); 342 343 devfspath = di_devfs_path(node); 344 if (devfspath == NULL) { 345 devfsadm_print(debug_mid, "agp_process: devfspath is NULL\n"); 346 return (DEVFSADM_CONTINUE); 347 } 348 349 I_path = (char *)malloc(PATH_MAX); 350 351 if (I_path == NULL) { 352 di_devfs_path_free(devfspath); 353 devfsadm_print(debug_mid, "agp_process: malloc failed\n"); 354 return (DEVFSADM_CONTINUE); 355 } 356 357 p_path = (char *)malloc(PATH_MAX); 358 359 if (p_path == NULL) { 360 devfsadm_print(debug_mid, "agp_process: malloc failed\n"); 361 di_devfs_path_free(devfspath); 362 free(I_path); 363 return (DEVFSADM_CONTINUE); 364 } 365 366 (void) strlcpy(p_path, devfspath, PATH_MAX); 367 (void) strlcat(p_path, ":", PATH_MAX); 368 (void) strlcat(p_path, minor_nm, PATH_MAX); 369 di_devfs_path_free(devfspath); 370 371 devfsadm_print(debug_mid, "agp_process: path %s\n", p_path); 372 373 for (i = 0; ; i++) { 374 if ((driver_name_table[i].driver_name == NULL) || 375 (strcmp(drv_nm, driver_name_table[i].driver_name) == 0)) { 376 index = driver_name_table[i].index; 377 break; 378 } 379 } 380 switch (index) { 381 case DRIVER_AGPPSEUDO: 382 devfsadm_print(debug_mid, 383 "agp_process: psdeudo driver name\n"); 384 name = "agpgart"; 385 (void) snprintf(I_path, PATH_MAX, "%s", name); 386 devfsadm_print(debug_mid, 387 "mklink %s -> %s\n", I_path, p_path); 388 389 (void) devfsadm_mklink(I_path, node, minor, 0); 390 391 free(I_path); 392 free(p_path); 393 return (DEVFSADM_CONTINUE); 394 case DRIVER_AGPTARGET: 395 devfsadm_print(debug_mid, 396 "agp_process: target driver name\n"); 397 rules[0] = agptarget_rules[0]; 398 name = "agptarget"; 399 break; 400 case DRIVER_CPUGART: 401 devfsadm_print(debug_mid, 402 "agp_process: cpugart driver name\n"); 403 rules[0] = cpugart_rules[0]; 404 name = "cpugart"; 405 break; 406 case DRIVER_AGPMASTER: 407 devfsadm_print(debug_mid, 408 "agp_process: agpmaster driver name\n"); 409 rules[0] = agpmaster_rules[0]; 410 name = "agpmaster"; 411 break; 412 case DRIVER_UNKNOWN: 413 devfsadm_print(debug_mid, 414 "agp_process: unknown driver name=%s\n", drv_nm); 415 free(I_path); 416 free(p_path); 417 return (DEVFSADM_CONTINUE); 418 } 419 420 if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) { 421 devfsadm_print(debug_mid, "agp_process: exit/coninue\n"); 422 free(I_path); 423 free(p_path); 424 return (DEVFSADM_CONTINUE); 425 } 426 427 428 (void) snprintf(I_path, PATH_MAX, "agp/%s%s", name, buf); 429 430 devfsadm_print(debug_mid, "agp_process: p_path=%s buf=%s\n", 431 p_path, buf); 432 433 free(buf); 434 435 devfsadm_print(debug_mid, "mklink %s -> %s\n", I_path, p_path); 436 437 (void) devfsadm_mklink(I_path, node, minor, 0); 438 439 free(p_path); 440 free(I_path); 441 442 return (DEVFSADM_CONTINUE); 443 } 444 445 /* 446 * /dev/mc/mc<chipid> -> /devices/.../pci1022,1102@<chipid+24>,2:mc-amd 447 */ 448 static int 449 mc_node(di_minor_t minor, di_node_t node) 450 { 451 const char *minorname = di_minor_name(minor); 452 const char *busaddr = di_bus_addr(node); 453 char linkpath[PATH_MAX]; 454 int unitaddr; 455 char *c; 456 457 if (minorname == NULL || busaddr == NULL) 458 return (DEVFSADM_CONTINUE); 459 460 errno = 0; 461 unitaddr = strtol(busaddr, &c, 16); 462 463 if (errno != 0 || unitaddr < MC_AMD_DEV_OFFSET) 464 return (DEVFSADM_CONTINUE); 465 466 (void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u", 467 unitaddr - MC_AMD_DEV_OFFSET); 468 (void) devfsadm_mklink(linkpath, node, minor, 0); 469 return (DEVFSADM_CONTINUE); 470 } 471