1.对于每个PC来说,都有一个或者多个称为主机(host)控制器的设备,该主机控制器和一个根集线器(Hub)作为一个整体。
2.每个Host控制器其实就是一个PCI设备,挂载在PCI总线上。驱动开发人员应该给Host控制器提供驱动程序,用usb_hcd结构体表示。
3.USB Host控制器都会自带一个集线器,称为根集线器,其又可接子集线器。
4.USB设备是插在USB总线上工作的设备,广义上讲Hub也算是USB设备。
5.USB驱动有USB主机控制器驱动和USB设备驱动组成,前者驱动芯片上的主机控制器,后者驱动具体的USB设备。
6.通常计算机的CPU不是直接和USB设备通信,而是和主机控制器通信。CPU先发送指令给主机控制器,后者指挥USB设备完成相应的任务。
7.USB主机控制器驱动用hc_driver表示,其在/drivers/usb/core/hcd.h中定义。
8.USB核心层(USB core)负责对USB设备的整体控制,包括实现USB主机控制器到USB设备之间的数据通信。
9.USB设备驱动用usb_device 表示,主要用来将USB设备挂接到USB核心中,并启动USB设备。对设备的具体读写操作放在usb_driver中的usb_class_drivers成员来实现,该成员定义了一个file_operations结构体,用来对设备进行读写操作。
10.USB设备和USB驱动之间进行通信需要USB设备固件和USB协议二者。固件指的是“固化的软件”,固化在集成电路内部的程序,负责控制和协调集成电路,并且在设备和总线之间收发数据。驱动则有二个(已提及)。
11.大部分驱动程序都在drivers目录下,USB目录包含了所有USB设备的驱动。在USB目录下有一个重要的storage目录,存放了USB设备驱动的代码。
12.Linux内核源码中几乎每个目录下都有一个Makefile文件和Kconfig文件。Makefile定义哪些文件需要编译,哪些不需要编译;Kconfig文件用来组织需要编译入内核的模块和功能,其给用户提供一个选择配置内核的机会。
14.Linux系统中总线的概念和时间物理主机中总线概念不同。实际物理总线入数据总线和地址总线等。Linux中总线是与物理总线相对应的数据结构。如USB总线、SCSI总线、PCI总线,分别对应usb_bus_type,scsi_bus_type,pci_bus_type变量,他们的类型都是bus_type
15.Linux将USB总线和两个链表联系起来,一个是drivers_kset,另一个是devices_kset.前者表示连接到该总线上的所有驱动程序,后者表示连接到总线上的所有设备。当有新设备添加入系统时,系统为设备分配一个struct device数据结构,并将其挂接到devices_kset链表中。而每当驱动注册时会将自己在总线上注册,并连接到总线的驱动链表中。这时驱动会遍历总线的设备链表,寻找自己合适的设备。
16.USB设备驱动使用usb_driver结构体表示。这个结构体成员:name字段是指向驱动程序名字的指针。probe函数指向USB驱动程序的探测函数。当有USB设备插入时,USB核心层会调用该函数进行设备的初始化工作。disconnect函数指向USB驱动的断开函数,当驱动程序从内核中卸载时,会调用它做一些卸载工作。ioctl函数用来对设备进行控制的函数。id_table表包含了驱动支持的设备列表。
17.如何知道驱动支持哪些设备呢?通过usb_driver结构体中的id_table成员完成这个功能。它描述了所有支持的USB设备列表,它指向一个usb_device_id数组。usb_device_id结构体包含了USB设备的相关信息。
19.通过调用usb_deregister函数对设备驱动进行注销。
20.usb_driver结构体中的probe函数原型:int (*probe) (struct usb_interface *intf,const struct usb_device_id *id);第一个参数usb_interface是驱动中最重要的一个结构体,代表设备的一种功能,在USB驱动中只有一个。
21.USB协议规定,USB设备的逻辑结构包含设备、配置、接口、端点。每一项只是软件上划分而已,分别用usb_device,usb_host_config,usb_interface,usb_host_endpoint表示。一个USB设备(包括复合设备)用usb_device结构体表示,而且只有一个。一个配置是一组不同功能的组合,多个配置之间相互切换。接口代表一个基本的功能。USB核心层在设备插入时会读取USB设备接口的信息,并创建一个usb_interface的结构体,接着核心层在总线上找到合适的驱动后,调用probe函数并传入。
22.端点(usb_host_endpoint)。主机只能通过端点和USB设备通信,只能单向传输。U盘有输出端点、输入端点和控制端点。控制端点为端点0,控制初始化工作,必不可少。usb_host_endpoint结构体定义中的成员:struct usb_endpoint_descriptor desc;//端点描述符,必不可少 struct list_head urb_list;//端点要处理的urb队列,urb(USB request block)包含了传输的所有信息
23.usb_endpoint_descriptor为端点描述符。
24.端点的四种通信方式:控制传输、中断传输、批量传输、等时传输。
端点定义为:
struct usb_endpoint_descriptor
{
__u8 bLength;//表示端点描述符的长度,以字节为单位
__u8 bDescriptorType;//表示描述符的类型,这里就是USB_DT_ENDPOINT,0x05
__u8 bEndpointAddress;//0-3位表示端点号,最高位表示端点的方向,可与USB_ENDPOINT_DIR_MASK(0x80)相与得到,常用到宏USB_DIR_OUT(0),USB_DIR_IN(0x80)
__u8 bmAttributes;//表示一种属性
__le16 wMaxPacketSize;//端点一次可处理的最大字节数,如果发送大于它的字节数,则分多次传输
__u8 bInterval;//端点数据传输 的时间间隔
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));//__attribute__ ((packed))是一个编译选项,告诉编译器,这个结构的元素都是一字节对齐的,不需要填充位。
25.接口描述符:
struct usb_interface_descriptor {
//描述符的字节长度。协议里规定,每个描述符必须以一个字节打头来表明描述符的长度。接口描述符的bLength应该是9
//描述符的类型。各种描述符的类型都在ch9.h, * Descriptor types ... USB 2.0 spec table 9.5
//接口号。每个配置可以包含多个接口,这个值就是它们的索引值
//接口拥有的端点数量。这里并不包括端点0
//此Interface所属Class。例如:HID=0x03
//此值基于bInterfaceClass之上。表明在某个Interface class中的子class。例如:HID中有:USB_INTERFACE_SUBCLASS_BOOT
//同上,HID中就有USB_INTERFACE_PROTOCOL_MOUSE
} __attribute__ ((packed));
26.urb传输过程
驱动程序要进行数据传输时,需要分配并初始化一个urb结构体,将其提交给usb核心层。USB核心层对urb进行解析,将控制信息提交给主机控制器,由主机控制器负责数据到设备的传输,当数据回传到主机控制器后,会转发给USB核心,唤醒等待的驱动程序,由驱动程序完成剩下的工作。
分配urb函数usb_alloc_urb()
销毁urb函数usb_free_urb()
提交urb函数usb_submit_urb()