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