xref: /titanic_52/usr/src/uts/intel/io/acpica/master_ops.c (revision 68c47f65208790c466e5e484f2293d3baed71c6a)
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 <sys/kobj.h>
27 #include <sys/kobj_lex.h>
28 #include <sys/ddi.h>
29 #include <sys/sunddi.h>
30 #include <sys/sunndi.h>
31 #include <sys/acpi/acpi.h>
32 #include <sys/acpica.h>
33 
34 #define	masterfile "/boot/solaris/devicedb/master"
35 
36 /*
37  * Internal definitions
38  */
39 
40 typedef enum {
41 	MF_UNEXPECTED = -1,
42 	MF_IDENT,
43 	MF_STRING,
44 	MF_EOF,
45 	MF_NEWLINE,
46 	MF_EQUALS,
47 	MF_BIT_OR
48 } mftoken_t;
49 
50 typedef enum {
51 	MF_INIT,
52 	MF_DEVID,
53 	MF_NAME,
54 	MF_DEVTYPE,
55 	MF_BUSTYPE,
56 	MF_BEFNAME,
57 	MF_DESCRIPTION,
58 	MF_PROPNAME,
59 	MF_PROPASSIGN,
60 	MF_PROPVAL,
61 	MF_VERSION_DONE,
62 	MF_VALID_DONE,
63 	MF_ERROR_DONE
64 } mfparse_t;
65 
66 
67 static master_rec_t *master_list = NULL;
68 
69 device_id_t *
70 mf_alloc_device_id()
71 {
72 	return ((device_id_t *)kmem_zalloc(sizeof (device_id_t), KM_SLEEP));
73 }
74 
75 void
76 mf_free_device_id(device_id_t *d)
77 {
78 	if (d->id != NULL)
79 		strfree(d->id);
80 
81 	kmem_free(d, sizeof (device_id_t));
82 }
83 
84 static property_t *
85 mf_alloc_property()
86 {
87 	return ((property_t *)kmem_zalloc(sizeof (property_t), KM_SLEEP));
88 }
89 
90 static void
91 mf_free_property(property_t *p)
92 {
93 	if (p->name != NULL)
94 		strfree(p->name);
95 
96 	if (p->value != NULL)
97 		strfree(p->value);
98 
99 	kmem_free(p, sizeof (property_t));
100 }
101 
102 static master_rec_t *
103 mf_alloc_master_rec()
104 {
105 	return ((master_rec_t *)kmem_zalloc(sizeof (master_rec_t), KM_SLEEP));
106 }
107 
108 static void
109 mf_free_master_rec(master_rec_t *m)
110 {
111 	device_id_t *d;
112 	property_t *p;
113 
114 	if (m->name != NULL)
115 		strfree(m->name);
116 
117 	if (m->description != NULL)
118 		strfree(m->description);
119 
120 	d = m->device_ids;
121 	while (d != NULL) {
122 		device_id_t *next;
123 
124 		next = d->next;
125 		mf_free_device_id(d);
126 		d = next;
127 	}
128 
129 	p = m->properties;
130 	while (p != NULL) {
131 		property_t *next;
132 
133 		next = p->next;
134 		mf_free_property(p);
135 		p = next;
136 	}
137 
138 	kmem_free(m, sizeof (master_rec_t));
139 }
140 
141 void
142 free_master_data()
143 {
144 	master_rec_t *m;
145 
146 	m = master_list;
147 	while (m != NULL) {
148 		master_rec_t *next;
149 
150 		next = m->next;
151 		mf_free_master_rec(m);
152 		m = next;
153 	}
154 	master_list = NULL;
155 }
156 
157 /*
158  * Unfortunately, kobj_lex() is too sophisticated for our needs
159  */
160 static mftoken_t
161 mf_lex(struct _buf *file, char *val, size_t size)
162 {
163 	char *cp;
164 	int ch, badquote;
165 	size_t remain;
166 	mftoken_t token = MF_UNEXPECTED;
167 
168 	if (size < 2)
169 		return (token);	/* MF_UNEXPECTED */
170 
171 	cp = val;
172 
173 	/* skip leading whitespace */
174 	while ((ch = kobj_getc(file)) == ' ' || ch == '\t')
175 		;
176 
177 	/* strip comments */
178 	if (ch == '#') {
179 		while ((ch = kobj_getc(file)) != '\n' && ch != '\r' &&
180 		    ch != -1)
181 			;
182 	}
183 
184 	remain = size - 1;
185 	*cp++ = (char)ch;
186 	switch (ch) {
187 	case -1:
188 		token = MF_EOF;
189 		break;
190 	case '\n':
191 	case '\r':
192 		token = MF_NEWLINE;
193 		break;
194 	case '=':
195 		token = MF_EQUALS;
196 		break;
197 	case '|':
198 		token = MF_BIT_OR;
199 		break;
200 	case '"':
201 		remain++;
202 		cp--;
203 		badquote = 0;
204 		while (!badquote && (ch  = kobj_getc(file)) != '"') {
205 			switch (ch) {
206 			case '\n':
207 			case -1:
208 				remain = size - 1;
209 				cp = val;
210 				*cp++ = '\n';
211 				badquote = 1;
212 				/* since we consumed the newline/EOF */
213 				(void) kobj_ungetc(file);
214 				break;
215 			default:
216 				if (--remain == 0) {
217 					token = MF_UNEXPECTED;
218 					goto out;
219 				}
220 				*cp++ = (char)ch;
221 				break;
222 			}
223 		}
224 		token = MF_STRING;
225 		break;
226 	default:
227 		do {
228 			if (--remain == 0) {
229 				token = MF_UNEXPECTED;
230 				break;
231 			}
232 
233 			token = MF_IDENT;
234 			*cp++ = (char)(ch = kobj_getc(file));
235 
236 			/* if terminating character, break out */
237 			if ((ch == -1) || (ch == ' ') || (ch == '\t') ||
238 			    (ch == '\n') || (ch == '\r') || (ch == '=') ||
239 			    (ch == '|')) {
240 				(void) kobj_ungetc(file);
241 				remain++;
242 				cp--;
243 				break;
244 			}
245 
246 			if ((ch == '#') || (ch == '"'))
247 				token = MF_UNEXPECTED;
248 		} while (token != MF_UNEXPECTED);
249 		break;
250 	}
251 out:
252 	*cp = '\0';
253 
254 	return (token);
255 }
256 
257 static master_rec_t *
258 get_line(struct _buf *file)
259 {
260 	master_rec_t *m = NULL;
261 	device_id_t *d = NULL;
262 	property_t *p = NULL;
263 	mftoken_t token;
264 	char tokval[MAXPATHLEN];
265 	mfparse_t parse_state;
266 
267 	parse_state = MF_INIT;
268 	token = mf_lex(file, tokval, sizeof (tokval));
269 	while (token != MF_EOF) {
270 		switch (parse_state) {
271 		case MF_INIT:
272 			m = mf_alloc_master_rec();
273 			parse_state = MF_DEVID;
274 			/*FALLTHROUGH*/
275 		case MF_DEVID:
276 			if (token == MF_IDENT) {
277 				d = mf_alloc_device_id();
278 				d->id = strdup(tokval);
279 				d->next = m->device_ids;
280 				m->device_ids = d;
281 				parse_state = MF_NAME;
282 			} else if (token != MF_NEWLINE)
283 				parse_state = MF_ERROR_DONE;
284 			break;
285 		case MF_NAME:
286 			if (token == MF_IDENT) {
287 				m->name = strdup(tokval);
288 				parse_state = MF_DEVTYPE;
289 			} else if (token == MF_BIT_OR) {
290 				parse_state = MF_DEVID;
291 			} else
292 				parse_state = MF_ERROR_DONE;
293 			break;
294 		case MF_DEVTYPE:
295 			if (token == MF_IDENT) {
296 				/* device_type not used */
297 				parse_state = MF_BUSTYPE;
298 			} else if (token == MF_NEWLINE) {
299 				/* version line ignored */
300 				parse_state = MF_VERSION_DONE;
301 			} else
302 				parse_state = MF_ERROR_DONE;
303 			break;
304 		case MF_BUSTYPE:
305 			if (token == MF_IDENT) {
306 				/* bus_type ignored */
307 				parse_state = MF_BEFNAME;
308 			} else
309 				parse_state = MF_ERROR_DONE;
310 			break;
311 		case MF_BEFNAME:
312 			if (token == MF_IDENT) {
313 				/* realmode driver name ignored */
314 				parse_state = MF_DESCRIPTION;
315 			} else
316 				parse_state = MF_ERROR_DONE;
317 			break;
318 		case MF_DESCRIPTION:
319 			if (token == MF_STRING) {
320 				m->description = strdup(tokval);
321 				parse_state = MF_PROPNAME;
322 			} else
323 				parse_state = MF_ERROR_DONE;
324 			break;
325 		case MF_PROPNAME:
326 			if (token == MF_IDENT) {
327 				p = mf_alloc_property();
328 				p->name = strdup(tokval);
329 				parse_state = MF_PROPASSIGN;
330 			} else if (token == MF_NEWLINE) {
331 				parse_state = MF_VALID_DONE;
332 			} else
333 				parse_state = MF_ERROR_DONE;
334 			break;
335 		case MF_PROPASSIGN:
336 			if (token == MF_EQUALS) {
337 				parse_state = MF_PROPVAL;
338 			} else
339 				parse_state = MF_ERROR_DONE;
340 			break;
341 		case MF_PROPVAL:
342 			if (token == MF_STRING || token == MF_IDENT) {
343 				p->value = strdup(tokval);
344 				p->next = m->properties;
345 				/* delete properties which begin with '$' */
346 				if (*p->name == '$') {
347 					mf_free_property(p);
348 				} else
349 					m->properties = p;
350 				p = NULL;
351 				parse_state = MF_PROPNAME;
352 			} else
353 				parse_state = MF_ERROR_DONE;
354 			break;
355 		case MF_VERSION_DONE:
356 		case MF_VALID_DONE:
357 		case MF_ERROR_DONE:
358 			/* terminating states handled outside switch() */
359 			break;
360 		}
361 
362 		if (parse_state == MF_VERSION_DONE) {
363 			/* ignore version line */
364 			mf_free_master_rec(m);
365 			parse_state = MF_INIT;
366 		} else if (parse_state == MF_VALID_DONE) {
367 			/* valid line */
368 			break;
369 		} else if (parse_state == MF_ERROR_DONE) {
370 			mf_free_master_rec(m);
371 			if (p != NULL)
372 				mf_free_property(p);
373 			/*
374 			 * Error in master file.  Should never happen
375 			 * since master file is not user-edited.  Eat rest
376 			 * of line to attempt error recovery
377 			 */
378 			cmn_err(CE_NOTE, "!error in %s", masterfile);
379 			while (token != MF_NEWLINE && token != MF_EOF)
380 				token = mf_lex(file, tokval, sizeof (tokval));
381 			parse_state = MF_INIT;
382 			continue;
383 		}
384 
385 		token = mf_lex(file, tokval, sizeof (tokval));
386 	}
387 
388 	return (m);
389 }
390 
391 void
392 process_master_file()
393 {
394 	struct _buf *file;
395 	master_rec_t *m;
396 
397 	if ((file = kobj_open_file(masterfile)) == NULL) {
398 		cmn_err(CE_WARN, "!cannot open master file: %s", masterfile);
399 		return;
400 	}
401 
402 	while ((m = get_line(file)) != NULL) {
403 		m->next = master_list;
404 		master_list = m;
405 	}
406 
407 	kobj_close_file(file);
408 }
409 
410 /*
411  * Return the first master file record found matching pnpid list
412  */
413 const master_rec_t *
414 master_file_lookup(device_id_t *pnpid)
415 {
416 	master_rec_t *m;
417 	device_id_t *d;
418 
419 	while (pnpid != NULL) {
420 		m = master_list;
421 		while (m != NULL) {
422 			d = m->device_ids;
423 			while (d != NULL) {
424 				if (strcmp(pnpid->id, d->id) == 0)
425 					return (m);
426 				d = d->next;
427 			}
428 			m = m->next;
429 		}
430 		pnpid = pnpid->next;
431 	}
432 
433 	return (NULL);
434 }
435