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