2005-04-17 02:20:36 +04:00
/*
* EISA bus support functions for sysfs .
*
* ( C ) 2002 , 2003 Marc Zyngier < maz @ wild - wind . fr . eu . org >
*
* This code is released under the GPL version 2.
*/
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/eisa.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/ioport.h>
# include <asm/io.h>
# define SLOT_ADDRESS(r,n) (r->bus_base_addr + (0x1000 * n))
# define EISA_DEVINFO(i,s) { .id = { .sig = i }, .name = s }
struct eisa_device_info {
struct eisa_device_id id ;
2008-05-02 08:02:41 +04:00
char name [ 50 ] ;
2005-04-17 02:20:36 +04:00
} ;
# ifdef CONFIG_EISA_NAMES
static struct eisa_device_info __initdata eisa_table [ ] = {
# include "devlist.h"
} ;
# define EISA_INFOS (sizeof (eisa_table) / (sizeof (struct eisa_device_info)))
# endif
# define EISA_MAX_FORCED_DEV 16
static int enable_dev [ EISA_MAX_FORCED_DEV ] ;
2007-10-14 22:35:30 +04:00
static unsigned int enable_dev_count ;
2005-04-17 02:20:36 +04:00
static int disable_dev [ EISA_MAX_FORCED_DEV ] ;
2007-10-14 22:35:30 +04:00
static unsigned int disable_dev_count ;
2005-04-17 02:20:36 +04:00
static int is_forced_dev ( int * forced_tab ,
int forced_count ,
struct eisa_root_device * root ,
struct eisa_device * edev )
{
int i , x ;
for ( i = 0 ; i < forced_count ; i + + ) {
x = ( root - > bus_nr < < 8 ) | edev - > slot ;
if ( forced_tab [ i ] = = x )
return 1 ;
}
return 0 ;
}
static void __init eisa_name_device ( struct eisa_device * edev )
{
# ifdef CONFIG_EISA_NAMES
int i ;
for ( i = 0 ; i < EISA_INFOS ; i + + ) {
if ( ! strcmp ( edev - > id . sig , eisa_table [ i ] . id . sig ) ) {
strlcpy ( edev - > pretty_name ,
eisa_table [ i ] . name ,
2008-05-02 08:02:41 +04:00
sizeof ( edev - > pretty_name ) ) ;
2005-04-17 02:20:36 +04:00
return ;
}
}
/* No name was found */
sprintf ( edev - > pretty_name , " EISA device %.7s " , edev - > id . sig ) ;
# endif
}
static char __init * decode_eisa_sig ( unsigned long addr )
{
static char sig_str [ EISA_SIG_LEN ] ;
u8 sig [ 4 ] ;
u16 rev ;
int i ;
for ( i = 0 ; i < 4 ; i + + ) {
# ifdef CONFIG_EISA_VLB_PRIMING
/*
* This ugly stuff is used to wake up VL - bus cards
* ( AHA - 284 x is the only known example ) , so we can
* read the EISA id .
*
* Thankfully , this only exists on x86 . . .
*/
outb ( 0x80 + i , addr ) ;
# endif
sig [ i ] = inb ( addr + i ) ;
if ( ! i & & ( sig [ 0 ] & 0x80 ) )
return NULL ;
}
sig_str [ 0 ] = ( ( sig [ 0 ] > > 2 ) & 0x1f ) + ( ' A ' - 1 ) ;
sig_str [ 1 ] = ( ( ( sig [ 0 ] & 3 ) < < 3 ) | ( sig [ 1 ] > > 5 ) ) + ( ' A ' - 1 ) ;
sig_str [ 2 ] = ( sig [ 1 ] & 0x1f ) + ( ' A ' - 1 ) ;
rev = ( sig [ 2 ] < < 8 ) | sig [ 3 ] ;
sprintf ( sig_str + 3 , " %04X " , rev ) ;
return sig_str ;
}
static int eisa_bus_match ( struct device * dev , struct device_driver * drv )
{
struct eisa_device * edev = to_eisa_device ( dev ) ;
struct eisa_driver * edrv = to_eisa_driver ( drv ) ;
const struct eisa_device_id * eids = edrv - > id_table ;
if ( ! eids )
return 0 ;
while ( strlen ( eids - > sig ) ) {
if ( ! strcmp ( eids - > sig , edev - > id . sig ) & &
edev - > state & EISA_CONFIG_ENABLED ) {
edev - > id . driver_data = eids - > driver_data ;
return 1 ;
}
eids + + ;
}
return 0 ;
}
2007-08-14 17:15:12 +04:00
static int eisa_bus_uevent ( struct device * dev , struct kobj_uevent_env * env )
2006-09-27 12:50:56 +04:00
{
struct eisa_device * edev = to_eisa_device ( dev ) ;
2007-08-14 17:15:12 +04:00
add_uevent_var ( env , " MODALIAS= " EISA_DEVICE_MODALIAS_FMT , edev - > id . sig ) ;
2006-09-27 12:50:56 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
struct bus_type eisa_bus_type = {
. name = " eisa " ,
. match = eisa_bus_match ,
2006-09-27 12:50:56 +04:00
. uevent = eisa_bus_uevent ,
2005-04-17 02:20:36 +04:00
} ;
int eisa_driver_register ( struct eisa_driver * edrv )
{
edrv - > driver . bus = & eisa_bus_type ;
2006-03-25 14:07:19 +03:00
return driver_register ( & edrv - > driver ) ;
2005-04-17 02:20:36 +04:00
}
void eisa_driver_unregister ( struct eisa_driver * edrv )
{
driver_unregister ( & edrv - > driver ) ;
}
2005-05-17 14:41:12 +04:00
static ssize_t eisa_show_sig ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct eisa_device * edev = to_eisa_device ( dev ) ;
return sprintf ( buf , " %s \n " , edev - > id . sig ) ;
}
static DEVICE_ATTR ( signature , S_IRUGO , eisa_show_sig , NULL ) ;
2005-05-17 14:41:12 +04:00
static ssize_t eisa_show_state ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct eisa_device * edev = to_eisa_device ( dev ) ;
return sprintf ( buf , " %d \n " , edev - > state & EISA_CONFIG_ENABLED ) ;
}
static DEVICE_ATTR ( enabled , S_IRUGO , eisa_show_state , NULL ) ;
2006-09-27 12:50:56 +04:00
static ssize_t eisa_show_modalias ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct eisa_device * edev = to_eisa_device ( dev ) ;
return sprintf ( buf , EISA_DEVICE_MODALIAS_FMT " \n " , edev - > id . sig ) ;
}
static DEVICE_ATTR ( modalias , S_IRUGO , eisa_show_modalias , NULL ) ;
2005-04-17 02:20:36 +04:00
static int __init eisa_init_device ( struct eisa_root_device * root ,
struct eisa_device * edev ,
int slot )
{
char * sig ;
unsigned long sig_addr ;
int i ;
sig_addr = SLOT_ADDRESS ( root , slot ) + EISA_VENDOR_ID_OFFSET ;
if ( ! ( sig = decode_eisa_sig ( sig_addr ) ) )
return - 1 ; /* No EISA device here */
memcpy ( edev - > id . sig , sig , EISA_SIG_LEN ) ;
edev - > slot = slot ;
edev - > state = inb ( SLOT_ADDRESS ( root , slot ) + EISA_CONFIG_OFFSET ) & EISA_CONFIG_ENABLED ;
edev - > base_addr = SLOT_ADDRESS ( root , slot ) ;
edev - > dma_mask = root - > dma_mask ; /* Default DMA mask */
eisa_name_device ( edev ) ;
edev - > dev . parent = root - > dev ;
edev - > dev . bus = & eisa_bus_type ;
edev - > dev . dma_mask = & edev - > dma_mask ;
edev - > dev . coherent_dma_mask = edev - > dma_mask ;
sprintf ( edev - > dev . bus_id , " %02X:%02X " , root - > bus_nr , slot ) ;
for ( i = 0 ; i < EISA_MAX_RESOURCES ; i + + ) {
# ifdef CONFIG_EISA_NAMES
edev - > res [ i ] . name = edev - > pretty_name ;
# else
edev - > res [ i ] . name = edev - > id . sig ;
# endif
}
if ( is_forced_dev ( enable_dev , enable_dev_count , root , edev ) )
edev - > state = EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED ;
if ( is_forced_dev ( disable_dev , disable_dev_count , root , edev ) )
edev - > state = EISA_CONFIG_FORCED ;
return 0 ;
}
static int __init eisa_register_device ( struct eisa_device * edev )
{
2006-10-11 12:22:22 +04:00
int rc = device_register ( & edev - > dev ) ;
if ( rc )
return rc ;
2005-04-17 02:20:36 +04:00
2006-10-11 12:22:22 +04:00
rc = device_create_file ( & edev - > dev , & dev_attr_signature ) ;
if ( rc ) goto err_devreg ;
rc = device_create_file ( & edev - > dev , & dev_attr_enabled ) ;
if ( rc ) goto err_sig ;
rc = device_create_file ( & edev - > dev , & dev_attr_modalias ) ;
if ( rc ) goto err_enab ;
2005-04-17 02:20:36 +04:00
return 0 ;
2006-10-11 12:22:22 +04:00
err_enab :
device_remove_file ( & edev - > dev , & dev_attr_enabled ) ;
err_sig :
device_remove_file ( & edev - > dev , & dev_attr_signature ) ;
err_devreg :
device_unregister ( & edev - > dev ) ;
return rc ;
2005-04-17 02:20:36 +04:00
}
static int __init eisa_request_resources ( struct eisa_root_device * root ,
struct eisa_device * edev ,
int slot )
{
int i ;
for ( i = 0 ; i < EISA_MAX_RESOURCES ; i + + ) {
/* Don't register resource for slot 0, since this is
* very likely to fail . . . : - ( Instead , grab the EISA
* id , now we can display something in / proc / ioports .
*/
/* Only one region for mainboard */
if ( ! slot & & i > 0 ) {
edev - > res [ i ] . start = edev - > res [ i ] . end = 0 ;
continue ;
}
if ( slot ) {
edev - > res [ i ] . name = NULL ;
edev - > res [ i ] . start = SLOT_ADDRESS ( root , slot ) + ( i * 0x400 ) ;
edev - > res [ i ] . end = edev - > res [ i ] . start + 0xff ;
edev - > res [ i ] . flags = IORESOURCE_IO ;
} else {
edev - > res [ i ] . name = NULL ;
edev - > res [ i ] . start = SLOT_ADDRESS ( root , slot ) + EISA_VENDOR_ID_OFFSET ;
edev - > res [ i ] . end = edev - > res [ i ] . start + 3 ;
edev - > res [ i ] . flags = IORESOURCE_BUSY ;
}
if ( request_resource ( root - > res , & edev - > res [ i ] ) )
goto failed ;
}
return 0 ;
failed :
while ( - - i > = 0 )
release_resource ( & edev - > res [ i ] ) ;
return - 1 ;
}
static void __init eisa_release_resources ( struct eisa_device * edev )
{
int i ;
for ( i = 0 ; i < EISA_MAX_RESOURCES ; i + + )
if ( edev - > res [ i ] . start | | edev - > res [ i ] . end )
release_resource ( & edev - > res [ i ] ) ;
}
static int __init eisa_probe ( struct eisa_root_device * root )
{
int i , c ;
struct eisa_device * edev ;
printk ( KERN_INFO " EISA: Probing bus %d at %s \n " ,
root - > bus_nr , root - > dev - > bus_id ) ;
/* First try to get hold of slot 0. If there is no device
* here , simply fail , unless root - > force_probe is set . */
2005-11-07 12:01:23 +03:00
if ( ! ( edev = kzalloc ( sizeof ( * edev ) , GFP_KERNEL ) ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " EISA: Couldn't allocate mainboard slot \n " ) ;
return - ENOMEM ;
}
if ( eisa_request_resources ( root , edev , 0 ) ) {
printk ( KERN_WARNING \
" EISA: Cannot allocate resource for mainboard \n " ) ;
kfree ( edev ) ;
if ( ! root - > force_probe )
return - EBUSY ;
goto force_probe ;
}
if ( eisa_init_device ( root , edev , 0 ) ) {
eisa_release_resources ( edev ) ;
kfree ( edev ) ;
if ( ! root - > force_probe )
return - ENODEV ;
goto force_probe ;
}
printk ( KERN_INFO " EISA: Mainboard %s detected. \n " , edev - > id . sig ) ;
if ( eisa_register_device ( edev ) ) {
printk ( KERN_ERR " EISA: Failed to register %s \n " ,
edev - > id . sig ) ;
eisa_release_resources ( edev ) ;
kfree ( edev ) ;
}
force_probe :
for ( c = 0 , i = 1 ; i < = root - > slots ; i + + ) {
2005-11-07 12:01:23 +03:00
if ( ! ( edev = kzalloc ( sizeof ( * edev ) , GFP_KERNEL ) ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " EISA: Out of memory for slot %d \n " ,
i ) ;
continue ;
}
if ( eisa_request_resources ( root , edev , i ) ) {
printk ( KERN_WARNING \
" Cannot allocate resource for EISA slot %d \n " ,
i ) ;
kfree ( edev ) ;
continue ;
}
if ( eisa_init_device ( root , edev , i ) ) {
eisa_release_resources ( edev ) ;
kfree ( edev ) ;
continue ;
}
printk ( KERN_INFO " EISA: slot %d : %s detected " ,
i , edev - > id . sig ) ;
switch ( edev - > state ) {
case EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED :
printk ( " (forced enabled) " ) ;
break ;
case EISA_CONFIG_FORCED :
printk ( " (forced disabled) " ) ;
break ;
case 0 :
printk ( " (disabled) " ) ;
break ;
}
printk ( " . \n " ) ;
c + + ;
if ( eisa_register_device ( edev ) ) {
printk ( KERN_ERR " EISA: Failed to register %s \n " ,
edev - > id . sig ) ;
eisa_release_resources ( edev ) ;
kfree ( edev ) ;
}
}
printk ( KERN_INFO " EISA: Detected %d card%s. \n " , c , c = = 1 ? " " : " s " ) ;
return 0 ;
}
static struct resource eisa_root_res = {
. name = " EISA root resource " ,
. start = 0 ,
. end = 0xffffffff ,
. flags = IORESOURCE_IO ,
} ;
static int eisa_bus_count ;
int __init eisa_root_register ( struct eisa_root_device * root )
{
int err ;
/* Use our own resources to check if this bus base address has
* been already registered . This prevents the virtual root
* device from registering after the real one has , for
* example . . . */
root - > eisa_root_res . name = eisa_root_res . name ;
root - > eisa_root_res . start = root - > res - > start ;
root - > eisa_root_res . end = root - > res - > end ;
root - > eisa_root_res . flags = IORESOURCE_BUSY ;
if ( ( err = request_resource ( & eisa_root_res , & root - > eisa_root_res ) ) )
return err ;
root - > bus_nr = eisa_bus_count + + ;
if ( ( err = eisa_probe ( root ) ) )
release_resource ( & root - > eisa_root_res ) ;
return err ;
}
static int __init eisa_init ( void )
{
int r ;
if ( ( r = bus_register ( & eisa_bus_type ) ) )
return r ;
printk ( KERN_INFO " EISA bus registered \n " ) ;
return 0 ;
}
module_param_array ( enable_dev , int , & enable_dev_count , 0444 ) ;
module_param_array ( disable_dev , int , & disable_dev_count , 0444 ) ;
postcore_initcall ( eisa_init ) ;
int EISA_bus ; /* for legacy drivers */
EXPORT_SYMBOL ( EISA_bus ) ;
EXPORT_SYMBOL ( eisa_bus_type ) ;
EXPORT_SYMBOL ( eisa_driver_register ) ;
EXPORT_SYMBOL ( eisa_driver_unregister ) ;