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