Linux以其稳定、高效、易定制、硬件支持广泛、源代码开放等特点,已在嵌入式领域迅速崛起,被国际上许多大型的跨国企业用作嵌入式产品的系统平台。
USB是Universal Serial Bus (通用串行总线)的缩写,是1995年由Microsoft、Compaq、IBM等公司联合制定的一种新的PC串行通信协议。它是一种快速、灵活的总线接口。与其它通信接口相比较,USB接口的最大特点是易于使用,这也是USB的主要设计目标。USB的成功得益于在USB标准中除定义了通信的物理层和电器层标准外。还定义了一套相对完整的软件协议堆栈。这使得多数USB设备都很容易在各种平台上工作。作为一种高速总线接口,USB适用于多种设备(如数码相机、MP3播放器、高速数据采集设备等)。另外,USB接口还支持热插拔,而且所有的配置过程都由系统自动完成,无须用户干预。
1 Linux下的USB设备驱动
在Linux内核的不断升级过程中,驱动程序的结构相对稳定。由于USB设备也是外围设备的一种,因此,它的驱动程序结构与普通设备的驱动程序相同。Linux系统的设备分为字符设备(CharDevice)和块设备(BlockDevice)。字符设备支持面向块字符的I/O操作,它不通过系统的快速缓存,而只支持顺序存取。块设备则支持面向块的I/O操作,所有块设备的I/O操作都通过在内核地址空间的I/O缓冲区进行,可以支持几乎任意长度和任意位置上的I/O请求。块设备与字符设备还有一点不同,就是块设备必须能够随机存取(RandomAccess),字符设备则没有这个要求。典型的字符设备包括鼠标、键盘、串行口等,而块设备主要包括硬盘软盘设备、CD-Rom等。由于USB设备主要都是通过快速串行通讯来读写数据,因此一般都可作为字符设备来进行处理。
2 Linux下的USB core
2.1 Linux中USB core与USB的结构关系
Linux操作系统中有一个叫做“USB core”的子系统,可提供支持USB设备驱动程序的API和USB主机控制器的驱动程序。同时提供有许多数据结构、宏定义和功能函数来对硬件或设备进行支持。在Linux下编写USB设备的驱动程序时,从严格意义上讲,就是使用这些USB core的子系统所定义的数据结构、宏和函数来编写数据的处理功能。在Linux下,core、host controller和driver三者之间的关系如图1所示。
2.2 USB core的初始化
USB core从USB子系统的初始化开始。USB子系统的初始化则在文件drivers/usb/core/usb.c里。其代码如下:
subsys_initcall(usb_init);
module_exit(usb_exit);
代码中的subsys_initcall是一个宏,相当于module_init,只不过因为这部分代码是核心,开发者通常把它看作一个子系统,而不仅仅是一个模块。因为USB core模块代表的不是某一个设备,而是所有USB设备赖以生存的模块。因此,在Linux中,像这样把一个类别的设备驱动归结为一个子系统(比如PCI子系统、scsi子系统等)。基本上,drivers/目录下面第一层的每个目录都可算作一个子系统,因为它们代表了一类设备。一般地,usb_init是真正的初始化函数,而usb_exit()则是整个USB子系统结束时的清理函数:
函数usb_init主要完成初始化和注册设备。
2.3 USB里的设备模型
Linux里一个很重要的概念是设备模型。对于驱动来说,设备的概念就是总线和与其相连的各种设备。在内核里,总线、设备、驱动也就是bus、device、driver是设备模型很重要的三个概念,它们都有自己专属的结构。在include/linux/devide.h里的定义为:
struct bus_type {……};
struct device {……);
struct device_driver {……};
每次出现一个设备都要向总线注册,每次出现一个驱动,也要向总线注册。系统初始化时,应扫描连接许多设备,并为每一个设备建立一个struct device的变量。每一次都应有一个驱动程序,并要准备一个struct device_driver结构的变量。还要把这些变量加入相应的链表(如把device插入devices链表,driver插入drivers链表)。这样,通过总线就能找到每一个设备和每一个驱动。然而,假如计算机里只有设备却没有对应的驱动,那么设备将无法工作。反过来,倘若只有驱动却没有设备,驱动也起不了任何作用。对于USB设备,它可以在计算机启动以后再插入或者拔出计算机。由于device可以在任何时刻出现,而driver也可以在任何时刻被加载,所以,每当一个struct device诞生时,它就会去BUS的drivers链表中寻找自己的另一半。如果找到了匹配的设备,就调用device_bind_driver,并绑定好。
Linux设备模型中的总线落实在USB子系统里就是usb_bus_type,它在usb_init函数中可用retval=bus_register(&usb_bus_type)语句注册,而在driver.c文件里的定义如下: