linuxDM900网卡设备驱动

 

#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"

 

#define DM9000_PHY 0x40

#define CARDNAME "dm9000"

#define PFX CARDNAME ": "

#define DM9000_TIMER_WUT jiffies+(HZ*2)

#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

 

static int watchdog = 5000;

module_param(watchdog, int, 0400);

MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");

 

 

typedef struct board_info {

 

void __iomem *io_addr;

 

void __iomem *io_data;

u16 irq;

u16 tx_pkt_cnt;

u16 queue_pkt_len;

u16 queue_start_addr;

u16 dbug_cnt;

u8 io_mode;


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;

struct resource *data_res;

struct resource *addr_req;

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;

 

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_EEPROM

static void program_eeprom(board_info_t * db);

#endif

 

static void

dm9000_reset(board_info_t * db)

{

PRINTK1("dm9000x: resetting\n");

 

 

writeb(DM9000_NCR, db->io_addr);

udelay(200);

 

writeb(NCR_RST, db->io_data);

udelay(200);

}

 


 

static u8

ior(board_info_t * db, int reg)

{

writeb(reg, db->io_addr);

return readb(db->io_data);

}

 

static void

iow(board_info_t * db, int reg, int value)

{

writeb(reg, db->io_addr);

writeb(value, db->io_data);

}

 

 

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);

}

 

 

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);

}

 

 

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);

}

 

static void dm9000_set_io(struct board_info *db, int byte_width)

{

 

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;

}

}

 

 

static void dm9000_timeout(struct net_device *dev)

{

board_info_t *db = (board_info_t *) dev->priv;

u8 reg_save;

unsigned long flags;

 

reg_save = readb(db->io_addr);

spin_lock_irqsave(&db->lock,flags);

 

netif_stop_queue(dev);

 

dm9000_reset(db);

 

dm9000_init_dm9000(dev);

 

 

dev->trans_start = jiffies;

netif_wake_queue(dev);

 

 

writeb(reg_save, db->io_addr);

spin_unlock_irqrestore(&db->lock,flags);

}

#ifdef CONFIG_NET_POLL_CONTROLLER

 

static void dm9000_poll_controller(struct net_device *dev)

{

disable_irq(dev->irq);

dm9000_interrupt(dev->irq,dev);

enable_irq(dev->irq);

}

#endif

 

static void

dm9000_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;

}

 


iounmap(db->io_addr);

iounmap(db->io_data);

 

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)

 

static int

dm9000_probe(struct platform_device *pdev)

{

struct dm9000_plat_data *pdata = pdev->dev.platform_data;

struct board_info *db;

struct net_device *ndev;

unsigned long base;

int ret = 0;

int iosize;

int i;

u32 id_val;

 

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, &pdev->dev);

PRINTK2("dm9000_probe()");

 

db = (struct board_info *) ndev->priv;

memset(db, 0, sizeof (*db));

 

spin_lock_init(&db->lock);

 

if (pdev->num_resources < 2) {

 ret = -ENODEV;

 goto out;

} else if (pdev->num_resources == 2) {

 base = pdev->resource[0].start;

 if (!request_mem_region(base, 4, ndev->name)) {

 ret = -EBUSY;

 goto out;

 }

 ndev->base_addr = base;

 ndev->irq = pdev->resource[1].start;

 db->io_addr = (void __iomem *)base;


 db->io_data = (void __iomem *)(base + 4);

} else {

 db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

 db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);

 db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

 if (db->addr_res == NULL || db->data_res == NULL ||

 db->irq_res == NULL) {

 printk(KERN_ERR PFX "insufficient resources\n");

 ret = -ENOENT;

 goto out;

 }

 i = res_size(db->addr_res);

 db->addr_req = request_mem_region(db->addr_res->start, i,

 pdev->name);

 if (db->addr_req == NULL) {

 printk(KERN_ERR PFX "cannot claim address reg area\n");

 ret = -EIO;

 goto out;

 }

 db->io_addr = ioremap(db->addr_res->start, i);

 if (db->io_addr == NULL) {

 printk(KERN_ERR "failed to ioremap address reg\n");

 ret = -EINVAL;

 goto out;

 }

 iosize = res_size(db->data_res);

 db->data_req = request_mem_region(db->data_res->start, iosize,

 pdev->name);

 if (db->data_req == NULL) {

 printk(KERN_ERR PFX "cannot claim data reg area\n");

 ret = -EIO;

 goto out;

 }

 db->io_data = ioremap(db->data_res->start, iosize);

 if (db->io_data == NULL) {

 printk(KERN_ERR "failed to ioremap data reg\n");

 ret = -EINVAL;

 goto out;

 }

 

 ndev->base_addr = (unsigned long)db->io_addr;

 ndev->irq = db->irq_res->start;

 

 dm9000_set_io(db, iosize);

}

 

if (pdata != NULL) {

 

 if (pdata->flags & DM9000_PLATF_8BITONLY)

 dm9000_set_io(db, 1);

 if (pdata->flags & DM9000_PLATF_16BITONLY)

 dm9000_set_io(db, 2);

 if (pdata->flags & DM9000_PLATF_32BITONLY)

 dm9000_set_io(db, 4);

 


 if (pdata->inblk != NULL)

 db->inblk = pdata->inblk;

 if (pdata->outblk != NULL)

 db->outblk = pdata->outblk;

 if (pdata->dumpblk != NULL)

 db->dumpblk = pdata->dumpblk;

}

 

dm9000_reset(db);

 

for (i = 0; i < 2; i++) {

 id_val = ior(db, DM9000_VIDL);

 id_val |= (u32)ior(db, DM9000_VIDH) << 8;

 id_val |= (u32)ior(db, DM9000_PIDL) << 16;

 id_val |= (u32)ior(db, DM9000_PIDH) << 24;

 if (id_val == DM9000_ID)

 break;

 printk("%s: read wrong id 0xx\n", CARDNAME, id_val);

}

 

if (id_val != DM9000_ID) {

 printk("%s: wrong id: 0xx\n", CARDNAME, id_val);

 goto release;

}

 

 

ether_setup(ndev);

ndev->open = &dm9000_open;

ndev->hard_start_xmit = &dm9000_start_xmit;

ndev->tx_timeout = &dm9000_timeout;

ndev->watchdog_timeo = msecs_to_jiffies(watchdog);

ndev->stop = &dm9000_stop;

ndev->get_stats = &dm9000_get_stats;

ndev->set_multicast_list = &dm9000_hash_table;

#ifdef CONFIG_NET_POLL_CONTROLLER

ndev->poll_controller = &dm9000_poll_controller;

#endif

#ifdef DM9000_PROGRAM_EEPROM

 

program_eeprom(db);

#endif

 

db->msg_enable = NETIF_MSG_LINK;

db->mii.phy_id_mask = 0x1f;

db->mii.reg_num_mask = 0x1f;

db->mii.force_media = 0;

db->mii.full_duplex = 0;

db->mii.dev = ndev;

db->mii.mdio_read = dm9000_phy_read;

db->mii.mdio_write = dm9000_phy_write;

 

for (i = 0; i < 64; i++)

 

 ((u16 *) db->srom)[i] = read_srom_word(db, i);


for (i = 0; i < 6; i++)

 ndev->dev_addr[i] = db->srom[i];

 

if (!is_valid_ether_addr(ndev->dev_addr)) {

 

 

 for (i = 0; i < 6; i++)

 ndev->dev_addr[i] = ior(db, i+DM9000_PAR);

}

 

if (!is_valid_ether_addr(ndev->dev_addr))

 printk("%s: Invalid ethernet MAC address. Please "

 "set using ifconfig\n", ndev->name);

platform_set_drvdata(pdev, ndev);

 

ret = register_netdev(ndev);

if (ret == 0) {

 printk("%s: dm9000 at %p,%p IRQ %d MAC: ",

 ndev->name, db->io_addr, db->io_data, ndev->irq);

 for (i = 0; i < 5; i++)

 printk("x:", ndev->dev_addr[i]);

 printk("x\n", ndev->dev_addr[5]);

}

return 0;

release:

out:

printk("%s: not found (%d).\n", CARDNAME, ret);

/失败时,释放资源*/

dm9000_release_board(pdev, db);

free_netdev(ndev);

return ret;

}

 

static int

dm9000_open(struct net_device *dev)

{

board_info_t *db = (board_info_t *) dev->priv;

PRINTK2("entering dm9000_open\n");

 

if (request_irq(dev->irq, &dm9000_interrupt, IRQF_SHARED, dev->name, dev))

 return -EAGAIN;

 

 

dm9000_reset(db);

 

dm9000_init_dm9000(dev);

 

db->dbug_cnt = 0;


init_timer(&db->timer);

db->timer.expires = DM9000_TIMER_WUT;

db->timer.data = (unsigned long) dev;

db->timer.function = &dm9000_timer;

add_timer(&db->timer);

 

mii_check_media(&db->mii, netif_msg_link(db), 1);

 

netif_start_queue(dev);

return 0;

}

 

 

 

static void

dm9000_init_dm9000(struct net_device *dev)

{

board_info_t *db = (board_info_t *) dev->priv;

PRINTK1("entering %s\n",__FUNCTION__);

 

db->io_mode = ior(db, DM9000_ISR) >> 6;

 

iow(db, DM9000_GPR, 0);

iow(db, DM9000_GPCR, GPCR_GEP_CNTL);

iow(db, DM9000_GPR, 0);

 

 

iow(db, DM9000_TCR, 0);

iow(db, DM9000_BPTR, 0x3f);

iow(db, DM9000_FCR, 0xff);

iow(db, DM9000_SMCR, 0);

 

 

iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);

 

iow(db, DM9000_ISR, ISR_CLR_STATUS);

 

dm9000_hash_table(dev);

 

iow(db, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);

 

iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);

 

db->tx_pkt_cnt = 0;

db->queue_pkt_len = 0;


dev->trans_start = 0;

}

 

static int

dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)

{

board_info_t *db = (board_info_t *) dev->priv;

PRINTK3("dm9000_start_xmit\n");

if (db->tx_pkt_cnt > 1)

 return 1;

 

netif_stop_queue(dev);

 

iow(db, DM9000_IMR, IMR_PAR);

 

writeb(DM9000_MWCMD, db->io_addr);

 

(db->outblk)(db->io_data, skb->data, skb->len);

 

db->stats.tx_bytes += skb->len;

 

if (db->tx_pkt_cnt == 0) {

 

 db->tx_pkt_cnt++;

 

 iow(db, DM9000_TXPLL, skb->len & 0xff);

 iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);

 

 iow(db, DM9000_TCR, TCR_TXREQ);

 

 dev->trans_start = jiffies;

} else {

 

 

 db->tx_pkt_cnt++;

 db->queue_pkt_len = skb->len;

}

 

dev_kfree_skb(skb);

 

if (db->tx_pkt_cnt == 1)

 netif_wake_queue(dev);

 

iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);


return 0;

}

static void

dm9000_shutdown(struct net_device *dev)

{

board_info_t *db = (board_info_t *) dev->priv;

 

dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);

 

iow(db, DM9000_GPR, 0x01);

 

iow(db, DM9000_IMR, IMR_PAR);

 

iow(db, DM9000_RCR, 0x00);

}

 

static int

dm9000_stop(struct net_device *ndev)

{

board_info_t *db = (board_info_t *) ndev->priv;

PRINTK1("entering %s\n",__FUNCTION__);

 

del_timer(&db->timer);

 

netif_stop_queue(ndev);

 

netif_carrier_off(ndev);

 

free_irq(ndev->irq, ndev);

 

dm9000_shutdown(ndev);

return 0;

}

 

static void

dm9000_tx_done(struct net_device *dev, board_info_t * db)

{

int tx_status = ior(db, DM9000_NSR);

 

if (tx_status & (NSR_TX2END | NSR_TX1END)) {

 

 db->tx_pkt_cnt--;

 db->stats.tx_packets++;

 

 if (db->tx_pkt_cnt > 0) {

 


 iow(db, DM9000_TXPLL, db->queue_pkt_len & 0xff);

 iow(db, DM9000_TXPLH, (db->queue_pkt_len >> 8) & 0xff);

 

 iow(db, DM9000_TCR, TCR_TXREQ);

 dev->trans_start = jiffies;

 }

 

 netif_wake_queue(dev);

}

}

static irqreturn_t

dm9000_interrupt(int irq, void *dev_id)

{

struct net_device *dev = dev_id;

board_info_t *db;

int int_status;

u8 reg_save;

PRINTK3("entering %s\n",__FUNCTION__);

if (!dev) {

 PRINTK1("dm9000_interrupt() without DEVICE arg\n");

 return IRQ_HANDLED;

}

 

db = (board_info_t *) dev->priv;

spin_lock(&db->lock);

 

 

reg_save = readb(db->io_addr);

 

iow(db, DM9000_IMR, IMR_PAR);

 

int_status = ior(db, DM9000_ISR);

iow(db, DM9000_ISR, int_status);

 

if (int_status & ISR_PRS)

 dm9000_rx(dev);

 

if (int_status & ISR_PTS)

 dm9000_tx_done(dev, db);

 

iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);

 

writeb(reg_save, db->io_addr);

spin_unlock(&db->lock);

return IRQ_HANDLED;

}

 

static struct net_device_stats *

dm9000_get_stats(struct net_device *dev)

{


board_info_t *db = (board_info_t *) dev->priv;

return &db->stats;

}

 

 

static void

dm9000_timer(unsigned long data)

{

struct net_device *dev = (struct net_device *) data;

board_info_t *db = (board_info_t *) dev->priv;

PRINTK3("dm9000_timer()\n");

 

mii_check_media(&db->mii, netif_msg_link(db), 0);

 

db->timer.expires = DM9000_TIMER_WUT;

add_timer(&db->timer);

}

 

struct dm9000_rxhdr {

u16 RxStatus;

u16 RxLen;

} __attribute__((__packed__));

 

static void

dm9000_rx(struct net_device *dev)

{

board_info_t *db = (board_info_t *) dev->priv;

struct dm9000_rxhdr rxhdr;

struct sk_buff *skb;

u8 rxbyte, *rdptr;

bool GoodPacket;

int RxLen;

 

do {

 ior(db, DM9000_MRCMDX);

 

 rxbyte = readb(db->io_data);

 

 if (rxbyte > DM9000_PKT_RDY) {

 printk("status check failed: %d\n", rxbyte);

 iow(db, DM9000_RCR, 0x00);

 iow(db, DM9000_ISR, IMR_PAR);

 return;

 }

 if (rxbyte != DM9000_PKT_RDY)

 return;

 

 GoodPacket = true;


 writeb(DM9000_MRCMD, db->io_addr);

 

 (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));

 

 RxLen = rxhdr.RxLen;

 

 if (RxLen < 0x40) {

 GoodPacket = false;

 PRINTK1("Bad Packet received (runt)\n");

 }

 

 if (RxLen > DM9000_PKT_MAX) {

 PRINTK1("RST: RX Len:%x\n", RxLen);

 }

 

 if (rxhdr.RxStatus & 0xbf00) {

 GoodPacket = false;

 if (rxhdr.RxStatus & 0x100) {

 PRINTK1("fifo error\n");

 db->stats.rx_fifo_errors++;

 }

 if (rxhdr.RxStatus & 0x200) {

 PRINTK1("crc error\n");

 db->stats.rx_crc_errors++;

 }

 if (rxhdr.RxStatus & 0x8000) {

 PRINTK1("length error\n");

 db->stats.rx_length_errors++;

 }

 }

 

 if (GoodPacket

 && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {

 

 skb_reserve(skb, 2);

 rdptr = (u8 *) skb_put(skb, RxLen - 4);

 

 

 (db->inblk)(db->io_data, rdptr, RxLen);

 

 db->stats.rx_bytes += RxLen;

 

 skb->protocol = eth_type_trans(skb, dev);

 

 netif_rx(skb);

 

 db->stats.rx_packets++;

 } else {

 

 (db->dumpblk)(db->io_data, RxLen);

 }

} while (rxbyte == DM9000_PKT_RDY);

}


static u16

read_srom_word(board_info_t * db, int offset)

{

iow(db, DM9000_EPAR, offset);

iow(db, DM9000_EPCR, EPCR_ERPRR);

mdelay(8);

iow(db, DM9000_EPCR, 0x0);

return (ior(db, DM9000_EPDRL) + (ior(db, DM9000_EPDRH) << 8));

}

#ifdef DM9000_PROGRAM_EEPROM

 

static void

write_srom_word(board_info_t * db, int offset, u16 val)

{

iow(db, DM9000_EPAR, offset);

iow(db, DM9000_EPDRH, ((val >> 8) & 0xff));

iow(db, DM9000_EPDRL, (val & 0xff));

iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);

mdelay(8);

iow(db, DM9000_EPCR, 0);

}

 

static void

program_eeprom(board_info_t * db)

{

u16 eeprom[] = { 0x0c00, 0x007f, 0x1300,

 0x0000,

 0x0a46, 0x9000,

 0x0000,

 0x0000,

};

int i;

for (i = 0; i < 8; i++)

 write_srom_word(db, i, eeprom[i]);

}

#endif

 

 

static unsigned long


cal_CRC(unsigned char *Data, unsigned int Len, u8 flag)

{

 u32 crc = ether_crc_le(Len, Data);

 if (flag)

 return ~crc;

 return crc;

}

 

static void

dm9000_hash_table(struct net_device *dev)

{

board_info_t *db = (board_info_t *) dev->priv;

struct dev_mc_list *mcptr = dev->mc_list;

int mc_cnt = dev->mc_count;

u32 hash_val;

u16 i, oft, hash_table[4];

unsigned long flags;

PRINTK2("dm9000_hash_table()\n");

spin_lock_irqsave(&db->lock,flags);

for (i = 0, oft = 0x10; i < 6; i++, oft++)

 iow(db, oft, dev->dev_addr[i]);

 

for (i = 0; i < 4; i++)

 hash_table[i] = 0x0;

 

hash_table[3] = 0x8000;

 

for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {

 hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;

 hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);

}

 

for (i = 0, oft = 0x16; i < 4; i++) {

 iow(db, oft++, hash_table[i] & 0xff);

 iow(db, oft++, (hash_table[i] >> 8) & 0xff);

}

spin_unlock_irqrestore(&db->lock,flags);

}

 

 

static int

dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)

{

board_info_t *db = (board_info_t *) dev->priv;

unsigned long flags;

unsigned int reg_save;

int ret;

spin_lock_irqsave(&db->lock,flags);

 

reg_save = readb(db->io_addr);

 

iow(db, DM9000_EPAR, DM9000_PHY | reg);


iow(db, DM9000_EPCR, 0xc);

udelay(100);

iow(db, DM9000_EPCR, 0x0);

 

ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);

 

writeb(reg_save, db->io_addr);

spin_unlock_irqrestore(&db->lock,flags);

return ret;

}

 

static void

dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int
value)

{

board_info_t *db = (board_info_t *) dev->priv;

unsigned long flags;

unsigned long reg_save;

spin_lock_irqsave(&db->lock,flags);

 

reg_save = readb(db->io_addr);

 

iow(db, DM9000_EPAR, DM9000_PHY | reg);

 

iow(db, DM9000_EPDRL, (value & 0xff));

iow(db, DM9000_EPDRH, ((value >> 8) & 0xff));

iow(db, DM9000_EPCR, 0xa);

udelay(500);

iow(db, DM9000_EPCR, 0x0);

 

writeb(reg_save, db->io_addr);

spin_unlock_irqrestore(&db->lock,flags);

}

 

static int

dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)

{

struct net_device *ndev = platform_get_drvdata(dev);

if (ndev) {

 if (netif_running(ndev)) {

 

 netif_device_detach(ndev);

 

 dm9000_shutdown(ndev);

 }

}

return 0;

}

static int

dm9000_drv_resume(struct platform_device *dev)

{

struct net_device *ndev = platform_get_drvdata(dev);

board_info_t *db = (board_info_t *) ndev->priv;


if (ndev) {

 if (netif_running(ndev)) {

 

 dm9000_reset(db);

 dm9000_init_dm9000(ndev);

 

 netif_device_attach(ndev);

 }

}

return 0;

}

static int

dm9000_drv_remove(struct platform_device *pdev)

{

struct net_device *ndev = platform_get_drvdata(pdev);

platform_set_drvdata(pdev, NULL);

 

unregister_netdev(ndev);

dm9000_release_board(pdev, (board_info_t *) ndev->priv);

 

free_netdev(ndev);

PRINTK1("clean_module() exit\n");

return 0;

}

static struct platform_driver dm9000_driver = {

.driver = {

 .name = "dm9000",

 .owner = THIS_MODULE,

},

.probe = dm9000_probe,

.remove = dm9000_drv_remove,

.suspend = dm9000_drv_suspend,

.resume = dm9000_drv_resume,

};

static int __init

dm9000_init(void)

{

printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);

return platform_driver_register(&dm9000_driver);

}

static void __exit

dm9000_cleanup(void)

{

platform_driver_unregister(&dm9000_driver);

}

module_init(dm9000_init);

module_exit(dm9000_cleanup);

MODULE_AUTHOR("Sascha Hauer, Ben Dooks");

MODULE_DESCRIPTION("Davicom DM9000 network driver");

MODULE_LICENSE("GPL");

你可能感兴趣的:(timer,struct,Module,table,null,resources)