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