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驱动笔记(六)--设备驱动框架相关推荐

  1. linux用户空间flash驱动,全面掌握Linux驱动框架——字符设备驱动、I2C驱动、总线设备驱动、NAND FLASH驱动...

    原标题:全面掌握Linux驱动框架--字符设备驱动.I2C驱动.总线设备驱动.NAND FLASH驱动 字符设备驱动 哈~ 这几天都在发图,通过这种方式,我们希望能帮大家梳理学过的知识,全局的掌握Li ...

  2. linux i2c核心,总线与设备驱动,Linux2.6.37 I2C驱动框架分析(一)

    最近工作中又使用到了I2C,所以借S3C2440开发板GT2440为硬件平台温习一遍I2C驱动体系. linux内核中IIC驱动的体系框架 linux内核中IIC部分驱动代码位于:/drivers/i ...

  3. Linux设备驱动开发---USB主机(控制器)与设备驱动(一)

    USB主机控制器与设备驱动---主机侧 一.Linux USB驱动层次 1.USB驱动(主机侧) 2.USB的逻辑组合(4个层次) 二.USB主机(控制器)驱动 1.主机控制器规格 2.主机控制器的相 ...

  4. 一起分析Linux系统设计思想——05字符设备驱动框架剖析(四)

    在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习.我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直 ...

  5. 【linux驱动之字符设备驱动基础】

    linux驱动之字符设备驱动基础 文章目录 linux驱动之字符设备驱动基础 前言 一.开启驱动学习之路 二.驱动预备知识 三.什么是驱动? 3.1 驱动概念 3.2 linux 体系架构 3.3 模 ...

  6. Linux设备驱动篇——[I2C设备驱动-1]

    Linux 设备驱动篇之I2c设备驱动 fulinux 一.I2C驱动体系 虽然I2C硬件体系结构和协议都很容易理解,但是Linux I2C驱动体系结构却有相当的复杂度,它主要由3部分组成,即I2C设 ...

  7. Linux驱动之字符设备驱动

    系列文章目录 第一章 Linux入门之驱动框架 第二章 Linux驱动之字符设备驱动 文章目录 系列文章目录 前言 一.认识字符设备驱动 1.基本概念 2.基本概念 二.字符设备旧框架 1.注册和注销 ...

  8. Linux驱动开发|块设备驱动

    块设备驱动 块设备驱动是 Linux 三大驱动类型之一,块设备驱动比字符设备驱动复杂得多,不同类型的存储设备又对应不同的驱动子系统,下面介绍块设备驱动框架及使用 一.块设备介绍 块设备是针对存储设备的 ...

  9. linux的驱动开发——字符设备驱动

    1.字符设备驱动 \qquad字符设备驱动是最基本,最常用的设备.它将千差万别的硬件设备采用统一的接口封装起来,屏蔽了硬件的差异,简化了应用层的操作. 2.描述所有字符设备的结构体 \qquad描述所 ...

  10. linux PCI驱动调用字符设备驱动方式

    上一篇文章写了字符设备驱动的基本结构及访问方式,在实际应用时首先需要绑定自己的硬件设备.本篇主要描述字符设备驱动与PCI接口类型的设备访问方式(内核为2.6.24及以上的方法,测试内核为2.6.32) ...

最新文章

  1. Linux学习 Unit 12
  2. 奥数国家队最强6人集结,深圳中学独占2席,人大附中连续三年入围
  3. java: 十六进制转八进制
  4. oracle数据库开多线程,学习笔记:Oracle表数据导入 DBA常用单线程插入 多线程插入 sql loader三种表数据导入案例...
  5. 【Flutter】开发之功能篇(七)
  6. java 过滤字符串_java实现压缩字符串和java字符串过滤
  7. 文字围绕浮动元素的妙用(HTML、CSS)
  8. 苹果被拒:4.Guideline 2.3.3 - Performance - Accurate Metadata
  9. 安卓微软数学(算数,积分,极限,代数)数学神器
  10. 《SAP从入门到精通》——1.3 SAP R/3系统工作原理
  11. ECharts柱状图常见效果
  12. CFAR原理详解及其matlab代码实现
  13. Adobe Premiere基础-时间重映射(十)
  14. 玩客部落ASO解读:应用商店关键词曝光原理
  15. Word插入脚注不显示编号
  16. 第06章 数据挖掘综合应用
  17. html实现简单动画,编写自己的代码库(css3常用动画的实现)
  18. 单条视频播放超7000万,网红界“大油田”如何掀起快手流量浪潮?
  19. 重学JS(《JavaScript高级程序设计》笔记) - HTML中的JS
  20. 关于嵌入式音视频程序开发的感想

热门文章

  1. (1)制作树莓派裸机操作系统
  2. 简单的图片管理器开发
  3. php抢票插件下载,实测两款 GitHub 开源抢票插件,所有坑我们都帮你踩过了
  4. 12306抢票插件拖垮GitHub网站
  5. 判断请求是否来自微信端
  6. 第四章:经典量化策略集锦(第五篇:布林强盗,一个霸道的交易系统)
  7. vbox虚拟机vdi文件用VMware打开
  8. 修·蓝博士:吃东西前一定要这样清理
  9. 打造自己的博客(二)试着添加这两个有意思的插件吧?
  10. C语言字符串处理的一些函数strok,strstr, strchr,strsub