2005-04-17 02:20:36 +04:00
/*
* Linux ARCnet driver - COM20020 chipset support
2015-05-05 20:05:47 +03:00
*
2005-04-17 02:20:36 +04:00
* Written 1997 by David Woodhouse .
* 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/kernel.h>
# include <linux/types.h>
# include <linux/ioport.h>
# include <linux/errno.h>
# include <linux/delay.h>
# include <linux/netdevice.h>
# include <linux/init.h>
2011-06-06 14:43:46 +04:00
# include <linux/interrupt.h>
2005-04-17 02:20:36 +04:00
# include <linux/arcdevice.h>
# include <linux/com20020.h>
2015-05-05 20:05:51 +03:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
# define VERSION "arcnet: COM20020 chipset support (by David Woodhouse et al.)\n"
2015-05-05 20:05:49 +03:00
static char * clockrates [ ] = {
" XXXXXXX " , " XXXXXXXX " , " XXXXXX " ,
" 2.5 Mb/s " , " 1.25Mb/s " , " 625 Kb/s " , " 312.5 Kb/s " ,
" 156.25 Kb/s " , " Reserved " , " Reserved " , " Reserved "
} ;
2005-04-17 02:20:36 +04:00
static void com20020_command ( struct net_device * dev , int command ) ;
static int com20020_status ( struct net_device * dev ) ;
static void com20020_setmask ( struct net_device * dev , int mask ) ;
static int com20020_reset ( struct net_device * dev , int really_reset ) ;
static void com20020_copy_to_card ( struct net_device * dev , int bufnum ,
int offset , void * buf , int count ) ;
static void com20020_copy_from_card ( struct net_device * dev , int bufnum ,
int offset , void * buf , int count ) ;
static void com20020_set_mc_list ( struct net_device * dev ) ;
static void com20020_close ( struct net_device * ) ;
static void com20020_copy_from_card ( struct net_device * dev , int bufnum ,
int offset , void * buf , int count )
{
int ioaddr = dev - > base_addr , ofs = 512 * bufnum + offset ;
/* set up the address register */
outb ( ( ofs > > 8 ) | RDDATAflag | AUTOINCflag , _ADDR_HI ) ;
outb ( ofs & 0xff , _ADDR_LO ) ;
/* copy the data */
2015-05-05 20:05:55 +03:00
TIME ( dev , " insb " , count , insb ( _MEMDATA , buf , count ) ) ;
2005-04-17 02:20:36 +04:00
}
static void com20020_copy_to_card ( struct net_device * dev , int bufnum ,
int offset , void * buf , int count )
{
int ioaddr = dev - > base_addr , ofs = 512 * bufnum + offset ;
/* set up the address register */
outb ( ( ofs > > 8 ) | AUTOINCflag , _ADDR_HI ) ;
outb ( ofs & 0xff , _ADDR_LO ) ;
/* copy the data */
2015-05-05 20:05:55 +03:00
TIME ( dev , " outsb " , count , outsb ( _MEMDATA , buf , count ) ) ;
2005-04-17 02:20:36 +04:00
}
/* Reset the card and check some basic stuff during the detection stage. */
int com20020_check ( struct net_device * dev )
{
int ioaddr = dev - > base_addr , status ;
2008-11-13 10:37:49 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
ARCRESET0 ;
mdelay ( RESETtime ) ;
lp - > setup = lp - > clockm ? 0 : ( lp - > clockp < < 1 ) ;
lp - > setup2 = ( lp - > clockm < < 4 ) | 8 ;
/* CHECK: should we do this for SOHARD cards ? */
/* Enable P1Mode for backplane mode */
lp - > setup = lp - > setup | P1MODE ;
SET_SUBADR ( SUB_SETUP1 ) ;
outb ( lp - > setup , _XREG ) ;
2015-05-05 20:05:49 +03:00
if ( lp - > clockm ! = 0 ) {
2005-04-17 02:20:36 +04:00
SET_SUBADR ( SUB_SETUP2 ) ;
outb ( lp - > setup2 , _XREG ) ;
2015-05-05 20:05:47 +03:00
2005-04-17 02:20:36 +04:00
/* must now write the magic "restart operation" command */
mdelay ( 1 ) ;
outb ( 0x18 , _COMMAND ) ;
}
lp - > config = 0x21 | ( lp - > timeout < < 3 ) | ( lp - > backplane < < 2 ) ;
/* set node ID to 0x42 (but transmitter is disabled, so it's okay) */
SETCONF ;
2015-05-05 20:05:47 +03:00
outb ( 0x42 , ioaddr + BUS_ALIGN * 7 ) ;
2005-04-17 02:20:36 +04:00
status = ASTATUS ( ) ;
if ( ( status & 0x99 ) ! = ( NORXflag | TXFREEflag | RESETflag ) ) {
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " status invalid (%Xh). \n " , status ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
2015-05-05 20:05:55 +03:00
arc_printk ( D_INIT_REASONS , dev , " status after reset: %X \n " , status ) ;
2005-04-17 02:20:36 +04:00
/* Enable TX */
outb ( 0x39 , _CONFIG ) ;
2015-05-05 20:05:47 +03:00
outb ( inb ( ioaddr + BUS_ALIGN * 8 ) , ioaddr + BUS_ALIGN * 7 ) ;
2005-04-17 02:20:36 +04:00
ACOMMAND ( CFLAGScmd | RESETclear | CONFIGclear ) ;
status = ASTATUS ( ) ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_INIT_REASONS , dev , " status after reset acknowledged: %X \n " ,
status ) ;
2005-04-17 02:20:36 +04:00
/* Read first location of memory */
outb ( 0 | RDDATAflag | AUTOINCflag , _ADDR_HI ) ;
outb ( 0 , _ADDR_LO ) ;
if ( ( status = inb ( _MEMDATA ) ) ! = TESTvalue ) {
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Signature byte not found (%02Xh != D1h). \n " ,
status ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
return 0 ;
}
2014-09-29 13:55:35 +04:00
static int com20020_set_hwaddr ( struct net_device * dev , void * addr )
{
int ioaddr = dev - > base_addr ;
struct arcnet_local * lp = netdev_priv ( dev ) ;
struct sockaddr * hwaddr = addr ;
memcpy ( dev - > dev_addr , hwaddr - > sa_data , 1 ) ;
SET_SUBADR ( SUB_NODE ) ;
outb ( dev - > dev_addr [ 0 ] , _XREG ) ;
return 0 ;
}
2009-01-09 16:01:10 +03:00
const struct net_device_ops com20020_netdev_ops = {
. ndo_open = arcnet_open ,
. ndo_stop = arcnet_close ,
. ndo_start_xmit = arcnet_send_packet ,
. ndo_tx_timeout = arcnet_timeout ,
2014-09-29 13:55:35 +04:00
. ndo_set_mac_address = com20020_set_hwaddr ,
2011-08-16 10:29:01 +04:00
. ndo_set_rx_mode = com20020_set_mc_list ,
2009-01-09 16:01:10 +03:00
} ;
2005-04-17 02:20:36 +04:00
/* Set up the struct net_device associated with this card. Called after
* probing succeeds .
*/
int com20020_found ( struct net_device * dev , int shared )
{
struct arcnet_local * lp ;
int ioaddr = dev - > base_addr ;
/* 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 - > hw . owner = THIS_MODULE ;
lp - > hw . command = com20020_command ;
lp - > hw . status = com20020_status ;
lp - > hw . intmask = com20020_setmask ;
lp - > hw . reset = com20020_reset ;
lp - > hw . copy_to_card = com20020_copy_to_card ;
lp - > hw . copy_from_card = com20020_copy_from_card ;
lp - > hw . close = com20020_close ;
if ( ! dev - > dev_addr [ 0 ] )
2015-05-05 20:05:47 +03:00
dev - > dev_addr [ 0 ] = inb ( ioaddr + BUS_ALIGN * 8 ) ; /* FIXME: do this some other way! */
2005-04-17 02:20:36 +04:00
SET_SUBADR ( SUB_SETUP1 ) ;
outb ( lp - > setup , _XREG ) ;
2015-05-05 20:05:49 +03:00
if ( lp - > card_flags & ARC_CAN_10MBIT ) {
2005-04-17 02:20:36 +04:00
SET_SUBADR ( SUB_SETUP2 ) ;
outb ( lp - > setup2 , _XREG ) ;
2015-05-05 20:05:47 +03:00
2005-04-17 02:20:36 +04:00
/* must now write the magic "restart operation" command */
mdelay ( 1 ) ;
outb ( 0x18 , _COMMAND ) ;
}
lp - > config = 0x20 | ( lp - > timeout < < 3 ) | ( lp - > backplane < < 2 ) | 1 ;
/* Default 0x38 + register: Node ID */
SETCONF ;
outb ( dev - > dev_addr [ 0 ] , _XREG ) ;
/* reserve the irq */
2009-11-19 10:29:17 +03:00
if ( request_irq ( dev - > irq , arcnet_interrupt , shared ,
2005-04-17 02:20:36 +04:00
" arcnet (COM20020) " , dev ) ) {
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 ;
}
dev - > base_addr = ioaddr ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " %s: station %02Xh found at %03lXh, IRQ %d. \n " ,
lp - > card_name , dev - > dev_addr [ 0 ] , dev - > base_addr , dev - > irq ) ;
2005-04-17 02:20:36 +04:00
if ( lp - > backplane )
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Using backplane mode. \n " ) ;
2005-04-17 02:20:36 +04:00
if ( lp - > timeout ! = 3 )
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Using extended timeout value of %d \n " ,
lp - > timeout ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Using CKP %d - data rate %s \n " ,
lp - > setup > > 1 ,
clockrates [ 3 - ( ( lp - > setup2 & 0xF0 ) > > 4 ) + ( ( lp - > setup & 0x0F ) > > 1 ) ] ) ;
2005-04-17 02:20:36 +04:00
if ( register_netdev ( dev ) ) {
free_irq ( dev - > irq , dev ) ;
return - EIO ;
}
return 0 ;
}
2015-05-05 20:05:52 +03:00
/* Do a hardware reset on the card, and set up necessary registers.
2015-05-05 20:05:47 +03:00
*
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 com20020_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
u_int ioaddr = dev - > base_addr ;
u_char inbyte ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_DEBUG , dev , " %s: %d: %s: dev: %p, lp: %p, dev->name: %s \n " ,
__FILE__ , __LINE__ , __func__ , dev , lp , dev - > name ) ;
arc_printk ( D_INIT , dev , " Resetting %s (status=%02Xh) \n " ,
dev - > name , ASTATUS ( ) ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:55 +03:00
arc_printk ( D_DEBUG , dev , " %s: %d: %s \n " , __FILE__ , __LINE__ , __func__ ) ;
2005-04-17 02:20:36 +04:00
lp - > config = TXENcfg | ( lp - > timeout < < 3 ) | ( lp - > backplane < < 2 ) ;
/* power-up defaults */
SETCONF ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_DEBUG , dev , " %s: %d: %s \n " , __FILE__ , __LINE__ , __func__ ) ;
2005-04-17 02:20:36 +04:00
if ( really_reset ) {
/* reset the card */
ARCRESET ;
mdelay ( RESETtime * 2 ) ; /* COM20020 seems to be slower sometimes */
}
/* clear flags & end reset */
2015-05-05 20:05:55 +03:00
arc_printk ( D_DEBUG , dev , " %s: %d: %s \n " , __FILE__ , __LINE__ , __func__ ) ;
2005-04-17 02:20:36 +04:00
ACOMMAND ( CFLAGScmd | RESETclear | CONFIGclear ) ;
/* verify that the ARCnet signature byte is present */
2015-05-05 20:05:55 +03:00
arc_printk ( D_DEBUG , dev , " %s: %d: %s \n " , __FILE__ , __LINE__ , __func__ ) ;
2005-04-17 02:20:36 +04:00
com20020_copy_from_card ( dev , 0 , 0 , & inbyte , 1 ) ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_DEBUG , dev , " %s: %d: %s \n " , __FILE__ , __LINE__ , __func__ ) ;
2005-04-17 02:20:36 +04:00
if ( inbyte ! = TESTvalue ) {
2015-05-05 20:05:55 +03:00
arc_printk ( D_DEBUG , dev , " %s: %d: %s \n " ,
__FILE__ , __LINE__ , __func__ ) ;
arc_printk ( D_NORMAL , dev , " reset failed: TESTvalue not present. \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
/* enable extended (512-byte) packets */
ACOMMAND ( CONFIGcmd | EXTconf ) ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_DEBUG , dev , " %s: %d: %s \n " , __FILE__ , __LINE__ , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* done! return success. */
return 0 ;
}
static void com20020_setmask ( struct net_device * dev , int mask )
{
u_int ioaddr = dev - > base_addr ;
2015-05-05 20:05:48 +03:00
2015-05-05 20:05:55 +03:00
arc_printk ( D_DURING , dev , " Setting mask to %x at %x \n " , mask , ioaddr ) ;
2005-04-17 02:20:36 +04:00
AINTMASK ( mask ) ;
}
static void com20020_command ( struct net_device * dev , int cmd )
{
u_int ioaddr = dev - > base_addr ;
2015-05-05 20:05:48 +03:00
2005-04-17 02:20:36 +04:00
ACOMMAND ( cmd ) ;
}
static int com20020_status ( struct net_device * dev )
{
u_int ioaddr = dev - > base_addr ;
2015-05-05 20:05:47 +03:00
return ASTATUS ( ) + ( ADIAGSTATUS ( ) < < 8 ) ;
2005-04-17 02:20:36 +04:00
}
static void com20020_close ( 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
int ioaddr = dev - > base_addr ;
/* disable transmitter */
lp - > config & = ~ TXENcfg ;
SETCONF ;
}
/* Set or clear the multicast filter for this adaptor.
* num_addrs = = - 1 Promiscuous mode , receive all packets
* num_addrs = = 0 Normal mode , clear multicast list
* num_addrs > 0 Multicast mode , receive normal and MC packets , and do
* best - effort filtering .
* FIXME - do multicast stuff , not just promiscuous .
*/
static void com20020_set_mc_list ( 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
int ioaddr = dev - > base_addr ;
if ( ( dev - > flags & IFF_PROMISC ) & & ( dev - > flags & IFF_UP ) ) { /* Enable promiscuous mode */
if ( ! ( lp - > setup & PROMISCset ) )
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Setting promiscuous flag... \n " ) ;
2005-04-17 02:20:36 +04:00
SET_SUBADR ( SUB_SETUP1 ) ;
lp - > setup | = PROMISCset ;
outb ( lp - > setup , _XREG ) ;
} else
/* Disable promiscuous mode, use normal mode */
{
if ( ( lp - > setup & PROMISCset ) )
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " Resetting promiscuous flag... \n " ) ;
2005-04-17 02:20:36 +04:00
SET_SUBADR ( SUB_SETUP1 ) ;
lp - > setup & = ~ PROMISCset ;
outb ( lp - > setup , _XREG ) ;
}
}
2006-11-09 06:51:03 +03:00
# if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \
2007-02-12 11:52:22 +03:00
defined ( CONFIG_ARCNET_COM20020_ISA_MODULE ) | | \
defined ( CONFIG_ARCNET_COM20020_CS_MODULE )
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( com20020_check ) ;
EXPORT_SYMBOL ( com20020_found ) ;
2009-01-26 08:17:25 +03:00
EXPORT_SYMBOL ( com20020_netdev_ops ) ;
2006-11-09 06:51:03 +03:00
# endif
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2006-11-09 06:51:03 +03:00
# ifdef MODULE
2008-02-28 10:31:08 +03:00
static int __init com20020_module_init ( void )
2005-04-17 02:20:36 +04:00
{
2015-05-05 20:05:54 +03:00
if ( BUGLVL ( D_NORMAL ) )
printk ( VERSION ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-02-28 10:31:08 +03:00
static void __exit com20020_module_exit ( void )
2005-04-17 02:20:36 +04:00
{
}
2008-02-28 10:31:08 +03:00
module_init ( com20020_module_init ) ;
module_exit ( com20020_module_exit ) ;
2005-04-17 02:20:36 +04:00
# endif /* MODULE */