USB BOT CDROM

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,表示命令不支持就可以了。

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180327G0BQ8M00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券