15a04522aSIan Romanick /*
25a04522aSIan Romanick * (C) Copyright IBM Corporation 2006
35a04522aSIan Romanick * All Rights Reserved.
45a04522aSIan Romanick *
55a04522aSIan Romanick * Permission is hereby granted, free of charge, to any person obtaining a
65a04522aSIan Romanick * copy of this software and associated documentation files (the "Software"),
75a04522aSIan Romanick * to deal in the Software without restriction, including without limitation
85a04522aSIan Romanick * on the rights to use, copy, modify, merge, publish, distribute, sub
95a04522aSIan Romanick * license, and/or sell copies of the Software, and to permit persons to whom
105a04522aSIan Romanick * the Software is furnished to do so, subject to the following conditions:
115a04522aSIan Romanick *
125a04522aSIan Romanick * The above copyright notice and this permission notice (including the next
135a04522aSIan Romanick * paragraph) shall be included in all copies or substantial portions of the
145a04522aSIan Romanick * Software.
155a04522aSIan Romanick *
165a04522aSIan Romanick * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
175a04522aSIan Romanick * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
185a04522aSIan Romanick * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
195a04522aSIan Romanick * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
205a04522aSIan Romanick * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
215a04522aSIan Romanick * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
225a04522aSIan Romanick * DEALINGS IN THE SOFTWARE.
235a04522aSIan Romanick */
245a04522aSIan Romanick
255a04522aSIan Romanick /**
265a04522aSIan Romanick * \file common_device_name.c
275a04522aSIan Romanick * Support routines used to determine the vendor or device names associated
285a04522aSIan Romanick * with a particular device or vendor.
295a04522aSIan Romanick */
305a04522aSIan Romanick
311a2ac5f1SChad Versace #ifndef ANDROID
325a04522aSIan Romanick #include "config.h"
331a2ac5f1SChad Versace #endif
341a2ac5f1SChad Versace
355a04522aSIan Romanick #include <stdio.h>
365a04522aSIan Romanick #include <stdlib.h>
375a04522aSIan Romanick #include <ctype.h>
385a04522aSIan Romanick
395a04522aSIan Romanick #if defined(HAVE_STRING_H)
405a04522aSIan Romanick # include <string.h>
415a04522aSIan Romanick #elif defined(HAVE_STRINGS_H)
425a04522aSIan Romanick # include <strings.h>
435a04522aSIan Romanick #endif
445a04522aSIan Romanick
455a04522aSIan Romanick #if defined(HAVE_INTTYPES_H)
465a04522aSIan Romanick # include <inttypes.h>
475a04522aSIan Romanick #elif defined(HAVE_STDINT_H)
485a04522aSIan Romanick # include <stdint.h>
495a04522aSIan Romanick #endif
505a04522aSIan Romanick
515a04522aSIan Romanick #include "pciaccess.h"
52adc46f65SJulien Cristau #include "pciaccess_private.h"
535a04522aSIan Romanick
545a04522aSIan Romanick #define DO_MATCH(a,b) (((a) == PCI_MATCH_ANY) || ((a) == (b)))
555a04522aSIan Romanick
5645015ab3SKel Modderman #ifdef HAVE_ZLIB
5745015ab3SKel Modderman #include <zlib.h>
5845015ab3SKel Modderman typedef gzFile pci_id_file;
5945015ab3SKel Modderman
6045015ab3SKel Modderman static pci_id_file
pci_id_file_open(void)6176363486SJulien Cristau pci_id_file_open(void)
6245015ab3SKel Modderman {
6345015ab3SKel Modderman pci_id_file result;
6445015ab3SKel Modderman
6545015ab3SKel Modderman result = gzopen(PCIIDS_PATH "/pci.ids.gz", "rb");
6645015ab3SKel Modderman if (result)
6745015ab3SKel Modderman return result;
6845015ab3SKel Modderman
6945015ab3SKel Modderman return gzopen(PCIIDS_PATH "/pci.ids", "rb");
7045015ab3SKel Modderman }
7145015ab3SKel Modderman
7245015ab3SKel Modderman #define pci_id_file_gets(l, s, f) gzgets(f, l, s)
7345015ab3SKel Modderman #define pci_id_file_close(f) gzclose(f)
7445015ab3SKel Modderman #else
7545015ab3SKel Modderman typedef FILE pci_id_file;
7645015ab3SKel Modderman #define pci_id_file_open() fopen(PCIIDS_PATH "/pci.ids", "r")
7745015ab3SKel Modderman #define pci_id_file_gets(l, s, f) fgets(l, s, f)
7845015ab3SKel Modderman #define pci_id_file_close(f) fclose(f)
7945015ab3SKel Modderman #endif
8045015ab3SKel Modderman
815a04522aSIan Romanick /**
825a04522aSIan Romanick * Node for sorting vendor IDs.
835a04522aSIan Romanick *
845a04522aSIan Romanick * Each structure forms an internal node of an n-way tree. Each node selects
855a04522aSIan Romanick * \c pci_id_node::bits number of bits from the vendor ID. Starting from the
865a04522aSIan Romanick * root of the tree, a slice of the low-order bits of the vendor ID are
875a04522aSIan Romanick * selected and used as an index into the \c pci_id_node::children array.
885a04522aSIan Romanick *
895a04522aSIan Romanick * At the leaf nodes (i.e., the node entered when all 16 bits of the vendor ID
905a04522aSIan Romanick * have been used), the \c pci_id_node::children is actually an array of
915a04522aSIan Romanick * pointers to \c pci_id_leaf structures.
925a04522aSIan Romanick *
935a04522aSIan Romanick * \todo
945a04522aSIan Romanick * Determine if there is a cleaner way (in the source code) to have the
955a04522aSIan Romanick * \c children array change type based on whether the node is internal or
965a04522aSIan Romanick * a leaf.
975a04522aSIan Romanick *
985a04522aSIan Romanick * \todo
995a04522aSIan Romanick * Currently \c bits is always 4. Decide if this value can ever change
1005a04522aSIan Romanick * (i.e., to pull-up levels of the n-way tree when all the children's children
1015a04522aSIan Romanick * are full). If it can, rip it out and hard-code it to 4 everywhere.
1025a04522aSIan Romanick */
1035a04522aSIan Romanick struct pci_id_node {
1045a04522aSIan Romanick unsigned bits;
1055a04522aSIan Romanick struct pci_id_node * children[16];
1065a04522aSIan Romanick };
1075a04522aSIan Romanick
1085a04522aSIan Romanick struct pci_id_leaf {
1095a04522aSIan Romanick uint16_t vendor;
1105a04522aSIan Romanick const char * vendor_name;
1115a04522aSIan Romanick
1125a04522aSIan Romanick size_t num_devices;
1135a04522aSIan Romanick struct pci_device_leaf * devices;
1145a04522aSIan Romanick };
1155a04522aSIan Romanick
1165a04522aSIan Romanick struct pci_device_leaf {
1175a04522aSIan Romanick struct pci_id_match id;
1185a04522aSIan Romanick const char * device_name;
1195a04522aSIan Romanick };
1205a04522aSIan Romanick
1215a04522aSIan Romanick /**
1225a04522aSIan Romanick * Root of the PCI vendor ID search tree.
1235a04522aSIan Romanick */
124adc46f65SJulien Cristau _pci_hidden struct pci_id_node * tree = NULL;
1255a04522aSIan Romanick
1265a04522aSIan Romanick /**
1275a04522aSIan Romanick * Get a pointer to the leaf node for a vendor ID.
1285a04522aSIan Romanick *
1295a04522aSIan Romanick * If the vendor ID does not exist in the tree, it is added.
1305a04522aSIan Romanick */
1315a04522aSIan Romanick static struct pci_id_leaf *
insert(uint16_t vendor)1325a04522aSIan Romanick insert( uint16_t vendor )
1335a04522aSIan Romanick {
1345a04522aSIan Romanick struct pci_id_node * n;
1355a04522aSIan Romanick unsigned bits = 0;
1365a04522aSIan Romanick
1375a04522aSIan Romanick if ( tree == NULL ) {
1385a04522aSIan Romanick tree = calloc( 1, sizeof( struct pci_id_node ) );
139790e93c3Sarsharma
140790e93c3Sarsharma if ( tree == NULL )
141790e93c3Sarsharma return NULL;
142790e93c3Sarsharma
1435a04522aSIan Romanick tree->bits = 4;
1445a04522aSIan Romanick }
1455a04522aSIan Romanick
1465a04522aSIan Romanick n = tree;
1475a04522aSIan Romanick while ( n != NULL ) {
1485a04522aSIan Romanick const unsigned used_bits = n->bits;
1495a04522aSIan Romanick const unsigned mask = (1 << used_bits) - 1;
1505a04522aSIan Romanick const unsigned idx = (vendor & (mask << bits)) >> bits;
1515a04522aSIan Romanick
1525a04522aSIan Romanick
1535a04522aSIan Romanick if ( bits >= 16 ) {
1545a04522aSIan Romanick break;
1555a04522aSIan Romanick }
1565a04522aSIan Romanick
1575a04522aSIan Romanick bits += used_bits;
1585a04522aSIan Romanick
1595a04522aSIan Romanick if ( n->children[ idx ] == NULL ) {
1605a04522aSIan Romanick if ( bits < 16 ) {
1615a04522aSIan Romanick struct pci_id_node * child =
1625a04522aSIan Romanick calloc( 1, sizeof( struct pci_id_node ) );
1635a04522aSIan Romanick
164790e93c3Sarsharma if ( child == NULL )
165790e93c3Sarsharma return NULL;
166790e93c3Sarsharma
1675a04522aSIan Romanick child->bits = 4;
1685a04522aSIan Romanick
1695a04522aSIan Romanick n->children[ idx ] = child;
1705a04522aSIan Romanick }
1715a04522aSIan Romanick else {
1725a04522aSIan Romanick struct pci_id_leaf * leaf =
1735a04522aSIan Romanick calloc( 1, sizeof( struct pci_id_leaf ) );
1745a04522aSIan Romanick
175790e93c3Sarsharma if ( leaf == NULL )
176790e93c3Sarsharma return NULL;
177790e93c3Sarsharma
1785a04522aSIan Romanick leaf->vendor = vendor;
1795a04522aSIan Romanick
1805a04522aSIan Romanick n->children[ idx ] = (struct pci_id_node *) leaf;
1815a04522aSIan Romanick }
1825a04522aSIan Romanick }
1835a04522aSIan Romanick
1845a04522aSIan Romanick n = n->children[ idx ];
1855a04522aSIan Romanick }
1865a04522aSIan Romanick
1875a04522aSIan Romanick return (struct pci_id_leaf *) n;
1885a04522aSIan Romanick }
1895a04522aSIan Romanick
1905a04522aSIan Romanick
1915a04522aSIan Romanick /**
1925a04522aSIan Romanick * Populate a vendor node with all the devices associated with that vendor
1935a04522aSIan Romanick *
1945a04522aSIan Romanick * \param vend Vendor node that is to be filled from the pci.ids file.
1955a04522aSIan Romanick *
1965a04522aSIan Romanick * \todo
1975a04522aSIan Romanick * The parsing in this function should be more rhobust. There are some error
1985a04522aSIan Romanick * cases (i.e., a 0-tab line followed by a 2-tab line) that aren't handled
1995a04522aSIan Romanick * correctly. I don't think there are any security problems with the code,
2005a04522aSIan Romanick * but it's not impossible.
2015a04522aSIan Romanick */
2025a04522aSIan Romanick static void
populate_vendor(struct pci_id_leaf * vend,int fill_device_data)2035a04522aSIan Romanick populate_vendor( struct pci_id_leaf * vend, int fill_device_data )
2045a04522aSIan Romanick {
2050821f3b4SAlan Coopersmith pci_id_file * f;
2065a04522aSIan Romanick char buf[128];
2075a04522aSIan Romanick unsigned vendor = PCI_MATCH_ANY;
2085a04522aSIan Romanick
2095a04522aSIan Romanick
210d05da652SIan Romanick /* If the device tree for this vendor is already populated, don't do
211d05da652SIan Romanick * anything. This avoids wasted processing and potential memory leaks.
212d05da652SIan Romanick */
213d05da652SIan Romanick if (vend->num_devices != 0) {
214d05da652SIan Romanick return;
215d05da652SIan Romanick }
216d05da652SIan Romanick
2170821f3b4SAlan Coopersmith f = pci_id_file_open();
2180821f3b4SAlan Coopersmith
2190821f3b4SAlan Coopersmith /* If the pci.ids file could not be opened, there's nothing we can do.
2200821f3b4SAlan Coopersmith */
2210821f3b4SAlan Coopersmith if (f == NULL) {
2220821f3b4SAlan Coopersmith return;
2230821f3b4SAlan Coopersmith }
224d05da652SIan Romanick
22545015ab3SKel Modderman while( pci_id_file_gets( buf, sizeof( buf ), f ) != NULL ) {
2265a04522aSIan Romanick unsigned num_tabs;
2275a04522aSIan Romanick char * new_line;
2285a04522aSIan Romanick size_t length;
2295a04522aSIan Romanick
2305a04522aSIan Romanick /* Each line either starts with zero, one, or two tabs followed by
2315a04522aSIan Romanick * a series of 4 hex digits. Any lines not matching that are ignored.
2325a04522aSIan Romanick */
2335a04522aSIan Romanick
2345a04522aSIan Romanick for ( num_tabs = 0 ; num_tabs < 3 ; num_tabs++ ) {
2355a04522aSIan Romanick if ( buf[ num_tabs ] != '\t' ) {
2365a04522aSIan Romanick break;
2375a04522aSIan Romanick }
2385a04522aSIan Romanick }
2395a04522aSIan Romanick
2405a04522aSIan Romanick if ( !isxdigit( buf[ num_tabs + 0 ] )
2415a04522aSIan Romanick || !isxdigit( buf[ num_tabs + 1 ] )
2425a04522aSIan Romanick || !isxdigit( buf[ num_tabs + 2 ] )
2435a04522aSIan Romanick || !isxdigit( buf[ num_tabs + 3 ] ) ) {
2445a04522aSIan Romanick continue;
2455a04522aSIan Romanick }
2465a04522aSIan Romanick
2475a04522aSIan Romanick new_line = strchr( buf, '\n' );
2485a04522aSIan Romanick if ( new_line != NULL ) {
2495a04522aSIan Romanick *new_line = '\0';
2505a04522aSIan Romanick }
2515a04522aSIan Romanick
2525a04522aSIan Romanick length = strlen( buf );
2535a04522aSIan Romanick (void) memset( buf + length, 0, sizeof( buf ) - length );
2545a04522aSIan Romanick
2555a04522aSIan Romanick
2565a04522aSIan Romanick if ( num_tabs == 0 ) {
2575a04522aSIan Romanick vendor = (unsigned) strtoul( & buf[ num_tabs ], NULL, 16 );
2585a04522aSIan Romanick if ( vend->vendor == vendor ) {
259d05da652SIan Romanick /* vendor_name may already be set from a previous invocation
260d05da652SIan Romanick * of this function with fill_device_data = 0.
261d05da652SIan Romanick */
2620ac748d0SDoug Chapman if (vend->vendor_name == NULL) {
2635a04522aSIan Romanick vend->vendor_name = strdup( & buf[ num_tabs + 6 ] );
264d05da652SIan Romanick }
2655a04522aSIan Romanick
2665a04522aSIan Romanick /* If we're not going to fill in all of the device data as
2675a04522aSIan Romanick * well, then bail out now. We have all the information that
2685a04522aSIan Romanick * we need.
2695a04522aSIan Romanick */
2705a04522aSIan Romanick if ( ! fill_device_data ) {
2715a04522aSIan Romanick break;
2725a04522aSIan Romanick }
2735a04522aSIan Romanick }
2745a04522aSIan Romanick }
2755a04522aSIan Romanick else if ( vendor == vend->vendor ) {
2765a04522aSIan Romanick struct pci_device_leaf * d;
2775a04522aSIan Romanick struct pci_device_leaf * dev;
2785a04522aSIan Romanick struct pci_device_leaf * last_dev;
2795a04522aSIan Romanick
2805a04522aSIan Romanick
2815a04522aSIan Romanick
2825a04522aSIan Romanick d = realloc( vend->devices, (vend->num_devices + 1)
2835a04522aSIan Romanick * sizeof( struct pci_device_leaf ) );
2845a04522aSIan Romanick if ( d == NULL ) {
285*7a6b154aSxianju6x goto cleanup;
2865a04522aSIan Romanick }
2875a04522aSIan Romanick
2885a04522aSIan Romanick last_dev = & d[ vend->num_devices - 1 ];
2895a04522aSIan Romanick dev = & d[ vend->num_devices ];
2905a04522aSIan Romanick vend->num_devices++;
2915a04522aSIan Romanick vend->devices = d;
2925a04522aSIan Romanick
2935a04522aSIan Romanick if ( num_tabs == 1 ) {
2945a04522aSIan Romanick dev->id.vendor_id = vend->vendor;
2955a04522aSIan Romanick dev->id.device_id = (unsigned) strtoul( & buf[ num_tabs ],
2965a04522aSIan Romanick NULL, 16 );
2975a04522aSIan Romanick dev->id.subvendor_id = PCI_MATCH_ANY;
2985a04522aSIan Romanick dev->id.subdevice_id = PCI_MATCH_ANY;
2995a04522aSIan Romanick
3005a04522aSIan Romanick dev->id.device_class = 0;
3015a04522aSIan Romanick dev->id.device_class_mask = 0;
3025a04522aSIan Romanick dev->id.match_data = 0;
3035a04522aSIan Romanick
3045a04522aSIan Romanick dev->device_name = strdup( & buf[ num_tabs + 6 ] );
3055a04522aSIan Romanick }
3065a04522aSIan Romanick else {
3075a04522aSIan Romanick dev->id = last_dev->id;
3085a04522aSIan Romanick
3095a04522aSIan Romanick dev->id.subvendor_id= (unsigned) strtoul( & buf[ num_tabs ],
3105a04522aSIan Romanick NULL, 16 );
3115a04522aSIan Romanick dev->id.subdevice_id = (unsigned) strtoul( & buf[ num_tabs + 5 ],
3125a04522aSIan Romanick NULL, 16 );
3135a04522aSIan Romanick dev->device_name = strdup( & buf[ num_tabs + 5 + 6 ] );
3145a04522aSIan Romanick }
3155a04522aSIan Romanick }
3165a04522aSIan Romanick }
317*7a6b154aSxianju6x cleanup:
31845015ab3SKel Modderman pci_id_file_close( f );
3195a04522aSIan Romanick }
3205a04522aSIan Romanick
3215a04522aSIan Romanick
32227f0ffcaSIan Romanick /**
32327f0ffcaSIan Romanick * Find the name of the specified device.
32427f0ffcaSIan Romanick *
32527f0ffcaSIan Romanick * Finds the actual product name of the specified device. If a subvendor ID
32627f0ffcaSIan Romanick * and subdevice ID are specified in \c m, the returned name will be the name
32727f0ffcaSIan Romanick * of the subdevice.
32827f0ffcaSIan Romanick */
3295a04522aSIan Romanick static const char *
find_device_name(const struct pci_id_match * m)3305a04522aSIan Romanick find_device_name( const struct pci_id_match * m )
3315a04522aSIan Romanick {
3325a04522aSIan Romanick struct pci_id_leaf * vend;
3335a04522aSIan Romanick unsigned i;
3345a04522aSIan Romanick
3355a04522aSIan Romanick
3365a04522aSIan Romanick if ( m->vendor_id == PCI_MATCH_ANY ) {
3375a04522aSIan Romanick return NULL;
3385a04522aSIan Romanick }
3395a04522aSIan Romanick
3405a04522aSIan Romanick
3415a04522aSIan Romanick vend = insert( m->vendor_id );
3425a04522aSIan Romanick if ( vend == NULL ) {
3435a04522aSIan Romanick return NULL;
3445a04522aSIan Romanick }
3455a04522aSIan Romanick
3465a04522aSIan Romanick if ( vend->num_devices == 0 ) {
3475a04522aSIan Romanick populate_vendor( vend, 1 );
3485a04522aSIan Romanick }
3495a04522aSIan Romanick
3505a04522aSIan Romanick
3515a04522aSIan Romanick for ( i = 0 ; i < vend->num_devices ; i++ ) {
3525a04522aSIan Romanick struct pci_device_leaf * d = & vend->devices[ i ];
3535a04522aSIan Romanick
3545a04522aSIan Romanick if ( DO_MATCH( m->vendor_id, d->id.vendor_id )
3555a04522aSIan Romanick && DO_MATCH( m->device_id, d->id.device_id )
3565a04522aSIan Romanick && DO_MATCH( m->subvendor_id, d->id.subvendor_id )
3575a04522aSIan Romanick && DO_MATCH( m->subdevice_id, d->id.subdevice_id ) ) {
3585a04522aSIan Romanick return d->device_name;
3595a04522aSIan Romanick }
3605a04522aSIan Romanick }
3615a04522aSIan Romanick
3625a04522aSIan Romanick return NULL;
3635a04522aSIan Romanick }
3645a04522aSIan Romanick
3655a04522aSIan Romanick
36627f0ffcaSIan Romanick /**
36727f0ffcaSIan Romanick * Find the vendor name of the specified device.
36827f0ffcaSIan Romanick *
36927f0ffcaSIan Romanick * Finds the actual vendor name of the specified device. If a subvendor ID
37027f0ffcaSIan Romanick * and subdevice ID are specified in \c m, the returned name will be the name
37127f0ffcaSIan Romanick * associated with the subvendor.
37227f0ffcaSIan Romanick */
3735a04522aSIan Romanick static const char *
find_vendor_name(const struct pci_id_match * m)3745a04522aSIan Romanick find_vendor_name( const struct pci_id_match * m )
3755a04522aSIan Romanick {
3765a04522aSIan Romanick struct pci_id_leaf * vend;
3775a04522aSIan Romanick
3785a04522aSIan Romanick
3795a04522aSIan Romanick if ( m->vendor_id == PCI_MATCH_ANY ) {
3805a04522aSIan Romanick return NULL;
3815a04522aSIan Romanick }
3825a04522aSIan Romanick
3835a04522aSIan Romanick
3845a04522aSIan Romanick vend = insert( m->vendor_id );
3855a04522aSIan Romanick if ( vend == NULL ) {
3865a04522aSIan Romanick return NULL;
3875a04522aSIan Romanick }
3885a04522aSIan Romanick
3895a04522aSIan Romanick if ( vend->vendor_name == NULL ) {
3905a04522aSIan Romanick populate_vendor( vend, 0 );
3915a04522aSIan Romanick }
3925a04522aSIan Romanick
3935a04522aSIan Romanick
3945a04522aSIan Romanick return vend->vendor_name;
3955a04522aSIan Romanick }
3965a04522aSIan Romanick
3975a04522aSIan Romanick
3985a04522aSIan Romanick /**
3995a04522aSIan Romanick * Get a name based on an arbitrary PCI search structure.
4005a04522aSIan Romanick */
4015b4db5c3SIan Romanick void
pci_get_strings(const struct pci_id_match * m,const char ** device_name,const char ** vendor_name,const char ** subdevice_name,const char ** subvendor_name)4025b4db5c3SIan Romanick pci_get_strings( const struct pci_id_match * m,
4035b4db5c3SIan Romanick const char ** device_name,
4045b4db5c3SIan Romanick const char ** vendor_name,
4055b4db5c3SIan Romanick const char ** subdevice_name,
4065b4db5c3SIan Romanick const char ** subvendor_name )
4075a04522aSIan Romanick {
4085b4db5c3SIan Romanick struct pci_id_match temp;
4095b4db5c3SIan Romanick
4105b4db5c3SIan Romanick
4115b4db5c3SIan Romanick temp = *m;
4125b4db5c3SIan Romanick temp.subvendor_id = PCI_MATCH_ANY;
4135b4db5c3SIan Romanick temp.subdevice_id = PCI_MATCH_ANY;
4145b4db5c3SIan Romanick
4155b4db5c3SIan Romanick if ( device_name != NULL ) {
4165b4db5c3SIan Romanick *device_name = find_device_name( & temp );
4175b4db5c3SIan Romanick }
4185b4db5c3SIan Romanick
4195b4db5c3SIan Romanick if ( vendor_name != NULL ) {
4205b4db5c3SIan Romanick *vendor_name = find_vendor_name( & temp );
4215b4db5c3SIan Romanick }
4225b4db5c3SIan Romanick
4235b4db5c3SIan Romanick if ( subdevice_name != NULL ) {
4245b4db5c3SIan Romanick *subdevice_name = find_device_name( m );
4255b4db5c3SIan Romanick }
4265b4db5c3SIan Romanick
4275b4db5c3SIan Romanick if ( subvendor_name != NULL ) {
4285b4db5c3SIan Romanick *subvendor_name = find_vendor_name( m );
4295b4db5c3SIan Romanick }
4305a04522aSIan Romanick }
4315a04522aSIan Romanick
4325a04522aSIan Romanick
4335a04522aSIan Romanick /**
4345a04522aSIan Romanick * Get the name associated with the device's primary device ID.
4355a04522aSIan Romanick */
4365a04522aSIan Romanick const char *
pci_device_get_device_name(const struct pci_device * dev)4375a04522aSIan Romanick pci_device_get_device_name( const struct pci_device * dev )
4385a04522aSIan Romanick {
4395a04522aSIan Romanick struct pci_id_match m;
4405a04522aSIan Romanick
4415a04522aSIan Romanick
4425a04522aSIan Romanick m.vendor_id = dev->vendor_id;
4435a04522aSIan Romanick m.device_id = dev->device_id;
4445a04522aSIan Romanick m.subvendor_id = PCI_MATCH_ANY;
4455a04522aSIan Romanick m.subdevice_id = PCI_MATCH_ANY;
4465a04522aSIan Romanick m.device_class = 0;
4475a04522aSIan Romanick m.device_class_mask = 0;
4485a04522aSIan Romanick m.match_data = 0;
4495a04522aSIan Romanick
4505a04522aSIan Romanick return find_device_name( & m );
4515a04522aSIan Romanick }
4525a04522aSIan Romanick
4535a04522aSIan Romanick
4545a04522aSIan Romanick /**
4555a04522aSIan Romanick * Get the name associated with the device's subdevice ID.
4565a04522aSIan Romanick */
4575a04522aSIan Romanick const char *
pci_device_get_subdevice_name(const struct pci_device * dev)4585a04522aSIan Romanick pci_device_get_subdevice_name( const struct pci_device * dev )
4595a04522aSIan Romanick {
4605a04522aSIan Romanick struct pci_id_match m;
4615a04522aSIan Romanick
4625a04522aSIan Romanick
4635a04522aSIan Romanick if ( (dev->subvendor_id == 0) || (dev->subdevice_id == 0) ) {
4645a04522aSIan Romanick return NULL;
4655a04522aSIan Romanick }
4665a04522aSIan Romanick
4675a04522aSIan Romanick m.vendor_id = dev->vendor_id;
4685a04522aSIan Romanick m.device_id = dev->device_id;
4695a04522aSIan Romanick m.subvendor_id = dev->subvendor_id;
4705a04522aSIan Romanick m.subdevice_id = dev->subdevice_id;
4715a04522aSIan Romanick m.device_class = 0;
4725a04522aSIan Romanick m.device_class_mask = 0;
4735a04522aSIan Romanick m.match_data = 0;
4745a04522aSIan Romanick
4755a04522aSIan Romanick return find_device_name( & m );
4765a04522aSIan Romanick }
4775a04522aSIan Romanick
4785a04522aSIan Romanick
4795a04522aSIan Romanick /**
4805a04522aSIan Romanick * Get the name associated with the device's primary vendor ID.
4815a04522aSIan Romanick */
4825a04522aSIan Romanick const char *
pci_device_get_vendor_name(const struct pci_device * dev)4835a04522aSIan Romanick pci_device_get_vendor_name( const struct pci_device * dev )
4845a04522aSIan Romanick {
4855a04522aSIan Romanick struct pci_id_match m;
4865a04522aSIan Romanick
4875a04522aSIan Romanick
4885a04522aSIan Romanick m.vendor_id = dev->vendor_id;
4895a04522aSIan Romanick m.device_id = PCI_MATCH_ANY;
4905a04522aSIan Romanick m.subvendor_id = PCI_MATCH_ANY;
4915a04522aSIan Romanick m.subdevice_id = PCI_MATCH_ANY;
4925a04522aSIan Romanick m.device_class = 0;
4935a04522aSIan Romanick m.device_class_mask = 0;
4945a04522aSIan Romanick m.match_data = 0;
4955a04522aSIan Romanick
4965a04522aSIan Romanick return find_vendor_name( & m );
4975a04522aSIan Romanick }
4985a04522aSIan Romanick
4995a04522aSIan Romanick
5005a04522aSIan Romanick /**
5015a04522aSIan Romanick * Get the name associated with the device's subvendor ID.
5025a04522aSIan Romanick */
5035a04522aSIan Romanick const char *
pci_device_get_subvendor_name(const struct pci_device * dev)5045a04522aSIan Romanick pci_device_get_subvendor_name( const struct pci_device * dev )
5055a04522aSIan Romanick {
5065a04522aSIan Romanick struct pci_id_match m;
5075a04522aSIan Romanick
5085a04522aSIan Romanick
5095a04522aSIan Romanick if ( dev->subvendor_id == 0 ) {
5105a04522aSIan Romanick return NULL;
5115a04522aSIan Romanick }
5125a04522aSIan Romanick
5135a04522aSIan Romanick
5145a04522aSIan Romanick m.vendor_id = dev->subvendor_id;
5155a04522aSIan Romanick m.device_id = PCI_MATCH_ANY;
5165a04522aSIan Romanick m.subvendor_id = PCI_MATCH_ANY;
5175a04522aSIan Romanick m.subdevice_id = PCI_MATCH_ANY;
5185a04522aSIan Romanick m.device_class = 0;
5195a04522aSIan Romanick m.device_class_mask = 0;
5205a04522aSIan Romanick m.match_data = 0;
5215a04522aSIan Romanick
5225a04522aSIan Romanick return find_vendor_name( & m );
5235a04522aSIan Romanick }
524