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