Linux USB 驱动

来源:互联网 发布:清华大学软件工程硕士 编辑:程序博客网 时间:2024/06/06 10:49
一、USB连接结构

        USB采用树形拓扑结构,如图2.3所示。对于每个PC来说,都有一个或多个称为Host控制器(HC)的设备,该Host控制器和一个根Hub作为一个整体;这个根Hub下可以接多级的Hub,每个子Hub又可以接子Hub;每个USB作为一个节点接在不同级别的Hub上;一个Host控制器下最多可连接127个USB设备。


二、USB驱动结构
        USB驱动可以从两个角度去观察,一个是主机角度,另一个是设备角度。

        从主机角度看,USB驱动处于最底层的是USB主机控制器硬件,其上是USB主机控制器驱动,主机控制器驱动上为USB核心层,最上面是USB设备驱动(针对特定的设备如U盘、键盘、摄像头等)。因此,从主机角度来说要实现的驱动包括USB主机控制器驱动和USB设备驱动,前者是控制插入其中的USB设备,后者控制USB设备和高层的通信。        USB核心层则负责USB驱动管理和协议处理等工作。USB设备驱动和USB核心层之间、USB核心层和USB主机控制器驱动之间的通信均是通过USB请求包(USB request block:URB)进行数据的传递。Linux内核提供了一系列函数操作URB,如创建、销毁、提交和取消等。
        从设备角度看,在USB控制器之上有USB设备控制器(UDC)驱动、Gadget API和Gadget驱动程序。USB设备控制器驱动直接访问USB控制器,控制其和主机上的USB控制器进行通信,同时向上提供与硬件相关的函数接口,Gadget API对函数接口进行了简单的包装。Gadget驱动程序控制USB设备功能的实现,使设备表现出相应特性如“USB Mass Storage”、“打印机”等。

三、USB设备的逻辑组织
        USB设备的逻辑组织包含了设备、配置、接口和端点四层。
        每个USB设备都提供了不同级别的配置信息,可以包含一个或多个配置,不同的配置使设备有不同的功能。一个配置有一个或多个接口,而每个接口有零个或多个端点组成,如图2.5所示。一个配置中所有接口可同时有效,且对应不同的驱动程序。主机通过USB设备最末端的端点与设备进行通信。每个端点有唯一的地址且数据传输方向是单项的,它通过管道(Pipes)和USB主机控制器连接。


        在设备、配置、接口和端点的定义结构体中,都有相应的成员用来描述这种层次化的配置信息,称作描述符。


四、USB主机控制器驱动
        上面提到USB主机控制器是最底层的结构,直接与USB设备的主机控制器进行通信。其功能主要有检测外围USB设备的插入和拔出、管理主机和设备之间的控制信息、管理主机和设备之间的数据交互、连接USB状态和活动统计、休眠和唤醒USB设备等。
        目前的PC结构中,USB主机控制器是架构在PCI总线上作为PCI总线上的一个设备而存在的,因此编写主机控制器驱动既要编写PCI设备驱动,也要创建主机控制器驱动,填充其数据结构,编写对应的接口函数。PCI驱动可以通过函数pci_register_driver进行注册,函数参数struct pci_driver为描述了PCI驱动的结构体。在struct pci_driver的probe接口中通过调用函数usb_create_hcd创建主机控制器设备。函数usb_create_hcd的参数struct hc_driver定义了一些操作接口函数,这些接口函数是驱动编写需要重点实现的。
        struct pci_driver和struct hc_driver结构中部分成员如下:

struct pci_driver {struct list_head node;char *name;const struct pci_device_id *id_table;int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id)void (*remove) (struct pci_dev *dev);int  (*suspend) (struct pci_dev *dev, pm_message_t state);int  (*resume) (struct pci_dev *dev);void (*shutdown) (struct pci_dev *dev);……};
struct list_head node  这是链表的头;
char* name 驱动的名字,它必须是唯一的,在内核中所有的PCI驱动里面,通常被设置为各驱动模块名字相同,它显示在在sysfs中的/sysbus/pci/drivers/下;
const struct pci_device_id  *id_table  是一个指向pci设备的id编号的指针,用于描述当前PCI设备的编号,一般用做probe的输入参数;
int (*probe) (struct pci_dev *dev, const struct pci_device_id *id) 指向PCI驱动中的probe函数指针,这个函数被PCI核心调用,当PCI核心认为有一个它可以控制的struct pci_dev时,它传递struct pci_dev和一个指向pci_device_id的指针给这个函数,用来决定是否控制该设备;如果这个PCI核心需要这个设备,它应当初始化这个设备,并返回0;如果PCI核心不想拥有这个设备,或者产生一个错误,它应当返回一个负的错误值;
void (*remove) (struct pci_dev  *dev) 指向PCI核心在struct pci_dev被告从系统中去除时调用的函数指针,或者当PCI驱动被从内核中卸载时;
int (*suspend) (struct pci_dev  *dev, pm_message_t state) 当struct pci_dev被挂起时PCI核心调用的函数指针,挂起状态在state 变量时传递,这个函数是可选的;
int (*resume) (struct pci_def  *dev) 当pci_dev被告恢复时PCI核心调用的函数指针,它的调用一定是在suspend函数执行之后,这个函数可选;
void (*shutdown) (struct pci_dev *dev) 当此设备需要关闭时,此函数指针所指向的函数将会被调用。


struct hc_driver{int (*reset) (struct usb_hcd *hcd);int (*start) (struct usb_hcd *hcd);int (*suspend) (struct usb_hcd *hcd, pm_message_t message);int (*resume) (struct usb_hcd *hcd);void (*stop) (struct usb_hcd *hcd);int (*get_frame_number) (struct usb_hcd *hcd);int (*urb_enqueue) (struct usb_hcd *hcd,int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);/* root hub support */……}

(本文是将相关材料整理后写出的,来源:宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2010)

0 0
原创粉丝点击