📄 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/spinlock.h>#include <linux/crc32.h>#include <linux/mii.h>#include <linux/dm9000.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <asm/delay.h>#include <asm/irq.h>#include <asm/io.h>#include "dm9000.h"/* Board/System/Debug information/definition ---------------- */#define DM9000_PHY 0x40 /* PHY address 0x01 */#define TRUE 1#define FALSE 0#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#ifdef CONFIG_BLACKFIN#define readsb insb#define readsw insw#define readsl insl#define writesb outsb#define writesw outsw#define writesl outsl//#define DM9000_IRQ_FLAGS (IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_LOW)#define DM9000_IRQ_FLAGS (IRQF_SHARED | IRQF_TRIGGER_LOW)#else#define DM9000_IRQ_FLAGS IRQF_SHARED#endif/* * Transmit timeout, default 5 seconds. */static int watchdog = 5000;module_param(watchdog, int, 0400);MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");/* 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 io_mode; /* 0:word, 2:byte */ 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 platform_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 *);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 *);//#define DM9000_PROGRAM_EEPROM#ifdef DM9000_PROGRAM_EEPROMstatic void program_eeprom(board_info_t * db);#endif/* DM9000 network board routine ---------------------------- */static 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);}/* * Read a byte from I/O port */static u8ior(board_info_t * db, int reg){ writeb(reg, db->io_addr); asm("ssync;"); 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); asm("ssync;"); writeb(value, db->io_data); asm("ssync;");}/* routines for sending block to chip */static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count){ writesb(reg, data, count); asm("ssync;");}static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count){// writesw(reg, data, (count+1) >> 1); int i;// int tmp; count = (count + 1) >> 1; printk("outblk_16bit\n"); for (i = 0; i < count; i++) { writew(((u16*)data)[i], reg); asm("ssync;"); asm("ssync;"); }}static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count){ writesl(reg, data, (count+3) >> 2); asm("ssync;");}/* input block from chip to memory */static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count){ readsb(reg, data, count); asm("ssync;");}static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count){ readsw(reg, data, (count+1) >> 1);/* int i;// int tmp; count = (count + 1) >> 1; printk("inblk_16bit\n"); for (i = 0; i < count; i++) { ((u16*)data)[i] = readw(reg); asm("ssync;"); asm("ssync;"); }*/}static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count){ readsl(reg, data, (count+3) >> 2); asm("ssync;");}/* 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); asm("ssync;"); }}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); asm("ssync;"); 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); asm("ssync;"); spin_unlock_irqrestore(&db->lock,flags);}#ifdef CONFIG_NET_POLL_CONTROLLER/* *Used by netconsole */static void dm9000_poll_controller(struct net_device *dev){ printk("into poll_controller\n"); disable_irq(dev->irq); dm9000_interrupt(dev->irq,dev); enable_irq(dev->irq); printk("out of poll_controller\n");}#endif/* 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); } if (db->addr_req != NULL) { release_resource(db->addr_req); kfree(db->addr_req); }}#define res_size(_r) (((_r)->end - (_r)->start) + 1)/* * Search DM9000 board, allocate space and register it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -