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