common_device_name.c revision 845f12d7
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