DM9000 网卡驱动程序分析

来源:互联网 发布:全速建站软件 编辑:程序博客网 时间:2024/04/28 04:13

平台:MINI2440

系统:Linux-2.6.36.2

mach-s3c2410/include/mach/map.h:

#define S3C2410_CS4 (0x20000000)  //AEN接nGCS4,BANK4

mach-mini2440.c:

#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)   //TXD[2:0]悬空static struct resource mini2440_dm9k_resource[] = {        [0] = {                .start = MACH_MINI2440_DM9K_BASE,                .end   = MACH_MINI2440_DM9K_BASE + 3,                .flags = IORESOURCE_MEM        },        [1] = {                .start = MACH_MINI2440_DM9K_BASE + 4,                .end   = MACH_MINI2440_DM9K_BASE + 7,                .flags = IORESOURCE_MEM        },        [2] = {                .start = IRQ_EINT7,   //中断使用了EINT7.                .end   = IRQ_EINT7,                .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,        }};
DM9000平台设备的定义:

static struct dm9000_plat_data mini2440_dm9k_pdata = {        .flags          = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),};static struct platform_device mini2440_device_eth = {        .name           = "dm9000",        .id             = -1,        .num_resources  = ARRAY_SIZE(mini2440_dm9k_resource),        .resource       = mini2440_dm9k_resource,        .dev            = {                .platform_data  = &mini2440_dm9k_pdata,        },};
板子初始化时将平台设备驱动加载到总线上:

static struct platform_device *mini2440_devices[] __initdata = {&s3c_device_usb,&s3c_device_rtc,&s3c_device_lcd,&s3c_device_wdt,&s3c_device_i2c0,&s3c_device_iis,&mini2440_device_eth,&s3c24xx_uda134x,&s3c_device_nand,&s3c_device_sdi,&s3c_device_usbgadget,};
dm9000.c:platform_driver与重要操作函数:

static struct platform_driver dm9000_driver = {.driver= {.name    = "dm9000",.owner = THIS_MODULE,},.probe   = dm9000_probe,.remove  = __devexit_p(dm9000_drv_remove),.suspend = dm9000_drv_suspend,.resume  = dm9000_drv_resume,};
net_device_ops与重要操作函数:

static const struct net_device_ops dm9000_netdev_ops = {.ndo_open= dm9000_open,.ndo_stop= dm9000_stop,.ndo_start_xmit= dm9000_start_xmit,.ndo_tx_timeout= dm9000_timeout,.ndo_set_multicast_list= dm9000_hash_table,.ndo_do_ioctl= dm9000_ioctl,.ndo_change_mtu= eth_change_mtu,.ndo_validate_addr= eth_validate_addr,.ndo_set_mac_address= eth_mac_addr,#ifdef CONFIG_NET_POLL_CONTROLLER.ndo_poll_controller= dm9000_poll_controller,#endif};
ethtool_ops:

static const struct ethtool_ops dm9000_ethtool_ops = {  //查询与设置网卡的参数.get_drvinfo= dm9000_get_drvinfo,.get_settings= dm9000_get_settings,.set_settings= dm9000_set_settings,.get_msglevel= dm9000_get_msglevel,.set_msglevel= dm9000_set_msglevel,.nway_reset= dm9000_nway_reset,.get_link= dm9000_get_link, .get_eeprom_len= dm9000_get_eeprom_len, .get_eeprom= dm9000_get_eeprom, .set_eeprom= dm9000_set_eeprom,};
board_info结构体,内容是与芯片相关的信息:

typedef struct board_info {void __iomem*io_addr;/* Register I/O base address */void __iomem*io_data;/* Data I/O address */u16 irq;/* IRQ */u16tx_pkt_cnt;u16queue_pkt_len;u16queue_start_addr;u16dbug_cnt;u8io_mode;/* 0:word, 2:byte */u8phy_addr;u8imr_all;unsigned intflags;unsigned intin_suspend :1;intdebug_level;enum dm9000_type type;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 device*dev;     /* parent device */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 mutex addr_lock;/* phy and eeprom access lock */struct delayed_work phy_poll;struct net_device  *ndev;spinlock_tlock;struct mii_if_info mii;u32msg_enable;} board_info_t;
注册平台驱动:

static int __init dm9000_init(void){printk(KERN_INFO "%s Ethernet Driver, V%s/n", CARDNAME, DRV_VERSION);return platform_driver_register(&dm9000_driver);}
完成match之后执行Probe函数,获得资源信息,最终注册网络设备。

dm9000_remove:在卸载时使用,释放内存空间:

static int __devexit 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 *) netdev_priv(ndev));free_netdev(ndev);/* free device structure */dev_dbg(&pdev->dev, "released and freed device/n");return 0;}
dm9000_suspend:并没有将网络设备从内核移除,只是标志设备为removed状态,并设置挂起标志位,最后关闭设备:

static int dm9000_drv_suspend(struct platform_device *dev, pm_message_t state){struct net_device *ndev = platform_get_drvdata(dev);board_info_t *db;if (ndev) {db = netdev_priv(ndev);db->in_suspend = 1;if (netif_running(ndev)) {netif_device_detach(ndev);dm9000_shutdown(ndev);}}return 0;}
dm9000_resume:
static int dm9000_drv_resume(struct platform_device *dev){struct net_device *ndev = platform_get_drvdata(dev);board_info_t *db = netdev_priv(ndev);if (ndev) {if (netif_running(ndev)) {dm9000_reset(db);dm9000_init_dm9000(ndev);netif_device_attach(ndev);//标志为attach状态。}db->in_suspend = 0;}return 0;}
dm9000_open:向内核注册中断:

static int dm9000_open(struct net_device *dev){board_info_t *db = netdev_priv(dev);unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;if (netif_msg_ifup(db))dev_dbg(db->dev, "enabling %s\n", dev->name);/* If there is no IRQ type specified, default to something that * may work, and tell the user that this is a problem */if (irqflags == IRQF_TRIGGER_NONE)dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");irqflags |= IRQF_SHARED;if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))  //注册中断return -EAGAIN;/* Initialize DM9000 board */dm9000_reset(db);dm9000_init_dm9000(dev);/* Init driver variable */db->dbug_cnt = 0;mii_check_media(&db->mii, netif_msg_link(db), 1);netif_start_queue(dev);dm9000_schedule_poll(db);return 0;}
dm9000_stop:

static int dm9000_stop(struct net_device *ndev){board_info_t *db = netdev_priv(ndev);if (netif_msg_ifdown(db))dev_dbg(db->dev, "shutting down %s\n", ndev->name);cancel_delayed_work_sync(&db->phy_poll);netif_stop_queue(ndev);netif_carrier_off(ndev);                  free_irq(ndev->irq, ndev);dm9000_shutdown(ndev);return 0;}
dm9000_start_xmit():发送数据包函数:

static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev){unsigned long flags;board_info_t *db = netdev_priv(dev);dm9000_dbg(db, 3, "%s:/n", __func__);if (db->tx_pkt_cnt > 1)return NETDEV_TX_BUSY;        /*获得自旋锁*/spin_lock_irqsave(&db->lock, flags); /* Move data to DM9000 TX RAM */writeb(DM9000_MWCMD, db->io_addr);(db->outblk)(db->io_data, skb->data, skb->len);//将skbuffer中的data写入DM9000的TX RAM,并计数dev->stats.tx_bytes += skb->len;db->tx_pkt_cnt++;/* TX control: First packet immediately send, second packet queue */if (db->tx_pkt_cnt == 1) {           //如果是第一个包/* Set TX length to DM9000 */iow(db, DM9000_TXPLL, skb->len);iow(db, DM9000_TXPLH, skb->len >> 8);/* Issue TX polling command */iow(db, DM9000_TCR, TCR_TXREQ);/* Cleared after TX complete */dev->trans_start = jiffies;/* save the time stamp */} else {    //不是第一个包/* Second packet */db->queue_pkt_len = skb->len;netif_stop_queue(dev);}        /*释放自旋锁*/spin_unlock_irqrestore(&db->lock, flags);/* free this SKB */dev_kfree_skb(skb);return 0;}
dm9000_timeout():超时调用:

static void dm9000_timeout(struct net_device *dev){board_info_t *db = netdev_priv(dev);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);               //重启并初始化DM9000/* 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);}
dm9000_hash_table():设置组播地址:

static void dm9000_hash_table(struct net_device *dev){board_info_t *db = netdev_priv(dev);struct dev_mc_list *mcptr = dev->mc_list;int mc_cnt = dev->mc_count;int i, oft;u32 hash_val;u16 hash_table[4];u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;unsigned long flags;dm9000_dbg(db, 1, "entering %s/n", __func__);spin_lock_irqsave(&db->lock, flags);for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)iow(db, oft, dev->dev_addr[i]);/* Clear Hash Table */for (i = 0; i < 4; i++)hash_table[i] = 0x0;/* broadcast address */hash_table[3] = 0x8000;if (dev->flags & IFF_PROMISC)rcr |= RCR_PRMSC;if (dev->flags & IFF_ALLMULTI)rcr |= RCR_ALL;/* the multicast address in Hash Table : 64 bits */for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f;hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);}/* Write the hash table to MAC MD table */for (i = 0, oft = DM9000_MAR; i < 4; i++) {iow(db, oft++, hash_table[i]);iow(db, oft++, hash_table[i] >> 8);}iow(db, DM9000_RCR, rcr);spin_unlock_irqrestore(&db->lock, flags);}
dm9000_rx():接收函数:

static void dm9000_rx(struct net_device *dev){board_info_t *db = netdev_priv(dev);struct dm9000_rxhdr rxhdr;struct sk_buff *skb;u8 rxbyte, *rdptr;bool GoodPacket;int RxLen;/* Check packet ready or not */do {ior(db, DM9000_MRCMDX);/* Dummy read *//* Get most updated data */rxbyte = readb(db->io_data);/* Status check: this byte must be 0 or 1 */if (rxbyte > DM9000_PKT_RDY) {dev_warn(db->dev, "status check fail: %d/n", rxbyte);iow(db, DM9000_RCR, 0x00);/* Stop Device */iow(db, DM9000_ISR, IMR_PAR);/* Stop INT request */return;}if (rxbyte != DM9000_PKT_RDY)return;/* A packet ready now  & Get status/length */GoodPacket = true;writeb(DM9000_MRCMD, db->io_addr);(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));//读四个字节到rxhdr变量RxLen = le16_to_cpu(rxhdr.RxLen);if (netif_msg_rx_status(db))dev_dbg(db->dev, "RX: status %02x, length %04x/n",rxhdr.RxStatus, RxLen);/* Packet Status check */if (RxLen < 0x40) {GoodPacket = false;if (netif_msg_rx_err(db))dev_dbg(db->dev, "RX: Bad Packet (runt)/n");}if (RxLen > DM9000_PKT_MAX) {dev_dbg(db->dev, "RST: RX Len:%x/n", RxLen);}/* rxhdr.RxStatus is identical to RSR register. */if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |      RSR_PLE | RSR_RWTO |      RSR_LCS | RSR_RF)) {GoodPacket = false;if (rxhdr.RxStatus & RSR_FOE) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "fifo error/n");dev->stats.rx_fifo_errors++;}if (rxhdr.RxStatus & RSR_CE) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "crc error/n");dev->stats.rx_crc_errors++;}if (rxhdr.RxStatus & RSR_RF) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "length error/n");dev->stats.rx_length_errors++;}}/* Move data from DM9000 */   //将RX SRAM中的data放到sk_buffer。if (GoodPacket    && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {skb_reserve(skb, 2);rdptr = (u8 *) skb_put(skb, RxLen - 4);/* Read received packet from RX SRAM */(db->inblk)(db->io_data, rdptr, RxLen);dev->stats.rx_bytes += RxLen;/* Pass to upper layer */skb->protocol = eth_type_trans(skb, dev);netif_rx(skb);dev->stats.rx_packets++;} else {/* need to dump the packet's data */(db->dumpblk)(db->io_data, RxLen);}} while (rxbyte == DM9000_PKT_RDY);}
dm9000_interrupt:

static irqreturn_t dm9000_interrupt(int irq, void *dev_id){struct net_device *dev = dev_id;board_info_t *db = netdev_priv(dev);int int_status;unsigned long flags;u8 reg_save;dm9000_dbg(db, 3, "entering %s/n", __func__);/* A real interrupt coming *//* holders of db->lock must always block IRQs */spin_lock_irqsave(&db->lock, flags);/* Save previous register address */reg_save = readb(db->io_addr);/* Disable all interrupts */iow(db, DM9000_IMR, IMR_PAR);/* Got DM9000 interrupt status */int_status = ior(db, DM9000_ISR);/* Got ISR */iow(db, DM9000_ISR, int_status);/* Clear ISR status */if (netif_msg_intr(db))dev_dbg(db->dev, "interrupt status %02x/n", int_status);/* Received the coming packet */if (int_status & ISR_PRS)dm9000_rx(dev);               //取数据/* Trnasmit Interrupt check */if (int_status & ISR_PTS)dm9000_tx_done(dev, db);      //调用done函数if (db->type != TYPE_DM9000E) {if (int_status & ISR_LNKCHNG) {/* fire a link-change request */schedule_delayed_work(&db->phy_poll, 1);}}/* Re-enable interrupt mask */iow(db, DM9000_IMR, db->imr_all);/* Restore previous register address */writeb(reg_save, db->io_addr);spin_unlock_irqrestore(&db->lock, flags);return IRQ_HANDLED;}
dm9000_tx_done:

static void dm9000_tx_done(struct net_device *dev, board_info_t *db){int tx_status = ior(db, DM9000_NSR);/* Got TX status */  //读取NSR的状态,得知发送的状态if (tx_status & (NSR_TX2END | NSR_TX1END)) {/* One packet sent complete */db->tx_pkt_cnt--;dev->stats.tx_packets++;if (netif_msg_tx_done(db))dev_dbg(db->dev, "tx done, NSR %02x/n", tx_status);/* Queue packet check & send */if (db->tx_pkt_cnt > 0) {iow(db, DM9000_TXPLL, db->queue_pkt_len);iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);iow(db, DM9000_TCR, TCR_TXREQ);dev->trans_start = jiffies;}  //通知内核可以将待发送的数据包进入发送队列netif_wake_queue(dev);}}

1 0
原创粉丝点击