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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <regex.h>
29 #include <devfsadm.h>
30 #include <stdio.h>
31 #include <strings.h>
32 #include <stdlib.h>
33 #include <limits.h>
34 #include <sys/mkdev.h>
35 #include <bsm/devalloc.h>
36 
37 extern int system_labeled;
38 
39 static int node_name(di_minor_t minor, di_node_t node);
40 
41 
42 static int ddi_other(di_minor_t minor, di_node_t node);
43 static int diskette(di_minor_t minor, di_node_t node);
44 static int ecpp_create(di_minor_t minor, di_node_t node);
45 static int mc_node(di_minor_t minor, di_node_t node);
46 static int ddi_cardreader(di_minor_t minor, di_node_t node);
47 static int starcat_sbbc_node(di_minor_t minor, di_node_t node);
48 static int wrsm(di_minor_t minor, di_node_t node);
49 static int lom(di_minor_t minor, di_node_t node);
50 static int ntwdt_create(di_minor_t minor, di_node_t node);
51 
52 static devfsadm_create_t misc_cbt[] = {
53 	{ "other", "ddi_other", NULL,
54 	    TYPE_EXACT, ILEVEL_0, ddi_other
55 	},
56 	{ "memory-controller", "ddi_mem_ctrl", NULL,
57 	    TYPE_EXACT, ILEVEL_0, mc_node
58 	},
59 	{ "pseudo", "ddi_pseudo", "sbbc",
60 	    TYPE_EXACT | DRV_EXACT, ILEVEL_1, starcat_sbbc_node
61 	},
62 	{ "disk",  "ddi_block:diskette", NULL,
63 	    TYPE_EXACT, ILEVEL_1, diskette
64 	},
65 	{ "printer",  "ddi_printer", NULL,
66 	    TYPE_EXACT, ILEVEL_1, ecpp_create
67 	},
68 	{ "card-reader", "ddi_smartcard_reader", NULL,
69 		TYPE_EXACT, ILEVEL_0, ddi_cardreader
70 	},
71 	{ "pseudo", "(^ddi_pseudo$)|(^ddi_ctl:devctl$)", "wrsm",
72 	    TYPE_RE | DRV_EXACT, ILEVEL_0, wrsm,
73 	},
74 	{ "network", "ddi_net", "wrsmd",
75 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, node_name,
76 	},
77 	{ "pseudo", "ddi_pseudo", "lw8",
78 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, lom
79 	},
80 	{ "pseudo", "ddi_pseudo", "ntwdt",
81 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, ntwdt_create
82 	},
83 };
84 
85 DEVFSADM_CREATE_INIT_V0(misc_cbt);
86 
87 /* Smart Card Reader device link */
88 #define	CARDREADER_LINK		"^scmi2c[0-9]+$"
89 
90 /* Rules for removing links */
91 static devfsadm_remove_t sparc_remove_cbt[] = {
92 	{ "card-reader", CARDREADER_LINK, RM_PRE | RM_ALWAYS,
93 		ILEVEL_0, devfsadm_rm_all }
94 };
95 
96 DEVFSADM_REMOVE_INIT_V0(sparc_remove_cbt);
97 
98 
99 /*
100  * Handles minor node type "ddi_other"
101  * type=ddi_other;name=SUNW,pmc    pmc
102  * type=ddi_other;name=SUNW,mic    mic\M0
103  */
104 static int
105 ddi_other(di_minor_t minor, di_node_t node)
106 {
107 	char path[PATH_MAX + 1];
108 	char *nn = di_node_name(node);
109 	char *mn = di_minor_name(minor);
110 
111 	if (strcmp(nn, "SUNW,pmc") == 0) {
112 		(void) devfsadm_mklink("pcm", node, minor, 0);
113 	} else if (strcmp(nn, "SUNW,mic") == 0) {
114 		(void) strcpy(path, "mic");
115 		(void) strcat(path, mn);
116 		(void) devfsadm_mklink(path, node, minor, 0);
117 	}
118 
119 	return (DEVFSADM_CONTINUE);
120 }
121 
122 /*
123  * This function is called for diskette nodes
124  */
125 static int
126 diskette(di_minor_t minor, di_node_t node)
127 {
128 	int	flags = 0;
129 	char	*mn = di_minor_name(minor);
130 
131 	if (system_labeled)
132 		flags = DA_ADD|DA_FLOPPY;
133 
134 	if (strcmp(mn, "c") == 0) {
135 		(void) devfsadm_mklink("diskette", node, minor, flags);
136 		(void) devfsadm_mklink("diskette0", node, minor, flags);
137 
138 	} else if (strcmp(mn, "c,raw") == 0) {
139 		(void) devfsadm_mklink("rdiskette", node, minor, flags);
140 		(void) devfsadm_mklink("rdiskette0", node, minor, flags);
141 
142 	}
143 	return (DEVFSADM_CONTINUE);
144 }
145 
146 /*
147  * Handles links of the form:
148  * type=ddi_pseudo;name=xyz  \D
149  */
150 static int
151 node_name(di_minor_t minor, di_node_t node)
152 {
153 	(void) devfsadm_mklink(di_node_name(node), node, minor, 0);
154 	return (DEVFSADM_CONTINUE);
155 }
156 
157 /*
158  * Handles links of the form:
159  * type=ddi_printer;name=ecpp  ecpp\N0
160  */
161 static int
162 ecpp_create(di_minor_t minor, di_node_t node)
163 {
164 	char *buf;
165 	char path[PATH_MAX + 1];
166 	devfsadm_enumerate_t rules[1] = {"^ecpp([0-9]+)$", 1, MATCH_ALL};
167 
168 	if (strcmp(di_driver_name(node), "ecpp") != 0) {
169 		return (DEVFSADM_CONTINUE);
170 	}
171 
172 	if ((buf = di_devfs_path(node)) == NULL) {
173 		return (DEVFSADM_CONTINUE);
174 	}
175 
176 	(void) snprintf(path, sizeof (path), "%s:%s",
177 	    buf, di_minor_name(minor));
178 
179 	di_devfs_path_free(buf);
180 
181 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) {
182 		return (DEVFSADM_CONTINUE);
183 	}
184 
185 	(void) snprintf(path, sizeof (path), "ecpp%s", buf);
186 	free(buf);
187 
188 	(void) devfsadm_mklink(path, node, minor, 0);
189 	return (DEVFSADM_CONTINUE);
190 }
191 
192 /* Rules for memory controller */
193 static devfsadm_enumerate_t mc_rules[1] =
194 	{"^mc$/^mc([0-9]+)$", 1, MATCH_ALL};
195 
196 
197 static int
198 mc_node(di_minor_t minor, di_node_t node)
199 {
200 	char path[PATH_MAX], l_path[PATH_MAX], *buf, *devfspath;
201 	char *minor_nm;
202 
203 	minor_nm = di_minor_name(minor);
204 
205 	if (minor_nm == NULL) {
206 		return (DEVFSADM_CONTINUE);
207 	}
208 
209 	devfspath = di_devfs_path(node);
210 
211 	(void) strcpy(path, devfspath);
212 	(void) strcat(path, ":");
213 	(void) strcat(path, minor_nm);
214 	di_devfs_path_free(devfspath);
215 
216 	/* build the physical path from the components */
217 	if (devfsadm_enumerate_int(path, 0, &buf, mc_rules, 1)) {
218 		return (DEVFSADM_CONTINUE);
219 	}
220 
221 	(void) strcpy(l_path, "mc/mc");
222 	(void) strcat(l_path, buf);
223 
224 	free(buf);
225 
226 	(void) devfsadm_mklink(l_path, node, minor, 0);
227 	return (DEVFSADM_CONTINUE);
228 }
229 
230 
231 /*
232  * This function is called for Smartcard card reader nodes
233  * Handles minor node type "ddi_smartcard_reader"
234  * type=ddi_smartcard_reader;name=card-reader   scmi2c\N0
235  * Calls enumerate to assign logical card-reader id and then
236  * devfsadm_mklink to make the link.
237  */
238 static int
239 ddi_cardreader(di_minor_t minor, di_node_t node)
240 {
241 	char p_path[PATH_MAX +1], l_path[PATH_MAX +1];
242 	char *buf;
243 	char *ptr;
244 	char *nn, *mn;
245 
246 	devfsadm_enumerate_t rules[1] = {"^scmi2c([0-9]+)$", 1, MATCH_ALL};
247 
248 	nn = di_node_name(node);
249 	if (strcmp(nn, "card-reader")) {
250 		return (DEVFSADM_CONTINUE);
251 	}
252 
253 	if (NULL == (ptr = di_devfs_path(node))) {
254 		return (DEVFSADM_CONTINUE);
255 	}
256 
257 	(void) strcpy(p_path, ptr);
258 	(void) strcat(p_path, ":");
259 
260 	mn = di_minor_name(minor);
261 
262 	(void) strcat(p_path, mn);
263 	di_devfs_path_free(ptr);
264 
265 	if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) {
266 		return (DEVFSADM_CONTINUE);
267 	}
268 	(void) snprintf(l_path, sizeof (l_path), "scmi2c%s", buf);
269 	free(buf);
270 	(void) devfsadm_mklink(l_path, node, minor, 0);
271 
272 	return (DEVFSADM_CONTINUE);
273 }
274 
275 
276 
277 
278 
279 
280 
281 
282 /*
283  * Starcat sbbc node.  We only really care about generating a /dev
284  * link for the lone sbbc on the SC (as opposed to the potentially
285  * numerous sbbcs on the domain), so only operate on instance 0.
286  */
287 static int
288 starcat_sbbc_node(di_minor_t minor, di_node_t node)
289 {
290 	char *mn;
291 
292 	if (di_instance(node) == 0) {
293 		mn = di_minor_name(minor);
294 		(void) devfsadm_mklink(mn, node, minor, 0);
295 	}
296 	return (DEVFSADM_CONTINUE);
297 
298 }
299 
300 int
301 wrsm(di_minor_t minor, di_node_t node)
302 {
303 	const char *node_name = di_node_name(node);
304 	const char *minor_name = di_minor_name(minor);
305 	char path[PATH_MAX + 1];
306 
307 	if (minor_name == NULL || node_name == NULL) {
308 		return (DEVFSADM_CONTINUE);
309 	}
310 	if (strcmp(minor_name, "admin") == 0) {
311 		/* admin pseudo device */
312 		(void) snprintf(path, sizeof (path), "%s%s", node_name,
313 		    minor_name);
314 	} else if (strcmp(minor_name, "ctrl") == 0) {
315 		/* controller pseudo device */
316 		dev_t dev = di_minor_devt(minor);
317 		minor_t dev_minor = minor(dev);
318 		(void) snprintf(path, sizeof (path), "%s%u", node_name,
319 		    (uint_t)dev_minor);
320 	} else {
321 		/*
322 		 * For hardware devices, the devlink must be
323 		 * /dev/<node_name><portid>. devpath is of the format
324 		 * ".../<node_name>@<portid>,0". Need to extract the
325 		 * <portid> for use in bulding devlink.
326 		 */
327 		char devpath[PATH_MAX + 1];
328 		char *devfs_path;
329 		int i;
330 
331 		devfs_path = di_devfs_path(node);
332 		if (devfs_path == NULL) {
333 			return (DEVFSADM_CONTINUE);
334 		}
335 		(void) strcpy(devpath, devfs_path);
336 		di_devfs_path_free(devfs_path);
337 
338 		for (i = strlen(devpath); devpath[i] != '@' && i > 0; i--) {
339 			if (devpath[i] == ',') {
340 				devpath[i] = 0;
341 			}
342 		}
343 		if (i == 0) {
344 			return (DEVFSADM_CONTINUE);
345 		}
346 		(void) snprintf(path, sizeof (path), "wci%s", &devpath[i+1]);
347 	}
348 	(void) devfsadm_mklink(path, node, minor, 0);
349 
350 	return (DEVFSADM_CONTINUE);
351 }
352 
353 /*
354  * Creates /dev/lom nodes for Platform Specific lom driver
355  */
356 static int
357 lom(di_minor_t minor, di_node_t node)
358 {
359 	(void) devfsadm_mklink("lom", node, minor, 0);
360 	return (DEVFSADM_CONTINUE);
361 }
362 
363 /*
364  * Creates /dev/ntwdt nodes for Platform Specific ntwdt driver
365  */
366 static int
367 ntwdt_create(di_minor_t minor, di_node_t node)
368 {
369 	(void) devfsadm_mklink("ntwdt", node, minor, 0);
370 	return (DEVFSADM_CONTINUE);
371 }
372