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
2010-03-06 00:42:48 +03:00
static int is_forced_dev ( int * forced_tab ,
int forced_count ,
struct eisa_root_device * root ,
struct eisa_device * edev )
2005-04-17 02:20:36 +04:00
{
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 ;
}
2010-03-06 00:42:48 +03:00
static void __init eisa_name_device ( struct eisa_device * edev )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_EISA_NAMES
int i ;
for ( i = 0 ; i < EISA_INFOS ; i + + ) {
2010-03-06 00:42:48 +03:00
if ( ! strcmp ( edev - > id . sig , eisa_table [ i ] . id . sig ) ) {
strlcpy ( edev - > pretty_name ,
eisa_table [ i ] . name ,
sizeof ( edev - > pretty_name ) ) ;
2005-04-17 02:20:36 +04:00
return ;
}
}
/* No name was found */
2010-03-06 00:42:48 +03:00
sprintf ( edev - > pretty_name , " EISA device %.7s " , edev - > id . sig ) ;
2005-04-17 02:20:36 +04:00
# endif
}
static char __init * decode_eisa_sig ( unsigned long addr )
{
2018-01-17 12:44:06 +03:00
static char sig_str [ EISA_SIG_LEN ] ;
2005-04-17 02:20:36 +04:00
u8 sig [ 4 ] ;
2018-01-17 12:44:06 +03:00
u16 rev ;
2005-04-17 02:20:36 +04:00
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
2010-03-06 00:42:48 +03:00
sig [ i ] = inb ( addr + i ) ;
2005-04-17 02:20:36 +04:00
if ( ! i & & ( sig [ 0 ] & 0x80 ) )
return NULL ;
}
2018-01-17 12:44:06 +03:00
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 ;
2005-04-17 02:20:36 +04:00
}
2010-03-06 00:42:48 +03:00
static int eisa_bus_match ( struct device * dev , struct device_driver * drv )
2005-04-17 02:20:36 +04:00
{
2010-03-06 00:42:48 +03:00
struct eisa_device * edev = to_eisa_device ( dev ) ;
struct eisa_driver * edrv = to_eisa_driver ( drv ) ;
2005-04-17 02:20:36 +04:00
const struct eisa_device_id * eids = edrv - > id_table ;
if ( ! eids )
return 0 ;
2010-03-06 00:42:48 +03:00
while ( strlen ( eids - > sig ) ) {
if ( ! strcmp ( eids - > sig , edev - > id . sig ) & &
2005-04-17 02:20:36 +04:00
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
} ;
2010-03-06 00:42:48 +03:00
EXPORT_SYMBOL ( eisa_bus_type ) ;
2005-04-17 02:20:36 +04:00
2010-03-06 00:42:48 +03:00
int eisa_driver_register ( struct eisa_driver * edrv )
2005-04-17 02:20:36 +04:00
{
edrv - > driver . bus = & eisa_bus_type ;
2010-03-06 00:42:48 +03:00
return driver_register ( & edrv - > driver ) ;
2005-04-17 02:20:36 +04:00
}
2010-03-06 00:42:48 +03:00
EXPORT_SYMBOL ( eisa_driver_register ) ;
2005-04-17 02:20:36 +04:00
2010-03-06 00:42:48 +03:00
void eisa_driver_unregister ( struct eisa_driver * edrv )
2005-04-17 02:20:36 +04:00
{
2010-03-06 00:42:48 +03:00
driver_unregister ( & edrv - > driver ) ;
2005-04-17 02:20:36 +04:00
}
2010-03-06 00:42:48 +03:00
EXPORT_SYMBOL ( eisa_driver_unregister ) ;
2005-04-17 02:20:36 +04:00
2010-03-06 00:42:48 +03:00
static ssize_t eisa_show_sig ( struct device * dev , struct device_attribute * attr ,
char * buf )
2005-04-17 02:20:36 +04:00
{
2010-03-06 00:42:48 +03:00
struct eisa_device * edev = to_eisa_device ( dev ) ;
return sprintf ( buf , " %s \n " , edev - > id . sig ) ;
2005-04-17 02:20:36 +04:00
}
static DEVICE_ATTR ( signature , S_IRUGO , eisa_show_sig , NULL ) ;
2010-03-06 00:42:48 +03:00
static ssize_t eisa_show_state ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
2005-04-17 02:20:36 +04:00
{
2010-03-06 00:42:48 +03:00
struct eisa_device * edev = to_eisa_device ( dev ) ;
return sprintf ( buf , " %d \n " , edev - > state & EISA_CONFIG_ENABLED ) ;
2005-04-17 02:20:36 +04:00
}
static DEVICE_ATTR ( enabled , S_IRUGO , eisa_show_state , NULL ) ;
2010-03-06 00:42:48 +03:00
static ssize_t eisa_show_modalias ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
2006-09-27 12:50:56 +04:00
{
2010-03-06 00:42:48 +03:00
struct eisa_device * edev = to_eisa_device ( dev ) ;
return sprintf ( buf , EISA_DEVICE_MODALIAS_FMT " \n " , edev - > id . sig ) ;
2006-09-27 12:50:56 +04:00
}
static DEVICE_ATTR ( modalias , S_IRUGO , eisa_show_modalias , NULL ) ;
2010-03-06 00:42:48 +03:00
static int __init eisa_init_device ( struct eisa_root_device * root ,
struct eisa_device * edev ,
int slot )
2005-04-17 02:20:36 +04:00
{
char * sig ;
2010-03-06 00:42:48 +03:00
unsigned long sig_addr ;
2005-04-17 02:20:36 +04:00
int i ;
2010-03-06 00:42:48 +03:00
sig_addr = SLOT_ADDRESS ( root , slot ) + EISA_VENDOR_ID_OFFSET ;
2005-04-17 02:20:36 +04:00
2010-03-06 00:42:48 +03:00
sig = decode_eisa_sig ( sig_addr ) ;
if ( ! sig )
2005-04-17 02:20:36 +04:00
return - 1 ; /* No EISA device here */
2018-01-17 12:44:06 +03:00
2010-03-06 00:42:48 +03:00
memcpy ( edev - > id . sig , sig , EISA_SIG_LEN ) ;
2005-04-17 02:20:36 +04:00
edev - > slot = slot ;
2010-03-06 00:42:48 +03:00
edev - > state = inb ( SLOT_ADDRESS ( root , slot ) + EISA_CONFIG_OFFSET )
& EISA_CONFIG_ENABLED ;
edev - > base_addr = SLOT_ADDRESS ( root , slot ) ;
2005-04-17 02:20:36 +04:00
edev - > dma_mask = root - > dma_mask ; /* Default DMA mask */
2010-03-06 00:42:48 +03:00
eisa_name_device ( edev ) ;
2005-04-17 02:20:36 +04:00
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 ;
2009-03-25 02:38:22 +03:00
dev_set_name ( & edev - > dev , " %02X:%02X " , root - > bus_nr , slot ) ;
2005-04-17 02:20:36 +04:00
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
}
2010-03-06 00:42:48 +03:00
if ( is_forced_dev ( enable_dev , enable_dev_count , root , edev ) )
2005-04-17 02:20:36 +04:00
edev - > state = EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED ;
2018-01-17 12:44:06 +03:00
2010-03-06 00:42:48 +03:00
if ( is_forced_dev ( disable_dev , disable_dev_count , root , edev ) )
2005-04-17 02:20:36 +04:00
edev - > state = EISA_CONFIG_FORCED ;
return 0 ;
}
2010-03-06 00:42:48 +03:00
static int __init eisa_register_device ( struct eisa_device * edev )
2005-04-17 02:20:36 +04:00
{
2010-03-06 00:42:48 +03:00
int rc = device_register ( & edev - > dev ) ;
2013-12-13 22:39:54 +04:00
if ( rc ) {
put_device ( & edev - > dev ) ;
2006-10-11 12:22:22 +04:00
return rc ;
2013-12-13 22:39:54 +04:00
}
2005-04-17 02:20:36 +04:00
2010-03-06 00:42:48 +03: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 :
2010-03-06 00:42:48 +03:00
device_remove_file ( & edev - > dev , & dev_attr_enabled ) ;
2006-10-11 12:22:22 +04:00
err_sig :
2010-03-06 00:42:48 +03:00
device_remove_file ( & edev - > dev , & dev_attr_signature ) ;
2006-10-11 12:22:22 +04:00
err_devreg :
device_unregister ( & edev - > dev ) ;
return rc ;
2005-04-17 02:20:36 +04:00
}
2010-03-06 00:42:48 +03:00
static int __init eisa_request_resources ( struct eisa_root_device * root ,
struct eisa_device * edev ,
int slot )
2005-04-17 02:20:36 +04:00
{
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 ;
}
2018-01-17 12:44:06 +03:00
2005-04-17 02:20:36 +04:00
if ( slot ) {
2014-01-18 01:57:29 +04:00
edev - > res [ i ] . name = NULL ;
2010-03-06 00:42:48 +03:00
edev - > res [ i ] . start = SLOT_ADDRESS ( root , slot )
+ ( i * 0x400 ) ;
2005-04-17 02:20:36 +04:00
edev - > res [ i ] . end = edev - > res [ i ] . start + 0xff ;
edev - > res [ i ] . flags = IORESOURCE_IO ;
} else {
2014-01-18 01:57:29 +04:00
edev - > res [ i ] . name = NULL ;
2010-03-06 00:42:48 +03:00
edev - > res [ i ] . start = SLOT_ADDRESS ( root , slot )
+ EISA_VENDOR_ID_OFFSET ;
2005-04-17 02:20:36 +04:00
edev - > res [ i ] . end = edev - > res [ i ] . start + 3 ;
2013-04-16 00:33:56 +04:00
edev - > res [ i ] . flags = IORESOURCE_IO | IORESOURCE_BUSY ;
2005-04-17 02:20:36 +04:00
}
2010-03-06 00:42:48 +03:00
if ( request_resource ( root - > res , & edev - > res [ i ] ) )
2005-04-17 02:20:36 +04:00
goto failed ;
}
return 0 ;
2018-01-17 12:44:06 +03:00
2005-04-17 02:20:36 +04:00
failed :
while ( - - i > = 0 )
2010-03-06 00:42:48 +03:00
release_resource ( & edev - > res [ i ] ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2010-03-06 00:42:48 +03:00
static void __init eisa_release_resources ( struct eisa_device * edev )
2005-04-17 02:20:36 +04:00
{
int i ;
for ( i = 0 ; i < EISA_MAX_RESOURCES ; i + + )
if ( edev - > res [ i ] . start | | edev - > res [ i ] . end )
2010-03-06 00:42:48 +03:00
release_resource ( & edev - > res [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2010-03-06 00:42:48 +03:00
static int __init eisa_probe ( struct eisa_root_device * root )
2005-04-17 02:20:36 +04:00
{
2018-01-17 12:44:06 +03:00
int i , c ;
2005-04-17 02:20:36 +04:00
struct eisa_device * edev ;
2013-04-16 00:33:42 +04:00
char * enabled_str ;
2005-04-17 02:20:36 +04:00
2013-04-16 00:33:42 +04:00
dev_info ( root - > dev , " Probing EISA bus %d \n " , root - > bus_nr ) ;
2005-04-17 02:20:36 +04:00
/* First try to get hold of slot 0. If there is no device
* here , simply fail , unless root - > force_probe is set . */
2018-01-17 12:44:06 +03:00
2010-03-06 00:42:48 +03:00
edev = kzalloc ( sizeof ( * edev ) , GFP_KERNEL ) ;
2018-01-17 12:45:01 +03:00
if ( ! edev )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2018-01-17 12:44:06 +03:00
2014-01-18 01:57:29 +04:00
if ( eisa_request_resources ( root , edev , 0 ) ) {
dev_warn ( root - > dev ,
2018-01-17 12:44:06 +03:00
" EISA: Cannot allocate resource for mainboard \n " ) ;
2010-03-06 00:42:48 +03:00
kfree ( edev ) ;
2005-04-17 02:20:36 +04:00
if ( ! root - > force_probe )
2014-01-18 01:57:29 +04:00
return - EBUSY ;
2005-04-17 02:20:36 +04:00
goto force_probe ;
}
2014-01-18 01:57:29 +04:00
if ( eisa_init_device ( root , edev , 0 ) ) {
eisa_release_resources ( edev ) ;
2010-03-06 00:42:48 +03:00
kfree ( edev ) ;
2005-04-17 02:20:36 +04:00
if ( ! root - > force_probe )
2014-01-18 01:57:29 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
goto force_probe ;
}
2013-04-16 00:33:42 +04:00
dev_info ( & edev - > dev , " EISA: Mainboard %s detected \n " , edev - > id . sig ) ;
2005-04-17 02:20:36 +04:00
2010-03-06 00:42:48 +03:00
if ( eisa_register_device ( edev ) ) {
2013-04-16 00:33:42 +04:00
dev_err ( & edev - > dev , " EISA: Failed to register %s \n " ,
2018-01-17 12:44:06 +03:00
edev - > id . sig ) ;
2010-03-06 00:42:48 +03:00
eisa_release_resources ( edev ) ;
kfree ( edev ) ;
2005-04-17 02:20:36 +04:00
}
2018-01-17 12:44:06 +03:00
2005-04-17 02:20:36 +04:00
force_probe :
2018-01-17 12:44:06 +03:00
for ( c = 0 , i = 1 ; i < = root - > slots ; i + + ) {
2010-03-06 00:42:48 +03:00
edev = kzalloc ( sizeof ( * edev ) , GFP_KERNEL ) ;
if ( ! edev ) {
2013-04-16 00:33:42 +04:00
dev_err ( root - > dev , " EISA: Out of memory for slot %d \n " ,
i ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
2013-04-16 00:34:02 +04:00
if ( eisa_request_resources ( root , edev , i ) ) {
dev_warn ( root - > dev ,
2018-01-17 12:44:06 +03:00
" Cannot allocate resource for EISA slot %d \n " ,
i ) ;
2010-03-06 00:42:48 +03:00
kfree ( edev ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
2013-04-16 00:33:42 +04:00
2014-01-18 01:57:29 +04:00
if ( eisa_init_device ( root , edev , i ) ) {
eisa_release_resources ( edev ) ;
kfree ( edev ) ;
continue ;
}
2013-04-16 00:33:42 +04:00
if ( edev - > state = = ( EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED ) )
enabled_str = " (forced enabled) " ;
else if ( edev - > state = = EISA_CONFIG_FORCED )
enabled_str = " (forced disabled) " ;
else if ( edev - > state = = 0 )
enabled_str = " (disabled) " ;
else
enabled_str = " " ;
dev_info ( & edev - > dev , " EISA: slot %d: %s detected%s \n " , i ,
edev - > id . sig , enabled_str ) ;
2005-04-17 02:20:36 +04:00
c + + ;
2010-03-06 00:42:48 +03:00
if ( eisa_register_device ( edev ) ) {
2013-04-16 00:33:42 +04:00
dev_err ( & edev - > dev , " EISA: Failed to register %s \n " ,
2018-01-17 12:44:06 +03:00
edev - > id . sig ) ;
2010-03-06 00:42:48 +03:00
eisa_release_resources ( edev ) ;
kfree ( edev ) ;
2005-04-17 02:20:36 +04:00
}
2018-01-17 12:44:06 +03:00
}
2005-04-17 02:20:36 +04:00
2013-04-16 00:33:42 +04:00
dev_info ( root - > dev , " EISA: Detected %d card%s \n " , c , c = = 1 ? " " : " s " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static struct resource eisa_root_res = {
. name = " EISA root resource " ,
. start = 0 ,
. end = 0xffffffff ,
. flags = IORESOURCE_IO ,
} ;
static int eisa_bus_count ;
2010-03-06 00:42:48 +03:00
int __init eisa_root_register ( struct eisa_root_device * root )
2005-04-17 02:20:36 +04:00
{
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 . . . */
2018-01-17 12:44:06 +03:00
2005-04-17 02:20:36 +04:00
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 ;
2010-03-06 00:42:48 +03:00
err = request_resource ( & eisa_root_res , & root - > eisa_root_res ) ;
if ( err )
2005-04-17 02:20:36 +04:00
return err ;
2018-01-17 12:44:06 +03:00
2005-04-17 02:20:36 +04:00
root - > bus_nr = eisa_bus_count + + ;
2010-03-06 00:42:48 +03:00
err = eisa_probe ( root ) ;
if ( err )
release_resource ( & root - > eisa_root_res ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
2010-03-06 00:42:48 +03:00
static int __init eisa_init ( void )
2005-04-17 02:20:36 +04:00
{
int r ;
2018-01-17 12:44:06 +03:00
2010-03-06 00:42:48 +03:00
r = bus_register ( & eisa_bus_type ) ;
if ( r )
2005-04-17 02:20:36 +04:00
return r ;
2010-03-06 00:42:48 +03:00
printk ( KERN_INFO " EISA bus registered \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
module_param_array ( enable_dev , int , & enable_dev_count , 0444 ) ;
module_param_array ( disable_dev , int , & disable_dev_count , 0444 ) ;
2010-03-06 00:42:48 +03:00
postcore_initcall ( eisa_init ) ;
2005-04-17 02:20:36 +04:00
int EISA_bus ; /* for legacy drivers */
2010-03-06 00:42:48 +03:00
EXPORT_SYMBOL ( EISA_bus ) ;