嵌入式开发记录-day37 USB驱动认识

1、USB驱动的框架

  1、USB主机端和设备端

USB设备端的设备注册是在设备端中;USB主控制器的设备注 册需要在平台文件中注册

 

 

  1、USB HCD这一层涉及到硬件部分,因此驱动会有差异;

  2、USB CORE:这层完全是脱离硬件部分,纯软件实现,因此是Linux内核提供的,那么与硬件通信,就需要USB HCD给上层提供供访问的接口;

  3、USB DEVICE DRIVER:分为两大类,存储设备(例如U盘)和HID(人机界面)

2、USB主控制器驱动主要的功能

  1、解析和维护URB :URB主控制实现,USB应用与硬件进行通信的中间站;

  2、负责不同USB 传输类型的调度工作 :USB设备有很多种类,都需要传输数据;

  3、负责USB 数据的实际传输工作 –

  4、 实现虚拟USB HUB(集线器)的功能

3、USB驱动常用的目录

  1、  usb核心层驱动:drivers/usb/core/ –这一部分对应上面相应的结构,这部分驱动是通用的;

    USB串口驱动:drivers/usb/serial/ – 在这里可以添加自己的串口驱动

    usb主控制器驱动:drivers/usb/host/-  驱动源码:ehci-s5p.c – 设备注册:plat-s5p/dev-ehci.c 一些比较重要的驱动大多数都不在平台文件下;

  2、总结

  1、USB设备驱动分为:USB主控制器、USB主控制器驱动(芯片原厂出方案)、USB Core(Linux内核中通用的)和 USB设备驱动
  2、 主控制器不同厂商会使用不同型号,导致这部分代码会有区别。在驱 动分层的时候,需要给USB Core提供统一的接口。 – 这样可以最大程度的来实现代码复用

  3、芯片厂商提供的方案中,会有和硬件匹配的软件方案,这部分都会做 好。USB Core是这部分代码是Linux官方提供,全部通用。USB设备驱 动是外部USB设备制造商提供驱动,这部分可能会有少量的修改--前面 移植教程做的事情

4、USB的枚举流程

  1、USB设备插上以后,USB设备初始化的过程;

  2、USB的硬件设计

 

 

     1、在USB主机的DATA+和DATA-差分线上都有下拉15K的电阻。因此在没有设备接入的时候,两根线上的电平都是低电平;

    2、在从机端,USB设备端(鼠标键盘等),都有1.5K的上拉电阻。当USB接 口空置的时候,显然集线器上检测到的DATA+和DATA-都是低电平,当 USB设备插入的时候,就会被拉高(1.5K 和15K电阻分压,在15K电阻上的电压),这个时候是产生低电平到高电平的变 化。 

    3、高速设备D+上拉,低速设备D-上拉,是指外部设备,鼠标键盘都是低速设备;

  3、USB的软件枚举流程

  USB枚举主机控制器和集线器完成了大部分的工作

    1、热拔插检测 - 主要检测电平的变化;

    2、主机发送Get_Status请求 - 

    3、 主机发送Set_Feature请求,集线器重启端口 - 

    4、 集线器在设备和主机之间建立一个信号通路 - 

    5、 集线器检测设备速度 - 根据上下拉电阻,检测电平,来判断是高低速设备;

   前五个步骤中,主要工作是检测到USB设备、向主机报告在某个时间 点有一个USB设备接入、集线器重启接入USB的端口、集线器在主控制 器和USB设备之间建立一个信号通路,最后集线器检测设备速度。主 控制器和USB设备之间建立了一个信号通路,而且主控制获取了设备 是高速设备还是低速设备的信息。

   在所有的USB设备中(不管是鼠标、键盘、蓝牙,还是网卡、U盘等等) ,设备内部都有一个存储器,用于保存设备的信息。例如:生产厂商、 产品的ID等等

    6、 获取最大数据包长度 •

    7、 主机分配一个新的地址给设备 •

    8 、主机重新发送Get_Device_Descriptor命令,读取完整设备描述符 - 厂商ID 设备ID等信息

    9 、主机发送Get_Device_Configuration命令,获取完整配置信息 - 设备的速度等信息;

    10、主机发送Get_Device_String命令,获得描述字符集(unicode)- 根据返回的描述字符集获取设备的信息

    11、 主机展示新设备信息 – 插上USB设备,就到这一步了,没有驱动也可以执行到这一步;

      打印USB设备的信息!到这一步都不需要从机设备的驱动 –

      驱动移植的时候需要这里打印的两个ID号 •

    12、 主设备(PC)判断能否提供该类USB的驱动

       需要匹配两个ID号,在加载USB设备驱动的时候,会将这两个ID号添加到 USB设备链表中,最终会在这一步进行匹配。 •

    13、 主机发送Set_Configuration(x)命令,请求为设备选择一个配置      

      如果在内核中发现了和设备一致的ID,会进行初始化工作,驱动就运行起 来,可以和从机端进行通信了

  4、小结

    USB设备枚举流程中,大部分工作都是主控制器和集线器完成。在主 控制器和集线器完成基本工作之后,得到非常重要的描述符信息“设 备描述  符、配置描述符、接口描述符、端点描述符”,系统根据获取 的这些信息,结合内核来判断“内核中是否有对应的USB设备的驱动” ,假如有,则将这些信息传递给USB设备驱动,最后USB设备驱动利用 描述符信息来进行初始化工作。

     需要学习和掌握的USB驱动知识,最重要的部分是“USB描述符”和 “USB设备外部驱动”。

     设备描述符用于probe,也就是初始化

     配置描述符、接口描述符、端点描述符最终是为了实现urb(类比 i2c_transfer等等)功能,也就是主机和从机进行数据通信

5、USB的描述符

  1、描述符所在的文件路径,描述符有四种,在“include\linux\usb\ch9.h”头文件中 ,有四种结构体;

    设备描述符:usb_device_descriptor –

    配置描述符:usb_config_descriptor –

    接口描述符:usb_interface_descriptor –

    端点描述符:usb_endpoint_descriptor

  2、描述符结构体说明

// 结构体在include\linux\usb\ch9.h中定义

// 设备描述符结构体
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength; //该描述符结构体大小(18 字节)
__u8 bDescriptorType; //描述符类型(本结构体中固定为0x01)
__le16 bcdUSB; //USB 版本号
__u8 bDeviceClass; //设备类代码(由USB 官方分配)
__u8 bDeviceSubClass; //子类代码(由USB 官方分配)
__u8 bDeviceProtocol; //设备协议代码(由USB 官方分配)
__u8 bMaxPacketSize0; //端点0 的最大包大小(有效大小为8,16,32,64)
__le16 idVendor; //生产厂商编号(由USB 官方分配)
__le16 idProduct; //产品编号(制造厂商分配)
__le16 bcdDevice; //设备出厂编号
__u8 iManufacturer; //设备厂商字符串索引
__u8 iProduct; //产品描述字符串索引
__u8 iSerialNumber; //设备序列号字符串索引
__u8 bNumConfigurations; //当前速度下能支持的配置数量  可以连接多少个配置
} __attribute__ ((packed));


// 配置描述符结构体
struct usb_config_descriptor {
__u8 bLength; //该描述符结构体大小
__u8 bDescriptorType; //描述符类型(本结构体中固定为0x02)
__le16 wTotalLength; //此配置返回的所有数据大小
__u8 bNumInterfaces; //此配置的接口数量
__u8 bConfigurationValue; //Set_Configuration 命令所需要的参数值
__u8 iConfiguration; //描述该配置的字符串的索引值
__u8 bmAttributes; //供电模式的选择
__u8 bMaxPower; //设备从总线提取的最大电流
} __attribute__ ((packed));

// 接口描述符结构体
struct usb_interface_descriptor {
__u8 bLength; //该描述符结构大小
__u8 bDescriptorType; //接口描述符的类型编号(0x04)
__u8 bInterfaceNumber; //接口描述符的类型编号(0x04)
__u8 bAlternateSetting; //接口描述符的类型编号(0x04)
__u8 bNumEndpoints; //该接口使用的端点数,不包括端点0
__u8 bInterfaceClass; //接口类型
__u8 bInterfaceSubClass; //接口子类型
__u8 bInterfaceProtocol; //接口遵循的协议
__u8 iInterface; //描述该接口的字符串索引值
} __attribute__ ((packed));


// 端点描述符结构体
struct usb_endpoint_descriptor {
__u8 bLength; //端点描述符字节数大小(7 个字节)
__u8 bDescriptorType; //端点描述符类型编号(0x05)
__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));
View Code

通过lsusb和lsusb -v可以查询Ubuntu上的usb设备 – 开发板上的lsusb命令应该是精简版 

 3、USB端点描述符

 // USB端点描述符
struct usb_endpoint_descriptor {
__u8 bLength; //端点描述符字节数大小(7 个字节) 
__u8 bDescriptorType; //端点描述符类型编号(0x05) – 
__u8 bEndpointAddress; //端点地址及输入输出属性。bit0:3表示端点地址 bit4:6保留,bit7表示方向1输入:0输出。 –
 __u8 bmAttributes; //端点的传输类型属性。00表示控制传输(双向), 01表示等时传输,10表示批量传输,11表示中断传输。 –
 __le16 wMaxPacketSize; //端点收、发的最大包大小 – 
__u8 bInterval; //主机查询端点的时间间隔。希望主机轮询设备的时间间 隔 __u8 bRefresh; //声卡用到的变量 –
__u8 bSynchAddress; – } __attribute__ ((packed));

  4、USB传输方式

  控制传输:获取和配置设备; –

  中断传输:例如USB鼠标; –

  批量传输:大容量数据传输,数据传输稳定,没有固定时间,U盘、USB 打印机和USB扫描仪; –

  等时传输:可以传输大批量数据,但是对数据是否到达没有保证,且可 以默许错误的发生,对实时性要求比较高,例如camera、音视频等等

6、USB的请求块URB

  1、申请urb

  struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)

  申请urb必须使用这个函数,这样便于USB主控制器统一管理USB 设备 ,而在spi、I2c中自己定义一个结构体变量,在这里必须使用返回值;

  2、 初始化urb

  void usb_fill_int[control][bulk]_urb (中断、控制、)

  参数pipe:管道信息(使用usb_sndintpipe、usb_rcvintpipe 等函数)pipe是usb通信的公路,端点是目的地 –

  参数*transfer_buffer:发送数据到设备或从设备接收数据的缓冲区 –

  参数buffer_length:缓冲区的大小 –

  参数complete_fn:当urb被完全传输或发生错误时,被调用 –

  参数*context:指向数据点的指针,它可被USB 驱动设置 –

  参数interval:urb 被轮询到的时间间隔   // 分配CPU的时间

  3、提交urb分为异步提交和同步提交 – URB提交完成后,剩下的就交给USB主控制器完成

  异步提交int usb_submit_urb(struct urb *urb, gfp_t mem_flags) –

  同步提交usb_control[interrupt][bulk]_msg –

  urb是否完成,可以根据URB提交之后返回值判断。返回值为0则完 成,负数则失败。

  4、 注销和释放 –

  注销urb:usb_kill_urb或者usb_unlink_urb –

  释放urb:usb_free_urb

描述USB设备 –

  struct usb_device... –

  注意USB描述符是保存在从机中的信息,主机还是需要有描述USB设备的 结构体。在USB从机设备驱动中,设备信息是通过USB主控制器传输过来 ,在驱动中获取的。 –

  usb_device中的成员需要获取的信息是设备描述符中的信息。

  在驱动初始 化probe中可以看到这样的赋值

 

posted @ 2020-08-31 23:59  笑不出花的旦旦  阅读(703)  评论(0)    收藏  举报