📄 dm9000.c
字号:
/* * dm9000.c: Version 1.2 03/18/2003 * * A Davicom DM9000 ISA NIC fast Ethernet driver for Linux. * Copyright (C) 1997 Sten Wang * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. * * V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match * 06/22/2001 Support DM9801 progrmming * E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000 * E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200 * R17 = (R17 & 0xfff0) | NF + 3 * E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200 * R17 = (R17 & 0xfff0) | NF * * v1.00 modify by simon 2001.9.5 * change for kernel 2.4.x * * v1.1 11/09/2001 fix force mode bug * * v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>: * Fixed phy reset. * Added tx/rx 32 bit mode. * Cleaned up for kernel merge. * * 03/03/2004 Sascha Hauer <s.hauer@pengutronix.de> * Port to 2.6 kernel * * 24-Sep-2004 Ben Dooks <ben@simtec.co.uk> * Cleanup of code to remove ifdefs * Allowed platform device data to influence access width * Reformatting areas of code * * 17-Mar-2005 Sascha Hauer <s.hauer@pengutronix.de> * * removed 2.4 style module parameters * * removed removed unused stat counter and fixed * net_device_stats * * introduced tx_timeout function * * reworked locking * * 01-Jul-2005 Ben Dooks <ben@simtec.co.uk> * * fixed spinlock call without pointer * * ensure spinlock is initialised */#include <linux/module.h>#include <linux/ioport.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/version.h>#include <linux/spinlock.h>#include <linux/crc32.h>#include <linux/mii.h>#include <linux/dm9000.h>#include <linux/delay.h>#include <asm/delay.h>#include <asm/irq.h>#include <asm/io.h>//add by yf 20080623 start#include <asm/arch/regs-serial.h>#include <asm/arch/regs-clock.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/regs-mem.h>#include <asm/arch/regs-dsc.h>#include <asm/arch/regs-irq.h>#include <asm-arm/arch/irqs.h> //end add by yf 20080623#include "dm9000.h"/* Board/System/Debug information/definition ---------------- */#define DM9000_PHY 0x40 /* PHY address 0x01 */#define TRUE 1#define FALSE 0 #define FULL 2#define HALF 1#define CARDNAME "dm9000"#define PFX CARDNAME ": "#define DM9000_TIMER_WUT jiffies+(HZ*2) /* timer wakeup time : 2 second */#define DM9000_DEBUG 0#if DM9000_DEBUG > 2#define PRINTK3(args...) printk(CARDNAME ": " args)#else#define PRINTK3(args...) do { } while(0)#endif#if DM9000_DEBUG > 1#define PRINTK2(args...) printk(CARDNAME ": " args)#else#define PRINTK2(args...) do { } while(0)#endif#if DM9000_DEBUG > 0#define PRINTK1(args...) printk(CARDNAME ": " args)#define PRINTK(args...) printk(CARDNAME ": " args)#else#define PRINTK1(args...) do { } while(0)#define PRINTK(args...) printk(KERN_DEBUG args)#endif/* * Transmit timeout, default 5 seconds. */static int watchdog = 5000;module_param(watchdog, int, 0400);MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");enum DM9000_PHY_mode { DM9000_10MHD = 0, DM9000_100MHD = 1, DM9000_10MFD = 4, DM9000_100MFD = 5, DM9000_AUTO = 8, };/* For module input parameter *///static int mode = DM9000_AUTO;static int media_mode = DM9000_AUTO;/* Structure/enum declaration ------------------------------- */typedef struct board_info { void __iomem *io_addr; /* Register I/O base address */ void __iomem *io_data; /* Data I/O address */ u16 irq; /* IRQ */ u16 tx_pkt_cnt; u16 queue_pkt_len; u16 queue_start_addr; u16 dbug_cnt; u8 op_mode; /* PHY operation mode *///add by yf 20080704 u8 io_mode; /* 0:word, 2:byte */ //u8 Speed; /* current speed */ u8 phy_addr; void (*inblk)(void __iomem *port, void *data, int length); void (*outblk)(void __iomem *port, void *data, int length); void (*dumpblk)(void __iomem *port, int length); struct resource *addr_res; /* resources found */ struct resource *data_res; struct resource *addr_req; /* resources requested */ struct resource *data_req; struct resource *irq_res; struct timer_list timer; struct net_device_stats stats; unsigned char srom[128]; spinlock_t lock; struct mii_if_info mii; u32 msg_enable;} board_info_t;/* function declaration ------------------------------------- */static int dm9000_probe(struct device *);static int dm9000_open(struct net_device *);static int dm9000_start_xmit(struct sk_buff *, struct net_device *);static int dm9000_stop(struct net_device *);static void dm9000_timer(unsigned long);static void dm9000_init_dm9000(struct net_device *);static struct net_device_stats *dm9000_get_stats(struct net_device *);static irqreturn_t dm9000_interrupt(int, void *, struct pt_regs *);static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value);//static u16 read_srom_word(board_info_t *, int);static void dm9000_rx(struct net_device *);static void dm9000_hash_table(struct net_device *);static void dm9000_cpu_init(void);static void set_PHY_mode(struct net_device *dev);//#define DM9000_PROGRAM_EEPROM#ifdef DM9000_PROGRAM_EEPROMstatic void program_eeprom(board_info_t * db);#endif/* DM9000 network board routine ---------------------------- *///add by yf 20080704 startstatic void set_PHY_mode(struct net_device *dev){ board_info_t *db = (board_info_t *) dev->priv; u16 phy_reg0 = 0x1200; /* Auto-negotiation & Restart Auto-negotiation */ u16 phy_reg4 = 0x01E1 | 0x0400 ; /* Default flow control disable*/ if ( !(db->op_mode & DM9000_AUTO) ) // op_mode didn't auto sense */ { switch(db->op_mode) { case DM9000_10MHD: phy_reg4 = 0x21; phy_reg0 = 0x1000; break; case DM9000_10MFD: phy_reg4 = 0x41; phy_reg0 = 0x1100; break; case DM9000_100MHD: phy_reg4 = 0x81; phy_reg0 = 0x3000; break; case DM9000_100MFD: phy_reg4 = 0x101; phy_reg0 = 0x3100; break; default: break; } // end of switch } // end of if dm9000_phy_write(dev, 0, 0, phy_reg0); dm9000_phy_write(dev, 0, 4, phy_reg4);}//add by yf 20080704 endstatic voiddm9000_reset(board_info_t * db){ PRINTK1("dm9000x: resetting\n"); /* RESET device */ writeb(DM9000_NCR, db->io_addr); udelay(200); writeb(NCR_RST, db->io_data); udelay(200);}static void dm9000_cpu_init(void){ /*bwscon: 16bit , wait:yes, */ writel( (readl(S3C2410_BWSCON) & (~(0xf<<12) ) ) |(S3C2410_BWSCON_DW3_16)\ , S3C2410_BWSCON ); // |S3C2410_BWSCON_WS3, S3C2410_BWSCON ); /*dsc1: 8ma */ writel( (readl(S3C2440_DSC1) & (~(0x3<<8) ) ) |(S3C2440_DSC1_CS3_8mA) , S3C2440_DSC1 ); s3c2410_gpio_cfgpin(S3C2410_GPG0 , S3C2410_GPG0_EINT8);// writel( (readl(S3C2410_EXTINT1) & (~(1 << 5) ) ) , S3C2410_EXTINT1 );//Rising edge triggered // writel( (readl(S3C2410_INTMOD) & (~(1 << 5) ) ) , S3C2410_INTMOD );//EINT8--23 :IRQ mode writel( (readl(S3C2410_INTMSK) & (~(1 << 8) ) ) , S3C2410_INTMSK ); //enable eint8 // udelay(10); writel( S3C2410_BANKCON_Tacc3, S3C2410_BANKCON3 ); // bankcon3设定顺序必须在dsc和bswcon之后 //udelay(10);}/* * Read a byte from I/O port */static u8ior(board_info_t * db, int reg){ writeb(reg, db->io_addr); return readb(db->io_data);}/* * Write a byte to I/O port */static voidiow(board_info_t * db, int reg, int value){ writeb(reg, db->io_addr); writeb(value, db->io_data);}/* routines for sending block to chip */static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count){ writesb(reg, data, count);}static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count){ writesw(reg, data, (count+1) >> 1);}static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count){ writesl(reg, data, (count+3) >> 2);}/* input block from chip to memory */static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count){ readsb(reg, data, count);}static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count){ readsw(reg, data, (count+1) >> 1);}static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count){ readsl(reg, data, (count+3) >> 2);}/* dump block from chip to null */static void dm9000_dumpblk_8bit(void __iomem *reg, int count){ int i; int tmp; for (i = 0; i < count; i++) tmp = readb(reg);}static void dm9000_dumpblk_16bit(void __iomem *reg, int count){ int i; int tmp; count = (count + 1) >> 1; for (i = 0; i < count; i++) tmp = readw(reg);}static void dm9000_dumpblk_32bit(void __iomem *reg, int count){ int i; int tmp; count = (count + 3) >> 2; for (i = 0; i < count; i++) tmp = readl(reg);}/* dm9000_set_io * * select the specified set of io routines to use with the * device */static void dm9000_set_io(struct board_info *db, int byte_width){ /* use the size of the data resource to work out what IO * routines we want to use */ switch (byte_width) { case 1: db->dumpblk = dm9000_dumpblk_8bit; db->outblk = dm9000_outblk_8bit; db->inblk = dm9000_inblk_8bit; break; case 2: db->dumpblk = dm9000_dumpblk_16bit; db->outblk = dm9000_outblk_16bit; db->inblk = dm9000_inblk_16bit; break; case 3: printk(KERN_ERR PFX ": 3 byte IO, falling back to 16bit\n"); db->dumpblk = dm9000_dumpblk_16bit; db->outblk = dm9000_outblk_16bit; db->inblk = dm9000_inblk_16bit; break; case 4: default: db->dumpblk = dm9000_dumpblk_32bit; db->outblk = dm9000_outblk_32bit; db->inblk = dm9000_inblk_32bit; break; }}/* Our watchdog timed out. Called by the networking layer */static void dm9000_timeout(struct net_device *dev){ board_info_t *db = (board_info_t *) dev->priv; u8 reg_save; unsigned long flags; /* Save previous register address */ reg_save = readb(db->io_addr); spin_lock_irqsave(&db->lock,flags); netif_stop_queue(dev); dm9000_reset(db); dm9000_init_dm9000(dev); /* We can accept TX packets again */ dev->trans_start = jiffies; netif_wake_queue(dev); /* Restore previous register address */ writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock,flags);}/* dm9000_release_board * * release a board, and any mapped resources */static voiddm9000_release_board(struct platform_device *pdev, struct board_info *db){ if (db->data_res == NULL) { if (db->addr_res != NULL) release_mem_region((unsigned long)db->io_addr, 4); return; } /* unmap our resources */ iounmap(db->io_addr); iounmap(db->io_data); /* release the resources */ if (db->data_req != NULL) { release_resource(db->data_req); kfree(db->data_req); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -