xref: /titanic_44/usr/src/cmd/devfsadm/misc_link.c (revision bde3d612a7c090234c60e6e4578821237a5db135)
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