14f5e7dd7Smrg/* 24f5e7dd7Smrg * (C) Copyright IBM Corporation 2006 34f5e7dd7Smrg * All Rights Reserved. 44f5e7dd7Smrg * 54f5e7dd7Smrg * Permission is hereby granted, free of charge, to any person obtaining a 64f5e7dd7Smrg * copy of this software and associated documentation files (the "Software"), 74f5e7dd7Smrg * to deal in the Software without restriction, including without limitation 84f5e7dd7Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 94f5e7dd7Smrg * license, and/or sell copies of the Software, and to permit persons to whom 104f5e7dd7Smrg * the Software is furnished to do so, subject to the following conditions: 114f5e7dd7Smrg * 124f5e7dd7Smrg * The above copyright notice and this permission notice (including the next 134f5e7dd7Smrg * paragraph) shall be included in all copies or substantial portions of the 144f5e7dd7Smrg * Software. 154f5e7dd7Smrg * 164f5e7dd7Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 174f5e7dd7Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 184f5e7dd7Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 194f5e7dd7Smrg * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 204f5e7dd7Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 214f5e7dd7Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 224f5e7dd7Smrg * DEALINGS IN THE SOFTWARE. 234f5e7dd7Smrg */ 244f5e7dd7Smrg 254f5e7dd7Smrg/** 264f5e7dd7Smrg * \file common_device_name.c 274f5e7dd7Smrg * Support routines used to determine the vendor or device names associated 284f5e7dd7Smrg * with a particular device or vendor. 294f5e7dd7Smrg */ 304f5e7dd7Smrg 319266c31dSmrg#ifdef HAVE_CONFIG_H 324f5e7dd7Smrg#include "config.h" 3347fd271eSmrg#endif 3447fd271eSmrg 354f5e7dd7Smrg#include <stdio.h> 364f5e7dd7Smrg#include <stdlib.h> 374f5e7dd7Smrg#include <ctype.h> 384f5e7dd7Smrg 394f5e7dd7Smrg#if defined(HAVE_STRING_H) 404f5e7dd7Smrg# include <string.h> 414f5e7dd7Smrg#elif defined(HAVE_STRINGS_H) 424f5e7dd7Smrg# include <strings.h> 434f5e7dd7Smrg#endif 444f5e7dd7Smrg 454f5e7dd7Smrg#if defined(HAVE_INTTYPES_H) 464f5e7dd7Smrg# include <inttypes.h> 474f5e7dd7Smrg#elif defined(HAVE_STDINT_H) 484f5e7dd7Smrg# include <stdint.h> 494f5e7dd7Smrg#endif 504f5e7dd7Smrg 514f5e7dd7Smrg#include "pciaccess.h" 524f5e7dd7Smrg#include "pciaccess_private.h" 534f5e7dd7Smrg 544f5e7dd7Smrg#define DO_MATCH(a,b) (((a) == PCI_MATCH_ANY) || ((a) == (b))) 554f5e7dd7Smrg 564f5e7dd7Smrg#ifdef HAVE_ZLIB 572e46f441Smrg 584f5e7dd7Smrg#include <zlib.h> 594f5e7dd7Smrgtypedef gzFile pci_id_file; 604f5e7dd7Smrg 614f5e7dd7Smrgstatic pci_id_file 6269bf0a65Smrgpci_id_file_open(void) 634f5e7dd7Smrg{ 644f5e7dd7Smrg pci_id_file result; 654f5e7dd7Smrg 664f5e7dd7Smrg result = gzopen(PCIIDS_PATH "/pci.ids.gz", "rb"); 674f5e7dd7Smrg if (result) 684f5e7dd7Smrg return result; 694f5e7dd7Smrg 704f5e7dd7Smrg return gzopen(PCIIDS_PATH "/pci.ids", "rb"); 714f5e7dd7Smrg} 724f5e7dd7Smrg 734f5e7dd7Smrg#define pci_id_file_gets(l, s, f) gzgets(f, l, s) 744f5e7dd7Smrg#define pci_id_file_close(f) gzclose(f) 752e46f441Smrg 762e46f441Smrg#else /* not zlib */ 772e46f441Smrg 782e46f441Smrgtypedef FILE * pci_id_file; 792e46f441Smrg 802e46f441Smrgstatic pci_id_file 812e46f441Smrgpci_id_file_open(void) 822e46f441Smrg{ 832e46f441Smrg pci_id_file result; 842e46f441Smrg 852e46f441Smrg result = fopen(PCIIDS_PATH "/pci.ids", "re"); 862e46f441Smrg if (result) 872e46f441Smrg return result; 88845f12d7Smrg#ifdef __FreeBSD__ 89845f12d7Smrg return fopen("/usr/share/misc/pci_vendors", "re"); 902e46f441Smrg#endif 912e46f441Smrg 922e46f441Smrg return fopen(PCIIDS_PATH "/pci.ids", "r"); 932e46f441Smrg} 942e46f441Smrg 954f5e7dd7Smrg#define pci_id_file_gets(l, s, f) fgets(l, s, f) 964f5e7dd7Smrg#define pci_id_file_close(f) fclose(f) 972e46f441Smrg 984f5e7dd7Smrg#endif 994f5e7dd7Smrg 1004f5e7dd7Smrg/** 1014f5e7dd7Smrg * Node for sorting vendor IDs. 1022e46f441Smrg * 1034f5e7dd7Smrg * Each structure forms an internal node of an n-way tree. Each node selects 1044f5e7dd7Smrg * \c pci_id_node::bits number of bits from the vendor ID. Starting from the 1054f5e7dd7Smrg * root of the tree, a slice of the low-order bits of the vendor ID are 1064f5e7dd7Smrg * selected and used as an index into the \c pci_id_node::children array. 1074f5e7dd7Smrg * 1084f5e7dd7Smrg * At the leaf nodes (i.e., the node entered when all 16 bits of the vendor ID 1094f5e7dd7Smrg * have been used), the \c pci_id_node::children is actually an array of 1104f5e7dd7Smrg * pointers to \c pci_id_leaf structures. 1112e46f441Smrg * 1124f5e7dd7Smrg * \todo 1134f5e7dd7Smrg * Determine if there is a cleaner way (in the source code) to have the 1144f5e7dd7Smrg * \c children array change type based on whether the node is internal or 1154f5e7dd7Smrg * a leaf. 1164f5e7dd7Smrg * 1174f5e7dd7Smrg * \todo 1184f5e7dd7Smrg * Currently \c bits is always 4. Decide if this value can ever change 1194f5e7dd7Smrg * (i.e., to pull-up levels of the n-way tree when all the children's children 1204f5e7dd7Smrg * are full). If it can, rip it out and hard-code it to 4 everywhere. 1214f5e7dd7Smrg */ 1224f5e7dd7Smrgstruct pci_id_node { 1234f5e7dd7Smrg unsigned bits; 1244f5e7dd7Smrg struct pci_id_node * children[16]; 1254f5e7dd7Smrg}; 1264f5e7dd7Smrg 1274f5e7dd7Smrgstruct pci_id_leaf { 1284f5e7dd7Smrg uint16_t vendor; 1294f5e7dd7Smrg const char * vendor_name; 1302e46f441Smrg 1314f5e7dd7Smrg size_t num_devices; 1324f5e7dd7Smrg struct pci_device_leaf * devices; 1334f5e7dd7Smrg}; 1344f5e7dd7Smrg 1354f5e7dd7Smrgstruct pci_device_leaf { 1364f5e7dd7Smrg struct pci_id_match id; 1374f5e7dd7Smrg const char * device_name; 1384f5e7dd7Smrg}; 1394f5e7dd7Smrg 1404f5e7dd7Smrg/** 1414f5e7dd7Smrg * Root of the PCI vendor ID search tree. 1424f5e7dd7Smrg */ 1434f5e7dd7Smrg_pci_hidden struct pci_id_node * tree = NULL; 1444f5e7dd7Smrg 1454f5e7dd7Smrg/** 1464f5e7dd7Smrg * Get a pointer to the leaf node for a vendor ID. 1472e46f441Smrg * 1484f5e7dd7Smrg * If the vendor ID does not exist in the tree, it is added. 1494f5e7dd7Smrg */ 1504f5e7dd7Smrgstatic struct pci_id_leaf * 1514f5e7dd7Smrginsert( uint16_t vendor ) 1524f5e7dd7Smrg{ 1534f5e7dd7Smrg struct pci_id_node * n; 1544f5e7dd7Smrg unsigned bits = 0; 1554f5e7dd7Smrg 1564f5e7dd7Smrg if ( tree == NULL ) { 1574f5e7dd7Smrg tree = calloc( 1, sizeof( struct pci_id_node ) ); 158814b5855Smrg 159814b5855Smrg if ( tree == NULL ) 160814b5855Smrg return NULL; 161814b5855Smrg 1624f5e7dd7Smrg tree->bits = 4; 1634f5e7dd7Smrg } 1644f5e7dd7Smrg 1654f5e7dd7Smrg n = tree; 1664f5e7dd7Smrg while ( n != NULL ) { 1674f5e7dd7Smrg const unsigned used_bits = n->bits; 1684f5e7dd7Smrg const unsigned mask = (1 << used_bits) - 1; 1694f5e7dd7Smrg const unsigned idx = (vendor & (mask << bits)) >> bits; 1704f5e7dd7Smrg 1714f5e7dd7Smrg 1724f5e7dd7Smrg if ( bits >= 16 ) { 1734f5e7dd7Smrg break; 1744f5e7dd7Smrg } 1754f5e7dd7Smrg 1764f5e7dd7Smrg bits += used_bits; 1774f5e7dd7Smrg 1784f5e7dd7Smrg if ( n->children[ idx ] == NULL ) { 1794f5e7dd7Smrg if ( bits < 16 ) { 1804f5e7dd7Smrg struct pci_id_node * child = 1814f5e7dd7Smrg calloc( 1, sizeof( struct pci_id_node ) ); 1824f5e7dd7Smrg 183814b5855Smrg if ( tree == NULL ) 184814b5855Smrg return NULL; 185814b5855Smrg 1864f5e7dd7Smrg child->bits = 4; 1874f5e7dd7Smrg 1884f5e7dd7Smrg n->children[ idx ] = child; 1894f5e7dd7Smrg } 1904f5e7dd7Smrg else { 1912e46f441Smrg struct pci_id_leaf * leaf = 1924f5e7dd7Smrg calloc( 1, sizeof( struct pci_id_leaf ) ); 1934f5e7dd7Smrg 194814b5855Smrg if ( tree == NULL ) 195814b5855Smrg return NULL; 196814b5855Smrg 1974f5e7dd7Smrg leaf->vendor = vendor; 1984f5e7dd7Smrg 1994f5e7dd7Smrg n->children[ idx ] = (struct pci_id_node *) leaf; 2004f5e7dd7Smrg } 2014f5e7dd7Smrg } 2024f5e7dd7Smrg 2034f5e7dd7Smrg n = n->children[ idx ]; 2044f5e7dd7Smrg } 2054f5e7dd7Smrg 2064f5e7dd7Smrg return (struct pci_id_leaf *) n; 2074f5e7dd7Smrg} 2084f5e7dd7Smrg 2094f5e7dd7Smrg 2104f5e7dd7Smrg/** 2114f5e7dd7Smrg * Populate a vendor node with all the devices associated with that vendor 2122e46f441Smrg * 2134f5e7dd7Smrg * \param vend Vendor node that is to be filled from the pci.ids file. 2142e46f441Smrg * 2154f5e7dd7Smrg * \todo 2164f5e7dd7Smrg * The parsing in this function should be more rhobust. There are some error 2174f5e7dd7Smrg * cases (i.e., a 0-tab line followed by a 2-tab line) that aren't handled 2184f5e7dd7Smrg * correctly. I don't think there are any security problems with the code, 2194f5e7dd7Smrg * but it's not impossible. 2204f5e7dd7Smrg */ 2214f5e7dd7Smrgstatic void 2224f5e7dd7Smrgpopulate_vendor( struct pci_id_leaf * vend, int fill_device_data ) 2234f5e7dd7Smrg{ 2242e46f441Smrg pci_id_file f; 2254f5e7dd7Smrg char buf[128]; 2264f5e7dd7Smrg unsigned vendor = PCI_MATCH_ANY; 2274f5e7dd7Smrg 2284f5e7dd7Smrg 2294f5e7dd7Smrg /* If the device tree for this vendor is already populated, don't do 2304f5e7dd7Smrg * anything. This avoids wasted processing and potential memory leaks. 2314f5e7dd7Smrg */ 2324f5e7dd7Smrg if (vend->num_devices != 0) { 2334f5e7dd7Smrg return; 2344f5e7dd7Smrg } 2354f5e7dd7Smrg 2364f5e7dd7Smrg f = pci_id_file_open(); 2372e46f441Smrg 2384f5e7dd7Smrg /* If the pci.ids file could not be opened, there's nothing we can do. 2394f5e7dd7Smrg */ 2404f5e7dd7Smrg if (f == NULL) { 2414f5e7dd7Smrg return; 2424f5e7dd7Smrg } 2434f5e7dd7Smrg 2444f5e7dd7Smrg while( pci_id_file_gets( buf, sizeof( buf ), f ) != NULL ) { 2454f5e7dd7Smrg unsigned num_tabs; 2464f5e7dd7Smrg char * new_line; 2474f5e7dd7Smrg size_t length; 2484f5e7dd7Smrg 2494f5e7dd7Smrg /* Each line either starts with zero, one, or two tabs followed by 2504f5e7dd7Smrg * a series of 4 hex digits. Any lines not matching that are ignored. 2514f5e7dd7Smrg */ 2524f5e7dd7Smrg 2534f5e7dd7Smrg for ( num_tabs = 0 ; num_tabs < 3 ; num_tabs++ ) { 2544f5e7dd7Smrg if ( buf[ num_tabs ] != '\t' ) { 2554f5e7dd7Smrg break; 2564f5e7dd7Smrg } 2574f5e7dd7Smrg } 2582e46f441Smrg 2594f5e7dd7Smrg if ( !isxdigit( buf[ num_tabs + 0 ] ) 2604f5e7dd7Smrg || !isxdigit( buf[ num_tabs + 1 ] ) 2614f5e7dd7Smrg || !isxdigit( buf[ num_tabs + 2 ] ) 2624f5e7dd7Smrg || !isxdigit( buf[ num_tabs + 3 ] ) ) { 2634f5e7dd7Smrg continue; 2644f5e7dd7Smrg } 2652e46f441Smrg 2664f5e7dd7Smrg new_line = strchr( buf, '\n' ); 2674f5e7dd7Smrg if ( new_line != NULL ) { 2684f5e7dd7Smrg *new_line = '\0'; 2694f5e7dd7Smrg } 2704f5e7dd7Smrg 2714f5e7dd7Smrg length = strlen( buf ); 2724f5e7dd7Smrg (void) memset( buf + length, 0, sizeof( buf ) - length ); 2734f5e7dd7Smrg 2744f5e7dd7Smrg 2754f5e7dd7Smrg if ( num_tabs == 0 ) { 2764f5e7dd7Smrg vendor = (unsigned) strtoul( & buf[ num_tabs ], NULL, 16 ); 2774f5e7dd7Smrg if ( vend->vendor == vendor ) { 2784f5e7dd7Smrg /* vendor_name may already be set from a previous invocation 2794f5e7dd7Smrg * of this function with fill_device_data = 0. 2804f5e7dd7Smrg */ 2814f5e7dd7Smrg if (vend->vendor_name == NULL) { 2824f5e7dd7Smrg vend->vendor_name = strdup( & buf[ num_tabs + 6 ] ); 2834f5e7dd7Smrg } 2844f5e7dd7Smrg 2854f5e7dd7Smrg /* If we're not going to fill in all of the device data as 2864f5e7dd7Smrg * well, then bail out now. We have all the information that 2874f5e7dd7Smrg * we need. 2884f5e7dd7Smrg */ 2894f5e7dd7Smrg if ( ! fill_device_data ) { 2904f5e7dd7Smrg break; 2914f5e7dd7Smrg } 2924f5e7dd7Smrg } 2934f5e7dd7Smrg } 2944f5e7dd7Smrg else if ( vendor == vend->vendor ) { 2954f5e7dd7Smrg struct pci_device_leaf * d; 2964f5e7dd7Smrg struct pci_device_leaf * dev; 2974f5e7dd7Smrg struct pci_device_leaf * last_dev; 2982e46f441Smrg 2994f5e7dd7Smrg 3004f5e7dd7Smrg 3014f5e7dd7Smrg d = realloc( vend->devices, (vend->num_devices + 1) 3024f5e7dd7Smrg * sizeof( struct pci_device_leaf ) ); 3034f5e7dd7Smrg if ( d == NULL ) { 3042e46f441Smrg goto cleanup; 3054f5e7dd7Smrg } 3064f5e7dd7Smrg 3074f5e7dd7Smrg last_dev = & d[ vend->num_devices - 1 ]; 3084f5e7dd7Smrg dev = & d[ vend->num_devices ]; 3094f5e7dd7Smrg vend->num_devices++; 3104f5e7dd7Smrg vend->devices = d; 3114f5e7dd7Smrg 3124f5e7dd7Smrg if ( num_tabs == 1 ) { 3134f5e7dd7Smrg dev->id.vendor_id = vend->vendor; 3142e46f441Smrg dev->id.device_id = (unsigned) strtoul( & buf[ num_tabs ], 3154f5e7dd7Smrg NULL, 16 ); 3164f5e7dd7Smrg dev->id.subvendor_id = PCI_MATCH_ANY; 3174f5e7dd7Smrg dev->id.subdevice_id = PCI_MATCH_ANY; 3184f5e7dd7Smrg 3194f5e7dd7Smrg dev->id.device_class = 0; 3204f5e7dd7Smrg dev->id.device_class_mask = 0; 3214f5e7dd7Smrg dev->id.match_data = 0; 3224f5e7dd7Smrg 3234f5e7dd7Smrg dev->device_name = strdup( & buf[ num_tabs + 6 ] ); 3244f5e7dd7Smrg } 3254f5e7dd7Smrg else { 3264f5e7dd7Smrg dev->id = last_dev->id; 3274f5e7dd7Smrg 3284f5e7dd7Smrg dev->id.subvendor_id= (unsigned) strtoul( & buf[ num_tabs ], 3294f5e7dd7Smrg NULL, 16 ); 3302e46f441Smrg dev->id.subdevice_id = (unsigned) strtoul( & buf[ num_tabs + 5 ], 3314f5e7dd7Smrg NULL, 16 ); 3324f5e7dd7Smrg dev->device_name = strdup( & buf[ num_tabs + 5 + 6 ] ); 3334f5e7dd7Smrg } 3344f5e7dd7Smrg } 3354f5e7dd7Smrg } 3362e46f441Smrg 3372e46f441Smrg cleanup: 3384f5e7dd7Smrg pci_id_file_close( f ); 3394f5e7dd7Smrg} 3404f5e7dd7Smrg 3414f5e7dd7Smrg 3424f5e7dd7Smrg/** 3434f5e7dd7Smrg * Find the name of the specified device. 3444f5e7dd7Smrg * 3454f5e7dd7Smrg * Finds the actual product name of the specified device. If a subvendor ID 3464f5e7dd7Smrg * and subdevice ID are specified in \c m, the returned name will be the name 3474f5e7dd7Smrg * of the subdevice. 3484f5e7dd7Smrg */ 3494f5e7dd7Smrgstatic const char * 3504f5e7dd7Smrgfind_device_name( const struct pci_id_match * m ) 3514f5e7dd7Smrg{ 3524f5e7dd7Smrg struct pci_id_leaf * vend; 3534f5e7dd7Smrg unsigned i; 3544f5e7dd7Smrg 3554f5e7dd7Smrg 3564f5e7dd7Smrg if ( m->vendor_id == PCI_MATCH_ANY ) { 3574f5e7dd7Smrg return NULL; 3584f5e7dd7Smrg } 3594f5e7dd7Smrg 3604f5e7dd7Smrg 3614f5e7dd7Smrg vend = insert( m->vendor_id ); 3624f5e7dd7Smrg if ( vend == NULL ) { 3634f5e7dd7Smrg return NULL; 3644f5e7dd7Smrg } 3654f5e7dd7Smrg 3664f5e7dd7Smrg if ( vend->num_devices == 0 ) { 3674f5e7dd7Smrg populate_vendor( vend, 1 ); 3684f5e7dd7Smrg } 3694f5e7dd7Smrg 3704f5e7dd7Smrg 3714f5e7dd7Smrg for ( i = 0 ; i < vend->num_devices ; i++ ) { 3724f5e7dd7Smrg struct pci_device_leaf * d = & vend->devices[ i ]; 3734f5e7dd7Smrg 3744f5e7dd7Smrg if ( DO_MATCH( m->vendor_id, d->id.vendor_id ) 3754f5e7dd7Smrg && DO_MATCH( m->device_id, d->id.device_id ) 3764f5e7dd7Smrg && DO_MATCH( m->subvendor_id, d->id.subvendor_id ) 3774f5e7dd7Smrg && DO_MATCH( m->subdevice_id, d->id.subdevice_id ) ) { 3784f5e7dd7Smrg return d->device_name; 3794f5e7dd7Smrg } 3804f5e7dd7Smrg } 3814f5e7dd7Smrg 3824f5e7dd7Smrg return NULL; 3834f5e7dd7Smrg} 3844f5e7dd7Smrg 3854f5e7dd7Smrg 3864f5e7dd7Smrg/** 3874f5e7dd7Smrg * Find the vendor name of the specified device. 3884f5e7dd7Smrg * 3894f5e7dd7Smrg * Finds the actual vendor name of the specified device. If a subvendor ID 3904f5e7dd7Smrg * and subdevice ID are specified in \c m, the returned name will be the name 3914f5e7dd7Smrg * associated with the subvendor. 3924f5e7dd7Smrg */ 3934f5e7dd7Smrgstatic const char * 3944f5e7dd7Smrgfind_vendor_name( const struct pci_id_match * m ) 3954f5e7dd7Smrg{ 3964f5e7dd7Smrg struct pci_id_leaf * vend; 3974f5e7dd7Smrg 3984f5e7dd7Smrg 3994f5e7dd7Smrg if ( m->vendor_id == PCI_MATCH_ANY ) { 4004f5e7dd7Smrg return NULL; 4014f5e7dd7Smrg } 4024f5e7dd7Smrg 4034f5e7dd7Smrg 4044f5e7dd7Smrg vend = insert( m->vendor_id ); 4054f5e7dd7Smrg if ( vend == NULL ) { 4064f5e7dd7Smrg return NULL; 4074f5e7dd7Smrg } 4084f5e7dd7Smrg 4094f5e7dd7Smrg if ( vend->vendor_name == NULL ) { 4104f5e7dd7Smrg populate_vendor( vend, 0 ); 4114f5e7dd7Smrg } 4124f5e7dd7Smrg 4134f5e7dd7Smrg 4144f5e7dd7Smrg return vend->vendor_name; 4154f5e7dd7Smrg} 4164f5e7dd7Smrg 4174f5e7dd7Smrg 4184f5e7dd7Smrg/** 4194f5e7dd7Smrg * Get a name based on an arbitrary PCI search structure. 4204f5e7dd7Smrg */ 4214f5e7dd7Smrgvoid 4224f5e7dd7Smrgpci_get_strings( const struct pci_id_match * m, 4234f5e7dd7Smrg const char ** device_name, 4244f5e7dd7Smrg const char ** vendor_name, 4254f5e7dd7Smrg const char ** subdevice_name, 4264f5e7dd7Smrg const char ** subvendor_name ) 4274f5e7dd7Smrg{ 4284f5e7dd7Smrg struct pci_id_match temp; 4294f5e7dd7Smrg 4304f5e7dd7Smrg 4314f5e7dd7Smrg temp = *m; 4324f5e7dd7Smrg temp.subvendor_id = PCI_MATCH_ANY; 4334f5e7dd7Smrg temp.subdevice_id = PCI_MATCH_ANY; 4344f5e7dd7Smrg 4354f5e7dd7Smrg if ( device_name != NULL ) { 4364f5e7dd7Smrg *device_name = find_device_name( & temp ); 4374f5e7dd7Smrg } 4384f5e7dd7Smrg 4394f5e7dd7Smrg if ( vendor_name != NULL ) { 4404f5e7dd7Smrg *vendor_name = find_vendor_name( & temp ); 4414f5e7dd7Smrg } 4424f5e7dd7Smrg 4434f5e7dd7Smrg if ( subdevice_name != NULL ) { 4444f5e7dd7Smrg *subdevice_name = find_device_name( m ); 4454f5e7dd7Smrg } 4464f5e7dd7Smrg 4474f5e7dd7Smrg if ( subvendor_name != NULL ) { 4484f5e7dd7Smrg *subvendor_name = find_vendor_name( m ); 4494f5e7dd7Smrg } 4504f5e7dd7Smrg} 4514f5e7dd7Smrg 4524f5e7dd7Smrg 4534f5e7dd7Smrg/** 4544f5e7dd7Smrg * Get the name associated with the device's primary device ID. 4554f5e7dd7Smrg */ 4564f5e7dd7Smrgconst char * 4574f5e7dd7Smrgpci_device_get_device_name( const struct pci_device * dev ) 4584f5e7dd7Smrg{ 4594f5e7dd7Smrg struct pci_id_match m; 4604f5e7dd7Smrg 4614f5e7dd7Smrg 4624f5e7dd7Smrg m.vendor_id = dev->vendor_id; 4634f5e7dd7Smrg m.device_id = dev->device_id; 4644f5e7dd7Smrg m.subvendor_id = PCI_MATCH_ANY; 4654f5e7dd7Smrg m.subdevice_id = PCI_MATCH_ANY; 4664f5e7dd7Smrg m.device_class = 0; 4674f5e7dd7Smrg m.device_class_mask = 0; 4684f5e7dd7Smrg m.match_data = 0; 4694f5e7dd7Smrg 4704f5e7dd7Smrg return find_device_name( & m ); 4714f5e7dd7Smrg} 4724f5e7dd7Smrg 4734f5e7dd7Smrg 4744f5e7dd7Smrg/** 4754f5e7dd7Smrg * Get the name associated with the device's subdevice ID. 4764f5e7dd7Smrg */ 4774f5e7dd7Smrgconst char * 4784f5e7dd7Smrgpci_device_get_subdevice_name( const struct pci_device * dev ) 4794f5e7dd7Smrg{ 4804f5e7dd7Smrg struct pci_id_match m; 4814f5e7dd7Smrg 4824f5e7dd7Smrg 4834f5e7dd7Smrg if ( (dev->subvendor_id == 0) || (dev->subdevice_id == 0) ) { 4844f5e7dd7Smrg return NULL; 4854f5e7dd7Smrg } 4864f5e7dd7Smrg 4874f5e7dd7Smrg m.vendor_id = dev->vendor_id; 4884f5e7dd7Smrg m.device_id = dev->device_id; 4894f5e7dd7Smrg m.subvendor_id = dev->subvendor_id; 4904f5e7dd7Smrg m.subdevice_id = dev->subdevice_id; 4914f5e7dd7Smrg m.device_class = 0; 4924f5e7dd7Smrg m.device_class_mask = 0; 4934f5e7dd7Smrg m.match_data = 0; 4944f5e7dd7Smrg 4954f5e7dd7Smrg return find_device_name( & m ); 4964f5e7dd7Smrg} 4974f5e7dd7Smrg 4984f5e7dd7Smrg 4994f5e7dd7Smrg/** 5004f5e7dd7Smrg * Get the name associated with the device's primary vendor ID. 5014f5e7dd7Smrg */ 5024f5e7dd7Smrgconst char * 5034f5e7dd7Smrgpci_device_get_vendor_name( const struct pci_device * dev ) 5044f5e7dd7Smrg{ 5054f5e7dd7Smrg struct pci_id_match m; 5064f5e7dd7Smrg 5074f5e7dd7Smrg 5084f5e7dd7Smrg m.vendor_id = dev->vendor_id; 5094f5e7dd7Smrg m.device_id = PCI_MATCH_ANY; 5104f5e7dd7Smrg m.subvendor_id = PCI_MATCH_ANY; 5114f5e7dd7Smrg m.subdevice_id = PCI_MATCH_ANY; 5124f5e7dd7Smrg m.device_class = 0; 5134f5e7dd7Smrg m.device_class_mask = 0; 5144f5e7dd7Smrg m.match_data = 0; 5154f5e7dd7Smrg 5164f5e7dd7Smrg return find_vendor_name( & m ); 5174f5e7dd7Smrg} 5184f5e7dd7Smrg 5194f5e7dd7Smrg 5204f5e7dd7Smrg/** 5214f5e7dd7Smrg * Get the name associated with the device's subvendor ID. 5224f5e7dd7Smrg */ 5234f5e7dd7Smrgconst char * 5244f5e7dd7Smrgpci_device_get_subvendor_name( const struct pci_device * dev ) 5254f5e7dd7Smrg{ 5264f5e7dd7Smrg struct pci_id_match m; 5274f5e7dd7Smrg 5284f5e7dd7Smrg 5294f5e7dd7Smrg if ( dev->subvendor_id == 0 ) { 5304f5e7dd7Smrg return NULL; 5314f5e7dd7Smrg } 5324f5e7dd7Smrg 5334f5e7dd7Smrg 5344f5e7dd7Smrg m.vendor_id = dev->subvendor_id; 5354f5e7dd7Smrg m.device_id = PCI_MATCH_ANY; 5364f5e7dd7Smrg m.subvendor_id = PCI_MATCH_ANY; 5374f5e7dd7Smrg m.subdevice_id = PCI_MATCH_ANY; 5384f5e7dd7Smrg m.device_class = 0; 5394f5e7dd7Smrg m.device_class_mask = 0; 5404f5e7dd7Smrg m.match_data = 0; 5414f5e7dd7Smrg 5424f5e7dd7Smrg return find_vendor_name( & m ); 5434f5e7dd7Smrg} 544