?? dm9ks.c
字號:
/*
dm9ks.c: Version 2.06 2007/01/03
A Davicom DM9000A/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()
*/
#if defined(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>
#ifdef CONFIG_ARCH_MAINSTONE
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#endif
//#define DM8606
/* 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_EPCR 0x0b
#define DM9KS_EPAR 0x0c
#define DM9KS_EPDRL 0x0d
#define DM9KS_EPDRH 0x0e
#define DM9KS_GPR 0x1f /* General purpose register */
#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_MRCMDX 0xf0
#define DM9KS_MRCMD 0xf2
#define DM9KS_MDRAL 0xf4
#define DM9KS_MDRAH 0xf5
#define DM9KS_MWCMD 0xf8
#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 */
#if defined(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[4];
RX_DESC desc;
} rx_t;
#ifndef CONFIG_ARCH_MAINSTONE
#pragma pack(pop)
#endif
enum DM9KS_PHY_mode {
DM9KS_10MHD = 0,
DM9KS_100MHD = 1,
DM9KS_10MFD = 4,
DM9KS_100MFD = 5,
DM9KS_AUTO = 8,
};
/* Structure/enum declaration ------------------------------- */
typedef struct board_info {
u32 reset_counter; /* counter: RESET */
u32 reset_tx_timeout; /* RESET caused by TX Timeout */
u32 io_addr; /* Register I/O base address */
u32 io_data; /* Data I/O address */
int tx_pkt_cnt;
u8 op_mode; /* PHY operation mode */
u8 io_mode; /* 0:word, 2:byte */
u8 device_wait_reset; /* device state */
u8 Speed; /* current speed */
int cont_rx_pkt_cnt;/* current number of continuos rx packets */
struct timer_list timer;
struct net_device_stats stats;
unsigned char srom[128];
spinlock_t lock;
} board_info_t;
/* Global variable declaration ----------------------------- */
/*static int dmfe_debug = 0;*/
static struct net_device * dmfe_dev = NULL;
/* For module input parameter */
static int mode = DM9KS_AUTO;
static int media_mode = DM9KS_AUTO;
static u8 irq = DM9KS_IRQ;
static u32 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
static irqreturn_t dmfe_interrupt(int , void *, struct pt_regs *);
#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 *);
#if defined(CHECKSUM)
static u8 check_rx_ready(u8);
#endif
#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(0, "dmfe_probe()",0);
#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,2);
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[6]={0x00,0x60,0x6E,0x33,0x44,0x55};
u8 HasEEPROM=0;
DMFE_DBUG(0, "dmfe_probe1()",0);
/* Search All DM9000 serial NIC */
do {
outb(DM9KS_VID_L, iobase);
id_val = inb(iobase + 4);
outb(DM9KS_VID_H, iobase);
id_val |= inb(iobase + 4) << 8;
outb(DM9KS_PID_L, iobase);
id_val |= inb(iobase + 4) << 16;
outb(DM9KS_PID_H, iobase);
id_val |= inb(iobase + 4) << 24;
if (id_val == DM9KS_ID || id_val == DM9010_ID) {
/* Request IO from system */
if(!request_region(iobase, 2, dev->name))
return -ENODEV;
printk("<DM9KS> I/O: %x, VID: %x \n",iobase, id_val);
dm9000_found = TRUE;
/* Allocated board information structure */
memset(dev->priv, 0, sizeof(struct board_info));
db = (board_info_t *)dev->priv;
dmfe_dev = dev;
db->io_addr = iobase;
db->io_data = iobase + 4;
/* driver system function */
dev->base_addr = iobase;
dev->irq = irq;
dev->open = &dmfe_open;
dev->hard_start_xmit = &dmfe_start_xmit;
dev->watchdog_timeo = 5*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 defined(CHECKSUM)
dev->features |= NETIF_F_IP_CSUM;
#endif
/* Read SROM content */
for (i=0; i<64; i++)
((u16 *)db->srom)[i] = read_srom_word(db, i);
/* Detect EEPROM */
for (i=0; i<6; i++)
if(db->srom[i]) HasEEPROM=1;
/* Set Node Address */
for (i=0; i<6; 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 ? 0:-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(0, "dmfe_open", 0);
if (request_irq(dev->irq,&dmfe_interrupt,SA_SHIRQ,dev->name,dev))
return -EAGAIN;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -