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