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 (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <regex.h> 26 #include <devfsadm.h> 27 #include <stdio.h> 28 #include <strings.h> 29 #include <stdlib.h> 30 #include <limits.h> 31 #include <sys/zone.h> 32 #include <sys/zcons.h> 33 #include <sys/cpuid_drv.h> 34 35 static int display(di_minor_t minor, di_node_t node); 36 static int parallel(di_minor_t minor, di_node_t node); 37 static int node_slash_minor(di_minor_t minor, di_node_t node); 38 static int driver_minor(di_minor_t minor, di_node_t node); 39 static int node_name(di_minor_t minor, di_node_t node); 40 static int minor_name(di_minor_t minor, di_node_t node); 41 static int wifi_minor_name(di_minor_t minor, di_node_t node); 42 static int conskbd(di_minor_t minor, di_node_t node); 43 static int consms(di_minor_t minor, di_node_t node); 44 static int power_button(di_minor_t minor, di_node_t node); 45 static int fc_port(di_minor_t minor, di_node_t node); 46 static int printer_create(di_minor_t minor, di_node_t node); 47 static int se_hdlc_create(di_minor_t minor, di_node_t node); 48 static int ppm(di_minor_t minor, di_node_t node); 49 static int gpio(di_minor_t minor, di_node_t node); 50 static int av_create(di_minor_t minor, di_node_t node); 51 static int tsalarm_create(di_minor_t minor, di_node_t node); 52 static int ntwdt_create(di_minor_t minor, di_node_t node); 53 static int zcons_create(di_minor_t minor, di_node_t node); 54 static int cpuid(di_minor_t minor, di_node_t node); 55 static int glvc(di_minor_t minor, di_node_t node); 56 static int ses_callback(di_minor_t minor, di_node_t node); 57 static int kmdrv_create(di_minor_t minor, di_node_t node); 58 59 static devfsadm_create_t misc_cbt[] = { 60 { "pseudo", "ddi_pseudo", "(^sad$)", 61 TYPE_EXACT | DRV_RE, ILEVEL_0, node_slash_minor 62 }, 63 { "pseudo", "ddi_pseudo", "zsh", 64 TYPE_EXACT | DRV_EXACT, ILEVEL_0, driver_minor 65 }, 66 { "network", "ddi_network", NULL, 67 TYPE_EXACT, ILEVEL_0, minor_name 68 }, 69 { "wifi", "ddi_network:wifi", NULL, 70 TYPE_EXACT, ILEVEL_0, wifi_minor_name 71 }, 72 { "display", "ddi_display", NULL, 73 TYPE_EXACT, ILEVEL_0, display 74 }, 75 { "parallel", "ddi_parallel", NULL, 76 TYPE_EXACT, ILEVEL_0, parallel 77 }, 78 { "enclosure", DDI_NT_SCSI_ENCLOSURE, NULL, 79 TYPE_EXACT, ILEVEL_0, ses_callback 80 }, 81 { "pseudo", "ddi_pseudo", "(^winlock$)|(^pm$)", 82 TYPE_EXACT | DRV_RE, ILEVEL_0, node_name 83 }, 84 { "pseudo", "ddi_pseudo", "conskbd", 85 TYPE_EXACT | DRV_EXACT, ILEVEL_0, conskbd 86 }, 87 { "pseudo", "ddi_pseudo", "consms", 88 TYPE_EXACT | DRV_EXACT, ILEVEL_0, consms 89 }, 90 { "pseudo", "ddi_pseudo", "rsm", 91 TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name 92 }, 93 { "pseudo", "ddi_pseudo", 94 "(^lockstat$)|(^SUNW,rtvc$)|(^vol$)|(^log$)|(^sy$)|" 95 "(^ksyms$)|(^clone$)|(^tl$)|(^tnf$)|(^kstat$)|(^mdesc$)|(^eeprom$)|" 96 "(^ptsl$)|(^mm$)|(^wc$)|(^dump$)|(^cn$)|(^svvslo$)|(^ptm$)|" 97 "(^ptc$)|(^openeepr$)|(^poll$)|(^sysmsg$)|(^random$)|(^trapstat$)|" 98 "(^cryptoadm$)|(^crypto$)|(^pool$)|(^poolctl$)|(^bl$)|(^kmdb$)|" 99 "(^sysevent$)|(^kssl$)|(^physmem$)", 100 TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name 101 }, 102 { "pseudo", "ddi_pseudo", 103 "(^ip$)|(^tcp$)|(^udp$)|(^icmp$)|" 104 "(^ip6$)|(^tcp6$)|(^udp6$)|(^icmp6$)|" 105 "(^rts$)|(^arp$)|(^ipsecah$)|(^ipsecesp$)|(^keysock$)|(^spdsock$)|" 106 "(^nca$)|(^rds$)|(^sdp$)|(^ipnet$)|(^dlpistub$)|(^bpf$)", 107 TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name 108 }, 109 { "pseudo", "ddi_pseudo", 110 "(^ipf$)|(^ipnat$)|(^ipstate$)|(^ipauth$)|" 111 "(^ipsync$)|(^ipscan$)|(^iplookup$)", 112 TYPE_EXACT | DRV_RE, ILEVEL_0, minor_name, 113 }, 114 { "pseudo", "ddi_pseudo", "dld", 115 TYPE_EXACT | DRV_EXACT, ILEVEL_0, node_name 116 }, 117 { "pseudo", "ddi_pseudo", 118 "(^kdmouse$)|(^rootprop$)", 119 TYPE_EXACT | DRV_RE, ILEVEL_0, node_name 120 }, 121 { "pseudo", "ddi_pseudo", "tod", 122 TYPE_EXACT | DRV_EXACT, ILEVEL_0, node_name 123 }, 124 { "pseudo", "ddi_pseudo", "envctrl(two)?", 125 TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name, 126 }, 127 { "pseudo", "ddi_pseudo", "fcode", 128 TYPE_EXACT | DRV_RE, ILEVEL_0, minor_name, 129 }, 130 { "power_button", "ddi_power_button", NULL, 131 TYPE_EXACT, ILEVEL_0, power_button, 132 }, 133 { "FC port", "ddi_ctl:devctl", "fp", 134 TYPE_EXACT | DRV_EXACT, ILEVEL_0, fc_port 135 }, 136 { "printer", "ddi_printer", NULL, 137 TYPE_EXACT, ILEVEL_0, printer_create 138 }, 139 { "pseudo", "ddi_pseudo", "se", 140 TYPE_EXACT | DRV_EXACT, ILEVEL_0, se_hdlc_create 141 }, 142 { "ppm", "ddi_ppm", NULL, 143 TYPE_EXACT, ILEVEL_0, ppm 144 }, 145 { "pseudo", "ddi_pseudo", "gpio_87317", 146 TYPE_EXACT | DRV_EXACT, ILEVEL_0, gpio 147 }, 148 { "pseudo", "ddi_pseudo", "sckmdrv", 149 TYPE_EXACT | DRV_RE, ILEVEL_0, kmdrv_create, 150 }, 151 { "pseudo", "ddi_pseudo", "oplkmdrv", 152 TYPE_EXACT | DRV_RE, ILEVEL_0, kmdrv_create, 153 }, 154 { "av", "^ddi_av:(isoch|async)$", NULL, 155 TYPE_RE, ILEVEL_0, av_create, 156 }, 157 { "pseudo", "ddi_pseudo", "tsalarm", 158 TYPE_EXACT | DRV_RE, ILEVEL_0, tsalarm_create, 159 }, 160 { "pseudo", "ddi_pseudo", "ntwdt", 161 TYPE_EXACT | DRV_RE, ILEVEL_0, ntwdt_create, 162 }, 163 { "pseudo", "ddi_pseudo", "daplt", 164 TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name 165 }, 166 { "pseudo", "ddi_pseudo", "zcons", 167 TYPE_EXACT | DRV_EXACT, ILEVEL_0, zcons_create, 168 }, 169 { "pseudo", "ddi_pseudo", CPUID_DRIVER_NAME, 170 TYPE_EXACT | DRV_EXACT, ILEVEL_0, cpuid, 171 }, 172 { "pseudo", "ddi_pseudo", "glvc", 173 TYPE_EXACT | DRV_EXACT, ILEVEL_0, glvc, 174 }, 175 { "pseudo", "ddi_pseudo", "dm2s", 176 TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name, 177 }, 178 { "pseudo", "ddi_pseudo", "nsmb", 179 TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name, 180 }, 181 { "pseudo", "ddi_pseudo", "mem_cache", 182 TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name, 183 }, 184 { "pseudo", "ddi_pseudo", "fm", 185 TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name, 186 }, 187 { "pseudo", "ddi_pseudo", "tpm", 188 TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name 189 }, 190 }; 191 192 DEVFSADM_CREATE_INIT_V0(misc_cbt); 193 194 static devfsadm_remove_t misc_remove_cbt[] = { 195 { "pseudo", "^profile$", 196 RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 197 }, 198 { "pseudo", "^rsm$", 199 RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 200 }, 201 { "printer", "^printers/[0-9]+$", 202 RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 203 }, 204 { "av", "^av/[0-9]+/(async|isoch)$", 205 RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 206 }, 207 { "pseudo", "^daplt$", 208 RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 209 }, 210 { "pseudo", "^zcons/" ZONENAME_REGEXP "/(" ZCONS_MASTER_NAME "|" 211 ZCONS_SLAVE_NAME ")$", 212 RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 213 }, 214 { "pseudo", "^" CPUID_SELF_NAME "$", RM_ALWAYS | RM_PRE | RM_HOT, 215 ILEVEL_0, devfsadm_rm_all 216 }, 217 { "enclosure", "^es/ses[0-9]+$", RM_POST, 218 ILEVEL_0, devfsadm_rm_all 219 }, 220 { "pseudo", "^pfil$", 221 RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 222 }, 223 { "pseudo", "^tpm$", 224 RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 225 }, 226 { "pseudo", "^sctp|sctp6$", 227 RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_link 228 } 229 }; 230 231 /* Rules for gpio devices */ 232 static devfsadm_enumerate_t gpio_rules[1] = 233 {"^gpio([0-9]+)$", 1, MATCH_ALL}; 234 235 DEVFSADM_REMOVE_INIT_V0(misc_remove_cbt); 236 237 /* 238 * Handles minor node type "ddi_display". 239 * 240 * type=ddi_display fbs/\M0 fb\N0 241 */ 242 static int 243 display(di_minor_t minor, di_node_t node) 244 { 245 char l_path[PATH_MAX + 1], contents[PATH_MAX + 1], *buf; 246 devfsadm_enumerate_t rules[1] = {"^fb([0-9]+)$", 1, MATCH_ALL}; 247 char *mn = di_minor_name(minor); 248 249 /* create fbs/\M0 primary link */ 250 (void) strcpy(l_path, "fbs/"); 251 (void) strcat(l_path, mn); 252 (void) devfsadm_mklink(l_path, node, minor, 0); 253 254 /* create fb\N0 which links to fbs/\M0 */ 255 if (devfsadm_enumerate_int(l_path, 0, &buf, rules, 1)) { 256 return (DEVFSADM_CONTINUE); 257 } 258 (void) strcpy(contents, l_path); 259 (void) strcpy(l_path, "fb"); 260 (void) strcat(l_path, buf); 261 free(buf); 262 (void) devfsadm_secondary_link(l_path, contents, 0); 263 return (DEVFSADM_CONTINUE); 264 } 265 266 /* 267 * Handles minor node type "ddi_parallel". 268 * type=ddi_parallel;name=mcpp mcpp\N0 269 */ 270 static int 271 parallel(di_minor_t minor, di_node_t node) 272 { 273 char path[PATH_MAX + 1], *buf; 274 devfsadm_enumerate_t rules[1] = {"mcpp([0-9]+)$", 1, MATCH_ALL}; 275 276 277 if (strcmp(di_node_name(node), "mcpp") != 0) { 278 return (DEVFSADM_CONTINUE); 279 } 280 281 if (NULL == (buf = di_devfs_path(node))) { 282 return (DEVFSADM_CONTINUE); 283 } 284 285 (void) snprintf(path, sizeof (path), "%s:%s", 286 buf, di_minor_name(minor)); 287 288 di_devfs_path_free(buf); 289 290 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 291 return (DEVFSADM_CONTINUE); 292 } 293 (void) snprintf(path, sizeof (path), "mcpp%s", buf); 294 free(buf); 295 296 (void) devfsadm_mklink(path, node, minor, 0); 297 return (DEVFSADM_CONTINUE); 298 } 299 300 static int 301 ses_callback(di_minor_t minor, di_node_t node) 302 { 303 char l_path[PATH_MAX]; 304 char *buf; 305 char *devfspath; 306 char p_path[PATH_MAX]; 307 devfsadm_enumerate_t re[] = {"^es$/^ses([0-9]+)$", 1, MATCH_ALL}; 308 309 /* find devices path -- need to free mem */ 310 if (NULL == (devfspath = di_devfs_path(node))) { 311 return (DEVFSADM_CONTINUE); 312 } 313 314 (void) snprintf(p_path, sizeof (p_path), "%s:%s", devfspath, 315 di_minor_name(minor)); 316 317 318 /* find next number to use; buf is an ascii number */ 319 if (devfsadm_enumerate_int(p_path, 0, &buf, re, 1)) { 320 /* free memory */ 321 di_devfs_path_free(devfspath); 322 return (DEVFSADM_CONTINUE); 323 } 324 325 (void) snprintf(l_path, sizeof (l_path), "es/ses%s", buf); 326 327 (void) devfsadm_mklink(l_path, node, minor, 0); 328 /* free memory */ 329 free(buf); 330 di_devfs_path_free(devfspath); 331 return (DEVFSADM_CONTINUE); 332 333 } 334 335 static int 336 node_slash_minor(di_minor_t minor, di_node_t node) 337 { 338 339 char path[PATH_MAX + 1]; 340 341 (void) strcpy(path, di_node_name(node)); 342 (void) strcat(path, "/"); 343 (void) strcat(path, di_minor_name(minor)); 344 (void) devfsadm_mklink(path, node, minor, 0); 345 return (DEVFSADM_CONTINUE); 346 } 347 348 static int 349 driver_minor(di_minor_t minor, di_node_t node) 350 { 351 char path[PATH_MAX + 1]; 352 353 (void) strcpy(path, di_driver_name(node)); 354 (void) strcat(path, di_minor_name(minor)); 355 (void) devfsadm_mklink(path, node, minor, 0); 356 return (DEVFSADM_CONTINUE); 357 } 358 359 /* 360 * Handles links of the form: 361 * type=ddi_pseudo;name=xyz \D 362 */ 363 static int 364 node_name(di_minor_t minor, di_node_t node) 365 { 366 (void) devfsadm_mklink(di_node_name(node), node, minor, 0); 367 return (DEVFSADM_CONTINUE); 368 } 369 370 /* 371 * Handles links of the form: 372 * type=ddi_pseudo;name=xyz \M0 373 */ 374 static int 375 minor_name(di_minor_t minor, di_node_t node) 376 { 377 char *mn = di_minor_name(minor); 378 379 (void) devfsadm_mklink(mn, node, minor, 0); 380 if (strcmp(mn, "icmp") == 0) { 381 (void) devfsadm_mklink("rawip", node, minor, 0); 382 } 383 if (strcmp(mn, "icmp6") == 0) { 384 (void) devfsadm_mklink("rawip6", node, minor, 0); 385 } 386 if (strcmp(mn, "ipf") == 0) { 387 (void) devfsadm_mklink("ipl", node, minor, 0); 388 } 389 return (DEVFSADM_CONTINUE); 390 } 391 392 /* 393 * create links at /dev/wifi for wifi minor node 394 */ 395 static int 396 wifi_minor_name(di_minor_t minor, di_node_t node) 397 { 398 char buf[256]; 399 char *mn = di_minor_name(minor); 400 401 (void) snprintf(buf, sizeof (buf), "%s%s", "wifi/", mn); 402 (void) devfsadm_mklink(buf, node, minor, 0); 403 404 return (DEVFSADM_CONTINUE); 405 } 406 407 static int 408 conskbd(di_minor_t minor, di_node_t node) 409 { 410 (void) devfsadm_mklink("kbd", node, minor, 0); 411 return (DEVFSADM_CONTINUE); 412 } 413 414 static int 415 consms(di_minor_t minor, di_node_t node) 416 { 417 (void) devfsadm_mklink("mouse", node, minor, 0); 418 return (DEVFSADM_CONTINUE); 419 } 420 421 static int 422 power_button(di_minor_t minor, di_node_t node) 423 { 424 (void) devfsadm_mklink("power_button", node, minor, 0); 425 return (DEVFSADM_CONTINUE); 426 } 427 428 static int 429 fc_port(di_minor_t minor, di_node_t node) 430 { 431 devfsadm_enumerate_t rules[1] = {"fc/fp([0-9]+)$", 1, MATCH_ALL}; 432 char *buf, path[PATH_MAX + 1]; 433 char *ptr; 434 435 if (NULL == (ptr = di_devfs_path(node))) { 436 return (DEVFSADM_CONTINUE); 437 } 438 439 (void) strcpy(path, ptr); 440 (void) strcat(path, ":"); 441 (void) strcat(path, di_minor_name(minor)); 442 443 di_devfs_path_free(ptr); 444 445 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) != 0) { 446 return (DEVFSADM_CONTINUE); 447 } 448 449 (void) strcpy(path, "fc/fp"); 450 (void) strcat(path, buf); 451 free(buf); 452 453 (void) devfsadm_mklink(path, node, minor, 0); 454 return (DEVFSADM_CONTINUE); 455 } 456 457 /* 458 * Handles: 459 * minor node type "ddi_printer". 460 * rules of the form: type=ddi_printer;name=bpp \M0 461 */ 462 static int 463 printer_create(di_minor_t minor, di_node_t node) 464 { 465 char *mn; 466 char path[PATH_MAX + 1], *buf; 467 devfsadm_enumerate_t rules[1] = {"^printers$/^([0-9]+)$", 1, MATCH_ALL}; 468 469 mn = di_minor_name(minor); 470 471 if (strcmp(di_driver_name(node), "bpp") == 0) { 472 (void) devfsadm_mklink(mn, node, minor, 0); 473 } 474 475 if (NULL == (buf = di_devfs_path(node))) { 476 return (DEVFSADM_CONTINUE); 477 } 478 479 (void) snprintf(path, sizeof (path), "%s:%s", buf, mn); 480 di_devfs_path_free(buf); 481 482 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 483 return (DEVFSADM_CONTINUE); 484 } 485 486 (void) snprintf(path, sizeof (path), "printers/%s", buf); 487 free(buf); 488 489 (void) devfsadm_mklink(path, node, minor, 0); 490 491 return (DEVFSADM_CONTINUE); 492 } 493 494 /* 495 * Handles links of the form: 496 * type=ddi_pseudo;name=se;minor2=hdlc se_hdlc\N0 497 * type=ddi_pseudo;name=serial;minor2=hdlc se_hdlc\N0 498 */ 499 static int 500 se_hdlc_create(di_minor_t minor, di_node_t node) 501 { 502 devfsadm_enumerate_t rules[1] = {"^se_hdlc([0-9]+)$", 1, MATCH_ALL}; 503 char *buf, path[PATH_MAX + 1]; 504 char *ptr; 505 char *mn; 506 507 mn = di_minor_name(minor); 508 509 /* minor node should be of the form: "?,hdlc" */ 510 if (strcmp(mn + 1, ",hdlc") != 0) { 511 return (DEVFSADM_CONTINUE); 512 } 513 514 if (NULL == (ptr = di_devfs_path(node))) { 515 return (DEVFSADM_CONTINUE); 516 } 517 518 (void) strcpy(path, ptr); 519 (void) strcat(path, ":"); 520 (void) strcat(path, mn); 521 522 di_devfs_path_free(ptr); 523 524 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) != 0) { 525 return (DEVFSADM_CONTINUE); 526 } 527 528 (void) strcpy(path, "se_hdlc"); 529 (void) strcat(path, buf); 530 free(buf); 531 532 (void) devfsadm_mklink(path, node, minor, 0); 533 534 return (DEVFSADM_CONTINUE); 535 } 536 537 static int 538 gpio(di_minor_t minor, di_node_t node) 539 { 540 char l_path[PATH_MAX], p_path[PATH_MAX], *buf, *devfspath; 541 char *minor_nm, *drvr_nm; 542 543 544 minor_nm = di_minor_name(minor); 545 drvr_nm = di_driver_name(node); 546 if ((minor_nm == NULL) || (drvr_nm == NULL)) { 547 return (DEVFSADM_CONTINUE); 548 } 549 550 devfspath = di_devfs_path(node); 551 552 (void) strcpy(p_path, devfspath); 553 (void) strcat(p_path, ":"); 554 (void) strcat(p_path, minor_nm); 555 di_devfs_path_free(devfspath); 556 557 /* build the physical path from the components */ 558 if (devfsadm_enumerate_int(p_path, 0, &buf, gpio_rules, 1)) { 559 return (DEVFSADM_CONTINUE); 560 } 561 562 (void) snprintf(l_path, sizeof (l_path), "%s%s", "gpio", buf); 563 564 free(buf); 565 566 (void) devfsadm_mklink(l_path, node, minor, 0); 567 568 return (DEVFSADM_CONTINUE); 569 } 570 571 /* 572 * Creates /dev/ppm nodes for Platform Specific PM module 573 */ 574 static int 575 ppm(di_minor_t minor, di_node_t node) 576 { 577 (void) devfsadm_mklink("ppm", node, minor, 0); 578 return (DEVFSADM_CONTINUE); 579 } 580 581 /* 582 * Handles: 583 * /dev/av/[0-9]+/(async|isoch) 584 */ 585 static int 586 av_create(di_minor_t minor, di_node_t node) 587 { 588 devfsadm_enumerate_t rules[1] = {"^av$/^([0-9]+)$", 1, MATCH_ADDR}; 589 char *minor_str; 590 char path[PATH_MAX + 1]; 591 char *buf; 592 593 if ((buf = di_devfs_path(node)) == NULL) { 594 return (DEVFSADM_CONTINUE); 595 } 596 597 minor_str = di_minor_name(minor); 598 (void) snprintf(path, sizeof (path), "%s:%s", buf, minor_str); 599 di_devfs_path_free(buf); 600 601 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 602 return (DEVFSADM_CONTINUE); 603 } 604 605 (void) snprintf(path, sizeof (path), "av/%s/%s", buf, minor_str); 606 free(buf); 607 608 (void) devfsadm_mklink(path, node, minor, 0); 609 610 return (DEVFSADM_CONTINUE); 611 } 612 613 /* 614 * Creates /dev/lom and /dev/tsalarm:ctl for tsalarm node 615 */ 616 static int 617 tsalarm_create(di_minor_t minor, di_node_t node) 618 { 619 char buf[PATH_MAX + 1]; 620 char *mn = di_minor_name(minor); 621 622 (void) snprintf(buf, sizeof (buf), "%s%s", di_node_name(node), ":ctl"); 623 624 (void) devfsadm_mklink(mn, node, minor, 0); 625 (void) devfsadm_mklink(buf, node, minor, 0); 626 627 return (DEVFSADM_CONTINUE); 628 } 629 630 /* 631 * Creates /dev/ntwdt for ntwdt node 632 */ 633 static int 634 ntwdt_create(di_minor_t minor, di_node_t node) 635 { 636 (void) devfsadm_mklink("ntwdt", node, minor, 0); 637 return (DEVFSADM_CONTINUE); 638 } 639 640 static int 641 zcons_create(di_minor_t minor, di_node_t node) 642 { 643 char *minor_str; 644 char *zonename; 645 char path[MAXPATHLEN]; 646 647 minor_str = di_minor_name(minor); 648 649 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename", 650 &zonename) == -1) { 651 return (DEVFSADM_CONTINUE); 652 } 653 654 (void) snprintf(path, sizeof (path), "zcons/%s/%s", zonename, 655 minor_str); 656 (void) devfsadm_mklink(path, node, minor, 0); 657 658 return (DEVFSADM_CONTINUE); 659 } 660 661 /* 662 * /dev/cpu/self/cpuid -> /devices/pseudo/cpuid@0:self 663 */ 664 static int 665 cpuid(di_minor_t minor, di_node_t node) 666 { 667 (void) devfsadm_mklink(CPUID_SELF_NAME, node, minor, 0); 668 return (DEVFSADM_CONTINUE); 669 } 670 671 /* 672 * For device 673 * /dev/spfma -> /devices/virtual-devices/fma@5:glvc 674 */ 675 static int 676 glvc(di_minor_t minor, di_node_t node) 677 { 678 char node_name[MAXNAMELEN + 1]; 679 680 (void) strcpy(node_name, di_node_name(node)); 681 682 if (strncmp(node_name, "fma", 3) == 0) { 683 /* Only one fma channel */ 684 (void) devfsadm_mklink("spfma", node, minor, 0); 685 } 686 return (DEVFSADM_CONTINUE); 687 } 688 689 /* 690 * Handles links of the form: 691 * type=ddi_pseudo;name=sckmdrv kmdrv\M0 692 * type=ddi_pseudo;name=oplkmdrv kmdrv\M0 693 */ 694 static int 695 kmdrv_create(di_minor_t minor, di_node_t node) 696 { 697 698 (void) devfsadm_mklink("kmdrv", node, minor, 0); 699 return (DEVFSADM_CONTINUE); 700 } 701