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() 等函数。但是使用时要注意,这几个函数是同步的,不能在中断上下文或持有自旋锁的情况下使用。
Linux-USB驱动笔记(六)--设备驱动框架相关推荐
- linux用户空间flash驱动,全面掌握Linux驱动框架——字符设备驱动、I2C驱动、总线设备驱动、NAND FLASH驱动...
原标题:全面掌握Linux驱动框架--字符设备驱动.I2C驱动.总线设备驱动.NAND FLASH驱动 字符设备驱动 哈~ 这几天都在发图,通过这种方式,我们希望能帮大家梳理学过的知识,全局的掌握Li ...
- linux i2c核心,总线与设备驱动,Linux2.6.37 I2C驱动框架分析(一)
最近工作中又使用到了I2C,所以借S3C2440开发板GT2440为硬件平台温习一遍I2C驱动体系. linux内核中IIC驱动的体系框架 linux内核中IIC部分驱动代码位于:/drivers/i ...
- Linux设备驱动开发---USB主机(控制器)与设备驱动(一)
USB主机控制器与设备驱动---主机侧 一.Linux USB驱动层次 1.USB驱动(主机侧) 2.USB的逻辑组合(4个层次) 二.USB主机(控制器)驱动 1.主机控制器规格 2.主机控制器的相 ...
- 一起分析Linux系统设计思想——05字符设备驱动框架剖析(四)
在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习.我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直 ...
- 【linux驱动之字符设备驱动基础】
linux驱动之字符设备驱动基础 文章目录 linux驱动之字符设备驱动基础 前言 一.开启驱动学习之路 二.驱动预备知识 三.什么是驱动? 3.1 驱动概念 3.2 linux 体系架构 3.3 模 ...
- Linux设备驱动篇——[I2C设备驱动-1]
Linux 设备驱动篇之I2c设备驱动 fulinux 一.I2C驱动体系 虽然I2C硬件体系结构和协议都很容易理解,但是Linux I2C驱动体系结构却有相当的复杂度,它主要由3部分组成,即I2C设 ...
- Linux驱动之字符设备驱动
系列文章目录 第一章 Linux入门之驱动框架 第二章 Linux驱动之字符设备驱动 文章目录 系列文章目录 前言 一.认识字符设备驱动 1.基本概念 2.基本概念 二.字符设备旧框架 1.注册和注销 ...
- Linux驱动开发|块设备驱动
块设备驱动 块设备驱动是 Linux 三大驱动类型之一,块设备驱动比字符设备驱动复杂得多,不同类型的存储设备又对应不同的驱动子系统,下面介绍块设备驱动框架及使用 一.块设备介绍 块设备是针对存储设备的 ...
- linux的驱动开发——字符设备驱动
1.字符设备驱动 \qquad字符设备驱动是最基本,最常用的设备.它将千差万别的硬件设备采用统一的接口封装起来,屏蔽了硬件的差异,简化了应用层的操作. 2.描述所有字符设备的结构体 \qquad描述所 ...
- linux PCI驱动调用字符设备驱动方式
上一篇文章写了字符设备驱动的基本结构及访问方式,在实际应用时首先需要绑定自己的硬件设备.本篇主要描述字符设备驱动与PCI接口类型的设备访问方式(内核为2.6.24及以上的方法,测试内核为2.6.32) ...
最新文章
- Linux学习 Unit 12
- 奥数国家队最强6人集结,深圳中学独占2席,人大附中连续三年入围
- java: 十六进制转八进制
- oracle数据库开多线程,学习笔记:Oracle表数据导入 DBA常用单线程插入 多线程插入 sql loader三种表数据导入案例...
- 【Flutter】开发之功能篇(七)
- java 过滤字符串_java实现压缩字符串和java字符串过滤
- 文字围绕浮动元素的妙用(HTML、CSS)
- 苹果被拒:4.Guideline 2.3.3 - Performance - Accurate Metadata
- 安卓微软数学(算数,积分,极限,代数)数学神器
- 《SAP从入门到精通》——1.3 SAP R/3系统工作原理
- ECharts柱状图常见效果
- CFAR原理详解及其matlab代码实现
- Adobe Premiere基础-时间重映射(十)
- 玩客部落ASO解读:应用商店关键词曝光原理
- Word插入脚注不显示编号
- 第06章 数据挖掘综合应用
- html实现简单动画,编写自己的代码库(css3常用动画的实现)
- 单条视频播放超7000万,网红界“大油田”如何掀起快手流量浪潮?
- 重学JS(《JavaScript高级程序设计》笔记) - HTML中的JS
- 关于嵌入式音视频程序开发的感想