xref: /libpciaccess/src/common_device_name.c (revision 7a6b154a)
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