📄 dm9000x.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 <saschahauer@web.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 */#if defined(MODVERSIONS)#include <linux/modversions.h>#endif#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 <asm/delay.h>#include <asm/irq.h>#include <asm/io.h>#include "dm9000x.h"#include <asm-arm/arch/irqs.h>#include <asm-arm/arch/hardware.h>#include <asm-arm/arch/regs-gpio.h> /* Board/System/Debug information/definition ---------------- */static void *bwscon;static void *gpfcon;static void *extint0;static void *intmsk;#define BWSCON (0x48000000)#define GPFCON (0x56000050)#define EXTINT0 (0x56000088)#define INTMSK (0x4A000008)#define DM9000_REG00 0x00#define DM9000_REG05 0x30 /* SKIP_CRC/SKIP_LONG */#define DM9000_REG08 0x27#define DM9000_REG09 0x38#define DM9000_REG0A 0xff#define DM9000_REGFF 0x83 /* IMR */#define DM9000_PHY 0x40 /* PHY address 0x01 */#define TRUE 1#define FALSE 0#define CARDNAME "dm9000"#define PFX CARDNAME ": "#define DMFE_TIMER_WUT jiffies+(HZ*2) /* timer wakeup time : 2 second */#define DMFE_TX_TIMEOUT (HZ*2) /* tx packet time-out time 1.5 s" */#define DMFE_DEBUG 0#if DMFE_DEBUG > 2#define PRINTK3(args...) printk(CARDNAME ": " args)#else#define PRINTK3(args...) do { } while(0)#endif#if DMFE_DEBUG > 1#define PRINTK2(args...) printk(CARDNAME ": " args)#else#define PRINTK2(args...) do { } while(0)#endif#if DMFE_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)#endifenum DM9000_PHY_mode { DM9000_10MHD = 0, DM9000_100MHD = 1, DM9000_10MFD = 4, DM9000_100MFD = 5, DM9000_AUTO = 8, DM9000_1M_HPNA = 0x10};/* Structure/enum declaration ------------------------------- */typedef struct board_info { u32 runt_length_counter; /* counter: RX length < 64byte */ u32 long_length_counter; /* counter: RX length > 1514byte */ u32 reset_counter; /* counter: RESET */ u32 reset_tx_timeout; /* RESET caused by TX Timeout */ u32 reset_rx_status; /* RESET caused by RX Statsus wrong */ 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 reg0, reg5, reg8, reg9, rega; /* registers saved */ u8 op_mode; /* PHY operation mode */ u8 io_mode; /* 0:word, 2:byte */ u8 phy_addr; u8 device_wait_reset; /* device state */ 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;/* Global variable declaration ----------------------------- */static int dmfe_debug = 0;/* For module input parameter */static int debug = 0;static int mode = DM9000_AUTO;static int media_mode = DM9000_AUTO;static u8 reg5 = DM9000_REG05;static u8 reg8 = DM9000_REG08;static u8 reg9 = DM9000_REG09;static u8 rega = DM9000_REG0A;static u8 nfloor = 0;#ifdef CONFIG_MX1_SCB9328#include <asm/arch/hardware.h>#include <asm/arch/irqs.h>#include <asm/arch/scb9328.h>#elsestatic u8 irqline = 3;#endif/* function declaration ------------------------------------- */static int dmfe_probe(struct device *);static int dmfe_open(struct net_device *);static int dmfe_start_xmit(struct sk_buff *, struct net_device *);static int dmfe_stop(struct net_device *);static int dmfe_do_ioctl(struct net_device *, struct ifreq *, int);static void dmfe_timer(unsigned long);static void dmfe_init_dm9000(struct net_device *);static struct net_device_stats *dmfe_get_stats(struct net_device *);static irqreturn_t dmfe_interrupt(int, void *, struct pt_regs *);static int dmfe_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);static void dmfe_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value);static u16 read_srom_word(board_info_t *, int);static void dmfe_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 voiddmfe_reset(board_info_t * db){ PRINTK1("dm9000x: resetting\n"); /* RESET device */ writeb(DMFE_NCR, db->io_addr); udelay(200); /* delay 100us */ writeb(NCR_RST, db->io_data); udelay(200); /* delay 100us */}/* * 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+1);}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);}/* dmfe_set_io * * select the specified set of io routines to use with the * device*/static void dmfe_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; }}/* dmfe_release_board * * release a board, and any mapped resources*/static voiddmfe_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_res != NULL) { release_resource(db->data_req); kfree(db->addr_req); }}#define res_size(_r) (((_r)->end - (_r)->start) + 1)/* Search DM9000 board, allocate space and register it*/static intdmfe_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 */ struct net_device *ndev; unsigned long base; int ret = 0; int iosize; int i; u32 id_val; unsigned char ne_def_eth_mac_addr[]={0x00,0x12,0x34,0x56,0x80,0x49}; 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) & ~(0x3 << 14)) | (0x2 << 14), gpfcon); writel( readl(gpfcon) | (0x1 << 7), gpfcon); // Disable pull-up writel( (readl(extint0) & ~(0xf << 28)) | (0x4 << 28), extint0); //rising edge writel( (readl(intmsk)) & ~0x80, intmsk); printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME); /* Init network device */ ndev = alloc_etherdev(sizeof (struct board_info)); if (!ndev) { printk("%s: could not allocate device.\n", CARDNAME); return -ENOMEM; } SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, dev); PRINTK2("dmfe_probe()"); /* setup board info structure */ db = (struct board_info *) ndev->priv; memset(db, 0, sizeof (*db)); if (pdev->num_resources < 2) { ret = -ENODEV; goto out; } switch (pdev->num_resources) { case 2: base = pdev->resource[0].start; if (!request_mem_region(base, 4, ndev->name)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -