📄 rtl8019.c.old
字号:
/* * linux/deriver/net/Rtl8019as.c * Ethernet driver for Samsung 44B0 * Copyright (C) 2003 antiscle <hzh12@163.net> */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/kernel.h> // printk()#include <linux/slab.h> // kmalloc()#include <linux/errno.h> // error codes#include <linux/types.h> // size_t#include <linux/interrupt.h> // mark_bh#include <linux/in.h>#include <linux/netdevice.h> // net_device#include <linux/etherdevice.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/skbuff.h>#include <asm/irq.h>#include "Rtl8019.h"#undef DEBUG#define DEBUG 1#ifdef DEBUG#define TRACE(str, args...) printk("Rtl8019as eth: " str, ## args)#else#define TRACE(str, args...)#endiftypedef unsigned char U8;
#define outportb(port, data) *((volatile U8 *)(port)) = (U8)(data)#define inportb(port) *((volatile U8 *)(port))#define ETH_FRAME_LEN 1514#define RPSTART 0x4c#define RPSTOP 0x80#define SPSTART 0x40static int timeout = 100; // tx watchdog ticks 100 = 1sstatic char *version = "Samsung S3C44B0 Rtl8019as driver version 0.1 (2002-02-20) <hzh12@163.net>\n";/* * This structure is private to each device. It is used to pass * packets in and out, so there is place for a packet */struct nic_8019_priv { struct net_device_stats stats; spinlock_t lock; struct sk_buff *skb;};/******************************************************************************/
static U8 rBNRY;
static U8 SrcMacID[ETH_ALEN] = {0x00,0x80,0x48,0x12,0x34,0x56};
static void SetRegPage(U8 PageIdx)
{
U8 temp;
temp = inportb(BaseAddr);
temp = (temp&0x3b)|(PageIdx<<6);
outportb(BaseAddr, temp);
}
/*static void SetMacID()
{
int i;
SetRegPage(1);
for(i=0; i<6; i++)
outportb(PAR0+i, SrcMacID[i]);
}*/
/*
* rx
*/
static void nic_8019_rx(int irq, void *dev_id, struct pt_regs *regs)
{
U8 RxPageBeg, RxPageEnd;
U8 RxNextPage;
U8 RxStatus;
U8 *data; int i, RxLength; struct sk_buff *skb;
struct net_device *dev = (struct net_device *) dev_id;
struct nic_8019_priv *priv = (struct nic_8019_priv *) dev->priv;
TRACE("Interrupt!\n");
spin_lock(&priv->lock);
SetRegPage(0);
outportb(BNRY, rBNRY); //???
RxStatus = inportb(ISR);
if(RxStatus&2)
{
outportb(ISR, 0x2); //发送成功
priv->stats.tx_packets++; TRACE("Transmit one packet complete\n");
}
if(RxStatus&1)
{
TRACE("Received Packet\n") outportb(ISR, 0x1); //接收成功, 清除中断标志
SetRegPage(1);
RxPageEnd = inportb(CURR);
SetRegPage(0);
RxPageBeg = rBNRY+1;
if(RxPageBeg>=RPSTOP)
RxPageBeg = RPSTART;
outportb(BaseAddr, 0x22); // stop remote dma
//outport(RSAR0, RxPageBeg<<8);
//outport(RBCR0, 256);
outportb(RSAR0, 0);
outportb(RSAR1, RxPageBeg);
outportb(RBCR0, 4);
outportb(RBCR1, 0);
outportb(BaseAddr, 0xa);
RxStatus = inportb(RWPORT);
RxNextPage = inportb(RWPORT);
RxLength = inportb(RWPORT);
RxLength |= inportb(RWPORT)<<8;
trace("\nRxBeg = %x, RxEnd = %x, staus = %x, nextpage = %x, size = %x", RxPageBeg, RxPageEnd, RxStatus, RxNextPage, RxLength);
trace("\n%x, %x, %x", RxPageBeg, RxPageEnd, RxLength); RxLength -= 4; if(RxLength>ETH_FRAME_LEN)
{
if(RxPageEnd==RPSTART)
rBNRY = RPSTOP-1;
else
rBNRY = RxPageEnd-1;
outportb(BNRY, rBNRY); trace("RxLength more long than %x\n", ETH_FRAME_LEN);
return;
}
skb = dev_alloc_skb(RxLength);
if(!skb)
{
trace("Rtl8019as eth: low on mem - packet dropped\n");
priv->stats.rx_dropped++;
return;
}
skb->dev = dev;
skb_reserve(skb, 2); skb_put(skb, RxLength);
data = (U8 *)skb->data;// eth_copy_and_sum(skb, data, len, 0);
outportb(RSAR0, 4);
outportb(RSAR1, RxPageBeg);
outportb(RBCR0, RxLength);
outportb(RBCR1, RxLength>>8);
outportb(BaseAddr, 0xa);
i = 4;
data -= 4;
for(; RxLength--;)
{
if(!(i&0xff))
{
outportb(BNRY, RxPageBeg);
RxPageBeg++;
if(RxPageBeg>=RPSTOP)
RxPageBeg = RPSTART;
}
data[i++] = inportb(RWPORT);
trace("%x,", skb->data[i-1]); }
trace("\n"); outportb(BNRY, RxPageBeg);
rBNRY = RxPageBeg;
skb->protocol = eth_type_trans(skb, dev);
trace("\n protocol=%x\n", skb->protocol); priv->stats.rx_packets++;
priv->stats.rx_bytes += RxLength;
netif_rx(skb);
}
else
{
outportb(ISR, 0xfe);
}
spin_unlock(&priv->lock);
return IRQ_HANDLED;}
/*
* Open and Close
*/
static int nic_8019_open(struct net_device *dev)
{ int i;
// unsigned long status;
MOD_INC_USE_COUNT;
TRACE("open\n");
// wake up Rtl8019as
SetRegPage(3);
outportb(CR9346, 0xcf); //set eem1-0, 11 ,enable write config register
outportb(CONFIG3, 0x50); //clear pwrdn, sleep mode, set led0 as led_col, led1 as led_crs
outportb(CR9346, 0x3f); //disable write config register
// initialize
outportb(RstAddr, 0x5a);
i = 20000;
while(i--);
SetRegPage(0);
inportb(ISR);
outportb(BaseAddr, 0x21); /* set page 0 and stop */
outportb(Pstart, RPSTART); /* set Pstart 0x4c */
outportb(Pstop, RPSTOP); /* set Pstop 0x80 */
outportb(BNRY, RPSTART); /* BNRY-> the last page has been read */
outportb(TPSR, SPSTART); /* transmit page start register, 0x40 */
outportb(RCR, 0xcc); /* set RCR 0xcc */
outportb(TCR, 0xe0); /* set TCR 0xe0 */
#ifdef RTL8019_OP_16
outportb(DCR, 0xc9); /* set DCR 0xc9, 16bit DMA */
#else
outportb(DCR, 0xc8); /* 8bit DMA */
#endif
outportb(IMR, 0x03); /* set IMR 0x01, enable rx int */
outportb(ISR, 0xff); /* clear ISR */
SetRegPage(1);
for(i=0; i<6; i++)
outportb(BaseAddr+1+i, dev->dev_addr[i]); // set mac id
outportb(CURR, RPSTART+1);
outportb(MAR0, 0x00);
outportb(MAR1, 0x41);
outportb(MAR2, 0x00);
outportb(MAR3, 0x80);
outportb(MAR4, 0x00);
outportb(MAR5, 0x00);
outportb(MAR6, 0x00);
outportb(MAR7, 0x00);
outportb(BaseAddr, 0x22); /* set page 0 and start */
rBNRY = RPSTART;
// i = inportb(ID8019L);
// i |= inportb(ID8019H)<<8; // read rtl8019as ID
// Disable irqs disable_irq(dev->irq); // register rx isr if(request_irq(dev->irq, &nic_8019_rx, SA_INTERRUPT, "eth rx isr", dev)) { printk(KERN_ERR "Rtl8019: Can't get irq %d\n", dev->irq); return -EAGAIN; } enable_irq(dev->irq);
// Start the transmit queue
netif_start_queue(dev);
return 0;
}
static int nic_8019_stop(struct net_device *dev)
{
TRACE("stop\n");
SetRegPage(3);
outportb(CR9346, 0xcf); // set eem1-0, 11 ,enable write config register
outportb(CONFIG3, 0x66); // enter pwrdn, sleep mode, set led0 as led_col, led1 as led_crs
outportb(CR9346, 0x3f); // disable write config register
free_irq(dev->irq, dev);
netif_stop_queue(dev);
MOD_DEC_USE_COUNT;
return 0;
}
static int nic_8019_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int i;
int len;
char *data;
struct nic_8019_priv *priv = (struct nic_8019_priv *) dev->priv;
TRACE("start_xmit\n");
len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
// printk("\nTx Length = %d,%x,%x", len, skb->data[12], skb->data[13]); data = skb->data;
dev->trans_start = jiffies;
outportb(BaseAddr, 0x22); //switch to page 0 and stop remote dma
outportb(RSAR0, 0);
outportb(RSAR1, SPSTART);
outportb(RBCR0, len&0xff);
outportb(RBCR1, len>>8);
outportb(BaseAddr, 0x12);
for(i=0; i<len; i++)
{
outportb(RWPORT, data[i]); // copy data to nic ram
}
while(inportb(BaseAddr)&4); // wait for last tx operation end
outportb(TPSR, SPSTART);
outportb(TBCR0, len&0xff);
outportb(TBCR1, len>>8);
outportb(BaseAddr, 0x1e); // begin to send
dev_kfree_skb(skb);
return 0;
}
static struct net_device_stats *nic_8019_get_stats(struct net_device *dev)
{
struct nic_8019_priv *priv = (struct nic_8019_priv *) dev->priv;
TRACE("get_stats\n");
return &priv->stats;
}
/******************************************************************************/
static int nic_8019_init(struct net_device *dev)
{
int i;
TRACE("init\n");
ether_setup(dev); // Assign some of the fields
// set net_device methods
dev->open = nic_8019_open;
dev->stop = nic_8019_stop;
dev->get_stats = nic_8019_get_stats;
dev->hard_start_xmit = nic_8019_start_xmit;
// set net_device data members
dev->watchdog_timeo = timeout;
dev->irq = INT_EXTINT1;
dev->dma = 0;
// set MAC address manually
printk(KERN_INFO "%s: ", dev->name);
for(i=0; i<6; i++)
{
dev->dev_addr[i] = SrcMacID[i];
printk("%2.2x%c", dev->dev_addr[i], (i==5) ? ' ' : ':');
}
printk("\n");
SET_MODULE_OWNER(dev);
dev->priv = kmalloc(sizeof(struct nic_8019_priv), GFP_KERNEL);
if(dev->priv == NULL)
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct nic_8019_priv));
spin_lock_init(&((struct nic_8019_priv *) dev->priv)->lock);
return 0;
}
static struct net_device nic_8019_netdevs = {
init: nic_8019_init,
};
/*
* Finally, the module stuff
*/
int __init nic_8019_init_module(void)
{
int result;
TRACE("init_module\n");
//Print version information
printk(KERN_INFO "%s", version);
//register_netdev will call nic_8019_init()
if((result = register_netdev(&nic_8019_netdevs)))
printk("Rtl8019as eth: Error %i registering device \"%s\"\n", result, nic_8019_netdevs.name);
return result ? 0 : -ENODEV;
}
void __exit nic_8019_cleanup(void)
{
TRACE("cleanup\n");
kfree(nic_8019_netdevs.priv);
unregister_netdev(&nic_8019_netdevs);
return;
}
module_init(nic_8019_init_module);
module_exit(nic_8019_cleanup);
MODULE_DESCRIPTION("Rtl8019as ethernet driver");
MODULE_AUTHOR("antiscle <hzh12@163.net>");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -