xref: /titanic_41/usr/src/cmd/hal/hald/ids.c (revision 0a44ef6d9afbfe052a7e975f55ea0d2954b62a82)
1 /***************************************************************************
2  * CVSID: $Id$
3  *
4  * ids.c : Lookup names from hardware identifiers
5  *
6  * Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
7  *
8  * Licensed under the Academic Free License version 2.1
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  **************************************************************************/
25 
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29 
30 #include <ctype.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <unistd.h>
34 
35 #include <dbus/dbus.h>
36 #include <dbus/dbus-glib.h>
37 
38 #include "logger.h"
39 
40 #include "ids.h"
41 
42 /** Pointer to where the pci.ids file is loaded */
43 static char *pci_ids = NULL;
44 
45 /** Length of data store at at pci_ids */
46 static unsigned int pci_ids_len;
47 
48 /** Iterator position into pci_ids */
49 static unsigned int pci_ids_iter_pos;
50 
51 /** Initialize the pci.ids line iterator to the beginning of the file */
52 static void
53 pci_ids_line_iter_init ()
54 {
55 	pci_ids_iter_pos = 0;
56 }
57 
58 /** Maximum length of lines in pci.ids */
59 #define PCI_IDS_MAX_LINE_LEN 512
60 
61 /** Get the next line from pci.ids
62  *
63  *  @param  line_len            Pointer to where number of bytes in line will
64  *                              be stored
65  *  @return                     Pointer to the line; only valid until the
66  *                              next invocation of this function
67  */
68 static char *
69 pci_ids_line_iter_get_line (unsigned int *line_len)
70 {
71 	unsigned int i;
72 	static char line[PCI_IDS_MAX_LINE_LEN];
73 
74 	for (i = 0;
75 	     pci_ids_iter_pos < pci_ids_len &&
76 	     i < PCI_IDS_MAX_LINE_LEN - 1 &&
77 	     pci_ids[pci_ids_iter_pos] != '\n'; i++, pci_ids_iter_pos++) {
78 		line[i] = pci_ids[pci_ids_iter_pos];
79 	}
80 
81 	line[i] = '\0';
82 	if (line_len != NULL)
83 		*line_len = i;
84 
85 	pci_ids_iter_pos++;
86 
87 	return line;
88 }
89 
90 /** See if there are more lines to process in pci.ids
91  *
92  *  @return                     #TRUE iff there are more lines to process
93  */
94 static dbus_bool_t
95 pci_ids_line_iter_has_more ()
96 {
97 	return pci_ids_iter_pos < pci_ids_len;
98 }
99 
100 
101 /** Find the names for a PCI device.
102  *
103  *  The pointers returned are only valid until the next invocation of this
104  *  function.
105  *
106  *  @param  vendor_id           PCI vendor id or 0 if unknown
107  *  @param  product_id          PCI product id or 0 if unknown
108  *  @param  subsys_vendor_id    PCI subsystem vendor id or 0 if unknown
109  *  @param  subsys_product_id   PCI subsystem product id or 0 if unknown
110  *  @param  vendor_name         Set to pointer of result or NULL
111  *  @param  product_name        Set to pointer of result or NULL
112  *  @param  subsys_vendor_name  Set to pointer of result or NULL
113  *  @param  subsys_product_name Set to pointer of result or NULL
114  */
115 void
116 ids_find_pci (int vendor_id, int product_id,
117 	      int subsys_vendor_id, int subsys_product_id,
118 	      char **vendor_name, char **product_name,
119 	      char **subsys_vendor_name, char **subsys_product_name)
120 {
121 	char *line;
122 	unsigned int i;
123 	unsigned int line_len;
124 	unsigned int num_tabs;
125 	char rep_vi[8];
126 	char rep_pi[8];
127 	char rep_svi[8];
128 	char rep_spi[8];
129 	dbus_bool_t vendor_matched = FALSE;
130 	dbus_bool_t product_matched = FALSE;
131 	static char store_vn[PCI_IDS_MAX_LINE_LEN];
132 	static char store_pn[PCI_IDS_MAX_LINE_LEN];
133 	static char store_svn[PCI_IDS_MAX_LINE_LEN];
134 	static char store_spn[PCI_IDS_MAX_LINE_LEN];
135 
136 	snprintf (rep_vi, 8, "%04x", vendor_id);
137 	snprintf (rep_pi, 8, "%04x", product_id);
138 	snprintf (rep_svi, 8, "%04x", subsys_vendor_id);
139 	snprintf (rep_spi, 8, "%04x", subsys_product_id);
140 
141 	*vendor_name = NULL;
142 	*product_name = NULL;
143 	*subsys_vendor_name = NULL;
144 	*subsys_product_name = NULL;
145 
146 	for (pci_ids_line_iter_init (); pci_ids_line_iter_has_more ();) {
147 		line = pci_ids_line_iter_get_line (&line_len);
148 
149 		/* skip lines with no content */
150 		if (line_len < 4)
151 			continue;
152 
153 		/* skip comments */
154 		if (line[0] == '#')
155 			continue;
156 
157 		/* count number of tabs */
158 		num_tabs = 0;
159 		for (i = 0; i < line_len; i++) {
160 			if (line[i] != '\t')
161 				break;
162 			num_tabs++;
163 		}
164 
165 		switch (num_tabs) {
166 		case 0:
167 			/* vendor names */
168 			vendor_matched = FALSE;
169 
170 			/* first check subsys_vendor_id, if haven't done
171 			 * already */
172 			if (*subsys_vendor_name == NULL
173 			    && subsys_vendor_id != 0) {
174 				if ((*((dbus_uint32_t *) line)) ==
175 				    (*((dbus_uint32_t *) rep_svi))) {
176 					/* found it */
177 					for (i = 4; i < line_len; i++) {
178 						if (!isspace (line[i]))
179 							break;
180 					}
181 					strncpy (store_svn, line + i,
182 						 PCI_IDS_MAX_LINE_LEN);
183 					*subsys_vendor_name = store_svn;
184 				}
185 			}
186 
187 			/* check vendor_id */
188 			if (vendor_id != 0) {
189 				if (memcmp (line, rep_vi, 4) == 0) {
190 					/* found it */
191 					vendor_matched = TRUE;
192 
193 					for (i = 4; i < line_len; i++) {
194 						if (!isspace (line[i]))
195 							break;
196 					}
197 					strncpy (store_vn, line + i,
198 						 PCI_IDS_MAX_LINE_LEN);
199 					*vendor_name = store_vn;
200 				}
201 			}
202 
203 			break;
204 
205 		case 1:
206 			product_matched = FALSE;
207 
208 			/* product names */
209 			if (!vendor_matched)
210 				continue;
211 
212 			/* check product_id */
213 			if (product_id != 0) {
214 				if (memcmp (line + 1, rep_pi, 4) == 0) {
215 					/* found it */
216 
217 					product_matched = TRUE;
218 
219 					for (i = 5; i < line_len; i++) {
220 						if (!isspace (line[i]))
221 							break;
222 					}
223 					strncpy (store_pn, line + i,
224 						 PCI_IDS_MAX_LINE_LEN);
225 					*product_name = store_pn;
226 				}
227 			}
228 			break;
229 
230 		case 2:
231 			/* subsystem_vendor subsystem_product */
232 			if (!vendor_matched || !product_matched)
233 				continue;
234 
235 			/* check product_id */
236 			if (subsys_vendor_id != 0
237 			    && subsys_product_id != 0) {
238 				if (memcmp (line + 2, rep_svi, 4) == 0
239 				    && memcmp (line + 7, rep_spi,
240 					       4) == 0) {
241 					/* found it */
242 					for (i = 11; i < line_len; i++) {
243 						if (!isspace (line[i]))
244 							break;
245 					}
246 					strncpy (store_spn, line + i,
247 						 PCI_IDS_MAX_LINE_LEN);
248 					*subsys_product_name = store_spn;
249 				}
250 			}
251 
252 			break;
253 
254 		default:
255 			break;
256 		}
257 
258 	}
259 }
260 
261 /** Free resources used by to store the PCI database
262  *
263  *  @param                      #FALSE if the PCI database wasn't loaded
264  */
265 static dbus_bool_t
266 pci_ids_free ()
267 {
268 	if (pci_ids != NULL) {
269 		free (pci_ids);
270 		pci_ids = NULL;
271 		return TRUE;
272 	}
273 	return FALSE;
274 }
275 
276 /** Load the PCI database used for mapping vendor, product, subsys_vendor
277  *  and subsys_product numbers into names.
278  *
279  *  @param  path                Path of the pci.ids file, e.g.
280  *                              /usr/share/hwdata/pci.ids
281  *  @return                     #TRUE if the file was succesfully loaded
282  */
283 static dbus_bool_t
284 pci_ids_load (const char *path)
285 {
286 	FILE *fp;
287 	unsigned int num_read;
288 
289 	fp = fopen (path, "r");
290 	if (fp == NULL) {
291 		HAL_ERROR (("couldn't open PCI database at %s,", path));
292 		return FALSE;
293 	}
294 
295 	fseek (fp, 0, SEEK_END);
296 	pci_ids_len = ftell (fp);
297 	fseek (fp, 0, SEEK_SET);
298 
299 	pci_ids = malloc (pci_ids_len);
300 	if (pci_ids == NULL) {
301 		DIE (("Couldn't allocate %d bytes for PCI database file\n",
302 		      pci_ids_len));
303 	}
304 
305 	num_read = fread (pci_ids, sizeof (char), pci_ids_len, fp);
306 	if (pci_ids_len != num_read) {
307 		HAL_ERROR (("Error loading PCI database file"));
308 		pci_ids_free();
309 		fclose(fp);
310 		return FALSE;
311 	}
312 
313 	fclose(fp);
314 	return TRUE;
315 }
316 
317 /*==========================================================================*/
318 
319 /** Pointer to where the usb.ids file is loaded */
320 static char *usb_ids = NULL;
321 
322 /** Length of data store at at usb_ids */
323 static unsigned int usb_ids_len;
324 
325 /** Iterator position into usb_ids */
326 static unsigned int usb_ids_iter_pos;
327 
328 /** Initialize the usb.ids line iterator to the beginning of the file */
329 static void
330 usb_ids_line_iter_init ()
331 {
332 	usb_ids_iter_pos = 0;
333 }
334 
335 /** Maximum length of lines in usb.ids */
336 #define USB_IDS_MAX_LINE_LEN 512
337 
338 /** Get the next line from usb.ids
339  *
340  *  @param  line_len            Pointer to where number of bytes in line will
341  *                              be stored
342  *  @return                     Pointer to the line; only valid until the
343  *                              next invocation of this function
344  */
345 static char *
346 usb_ids_line_iter_get_line (unsigned int *line_len)
347 {
348 	unsigned int i;
349 	static char line[USB_IDS_MAX_LINE_LEN];
350 
351 	for (i = 0;
352 	     usb_ids_iter_pos < usb_ids_len &&
353 	     i < USB_IDS_MAX_LINE_LEN - 1 &&
354 	     usb_ids[usb_ids_iter_pos] != '\n'; i++, usb_ids_iter_pos++) {
355 		line[i] = usb_ids[usb_ids_iter_pos];
356 	}
357 
358 	line[i] = '\0';
359 	if (line_len != NULL)
360 		*line_len = i;
361 
362 	usb_ids_iter_pos++;
363 
364 	return line;
365 }
366 
367 /** See if there are more lines to process in usb.ids
368  *
369  *  @return                     #TRUE iff there are more lines to process
370  */
371 static dbus_bool_t
372 usb_ids_line_iter_has_more ()
373 {
374 	return usb_ids_iter_pos < usb_ids_len;
375 }
376 
377 /** Find the names for a USB device.
378  *
379  *  The pointers returned are only valid until the next invocation of this
380  *  function.
381  *
382  *  @param  vendor_id           USB vendor id or 0 if unknown
383  *  @param  product_id          USB product id or 0 if unknown
384  *  @param  vendor_name         Set to pointer of result or NULL
385  *  @param  product_name        Set to pointer of result or NULL
386  */
387 void
388 ids_find_usb (int vendor_id, int product_id,
389 	      char **vendor_name, char **product_name)
390 {
391 	char *line;
392 	unsigned int i;
393 	unsigned int line_len;
394 	unsigned int num_tabs;
395 	char rep_vi[8];
396 	char rep_pi[8];
397 	static char store_vn[USB_IDS_MAX_LINE_LEN];
398 	static char store_pn[USB_IDS_MAX_LINE_LEN];
399 	dbus_bool_t vendor_matched = FALSE;
400 
401 	snprintf (rep_vi, 8, "%04x", vendor_id);
402 	snprintf (rep_pi, 8, "%04x", product_id);
403 
404 	*vendor_name = NULL;
405 	*product_name = NULL;
406 
407 	for (usb_ids_line_iter_init (); usb_ids_line_iter_has_more ();) {
408 		line = usb_ids_line_iter_get_line (&line_len);
409 
410 		/* skip lines with no content */
411 		if (line_len < 4)
412 			continue;
413 
414 		/* skip comments */
415 		if (line[0] == '#')
416 			continue;
417 
418 		/* count number of tabs */
419 		num_tabs = 0;
420 		for (i = 0; i < line_len; i++) {
421 			if (line[i] != '\t')
422 				break;
423 			num_tabs++;
424 		}
425 
426 		switch (num_tabs) {
427 		case 0:
428 			/* vendor names */
429 			vendor_matched = FALSE;
430 
431 			/* check vendor_id */
432 			if (vendor_id != 0) {
433 				if (memcmp (line, rep_vi, 4) == 0) {
434 					/* found it */
435 					vendor_matched = TRUE;
436 
437 					for (i = 4; i < line_len; i++) {
438 						if (!isspace (line[i]))
439 							break;
440 					}
441 					strncpy (store_vn, line + i,
442 						 USB_IDS_MAX_LINE_LEN);
443 					*vendor_name = store_vn;
444 				}
445 			}
446 			break;
447 
448 		case 1:
449 			/* product names */
450 			if (!vendor_matched)
451 				continue;
452 
453 			/* check product_id */
454 			if (product_id != 0) {
455 				if (memcmp (line + 1, rep_pi, 4) == 0) {
456 					/* found it */
457 					for (i = 5; i < line_len; i++) {
458 						if (!isspace (line[i]))
459 							break;
460 					}
461 					strncpy (store_pn, line + i,
462 						 USB_IDS_MAX_LINE_LEN);
463 					*product_name = store_pn;
464 
465 					/* no need to continue the search */
466 					return;
467 				}
468 			}
469 			break;
470 
471 		default:
472 			break;
473 		}
474 
475 	}
476 }
477 
478 /** Free resources used by to store the USB database
479  *
480  *  @param                      #FALSE if the USB database wasn't loaded
481  */
482 static dbus_bool_t
483 usb_ids_free ()
484 {
485 	if (usb_ids != NULL) {
486 		free (usb_ids);
487 		usb_ids = NULL;
488 		return TRUE;
489 	}
490 	return FALSE;
491 }
492 
493 /** Load the USB database used for mapping vendor, product, subsys_vendor
494  *  and subsys_product numbers into names.
495  *
496  *  @param  path                Path of the usb.ids file, e.g.
497  *                              /usr/share/hwdata/usb.ids
498  *  @return                     #TRUE if the file was succesfully loaded
499  */
500 static dbus_bool_t
501 usb_ids_load (const char *path)
502 {
503 	FILE *fp;
504 	unsigned int num_read;
505 
506 	fp = fopen (path, "r");
507 	if (fp == NULL) {
508 		printf ("couldn't open USB database at %s,", path);
509 		return FALSE;
510 	}
511 
512 	fseek (fp, 0, SEEK_END);
513 	usb_ids_len = ftell (fp);
514 	fseek (fp, 0, SEEK_SET);
515 
516 	usb_ids = malloc (usb_ids_len);
517 	if (usb_ids == NULL) {
518 		printf
519 		    ("Couldn't allocate %d bytes for USB database file\n",
520 		     usb_ids_len);
521 		fclose(fp);
522 		return FALSE;
523 	}
524 
525 	num_read = fread (usb_ids, sizeof (char), usb_ids_len, fp);
526 	if (usb_ids_len != num_read) {
527 		printf ("Error loading USB database file\n");
528 		usb_ids_free ();
529 		fclose(fp);
530 		return FALSE;
531 	}
532 
533 	fclose(fp);
534 	return TRUE;
535 }
536 
537 
538 void
539 ids_init (void)
540 {
541 	/* Load /usr/share/hwdata/pci.ids */
542 	pci_ids_load (HWDATA_DIR "/pci.ids");
543 
544 	/* Load /usr/share/hwdata/usb.ids */
545 	usb_ids_load (HWDATA_DIR "/usb.ids");
546 }
547 
548 
549 /* This, somewhat incomplete, list is from this sources:
550  * http://www.plasma-online.de/english/identify/serial/pnp_id_pnp.html
551  * http://www-pc.uni-regensburg.de/hardware/TECHNIK/PCI_PNP/pnpid.txt
552  *
553  * Keep this sorted!
554  */
555 struct pnp_id {
556 	char *id;
557    	char *desc;
558 } static pnp_ids_list[] = {
559 	/* Crystal Semiconductor devices */
560 	{"CSC0000", "Crystal Semiconductor CS423x sound -- SB/WSS/OPL3 emulation"},
561 	{"CSC0001", "Crystal Semiconductor CS423x sound -- joystick"},
562 	{"CSC0003", "Crystal Semiconductor CS423x sound -- MPU401"},
563 	{"CSC0010", "Crystal Semiconductor CS423x sound -- control"},
564 	/* IBM devices */
565 	{"IBM0071", "IBM infrared communications device"},
566 	{"IBM3760", "IBM DSP"},
567 	{"IBM3780", "IBM pointing device"},
568         /* FinePoint devices */
569         {"FPI2004", "FinePoint Innovations Tablet"},
570         /* Fujitsu (Siemens Computers) devices */
571         {"FUJ02E5", "Wacom Serial Pen HID Tablet"},
572         {"FUJ02E6", "Fujitsu Serial TouchScreen"},
573 	/* interrupt controllers */
574 	{"PNP0000", "AT Interrupt Controller"},
575 	{"PNP0001", "EISA Interrupt Controller"},
576 	{"PNP0002", "MCA Interrupt Controller"},
577 	{"PNP0003", "APIC"},
578 	{"PNP0004", "Cyrix SLiC MP interrupt controller"},
579 	/* timers */
580 	{"PNP0100", "AT Timer"},
581 	{"PNP0101", "EISA Timer"},
582 	{"PNP0102", "MCA Timer"},
583 	/* DMA controllers */
584 	{"PNP0200", "AT DMA Controller"},
585 	{"PNP0201", "EISA DMA Controller"},
586 	{"PNP0202", "MCA DMA Controller"},
587 	/* keyboards */
588 	{"PNP0300", "IBM PC/XT keyboard controller (83-key)"},
589 	{"PNP0301", "IBM PC/AT keyboard controller (86-key)"},
590 	{"PNP0302", "IBM PC/XT keyboard controller (84-key)"},
591 	{"PNP0303", "IBM Enhanced (101/102-key, PS/2 mouse support)"},
592 	{"PNP0304", "Olivetti Keyboard (83-key)"},
593 	{"PNP0305", "Olivetti Keyboard (102-key)"},
594 	{"PNP0306", "Olivetti Keyboard (86-key)"},
595 	{"PNP0307", "Microsoft Windows(R) Keyboard"},
596 	{"PNP0308", "General Input Device Emulation Interface (GIDEI) legacy"},
597 	{"PNP0309", "Olivetti Keyboard (A101/102 key)"},
598 	{"PNP030A", "AT&T 302 keyboard"},
599 	{"PNP030B", "Reserved by Microsoft"},
600 	{"PNP0320", "Japanese 101-key keyboard"},
601 	{"PNP0321", "Japanese AX keyboard"},
602 	{"PNP0322", "Japanese 106-key keyboard A01"},
603 	{"PNP0323", "Japanese 106-key keyboard 002/003"},
604 	{"PNP0324", "Japanese 106-key keyboard 001"},
605 	{"PNP0325", "Japanese Toshiba Desktop keyboard"},
606 	{"PNP0326", "Japanese Toshiba Laptop keyboard"},
607 	{"PNP0327", "Japanese Toshiba Notebook keyboard"},
608 	{"PNP0340", "Korean 84-key keyboard"},
609 	{"PNP0341", "Korean 86-key keyboard"},
610 	{"PNP0342", "Korean Enhanced keyboard"},
611 	{"PNP0343", "Korean Enhanced keyboard 101b"},
612 	{"PNP0343", "Korean Enhanced keyboard 101c"},
613 	{"PNP0344", "Korean Enhanced keyboard 103"},
614 	/* parallel ports */
615 	{"PNP0400", "Standard LPT printer port"},
616 	{"PNP0401", "ECP printer port"},
617 	/* serial ports */
618 	{"PNP0500", "Standard PC COM port"},
619 	{"PNP0501", "16550A-compatible COM port"},
620 	{"PNP0502", "Multiport serial device (non-intelligent 16550)"},
621 	{"PNP0510", "Generic IRDA-compatible device"},
622 	{"PNP0511", "Generic IRDA-compatible device"},
623 	/* IDE controller */
624 	{"PNP0600", "Generic ESDI/IDE/ATA compatible hard disk controller"},
625 	{"PNP0601", "Plus Hardcard II"},
626 	{"PNP0602", "Plus Hardcard IIXL/EZ"},
627 	{"PNP0603", "Generic IDE supporting Microsoft Device Bay Specification"},
628 	{"PNP0604", "PC standard floppy disk controller"},
629 	{"PNP0605", "HP Omnibook floppy disk controller"},
630 	{"PNP0680", "Bus Master E-IDE controller"},
631 	{"PNP0700", "PC standard floppy disk controller"},
632 	{"PNP0701", "Standard floppy controller supporting MS Device Bay Spec"},
633 	/* system devices */
634 	{"PNP0800", "AT-style speaker sound"},
635 	/* obsolete devices */
636 	{"PNP0802", "Microsoft Sound System compatible device (obsolete, use PNPB0xx instead)"},
637 	/* display adapters / graphic cards */
638 	{"PNP0900", "VGA Compatible"},
639 	{"PNP0901", "Video Seven VRAM/VRAM II/1024i"},
640 	{"PNP0902", "IBM 8514/A Compatible"},
641 	{"PNP0903", "Trident VGA"},
642 	{"PNP0904", "Cirrus Logic Laptop VGA"},
643 	{"PNP0905", "Cirrus Logic VGA"},
644 	{"PNP0906", "Tseng Labs ET4000"},
645 	{"PNP0907", "Western Digital VGA"},
646 	{"PNP0908", "Western Digital Laptop VGA"},
647 	{"PNP0909", "S3 Inc. 911/924"},
648 	{"PNP090A", "ATI Ultra Pro/Plus (Mach 32)"},
649 	{"PNP090B", "ATI Ultra (Mach 8)"},
650 	{"PNP090C", "IBM XGA Compatible"},
651 	{"PNP090D", "ATI VGA Wonder"},
652 	{"PNP090E", "Weitek P9000 Graphics Adapter"},
653 	{"PNP090F", "Oak Technology VGA"},
654 	{"PNP0910", "Compaq QVision"},
655 	{"PNP0911", "IBM XGA/2"},
656 	{"PNP0912", "Tseng Labs ET4000 W32/W32i/W32p"},
657 	{"PNP0913", "S3 Inc. 801/928/964"},
658 	{"PNP0914", "Cirrus Logic 5429/5434 (memory mapped)"},
659 	{"PNP0915", "Compaq Advanced VGA (AVGA)"},
660 	{"PNP0916", "ATI Ultra Pro Turbo (Mach64)"},
661 	{"PNP0917", "Reserved by Microsoft"},
662 	{"PNP0918", "Matrox MGA"},
663 	{"PNP0919", "Compaq QVision 2000"},
664 	{"PNP091A", "Tseng Labs W128"},
665 	{"PNP0930", "Chips & Technologies Super VGA"},
666 	{"PNP0931", "Chips & Technologies Accelerator"},
667 	{"PNP0940", "NCR 77c22e Super VGA"},
668 	{"PNP0941", "NCR 77c32blt"},
669 	{"PNP09FF", "Plug and Play Monitors (VESA DDC)"},
670 	/* peripheral buses */
671 	{"PNP0A00", "ISA Bus"},
672 	{"PNP0A01", "EISA Bus"},
673 	{"PNP0A02", "MCA Bus"},
674 	{"PNP0A03", "PCI Bus"},
675 	{"PNP0A04", "VESA/VL Bus"},
676 	{"PNP0A05", "Generic ACPI Bus"},
677 	{"PNP0A06", "Generic ACPI Extended-IO Bus (EIO bus)"},
678 	/* system devices */
679 	{"PNP0B00", "AT Real-Time Clock"},
680 	{"PNP0C00", "Plug and Play BIOS (only created by the root enumerator)"},
681 	{"PNP0C01", "System Board"},
682 	{"PNP0C02", "General ID for reserving resources required by PnP motherboard registers. (Not device specific.)"},
683 	{"PNP0C03", "Plug and Play BIOS Event Notification Interrupt"},
684 	{"PNP0C04", "Math Coprocessor"},
685 	{"PNP0C05", "APM BIOS (Version independent)"},
686 	{"PNP0C06", "Reserved for identification of early Plug and Play BIOS implementation"},
687 	{"PNP0C07", "Reserved for identification of early Plug and Play BIOS implementation"},
688 	{"PNP0C08", "ACPI system board hardware"},
689 	{"PNP0C09", "ACPI Embedded Controller"},
690 	{"PNP0C0A", "ACPI Control Method Battery"},
691 	{"PNP0C0B", "ACPI Fan"},
692 	{"PNP0C0C", "ACPI power button device"},
693 	{"PNP0C0D", "ACPI lid device"},
694 	{"PNP0C0E", "ACPI sleep button device"},
695 	{"PNP0C0F", "PCI interrupt link device"},
696 	{"PNP0C10", "ACPI system indicator device"},
697 	{"PNP0C11", "ACPI thermal zone"},
698 	{"PNP0C12", "Device Bay Controller"},
699 	{"PNP0C13", "Plug and Play BIOS (used when ACPI mode cannot be used)"},
700 	{"PNP0CF0", "Compaq LTE Lite Support"},
701 	{"PNP0CF1", "Compaq LTE Elite Support"},
702 	/* PCMCIA controllers */
703 	{"PNP0E00", "Intel 82365-Compatible PCMCIA Controller"},
704 	{"PNP0E01", "Cirrus Logic CL-PD6720 PCMCIA Controller"},
705 	{"PNP0E02", "VLSI VL82C146 PCMCIA Controller"},
706 	{"PNP0E03", "Intel 82365-compatible CardBus controller"},
707 	/* mice */
708 	{"PNP0F00", "Microsoft Bus Mouse"},
709 	{"PNP0F01", "Microsoft Serial Mouse"},
710 	{"PNP0F02", "Microsoft InPort Mouse"},
711 	{"PNP0F03", "Microsoft PS/2-style Mouse"},
712 	{"PNP0F04", "Mouse Systems Mouse"},
713 	{"PNP0F05", "Mouse Systems 3-Button Mouse (COM2)"},
714 	{"PNP0F06", "Genius Mouse (COM1)"},
715 	{"PNP0F07", "Genius Mouse (COM2)"},
716 	{"PNP0F08", "Logitech Serial Mouse"},
717 	{"PNP0F09", "Microsoft BallPoint Serial Mouse"},
718 	{"PNP0F0A", "Microsoft Plug and Play Mouse"},
719 	{"PNP0F0B", "Microsoft Plug and Play BallPoint Mouse"},
720 	{"PNP0F0C", "Microsoft-compatible Serial Mouse"},
721 	{"PNP0F0D", "Microsoft-compatible InPort-compatible Mouse"},
722 	{"PNP0F0E", "Microsoft-compatible PS/2-style Mouse"},
723 	{"PNP0F0F", "Microsoft-compatible Serial BallPoint-compatible Mouse"},
724 	{"PNP0F10", "Texas Instruments QuickPort Mouse"},
725 	{"PNP0F11", "Microsoft-compatible Bus Mouse"},
726 	{"PNP0F12", "Logitech PS/2-style Mouse"},
727 	{"PNP0F13", "PS/2 Port for PS/2-style Mice"},
728 	{"PNP0F14", "Microsoft Kids Mouse"},
729 	{"PNP0F15", "Logitech bus mouse"},
730 	{"PNP0F16", "Logitech SWIFT device"},
731 	{"PNP0F17", "Logitech-compatible serial mouse"},
732 	{"PNP0F18", "Logitech-compatible bus mouse"},
733 	{"PNP0F19", "Logitech-compatible PS/2-style Mouse"},
734 	{"PNP0F1A", "Logitech-compatible SWIFT Device"},
735 	{"PNP0F1B", "HP Omnibook Mouse"},
736 	{"PNP0F1C", "Compaq LTE Trackball PS/2-style Mouse"},
737 	{"PNP0F1D", "Compaq LTE Trackball Serial Mouse"},
738 	{"PNP0F1E", "Microsoft Kids Trackball Mouse"},
739 	{"PNP0F1F", "Reserved by Microsoft Input Device Group"},
740 	{"PNP0F20", "Reserved by Microsoft Input Device Group"},
741 	{"PNP0F21", "Reserved by Microsoft Input Device Group"},
742 	{"PNP0F22", "Reserved by Microsoft Input Device Group"},
743 	{"PNP0F23", "Reserved by Microsoft Input Device Group"},
744 	{"PNP0FFF", "Reserved by Microsoft Systems"},
745 	{"PNP0XXX", "Unknown System Device"},
746 	/* network cards */
747 	{"PNP8000", "Network Adapter"},
748 	{"PNP8001", "Novell/Anthem NE3200"},
749 	{"PNP8004", "Compaq NE3200"},
750 	{"PNP8006", "Intel EtherExpress/32"},
751 	{"PNP8008", "HP EtherTwist EISA LAN Adapter/32 (HP27248A)"},
752 	{"PNP8065", "Ungermann-Bass NIUps or NIUps/EOTP"},
753 	{"PNP8072", "DEC (DE211) EtherWorks MC/TP"},
754 	{"PNP8073", "DEC (DE212) EtherWorks MC/TP_BNC"},
755 	{"PNP8074", "HP MC LAN Adapter/16 TP (PC27246)"},
756 	{"PNP8078", "DCA 10 Mb MCA"},
757 	{"PNP807F", "Racal NI9210"},
758 	{"PNP8081", "Pure Data Ethernet"},
759 	{"PNP8096", "Thomas-Conrad TC4046"},
760 	{"PNP80C9", "IBM Token Ring"},
761 	{"PNP80CA", "IBM Token Ring II"},
762 	{"PNP80CB", "IBM Token Ring II/Short"},
763 	{"PNP80CC", "IBM Token Ring 4/16Mbs"},
764 	{"PNP80D3", "Novell/Anthem NE1000"},
765 	{"PNP80D4", "Novell/Anthem NE2000"},
766 	{"PNP80D5", "NE1000 Compatible"},
767 	{"PNP80D6", "NE2000 Compatible"},
768 	{"PNP80D7", "Novell/Anthem NE1500T"},
769 	{"PNP80D8", "Novell/Anthem NE2100"},
770 	{"PNP80D9", "NE2000 Plus"},
771 	{"PNP80DD", "SMC ARCNETPC"},
772 	{"PNP80DE", "SMC ARCNET PC100, PC200"},
773 	{"PNP80DF", "SMC ARCNET PC110, PC210, PC250"},
774 	{"PNP80E0", "SMC ARCNET PC130/E"},
775 	{"PNP80E1", "SMC ARCNET PC120, PC220, PC260"},
776 	{"PNP80E2", "SMC ARCNET PC270/E"},
777 	{"PNP80E5", "SMC ARCNET PC600W, PC650W"},
778 	{"PNP80E7", "DEC DEPCA"},
779 	{"PNP80E8", "DEC (DE100) EtherWorks LC"},
780 	{"PNP80E9", "DEC (DE200) EtherWorks Turbo"},
781 	{"PNP80EA", "DEC (DE101) EtherWorks LC/TP"},
782 	{"PNP80EB", "DEC (DE201) EtherWorks Turbo/TP"},
783 	{"PNP80EC", "DEC (DE202) EtherWorks Turbo/TP_BNC"},
784 	{"PNP80ED", "DEC (DE102) EtherWorks LC/TP_BNC"},
785 	{"PNP80EE", "DEC EE101 (Built-In)"},
786 	{"PNP80EF", "DEC PC 433 WS (Built-In)"},
787 	{"PNP80F1", "3Com EtherLink Plus"},
788 	{"PNP80F3", "3Com EtherLink II or IITP (8 or 16-bit)"},
789 	{"PNP80F4", "3Com TokenLink"},
790 	{"PNP80F6", "3Com EtherLink 16"},
791 	{"PNP80F7", "3Com EtherLink III"},
792 	{"PNP80F8", "3Com Generic Etherlink Plug and Play Device"},
793 	{"PNP80FB", "Thomas Conrad TC6045"},
794 	{"PNP80FC", "Thomas Conrad TC6042"},
795 	{"PNP80FD", "Thomas Conrad TC6142"},
796 	{"PNP80FE", "Thomas Conrad TC6145"},
797 	{"PNP80FF", "Thomas Conrad TC6242"},
798 	{"PNP8100", "Thomas Conrad TC6245"},
799 	{"PNP8101", "Thomas-Conrad TC4045"},
800 	{"PNP8104", "Thomas-Conrad TC4035"},
801 	{"PNP8105", "DCA 10 MB"},
802 	{"PNP8106", "DCA 10 MB Fiber Optic"},
803 	{"PNP8107", "DCA 10 MB Twisted Pair"},
804 	{"PNP8113", "Racal NI6510"},
805 	{"PNP8114", "Racal NI5210/8 or NI5210/16"},
806 	{"PNP8119", "Ungermann-Bass pcNIU"},
807 	{"PNP811A", "Ungermann-Bass pcNIU/ex 128K"},
808 	{"PNP811B", "Ungermann-Bass pcNIU/ex 512K"},
809 	{"PNP811C", "Ungermann-Bass NIUpc"},
810 	{"PNP811D", "Ungermann-Bass NIUpc/3270"},
811 	{"PNP8120", "Ungermann-Bass NIUpc/EOTP"},
812 	{"PNP8123", "SMC StarCard PLUS (WD/8003S)"},
813 	{"PNP8124", "SMC StarCard PLUS With On Board Hub (WD/8003SH)"},
814 	{"PNP8125", "SMC EtherCard PLUS (WD/8003E)"},
815 	{"PNP8126", "SMC EtherCard PLUS With Boot ROM Socket (WD/8003EBT)"},
816 	{"PNP8127", "SMC EtherCard PLUS With Boot ROM Socket (WD/8003EB)"},
817 	{"PNP8128", "SMC EtherCard PLUS TP (WD/8003WT)"},
818 	{"PNP812A", "SMC EtherCard PLUS 16 With Boot ROM Socket (WD/8013EBT)"},
819 	{"PNP812D", "Intel EtherExpress 16 or 16TP"},
820 	{"PNP812F", "Intel TokenExpress 16/4"},
821 	{"PNP8130", "Intel TokenExpress MCA 16/4"},
822 	{"PNP8132", "Intel EtherExpress 16 (MCA)"},
823 	{"PNP8133", "Compaq Ethernet 16E"},
824 	{"PNP8137", "Artisoft AE-1"},
825 	{"PNP8138", "Artisoft AE-2 or AE-3"},
826 	{"PNP8141", "Amplicard AC 210/XT"},
827 	{"PNP8142", "Amplicard AC 210/AT"},
828 	{"PNP814B", "Everex SpeedLink /PC16 (EV2027)"},
829 	{"PNP8155", "HP PC LAN Adapter/8 TP (HP27245)"},
830 	{"PNP8156", "HP PC LAN Adapter/16 TP (HP27247A)"},
831 	{"PNP8157", "HP PC LAN Adapter/8 TL (HP27250)"},
832 	{"PNP8158", "HP PC LAN Adapter/16 TP Plus (HP27247B)"},
833 	{"PNP8159", "HP PC LAN Adapter/16 TL Plus (HP27252)"},
834 	{"PNP815F", "National Semiconductor Ethernode *16AT"},
835 	{"PNP8160", "National Semiconductor AT/LANTIC EtherNODE 16-AT3"},
836 	{"PNP8169", "NCR StarCard"},
837 	{"PNP816A", "NCR Token-Ring 4 Mbs ISA"},
838 	{"PNP816B", "NCR WaveLAN AT"},
839 	{"PNP816C", "NCR WaveLan MC"},
840 	{"PNP816D", "NCR Token-Ring 16/4 Mbs ISA"},
841 	{"PNP8191", "Olicom 16/4 Token-Ring Adapter"},
842 	{"PNP81A5", "Research Machines Ethernet"},
843 	{"PNP81B9", "ToshibaLAN (internal)"},
844 	{"PNP81C3", "SMC EtherCard PLUS Elite (WD/8003EP)"},
845 	{"PNP81C4", "SMC EtherCard PLUS 10T (WD/8003W)"},
846 	{"PNP81C5", "SMC EtherCard PLUS Elite 16 (WD/8013EP)"},
847 	{"PNP81C6", "SMC EtherCard PLUS Elite 16T (WD/8013W)"},
848 	{"PNP81C7", "SMC EtherCard PLUS Elite 16 Combo (WD/8013EW or 8013EWC)"},
849 	{"PNP81C8", "SMC EtherElite Ultra 16"},
850 	{"PNP81C9", "SMC TigerCard (8216L, 8216LC, 8216LT)"},
851 	{"PNP81CA", "SMC EtherEZ (8416)"},
852 	{"PNP81D7", "Madge Smart 16/4 PC Ringnode"},
853 	{"PNP81D8", "Madge Smart 16/4 Ringnode ISA"},
854 	{"PNP81E4", "Pure Data PDI9025-32 (Token Ring)"},
855 	{"PNP81E6", "Pure Data PDI508+ (ArcNet)"},
856 	{"PNP81E7", "Pure Data PDI516+ (ArcNet)"},
857 	{"PNP81EB", "Proteon Token Ring (P1390)"},
858 	{"PNP81EC", "Proteon Token Ring (P1392)"},
859 	{"PNP81ED", "Proteon Token Ring ISA (P1340)"},
860 	{"PNP81EE", "Proteon Token Ring ISA (P1342)"},
861 	{"PNP81EF", "Proteon Token Ring ISA (P1346)"},
862 	{"PNP81F0", "Proteon Token Ring ISA (P1347)"},
863 	{"PNP81FF", "Cabletron E2000 Series DNI"},
864 	{"PNP8200", "Cabletron E2100 Series DNI"},
865 	{"PNP8201", "Cabletron T2015 4/16 Mbit/s DNI"},
866 	{"PNP8209", "Zenith Data Systems Z-Note"},
867 	{"PNP820A", "Zenith Data Systems NE2000-Compatible"},
868 	{"PNP8213", "Xircom Pocket Ethernet II"},
869 	{"PNP8214", "Xircom Pocket Ethernet I"},
870 	{"PNP8215", "Xircom Pocket Ethernet III Adapter"},
871 	{"PNP821D", "RadiSys EXM-10"},
872 	{"PNP8227", "SMC 3000 Series"},
873 	{"PNP8228", "SMC 91C2 controller"},
874 	{"PNP8231", "AMD AM2100/AM1500T"},
875 	{"PNP824F", "RCE 10Base-T (16 bit)"},
876 	{"PNP8250", "RCE 10Base-T (8 bit)"},
877 	{"PNP8263", "Tulip NCC-16"},
878 	{"PNP8277", "Exos 105"},
879 	{"PNP828A", "Intel '595 based Ethernet"},
880 	{"PNP828B", "TI2000-style Token Ring"},
881 	{"PNP828C", "AMD PCNet Family cards"},
882 	{"PNP828D", "AMD PCNet32 (VL version)"},
883 	{"PNP8294", "IrDA Infrared NDIS driver (Microsoft-supplied)"},
884 	{"PNP82BD", "IBM PCMCIA-NIC"},
885 	{"PNP82C0", "Eagle Technology NE200T"},
886 	{"PNP82C2", "Xircom CE10"},
887 	{"PNP82C3", "Xircom CEM2"},
888 	{"PNP82C4", "Xircom CE2"},
889 	{"PNP8321", "DEC Ethernet (All Types)"},
890 	{"PNP8323", "SMC EtherCard (All Types except 8013/A)"},
891 	{"PNP8324", "ARCNET Compatible"},
892 	{"PNP8325", "SMC TokenCard PLUS (8115T)"},
893 	{"PNP8326", "Thomas Conrad (All Arcnet Types)"},
894 	{"PNP8327", "IBM Token Ring (All Types)"},
895 	{"PNP8328", "Ungermann-Bass NIU"},
896 	{"PNP8329", "Proteon ProNET-4/16 ISA Token Ring (P1392+,P1392,1390)"},
897 	{"PNP8385", "Remote Network Access [RNA] Driver"},
898 	{"PNP8387", "Remote Network Access [RNA] PPP Driver"},
899 	{"PNP8388", "Reserved for Microsoft Networking components"},
900 	{"PNP8389", "Peer IrLAN infrared driver (Microsoft-supplied)"},
901 	{"PNP8390", "Generic network adapter"},
902 	{"PNP8XXX", "Unknown Network Adapter"},
903 	/* modems */
904 	{"PNP9000", "Modem"},
905 	/* CD controller */
906 	{"PNPA000", "Adaptec 154x compatible SCSI controller"},
907 	{"PNPA001", "Adaptec 174x compatible SCSI controller"},
908 	{"PNPA002", "Future Domain 16-700 compatible controller"},
909 	{"PNPA003", "Mitsumi CD-ROM adapter (Panasonic spec., used on SBPro/SB16)"},
910 	{"PNPA01B", "Trantor 128 SCSI Controller"},
911 	{"PNPA01D", "Trantor T160 SCSI Controller"},
912 	{"PNPA01E", "Trantor T338 Parallel SCSI controller"},
913 	{"PNPA01F", "Trantor T348 Parallel SCSI controller"},
914 	{"PNPA020", "Trantor Media Vision SCSI controller"},
915 	{"PNPA022", "Always IN-2000 SCSI controller"},
916 	{"PNPA02B", "Sony proprietary CD-ROM controller"},
917 	{"PNPA02D", "Trantor T13b 8-bit SCSI controller"},
918 	{"PNPA02F", "Trantor T358 Parallel SCSI controller"},
919 	{"PNPA030", "Mitsumi LU-005 Single Speed CD-ROM controller + drive"},
920 	{"PNPA031", "Mitsumi FX-001 Single Speed CD-ROM controller + drive"},
921 	{"PNPA032", "Mitsumi FX-001 Double Speed CD-ROM controller + drive"},
922 	{"PNPAXXX", "Unknown SCSI, Proprietary CD Adapter"},
923 	/* multimedia devices */
924 	{"PNPB000", "Creative Labs Sound Blaster 1.5 (or compatible sound device)"},
925 	{"PNPB001", "Creative Labs Sound Blaster 2.0 (or compatible sound device)"},
926 	{"PNPB002", "Creative Labs Sound Blaster Pro (or compatible sound device)"},
927 	{"PNPB003", "Creative Labs Sound Blaster 16 (or compatible sound device)"},
928 	{"PNPB004", "MediaVision Thunderboard (or compatible sound device)"},
929 	{"PNPB005", "Adlib-compatible FM synthesizer device"},
930 	{"PNPB006", "MPU401 compatible"},
931 	{"PNPB007", "Microsoft Windows Sound System-compatible sound device"},
932 	{"PNPB008", "Compaq Business Audio"},
933 	{"PNPB009", "Plug and Play Microsoft Windows Sound System Device"},
934 	{"PNPB00A", "MediaVision Pro Audio Spectrum (Trantor SCSI enabled, Thunder Chip Disabled)"},
935 	{"PNPB00B", "MediaVision Pro Audio 3D"},
936 	{"PNPB00C", "MusicQuest MQX-32M"},
937 	{"PNPB00D", "MediaVision Pro Audio Spectrum Basic (No Trantor SCSI, Thunder Chip Enabled)"},
938 	{"PNPB00E", "MediaVision Pro Audio Spectrum (Trantor SCSI enabled, Thunder Chip Disabled)"},
939 	{"PNPB00F", "MediaVision Jazz-16 chipset (OEM Versions)"},
940 	{"PNPB010", "Orchid Videola - Auravision VxP500 chipset"},
941 	{"PNPB018", "MediaVision Pro Audio Spectrum 8-bit"},
942 	{"PNPB019", "MediaVision Pro Audio Spectrum Basic (No Trantor SCSI, Thunder Chip Enabled)"},
943 	{"PNPB020", "Yamaha OPL3-compatible FM synthesizer device"},
944 	{"PNPB02F", "Joystick/Game port"},
945 	{"PNPB077", "OAK Mozart Sound System"},
946 	{"PNPB078", "OAK Mozart Sound System MPU-401"},
947 	{"PNPBXXX", "Unknown Multimedia Device"},
948 	/* modems */
949 	{"PNPC000", "Compaq 14400 Modem (TBD)"},
950 	{"PNPC001", "Compaq 2400/9600 Modem (TBD)"},
951 	{"PNPCXXX", "Unknown Modem"},
952 	/* some other network cards */
953 	{"PNPD300", "SK-NET TR4/16+ Token-Ring"},
954 	{"PNPE000", "SK-NET G16, G16/TP Ethernet"},
955 	{"PNPF000", "SK-NET FDDI-FI FDDI LAN"},
956 	/* Toshiba devices */
957 	{"TOS6200", "Toshiba Notebook Extra HCI driver"},
958 	{"TOS6202", "Toshiba Notebook Extra HCI driver"},
959 	{"TOS6207", "Toshiba Notebook Extra HCI driver"},
960 	{"TOS7400", "Toshiba AcuPoint"},
961 	/* Wacom devices */
962 	{"WACf004", "Wacom Serial Tablet PC Pen Tablet/Digitizer"},
963 	{"WACf005", "Wacom Serial Tablet PC Pen Tablet/Digitizer"},
964 	{"WACf006", "Wacom Serial Tablet PC Pen Tablet/Digitizer"}
965 };
966 
967 static int
968 ids_comp_pnp(const void *id1, const void *id2) {
969         struct pnp_id *pnp_id1 = (struct pnp_id *) id1;
970         struct pnp_id *pnp_id2 = (struct pnp_id *) id2;
971         return strcasecmp(pnp_id1->id, pnp_id2->id);
972 }
973 
974 void
975 ids_find_pnp (const char *pnp_id, char **pnp_description)
976 {
977 	static gboolean sorted = FALSE;
978 	struct pnp_id search, *res;
979 
980 	if (!sorted) {
981 		/* sort the list, to be sure that all is in correc order */
982 		qsort(pnp_ids_list, sizeof(pnp_ids_list)/sizeof(pnp_ids_list[0]),
983 		      sizeof(struct pnp_id), ids_comp_pnp);
984 		sorted = TRUE;
985 	}
986 
987         search.id = (char *) pnp_id;
988         res = bsearch(&search, pnp_ids_list, sizeof(pnp_ids_list)/sizeof(pnp_ids_list[0]),
989 		      sizeof(struct pnp_id), ids_comp_pnp);
990 
991         if (res != NULL)
992         	*pnp_description = res->desc;
993 	else
994         	*pnp_description = NULL;
995         return;
996 }
997