2012-10-21 06:44:29 +02:00
/*
* pci . c - PCI functions for X - Sys
* Copyright ( C ) 1997 - 1999 Martin Mares < mj @ atrey . karlin . mff . cuni . cz > [ PCI routines from lspci ]
* Copyright ( C ) 2000 Tom Rini < trini @ kernel . crashing . org > [ XorgAutoConfig pci . c , based on lspci ]
* Copyright ( C ) 2005 , 2006 Tony Vroon
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2012-12-23 20:36:54 +01:00
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
2012-10-21 06:44:29 +02:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# include <pci/pci.h>
2014-12-28 12:08:20 +01:00
# include <glib.h>
2015-02-14 19:35:02 +01:00
# include "sysinfo.h"
2012-10-21 06:44:29 +02:00
static struct pci_filter filter ; /* Device filter */
static struct pci_access * pacc ;
int bus , dev , func ; /* Location of the card */
struct device {
2015-02-14 19:35:02 +01:00
struct device * next ;
struct pci_dev * dev ;
unsigned int config_cnt ;
u8 config [ 256 ] ;
2012-10-21 06:44:29 +02:00
} ;
static struct device * first_dev ;
static struct device * scan_device ( struct pci_dev * p )
{
2015-02-14 19:35:02 +01:00
int how_much = 64 ;
struct device * d ;
if ( ! pci_filter_match ( & filter , p ) )
return NULL ;
d = g_new0 ( struct device , 1 ) ;
d - > dev = p ;
if ( ! pci_read_block ( p , 0 , d - > config , how_much ) )
exit ( 1 ) ;
if ( how_much < 128 & & ( d - > config [ PCI_HEADER_TYPE ] & 0x7f ) = = PCI_HEADER_TYPE_CARDBUS )
{
/* For cardbus bridges, we need to fetch 64 bytes more to get the full standard header... */
if ( ! pci_read_block ( p , 64 , d - > config + 64 , 64 ) )
exit ( 1 ) ;
how_much = 128 ;
}
d - > config_cnt = how_much ;
pci_setup_cache ( p , d - > config , d - > config_cnt ) ;
pci_fill_info ( p , PCI_FILL_IDENT ) ;
return d ;
2012-10-21 06:44:29 +02:00
}
static void scan_devices ( void )
{
2015-02-14 19:35:02 +01:00
struct device * d ;
struct pci_dev * p ;
pci_scan_bus ( pacc ) ;
for ( p = pacc - > devices ; p ; p = p - > next )
{
if ( ( d = scan_device ( p ) ) )
{
d - > next = first_dev ;
first_dev = d ;
}
}
2012-10-21 06:44:29 +02:00
}
static u16 get_conf_word ( struct device * d , unsigned int pos )
{
2015-02-14 19:35:02 +01:00
return d - > config [ pos ] | ( d - > config [ pos + 1 ] < < 8 ) ;
2012-10-21 06:44:29 +02:00
}
int pci_find_by_class ( u16 * class , char * vendor , char * device )
{
struct device * d ;
struct pci_dev * p ;
int nomatch = 1 ;
2017-11-18 06:14:13 +01:00
/* libpci has no way to report errors it calls exit()
* so we need to manually avoid potential failures like this one */
if ( ! g_file_test ( " /proc/bus/pci " , G_FILE_TEST_EXISTS ) )
return 1 ;
2012-10-21 06:44:29 +02:00
pacc = pci_alloc ( ) ;
pci_filter_init ( pacc , & filter ) ;
pci_init ( pacc ) ;
scan_devices ( ) ;
2015-02-14 19:35:02 +01:00
for ( d = first_dev ; d ; d = d - > next )
{
p = d - > dev ;
/* Acquire vendor & device ID if the class matches */
if ( get_conf_word ( d , PCI_CLASS_DEVICE ) = = * class )
{
nomatch = 0 ;
2014-12-18 00:49:59 +01:00
g_snprintf ( vendor , 7 , " %04x " , p - > vendor_id ) ;
g_snprintf ( device , 7 , " %04x " , p - > device_id ) ;
2015-02-14 19:35:02 +01:00
break ;
}
}
2012-10-21 06:44:29 +02:00
2015-02-14 19:35:02 +01:00
pci_cleanup ( pacc ) ;
return nomatch ;
2012-10-21 06:44:29 +02:00
}
void pci_find_fullname ( char * fullname , char * vendor , char * device )
{
2012-10-21 09:56:09 +02:00
char buffer [ bsize ] ;
char vendorname [ bsize / 2 ] = " " ;
char devicename [ bsize / 2 ] = " " ;
char * position ;
2012-10-21 06:44:29 +02:00
int cardfound = 0 ;
2014-07-19 05:36:13 +02:00
FILE * fp ;
2012-10-21 09:56:09 +02:00
2017-06-20 22:26:28 +02:00
fp = fopen ( PCIIDS_FILE , " r " ) ;
2015-02-14 19:35:02 +01:00
if ( fp = = NULL )
{
2014-12-18 00:49:59 +01:00
g_snprintf ( fullname , bsize , " %s:%s " , vendor , device ) ;
2015-02-14 19:35:02 +01:00
//sysinfo_print_error ("pci.ids file not found! You might want to adjust your pciids setting with /SYSINFO SET pciids (you can query its current value with /SYSINFO LIST).\n");
2012-10-21 06:44:29 +02:00
return ;
}
2015-02-14 19:35:02 +01:00
while ( fgets ( buffer , bsize , fp ) ! = NULL )
{
if ( ! isspace ( buffer [ 0 ] ) & & strstr ( buffer , vendor ) ! = NULL )
{
position = strstr ( buffer , vendor ) ;
position + = 6 ;
2018-09-01 22:32:37 +02:00
g_strlcpy ( vendorname , position , sizeof ( vendorname ) ) ;
2015-02-14 19:35:02 +01:00
position = strstr ( vendorname , " \n " ) ;
* ( position ) = ' \0 ' ;
2012-10-21 06:44:29 +02:00
break ;
2015-02-14 19:35:02 +01:00
}
2012-10-21 06:44:29 +02:00
}
2015-02-14 19:35:02 +01:00
while ( fgets ( buffer , bsize , fp ) ! = NULL )
{
if ( strstr ( buffer , device ) ! = NULL )
{
position = strstr ( buffer , device ) ;
position + = 6 ;
2018-09-01 22:32:37 +02:00
g_strlcpy ( devicename , position , sizeof ( devicename ) ) ;
2012-10-21 06:44:29 +02:00
position = strstr ( devicename , " ( " ) ;
if ( position = = NULL )
2015-02-14 19:35:02 +01:00
position = strstr ( devicename , " \n " ) ;
* ( position ) = ' \0 ' ;
2012-10-21 06:44:29 +02:00
cardfound = 1 ;
break ;
2015-02-14 19:35:02 +01:00
}
2012-10-21 06:44:29 +02:00
}
if ( cardfound = = 1 )
2014-12-18 00:49:59 +01:00
g_snprintf ( fullname , bsize , " %s %s " , vendorname , devicename ) ;
2012-10-21 06:44:29 +02:00
else
2017-11-18 06:14:13 +01:00
g_snprintf ( fullname , bsize , " %s:%s " , vendor , device ) ;
2012-10-21 06:44:29 +02:00
fclose ( fp ) ;
}