?? cerf89x0.c
字號:
/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 * driver for linux. *//* Written 1996 by Russell Nelson, with reference to skeleton.c written 1993-1994 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. The author may be reached at nelson@crynwr.com, Crynwr Software, 521 Pleasant Valley Rd., Potsdam, NY 13676 Changelog: Mike Cruse : mcruse@cti-ltd.com Russ Nelson : Jul 13 1998. Added RxOnly DMA support. Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility. Alan Cox : Removed 1.2 support, added 2.1 extra counters. Andrew Morton : andrewm@uow.edu.au Sangwook Lee : hitchcar@sec.samsung.com*/static char *version ="cerf89x0.c: (kernel 2.3.99) Russell Nelson, Andrew Morton\n";/* ======================= end of configuration ======================= *//* Always include 'config.h' first in case the user wants to turn on or override something. */#ifdef MODULE#include <linux/module.h>#include <linux/version.h>#else#define MOD_INC_USE_COUNT#define MOD_DEC_USE_COUNT#endif/* * Set this to zero to remove all the debug statements via * dead code elimination */#define DEBUGGING 1/* Sources: Crynwr packet driver epktisa. Crystal Semiconductor data sheets.*/#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <asm/irq.h>#include <asm/hardware.h>#define IRQ_LAN IRQ_EINT8_23#include "cs89x0.h"/* First, a few definitions that the brave might change. *//* A zero-terminated list of I/O addresses to be probed. */static unsigned int netcard_portlist[] __initdata = { (0xd0000000+0x00000300), 0};#ifdef DEBUGGINGstatic unsigned int net_debug = 4;#else#define net_debug 0 /* gcc will remove all the debug code for us */#endif/* The number of low I/O ports used by the ethercard. */#define NETCARD_IO_EXTENT 16/* Information that need to be kept for each board. */struct net_local { struct net_device_stats stats; int chip_type; /* one of: CS8900, CS8920, CS8920M */ char chip_revision; /* revision letter of the chip ('A'...) */ int send_cmd; /* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */ int auto_neg_cnf; /* auto-negotiation word from EEPROM */ int adapter_cnf; /* adapter configuration from EEPROM */ int isa_config; /* ISA configuration from EEPROM */ int irq_map; /* IRQ map from EEPROM */ int rx_mode; /* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */ int curr_rx_cfg; /* a copy of PP_RxCFG */ int linectl; /* either 0 or LOW_RX_SQUELCH, depending on configuration. */ int send_underrun; /* keep track of how many underruns in a row we get */ struct sk_buff * Gskb; /* pinnter to TX buff waiting for Ready4Tx */ spinlock_t lock;};/* Index to functions, as function prototypes. */extern int cerf89x0_probe(struct net_device *dev);static int S3C2410_HWinit(void);static int cerf89x0_probe1(struct net_device *dev, int ioaddr);static int net_open(struct net_device *dev);static int net_send_packet(struct sk_buff *skb, struct net_device *dev);static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void set_multicast_list(struct net_device *dev);static void net_timeout(struct net_device *dev);static void net_rx(struct net_device *dev);static int net_close(struct net_device *dev);static struct net_device_stats *net_get_stats(struct net_device *dev);static void reset_chip(struct net_device *dev);static int set_mac_address(struct net_device *dev, void *addr);static void count_rx_errors(int status, struct net_local *lp);/* Example routines you must write ;->. */#define tx_done(dev) 1/* Check for a network chip of this type, and return '0' if one exists. * Return ENODEV on Failure. */#ifdef CONFIG_S3C2410_SMDK#define CS8900_Tacs (0x0) // 0clk#define CS8900_Tcos (0x3) // 4clk#define CS8900_Tacc (0x7) // 14clk#define CS8900_Tcoh (0x1) // 1clk#define CS8900_Tah (0x3) // 4clk#define CS8900_Tacp (0x3) // 6clk#define CS8900_PMC (0x0) // normal(1data)int __init S3C2410_HWinit(){ // initialize CS8900 BWSCON = (BWSCON&~(0xf<<12))|(0xd<<12); /* nWAIT */ // rGSTATUS0; /* Read Only */ GPGCON &= ~(3 << 2); GPGCON |= (2 << 2); /* GPG1 set to EINT9 */ BANKCON3=((CS8900_Tacs<<13)+(CS8900_Tcos<<11)+(CS8900_Tacc<<8) +(CS8900_Tcoh<<6)+(CS8900_Tah<<4)+(CS8900_Tacp<<2)+(CS8900_PMC)); EXTINT1 &= ~(7 << 4); EXTINT1 |= (4 << 4); /* EINT9 rising edge */ return 0;}#endifint __init cerf89x0_probe(struct net_device *dev){ static int initialised = 0; int i; if (initialised) return -ENODEV; initialised = 1;#ifdef CONFIG_S3C2410_SMDK S3C2410_HWinit();#endif if (net_debug) printk("cerf89x0:cerf89x0_probe()\n"); #ifdef CONFIG_S3C2410_SMDK GPGUP |= (1 << 1); /* GPG1 pull-up disable */ GPGCON &= ~(3 << 2); GPGCON |= (2 << 2); /* GPG1 set to EINT9 */#endif for (i = 0; netcard_portlist[i]; i++) { int ioaddr = netcard_portlist[i]; if (cerf89x0_probe1(dev, ioaddr) == 0) return 0; } printk(KERN_WARNING "cerf89x0: no cs8900 detected.\n"); return ENODEV;}extern u8 inlineraw_readb(u32 addr){ return (*(volatile u8 *)(addr));}extern u16 inlineraw_readw(u32 addr){ return (*(volatile u16 *)(addr));}extern void inlineraw_writeb(u8 value, u32 addr){ (*(volatile u8 *)(addr)) = value;}extern void inlineraw_writew(u16 value, u32 addr){ (*(volatile u16 *)(addr)) = value;}extern u16 inlinereadreg(struct net_device *dev, int portno){ raw_writew(portno, dev->base_addr + ADD_PORT); return raw_readw(dev->base_addr + DATA_PORT);}extern void inlinewritereg(struct net_device *dev, int portno, u16 value){ raw_writew(portno, dev->base_addr + ADD_PORT); raw_writew(value, dev->base_addr + DATA_PORT);}extern u16 inlinereadword(struct net_device *dev, int portno){ return raw_readw(dev->base_addr + portno);}extern void inlinewriteword(struct net_device *dev, int portno, u16 value){ raw_writew(value, dev->base_addr + portno);}static void writeblock(struct net_device *dev, char *pData, int Length){ int i; for (i = 0 ; i < (Length / 2); i++) { writeword(dev, TX_FRAME_PORT, *(u16 *)pData ); pData += 2; } if (Length % 2) { u16 OddWordValue = *pData; writeword(dev, TX_FRAME_PORT, OddWordValue); }}static void readblock(struct net_device *dev, char *pData, int Length){#if 0 u16 wOddWord; int i; u16 StartOffset = PP_RxFrame | AUTOINCREMENT; writeword(dev, ADD_PORT, StartOffset); if ((u32) pData % 2) { for (i=0; i < (Length/2); i++) { wOddWord = readword(dev, DATA_PORT); *(u8*)pData++ = (u8) wOddWord & 0xFF; *(u8*)pData++ = (u8) (wOddWord >> 8) & 0xFF; } } else { for (i=0; i < (Length/2); i++) { *(u16*) pData = readword(dev, DATA_PORT); pData += 2; } } switch (Length % 2) { case 1: *pData = (u8) (readword(dev, DATA_PORT) & 0xff); }#endif u16 InputWord; int i; for (i=0; i < (Length>>1); i++) { InputWord = readword(dev, RX_FRAME_PORT); *(u8*)pData++ = (u8) InputWord & 0xFF; *(u8*)pData++ = (u8) (InputWord >> 8) & 0xFF; } switch (Length & 0x1) { case 1: *pData = (u8) (readword(dev, RX_FRAME_PORT) & 0xff); }}/* This is the real probe routine. Linux has a history of friendly device probes on the ISA bus. A good device probes avoids doing writes, and verifies that the correct device exists and functions. Return 0 on success. */char chip_version(int PID){ switch(PID) { case 0x7: return 'B'; case 0x8: return 'C'; case 0x9: return 'D'; default : return '?'; }}static int __initcerf89x0_probe1(struct net_device *dev, int ioaddr){ struct net_local *lp; static unsigned version_printed = 0; int i; unsigned rev_type = 0; u16 MacAddr[3] = {0,0,0}; int retval; unsigned short wData; /* Initialize the device structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (dev->priv == 0) { retval = ENOMEM; goto out; } memset(dev->priv, 0, sizeof(struct net_local)); } lp = (struct net_local *)dev->priv; /* Bus Reset Consideration */ wData = raw_readw(ioaddr + ADD_PORT); if ((wData & ADD_MASK) != ADD_SIG ) { // if (net_debug) printk("cerf89x0:cerf89x0_probe1() 0x%08X\n", wData); // printk(" BWSCON 0x%08X\n", rBWSCON); retval = ENODEV; goto out1; } /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; /* get the chip type */ rev_type = readreg(dev, PRODUCT_ID_ADD); lp->chip_type = rev_type &~ REVISON_BITS; lp->chip_revision = chip_version((rev_type & REVISON_BITS) >> 8); /* Check the chip type and revision in order to set the correct send command CS8920 revision C and CS8900 revision F can use the faster send. *//* lp->send_cmd = TX_AFTER_381; */ lp->send_cmd = TX_AFTER_ALL; /* if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') lp->send_cmd = TX_NOW; if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') lp->send_cmd = TX_NOW;*/ reset_chip(dev); if (net_debug && version_printed++ == 0) printk(version); printk(KERN_INFO "%s: cs89%c0%s rev %c Base %x", dev->name, lp->chip_type==CS8900 ? '0' : '2', lp->chip_type==CS8920M ? "M" : "", lp->chip_revision, (unsigned int )dev->base_addr); MacAddr[0] = 0x0000; MacAddr[1] = 0x24f0; MacAddr[2] = 0x5b05; for (i = 0; i < ETH_ALEN/2; i++) { dev->dev_addr[i*2] = MacAddr[i]; dev->dev_addr[i*2+1] = MacAddr[i] >> 8; } dev->irq = IRQ_LAN; printk(KERN_INFO ", IRQ %d", dev->irq); /* print the ethernet address. */ printk(", MAC "); for (i = 0; i < ETH_ALEN; i++) { printk("%s%02X", i ? ":" : "", dev->dev_addr[i]); } printk("\n"); dev->open = net_open; dev->stop = net_close; dev->tx_timeout = net_timeout; dev->watchdog_timeo = 3 * HZ ; dev->hard_start_xmit = net_send_packet; dev->get_stats = net_get_stats; dev->set_multicast_list = set_multicast_list; dev->set_mac_address = set_mac_address; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); return 0;out1: kfree(dev->priv); dev->priv = 0;out: return retval;}void __init reset_chip(struct net_device *dev){ int reset_start_time; writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); /* wait 30 ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(30*HZ/1000); /* Wait until the chip is reset */ reset_start_time = jiffies; while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 4) ;}/* Open/initialize the board. This is called (in the current kernel) sometime after booting when the 'ifconfig' program is run. This routine should set everything up anew at each open, even registers that "should" only need to be set once at boot, so that there is non-reboot way to recover if something goes wrong. *//* AKPM: do we need to do any locking here? */static intnet_open(struct net_device *dev){ struct net_local *lp = (struct net_local *)dev->priv;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -