Linux内核USB驱动框架【后面部分转载】
2013-11-13 16:25
260 查看
可以从以下书籍中了解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右侧是设备驱动结构。与USB主机类似,USB设备提供了相同的层次结构与之对应。但是在USB设备一侧使用名为Gadget API的结构作为核心。Gadget API是Linux内核实现的对应USB设备的核心结构。Gadget API屏蔽了USB设备控制器的细节,控制具体的USB设备实现。
2.设备
每个USB设备提供了不同级别的配置信息。一个USB设备可以包含一个或多个配置,不同的配置使设备表现出不同的特点。其中,设备的配置是通过接口组成的。Linux内核定义了USB设备描述结构如下:
struct usb_device_descriptor {
__u8 bLength; // 设备描述符长度
__u8 bDescriptorType; // 设备类型
__le16 bcdUSB; // USB版本号(使用BCD编码)
__u8 bDeviceClass; // USB设备类型
__u8 bDeviceSubClass; // USB设备子类型
__u8 bDeviceProtocol; // USB设备协议号
__u8 bMaxPacketSize0; // 传输数据的最大包长
__le16 idVendor; // 厂商编号
__le16 idProduct; // 产品编号
__le16 bcdDevice; // 设备出厂号
__u8 iManufacturer; // 厂商字符串索引
__u8 iProduct; // 产品字符串索引
__u8 iSerialNumber; // 产品序列号索引
__u8 bNumConfigurations; // 最大的配置数量
} __attribute__ ((packed));
从usb_device_descriptor结构定义看出,一个设备描述符定义了与USB设备有关的所有信息。
3.接口
在USB体系中,接口是由多个端点组成的。一个接口代表一个基本的功能,是USB设备驱动程序控制的对象。一个USB设备最少有一个接口,功能复杂的USB设备可以有多个接口。接口描述定义如下:
struct usb_interface_descriptor {
__u8 bLength; // 描述符长度
__u8 bDescriptorType; // 描述符类型
__u8 bInterfaceNumber; // 接口编号
__u8 bAlternateSetting; // 备用接口编号
__u8 bNumEndpoints; // 端点数量
__u8 bInterfaceClass; // 接口类型
__u8 bInterfaceSubClass; // 接口子类型
__u8 bInterfaceProtocol; // 接口使用的协议
__u8 iInterface; // 接口索引字符串数值
} __attribute__ ((packed));
4.端点
端点是USB总线通信的基本形式,每个USB设备接口可以认为是端点的集合。主机只能通过端点与设备通信。USB体系结构规定每个端点都有一个唯一的地址,由设备地址和端点号决定端点地址。端点还包括了与主机通信用到的属性,如传输方式、总线访问频率、带宽和端点号等。端点的通信是单向的,通过端点传输的数据只能是从主机到设备或者从设备到主机。端点定义描述如下:
struct usb_endpoint_descriptor {
__u8 bLength; // 描述符长度
__u8 bDescriptorType; // 描述符类型
__u8 bEndpointAddress; // 端点地址
__u8 bmAttributes; // 端点属性
__le16 wMaxPacketSize; // 端点接收的最大数据包长度
__u8 bInterval; // 轮询端点的时间间隔
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
5.配置
配置是一个接口的集合。Linux内核配置的定义如下:
struct usb_config_descriptor {
__u8 bLength; // 描述符长度
__u8 bDescriptorType; // 描述符类型
__le16 wTotalLength; // 配置返回数据长度
__u8 bNumInterfaces; // 最大接口数
__u8 bConfigurationValue; // 配置参数值
__u8 iConfiguration; // 配置描述字符串索引
__u8 bmAttributes; // 供电模式
__u8 bMaxPower; // 接口的最大电流
} __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主机控制器的硬件信息、状态和操作函数,定义如下:
struct usb_hcd { /* usb_bus.hcpriv points to this */
/*
* housekeeping // 控制器基本信息
*/
struct usb_bus self; /* hcd is-a bus */
const char *product_desc; /* product/vendor string */
// 厂商名称字符串
char irq_descr[24]; /* driver + bus # */
// 驱动和总线类型
struct timer_list rh_timer; /* drives root-hub polling */
// 根hub轮询时间间隔
struct urb *status_urb; /* the current status urb */
// 当前urb状态
/*
* hardware info/state // 硬件信息和状态
*/
const struct hc_driver *driver; /* hw-specific hooks */
// 控制器驱动使用的回调函数
/* Flags that need to be manipulated atomically */
unsigned long flags;
#define HCD_FLAG_HW_ACCESSIBLE 0x00000001
#define HCD_FLAG_SAW_IRQ 0x00000002
unsigned rh_registered:1;/* is root hub registered? */
// 是否注册根hub
/* The next flag is a stopgap, to be removed when all the HCDs
* support the new root-hub polling mechanism. */
unsigned uses_new_polling:1; // 是否允许轮询根hub状态
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
// 状态是否改变
int irq; /* irq allocated */ // 控制器的中断请求号
void __iomem *regs; /* device memory/io */
// 控制器使用的内存和I/O
u64 rsrc_start; /* memory/io resource start */
// 控制器使用的内存和I/O起始地址
u64 rsrc_len; /* memory/io resource length */
// 控制器使用的内存和I/O资源长度
unsigned power_budget; /* in mA, 0 = no limit */
#define HCD_BUFFER_POOLS 4
struct dma_pool *pool [HCD_BUFFER_POOLS];
int state;
# define __ACTIVE 0x01
# define __SUSPEND 0x04
# define __TRANSIENT 0x80
# define HC_STATE_HALT 0
# define HC_STATE_RUNNING (__ACTIVE)
# define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
# define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
# define HC_STATE_SUSPENDED (__SUSPEND)
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
/* more shared queuing code would be good; it should support
* smarter scheduling, handle transaction translators, etc;
* input size of periodic table to an interrupt scheduler.
* (ohci 32, uhci 1024, ehci 256/512/1024).
*/
/* The HC driver's private data is stored at the end of
* this structure.
*/
unsigned long hcd_priv[0]
__attribute__ ((aligned (sizeof(unsigned long))));
};
2.OHCI控制器驱动
usb_hcd结构可以理解为一个通用的USB控制器描述结构。OHCI主机控制器是usb_hcd结构的具体实现,内核使用ohci_hcd结构描述OHCI主机控制器,定义如下:
struct ohci_hcd {
spinlock_t lock;
/*
* I/O memory used to communicate with the HC (dma-consistent)
// 用于HC通信的I/O内存地址
*/
struct ohci_regs __iomem *regs;
/*
* main memory used to communicate with the HC (dma-consistent).
// 用于HC通行的主内存地址
* hcd adds to schedule for a live hc any time, but removals finish
* only at the start of the next frame.
*/
struct ohci_hcca *hcca;
dma_addr_t hcca_dma;
struct ed *ed_rm_list; /* to be removed */
// 将被移除列表
struct ed *ed_bulktail; /* last in bulk list */
// 列表最后一项
struct ed *ed_controltail; /* last in ctrl list */
// 控制列表最后一项
struct ed *periodic [NUM_INTS]; /* shadow int_table */
/*
* OTG controllers and transceivers need software interaction;
* other external transceivers should be software-transparent
*/
struct otg_transceiver *transceiver;
/*
* memory management for queue data structures
// 内存管理队列使用的数据结构
*/
struct dma_pool *td_cache;
struct dma_pool *ed_cache;
struct td *td_hash [TD_HASH_SIZE];
struct list_head pending;
/*
* driver state
*/
int num_ports;
int load [NUM_INTS];
u32 hc_control; /* copy of hc control
reg */// HC控制寄存器复制
unsigned long next_statechange; /* suspend/resume */
// 挂起/恢复
u32 fminterval; /* saved register */ // 保存的寄存器
struct notifier_block reboot_notifier;
unsigned long flags; /* for HC bugs */
/* 以下是各厂家芯片ID定义 */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */
#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/
// 芯片的初始化逻辑里也同样会有怪异的Bug
};
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设备驱动,定义如下:
struct usb_driver {
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id); // 探测函数
void (*disconnect) (struct usb_interface *intf); // 断开连接函数
int (*ioctl) (struct usb_interface *intf, unsigned int code,
void *buf); // I/O控制函数
int (*suspend) (struct usb_interface *intf, pm_message_t message);
// 挂起函数
int (*resume) (struct usb_interface *intf); // 恢复函数
void (*pre_reset) (struct usb_interface *intf);
void (*post_reset) (struct usb_interface *intf);
const struct usb_device_id *id_table;
struct usb_dynids dynids;
struct device_driver driver;
unsigned int no_dynamic_id:1;
};
实现一个USB设备的驱动主要是实现probe()和disconnect()函数接口。probe()函数在插入USB设备的时候被调用,disconnect()函数在拔出USB设备的时候被调用。在25.2.4节中详细讲解USB设备驱动程序框架。
3.USB请求块
USB请求块(USB request block,urb)的功能类似于网络设备中的sk_buff,用于描述USB设备与主机通信的基本数据结构。urb结构在内核中定义如下:
struct urb
{
/* private: usb core and host controller only
fields in the urb */ // 私有数据,仅供USB核心和主机控制器使用
struct kref kref; /* reference count of the URB */
// urb引用计数
spinlock_t lock; /* lock for the URB */ // urb锁
void *hcpriv; /* private data for host controller */
// 主机控制器私有数据
int bandwidth; /* bandwidth for INT/ISO request */
// 请求带宽
atomic_t use_count; /* concurrent submissions counter */
// 并发传输计数
u8 reject; /* submissions will fail */ // 传输即将失败标志
/* public: documented fields in the urb that can
be used by drivers */ // 公有数据,可以被驱动使用
struct list_head urb_list; /* list head for use by the urb's
// 链表头
* current owner */
struct usb_device *dev; /* (in) pointer to associated device */
// 关联的USB设备
unsigned int pipe; /* (in) pipe information */ // 管道信息
int status; /* (return) non-ISO status */ // 当前状态
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
// 数据缓冲区
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
// DMA使用的缓冲区
int transfer_buffer_length; /* (in) data buffer length */
// 缓冲区大小
int actual_length; /* (return) actual transfer length */
//
际接收或发送数据的长度
unsigned char *setup_packet; /* (in) setup packet (control only) */
dma_addr_t setup_dma; /* (in) dma addr for setup_packet */
// 设置数据包缓冲区
int start_frame; /* (modify) start frame (ISO) */
// 等时传输中返回初始帧
int number_of_packets; /* (in) number of ISO packets */
// 等时传输中缓冲区数据
int interval; /* (modify) transfer interval
// 轮询的时间间隔
* (INT/ISO) */
int error_count; /* (return) number of ISO errors */
// 出错次数
void *context; /* (in) context for completion */
usb_complete_t complete; /* (in) completion routine */
struct usb_iso_packet_descriptor iso_frame_desc[0];
/* (in) ISO ONLY */
};
内核提供了一组函数操作urb类型的结构变量。urb的使用流程如下:
(1)创建urb。在使用之前,USB设备驱动需要调用usb_alloc_urb()函数创建一个urb,函数定义如下:
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
iso_packets参数是urb包含的等时数据包数目,如果为0表示不创建等时数据包。mem_flags参数是分配内存标志。如果分配urb成功,函数返回一个urb结构类型的指针,否则返回0。
内核还提供了释放urb的函数,定义如下:
void usb_free_urb(struct urb *urb)
在不使用urb的时候(退出驱动程序或者挂起驱动),需要使用usb_free_urb()函数释放urb。
(2)初始化urb,设置USB设备的端点。使用内核提供的usb_int_urb()函数设置urb初始结构,定义如下:
void usb_init_urb(struct urb *urb);
(3)提交urb到USB核心。在分配并设置urb完毕后,使用usb_submit_urb()函数把新的urb提交到USB核心,函数定义如下:
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
参数urb指向被提交的urb结构,mem_flags是传递给USB核心的内存选项,用于告知USB核心如何分配内存缓冲区。如果函数执行成功,urb的控制权被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总线结构 |
2.设备
每个USB设备提供了不同级别的配置信息。一个USB设备可以包含一个或多个配置,不同的配置使设备表现出不同的特点。其中,设备的配置是通过接口组成的。Linux内核定义了USB设备描述结构如下:
struct usb_device_descriptor {
__u8 bLength; // 设备描述符长度
__u8 bDescriptorType; // 设备类型
__le16 bcdUSB; // USB版本号(使用BCD编码)
__u8 bDeviceClass; // USB设备类型
__u8 bDeviceSubClass; // USB设备子类型
__u8 bDeviceProtocol; // USB设备协议号
__u8 bMaxPacketSize0; // 传输数据的最大包长
__le16 idVendor; // 厂商编号
__le16 idProduct; // 产品编号
__le16 bcdDevice; // 设备出厂号
__u8 iManufacturer; // 厂商字符串索引
__u8 iProduct; // 产品字符串索引
__u8 iSerialNumber; // 产品序列号索引
__u8 bNumConfigurations; // 最大的配置数量
} __attribute__ ((packed));
从usb_device_descriptor结构定义看出,一个设备描述符定义了与USB设备有关的所有信息。
3.接口
在USB体系中,接口是由多个端点组成的。一个接口代表一个基本的功能,是USB设备驱动程序控制的对象。一个USB设备最少有一个接口,功能复杂的USB设备可以有多个接口。接口描述定义如下:
struct usb_interface_descriptor {
__u8 bLength; // 描述符长度
__u8 bDescriptorType; // 描述符类型
__u8 bInterfaceNumber; // 接口编号
__u8 bAlternateSetting; // 备用接口编号
__u8 bNumEndpoints; // 端点数量
__u8 bInterfaceClass; // 接口类型
__u8 bInterfaceSubClass; // 接口子类型
__u8 bInterfaceProtocol; // 接口使用的协议
__u8 iInterface; // 接口索引字符串数值
} __attribute__ ((packed));
4.端点
端点是USB总线通信的基本形式,每个USB设备接口可以认为是端点的集合。主机只能通过端点与设备通信。USB体系结构规定每个端点都有一个唯一的地址,由设备地址和端点号决定端点地址。端点还包括了与主机通信用到的属性,如传输方式、总线访问频率、带宽和端点号等。端点的通信是单向的,通过端点传输的数据只能是从主机到设备或者从设备到主机。端点定义描述如下:
struct usb_endpoint_descriptor {
__u8 bLength; // 描述符长度
__u8 bDescriptorType; // 描述符类型
__u8 bEndpointAddress; // 端点地址
__u8 bmAttributes; // 端点属性
__le16 wMaxPacketSize; // 端点接收的最大数据包长度
__u8 bInterval; // 轮询端点的时间间隔
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
5.配置
配置是一个接口的集合。Linux内核配置的定义如下:
struct usb_config_descriptor {
__u8 bLength; // 描述符长度
__u8 bDescriptorType; // 描述符类型
__le16 wTotalLength; // 配置返回数据长度
__u8 bNumInterfaces; // 最大接口数
__u8 bConfigurationValue; // 配置参数值
__u8 iConfiguration; // 配置描述字符串索引
__u8 bmAttributes; // 供电模式
__u8 bMaxPower; // 接口的最大电流
} __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主机控制器的硬件信息、状态和操作函数,定义如下:
struct usb_hcd { /* usb_bus.hcpriv points to this */
/*
* housekeeping // 控制器基本信息
*/
struct usb_bus self; /* hcd is-a bus */
const char *product_desc; /* product/vendor string */
// 厂商名称字符串
char irq_descr[24]; /* driver + bus # */
// 驱动和总线类型
struct timer_list rh_timer; /* drives root-hub polling */
// 根hub轮询时间间隔
struct urb *status_urb; /* the current status urb */
// 当前urb状态
/*
* hardware info/state // 硬件信息和状态
*/
const struct hc_driver *driver; /* hw-specific hooks */
// 控制器驱动使用的回调函数
/* Flags that need to be manipulated atomically */
unsigned long flags;
#define HCD_FLAG_HW_ACCESSIBLE 0x00000001
#define HCD_FLAG_SAW_IRQ 0x00000002
unsigned rh_registered:1;/* is root hub registered? */
// 是否注册根hub
/* The next flag is a stopgap, to be removed when all the HCDs
* support the new root-hub polling mechanism. */
unsigned uses_new_polling:1; // 是否允许轮询根hub状态
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
// 状态是否改变
int irq; /* irq allocated */ // 控制器的中断请求号
void __iomem *regs; /* device memory/io */
// 控制器使用的内存和I/O
u64 rsrc_start; /* memory/io resource start */
// 控制器使用的内存和I/O起始地址
u64 rsrc_len; /* memory/io resource length */
// 控制器使用的内存和I/O资源长度
unsigned power_budget; /* in mA, 0 = no limit */
#define HCD_BUFFER_POOLS 4
struct dma_pool *pool [HCD_BUFFER_POOLS];
int state;
# define __ACTIVE 0x01
# define __SUSPEND 0x04
# define __TRANSIENT 0x80
# define HC_STATE_HALT 0
# define HC_STATE_RUNNING (__ACTIVE)
# define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
# define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
# define HC_STATE_SUSPENDED (__SUSPEND)
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
/* more shared queuing code would be good; it should support
* smarter scheduling, handle transaction translators, etc;
* input size of periodic table to an interrupt scheduler.
* (ohci 32, uhci 1024, ehci 256/512/1024).
*/
/* The HC driver's private data is stored at the end of
* this structure.
*/
unsigned long hcd_priv[0]
__attribute__ ((aligned (sizeof(unsigned long))));
};
2.OHCI控制器驱动
usb_hcd结构可以理解为一个通用的USB控制器描述结构。OHCI主机控制器是usb_hcd结构的具体实现,内核使用ohci_hcd结构描述OHCI主机控制器,定义如下:
struct ohci_hcd {
spinlock_t lock;
/*
* I/O memory used to communicate with the HC (dma-consistent)
// 用于HC通信的I/O内存地址
*/
struct ohci_regs __iomem *regs;
/*
* main memory used to communicate with the HC (dma-consistent).
// 用于HC通行的主内存地址
* hcd adds to schedule for a live hc any time, but removals finish
* only at the start of the next frame.
*/
struct ohci_hcca *hcca;
dma_addr_t hcca_dma;
struct ed *ed_rm_list; /* to be removed */
// 将被移除列表
struct ed *ed_bulktail; /* last in bulk list */
// 列表最后一项
struct ed *ed_controltail; /* last in ctrl list */
// 控制列表最后一项
struct ed *periodic [NUM_INTS]; /* shadow int_table */
/*
* OTG controllers and transceivers need software interaction;
* other external transceivers should be software-transparent
*/
struct otg_transceiver *transceiver;
/*
* memory management for queue data structures
// 内存管理队列使用的数据结构
*/
struct dma_pool *td_cache;
struct dma_pool *ed_cache;
struct td *td_hash [TD_HASH_SIZE];
struct list_head pending;
/*
* driver state
*/
int num_ports;
int load [NUM_INTS];
u32 hc_control; /* copy of hc control
reg */// HC控制寄存器复制
unsigned long next_statechange; /* suspend/resume */
// 挂起/恢复
u32 fminterval; /* saved register */ // 保存的寄存器
struct notifier_block reboot_notifier;
unsigned long flags; /* for HC bugs */
/* 以下是各厂家芯片ID定义 */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */
#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/
// 芯片的初始化逻辑里也同样会有怪异的Bug
};
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设备驱动,定义如下:
struct usb_driver {
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id); // 探测函数
void (*disconnect) (struct usb_interface *intf); // 断开连接函数
int (*ioctl) (struct usb_interface *intf, unsigned int code,
void *buf); // I/O控制函数
int (*suspend) (struct usb_interface *intf, pm_message_t message);
// 挂起函数
int (*resume) (struct usb_interface *intf); // 恢复函数
void (*pre_reset) (struct usb_interface *intf);
void (*post_reset) (struct usb_interface *intf);
const struct usb_device_id *id_table;
struct usb_dynids dynids;
struct device_driver driver;
unsigned int no_dynamic_id:1;
};
实现一个USB设备的驱动主要是实现probe()和disconnect()函数接口。probe()函数在插入USB设备的时候被调用,disconnect()函数在拔出USB设备的时候被调用。在25.2.4节中详细讲解USB设备驱动程序框架。
3.USB请求块
USB请求块(USB request block,urb)的功能类似于网络设备中的sk_buff,用于描述USB设备与主机通信的基本数据结构。urb结构在内核中定义如下:
struct urb
{
/* private: usb core and host controller only
fields in the urb */ // 私有数据,仅供USB核心和主机控制器使用
struct kref kref; /* reference count of the URB */
// urb引用计数
spinlock_t lock; /* lock for the URB */ // urb锁
void *hcpriv; /* private data for host controller */
// 主机控制器私有数据
int bandwidth; /* bandwidth for INT/ISO request */
// 请求带宽
atomic_t use_count; /* concurrent submissions counter */
// 并发传输计数
u8 reject; /* submissions will fail */ // 传输即将失败标志
/* public: documented fields in the urb that can
be used by drivers */ // 公有数据,可以被驱动使用
struct list_head urb_list; /* list head for use by the urb's
// 链表头
* current owner */
struct usb_device *dev; /* (in) pointer to associated device */
// 关联的USB设备
unsigned int pipe; /* (in) pipe information */ // 管道信息
int status; /* (return) non-ISO status */ // 当前状态
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
// 数据缓冲区
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
// DMA使用的缓冲区
int transfer_buffer_length; /* (in) data buffer length */
// 缓冲区大小
int actual_length; /* (return) actual transfer length */
//
际接收或发送数据的长度
unsigned char *setup_packet; /* (in) setup packet (control only) */
dma_addr_t setup_dma; /* (in) dma addr for setup_packet */
// 设置数据包缓冲区
int start_frame; /* (modify) start frame (ISO) */
// 等时传输中返回初始帧
int number_of_packets; /* (in) number of ISO packets */
// 等时传输中缓冲区数据
int interval; /* (modify) transfer interval
// 轮询的时间间隔
* (INT/ISO) */
int error_count; /* (return) number of ISO errors */
// 出错次数
void *context; /* (in) context for completion */
usb_complete_t complete; /* (in) completion routine */
struct usb_iso_packet_descriptor iso_frame_desc[0];
/* (in) ISO ONLY */
};
内核提供了一组函数操作urb类型的结构变量。urb的使用流程如下:
(1)创建urb。在使用之前,USB设备驱动需要调用usb_alloc_urb()函数创建一个urb,函数定义如下:
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
iso_packets参数是urb包含的等时数据包数目,如果为0表示不创建等时数据包。mem_flags参数是分配内存标志。如果分配urb成功,函数返回一个urb结构类型的指针,否则返回0。
内核还提供了释放urb的函数,定义如下:
void usb_free_urb(struct urb *urb)
在不使用urb的时候(退出驱动程序或者挂起驱动),需要使用usb_free_urb()函数释放urb。
(2)初始化urb,设置USB设备的端点。使用内核提供的usb_int_urb()函数设置urb初始结构,定义如下:
void usb_init_urb(struct urb *urb);
(3)提交urb到USB核心。在分配并设置urb完毕后,使用usb_submit_urb()函数把新的urb提交到USB核心,函数定义如下:
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
参数urb指向被提交的urb结构,mem_flags是传递给USB核心的内存选项,用于告知USB核心如何分配内存缓冲区。如果函数执行成功,urb的控制权被USB核心接管,否则函数返回错误。
相关文章推荐
- Linux内核usb驱动框架——U盘挂载
- 25.2.1 Linux内核USB驱动框架
- Linux下的硬件驱动——USB设备(上)(驱动配置部分)
- Linux USB驱动框架分析(一)
- linux内核驱动之USB设备添加pid,vid
- Usb设备驱动5:usb-firmware简易框架
- Linux下的硬件驱动——USB设备(下)(驱动开发部分)
- linux usb驱动框架(一)
- Linux下的硬件驱动——USB设备(下)(驱动开发部分)
- Linux下的硬件驱动——USB设备(下)(驱动开发部分)
- 【转】Linux USB驱动框架分析
- Linux下的硬件驱动——USB设备(上)(驱动配置部分
- Linux下USB驱动框架分析
- Linux USB驱动框架分析
- 【转载】实体框架之领域驱动实践(四):存储过程 - 领域驱动的反模式
- 【转载】实体框架之领域驱动实践(七):模型对象的生命周期 - 仓储
- Linux下USB驱动框架分析
- USB硬盘驱动框架
- 驱动框架6——linux内核的gpiolib学习