Linux-USB驱动笔记(六)--设备驱动框架
Linux-USB驱动笔记(六)—设备驱动框架
- 1、前言
- 2、USB设备驱动
- 3、重要结构体
- 3.1、usb_driver — USB设备驱动
- 3.2、usb_device_id — 支持的USB设备信息
- 3.3、urb — USB请求块
- 4、API函数
- 5、URB发送流程
1、前言
Linux-USB驱动笔记一
Linux-USB驱动笔记二
Linux-USB驱动笔记三
Linux-USB驱动笔记(四)–USB整体框架
Linux-USB驱动笔记(五)–主机控制器驱动框架
2、USB设备驱动
这里的USB设备驱动指的是主机角度来看的,怎样访问被插入的USB设备,而不是指USB设备内部本身运行的固件程序。Linux系统实现了几类通用的USB设备驱动:
- 音频设备
- HID(人机接口)
- 显示设备
- 存储设备
- 通信设备
一般的通用Linux设备(如U盘,USB鼠标,USB键盘等)都不需要工程师再编写驱动,而工程师需要编写的是特定厂商、特定芯片的驱动,而且往往也可以参考已经在内核中提供的驱动模板。很多时候,只需要添加VID,PID等信息即可使用。
3、重要结构体
Linux中使用usb_driver结构体描述一个USB设备驱动,它和i2c_driver, platform_driver类似。
3.1、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 (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
void *buf); //IOCTL
//电源管理
int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
int (*reset_resume)(struct usb_interface *intf);
//usb_reset_device()复位设备的前后回调
int (*pre_reset)(struct usb_interface *intf);
int (*post_reset)(struct usb_interface *intf);
//支持热插拔的USB设备ID表(PID/VID)
const struct usb_device_id *id_table;
struct usb_dynids dynids; //在内部用于保存此驱动程序动态添加的设备id列表
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1; //设置为1则不允许动态添加ID列表
unsigned int supports_autosuspend:1; //设置为0则不允许自动挂起
unsigned int disable_hub_initiated_lpm:1;//设置为1则不允许hub初始化为lpm
//设置为1则不允许在调用disconnect函数之前kill URB和关闭端点
unsigned int soft_unbind:1;
};
上面主要要实现probe()和disconnect(), 即插入和拔出回调。
usb_driver结构体中的id_table成员描述了这个USB驱动所支持的USB设备列表,它指向一个usb_device_id数组。
3.2、usb_device_id – 支持的USB设备信息
struct usb_device_id {
__u16 match_flags; //表明要和那些成员匹配
/* Used for product specific matches; range is inclusive */
__u16 idVendor; //厂商ID
__u16 idProduct; //产品ID
__u16 bcdDevice_lo; //供应商分配的产品版本号范围的低端。
__u16 bcdDevice_hi; //供应商分配的产品版本号范围的顶端。
/* Used for device class matches */
__u8 bDeviceClass; //设备类,由USB论坛分配
__u8 bDeviceSubClass;//设备子类
__u8 bDeviceProtocol;//设备协议
/* Used for interface class matches */
__u8 bInterfaceClass; //接口类,由USB论坛分配
__u8 bInterfaceSubClass; //接口子类
__u8 bInterfaceProtocol; //接口协议
/* Used for vendor-specific interface matches */
__u8 bInterfaceNumber; //接口号
/* not matched against */
kernel_ulong_t driver_info
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
上面结构体包含USB设备的厂商ID、 产品ID 、产品版本、设备类、接口类等信息以及要匹配标志成员match_flags(表明要与哪些成员匹配),定义如下
#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400
可以通过下面的宏来生成usb_device_id结构体
/* vend:厂商ID prod:产品ID lo:产品版本号范围的低端 hi:产品版本号范围的顶端 cl:接口类 pr:接口协议 num:接口号 sc:设备子类 */
USB_DEVICE(vend, prod)
USB_DEVICE_VER(vend, prod, lo, hi)
USB_DEVICE_INTERFACE_CLASS(vend, prod, cl)
USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr)
USB_DEVICE_INTERFACE_NUMBER(vend, prod, num)
USB_DEVICE_INFO(cl, sc, pr)
USB_INTERFACE_INFO(cl, sc, pr)
USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr)
USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr)
当USB核心检测到某个设备的属性和某个驱动程序的usb_device_id结构体所携带的信息一致时,这个驱动的probe()就被执行。拔掉设备或者卸载驱动模块后,USB核心就执行disconnect()函数。
3.3、urb – USB请求块
struct urb {
//私有:仅USB核心和主机控制使用
struct kref kref; /* URB引用计数 */
void *hcpriv; /* 主机控制器私有数据 */
atomic_t use_count; /* 并发提交计数 */
atomic_t reject; /* 提交会失败 */
int unlinked; /* 分离错误码 */
/* 公共: 在urb中可由驱动程序使用的文档化字段 */
struct list_head urb_list; /* URB当前的使用者*/
struct list_head anchor_list; /* 锚列表中的成员关系 */
struct usb_anchor *anchor;
struct usb_device *dev; /* 指向相关设备 */
struct usb_host_endpoint *ep; /* 指向端点 */
unsigned int pipe; /* 管道信息(保存端点编号、方向、类型等) */
unsigned int stream_id; /* 流ID */
int status; /* (return) non-ISO status */
//可以使用各种标志来影响URB提交、解除链接或操作的处理方式。
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) 关联的数据buffer */
dma_addr_t transfer_dma; /* (in) transfer_buffer的DMA地址 */
struct scatterlist *sg; /* (in) 散集缓冲区列表 */
int num_mapped_sgs; /* (internal)散集缓冲区列表条目映射数 */
int num_sgs; /* (in)散集缓冲区列表条目数 */
u32 transfer_buffer_length; /* (in) 数据缓冲区长度 */
u32 actual_length; /* (return) 实际传输长度 */
unsigned char *setup_packet; /* (in) 设置数据包 (仅用在控制传送) */
dma_addr_t setup_dma; /* (in) DMA地址设置数据包 */
int start_frame; /* (modify) 起始帧 (同步传输) */
int number_of_packets; /* (in) 同步传输数据包数 */
int interval; /* (modify) 指定中断或同步传输的轮询间隔 * (INT/ISO) */
int error_count; /* (return) 同步传输错误数 */
void *context; /* (in) 完成上下文 */
usb_complete_t complete; /* (in) 完成处理 */
//用于提供同步传输缓冲区的数组,并收集每个缓冲区的传输状态。
struct usb_iso_packet_descriptor iso_frame_desc[0];
/* (in) 仅同步使用 */
};
URB(USB请求块)是USB设备驱动中用来描述与USB设备通信的基本载体和核心数据结构。
4、API函数
//注册usb_driver
#define usb_register(driver) \ usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
int usb_register_driver(struct usb_driver *, struct module *,
const char *);
//注销usb_driver
void usb_deregister(struct usb_driver *);
/**************************URB相关函数******************************/
/* 函数功能:创建一个URB iso_packets:该URB中包含的同步数据包数 mem_flags:内存分配的标志,和kmalloc()的标志参数含义相同 */
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
//释放URB内存
void usb_free_urb(struct urb *urb);
/* 函数功能:初始化一个控制URB urb:要被初始化的URB dev:这个URB将被发送到的USB设备 pipe:URB要被发送到的USB设备的特定端点 setup_packet:设置数据包的缓冲区 transfer_buffer:发送或接收数据缓冲区 buffer_length:transfer_buffer的大小 complete_fn:URB完成之后的回调函数 context:完成回调函数的上下文 */
static inline void usb_fill_control_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
//初始化一个批量URB
//参数含义同上
static inline void usb_fill_bulk_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
//初始化一个中断URB
//interval:URB被调度的间隔
//其他参数含义同上
static inline void usb_fill_int_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context,
int interval)
//提交URB给USB核心,异步的
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
//创建各种pipe
#define usb_sndctrlpipe(dev, endpoint) \ ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))
#define usb_rcvctrlpipe(dev, endpoint) \ ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndisocpipe(dev, endpoint) \ ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))
#define usb_rcvisocpipe(dev, endpoint) \ ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndbulkpipe(dev, endpoint) \ ((PIPE_BULK << 30) | __create_pipe(dev, endpoint))
#define usb_rcvbulkpipe(dev, endpoint) \ ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndintpipe(dev, endpoint) \ ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint))
#define usb_rcvintpipe(dev, endpoint) \ ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
/************************封装函数(URB发送)*************************/
/* 函数功能: 创建一个控制URB并发送到指定设备 dev:要发送的USB设备 pipe:要发送到的USB设备的端点 request:USB消息请求值 requesttype:USB消息请求类型值 value:USB消息值 index:USB消息index值 data:要发送的数据 size:要发送的数据大小 timeout:发送超时时间 */
int usb_control_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value, __u16 index,
void *data, __u16 size, int timeout);
/* 函数功能:创建一个中断URB并发送给指定设备 actual_length:传输的实际长度 */
int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout);
/* 函数功能:创建一个批量URB并发送给指定设备 */
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length,
int timeout);
/**************************其他函数********************************/
//注册一个usb设备
int usb_register_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver)
//注销一个usb设备
void usb_deregister_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver)
//保存私有数据到接口设备
static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
//获取接口设备中的私有数据
static inline void *usb_get_intfdata(struct usb_interface *intf)
5、URB发送流程
URB发送流程:
同步URB没有初始化函数,我们只能手动对其进行初始化,然后才能提交给USB核心。
有时候USB驱动程序只是从USB设备接收或发送一些简单的数据,这时候,没必要将URB创建、初始化、提交、完成处理的整个流程走一遍。这可以使用usb_control_msg(), usb_interrupt_msg(), usb_bulk_msg() 等函数。但是使用时要注意,这几个函数是同步的,不能在中断上下文或持有自旋锁的情况下使用。
还没有评论,来说两句吧...