dm9000网卡的linux驱动分析

分析内核自带的dm9000网卡驱动程序:
      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,
      };
1 从驱动的入口函数开始分析
  dm9000_init
    >platform_driver_register(&dm9000_driver)//这里注册了个平台driver驱动
   
       ===>>linux-2.6.22\arch\arm\plat-s3c24xx\devs.c
            /*加入DM9000网卡支持*/
      #include <linux/dm9000.h>
      #include <linux/ioport.h>
      #define DM9000_BASE 0x20000000
      static struct resource s3c_dm9000_resource[] ={
       [0] = {
        .start = DM9000_BASE,
        .end   =  DM9000_BASE +0x03 ,
        .flags =  IORESOURCE_MEM,
       },
       [1] = {
        .start = DM9000_BASE + 0x4,
        .end   =  DM9000_BASE + 0x4 +0x3 ,
        .flags =  IORESOURCE_MEM,
       },
       [2] = {
        .start = IRQ_EINT7,
        .end   = IRQ_EINT7,
        .flags =  IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
       }
      };
      
      static struct dm9000_plat_data s3c_device_dm9000_platdata = {
       .flags = DM9000_PLATF_16BITONLY,
      };
      
      struct platform_device s3c_device_dm9000 = {
       .name = "dm9000",
       .id      = -1,
       .num_resources = ARRAY_SIZE(s3c_dm9000_resource),
       .resource   = s3c_dm9000_resource,
       .dev ={
         .platform_data = &s3c_device_dm9000_platdata,
        }
      };
   ===>>EXPORT_SYMBOL(s3c_device_dm9000);

    那么接下来就分析平台driver的probe函数。
    >dm9000_probe
      >配置网卡所使用的内存bank相关的memory controller:bwscon、bankcon4、s3c2410_gpio_cfgpin
      >struct net_device *ndev = alloc_etherdev //分配一个网卡结构体
      > 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);
    > request_mem_region//为相关结构体成员映射内存空间
    > dm9000_set_io(db, 2);
      db->outblk  = dm9000_outblk_16bit;
    > dm9000_reset(db)
    > ether_setup(ndev);//设置net_device一些通用的成员
    > 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;
   > is_valid_ether_addr(ndev->dev_addr) //检测是否是有效的mac地址,如果无效可以手动地写入MAC地址
   > platform_set_drvdata(pdev, ndev);
   > ret = register_netdev(ndev);//注册网卡
2 接下来分析网卡的open函数 dm9000_open
   dm9000_open
     > request_irq(dev->irq, &dm9000_interrupt, IRQF_SHARED, dev->name, dev)//注册中断
     > dm9000_reset
     > dm9000_init_dm9000(dev)
     > init_timer(&db->timer);。。。。。等操作
       加入一个定时器,定时2秒,
       处理函数:dm9000_timer
                    >mii_check_media(&db->mii, netif_msg_link(db), 0);
     > mii_check_media(&db->mii, netif_msg_link(db), 1);//检查mii接口的duplex 改变
     > netif_start_queue(dev);//启动网卡数据队列
3 接下来分析网卡的发包函数dm9000_start_xmit (ndev->hard_start_xmit = &dm9000_start_xmit)
   dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)//发包函数
      > netif_stop_queue(dev);
      > iow(db, DM9000_IMR, IMR_PAR);/* Disable all interrupts */
       writeb(DM9000_MWCMD, db->io_addr); /* Move data to DM9000 TX RAM */
     > (db->outblk)(db->io_data, skb->data, skb->len)
       ||
       >也就是调用: dm9000_outblk_16bit(db->io_data, skb->data, skb->len) //拷贝skb->data中数据到网卡数据io
            >writesw(db->io_data, skb->data, (skb->len+1) >> 1);
     > 第一次发包?立即发:进行入队列-》db->tx_pkt_cnt++; db->queue_pkt_len = skb->len;
     > dev_kfree_skb(skb);
     > netif_wake_queue
     > iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);/* Re-enable interrupt */ 
4 收包分析
   当有数据包时,引发中断,调用中断注册的处理函数dm9000_interrupt
   dm9000_interrupt
      >dm9000_rx
         >(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
          ||
          dm9000_inblk_16bit(void __iomem *reg, void *data, int count)
               readsw(reg, data, (count+1) >> 1);
         > skb = dev_alloc_skb(RxLen + 4)
         > skb_reserve(skb, 2)
         > rdptr = (u8 *) skb_put(skb, RxLen - 4)
         > skb->protocol = eth_type_trans(skb, dev);
      > netif_rx(skb);//向上报告,接收到的数据
  
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值