Home | History | Annotate | Download | only in i386
      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