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