usbnet驱动深入分析-usb虚拟网卡host端【转】

简介: 转自:http://blog.csdn.net/zh98jm/article/details/6339320 1、驱动流程:   2、明确probe函数的功能: probe有usb core 经枚举过程,匹配 id_table ,识别到驱动,并调用probe来初始化一些信息。

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

【作者】 张昺华
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
目录
相关文章
|
19天前
|
负载均衡 安全 Linux
02.Linux网卡:连接虚拟与现实的桥梁🌉
在介绍Linux网卡之前,让我们先迈入时光机🕰️,回到1980年代末期,互联网正在逐步从一个科研网络向公众网络转变,Linux——一个自由和开源的操作系统诞生了🐧。Linux的出现,对于计算机科学领域来说,就像是一场革命🔥,它不仅促进了开源文化的发展🌱,也让更多的人能够自由地使用和修改操作系统💻。
02.Linux网卡:连接虚拟与现实的桥梁🌉
|
15天前
|
Linux SDN 网络虚拟化
Linux虚拟网络设备全景解析:定义、工作模式与实践应用
在深入探索Linux操作系统的强大功能时,我们不可避免地会遇到虚拟网络设备的概念。这些设备扮演着构建和维护虚拟化环境中网络通信的关键角色。本文旨在详细介绍Linux虚拟网络设备的定义、工作模式以及它们的多样化用途。
Linux虚拟网络设备全景解析:定义、工作模式与实践应用
|
Linux SoC
高通平台开发系列讲解(USB篇)port_bridge转发应用分析
高通平台开发系列讲解(USB篇)port_bridge转发应用分析
303 0
高通平台开发系列讲解(USB篇)port_bridge转发应用分析
|
Linux API 芯片
Linux下网卡phy状态检测与控制
最近在一个项目中,集成一个交换机芯片的时候,遇到一些麻烦,发现交换机的性能总是上 不去,100M的交换机,实际交换能力只有10M。跟做硬件的同事一起,花了几周时间调试, 才找到问题。原来是接到交换机芯片上的几个子系统,用的Micrel 8041PHY芯片,默认关闭 了硬件流控,导致交换机无法通过流控来控制网络数据交换,结果使得其性能下降。而交换 机每个端口的PHY与子系统的PHY都使用的Auto Negotiation来协商链接状态,子系统默认不 支持流控,交换机也关闭了流控。
|
存储 网络协议 Linux

热门文章

最新文章