Linux内核USB驱动框架【后面部分转载】

2019-07-13 00:25发布

可以从以下书籍中了解USB驱动的详细知识:
1. Linux内核源代码情景分析(上).pdf
第8章: 设备驱动
  8.9 通用串行外部总线USB:
  
  
2.Linux设备驱动开发详解_宋宝华.pdf
第 20 章USB 主机与设备驱动


下面内容转自:http://book.51cto.com/art/200912/169137.htm 《ARM嵌入式Linux系统开发详解》第25章USB驱动开发,本章讲解了Linux内核USB驱动体系结构、USB设备驱动结构等知识,并在最后给出了两个USB设备驱动开发实例。本节为大家介绍Linux内核USB驱动框架。 AD: 25.2  USB驱动程序框架 Linux内核提供了完整的USB驱动程序框架。USB总线采用树形结构,在一条总线上只能有唯一的主机设备。Linux内核从主机和设备两个角度观察USB总线结构。本节介绍Linux内核USB驱动程序框架。 25.2.1  Linux内核USB驱动框架 图25-2是Linux内核从主机和设备两个角度观察USB总线结构的示意图。 从图25-2中可以看出,Linux内核USB驱动是按照主机驱动和设备驱动两套体系实现的,下面介绍两套体系的结构和特点。 1.基本结构 图25-2的左侧是主机驱动结构。主机驱动的最底层是USB主机控制器,提供了OHCI/EHCI/UHCI这3种类型的总线控制功能。在USB控制器的上一层是主机控制器的驱动,分别对应OHCI/EHCI/UHCI这3种类型的总线接口。USB核心部分连接了USB控制器驱动和设备驱动,是两者之间的转换接口。USB设备驱动层提供了各种设备的驱动程序。 USB主机部分的设计结构完全是从USB总线特点出发的。在USB总线上可以连接各种不同类型的设备,包括字符设备、块设备和网络设备。所有类型的USB设备都是用相同的电气接口,使用的传输协议也基本相同。向用户提供某种特定类型的USB设备时,需要处理USB总线协议。内核完成所有的USB总线协议处理,并且向用户提供编程接口。   (点击查看大图)图25-2  Linux内核USB总线结构 图25-2右侧是设备驱动结构。与USB主机类似,USB设备提供了相同的层次结构与之对应。但是在USB设备一侧使用名为Gadget API的结构作为核心。Gadget API是Linux内核实现的对应USB设备的核心结构。Gadget API屏蔽了USB设备控制器的细节,控制具体的USB设备实现。 2.设备 每个USB设备提供了不同级别的配置信息。一个USB设备可以包含一个或多个配置,不同的配置使设备表现出不同的特点。其中,设备的配置是通过接口组成的。Linux内核定义了USB设备描述结构如下:
  1. struct usb_device_descriptor {  
  2.     __u8  bLength;              // 设备描述符长度  
  3.     __u8  bDescriptorType;      // 设备类型  
  4.  
  5.     __le16 bcdUSB;              // USB版本号(使用BCD编码)  
  6.     __u8  bDeviceClass;         // USB设备类型  
  7.     __u8  bDeviceSubClass;      // USB设备子类型  
  8.     __u8  bDeviceProtocol;      // USB设备协议号  
  9.     __u8  bMaxPacketSize0;      // 传输数据的最大包长  
  10.     __le16 idVendor;            // 厂商编号  
  11.     __le16 idProduct;           // 产品编号  
  12.     __le16 bcdDevice;           // 设备出厂号  
  13.     __u8  iManufacturer;        // 厂商字符串索引  
  14.     __u8  iProduct;             // 产品字符串索引  
  15.     __u8  iSerialNumber;        // 产品序列号索引  
  16.     __u8  bNumConfigurations;   // 最大的配置数量  
  17. } __attribute__ ((packed)); 
从usb_device_descriptor结构定义看出,一个设备描述符定义了与USB设备有关的所有信息。 3.接口 在USB体系中,接口是由多个端点组成的。一个接口代表一个基本的功能,是USB设备驱动程序控制的对象。一个USB设备最少有一个接口,功能复杂的USB设备可以有多个接口。接口描述定义如下:
  1. struct usb_interface_descriptor {  
  2.     __u8  bLength;              // 描述符长度  
  3.     __u8  bDescriptorType;      // 描述符类型  
  4.  
  5.     __u8  bInterfaceNumber;     // 接口编号  
  6.     __u8  bAlternateSetting;    // 备用接口编号  
  7.     __u8  bNumEndpoints;        // 端点数量  
  8.     __u8  bInterfaceClass;      // 接口类型  
  9.     __u8  bInterfaceSubClass;   // 接口子类型  
  10.     __u8  bInterfaceProtocol;   // 接口使用的协议  
  11.     __u8  iInterface;           // 接口索引字符串数值  
  12. } __attribute__ ((packed)); 
4.端点 端点是USB总线通信的基本形式,每个USB设备接口可以认为是端点的集合。主机只能通过端点与设备通信。USB体系结构规定每个端点都有一个唯一的地址,由设备地址和端点号决定端点地址。端点还包括了与主机通信用到的属性,如传输方式、总线访问频率、带宽和端点号等。端点的通信是单向的,通过端点传输的数据只能是从主机到设备或者从设备到主机。端点定义描述如下:
  1. struct usb_endpoint_descriptor {  
  2.     __u8  bLength;              // 描述符长度  
  3.     __u8  bDescriptorType;      // 描述符类型  
  4.  
  5.     __u8  bEndpointAddress;     // 端点地址  
  6.     __u8  bmAttributes;         // 端点属性  
  7.     __le16 wMaxPacketSize;      // 端点接收的最大数据包长度  
  8.     __u8  bInterval;            // 轮询端点的时间间隔  
  9.  
  10.     /* NOTE:  these two are _only_ in audio endpoints. */  
  11.     /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */  
  12.     __u8  bRefresh;  
  13.     __u8  bSynchAddress;  
  14. } __attribute__ ((packed)); 
5.配置 配置是一个接口的集合。Linux内核配置的定义如下:
  1. struct usb_config_descriptor {  
  2.     __u8  bLength;              // 描述符长度  
  3.     __u8  bDescriptorType;      // 描述符类型  
  4.  
  5.     __le16 wTotalLength;        // 配置返回数据长度  
  6.     __u8  bNumInterfaces;       // 最大接口数  
  7.     __u8  bConfigurationValue;  // 配置参数值  
  8.     __u8  iConfiguration;       // 配置描述字符串索引  
  9.     __u8  bmAttributes;         // 供电模式  
  10.     __u8  bMaxPower;            // 接口的最大电流  
  11. } __attribute__ ((packed)); 
配置描述符结构定义了配置的基本属性和接口数量等信息。
25.2.2  主机驱动结构 USB主机控制器有3种类型: OHCI:英文全称是Open Host Controller Interface,是用于SiS和Ali芯片组的USB控制器。 UHCI:英文全称是Universal Host Controller Interface,用于Intel和AMD芯片组的USB控制器。UHCI类型的控制器比OHCI控制器硬件结构要简单,但是需要额外的驱动支持,因此从理论上说速度要慢。 EHCI:是USB 2.0规范提出的一种控制器标准,可以兼容UHCI和OHCI。 1.USB主机控制器驱动 Linux内核使用usb_hcd结构描述USB主机控制器驱动。usb_hcd结构描述了USB主机控制器的硬件信息、状态和操作函数,定义如下:
  1. struct usb_hcd {    /* usb_bus.hcpriv points to this */  
  2.  
  3.     /*        
  4.      * housekeeping                     // 控制器基本信息  
  5.      */  
  6.     struct usb_bus      self;       /* hcd is-a bus */  
  7.  
  8.     const char      *product_desc;  /* product/vendor string */ 
    // 厂商名称字符串  
  9.     char            irq_descr[24];  /* driver + bus # */        
    // 驱动和总线类型  
  10.  
  11.     struct timer_list   rh_timer;   /* drives root-hub polling */ 
    // 根hub轮询时间间隔  
  12.     struct urb      *status_urb;    /* the current status urb */ 
    // 当前urb状态  
  13.  
  14.     /*  
  15.      * hardware info/state              // 硬件信息和状态  
  16.      */  
  17.     const struct hc_driver  *driver;    /* hw-specific hooks */  
    // 控制器驱动使用的回调函数  
  18.  
  19.     /* Flags that need to be manipulated atomically */  
  20.     unsigned long       flags;  
  21. #define HCD_FLAG_HW_ACCESSIBLE  0x00000001  
  22. #define HCD_FLAG_SAW_IRQ    0x00000002  
  23.  
  24.     unsigned        rh_registered:1;/* is root hub registered? */     
    // 是否注册根hub  
  25.  
  26.     /* The next flag is a stopgap, to be removed when all the HCDs  
  27.      * support the new root-hub polling mechanism. */  
  28.     unsigned        uses_new_polling:1;             // 是否允许轮询根hub状态  
  29.     unsigned        poll_rh:1;  /* poll for rh status? */  
  30.     unsigned        poll_pending:1; /* status has changed? */    
    // 状态是否改变  
  31.  
  32.     int         irq;        /* irq allocated */     // 控制器的中断请求号  
  33.     void __iomem        *regs;      /* device memory/io */    

    // 控制器使用的内存和I/O  
  34.     u64         rsrc_start; /* memory/io resource start */        
  35.                                               // 控制器使用的内存和I/O起始地址  
  36.     u64         rsrc_len;   /* memory/io resource length */        
    // 控制器使用的内存和I/O资源长度  
  37.     unsigned        power_budget;   /* in mA, 0 = no limit */  
  38.  
  39. #define HCD_BUFFER_POOLS    4  
  40.     struct dma_pool     *pool [HCD_BUFFER_POOLS];  
  41.  
  42.     int         state;  
  43. #   define  __ACTIVE        0x01  
  44. #   define  __SUSPEND       0x04  
  45. #   define  __TRANSIENT     0x80  
  46.  
  47. #   define  HC_STATE_HALT       0  
  48. #   define  HC_STATE_RUNNING    (__ACTIVE)  
  49. #   define  HC_STATE_QUIESCING  (__SUSPEND|__TRANSIENT|__ACTIVE)  
  50. #   define  HC_STATE_RESUMING   (__SUSPEND|__TRANSIENT)  
  51. #   define  HC_STATE_SUSPENDED  (__SUSPEND)  
  52.  
  53. #define HC_IS_RUNNING(state) ((state) & __ACTIVE)  
  54. #define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)  
  55.  
  56.     /* more shared queuing code would be good; it should support  
  57.      * smarter scheduling, handle transaction translators, etc;  
  58.      * input size of periodic table to an interrupt scheduler.   
  59.      * (ohci 32, uhci 1024, ehci 256/512/1024).  
  60.      */  
  61.  
  62.     /* The HC driver's private data is stored at the end of  
  63.      * this structure.  
  64.      */  
  65.     unsigned long hcd_priv[0]  
  66.             __attribute__ ((aligned (sizeof(unsigned long))));  
  67. }; 
2.OHCI控制器驱动 usb_hcd结构可以理解为一个通用的USB控制器描述结构。OHCI主机控制器是usb_hcd结构的具体实现,内核使用ohci_hcd结构描述OHCI主机控制器,定义如下:
  1. struct ohci_hcd {  
  2.     spinlock_t      lock;  
  3.  
  4.     /*  
  5.      * I/O memory used to communicate with the HC (dma-consistent)

    // 用于HC通信的I/O内存地址  
  6.      */  
  7.     struct ohci_regs __iomem *regs;  
  8.  
  9.     /*  
  10.      * main memory used to communicate with the HC (dma-consistent).    
    // 用于HC通行的主内存地址  
  11.      * hcd adds to schedule for a live hc any time, but removals finish  
  12.      * only at the start of the next frame.  
  13.      */  
  14.     struct ohci_hcca    *hcca;  
  15.     dma_addr_t      hcca_dma;  
  16.  
  17.     struct ed       *ed_rm_list;        /* to be removed */  
    // 将被移除列表  
  18.  
  19.     struct ed       *ed_bulktail;       /* last in bulk list */ 
    // 列表最后一项  
  20.     struct ed       *ed_controltail;    /* last in ctrl list */     
    // 控制列表最后一项  
  21.     struct ed       *periodic [NUM_INTS];   /* shadow int_table */  
  22.  
  23.     /*  
  24.      * OTG controllers and transceivers need software interaction;  
  25.      * other external transceivers should be software-transparent   
  26.      */  
  27.     struct otg_transceiver  *transceiver;  
  28.  
  29.     /*  
  30.      * memory management for queue data structures 

    // 内存管理队列使用的数据结构  
  31.      */  
  32.     struct dma_pool     *td_cache;  
  33.     struct dma_pool     *ed_cache;  
  34.     struct td       *td_hash [TD_HASH_SIZE];  
  35.     struct list_head    pending;  
  36.  
  37.     /*  
  38.      * driver state  
  39.      */  
  40.     int         num_ports;  
  41.     int         load [NUM_INTS];  
  42.     u32             hc_control; /* copy of hc control
    reg */// HC控制寄存器复制
  43.     unsigned long       next_statechange;   /* suspend/resume */    
    // 挂起/恢复  
  44.     u32         fminterval;     /* saved register */    // 保存的寄存器  
  45.  
  46.     struct notifier_block   reboot_notifier;  
  47.  
  48.     unsigned long       flags;      /* for HC bugs */  
  49. /* 以下是各厂家芯片ID定义 */  
  50. #define OHCI_QUIRK_AMD756   0x01            /* erratum #4 */  
  51. #define OHCI_QUIRK_SUPERIO  0x02            /* natsemi */  
  52. #define OHCI_QUIRK_INITRESET    0x04        /* SiS, OPTi, ... */  
  53. #define OHCI_BIG_ENDIAN     0x08            /* big endian HC */  
  54. #define OHCI_QUIRK_ZFMICRO  0x10            /* Compaq ZFMicro chipset*/  
  55.     // 芯片的初始化逻辑里也同样会有怪异的Bug  
  56.  
  57. }; 
OHCI主机控制器是嵌入式系统最常用的一种USB主机控制器。

25.2.3  设备驱动结构 USB协议规定了许多种USB设备类型。Linux内核实现了音频设备、通信设备、人机接口、存储设备、电源设备、打印设备等几种USB设备类。 1.基本概念 Linux内核实现的USB设备类驱动都是针对通用的设备类型设计的。如存储设备类,只要USB存储设备是按照标准的USB存储设备规范实现的,就可以直接被内核USB存储设备驱动程序驱动。如果一个USB设备是非标准的,则需要编写对应设备的驱动程序。 Linux内核为不同的USB设备分配了设备号。在内核中还提供了一个usbfs文件系统,通过usbfs文件系统,用户可以方便地使用USB设备。为了使用usbfs,使用root权限在控制台输入"mount -t usbfs none /proc/bus/usb",可以加载USB文件系统到内核。在插入一个USB设备的时候,内核会试图加载对应的驱动程序。 2.设备驱动结构 内核使用usb_driver结构体描述USB设备驱动,定义如下:
  1. struct usb_driver {  
  2.     const char *name;  
  3.  
  4.     int (*probe) (struct usb_interface *intf,  
  5.                    const struct usb_device_id *id);         // 探测函数  
  6.  
  7.     void (*disconnect) (struct usb_interface *intf);        // 断开连接函数  
  8.  
  9.     int (*ioctl) (struct usb_interface *intf, unsigned int code,  
  10.                    void *buf);                              // I/O控制函数  
  11.  
  12.     int (*suspend) (struct usb_interface *intf, pm_message_t message); 
    // 挂起函数  
  13.     int (*resume) (struct usb_interface *intf);         // 恢复函数  
  14.  
  15.     void (*pre_reset) (struct usb_interface *intf);  
  16.     void (*post_reset) (struct usb_interface *intf);  
  17.  
  18.     const struct usb_device_id *id_table;  
  19.  
  20.     struct usb_dynids dynids;  
  21.     struct device_driver driver;  
  22.     unsigned int no_dynamic_id:1;  
  23. }; 
实现一个USB设备的驱动主要是实现probe()和disconnect()函数接口。probe()函数在插入USB设备的时候被调用,disconnect()函数在拔出USB设备的时候被调用。在25.2.4节中详细讲解USB设备驱动程序框架。 3.USB请求块 USB请求块(USB request block,urb)的功能类似于网络设备中的sk_buff,用于描述USB设备与主机通信的基本数据结构。urb结构在内核中定义如下:
  1. struct urb  
  2. {  
  3.     /* private: usb core and host controller only
    fields in the urb */  // 私有数据,仅供USB核心和主机控制器使用  
  4.     struct kref kref;       /* reference count of the URB */ 

    // urb引用计数  
  5.     spinlock_t lock;        /* lock for the URB */  // urb锁  
  6.     void *hcpriv;           /* private data for host controller */ 

    // 主机控制器私有数据  
  7.     int bandwidth;          /* bandwidth for INT/ISO request */   
    // 请求带宽  
  8.     atomic_t use_count;     /* concurrent submissions counter */ 

    // 并发传输计数  
  9.     u8 reject;          /* submissions will fail */ // 传输即将失败标志  
  10.  
  11.     /* public: documented fields in the urb that can 
    be used by drivers */  // 公有数据,可以被驱动使用  
  12.     struct list_head urb_list;  /* list head for use by the urb's 
    // 链表头  
  13.                      * current owner */  
  14.     struct usb_device *dev;     /* (in) pointer to associated device */
    // 关联的USB设备  
  15.     unsigned int pipe;      /* (in) pipe information */     // 管道信息  
  16.     int status;         /* (return) non-ISO status */       // 当前状态  
  17.     unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/  
  18.     void *transfer_buffer;      /* (in) associated data buffer */        
    // 数据缓冲区  
  19.     dma_addr_t transfer_dma;    /* (in) dma addr for transfer_buffer */ 
    // DMA使用的缓冲区  
  20.     int transfer_buffer_length; /* (in) data buffer length */  

    // 缓冲区大小  
  21.     int actual_length;      /* (return) actual transfer length */      
    // 
    际接收或发送数据的长度  
  22.     unsigned char *setup_packet;    /* (in) setup packet (control only) */
  23.     dma_addr_t setup_dma;       /* (in) dma addr for setup_packet */  

    // 设置数据包缓冲区  
  24.     int start_frame;        /* (modify) start frame (ISO) */      

    // 等时传输中返回初始帧  
  25.     int number_of_packets;      /* (in) number of ISO packets */ 

    // 等时传输中缓冲区数据  
  26.     int interval;           /* (modify) transfer interval   

    // 轮询的时间间隔  
  27.                      * (INT/ISO) */  
  28.     int error_count;        /* (return) number of ISO errors */ 
    // 出错次数  
  29.     void *context;          /* (in) context for completion */  
  30.     usb_complete_t complete;    /* (in) completion routine */  
  31.     struct usb_iso_packet_descriptor iso_frame_desc[0];  
  32.                     /* (in) ISO ONLY */  
  33. }; 
内核提供了一组函数操作urb类型的结构变量。urb的使用流程如下: (1)创建urb。在使用之前,USB设备驱动需要调用usb_alloc_urb()函数创建一个urb,函数定义如下:
  1. struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags); 
iso_packets参数是urb包含的等时数据包数目,如果为0表示不创建等时数据包。mem_flags参数是分配内存标志。如果分配urb成功,函数返回一个urb结构类型的指针,否则返回0。 内核还提供了释放urb的函数,定义如下:
  1. void usb_free_urb(struct urb *urb) 
在不使用urb的时候(退出驱动程序或者挂起驱动),需要使用usb_free_urb()函数释放urb。 (2)初始化urb,设置USB设备的端点。使用内核提供的usb_int_urb()函数设置urb初始结构,定义如下:
  1. void usb_init_urb(struct urb *urb); 
(3)提交urb到USB核心。在分配并设置urb完毕后,使用usb_submit_urb()函数把新的urb提交到USB核心,函数定义如下:
  1. int usb_submit_urb(struct urb *urb, gfp_t mem_flags); 
参数urb指向被提交的urb结构,mem_flags是传递给USB核心的内存选项,用于告知USB核心如何分配内存缓冲区。如果函数执行成功,urb的控制权被USB核心接管,否则函数返回错误。