1.设备描述符
码实现如下:
const uchar code DeviceDescriptorBot[] =
{
0x12,//设备描述符长度
0x01,//设备描述符类型
0x10,0x01,//usb bcd
0x00,//class设置为,具体功能由接口描述符指定
0x00,//SubClass,设置为,具体功能由接口描述符指定
0x00,//protocol,设置为,具体功能由接口描述符指定
USB_EP0_MAX_PACKET_SIZE,//控制端点buf的大小字节数
USB_VID% 0x100,USB_VID / 0x100,//vid和pid设置
USB_PID_BOT% 0x100,USB_PID_BOT / 0x100,
0x01,0x00,//bcddevice
0x01,//厂商字符串索引
0x02,//产品字符串索引
0x00,//设备序列号索引,PID和VID一样的多个设备同时连接到主机的时候,主机依靠这个序列号字符串索引来区别具体是哪一个设备。不存在设置为,字符串索引从1开始。
0x01,//the number of configurations
};
2.配置描述符以及其它描述符
const uchar code ConfigDescriptorBot[] =
{
0x09,//配置描述符长度
0x02,//配置描述符类型
(9+ (9 + 7 + 7)),//配置描述符集合长度低字节
0x00,//高字节
//------- configration descriptor----
0x01,//接口数量
0x01,//配置描述符识别符从1开始,一个设备可能同时存在多个配置描述符,这个来区分是具体哪一个配置描述符,调用setconfig操作时会引用此值。
0x01,//配置描述符对应的字符串描述符
0x80,//总线供电
0x32,//100ma
//---------------------------
//-------interface ------------
0x09,//接口描述符长度
0x04,//接口描述符类型
0x00,//接口描述符索引,从开始,就是第几个接口描述符
0x00,//如果接口描述符索引值一样(共享端点),这个值就是用来区分具体是哪一个接口,见描述符详解文章
0x02,//端点个数
0x08,//接口实现功能为Mass storage,具体的看massstorage规范即可
0x06,//子类识别码为06,采用SCSI命令集合
0x50,//采用BOT协议。
0x00,//index of string
//---------------------------
//---------------endpoint-------
0x07,//端点描述符长度
0x05,//端点描述符类型
0x80|USB_BOT_IN_ENDPOINT,//IN端点
0x02,//BULK传输
USB_BOT_IN_BUFFERSIZE,//指定端点大小64字节,低字节
0x00,//高字节
0x00,//中断端点使用,bulk传输不使用
0x07,//端点描述符长度
0x05,//端点描述符类型
0x00|USB_BOT_OUT_ENDPOINT,//OUT端点
0x02,//BULK传输
USB_BOT_OUT_BUFFERSIZE,//指定端点大小64字节,低字节
0x00,//高字节
0x00,//中断端点使用,bulk传输不使用
//------------------------------
};
3.描述符实现说明
Mass Storage实现描述符时没有类描述符,只是在接口描述符中指定具体的功能。但是会有比较多的类描述符。
其中要了解SCSI、UFI指令。还有文件系统FAT16。USB mass storage规范中对各个对应的描述符都有详细的说明。如接口描述中会指明使用的是那一中命令和协议。
USB mass storage协议采用的是SCIS命令集合和BOT协议,则要看两者相关的协议。
4.BOT协议
协议传输数据方式为CBW->DATA->CSW过程。详细请看BOT协议规范。
4.1 CBW
主机要发送数据或者获取数据都是要先发送CBW字段,全长为31字节。
dCBWSignature:
dCBWTag:
主机分配,设备返回DSW时,将此值添加到对应的字段中;
dCBWDataTransferLength:
主机在数据传输阶段期望传输数据的长度字节数,就是执行此命令时期望处理的数据,小端结构低字节在先。
bmCBWFlags:
指明数据传输阶段方向,主机到设备或者是设备到主机;最高位D7:0-主机到设备,1-设备到主机。
bCBWLUN:
主机发送命令到对应的逻辑单元,代表第一个逻辑单元,1代表第二个逻辑单元,依此类推;
bCBWCBLength:
主机发送命令数据的长度,就是CBWCB单元;
CBWCB:
主机发送给设备的命令块,设备要解析此命令块,对后续数据做出相应的处理。
4.2 CSW
CSWSignature:
dCSWTag:
CBW阶段的dCSWTag值;
dCSWDataResidue:
表示实际数据处理的差值,即完成数据传输和主机期望数据之间的差值;
4.3 DATA
对于数据阶段就是不同的IN包或OUT包数据。
4.4 Bulk-Only Mass Storage Reset(class-specificrequest)
通知后续数据传输为BOT传输开始一个CBW,如果设备未收到此请求后续的端点都返回NAK操作。无数据阶段,响应状态阶段即可,控制传输,状态阶段为长度的IN包。
4.5 Get Max LUN (class-specific request)
控制传输1字节的逻辑单元值,一般设置为,代表一个逻辑单元,主机响应状态包。
5. SCSI命令
实际开发过程中,很多命令都是UFI命令。
5.1 inquiry
实现为UFI命令。
5.1.1 Logical Unit Number
根据GetMaxLun返回的逻辑单元个数(从开始,代表第一个逻辑单元。依此类推),发送不同的值,代表要访问的逻辑单元。有时候需要实现两个或者多个USB功能,如U盘、CDROM,则在实现的时候GetMaxLun会返回有个两个逻辑单元,第一个代表u盘,第二个代表访问CDROM。
5.1.2字段解释
5.1.3 Allocation Length
设置主机期望返回的数据长度,主机为返回的数据开辟的空间buf字节数,一般为0x24,即为36字节。
5.1.4 bushound抓取的inquiry数据
dCBWTag:主机分配0x87af30a8;
bmCBWFlags:指明数据传输方向,0x80->设备到主机;
bCBWLUN:00,第一个逻辑单元;
bCBWCBLength:0x06,命令数据的长度;
5.1.5 inquiry应答
命令来自于UFI命令。
5.1.6 Peripheral device type
这个图又来自于SCSI命令集合。设置为0x00代表为U盘设备,设置为0x05代表为CDROM设备。目前只做过这两种设备,U盘是主机会枚举到一个可以移动的硬盘,CDROM是主机枚举到一个光盘。
5.1.7 RMB
最高为代表是否为可以移动媒介。
0x80:可以移动媒介;
0x00:不可以移动媒介。
5.1.8各个字段解析
5.1.9 bushound抓取的inquiry应答数据
这个U盘实现的inquiry指令是按照SCSI命令集合实现的。主要是告诉主机设备类型和设备相关信息。
0x00:代表为U盘媒介;
0x80:可以移动U盘;
Version:0x04,此值来自于SCSI规范;
Response Data format:0x02此值来自于SCSI规范;
Additional length:额外的数据长度为0x1F字节,就是后续的数据长度不包括长度本身;
后续为厂商信息、产品信息、产品版本号。
CDROM实现方式:
0x05:代表为CDROM媒介;
0x80:可以移动;
Version:0x00,此值来自于SCSI规范;
Response Data format:0x02此值来自于SCSI规范;
Additional length:额外的数据长度为0x1F字节,就是后续的数据长度不包括长度本身;
后续为厂商信息、产品信息、产品版本号。
5.2 GET EVENT/STATUSNOTIFICATION
这个命令只有是在CDROM实现的时候,主机会下发这个命令,属于MMC-2指令。
这个命令的主要功能是查询设备事件是否发生和主机执行异步操作功能。
如果设备支持主机请求的事件则响应对应的事件数据,若果不支持则正确终止,不响应任何的事件数据,响应的事件类型为不支持。
5.2.1命令格式
IMMED:指明是查询事件还是执行异步事件;
Notification Class Request:指明请求的事件类型;
Allocation Length:请求设备传输数据的最大长度,设备实际发送的数据长度可以小于这个长度;
5.2.2注意说明
就是说如果请求设备的逻辑单元如果不支持请求的事件类,则对应的逻辑单元成功的阻止这个命令,返回数据只包括应答状态,并指明支持的类为,就是不支持任何的事件请求。
不支持只返回Event Header即可,实现时不支持即可。
Event Data Length:指明后续数据的长度,字节数,不包括长度本身。
Notification Class:指明响应的事件类型:
不支持给000b即可。
Support event calssses:指明此设备支持的事件类型,不支持全部设置为。
5.2.3 bushound抓取的数据
CDROM设备返回的数据为00020000,长度为两个字节,不支持任何事件类型。
5.3 GET CONFIGURATION
这个命令是在实现CDROM的时候,需要实现的。
5.3.1命令格式
RT: 00b,就是返回FeatureHeader和所有逻辑单元支持的特性描述,从Starting Feature Number指定的起始特性号开始;
RT:01b:就是返回Feature Header和逻辑单元当前激活的功能特性描述;
以上两种其实实际实现时实现代码一样,支持的即为激活的。也不考虑Starting Feature Number,就是自己设备支持的都认为要返回的。
RT:02b:就是返回Feature Header和当前Starting Feature Number指定的特性描述,如果不支持Starting Feature Number指定的特性描述,就不返回特性描述,只返回Feature Header即可。
Allocation Length:期望设备传输的最大数据长度。
主机一般是下发期望获取的长度为08,这样主机可以知道设备支持的特性长度和当前支持的功能是什么(如CDROM,具体见应答功能部分),而设备只返回前8个字节即可。
5.3.2命令应答
应答数据格式为Feature Header和Feature Descriptor两个字段。
5.3.2.1 Feature Header
Data Length:指明后续数据的长度,字节数,不包括数据长度本身。
Current Profile :指明当前设备支持的功能:
CDROM实现时,设置为0x0008,指定为CDROM设备。
5.3.2.2 Feature Descriptor
这里要实现设备支持的全部特性。,每一个特性MMC规范中都有对应的定义,实现自己支持的就可以了。
Feature code如下:
实现自己支持的就可以了。CDROM实现时主要实现了一下功能的Feature。
5.3.2.3 profile list
指明此设备支持的功能列表,如果CDROM等。具体见TABLE 40图片中的功能。
实际代码实现:指明代码当前激活的设备是这个功能是当前激活的功能,CDROM设备实现时如下,只支持一个设备CDROM,且CDROM为当前激活的功能。
const uchar code ConfigFeature_00[] = {
//FeatureDescriptor
0x00,0x00, //Feature Code (0x0000 means ProfileList Feature)
0x03, //present current
0x04, //Additional Length
0x00,0x08,0x01,0x00, //CD-ROM (CurrentP=1)
};
CDROM要实现的特性如下图
5.3.2.4 Core Feature
这个特性是设备告诉主机自己的物理接口,就是说自己支持的命令族是哪一类。
代码实现:
/*MMC-2 Table-42 Core Feature Descriptor Format*/
const uchar code ConfigFeature_01[] = {
//FeatureDescriptor
0x00,0x01, //Core Feature
0x03, //present current
0x04, //Additional Length
0x00,0x00,0x00,0x01, //Physical Interface Standard = SCSIFamily
};
实现为SCSI命令接口。
但不管是什么接口,都必须支持以下的指令:
5.3.2.5Morphing Feature (0002h)
指明逻辑单元支持的操作模式,不同的操作模式就不有不同的指令支持。
代码实现:
/*MMC-2 Table-45 Morphing DescriptorFormat*/
const uchar code ConfigFeature_02[] = {
//FeatureDescriptor
0x00,0x02, //Morphing Descriptor
0x03, //presentcurrent
0x04, //Additional Length
0x00, //supports only the pollingimplementation of GET EVENT/STATUS NOTIFICATION
// 0x01, //supports both polling andasynchronous GET EVENT/STATUS NOTIFICATION
0x00,0x00,0x00, //Reserved
};
5.3.2.6 Removable Medium Feature (0003h)
说明设备是否可以通过命令移除,就是通过鼠标右键执行弹出操作。
代码实现:
/*MMC-2 Table-47 Removable MediumDescriptor Format*/
const uchar code ConfigFeature_03[] = {
//FeatureDescriptor
0x00,0x03, //Removable Medium Descriptor
0x03, //present current
0x04, //Additional Length
0x20, //load midia type = 01
// 0x21, //load midia type = 01 ; lock= 01
// 0x41, //load midia type = 02 ; lock= 01 //lyt
0x00,0x00,0x00, //Reserved
};
这里不支持指令拔出。
5.3.2.7 Random Readable Feature (0010h)
告诉主机设备支持读指令的操作。支持的指令为:
代码实现:
/*MMC-2 Table-50 Random Readable DescriptorFormat*/
const uchar code ConfigFeature_10[] = {
//FeatureDescriptor
0x00,0x10, //Random Readable Descriptor
0x03, //present current
0x08, //Additional Length
0x00,0x00,0x08,0x00, //block size应和read CAPACITY指定的大小保持一致2048。
0x00,0x01, //Blocking (CDROM=1 DVD=10h)
0x00, //Readwrite Error recory page is NOT present
0x00, //Reserved
};
实际主机操作过程中,都是按照逻辑块进行操作的,操作的最小单元为一个逻辑块大小。而cDROM为只读媒介,实际的读写命令是主机软件自己实现的指令。
5.3.2.8CD Read Feature (001Eh)
代码实现:
/*MMC-2 Table-54 CD ReadDescriptor Format*/
const uchar codeConfigFeature_1E[] = {
//Feature Descriptor
0x00,0x1E, //CD ReadDescriptor
0x05, //Version=1;Present = 0; Current = 1
0x04, //AdditionalLength
0x00, //C2Flag=0; CD Text=0;不支持Format=0x05的READTOC指令
//0x01, //CD Text= 1; supports Format Code 5h of the READ TOC/PMA/ATIP command.
5.3.2.9Power Management Feature (0100h)
代码实现:
/*MMC-2 Table-87 PowerManagement Descriptor Format*/
const uchar codeConfigFeature_100[] = {
0x01,0x00, //PowerManagement Descriptor
0x03,
0x00, //AdditionalLength
};
5.3.2.10Time-Out Feature (0105h)
代码实现
/*MMC-2 Table-96 Time-OutDescriptor Format*/
const uchar codeConfigFeature_105[] = {
0x01,0x05, //Time-OutDescriptor
0x03,
0x00, //AdditionalLength
};
5.3.3 busHound抓取的数据
5.4 MODE SENSE(10)
这个命令是返回设备的一些参数数据。
5.4.1命令格式
DBD:1,指示返回数据中不需要携带块描述符的操作;,指示需要携带。
PC:设置返回主机要求的参数值:
一般设备不支持01类型,如果是01就是不返回参数数据;
10返回默认参数值,设备自己设置为默认page code为2A,即为默认主机就不指定;
11和10返回的数据一样,返回几个pagecode的参数数据,要看pagecode值。
PAGE CODE:返回指定page code的参数值,如果是3F则返回全部page code的参数值。
5.4.2命令应答
命令应答格式如下:
Mode parameter header:指明参数头,必须要存在;
Mode data length:指明后续数据长度,不包括本身;
Medium type:媒介类型,0x01指定为CD_ROM实现。
其它字段全部设置为,不支持。
代码实现:
下面是参数的page CODE实现,在MMC的规范中指明了具体的pagecode实现格式:
5.4.2.1 mode page0D
格式定义如下:
代码实现如下:
5.4.2.2 mode page 1A
格式如下:
代码如下:
5.4.2.3 mod page 2A
格式如下:
代码实现:
代码实现这3个page code就可以了。
5.4.2.3 bus hound抓取的数据
5.5 READ CAPACITY
这个命令是告诉主机设备实际的存储能力是多大字节。这个命令和READFORMAT CAPACITY差不多,CD设备由于不允许格式化,所以不用支持READFORMAT CAPACITY这个命令,这个命令是告诉主机最大格式化容量,由于文件系统要记录媒介的容量,实际的存储能力还是通过READCAPACITY来体系的。
5.5.1命令格式
5.5.2命令应答
告诉主机媒介有多少block以及一个block的大小字节数。CDROM设备一块的字节数为2048字节。
Logical Block Address:逻辑块个数,实际计算要加1,从开始。
5.5.3 bushoud抓取的数据
5.6 READ 10命令
从媒介中读取指定大小和地址的数据,实际运行过程中,PC系统会缓存一块数据,就枚举成功后就先读取一块数据进行缓存。调用写命令的时候会先把数据写到缓存中。最后再把数据写到媒介中。
注:实际代码实现过程中自己又顶一个了一对命令F1和F2分别为读和写命令,这样也不用缓存数据到内存中,这个实现和主机实现驱动有关,是解决缓存的数据不能及时写到媒介中的一种方式。
5.6.1命令格式
5.6.2命令应答
就是从起始块读取相应块数的数据发送到主机即可。
5.6.3 bushound数据
5.7READ TOC/PMA/ATIP
读取磁盘的TOC信息:
5.7.1命令格式
MSF字段可以忽略,早期版本使用,返回数据是否从指定的track号开始返回数据,后续版本都是从Format格式去判断。
5.7.2应答格式
Track number为0xAA代表为lead out区。
Format:
00:
应答代码如下:只有一个track.设置为数据track。
01;
代码实现:
02:
5.8REQUEST SENSE
返回sense data。但是一般设置为不支持。
5.8.1命令格式
5.8.2命令应答
命令应答采用固定格式
SENSE KEY设置为02H,ASC、ASCQ分别设置为3A、00表示不支持。
5.8.3 bushound抓取的数据
这个移植按照这个实现就可以了。
5.9其它命令
对于其它命令返回空数据即可,
将CSW的状态位设置位1,表示命令不支持就可以了。
领取专属 10元无门槛券
私享最新 技术干货