Linux-USB驱动笔记(六)--设备驱动框架

深碍√TFBOYSˉ_ 2022-09-09 06:01 361阅读 0赞

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设备驱动

  1. struct usb_driver {
  2. const char *name; //驱动名,唯一
  3. int (*probe) (struct usb_interface *intf,
  4. const struct usb_device_id *id); //匹配回调
  5. void (*disconnect) (struct usb_interface *intf);//接口断开回调
  6. int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
  7. void *buf); //IOCTL
  8. //电源管理
  9. int (*suspend) (struct usb_interface *intf, pm_message_t message);
  10. int (*resume) (struct usb_interface *intf);
  11. int (*reset_resume)(struct usb_interface *intf);
  12. //usb_reset_device()复位设备的前后回调
  13. int (*pre_reset)(struct usb_interface *intf);
  14. int (*post_reset)(struct usb_interface *intf);
  15. //支持热插拔的USB设备ID表(PID/VID)
  16. const struct usb_device_id *id_table;
  17. struct usb_dynids dynids; //在内部用于保存此驱动程序动态添加的设备id列表
  18. struct usbdrv_wrap drvwrap;
  19. unsigned int no_dynamic_id:1; //设置为1则不允许动态添加ID列表
  20. unsigned int supports_autosuspend:1; //设置为0则不允许自动挂起
  21. unsigned int disable_hub_initiated_lpm:1;//设置为1则不允许hub初始化为lpm
  22. //设置为1则不允许在调用disconnect函数之前kill URB和关闭端点
  23. unsigned int soft_unbind:1;
  24. };

上面主要要实现probe()和disconnect(), 即插入和拔出回调。

usb_driver结构体中的id_table成员描述了这个USB驱动所支持的USB设备列表,它指向一个usb_device_id数组。

3.2、usb_device_id – 支持的USB设备信息

  1. struct usb_device_id {
  2. __u16 match_flags; //表明要和那些成员匹配
  3. /* Used for product specific matches; range is inclusive */
  4. __u16 idVendor; //厂商ID
  5. __u16 idProduct; //产品ID
  6. __u16 bcdDevice_lo; //供应商分配的产品版本号范围的低端。
  7. __u16 bcdDevice_hi; //供应商分配的产品版本号范围的顶端。
  8. /* Used for device class matches */
  9. __u8 bDeviceClass; //设备类,由USB论坛分配
  10. __u8 bDeviceSubClass;//设备子类
  11. __u8 bDeviceProtocol;//设备协议
  12. /* Used for interface class matches */
  13. __u8 bInterfaceClass; //接口类,由USB论坛分配
  14. __u8 bInterfaceSubClass; //接口子类
  15. __u8 bInterfaceProtocol; //接口协议
  16. /* Used for vendor-specific interface matches */
  17. __u8 bInterfaceNumber; //接口号
  18. /* not matched against */
  19. kernel_ulong_t driver_info
  20. __attribute__((aligned(sizeof(kernel_ulong_t))));
  21. };

上面结构体包含USB设备的厂商ID、 产品ID 、产品版本、设备类、接口类等信息以及要匹配标志成员match_flags(表明要与哪些成员匹配),定义如下

  1. #define USB_DEVICE_ID_MATCH_VENDOR 0x0001
  2. #define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
  3. #define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
  4. #define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
  5. #define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
  6. #define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
  7. #define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
  8. #define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
  9. #define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
  10. #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
  11. #define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400

可以通过下面的宏来生成usb_device_id结构体

  1. /* vend:厂商ID prod:产品ID lo:产品版本号范围的低端 hi:产品版本号范围的顶端 cl:接口类 pr:接口协议 num:接口号 sc:设备子类 */
  2. USB_DEVICE(vend, prod)
  3. USB_DEVICE_VER(vend, prod, lo, hi)
  4. USB_DEVICE_INTERFACE_CLASS(vend, prod, cl)
  5. USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr)
  6. USB_DEVICE_INTERFACE_NUMBER(vend, prod, num)
  7. USB_DEVICE_INFO(cl, sc, pr)
  8. USB_INTERFACE_INFO(cl, sc, pr)
  9. USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr)
  10. USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr)

当USB核心检测到某个设备的属性和某个驱动程序的usb_device_id结构体所携带的信息一致时,这个驱动的probe()就被执行。拔掉设备或者卸载驱动模块后,USB核心就执行disconnect()函数。

3.3、urb – USB请求块

  1. struct urb {
  2. //私有:仅USB核心和主机控制使用
  3. struct kref kref; /* URB引用计数 */
  4. void *hcpriv; /* 主机控制器私有数据 */
  5. atomic_t use_count; /* 并发提交计数 */
  6. atomic_t reject; /* 提交会失败 */
  7. int unlinked; /* 分离错误码 */
  8. /* 公共: 在urb中可由驱动程序使用的文档化字段 */
  9. struct list_head urb_list; /* URB当前的使用者*/
  10. struct list_head anchor_list; /* 锚列表中的成员关系 */
  11. struct usb_anchor *anchor;
  12. struct usb_device *dev; /* 指向相关设备 */
  13. struct usb_host_endpoint *ep; /* 指向端点 */
  14. unsigned int pipe; /* 管道信息(保存端点编号、方向、类型等) */
  15. unsigned int stream_id; /* 流ID */
  16. int status; /* (return) non-ISO status */
  17. //可以使用各种标志来影响URB提交、解除链接或操作的处理方式。
  18. unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
  19. void *transfer_buffer; /* (in) 关联的数据buffer */
  20. dma_addr_t transfer_dma; /* (in) transfer_buffer的DMA地址 */
  21. struct scatterlist *sg; /* (in) 散集缓冲区列表 */
  22. int num_mapped_sgs; /* (internal)散集缓冲区列表条目映射数 */
  23. int num_sgs; /* (in)散集缓冲区列表条目数 */
  24. u32 transfer_buffer_length; /* (in) 数据缓冲区长度 */
  25. u32 actual_length; /* (return) 实际传输长度 */
  26. unsigned char *setup_packet; /* (in) 设置数据包 (仅用在控制传送) */
  27. dma_addr_t setup_dma; /* (in) DMA地址设置数据包 */
  28. int start_frame; /* (modify) 起始帧 (同步传输) */
  29. int number_of_packets; /* (in) 同步传输数据包数 */
  30. int interval; /* (modify) 指定中断或同步传输的轮询间隔 * (INT/ISO) */
  31. int error_count; /* (return) 同步传输错误数 */
  32. void *context; /* (in) 完成上下文 */
  33. usb_complete_t complete; /* (in) 完成处理 */
  34. //用于提供同步传输缓冲区的数组,并收集每个缓冲区的传输状态。
  35. struct usb_iso_packet_descriptor iso_frame_desc[0];
  36. /* (in) 仅同步使用 */
  37. };

URB(USB请求块)是USB设备驱动中用来描述与USB设备通信的基本载体和核心数据结构。

4、API函数

  1. //注册usb_driver
  2. #define usb_register(driver) \ usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
  3. int usb_register_driver(struct usb_driver *, struct module *,
  4. const char *);
  5. //注销usb_driver
  6. void usb_deregister(struct usb_driver *);
  7. /**************************URB相关函数******************************/
  8. /* 函数功能:创建一个URB iso_packets:该URB中包含的同步数据包数 mem_flags:内存分配的标志,和kmalloc()的标志参数含义相同 */
  9. struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
  10. //释放URB内存
  11. void usb_free_urb(struct urb *urb);
  12. /* 函数功能:初始化一个控制URB urb:要被初始化的URB dev:这个URB将被发送到的USB设备 pipe:URB要被发送到的USB设备的特定端点 setup_packet:设置数据包的缓冲区 transfer_buffer:发送或接收数据缓冲区 buffer_length:transfer_buffer的大小 complete_fn:URB完成之后的回调函数 context:完成回调函数的上下文 */
  13. static inline void usb_fill_control_urb(struct urb *urb,
  14. struct usb_device *dev,
  15. unsigned int pipe,
  16. unsigned char *setup_packet,
  17. void *transfer_buffer,
  18. int buffer_length,
  19. usb_complete_t complete_fn,
  20. void *context)
  21. //初始化一个批量URB
  22. //参数含义同上
  23. static inline void usb_fill_bulk_urb(struct urb *urb,
  24. struct usb_device *dev,
  25. unsigned int pipe,
  26. void *transfer_buffer,
  27. int buffer_length,
  28. usb_complete_t complete_fn,
  29. void *context)
  30. //初始化一个中断URB
  31. //interval:URB被调度的间隔
  32. //其他参数含义同上
  33. static inline void usb_fill_int_urb(struct urb *urb,
  34. struct usb_device *dev,
  35. unsigned int pipe,
  36. void *transfer_buffer,
  37. int buffer_length,
  38. usb_complete_t complete_fn,
  39. void *context,
  40. int interval)
  41. //提交URB给USB核心,异步的
  42. int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
  43. //创建各种pipe
  44. #define usb_sndctrlpipe(dev, endpoint) \ ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))
  45. #define usb_rcvctrlpipe(dev, endpoint) \ ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
  46. #define usb_sndisocpipe(dev, endpoint) \ ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))
  47. #define usb_rcvisocpipe(dev, endpoint) \ ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
  48. #define usb_sndbulkpipe(dev, endpoint) \ ((PIPE_BULK << 30) | __create_pipe(dev, endpoint))
  49. #define usb_rcvbulkpipe(dev, endpoint) \ ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
  50. #define usb_sndintpipe(dev, endpoint) \ ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint))
  51. #define usb_rcvintpipe(dev, endpoint) \ ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
  52. /************************封装函数(URB发送)*************************/
  53. /* 函数功能: 创建一个控制URB并发送到指定设备 dev:要发送的USB设备 pipe:要发送到的USB设备的端点 request:USB消息请求值 requesttype:USB消息请求类型值 value:USB消息值 index:USB消息index值 data:要发送的数据 size:要发送的数据大小 timeout:发送超时时间 */
  54. int usb_control_msg(struct usb_device *dev, unsigned int pipe,
  55. __u8 request, __u8 requesttype, __u16 value, __u16 index,
  56. void *data, __u16 size, int timeout);
  57. /* 函数功能:创建一个中断URB并发送给指定设备 actual_length:传输的实际长度 */
  58. int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
  59. void *data, int len, int *actual_length, int timeout);
  60. /* 函数功能:创建一个批量URB并发送给指定设备 */
  61. int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
  62. void *data, int len, int *actual_length,
  63. int timeout);
  64. /**************************其他函数********************************/
  65. //注册一个usb设备
  66. int usb_register_dev(struct usb_interface *intf,
  67. struct usb_class_driver *class_driver)
  68. //注销一个usb设备
  69. void usb_deregister_dev(struct usb_interface *intf,
  70. struct usb_class_driver *class_driver)
  71. //保存私有数据到接口设备
  72. static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
  73. //获取接口设备中的私有数据
  74. 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() 等函数。但是使用时要注意,这几个函数是同步的,不能在中断上下文或持有自旋锁的情况下使用。

发表评论

表情:
评论列表 (有 0 条评论,361人围观)

还没有评论,来说两句吧...

相关阅读