common_device_name.c revision 47fd271e
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 3147fd271eSmrg#if defined(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 574f5e7dd7Smrg#include <zlib.h> 584f5e7dd7Smrgtypedef gzFile pci_id_file; 594f5e7dd7Smrg 604f5e7dd7Smrgstatic pci_id_file 614f5e7dd7Smrgpci_id_file_open() 624f5e7dd7Smrg{ 634f5e7dd7Smrg pci_id_file result; 644f5e7dd7Smrg 654f5e7dd7Smrg result = gzopen(PCIIDS_PATH "/pci.ids.gz", "rb"); 664f5e7dd7Smrg if (result) 674f5e7dd7Smrg return result; 684f5e7dd7Smrg 694f5e7dd7Smrg return gzopen(PCIIDS_PATH "/pci.ids", "rb"); 704f5e7dd7Smrg} 714f5e7dd7Smrg 724f5e7dd7Smrg#define pci_id_file_gets(l, s, f) gzgets(f, l, s) 734f5e7dd7Smrg#define pci_id_file_close(f) gzclose(f) 744f5e7dd7Smrg#else 754f5e7dd7Smrgtypedef FILE pci_id_file; 764f5e7dd7Smrg#define pci_id_file_open() fopen(PCIIDS_PATH "/pci.ids", "r") 774f5e7dd7Smrg#define pci_id_file_gets(l, s, f) fgets(l, s, f) 784f5e7dd7Smrg#define pci_id_file_close(f) fclose(f) 794f5e7dd7Smrg#endif 804f5e7dd7Smrg 814f5e7dd7Smrg/** 824f5e7dd7Smrg * Node for sorting vendor IDs. 834f5e7dd7Smrg * 844f5e7dd7Smrg * Each structure forms an internal node of an n-way tree. Each node selects 854f5e7dd7Smrg * \c pci_id_node::bits number of bits from the vendor ID. Starting from the 864f5e7dd7Smrg * root of the tree, a slice of the low-order bits of the vendor ID are 874f5e7dd7Smrg * selected and used as an index into the \c pci_id_node::children array. 884f5e7dd7Smrg * 894f5e7dd7Smrg * At the leaf nodes (i.e., the node entered when all 16 bits of the vendor ID 904f5e7dd7Smrg * have been used), the \c pci_id_node::children is actually an array of 914f5e7dd7Smrg * pointers to \c pci_id_leaf structures. 924f5e7dd7Smrg * 934f5e7dd7Smrg * \todo 944f5e7dd7Smrg * Determine if there is a cleaner way (in the source code) to have the 954f5e7dd7Smrg * \c children array change type based on whether the node is internal or 964f5e7dd7Smrg * a leaf. 974f5e7dd7Smrg * 984f5e7dd7Smrg * \todo 994f5e7dd7Smrg * Currently \c bits is always 4. Decide if this value can ever change 1004f5e7dd7Smrg * (i.e., to pull-up levels of the n-way tree when all the children's children 1014f5e7dd7Smrg * are full). If it can, rip it out and hard-code it to 4 everywhere. 1024f5e7dd7Smrg */ 1034f5e7dd7Smrgstruct pci_id_node { 1044f5e7dd7Smrg unsigned bits; 1054f5e7dd7Smrg struct pci_id_node * children[16]; 1064f5e7dd7Smrg}; 1074f5e7dd7Smrg 1084f5e7dd7Smrgstruct pci_id_leaf { 1094f5e7dd7Smrg uint16_t vendor; 1104f5e7dd7Smrg const char * vendor_name; 1114f5e7dd7Smrg 1124f5e7dd7Smrg size_t num_devices; 1134f5e7dd7Smrg struct pci_device_leaf * devices; 1144f5e7dd7Smrg}; 1154f5e7dd7Smrg 1164f5e7dd7Smrgstruct pci_device_leaf { 1174f5e7dd7Smrg struct pci_id_match id; 1184f5e7dd7Smrg const char * device_name; 1194f5e7dd7Smrg}; 1204f5e7dd7Smrg 1214f5e7dd7Smrg/** 1224f5e7dd7Smrg * Root of the PCI vendor ID search tree. 1234f5e7dd7Smrg */ 1244f5e7dd7Smrg_pci_hidden struct pci_id_node * tree = NULL; 1254f5e7dd7Smrg 1264f5e7dd7Smrg/** 1274f5e7dd7Smrg * Get a pointer to the leaf node for a vendor ID. 1284f5e7dd7Smrg * 1294f5e7dd7Smrg * If the vendor ID does not exist in the tree, it is added. 1304f5e7dd7Smrg */ 1314f5e7dd7Smrgstatic struct pci_id_leaf * 1324f5e7dd7Smrginsert( uint16_t vendor ) 1334f5e7dd7Smrg{ 1344f5e7dd7Smrg struct pci_id_node * n; 1354f5e7dd7Smrg unsigned bits = 0; 1364f5e7dd7Smrg 1374f5e7dd7Smrg if ( tree == NULL ) { 1384f5e7dd7Smrg tree = calloc( 1, sizeof( struct pci_id_node ) ); 1394f5e7dd7Smrg tree->bits = 4; 1404f5e7dd7Smrg } 1414f5e7dd7Smrg 1424f5e7dd7Smrg n = tree; 1434f5e7dd7Smrg while ( n != NULL ) { 1444f5e7dd7Smrg const unsigned used_bits = n->bits; 1454f5e7dd7Smrg const unsigned mask = (1 << used_bits) - 1; 1464f5e7dd7Smrg const unsigned idx = (vendor & (mask << bits)) >> bits; 1474f5e7dd7Smrg 1484f5e7dd7Smrg 1494f5e7dd7Smrg if ( bits >= 16 ) { 1504f5e7dd7Smrg break; 1514f5e7dd7Smrg } 1524f5e7dd7Smrg 1534f5e7dd7Smrg bits += used_bits; 1544f5e7dd7Smrg 1554f5e7dd7Smrg if ( n->children[ idx ] == NULL ) { 1564f5e7dd7Smrg if ( bits < 16 ) { 1574f5e7dd7Smrg struct pci_id_node * child = 1584f5e7dd7Smrg calloc( 1, sizeof( struct pci_id_node ) ); 1594f5e7dd7Smrg 1604f5e7dd7Smrg child->bits = 4; 1614f5e7dd7Smrg 1624f5e7dd7Smrg n->children[ idx ] = child; 1634f5e7dd7Smrg } 1644f5e7dd7Smrg else { 1654f5e7dd7Smrg struct pci_id_leaf * leaf = 1664f5e7dd7Smrg calloc( 1, sizeof( struct pci_id_leaf ) ); 1674f5e7dd7Smrg 1684f5e7dd7Smrg leaf->vendor = vendor; 1694f5e7dd7Smrg 1704f5e7dd7Smrg n->children[ idx ] = (struct pci_id_node *) leaf; 1714f5e7dd7Smrg } 1724f5e7dd7Smrg } 1734f5e7dd7Smrg 1744f5e7dd7Smrg n = n->children[ idx ]; 1754f5e7dd7Smrg } 1764f5e7dd7Smrg 1774f5e7dd7Smrg return (struct pci_id_leaf *) n; 1784f5e7dd7Smrg} 1794f5e7dd7Smrg 1804f5e7dd7Smrg 1814f5e7dd7Smrg/** 1824f5e7dd7Smrg * Populate a vendor node with all the devices associated with that vendor 1834f5e7dd7Smrg * 1844f5e7dd7Smrg * \param vend Vendor node that is to be filled from the pci.ids file. 1854f5e7dd7Smrg * 1864f5e7dd7Smrg * \todo 1874f5e7dd7Smrg * The parsing in this function should be more rhobust. There are some error 1884f5e7dd7Smrg * cases (i.e., a 0-tab line followed by a 2-tab line) that aren't handled 1894f5e7dd7Smrg * correctly. I don't think there are any security problems with the code, 1904f5e7dd7Smrg * but it's not impossible. 1914f5e7dd7Smrg */ 1924f5e7dd7Smrgstatic void 1934f5e7dd7Smrgpopulate_vendor( struct pci_id_leaf * vend, int fill_device_data ) 1944f5e7dd7Smrg{ 1954f5e7dd7Smrg pci_id_file * f; 1964f5e7dd7Smrg char buf[128]; 1974f5e7dd7Smrg unsigned vendor = PCI_MATCH_ANY; 1984f5e7dd7Smrg 1994f5e7dd7Smrg 2004f5e7dd7Smrg /* If the device tree for this vendor is already populated, don't do 2014f5e7dd7Smrg * anything. This avoids wasted processing and potential memory leaks. 2024f5e7dd7Smrg */ 2034f5e7dd7Smrg if (vend->num_devices != 0) { 2044f5e7dd7Smrg return; 2054f5e7dd7Smrg } 2064f5e7dd7Smrg 2074f5e7dd7Smrg f = pci_id_file_open(); 2084f5e7dd7Smrg 2094f5e7dd7Smrg /* If the pci.ids file could not be opened, there's nothing we can do. 2104f5e7dd7Smrg */ 2114f5e7dd7Smrg if (f == NULL) { 2124f5e7dd7Smrg return; 2134f5e7dd7Smrg } 2144f5e7dd7Smrg 2154f5e7dd7Smrg while( pci_id_file_gets( buf, sizeof( buf ), f ) != NULL ) { 2164f5e7dd7Smrg unsigned num_tabs; 2174f5e7dd7Smrg char * new_line; 2184f5e7dd7Smrg size_t length; 2194f5e7dd7Smrg 2204f5e7dd7Smrg /* Each line either starts with zero, one, or two tabs followed by 2214f5e7dd7Smrg * a series of 4 hex digits. Any lines not matching that are ignored. 2224f5e7dd7Smrg */ 2234f5e7dd7Smrg 2244f5e7dd7Smrg for ( num_tabs = 0 ; num_tabs < 3 ; num_tabs++ ) { 2254f5e7dd7Smrg if ( buf[ num_tabs ] != '\t' ) { 2264f5e7dd7Smrg break; 2274f5e7dd7Smrg } 2284f5e7dd7Smrg } 2294f5e7dd7Smrg 2304f5e7dd7Smrg if ( !isxdigit( buf[ num_tabs + 0 ] ) 2314f5e7dd7Smrg || !isxdigit( buf[ num_tabs + 1 ] ) 2324f5e7dd7Smrg || !isxdigit( buf[ num_tabs + 2 ] ) 2334f5e7dd7Smrg || !isxdigit( buf[ num_tabs + 3 ] ) ) { 2344f5e7dd7Smrg continue; 2354f5e7dd7Smrg } 2364f5e7dd7Smrg 2374f5e7dd7Smrg new_line = strchr( buf, '\n' ); 2384f5e7dd7Smrg if ( new_line != NULL ) { 2394f5e7dd7Smrg *new_line = '\0'; 2404f5e7dd7Smrg } 2414f5e7dd7Smrg 2424f5e7dd7Smrg length = strlen( buf ); 2434f5e7dd7Smrg (void) memset( buf + length, 0, sizeof( buf ) - length ); 2444f5e7dd7Smrg 2454f5e7dd7Smrg 2464f5e7dd7Smrg if ( num_tabs == 0 ) { 2474f5e7dd7Smrg vendor = (unsigned) strtoul( & buf[ num_tabs ], NULL, 16 ); 2484f5e7dd7Smrg if ( vend->vendor == vendor ) { 2494f5e7dd7Smrg /* vendor_name may already be set from a previous invocation 2504f5e7dd7Smrg * of this function with fill_device_data = 0. 2514f5e7dd7Smrg */ 2524f5e7dd7Smrg if (vend->vendor_name == NULL) { 2534f5e7dd7Smrg vend->vendor_name = strdup( & buf[ num_tabs + 6 ] ); 2544f5e7dd7Smrg } 2554f5e7dd7Smrg 2564f5e7dd7Smrg /* If we're not going to fill in all of the device data as 2574f5e7dd7Smrg * well, then bail out now. We have all the information that 2584f5e7dd7Smrg * we need. 2594f5e7dd7Smrg */ 2604f5e7dd7Smrg if ( ! fill_device_data ) { 2614f5e7dd7Smrg break; 2624f5e7dd7Smrg } 2634f5e7dd7Smrg } 2644f5e7dd7Smrg } 2654f5e7dd7Smrg else if ( vendor == vend->vendor ) { 2664f5e7dd7Smrg struct pci_device_leaf * d; 2674f5e7dd7Smrg struct pci_device_leaf * dev; 2684f5e7dd7Smrg struct pci_device_leaf * last_dev; 2694f5e7dd7Smrg 2704f5e7dd7Smrg 2714f5e7dd7Smrg 2724f5e7dd7Smrg d = realloc( vend->devices, (vend->num_devices + 1) 2734f5e7dd7Smrg * sizeof( struct pci_device_leaf ) ); 2744f5e7dd7Smrg if ( d == NULL ) { 2754f5e7dd7Smrg return; 2764f5e7dd7Smrg } 2774f5e7dd7Smrg 2784f5e7dd7Smrg last_dev = & d[ vend->num_devices - 1 ]; 2794f5e7dd7Smrg dev = & d[ vend->num_devices ]; 2804f5e7dd7Smrg vend->num_devices++; 2814f5e7dd7Smrg vend->devices = d; 2824f5e7dd7Smrg 2834f5e7dd7Smrg if ( num_tabs == 1 ) { 2844f5e7dd7Smrg dev->id.vendor_id = vend->vendor; 2854f5e7dd7Smrg dev->id.device_id = (unsigned) strtoul( & buf[ num_tabs ], 2864f5e7dd7Smrg NULL, 16 ); 2874f5e7dd7Smrg dev->id.subvendor_id = PCI_MATCH_ANY; 2884f5e7dd7Smrg dev->id.subdevice_id = PCI_MATCH_ANY; 2894f5e7dd7Smrg 2904f5e7dd7Smrg dev->id.device_class = 0; 2914f5e7dd7Smrg dev->id.device_class_mask = 0; 2924f5e7dd7Smrg dev->id.match_data = 0; 2934f5e7dd7Smrg 2944f5e7dd7Smrg dev->device_name = strdup( & buf[ num_tabs + 6 ] ); 2954f5e7dd7Smrg } 2964f5e7dd7Smrg else { 2974f5e7dd7Smrg dev->id = last_dev->id; 2984f5e7dd7Smrg 2994f5e7dd7Smrg dev->id.subvendor_id= (unsigned) strtoul( & buf[ num_tabs ], 3004f5e7dd7Smrg NULL, 16 ); 3014f5e7dd7Smrg dev->id.subdevice_id = (unsigned) strtoul( & buf[ num_tabs + 5 ], 3024f5e7dd7Smrg NULL, 16 ); 3034f5e7dd7Smrg dev->device_name = strdup( & buf[ num_tabs + 5 + 6 ] ); 3044f5e7dd7Smrg } 3054f5e7dd7Smrg } 3064f5e7dd7Smrg } 3074f5e7dd7Smrg 3084f5e7dd7Smrg pci_id_file_close( f ); 3094f5e7dd7Smrg} 3104f5e7dd7Smrg 3114f5e7dd7Smrg 3124f5e7dd7Smrg/** 3134f5e7dd7Smrg * Find the name of the specified device. 3144f5e7dd7Smrg * 3154f5e7dd7Smrg * Finds the actual product name of the specified device. If a subvendor ID 3164f5e7dd7Smrg * and subdevice ID are specified in \c m, the returned name will be the name 3174f5e7dd7Smrg * of the subdevice. 3184f5e7dd7Smrg */ 3194f5e7dd7Smrgstatic const char * 3204f5e7dd7Smrgfind_device_name( const struct pci_id_match * m ) 3214f5e7dd7Smrg{ 3224f5e7dd7Smrg struct pci_id_leaf * vend; 3234f5e7dd7Smrg unsigned i; 3244f5e7dd7Smrg 3254f5e7dd7Smrg 3264f5e7dd7Smrg if ( m->vendor_id == PCI_MATCH_ANY ) { 3274f5e7dd7Smrg return NULL; 3284f5e7dd7Smrg } 3294f5e7dd7Smrg 3304f5e7dd7Smrg 3314f5e7dd7Smrg vend = insert( m->vendor_id ); 3324f5e7dd7Smrg if ( vend == NULL ) { 3334f5e7dd7Smrg return NULL; 3344f5e7dd7Smrg } 3354f5e7dd7Smrg 3364f5e7dd7Smrg if ( vend->num_devices == 0 ) { 3374f5e7dd7Smrg populate_vendor( vend, 1 ); 3384f5e7dd7Smrg } 3394f5e7dd7Smrg 3404f5e7dd7Smrg 3414f5e7dd7Smrg for ( i = 0 ; i < vend->num_devices ; i++ ) { 3424f5e7dd7Smrg struct pci_device_leaf * d = & vend->devices[ i ]; 3434f5e7dd7Smrg 3444f5e7dd7Smrg if ( DO_MATCH( m->vendor_id, d->id.vendor_id ) 3454f5e7dd7Smrg && DO_MATCH( m->device_id, d->id.device_id ) 3464f5e7dd7Smrg && DO_MATCH( m->subvendor_id, d->id.subvendor_id ) 3474f5e7dd7Smrg && DO_MATCH( m->subdevice_id, d->id.subdevice_id ) ) { 3484f5e7dd7Smrg return d->device_name; 3494f5e7dd7Smrg } 3504f5e7dd7Smrg } 3514f5e7dd7Smrg 3524f5e7dd7Smrg return NULL; 3534f5e7dd7Smrg} 3544f5e7dd7Smrg 3554f5e7dd7Smrg 3564f5e7dd7Smrg/** 3574f5e7dd7Smrg * Find the vendor name of the specified device. 3584f5e7dd7Smrg * 3594f5e7dd7Smrg * Finds the actual vendor name of the specified device. If a subvendor ID 3604f5e7dd7Smrg * and subdevice ID are specified in \c m, the returned name will be the name 3614f5e7dd7Smrg * associated with the subvendor. 3624f5e7dd7Smrg */ 3634f5e7dd7Smrgstatic const char * 3644f5e7dd7Smrgfind_vendor_name( const struct pci_id_match * m ) 3654f5e7dd7Smrg{ 3664f5e7dd7Smrg struct pci_id_leaf * vend; 3674f5e7dd7Smrg 3684f5e7dd7Smrg 3694f5e7dd7Smrg if ( m->vendor_id == PCI_MATCH_ANY ) { 3704f5e7dd7Smrg return NULL; 3714f5e7dd7Smrg } 3724f5e7dd7Smrg 3734f5e7dd7Smrg 3744f5e7dd7Smrg vend = insert( m->vendor_id ); 3754f5e7dd7Smrg if ( vend == NULL ) { 3764f5e7dd7Smrg return NULL; 3774f5e7dd7Smrg } 3784f5e7dd7Smrg 3794f5e7dd7Smrg if ( vend->vendor_name == NULL ) { 3804f5e7dd7Smrg populate_vendor( vend, 0 ); 3814f5e7dd7Smrg } 3824f5e7dd7Smrg 3834f5e7dd7Smrg 3844f5e7dd7Smrg return vend->vendor_name; 3854f5e7dd7Smrg} 3864f5e7dd7Smrg 3874f5e7dd7Smrg 3884f5e7dd7Smrg/** 3894f5e7dd7Smrg * Get a name based on an arbitrary PCI search structure. 3904f5e7dd7Smrg */ 3914f5e7dd7Smrgvoid 3924f5e7dd7Smrgpci_get_strings( const struct pci_id_match * m, 3934f5e7dd7Smrg const char ** device_name, 3944f5e7dd7Smrg const char ** vendor_name, 3954f5e7dd7Smrg const char ** subdevice_name, 3964f5e7dd7Smrg const char ** subvendor_name ) 3974f5e7dd7Smrg{ 3984f5e7dd7Smrg struct pci_id_match temp; 3994f5e7dd7Smrg 4004f5e7dd7Smrg 4014f5e7dd7Smrg temp = *m; 4024f5e7dd7Smrg temp.subvendor_id = PCI_MATCH_ANY; 4034f5e7dd7Smrg temp.subdevice_id = PCI_MATCH_ANY; 4044f5e7dd7Smrg 4054f5e7dd7Smrg if ( device_name != NULL ) { 4064f5e7dd7Smrg *device_name = find_device_name( & temp ); 4074f5e7dd7Smrg } 4084f5e7dd7Smrg 4094f5e7dd7Smrg if ( vendor_name != NULL ) { 4104f5e7dd7Smrg *vendor_name = find_vendor_name( & temp ); 4114f5e7dd7Smrg } 4124f5e7dd7Smrg 4134f5e7dd7Smrg if ( subdevice_name != NULL ) { 4144f5e7dd7Smrg *subdevice_name = find_device_name( m ); 4154f5e7dd7Smrg } 4164f5e7dd7Smrg 4174f5e7dd7Smrg if ( subvendor_name != NULL ) { 4184f5e7dd7Smrg *subvendor_name = find_vendor_name( m ); 4194f5e7dd7Smrg } 4204f5e7dd7Smrg} 4214f5e7dd7Smrg 4224f5e7dd7Smrg 4234f5e7dd7Smrg/** 4244f5e7dd7Smrg * Get the name associated with the device's primary device ID. 4254f5e7dd7Smrg */ 4264f5e7dd7Smrgconst char * 4274f5e7dd7Smrgpci_device_get_device_name( const struct pci_device * dev ) 4284f5e7dd7Smrg{ 4294f5e7dd7Smrg struct pci_id_match m; 4304f5e7dd7Smrg 4314f5e7dd7Smrg 4324f5e7dd7Smrg m.vendor_id = dev->vendor_id; 4334f5e7dd7Smrg m.device_id = dev->device_id; 4344f5e7dd7Smrg m.subvendor_id = PCI_MATCH_ANY; 4354f5e7dd7Smrg m.subdevice_id = PCI_MATCH_ANY; 4364f5e7dd7Smrg m.device_class = 0; 4374f5e7dd7Smrg m.device_class_mask = 0; 4384f5e7dd7Smrg m.match_data = 0; 4394f5e7dd7Smrg 4404f5e7dd7Smrg return find_device_name( & m ); 4414f5e7dd7Smrg} 4424f5e7dd7Smrg 4434f5e7dd7Smrg 4444f5e7dd7Smrg/** 4454f5e7dd7Smrg * Get the name associated with the device's subdevice ID. 4464f5e7dd7Smrg */ 4474f5e7dd7Smrgconst char * 4484f5e7dd7Smrgpci_device_get_subdevice_name( const struct pci_device * dev ) 4494f5e7dd7Smrg{ 4504f5e7dd7Smrg struct pci_id_match m; 4514f5e7dd7Smrg 4524f5e7dd7Smrg 4534f5e7dd7Smrg if ( (dev->subvendor_id == 0) || (dev->subdevice_id == 0) ) { 4544f5e7dd7Smrg return NULL; 4554f5e7dd7Smrg } 4564f5e7dd7Smrg 4574f5e7dd7Smrg m.vendor_id = dev->vendor_id; 4584f5e7dd7Smrg m.device_id = dev->device_id; 4594f5e7dd7Smrg m.subvendor_id = dev->subvendor_id; 4604f5e7dd7Smrg m.subdevice_id = dev->subdevice_id; 4614f5e7dd7Smrg m.device_class = 0; 4624f5e7dd7Smrg m.device_class_mask = 0; 4634f5e7dd7Smrg m.match_data = 0; 4644f5e7dd7Smrg 4654f5e7dd7Smrg return find_device_name( & m ); 4664f5e7dd7Smrg} 4674f5e7dd7Smrg 4684f5e7dd7Smrg 4694f5e7dd7Smrg/** 4704f5e7dd7Smrg * Get the name associated with the device's primary vendor ID. 4714f5e7dd7Smrg */ 4724f5e7dd7Smrgconst char * 4734f5e7dd7Smrgpci_device_get_vendor_name( const struct pci_device * dev ) 4744f5e7dd7Smrg{ 4754f5e7dd7Smrg struct pci_id_match m; 4764f5e7dd7Smrg 4774f5e7dd7Smrg 4784f5e7dd7Smrg m.vendor_id = dev->vendor_id; 4794f5e7dd7Smrg m.device_id = PCI_MATCH_ANY; 4804f5e7dd7Smrg m.subvendor_id = PCI_MATCH_ANY; 4814f5e7dd7Smrg m.subdevice_id = PCI_MATCH_ANY; 4824f5e7dd7Smrg m.device_class = 0; 4834f5e7dd7Smrg m.device_class_mask = 0; 4844f5e7dd7Smrg m.match_data = 0; 4854f5e7dd7Smrg 4864f5e7dd7Smrg return find_vendor_name( & m ); 4874f5e7dd7Smrg} 4884f5e7dd7Smrg 4894f5e7dd7Smrg 4904f5e7dd7Smrg/** 4914f5e7dd7Smrg * Get the name associated with the device's subvendor ID. 4924f5e7dd7Smrg */ 4934f5e7dd7Smrgconst char * 4944f5e7dd7Smrgpci_device_get_subvendor_name( const struct pci_device * dev ) 4954f5e7dd7Smrg{ 4964f5e7dd7Smrg struct pci_id_match m; 4974f5e7dd7Smrg 4984f5e7dd7Smrg 4994f5e7dd7Smrg if ( dev->subvendor_id == 0 ) { 5004f5e7dd7Smrg return NULL; 5014f5e7dd7Smrg } 5024f5e7dd7Smrg 5034f5e7dd7Smrg 5044f5e7dd7Smrg m.vendor_id = dev->subvendor_id; 5054f5e7dd7Smrg m.device_id = PCI_MATCH_ANY; 5064f5e7dd7Smrg m.subvendor_id = PCI_MATCH_ANY; 5074f5e7dd7Smrg m.subdevice_id = PCI_MATCH_ANY; 5084f5e7dd7Smrg m.device_class = 0; 5094f5e7dd7Smrg m.device_class_mask = 0; 5104f5e7dd7Smrg m.match_data = 0; 5114f5e7dd7Smrg 5124f5e7dd7Smrg return find_vendor_name( & m ); 5134f5e7dd7Smrg} 514