2005-04-16 15:20:36 -07:00
/*
* Linux ARCnet driver - COM90xx chipset ( memory - mapped buffers )
*
* Written 1994 - 1999 by Avery Pennarun .
* Written 1999 by Martin Mares < mj @ ucw . cz > .
* Derived from skeleton . c by Donald Becker .
*
* Special thanks to Contemporary Controls , Inc . ( www . ccontrols . com )
* for sponsoring the further development of this driver .
*
* * * * * * * * * * * * * * * * * * * * * * *
*
* The original copyright of skeleton . c was as follows :
*
* skeleton . c Written 1993 by Donald Becker .
* Copyright 1993 United States Government as represented by the
* Director , National Security Agency . This software may only be used
* and distributed according to the terms of the GNU General Public License as
* modified by SRC , incorporated herein by reference .
*
* * * * * * * * * * * * * * * * * * * * * * *
*
* For more details , see drivers / net / arcnet . c
*
* * * * * * * * * * * * * * * * * * * * * * *
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/ioport.h>
# include <linux/delay.h>
# include <linux/netdevice.h>
# include <asm/io.h>
# include <linux/arcdevice.h>
# define VERSION "arcnet: COM90xx chipset support\n"
/* Define this to speed up the autoprobe by assuming if only one io port and
* shmem are left in the list at Stage 5 , they must correspond to each
* other .
*
* This is undefined by default because it might not always be true , and the
* extra check makes the autoprobe even more careful . Speed demons can turn
* it on - I think it should be fine if you only have one ARCnet card
* installed .
*
* If no ARCnet cards are installed , this delay never happens anyway and thus
* the option has no effect .
*/
# undef FAST_PROBE
/* Internal function declarations */
2005-12-02 03:54:44 -05:00
static int com90xx_found ( int ioaddr , int airq , u_long shmem , void __iomem * ) ;
2005-04-16 15:20:36 -07:00
static void com90xx_command ( struct net_device * dev , int command ) ;
static int com90xx_status ( struct net_device * dev ) ;
static void com90xx_setmask ( struct net_device * dev , int mask ) ;
static int com90xx_reset ( struct net_device * dev , int really_reset ) ;
static void com90xx_copy_to_card ( struct net_device * dev , int bufnum , int offset ,
void * buf , int count ) ;
static void com90xx_copy_from_card ( struct net_device * dev , int bufnum , int offset ,
void * buf , int count ) ;
/* Known ARCnet cards */
static struct net_device * cards [ 16 ] ;
static int numcards ;
/* Handy defines for ARCnet specific stuff */
/* The number of low I/O ports used by the card */
# define ARCNET_TOTAL_SIZE 16
/* Amount of I/O memory used by the card */
# define BUFFER_SIZE (512)
# define MIRROR_SIZE (BUFFER_SIZE*4)
/* COM 9026 controller chip --> ARCnet register addresses */
# define _INTMASK (ioaddr+0) /* writable */
# define _STATUS (ioaddr+0) /* readable */
# define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
# define _CONFIG (ioaddr+2) /* Configuration register */
# define _RESET (ioaddr+8) /* software reset (on read) */
# define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
# define _ADDR_HI (ioaddr+15) /* Control registers for said */
# define _ADDR_LO (ioaddr+14)
# undef ASTATUS
# undef ACOMMAND
# undef AINTMASK
# define ASTATUS() inb(_STATUS)
# define ACOMMAND(cmd) outb((cmd),_COMMAND)
# define AINTMASK(msk) outb((msk),_INTMASK)
static int com90xx_skip_probe __initdata = 0 ;
/* Module parameters */
static int io ; /* use the insmod io= irq= shmem= options */
static int irq ;
static int shmem ;
static char device [ 9 ] ; /* use eg. device=arc1 to change name */
module_param ( io , int , 0 ) ;
module_param ( irq , int , 0 ) ;
module_param ( shmem , int , 0 ) ;
module_param_string ( device , device , sizeof ( device ) , 0 ) ;
static void __init com90xx_probe ( void )
{
int count , status , ioaddr , numprint , airq , openparen = 0 ;
unsigned long airqmask ;
int ports [ ( 0x3f0 - 0x200 ) / 16 + 1 ] =
{ 0 } ;
2005-12-02 03:54:44 -05:00
unsigned long * shmems ;
void __iomem * * iomem ;
2005-04-16 15:20:36 -07:00
int numports , numshmems , * port ;
u_long * p ;
2005-12-02 03:54:44 -05:00
int index ;
2005-04-16 15:20:36 -07:00
if ( ! io & & ! irq & & ! shmem & & ! * device & & com90xx_skip_probe )
return ;
2006-04-01 00:49:35 -08:00
shmems = kzalloc ( ( ( 0x100000 - 0xa0000 ) / 0x800 ) * sizeof ( unsigned long ) ,
2005-12-02 03:54:44 -05:00
GFP_KERNEL ) ;
if ( ! shmems )
return ;
2006-04-01 00:49:35 -08:00
iomem = kzalloc ( ( ( 0x100000 - 0xa0000 ) / 0x800 ) * sizeof ( void __iomem * ) ,
2005-12-02 03:54:44 -05:00
GFP_KERNEL ) ;
if ( ! iomem ) {
kfree ( shmems ) ;
return ;
}
2005-04-16 15:20:36 -07:00
BUGLVL ( D_NORMAL ) printk ( VERSION ) ;
/* set up the arrays where we'll store the possible probe addresses */
numports = numshmems = 0 ;
if ( io )
ports [ numports + + ] = io ;
else
for ( count = 0x200 ; count < = 0x3f0 ; count + = 16 )
ports [ numports + + ] = count ;
if ( shmem )
shmems [ numshmems + + ] = shmem ;
else
for ( count = 0xA0000 ; count < = 0xFF800 ; count + = 2048 )
shmems [ numshmems + + ] = count ;
/* Stage 1: abandon any reserved ports, or ones with status==0xFF
* ( empty ) , and reset any others by reading the reset port .
*/
numprint = - 1 ;
for ( port = & ports [ 0 ] ; port - ports < numports ; port + + ) {
numprint + + ;
numprint % = 8 ;
if ( ! numprint ) {
BUGMSG2 ( D_INIT , " \n " ) ;
BUGMSG2 ( D_INIT , " S1: " ) ;
}
BUGMSG2 ( D_INIT , " %Xh " , * port ) ;
ioaddr = * port ;
if ( ! request_region ( * port , ARCNET_TOTAL_SIZE , " arcnet (90xx) " ) ) {
BUGMSG2 ( D_INIT_REASONS , " (request_region) \n " ) ;
BUGMSG2 ( D_INIT_REASONS , " S1: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
* port - - = ports [ - - numports ] ;
continue ;
}
if ( ASTATUS ( ) = = 0xFF ) {
BUGMSG2 ( D_INIT_REASONS , " (empty) \n " ) ;
BUGMSG2 ( D_INIT_REASONS , " S1: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
release_region ( * port , ARCNET_TOTAL_SIZE ) ;
* port - - = ports [ - - numports ] ;
continue ;
}
inb ( _RESET ) ; /* begin resetting card */
BUGMSG2 ( D_INIT_REASONS , " \n " ) ;
BUGMSG2 ( D_INIT_REASONS , " S1: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
}
BUGMSG2 ( D_INIT , " \n " ) ;
if ( ! numports ) {
BUGMSG2 ( D_NORMAL , " S1: No ARCnet cards found. \n " ) ;
2005-12-02 03:54:44 -05:00
kfree ( shmems ) ;
kfree ( iomem ) ;
2005-04-16 15:20:36 -07:00
return ;
}
/* Stage 2: we have now reset any possible ARCnet cards, so we can't
* do anything until they finish . If D_INIT , print the list of
* cards that are left .
*/
numprint = - 1 ;
for ( port = & ports [ 0 ] ; port < ports + numports ; port + + ) {
numprint + + ;
numprint % = 8 ;
if ( ! numprint ) {
BUGMSG2 ( D_INIT , " \n " ) ;
BUGMSG2 ( D_INIT , " S2: " ) ;
}
BUGMSG2 ( D_INIT , " %Xh " , * port ) ;
}
BUGMSG2 ( D_INIT , " \n " ) ;
mdelay ( RESETtime ) ;
/* Stage 3: abandon any shmem addresses that don't have the signature
* 0xD1 byte in the right place , or are read - only .
*/
numprint = - 1 ;
2005-12-02 03:54:44 -05:00
for ( index = 0 , p = & shmems [ 0 ] ; index < numshmems ; p + + , index + + ) {
void __iomem * base ;
2005-04-16 15:20:36 -07:00
numprint + + ;
numprint % = 8 ;
if ( ! numprint ) {
BUGMSG2 ( D_INIT , " \n " ) ;
BUGMSG2 ( D_INIT , " S3: " ) ;
}
BUGMSG2 ( D_INIT , " %lXh " , * p ) ;
2005-12-02 03:54:44 -05:00
if ( ! request_mem_region ( * p , MIRROR_SIZE , " arcnet (90xx) " ) ) {
2005-04-16 15:20:36 -07:00
BUGMSG2 ( D_INIT_REASONS , " (request_mem_region) \n " ) ;
BUGMSG2 ( D_INIT_REASONS , " Stage 3: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
2005-12-02 03:54:44 -05:00
goto out ;
}
base = ioremap ( * p , MIRROR_SIZE ) ;
if ( ! base ) {
BUGMSG2 ( D_INIT_REASONS , " (ioremap) \n " ) ;
BUGMSG2 ( D_INIT_REASONS , " Stage 3: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
goto out1 ;
2005-04-16 15:20:36 -07:00
}
2005-12-02 03:54:44 -05:00
if ( readb ( base ) ! = TESTvalue ) {
2005-04-16 15:20:36 -07:00
BUGMSG2 ( D_INIT_REASONS , " (%02Xh != %02Xh) \n " ,
2005-12-02 03:54:44 -05:00
readb ( base ) , TESTvalue ) ;
2005-04-16 15:20:36 -07:00
BUGMSG2 ( D_INIT_REASONS , " S3: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
2005-12-02 03:54:44 -05:00
goto out2 ;
2005-04-16 15:20:36 -07:00
}
/* By writing 0x42 to the TESTvalue location, we also make
* sure no " mirror " shmem areas show up - if they occur
* in another pass through this loop , they will be discarded
* because * cptr ! = TESTvalue .
*/
2005-12-02 03:54:44 -05:00
writeb ( 0x42 , base ) ;
if ( readb ( base ) ! = 0x42 ) {
2005-04-16 15:20:36 -07:00
BUGMSG2 ( D_INIT_REASONS , " (read only) \n " ) ;
BUGMSG2 ( D_INIT_REASONS , " S3: " ) ;
2005-12-02 03:54:44 -05:00
goto out2 ;
2005-04-16 15:20:36 -07:00
}
BUGMSG2 ( D_INIT_REASONS , " \n " ) ;
BUGMSG2 ( D_INIT_REASONS , " S3: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
2005-12-02 03:54:44 -05:00
iomem [ index ] = base ;
continue ;
out2 :
iounmap ( base ) ;
out1 :
release_mem_region ( * p , MIRROR_SIZE ) ;
out :
* p - - = shmems [ - - numshmems ] ;
index - - ;
2005-04-16 15:20:36 -07:00
}
BUGMSG2 ( D_INIT , " \n " ) ;
if ( ! numshmems ) {
BUGMSG2 ( D_NORMAL , " S3: No ARCnet cards found. \n " ) ;
for ( port = & ports [ 0 ] ; port < ports + numports ; port + + )
release_region ( * port , ARCNET_TOTAL_SIZE ) ;
2005-12-02 03:54:44 -05:00
kfree ( shmems ) ;
kfree ( iomem ) ;
2005-04-16 15:20:36 -07:00
return ;
}
/* Stage 4: something of a dummy, to report the shmems that are
* still possible after stage 3.
*/
numprint = - 1 ;
for ( p = & shmems [ 0 ] ; p < shmems + numshmems ; p + + ) {
numprint + + ;
numprint % = 8 ;
if ( ! numprint ) {
BUGMSG2 ( D_INIT , " \n " ) ;
BUGMSG2 ( D_INIT , " S4: " ) ;
}
BUGMSG2 ( D_INIT , " %lXh " , * p ) ;
}
BUGMSG2 ( D_INIT , " \n " ) ;
/* Stage 5: for any ports that have the correct status, can disable
* the RESET flag , and ( if no irq is given ) generate an autoirq ,
* register an ARCnet device .
*
* Currently , we can only register one device per probe , so quit
* after the first one is found .
*/
numprint = - 1 ;
for ( port = & ports [ 0 ] ; port < ports + numports ; port + + ) {
int found = 0 ;
numprint + + ;
numprint % = 8 ;
if ( ! numprint ) {
BUGMSG2 ( D_INIT , " \n " ) ;
BUGMSG2 ( D_INIT , " S5: " ) ;
}
BUGMSG2 ( D_INIT , " %Xh " , * port ) ;
ioaddr = * port ;
status = ASTATUS ( ) ;
if ( ( status & 0x9D )
! = ( NORXflag | RECONflag | TXFREEflag | RESETflag ) ) {
BUGMSG2 ( D_INIT_REASONS , " (status=%Xh) \n " , status ) ;
BUGMSG2 ( D_INIT_REASONS , " S5: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
release_region ( * port , ARCNET_TOTAL_SIZE ) ;
* port - - = ports [ - - numports ] ;
continue ;
}
ACOMMAND ( CFLAGScmd | RESETclear | CONFIGclear ) ;
status = ASTATUS ( ) ;
if ( status & RESETflag ) {
BUGMSG2 ( D_INIT_REASONS , " (eternal reset, status=%Xh) \n " ,
status ) ;
BUGMSG2 ( D_INIT_REASONS , " S5: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
release_region ( * port , ARCNET_TOTAL_SIZE ) ;
* port - - = ports [ - - numports ] ;
continue ;
}
/* skip this completely if an IRQ was given, because maybe
* we ' re on a machine that locks during autoirq !
*/
if ( ! irq ) {
/* if we do this, we're sure to get an IRQ since the
* card has just reset and the NORXflag is on until
* we tell it to start receiving .
*/
airqmask = probe_irq_on ( ) ;
AINTMASK ( NORXflag ) ;
udelay ( 1 ) ;
AINTMASK ( 0 ) ;
airq = probe_irq_off ( airqmask ) ;
if ( airq < = 0 ) {
BUGMSG2 ( D_INIT_REASONS , " (airq=%d) \n " , airq ) ;
BUGMSG2 ( D_INIT_REASONS , " S5: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
release_region ( * port , ARCNET_TOTAL_SIZE ) ;
* port - - = ports [ - - numports ] ;
continue ;
}
} else {
airq = irq ;
}
BUGMSG2 ( D_INIT , " (%d, " , airq ) ;
openparen = 1 ;
/* Everything seems okay. But which shmem, if any, puts
* back its signature byte when the card is reset ?
*
* If there are multiple cards installed , there might be
* multiple shmems still in the list .
*/
# ifdef FAST_PROBE
if ( numports > 1 | | numshmems > 1 ) {
inb ( _RESET ) ;
mdelay ( RESETtime ) ;
} else {
/* just one shmem and port, assume they match */
2005-12-02 03:54:44 -05:00
writeb ( TESTvalue , iomem [ 0 ] ) ;
2005-04-16 15:20:36 -07:00
}
# else
inb ( _RESET ) ;
mdelay ( RESETtime ) ;
# endif
2005-12-02 03:54:44 -05:00
for ( index = 0 ; index < numshmems ; index + + ) {
u_long ptr = shmems [ index ] ;
void __iomem * base = iomem [ index ] ;
2005-04-16 15:20:36 -07:00
2005-12-02 03:54:44 -05:00
if ( readb ( base ) = = TESTvalue ) { /* found one */
2005-04-16 15:20:36 -07:00
BUGMSG2 ( D_INIT , " %lXh) \n " , * p ) ;
openparen = 0 ;
/* register the card */
2005-12-02 03:54:44 -05:00
if ( com90xx_found ( * port , airq , ptr , base ) = = 0 )
2005-04-16 15:20:36 -07:00
found = 1 ;
numprint = - 1 ;
/* remove shmem from the list */
2005-12-02 03:54:44 -05:00
shmems [ index ] = shmems [ - - numshmems ] ;
iomem [ index ] = iomem [ numshmems ] ;
2005-04-16 15:20:36 -07:00
break ; /* go to the next I/O port */
} else {
2005-12-02 03:54:44 -05:00
BUGMSG2 ( D_INIT_REASONS , " %Xh- " , readb ( base ) ) ;
2005-04-16 15:20:36 -07:00
}
}
if ( openparen ) {
BUGLVL ( D_INIT ) printk ( " no matching shmem) \n " ) ;
BUGLVL ( D_INIT_REASONS ) printk ( " S5: " ) ;
BUGLVL ( D_INIT_REASONS ) numprint = 0 ;
}
if ( ! found )
release_region ( * port , ARCNET_TOTAL_SIZE ) ;
* port - - = ports [ - - numports ] ;
}
BUGLVL ( D_INIT_REASONS ) printk ( " \n " ) ;
/* Now put back TESTvalue on all leftover shmems. */
2005-12-02 03:54:44 -05:00
for ( index = 0 ; index < numshmems ; index + + ) {
writeb ( TESTvalue , iomem [ index ] ) ;
iounmap ( iomem [ index ] ) ;
release_mem_region ( shmems [ index ] , MIRROR_SIZE ) ;
2005-04-16 15:20:36 -07:00
}
2005-12-02 03:54:44 -05:00
kfree ( shmems ) ;
kfree ( iomem ) ;
2005-04-16 15:20:36 -07:00
}
2005-12-02 03:54:44 -05:00
static int check_mirror ( unsigned long addr , size_t size )
{
void __iomem * p ;
int res = - 1 ;
if ( ! request_mem_region ( addr , size , " arcnet (90xx) " ) )
return - 1 ;
p = ioremap ( addr , size ) ;
if ( p ) {
if ( readb ( p ) = = TESTvalue )
res = 1 ;
else
res = 0 ;
iounmap ( p ) ;
}
release_mem_region ( addr , size ) ;
return res ;
}
2005-04-16 15:20:36 -07:00
/* Set up the struct net_device associated with this card. Called after
* probing succeeds .
*/
2005-12-02 03:54:44 -05:00
static int __init com90xx_found ( int ioaddr , int airq , u_long shmem , void __iomem * p )
2005-04-16 15:20:36 -07:00
{
struct net_device * dev = NULL ;
struct arcnet_local * lp ;
u_long first_mirror , last_mirror ;
int mirror_size ;
/* allocate struct net_device */
dev = alloc_arcdev ( device ) ;
if ( ! dev ) {
BUGMSG2 ( D_NORMAL , " com90xx: Can't allocate device! \n " ) ;
2005-12-02 03:54:44 -05:00
iounmap ( p ) ;
release_mem_region ( shmem , MIRROR_SIZE ) ;
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
}
lp = dev - > priv ;
/* find the real shared memory start/end points, including mirrors */
/* guess the actual size of one "memory mirror" - the number of
* bytes between copies of the shared memory . On most cards , it ' s
* 2 k ( or there are no mirrors at all ) but on some , it ' s 4 k .
*/
mirror_size = MIRROR_SIZE ;
2005-12-02 03:54:44 -05:00
if ( readb ( p ) = = TESTvalue & &
check_mirror ( shmem - MIRROR_SIZE , MIRROR_SIZE ) = = 0 & &
check_mirror ( shmem - 2 * MIRROR_SIZE , MIRROR_SIZE ) = = 1 )
mirror_size = 2 * MIRROR_SIZE ;
2005-04-16 15:20:36 -07:00
2005-12-02 03:54:44 -05:00
first_mirror = shmem - mirror_size ;
while ( check_mirror ( first_mirror , mirror_size ) = = 1 )
2005-04-16 15:20:36 -07:00
first_mirror - = mirror_size ;
first_mirror + = mirror_size ;
2005-12-02 03:54:44 -05:00
last_mirror = shmem + mirror_size ;
while ( check_mirror ( last_mirror , mirror_size ) = = 1 )
2005-04-16 15:20:36 -07:00
last_mirror + = mirror_size ;
last_mirror - = mirror_size ;
dev - > mem_start = first_mirror ;
dev - > mem_end = last_mirror + MIRROR_SIZE - 1 ;
2005-12-02 03:54:44 -05:00
iounmap ( p ) ;
release_mem_region ( shmem , MIRROR_SIZE ) ;
2005-04-16 15:20:36 -07:00
if ( ! request_mem_region ( dev - > mem_start , dev - > mem_end - dev - > mem_start + 1 , " arcnet (90xx) " ) )
goto err_free_dev ;
/* reserve the irq */
if ( request_irq ( airq , & arcnet_interrupt , 0 , " arcnet (90xx) " , dev ) ) {
BUGMSG ( D_NORMAL , " Can't get IRQ %d! \n " , airq ) ;
goto err_release_mem ;
}
dev - > irq = airq ;
/* Initialize the rest of the device structure. */
lp - > card_name = " COM90xx " ;
lp - > hw . command = com90xx_command ;
lp - > hw . status = com90xx_status ;
lp - > hw . intmask = com90xx_setmask ;
lp - > hw . reset = com90xx_reset ;
lp - > hw . owner = THIS_MODULE ;
lp - > hw . copy_to_card = com90xx_copy_to_card ;
lp - > hw . copy_from_card = com90xx_copy_from_card ;
lp - > mem_start = ioremap ( dev - > mem_start , dev - > mem_end - dev - > mem_start + 1 ) ;
if ( ! lp - > mem_start ) {
BUGMSG ( D_NORMAL , " Can't remap device memory! \n " ) ;
goto err_free_irq ;
}
/* get and check the station ID from offset 1 in shmem */
dev - > dev_addr [ 0 ] = readb ( lp - > mem_start + 1 ) ;
dev - > base_addr = ioaddr ;
BUGMSG ( D_NORMAL , " COM90xx station %02Xh found at %03lXh, IRQ %d, "
" ShMem %lXh (%ld*%xh). \n " ,
dev - > dev_addr [ 0 ] ,
dev - > base_addr , dev - > irq , dev - > mem_start ,
( dev - > mem_end - dev - > mem_start + 1 ) / mirror_size , mirror_size ) ;
if ( register_netdev ( dev ) )
goto err_unmap ;
cards [ numcards + + ] = dev ;
return 0 ;
err_unmap :
iounmap ( lp - > mem_start ) ;
err_free_irq :
free_irq ( dev - > irq , dev ) ;
err_release_mem :
release_mem_region ( dev - > mem_start , dev - > mem_end - dev - > mem_start + 1 ) ;
err_free_dev :
free_netdev ( dev ) ;
return - EIO ;
}
static void com90xx_command ( struct net_device * dev , int cmd )
{
short ioaddr = dev - > base_addr ;
ACOMMAND ( cmd ) ;
}
static int com90xx_status ( struct net_device * dev )
{
short ioaddr = dev - > base_addr ;
return ASTATUS ( ) ;
}
static void com90xx_setmask ( struct net_device * dev , int mask )
{
short ioaddr = dev - > base_addr ;
AINTMASK ( mask ) ;
}
/*
* Do a hardware reset on the card , and set up necessary registers .
*
* This should be called as little as possible , because it disrupts the
* token on the network ( causes a RECON ) and requires a significant delay .
*
* However , it does make sure the card is in a defined state .
*/
int com90xx_reset ( struct net_device * dev , int really_reset )
{
struct arcnet_local * lp = dev - > priv ;
short ioaddr = dev - > base_addr ;
BUGMSG ( D_INIT , " Resetting (status=%02Xh) \n " , ASTATUS ( ) ) ;
if ( really_reset ) {
/* reset the card */
inb ( _RESET ) ;
mdelay ( RESETtime ) ;
}
ACOMMAND ( CFLAGScmd | RESETclear ) ; /* clear flags & end reset */
ACOMMAND ( CFLAGScmd | CONFIGclear ) ;
/* don't do this until we verify that it doesn't hurt older cards! */
/* outb(inb(_CONFIG) | ENABLE16flag, _CONFIG); */
/* verify that the ARCnet signature byte is present */
if ( readb ( lp - > mem_start ) ! = TESTvalue ) {
if ( really_reset )
BUGMSG ( D_NORMAL , " reset failed: TESTvalue not present. \n " ) ;
return 1 ;
}
/* enable extended (512-byte) packets */
ACOMMAND ( CONFIGcmd | EXTconf ) ;
/* clean out all the memory to make debugging make more sense :) */
BUGLVL ( D_DURING )
memset_io ( lp - > mem_start , 0x42 , 2048 ) ;
/* done! return success. */
return 0 ;
}
static void com90xx_copy_to_card ( struct net_device * dev , int bufnum , int offset ,
void * buf , int count )
{
struct arcnet_local * lp = dev - > priv ;
void __iomem * memaddr = lp - > mem_start + bufnum * 512 + offset ;
TIME ( " memcpy_toio " , count , memcpy_toio ( memaddr , buf , count ) ) ;
}
static void com90xx_copy_from_card ( struct net_device * dev , int bufnum , int offset ,
void * buf , int count )
{
struct arcnet_local * lp = dev - > priv ;
void __iomem * memaddr = lp - > mem_start + bufnum * 512 + offset ;
TIME ( " memcpy_fromio " , count , memcpy_fromio ( buf , memaddr , count ) ) ;
}
MODULE_LICENSE ( " GPL " ) ;
static int __init com90xx_init ( void )
{
if ( irq = = 2 )
irq = 9 ;
com90xx_probe ( ) ;
if ( ! numcards )
return - EIO ;
return 0 ;
}
static void __exit com90xx_exit ( void )
{
struct net_device * dev ;
struct arcnet_local * lp ;
int count ;
for ( count = 0 ; count < numcards ; count + + ) {
dev = cards [ count ] ;
lp = dev - > priv ;
unregister_netdev ( dev ) ;
free_irq ( dev - > irq , dev ) ;
iounmap ( lp - > mem_start ) ;
release_region ( dev - > base_addr , ARCNET_TOTAL_SIZE ) ;
release_mem_region ( dev - > mem_start , dev - > mem_end - dev - > mem_start + 1 ) ;
free_netdev ( dev ) ;
}
}
module_init ( com90xx_init ) ;
module_exit ( com90xx_exit ) ;
# ifndef MODULE
static int __init com90xx_setup ( char * s )
{
int ints [ 8 ] ;
s = get_options ( s , 8 , ints ) ;
if ( ! ints [ 0 ] & & ! * s ) {
printk ( " com90xx: Disabled. \n " ) ;
return 1 ;
}
switch ( ints [ 0 ] ) {
default : /* ERROR */
printk ( " com90xx: Too many arguments. \n " ) ;
case 3 : /* Mem address */
shmem = ints [ 3 ] ;
case 2 : /* IRQ */
irq = ints [ 2 ] ;
case 1 : /* IO address */
io = ints [ 1 ] ;
}
if ( * s )
snprintf ( device , sizeof ( device ) , " %s " , s ) ;
return 1 ;
}
__setup ( " com90xx= " , com90xx_setup ) ;
# endif