xref: /titanic_51/usr/src/cmd/devfsadm/audio_link.c (revision 7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <regex.h>
30 #include <devfsadm.h>
31 #include <strings.h>
32 #include <stdlib.h>
33 #include <limits.h>
34 #include <stdio.h>
35 
36 #define	MAX_AUDIO_LINK 100
37 #define	RE_SIZE 64
38 
39 static void check_audio_link(char *secondary_link,
40 				const char *primary_link_format);
41 static int audio_process(di_minor_t minor, di_node_t node);
42 
43 static devfsadm_create_t audio_cbt[] = {
44 	{ "audio", "ddi_audio", NULL,
45 	TYPE_EXACT, ILEVEL_0, audio_process
46 	}
47 };
48 
49 DEVFSADM_CREATE_INIT_V0(audio_cbt);
50 
51 /*
52  * the following can't be one big RE with a bunch of alterations "|"
53  * because recurse_dev_re() would not work.
54  */
55 static devfsadm_remove_t audio_remove_cbt[] = {
56 	{ "audio",
57 	"^audio(ctl)?$",
58 	RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_link
59 	},
60 	{ "audio",
61 	"^sound/[0-9]+.*$",
62 	RM_PRE|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
63 	},
64 	{ "audio",
65 	"^isdn/[0-9]+/mgt$",
66 	RM_PRE, ILEVEL_0, devfsadm_rm_all
67 	},
68 	{ "audio",
69 	"^isdn/[0-9]+/aux/0(ctl)?$",
70 	RM_PRE, ILEVEL_0, devfsadm_rm_all
71 	},
72 	{ "audio",
73 	"^isdn/[0-9]+/(nt)|(te)/((dtrace)|(mgt)|(b1)|(b2)|(d))$",
74 	RM_PRE, ILEVEL_0, devfsadm_rm_all
75 	}
76 };
77 
78 DEVFSADM_REMOVE_INIT_V0(audio_remove_cbt);
79 
80 static regex_t isdn_re;
81 
82 #define	ISDN_RE "((nt)|(te)|(aux))\\,((0)|(0ctl)|(d)|(b1)|(b2)|(mgt)|(dtrace))"
83 #define	F 1
84 #define	S 5
85 
86 int
87 minor_init(void)
88 {
89 	if (0 != regcomp(&isdn_re, ISDN_RE, REG_EXTENDED)) {
90 		devfsadm_errprint("SUNW_audio_link: minor_init: regular "
91 				    "expression bad: '%s'\n", ISDN_RE);
92 		return (DEVFSADM_FAILURE);
93 	} else {
94 		return (DEVFSADM_SUCCESS);
95 	}
96 }
97 
98 int
99 minor_fini(void)
100 {
101 	regfree(&isdn_re);
102 	check_audio_link("audio", "sound/%d");
103 	check_audio_link("audioctl", "sound/%dctl");
104 	return (DEVFSADM_SUCCESS);
105 }
106 
107 
108 #define	COPYSUB(to, from, pm, pos) (void) strncpy(to, &from[pm[pos].rm_so], \
109 		    pm[pos].rm_eo - pm[pos].rm_so); \
110 		    to[pm[pos].rm_eo - pm[pos].rm_so] = 0;
111 
112 /*
113  * This function is called for every audio node.
114  * Calls enumerate to assign a logical unit id, and then
115  * devfsadm_mklink to make the link.
116  */
117 static int
118 audio_process(di_minor_t minor, di_node_t node)
119 {
120 	char path[PATH_MAX + 1];
121 	char *buf;
122 	char *mn;
123 	char m1[10];
124 	char m2[10];
125 	char *devfspath;
126 	char re_string[RE_SIZE+1];
127 	devfsadm_enumerate_t rules[1] = {NULL};
128 	regmatch_t pmatch[12];
129 	char *au_mn;
130 
131 
132 	mn = di_minor_name(minor);
133 
134 	if ((devfspath = di_devfs_path(node)) == NULL) {
135 		return (DEVFSADM_CONTINUE);
136 	}
137 	(void) strcpy(path, devfspath);
138 	(void) strcat(path, ":");
139 	(void) strcat(path, mn);
140 	di_devfs_path_free(devfspath);
141 
142 	if (strstr(mn, "sound,") != NULL) {
143 		(void) snprintf(re_string, RE_SIZE, "%s", "^sound$/^([0-9]+)");
144 	} else {
145 		(void) strcpy(re_string, "isdn/([0-9]+)");
146 	}
147 
148 	/*
149 	 * We want a match against the physical path
150 	 * without the minor name component.
151 	 */
152 	rules[0].re = re_string;
153 	rules[0].subexp = 1;
154 	rules[0].flags = MATCH_ADDR;
155 
156 	/*
157 	 * enumerate finds the logical audio id, and stuffs
158 	 * it in buf
159 	 */
160 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) {
161 		return (DEVFSADM_CONTINUE);
162 	}
163 
164 	path[0] = '\0';
165 
166 	if (strstr(mn, "sound,") != NULL) {
167 		(void) strcpy(path, "sound/");
168 		(void) strcat(path, buf);
169 
170 		/* if this is a minor node, tack on the correct suffix */
171 		au_mn = strchr(mn, ',');
172 		if (strcmp(++au_mn, "audio") != 0 &&
173 		    strcmp(au_mn, "sbpro") != 0) {
174 
175 			/*
176 			 * audioctl/sbproctl are special cases. They are handled
177 			 * by stripping off the audio/sbpro from the node name
178 			 */
179 			if (strcmp(au_mn, "audioctl") == 0 ||
180 			    strcmp(au_mn, "sbproctl") == 0)
181 				au_mn = strstr(au_mn, "ctl");
182 			(void) strcat(path, au_mn);
183 		}
184 	}
185 
186 	if (regexec(&isdn_re, mn, sizeof (pmatch) / sizeof (pmatch[0]),
187 	    pmatch, 0) == 0) {
188 		COPYSUB(m1, mn, pmatch, F);
189 		COPYSUB(m2, mn, pmatch, S);
190 		(void) strcpy(path, "isdn/");
191 		(void) strcat(path, buf);
192 		(void) strcat(path, "/");
193 		(void) strcat(path, m1);
194 		(void) strcat(path, "/");
195 		(void) strcat(path, m2);
196 	}
197 
198 	if (strstr("mgt,mgt", mn) != NULL) {
199 		(void) strcpy(path, "isdn/");
200 		(void) strcat(path, buf);
201 		(void) strcat(path, "/mgt");
202 	}
203 
204 	free(buf);
205 
206 	if (path[0] == '\0') {
207 		devfsadm_errprint("SUNW_audio_link: audio_process: can't find"
208 			" match for'%s'\n", mn);
209 		return (DEVFSADM_CONTINUE);
210 	}
211 
212 	(void) devfsadm_mklink(path, node, minor, 0);
213 	return (DEVFSADM_CONTINUE);
214 }
215 
216 
217 static void
218 check_audio_link(char *secondary_link, const char *primary_link_format)
219 {
220 	char primary_link[PATH_MAX + 1];
221 	int i;
222 
223 	/* if link is present, return */
224 	if (devfsadm_link_valid(secondary_link) == DEVFSADM_TRUE) {
225 		return;
226 	}
227 
228 	for (i = 0; i < MAX_AUDIO_LINK; i++) {
229 		(void) sprintf(primary_link, primary_link_format, i);
230 		if (devfsadm_link_valid(primary_link) == DEVFSADM_TRUE) {
231 			(void) devfsadm_secondary_link(secondary_link,
232 						primary_link, 0);
233 			break;
234 		}
235 	}
236 }
237