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> 59typedef gzFile pci_id_file; 60 61static pci_id_file 62pci_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 78typedef FILE * pci_id_file; 79 80static pci_id_file 81pci_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 */ 122struct pci_id_node { 123 unsigned bits; 124 struct pci_id_node * children[16]; 125}; 126 127struct 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 135struct 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 */ 150static struct pci_id_leaf * 151insert( 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 */ 221static void 222populate_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 */ 349static const char * 350find_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 */ 393static const char * 394find_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 */ 421void 422pci_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 */ 456const char * 457pci_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 */ 477const char * 478pci_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 */ 502const char * 503pci_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 */ 523const char * 524pci_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