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