ARM-Linux驱动--DM9000网卡驱动分析(三) .

转载 2011年10月18日 12:39:12
 

下面开始看网卡设备的打开、关闭函数和操作函数

  1. static const struct net_device_ops dm9000_netdev_ops = {  
  2.     .ndo_open       = dm9000_open,/* 打开设备函数 */  
  3.     .ndo_stop       = dm9000_stop,/* 关闭设备函数 */  
  4.     .ndo_start_xmit     = dm9000_start_xmit,/* 开始发送数据 */  
  5.     .ndo_tx_timeout     = dm9000_timeout,/* 发送超时 */  
  6.     .ndo_set_multicast_list = dm9000_hash_table,/* 设定多播列表 */  
  7.     .ndo_do_ioctl       = dm9000_ioctl,/* io操作函数 */  
  8.     .ndo_change_mtu     = eth_change_mtu,/* 改变MTU */  
  9.     .ndo_validate_addr  = eth_validate_addr,  
  10.     .ndo_set_mac_address    = eth_mac_addr,  
  11. #ifdef CONFIG_NET_POLL_CONTROLLER   
  12.     .ndo_poll_controller    = dm9000_poll_controller,  
  13. #endif   
  14. };  

1DM9000的打开函数

由于在函数alloc_netdev_mq()中分配net_device和网卡的私有数据是一起分配的,详见函数的实现

  1. struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,  
  2.         void (*setup)(struct net_device *), unsigned int queue_count)  
  3. {  
  4. ...................  
  5. alloc_size = sizeof(struct net_device);  
  6.     if (sizeof_priv) {  
  7.         /* ensure 32-byte alignment of private area */  
  8.         alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);  
  9.         alloc_size += sizeof_priv;  
  10.     }  
  11.     /* ensure 32-byte alignment of whole construct */  
  12.     alloc_size += NETDEV_ALIGN - 1;  
  13.   
  14.     p = kzalloc(alloc_size, GFP_KERNEL);  
  15.     if (!p) {  
  16.         printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");  
  17.         return NULL;  
  18.     }  
  19.   
  20.     tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL);  
  21.     if (!tx) {  
  22.         printk(KERN_ERR "alloc_netdev: Unable to allocate "  
  23.                "tx qdiscs.\n");  
  24.         goto free_p;  
  25.     }  
  26.   
  27. #ifdef CONFIG_RPS   
  28.     rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);  
  29.     if (!rx) {  
  30.         printk(KERN_ERR "alloc_netdev: Unable to allocate "  
  31.                "rx queues.\n");  
  32.         goto free_tx;  
  33.     }  
  34. ..............  
  35. }  

所以使用函数netdev_priv()函数返回的是网卡的私有数据的地址,函数的实现如下:

  1. /** 
  2.  *      netdev_priv - access network device private data 
  3.  *      @dev: network device 
  4.  * 
  5.  * Get network device private data 
  6.  */  
  7. static inline void *netdev_priv(const struct net_device *dev)  
  8. {  
  9.         return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);  
  10. }  

这样两者会同时生存和消失。

dm9000_open()函数

  1. /* 
  2.  *  Open the interface. 
  3.  *  The interface is opened whenever "ifconfig" actives it. 
  4.  */  
  5. static int  
  6. dm9000_open(struct net_device *dev)  
  7. {  
  8.         board_info_t *db = netdev_priv(dev);/* 返回board_info_t的地址 */  
  9.         unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;  
  10.   
  11.         if (netif_msg_ifup(db))  
  12.                 dev_dbg(db->dev, "enabling %s\n", dev->name);  
  13.   
  14.         /* If there is no IRQ type specified, default to something that 
  15.          * may work, and tell the user that this is a problem */  
  16.   
  17.         if (irqflags == IRQF_TRIGGER_NONE)  
  18.                 dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");  
  19.   
  20.         irqflags |= IRQF_SHARED;  
  21.           
  22.         /* 注册中断 */  
  23.         if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))  
  24.                 return -EAGAIN;  
  25.   
  26.         /* Initialize DM9000 board */  
  27.         dm9000_reset(db);/* 复位DM9000 */  
  28.         dm9000_init_dm9000(dev);/* 根据net_device的数据初始化DM9000 */  
  29.   
  30.         /* Init driver variable */  
  31.         db->dbug_cnt = 0;  
  32.   
  33.         mii_check_media(&db->mii, netif_msg_link(db), 1);/* 检测mii接口的状态 */  
  34.         netif_start_queue(dev);/* 用来告诉上层网络协定这个驱动程序还有空的缓冲区可用,请把下 一个封包送进来。*/  
  35.           
  36.         /*在probe函数中初始化的等待队列 INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);    
  37.         *初始化定时器,调用等待队列*/  
  38.         dm9000_schedule_poll(db);  
  39.   
  40.         return 0;  
  41. }  

2、网卡关闭函数

  1. /* 
  2.  * Stop the interface. 
  3.  * The interface is stopped when it is brought. 
  4.  */  
  5. static int  
  6. dm9000_stop(struct net_device *ndev)  
  7. {  
  8.         board_info_t *db = netdev_priv(ndev);/* 同上,获取网卡的私有结构信息的地址 */  
  9.   
  10.         if (netif_msg_ifdown(db))  
  11.                 dev_dbg(db->dev, "shutting down %s\n", ndev->name);  
  12.   
  13.         cancel_delayed_work_sync(&db->phy_poll);/* 终止phy_poll队列中被延迟的任务 */  
  14.   
  15.         netif_stop_queue(ndev);/* 关闭发送队列 */  
  16.         netif_carrier_off(ndev);/*通知该内核设备载波丢失,大部分涉及实际的物理连接的网络技术提供有一个载波状态,载波存在说明硬件存在并准备好*/  
  17.   
  18.         /* free interrupt */  
  19.         free_irq(ndev->irq, ndev);/* 释放中断 */  
  20.   
  21.         dm9000_shutdown(ndev);/* 关闭DM9000网卡 */  
  22.   
  23.         return 0;  
  24. }  

下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR01,关闭dm9000电源,配置寄存器IMR71disable中断,配置寄存器RCRdisable接收

函数如下:

  1. static void  
  2. dm9000_shutdown(struct net_device *dev)  
  3. {  
  4.         board_info_t *db = netdev_priv(dev);/* 获取网卡私有信息的地址 */  
  5.   
  6.         /* RESET device */  
  7.         dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET ,复位PHY*/  
  8.         iow(db, DM9000_GPR, 0x01);      /* Power-Down PHY ,关闭PHY*/  
  9.         iow(db, DM9000_IMR, IMR_PAR);   /* Disable all interrupt ,关闭所有的中断*/  
  10.         iow(db, DM9000_RCR, 0x00);      /* Disable RX ,不再接受数据*/  
  11. }  

3、接下来了解一下数据的发送函数dm9000_start_xmit

上图可以看出DM9000SRAM中地址0x00000x0BFFTXBuffer,从0x0C000x3FFFRXBuffer,包的有效数据必须提前放到TXBuffer缓冲区,使用端口命令来选择MWCMD寄存器。最后设置TXCR寄存器的bit[0]TXREQ来自动发送包。
发送包的步骤如下:

1)检查存储器宽度,通过读取ISRbit[7:6]来确定位数
2)写数据到TXSRAM
3)写传输长度到TXPLLTXPLH寄存器
4)设置TXCRbit[0]TXREQ来发送包

  1. /* 
  2.  *  Hardware start transmission. 
  3.  *  Send a packet to media from the upper layer. 
  4.  */  
  5. static int  
  6. dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)  
  7. {  
  8.         unsigned long flags;  
  9.         board_info_t *db = netdev_priv(dev);/* 获取网卡虽有信息的存储结构信息的地址 */  
  10.   
  11.         dm9000_dbg(db, 3, "%s:\n", __func__);  
  12.   
  13.         if (db->tx_pkt_cnt > 1)  
  14.                 return NETDEV_TX_BUSY;  
  15.   
  16.         spin_lock_irqsave(&db->lock, flags);/* 获得自旋锁 */  
  17.   
  18.         /* Move data to DM9000 TX RAM */  
  19.         /*MWCMD 即 Memory data write command with address increment Register(F8H) 
  20.         * 根据 IO 操作模式(8-bit or 16-bit)来增加写指针 1 或 2 
  21.         */  
  22.         writeb(DM9000_MWCMD, db->io_addr);  
  23.   
  24.         (db->outblk)(db->io_data, skb->data, skb->len);/* 将数据从sk_buff中copy到网卡的TX SRAM中 */  
  25.           
  26.         dev->stats.tx_bytes += skb->len;/* 统计发送的字节数 */  
  27.           
  28.         db->tx_pkt_cnt++;/* 待发送计数 */  
  29.         /* TX control: First packet immediately send, second packet queue */  
  30.         if (db->tx_pkt_cnt == 1) {  
  31.                 dm9000_send_packet(dev, skb->ip_summed, skb->len);/* 如果计数为1,直接发送 */  
  32.         } else {/* 如果是第2个,则 */  
  33.                 /* Second packet */  
  34.                 db->queue_pkt_len = skb->len;  
  35.                 db->queue_ip_summed = skb->ip_summed;  
  36.                 netif_stop_queue(dev);/* 告诉上层停止发送 */  
  37.         }  
  38.         spin_unlock_irqrestore(&db->lock, flags);/* 解锁 */  
  39.         /* free this SKB ,释放SKB*/  
  40.         dev_kfree_skb(skb);  
  41.   
  42.         return NETDEV_TX_OK;  
  43. }  

上面函数调用下面的函数 dm9000_send_packet来发送数据

  1. static void dm9000_send_packet(struct net_device *dev,  
  2.                                int ip_summed,  
  3.                                u16 pkt_len)  
  4. {  
  5.         board_info_t *dm = to_dm9000_board(dev);  
  6.   
  7.         /* The DM9000 is not smart enough to leave fragmented packets alone. */  
  8.         if (dm->ip_summed != ip_summed) {  
  9.                 if (ip_summed == CHECKSUM_NONE)  
  10.                         iow(dm, DM9000_TCCR, 0);  
  11.                 else  
  12.                         iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);  
  13.                 dm->ip_summed = ip_summed;  
  14.         }  
  15.   
  16.         /* Set TX length to DM9000 */  
  17.         /* 设置TX数据的长度到寄存器TXPLL和TXPLH */  
  18.         iow(dm, DM9000_TXPLL, pkt_len);  
  19.         iow(dm, DM9000_TXPLH, pkt_len >> 8);  
  20.   
  21.         /* Issue TX polling command */  
  22.         /* 设置发送控制寄存器的发送请求位 */  
  23.         iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */  
  24. }  

5、下面看一下当一个数据包发送完成后的中断处理函数dm9000_tx_done

  1. /* 
  2.  * DM9000 interrupt handler 
  3.  * receive the packet to upper layer, free the transmitted packet 
  4.  */  
  5.   
  6. static void dm9000_tx_done(struct net_device *dev, board_info_t *db)  
  7. {  
  8.         int tx_status = ior(db, DM9000_NSR);    /* Got TX status */  
  9.   
  10.         if (tx_status & (NSR_TX2END | NSR_TX1END)) {/* 第一个或第二个数据包发送完毕 */  
  11.                 /* One packet sent complete */  
  12.                 db->tx_pkt_cnt--;/* 待发送的数据包个数减1 */  
  13.                 dev->stats.tx_packets++;/* 发送的数据包加1 */  
  14.   
  15.                 if (netif_msg_tx_done(db))  
  16.                         dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);  
  17.   
  18.                 /* Queue packet check & send */  
  19.                 if (db->tx_pkt_cnt > 0)/* 如果还有数据包 */  
  20.                         dm9000_send_packet(dev, db->queue_ip_summed,  
  21.                                            db->queue_pkt_len);  
  22.                 netif_wake_queue(dev);/* 告诉内核,将数据包放入发生那个队列 */  
  23.         }  
  24. }  

网卡DM9000驱动移植

-
  • 1970年01月01日 08:00

详细透彻的分析DM9000网卡驱动程序(3)

内核版本:2.6.39.1 时间:2011-11 作者:bingqingsuimeng 版权所有归作者,只供学习交流,若有其它用途请联系作者,转载请遵守IT人职业规范,请注明转载地址 http...
  • qq_21792169
  • qq_21792169
  • 2015-10-08 14:42:40
  • 3402

linux内核-dm9000网卡驱动添加

****************************************************************************************************...
  • zouleideboke
  • zouleideboke
  • 2017-03-23 22:24:29
  • 562

dm9000网卡驱动分析

  • 2011年11月18日 08:31
  • 82KB
  • 下载

ARM-Linux驱动--DM9000网卡驱动分析

硬件平台:FL2440(s3c2440) 内核版本:2.6.35 主机平台:Ubuntu11.04 内核版本:2.6.39 原创作品,转载请标明出处http://blog.cs...
  • zjy900507
  • zjy900507
  • 2017-12-25 16:11:48
  • 179

源码开放学ARM—DM9000网卡驱动

Linux 网卡驱动实验 源码开放学ARM:http://www.lumit.org/LASO/zh/chp106-4.html 标准Board Linux启动 & uBuntu Linux ...
  • a746742897
  • a746742897
  • 2016-10-25 12:59:52
  • 644

ARM-Linux驱动--DM9000网卡驱动分析(三)

硬件平台:FL2440(s3c2440) 内核版本:2.6.35 主机平台:Ubuntu11.04 内核版本:2.6.39 交叉编译器:arm-linuc-gcc4.3.2 ...
  • SunboyJohn690905084
  • SunboyJohn690905084
  • 2013-12-24 09:54:22
  • 849

dm9000内核网卡驱动分析

  • 2012年07月21日 15:59
  • 36KB
  • 下载

MINI2440+DM9000网络驱动分析之一

1.DM9000硬件接口:     DM9000提供了三组接口:EEPROM Interface、MII Interface和Processor Interface.相对于EEPROM Interfa...
  • tang_jin_chan
  • tang_jin_chan
  • 2013-11-18 11:57:50
  • 1278

【学习笔记】DM9000裸机驱动(一)

1 总体介绍 DM9000是以太网MAC控制器。它有一个一般处理接口、一个10/100M自适应的PHY和4K DWORD值的SRAM。它的目的是在低功耗和高性能进程的3.3V与5V的支持宽带。 D...
  • chjr1000
  • chjr1000
  • 2012-07-07 17:27:38
  • 5865
收藏助手
不良信息举报
您举报文章:ARM-Linux驱动--DM9000网卡驱动分析(三) .
举报原因:
原因补充:

(最多只允许输入30个字)