转自: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

usbnet驱动深入分析-usb虚拟网卡host端【转】的更多相关文章

  1. Linux主机USB RNDIS网卡驱动实现不完整导致的一例问题

    某通信模块设备,通过USB提供RDNIS和ECM网卡功能.在实际应用中发现,USB RNDIS网卡模式下,当使用AT指令以不同的CID拨号的时候,在Windows主机上能正常拨号成功,但在Linux主 ...

  2. 二十、网卡框架分析、虚拟网卡驱动和DM9621驱动分析

    一.网络设备驱动的结构 网卡设备不同于字符设备和块设备, 网络设备并不对应于/dev目录下的文件,它存放在/sys/class/net目录下. Linux系统对网络设备驱动定义了四个层次: 1. 网络 ...

  3. 解决vmware安装 win7 后 没有虚拟网卡驱动 不能上网的问题

    项目需要用到win7 32位系统,于是装个虚拟机,换了好几个系统资源,都是没有网卡驱动, XP 2003 都能上网唯独WIN7 不行,安装vmware tools也不管用,终于找到了这个东西.vmwa ...

  4. 26.Linux-网卡驱动介绍以及制作虚拟网卡驱动(详解)

    1.描述 网卡的驱动其实很简单,它还是与硬件相关,主要是负责收发网络的数据包,它将上层协议传递下来的数据包以特定的媒介访问控制方式进行发送, 并将接收到的数据包传递给上层协议. 网卡设备与字符设备和块 ...

  5. 虚拟网卡 TUN/TAP 驱动程序设计原理

    简介 虚拟网卡Tun/tap驱动是一个开源项目,支持很多的类UNIX平台,OpenVPN和Vtun都是基于它实现隧道包封装.本文将介绍tun/tap驱动的使用并分析虚拟网卡tun/tap驱动程序在li ...

  6. 虚拟网卡TUN/TAP 驱动程序设计原理

    昨天韦哥写了<Linux下Tun/Tap设备通信原理>一文,只提到了两个使用Tun的用户进程之间的通信路径,并没有说明Tun虚拟网卡驱动是如何实现的,而正好看到了这里的一篇讲解这方面的文章 ...

  7. Linux网卡驱动框架及制作虚拟网卡

    1.概述 网卡驱动与硬件相关,主要负责收发网络的数据包,将上层协议传递下来的数据包以特定的媒介访问控制方式进行发送,并将接收到的数据包传递给上层协议. 网卡设备与字符设备,块设备不同,网络设备驱动程序 ...

  8. 虚拟网卡 TUN/TAP 驱动程序设计原理(经典)

    盗用-收藏 简介 虚拟网卡Tun/tap驱动是一个开源项目,支持很多的类UNIX平台,OpenVPN和Vtun都是基于它实现隧道包封装.本文将介绍tun/tap驱动的使用并分析虚拟网卡tun/tap驱 ...

  9. 【驱动】USB驱动·入门

    [驱动]USB驱动·入门 Preface USB是目前最流行的系统总线之一.随着计算机周围硬件的不断扩展,各种设备使用不同的总线接口,导致计算机外部总线种类繁多,管理困难.USB总线正是因此而诞生的. ...

随机推荐

  1. Eclipse中设置作者、日期等的方式

    1.点击Windows->Preferences->Java->Code Style->Code Templates: 2.点击展开右侧的Comments选项卡,里面的选项对应 ...

  2. BZOJ3252 攻略(贪心+dfs序+线段树)

    考虑贪心,每次选价值最大的链.选完之后对于链上点dfs序暴力修改子树.因为每个点最多被选一次,复杂度非常正确. #include<iostream> #include<cstdio& ...

  3. java中new两个对象,在堆中开辟几个对象空间

    内存堆中有两个对象,两个对象里都有独立的变量.p1 p2指向的不是同一个内存空间. 也可以这样描述引用p1,p2指向两个不同的对象.

  4. 【刷题】BZOJ 3591 最长上升子序列

    Description 给出1~n的一个排列的一个最长上升子序列,求原排列可能的种类数. Input 第一行一个整数n. 第二行一个整数k,表示最长上升子序列的长度. 第三行k个整数,表示这个最长上升 ...

  5. 谷歌钦定的编程语言Kotlin大揭秘

    第一时间关注程序猿(媛)身边的故事 谷歌钦定的编程语言Kotlin大揭秘 语法+高级特性+实现原理:移动开发者升职加薪宝典! 谷歌作为世界级的科技公司巨头,强悍的技术研发与创新能力使其一直是业界的楷模 ...

  6. HDU.5692 Snacks ( DFS序 线段树维护最大值 )

    HDU.5692 Snacks ( DFS序 线段树维护最大值 ) 题意分析 给出一颗树,节点标号为0-n,每个节点有一定权值,并且规定0号为根节点.有两种操作:操作一为询问,给出一个节点x,求从0号 ...

  7. ubuntu下访问其他盘出现挂在错误解决办法

    Error mounting /dev/sda5 at /media Linux下不能进入windows的NTFS分区之挂载错误问题 电 脑安装了win8,后在另一个分区(在win8下未分配空间)安装 ...

  8. 四、java面向对象编程_2

    目录 六.对象的创建和使用 七.this关键字 八.static关键字 九.package和import语句 十.类的继承 十一.访问控制 十二.方法的重写 十三.super关键字 十四.继承中的构造 ...

  9. Date时间格式比较大小

    方法一: 两个Date类型的变量可以通过compareTo方法来比较.此方法的描述是这样的:如果参数 Date 等于此 Date,则返回值 0:如果此 Date 在 Date 参数之前,则返回小于 0 ...

  10. select()函数

    select(),确定一个或多个套接口的状态,本函数用于确定一个或多个套接口的状态,对每一个套接口,调用者可查询它的可读性.可写性及错误状态信息,用fd_set结构来表示一组等待检查的套接口,在调用返 ...