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