博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LINUX USB驱动开发(1)-USB驱动重要数据结构
阅读量:2435 次
发布时间:2019-05-10

本文共 12068 字,大约阅读时间需要 40 分钟。

USB设备为主机提供了多种多样的附加功能,如文件传输,声音播放等,但对USB主机来说,它与所有USB设备的接口都是一致的。一个USB设备由3个功能模块组成:USB总线接口、USB逻辑设备和功能单元:

a – 这里的USB总线接口指的是USB设备中的串行接口引擎(SIE);
b – USB逻辑设备被USB系统软件看作是一个端点的集合;
c – 功能单元被客户软件看作是一个接口的集合。SIE、端点和接口都是USB设备的组成单元;
为了更好地描述USB设备的特征,USB提出了设备架构的概念。从这个角度来看,可以认为USB设备是由一些配置、接口和端点组成,即一个USB设备可以含有一个或多个配置,在每个配置中可含有一个或多个接口,在每个接口中可含有若干个端点。其中,配置和接口是对USB设备功能的抽象,实际的数据传输由端点来完成。在使用USB设备前,必须指明其采用的配置和接口。这个步骤一般是在设备接入主机时设备进行枚举时完成的
设备通常有一个或多个配置;
配置通常有一个或多个接口;
接口通常有一个或多个设置;
接口有零或多个端点。

这样的概念太抽象了,可以这样看:有一个设备,如支持视频和音频的一个播放器。那么,对于上面提到的4个描述符,对它们设置的时候,它们分别对于哪一个描述符呢?

从我现在的理解来看,这样一个设备对应一个设备描述符,支持视频的功能对应一个接口描述符,支持音频功能的对应一个接口描述符。为了支持视频,在下层有多个端口同时工作为提供视频数据传输的支持,所以有多个端点描述符。

1.描述结构

USB设备使用各种描述符来说明其设备架构,包括设备描述符、配置描述符、接口描述符、端点描述符和字符串描述符,他们通常被保存在USB设备的固件程序中。

设备描述符

设备代表一个USB设备,它由一个或多个配置组成。设备描述符用于说明设备的总体信息,并指明其所含的配置的个数。一个USB设备只能有一个设备描述符。

struct usb_device_descriptor  {      _ _u8 bLength; //描述符长度      _ _u8 bDescriptorType; //描述符类型编号      _ _le16 bcdUSB; //USB版本号      _ _u8 bDeviceClass; //USB分配的设备类code      _ _u8 bDeviceSubClass;// USB分配的子类code      _ _u8 bDeviceProtocol; //USB分配的协议code      _ _u8 bMaxPacketSize0; //endpoint0最大包大小      _ _le16 idVendor; //厂商编号      _ _le16 idProduct; //产品编号      _ _le16 bcdDevice; //设备出厂编号      _ _u8 iManufacturer; //描述厂商字符串的索引      _ _u8 iProduct; //描述产品字符串的索引      _ _u8 iSerialNumber; //描述设备序列号字符串的索引      _ _u8 bNumConfigurations; //可能的配置数量  } _ _attribute_ _ ((packed));

2配置描述符

一个USB设备可以包含一个或多个配置,如USB设备的低功耗模式和高功耗模式可分别对应一个配置。在使用USB设备前,必须为其选择一个合适的配置。配置描述符用于说明USB设备中各个配置的特性,如配置所含接口的个数等。USB设备的每一个配置都必须有一个配置描述符。

struct usb_config_descriptor  {      _ _u8 bLength; //描述符长度      _ _u8 bDescriptorType; //描述符类型编号      _ _le16 wTotalLength; //配置所返回的所有数据的大小      _ _u8 bNumInterfaces; // 配置所支持的接口数      _ _u8 bConfigurationValue; //Set_Configuration命令需要的参数值      _ _u8 iConfiguration; //描述该配置的字符串的索引值      _ _u8 bmAttributes; //供电模式的选择      _ _u8 bMaxPower; //设备从总线提取的最大电流  } _ _attribute_ _ ((packed));

3接口描述符

一个配置可以包含一个或多个接口,例如对一个光驱来说,当用于文件传输时,使用其大容量存储接口;而当用于播放CD时,使用其音频接口。接口是端点的集合,可以包含一个或多个可替换设置,用户能够在USB处于配置状态时改变当前接口所含的个数和特性。接口描述符用于说明设备中各个接口的特性,如接口所属的设备类及其子类等。USB设备的每个接口都必须有一个接口描述符

struct usb_interface_descriptor  {      _ _u8 bLength;           //描述符长度      _ _u8 bDescriptorType; //描述符类型      _ _u8 bInterfaceNumber;   // 接口的编号      _ _u8 bAlternateSetting; //备用的接口描述符编号      _ _u8 bNumEndpoints;      //该接口使用的端点数,不包括端点0      _ _u8 bInterfaceClass;    //接口类型      _ _u8 bInterfaceSubClass; //接口子类型      _ _u8 bInterfaceProtocol; //接口所遵循的协议      _ _u8 iInterface; //描述该接口的字符串索引值  } _ _attribute_ _ ((packed));

4、端点描述符

端点是USB设备中的实际物理单元,USB数据传输就是在主机和USB设备各个端点之间进行的。端点一般由USB接口芯片提供,例如Freescale公司的MC68HC908JB8和MC9S12UF32。USB设备中的每一个端点都有唯一的端点号,每个端点所支持的数据传输方向一般而言也是确定的:或是输入(IN),或是输出(OUT)。也有些芯片提供的端点的数据方向是可以配置的,例如MC68HC908JB8包含有两个用于数据收发的端点:端点1和端点2。其中端点1只能用于数据发送,即支持输入(IN)操作;端点2既能用于数据发送,也可用于数据接收,即支持输入(IN)和输出(OUT)操作。而MC9S12UF32具有6个端点。
利用设备地址、端点号和传输方向就可以指定一个端点,并与它进行通信。端点的传输特性还决定了其与主机通信是所采用的传输类型,例如控制端点只能使用控制传输。根据端点的不同用途,可将端点分为两类:0号端点和非0号端点。
0号端点比较特殊,它有数据输入IN和数据输出OUT两个物理单元,且只能支持控制传输。所有的USB设备都必须含有一个0号端点,用作默认控制管道。USB系统软件就是使用该管道与USB逻辑设备进行配置通信的。0号端点在USB设备上的以后就可以使用,而非0号端点必须要在配置以后才可以使用。
根据具体应用的需要,USB设备还可以含有多个除0号端点以外的其他端点。对于低速设备,其附加的端点数最多为2个;对于全速/高速设备,其附加的端点数最多为15个。

struct usb_endpoint_descriptor  {      _ _u8 bLength; //描述符长度      _ _u8 bDescriptorType; //描述符类型      _ _u8 bEndpointAddress; //端点地址:0~3位是端点号,第7位是方向(0-OUT,1-IN)      _ _u8 bmAttributes; //端点属性:bit[0:1] 的值为00表示控制,为01表示同步,为02表示批量,为03表示中断      _ _le16 wMaxPacketSize;  本端点接收或发送的最大信息包的大小      _ _u8 bInterval;//轮询数据传送端点的时间间隔                             //对于批量传送的端点以及控制传送的端点,此域忽略                          //对于同步传送的端点,此域必须为1      _ _u8 bRefresh;      _ _u8 bSynchAddress;  } _ _attribute_ _ ((packed));

5.字符串描述符

在USB设备中通常还含有字符串描述符,以说明一些专用信息,如制造商的名称、设备的序列号等。它的内容以UNICODE的形式给出,且可以被客户软件所读取。对USB设备来说,字符串描述符是可选的。
struct usb_string_descriptor  {      _ _u8 bLength; //描述符长度      _ _u8 bDescriptorType; //描述符类型      _ _le16 wData[1];  } _ _attribute_ _ ((packed));

6.6、管道

在USB系统结构中,可以认为数据传输时在USB主机软件与USB设备的各个端点之间直接进行的,它们之间的连接称为管道。管道是在USB设备的配置过程中建立的。管道是对USB主机与USB设备间通信流的抽象,表示USB主机的数据缓冲区与USB设备的端点之间存在着逻辑数据传输,而实际的数据传输是由USB总线接口层来完成的。

管道与USB设备中的端点一一对应。一个USB设备含有多少个端点,其与USB主机进行通信时就可以使用多少条管道,且端点的类型决定了管道中数据的传输类型,例如中断端点对应中断管道,且该管道只能进行中断传输。不论存在着多少条管道,在各个管道中进行的数据传输都是相互独立的。

7、USB端点分类

USB 通讯的最基本形式是通过端点。一个USB端点只能向一个方向传输数据(从主机到设备(称为输出端点)或者从设备到主机(称为输入端点))。端点可被看作一个单向的管道。

USB 端点有 4 种不同类型, 分别具有不同的数据传送方式:

1) 控制CONTROL

控制端点被用来控制对USB设备的不同部分访问. 通常用作配置设备、获取设备信息、发送命令到设备或获取设备状态报告。这些端点通常较小。每个 USB 设备都有一个控制端点称为”端点 0”, 被 USB 核心用来在插入时配置设备。USB协议保证总有足够的带宽留给控制端点传送数据到设备.

2) 中断INTERRUPT

每当 USB 主机向设备请求数据时,中断端点以固定的速率传送小量的数据。此为USB 键盘和鼠标的主要的数据传送方法。它还用以传送数据到USB设备来控制设备。通常不用来传送大量数据。USB协议保证总有足够的带宽留给中断端点传送数据到设备.

3) 批量BULK

批量端点用以传送大量数据。这些端点通常比中断端点大得多. 它们普遍用于不能有任何数据丢失的情况。USB 协议不保证传输在特定时间范围内完成。如果总线上没有足够的空间来发送整个BULK包,它被分为多个包进行传输。这些端点普遍用于打印机、USB Mass Storage和USB网络设备上。

4) 等时ISOCHRONOUS

等时端点也批量传送大量数据, 但是这个数据不被保证能送达。这些端点用在可以处理数据丢失的设备中,并且更多依赖于保持持续的数据流。如音频和视频设备等等。

控制和批量端点用于异步数据传送,而中断和等时端点是周期性的。这意味着这些端点被设置来在固定的时间连续传送数据,USB 核心为它们保留了相应的带宽。

struct usb_host_endpoint{      struct usb_endpoint_descriptor desc;//端点描述符      struct list_head urb_list;//此端点的URB对列,由USB核心维护      void *hcpriv;      struct ep_device *ep_dev; /* For sysfs info */      unsigned char*extra;/* Extra descriptors */      int extralen;      int enabled;  };

当调用USB设备驱动调用usb_submit_urb提交urb请求时,将调用int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)把此urb增加到urb_list的尾巴上。(hcd: Host Controller Driver,对应数据结构struct usb_hcd )

2. USB 驱动的几个重要数据结构

2.1struct usb_interface 接口函数

struct usb_interface  {           struct usb_host_interface *altsetting;           struct usb_host_interface *cur_altsetting;                 unsigned num_altsetting;                   int minor;                                 enum usb_interface_condition condition;                    unsigned is_active:1;                      unsigned needs_remote_wakeup:1;            struct device dev;                         struct device *usb_dev;                    int pm_usage_cnt;                 };

struct usb_interface中的struct usb_host_interface *cur_altsetting成员,表示当前正在使用的设置

1.

struct usb_host_interface   {           struct usb_interface_descriptor desc;//usb描述符,主要有四种usb描述符,设备描述符,配置描述符,接口描述符和端点描述符,协议里规定一个usb设备是必须支持这四大描述符的。                                   //usb描述符放在usb设备的eeprom里边           /* array of desc.bNumEndpoint endpoints associated with this           * interface setting. these will be in no particular order.           */           struct usb_host_endpoint *endpoint;//这个设置所使用的端点           char *string;           /* iInterface string, if present */           unsigned char *extra;   /* Extra descriptors */关于额外描述符           int extralen;  };

2.2struct usb_host_endpoint 端点函数

struct usb_host_endpoint   {           struct usb_endpoint_descriptor desc;           struct list_head                urb_list;//端点要处理的urb队列.urb是usb通信的主角,设备中的每个端点都可以处理一个urb队列.要想和你的usb通信,就得创建一个urb,并且为它赋好值,                                     //交给咱们的usb core,它会找到合适的host controller,从而进行具体的数据传输           void                            *hcpriv;//这是提供给HCD(host controller driver)用的           struct ep_device                *ep_dev;        /* For sysfs info */           unsigned char *extra;   /* Extra descriptors */           int extralen;  };

2.3struct usb_device 设备函数

struct usb_device {      int devnum;         //devnum只是usb设备在一条usb总线上的编号.一条usb_bus_type类型的总线上最多可以连上128个设备      char devpath [16];   /* Use in messages: /port/port/...*/  //对于root hub.会将dev->devpath[0]=’0’      enum usb_device_state   state;  //设备的状态Attached,Powered,Default,Address,Configured,Suspended;                                 //Attached表示设备已经连接到usb接口上了,是hub检测到设备时的初始状态。那么这里所谓的USB_STATE_NOTATTACHED就是表示设备并没有Attached。                                 //Address状态表示主机分配了一个唯一的地址给设备,此时设备可以使用缺省管道响应主机的请求                                 //Configured状态表示设备已经被主机配置过了,也就是协议里说的处理了一个带有非0值的SetConfiguration()请求,此时主机可以使用设备提供的所有功能                                 //Suspended挂起状态,为了省电,设备在指定的时间内,3ms吧,如果没有发生总线传输,就要进入挂起状态。此时,usb设备要自己维护包括地址、配置在内的信息                   enum usb_device_speed   speed;  /* high/full/low (or error) */      struct usb_tt   *tt;            //如果一个高速设备里有这么一个TT,那么就可以连接低速/全速设备,如不然,那低速/全速设备没法用,只能连接到OHCI/UHCI那边出来的hub口里。      int             ttport;         //如果一个高速设备里有这么一个TT,那么就可以连接低速/全速设备,如不然,那低速/全速设备没法用,只能连接到OHCI/UHCI那边出来的hub口里。      unsigned int toggle[2];         /* one bit for each endpoint     //他实际上就是一个位图.IN方向的是toggle[0].OUT方向的是toggle[1].其实,这个数组中的每一位表示ep的toggle值                                              * ([0] = IN, [1] = OUT) */它里面的每一位表示的就是每个端点当前发送或接收的数据包是DATA0还是DATA1      struct usb_device *parent;      /* our hub, unless we're the root */                                //USB设备是从Root Hub开始,一个一个往外面连的,比如Root Hub有4个口,每个口连一个USB设备,比如其中有一个是Hub,那么这个Hub有可以继续有多个口,于是一级一级的往下连,                                 //最终连成了一棵树。      struct usb_bus *bus;            /* Bus we're part of */设备所在的总线      struct usb_host_endpoint ep0;   //端点0的特殊地位决定了她必将受到特殊的待遇,在struct usb_device对象产生的时候它就要初始化      struct device dev;              /* Generic device interface */嵌入到struct usb_device结构里的struct device结构      struct usb_device_descriptor descriptor;/* Descriptor */设备描述符,此结构体的bMaxPacketSize0 filed保存了端点0的maximum packet size      struct usb_host_config *config; //设备拥有的所有配置      struct usb_host_config *actconfig;//设备正在使用的配置      struct usb_host_endpoint *ep_in[16];//ep_in[16],359行,ep_out[16],除了端点0,一个设备即使在高速模式下也最多只能再有15个IN端点和15个OUT端点,端点0太特殊了,      struct usb_host_endpoint *ep_out[16];//对应的管道是Message管道,又能进又能出特能屈能伸的那种,所以这里的ep_in和ep_out数组都有16个值      char **rawdescriptors;          /* Raw descriptors for each config */      unsigned short bus_mA;          /* Current available from the bus */这个值是在host controller的驱动程序中设置的,通常来讲,计算机的usb端口可以提供500mA的电流      u8 portnum;                     //不管是root hub还是一般的hub,你的USB设备总归要插在一个hub的端口上才能用,portnum就是那个端口号。      u8 level;                       //层次,也可以说是级别,表征usb设备树的级连关系。Root Hub的level当然就是0,其下面一层就是level 1,再下面一层就是level 2,依此类推      unsigned discon_suspended:1;    /* Disconnected while suspended */      unsigned have_langid:1;         /* whether string_langid is valid */      int string_langid;              /* language ID for strings */      /* static strings from the device */      char *product;                  /* iProduct string, if present */      char *manufacturer;             /* iManufacturer string, if present */      char *serial;                   /* iSerialNumber string, if present */                                      //分别用来保存产品、厂商和序列号对应的字符串描述符信息      struct list_head filelist;  #ifdef CONFIG_USB_DEVICE_CLASS      struct device *usb_classdev;  #endif  #ifdef CONFIG_USB_DEVICEFS      struct dentry *usbfs_dentry;    /* usbfs dentry entry for the device */  #endif      /*     * Child devices - these can be either new devices     * (if this is a hub device), or different instances     * of this same device.     *     * Each instance needs its own set of data structures.     */      int maxchild;                   /* Number of ports if hub */      struct usb_device *children[USB_MAXCHILDREN];      int pm_usage_cnt;               /* usage counter for autosuspend */      u32 quirks;                     //quirk就是用来判断这些有毛病的产品啥毛病的  #ifdef CONFIG_PM      struct delayed_work autosuspend; /* for delayed autosuspends */      struct mutex pm_mutex;          /* protects PM operations */      unsigned long last_busy;        /* time of last use */      int autosuspend_delay;          /* in jiffies */      unsigned auto_pm:1;             /* autosuspend/resume in progress */      unsigned do_remote_wakeup:1;    /* remote wakeup should be enabled */      unsigned autosuspend_disabled:1; /* autosuspend and autoresume */      unsigned autoresume_disabled:1;  /*  disabled by the user */  #endif  };

2.4struct usb_host_config 配置函数

struct usb_host_config {      struct usb_config_descriptor    desc;      char *string;                 struct usb_interface *interface[USB_MAXINTERFACES];            //配置所包含的接口,这个数组的顺序未必是按照配置里接口号的顺序      struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];        //usb接口的缓存      unsigned char *extra;         int extralen;  };

转载地址:http://sxomb.baihongyu.com/

你可能感兴趣的文章
一致性hash
查看>>
J.U.C之ConcurrentHashMap分析
查看>>
J.U.C之CopyOnWriteArrayList
查看>>
J.U.C之Atomic&CAS
查看>>
类的生命周期
查看>>
Joda-Time学习
查看>>
Guava扩展工具包
查看>>
Jedis分片策略-一致性Hash
查看>>
BeanFactory和FactoryBean
查看>>
用户态和内核态的概念区别
查看>>
情境领导力
查看>>
赋能:打造应对不确定性的敏捷组织
查看>>
Java 学习方法浅谈
查看>>
Jsp连接数据库大全
查看>>
WebSphere Application Server 常见问题及解答:安全
查看>>
WebSphere Application Server 常见问题及解答:集群
查看>>
使用 SIBus JMS 提供者
查看>>
调试 SCA 调用
查看>>
SOA 治理框架和解决方案架构
查看>>
面向企业的云计算—了解云的一些基本概念
查看>>