xref: /illumos-gate/usr/src/cmd/devfsadm/i386/misc_link_i386.c (revision 67a4bb8f9ad4c49e9aa9e21e2114a7c093c3a73a)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 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 <ctype.h>
34 #include <sys/mc_amd.h>
35 #include <bsm/devalloc.h>
36 
37 extern int system_labeled;
38 
39 static int lp(di_minor_t minor, di_node_t node);
40 static int serial_dialout(di_minor_t minor, di_node_t node);
41 static int serial(di_minor_t minor, di_node_t node);
42 static int diskette(di_minor_t minor, di_node_t node);
43 static int vt00(di_minor_t minor, di_node_t node);
44 static int kdmouse(di_minor_t minor, di_node_t node);
45 static int ipmi(di_minor_t minor, di_node_t node);
46 static int smbios(di_minor_t minor, di_node_t node);
47 static int agp_process(di_minor_t minor, di_node_t node);
48 static int drm_node(di_minor_t minor, di_node_t node);
49 static int mc_node(di_minor_t minor, di_node_t node);
50 static int xsvc(di_minor_t minor, di_node_t node);
51 static int srn(di_minor_t minor, di_node_t node);
52 static int ucode(di_minor_t minor, di_node_t node);
53 static int heci(di_minor_t minor, di_node_t node);
54 
55 
56 static devfsadm_create_t misc_cbt[] = {
57 	{ "vt00", "ddi_display", NULL,
58 	    TYPE_EXACT, ILEVEL_0,	vt00
59 	},
60 	{ "drm", "ddi_display:drm", NULL,
61 	    TYPE_EXACT, ILEVEL_0,	drm_node
62 	},
63 	{ "mouse", "ddi_mouse", "mouse8042",
64 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, kdmouse
65 	},
66 	{ "pseudo", "ddi_pseudo", "ipmi",
67 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, ipmi,
68 	},
69 	{ "pseudo", "ddi_pseudo", "smbios",
70 	    TYPE_EXACT | DRV_EXACT, ILEVEL_1, smbios,
71 	},
72 	/* floppies share the same class, but not link regex, as hard disks */
73 	{ "disk",  "ddi_block:diskette", NULL,
74 	    TYPE_EXACT, ILEVEL_1, diskette
75 	},
76 	{ "parallel",  "ddi_printer", NULL,
77 	    TYPE_EXACT, ILEVEL_1, lp
78 	},
79 	{ "serial", "ddi_serial:mb", NULL,
80 	    TYPE_EXACT, ILEVEL_1, serial
81 	},
82 	{ "serial",  "ddi_serial:dialout,mb", NULL,
83 	    TYPE_EXACT, ILEVEL_1, serial_dialout
84 	},
85 	{ "agp", "ddi_agp:pseudo", NULL,
86 	    TYPE_EXACT, ILEVEL_0, agp_process
87 	},
88 	{ "agp", "ddi_agp:target", NULL,
89 	    TYPE_EXACT, ILEVEL_0, agp_process
90 	},
91 	{ "agp", "ddi_agp:cpugart", NULL,
92 	    TYPE_EXACT, ILEVEL_0, agp_process
93 	},
94 	{ "agp", "ddi_agp:master", NULL,
95 	    TYPE_EXACT, ILEVEL_0, agp_process
96 	},
97 	{ "pseudo", "ddi_pseudo", NULL,
98 	    TYPE_EXACT, ILEVEL_0, xsvc
99 	},
100 	{ "pseudo", "ddi_pseudo", NULL,
101 	    TYPE_EXACT, ILEVEL_0, srn
102 	},
103 	{ "memory-controller", "ddi_mem_ctrl", NULL,
104 	    TYPE_EXACT, ILEVEL_0, mc_node
105 	},
106 	{ "pseudo", "ddi_pseudo", "ucode",
107 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, ucode,
108 	},
109 	{ "pseudo", "ddi_pseudo", "heci",
110 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, heci,
111 	}
112 };
113 
114 DEVFSADM_CREATE_INIT_V0(misc_cbt);
115 
116 static char *debug_mid = "misc_mid";
117 
118 typedef enum {
119 	DRIVER_AGPPSEUDO = 0,
120 	DRIVER_AGPTARGET,
121 	DRIVER_CPUGART,
122 	DRIVER_AGPMASTER_DRM_I915,
123 	DRIVER_AGPMASTER_DRM_RADEON,
124 	DRIVER_AGPMASTER_VGATEXT,
125 	DRIVER_UNKNOWN
126 } driver_defs_t;
127 
128 typedef struct {
129 	char	*driver_name;
130 	int	index;
131 } driver_name_table_entry_t;
132 
133 static driver_name_table_entry_t driver_name_table[] = {
134 	{ "agpgart",		DRIVER_AGPPSEUDO },
135 	{ "agptarget",		DRIVER_AGPTARGET },
136 	{ "amd64_gart",		DRIVER_CPUGART },
137 	/* AGP master device managed by drm driver */
138 	{ "i915",		DRIVER_AGPMASTER_DRM_I915 },
139 	{ "radeon",		DRIVER_AGPMASTER_DRM_RADEON },
140 	{ "vgatext",		DRIVER_AGPMASTER_VGATEXT },
141 	{ NULL,			DRIVER_UNKNOWN }
142 };
143 
144 static devfsadm_enumerate_t agptarget_rules[1] =
145 	{ "^agp$/^agptarget([0-9]+)$", 1, MATCH_ALL };
146 static devfsadm_enumerate_t cpugart_rules[1] =
147 	{ "^agp$/^cpugart([0-9]+)$", 1, MATCH_ALL };
148 static devfsadm_enumerate_t agpmaster_rules[1] =
149 	{  "^agp$/^agpmaster([0-9]+)$", 1, MATCH_ALL };
150 
151 static devfsadm_remove_t misc_remove_cbt[] = {
152 	{ "vt", "vt[0-9][0-9]", RM_PRE|RM_ALWAYS,
153 		ILEVEL_0, devfsadm_rm_all
154 	},
155 	{ "pseudo", "^ucode$", RM_ALWAYS | RM_PRE | RM_HOT,
156 		ILEVEL_0, devfsadm_rm_all
157 	},
158 	{ "mouse", "^kdmouse$", RM_ALWAYS | RM_PRE,
159 		ILEVEL_0, devfsadm_rm_all
160 	},
161 	{ "disk", "^(diskette|rdiskette)([0-9]*)$",
162 		RM_ALWAYS | RM_PRE, ILEVEL_1, devfsadm_rm_all
163 	},
164 	{ "parallel", "^(lp|ecpp)([0-9]+)$", RM_ALWAYS | RM_PRE,
165 		ILEVEL_1, devfsadm_rm_all
166 	},
167 	{ "serial", "^(tty|ttyd)([0-9]+)$", RM_ALWAYS | RM_PRE,
168 		ILEVEL_1, devfsadm_rm_all
169 	},
170 	{ "serial", "^tty[a-z]$", RM_ALWAYS | RM_PRE,
171 		ILEVEL_1, devfsadm_rm_all
172 	}
173 };
174 
175 DEVFSADM_REMOVE_INIT_V0(misc_remove_cbt);
176 
177 /*
178  * Handles minor node type "ddi_display", in addition to generic processing
179  * done by display().
180  *
181  * This creates a /dev/vt00 link to /dev/fb, for backwards compatibility.
182  */
183 /* ARGSUSED */
184 int
185 vt00(di_minor_t minor, di_node_t node)
186 {
187 	(void) devfsadm_secondary_link("vt00", "fb", 0);
188 	return (DEVFSADM_CONTINUE);
189 }
190 
191 /*
192  * type=ddi_block:diskette;addr=0,0;minor=c        diskette
193  * type=ddi_block:diskette;addr=0,0;minor=c,raw    rdiskette
194  * type=ddi_block:diskette;addr1=0;minor=c diskette\A2
195  * type=ddi_block:diskette;addr1=0;minor=c,raw     rdiskette\A2
196  */
197 static int
198 diskette(di_minor_t minor, di_node_t node)
199 {
200 	int flags = 0;
201 	char *a2;
202 	char link[PATH_MAX];
203 	char *addr = di_bus_addr(node);
204 	char *mn = di_minor_name(minor);
205 
206 	if (system_labeled)
207 		flags = DA_ADD|DA_FLOPPY;
208 
209 	if (strcmp(addr, "0,0") == 0) {
210 		if (strcmp(mn, "c") == 0) {
211 			(void) devfsadm_mklink("diskette", node, minor, flags);
212 		} else if (strcmp(mn, "c,raw") == 0) {
213 			(void) devfsadm_mklink("rdiskette", node, minor, flags);
214 		}
215 
216 	}
217 
218 	if (addr[0] == '0') {
219 		if ((a2 = strchr(addr, ',')) != NULL) {
220 			a2++;
221 			if (strcmp(mn, "c") == 0) {
222 				(void) strcpy(link, "diskette");
223 				(void) strcat(link, a2);
224 				(void) devfsadm_mklink(link, node, minor,
225 				    flags);
226 			} else if (strcmp(mn, "c,raw") == 0) {
227 				(void) strcpy(link, "rdiskette");
228 				(void) strcat(link, a2);
229 				(void) devfsadm_mklink(link, node, minor,
230 				    flags);
231 			}
232 		}
233 	}
234 
235 	return (DEVFSADM_CONTINUE);
236 }
237 
238 /*
239  * type=ddi_printer;name=lp;addr=1,3bc      lp0
240  * type=ddi_printer;name=lp;addr=1,378      lp1
241  * type=ddi_printer;name=lp;addr=1,278      lp2
242  */
243 static int
244 lp(di_minor_t minor, di_node_t node)
245 {
246 	char *addr = di_bus_addr(node);
247 	char *buf;
248 	char path[PATH_MAX + 1];
249 	devfsadm_enumerate_t rules[1] = {"^ecpp([0-9]+)$", 1, MATCH_ALL};
250 
251 	if (strcmp(addr, "1,3bc") == 0) {
252 		(void) devfsadm_mklink("lp0", node, minor, 0);
253 
254 	} else if (strcmp(addr, "1,378") == 0) {
255 		(void) devfsadm_mklink("lp1", node, minor, 0);
256 
257 	} else if (strcmp(addr, "1,278") == 0) {
258 		(void) devfsadm_mklink("lp2", node, minor, 0);
259 	}
260 
261 	if (strcmp(di_driver_name(node), "ecpp") != 0) {
262 		return (DEVFSADM_CONTINUE);
263 	}
264 
265 	if ((buf = di_devfs_path(node)) == NULL) {
266 		return (DEVFSADM_CONTINUE);
267 	}
268 
269 	(void) snprintf(path, sizeof (path), "%s:%s",
270 	    buf, di_minor_name(minor));
271 
272 	di_devfs_path_free(buf);
273 
274 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) {
275 		return (DEVFSADM_CONTINUE);
276 	}
277 
278 	(void) snprintf(path, sizeof (path), "ecpp%s", buf);
279 	free(buf);
280 	(void) devfsadm_mklink(path, node, minor, 0);
281 	return (DEVFSADM_CONTINUE);
282 }
283 
284 /*
285  * type=ddi_serial:mb;minor=a      tty00
286  * type=ddi_serial:mb;minor=b      tty01
287  * type=ddi_serial:mb;minor=c      tty02
288  * type=ddi_serial:mb;minor=d      tty03
289  */
290 static int
291 serial(di_minor_t minor, di_node_t node)
292 {
293 
294 	char *mn = di_minor_name(minor);
295 	char link[PATH_MAX];
296 
297 	(void) strcpy(link, "tty");
298 	(void) strcat(link, mn);
299 	(void) devfsadm_mklink(link, node, minor, 0);
300 
301 	if (strcmp(mn, "a") == 0) {
302 		(void) devfsadm_mklink("tty00", node, minor, 0);
303 
304 	} else if (strcmp(mn, "b") == 0) {
305 		(void) devfsadm_mklink("tty01", node, minor, 0);
306 
307 	} else if (strcmp(mn, "c") == 0) {
308 		(void) devfsadm_mklink("tty02", node, minor, 0);
309 
310 	} else if (strcmp(mn, "d") == 0) {
311 		(void) devfsadm_mklink("tty03", node, minor, 0);
312 	}
313 	return (DEVFSADM_CONTINUE);
314 }
315 
316 /*
317  * type=ddi_serial:dialout,mb;minor=a,cu   ttyd0
318  * type=ddi_serial:dialout,mb;minor=b,cu   ttyd1
319  * type=ddi_serial:dialout,mb;minor=c,cu   ttyd2
320  * type=ddi_serial:dialout,mb;minor=d,cu   ttyd3
321  */
322 static int
323 serial_dialout(di_minor_t minor, di_node_t node)
324 {
325 	char *mn = di_minor_name(minor);
326 
327 	if (strcmp(mn, "a,cu") == 0) {
328 		(void) devfsadm_mklink("ttyd0", node, minor, 0);
329 		(void) devfsadm_mklink("cua0", node, minor, 0);
330 
331 	} else if (strcmp(mn, "b,cu") == 0) {
332 		(void) devfsadm_mklink("ttyd1", node, minor, 0);
333 		(void) devfsadm_mklink("cua1", node, minor, 0);
334 
335 	} else if (strcmp(mn, "c,cu") == 0) {
336 		(void) devfsadm_mklink("ttyd2", node, minor, 0);
337 		(void) devfsadm_mklink("cua2", node, minor, 0);
338 
339 	} else if (strcmp(mn, "d,cu") == 0) {
340 		(void) devfsadm_mklink("ttyd3", node, minor, 0);
341 		(void) devfsadm_mklink("cua3", node, minor, 0);
342 	}
343 	return (DEVFSADM_CONTINUE);
344 }
345 
346 static int
347 kdmouse(di_minor_t minor, di_node_t node)
348 {
349 	(void) devfsadm_mklink("kdmouse", node, minor, 0);
350 	return (DEVFSADM_CONTINUE);
351 }
352 
353 static int
354 ipmi(di_minor_t minor, di_node_t node)
355 {
356 	/*
357 	 * Follow convention from other systems, and include an instance#,
358 	 * even though there will only be one.
359 	 */
360 	(void) devfsadm_mklink("ipmi0", node, minor, 0);
361 	return (DEVFSADM_CONTINUE);
362 }
363 
364 static int
365 smbios(di_minor_t minor, di_node_t node)
366 {
367 	(void) devfsadm_mklink("smbios", node, minor, 0);
368 	return (DEVFSADM_CONTINUE);
369 }
370 
371 static int
372 agp_process(di_minor_t minor, di_node_t node)
373 {
374 	char *minor_nm, *drv_nm;
375 	char *devfspath;
376 	char *I_path, *p_path, *buf;
377 	char *name = (char *)NULL;
378 	int i, index;
379 	devfsadm_enumerate_t rules[1];
380 
381 	minor_nm = di_minor_name(minor);
382 	drv_nm = di_driver_name(node);
383 
384 	if ((minor_nm == NULL) || (drv_nm == NULL)) {
385 		return (DEVFSADM_CONTINUE);
386 	}
387 
388 	devfsadm_print(debug_mid, "agp_process: minor=%s node=%s\n",
389 	    minor_nm, di_node_name(node));
390 
391 	devfspath = di_devfs_path(node);
392 	if (devfspath == NULL) {
393 		devfsadm_print(debug_mid, "agp_process: devfspath is NULL\n");
394 		return (DEVFSADM_CONTINUE);
395 	}
396 
397 	I_path = (char *)malloc(PATH_MAX);
398 
399 	if (I_path == NULL) {
400 		di_devfs_path_free(devfspath);
401 		devfsadm_print(debug_mid,  "agp_process: malloc failed\n");
402 		return (DEVFSADM_CONTINUE);
403 	}
404 
405 	p_path = (char *)malloc(PATH_MAX);
406 
407 	if (p_path == NULL) {
408 		devfsadm_print(debug_mid,  "agp_process: malloc failed\n");
409 		di_devfs_path_free(devfspath);
410 		free(I_path);
411 		return (DEVFSADM_CONTINUE);
412 	}
413 
414 	(void) strlcpy(p_path, devfspath, PATH_MAX);
415 	(void) strlcat(p_path, ":", PATH_MAX);
416 	(void) strlcat(p_path, minor_nm, PATH_MAX);
417 	di_devfs_path_free(devfspath);
418 
419 	devfsadm_print(debug_mid, "agp_process: path %s\n", p_path);
420 
421 	for (i = 0; ; i++) {
422 		if ((driver_name_table[i].driver_name == NULL) ||
423 		    (strcmp(drv_nm, driver_name_table[i].driver_name) == 0)) {
424 			index = driver_name_table[i].index;
425 			break;
426 		}
427 	}
428 	switch (index) {
429 	case DRIVER_AGPPSEUDO:
430 		devfsadm_print(debug_mid,
431 		    "agp_process: psdeudo driver name\n");
432 		name = "agpgart";
433 		(void) snprintf(I_path, PATH_MAX, "%s", name);
434 		devfsadm_print(debug_mid,
435 		    "mklink %s -> %s\n", I_path, p_path);
436 
437 		(void) devfsadm_mklink(I_path, node, minor, 0);
438 
439 		free(I_path);
440 		free(p_path);
441 		return (DEVFSADM_CONTINUE);
442 	case DRIVER_AGPTARGET:
443 		devfsadm_print(debug_mid,
444 		    "agp_process: target driver name\n");
445 		rules[0] = agptarget_rules[0];
446 		name = "agptarget";
447 		break;
448 	case DRIVER_CPUGART:
449 		devfsadm_print(debug_mid,
450 		    "agp_process: cpugart driver name\n");
451 		rules[0] = cpugart_rules[0];
452 		name = "cpugart";
453 		break;
454 	case DRIVER_AGPMASTER_DRM_I915:
455 	case DRIVER_AGPMASTER_DRM_RADEON:
456 	case DRIVER_AGPMASTER_VGATEXT:
457 		devfsadm_print(debug_mid,
458 		    "agp_process: agpmaster driver name\n");
459 		rules[0] = agpmaster_rules[0];
460 		name = "agpmaster";
461 		break;
462 	case DRIVER_UNKNOWN:
463 		devfsadm_print(debug_mid,
464 		    "agp_process: unknown driver name=%s\n", drv_nm);
465 		free(I_path);
466 		free(p_path);
467 		return (DEVFSADM_CONTINUE);
468 	}
469 
470 	if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) {
471 		devfsadm_print(debug_mid, "agp_process: exit/coninue\n");
472 		free(I_path);
473 		free(p_path);
474 		return (DEVFSADM_CONTINUE);
475 	}
476 
477 
478 	(void) snprintf(I_path, PATH_MAX, "agp/%s%s", name, buf);
479 
480 	devfsadm_print(debug_mid, "agp_process: p_path=%s buf=%s\n",
481 	    p_path, buf);
482 
483 	free(buf);
484 
485 	devfsadm_print(debug_mid, "mklink %s -> %s\n", I_path, p_path);
486 
487 	(void) devfsadm_mklink(I_path, node, minor, 0);
488 
489 	free(p_path);
490 	free(I_path);
491 
492 	return (DEVFSADM_CONTINUE);
493 }
494 
495 static int
496 drm_node(di_minor_t minor, di_node_t node)
497 {
498 	char *minor_nm, *drv_nm;
499 	char *devfspath;
500 	char *I_path, *p_path, *buf;
501 	char *name = "card";
502 
503 	devfsadm_enumerate_t drm_rules[1] = {"^dri$/^card([0-9]+)$", 1,
504 		MATCH_ALL };
505 
506 
507 	minor_nm = di_minor_name(minor);
508 	drv_nm = di_driver_name(node);
509 	if ((minor_nm == NULL) || (drv_nm == NULL)) {
510 		return (DEVFSADM_CONTINUE);
511 	}
512 
513 	devfsadm_print(debug_mid, "drm_node: minor=%s node=%s type=%s\n",
514 	    minor_nm, di_node_name(node), di_minor_nodetype(minor));
515 
516 	devfspath = di_devfs_path(node);
517 	if (devfspath == NULL) {
518 		devfsadm_print(debug_mid, "drm_node: devfspath is NULL\n");
519 		return (DEVFSADM_CONTINUE);
520 	}
521 
522 	I_path = (char *)malloc(PATH_MAX);
523 
524 	if (I_path == NULL) {
525 		di_devfs_path_free(devfspath);
526 		devfsadm_print(debug_mid,  "drm_node: malloc failed\n");
527 		return (DEVFSADM_CONTINUE);
528 	}
529 
530 	p_path = (char *)malloc(PATH_MAX);
531 
532 	if (p_path == NULL) {
533 		devfsadm_print(debug_mid,  "drm_node: malloc failed\n");
534 		di_devfs_path_free(devfspath);
535 		free(I_path);
536 		return (DEVFSADM_CONTINUE);
537 	}
538 
539 	(void) strlcpy(p_path, devfspath, PATH_MAX);
540 	(void) strlcat(p_path, ":", PATH_MAX);
541 	(void) strlcat(p_path, minor_nm, PATH_MAX);
542 	di_devfs_path_free(devfspath);
543 
544 	devfsadm_print(debug_mid, "drm_node: p_path %s\n", p_path);
545 
546 	if (devfsadm_enumerate_int(p_path, 0, &buf, drm_rules, 1)) {
547 		free(p_path);
548 		devfsadm_print(debug_mid, "drm_node: exit/coninue\n");
549 		return (DEVFSADM_CONTINUE);
550 	}
551 	(void) snprintf(I_path, PATH_MAX, "dri/%s%s", name, buf);
552 
553 	devfsadm_print(debug_mid, "drm_node: p_path=%s buf=%s\n",
554 	    p_path, buf);
555 
556 	free(buf);
557 
558 	devfsadm_print(debug_mid, "mklink %s -> %s\n", I_path, p_path);
559 	(void) devfsadm_mklink(I_path, node, minor, 0);
560 
561 	free(p_path);
562 	free(I_path);
563 
564 	return (0);
565 }
566 
567 /*
568  * /dev/mc/mc<chipid> -> /devices/.../pci1022,1102@<chipid+24>,2:mc-amd
569  */
570 static int
571 mc_node(di_minor_t minor, di_node_t node)
572 {
573 	const char *minorname = di_minor_name(minor);
574 	const char *busaddr = di_bus_addr(node);
575 	char linkpath[PATH_MAX];
576 	int unitaddr;
577 	char *c;
578 
579 	if (minorname == NULL || busaddr == NULL)
580 		return (DEVFSADM_CONTINUE);
581 
582 	errno = 0;
583 	unitaddr = strtol(busaddr, &c, 16);
584 
585 	if (errno != 0)
586 		return (DEVFSADM_CONTINUE);
587 
588 	if (unitaddr == 0) {
589 		(void) snprintf(linkpath, sizeof (linkpath), "mc/mc");
590 	} else if (unitaddr >= MC_AMD_DEV_OFFSET) {
591 		(void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u",
592 		    unitaddr - MC_AMD_DEV_OFFSET);
593 	} else {
594 		(void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u",
595 		    minor->dev_minor);
596 	}
597 	(void) devfsadm_mklink(linkpath, node, minor, 0);
598 	return (DEVFSADM_CONTINUE);
599 }
600 
601 /*
602  * Creates \M0 devlink for xsvc node
603  */
604 static int
605 xsvc(di_minor_t minor, di_node_t node)
606 {
607 	char *mn;
608 
609 	if (strcmp(di_node_name(node), "xsvc") != 0)
610 		return (DEVFSADM_CONTINUE);
611 
612 	mn = di_minor_name(minor);
613 	if (mn == NULL)
614 		return (DEVFSADM_CONTINUE);
615 
616 	(void) devfsadm_mklink(mn, node, minor, 0);
617 	return (DEVFSADM_CONTINUE);
618 }
619 
620 /*
621  * Creates \M0 devlink for srn device
622  */
623 static int
624 srn(di_minor_t minor, di_node_t node)
625 {
626 	char *mn;
627 
628 	if (strcmp(di_node_name(node), "srn") != 0)
629 		return (DEVFSADM_CONTINUE);
630 
631 	mn = di_minor_name(minor);
632 	if (mn == NULL)
633 		return (DEVFSADM_CONTINUE);
634 
635 	(void) devfsadm_mklink(mn, node, minor, 0);
636 	return (DEVFSADM_CONTINUE);
637 }
638 
639 /*
640  *	/dev/ucode	->	/devices/pseudo/ucode@0:ucode
641  */
642 static int
643 ucode(di_minor_t minor, di_node_t node)
644 {
645 	(void) devfsadm_mklink("ucode", node, minor, 0);
646 	return (DEVFSADM_CONTINUE);
647 }
648 
649 static int
650 heci(di_minor_t minor, di_node_t node)
651 {
652 	if (strcmp(di_minor_name(minor), "AMT") == 0) {
653 		(void) devfsadm_mklink("heci", node, minor, 0);
654 	}
655 	return (DEVFSADM_CONTINUE);
656 }
657