dm9000.c
来自「《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序」· C语言 代码 · 共 1,308 行 · 第 1/3 页
C
1,308 行
/** 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* 25-MAY-2007 Feng Guojin<fgjnew@163.com>* *port to s3c2410 board*/#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 <asm/delay.h>#include <asm/irq.h>#include <asm/io.h>#include "dm9000.h"#include "dm.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/** 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 *io_addr; /* Register I/O base address */ void *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 *port, void *data, int length); void (*outblk)(void *port, void *data, int length); void (*dumpblk)(void *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 irq, void *dev_id, struct pt_regs *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 *);//#define DM9000_PROGRAM_EEPROM#ifdef DM9000_PROGRAM_EEPROMstatic void program_eeprom(board_info_t * db);#endif/* DM9000 network board routine ---------------------------- */static void *bwscon;static void *gpfcon;static void *extint0;static void *intmsk;#define BWSCON (0x48000000)#define GPFCON (0x56000060)#define EXTINT0 (0x5600008C)#define INTMSK (0x4A000008)void initGPIO(void);void initGPIO(){ bwscon=ioremap_nocache(BWSCON,0x0000004); gpfcon=ioremap_nocache(GPFCON,0x0000004); extint0=ioremap_nocache(EXTINT0,0x0000004); intmsk=ioremap_nocache(INTMSK,0x0000004); writel(readl(bwscon)|0xc0000,bwscon); writel(readl(gpfcon)|0x2000,gpfcon); writel(readl(gpfcon)&0xffffefff,gpfcon); writel(readl(extint0)|0x1000000,extint0); writel(readl(extint0)&0xf9ffffff,extint0); writel(readl(intmsk)&0xffffffdf,intmsk);}static struct net_device *ndev= NULL;static void dm9000_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); 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 *reg, void *data, int count){ writesb(reg, data, count);}static void dm9000_outblk_16bit(void *reg, void *data, int count){ writesw(reg, data, (count+1) >> 1);}static void dm9000_outblk_32bit(void *reg, void *data, int count){ writesl(reg, data, (count+3) >> 2);}/* input block from chip to memory */static void dm9000_inblk_8bit(void *reg, void *data, int count){ readsb(reg, data, count);}static void dm9000_inblk_16bit(void *reg, void *data, int count){ readsw(reg, data, (count+1) >> 1);}static void dm9000_inblk_32bit(void *reg, void *data, int count){ readsl(reg, data, (count+3) >> 2);}/* dump block from chip to null */static void dm9000_dumpblk_8bit(void *reg, int count){ int i; int tmp; for (i = 0; i < count; i++) tmp = readb(reg);}static void dm9000_dumpblk_16bit(void *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 *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);}#ifdef CONFIG_NET_POLL_CONTROLLER/**Used by netconsole*/static void dm9000_poll_controller(struct net_device *dev){ disable_irq(dev->irq); dm9000_interrupt(dev->irq,dev); enable_irq(dev->irq);}#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*///static int dm9000_probe(struct platform_device *pdev)static int dm9000_probe(struct device *dev){ struct platform_device *pdev = to_platform_device(dev); struct dm9000_plat_data *pdata = pdev->dev.platform_data; struct board_info *db; /* Point a board information structure */ unsigned long base; int ret = 0; int iosize; int i; u32 id_val; initGPIO(); /* Init network device */ ndev = alloc_etherdev(sizeof (struct board_info)); if (!ndev) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?