[原创]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
比内核中的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");
相关文章推荐
- WinCE5.0 SMDK2410 BSP在GEC2410开发板上的移植(14)-移植CS8900A网卡NDIS Miniport驱动
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- linux-2.6.35内核配置和网卡驱动添加
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核) --SMP多核启动以及CPU热插拔驱动
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- cs8900网卡驱动安装,内核2.6.33,处理器samsung2410
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核) --中断控制器
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- linux-2.6.27移植到AT91SAM9260平台终端之(02)_内核移植准备工作
- linux3.1.8内核移植到gt2440---CS8900A驱动移植
- Linux内核驱动学习(一)----内核简介 | 配置 | 编译| 安装(PC平台下)
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- 基于S3C2410平台移植Linux 2.6.14内核&驱动指南
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- 移植linux网卡驱动中关于mac芯片和phy之间的常用接口知识
- linux内核当中的2410单点触摸驱动在线阅读地址