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