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