2005-04-17 02:20:36 +04:00
/*
* Linux ARCnet driver - " RIM I " ( entirely mem - mapped ) cards
2015-05-05 20:05:47 +03:00
*
2005-04-17 02:20:36 +04:00
* Written 1994 - 1999 by Avery Pennarun .
* Written 1999 - 2000 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
*
* * * * * * * * * * * * * * * * * * * * * * *
*/
2015-05-05 20:05:56 +03:00
# define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/ioport.h>
# include <linux/delay.h>
# include <linux/netdevice.h>
# include <linux/bootmem.h>
# include <linux/init.h>
2011-06-06 14:43:46 +04:00
# include <linux/interrupt.h>
2015-05-05 20:05:51 +03:00
# include <linux/io.h>
2015-05-05 20:06:03 +03:00
# include "arcdevice.h"
2015-05-05 20:06:13 +03:00
# include "com9026.h"
2005-04-17 02:20:36 +04:00
/* Internal function declarations */
static int arcrimi_probe ( struct net_device * dev ) ;
static int arcrimi_found ( struct net_device * dev ) ;
static void arcrimi_command ( struct net_device * dev , int command ) ;
static int arcrimi_status ( struct net_device * dev ) ;
static void arcrimi_setmask ( struct net_device * dev , int mask ) ;
static int arcrimi_reset ( struct net_device * dev , int really_reset ) ;
static void arcrimi_copy_to_card ( struct net_device * dev , int bufnum , int offset ,
void * buf , int count ) ;
2015-05-05 20:06:02 +03:00
static void arcrimi_copy_from_card ( struct net_device * dev , int bufnum ,
int offset , void * buf , int count ) ;
2005-04-17 02:20:36 +04:00
/* Handy defines for ARCnet specific stuff */
/* Amount of I/O memory used by the card */
2015-05-05 20:05:47 +03:00
# define BUFFER_SIZE (512)
# define MIRROR_SIZE (BUFFER_SIZE * 4)
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:52 +03:00
/* We cannot probe for a RIM I card; one reason is I don't know how to reset
2005-04-17 02:20:36 +04:00
* them . In fact , we can ' t even get their node ID automatically . So , we
* need to be passed a specific shmem address , IRQ , and node ID .
*/
static int __init arcrimi_probe ( struct net_device * dev )
{
2015-05-05 20:05:54 +03:00
if ( BUGLVL ( D_NORMAL ) ) {
2015-05-05 20:05:56 +03:00
pr_info ( " %s \n " , " RIM I (entirely mem-mapped) support " ) ;
pr_info ( " E-mail me if you actually test the RIM I driver, please! \n " ) ;
pr_info ( " Given: node %02Xh, shmem %lXh, irq %d \n " ,
dev - > dev_addr [ 0 ] , dev - > mem_start , dev - > irq ) ;
2015-05-05 20:05:54 +03:00
}
2005-04-17 02:20:36 +04:00
if ( dev - > mem_start < = 0 | | dev - > irq < = 0 ) {
2015-05-05 20:05:54 +03:00
if ( BUGLVL ( D_NORMAL ) )
2015-05-05 20:05:56 +03:00
pr_err ( " No autoprobe for RIM I; you must specify the shmem and irq! \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
2005-12-02 11:54:44 +03:00
if ( dev - > dev_addr [ 0 ] = = 0 ) {
2015-05-05 20:05:54 +03:00
if ( BUGLVL ( D_NORMAL ) )
2015-05-05 20:05:56 +03:00
pr_err ( " You need to specify your card's station ID! \n " ) ;
2005-12-02 11:54:44 +03:00
return - ENODEV ;
}
2015-05-05 20:05:52 +03:00
/* Grab the memory region at mem_start for MIRROR_SIZE bytes.
2005-04-17 02:20:36 +04:00
* Later in arcrimi_found ( ) the real size will be determined
* and this reserve will be released and the correct size
* will be taken .
*/
2005-12-02 11:54:44 +03:00
if ( ! request_mem_region ( dev - > mem_start , MIRROR_SIZE , " arcnet (90xx) " ) ) {
2015-05-05 20:05:54 +03:00
if ( BUGLVL ( D_NORMAL ) )
2015-05-05 20:05:56 +03:00
pr_notice ( " Card memory already allocated \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
return arcrimi_found ( dev ) ;
}
2005-12-02 11:54:44 +03: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 ) {
2015-05-05 20:06:10 +03:00
if ( arcnet_readb ( p , COM9026_REG_R_STATUS ) = = TESTvalue )
2005-12-02 11:54:44 +03:00
res = 1 ;
else
res = 0 ;
iounmap ( p ) ;
}
release_mem_region ( addr , size ) ;
return res ;
}
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:52 +03:00
/* Set up the struct net_device associated with this card.
* Called after probing succeeds .
2005-04-17 02:20:36 +04:00
*/
static int __init arcrimi_found ( struct net_device * dev )
{
struct arcnet_local * lp ;
unsigned long first_mirror , last_mirror , shmem ;
2005-12-02 11:54:44 +03:00
void __iomem * p ;
2005-04-17 02:20:36 +04:00
int mirror_size ;
int err ;
2005-12-02 11:54:44 +03:00
p = ioremap ( dev - > mem_start , MIRROR_SIZE ) ;
if ( ! p ) {
release_mem_region ( dev - > mem_start , MIRROR_SIZE ) ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Can't ioremap \n " ) ;
2005-12-02 11:54:44 +03:00
return - ENODEV ;
}
2005-04-17 02:20:36 +04:00
/* reserve the irq */
2009-11-19 10:29:17 +03:00
if ( request_irq ( dev - > irq , arcnet_interrupt , 0 , " arcnet (RIM I) " , dev ) ) {
2005-12-02 11:54:44 +03:00
iounmap ( p ) ;
release_mem_region ( dev - > mem_start , MIRROR_SIZE ) ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Can't get IRQ %d! \n " , dev - > irq ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
shmem = dev - > mem_start ;
2015-05-05 20:06:10 +03:00
arcnet_writeb ( TESTvalue , p , COM9026_REG_W_INTMASK ) ;
arcnet_writeb ( TESTvalue , p , COM9026_REG_W_COMMAND ) ;
/* actually the station/node ID */
2005-04-17 02:20:36 +04:00
/* 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 ;
2015-05-05 20:06:10 +03:00
if ( arcnet_readb ( p , COM9026_REG_R_STATUS ) = = TESTvalue & &
2009-12-03 10:58:21 +03:00
check_mirror ( shmem - MIRROR_SIZE , MIRROR_SIZE ) = = 0 & &
check_mirror ( shmem - 2 * MIRROR_SIZE , MIRROR_SIZE ) = = 1 )
2005-12-02 11:54:44 +03:00
mirror_size = 2 * MIRROR_SIZE ;
2005-04-17 02:20:36 +04:00
2005-12-02 11:54:44 +03:00
first_mirror = shmem - mirror_size ;
while ( check_mirror ( first_mirror , mirror_size ) = = 1 )
2005-04-17 02:20:36 +04:00
first_mirror - = mirror_size ;
first_mirror + = mirror_size ;
2005-12-02 11:54:44 +03:00
last_mirror = shmem + mirror_size ;
while ( check_mirror ( last_mirror , mirror_size ) = = 1 )
2005-04-17 02:20:36 +04:00
last_mirror + = mirror_size ;
last_mirror - = mirror_size ;
dev - > mem_start = first_mirror ;
dev - > mem_end = last_mirror + MIRROR_SIZE - 1 ;
/* initialize the rest of the device structure. */
2008-11-13 10:37:49 +03:00
lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
lp - > card_name = " RIM I " ;
lp - > hw . command = arcrimi_command ;
lp - > hw . status = arcrimi_status ;
lp - > hw . intmask = arcrimi_setmask ;
lp - > hw . reset = arcrimi_reset ;
lp - > hw . owner = THIS_MODULE ;
lp - > hw . copy_to_card = arcrimi_copy_to_card ;
lp - > hw . copy_from_card = arcrimi_copy_from_card ;
2015-05-05 20:05:52 +03:00
/* re-reserve the memory region - arcrimi_probe() alloced this reqion
2005-04-17 02:20:36 +04:00
* but didn ' t know the real size . Free that region and then re - get
* with the correct size . There is a VERY slim chance this could
* fail .
*/
2005-12-02 11:54:44 +03:00
iounmap ( p ) ;
release_mem_region ( shmem , MIRROR_SIZE ) ;
2005-04-17 02:20:36 +04:00
if ( ! request_mem_region ( dev - > mem_start ,
dev - > mem_end - dev - > mem_start + 1 ,
" arcnet (90xx) " ) ) {
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Card memory already allocated \n " ) ;
2005-04-17 02:20:36 +04:00
goto err_free_irq ;
}
2015-05-05 20:06:02 +03:00
lp - > mem_start = ioremap ( dev - > mem_start ,
dev - > mem_end - dev - > mem_start + 1 ) ;
2005-04-17 02:20:36 +04:00
if ( ! lp - > mem_start ) {
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Can't remap device memory! \n " ) ;
2005-04-17 02:20:36 +04:00
goto err_release_mem ;
}
/* get and check the station ID from offset 1 in shmem */
2015-05-05 20:06:10 +03:00
dev - > dev_addr [ 0 ] = arcnet_readb ( lp - > mem_start , COM9026_REG_R_STATION ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " ARCnet RIM I: station %02Xh found at IRQ %d, ShMem %lXh (%ld*%d bytes) \n " ,
dev - > dev_addr [ 0 ] ,
dev - > irq , dev - > mem_start ,
( dev - > mem_end - dev - > mem_start + 1 ) / mirror_size ,
mirror_size ) ;
2005-04-17 02:20:36 +04:00
err = register_netdev ( dev ) ;
if ( err )
goto err_unmap ;
return 0 ;
err_unmap :
iounmap ( lp - > mem_start ) ;
err_release_mem :
release_mem_region ( dev - > mem_start , dev - > mem_end - dev - > mem_start + 1 ) ;
err_free_irq :
free_irq ( dev - > irq , dev ) ;
return - EIO ;
}
2015-05-05 20:05:52 +03:00
/* Do a hardware reset on the card, and set up necessary registers.
2005-04-17 02:20:36 +04:00
*
* 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 .
*/
static int arcrimi_reset ( struct net_device * dev , int really_reset )
{
2008-11-13 10:37:49 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void __iomem * ioaddr = lp - > mem_start + 0x800 ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_INIT , dev , " Resetting %s (status=%02Xh) \n " ,
2015-05-05 20:06:10 +03:00
dev - > name , arcnet_readb ( ioaddr , COM9026_REG_R_STATUS ) ) ;
2005-04-17 02:20:36 +04:00
if ( really_reset ) {
2015-05-05 20:06:10 +03:00
arcnet_writeb ( TESTvalue , ioaddr , - 0x800 ) ; /* fake reset */
2005-04-17 02:20:36 +04:00
return 0 ;
}
2015-05-05 20:06:10 +03:00
/* clear flags & end reset */
arcnet_writeb ( CFLAGScmd | RESETclear , ioaddr , COM9026_REG_W_COMMAND ) ;
arcnet_writeb ( CFLAGScmd | CONFIGclear , ioaddr , COM9026_REG_W_COMMAND ) ;
2005-04-17 02:20:36 +04:00
/* enable extended (512-byte) packets */
2015-05-05 20:06:10 +03:00
arcnet_writeb ( CONFIGcmd | EXTconf , ioaddr , COM9026_REG_W_COMMAND ) ;
2005-04-17 02:20:36 +04:00
/* done! return success. */
return 0 ;
}
static void arcrimi_setmask ( struct net_device * dev , int mask )
{
2008-11-13 10:37:49 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void __iomem * ioaddr = lp - > mem_start + 0x800 ;
2015-05-05 20:06:10 +03:00
arcnet_writeb ( mask , ioaddr , COM9026_REG_W_INTMASK ) ;
2005-04-17 02:20:36 +04:00
}
static int arcrimi_status ( struct net_device * dev )
{
2008-11-13 10:37:49 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void __iomem * ioaddr = lp - > mem_start + 0x800 ;
2015-05-05 20:06:10 +03:00
return arcnet_readb ( ioaddr , COM9026_REG_R_STATUS ) ;
2005-04-17 02:20:36 +04:00
}
static void arcrimi_command ( struct net_device * dev , int cmd )
{
2008-11-13 10:37:49 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void __iomem * ioaddr = lp - > mem_start + 0x800 ;
2015-05-05 20:06:10 +03:00
arcnet_writeb ( cmd , ioaddr , COM9026_REG_W_COMMAND ) ;
2005-04-17 02:20:36 +04:00
}
static void arcrimi_copy_to_card ( struct net_device * dev , int bufnum , int offset ,
void * buf , int count )
{
2008-11-13 10:37:49 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void __iomem * memaddr = lp - > mem_start + 0x800 + bufnum * 512 + offset ;
2015-05-05 20:05:48 +03:00
2015-05-05 20:05:55 +03:00
TIME ( dev , " memcpy_toio " , count , memcpy_toio ( memaddr , buf , count ) ) ;
2005-04-17 02:20:36 +04:00
}
2015-05-05 20:06:02 +03:00
static void arcrimi_copy_from_card ( struct net_device * dev , int bufnum ,
int offset , void * buf , int count )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void __iomem * memaddr = lp - > mem_start + 0x800 + bufnum * 512 + offset ;
2015-05-05 20:05:48 +03:00
2015-05-05 20:05:55 +03:00
TIME ( dev , " memcpy_fromio " , count , memcpy_fromio ( buf , memaddr , count ) ) ;
2005-04-17 02:20:36 +04:00
}
static int node ;
static int io ; /* use the insmod io= irq= node= options */
static int irq ;
static char device [ 9 ] ; /* use eg. device=arc1 to change name */
module_param ( node , int , 0 ) ;
module_param ( io , int , 0 ) ;
module_param ( irq , int , 0 ) ;
module_param_string ( device , device , sizeof ( device ) , 0 ) ;
MODULE_LICENSE ( " GPL " ) ;
static struct net_device * my_dev ;
static int __init arc_rimi_init ( void )
{
struct net_device * dev ;
dev = alloc_arcdev ( device ) ;
if ( ! dev )
return - ENOMEM ;
if ( node & & node ! = 0xff )
dev - > dev_addr [ 0 ] = node ;
dev - > mem_start = io ;
dev - > irq = irq ;
if ( dev - > irq = = 2 )
dev - > irq = 9 ;
if ( arcrimi_probe ( dev ) ) {
free_netdev ( dev ) ;
return - EIO ;
}
my_dev = dev ;
return 0 ;
}
static void __exit arc_rimi_exit ( void )
{
struct net_device * dev = my_dev ;
2008-11-13 10:37:49 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
unregister_netdev ( dev ) ;
iounmap ( lp - > mem_start ) ;
release_mem_region ( dev - > mem_start , dev - > mem_end - dev - > mem_start + 1 ) ;
free_irq ( dev - > irq , dev ) ;
free_netdev ( dev ) ;
}
# ifndef MODULE
static int __init arcrimi_setup ( char * s )
{
int ints [ 8 ] ;
2015-05-05 20:05:48 +03:00
2005-04-17 02:20:36 +04:00
s = get_options ( s , 8 , ints ) ;
if ( ! ints [ 0 ] )
return 1 ;
switch ( ints [ 0 ] ) {
default : /* ERROR */
2015-05-05 20:05:56 +03:00
pr_err ( " Too many arguments \n " ) ;
2005-04-17 02:20:36 +04:00
case 3 : /* Node ID */
node = 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 ( " arcrimi= " , arcrimi_setup ) ;
# endif /* MODULE */
module_init ( arc_rimi_init )
module_exit ( arc_rimi_exit )