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