zoukankan      html  css  js  c++  java
  • usbnet驱动深入分析-usb虚拟网卡host端【转】

    转自:http://blog.csdn.net/zh98jm/article/details/6339320

    1、驱动流程:

     

    2、明确probe函数的功能:

    probe有usb core 经枚举过程,匹配 id_table ,识别到驱动,并调用probe来初始化一些信息。

    如 dev->driver_info = info 只是取得注册时的一些信息,用于一些比较特殊的设备,如bind 与收发与普通的网卡不同时,增加或减少一些配置。

    主要做了:

     skb_queue_head_init (&dev->rxq);
     skb_queue_head_init (&dev->txq);
     skb_queue_head_init (&dev->done);

    /*tasklet 软中断初始化,数据接收发送关键函数*/

     dev->bh.func = usbnet_bh;
     dev->bh.data = (unsigned long) dev;

    /*初始化关键队列,通过usbnet_defer_kevent 设置USB数据传输过程错误,并设置标志,调用schedule_work,提交到工作队列来处理错误事件*/
     INIT_WORK (&dev->kevent, kevent);

    /*内核定时器初始化,用来处理USB传输过程的一些错误,如一些CRC错误,调用mod_timer启动内核定时器*/
     dev->delay.function = usbnet_bh;
     dev->delay.data = (unsigned long) dev;
     init_timer (&dev->delay);

    初始化了三个队列,分别是发送 接收 处理;

    1)数据发送完成后通过 defer_bh 函数移动到 done队列,触发软中断tasklet,来处理tx_done;

    2)数据接收完成后 与发送数一样 通过 defer_bh 来处理rx_done,其中调用了netif_rx来提交数据到网络层。

     net->change_mtu = usbnet_change_mtu;
     net->get_stats = usbnet_get_stats;
     net->hard_start_xmit = usbnet_start_xmit;
     net->open = usbnet_open;
     net->stop = usbnet_stop; SET_NETDEV_DEV(net, &udev->dev);/*net关联usb接口*/
     status = register_netdev (net);/*注册网络设备*/

    需要注意的函数为 usbnet_start_xmit 与 usbnet_open 。

     

    获取usb端点地址,有当前的配置获取bulk in out 的地址,用来收发数据,这部分过程可以参考usb-skeleton.c程序,不做详细介绍。

     

    3、数据发送

    其中 usbnet_start_xmit 为网卡发送函数,有上层调用send函数时,传下skb数据包。

    在 usbnet_start_xmit 中,usb_alloc_urb (0, GFP_ATOMIC)分配内存---->usb_fill_bulk_urb (urb, dev->udev, dev->out,  skb->data, skb->len, tx_complete, skb) 填充urb----->usb_submit_urb (urb, GFP_ATOMIC)提交urb。

    成功时__skb_queue_tail (&dev->txq, skb),在完成函数 tx_complete 函数中 会设置tx_done标志等,然后调用defer_bh来处理。

     

    4、数据的接收

     

    第一种可能:

    这是这部分驱动中最难的一部分。接收数据关键起始点为 usbnet_open 函数,上层 通过 ifconfig usb0 up 时,open函数被调用了,open函数中 触发了软中断 tasklet_schedule();

    static void usbnet_bh (unsigned long param)
    {
     struct usbnet  *dev = (struct usbnet *) param;
     struct sk_buff  *skb;
     struct skb_data  *entry;

     while ((skb = skb_dequeue (&dev->done))) {
      entry = (struct skb_data *) skb->cb;
      switch (entry->state) {
      case rx_done:
       entry->state = rx_cleanup;
       rx_process (dev, skb);
       continue;
      case tx_done:
      case rx_cleanup:
       usb_free_urb (entry->urb);
       dev_kfree_skb (skb);
       continue;
      default:
       devdbg (dev, "bogus skb state %d", entry->state);
      }
     }

    ···

     if (netif_running (dev->net)
       && netif_device_present (dev->net)
       && !timer_pending (&dev->delay)
       && !test_bit (EVENT_RX_HALT, &dev->flags)) {
      int temp = dev->rxq.qlen;
      int qlen = RX_QLEN (dev);

      if (temp < qlen) {
       struct urb *urb;
       int  i;

       for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) {
        urb = usb_alloc_urb (0, GFP_ATOMIC);
        if (urb != NULL)
         rx_submit (dev, urb, GFP_ATOMIC);
       }
       if (temp != dev->rxq.qlen && netif_msg_link (dev))
        devdbg (dev, "rxqlen %d --> %d",
          temp, dev->rxq.qlen);
       if (dev->rxq.qlen < qlen)
        tasklet_schedule (&dev->bh);
      }
    ···

    }

    个人认为蓝色部分为接收提供了4个urb来接收数据(full speed),从rx_complete 中可以看出,urb 没有数据时阻塞 ,该函数未被调用,然后数据进来时,urb又有数据,又调用了rx_submit来提交数据,

     

    rx_complete 函数部分代码:

    ···

     defer_bh(dev, skb, &dev->rxq);  /*在complete函数完成时调用tasklet_bh*/

     

    if (urb) {
      if (netif_running (dev->net)
        && !test_bit (EVENT_RX_HALT, &dev->flags)) {
       rx_submit (dev, urb, GFP_ATOMIC);      /*接收数据*/        
       return;
      }
     ···

    第二种可能:

     

    由第一种中 tasklet_bh  蓝色部分开始接收数,由于没有数据进来提交urb时,进入default 又开始调用tasklet,形成循环。

    rx_submit部分代码:

    ···

     switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
      case -EPIPE:
       usbnet_defer_kevent (dev, EVENT_RX_HALT);
       break;
      case -ENOMEM:
       usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
       break;
      case -ENODEV:
       if (netif_msg_ifdown (dev))
        devdbg (dev, "device gone");
       netif_device_detach (dev->net);
       break;
      default:
       if (netif_msg_rx_err (dev))
        devdbg (dev, "rx submit, %d", retval);
       tasklet_schedule (&dev->bh);
       break;
      case 0:
       __skb_queue_tail (&dev->rxq, skb);
      }

    ···

     

    个人总结:

    啃了一个礼拜终于啃完了,只是对urb的整体机制不够深入了解呀,但还是把usbnet给裁了,只支持bulk。欢迎技术交流呀!

    奶奶的第一次写技术博客。不容易,希望对大家有帮助。USB驱动是个不错的东西。QQ:497067994

  • 相关阅读:
    HDU2203
    POJ3616
    堆排序
    POJ1386+欧拉回路
    快速排序(实现)
    HDU3549+FordFulkerson
    POJ2155
    POJ1195
    mysql案例~关于linux服务器本身的优化问题
    mysql案例~mysql主从复制延迟概总
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5066532.html
Copyright © 2011-2022 走看看