基于DM9000C的原厂代码修改dm9000c的驱动程序。

首先确认内存的基地址 iobase.

确定中断号码。

打开模块的初始化函数定义。

配置内存控制器的相应时序(结合DM9000C.C的手册).

程序代码:

/*

  dm9ks.c: Version 2.08 2007/02/12 

        A Davicom DM9000/DM9010 ISA NIC fast Ethernet driver for Linux.

    This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. (C)Copyright 1997-2007 DAVICOM Semiconductor,Inc. All Rights Reserved. V2.00 Spenser - 01/10/2005
- Modification for PXA270 MAINSTONE.
- Modified dmfe_tx_done().
- Add dmfe_timeout().
V2.01 10/07/2005 -Modified dmfe_timer()
-Dected network speed 10/100M
V2.02 10/12/2005 -Use link change to chage db->Speed
-dmfe_open() wait for Link OK
V2.03 11/22/2005 -Power-off and Power-on PHY in dmfe_init_dm9000()
-support IOL
V2.04 12/13/2005 -delay 1.6s between power-on and power-off in
dmfe_init_dm9000()
-set LED mode 1 in dmfe_init_dm9000()
-add data bus driving capability in dmfe_init_dm9000()
(optional)
10/3/2006 -Add DM8606 read/write function by MDC and MDIO
V2.06 01/03/2007 -CONT_RX_PKT_CNT=0xFFFF
-modify dmfe_tx_done function
-check RX FIFO pointer
-if using physical address, re-define I/O function
-add db->cont_rx_pkt_cnt=0 at the front of dmfe_packet_receive()
V2.08 02/12/2007 -module parameter macro
2.4 MODULE_PARM
2.6 module_param
-remove #include <linux/config>
-fix dmfe_interrupt for kernel 2.6.20
V2.09 05/24/2007 -support ethtool and mii-tool
05/30/2007 -fix the driver bug when ifconfig eth0 (-)promisc and (-)allmulti.
06/05/2007 -fix dm9000b issue(ex. 10M TX idle=65mA, 10M harmonic)
-add flow control function (option)
10/01/2007 -Add #include <asm/uaccess.h>
-Modyfy dmfe_do_ioctl for kernel 2.6.7
11/23/2007 -Add TDBUG to check TX FIFO pointer shift
- Remove check_rx_ready()
- Add #define CHECKSUM to modify CHECKSUM function
12/20/2007 -Modify TX timeout routine(+)check TCR&0x01 */ //#define CHECKSUM
//#define TDBUG /* check TX FIFO pointer */
//#define RDBUG /* check RX FIFO pointer */
//#define DM8606 #define DRV_NAME "dm9KS"
#define DRV_VERSION "2.09"
#define DRV_RELDATE "2007-11-22" #ifdef MODVERSIONS
#include <linux/modversions.h>
#endif //#include <linux/config.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#include <asm/dma.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <asm/uaccess.h> //#ifdef CONFIG_ARCH_MAINSTONE
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
//#endif /* Board/System/Debug information/definition ---------------- */ #define DM9KS_ID 0x90000A46
#define DM9010_ID 0x90100A46
/*-------register name-----------------------*/
#define DM9KS_NCR 0x00 /* Network control Reg.*/
#define DM9KS_NSR 0x01 /* Network Status Reg.*/
#define DM9KS_TCR 0x02 /* TX control Reg.*/
#define DM9KS_RXCR 0x05 /* RX control Reg.*/
#define DM9KS_BPTR 0x08
#define DM9KS_FCTR 0x09
#define DM9KS_FCR 0x0a
#define DM9KS_EPCR 0x0b
#define DM9KS_EPAR 0x0c
#define DM9KS_EPDRL 0x0d
#define DM9KS_EPDRH 0x0e
#define DM9KS_GPR 0x1f /* General purpose register */
#define DM9KS_CHIPR 0x2c
#define DM9KS_TCR2 0x2d
#define DM9KS_SMCR 0x2f /* Special Mode Control Reg.*/
#define DM9KS_ETXCSR 0x30 /* Early Transmit control/status Reg.*/
#define DM9KS_TCCR 0x31 /* Checksum cntrol Reg. */
#define DM9KS_RCSR 0x32 /* Receive Checksum status Reg.*/
#define DM9KS_BUSCR 0x38
#define DM9KS_MRCMDX 0xf0
#define DM9KS_MRCMD 0xf2
#define DM9KS_MDRAL 0xf4
#define DM9KS_MDRAH 0xf5
#define DM9KS_MWCMD 0xf8
#define DM9KS_MDWAL 0xfa
#define DM9KS_MDWAH 0xfb
#define DM9KS_TXPLL 0xfc
#define DM9KS_TXPLH 0xfd
#define DM9KS_ISR 0xfe
#define DM9KS_IMR 0xff
/*---------------------------------------------*/
#define DM9KS_REG05 0x30 /* SKIP_CRC/SKIP_LONG */
#define DM9KS_REGFF 0xA3 /* IMR */
#define DM9KS_DISINTR 0x80 #define DM9KS_PHY 0x40 /* PHY address 0x01 */
#define DM9KS_PKT_RDY 0x01 /* Packet ready to receive */ /* Added for PXA of MAINSTONE */
#ifdef CONFIG_ARCH_MAINSTONE
#include <asm/arch/mainstone.h>
#define DM9KS_MIN_IO (MST_ETH_PHYS + 0x300)
#define DM9KS_MAX_IO (MST_ETH_PHYS + 0x370)
#define DM9K_IRQ MAINSTONE_IRQ(3)
#else
#define DM9KS_MIN_IO 0x300
#define DM9KS_MAX_IO 0x370
#define DM9KS_IRQ 3
#endif #define DM9KS_VID_L 0x28
#define DM9KS_VID_H 0x29
#define DM9KS_PID_L 0x2A
#define DM9KS_PID_H 0x2B #define DM9KS_RX_INTR 0x01
#define DM9KS_TX_INTR 0x02
#define DM9KS_LINK_INTR 0x20 #define DM9KS_DWORD_MODE 1
#define DM9KS_BYTE_MODE 2
#define DM9KS_WORD_MODE 0 #define TRUE 1
#define FALSE 0
/* Number of continuous Rx packets */
#define CONT_RX_PKT_CNT 0xFFFF #define DMFE_TIMER_WUT jiffies+(HZ*5) /* timer wakeup time : 5 second */ #ifdef DM9KS_DEBUG
#define DMFE_DBUG(dbug_now, msg, vaule)\
if (dmfe_debug||dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
#else
#define DMFE_DBUG(dbug_now, msg, vaule)\
if (dbug_now) printk(KERN_ERR "dmfe: %s %x\n", msg, vaule)
#endif #ifndef CONFIG_ARCH_MAINSTONE
#pragma pack(push, 1)
#endif typedef struct _RX_DESC
{
u8 rxbyte;
u8 status;
u16 length;
}RX_DESC; typedef union{
u8 buf[];
RX_DESC desc;
} rx_t;
#ifndef CONFIG_ARCH_MAINSTONE
#pragma pack(pop)
#endif enum DM9KS_PHY_mode {
DM9KS_10MHD = ,
DM9KS_100MHD = ,
DM9KS_10MFD = ,
DM9KS_100MFD = ,
DM9KS_AUTO = ,
}; /* Structure/enum declaration ------------------------------- */
typedef struct board_info {
u32 io_addr;/* Register I/O base address */
u32 io_data;/* Data I/O address */
u8 op_mode;/* PHY operation mode */
u8 io_mode;/* 0:word, 2:byte */
u8 Speed; /* current speed */
u8 chip_revision;
int rx_csum;/* 0:disable, 1:enable */ u32 reset_counter;/* counter: RESET */
u32 reset_tx_timeout;/* RESET caused by TX Timeout */
int tx_pkt_cnt;
int cont_rx_pkt_cnt;/* current number of continuos rx packets */
struct net_device_stats stats; struct timer_list timer;
unsigned char srom[];
spinlock_t lock;
struct mii_if_info mii;
} board_info_t;
/* Global variable declaration ----------------------------- */
/*static int dmfe_debug = 0;*/
static struct net_device * dmfe_dev = NULL;
static struct ethtool_ops dmfe_ethtool_ops;
/* For module input parameter */
static int mode = DM9KS_AUTO;
static int media_mode = DM9KS_AUTO;
static int irq = DM9KS_IRQ;
static int iobase = DM9KS_MIN_IO; #if 0 // use physical address; Not virtual address
#ifdef outb
#undef outb
#endif
#ifdef outw
#undef outw
#endif
#ifdef outl
#undef outl
#endif
#ifdef inb
#undef inb
#endif
#ifdef inw
#undef inw
#endif
#ifdef inl
#undef inl
#endif
void outb(u8 reg, u32 ioaddr)
{
(*(volatile u8 *)(ioaddr)) = reg;
}
void outw(u16 reg, u32 ioaddr)
{
(*(volatile u16 *)(ioaddr)) = reg;
}
void outl(u32 reg, u32 ioaddr)
{
(*(volatile u32 *)(ioaddr)) = reg;
}
u8 inb(u32 ioaddr)
{
return (*(volatile u8 *)(ioaddr));
}
u16 inw(u32 ioaddr)
{
return (*(volatile u16 *)(ioaddr));
}
u32 inl(u32 ioaddr)
{
return (*(volatile u32 *)(ioaddr));
}
#endif /* function declaration ------------------------------------- */
int dmfe_probe1(struct net_device *);
static int dmfe_open(struct net_device *);
static int dmfe_start_xmit(struct sk_buff *, struct net_device *);
static void dmfe_tx_done(unsigned long);
static void dmfe_packet_receive(struct net_device *);
static int dmfe_stop(struct net_device *);
static struct net_device_stats * dmfe_get_stats(struct net_device *);
static int dmfe_do_ioctl(struct net_device *, struct ifreq *, int);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void dmfe_interrupt(int , void *, struct pt_regs *);
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t dmfe_interrupt(int , void *, struct pt_regs *);
#else
static irqreturn_t dmfe_interrupt(int , void *);/* for kernel 2.6.20 */
#endif
#endif
static void dmfe_timer(unsigned long);
static void dmfe_init_dm9000(struct net_device *);
static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
u8 ior(board_info_t *, int);
void iow(board_info_t *, int, u8);
static u16 phy_read(board_info_t *, int);
static void phy_write(board_info_t *, int, u16);
static u16 read_srom_word(board_info_t *, int);
static void dm9000_hash_table(struct net_device *);
static void dmfe_timeout(struct net_device *);
static void dmfe_reset(struct net_device *);
static int mdio_read(struct net_device *, int, int);
static void mdio_write(struct net_device *, int, int, int);
static void dmfe_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
static int dmfe_get_settings(struct net_device *, struct ethtool_cmd *);
static int dmfe_set_settings(struct net_device *, struct ethtool_cmd *);
static u32 dmfe_get_link(struct net_device *);
static int dmfe_nway_reset(struct net_device *);
static uint32_t dmfe_get_rx_csum(struct net_device *);
static uint32_t dmfe_get_tx_csum(struct net_device *);
static int dmfe_set_rx_csum(struct net_device *, uint32_t );
static int dmfe_set_tx_csum(struct net_device *, uint32_t ); #ifdef DM8606
#include "dm8606.h"
#endif //DECLARE_TASKLET(dmfe_tx_tasklet,dmfe_tx_done,0); /* DM9000 network baord routine ---------------------------- */ /*
Search DM9000 board, allocate space and register it
*/ struct net_device * __init dmfe_probe(void)
{
struct net_device *dev;
int err; DMFE_DBUG(, "dmfe_probe()",); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
dev = init_etherdev(NULL, sizeof(struct board_info));
//ether_setup(dev);
#else
dev= alloc_etherdev(sizeof(struct board_info));
#endif if(!dev)
return ERR_PTR(-ENOMEM); SET_MODULE_OWNER(dev);
err = dmfe_probe1(dev);
if (err)
goto out;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
err = register_netdev(dev);
if (err)
goto out1;
#endif
return dev;
out1:
release_region(dev->base_addr,);
out:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
kfree(dev);
#else
free_netdev(dev);
#endif
return ERR_PTR(err);
} int __init dmfe_probe1(struct net_device *dev)
{
struct board_info *db; /* Point a board information structure */
u32 id_val;
u16 i, dm9000_found = FALSE;
u8 MAC_addr[]={0x00,0x60,0x6E,0x33,0x44,0x55};
u8 HasEEPROM=,chip_info;
DMFE_DBUG(, "dmfe_probe1()",); /* Search All DM9000 serial NIC */
do {
outb(DM9KS_VID_L, iobase);
id_val = inb(iobase + );
outb(DM9KS_VID_H, iobase);
id_val |= inb(iobase + ) << ;
outb(DM9KS_PID_L, iobase);
id_val |= inb(iobase + ) << ;
outb(DM9KS_PID_H, iobase);
id_val |= inb(iobase + ) << ; if (id_val == DM9KS_ID || id_val == DM9010_ID) { /* Request IO from system */
if(!request_region(iobase, , dev->name))
return -ENODEV; printk(KERN_ERR"<DM9KS> I/O: %x, VID: %x \n",iobase, id_val);
dm9000_found = TRUE; /* Allocated board information structure */
memset(dev->priv, , sizeof(struct board_info));
db = (board_info_t *)dev->priv;
dmfe_dev = dev;
db->io_addr = iobase;
db->io_data = iobase + ;
db->chip_revision = ior(db, DM9KS_CHIPR); chip_info = ior(db,0x43);
//if((db->chip_revision!=0x1A) || ((chip_info&(1<<5))!=0) || ((chip_info&(1<<2))!=1)) return -ENODEV; /* driver system function */
dev->base_addr = iobase;
dev->irq = irq;
dev->open = &dmfe_open;
dev->hard_start_xmit = &dmfe_start_xmit;
dev->watchdog_timeo = *HZ;
dev->tx_timeout = dmfe_timeout;
dev->stop = &dmfe_stop;
dev->get_stats = &dmfe_get_stats;
dev->set_multicast_list = &dm9000_hash_table;
dev->do_ioctl = &dmfe_do_ioctl;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,28)
dev->ethtool_ops = &dmfe_ethtool_ops;
#endif
#ifdef CHECKSUM
//dev->features |= NETIF_F_IP_CSUM;
dev->features |= NETIF_F_IP_CSUM|NETIF_F_SG;
#endif
db->mii.dev = dev;
db->mii.mdio_read = mdio_read;
db->mii.mdio_write = mdio_write;
db->mii.phy_id = ;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
db->mii.phy_id_mask = 0x1F;
db->mii.reg_num_mask = 0x1F;
#endif
//db->msg_enable =(debug == 0 ? DMFE_DEF_MSG_ENABLE : ((1 << debug) - 1)); /* Read SROM content */
for (i=; i<; i++)
((u16 *)db->srom)[i] = read_srom_word(db, i); /* Get the PID and VID from EEPROM to check */
id_val = (((u16 *)db->srom)[])|(((u16 *)db->srom)[]<<);
printk("id_val=%x\n", id_val);
if (id_val == DM9KS_ID || id_val == DM9010_ID)
HasEEPROM =; /* Set Node Address */
for (i=; i<; i++)
{
if (HasEEPROM) /* use EEPROM */
dev->dev_addr[i] = db->srom[i];
else /* No EEPROM */
dev->dev_addr[i] = MAC_addr[i];
}
}//end of if()
iobase += 0x10;
}while(!dm9000_found && iobase <= DM9KS_MAX_IO); return dm9000_found ? :-ENODEV;
} /*
Open the interface.
The interface is opened whenever "ifconfig" actives it.
*/
static int dmfe_open(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
u8 reg_nsr;
int i;
DMFE_DBUG(, "dmfe_open", ); if (request_irq(dev->irq,&dmfe_interrupt,IRQF_TRIGGER_RISING,dev->name,dev))
return -EAGAIN; /* Initilize DM910X board */
dmfe_init_dm9000(dev);
#ifdef DM8606
// control DM8606
printk("[8606]reg0=0x%04x\n",dm8606_read(db,));
printk("[8606]reg1=0x%04x\n",dm8606_read(db,0x1));
#endif
/* Init driver variable */
db->reset_counter = ;
db->reset_tx_timeout = ;
db->cont_rx_pkt_cnt = ; /* check link state and media speed */
db->Speed =;
i=;
do {
reg_nsr = ior(db,DM9KS_NSR);
if(reg_nsr & 0x40) /* link OK!! */
{
/* wait for detected Speed */
mdelay();
reg_nsr = ior(db,DM9KS_NSR);
if(reg_nsr & 0x80)
db->Speed =;
else
db->Speed =;
break;
}
i++;
mdelay();
}while(i<); /* wait 3 second */
//printk("i=%d Speed=%d\n",i,db->Speed);
/* set and active a timer process */
init_timer(&db->timer);
db->timer.expires = DMFE_TIMER_WUT;
db->timer.data = (unsigned long)dev;
db->timer.function = &dmfe_timer;
add_timer(&db->timer); //Move to DM9000 initiallization was finished. netif_start_queue(dev); return ;
} /* Set PHY operationg mode
*/
static void set_PHY_mode(board_info_t *db)
{
#ifndef DM8606
u16 phy_reg0 = 0x1000;/* Auto-negotiation*/
u16 phy_reg4 = 0x01e1; if ( !(db->op_mode & DM9KS_AUTO) ) // op_mode didn't auto sense */
{
switch(db->op_mode) {
case DM9KS_10MHD: phy_reg4 = 0x21;
phy_reg0 = 0x1000;
break;
case DM9KS_10MFD: phy_reg4 = 0x41;
phy_reg0 = 0x1100;
break;
case DM9KS_100MHD: phy_reg4 = 0x81;
phy_reg0 = 0x3000;
break;
case DM9KS_100MFD: phy_reg4 = 0x101;
phy_reg0 = 0x3100;
break;
default:
break;
} // end of switch
} // end of if
#ifdef FLOW_CONTROL
phy_write(db, , phy_reg4|(<<));
#else
phy_write(db, , phy_reg4);
#endif //end of FLOW_CONTROL
phy_write(db, , phy_reg0|0x200);
#else
/* Fiber mode */
phy_write(db, , 0x4014);
phy_write(db, , 0x2100);
#endif //end of DM8606 if (db->chip_revision == 0x1A)
{
//set 10M TX idle =65mA (TX 100% utility is 160mA)
phy_write(db,, phy_read(db,)|(<<)|(<<)); //:fix harmonic
//For short code:
//PHY_REG 27 (1Bh) <- 0000h
phy_write(db, , 0x0000);
//PHY_REG 27 (1Bh) <- AA00h
phy_write(db, , 0xaa00); //PHY_REG 27 (1Bh) <- 0017h
phy_write(db, , 0x0017);
//PHY_REG 27 (1Bh) <- AA17h
phy_write(db, , 0xaa17); //PHY_REG 27 (1Bh) <- 002Fh
phy_write(db, , 0x002f);
//PHY_REG 27 (1Bh) <- AA2Fh
phy_write(db, , 0xaa2f); //PHY_REG 27 (1Bh) <- 0037h
phy_write(db, , 0x0037);
//PHY_REG 27 (1Bh) <- AA37h
phy_write(db, , 0xaa37); //PHY_REG 27 (1Bh) <- 0040h
phy_write(db, , 0x0040);
//PHY_REG 27 (1Bh) <- AA40h
phy_write(db, , 0xaa40); //For long code:
//PHY_REG 27 (1Bh) <- 0050h
phy_write(db, , 0x0050);
//PHY_REG 27 (1Bh) <- AA50h
phy_write(db, , 0xaa50); //PHY_REG 27 (1Bh) <- 006Bh
phy_write(db, , 0x006b);
//PHY_REG 27 (1Bh) <- AA6Bh
phy_write(db, , 0xaa6b); //PHY_REG 27 (1Bh) <- 007Dh
phy_write(db, , 0x007d);
//PHY_REG 27 (1Bh) <- AA7Dh
phy_write(db, , 0xaa7d); //PHY_REG 27 (1Bh) <- 008Dh
phy_write(db, , 0x008d);
//PHY_REG 27 (1Bh) <- AA8Dh
phy_write(db, , 0xaa8d); //PHY_REG 27 (1Bh) <- 009Ch
phy_write(db, , 0x009c);
//PHY_REG 27 (1Bh) <- AA9Ch
phy_write(db, , 0xaa9c); //PHY_REG 27 (1Bh) <- 00A3h
phy_write(db, , 0x00a3);
//PHY_REG 27 (1Bh) <- AAA3h
phy_write(db, , 0xaaa3); //PHY_REG 27 (1Bh) <- 00B1h
phy_write(db, , 0x00b1);
//PHY_REG 27 (1Bh) <- AAB1h
phy_write(db, , 0xaab1); //PHY_REG 27 (1Bh) <- 00C0h
phy_write(db, , 0x00c0);
//PHY_REG 27 (1Bh) <- AAC0h
phy_write(db, , 0xaac0); //PHY_REG 27 (1Bh) <- 00D2h
phy_write(db, , 0x00d2);
//PHY_REG 27 (1Bh) <- AAD2h
phy_write(db, , 0xaad2); //PHY_REG 27 (1Bh) <- 00E0h
phy_write(db, , 0x00e0);
//PHY_REG 27 (1Bh) <- AAE0h
phy_write(db, , 0xaae0);
//PHY_REG 27 (1Bh) <- 0000h
phy_write(db, , 0x0000);
}
} /*
Initilize dm9000 board
*/
static void dmfe_init_dm9000(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
DMFE_DBUG(, "dmfe_init_dm9000()", ); spin_lock_init(&db->lock); iow(db, DM9KS_GPR, ); /* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */
mdelay(); /* wait for PHY power-on ready */ /* do a software reset and wait 20us */
iow(db, DM9KS_NCR, );
udelay(); /* wait 20us at least for software reset ok */
iow(db, DM9KS_NCR, ); /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on */
udelay(); /* wait 20us at least for software reset ok */ /* I/O mode */
db->io_mode = ior(db, DM9KS_ISR) >> ; /* ISR bit7:6 keeps I/O mode */ /* Set PHY */
db->op_mode = media_mode;
set_PHY_mode(db); /* Program operating register */
iow(db, DM9KS_NCR, );
iow(db, DM9KS_TCR, ); /* TX Polling clear */
iow(db, DM9KS_BPTR, 0x3f); /* Less 3kb, 600us */
iow(db, DM9KS_SMCR, ); /* Special Mode */
iow(db, DM9KS_NSR, 0x2c); /* clear TX status */
iow(db, DM9KS_ISR, 0x0f); /* Clear interrupt status */
iow(db, DM9KS_TCR2, 0x80); /* Set LED mode 1 */
if (db->chip_revision == 0x1A){
/* Data bus current driving/sinking capability */
iow(db, DM9KS_BUSCR, 0x01); /* default: 2mA */
}
#ifdef FLOW_CONTROL
iow(db, DM9KS_BPTR, 0x37);
iow(db, DM9KS_FCTR, 0x38);
iow(db, DM9KS_FCR, 0x29);
#endif #ifdef DM8606
iow(db,0x34,);
#endif if (dev->features & NETIF_F_HW_CSUM){
printk(KERN_INFO "DM9KS:enable TX checksum\n");
iow(db, DM9KS_TCCR, 0x07); /* TX UDP/TCP/IP checksum enable */
}
if (db->rx_csum){
printk(KERN_INFO "DM9KS:enable RX checksum\n");
iow(db, DM9KS_RCSR, 0x02); /* RX checksum enable */
} #ifdef ETRANS
/*If TX loading is heavy, the driver can try to anbel "early transmit".
The programmer can tune the "Early Transmit Threshold" to get
the optimization. (DM9KS_ETXCSR.[1-0]) Side Effect: It will happen "Transmit under-run". When TX under-run
always happens, the programmer can increase the value of "Early
Transmit Threshold". */
iow(db, DM9KS_ETXCSR, 0x83);
#endif /* Set address filter table */
dm9000_hash_table(dev); /* Activate DM9000/DM9010 */
iow(db, DM9KS_IMR, DM9KS_REGFF); /* Enable TX/RX interrupt mask */
iow(db, DM9KS_RXCR, DM9KS_REG05 | ); /* RX enable */ /* Init Driver variable */
db->tx_pkt_cnt = ; netif_carrier_on(dev); } /*
Hardware start transmission.
Send a packet to media from the upper layer.
*/
static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
char * data_ptr;
int i, tmplen;
u16 MDWAH, MDWAL; #ifdef TDBUG /* check TX FIFO pointer */
u16 MDWAH1, MDWAL1;
u16 tx_ptr;
#endif DMFE_DBUG(, "dmfe_start_xmit", );
if (db->chip_revision != 0x1A)
{
if(db->Speed == )
{if (db->tx_pkt_cnt >= ) return ;}
else
{if (db->tx_pkt_cnt >= ) return ;}
}else
if (db->tx_pkt_cnt >= ) return ; /* packet counting */
db->tx_pkt_cnt++; db->stats.tx_packets++;
db->stats.tx_bytes+=skb->len;
if (db->chip_revision != 0x1A)
{
if (db->Speed == )
{if (db->tx_pkt_cnt >= ) netif_stop_queue(dev);}
else
{if (db->tx_pkt_cnt >= ) netif_stop_queue(dev);}
}else
if (db->tx_pkt_cnt >= ) netif_stop_queue(dev); /* Disable all interrupt */
iow(db, DM9KS_IMR, DM9KS_DISINTR); MDWAH = ior(db,DM9KS_MDWAH);
MDWAL = ior(db,DM9KS_MDWAL); /* Set TX length to reg. 0xfc & 0xfd */
iow(db, DM9KS_TXPLL, (skb->len & 0xff));
iow(db, DM9KS_TXPLH, (skb->len >> ) & 0xff); /* Move data to TX SRAM */
data_ptr = (char *)skb->data; outb(DM9KS_MWCMD, db->io_addr); // Write data into SRAM trigger
switch(db->io_mode)
{
case DM9KS_BYTE_MODE:
for (i = ; i < skb->len; i++)
outb((data_ptr[i] & 0xff), db->io_data);
break;
case DM9KS_WORD_MODE:
tmplen = (skb->len + ) / ;
for (i = ; i < tmplen; i++)
outw(((u16 *)data_ptr)[i], db->io_data);
break;
case DM9KS_DWORD_MODE:
tmplen = (skb->len + ) / ;
for (i = ; i< tmplen; i++)
outl(((u32 *)data_ptr)[i], db->io_data);
break;
} #ifndef ETRANS
/* Issue TX polling command */
iow(db, DM9KS_TCR, 0x1); /* Cleared after TX complete*/
#endif #ifdef TDBUG /* check TX FIFO pointer */
MDWAH1 = ior(db,DM9KS_MDWAH);
MDWAL1 = ior(db,DM9KS_MDWAL);
tx_ptr = (MDWAH<<)|MDWAL;
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
tx_ptr += skb->len;
break;
case DM9KS_WORD_MODE:
tx_ptr += ((skb->len + ) / )*;
break;
case DM9KS_DWORD_MODE:
tx_ptr += ((skb->len+)/)*;
break;
}
if (tx_ptr > 0x0bff)
tx_ptr -= 0x0c00;
if (tx_ptr != ((MDWAH1<<)|MDWAL1))
printk("[dm9ks:TX FIFO ERROR\n");
#endif
/* Saved the time stamp */
dev->trans_start = jiffies;
db->cont_rx_pkt_cnt =; /* Free this SKB */
dev_kfree_skb(skb); /* Re-enable interrupt */
iow(db, DM9KS_IMR, DM9KS_REGFF); return ;
} /*
Stop the interface.
The interface is stopped when it is brought.
*/
static int dmfe_stop(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
DMFE_DBUG(, "dmfe_stop", ); /* deleted timer */
del_timer(&db->timer); netif_stop_queue(dev); /* free interrupt */
free_irq(dev->irq, dev); /* RESET devie */
phy_write(db, 0x00, 0x8000); /* PHY RESET */
//iow(db, DM9KS_GPR, 0x01); /* Power-Down PHY */
iow(db, DM9KS_IMR, DM9KS_DISINTR); /* Disable all interrupt */
iow(db, DM9KS_RXCR, 0x00); /* Disable RX */ /* Dump Statistic counter */
#if FALSE
printk("\nRX FIFO OVERFLOW %lx\n", db->stats.rx_fifo_errors);
printk("RX CRC %lx\n", db->stats.rx_crc_errors);
printk("RX LEN Err %lx\n", db->stats.rx_length_errors);
printk("RESET %x\n", db->reset_counter);
printk("RESET: TX Timeout %x\n", db->reset_tx_timeout);
printk("g_TX_nsr %x\n", g_TX_nsr);
#endif return ;
} static void dmfe_tx_done(unsigned long unused)
{
struct net_device *dev = dmfe_dev;
board_info_t *db = (board_info_t *)dev->priv;
int nsr; DMFE_DBUG(, "dmfe_tx_done()", ); nsr = ior(db, DM9KS_NSR);
if (nsr & 0x0c)
{
if(nsr & 0x04) db->tx_pkt_cnt--;
if(nsr & 0x08) db->tx_pkt_cnt--;
if(db->tx_pkt_cnt < )
{
printk(KERN_DEBUG "DM9KS:tx_pkt_cnt ERROR!!\n");
while(ior(db,DM9KS_TCR) & 0x1){}
db->tx_pkt_cnt = ;
} }else{
while(ior(db,DM9KS_TCR) & 0x1){}
db->tx_pkt_cnt = ;
} netif_wake_queue(dev); return;
} /*
DM9000 insterrupt handler
receive the packet to upper layer, free the transmitted packet
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#else
static irqreturn_t dmfe_interrupt(int irq, void *dev_id) /* for kernel 2.6.20*/
#endif
#endif
{
struct net_device *dev = dev_id;
board_info_t *db;
int int_status,i;
u8 reg_save; DMFE_DBUG(, "dmfe_interrupt()", ); /* A real interrupt coming */
db = (board_info_t *)dev->priv;
spin_lock(&db->lock); /* Save previous register address */
reg_save = inb(db->io_addr); /* Disable all interrupt */
iow(db, DM9KS_IMR, DM9KS_DISINTR); /* Got DM9000/DM9010 interrupt status */
int_status = ior(db, DM9KS_ISR); /* Got ISR */
iow(db, DM9KS_ISR, int_status); /* Clear ISR status */ /* Link status change */
if (int_status & DM9KS_LINK_INTR)
{
netif_stop_queue(dev);
for(i=; i<; i++) /*wait link OK, waiting time =0.5s */
{
phy_read(db,0x1);
if(phy_read(db,0x1) & 0x4) /*Link OK*/
{
/* wait for detected Speed */
for(i=; i<;i++)
udelay();
/* set media speed */
if(phy_read(db,)&0x2000) db->Speed =;
else db->Speed =;
break;
}
udelay();
}
netif_wake_queue(dev);
//printk("[INTR]i=%d speed=%d\n",i, (int)(db->Speed));
}
/* Received the coming packet */
if (int_status & DM9KS_RX_INTR)
dmfe_packet_receive(dev); /* Trnasmit Interrupt check */
if (int_status & DM9KS_TX_INTR)
dmfe_tx_done(); if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
{
iow(db, DM9KS_IMR, 0xa2);
}
else
{
/* Re-enable interrupt mask */
iow(db, DM9KS_IMR, DM9KS_REGFF);
} /* Restore previous register address */
outb(reg_save, db->io_addr); spin_unlock(&db->lock);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
return IRQ_HANDLED;
#endif
} /*
Get statistics from driver.
*/
static struct net_device_stats * dmfe_get_stats(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
DMFE_DBUG(, "dmfe_get_stats", );
return &db->stats;
}
/*
* Process the ethtool ioctl command
*/
static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr)
{
//struct dmfe_board_info *db = dev->priv;
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
u32 ethcmd; if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
return -EFAULT; switch (ethcmd)
{
case ETHTOOL_GDRVINFO:
strcpy(info.driver, DRV_NAME);
strcpy(info.version, DRV_VERSION); sprintf(info.bus_info, "ISA 0x%lx %d",dev->base_addr, dev->irq);
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
return ;
} return -EOPNOTSUPP;
}
/*
Process the upper socket ioctl command
*/
static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
board_info_t *db = (board_info_t *)dev->priv;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) /* for kernel 2.6.7 */
struct mii_ioctl_data *data=(struct mii_ioctl_data *)&ifr->ifr_data;
#endif
int rc=; DMFE_DBUG(, "dmfe_do_ioctl()", ); if (!netif_running(dev))
return -EINVAL; if (cmd == SIOCETHTOOL)
rc = dmfe_ethtool_ioctl(dev, (void *) ifr->ifr_data);
else {
spin_lock_irq(&db->lock);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) /* for kernel 2.6.7 */
rc = generic_mii_ioctl(&db->mii, data, cmd, NULL);
#else
rc = generic_mii_ioctl(&db->mii, if_mii(ifr), cmd, NULL);
#endif
spin_unlock_irq(&db->lock);
} return rc;
} /* Our watchdog timed out. Called by the networking layer */
static void dmfe_timeout(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
int i; DMFE_DBUG(, "dmfe_TX_timeout()", );
printk("TX time-out -- dmfe_timeout().\n");
db->reset_tx_timeout++;
db->stats.tx_errors++; #if FALSE
printk("TX packet count = %d\n", db->tx_pkt_cnt);
printk("TX timeout = %d\n", db->reset_tx_timeout);
printk("22H=0x%02x 23H=0x%02x\n",ior(db,0x22),ior(db,0x23));
printk("faH=0x%02x fbH=0x%02x\n",ior(db,0xfa),ior(db,0xfb));
#endif i=; while((i++<)&&(ior(db,DM9KS_TCR) & 0x01))
{
udelay();
} if(i<)
{
db->tx_pkt_cnt = ;
netif_wake_queue(dev);
}
else
{
dmfe_reset(dev);
} } static void dmfe_reset(struct net_device * dev)
{
board_info_t *db = (board_info_t *)dev->priv;
u8 reg_save;
int i;
/* Save previous register address */
reg_save = inb(db->io_addr); netif_stop_queue(dev);
db->reset_counter++;
dmfe_init_dm9000(dev); db->Speed =;
for(i=; i<; i++) /*wait link OK, waiting time=1 second */
{
if(phy_read(db,0x1) & 0x4) /*Link OK*/
{
if(phy_read(db,)&0x2000) db->Speed =;
else db->Speed =;
break;
}
udelay();
} netif_wake_queue(dev); /* Restore previous register address */
outb(reg_save, db->io_addr); }
/*
A periodic timer routine
*/
static void dmfe_timer(unsigned long data)
{
struct net_device * dev = (struct net_device *)data;
board_info_t *db = (board_info_t *)dev->priv;
DMFE_DBUG(, "dmfe_timer()", ); if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
{
db->cont_rx_pkt_cnt=;
iow(db, DM9KS_IMR, DM9KS_REGFF);
}
/* Set timer again */
db->timer.expires = DMFE_TIMER_WUT;
add_timer(&db->timer); return;
} /*
Received a packet and pass to upper layer
*/
static void dmfe_packet_receive(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
struct sk_buff *skb;
u8 rxbyte;
u16 i, GoodPacket, tmplen = , MDRAH, MDRAL;
u32 tmpdata; rx_t rx; u16 * ptr = (u16*)&rx;
u8* rdptr; DMFE_DBUG(, "dmfe_packet_receive()", ); db->cont_rx_pkt_cnt=; do {
/*store the value of Memory Data Read address register*/
MDRAH=ior(db, DM9KS_MDRAH);
MDRAL=ior(db, DM9KS_MDRAL); ior(db, DM9KS_MRCMDX); /* Dummy read */
rxbyte = inb(db->io_data); /* Got most updated data */ #ifdef CHECKSUM
if (rxbyte&0x2) /* check RX byte */
{
printk("dm9ks: abnormal!\n");
dmfe_reset(dev);
break;
}else {
if (!(rxbyte&0x1))
break;
}
#else
if (rxbyte==)
break; if (rxbyte>)
{
printk("dm9ks: Rxbyte error!\n");
dmfe_reset(dev);
break;
}
#endif /* A packet ready now & Get status/length */
GoodPacket = TRUE;
outb(DM9KS_MRCMD, db->io_addr); /* Read packet status & length */
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
*ptr = inb(db->io_data) +
(inb(db->io_data) << );
*(ptr+) = inb(db->io_data) +
(inb(db->io_data) << );
break;
case DM9KS_WORD_MODE:
*ptr = inw(db->io_data);
*(ptr+) = inw(db->io_data);
break;
case DM9KS_DWORD_MODE:
tmpdata = inl(db->io_data);
*ptr = tmpdata;
*(ptr+) = tmpdata >> ;
break;
default:
break;
} /* Packet status check */
if (rx.desc.status & 0xbf)
{
GoodPacket = FALSE;
if (rx.desc.status & 0x01)
{
db->stats.rx_fifo_errors++;
printk(KERN_INFO"<RX FIFO error>\n");
}
if (rx.desc.status & 0x02)
{
db->stats.rx_crc_errors++;
printk(KERN_INFO"<RX CRC error>\n");
}
if (rx.desc.status & 0x80)
{
db->stats.rx_length_errors++;
printk(KERN_INFO"<RX Length error>\n");
}
if (rx.desc.status & 0x08)
printk(KERN_INFO"<Physical Layer error>\n");
} if (!GoodPacket)
{
// drop this packet!!!
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
for (i=; i<rx.desc.length; i++)
inb(db->io_data);
break;
case DM9KS_WORD_MODE:
tmplen = (rx.desc.length + ) / ;
for (i = ; i < tmplen; i++)
inw(db->io_data);
break;
case DM9KS_DWORD_MODE:
tmplen = (rx.desc.length + ) / ;
for (i = ; i < tmplen; i++)
inl(db->io_data);
break;
}
continue;/*next the packet*/
} skb = dev_alloc_skb(rx.desc.length+);
if (skb == NULL )
{
printk(KERN_INFO "%s: Memory squeeze.\n", dev->name);
/*re-load the value into Memory data read address register*/
iow(db,DM9KS_MDRAH,MDRAH);
iow(db,DM9KS_MDRAL,MDRAL);
return;
}
else
{
/* Move data from DM9000 */
skb->dev = dev;
skb_reserve(skb, );
rdptr = (u8*)skb_put(skb, rx.desc.length - ); /* Read received packet from RX SARM */
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
for (i=; i<rx.desc.length; i++)
rdptr[i]=inb(db->io_data);
break;
case DM9KS_WORD_MODE:
tmplen = (rx.desc.length + ) / ;
for (i = ; i < tmplen; i++)
((u16 *)rdptr)[i] = inw(db->io_data);
break;
case DM9KS_DWORD_MODE:
tmplen = (rx.desc.length + ) / ;
for (i = ; i < tmplen; i++)
((u32 *)rdptr)[i] = inl(db->io_data);
break;
} /* Pass to upper layer */
skb->protocol = eth_type_trans(skb,dev); #ifdef CHECKSUM
if((rxbyte&0xe0)==) /* receive packet no checksum fail */
skb->ip_summed = CHECKSUM_UNNECESSARY;
#endif netif_rx(skb);
dev->last_rx=jiffies;
db->stats.rx_packets++;
db->stats.rx_bytes += rx.desc.length;
db->cont_rx_pkt_cnt++;
#ifdef RDBG /* check RX FIFO pointer */
u16 MDRAH1, MDRAL1;
u16 tmp_ptr;
MDRAH1 = ior(db,DM9KS_MDRAH);
MDRAL1 = ior(db,DM9KS_MDRAL);
tmp_ptr = (MDRAH<<)|MDRAL;
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
tmp_ptr += rx.desc.length+;
break;
case DM9KS_WORD_MODE:
tmp_ptr += ((rx.desc.length+)/)*+;
break;
case DM9KS_DWORD_MODE:
tmp_ptr += ((rx.desc.length+)/)*+;
break;
}
if (tmp_ptr >=0x4000)
tmp_ptr = (tmp_ptr - 0x4000) + 0xc00;
if (tmp_ptr != ((MDRAH1<<)|MDRAL1))
printk("[dm9ks:RX FIFO ERROR\n");
#endif if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
{
dmfe_tx_done();
break;
}
} }while((rxbyte & 0x01) == DM9KS_PKT_RDY);
DMFE_DBUG(, "[END]dmfe_packet_receive()", ); } /*
Read a word data from SROM
*/
static u16 read_srom_word(board_info_t *db, int offset)
{
iow(db, DM9KS_EPAR, offset);
iow(db, DM9KS_EPCR, 0x4);
while(ior(db, DM9KS_EPCR)&0x1); /* Wait read complete */
iow(db, DM9KS_EPCR, 0x0);
return (ior(db, DM9KS_EPDRL) + (ior(db, DM9KS_EPDRH) << ) );
} /*
Set DM9000/DM9010 multicast address
*/
static void dm9000_hash_table(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
struct dev_mc_list *mcptr = dev->mc_list;
int mc_cnt = dev->mc_count;
u32 hash_val;
u16 i, oft, hash_table[]; DMFE_DBUG(, "dm9000_hash_table()", ); /* enable promiscuous mode */
if (dev->flags & IFF_PROMISC){
//printk(KERN_INFO "DM9KS:enable promiscuous mode\n");
iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)|(<<));
return;
}else{
//printk(KERN_INFO "DM9KS:disable promiscuous mode\n");
iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)&(~(<<)));
} /* Receive all multicast packets */
if (dev->flags & IFF_ALLMULTI){
//printk(KERN_INFO "DM9KS:Pass all multicast\n");
iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)|(<<));
}else{
//printk(KERN_INFO "DM9KS:Disable pass all multicast\n");
iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)&(~(<<)));
} /* Set Node address */
for (i = , oft = 0x10; i < ; i++, oft++)
iow(db, oft, dev->dev_addr[i]); /* Clear Hash Table */
for (i = ; i < ; i++)
hash_table[i] = 0x0; /* broadcast address */
hash_table[] = 0x8000; /* the multicast address in Hash Table : 64 bits */
for (i = ; i < mc_cnt; i++, mcptr = mcptr->next) {
hash_val = cal_CRC((char *)mcptr->dmi_addr, , ) & 0x3f;
hash_table[hash_val / ] |= (u16) << (hash_val % );
} /* Write the hash table to MAC MD table */
for (i = , oft = 0x16; i < ; i++) {
iow(db, oft++, hash_table[i] & 0xff);
iow(db, oft++, (hash_table[i] >> ) & 0xff);
}
} /*
Calculate the CRC valude of the Rx packet
flag = 1 : return the reverse CRC (for the received packet CRC)
0 : return the normal CRC (for Hash Table index)
*/
static unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
{
u32 crc = ether_crc_le(Len, Data); if (flag)
return ~crc; return crc;
} static int mdio_read(struct net_device *dev, int phy_id, int location)
{
board_info_t *db = (board_info_t *)dev->priv;
return phy_read(db, location);
} static void mdio_write(struct net_device *dev, int phy_id, int location, int val)
{
board_info_t *db = (board_info_t *)dev->priv;
phy_write(db, location, val);
} /*
Read a byte from I/O port
*/
u8 ior(board_info_t *db, int reg)
{
outb(reg, db->io_addr);
return inb(db->io_data);
} /*
Write a byte to I/O port
*/
void iow(board_info_t *db, int reg, u8 value)
{
outb(reg, db->io_addr);
outb(value, db->io_data);
} /*
Read a word from phyxcer
*/
static u16 phy_read(board_info_t *db, int reg)
{
/* Fill the phyxcer register into REG_0C */
iow(db, DM9KS_EPAR, DM9KS_PHY | reg); iow(db, DM9KS_EPCR, 0xc); /* Issue phyxcer read command */
while(ior(db, DM9KS_EPCR)&0x1); /* Wait read complete */
iow(db, DM9KS_EPCR, 0x0); /* Clear phyxcer read command */ /* The read data keeps on REG_0D & REG_0E */
return ( ior(db, DM9KS_EPDRH) << ) | ior(db, DM9KS_EPDRL); } /*
Write a word to phyxcer
*/
static void phy_write(board_info_t *db, int reg, u16 value)
{
/* Fill the phyxcer register into REG_0C */
iow(db, DM9KS_EPAR, DM9KS_PHY | reg); /* Fill the written data into REG_0D & REG_0E */
iow(db, DM9KS_EPDRL, (value & 0xff));
iow(db, DM9KS_EPDRH, ( (value >> ) & 0xff)); iow(db, DM9KS_EPCR, 0xa); /* Issue phyxcer write command */
while(ior(db, DM9KS_EPCR)&0x1); /* Wait read complete */
iow(db, DM9KS_EPCR, 0x0); /* Clear phyxcer write command */
}
//====dmfe_ethtool_ops member functions====
static void dmfe_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
//board_info_t *db = (board_info_t *)dev->priv;
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
sprintf(info->bus_info, "ISA 0x%lx irq=%d",dev->base_addr, dev->irq);
}
static int dmfe_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
board_info_t *db = (board_info_t *)dev->priv;
spin_lock_irq(&db->lock);
mii_ethtool_gset(&db->mii, cmd);
spin_unlock_irq(&db->lock);
return ;
}
static int dmfe_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
board_info_t *db = (board_info_t *)dev->priv;
int rc; spin_lock_irq(&db->lock);
rc = mii_ethtool_sset(&db->mii, cmd);
spin_unlock_irq(&db->lock);
return rc;
}
/*
* Check the link state
*/
static u32 dmfe_get_link(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
return mii_link_ok(&db->mii);
} /*
* Reset Auto-negitiation
*/
static int dmfe_nway_reset(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
return mii_nway_restart(&db->mii);
}
/*
* Get RX checksum offload state
*/
static uint32_t dmfe_get_rx_csum(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
return db->rx_csum;
}
/*
* Get TX checksum offload state
*/
static uint32_t dmfe_get_tx_csum(struct net_device *dev)
{
return (dev->features & NETIF_F_HW_CSUM) != ;
}
/*
* Enable/Disable RX checksum offload
*/
static int dmfe_set_rx_csum(struct net_device *dev, uint32_t data)
{
#ifdef CHECKSUM
board_info_t *db = (board_info_t *)dev->priv;
db->rx_csum = data; if(netif_running(dev)) {
dmfe_stop(dev);
dmfe_open(dev);
} else
dmfe_init_dm9000(dev);
#else
printk(KERN_ERR "DM9:Don't support checksum\n");
#endif
return ;
}
/*
* Enable/Disable TX checksum offload
*/
static int dmfe_set_tx_csum(struct net_device *dev, uint32_t data)
{
#ifdef CHECKSUM
if (data)
dev->features |= NETIF_F_HW_CSUM;
else
dev->features &= ~NETIF_F_HW_CSUM;
#else
printk(KERN_ERR "DM9:Don't support checksum\n");
#endif return ;
}
//=========================================
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,28) /* for kernel 2.4.28 */
static struct ethtool_ops dmfe_ethtool_ops = {
.get_drvinfo = dmfe_get_drvinfo,
.get_settings = dmfe_get_settings,
.set_settings = dmfe_set_settings,
.get_link = dmfe_get_link,
.nway_reset = dmfe_nway_reset,
.get_rx_csum = dmfe_get_rx_csum,
.set_rx_csum = dmfe_set_rx_csum,
.get_tx_csum = dmfe_get_tx_csum,
.set_tx_csum = dmfe_set_tx_csum,
};
#endif //#ifdef MODULE MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Davicom DM9000/DM9010 ISA/uP Fast Ethernet Driver");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
MODULE_PARM(mode, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(iobase, "i");
#else
module_param(mode, int, );
module_param(irq, int, );
module_param(iobase, int, );
#endif
MODULE_PARM_DESC(mode,"Media Speed, 0:10MHD, 1:10MFD, 4:100MHD, 5:100MFD");
MODULE_PARM_DESC(irq,"EtherLink IRQ number");
MODULE_PARM_DESC(iobase, "EtherLink I/O base address"); /* Description:
when user used insmod to add module, system invoked init_module()
to initilize and register.
*/
int __init dm9000c_init(void)
{
volatile unsigned long *bwscon; //0x48000000
volatile unsigned long *bankcon4; //0x48000014
iobase = (int)ioremap(0x20000000,);
irq = IRQ_EINT7; /* 设置内存控制器 */
bwscon = ioremap(0x48000000,);
bankcon4 = ioremap(0x48000014,);
*bwscon &= ~((0xf<<));
*bwscon |= (<<); *bankcon4 = (<<) | (<<) | (<<); iounmap(bwscon);
iounmap(bankcon4); switch(mode) {
case DM9KS_10MHD:
case DM9KS_100MHD:
case DM9KS_10MFD:
case DM9KS_100MFD:
media_mode = mode;
break;
default:
media_mode = DM9KS_AUTO;
}
dmfe_dev = dmfe_probe();
if(IS_ERR(dmfe_dev))
return PTR_ERR(dmfe_dev);
return ;
}
/* Description:
when user used rmmod to delete module, system invoked clean_module()
to un-register DEVICE.
*/
void __exit dm9000c_exit(void)
{
struct net_device *dev = dmfe_dev;
DMFE_DBUG(, "clean_module()", );
iounmap((void *)iobase);
unregister_netdev(dmfe_dev);
release_region(dev->base_addr, );
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
kfree(dev);
#else
free_netdev(dev);
#endif DMFE_DBUG(, "clean_module() exit", );
} module_init(dm9000c_init);
module_exit(dm9000c_exit);
//#endif

sd

嵌入式Linux驱动学习之路(二十六)DM9000C网卡驱动程序的更多相关文章

  1. 嵌入式Linux驱动学习之路(二十五)虚拟网卡驱动程序

    一.协议栈层次对比 设备无关层到驱动层的体系结构 1).网络协议接口层向网络层协议提供提供统一的数据包收发接口,不论上层协议为ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过 ...

  2. 嵌入式Linux驱动学习之路(二十四)Nor Flash驱动程序

    Nor Flash和Nand Flash的不同: 类型 NOR Flash  Nand Flash  接口 RAM-like,引脚多 引脚少 容量 小(1M.2M...) 大(512M.1G) 读 简 ...

  3. 嵌入式Linux驱动学习之路(二十二)用内存模拟磁盘

    安装驱动后,可在/dev/目录下发现已经生成了相应的设备文件. 格式化设备:mkdosfs /dev/ramblock. 挂载设备. 读写设备 . 驱动程序代码: /***************** ...

  4. 嵌入式Linux驱动学习之路(二十)USB设备驱动

    USB在接入系统的时候,以0的设备ID和主机通信,然后由主机为其分配新的ID. 在主机端,D+和D-都是下拉接地的.而设备端的D-接上拉时,表明此设备为高速设备:12M/s. D+接上拉时则是全速设备 ...

  5. 嵌入式Linux驱动学习之路(二十三)NAND FLASH驱动程序

    NAND FLASH是一个存储芯片. 在芯片上的DATA0-DATA7上既能传输数据也能传输地址. 当ALE为高电平时传输的是地址. 当CLE为高电平时传输的是命令. 当ALE和CLE都为低电平时传输 ...

  6. 嵌入式Linux驱动学习之路(二十七)字符设备驱动的另一种写法

    之前讲的字符设备驱动程序,只要有一个主设备号,那么次设备号无论是什么都会和同一个 struct file_operations 结构体对应. 而本节课讲的是如何在设备号相同的情况下,让不同的次设备号对 ...

  7. 嵌入式Linux驱动学习之路(二十一)字符设备驱动程序总结和块设备驱动程序的引入

    字符设备驱动程序 应用程序是调用C库中的open read write等函数.而为了操作硬件,所以引入了驱动模块. 构建一个简单的驱动,有一下步骤. 1. 创建file_operations 2. 申 ...

  8. 嵌入式Linux驱动学习之路(二)u-boot体验

    u-boot工程简介 现在的u-boot支持PowerPC.ARM.X86.MIPS体系结构的上百种开发板,已经称为功能最多.灵活性最强,并且开发最积极的开源Bootloader.目前由DENX的Wo ...

  9. 嵌入式Linux驱动学习之路(十二)按键驱动-poll机制

    实现的功能是在读取按键信息的时候,如果没有产生按键,则程序休眠在read函数中,利用poll机制,可以在没有退出的情况下让程序自动退出. 下面的程序就是在读取按键信息的时候,如果5000ms内没有按键 ...

随机推荐

  1. Hawk 4.3 转换器

    转换器是最为常用的一种类型,当然它的使用也是最复杂的. 转换器有三种子类型: A:单文档->单文档:例如仅将某一列的字符提取出来 B:单文档->多文档:典型的如从爬虫转换,每一行url都可 ...

  2. php-resque的设计和使用

    php-resque-1.2-annotated 一个 php-resque 源码阅读的项目,欢迎大家star php-resque的设计 在Resque中,一个后台任务被抽象为由三种角色共同完成: ...

  3. 由objC运行时所想到的。。。

    objC语言不仅仅有着面向对象的特点(封装,继承和多态),也拥有类似脚本语言的灵活(运行时),这让objC有着很多奇特的功能-可在运行时添加给类或对象添加方法,甚至可以添加类方法,甚至可以动态创建类. ...

  4. SQL Tuning 基础概述03 - 使用sql_trace和10046事件跟踪执行计划

    1.使用sql_trace跟踪执行计划 1.1 当前session跟踪: alter session set sql_trace = true; //开始sql_trace alter session ...

  5. ASP.NET Core 中文文档 第四章 MVC(2.1)模型绑定

    原文:Model Binding 作者:Rachel Appel 翻译:娄宇(Lyrics) 校对:许登洋(Seay).何镇汐 模型绑定介绍 ASP.NET Core MVC 中的模型绑定从 HTTP ...

  6. 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)

    今天没有延续上一篇讲的内容,穿插一段小插曲,WebSocket 实时数据通讯同步的问题,今天我们并不是很纯粹地讲 WebSocket 相关知识,我们通过 WebGL 3D 拓扑图来呈现一个有趣的 De ...

  7. ASP.NET Core官方计划路线及需要废除的一些Framework技术

    概述 下面是 ASP.NET Core的时间表和路线图. 注意日期和特性都可能更改. 作为.NET Core这么大的一个项目,很难准确预测每一个计划的是否有变动. 即便如此,我们还是计划公开和透明的实 ...

  8. 从零自学Hadoop(20):HBase数据模型相关操作上

    阅读目录 序 介绍 命名空间 表 系列索引 本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 文章是哥(mephisto)写的,SourceLink 序 ...

  9. C#WebBrowrse拦截下载对话框

    为了实现这个功能,可算是折腾不少时间,网上搜素出来的结果基本都是如何屏蔽警告对话框.后来请教一个技术大牛(程序员之窗的主要作者Starts_2000),他用C++实现了,他尝试了下C#也没有解决,就忙 ...

  10. asp.net记录错误日志的方法

    1.说明 在调试发布后的asp.net项目时有可能会遇到意想不到的错误,而未能及时的显示.这就需要记录日志来跟踪错误信息,所以写了个简单的记录信息的方法,记录简单的文本信息也可以使用.此方法是以生成文 ...