2005-04-17 02:20:36 +04:00
/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
Written 1994 - 1999 by Mika Kuoppala
Copyright ( C ) 1994 - 1999 by Mika Kuoppala
Based on skeleton . c and heavily on at1700 . c by Donald Becker
This software may be used and distributed according to the terms
of the GNU General Public License , incorporated herein by reference .
The author may be reached as miku @ iki . fi
This driver supports following cards :
- ICL EtherTeam 16 i
- ICL EtherTeam 32 EISA
( Uses true 32 bit transfers rather than 16 i compability mode )
Example Module usage :
insmod eth16i . o io = 0x2a0 mediatype = bnc
mediatype can be one of the following : bnc , tp , dix , auto , eprom
' auto ' will try to autoprobe mediatype .
' eprom ' will use whatever type defined in eprom .
I have benchmarked driver with PII / 300 Mhz as a ftp client
and 486 / 33 Mhz as a ftp server . Top speed was 1128.37 kilobytes / sec .
Sources :
- skeleton . c a sample network driver core for linux ,
written by Donald Becker < becker @ scyld . com >
- at1700 . c a driver for Allied Telesis AT1700 , written
by Donald Becker .
- e16iSRV . asm a Netware 3. X Server Driver for ICL EtherTeam16i
written by Markku Viima
- The Fujitsu MB86965 databook .
Author thanks following persons due to their valueble assistance :
Markku Viima ( ICL )
Ari Valve ( ICL )
Donald Becker
Kurt Huwig < kurt @ huwig . de >
Revision history :
Version Date Description
0.01 15.12 - 94 Initial version ( card detection )
0.02 23.01 - 95 Interrupt is now hooked correctly
0.03 01.02 - 95 Rewrote initialization part
0.04 07.02 - 95 Base skeleton done . . .
Made a few changes to signature checking
to make it a bit reliable .
- fixed bug in tx_buf mapping
- fixed bug in initialization ( DLC_EN
wasn ' t enabled when initialization
was done . )
0.05 08.02 - 95 If there were more than one packet to send ,
transmit was jammed due to invalid
register write . . . now fixed
0.06 19.02 - 95 Rewrote interrupt handling
0.07 13.04 - 95 Wrote EEPROM read routines
Card configuration now set according to
data read from EEPROM
0.08 23.06 - 95 Wrote part that tries to probe used interface
port if AUTO is selected
0.09 01.09 - 95 Added module support
0.10 04.09 - 95 Fixed receive packet allocation to work
with kernels > 1.3 . x
0.20 20.09 - 95 Added support for EtherTeam32 EISA
0.21 17.10 - 95 Removed the unnecessary extern
init_etherdev ( ) declaration . Some
other cleanups .
0.22 22.02 - 96 Receive buffer was not flushed
correctly when faulty packet was
received . Now fixed .
0.23 26.02 - 96 Made resetting the adapter
more reliable .
0.24 27.02 - 96 Rewrote faulty packet handling in eth16i_rx
0.25 22.05 - 96 kfree ( ) was missing from cleanup_module .
0.26 11.06 - 96 Sometimes card was not found by
check_signature ( ) . Now made more reliable .
0.27 23.06 - 96 Oops . 16 consecutive collisions halted
adapter . Now will try to retransmit
MAX_COL_16 times before finally giving up .
0.28 28.10 - 97 Added dev_id parameter ( NULL ) for free_irq
0.29 29.10 - 97 Multiple card support for module users
0.30 30.10 - 97 Fixed irq allocation bug .
( request_irq moved from probe to open )
0.30 a 21.08 - 98 Card detection made more relaxed . Driver
had problems with some TCP / IP - PROM boots
to find the card . Suggested by
Kurt Huwig < kurt @ huwig . de >
0.31 28.08 - 98 Media interface port can now be selected
with module parameters or kernel
boot parameters .
0.32 31.08 - 98 IRQ was never freed if open / close
pair wasn ' t called . Now fixed .
0.33 10.09 - 98 When eth16i_open ( ) was called after
eth16i_close ( ) chip never recovered .
Now more shallow reset is made on
close .
0.34 29.06 - 99 Fixed one bad # ifdef .
Changed ioaddr - > io for consistency
0.35 01.07 - 99 transmit , - receive bytes were never
updated in stats .
Bugs :
In some cases the media interface autoprobing code doesn ' t find
the correct interface type . In this case you can
manually choose the interface type in DOS with E16IC . EXE which is
configuration software for EtherTeam16i and EtherTeam32 cards .
This is also true for IRQ setting . You cannot use module
parameter to configure IRQ of the card ( yet ) .
To do :
- Real multicast support
- Rewrite the media interface autoprobing code . Its _horrible_ !
- Possibly merge all the MB86965 specific code to external
module for use by eth16 . c and Donald ' s at1700 . c
- IRQ configuration with module parameter . I will do
this when i will get enough info about setting
irq without configuration utility .
*/
static char * version =
" eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi) \n " ;
# 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/slab.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/spinlock.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/skbuff.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/system.h>
# include <asm/io.h>
# include <asm/dma.h>
/* Few macros */
# define BIT(a) ( (1 << (a)) )
# define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
# define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
/* This is the I/O address space for Etherteam 16i adapter. */
# define ETH16I_IO_EXTENT 32
/* Ticks before deciding that transmit has timed out */
# define TX_TIMEOUT (400*HZ / 1000)
/* Maximum loop count when receiving packets */
# define MAX_RX_LOOP 20
/* Some interrupt masks */
# define ETH16I_INTR_ON 0xef8a /* Higher is receive mask */
# define ETH16I_INTR_OFF 0x0000
/* Buffers header status byte meanings */
# define PKT_GOOD BIT(5)
# define PKT_GOOD_RMT BIT(4)
# define PKT_SHORT BIT(3)
# define PKT_ALIGN_ERR BIT(2)
# define PKT_CRC_ERR BIT(1)
# define PKT_RX_BUF_OVERFLOW BIT(0)
/* Transmit status register (DLCR0) */
# define TX_STATUS_REG 0
# define TX_DONE BIT(7)
# define NET_BUSY BIT(6)
# define TX_PKT_RCD BIT(5)
# define CR_LOST BIT(4)
# define TX_JABBER_ERR BIT(3)
# define COLLISION BIT(2)
# define COLLISIONS_16 BIT(1)
/* Receive status register (DLCR1) */
# define RX_STATUS_REG 1
# define RX_PKT BIT(7) /* Packet received */
# define BUS_RD_ERR BIT(6)
# define SHORT_PKT_ERR BIT(3)
# define ALIGN_ERR BIT(2)
# define CRC_ERR BIT(1)
# define RX_BUF_OVERFLOW BIT(0)
/* Transmit Interrupt Enable Register (DLCR2) */
# define TX_INTR_REG 2
# define TX_INTR_DONE BIT(7)
# define TX_INTR_COL BIT(2)
# define TX_INTR_16_COL BIT(1)
/* Receive Interrupt Enable Register (DLCR3) */
# define RX_INTR_REG 3
# define RX_INTR_RECEIVE BIT(7)
# define RX_INTR_SHORT_PKT BIT(3)
# define RX_INTR_CRC_ERR BIT(1)
# define RX_INTR_BUF_OVERFLOW BIT(0)
/* Transmit Mode Register (DLCR4) */
# define TRANSMIT_MODE_REG 4
# define LOOPBACK_CONTROL BIT(1)
# define CONTROL_OUTPUT BIT(2)
/* Receive Mode Register (DLCR5) */
# define RECEIVE_MODE_REG 5
# define RX_BUFFER_EMPTY BIT(6)
# define ACCEPT_BAD_PACKETS BIT(5)
# define RECEIVE_SHORT_ADDR BIT(4)
# define ACCEPT_SHORT_PACKETS BIT(3)
# define REMOTE_RESET BIT(2)
# define ADDRESS_FILTER_MODE BIT(1) | BIT(0)
# define REJECT_ALL 0
# define ACCEPT_ALL 3
# define MODE_1 1 /* NODE ID, BC, MC, 2-24th bit */
# define MODE_2 2 /* NODE ID, BC, MC, Hash Table */
/* Configuration Register 0 (DLCR6) */
# define CONFIG_REG_0 6
# define DLC_EN BIT(7)
# define SRAM_CYCLE_TIME_100NS BIT(6)
# define SYSTEM_BUS_WIDTH_8 BIT(5) /* 1 = 8bit, 0 = 16bit */
# define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */
# define TBS1 BIT(3)
# define TBS0 BIT(2)
# define SRAM_BS1 BIT(1) /* 00=8kb, 01=16kb */
# define SRAM_BS0 BIT(0) /* 10=32kb, 11=64kb */
# ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
# define ETH16I_TX_BUF_SIZE 3 /* 2 = 8kb, 3 = 16kb */
# endif
# define TX_BUF_1x2048 0
# define TX_BUF_2x2048 1
# define TX_BUF_2x4098 2
# define TX_BUF_2x8192 3
/* Configuration Register 1 (DLCR7) */
# define CONFIG_REG_1 7
# define POWERUP BIT(5)
/* Transmit start register */
# define TRANSMIT_START_REG 10
# define TRANSMIT_START_RB 2
# define TX_START BIT(7) /* Rest of register bit indicate*/
/* number of packets in tx buffer*/
/* Node ID registers (DLCR8-13) */
# define NODE_ID_0 8
# define NODE_ID_RB 0
/* Hash Table registers (HT8-15) */
# define HASH_TABLE_0 8
# define HASH_TABLE_RB 1
/* Buffer memory ports */
# define BUFFER_MEM_PORT_LB 8
# define DATAPORT BUFFER_MEM_PORT_LB
# define BUFFER_MEM_PORT_HB 9
/* 16 Collision control register (BMPR11) */
# define COL_16_REG 11
# define HALT_ON_16 0x00
# define RETRANS_AND_HALT_ON_16 0x02
/* Maximum number of attempts to send after 16 concecutive collisions */
# define MAX_COL_16 10
/* DMA Burst and Transceiver Mode Register (BMPR13) */
# define TRANSCEIVER_MODE_REG 13
# define TRANSCEIVER_MODE_RB 2
# define IO_BASE_UNLOCK BIT(7)
# define LOWER_SQUELCH_TRESH BIT(6)
# define LINK_TEST_DISABLE BIT(5)
# define AUI_SELECT BIT(4)
# define DIS_AUTO_PORT_SEL BIT(3)
/* Filter Self Receive Register (BMPR14) */
# define FILTER_SELF_RX_REG 14
# define SKIP_RX_PACKET BIT(2)
# define FILTER_SELF_RECEIVE BIT(0)
/* EEPROM Control Register (BMPR 16) */
# define EEPROM_CTRL_REG 16
/* EEPROM Data Register (BMPR 17) */
# define EEPROM_DATA_REG 17
/* NMC93CSx6 EEPROM Control Bits */
# define CS_0 0x00
# define CS_1 0x20
# define SK_0 0x00
# define SK_1 0x40
# define DI_0 0x00
# define DI_1 0x80
/* NMC93CSx6 EEPROM Instructions */
# define EEPROM_READ 0x80
/* NMC93CSx6 EEPROM Addresses */
# define E_NODEID_0 0x02
# define E_NODEID_1 0x03
# define E_NODEID_2 0x04
# define E_PORT_SELECT 0x14
# define E_PORT_BNC 0x00
# define E_PORT_DIX 0x01
# define E_PORT_TP 0x02
# define E_PORT_AUTO 0x03
# define E_PORT_FROM_EPROM 0x04
# define E_PRODUCT_CFG 0x30
/* Macro to slow down io between EEPROM clock transitions */
# define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
/* Jumperless Configuration Register (BMPR19) */
# define JUMPERLESS_CONFIG 19
/* ID ROM registers, writing to them also resets some parts of chip */
# define ID_ROM_0 24
# define ID_ROM_7 31
# define RESET ID_ROM_0
/* This is the I/O address list to be probed when seeking the card */
static unsigned int eth16i_portlist [ ] __initdata = {
0x260 , 0x280 , 0x2A0 , 0x240 , 0x340 , 0x320 , 0x380 , 0x300 , 0
} ;
static unsigned int eth32i_portlist [ ] __initdata = {
0x1000 , 0x2000 , 0x3000 , 0x4000 , 0x5000 , 0x6000 , 0x7000 , 0x8000 ,
0x9000 , 0xA000 , 0xB000 , 0xC000 , 0xD000 , 0xE000 , 0xF000 , 0
} ;
/* This is the Interrupt lookup table for Eth16i card */
static unsigned int eth16i_irqmap [ ] __initdata = { 9 , 10 , 5 , 15 , 0 } ;
# define NUM_OF_ISA_IRQS 4
/* This is the Interrupt lookup table for Eth32i card */
static unsigned int eth32i_irqmap [ ] __initdata = { 3 , 5 , 7 , 9 , 10 , 11 , 12 , 15 , 0 } ;
# define EISA_IRQ_REG 0xc89
# define NUM_OF_EISA_IRQS 8
static unsigned int eth16i_tx_buf_map [ ] = { 2048 , 2048 , 4096 , 8192 } ;
/* Use 0 for production, 1 for verification, >2 for debug */
# ifndef ETH16I_DEBUG
# define ETH16I_DEBUG 0
# endif
static unsigned int eth16i_debug = ETH16I_DEBUG ;
/* Information for each board */
struct eth16i_local {
struct net_device_stats stats ;
unsigned char tx_started ;
unsigned char tx_buf_busy ;
unsigned short tx_queue ; /* Number of packets in transmit buffer */
unsigned short tx_queue_len ;
unsigned int tx_buf_size ;
unsigned long open_time ;
unsigned long tx_buffered_packets ;
unsigned long tx_buffered_bytes ;
unsigned long col_16 ;
spinlock_t lock ;
} ;
/* Function prototypes */
static int eth16i_probe1 ( struct net_device * dev , int ioaddr ) ;
static int eth16i_check_signature ( int ioaddr ) ;
static int eth16i_probe_port ( int ioaddr ) ;
static void eth16i_set_port ( int ioaddr , int porttype ) ;
static int eth16i_send_probe_packet ( int ioaddr , unsigned char * b , int l ) ;
static int eth16i_receive_probe_packet ( int ioaddr ) ;
static int eth16i_get_irq ( int ioaddr ) ;
static int eth16i_read_eeprom ( int ioaddr , int offset ) ;
static int eth16i_read_eeprom_word ( int ioaddr ) ;
static void eth16i_eeprom_cmd ( int ioaddr , unsigned char command ) ;
static int eth16i_open ( struct net_device * dev ) ;
static int eth16i_close ( struct net_device * dev ) ;
static int eth16i_tx ( struct sk_buff * skb , struct net_device * dev ) ;
static void eth16i_rx ( struct net_device * dev ) ;
static void eth16i_timeout ( struct net_device * dev ) ;
static irqreturn_t eth16i_interrupt ( int irq , void * dev_id , struct pt_regs * regs ) ;
static void eth16i_reset ( struct net_device * dev ) ;
static void eth16i_timeout ( struct net_device * dev ) ;
static void eth16i_skip_packet ( struct net_device * dev ) ;
static void eth16i_multicast ( struct net_device * dev ) ;
static void eth16i_select_regbank ( unsigned char regbank , int ioaddr ) ;
static void eth16i_initialize ( struct net_device * dev , int boot ) ;
#if 0
static int eth16i_set_irq ( struct net_device * dev ) ;
# endif
# ifdef MODULE
static ushort eth16i_parse_mediatype ( const char * s ) ;
# endif
static struct net_device_stats * eth16i_get_stats ( struct net_device * dev ) ;
static char cardname [ ] __initdata = " ICL EtherTeam 16i/32 " ;
static int __init do_eth16i_probe ( struct net_device * dev )
{
int i ;
int ioaddr ;
int base_addr = dev - > base_addr ;
SET_MODULE_OWNER ( dev ) ;
if ( eth16i_debug > 4 )
printk ( KERN_DEBUG " Probing started for %s \n " , cardname ) ;
if ( base_addr > 0x1ff ) /* Check only single location */
return eth16i_probe1 ( dev , base_addr ) ;
else if ( base_addr ! = 0 ) /* Don't probe at all */
return - ENXIO ;
/* Seek card from the ISA io address space */
for ( i = 0 ; ( ioaddr = eth16i_portlist [ i ] ) ; i + + )
if ( eth16i_probe1 ( dev , ioaddr ) = = 0 )
return 0 ;
/* Seek card from the EISA io address space */
for ( i = 0 ; ( ioaddr = eth32i_portlist [ i ] ) ; i + + )
if ( eth16i_probe1 ( dev , ioaddr ) = = 0 )
return 0 ;
return - ENODEV ;
}
# ifndef MODULE
struct net_device * __init eth16i_probe ( int unit )
{
struct net_device * dev = alloc_etherdev ( sizeof ( struct eth16i_local ) ) ;
int err ;
if ( ! dev )
return ERR_PTR ( - ENOMEM ) ;
sprintf ( dev - > name , " eth%d " , unit ) ;
netdev_boot_setup_check ( dev ) ;
err = do_eth16i_probe ( dev ) ;
if ( err )
goto out ;
return dev ;
out :
free_netdev ( dev ) ;
return ERR_PTR ( err ) ;
}
# endif
static int __init eth16i_probe1 ( struct net_device * dev , int ioaddr )
{
struct eth16i_local * lp = netdev_priv ( dev ) ;
static unsigned version_printed ;
int retval ;
/* Let's grab the region */
if ( ! request_region ( ioaddr , ETH16I_IO_EXTENT , cardname ) )
return - EBUSY ;
/*
The MB86985 chip has on register which holds information in which
io address the chip lies . First read this register and compare
it to our current io address and if match then this could
be our chip .
*/
if ( ioaddr < 0x1000 ) {
if ( eth16i_portlist [ ( inb ( ioaddr + JUMPERLESS_CONFIG ) & 0x07 ) ]
! = ioaddr ) {
retval = - ENODEV ;
goto out ;
}
}
/* Now we will go a bit deeper and try to find the chip's signature */
if ( eth16i_check_signature ( ioaddr ) ! = 0 ) {
retval = - ENODEV ;
goto out ;
}
/*
Now it seems that we have found a ethernet chip in this particular
ioaddr . The MB86985 chip has this feature , that when you read a
certain register it will increase it ' s io base address to next
configurable slot . Now when we have found the chip , first thing is
to make sure that the chip ' s ioaddr will hold still here .
*/
eth16i_select_regbank ( TRANSCEIVER_MODE_RB , ioaddr ) ;
outb ( 0x00 , ioaddr + TRANSCEIVER_MODE_REG ) ;
outb ( 0x00 , ioaddr + RESET ) ; /* Reset some parts of chip */
BITSET ( ioaddr + CONFIG_REG_0 , BIT ( 7 ) ) ; /* Disable the data link */
if ( ( eth16i_debug & version_printed + + ) = = 0 )
printk ( KERN_INFO " %s " , version ) ;
dev - > base_addr = ioaddr ;
dev - > irq = eth16i_get_irq ( ioaddr ) ;
/* Try to obtain interrupt vector */
if ( ( retval = request_irq ( dev - > irq , ( void * ) & eth16i_interrupt , 0 , cardname , dev ) ) ) {
printk ( KERN_WARNING " %s at %#3x, but is unusable due to conflicting IRQ %d. \n " ,
cardname , ioaddr , dev - > irq ) ;
goto out ;
}
printk ( KERN_INFO " %s: %s at %#3x, IRQ %d, " ,
dev - > name , cardname , ioaddr , dev - > irq ) ;
/* Now we will have to lock the chip's io address */
eth16i_select_regbank ( TRANSCEIVER_MODE_RB , ioaddr ) ;
outb ( 0x38 , ioaddr + TRANSCEIVER_MODE_REG ) ;
eth16i_initialize ( dev , 1 ) ; /* Initialize rest of the chip's registers */
/* Now let's same some energy by shutting down the chip ;) */
BITCLR ( ioaddr + CONFIG_REG_1 , POWERUP ) ;
/* Initialize the device structure */
memset ( lp , 0 , sizeof ( struct eth16i_local ) ) ;
dev - > open = eth16i_open ;
dev - > stop = eth16i_close ;
dev - > hard_start_xmit = eth16i_tx ;
dev - > get_stats = eth16i_get_stats ;
dev - > set_multicast_list = eth16i_multicast ;
dev - > tx_timeout = eth16i_timeout ;
dev - > watchdog_timeo = TX_TIMEOUT ;
spin_lock_init ( & lp - > lock ) ;
2005-05-13 04:11:55 +04:00
retval = register_netdev ( dev ) ;
if ( retval )
goto out1 ;
2005-04-17 02:20:36 +04:00
return 0 ;
2005-05-13 04:11:55 +04:00
out1 :
free_irq ( dev - > irq , dev ) ;
2005-04-17 02:20:36 +04:00
out :
release_region ( ioaddr , ETH16I_IO_EXTENT ) ;
return retval ;
}
static void eth16i_initialize ( struct net_device * dev , int boot )
{
int ioaddr = dev - > base_addr ;
int i , node_w = 0 ;
unsigned char node_byte = 0 ;
/* Setup station address */
eth16i_select_regbank ( NODE_ID_RB , ioaddr ) ;
for ( i = 0 ; i < 3 ; i + + ) {
unsigned short node_val = eth16i_read_eeprom ( ioaddr , E_NODEID_0 + i ) ;
( ( unsigned short * ) dev - > dev_addr ) [ i ] = ntohs ( node_val ) ;
}
for ( i = 0 ; i < 6 ; i + + ) {
outb ( ( ( unsigned char * ) dev - > dev_addr ) [ i ] , ioaddr + NODE_ID_0 + i ) ;
if ( boot ) {
printk ( " %02x " , inb ( ioaddr + NODE_ID_0 + i ) ) ;
if ( i ! = 5 )
printk ( " : " ) ;
}
}
/* Now we will set multicast addresses to accept none */
eth16i_select_regbank ( HASH_TABLE_RB , ioaddr ) ;
for ( i = 0 ; i < 8 ; i + + )
outb ( 0x00 , ioaddr + HASH_TABLE_0 + i ) ;
/*
Now let ' s disable the transmitter and receiver , set the buffer ram
cycle time , bus width and buffer data path width . Also we shall
set transmit buffer size and total buffer size .
*/
eth16i_select_regbank ( 2 , ioaddr ) ;
node_byte = 0 ;
node_w = eth16i_read_eeprom ( ioaddr , E_PRODUCT_CFG ) ;
if ( ( node_w & 0xFF00 ) = = 0x0800 )
node_byte | = BUFFER_WIDTH_8 ;
node_byte | = SRAM_BS1 ;
if ( ( node_w & 0x00FF ) = = 64 )
node_byte | = SRAM_BS0 ;
node_byte | = DLC_EN | SRAM_CYCLE_TIME_100NS | ( ETH16I_TX_BUF_SIZE < < 2 ) ;
outb ( node_byte , ioaddr + CONFIG_REG_0 ) ;
/* We shall halt the transmitting, if 16 collisions are detected */
outb ( HALT_ON_16 , ioaddr + COL_16_REG ) ;
# ifdef MODULE
/* if_port already set by init_module() */
# else
dev - > if_port = ( dev - > mem_start < E_PORT_FROM_EPROM ) ?
dev - > mem_start : E_PORT_FROM_EPROM ;
# endif
/* Set interface port type */
if ( boot ) {
char * porttype [ ] = { " BNC " , " DIX " , " TP " , " AUTO " , " FROM_EPROM " } ;
switch ( dev - > if_port )
{
case E_PORT_FROM_EPROM :
dev - > if_port = eth16i_read_eeprom ( ioaddr , E_PORT_SELECT ) ;
break ;
case E_PORT_AUTO :
dev - > if_port = eth16i_probe_port ( ioaddr ) ;
break ;
case E_PORT_BNC :
case E_PORT_TP :
case E_PORT_DIX :
break ;
}
printk ( " %s interface. \n " , porttype [ dev - > if_port ] ) ;
eth16i_set_port ( ioaddr , dev - > if_port ) ;
}
/* Set Receive Mode to normal operation */
outb ( MODE_2 , ioaddr + RECEIVE_MODE_REG ) ;
}
static int eth16i_probe_port ( int ioaddr )
{
int i ;
int retcode ;
unsigned char dummy_packet [ 64 ] ;
/* Powerup the chip */
outb ( 0xc0 | POWERUP , ioaddr + CONFIG_REG_1 ) ;
BITSET ( ioaddr + CONFIG_REG_0 , DLC_EN ) ;
eth16i_select_regbank ( NODE_ID_RB , ioaddr ) ;
for ( i = 0 ; i < 6 ; i + + ) {
dummy_packet [ i ] = inb ( ioaddr + NODE_ID_0 + i ) ;
dummy_packet [ i + 6 ] = inb ( ioaddr + NODE_ID_0 + i ) ;
}
dummy_packet [ 12 ] = 0x00 ;
dummy_packet [ 13 ] = 0x04 ;
memset ( dummy_packet + 14 , 0 , sizeof ( dummy_packet ) - 14 ) ;
eth16i_select_regbank ( 2 , ioaddr ) ;
for ( i = 0 ; i < 3 ; i + + ) {
BITSET ( ioaddr + CONFIG_REG_0 , DLC_EN ) ;
BITCLR ( ioaddr + CONFIG_REG_0 , DLC_EN ) ;
eth16i_set_port ( ioaddr , i ) ;
if ( eth16i_debug > 1 )
printk ( KERN_DEBUG " Set port number %d \n " , i ) ;
retcode = eth16i_send_probe_packet ( ioaddr , dummy_packet , 64 ) ;
if ( retcode = = 0 ) {
retcode = eth16i_receive_probe_packet ( ioaddr ) ;
if ( retcode ! = - 1 ) {
if ( eth16i_debug > 1 )
printk ( KERN_DEBUG " Eth16i interface port found at %d \n " , i ) ;
return i ;
}
}
else {
if ( eth16i_debug > 1 )
printk ( KERN_DEBUG " TRANSMIT_DONE timeout when probing interface port \n " ) ;
}
}
if ( eth16i_debug > 1 )
printk ( KERN_DEBUG " Using default port \n " ) ;
return E_PORT_BNC ;
}
static void eth16i_set_port ( int ioaddr , int porttype )
{
unsigned short temp = 0 ;
eth16i_select_regbank ( TRANSCEIVER_MODE_RB , ioaddr ) ;
outb ( LOOPBACK_CONTROL , ioaddr + TRANSMIT_MODE_REG ) ;
temp | = DIS_AUTO_PORT_SEL ;
switch ( porttype ) {
case E_PORT_BNC :
temp | = AUI_SELECT ;
break ;
case E_PORT_TP :
break ;
case E_PORT_DIX :
temp | = AUI_SELECT ;
BITSET ( ioaddr + TRANSMIT_MODE_REG , CONTROL_OUTPUT ) ;
break ;
}
outb ( temp , ioaddr + TRANSCEIVER_MODE_REG ) ;
if ( eth16i_debug > 1 ) {
printk ( KERN_DEBUG " TRANSMIT_MODE_REG = %x \n " , inb ( ioaddr + TRANSMIT_MODE_REG ) ) ;
printk ( KERN_DEBUG " TRANSCEIVER_MODE_REG = %x \n " ,
inb ( ioaddr + TRANSCEIVER_MODE_REG ) ) ;
}
}
static int eth16i_send_probe_packet ( int ioaddr , unsigned char * b , int l )
{
2006-01-10 05:37:15 +03:00
unsigned long starttime ;
2005-04-17 02:20:36 +04:00
outb ( 0xff , ioaddr + TX_STATUS_REG ) ;
outw ( l , ioaddr + DATAPORT ) ;
outsw ( ioaddr + DATAPORT , ( unsigned short * ) b , ( l + 1 ) > > 1 ) ;
starttime = jiffies ;
outb ( TX_START | 1 , ioaddr + TRANSMIT_START_REG ) ;
while ( ( inb ( ioaddr + TX_STATUS_REG ) & 0x80 ) = = 0 ) {
2006-01-10 05:37:15 +03:00
if ( time_after ( jiffies , starttime + TX_TIMEOUT ) ) {
2005-04-17 02:20:36 +04:00
return - 1 ;
}
}
return 0 ;
}
static int eth16i_receive_probe_packet ( int ioaddr )
{
2006-01-10 05:37:15 +03:00
unsigned long starttime ;
2005-04-17 02:20:36 +04:00
starttime = jiffies ;
while ( ( inb ( ioaddr + TX_STATUS_REG ) & 0x20 ) = = 0 ) {
2006-01-10 05:37:15 +03:00
if ( time_after ( jiffies , starttime + TX_TIMEOUT ) ) {
2005-04-17 02:20:36 +04:00
if ( eth16i_debug > 1 )
printk ( KERN_DEBUG " Timeout occurred waiting transmit packet received \n " ) ;
starttime = jiffies ;
while ( ( inb ( ioaddr + RX_STATUS_REG ) & 0x80 ) = = 0 ) {
2006-01-10 05:37:15 +03:00
if ( time_after ( jiffies , starttime + TX_TIMEOUT ) ) {
2005-04-17 02:20:36 +04:00
if ( eth16i_debug > 1 )
printk ( KERN_DEBUG " Timeout occurred waiting receive packet \n " ) ;
return - 1 ;
}
}
if ( eth16i_debug > 1 )
printk ( KERN_DEBUG " RECEIVE_PACKET \n " ) ;
return ( 0 ) ; /* Found receive packet */
}
}
if ( eth16i_debug > 1 ) {
printk ( KERN_DEBUG " TRANSMIT_PACKET_RECEIVED %x \n " , inb ( ioaddr + TX_STATUS_REG ) ) ;
printk ( KERN_DEBUG " RX_STATUS_REG = %x \n " , inb ( ioaddr + RX_STATUS_REG ) ) ;
}
return ( 0 ) ; /* Return success */
}
#if 0
static int eth16i_set_irq ( struct net_device * dev )
{
const int ioaddr = dev - > base_addr ;
const int irq = dev - > irq ;
int i = 0 ;
if ( ioaddr < 0x1000 ) {
while ( eth16i_irqmap [ i ] & & eth16i_irqmap [ i ] ! = irq )
i + + ;
if ( i < NUM_OF_ISA_IRQS ) {
u8 cbyte = inb ( ioaddr + JUMPERLESS_CONFIG ) ;
cbyte = ( cbyte & 0x3F ) | ( i < < 6 ) ;
outb ( cbyte , ioaddr + JUMPERLESS_CONFIG ) ;
return 0 ;
}
}
else {
printk ( KERN_NOTICE " %s: EISA Interrupt cannot be set. Use EISA Configuration utility. \n " , dev - > name ) ;
}
return - 1 ;
}
# endif
static int __init eth16i_get_irq ( int ioaddr )
{
unsigned char cbyte ;
if ( ioaddr < 0x1000 ) {
cbyte = inb ( ioaddr + JUMPERLESS_CONFIG ) ;
return ( eth16i_irqmap [ ( ( cbyte & 0xC0 ) > > 6 ) ] ) ;
} else { /* Oh..the card is EISA so method getting IRQ different */
unsigned short index = 0 ;
cbyte = inb ( ioaddr + EISA_IRQ_REG ) ;
while ( ( cbyte & 0x01 ) = = 0 ) {
cbyte = cbyte > > 1 ;
index + + ;
}
return ( eth32i_irqmap [ index ] ) ;
}
}
static int __init eth16i_check_signature ( int ioaddr )
{
int i ;
unsigned char creg [ 4 ] = { 0 } ;
for ( i = 0 ; i < 4 ; i + + ) {
creg [ i ] = inb ( ioaddr + TRANSMIT_MODE_REG + i ) ;
if ( eth16i_debug > 1 )
printk ( " eth16i: read signature byte %x at %x \n " ,
creg [ i ] ,
ioaddr + TRANSMIT_MODE_REG + i ) ;
}
creg [ 0 ] & = 0x0F ; /* Mask collision cnr */
creg [ 2 ] & = 0x7F ; /* Mask DCLEN bit */
#if 0
/*
This was removed because the card was sometimes left to state
from which it couldn ' t be find anymore . If there is need
to more strict check still this have to be fixed .
*/
if ( ! ( ( creg [ 0 ] = = 0x06 ) & & ( creg [ 1 ] = = 0x41 ) ) ) {
if ( creg [ 1 ] ! = 0x42 )
return - 1 ;
}
# endif
if ( ! ( ( creg [ 2 ] = = 0x36 ) & & ( creg [ 3 ] = = 0xE0 ) ) ) {
creg [ 2 ] & = 0x40 ;
creg [ 3 ] & = 0x03 ;
if ( ! ( ( creg [ 2 ] = = 0x40 ) & & ( creg [ 3 ] = = 0x00 ) ) )
return - 1 ;
}
if ( eth16i_read_eeprom ( ioaddr , E_NODEID_0 ) ! = 0 )
return - 1 ;
if ( ( eth16i_read_eeprom ( ioaddr , E_NODEID_1 ) & 0xFF00 ) ! = 0x4B00 )
return - 1 ;
return 0 ;
}
static int eth16i_read_eeprom ( int ioaddr , int offset )
{
int data = 0 ;
eth16i_eeprom_cmd ( ioaddr , EEPROM_READ | offset ) ;
outb ( CS_1 , ioaddr + EEPROM_CTRL_REG ) ;
data = eth16i_read_eeprom_word ( ioaddr ) ;
outb ( CS_0 | SK_0 , ioaddr + EEPROM_CTRL_REG ) ;
return ( data ) ;
}
static int eth16i_read_eeprom_word ( int ioaddr )
{
int i ;
int data = 0 ;
for ( i = 16 ; i > 0 ; i - - ) {
outb ( CS_1 | SK_0 , ioaddr + EEPROM_CTRL_REG ) ;
eeprom_slow_io ( ) ;
outb ( CS_1 | SK_1 , ioaddr + EEPROM_CTRL_REG ) ;
eeprom_slow_io ( ) ;
data = ( data < < 1 ) |
( ( inb ( ioaddr + EEPROM_DATA_REG ) & DI_1 ) ? 1 : 0 ) ;
eeprom_slow_io ( ) ;
}
return ( data ) ;
}
static void eth16i_eeprom_cmd ( int ioaddr , unsigned char command )
{
int i ;
outb ( CS_0 | SK_0 , ioaddr + EEPROM_CTRL_REG ) ;
outb ( DI_0 , ioaddr + EEPROM_DATA_REG ) ;
outb ( CS_1 | SK_0 , ioaddr + EEPROM_CTRL_REG ) ;
outb ( DI_1 , ioaddr + EEPROM_DATA_REG ) ;
outb ( CS_1 | SK_1 , ioaddr + EEPROM_CTRL_REG ) ;
for ( i = 7 ; i > = 0 ; i - - ) {
short cmd = ( ( command & ( 1 < < i ) ) ? DI_1 : DI_0 ) ;
outb ( cmd , ioaddr + EEPROM_DATA_REG ) ;
outb ( CS_1 | SK_0 , ioaddr + EEPROM_CTRL_REG ) ;
eeprom_slow_io ( ) ;
outb ( CS_1 | SK_1 , ioaddr + EEPROM_CTRL_REG ) ;
eeprom_slow_io ( ) ;
}
}
static int eth16i_open ( struct net_device * dev )
{
struct eth16i_local * lp = netdev_priv ( dev ) ;
int ioaddr = dev - > base_addr ;
/* Powerup the chip */
outb ( 0xc0 | POWERUP , ioaddr + CONFIG_REG_1 ) ;
/* Initialize the chip */
eth16i_initialize ( dev , 0 ) ;
/* Set the transmit buffer size */
lp - > tx_buf_size = eth16i_tx_buf_map [ ETH16I_TX_BUF_SIZE & 0x03 ] ;
if ( eth16i_debug > 0 )
printk ( KERN_DEBUG " %s: transmit buffer size %d \n " ,
dev - > name , lp - > tx_buf_size ) ;
/* Now enable Transmitter and Receiver sections */
BITCLR ( ioaddr + CONFIG_REG_0 , DLC_EN ) ;
/* Now switch to register bank 2, for run time operation */
eth16i_select_regbank ( 2 , ioaddr ) ;
lp - > open_time = jiffies ;
lp - > tx_started = 0 ;
lp - > tx_queue = 0 ;
lp - > tx_queue_len = 0 ;
/* Turn on interrupts*/
outw ( ETH16I_INTR_ON , ioaddr + TX_INTR_REG ) ;
netif_start_queue ( dev ) ;
return 0 ;
}
static int eth16i_close ( struct net_device * dev )
{
struct eth16i_local * lp = netdev_priv ( dev ) ;
int ioaddr = dev - > base_addr ;
eth16i_reset ( dev ) ;
/* Turn off interrupts*/
outw ( ETH16I_INTR_OFF , ioaddr + TX_INTR_REG ) ;
netif_stop_queue ( dev ) ;
lp - > open_time = 0 ;
/* Disable transmit and receive */
BITSET ( ioaddr + CONFIG_REG_0 , DLC_EN ) ;
/* Reset the chip */
/* outb(0xff, ioaddr + RESET); */
/* outw(0xffff, ioaddr + TX_STATUS_REG); */
outb ( 0x00 , ioaddr + CONFIG_REG_1 ) ;
return 0 ;
}
static void eth16i_timeout ( struct net_device * dev )
{
struct eth16i_local * lp = netdev_priv ( dev ) ;
int ioaddr = dev - > base_addr ;
/*
If we get here , some higher level has decided that
we are broken . There should really be a " kick me "
function call instead .
*/
outw ( ETH16I_INTR_OFF , ioaddr + TX_INTR_REG ) ;
printk ( KERN_WARNING " %s: transmit timed out with status %04x, %s ? \n " ,
dev - > name ,
inw ( ioaddr + TX_STATUS_REG ) , ( inb ( ioaddr + TX_STATUS_REG ) & TX_DONE ) ?
" IRQ conflict " : " network cable problem " ) ;
dev - > trans_start = jiffies ;
/* Let's dump all registers */
if ( eth16i_debug > 0 ) {
printk ( KERN_DEBUG " %s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x. \n " ,
dev - > name , inb ( ioaddr + 0 ) ,
inb ( ioaddr + 1 ) , inb ( ioaddr + 2 ) ,
inb ( ioaddr + 3 ) , inb ( ioaddr + 4 ) ,
inb ( ioaddr + 5 ) ,
inb ( ioaddr + 6 ) , inb ( ioaddr + 7 ) ) ;
printk ( KERN_DEBUG " %s: transmit start reg: %02x. collision reg %02x \n " ,
dev - > name , inb ( ioaddr + TRANSMIT_START_REG ) ,
inb ( ioaddr + COL_16_REG ) ) ;
printk ( KERN_DEBUG " lp->tx_queue = %d \n " , lp - > tx_queue ) ;
printk ( KERN_DEBUG " lp->tx_queue_len = %d \n " , lp - > tx_queue_len ) ;
printk ( KERN_DEBUG " lp->tx_started = %d \n " , lp - > tx_started ) ;
}
lp - > stats . tx_errors + + ;
eth16i_reset ( dev ) ;
dev - > trans_start = jiffies ;
outw ( ETH16I_INTR_ON , ioaddr + TX_INTR_REG ) ;
netif_wake_queue ( dev ) ;
}
static int eth16i_tx ( struct sk_buff * skb , struct net_device * dev )
{
struct eth16i_local * lp = netdev_priv ( dev ) ;
int ioaddr = dev - > base_addr ;
int status = 0 ;
ushort length = skb - > len ;
unsigned char * buf ;
unsigned long flags ;
if ( length < ETH_ZLEN ) {
skb = skb_padto ( skb , ETH_ZLEN ) ;
if ( skb = = NULL )
return 0 ;
length = ETH_ZLEN ;
}
buf = skb - > data ;
netif_stop_queue ( dev ) ;
/* Turn off TX interrupts */
outw ( ETH16I_INTR_OFF , ioaddr + TX_INTR_REG ) ;
/* We would be better doing the disable_irq tricks the 3c509 does,
that would make this suck a lot less */
spin_lock_irqsave ( & lp - > lock , flags ) ;
if ( ( length + 2 ) > ( lp - > tx_buf_size - lp - > tx_queue_len ) ) {
if ( eth16i_debug > 0 )
printk ( KERN_WARNING " %s: Transmit buffer full. \n " , dev - > name ) ;
}
else {
outw ( length , ioaddr + DATAPORT ) ;
if ( ioaddr < 0x1000 )
outsw ( ioaddr + DATAPORT , buf , ( length + 1 ) > > 1 ) ;
else {
unsigned char frag = length % 4 ;
outsl ( ioaddr + DATAPORT , buf , length > > 2 ) ;
if ( frag ! = 0 ) {
outsw ( ioaddr + DATAPORT , ( buf + ( length & 0xFFFC ) ) , 1 ) ;
if ( frag = = 3 )
outsw ( ioaddr + DATAPORT ,
( buf + ( length & 0xFFFC ) + 2 ) , 1 ) ;
}
}
lp - > tx_buffered_packets + + ;
lp - > tx_buffered_bytes = length ;
lp - > tx_queue + + ;
lp - > tx_queue_len + = length + 2 ;
}
lp - > tx_buf_busy = 0 ;
if ( lp - > tx_started = = 0 ) {
/* If the transmitter is idle..always trigger a transmit */
outb ( TX_START | lp - > tx_queue , ioaddr + TRANSMIT_START_REG ) ;
lp - > tx_queue = 0 ;
lp - > tx_queue_len = 0 ;
dev - > trans_start = jiffies ;
lp - > tx_started = 1 ;
netif_wake_queue ( dev ) ;
}
else if ( lp - > tx_queue_len < lp - > tx_buf_size - ( ETH_FRAME_LEN + 2 ) ) {
/* There is still more room for one more packet in tx buffer */
netif_wake_queue ( dev ) ;
}
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
outw ( ETH16I_INTR_ON , ioaddr + TX_INTR_REG ) ;
/* Turn TX interrupts back on */
/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
status = 0 ;
dev_kfree_skb ( skb ) ;
return 0 ;
}
static void eth16i_rx ( struct net_device * dev )
{
struct eth16i_local * lp = netdev_priv ( dev ) ;
int ioaddr = dev - > base_addr ;
int boguscount = MAX_RX_LOOP ;
/* Loop until all packets have been read */
while ( ( inb ( ioaddr + RECEIVE_MODE_REG ) & RX_BUFFER_EMPTY ) = = 0 ) {
/* Read status byte from receive buffer */
ushort status = inw ( ioaddr + DATAPORT ) ;
/* Get the size of the packet from receive buffer */
ushort pkt_len = inw ( ioaddr + DATAPORT ) ;
if ( eth16i_debug > 4 )
printk ( KERN_DEBUG " %s: Receiving packet mode %02x status %04x. \n " ,
dev - > name ,
inb ( ioaddr + RECEIVE_MODE_REG ) , status ) ;
if ( ! ( status & PKT_GOOD ) ) {
lp - > stats . rx_errors + + ;
if ( ( pkt_len < ETH_ZLEN ) | | ( pkt_len > ETH_FRAME_LEN ) ) {
lp - > stats . rx_length_errors + + ;
eth16i_reset ( dev ) ;
return ;
}
else {
eth16i_skip_packet ( dev ) ;
lp - > stats . rx_dropped + + ;
}
}
else { /* Ok so now we should have a good packet */
struct sk_buff * skb ;
skb = dev_alloc_skb ( pkt_len + 3 ) ;
if ( skb = = NULL ) {
printk ( KERN_WARNING " %s: Could'n allocate memory for packet (len %d) \n " ,
dev - > name , pkt_len ) ;
eth16i_skip_packet ( dev ) ;
lp - > stats . rx_dropped + + ;
break ;
}
skb - > dev = dev ;
skb_reserve ( skb , 2 ) ;
/*
Now let ' s get the packet out of buffer .
size is ( pkt_len + 1 ) > > 1 , cause we are now reading words
and it have to be even aligned .
*/
if ( ioaddr < 0x1000 )
insw ( ioaddr + DATAPORT , skb_put ( skb , pkt_len ) ,
( pkt_len + 1 ) > > 1 ) ;
else {
unsigned char * buf = skb_put ( skb , pkt_len ) ;
unsigned char frag = pkt_len % 4 ;
insl ( ioaddr + DATAPORT , buf , pkt_len > > 2 ) ;
if ( frag ! = 0 ) {
unsigned short rest [ 2 ] ;
rest [ 0 ] = inw ( ioaddr + DATAPORT ) ;
if ( frag = = 3 )
rest [ 1 ] = inw ( ioaddr + DATAPORT ) ;
memcpy ( buf + ( pkt_len & 0xfffc ) , ( char * ) rest , frag ) ;
}
}
skb - > protocol = eth_type_trans ( skb , dev ) ;
if ( eth16i_debug > 5 ) {
int i ;
printk ( KERN_DEBUG " %s: Received packet of length %d. \n " ,
dev - > name , pkt_len ) ;
for ( i = 0 ; i < 14 ; i + + )
printk ( KERN_DEBUG " %02x " , skb - > data [ i ] ) ;
printk ( KERN_DEBUG " . \n " ) ;
}
netif_rx ( skb ) ;
dev - > last_rx = jiffies ;
lp - > stats . rx_packets + + ;
lp - > stats . rx_bytes + = pkt_len ;
} /* else */
if ( - - boguscount < = 0 )
break ;
} /* while */
}
static irqreturn_t eth16i_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
struct net_device * dev = dev_id ;
struct eth16i_local * lp ;
int ioaddr = 0 , status ;
int handled = 0 ;
ioaddr = dev - > base_addr ;
lp = netdev_priv ( dev ) ;
/* Turn off all interrupts from adapter */
outw ( ETH16I_INTR_OFF , ioaddr + TX_INTR_REG ) ;
/* eth16i_tx won't be called */
spin_lock ( & lp - > lock ) ;
status = inw ( ioaddr + TX_STATUS_REG ) ; /* Get the status */
outw ( status , ioaddr + TX_STATUS_REG ) ; /* Clear status bits */
if ( status )
handled = 1 ;
if ( eth16i_debug > 3 )
printk ( KERN_DEBUG " %s: Interrupt with status %04x. \n " , dev - > name , status ) ;
if ( status & 0x7f00 ) {
lp - > stats . rx_errors + + ;
if ( status & ( BUS_RD_ERR < < 8 ) )
printk ( KERN_WARNING " %s: Bus read error. \n " , dev - > name ) ;
if ( status & ( SHORT_PKT_ERR < < 8 ) ) lp - > stats . rx_length_errors + + ;
if ( status & ( ALIGN_ERR < < 8 ) ) lp - > stats . rx_frame_errors + + ;
if ( status & ( CRC_ERR < < 8 ) ) lp - > stats . rx_crc_errors + + ;
if ( status & ( RX_BUF_OVERFLOW < < 8 ) ) lp - > stats . rx_over_errors + + ;
}
if ( status & 0x001a ) {
lp - > stats . tx_errors + + ;
if ( status & CR_LOST ) lp - > stats . tx_carrier_errors + + ;
if ( status & TX_JABBER_ERR ) lp - > stats . tx_window_errors + + ;
#if 0
if ( status & COLLISION ) {
lp - > stats . collisions + =
( ( inb ( ioaddr + TRANSMIT_MODE_REG ) & 0xF0 ) > > 4 ) ;
}
# endif
if ( status & COLLISIONS_16 ) {
if ( lp - > col_16 < MAX_COL_16 ) {
lp - > col_16 + + ;
lp - > stats . collisions + + ;
/* Resume transmitting, skip failed packet */
outb ( 0x02 , ioaddr + COL_16_REG ) ;
}
else {
printk ( KERN_WARNING " %s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem? \n " , dev - > name ) ;
}
}
}
if ( status & 0x00ff ) { /* Let's check the transmit status reg */
if ( status & TX_DONE ) { /* The transmit has been done */
lp - > stats . tx_packets = lp - > tx_buffered_packets ;
lp - > stats . tx_bytes + = lp - > tx_buffered_bytes ;
lp - > col_16 = 0 ;
if ( lp - > tx_queue ) { /* Is there still packets ? */
/* There was packet(s) so start transmitting and write also
how many packets there is to be sended */
outb ( TX_START | lp - > tx_queue , ioaddr + TRANSMIT_START_REG ) ;
lp - > tx_queue = 0 ;
lp - > tx_queue_len = 0 ;
lp - > tx_started = 1 ;
}
else {
lp - > tx_started = 0 ;
}
netif_wake_queue ( dev ) ;
}
}
if ( ( status & 0x8000 ) | |
( ( inb ( ioaddr + RECEIVE_MODE_REG ) & RX_BUFFER_EMPTY ) = = 0 ) ) {
eth16i_rx ( dev ) ; /* We have packet in receive buffer */
}
/* Turn interrupts back on */
outw ( ETH16I_INTR_ON , ioaddr + TX_INTR_REG ) ;
if ( lp - > tx_queue_len < lp - > tx_buf_size - ( ETH_FRAME_LEN + 2 ) ) {
/* There is still more room for one more packet in tx buffer */
netif_wake_queue ( dev ) ;
}
spin_unlock ( & lp - > lock ) ;
return IRQ_RETVAL ( handled ) ;
}
static void eth16i_skip_packet ( struct net_device * dev )
{
int ioaddr = dev - > base_addr ;
inw ( ioaddr + DATAPORT ) ;
inw ( ioaddr + DATAPORT ) ;
inw ( ioaddr + DATAPORT ) ;
outb ( SKIP_RX_PACKET , ioaddr + FILTER_SELF_RX_REG ) ;
while ( inb ( ioaddr + FILTER_SELF_RX_REG ) ! = 0 ) ;
}
static void eth16i_reset ( struct net_device * dev )
{
struct eth16i_local * lp = netdev_priv ( dev ) ;
int ioaddr = dev - > base_addr ;
if ( eth16i_debug > 1 )
printk ( KERN_DEBUG " %s: Resetting device. \n " , dev - > name ) ;
BITSET ( ioaddr + CONFIG_REG_0 , DLC_EN ) ;
outw ( 0xffff , ioaddr + TX_STATUS_REG ) ;
eth16i_select_regbank ( 2 , ioaddr ) ;
lp - > tx_started = 0 ;
lp - > tx_buf_busy = 0 ;
lp - > tx_queue = 0 ;
lp - > tx_queue_len = 0 ;
BITCLR ( ioaddr + CONFIG_REG_0 , DLC_EN ) ;
}
static void eth16i_multicast ( struct net_device * dev )
{
int ioaddr = dev - > base_addr ;
if ( dev - > mc_count | | dev - > flags & ( IFF_ALLMULTI | IFF_PROMISC ) )
{
dev - > flags | = IFF_PROMISC ; /* Must do this */
outb ( 3 , ioaddr + RECEIVE_MODE_REG ) ;
} else {
outb ( 2 , ioaddr + RECEIVE_MODE_REG ) ;
}
}
static struct net_device_stats * eth16i_get_stats ( struct net_device * dev )
{
struct eth16i_local * lp = netdev_priv ( dev ) ;
return & lp - > stats ;
}
static void eth16i_select_regbank ( unsigned char banknbr , int ioaddr )
{
unsigned char data ;
data = inb ( ioaddr + CONFIG_REG_1 ) ;
outb ( ( ( data & 0xF3 ) | ( ( banknbr & 0x03 ) < < 2 ) ) , ioaddr + CONFIG_REG_1 ) ;
}
# ifdef MODULE
static ushort eth16i_parse_mediatype ( const char * s )
{
if ( ! s )
return E_PORT_FROM_EPROM ;
if ( ! strncmp ( s , " bnc " , 3 ) )
return E_PORT_BNC ;
else if ( ! strncmp ( s , " tp " , 2 ) )
return E_PORT_TP ;
else if ( ! strncmp ( s , " dix " , 3 ) )
return E_PORT_DIX ;
else if ( ! strncmp ( s , " auto " , 4 ) )
return E_PORT_AUTO ;
else
return E_PORT_FROM_EPROM ;
}
# define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */
static struct net_device * dev_eth16i [ MAX_ETH16I_CARDS ] ;
static int io [ MAX_ETH16I_CARDS ] ;
#if 0
static int irq [ MAX_ETH16I_CARDS ] ;
# endif
static char * mediatype [ MAX_ETH16I_CARDS ] ;
static int debug = - 1 ;
MODULE_AUTHOR ( " Mika Kuoppala <miku@iki.fi> " ) ;
MODULE_DESCRIPTION ( " ICL EtherTeam 16i/32 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param_array ( io , int , NULL , 0 ) ;
MODULE_PARM_DESC ( io , " eth16i I/O base address(es) " ) ;
#if 0
module_param_array ( irq , int , NULL , 0 ) ;
MODULE_PARM_DESC ( irq , " eth16i interrupt request number " ) ;
# endif
module_param_array ( mediatype , charp , NULL , 0 ) ;
MODULE_PARM_DESC ( mediatype , " eth16i media type of interface(s) (bnc,tp,dix,auto,eprom) " ) ;
module_param ( debug , int , 0 ) ;
MODULE_PARM_DESC ( debug , " eth16i debug level (0-6) " ) ;
int init_module ( void )
{
int this_dev , found = 0 ;
struct net_device * dev ;
for ( this_dev = 0 ; this_dev < MAX_ETH16I_CARDS ; this_dev + + ) {
dev = alloc_etherdev ( sizeof ( struct eth16i_local ) ) ;
if ( ! dev )
break ;
dev - > base_addr = io [ this_dev ] ;
if ( debug ! = - 1 )
eth16i_debug = debug ;
if ( eth16i_debug > 1 )
printk ( KERN_NOTICE " eth16i(%d): interface type %s \n " , this_dev , mediatype [ this_dev ] ? mediatype [ this_dev ] : " none " ) ;
dev - > if_port = eth16i_parse_mediatype ( mediatype [ this_dev ] ) ;
if ( io [ this_dev ] = = 0 ) {
if ( this_dev ! = 0 ) /* Only autoprobe 1st one */
break ;
printk ( KERN_NOTICE " eth16i.c: Presently autoprobing (not recommended) for a single card. \n " ) ;
}
if ( do_eth16i_probe ( dev ) = = 0 ) {
2005-05-13 04:11:55 +04:00
dev_eth16i [ found + + ] = dev ;
continue ;
2005-04-17 02:20:36 +04:00
}
printk ( KERN_WARNING " eth16i.c No Eth16i card found (i/o = 0x%x). \n " ,
io [ this_dev ] ) ;
free_netdev ( dev ) ;
break ;
}
if ( found )
return 0 ;
return - ENXIO ;
}
void cleanup_module ( void )
{
int this_dev ;
for ( this_dev = 0 ; this_dev < MAX_ETH16I_CARDS ; this_dev + + ) {
struct net_device * dev = dev_eth16i [ this_dev ] ;
if ( dev - > priv ) {
unregister_netdev ( dev ) ;
free_irq ( dev - > irq , dev ) ;
release_region ( dev - > base_addr , ETH16I_IO_EXTENT ) ;
free_netdev ( dev ) ;
}
}
}
# endif /* MODULE */
/*
* Local variables :
* compile - command : " gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c "
* alt - compile - command : " gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c "
* tab - width : 8
* c - basic - offset : 8
* c - indent - level : 8
* End :
*/
/* End of file eth16i.c */