DM9000驱动解析 收藏.doc_第1页
DM9000驱动解析 收藏.doc_第2页
DM9000驱动解析 收藏.doc_第3页
DM9000驱动解析 收藏.doc_第4页
DM9000驱动解析 收藏.doc_第5页
已阅读5页,还剩26页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

DM9000驱动解析1 收藏 /* 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 :* Fixed phy reset.* Added tx/rx 32 bit mode.* Cleaned up for kernel merge.* 03/03/2004 Sascha Hauer * Port to 2.6 kernel* 24-Sep-2004 Ben Dooks * Cleanup of code to remove ifdefs* Allowed platform device data to influence access width* Reformatting areas of code* 17-Mar-2005 Sascha Hauer * * 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 * * fixed spinlock call without pointer* * ensure spinlock is initialised*/i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude i nclude dm9000.h/* Board/System/Debug information/definition - */#define DM9000_PHY 0x40 /* PHY address 0x01 */#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);/*DM9000 含有16K SRAM作为FIFO buffer,3K用于transmitt,13k用于receive*/* 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 srom128; /*网卡上EERPOM的内容*/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: resettingn);/* RESET device */*指定DM9000当前的命令寄存器是NCR*/writeb(DM9000_NCR, db-io_addr);udelay(200);/*向NCR寄存器写入复位标志,芯片复位*/writeb(NCR_RST, db-io_data);udelay(200);/* Read a byte from I/O port 读取寄存器的值,reg表明寄存器的偏移量 这里用宏名表示*/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 写寄存器的值,reg表明寄存器的偏移量 这里用宏名表示,value是写入数据*/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 */*类似于内存拷贝简单的理解为memcpy(reg,data,count)count是以字节为单位的!*/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 */*类似于内存拷贝简单的理解为memcpy(data,reg,count)count是以字节为单位的!*/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 */*类似于内存清理,将reg指向的count清空。多用于设备的接收缓存区清空count是以字节为单位的!*/static void dm9000_dumpblk_8bit(void _iomem *reg, int count)int i;int tmp;for (i = 0; i 1;for (i = 0; i 2;for (i = 0; i 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 16bitn); 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芯片*/dm9000_reset(db);/*初始化DM9000芯片*/dm9000_init_dm9000(dev);/* We can accept TX packets again */*重启发送*/dev-trans_start = jiffies;netif_wake_queue(dev);/* Restore previous register address */*io_addr的恢复,保证了芯片的配置和初始值一致*/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 intdm9000_probe(struct platform_device *pdev)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;/* 分配eth网卡资源,私有数据区保存board_info*/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();/* setup board info structure bord info初始化为0 */db = (struct board_info *) ndev-priv;memset(db, 0, sizeof (*db);/*初始化spinlock*/spin_lock_init(&db-lock);/*忽略*/if (pdev-num_resources num_resources = 2) base = pdev-resource0.start; if (!request_mem_region(base, 4, ndev-name) ret = -EBUSY; goto out; ndev-base_addr = base; ndev-irq = pdev-resource1.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 resourcesn); 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 arean); 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 regn); 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 arean); 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 regn); ret = -EINVAL; goto out; /* fill in parameters for net-dev structure */ ndev-base_addr = (unsigned long)db-io_addr; ndev-irq = db-irq_res-start; /* ensure at least we have a default set of IO routines */ dm9000_set_io(db, iosize);/* check to see if anything is being over-ridden */if (pdata != NULL) /* check to see if the driver wants to over-ride the * default IO width */ 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); /* check to see if there are any IO routine * over-rides */ if (pdata-inblk != NULL) db-inblk = pdata-inblk; if (pdata-outblk != NULL) db-outblk = pdata-outblk; if (pdata-dumpblk != NULL) db-dumpblk = pdata-dumpblk;/*根据board info信息,复位DM9000芯片*/dm9000_reset(db);/* try two times, DM9000 sometimes gets the first read wrong */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) 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_CONTROLLERndev-poll_controller = &dm9000_poll_controller;#endif#ifdef DM9000_PROGRAM_EEPROM/*开发时,需要更新EERPOM的值*/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; /*DM9000可以提供MII,外接PHY*/db-mii.mdio_write = dm9000_phy_write;/* 获取网卡上EEPROM9346的内容,走EERPOM接口 */for (i = 0; i srom)i = read_srom_word(db, i);/* Set Node Address EEPROM的前6个字节为MAC地址*/for (i = 0; i dev_addri = db-sromi;/*验证获取的MAC地址是否合法*/if (!is_valid_ether_addr(ndev-dev_addr) /* try reading from mac */ /*不合法,重新从DM9000的内部寄存器获取MAC,不走EEPROM接口*/ for (i = 0; i dev_addri = ior(db, i+DM9000_PAR);/*两种方式都失败,提示用ifconfig,驱动没有对应接口!*/if (!is_valid_ether_addr(ndev-dev_addr) printk(%s: Invalid ethernet MAC address. Please set using ifconfign, ndev-name);platform_set_drvdata(pdev, ndev);/*注册接口到系统中,状态默认down,不可用*/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 dev_addri); printk(%02xn, ndev-dev_addr5);return 0;release:out:printk(%s: not found (%d).n, CARDNAME, ret);/失败时,释放资源*/dm9000_release_board(pdev, db);free_netdev(ndev);return ret;/* Open the interface.* The interface is opened whenever ifconfig actives it. 当使用ifconfig激活该网络接口时调用*/static intdm9000_open(struct net_device *dev)board_info_t *db = (board_info_t *) dev-priv;PRINTK2(entering dm9000_openn);/*申请中断资源,注册中断函数*/if (request_irq(dev-irq, &dm9000_interrupt, IRQF_SHARED, dev-name, dev) return -EAGAIN;/* Initialize DM9000 board */*复位DM9000芯片*/dm9000_reset(db);/*配置DM9000芯片内寄存器,使其能工作*/dm9000_init_dm9000(dev);/* Init driver variable */db-dbug_cnt = 0;/* set and active a timer process */init_timer(&db-timer); /*初始化内核定时器*/db-timer.expires = DM9000_TIMER_WUT; /*2s唤醒一次*/db-timer.data = (unsigned long) dev;db-timer.function = &dm9000_timer; /*内核定时器溢出回调函数*/add_timer(&db-timer); /*启动内核定时器*/*检查mii接口状态*/mii_check_media(&db-mii, netif_msg_link(db), 1);/*启动发送队列*/netif_start_queue(dev);return 0;/* Initilize dm9000 board 配置DM9000芯片内部寄存器,使其能工作*/static voiddm9000_init_dm9000(struct net_device *dev)board_info_t *db = (board_info_t *) dev-priv;PRINTK1(entering %sn,_FUNCTION_);/* I/O mode检查当前芯片的总线带宽8bit,16bit,32bit芯片的总线带宽由硬件走线决定 */db-io_mode = ior(db, DM9000_ISR) 6; /* ISR bit7:6 keeps I/O mode */* GPIO0 on pre-activate PHY 启动PHY*/iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */iow(db, DM9000_GPR, 0); /* Enable PHY */* Program operating register */*清除发送配置选项*/iow(db, DM9000_TCR, 0); /* TX Polling clear */iow(db, DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */iow(db, DM9000_FCR, 0xff); /* Flow Control */iow(db, DM9000_SMCR, 0); /* Special Mode */* clear TX status */*清除发送标志位*/iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);/*清除中断标志位*/iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */* Set address filter table */dm9000_hash_table(d

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论