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