2005-04-17 02:20:36 +04:00
/*
* linux / drivers / acorn / net / etherh . c
*
* Copyright ( C ) 2000 - 2002 Russell King
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* NS8390 I - cubed EtherH and ANT EtherM specific driver
* Thanks to I - Cubed for information on their cards .
* EtherM conversion ( C ) 1999 Chris Kemp and Tim Watterton
* EtherM integration ( C ) 2000 Aleph One Ltd ( Tak - Shing Chan )
* EtherM integration re - engineered by Russell King .
*
* Changelog :
* 08 - 12 - 1996 RMK 1.00 Created
* RMK 1.03 Added support for EtherLan500 cards
* 23 - 11 - 1997 RMK 1.04 Added media autodetection
* 16 - 04 - 1998 RMK 1.05 Improved media autodetection
* 10 - 02 - 2000 RMK 1.06 Updated for 2.3 .43
* 13 - 05 - 2000 RMK 1.07 Updated for 2.3 .99 - pre8
* 12 - 10 - 1999 CK / TEW EtherM driver first release
* 21 - 12 - 2000 TTC EtherH / EtherM integration
* 25 - 12 - 2000 RMK 1.08 Clean integration of EtherM into this driver .
* 03 - 01 - 2002 RMK 1.09 Always enable IRQs if we ' re in the nic slot .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/in.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/ethtool.h>
# include <linux/skbuff.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/init.h>
# include <linux/bitops.h>
2006-01-10 05:37:15 +03:00
# include <linux/jiffies.h>
2005-04-17 02:20:36 +04:00
# include <asm/ecard.h>
# include <asm/io.h>
2012-03-28 21:30:01 +04:00
# include <asm/system_info.h>
2005-04-17 02:20:36 +04:00
2006-10-10 03:19:36 +04:00
# define EI_SHIFT(x) (ei_local->reg_offset[x])
2006-10-10 03:19:36 +04:00
# define ei_inb(_p) readb((void __iomem *)_p)
# define ei_outb(_v,_p) writeb(_v,(void __iomem *)_p)
# define ei_inb_p(_p) readb((void __iomem *)_p)
# define ei_outb_p(_v,_p) writeb(_v,(void __iomem *)_p)
2005-04-17 02:20:36 +04:00
# define NET_DEBUG 0
# define DEBUG_INIT 2
# define DRV_NAME "etherh"
# define DRV_VERSION "1.11"
2006-10-10 03:19:36 +04:00
static char version [ ] __initdata =
" EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION " \n " ;
2011-04-02 17:20:12 +04:00
# include "lib8390.c"
2006-10-10 03:19:36 +04:00
2005-04-17 02:20:36 +04:00
static unsigned int net_debug = NET_DEBUG ;
struct etherh_priv {
void __iomem * ioc_fast ;
void __iomem * memc ;
void __iomem * dma_base ;
unsigned int id ;
void __iomem * ctrl_port ;
unsigned char ctrl ;
u32 supported ;
} ;
struct etherh_data {
unsigned long ns8390_offset ;
unsigned long dataport_offset ;
unsigned long ctrlport_offset ;
int ctrl_ioc ;
const char name [ 16 ] ;
u32 supported ;
unsigned char tx_start_page ;
unsigned char stop_page ;
} ;
MODULE_AUTHOR ( " Russell King " ) ;
MODULE_DESCRIPTION ( " EtherH/EtherM driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
# define ETHERH500_DATAPORT 0x800 /* MEMC */
# define ETHERH500_NS8390 0x000 /* MEMC */
# define ETHERH500_CTRLPORT 0x800 /* IOC */
# define ETHERH600_DATAPORT 0x040 /* MEMC */
# define ETHERH600_NS8390 0x800 /* MEMC */
# define ETHERH600_CTRLPORT 0x200 /* MEMC */
# define ETHERH_CP_IE 1
# define ETHERH_CP_IF 2
# define ETHERH_CP_HEARTBEAT 2
# define ETHERH_TX_START_PAGE 1
# define ETHERH_STOP_PAGE 127
/*
* These came from CK / TEW
*/
# define ETHERM_DATAPORT 0x200 /* MEMC */
# define ETHERM_NS8390 0x800 /* MEMC */
# define ETHERM_CTRLPORT 0x23c /* MEMC */
# define ETHERM_TX_START_PAGE 64
# define ETHERM_STOP_PAGE 127
/* ------------------------------------------------------------------------ */
# define etherh_priv(dev) \
( ( struct etherh_priv * ) ( ( ( char * ) netdev_priv ( dev ) ) + sizeof ( struct ei_device ) ) )
static inline void etherh_set_ctrl ( struct etherh_priv * eh , unsigned char mask )
{
unsigned char ctrl = eh - > ctrl | mask ;
eh - > ctrl = ctrl ;
writeb ( ctrl , eh - > ctrl_port ) ;
}
static inline void etherh_clr_ctrl ( struct etherh_priv * eh , unsigned char mask )
{
unsigned char ctrl = eh - > ctrl & ~ mask ;
eh - > ctrl = ctrl ;
writeb ( ctrl , eh - > ctrl_port ) ;
}
static inline unsigned int etherh_get_stat ( struct etherh_priv * eh )
{
return readb ( eh - > ctrl_port ) ;
}
static void etherh_irq_enable ( ecard_t * ec , int irqnr )
{
struct etherh_priv * eh = ec - > irq_data ;
etherh_set_ctrl ( eh , ETHERH_CP_IE ) ;
}
static void etherh_irq_disable ( ecard_t * ec , int irqnr )
{
struct etherh_priv * eh = ec - > irq_data ;
etherh_clr_ctrl ( eh , ETHERH_CP_IE ) ;
}
static expansioncard_ops_t etherh_ops = {
. irqenable = etherh_irq_enable ,
. irqdisable = etherh_irq_disable ,
} ;
static void
etherh_setif ( struct net_device * dev )
{
struct ei_device * ei_local = netdev_priv ( dev ) ;
unsigned long flags ;
void __iomem * addr ;
local_irq_save ( flags ) ;
/* set the interface type */
switch ( etherh_priv ( dev ) - > id ) {
case PROD_I3_ETHERLAN600 :
case PROD_I3_ETHERLAN600A :
2006-10-10 03:19:36 +04:00
addr = ( void __iomem * ) dev - > base_addr + EN0_RCNTHI ;
2005-04-17 02:20:36 +04:00
switch ( dev - > if_port ) {
case IF_PORT_10BASE2 :
writeb ( ( readb ( addr ) & 0xf8 ) | 1 , addr ) ;
break ;
case IF_PORT_10BASET :
writeb ( ( readb ( addr ) & 0xf8 ) , addr ) ;
break ;
}
break ;
case PROD_I3_ETHERLAN500 :
switch ( dev - > if_port ) {
case IF_PORT_10BASE2 :
etherh_clr_ctrl ( etherh_priv ( dev ) , ETHERH_CP_IF ) ;
break ;
case IF_PORT_10BASET :
etherh_set_ctrl ( etherh_priv ( dev ) , ETHERH_CP_IF ) ;
break ;
}
break ;
default :
break ;
}
local_irq_restore ( flags ) ;
}
static int
etherh_getifstat ( struct net_device * dev )
{
struct ei_device * ei_local = netdev_priv ( dev ) ;
void __iomem * addr ;
int stat = 0 ;
switch ( etherh_priv ( dev ) - > id ) {
case PROD_I3_ETHERLAN600 :
case PROD_I3_ETHERLAN600A :
2006-10-10 03:19:36 +04:00
addr = ( void __iomem * ) dev - > base_addr + EN0_RCNTHI ;
2005-04-17 02:20:36 +04:00
switch ( dev - > if_port ) {
case IF_PORT_10BASE2 :
stat = 1 ;
break ;
case IF_PORT_10BASET :
stat = readb ( addr ) & 4 ;
break ;
}
break ;
case PROD_I3_ETHERLAN500 :
switch ( dev - > if_port ) {
case IF_PORT_10BASE2 :
stat = 1 ;
break ;
case IF_PORT_10BASET :
stat = etherh_get_stat ( etherh_priv ( dev ) ) & ETHERH_CP_HEARTBEAT ;
break ;
}
break ;
default :
stat = 0 ;
break ;
}
return stat ! = 0 ;
}
/*
* Configure the interface . Note that we ignore the other
* parts of ifmap , since its mostly meaningless for this driver .
*/
static int etherh_set_config ( struct net_device * dev , struct ifmap * map )
{
switch ( map - > port ) {
case IF_PORT_10BASE2 :
case IF_PORT_10BASET :
/*
* If the user explicitly sets the interface
* media type , turn off automedia detection .
*/
dev - > flags & = ~ IFF_AUTOMEDIA ;
dev - > if_port = map - > port ;
break ;
default :
return - EINVAL ;
}
etherh_setif ( dev ) ;
return 0 ;
}
/*
* Reset the 8390 ( hard reset ) . Note that we can ' t actually do this .
*/
static void
etherh_reset ( struct net_device * dev )
{
struct ei_device * ei_local = netdev_priv ( dev ) ;
2006-10-10 03:19:36 +04:00
void __iomem * addr = ( void __iomem * ) dev - > base_addr ;
2005-04-17 02:20:36 +04:00
writeb ( E8390_NODMA + E8390_PAGE0 + E8390_STOP , addr ) ;
/*
* See if we need to change the interface type .
* Note that we use ' interface_num ' as a flag
* to indicate that we need to change the media .
*/
if ( dev - > flags & IFF_AUTOMEDIA & & ei_local - > interface_num ) {
ei_local - > interface_num = 0 ;
if ( dev - > if_port = = IF_PORT_10BASET )
dev - > if_port = IF_PORT_10BASE2 ;
else
dev - > if_port = IF_PORT_10BASET ;
etherh_setif ( dev ) ;
}
}
/*
* Write a block of data out to the 8390
*/
static void
etherh_block_output ( struct net_device * dev , int count , const unsigned char * buf , int start_page )
{
struct ei_device * ei_local = netdev_priv ( dev ) ;
unsigned long dma_start ;
void __iomem * dma_base , * addr ;
if ( ei_local - > dmaing ) {
printk ( KERN_ERR " %s: DMAing conflict in etherh_block_input: "
" DMAstat %d irqlock %d \n " , dev - > name ,
ei_local - > dmaing , ei_local - > irqlock ) ;
return ;
}
/*
* Make sure we have a round number of bytes if we ' re in word mode .
*/
if ( count & 1 & & ei_local - > word16 )
count + + ;
ei_local - > dmaing = 1 ;
2006-10-10 03:19:36 +04:00
addr = ( void __iomem * ) dev - > base_addr ;
2005-04-17 02:20:36 +04:00
dma_base = etherh_priv ( dev ) - > dma_base ;
count = ( count + 1 ) & ~ 1 ;
writeb ( E8390_NODMA | E8390_PAGE0 | E8390_START , addr + E8390_CMD ) ;
writeb ( 0x42 , addr + EN0_RCNTLO ) ;
writeb ( 0x00 , addr + EN0_RCNTHI ) ;
writeb ( 0x42 , addr + EN0_RSARLO ) ;
writeb ( 0x00 , addr + EN0_RSARHI ) ;
writeb ( E8390_RREAD | E8390_START , addr + E8390_CMD ) ;
udelay ( 1 ) ;
writeb ( ENISR_RDC , addr + EN0_ISR ) ;
writeb ( count , addr + EN0_RCNTLO ) ;
writeb ( count > > 8 , addr + EN0_RCNTHI ) ;
writeb ( 0 , addr + EN0_RSARLO ) ;
writeb ( start_page , addr + EN0_RSARHI ) ;
writeb ( E8390_RWRITE | E8390_START , addr + E8390_CMD ) ;
if ( ei_local - > word16 )
writesw ( dma_base , buf , count > > 1 ) ;
else
writesb ( dma_base , buf , count ) ;
dma_start = jiffies ;
while ( ( readb ( addr + EN0_ISR ) & ENISR_RDC ) = = 0 )
2006-01-10 05:37:15 +03:00
if ( time_after ( jiffies , dma_start + 2 * HZ / 100 ) ) { /* 20ms */
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s: timeout waiting for TX RDC \n " ,
dev - > name ) ;
etherh_reset ( dev ) ;
2006-10-10 03:19:36 +04:00
__NS8390_init ( dev , 1 ) ;
2005-04-17 02:20:36 +04:00
break ;
}
writeb ( ENISR_RDC , addr + EN0_ISR ) ;
ei_local - > dmaing = 0 ;
}
/*
* Read a block of data from the 8390
*/
static void
etherh_block_input ( struct net_device * dev , int count , struct sk_buff * skb , int ring_offset )
{
struct ei_device * ei_local = netdev_priv ( dev ) ;
unsigned char * buf ;
void __iomem * dma_base , * addr ;
if ( ei_local - > dmaing ) {
printk ( KERN_ERR " %s: DMAing conflict in etherh_block_input: "
" DMAstat %d irqlock %d \n " , dev - > name ,
ei_local - > dmaing , ei_local - > irqlock ) ;
return ;
}
ei_local - > dmaing = 1 ;
2006-10-10 03:19:36 +04:00
addr = ( void __iomem * ) dev - > base_addr ;
2005-04-17 02:20:36 +04:00
dma_base = etherh_priv ( dev ) - > dma_base ;
buf = skb - > data ;
writeb ( E8390_NODMA | E8390_PAGE0 | E8390_START , addr + E8390_CMD ) ;
writeb ( count , addr + EN0_RCNTLO ) ;
writeb ( count > > 8 , addr + EN0_RCNTHI ) ;
writeb ( ring_offset , addr + EN0_RSARLO ) ;
writeb ( ring_offset > > 8 , addr + EN0_RSARHI ) ;
writeb ( E8390_RREAD | E8390_START , addr + E8390_CMD ) ;
if ( ei_local - > word16 ) {
readsw ( dma_base , buf , count > > 1 ) ;
if ( count & 1 )
buf [ count - 1 ] = readb ( dma_base ) ;
} else
readsb ( dma_base , buf , count ) ;
writeb ( ENISR_RDC , addr + EN0_ISR ) ;
ei_local - > dmaing = 0 ;
}
/*
* Read a header from the 8390
*/
static void
etherh_get_header ( struct net_device * dev , struct e8390_pkt_hdr * hdr , int ring_page )
{
struct ei_device * ei_local = netdev_priv ( dev ) ;
void __iomem * dma_base , * addr ;
if ( ei_local - > dmaing ) {
printk ( KERN_ERR " %s: DMAing conflict in etherh_get_header: "
" DMAstat %d irqlock %d \n " , dev - > name ,
ei_local - > dmaing , ei_local - > irqlock ) ;
return ;
}
ei_local - > dmaing = 1 ;
2006-10-10 03:19:36 +04:00
addr = ( void __iomem * ) dev - > base_addr ;
2005-04-17 02:20:36 +04:00
dma_base = etherh_priv ( dev ) - > dma_base ;
writeb ( E8390_NODMA | E8390_PAGE0 | E8390_START , addr + E8390_CMD ) ;
writeb ( sizeof ( * hdr ) , addr + EN0_RCNTLO ) ;
writeb ( 0 , addr + EN0_RCNTHI ) ;
writeb ( 0 , addr + EN0_RSARLO ) ;
writeb ( ring_page , addr + EN0_RSARHI ) ;
writeb ( E8390_RREAD | E8390_START , addr + E8390_CMD ) ;
if ( ei_local - > word16 )
readsw ( dma_base , hdr , sizeof ( * hdr ) > > 1 ) ;
else
readsb ( dma_base , hdr , sizeof ( * hdr ) ) ;
writeb ( ENISR_RDC , addr + EN0_ISR ) ;
ei_local - > dmaing = 0 ;
}
/*
* Open / initialize the board . This is called ( in the current kernel )
* sometime after booting when the ' ifconfig ' program is run .
*
* This routine should set everything up anew at each open , even
* registers that " should " only need to be set once at boot , so that
* there is non - reboot way to recover if something goes wrong .
*/
static int
etherh_open ( struct net_device * dev )
{
struct ei_device * ei_local = netdev_priv ( dev ) ;
if ( ! is_valid_ether_addr ( dev - > dev_addr ) ) {
printk ( KERN_WARNING " %s: invalid ethernet MAC address \n " ,
dev - > name ) ;
return - EINVAL ;
}
2006-10-10 03:19:36 +04:00
if ( request_irq ( dev - > irq , __ei_interrupt , 0 , dev - > name , dev ) )
2005-04-17 02:20:36 +04:00
return - EAGAIN ;
/*
* Make sure that we aren ' t going to change the
* media type on the next reset - we are about to
* do automedia manually now .
*/
ei_local - > interface_num = 0 ;
/*
* If we are doing automedia detection , do it now .
* This is more reliable than the 8390 ' s detection .
*/
if ( dev - > flags & IFF_AUTOMEDIA ) {
dev - > if_port = IF_PORT_10BASET ;
etherh_setif ( dev ) ;
mdelay ( 1 ) ;
if ( ! etherh_getifstat ( dev ) ) {
dev - > if_port = IF_PORT_10BASE2 ;
etherh_setif ( dev ) ;
}
} else
etherh_setif ( dev ) ;
etherh_reset ( dev ) ;
2006-10-10 03:19:36 +04:00
__ei_open ( dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* The inverse routine to etherh_open ( ) .
*/
static int
etherh_close ( struct net_device * dev )
{
2006-10-10 03:19:36 +04:00
__ei_close ( dev ) ;
2005-04-17 02:20:36 +04:00
free_irq ( dev - > irq , dev ) ;
return 0 ;
}
/*
* Initialisation
*/
static void __init etherh_banner ( void )
{
static int version_printed ;
if ( net_debug & & version_printed + + = = 0 )
printk ( KERN_INFO " %s " , version ) ;
}
/*
* Read the ethernet address string from the on board rom .
* This is an ascii string . . .
*/
2011-05-06 11:14:57 +04:00
static int __devinit etherh_addr ( char * addr , struct expansion_card * ec )
2005-04-17 02:20:36 +04:00
{
struct in_chunk_dir cd ;
char * s ;
if ( ! ecard_readchunk ( & cd , ec , 0xf5 , 0 ) ) {
printk ( KERN_ERR " %s: unable to read podule description string \n " ,
2008-05-30 19:42:11 +04:00
dev_name ( & ec - > dev ) ) ;
2005-04-17 02:20:36 +04:00
goto no_addr ;
}
s = strchr ( cd . d . string , ' ( ' ) ;
if ( s ) {
int i ;
for ( i = 0 ; i < 6 ; i + + ) {
addr [ i ] = simple_strtoul ( s + 1 , & s , 0x10 ) ;
if ( * s ! = ( i = = 5 ? ' ) ' : ' : ' ) )
break ;
}
if ( i = = 6 )
return 0 ;
}
printk ( KERN_ERR " %s: unable to parse MAC address: %s \n " ,
2008-05-30 19:42:11 +04:00
dev_name ( & ec - > dev ) , cd . d . string ) ;
2005-04-17 02:20:36 +04:00
no_addr :
return - ENODEV ;
}
/*
* Create an ethernet address from the system serial number .
*/
static int __init etherm_addr ( char * addr )
{
unsigned int serial ;
if ( system_serial_low = = 0 & & system_serial_high = = 0 )
return - ENODEV ;
serial = system_serial_low | system_serial_high ;
addr [ 0 ] = 0 ;
addr [ 1 ] = 0 ;
addr [ 2 ] = 0xa4 ;
addr [ 3 ] = 0x10 + ( serial > > 24 ) ;
addr [ 4 ] = serial > > 16 ;
addr [ 5 ] = serial > > 8 ;
return 0 ;
}
static void etherh_get_drvinfo ( struct net_device * dev , struct ethtool_drvinfo * info )
{
strlcpy ( info - > driver , DRV_NAME , sizeof ( info - > driver ) ) ;
strlcpy ( info - > version , DRV_VERSION , sizeof ( info - > version ) ) ;
2008-05-30 19:42:11 +04:00
strlcpy ( info - > bus_info , dev_name ( dev - > dev . parent ) ,
2005-04-17 02:20:36 +04:00
sizeof ( info - > bus_info ) ) ;
}
static int etherh_get_settings ( struct net_device * dev , struct ethtool_cmd * cmd )
{
cmd - > supported = etherh_priv ( dev ) - > supported ;
2011-04-27 22:32:40 +04:00
ethtool_cmd_speed_set ( cmd , SPEED_10 ) ;
2005-04-17 02:20:36 +04:00
cmd - > duplex = DUPLEX_HALF ;
cmd - > port = dev - > if_port = = IF_PORT_10BASET ? PORT_TP : PORT_BNC ;
2011-04-27 22:32:40 +04:00
cmd - > autoneg = ( dev - > flags & IFF_AUTOMEDIA ?
AUTONEG_ENABLE : AUTONEG_DISABLE ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int etherh_set_settings ( struct net_device * dev , struct ethtool_cmd * cmd )
{
switch ( cmd - > autoneg ) {
case AUTONEG_ENABLE :
dev - > flags | = IFF_AUTOMEDIA ;
break ;
case AUTONEG_DISABLE :
switch ( cmd - > port ) {
case PORT_TP :
dev - > if_port = IF_PORT_10BASET ;
break ;
case PORT_BNC :
dev - > if_port = IF_PORT_10BASE2 ;
break ;
default :
return - EINVAL ;
}
dev - > flags & = ~ IFF_AUTOMEDIA ;
break ;
default :
return - EINVAL ;
}
etherh_setif ( dev ) ;
return 0 ;
}
2006-09-13 22:30:00 +04:00
static const struct ethtool_ops etherh_ethtool_ops = {
2005-04-17 02:20:36 +04:00
. get_settings = etherh_get_settings ,
. set_settings = etherh_set_settings ,
. get_drvinfo = etherh_get_drvinfo ,
2012-04-04 02:59:26 +04:00
. get_ts_info = ethtool_op_get_ts_info ,
2005-04-17 02:20:36 +04:00
} ;
2008-12-03 01:52:25 +03:00
static const struct net_device_ops etherh_netdev_ops = {
. ndo_open = etherh_open ,
. ndo_stop = etherh_close ,
. ndo_set_config = etherh_set_config ,
2009-02-22 15:36:55 +03:00
. ndo_start_xmit = __ei_start_xmit ,
. ndo_tx_timeout = __ei_tx_timeout ,
. ndo_get_stats = __ei_get_stats ,
2011-08-16 10:29:01 +04:00
. ndo_set_rx_mode = __ei_set_multicast_list ,
2008-12-03 01:52:25 +03:00
. ndo_validate_addr = eth_validate_addr ,
2009-01-28 01:32:29 +03:00
. ndo_set_mac_address = eth_mac_addr ,
2008-12-03 01:52:25 +03:00
. ndo_change_mtu = eth_change_mtu ,
# ifdef CONFIG_NET_POLL_CONTROLLER
2009-02-22 15:36:55 +03:00
. ndo_poll_controller = __ei_poll ,
2008-12-03 01:52:25 +03:00
# endif
} ;
2005-04-17 02:20:36 +04:00
static u32 etherh_regoffsets [ 16 ] ;
static u32 etherm_regoffsets [ 16 ] ;
2011-05-06 11:14:57 +04:00
static int __devinit
2005-04-17 02:20:36 +04:00
etherh_probe ( struct expansion_card * ec , const struct ecard_id * id )
{
const struct etherh_data * data = id - > data ;
struct ei_device * ei_local ;
struct net_device * dev ;
struct etherh_priv * eh ;
2008-04-19 18:12:23 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
etherh_banner ( ) ;
ret = ecard_request_resources ( ec ) ;
if ( ret )
goto out ;
2006-10-10 03:19:36 +04:00
dev = ____alloc_ei_netdev ( sizeof ( struct etherh_priv ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev ) {
ret = - ENOMEM ;
goto release ;
}
SET_NETDEV_DEV ( dev , & ec - > dev ) ;
2008-12-03 01:52:25 +03:00
dev - > netdev_ops = & etherh_netdev_ops ;
2005-04-17 02:20:36 +04:00
dev - > irq = ec - > irq ;
dev - > ethtool_ops = & etherh_ethtool_ops ;
if ( data - > supported & SUPPORTED_Autoneg )
dev - > flags | = IFF_AUTOMEDIA ;
if ( data - > supported & SUPPORTED_TP ) {
dev - > flags | = IFF_PORTSEL ;
dev - > if_port = IF_PORT_10BASET ;
} else if ( data - > supported & SUPPORTED_BNC ) {
dev - > flags | = IFF_PORTSEL ;
dev - > if_port = IF_PORT_10BASE2 ;
} else
dev - > if_port = IF_PORT_UNKNOWN ;
eh = etherh_priv ( dev ) ;
eh - > supported = data - > supported ;
eh - > ctrl = 0 ;
eh - > id = ec - > cid . product ;
2007-05-10 21:40:51 +04:00
eh - > memc = ecardm_iomap ( ec , ECARD_RES_MEMC , 0 , PAGE_SIZE ) ;
2005-04-17 02:20:36 +04:00
if ( ! eh - > memc ) {
ret = - ENOMEM ;
goto free ;
}
eh - > ctrl_port = eh - > memc ;
if ( data - > ctrl_ioc ) {
2007-05-10 21:40:51 +04:00
eh - > ioc_fast = ecardm_iomap ( ec , ECARD_RES_IOCFAST , 0 , PAGE_SIZE ) ;
2005-04-17 02:20:36 +04:00
if ( ! eh - > ioc_fast ) {
ret = - ENOMEM ;
goto free ;
}
eh - > ctrl_port = eh - > ioc_fast ;
}
2005-06-29 21:10:54 +04:00
dev - > base_addr = ( unsigned long ) eh - > memc + data - > ns8390_offset ;
2005-04-17 02:20:36 +04:00
eh - > dma_base = eh - > memc + data - > dataport_offset ;
eh - > ctrl_port + = data - > ctrlport_offset ;
/*
* IRQ and control port handling - only for non - NIC slot cards .
*/
if ( ec - > slot_no ! = 8 ) {
2007-05-10 19:46:13 +04:00
ecard_setirq ( ec , & etherh_ops , eh ) ;
2005-04-17 02:20:36 +04:00
} else {
/*
* If we ' re in the NIC slot , make sure the IRQ is enabled
*/
etherh_set_ctrl ( eh , ETHERH_CP_IE ) ;
}
ei_local = netdev_priv ( dev ) ;
spin_lock_init ( & ei_local - > page_lock ) ;
if ( ec - > cid . product = = PROD_ANT_ETHERM ) {
etherm_addr ( dev - > dev_addr ) ;
ei_local - > reg_offset = etherm_regoffsets ;
} else {
etherh_addr ( dev - > dev_addr , ec ) ;
ei_local - > reg_offset = etherh_regoffsets ;
}
ei_local - > name = dev - > name ;
ei_local - > word16 = 1 ;
ei_local - > tx_start_page = data - > tx_start_page ;
ei_local - > rx_start_page = ei_local - > tx_start_page + TX_PAGES ;
ei_local - > stop_page = data - > stop_page ;
ei_local - > reset_8390 = etherh_reset ;
ei_local - > block_input = etherh_block_input ;
ei_local - > block_output = etherh_block_output ;
ei_local - > get_8390_hdr = etherh_get_header ;
ei_local - > interface_num = 0 ;
etherh_reset ( dev ) ;
2006-10-10 03:19:36 +04:00
__NS8390_init ( dev , 0 ) ;
2005-04-17 02:20:36 +04:00
ret = register_netdev ( dev ) ;
if ( ret )
goto free ;
2008-10-28 01:59:26 +03:00
printk ( KERN_INFO " %s: %s in slot %d, %pM \n " ,
dev - > name , data - > name , ec - > slot_no , dev - > dev_addr ) ;
2005-04-17 02:20:36 +04:00
ecard_set_drvdata ( ec , dev ) ;
return 0 ;
free :
free_netdev ( dev ) ;
release :
ecard_release_resources ( ec ) ;
out :
return ret ;
}
static void __devexit etherh_remove ( struct expansion_card * ec )
{
struct net_device * dev = ecard_get_drvdata ( ec ) ;
ecard_set_drvdata ( ec , NULL ) ;
unregister_netdev ( dev ) ;
free_netdev ( dev ) ;
ecard_release_resources ( ec ) ;
}
static struct etherh_data etherm_data = {
. ns8390_offset = ETHERM_NS8390 ,
. dataport_offset = ETHERM_NS8390 + ETHERM_DATAPORT ,
. ctrlport_offset = ETHERM_NS8390 + ETHERM_CTRLPORT ,
. name = " ANT EtherM " ,
. supported = SUPPORTED_10baseT_Half ,
. tx_start_page = ETHERM_TX_START_PAGE ,
. stop_page = ETHERM_STOP_PAGE ,
} ;
static struct etherh_data etherlan500_data = {
. ns8390_offset = ETHERH500_NS8390 ,
. dataport_offset = ETHERH500_NS8390 + ETHERH500_DATAPORT ,
. ctrlport_offset = ETHERH500_CTRLPORT ,
. ctrl_ioc = 1 ,
. name = " i3 EtherH 500 " ,
. supported = SUPPORTED_10baseT_Half ,
. tx_start_page = ETHERH_TX_START_PAGE ,
. stop_page = ETHERH_STOP_PAGE ,
} ;
static struct etherh_data etherlan600_data = {
. ns8390_offset = ETHERH600_NS8390 ,
. dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT ,
. ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT ,
. name = " i3 EtherH 600 " ,
. supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg ,
. tx_start_page = ETHERH_TX_START_PAGE ,
. stop_page = ETHERH_STOP_PAGE ,
} ;
static struct etherh_data etherlan600a_data = {
. ns8390_offset = ETHERH600_NS8390 ,
. dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT ,
. ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT ,
. name = " i3 EtherH 600A " ,
. supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg ,
. tx_start_page = ETHERH_TX_START_PAGE ,
. stop_page = ETHERH_STOP_PAGE ,
} ;
static const struct ecard_id etherh_ids [ ] = {
{ MANU_ANT , PROD_ANT_ETHERM , & etherm_data } ,
{ MANU_I3 , PROD_I3_ETHERLAN500 , & etherlan500_data } ,
{ MANU_I3 , PROD_I3_ETHERLAN600 , & etherlan600_data } ,
{ MANU_I3 , PROD_I3_ETHERLAN600A , & etherlan600a_data } ,
{ 0xffff , 0xffff }
} ;
static struct ecard_driver etherh_driver = {
. probe = etherh_probe ,
. remove = __devexit_p ( etherh_remove ) ,
. id_table = etherh_ids ,
. drv = {
. name = DRV_NAME ,
} ,
} ;
static int __init etherh_init ( void )
{
int i ;
for ( i = 0 ; i < 16 ; i + + ) {
etherh_regoffsets [ i ] = i < < 2 ;
etherm_regoffsets [ i ] = i < < 5 ;
}
return ecard_register_driver ( & etherh_driver ) ;
}
static void __exit etherh_exit ( void )
{
ecard_remove_driver ( & etherh_driver ) ;
}
module_init ( etherh_init ) ;
module_exit ( etherh_exit ) ;