2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/module.h>
# include "pci.h"
int pci_hotplug ( struct device * dev , char * * envp , int num_envp ,
char * buffer , int buffer_size )
{
struct pci_dev * pdev ;
char * scratch ;
int i = 0 ;
int length = 0 ;
if ( ! dev )
return - ENODEV ;
pdev = to_pci_dev ( dev ) ;
if ( ! pdev )
return - ENODEV ;
scratch = buffer ;
/* stuff we want to pass to /sbin/hotplug */
envp [ i + + ] = scratch ;
length + = scnprintf ( scratch , buffer_size - length , " PCI_CLASS=%04X " ,
pdev - > class ) ;
if ( ( buffer_size - length < = 0 ) | | ( i > = num_envp ) )
return - ENOMEM ;
+ + length ;
scratch + = length ;
envp [ i + + ] = scratch ;
length + = scnprintf ( scratch , buffer_size - length , " PCI_ID=%04X:%04X " ,
pdev - > vendor , pdev - > device ) ;
if ( ( buffer_size - length < = 0 ) | | ( i > = num_envp ) )
return - ENOMEM ;
+ + length ;
scratch + = length ;
envp [ i + + ] = scratch ;
length + = scnprintf ( scratch , buffer_size - length ,
" PCI_SUBSYS_ID=%04X:%04X " , pdev - > subsystem_vendor ,
pdev - > subsystem_device ) ;
if ( ( buffer_size - length < = 0 ) | | ( i > = num_envp ) )
return - ENOMEM ;
+ + length ;
scratch + = length ;
envp [ i + + ] = scratch ;
length + = scnprintf ( scratch , buffer_size - length , " PCI_SLOT_NAME=%s " ,
pci_name ( pdev ) ) ;
if ( ( buffer_size - length < = 0 ) | | ( i > = num_envp ) )
return - ENOMEM ;
envp [ i ] = NULL ;
return 0 ;
}
static int pci_visit_bus ( struct pci_visit * fn , struct pci_bus_wrapped * wrapped_bus , struct pci_dev_wrapped * wrapped_parent )
{
struct list_head * ln ;
struct pci_dev * dev ;
struct pci_dev_wrapped wrapped_dev ;
int result = 0 ;
pr_debug ( " PCI: Scanning bus %04x:%02x \n " , pci_domain_nr ( wrapped_bus - > bus ) ,
wrapped_bus - > bus - > number ) ;
if ( fn - > pre_visit_pci_bus ) {
result = fn - > pre_visit_pci_bus ( wrapped_bus , wrapped_parent ) ;
if ( result )
return result ;
}
ln = wrapped_bus - > bus - > devices . next ;
while ( ln ! = & wrapped_bus - > bus - > devices ) {
dev = pci_dev_b ( ln ) ;
ln = ln - > next ;
memset ( & wrapped_dev , 0 , sizeof ( struct pci_dev_wrapped ) ) ;
wrapped_dev . dev = dev ;
result = pci_visit_dev ( fn , & wrapped_dev , wrapped_bus ) ;
if ( result )
return result ;
}
if ( fn - > post_visit_pci_bus )
result = fn - > post_visit_pci_bus ( wrapped_bus , wrapped_parent ) ;
return result ;
}
static int pci_visit_bridge ( struct pci_visit * fn ,
struct pci_dev_wrapped * wrapped_dev ,
struct pci_bus_wrapped * wrapped_parent )
{
struct pci_bus * bus ;
struct pci_bus_wrapped wrapped_bus ;
int result = 0 ;
pr_debug ( " PCI: Scanning bridge %s \n " , pci_name ( wrapped_dev - > dev ) ) ;
if ( fn - > visit_pci_dev ) {
result = fn - > visit_pci_dev ( wrapped_dev , wrapped_parent ) ;
if ( result )
return result ;
}
bus = wrapped_dev - > dev - > subordinate ;
if ( bus ) {
memset ( & wrapped_bus , 0 , sizeof ( struct pci_bus_wrapped ) ) ;
wrapped_bus . bus = bus ;
result = pci_visit_bus ( fn , & wrapped_bus , wrapped_dev ) ;
}
return result ;
}
/**
* pci_visit_dev - scans the pci buses .
2005-05-01 19:59:26 +04:00
* @ fn : callback functions that are called while visiting
* @ wrapped_dev : the device to scan
* @ wrapped_parent : the bus where @ wrapped_dev is connected to
*
2005-04-17 02:20:36 +04:00
* Every bus and every function is presented to a custom
* function that can act upon it .
*/
int pci_visit_dev ( struct pci_visit * fn , struct pci_dev_wrapped * wrapped_dev ,
struct pci_bus_wrapped * wrapped_parent )
{
struct pci_dev * dev = wrapped_dev ? wrapped_dev - > dev : NULL ;
int result = 0 ;
if ( ! dev )
return 0 ;
if ( fn - > pre_visit_pci_dev ) {
result = fn - > pre_visit_pci_dev ( wrapped_dev , wrapped_parent ) ;
if ( result )
return result ;
}
switch ( dev - > class > > 8 ) {
case PCI_CLASS_BRIDGE_PCI :
result = pci_visit_bridge ( fn , wrapped_dev ,
wrapped_parent ) ;
if ( result )
return result ;
break ;
default :
pr_debug ( " PCI: Scanning device %s \n " , pci_name ( dev ) ) ;
if ( fn - > visit_pci_dev ) {
result = fn - > visit_pci_dev ( wrapped_dev ,
wrapped_parent ) ;
if ( result )
return result ;
}
}
if ( fn - > post_visit_pci_dev )
result = fn - > post_visit_pci_dev ( wrapped_dev , wrapped_parent ) ;
return result ;
}
EXPORT_SYMBOL ( pci_visit_dev ) ;