一 枚举过程:
◆ 用户将一个USB设备插入USB端口,主机为端口供电,设备此时处于上电状态。
◆主机检测设备。
◆集线器使用中断通道将事件报告给主机。
◆主机发送Get_Port_Status(读端口状态)请求,以获取更多的设备信息。
◆集线器检测设备是低速运行仍是高速运行,并将此信息送给主机,这是对Get_Port_Status请求的响应。
◆主机发送Set_Port_Feature(写端口状态)请求给集线器,要求它复位端口。
◆集线器对设备复位。
◆主机使用Chirp K信号来了解全速设备是否支持高速运行。
◆主机发送另外一个Get_Port_Status请求,肯定设备是否已经从复位状态退出。
◆设备此时处于缺省状态,且已准备好在零端点经过缺省通道响应主机控制传输。缺省地址为00h,设备能从总线获取高达100mA的电流。
◆主机发送Get_Deor(读设备描述符)报文,以便肯定最大数据包大小。设备描述符的八个字节是bMaxPacketSize。
◆经过发送Set_Address(写地址)请求,主机分配地址,设备此时处于地址状态。
◆主机发送Get_Deor报文,以获取更多的设备信息。主机经过发送描述符响应设备请求,随后发送所有的次级描述符。
◆主机分配并加载设备驱动程序。
◆经过发送Set_Configuration(写配置)请求,主机的设备驱动程序选择一个有效配置,设备此时处于配置状态。
◆主机为复合设备接口分配驱动程序。
◆若是集线器检测到有过流现象,或者主机要求集线器关闭电源,则USB总线切断设备供电电源。在这种状况下,设备与主机没法通讯,但设备处于链接状态。
◆若是在3毫秒内设备在总线上未见任何动做,则它将进入挂起状态,在挂起状态设备消耗的总线电能最少。编程
还有一个差很少,以下:
1)集线器检测新设备
主机集线器监视着每一个端口的信号电压,当有新设备接入时即可觉察。(集线器端口的两根信号线的每一根都有15kΩ的下拉电阻,而每个设备在D+都有一个1.5kΩ的上拉电阻。当用USB线将PC和设备接通后,设备的上拉电阻使信号线的电位升高,所以被主机集线器检测到。)
(2)主机知道了新设备链接后
每一个集线器用中断传输来报告在集线器上的事件。当主机知道了这个事件,它给集线器发送一个Get_Status请求来了解更多的消息。返回的消息告诉主机一个设备是何时链接的。
(3)集线器从新设置这个新设备
当主机知道有一个新的设备时,主机给集线器发送一个Set_Feature请求,请求集线器来从新设置端口。集线器使得设备的USB数据线处于重启(RESET)状态至少10ms。
(4)集线器在设备和主机之间创建一个信号通路
主机发送一个Get_Status请求来验证设备是否激起重启状态。返回的数据有一位表示设备仍然处于重启状态。当集线器释放了重启状态,设备就处于默认状态了,即设备已经准备好经过Endpoint 0 的默认流程响应控制传输。即设备如今使用默认地址0x0与主机通讯。
(5)集线器检测设备速度
集线器经过测定那根信号线(D+或D-)在空闲时有更高的电压来检测设备是低速设备仍是全速设备。(全速和高速设备D+有上拉电阻,低速设备D-有上拉电阻)。
如下,须要USB的firmware进行干预
(6)获取最大数据包长度
PC向address 0发送USB协议规定的Get_Device_Deor命令,以取得却缺省控制管道所支持的最大数据包长度,并在有限的时间内等待USB设备的响应,该长度包含在设备描述符的bMaxPacketSize0字段中,其地址偏移量为7,因此这时主机只需读取该描述符的前8个字节。注意,主机一次只能列举一个USB设备,因此同一时刻只能有一个USB设备使用缺省地址0。
如下操做雷同,不一样操做系统设定时延是不同的,好比说win2k大概是几毫秒,若是没有反应就再发送一次命令,重复三次。
(7)主机分配一个新的地址给设备
主机经过发送一个Set_Address请求来分配一个惟一的地址给设备。设备读取这个请求,返回一个确认,并保存新的地址。今后开始全部通讯都使用这个新地址。
(8)主机向新地址从新发送Get_Device_Deor命令,这次读取其设备描述符的所有字段,以了解该设备的整体信息,如VID,PID。
(9)主机向设备循环发送Get_Device_Configuration命令,要求USB设备回答,以读取所有配置信息。
(10)主机发送Get_Device_String命令,得到字符集描述(unicode),好比产商、产品描述、型号等等。
(11)此时主机将会弹出窗口,展现发现新设备的信息,产商、产品描述、型号等。
(12)根据Device_Deor和Device_Configuration应答,PC判断是否可以提供USB的Driver,通常win2k能提供几大类的设备,如游戏操做杆、存储、打印机、扫描仪等,操做就在后台运行。可是Win98却不能够,因此在此时将会弹出对话框,索要USB的Driver。
(13)加载了USB设备驱动之后,主机发送Set_Configuration(x)命令请求为该设备选择一个合适的配置(x表明非0的配置值)。若是配置成功,USB设备进入“配置”状态,并能够和客户软件进行数据传输。
此时,常规的USB完成了其必须进行的配置和链接工做。查看注册表,可以发现相应的项目已经添加完毕,至此设备应当能够开始使用。不过,USB协议还提供了一些用户可选的协议,设备若是不该答,也不会出错,可是会影响到系统的功能。数据结构
1.当主机用轮询的方式检测到USB端口有新的设备插入时,主机就会给HUB发送总线复位命令,要求HUB进行总线复位。
设备链接到主机并初始化完成(Softconnect 位被设置为 1),主机检测到D+与D-之间有电压差,就认为有新的设置接入。主机等待100ms后发出复位请求。设备接到复位请求后将产生一个外部中断信号。学习
2.主机使用默认地址0,来读取设备的描述符。
发送 Get_descriptor标准请求。主机向D12发送一个八字节请求:80 06 00 01 00 00 40 00 D12接收到请求后产生一个中断,咱们能够经过读中断寄存器知道中断源,而且能够加读最后状态寄存器来肯定第一个接到的包是否为一个Setup包。当控制器处理程序判断出它是一个Get_descriptor请求是,把设备描述符的前16个字节发送到端点0缓冲区中。剩下的2个字节描述符第一次请求时再也不发送。大数据
3.主机给设备分配一个地址
当主机收到正确的前16字节描述符后,会给设备分配一个地址,个人PC分配的地址为:0x03(这个要看你的机子当时的USB接口设备数目而定) Set_Address 请求所发送的数据为:00 05 03 00 00 00 00 00 ,其中的03就表示主机为设备分配的地址为0x03,在之后的通讯里设备就只对0x03地址做出应答。当D12产生一个接收中断后,跟据所分配的地址设置D12的地址寄存器相应位编码
4.主机以地址0x03 ,从新请求设备描述符
主机发送设备描述符标准请求Get_descriptor :80 06 00 01 00 00 12 00 这次将要求把18个字节所有发送完。因此主机要分两次来读取。第一次发送16个字节,第三次发送两个字节,最后主机发送0表示发送完毕的应答。操作系统
5.主机发送Get_configuration请求
因为事先没有知道描述符的长度,因此先以0xff的长度进行请求。其数据为:80 06 00 02 00 00 FF 00 我用的是周立功公司卖的D12开发板光盘资料中提供的驱动程序,发送的应答是一个描述集合其结构以下:
typedef struct USB_DESCRIPTOR {
USB_CONFIGURATION_DESCRIPTOR ConfigDescr; //配置描述符
USB_INTERFACE_DESCRIPTOR InterfaceDescr; //接口描述符
USB_ENDPOINT_DESCRIPTOR EP1_TXDescr; //端点1输入描述符
USB_ENDPOINT_DESCRIPTOR EP1_RXDescr; //端点1输出描述符
USB_ENDPOINT_DESCRIPTOR EP2_TXDescr; //端点2输入描述符
USB_ENDPOINT_DESCRIPTOR EP2_RXDescr; //端点2输出描述符
} USB_DESCRIPTOR, *PUSB_DESCRIPTOR;指针
6.Set_Conficuration
当读取完成描述符以后,须要对设备进行配置,使得设备从地址状态进入配置状态。这个在写固件的时候能够提升运行效率。
7.读取配置状态。
8.当主机能正确地收到这些数据以后,就能够加载D12的驱动程序。这时就可能做应用中的数据传输了。code
使用USB View 采集到的数据:索引
Device Descriptor:
bcdUSB: 0x0100
bDeviceClass: 0xDC
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x10 (16)
idVendor: 0x0471
idProduct: 0x0666
bcdDevice: 0x0100
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01接口
ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed: Full
Device Address: 0x02
Open Pipes: 4
Endpoint Descriptor:
bEndpointAddress: 0x81
Transfer Type: Interrupt
wMaxPacketSize: 0x0010 (16)
bInterval: 0x0A
Endpoint Descriptor:
bEndpointAddress: 0x01
Transfer Type: Interrupt
wMaxPacketSize: 0x0010 (16)
bInterval: 0x0A
Endpoint Descriptor:
bEndpointAddress: 0x82
Transfer Type: Bulk
wMaxPacketSize: 0x0040 (64)
bInterval: 0x0A
Endpoint Descriptor:
bEndpointAddress: 0x02
Transfer Type: Bulk
wMaxPacketSize: 0x0040 (64)
bInterval: 0x0A
参考资料:《PDIUSBD12 USB固件编程和驱动开发》
驱动开发网
USB 基本知识
USB的重要关键字:
一、端点:位于USB设备或主机上的一个数据缓冲区,用来存放和发送USB的各类数据,每个端点都有唯一的肯定地址,有不一样的传输特性(如输入端点、输出端点、配置端点、批量传输端点)
二、帧:时间概念,在USB中,一帧就是1MS,它是一个独立的单元,包含了一系列总线动做,USB将1帧分为好几份,每一份中是一个USB的传输动做。
三、上行、下行:设备到主机为上行,主机到设备为下行
下面以一问一答的形式开始学习吧。
问题一:USB的传输线结构是如何的呢?
答案一:一条USB的传输线分别由地线、电源线、D+、D-四条线构成,D+和D-是差分输入线,它使用的是3.3V的电压(注意哦,与CMOS的5V电平不一样),而电源线和地线可向设备提供5V电压,最大电流为500MA(能够在编程中设置的,至于硬件的实现机制,就不要管它了)。
问题二:数据是如何在USB传输线里面传送的
答案二:数据在USB线里传送是由低位到高位发送的。
问题三:USB的编码方案?
答案三:USB采用不归零取反来传输数据,当传输线上的差分数据输入0时就取反,输入1时就保持原值,为了确保信号发送的准确性,当在USB总线上发送一个包时,传输设备就要进行位插入***做(即在数据流中每连续6个1后就插入一个0),从而强迫NRZI码发生变化。这个了解就好了,这些是由专门硬件处理的。
问题四:USB的数据格式是怎么样的呢?
答案四:和其余的同样,USB数据是由二进制数字串构成的,首先数字串构成域(有七种),域再构成包,包再构成事务(IN、OUT、SETUP),事务最后构成传输(中断传输、并行传输、批量传输和控制传输)。下面简单介绍一下域、包、事务、传输,请注意他们之间的关系。
(一)域:是USB数据最小的单位,由若干位组成(至因而多少位由具体的域决定),域可分为七个类型:
一、同步域(SYNC),八位,值固定为0000 0001,用于本地时钟与输入同步
二、标识域(PID),由四位标识符+四位标识符反码构成,代表包的类型和格式,这是一个很重要的部分,这里能够计算出,USB的标识码有16种,具体分类请看问题五。
三、地址域(ADDR):七位地址,表明了设备在主机上的地址,地址000 0000被命名为零地址,是任何一个设备第一次链接到主机时,在被主机配置、枚举前的默认地址,由此能够知道为何一个USB主机只能接127个设备的缘由。
四、端点域(ENDP),四位,由此可知一个USB设备有的端点数量最大为16个。
五、帧号域(FRAM),11位,每个帧都有一个特定的帧号,帧号域最大容量0x800,对于同步传输有重要意义(同步传输为四种传输类型之一,请看下面)。
六、数据域(DATA):长度为0~1023字节,在不一样的传输类型中,数据域的长度各不相同,但必须为整数个字节的长度
七、校验域(CRC):对令牌包和数据包(对于包的分类请看下面)中非PID域进行校验的一种方法,CRC校验在通信中应用很泛,是一种很好的校验方法,至于具体的校验方法这里就很少说,请查阅相关资料,只须注意CRC码的除法是模2运算,不一样于10进制中的除法。
(二)包:由域构成的包有四种类型,分别是令牌包、数据包、握手包和特殊包,前面三种是重要的包,不一样的包的域结构不一样,介绍以下
一、令牌包:可分为输入包、输出包、设置包和帧起始包(注意这里的输入包是用于设置输入命令的,输出包是用来设置输出命令的,而不是放据数的)
其中输入包、输出包和设置包的格式都是同样的:
SYNC+PID+ADDR+ENDP+CRC5(五位的校验码)
(上面的缩写解释请看上面域的介绍,PID码的具体定义请看问题五)
帧起始包的格式:
SYNC+PID+11位FRAM+CRC5(五位的校验码)
二、数据包:分为DATA0包和DATA1包,当USB发送数据的时候,当一次发送的数据长度大于相应端点的容量时,就须要把数据包分为好几个包,分批发送,DATA0包和DATA1包交替发送,即若是第一个数据包是DATA0,那第二个数据包就是DATA1。但也有例外状况,在同步传输中(四类传输类型中之一),全部的数据包都是为DATA0,格式以下:
SYNC+PID+0~1023字节+CRC16
三、握手包:结构最为简单的包,格式以下
SYNC+PID
(注上面每种包都有不一样类型的,USB1.1共定义了十种包,具体请见问题五)
(三)事务:分别有IN事务、OUT事务和SETUP事务三大事务,每一种事务都由令牌包、数据包、握手包三个阶段构成,这里用阶段的意思是由于这些包的发送是有必定的时间前后顺序的,事务的三个阶段以下:
一、令牌包阶段:启动一个输入、输出或设置的事务
二、数据包阶段:按输入、输出发送相应的数据
三、握手包阶段:返回数据接收状况,在同步传输的IN和OUT事务中没有这个阶段,这是比较特殊的。
事务的三种类型以下(如下按三个阶段来讲明一个事务):
一、 IN事务:
令牌包阶段——主机发送一个PID为IN的输入包给设备,通知设备要往主机发送数据;
数据包阶段——设备根据状况会做出三种反应(要注意:数据包阶段也不老是传送数据的,根据传输状况还会提早进入握手包阶段)
1) 设备端点正常,设备往入主机里面发出数据包(DATA0与DATA1交替);
2) 设备正在忙,没法往主机发出数据包就发送NAK无效包,IN事务提早结束,到了下一个IN事务才继续;
3) 相应设备端点被禁止,发送错误包STALL包,事务也就提早结束了,总线进入空闲状态。
握手包阶段——主机正确接收到数据以后就会向设备发送ACK包。
二、 OUT事务:
令牌包阶段——主机发送一个PID为OUT的输出包给设备,通知设备要接收数据;
数据包阶段——比较简单,就是主机会设备送数据,DATA0与DATA1交替
握手包阶段——设备根据状况会做出三种反应
1)设备端点接收正确,设备往入主机返回ACK,通知主机能够发送新的数据,若是数据包发生了CRC校验错误,将不返回任何握手信息;
2) 设备正在忙,没法往主机发出数据包就发送NAK无效包,通知主机再次发送数据;
3) 相应设备端点被禁止,发送错误包STALL包,事务提早结束,总线直接进入空闲状态。
三、SETUT事务:
令牌包阶段——主机发送一个PID为SETUP的输出包给设备,通知设备要接收数据;
数据包阶段——比较简单,就是主机会设备送数据,注意,这里只有一个固定为8个字节的DATA0包,这8个字节的内容就是标准的USB设备请求命令(共有11条,具体请看问题七)
握手包阶段——设备接收到主机的命令信息后,返回ACK,此后总线进入空闲状态,并准备下一个传输(在SETUP事务后一般是一个IN或OUT事务构成的传输)
(四)传输:传输由OUT、IN、SETUP事务其中的事务构成,传输有四种类型,中断传输、批量传输、同步传输、控制传输,其中中断传输和批量转输的结构同样,同步传输有最简单的结构,而控制传输是最重要的也是最复杂的传输。
一、中断传输:由OUT事务和IN事务构成,用于键盘、鼠标等HID设备的数据传输中
二、批量传输:由OUT事务和IN事务构成,用于大容量数据传输,没有固定的传输速率,也不占用带宽,当总线忙时,USB会优先进行其余类型的数据传输,而暂时中止批量转输。
三、同步传输:由OUT事务和IN事务构成,有两个特殊地方,第一,在同步传输的IN和OUT事务中是没有返回包阶段的;第二,在数据包阶段全部的数据包都为DATA0
四、控制传输:最重要的也是最复杂的传输,控制传输由三个阶段构成(初始设置阶段、可选数据阶段、状态信息步骤),每个阶段能够当作一个的传输,也就是说控制传输实际上是由三个传输构成的,用来于USB设备初次加接到主机以后,主机经过控制传输来交换信息,设备地址和读取设备的描述符,使得主机识别设备,并安装相应的驱动程序,这是每个USB开发者都要关心的问题。
一、初始设置步骤:就是一个由SET事务构成的传输
二、可选数据步骤:就是一个由IN或OUT事务构成的传输,这个步骤是可选的,要看初始设置步骤有没有要求读/写数据(由SET事务的数据包阶段发送的标准请求命令决定)
三、 状态信息步骤:顾名思义,这个步骤就是要获取状态信息,由IN或OUT事务构成构成的传输,可是要注意这里的IN和OUT事务和以前的INT和OUT事务有两点不一样:
1) 传输方向相反,一般IN表示设备往主机送数据,OUT表示主机往设备送数据;在这里,IN表示主机往设备送数据,而OUT表示设备往主机送数据,这是为了和可选数据步骤相结合;
2) 在这个步骤里,数据包阶段的数据包都是0长度的,即SYNC+PID+CRC16
除了以上两点有区别外,其余的同样,这里就很少说
(思考:这些传输模式在实际***做中应如何经过什么方式去设置?)
问题五:标识码(PID)有哪些?
答案五:如同前面所说的标识码由四位数据组成,所以能够表示十六种标识码,在USB1.1规范里面,只用了十种标识码,USB2.0使用了十六种标识码,标识码的做用是用来讲明包的属性的,标识码是和包联系在一块儿的,首先简单介绍一下数据包的类型,数据包分为令牌包、数据、握手包和特殊包四种(具体分类请看问题七),标识码分别有如下十六种:
令牌包 :
0x01 输出(OUT)启动一个方向为主机到设备的传输,并包含了设备地址和标号
0x09 输入 (IN) 启动一个方向为设备到主机的传输,并包含了设备地址和标号
0x05 帧起始(SOF)表示一个帧的开始,而且包含了相应的帧号
0x0d 设置(SETUP)启动一个控制传输,用于主机对设备的初始化
数据包 :
0x03 偶数据包(DATA0),
0x0b 奇数据包(DATA1)
握手包:
0x02 确认接收到无误的数据包(ACK)
0x0a 无效,接收(发送)端正在忙而没法接收(发送)信息
0x0e 错误,端点被禁止或不支持控制管道请求
特殊包 0x0C 前导,用于启动下行端口的低速设备的数据传输
问题六:USB主机是如何识别USB设备的?
答案六:当USB设备插上主机时,主机就经过一系列的动做来对设备进行枚举配置(配置是属于枚举的一个态,态表示暂时的状态),这这些态以下:
一、接入态(Attached):设备接入主机后,主机经过检测信号线上的电平变化来发现设备的接入;
二、供电态(Powered):就是给设备供电,分为设备接入时的默认供电值,配置阶段后的供电值(按数据中要求的最大值,可经过编程设置)
三、缺省态(Default):USB在被配置以前,经过缺省地址0与主机进行通讯;
四、地址态(Address):通过了配置,USB设备被复位后,就能够按主机分配给它的惟一地址来与主机通讯,这种状态就是地址态;
五、配置态(Configured):经过各类标准的USB请求命令来获取设备的各类信息,并对设备的某此信息进行改变或设置。
六、挂起态(Suspended):总线供电设备在3ms内没有总线***做,即USB总线处于空闲状态的话,该设备就要自动进入挂起状态,在进入挂起状态后,总的电流功耗不超过280UA。
问题七:刚才在答案四提到的标准的USB设备请求命令到底是什么?
答案七:标准的USB设备请求命令是用在控制传输中的“初始设置步骤”里的数据包阶段(即DATA0,由八个字节构成),请看回问答四的内容。标准USB设备请求命令共有11个,大小都是8个字节,具备相同的结构,由5个字段构成(字段是标准请求命令的数据部分),结构以下(括号中的数字表示字节数,首字母bm,b,w分别表示位图、字节,双字节):
bmRequestType(1)+bRequest(1)+wvalue(2)+wIndex(2)+wLength(2)
各字段的意义以下:
一、bmRequestType:D7D6D5D4D3D2D1D0
D7=0主机到设备
=1设备到主机;
D6D5=00标准请求命令
=01 类请求命令
=10用户定义的命令
=11保留值
D4D3D2D1D0=00000 接收者为设备
=00001 接收者为设备
=00010 接收者为端点
=00011 接收者为其余接收者
=其余 其余值保留
二、bRequest:请求命令代码,在标准的USB命令中,每个命令都定义了编号,编号的值就为字段的值,编号与命令名称以下(要注意这里的命令代码要与其余字段结合使用,能够说命令代码是标准请求命令代码的核心,正是由于这些命令代码而决定了11个USB标准请求命令):
0) 0 GET_STATUS:用来返回特定接收者的状态
1) 1 CLEAR_FEATURE:用来清除或禁止接收者的某些特性
2) 3 SET_FEATURE:用来启用或激活命令接收者的某些特性
3) 5 SET_ADDRESS:用来给设备分配地址
4) 6 GET_DEscriptOR:用于主机获取设备的特定描述符
5) 7 SET_DEscriptOR:修改设备中有关的描述符,或者增长新的描述符
6) 8 GET_CONFIGURATION:用于主机获取设备当前设备的配置值(注同上面的不一样)
7) 9 SET_CONFIGURATION:用于主机指示设备采用的要求的配置
8) 10 GET_INTERFACE:用于获取当前某个接口描述符编号
9) 11 SET_INTERFACE:用于主机要求设备用某个描述符来描述接口
10) 12 SYNCH_FRAME:用于设备设置和报告一个端点的同步帧
以上的11个命令要说得明白真的有一匹布那么长,请各位去看书吧,这里就很少说了,控制传输是USB的重心,而这11个命令是控制传输的重心,因此这11个命令是重中之重,这个搞明白了,USB就算是入门了。
问题八:在标准的USB请求命令中,常常会看到描述符(Descriptor),这是什么来的呢?
回答八:Descriptor即描述符,是一个完整的数据结构,能够经过C语言等编程实现,并存储在USB设备中,用于描述一个USB设备的全部属性,USB主机是经过一系列命令来要求设备发送这些信息的。它的做用就是经过如问答节中的命令***做来给主机传递信息,从而让主机知道设备具备什么功能、属于哪一类设备、要占用多少带宽、使用哪类传输方式及数据量的大小,只有主机肯定了这些信息以后,设备才能真正开始工做,因此描述符也是十分重要的部分,要好好掌握。标准的描述符有5种,USB为这些描述符定义了编号:
1——设备描述符
2——配置描述符
3——字符描述符
4——接口描述符
5——端点描述符
上面的描述符之间有必定的关系,一个设备只有一个设备描述符,而一个设备描述符能够包含多个配置描述符,而一个配置描述符能够包含多个接口描述符,一个接口使用了几个端点,就有几个端点描述符。这间描述符是用必定的字段构成的,分别以下说明:
一、设备描述符
struct _DEVICE_DEscriptOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x12
BYTE bDescriptorType; //描述符类型编号,为0x01
WORD bcdUSB; //USB版本号
BYTE bDeviceClass; //USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型
//0x00不是在设备描述符中定义的,如HID
BYTE bDeviceSubClass; //usb分配的子类代码,同上,值由USB规定和分配的
BYTE bDeviceProtocl; //USB分配的设备协议代码,同上
BYTE bMaxPacketSize0; //端点0的最大包的大小
WORD idVendor; //厂商编号
WORD idProduct; //产品编号
WORD bcdDevice; //设备出厂编号
BYTE iManufacturer; //描述厂商字符串的索引
BYTE iProduct; //描述产品字符串的索引
BYTE iSerialNumber; //描述设备序列号字符串的索引
BYTE bNumConfiguration; //可能的配置数量
}
二、配置描述符
struct _CONFIGURATION_DEscriptOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x12
BYTE bDescriptorType; //描述符类型编号,为0x01
WORD wTotalLength; //配置所返回的全部数量的大小
BYTE bNumInterface; //此配置所支持的接口数量
BYTE bConfigurationVale; //Set_Configuration命令须要的参数值
BYTE iConfiguration; //描述该配置的字符串的索引值
BYTE bmAttribute; //供电模式的选择
BYTE MaxPower; //设备从总线提取的最大电流
}
三、字符描述符
struct _STRING_DEscriptOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x12
BYTE bDescriptorType; //描述符类型编号,为0x01
BYTE SomeDescriptor[36]; //UNICODE编码的字符串
}
四、接口描述符
struct _INTERFACE_DEscriptOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x12
BYTE bDescriptorType; //描述符类型编号,为0x01
BYTE bInterfaceNunber; //接口的编号
BYTE bAlternateSetting;//备用的接口描述符编号
BYTE bNumEndpoints; //该接口使用端点数,不包括端点0
BYTE bInterfaceClass; //接口类型
BYTE bInterfaceSubClass;//接口子类型
BYTE bInterfaceProtocol;//接口所遵循的协议
BYTE iInterface; //描述该接口的字符串索引值
}
五、端点描述符
struct _ENDPOIN_DEscriptOR_STRUCT
{
BYTE bLength; //设备描述符的字节数大小,为0x12
BYTE bDescriptorType; //描述符类型编号,为0x01
BYTE bEndpointAddress; //端点地址及输入输出属性
BYTE bmAttribute; //端点的传输类型属性
WORD wMaxPacketSize; //端点收、发的最大包的大小
BYTE bInterval; //主机查询端点的时间间隔
}
USB枚举实例转载:
对2440的USB HOST进行初始化完毕(主要包括对符合OHCI规范的寄存器的初始化—总线复位、中断使能、清除中断标志、电源管理、内存指针寄存器的初始化,各类数据结构的初始化等),等待USB设备的插入,当2440检测到有设备插入,就要对设备进行枚举了。那么为何要对设备进行枚举呢?起始枚举就至关于主机和设备创建链接的过程(接头),Host向Device询问一些东西,Device将自身的设备类型,如何进行通讯报告给Host,这样Host就知道怎么着对Device进行操做了。
枚举的过程实际上用到并且只用到了总线的“控制传输(Control Transfer)”的传输方式。这种传输方式一般用于配置/命令/状态等情形,其中的设置操做setup和状态操做status过程的数据包具备USB协议定义的数据结构,所以,控制传输只能经过消息管道进行。
一个完整的控制传输包括三个过程:1.创建链接 2.数据过程(可选) 3.状态过程
创建链接的过程都是有Host发起,它开始于一个Setup令牌包,后面紧跟一个DATA0包。若是是控制输入传输,数据过程则为输入数据,如果控制输出传输,则数据过程是输出数据。
数据过程的可选型是指设置过程须要指定数据长度,若是指定为0,则没有数据过程。状态过程跟在数据过程以后,状态过程刚好和数据过程的数据传输方向相反,由于此阶段主要是用来确认以前两阶段的全部数据都已经正确传输了。
好了,下面就结合个人这个实例来看看枚举的详细过程:
1.控制2440向U盘发送第一个Setup包,内容是80 06 00 01 00 00 08 00,其中最后的0008表示获得DEVICE_DCESCRIPTOR的前8个字节,由于这个包的主要目的是要得到USB Device中端点0的最大包的大小(第8个字节),因此只须要8个字节就能够了。USB Device返回的设备标识符为12 01 10 01 00 00 00 40,下面咱们须要对0x40记录下来,将其放到Endpoint Descriptor数据结构的DWORD0的MPS(bit16~bit32)块中去。
2.接下来2440发送第二个Setup包,内容是00 05 01 00 00 00 00 00这一个次的做用是为USB设备分配地址(至关于SD卡中的RCA)。若是USB Device接收并接受了此地址设置包,会返回一个长度为0的数据包。Host接收到长度为0的状态包以后就会返回一个ACK给Device,Device再接收到这个ACK以后,就能够启用新地址了。这样Device就获得了一个惟一的设备地址,做为主机通讯的惟一表示。
3.发送第三个Setup包,内容是80 06 00 02 00 00 09 00,此次是为了获取配置描述符集合的大小,此位位于读回数据的第三个字节。U盘返回的数据为09 02 20 00 01 01 00 80 32,即描述符集合总大小为0x20。
4.发送第四个Setup包,内容是80 06 00 02 00 00 09 00,和上次不一样的仅仅是,此次要读回来的数据是整个配置描述符区域。U盘返回来的数据是09 02 20 00 01 01 00 80 32 09 04 00 00 02 08 06 50 00 07 05 82 02 40 00 00 07 05 02 02 40 00 00。
这时候咱们就能够知道该设备是什么类型的设备,支持什么样的操做了。
上述这两个过程也有的程序就是直接读取0xff个字符大小,固然一样能够达到读回设备描述符集合的目的。
至此,咱们已经获得了所须要的设备信息,以后就能够对设备进行配置了。
5.向设备发送第五个Setup包,数据为00 09 01 00 00 00 00 00,USB Device返回一个长度为0的数据包,代表数据正确接收。
至此,USB的枚举过程就完成了。