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

📄 cs8900-2624.c

📁 cs8900网卡驱动。运行环境为ARM9+LINUX
💻 C
📖 第 1 页 / 共 2 页
字号:
/*********************************** * Author: Nolan * Date:   2008-08-19 * Description: Driver for cs8900 ethernet chip,  * support linux kernel 2.6.24 * Version: 0.2 ***********************************/	#include <linux/module.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/irq.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/platform_device.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/hardware.h>#include <asm/arch/regs-mem.h>#include "cs8900-2624.h"#define DRV_NAME "CS8900-2624"#define VER_STR	"Crystal Semiconductor ethernet chip CS8900A driver, for linux-2.6.24, adapted for s3c2410"struct cs8900_dev {	unsigned long phy_addr; /* 8900 I/O space address */	unsigned long addr_len; /* 8900 I/O space length */	void __iomem *ioaddr;	/* 8900 virtual address */	struct net_device *netdev;	struct net_device_stats cs8900_stats;	u16 txlen;		/* length of last tx frame */	spinlock_t lock;	/* lock */};/* function prototype */static void cs8900_reset(struct net_device *);static void cs8900_cleanup(struct net_device *);static void cs8900_hardware_init(struct net_device *);static irqreturn_t cs8900_interrupt(int, void *);static void cs8900_irq_receive(struct net_device *, u16);static void cs8900_irq_transmit(struct net_device *, u16);static void cs8900_irq_buffer(struct net_device *, u16);/********************************* * read data from cs8900 PacketPage register * reg: offset of register  * return value: content of register  ********************************/static inline u16 cs8900_read(struct net_device *dev, u16 reg){	u16 ret;	iowrite16(reg, (void __iomem *)(dev->base_addr + CS8900_PPtr));	ret = ioread16((void __iomem *)(dev->base_addr + CS8900_PData));	return ret;}/********************************* * write data from cs8900 PacketPage register * reg: offset of register * value: content of register  ********************************/static inline voidcs8900_write(struct net_device *dev, u16 reg, u16 value){	iowrite16(reg, (void __iomem *)(dev->base_addr + CS8900_PPtr));	iowrite16(value, (void __iomem *)(dev->base_addr + CS8900_PData));}/********************************** * set cs8900 register  * reg: offset * value: bits to set  *********************************/static inline void cs8900_set(struct net_device *dev, u16 reg, u16 value){	u16 ret;	ret = cs8900_read(dev, reg);	cs8900_write(dev, reg, (ret|value));}/********************************* * clear cs8900 register * reg: offset * value: bits to clear ********************************/static inline voidcs8900_clear(struct net_device *dev, u16 reg, u16 value){	u16 ret;	ret = cs8900_read(dev, reg);	cs8900_write(dev, reg, (ret&~value));}/******************************** * read one frame from cs8900 Receive buffer * length: frame length in bytes *******************************/static inline voidcs8900_frame_read(struct net_device *dev, struct sk_buff *skb, u16 length){	unsigned long count = (length + 1)/2;	void __iomem *ptr = (void *)(dev->base_addr + CS8900_Data);	/* read data from cs8900 Receive buffer */	ioread16_rep(ptr, skb_put(skb, length), count);}/******************************** * write one frame to cs8900 Transmit buffer *******************************/static inline void cs8900_frame_write(struct net_device *dev, struct sk_buff *skb){	unsigned long count = (skb->len + 1)/2;	void __iomem *ptr = (void *)(dev->base_addr + CS8900_Data);	/* Write frame to cs8900 transmit buffer */	iowrite16_rep(ptr, skb->data, count);}/*************************** * cs8900_reset: reset chip **************************/static void cs8900_reset(struct net_device *ndev){	int i;	/* Ascertained that cs8900 chip has finished reset. */	cs8900_set(ndev, PP_SelfCTL, RESET);	for (i=1000; i>0; i--) {		barrier();		if ((cs8900_read(ndev, PP_SelfCTL) & RESET) == 0) {			printk("Cs8900 has finished reset.\n");			break;		}		udelay(10);	}}/******************************* * cs8900_cleanup: release any mapped resources ******************************/static void cs8900_cleanup(struct net_device *ndev){	struct cs8900_dev *priv = netdev_priv(ndev);	if (NULL == ndev)		return;	if (NULL != priv->ioaddr)		iounmap(priv->ioaddr);		if (0 != priv->phy_addr)		release_mem_region(priv->phy_addr, priv->addr_len);}/*********************************** * cs8900_hardware_init * Initialize cs8900 register **********************************/static void cs8900_hardware_init(struct net_device *ndev){	u16 value;	/* RxCFG */	value = RxOKiE | 	/* Enable RxOK int */		BufferCRC | 	/* Received frame include CRC */		CRCerroriE | 	/* Enable CRC error int */		RuntiE |   /* Enable int when receive <64bytes frame */		ExtradataiE;	/* Enable int when receive >1518bytes frame */	cs8900_set(ndev, PP_RxCFG, value);	/* RxCTL */	value = RxOKA | 	/* Receive normal frame */		IndividualA |	/* Receive individual frame */		BroadcastA;	/* Receive broadcast frame */	cs8900_set(ndev, PP_RxCTL, value);	/* TxCFG */	value = TxOKiE |	/* Enable TxOK int */		Out_of_windowiE | /* Enable out-of-window int */		JabberiE | 	/* Enable Jabber int */		T16colliE;	/* Enable 16 collisions int */	cs8900_set(ndev, PP_TxCFG, value);	/* BufCFG */	value = Rdy4TxiE | 	/* Enable transmit ready int */		RxMissiE |	/* Enable Rx miss frame int */		TxColOvfiE |	/* Enable TxCOL counter overflow int */		MissOvfloiE;	/* Enable Rx miss counter over int */	cs8900_set(ndev, PP_BufCFG, value);	/* LineCTL */	value = SerRxON |	/* Enable receiver */		SerTxON;	/* Enable transmitter */	cs8900_set(ndev, PP_LineCTL, value);	/* SelfCTL: no need */		/* BusCTL */	value = EnableRQ;	/* Enable IRQ */	cs8900_set(ndev, PP_BusCTL, value);#ifdef	CONFIG_FULL_DUPLEX	/* TestCTL */	value = FDX;		/* Enable full duplex */	cs8900_set(ndev, PP_TestCTL, value);#endif /* FULL_FUPLEX */}/*********************************** * cs8900_open * open device. called when ndev->flags has been changed **********************************/static intcs8900_open(struct net_device *ndev){	int result;	printk(KERN_ERR "cs8900 entered cs8900_open\n");	/* set irq type */	//set_irq_type(ndev->irq, IRQT_RISING);	set_irq_type(ndev->irq, IRQT_BOTHEDGE);	/* Initialize hardware */	cs8900_hardware_init(ndev);	udelay(200);	/* wait a moment */	/* request irq */	result = request_irq(ndev->irq, 		cs8900_interrupt, 		IRQF_SHARED, 		ndev->name, 		ndev);	if (result) {		printk("%s: could not register irq %d routine \n", ndev->name, ndev->irq);		return result;	}	/* start tx queue */	netif_start_queue(ndev);	return 0;}/****************************** * cs8900_stop * called when ifdown *****************************/static intcs8900_stop(struct net_device *ndev){	/* stop tx queue */	netif_stop_queue(ndev);	/* unregister interrupt routine */	free_irq(ndev->irq, ndev);	/* clear all register */	cs8900_write(ndev, PP_BusCTL, 	0);	cs8900_write(ndev, PP_TestCTL, 	0);	cs8900_write(ndev, PP_SelfCTL, 	0);	cs8900_write(ndev, PP_LineCTL, 	0);	cs8900_write(ndev, PP_BufCFG, 	0);	cs8900_write(ndev, PP_TxCFG, 	0);	cs8900_write(ndev, PP_RxCTL, 	0);	cs8900_write(ndev, PP_RxCFG, 	0);	return 0;}/*************************************** * cs8900_get_stats * return rx&tx statistics value  **************************************/static struct net_device_stats *cs8900_get_stats(struct net_device *ndev){	return &ndev->stats;//	struct cs8900_dev *priv = netdev_priv(ndev);//	return &priv->cs8900_stats;}/************************************** * cs8900_transmit_timeout * called after transmit has stopped ndev->watchdog_timeo **************************************/static void cs8900_transmit_timeout(struct net_device *ndev){	struct cs8900_dev *priv = netdev_priv(ndev);	/* reset cs8900 *///	cs8900_reset(ndev);		/* reinitialize hardware *///	cs8900_hardware_init(ndev);//	udelay(200);	/* update net_device_stats */	ndev->stats.tx_errors++;	ndev->stats.tx_heartbeat_errors++;	/* update cs8900_priv */	spin_lock_irq(&priv->lock); /* protect txlen */	priv->txlen = 0;	spin_unlock_irq(&priv->lock);	/* wake up tx queue */	netif_wake_queue(ndev);}/****************************************** * cs8900_send_start: * Send one frame to cs8900 chip *****************************************/static intcs8900_send_start(struct sk_buff *skb, struct net_device *ndev){	struct cs8900_dev *priv = netdev_priv(ndev);	u16 status;	int i;	printk("CS8900 enter send_start()\n");	/* suspend tx queue, until next tx interrupt occur */	netif_stop_queue(ndev);	/* Send TxCMD to cs8900: after 5 bytes */	cs8900_write(ndev, PP_TxCMD, TxStart(After5));	/* Send TxLength: from skb */ 	cs8900_write(ndev, PP_TxLen, skb->len);	/* Get transmit status, read TxBidErr */		status = cs8900_read(ndev, PP_BusST);	if (status & TxBidErr) {		printk(KERN_WARNING "%s: Invalid frame size %d!\n", ndev->name, skb->len);		ndev->stats.tx_errors++;		ndev->stats.tx_aborted_errors++;		return 1;	}	if (status & Rdy4TxNOW)		printk("In %s, Ready to transmit\n", __FUNCTION__);	/* Wait for Transmitter ready */	for (i=0; i<10; i++) {	 	if(status & Rdy4TxNOW)			goto ready_to_tx;		udelay(10);	}	printk(KERN_WARNING "%s: Transmit buffer not free!\n", ndev->name);	ndev->stats.tx_errors++;	return 1;ready_to_tx:	/* send one frame */	cs8900_frame_write(ndev, skb);	/* Record tx frame length to priv->txlen */	spin_lock_irq(&priv->lock);	priv->txlen = skb->len;	spin_unlock_irq(&priv->lock);	/* Record last tx time */	ndev->trans_start = jiffies;		/* free skb */	dev_kfree_skb(skb);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -