zoukankan      html  css  js  c++  java
  • 【Linux高级驱动】如何分析并移植网卡驱动

    dm9000的驱动分析

    m9000_init
     platform_driver_register(&dm9000_driver);
    dm9000_probe
     /*获取平台数据*/
     struct dm9000_plat_data *pdata = pdev->dev.platform_data;
     /*表示一个网络设备*/
     struct net_device *ndev;
     /*为网络设备分配空间*/
     ndev = alloc_etherdev(sizeof(struct board_info));
     /*获取资源*/
     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);
     /*映射地址端口*/
     db->io_addr = ioremap(db->addr_res->start, iosize);
     /*映射数据端口*/
     db->io_data = ioremap(db->data_res->start, iosize);
     /*硬件相关的操作*/
     /*1.设置读写操作函数*/
     dm9000_set_io(db, 2);
      case 2:
      db->dumpblk = dm9000_dumpblk_16bit;
      db->outblk  = dm9000_outblk_16bit;
      db->inblk   = dm9000_inblk_16bit;
      break;
     
     /*2.复位 */
     dm9000_reset(db);
     /*3.读dm9000的ID号 */
     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;
     /* 获取芯片型号 */
     id_val = ior(db, DM9000_CHIPR);
     ether_setup(ndev);
     /*设置操作方法*/
     ndev->netdev_ops  = &dm9000_netdev_ops;
     /*注册网络设备*/
     register_netdev(ndev);   //register_chrdev

    cs8900a网卡驱动分析

    /*分配一个网络设备*/
    struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
    dev->irq = irq;
    dev->base_addr = io;
    cs89x0_probe1(dev, io, 1);
     /*识别芯片*/
     /*操作方法的设置*/
     dev->netdev_ops = &net_ops;
     /*注册网络设备*/
     register_netdev(dev);

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

    网卡驱动的数据接收发送流程?

    初始化设备

    dm9000_open(struct net_device *dev)
    {
      if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
      return -EAGAIN;
      /* Initialize DM9000 board */
      dm9000_reset(db);
        /* RESET device */
        writeb(DM9000_NCR, db->io_addr);
        udelay(200);
        writeb(NCR_RST, db->io_data);
        udelay(200);
      /* dm9000的初始化,芯片厂商会支持 */
      dm9000_init_dm9000(dev);
      
      /* 启动发送队列 */
      netif_start_queue(dev);
    }

    数据接收流程

    dm9000_interrupt(int irq, void *dev_id)
     /* 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 */
     /* Received the coming packet 读中断*/
     if (int_status & ISR_PRS)
      dm9000_rx(dev);
       
       ior(db, DM9000_MRCMDX); /* Dummy read 地址不自动增加*/
       rxbyte = readb(db->io_data);
       if (rxbyte & DM9000_PKT_ERR) {
        dev_warn(db->dev, "status check fail: %d ", rxbyte);
        iow(db, DM9000_RCR, 0x00);  /* Stop Device */
        iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
        return;
       }
       
       writeb(DM9000_MRCMD, db->io_addr);  /*地址自动增加的*/
       /* 读取状态信息 */
       (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); //dm9000_inblk_16bit
       RxLen = le16_to_cpu(rxhdr.RxLen);
       /*数据的状态判断*/
       if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
              RSR_PLE | RSR_RWTO |
              RSR_LCS | RSR_RF)) {
       struct sk_buff *skb;
       skb = dev_alloc_skb(RxLen + 4))   /*分配一个sk_buff数据包*/
       skb_reserve(skb, 2);  //data指针和tail指针同时下移  
       rdptr = (u8 *) skb_put(skb, RxLen - 4);
       (db->inblk)(db->io_data, rdptr, RxLen);  //dm9000_inblk_16bit   //读真正的有效数据(MAC头,TCP头,IP头,网络数据)
       dev->stats.rx_bytes += RxLen;
       /* Pass to upper layer,去掉MAC头 */
       skb->protocol = eth_type_trans(skb, dev);
       /* 将数据上报到上层 */
       netif_rx(skb);
       dev->stats.rx_packets++;

    数据发送流程

    sk_buff
    dm9000_start_xmit
     /* 将数据写入到DM9000的SRAM中 */
     /* Move data to DM9000 TX RAM */
     writeb(DM9000_MWCMD, db->io_addr);    //设置为自动增加
     //dm9000_outblk_16bit
     (db->outblk)(db->io_data, skb->data, skb->len);   //dm9000_outblk_16bit
     dev->stats.tx_bytes += skb->len;
     db->tx_pkt_cnt++;
     /*设置发送属性*/
     dm9000_send_packet(struct net_device *dev,
              int ip_summed,
              u16 pkt_len)
      /*指定数据包的长度*/
      iow(dm, DM9000_TXPLL, pkt_len);
      iow(dm, DM9000_TXPLH, pkt_len >> 8);
      /*启动发送:数据发送完成,产生中断*/
      iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
     netif_stop_queue(dev);
     
    dm9000_interrupt(int irq, void *dev_id)
     /* Save previous register address */
     reg_save = readb(db->io_addr);   //让他不自动增加
     /* 关中断 */
     iow(db, DM9000_IMR, IMR_PAR);
     
     /*获取中断状态*/
     int_status = ior(db, DM9000_ISR); /* Got ISR */
     iow(db, DM9000_ISR, int_status); /* Clear ISR status */
     /* Trnasmit Interrupt check,数据发送完成 */
     if (int_status & ISR_PTS)
      dm9000_tx_done(dev, db);
       db->tx_pkt_cnt--;
       dev->stats.tx_packets++;
       if (db->tx_pkt_cnt > 0)
        dm9000_send_packet(dev, db->queue_ip_summed,db->queue_pkt_len);
         /*指定数据包的长度*/
         iow(dm, DM9000_TXPLL, pkt_len);
         iow(dm, DM9000_TXPLH, pkt_len >> 8);
         /*启动发送:数据发送完成,产生中断*/
         iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */

       netif_wake_queue(dev);
     /* Re-enable interrupt mask */
     iow(db, DM9000_IMR, db->imr_all);
     /* Restore previous register address */
     writeb(reg_save, db->io_addr);  //恢复为自动增加

    怎么写网卡驱动

    1.cs89x0.c

    1.1 分配一个net_device结构体

         alloc_etherdev

    1.2 设置

        dev->open       = net_open;
        dev->stop       = net_close;
        dev->tx_timeout     = net_timeout;
        dev->watchdog_timeo = HZ;
        dev->hard_start_xmit    = net_send_packet;
        dev->get_stats      = net_get_stats;
        dev->set_multicast_list = set_multicast_list;
        dev->set_mac_address    = set_mac_address;

    1.3 注册

        register_netdev

    2. DM9000.c

    2.1 分配一个net_device结构体
        ndev = alloc_etherdev(sizeof (struct board_info));
    2.2 设置
       

        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;

    2.3 注册
        ret = register_netdev(ndev);

    任何设备的核心都是收发数据

    1. 发数据:
       上层要发送数据时,构造一个sk_buff,然后调用net_device的hard_start_xmit来发送

    2. 收数据:
       网卡收到数据后,发生中断
       在中断服务程序里:
       从硬件上读出数据,然后构造一个sk_buff,上报:
    a. 分配一个sk_buff结构体:
        dev_alloc_skb
    b. 使用硬件上得到数据填充这个结构体
    c. 上报:netif_rx

    测试方法

    1. 编译/安装驱动 farsight_net_1.c

       ifconfig fs_net0 up
       ifconfig fs_net0 192.188.1.1
       ping 192.188.1.1 成功,证明ping自己的话,不经过硬件
       ping 192.188.1.2 多次调用fsnet_hard_start_tx 
       PING 192.188.1.2 (192.188.1.2): 56 data bytes
       fsnet_hard_start_tx 
       fsnet_hard_start_tx    
       再次ifconfig发现fs_net0的rx/tx都是0


    2. 编译/安装驱动 farsight_net_2.c: 添加统计信息

    3. 编译/安装驱动 farsight_net_3.c: 设MAC地址
       ifconfig fs_net0
       ifconfig         可以看到MAC地址

    4. 编译/安装驱动 farsight_net_4.c: 构造ping的返回包
       ifconfig fs_net0 up
       ifconfig fs_net0 192.188.1.1
       ping 192.188.1.2                成功

    怎么移植网卡驱动

        网卡基本上都是内存接口(ram-like)
        1. 根据原理图确定访问地址, 在驱动里修改相应项
        2. 为了能通过这些地址访问网卡,对于2410还要设置memory controller
       比如设置位宽、时间参数
        3. 根据原理图确定中断号, 在驱动里修改相应项(包括中断号、中断触发方式(高/低有效))

     @成鹏致远

    (blogs:http://lcw.cnblogs.com

    (emailwwwlllll@126.com)

    (qq552158509





  • 相关阅读:
    P1194 买礼物(建模)
    024 Android 对话框(AlertDialog)的应用(与Android黑马培训班的024相对照学习)
    023 Android 滚动视图(ScollView)
    022 Android 开源项目使用指南
    021 Android 日历视图(Calendarview)
    020 ProgressBar(进度条)、SeekBar(拖动条)与星级评分条(RatingBar)
    019 Android 程序调试技巧汇总
    018 Android 单选按钮(RadioButton)和复选框(CheckBox)的使用
    017 Android ToggleButton(开关函数)与switch (开关按钮)
    016 Android Toast语句应用
  • 原文地址:https://www.cnblogs.com/lcw/p/3802633.html
Copyright © 2011-2022 走看看