您的位置:首页 > 运维架构 > Linux

[原创]CS8900A 网卡芯片驱动,Linux-2.6.27内核,SMDK2410平台

2010-02-19 14:07 441 查看
刚刚测试过的,平台为SMDK2410,内核为 2.6.27, 应该从 2.6.27 - 2.6.30 的内核都可以支持,假如不支持的话Q我: 126027268~~~

比内核中的cs89x0.c增加了链路状态检查定时器操作,因而解决了网线拔掉时发送超时内核报错的bug。

下载地址:http://download.csdn.net/source/2067455

(转载请注明本文地址: http://blog.csdn.net/rssn_net/archive/2010/02/19/5311601.aspx)
下面是两个代码文件 cs8900.h, cs8900.c

#ifndef CS8900_H
#define CS8900_H
/*
* linux/drivers/net/cs8900.h
*
* Author: Abraham van der Merwe <abraham at 2d3d.co.za>
*
* A Cirrus Logic CS8900A driver for Linux
* based on the cs89x0 driver written by Russell Nelson,
* Donald Becker, and others.
*
* This source code is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* Modified: rssn <rssn@163.com> 2010-2-18:
*  #define PP_LineST 0x0134
*  #define LinkOK    0x0080
*/
/*
* Ports
*/
#define PP_Address		0x0a	/* PacketPage Pointer Port (Section 4.10.10) */
#define PP_Data			0x0c	/* PacketPage Data Port (Section 4.10.10) */
/*
* Registers
*/
#define PP_ProductID		0x0000	/* Section 4.3.1   Product Identification Code */
#define PP_MemBase			0x002c	/* Section 4.9.2   Memory Base Address Register */
#define PP_IntNum			0x0022	/* Section 3.2.3   Interrupt Number */
#define PP_EEPROMCommand	0x0040	/* Section 4.3.11  EEPROM Command */
#define PP_EEPROMData		0x0042	/* Section 4.3.12  EEPROM Data */
#define PP_RxCFG			0x0102	/* Section 4.4.6   Receiver Configuration */
#define PP_RxCTL			0x0104	/* Section 4.4.8   Receiver Control */
#define PP_TxCFG			0x0106	/* Section 4.4.9   Transmit Configuration */
#define PP_BufCFG			0x010a	/* Section 4.4.12  Buffer Configuration */
#define PP_LineCTL			0x0112	/* Section 4.4.16  Line Control */
#define PP_SelfCTL			0x0114	/* Section 4.4.18  Self Control */
#define PP_BusCTL			0x0116	/* Section 4.4.20  Bus Control */
#define PP_TestCTL			0x0118	/* Section 4.4.22  Test Control */
#define PP_ISQ				0x0120	/* Section 4.4.5   Interrupt Status Queue */
#define PP_TxEvent			0x0128	/* Section 4.4.10  Transmitter Event */
#define PP_BufEvent			0x012c	/* Section 4.4.13  Buffer Event */
#define PP_RxMISS			0x0130	/* Section 4.4.14  Receiver Miss Counter */
#define PP_TxCOL			0x0132	/* Section 4.4.15  Transmit Collision Counter */
#define PP_LineST			0x0134  /* Section 4.4.17  Line Status */
#define PP_SelfST			0x0136	/* Section 4.4.19  Self Status */
#define PP_BusST			0x0138	/* Section 4.4.21  Bus Status */
#define PP_TxCMD			0x0144	/* Section 4.4.11  Transmit Command */
#define PP_TxLength			0x0146	/* Section 4.5.2   Transmit Length */
#define PP_IA				0x0158	/* Section 4.6.2   Individual Address (IEEE Address) */
#define PP_RxStatus			0x0400	/* Section 4.7.1   Receive Status */
#define PP_RxLength			0x0402	/* Section 4.7.1   Receive Length (in bytes) */
#define PP_RxFrame			0x0404	/* Section 4.7.2   Receive Frame Location */
#define PP_TxFrame			0x0a00	/* Section 4.7.2   Transmit Frame Location */
/*
* Values
*/
/* PP_IntNum */
#define INTRQ0			0x0000
#define INTRQ1			0x0001
#define INTRQ2			0x0002
#define INTRQ3			0x0003
/* PP_ProductID */
#define EISA_REG_CODE	0x630e
#define REVISION(x)		(((x) & 0x1f00) >> 8)
#define VERSION(x)		((x) & ~0x1f00)
#define CS8900A			0x0000
#define REV_B			7
#define REV_C			8
#define REV_D			9
/* PP_RxCFG */
#define Skip_1			0x0040
#define StreamE			0x0080
#define RxOKiE			0x0100
#define RxDMAonly		0x0200
#define AutoRxDMAE		0x0400
#define BufferCRC		0x0800
#define CRCerroriE		0x1000
#define RuntiE			0x2000
#define ExtradataiE		0x4000
/* PP_RxCTL */
#define IAHashA			0x0040
#define PromiscuousA	0x0080
#define RxOKA			0x0100
#define MulticastA		0x0200
#define IndividualA		0x0400
#define BroadcastA		0x0800
#define CRCerrorA		0x1000
#define RuntA			0x2000
#define ExtradataA		0x4000
/* PP_TxCFG */
#define Loss_of_CRSiE	0x0040
#define SQErroriE		0x0080
#define TxOKiE			0x0100
#define Out_of_windowiE	0x0200
#define JabberiE		0x0400
#define AnycolliE		0x0800
#define T16colliE		0x8000
/* PP_BufCFG */
#define SWint_X			0x0040
#define RxDMAiE			0x0080
#define Rdy4TxiE		0x0100
#define TxUnderruniE	0x0200
#define RxMissiE		0x0400
#define Rx128iE			0x0800
#define TxColOvfiE		0x1000
#define MissOvfloiE		0x2000
#define RxDestiE		0x8000
/* PP_LineCTL */
#define SerRxON			0x0040
#define SerTxON			0x0080
#define AUIonly			0x0100
#define AutoAUI_10BT	0x0200
#define ModBackoffE		0x0800
#define PolarityDis		0x1000
#define L2_partDefDis	0x2000
#define LoRxSquelch		0x4000
/* PP_SelfCTL */
#define RESET			0x0040
#define SWSuspend		0x0100
#define HWSleepE		0x0200
#define HWStandbyE		0x0400
#define HC0E			0x1000
#define HC1E			0x2000
#define HCB0			0x4000
#define HCB1			0x8000
/* PP_BusCTL */
#define ResetRxDMA		0x0040
#define DMAextend		0x0100
#define UseSA			0x0200
#define MemoryE			0x0400
#define DMABurst		0x0800
#define IOCHRDYE		0x1000
#define RxDMAsize		0x2000
#define EnableRQ		0x8000
/* PP_TestCTL */
#define DisableLT		0x0080
#define ENDECloop		0x0200
#define AUIloop			0x0400
#define DisableBackoff	0x0800
#define FDX				0x4000
/* PP_ISQ */
#define RegNum(x) ((x) & 0x3f)
#define RegContent(x) ((x) & ~0x3d)
#define RxEvent			0x0004
#define TxEvent			0x0008
#define BufEvent		0x000c
#define RxMISS			0x0010
#define TxCOL			0x0012
/* PP_RxStatus */
#define IAHash			0x0040
#define Dribblebits		0x0080
#define RxOK			0x0100
#define Hashed			0x0200
#define IndividualAdr	0x0400
#define Broadcast		0x0800
#define CRCerror		0x1000
#define Runt			0x2000
#define Extradata		0x4000
#define HashTableIndex(x) ((x) >> 0xa)
/* PP_TxCMD */
#define After5			0
#define After381		1
#define After1021		2
#define AfterAll		3
#define TxStart(x) ((x) << 6)
#define Force			0x0100
#define Onecoll			0x0200
#define InhibitCRC		0x1000
#define TxPadDis		0x2000
/* PP_BusST */
#define TxBidErr		0x0080
#define Rdy4TxNOW		0x0100
/* PP_TxEvent */
#define Loss_of_CRS		0x0040
#define SQEerror		0x0080
#define TxOK			0x0100
#define Out_of_window	0x0200
#define Jabber			0x0400
#define T16coll			0x8000
#define TX_collisions(x) (((x) >> 0xb) & ~0x8000)
/* PP_BufEvent */
#define SWint			0x0040
#define RxDMAFrame		0x0080
#define Rdy4Tx			0x0100
#define TxUnderrun		0x0200
#define RxMiss			0x0400
#define Rx128			0x0800
#define RxDest			0x8000
/* PP_RxMISS */
#define MissCount(x) ((x) >> 6)
/* PP_TxCOL */
#define ColCount(x) ((x) >> 6)
/* PP_LineST */
#define LinkOK			0x0080
/* PP_SelfST */
#define T3VActive		0x0040
#define INITD			0x0080
#define SIBUSY			0x0100
#define EEPROMpresent	0x0200
#define EEPROMOK		0x0400
#define ELpresent		0x0800
#define EEsize			0x1000
/* PP_EEPROMCommand */
#define EEWriteEnable   0x00F0
#define EEWriteDisable  0x0000
#define EEWriteRegister	0x0100
#define EEReadRegister	0x0200
#define EEEraseRegister	0x0300
#define ELSEL			0x0400
#endif	/* #ifndef CS8900_H */


/*
* linux/drivers/net/cs8900.c
*
* Cirrus Logic CS8900A driver for Linux 2.6.27,
*  fitting SMDK2410 board only.
*
* Author: Jianying Liu, <rssn@163.com>
* Date:   2010-2-18
* ( Please DO NOT remove these messages while redistributing. )
*
* This source code is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*/

//#define CS8900_DEBUG
#define FULL_DUPLEX
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/irq.h>
#include <asm/mach-types.h>
#include <mach/irqs.h>
#ifdef CONFIG_ARCH_S3C2410
#include <mach/regs-mem.h>
#include <mach/regs-gpio.h>
#include <asm/plat-s3c24xx/common-smdk.h>
#include <asm/plat-s3c24xx/smdk2410.h>
#endif
#include "cs8900.h"
typedef struct cs8900_priv
{
int iomem_sz;
spinlock_t lock;
struct net_device_stats stats;
struct timer_list timer;
} cs8900_priv_t;
/* --- Declarations start --- */
static u16 cs8900_readw(struct net_device *dev, u16 reg_addr);
static void cs8900_writew(struct net_device *dev, u16 reg_addr, u16 value);
static void cs8900_unsetw(struct net_device *dev, u16 reg_addr, u16 mask);
static void cs8900_rx(struct net_device *dev);
static irqreturn_t cs8900_interrupt(int irq, void *id);
static int cs8900_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int cs8900_open(struct net_device *dev);
static int cs8900_stop(struct net_device *dev);
static int cs8900_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static struct net_device_stats *cs8900_stats(struct net_device *dev);
static void cs8900_tx_timeout(struct net_device *dev);
static int set_mac_address(struct net_device *dev, void *addr);
static int cs8900_init(struct net_device *dev);
static void cs8900_timer(unsigned long data);
static void cs8900_update_mac(struct net_device *dev);
/* --- Declarations end --- */
static struct net_device  *cs8900_dev = NULL;
#ifdef CS8900_DEBUG
static void cs8900_watchw(struct net_device *dev, u16 reg_addr)
{
printk(KERN_INFO "%s: @0x%x = 0x%x/n", dev->name, reg_addr, cs8900_readw(dev, reg_addr) );
}
#endif
static u16 cs8900_readw(struct net_device *dev, u16 reg_addr)
{
outw(reg_addr, dev->base_addr + PP_Address);
return inw(dev->base_addr + PP_Data);
}
static void cs8900_writew(struct net_device *dev, u16 reg_addr, u16 value)
{
outw(reg_addr, dev->base_addr + PP_Address);
outw(value, dev->base_addr + PP_Data);
}
static void cs8900_setw(struct net_device *dev, u16 reg_addr, u16 mask)
{
cs8900_writew(dev, reg_addr, cs8900_readw(dev, reg_addr) | mask);
}
static void cs8900_unsetw(struct net_device *dev, u16 reg_addr, u16 mask)
{
cs8900_writew(dev, reg_addr, cs8900_readw(dev, reg_addr) & ~mask);
}
static void cs8900_rx(struct net_device *dev)
{
cs8900_priv_t *priv = netdev_priv(dev);
u16 status, len;
struct sk_buff *skb;

status = cs8900_readw(dev, PP_RxStatus);
len    = cs8900_readw(dev, PP_RxLength);
if(!(status & RxOK))
{
priv->stats.rx_errors++;
if((status & (Runt | Extradata))) priv->stats.rx_length_errors++;
if((status & CRCerror)) priv->stats.rx_crc_errors++;
return;
}
/* Allocate sk_buff for received packet data */
if((skb = dev_alloc_skb(len + 4)) == NULL)
{
priv->stats.rx_dropped++;
return;
}
skb->dev = dev;
skb_reserve(skb, 2);
insw(dev->base_addr, skb_put(skb, len), (len + 1) / 2);
skb->protocol = eth_type_trans(skb, dev);
/* Notify the higher level with it... */
netif_rx(skb);
//printk("%s: %s(): status: 0x%x, len: %d/n", dev->name, __FUNCTION__, status, len);
dev->last_rx = jiffies;
priv->stats.rx_packets++;
priv->stats.rx_bytes += len;
/* */
}
static irqreturn_t cs8900_interrupt(int irq, void *id)
{
struct net_device *dev = (struct net_device *)id;
cs8900_priv_t *priv = netdev_priv(dev);
u16 status;
int handled = 0;
while((status = cs8900_readw(dev, PP_ISQ)))
{
handled = 1;
switch(RegNum(status))
{
case RxEvent:
cs8900_rx(dev);
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: In interrupt [RxEvent]/n", dev->name);
#endif
break;
case TxEvent:
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: In interrupt [TxEvent]/n", dev->name);
#endif
priv->stats.collisions += ColCount(cs8900_readw(dev, PP_TxCOL));
if(!(RegContent(status) & TxOK))
{
priv->stats.tx_errors++;
if((RegContent(status) & Out_of_window))
priv->stats.tx_window_errors++;
if((RegContent(status) & Jabber))
priv->stats.tx_aborted_errors++;
break;
}
netif_wake_queue(dev);
break;
case BufEvent:
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: In interrupt [BufEvent]/n", dev->name);
#endif
if(RegContent(status) & RxMiss)
{
u16 missed = MissCount(cs8900_readw(dev, PP_RxMISS));
priv->stats.rx_errors++;
priv->stats.rx_missed_errors += missed;
}
if(RegContent(status) & TxUnderrun)
{
priv->stats.tx_errors++;
priv->stats.tx_fifo_errors++;
netif_wake_queue(dev);
}
break;
case TxCOL:
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: In interrupt [TxCOL]/n", dev->name);
#endif
priv->stats.collisions += ColCount(cs8900_readw(dev, PP_TxCOL));
break;
case RxMISS:
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: In interrupt [RxMISS]/n", dev->name);
#endif
status = MissCount(cs8900_readw(dev, PP_RxMISS));
priv->stats.rx_errors += status;
priv->stats.rx_missed_errors += status;
break;
default:
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: In interrupt [type: 0x%x]/n", dev->name, status);
#endif
break;
}
}
return IRQ_RETVAL(handled);
}
static int cs8900_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
cs8900_priv_t *priv = (cs8900_priv_t *)netdev_priv(dev);
u16 busst;
//int i;
spin_lock_irq(&priv->lock);
netif_stop_queue(dev);

/* Send TxStart command */
cs8900_writew(dev, PP_TxCMD, TxStart(After5));
cs8900_writew(dev, PP_TxLength, skb->len);
busst = cs8900_readw(dev, PP_BusST);
if(!(busst & Rdy4TxNOW))
{
netif_wake_queue(dev);
spin_unlock_irq(&priv->lock);
#ifdef CS8900_DEBUG
printk(KERN_WARNING "%s: Chip not ready for sending./n", dev->name);
#endif
priv->stats.tx_errors++;
return 1;
}
/* Send packet data */
outsw(dev->base_addr, skb->data, (skb->len + 1) / 2);
//for(i=0; i<(skb->len + 1) / 2; i++)
//	cs8900_writew(dev, 0x0, *((u16 *)skb->data + i) );
spin_unlock_irq(&priv->lock);
dev->trans_start = jiffies;
//#if 1
//while(!(cs8900_readw(dev, PP_BusST) & Rdy4TxNOW));
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
//netif_wake_queue(dev);
//#endif
dev_kfree_skb(skb);
return 0;
}
static int cs8900_open(struct net_device *dev)
{
#ifdef CONFIG_ARCH_S3C2410
/* Enable Ethernet controller */
//cs8900_writew(dev, PP_BusCTL, cs8900_readw(dev, PP_BusCTL) | MemoryE);
//cs8900_watchw(dev, PP_RxCTL);
//cs8900_watchw(dev, PP_RxCFG);
cs8900_setw(dev, PP_RxCFG, RxOKiE | BufferCRC | CRCerroriE | RuntiE | ExtradataiE);
cs8900_setw(dev, PP_RxCTL, RxOKA | IndividualA | BroadcastA);
cs8900_setw(dev, PP_BufCFG, Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE);
cs8900_setw(dev, PP_TxCFG, TxOKiE | Out_of_windowiE | JabberiE);
cs8900_setw(dev, PP_LineCTL, SerRxON | SerTxON);
/* Enable interrupt */
set_irq_type(dev->irq, IRQ_TYPE_EDGE_RISING /*(1<<1)||(1<<0)*/ );
cs8900_setw(dev, PP_BusCTL, EnableRQ | MemoryE);
#ifdef FULL_DUPLEX
cs8900_setw(dev, PP_TestCTL, FDX);
#endif	/* #ifdef FULL_DUPLEX */
/* Register interrupt handler */
udelay(200);
if(request_irq(dev->irq, cs8900_interrupt, /*0*/ IRQF_SHARED, dev->name, dev) < 0)
{
printk(KERN_ERR "%s: request_irq() %d error./n", dev->name, dev->irq);
return -1;
}
//printk(KERN_ERR "%s: request_irq() %d success./n", dev->name, dev->irq);
/* Setup interrupt number */
#ifdef CS8900_DEBUG
cs8900_watchw(dev, PP_IntNum);
#endif
cs8900_writew(dev, PP_IntNum, 0); /* IRQ map: {dev->irq, 0, 0, 0} */
#endif
/* Write Ethernet address to CS8900 chip */
cs8900_update_mac(dev);
netif_start_queue(dev);
return 0;
}
static int cs8900_stop(struct net_device *dev)
{
#ifdef CONFIG_ARCH_S3C2410
/* Disable Ethernet controller */
cs8900_unsetw(dev, PP_BusCTL, EnableRQ | MemoryE);
cs8900_unsetw(dev, PP_LineCTL, SerRxON | SerTxON);
cs8900_unsetw(dev, PP_TxCFG, TxOKiE | Out_of_windowiE | JabberiE);
cs8900_unsetw(dev, PP_BufCFG, Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE);
cs8900_unsetw(dev, PP_RxCTL, RxOKA | IndividualA | BroadcastA);
cs8900_unsetw(dev, PP_RxCFG, RxOKiE | BufferCRC | CRCerroriE | RuntiE | ExtradataiE);
#ifdef FULL_DUPLEX
cs8900_unsetw(dev, PP_TestCTL, FDX);
#endif	/* #ifdef FULL_DUPLEX */
#endif
/* Release interrupt handler */
free_irq(dev->irq, dev);
/* Stop transmission queue */
netif_stop_queue(dev);
return 0;
}
static void cs8900_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
cs8900_priv_t *priv = (cs8900_priv_t *)netdev_priv(dev);

if(!(dev->flags & IFF_UP))
goto __cs8900_time_quit;
#ifdef CS8900_DEBUG
//printk("%s: In timer.../n", dev->name);
//cs8900_watchw(dev, PP_LineST);
#endif
/* Check link status */
if((cs8900_readw(dev, PP_LineST) & LinkOK))
{
/* On */
if(!(dev->flags & IFF_RUNNING))
{
netif_carrier_on(dev);
dev->flags |= IFF_RUNNING;
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: Link up./n", dev->name);
#endif
}
}
else
{
/* Off */
if((dev->flags & IFF_RUNNING))
{
netif_carrier_off(dev);
dev->flags &= ~IFF_RUNNING;
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: Link down./n", dev->name);
#endif
}
}

__cs8900_time_quit:
priv->timer.expires = jiffies + 1 * HZ;
priv->timer.data = (unsigned long)dev;
priv->timer.function = cs8900_timer;
add_timer(&priv->timer);
}
static int cs8900_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
return 0;
}
static struct net_device_stats *cs8900_stats(struct net_device *dev)
{
cs8900_priv_t *priv = (cs8900_priv_t *)netdev_priv(dev);
return &priv->stats;
}
static void cs8900_tx_timeout(struct net_device *dev)
{
cs8900_priv_t *priv = (cs8900_priv_t *)netdev_priv(dev);
priv->stats.tx_errors++;
priv->stats.tx_heartbeat_errors++;
#ifdef CS8900_DEBUG
printk(KERN_WARNING "%s: Transmission timed out./n", dev->name);
#endif
netif_wake_queue(dev);
}
static void cs8900_update_mac(struct net_device *dev)
{
int i;
/* Write Ethernet address to CS8900 chip */
for(i=0; i < ETH_ALEN/2; i++)
cs8900_writew(dev, PP_IA + i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] <<8) );
}
static int set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *s = (struct sockaddr *)addr;
if(netif_running(dev) != 0)
return -1;
memcpy(dev->dev_addr, s->sa_data, ETH_ALEN);
#ifdef CS8900_DEBUG
printk(KERN_INFO "%s: Setting MAC address to `%02x:%02x:%02x:%02x:%02x:%02x`./n", dev->name,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
#endif
/* Write Ethernet address to CS8900 chip */
cs8900_update_mac(dev);
return 0;
}
static int cs8900_init(struct net_device *dev)
{
cs8900_priv_t *priv = (cs8900_priv_t *)netdev_priv(dev);
u16 value = 0;

memset(priv, 0x0, sizeof(cs8900_priv_t));
ether_setup(dev);

dev->open             = cs8900_open;
dev->stop             = cs8900_stop;
dev->do_ioctl         = cs8900_ioctl;
dev->get_stats        = cs8900_stats;
dev->hard_start_xmit  = cs8900_start_xmit;
dev->set_mac_address  = set_mac_address;
dev->tx_timeout       = cs8900_tx_timeout;
dev->watchdog_timeo   = 3 * HZ;

/* Add timer for link-state check */
init_timer(&priv->timer);
priv->timer.expires = jiffies + 1 * HZ;
priv->timer.data = (unsigned long)dev;
priv->timer.function = cs8900_timer;
add_timer(&priv->timer);
#ifdef CONFIG_ARCH_S3C2410
dev->dev_addr[0] = 0x08;
dev->dev_addr[1] = 0x00;
dev->dev_addr[2] = 0x3e;
dev->dev_addr[3] = 0x00;
dev->dev_addr[4] = 0x00;
dev->dev_addr[5] = 0x12;
#else
dev->dev_addr[0] = 0x00;
dev->dev_addr[1] = 0x12;
dev->dev_addr[2] = 0x34;
dev->dev_addr[3] = 0x56;
dev->dev_addr[4] = 0x78;
dev->dev_addr[5] = 0x9a;
#endif

dev->if_port   = IF_PORT_10BASET;
spin_lock_init(&priv->lock);

#ifdef CONFIG_ARCH_S3C2410
__raw_writel((__raw_readl(S3C2410_GPGCON)&~(0x3<<2))|(0x2<<2), S3C2410_GPGCON);
__raw_writel((__raw_readl(S3C2410_EXTINT1)&~(0x7<<4))|(0x4<<4), S3C2410_EXTINT1);
__raw_writel(0x2211d110, S3C2410_BWSCON);
__raw_writel(0x1f7c, S3C2410_BANKCON3);
dev->base_addr = vSMDK2410_ETH_IO + 0x300;
dev->irq = SMDK2410_ETH_IRQ;
priv->iomem_sz = 16;
//printk(KERN_ERR "%s[%d] request_mem_region(0x%lx, %d, %s).../n", __FILE__, __LINE__,
//	dev->base_addr, priv->iomem_sz, dev->name);
if(check_mem_region(dev->base_addr, priv->iomem_sz) != 0)
{
printk(KERN_ERR "%s[%d] check_mem_region(0x%lx, %d) error./n", __FILE__, __LINE__,
dev->base_addr, priv->iomem_sz);
//release_mem_region(dev->base_addr, priv->iomem_sz);
return -1;
}
/* Register IO memory */
request_mem_region(dev->base_addr, priv->iomem_sz, dev->name);
/* Verify EISA registration number for Cirrus Logic */
if((value = cs8900_readw(dev, PP_ProductID)) != EISA_REG_CODE)
{
printk(KERN_ERR "%s: incorrect ProductID 0x%04x/n", dev->name, value);
return -ENXIO;
}
/* Verify chip version */
value = cs8900_readw(dev, PP_ProductID + 2);
if(VERSION(value) != CS8900A)
{
printk(KERN_ERR "%s: unknown chip version 0x%08x/n", dev->name, VERSION(value));
return -ENXIO;
}
/* Print version message */
printk(KERN_INFO "%s: CS8900A rev %c at %#lx irq=%d, Jianying Liu <rssn@163.com>/n",
dev->name, 'B' + REVISION(value) - REV_B, dev->base_addr, dev->irq);
//#if 0
//	/* Get hardware address on CS8900 chip. */
//	int i;
//	for(i=0; i<ETH_ALEN/2; i++)
//	{
//		u16 __addr = cs8900_readw(dev, PP_IA + i*2);
//		dev->dev_addr[i*2]   = __addr & 0xff;
//		dev->dev_addr[i*2+1] = __addr >> 8;
//	}
//#endif

#endif /*CONFIG_ARCH_S3C2410*/
return 0;
}
int __init cs8900_module_init(void)
{
//printk(DRIVER_NAME", Jianying Liu <rssn@163.com>/n");
cs8900_dev = alloc_netdev(sizeof(cs8900_priv_t), "eth%d", ether_setup);
if(cs8900_dev==NULL)
{
printk(KERN_ERR "%s[%d] alloc_netdev() error./n", __FILE__, __LINE__);
return -1;
}
cs8900_dev->init = cs8900_init;
// register device to kernel
if(register_netdev(cs8900_dev) != 0)
{
free_netdev(cs8900_dev);
cs8900_dev = NULL;
printk(KERN_ERR "%s[%d] register_netdev() error./n", __FILE__, __LINE__);
return -1;
}
//

return 0;
}
void __exit cs8900_module_exit(void)
{
struct net_device *dev = cs8900_dev;
cs8900_priv_t *priv;
if(dev==NULL)
return;
priv = (cs8900_priv_t *)netdev_priv(dev);
/* Unregister this driver, and release data */
del_timer(&priv->timer);
unregister_netdev(dev);
release_mem_region(dev->base_addr, priv->iomem_sz);
free_netdev(dev);
//kfree(priv);
//printk(DRIVER_NAME" removed/n");
}
module_init(cs8900_module_init);
module_exit(cs8900_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jianying Liu <rssn@163.com>");
MODULE_DESCRIPTION("CS8900 Driver for S3C2410, v1.0");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: