基于USB设备的Linux网络驱动程序开发
口。USB驱动程序通过发送URB(USB Request Block)与USB Core交换数据,USB Core解释URB,并将URB中包含的数据请求通过USB主机控制器发送给对应的USB设备。另一方面,USB Core负责检测USB设备的插入和拔出等事件,当这些事件发生时,USB Core通知内核,使内核能够调用驱动程序的相应回调函数来通知驱动程序对这些事件做出响应。 4.2 USB网络设备驱动程序设计 除了必要的回调函数以外,Linux下的每一种驱动程序都必须有初始化函数和卸载函数。初始化函数需要根据相应的硬件设备,向内核注册不同的数据结构,来声明自己对该设备的支持。对于USB设备来说,初始化函数中需要注册struct usb_driver,该数据结构中的关键域分别为:owner,用于内核维护模块使用计数;name,驱动程序名称;probe,设备初始化函数指针;disconnect,设备删除函数指针;id_table,驱动程序支持设备列表。设备列表指明该驱动程序所支持的设备标识,对于USB设备来说,一般是Vendor ID和Product ID。每当一个USB设备插入系统,内核将查找现有的所有USB设备列表,判断应该调用哪个驱动程序所注册的probe函数来完成设备初始化。当USB设备拔出时,相应的disconnect函数也会被调用,来处理驱动程序的卸载。因此,USB网络驱动程序应在probe函数中初始化设备和注册网络接口。在disconnect函数中注销网络接口。 probe函数的主要代码如下: ether_setup(netdev); //使用内核通用的以太网回调函数设定hard_header等函数 SET_MODULE_OWNER(netdev); //设定模块拥有者,用于维护使用计数 netdev->open = thu_plc_open; //设定open函数 netdev->stop = thu_plc_close; //设定stop函数 netdev->tx_timeout = thu_plc_tx_timeout; //设定超时函数 netdev->hard_start_xmit = thu_plc_start_xmit; //设定发送函数 netdev->get_stats = thu_plc_netdev_stats; //设定状态统计函数 netdev->watchdog_timeo = THU_PLC_TX_TIMEOUT; //设定超时值 netdev->mtu = THU_PLC_MTU; //配置网络接口的MTU …… if(!thu_plc_config_dev(dev, intf, id)) { //配置USB网络设备 printk("couldn't configure the device\n"); break; } …… if(register_netdev(netdev) != 0) { //注册ethernet接口 printk("couldn't register the device\n"); break; } …… 其中thu_plc_config_dev函数用来检测和配置USB设备。当probe函数成功返回时,驱动程序已经完成了USB设备的检测和网络接口的注册。而网络接口的正式启用还需要用户或应用程序使能该接口。例如用户可以使用ifconfig命令来启用网络接口。当接口被正式启用时,驱动程序的open回调函数被调用,由于USB设备没有类似于硬件中断的异步通知方式,需要主机主动查询是否有数据需要读取,而网络设备则需要有能力来异步通知操作系统数据包的到达,因此,在open函数中需要向USB Core发送一个读请求的URB,使得当USB设备需要将数据包输入主机时,Linux能够及时响应。 open回调函数的主要代码如下: …… usb_fill_bulk_urb(dev->rx_urb, //构造读请求的URB dev->udev, usb_rcvbulkpipe(dev->udev, 6), //指定读端点 dev->rx_skb->data, 512, read_bulk_callback, //使用read_bulk_callback做为URB的 dev //回调函数。 ); if((result = usb_submit_urb(dev->rx_urb, GFP_KERNEL))){ //将URB发送给 …… //USB Core } netif_start_queue(netdev); //使能网络传输队列 …… 当读请求URB完成时,意味着主机收到了一个数据包或该URB超时,此时read_bulk_callback将会被内核调用。无论是哪种情况,为了将来可能到来的数据包能够及时得被主机读取,驱动程序都应该再发送一个读请求URB给USB Core。而在主机收到数据包的情况下,read_bulk_callback函数构造一个skb_buff数据结构来描述数据包,并调用 netif_rx函数,把该数据包交给上层协议,从而完成一次接受过程。 与接受过程相比,发送数据包的过程简单了很多。当网络子系统准备发送一个数据包时,上层协议将会构造一个skb_buff数据结构来描述数据包,并且调用网络驱动程序注册的hard_start_xmit回调函数来发送该数据包。由于该函数被调用时内核持有xmit_lock自旋锁,因而驱动程序可以不必考虑对设备写操作的同步问题。hard_start_xmit函数根据数据包的长度将其拆分为USB设备可以传输的长度,然后构造相应的写请求 URB,发送至USB Core即可。 hard_start_xmit回调函数的主要代码如下: …… usb_fill_bulk_urb(dev->tx_urb, //构造写请
- REDIce-Linux--灵活的实时Linux内核(11-12)
- linux文件系统基础(02-09)
- Linux标准趋向统一(11-12)
- linux基础技术(02-09)
- LINUX的目录树(02-09)
- 在Windows下启动Linux(02-09)