⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtl8019.c.old

📁 Fixed Rtl8019as driver for uclinux on the s3c44b0 soc
💻 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 + -