1 /*
2 * (C) Copyright IBM Corporation 2006
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file common_device_name.c
27 * Support routines used to determine the vendor or device names associated
28 * with a particular device or vendor.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <ctype.h>
38
39 #if defined(HAVE_STRING_H)
40 # include <string.h>
41 #elif defined(HAVE_STRINGS_H)
42 # include <strings.h>
43 #endif
44
45 #if defined(HAVE_INTTYPES_H)
46 # include <inttypes.h>
47 #elif defined(HAVE_STDINT_H)
48 # include <stdint.h>
49 #endif
50
51 #include "pciaccess.h"
52 #include "pciaccess_private.h"
53
54 #define DO_MATCH(a,b) (((a) == PCI_MATCH_ANY) || ((a) == (b)))
55
56 #ifdef HAVE_ZLIB
57
58 #include <zlib.h>
59 typedef gzFile pci_id_file;
60
61 static pci_id_file
pci_id_file_open(void)62 pci_id_file_open(void)
63 {
64 pci_id_file result;
65
66 result = gzopen(PCIIDS_PATH "/pci.ids.gz", "rb");
67 if (result)
68 return result;
69
70 return gzopen(PCIIDS_PATH "/pci.ids", "rb");
71 }
72
73 #define pci_id_file_gets(l, s, f) gzgets(f, l, s)
74 #define pci_id_file_close(f) gzclose(f)
75
76 #else /* not zlib */
77
78 typedef FILE * pci_id_file;
79
80 static pci_id_file
pci_id_file_open(void)81 pci_id_file_open(void)
82 {
83 pci_id_file result;
84
85 result = fopen(PCIIDS_PATH "/pci.ids", "re");
86 if (result)
87 return result;
88 #ifdef __FreeBSD__
89 return fopen("/usr/share/misc/pci_vendors", "re");
90 #endif
91
92 return fopen(PCIIDS_PATH "/pci.ids", "r");
93 }
94
95 #define pci_id_file_gets(l, s, f) fgets(l, s, f)
96 #define pci_id_file_close(f) fclose(f)
97
98 #endif
99
100 /**
101 * Node for sorting vendor IDs.
102 *
103 * Each structure forms an internal node of an n-way tree. Each node selects
104 * \c pci_id_node::bits number of bits from the vendor ID. Starting from the
105 * root of the tree, a slice of the low-order bits of the vendor ID are
106 * selected and used as an index into the \c pci_id_node::children array.
107 *
108 * At the leaf nodes (i.e., the node entered when all 16 bits of the vendor ID
109 * have been used), the \c pci_id_node::children is actually an array of
110 * pointers to \c pci_id_leaf structures.
111 *
112 * \todo
113 * Determine if there is a cleaner way (in the source code) to have the
114 * \c children array change type based on whether the node is internal or
115 * a leaf.
116 *
117 * \todo
118 * Currently \c bits is always 4. Decide if this value can ever change
119 * (i.e., to pull-up levels of the n-way tree when all the children's children
120 * are full). If it can, rip it out and hard-code it to 4 everywhere.
121 */
122 struct pci_id_node {
123 unsigned bits;
124 struct pci_id_node * children[16];
125 };
126
127 struct pci_id_leaf {
128 uint16_t vendor;
129 const char * vendor_name;
130
131 size_t num_devices;
132 struct pci_device_leaf * devices;
133 };
134
135 struct pci_device_leaf {
136 struct pci_id_match id;
137 const char * device_name;
138 };
139
140 /**
141 * Root of the PCI vendor ID search tree.
142 */
143 _pci_hidden struct pci_id_node * tree = NULL;
144
145 /**
146 * Get a pointer to the leaf node for a vendor ID.
147 *
148 * If the vendor ID does not exist in the tree, it is added.
149 */
150 static struct pci_id_leaf *
insert(uint16_t vendor)151 insert( uint16_t vendor )
152 {
153 struct pci_id_node * n;
154 unsigned bits = 0;
155
156 if ( tree == NULL ) {
157 tree = calloc( 1, sizeof( struct pci_id_node ) );
158
159 if ( tree == NULL )
160 return NULL;
161
162 tree->bits = 4;
163 }
164
165 n = tree;
166 while ( n != NULL ) {
167 const unsigned used_bits = n->bits;
168 const unsigned mask = (1 << used_bits) - 1;
169 const unsigned idx = (vendor & (mask << bits)) >> bits;
170
171
172 if ( bits >= 16 ) {
173 break;
174 }
175
176 bits += used_bits;
177
178 if ( n->children[ idx ] == NULL ) {
179 if ( bits < 16 ) {
180 struct pci_id_node * child =
181 calloc( 1, sizeof( struct pci_id_node ) );
182
183 if ( tree == NULL )
184 return NULL;
185
186 child->bits = 4;
187
188 n->children[ idx ] = child;
189 }
190 else {
191 struct pci_id_leaf * leaf =
192 calloc( 1, sizeof( struct pci_id_leaf ) );
193
194 if ( tree == NULL )
195 return NULL;
196
197 leaf->vendor = vendor;
198
199 n->children[ idx ] = (struct pci_id_node *) leaf;
200 }
201 }
202
203 n = n->children[ idx ];
204 }
205
206 return (struct pci_id_leaf *) n;
207 }
208
209
210 /**
211 * Populate a vendor node with all the devices associated with that vendor
212 *
213 * \param vend Vendor node that is to be filled from the pci.ids file.
214 *
215 * \todo
216 * The parsing in this function should be more rhobust. There are some error
217 * cases (i.e., a 0-tab line followed by a 2-tab line) that aren't handled
218 * correctly. I don't think there are any security problems with the code,
219 * but it's not impossible.
220 */
221 static void
populate_vendor(struct pci_id_leaf * vend,int fill_device_data)222 populate_vendor( struct pci_id_leaf * vend, int fill_device_data )
223 {
224 pci_id_file f;
225 char buf[128];
226 unsigned vendor = PCI_MATCH_ANY;
227
228
229 /* If the device tree for this vendor is already populated, don't do
230 * anything. This avoids wasted processing and potential memory leaks.
231 */
232 if (vend->num_devices != 0) {
233 return;
234 }
235
236 f = pci_id_file_open();
237
238 /* If the pci.ids file could not be opened, there's nothing we can do.
239 */
240 if (f == NULL) {
241 return;
242 }
243
244 while( pci_id_file_gets( buf, sizeof( buf ), f ) != NULL ) {
245 unsigned num_tabs;
246 char * new_line;
247 size_t length;
248
249 /* Each line either starts with zero, one, or two tabs followed by
250 * a series of 4 hex digits. Any lines not matching that are ignored.
251 */
252
253 for ( num_tabs = 0 ; num_tabs < 3 ; num_tabs++ ) {
254 if ( buf[ num_tabs ] != '\t' ) {
255 break;
256 }
257 }
258
259 if ( !isxdigit( buf[ num_tabs + 0 ] )
260 || !isxdigit( buf[ num_tabs + 1 ] )
261 || !isxdigit( buf[ num_tabs + 2 ] )
262 || !isxdigit( buf[ num_tabs + 3 ] ) ) {
263 continue;
264 }
265
266 new_line = strchr( buf, '\n' );
267 if ( new_line != NULL ) {
268 *new_line = '\0';
269 }
270
271 length = strlen( buf );
272 (void) memset( buf + length, 0, sizeof( buf ) - length );
273
274
275 if ( num_tabs == 0 ) {
276 vendor = (unsigned) strtoul( & buf[ num_tabs ], NULL, 16 );
277 if ( vend->vendor == vendor ) {
278 /* vendor_name may already be set from a previous invocation
279 * of this function with fill_device_data = 0.
280 */
281 if (vend->vendor_name == NULL) {
282 vend->vendor_name = strdup( & buf[ num_tabs + 6 ] );
283 }
284
285 /* If we're not going to fill in all of the device data as
286 * well, then bail out now. We have all the information that
287 * we need.
288 */
289 if ( ! fill_device_data ) {
290 break;
291 }
292 }
293 }
294 else if ( vendor == vend->vendor ) {
295 struct pci_device_leaf * d;
296 struct pci_device_leaf * dev;
297 struct pci_device_leaf * last_dev;
298
299
300
301 d = realloc( vend->devices, (vend->num_devices + 1)
302 * sizeof( struct pci_device_leaf ) );
303 if ( d == NULL ) {
304 goto cleanup;
305 }
306
307 last_dev = & d[ vend->num_devices - 1 ];
308 dev = & d[ vend->num_devices ];
309 vend->num_devices++;
310 vend->devices = d;
311
312 if ( num_tabs == 1 ) {
313 dev->id.vendor_id = vend->vendor;
314 dev->id.device_id = (unsigned) strtoul( & buf[ num_tabs ],
315 NULL, 16 );
316 dev->id.subvendor_id = PCI_MATCH_ANY;
317 dev->id.subdevice_id = PCI_MATCH_ANY;
318
319 dev->id.device_class = 0;
320 dev->id.device_class_mask = 0;
321 dev->id.match_data = 0;
322
323 dev->device_name = strdup( & buf[ num_tabs + 6 ] );
324 }
325 else {
326 dev->id = last_dev->id;
327
328 dev->id.subvendor_id= (unsigned) strtoul( & buf[ num_tabs ],
329 NULL, 16 );
330 dev->id.subdevice_id = (unsigned) strtoul( & buf[ num_tabs + 5 ],
331 NULL, 16 );
332 dev->device_name = strdup( & buf[ num_tabs + 5 + 6 ] );
333 }
334 }
335 }
336
337 cleanup:
338 pci_id_file_close( f );
339 }
340
341
342 /**
343 * Find the name of the specified device.
344 *
345 * Finds the actual product name of the specified device. If a subvendor ID
346 * and subdevice ID are specified in \c m, the returned name will be the name
347 * of the subdevice.
348 */
349 static const char *
find_device_name(const struct pci_id_match * m)350 find_device_name( const struct pci_id_match * m )
351 {
352 struct pci_id_leaf * vend;
353 unsigned i;
354
355
356 if ( m->vendor_id == PCI_MATCH_ANY ) {
357 return NULL;
358 }
359
360
361 vend = insert( m->vendor_id );
362 if ( vend == NULL ) {
363 return NULL;
364 }
365
366 if ( vend->num_devices == 0 ) {
367 populate_vendor( vend, 1 );
368 }
369
370
371 for ( i = 0 ; i < vend->num_devices ; i++ ) {
372 struct pci_device_leaf * d = & vend->devices[ i ];
373
374 if ( DO_MATCH( m->vendor_id, d->id.vendor_id )
375 && DO_MATCH( m->device_id, d->id.device_id )
376 && DO_MATCH( m->subvendor_id, d->id.subvendor_id )
377 && DO_MATCH( m->subdevice_id, d->id.subdevice_id ) ) {
378 return d->device_name;
379 }
380 }
381
382 return NULL;
383 }
384
385
386 /**
387 * Find the vendor name of the specified device.
388 *
389 * Finds the actual vendor name of the specified device. If a subvendor ID
390 * and subdevice ID are specified in \c m, the returned name will be the name
391 * associated with the subvendor.
392 */
393 static const char *
find_vendor_name(const struct pci_id_match * m)394 find_vendor_name( const struct pci_id_match * m )
395 {
396 struct pci_id_leaf * vend;
397
398
399 if ( m->vendor_id == PCI_MATCH_ANY ) {
400 return NULL;
401 }
402
403
404 vend = insert( m->vendor_id );
405 if ( vend == NULL ) {
406 return NULL;
407 }
408
409 if ( vend->vendor_name == NULL ) {
410 populate_vendor( vend, 0 );
411 }
412
413
414 return vend->vendor_name;
415 }
416
417
418 /**
419 * Get a name based on an arbitrary PCI search structure.
420 */
421 void
pci_get_strings(const struct pci_id_match * m,const char ** device_name,const char ** vendor_name,const char ** subdevice_name,const char ** subvendor_name)422 pci_get_strings( const struct pci_id_match * m,
423 const char ** device_name,
424 const char ** vendor_name,
425 const char ** subdevice_name,
426 const char ** subvendor_name )
427 {
428 struct pci_id_match temp;
429
430
431 temp = *m;
432 temp.subvendor_id = PCI_MATCH_ANY;
433 temp.subdevice_id = PCI_MATCH_ANY;
434
435 if ( device_name != NULL ) {
436 *device_name = find_device_name( & temp );
437 }
438
439 if ( vendor_name != NULL ) {
440 *vendor_name = find_vendor_name( & temp );
441 }
442
443 if ( subdevice_name != NULL ) {
444 *subdevice_name = find_device_name( m );
445 }
446
447 if ( subvendor_name != NULL ) {
448 *subvendor_name = find_vendor_name( m );
449 }
450 }
451
452
453 /**
454 * Get the name associated with the device's primary device ID.
455 */
456 const char *
pci_device_get_device_name(const struct pci_device * dev)457 pci_device_get_device_name( const struct pci_device * dev )
458 {
459 struct pci_id_match m;
460
461
462 m.vendor_id = dev->vendor_id;
463 m.device_id = dev->device_id;
464 m.subvendor_id = PCI_MATCH_ANY;
465 m.subdevice_id = PCI_MATCH_ANY;
466 m.device_class = 0;
467 m.device_class_mask = 0;
468 m.match_data = 0;
469
470 return find_device_name( & m );
471 }
472
473
474 /**
475 * Get the name associated with the device's subdevice ID.
476 */
477 const char *
pci_device_get_subdevice_name(const struct pci_device * dev)478 pci_device_get_subdevice_name( const struct pci_device * dev )
479 {
480 struct pci_id_match m;
481
482
483 if ( (dev->subvendor_id == 0) || (dev->subdevice_id == 0) ) {
484 return NULL;
485 }
486
487 m.vendor_id = dev->vendor_id;
488 m.device_id = dev->device_id;
489 m.subvendor_id = dev->subvendor_id;
490 m.subdevice_id = dev->subdevice_id;
491 m.device_class = 0;
492 m.device_class_mask = 0;
493 m.match_data = 0;
494
495 return find_device_name( & m );
496 }
497
498
499 /**
500 * Get the name associated with the device's primary vendor ID.
501 */
502 const char *
pci_device_get_vendor_name(const struct pci_device * dev)503 pci_device_get_vendor_name( const struct pci_device * dev )
504 {
505 struct pci_id_match m;
506
507
508 m.vendor_id = dev->vendor_id;
509 m.device_id = PCI_MATCH_ANY;
510 m.subvendor_id = PCI_MATCH_ANY;
511 m.subdevice_id = PCI_MATCH_ANY;
512 m.device_class = 0;
513 m.device_class_mask = 0;
514 m.match_data = 0;
515
516 return find_vendor_name( & m );
517 }
518
519
520 /**
521 * Get the name associated with the device's subvendor ID.
522 */
523 const char *
pci_device_get_subvendor_name(const struct pci_device * dev)524 pci_device_get_subvendor_name( const struct pci_device * dev )
525 {
526 struct pci_id_match m;
527
528
529 if ( dev->subvendor_id == 0 ) {
530 return NULL;
531 }
532
533
534 m.vendor_id = dev->subvendor_id;
535 m.device_id = PCI_MATCH_ANY;
536 m.subvendor_id = PCI_MATCH_ANY;
537 m.subdevice_id = PCI_MATCH_ANY;
538 m.device_class = 0;
539 m.device_class_mask = 0;
540 m.match_data = 0;
541
542 return find_vendor_name( & m );
543 }
544