分类: LINUX
2011-05-18 22:20:37
又是一个晚上,座在电脑前总结自己的实践,即使累了,但还是快乐着。前面总结bulkonly协议,现在总结一下scsi,scsi协议有很多,所以只总结这次在usb mass storage 里面用到的协议,主要包括inquiry,format , read write 等等命令。
下面会一个一个总结。
U盘需要处理的命令如下:
1:inquiry:设备的一个描述,告诉host你的设备是什么,名字叫什么,用的什么协议,这里用的SCSI协议—SPC2
2:READ FORMAT CAPACITIES:读格式容量(The READ FORMAT CAPACITIES command allows the host to request a list of the possible capacities that can be formatted on the currently installed medium.)
3:READ CAPACITY:读取容量信息
4:READ(10):回发在逻辑单元的数据,既回发MBR(Main Boot Record)主引导扇区
5:SENSE6: 目的在于获得设备内部很多潜在的信息,其中包括了是否设置了写保(The MODE SENSE(6) command (see table 62) provides a means for a device server to report parameters to an application client. It is a complementary command to the MODE SELECT(6) command. Device servers that implement the MODE SENSE(6) command shall also implement the MODE SELECT(6) command.)
6:WRITE(10):host向slave发生数据并写在u盘存储器里面。
7:TEST UNIT READY:检查U盘准备好没有。
1:inquiry
// The standard INQUIRY data shall contain at least 36 bytes
// This is the reduced structure for Mass Storage Devices
typedef struct
{
cyg_uint8 peripheral; // Device Type
cyg_uint8 rmb; // Removable Media Bit
cyg_uint8 version; // Version Field
cyg_uint8 resp_data_format; // Response Data Format
cyg_uint8 additional_len; // Additional Length
cyg_uint8 sccstp; // SCC Supported (include embedded storage array)
cyg_uint8 bque; // Basic Queuing
cyg_uint8 cmdque; // Command Queuing
cyg_uint8 vendor_id[8];
cyg_uint8 product_id[16];
cyg_uint8 product_rev[4];
} msd_scsi_inq_resp;
这个结构体就是为inquiry准备的数据包,这个命令是usb mass storage第一个接收到的命令
在这里只需要关注两个字段OPERATION CODE ,ALLOCATION LENGTH。其它的还没用到,每个命令都有一个OPERATION CODE
用来标志这个命令是什么命令,毕竟我们不会看数字就知道什么意思,电脑也不会看文字就是要做什么,是吧。现在这里是12,我们查一查SPC-2
协议,就知道OPERATION CODE 为12 就知道这次host需要slave做什么操作。
既然知道了这个操作,那么咱们就应该回复一下,毕竟来而不往非礼也。那咱们得准备一下礼物送给host,不然这个门打不开,马上就关起来了
就好像现在这个社会,有钱有权什么都可以,这个社会让我们这些刚毕业的怎么生存啊,咱学习嵌入式就是为了多赚点money。下面就是一个能够回复
Host的inquiry包。
/*
这是inquiry 请求包
*/
const msd_scsi_inq_resp inrq_resp = {
USBS_SCSI_DIRECT_ACCESS_BLOCK_DEVICE, // Direct Access Block device 0x00
USBS_SCSI_REMOVABLE_DEVICE, // Device is removable
0x04, // Comply with SPC-2
0x02, // Standard format
0x20, /* Response is 0x20 + 4 bytes ,表明这个请求包有多长,这里为36 */
0x00,
0x00,
0x00,
{'R','i','s','e','t','e','k',' '}, /*VENDOR IDENTIFICATION 8~15*/
{'M','a','s','s',' ','S','t','o','r','a','g','e',' ',' ',' ',' '}, /*PRODUCT IDENTIFICATION 16-31*/
{'0','.','0','1'}, /*PRODUCT REVISION LEVEL ,版本, 32~35*/
};
这个图下面还有数据端,但是在这里就只回了一个最小的数据包回去,那就总结这些字段就好了吧。
第0个字节:有这两个PERIPHERAL QUALIFIER ,PERIPHERAL DEVICE TYPE东东需要关注,PERIPHERAL QUALIFIER这里三位全为0
PERIPHERAL DEVICE TYPE的值都为0 ,表明意思是Direct-access device。
第一个字节:只要关注RMB表明这个设备可不可以移除,原文为:A removable medium (RMB) bit of zero indicates that the medium is not removable. A RMB bit
of one indicates that the medium is removable.
第二个字节:VERSION表明数据交流使用的协议版本是SPC-2,其值为0x04,
第三个字节:An AERC bit of one indicates that the processor device is capable of accepting asynchronous event reports. An AERC bit of zero indicates that the processor device does not support asynchronous event reports;
RESPONSE DATA FORMAT:A RESPONSE DATA FORMAT field value of two indicates that the data shall be in the format specified in this standard.
这里写为2就好,整个字节的值就是为0x02。
第四个字节:ADDITIONAL LENGTH表明这个值附加了多少数据,Response is 0x20 + 4 bytes ,表明这个请求包有多长,这里为36 ,前面有四个数据下面有32个刚好36个数据。
第五,第六,第七个字节都填0,想知道为什么的话,看看手册吧,不然这么总结就成了在翻译协议了。
第八字节—第十五字节:VENDOR IDENTIFICATION,在8个字节里面,随便写一些字符,写法如上面就可以了。而PRODUCT IDENTIFICATION和PRODUCT REVISION LEVEL都是想填什么就填什么,只要没有操作范围。一定要注意范围哦。
/*
Function: usb_msd_scsi_handle_inquiry:
Handle Inquiry Request Command
Data in : msd
Data out: NULL
*/
static inline cyg_int32 usb_msd_scsi_handle_inquiry( usb_msd * msd )
{
cyg_int32 tx_bytes = sizeof(msd_scsi_inq_resp);
DBG("USB Slave MSD: SCSI inquiry\n");
// Copy over to message buffer
memcpy( msd->buffer, (cyg_uint8 *) &inrq_resp, tx_bytes );
usb_msd_tx_send(msd , tx_bytes);
return tx_bytes;
}
通过端点2就把数据发给host,第一步就完成了。
2:READ FORMAT CAPACITIES
下表就是READ FORMAT CAPACITIES Command的命令表,这个命令也只需要关注两个字节,Operation Code (23h) and Logical Unit Number
Logical Unit Number(LUN),前面说过这个LUN,这里就为一个LUN。下面准备回复的数据。
这个usb_msd_scsi_read_format_capacities函数就是用来准备回复host数据的函数并且发送给host。还是按照协议回复,上图。
第一个需要准备的是Capacity List Header,然后是Current/Maximum Capacity Header等等。
又是一个图,这图图还真多,看看图,开心了吧,只用关注一个字节就好了,手册上说这个字段写0x08就好。
接下来是Current/Maximum Capacity Descriptor,0~3字节用来描述这个存储设备有多少块block,第四个字节Descriptor Code的值为0x02表示Formatted Media,5~7字节用来描述每块有多大,这次写的存储器每块的大小为512。下面的字段咱们偷偷懒就不回了,其实这样是很正确的。
/*
Function: usb_msd_scsi_read_format_capacities:
准备磁盘格式容量
Data in : msd
Data out: NULL
*/
static inline cyg_int32 usb_msd_scsi_read_format_capacities( usb_msd * msd )
{
cyg_uint8 BulkBuf[12] ={
[ 0] = 0x00,
[ 1] = 0x00,
[ 2] = 0x00,
[ 3] = 0x08, /* Capacity List Length */
/* Block Count */
[ 4] = (MSC_BlockCount >> 24) & 0xFF, /*表示磁盘有多少块*/
[ 5] = (MSC_BlockCount >> 16) & 0xFF,
[ 6] = (MSC_BlockCount >> 8) & 0xFF,
[ 7] = (MSC_BlockCount >> 0) & 0xFF,
/* Block Length */
[ 8] = 0x02, /* Descriptor Code: Formatted Media */ /*Formatted Media - Current media capacity*/
[ 9] = (MSC_BlockSize >> 16) & 0xFF, /*表示磁盘每块有多大*/
[10] = (MSC_BlockSize >> 8) & 0xFF,
[11] = (MSC_BlockSize >> 0) & 0xFF,
};
memset(msd->buffer , 0 , 512);
memcpy(msd->buffer , BulkBuf, 12);
usb_msd_tx_send(msd , 12);
return 0;
}
3:READ CAPACITY
这里回复存储容量,但是这里和上面的format还有点不明白,以后再处理,现在先这么总结先。
现在在上图,图解直观。
这个命令关注五个东东,Operation Code (25h),Logical Unit Number ,RelAdr ,Logical Block Address ,PMI。 其实待会有惊喜
Operation Code (25h),Logical Unit Number这两个就不说了,已经说过了,Logical Block Address(逻辑块地址)应该怎么
设置呢,手册上有这么一句话,看了应该很是高兴。RelAdr: This bit should be set to zero. Logical Block Address should be set to zero.
PMI: This bit should be set to zero. 贴了三句E文,看了后,是不是很开心,不用在烦恼剩下的描述了,全是0。既然协议都说是0
那么就不管了。命令是不管了,但是偶们还是要给host回复点东西吧,送礼了哦,不然host会嚷嚷你去睡觉。
这个回复和format差不多,还比它简单,只是注意现在在Block Count那里减1,我想应该是0的问题,如果0是第一个数据,那么你
自然要减一个下来。
/*
Function: usb_msd_scsi_handle_capacity:
读取磁盘的容量
Data in : msd
Data out: NULL
*/
static inline cyg_int32 usb_msd_scsi_handle_capacity( usb_msd * msd )
{
DBG("usb_msd_scsi_handle_capacity \n");
cyg_uint8 length = 8;
cyg_uint8 BulkBuf[ ] ={
/* Last Logical Block */
[ 0] = ((MSC_BlockCount - 1) >> 24) & 0xFF, /*回复有多少逻辑块*/
[ 1] = ((MSC_BlockCount - 1) >> 16) & 0xFF,
[ 2] = ((MSC_BlockCount - 1) >> 8) & 0xFF,
[ 3] = ((MSC_BlockCount - 1) >> 0) & 0xFF,
/* Block Length */
[ 4] = (MSC_BlockSize >> 24) & 0xFF, /*每块的大小,这里为512*/
[ 5] = (MSC_BlockSize >> 16) & 0xFF,
[ 6] = (MSC_BlockSize >> 8) & 0xFF,
[ 7] = (MSC_BlockSize >> 0) & 0xFF,
};
memset(msd->buffer , 0 , 512);
memcpy(msd->buffer , BulkBuf, length);
usb_msd_tx_send(msd , length);
return 0;
}
4:READ(10)
现在直奔主题了,上图
这个命令就是用来读取存储器里面存储的数据,包括MBR等数据。现在挑不熟悉的总结了,熟悉的就不说了。
咋一看都是比较熟悉的呢,那几个不熟悉的,在协议上说全是0。这里还有一个关注一下,Logical Block Address
前面说的是些0,但是这里不一样了,host必须给出存储器的块,slave才知道提交那块的数据。usb_msd_scsi_rwsetup
就是用来解析CBW包里面包含的块和要求回复数据的长度。Transfer Length (MSB) 和 Transfer Length (LSB)存储了数据
的长度。
/*
Function: usb_msd_scsi_MemoryRead:
读取磁盘数据
Data in : msd
Data out: NULL
*/
static inline void usb_msd_scsi_MemoryRead (usb_msd * msd) {
cyg_uint8 len;
DBG("usb_msd_scsi_MemoryRead \n");
if (Length > MSC_MAX_PACKET) {
len = MSC_MAX_PACKET;
} else {
len= Length;
}
if ((Offset + len) > MSC_MemorySize) {
len = MSC_MemorySize - Offset;
BulkStage = MSC_BS_DATA_IN_LAST_STALL;
}
usb_scsi_send(&DiskImage[Offset] , len);
Offset += len;
Length -= len;
msd->csw.data_residue -= len;
if (Length == 0) {
BulkStage = MSC_BS_DATA_IN_LAST;
}
if (BulkStage != MSC_BS_DATA_IN) {
msd->csw.status = CSW_CMD_PASSED;
}
}
/*
Function: usb_msd_scsi_handle_read:
handle the read command
Data in : msd
Data out: NULL
*/
static inline cyg_int32 usb_msd_scsi_handle_read(usb_msd * msd)
{
DBG("usb_msd_scsi_handle_read \n");
if(usb_msd_scsi_rwsetup(msd))
{
if ((msd->cbw->flags & 0x80) != 0) {
BulkStage = MSC_BS_DATA_IN;
usb_msd_scsi_MemoryRead(msd);
} else { /* direction mismatch */
stm32_usb_set_rxep_status (msd->tx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
msd->csw.status = CSW_PHASE_ERROR;
usb_msd_csw_send();
}
}
return 0;
}
5:SENSE6
这里需要知道SENSE6命令的操作码是0x1A,其他的都不怎么重要了,至少在这个实验里面。那应该怎么回复数据呢,如下图所示
MODE DATA LENGTH表示接下来有几个字段,这里自然是三个,接下来的三个字段都得换一个手册了,从SPC-2 JUMP 到SSC-3。
在SSC-3里面有这么一个图图,就是用来解析第三个字段的。表示是不是只读。当WP为0表示可读可写,反之只读。其他的就写0了。要是在其他的情况,比如不是usb mass storage那么还得研究协议哦。
/*
Function: usb_msd_scsi_handle_sense:
handle the sense command
目的在于获得设备内部
很多潜在的信息,其中
包括了是否设置了写保
护
Data in : msd
Data out: NULL
*/
static inline cyg_int32 usb_msd_scsi_handle_sense(usb_msd * msd)
{
DBG("usb_msd_scsi_handle_sense \n");
cyg_uint8 length = 4;
cyg_uint8 BulkBuf[ ] ={
[ 0] = 0x03,
[ 1] = 0x00,
[ 2] = 0x80, /*这里的第七位写了1 ,表示该磁盘开启了写保护*/
[ 3] = 0x00,
};
memset(msd->buffer , 0 , 512);
memcpy(msd->buffer , BulkBuf, length);
usb_msd_tx_send(msd , length);
return 0;
}
6:WRITE(10)
这个命令和read差不了多少,只是一个向host提交数据,一个是host向salve写数据。数据包不同就在操作码。
/*
Function: usb_msd_scsi_MemoryWrite:
向磁盘写数据,但是
现在只是只读,所以
该函数没实际用处
Data in : msd
Data out: NULL
*/
static inline void usb_msd_scsi_MemoryWrite (usb_msd * msd) {
//cyg_int32 n;
DBG("usb_msd_scsi_MemoryWrite \n");
if ((Offset + bulk_length) > MSC_MemorySize) {
bulk_length = MSC_MemorySize - Offset;
BulkStage = MSC_BS_CSW;
stm32_usb_set_rxep_status (msd->rx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
}
// for (n = 0; n < bulk_length; n++) {
//Memory[Offset + n] = msd->buffer[n];
// }
Offset += bulk_length;
Length -= bulk_length;
msd->csw.data_residue -= bulk_length;
if ((Length == 0) || (BulkStage == MSC_BS_CSW)) {
msd->csw.status= CSW_CMD_PASSED;
usb_msd_csw_send();
}
}
/*
Function: usb_msd_scsi_MemoryWrite:
确认数据是不是正确
写入,在这里没实际
用处
Data in : msd
Data out: NULL
*/
static inline void usb_msd_scsi_MemoryVerify (usb_msd * msd) {
#if 0
cyg_int32 reg_val , n;
DBG("usb_msd_scsi_MemoryVerify \n");
if ((Offset + bulk_length) > MSC_MemorySize) {
bulk_length = MSC_MemorySize - Offset;
BulkStage = MSC_BS_CSW;
stm32_usb_set_rxep_status (msd->rx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
}
for (n = 0; n < bulk_length; n++) {
if (Memory[Offset + n] != msd->buffer[n]) {
MemOK = __FALSE;
break;
}
}
Offset += bulk_length;
Length -= bulk_length;
msd->csw.data_residue -= bulk_length;
if ((Length == 0) || (BulkStage == MSC_BS_CSW)) {
msd->csw.status= (MemOK) ? CSW_CMD_PASSED : CSW_CMD_FAILED;
usb_msd_csw_send();
}
#endif
}
/*
Function: usb_msd_scsi_rwsetup:
解析CBW包,使读写
能够操作正确的位置
Data in : msd
Data out: NULL
*/
BOOL usb_msd_scsi_rwsetup (usb_msd * msd) {
cyg_uint32 n;
DBG("usb_msd_scsi_rwsetup \n");
/* Logical Block Address of First Block */
n = (msd->cbw->cb.data[2]<< 24) | /*msd->cbw->cb.data[0] = 0x28 ,而msd->cbw->cb.data[1] 表示逻辑单元*/
(msd->cbw->cb.data[3] << 16) |
(msd->cbw->cb.data[4] << 8) |
(msd->cbw->cb.data[5] << 0);
Offset = n * MSC_BlockSize;
/* Number of Blocks to transfer */
switch (msd->cbw->cb.data[0]) {
case USBS_SCSI_READ_10:
case USBS_SCSI_WRITE_10:
case USBS_SCSI_VERIFY_10:
n = (msd->cbw->cb.data[7] << 8) | /*msd->cbw->cb.data[7] = 0 , msd->cbw->cb.data[8] = 1*/
(msd->cbw->cb.data[8] << 0);
break;
case USBS_SCSI_READ_12:
case USBS_SCSI_WRITE_12:
n = (msd->cbw->cb.data[6] << 24) |
(msd->cbw->cb.data[7] << 16) |
(msd->cbw->cb.data[8] << 8) |
(msd->cbw->cb.data[9] << 0);
break;
}
Length = n * MSC_BlockSize; /*1*512 , 正好符合前面的请求数据量*/
if (msd->cbw->data_transfert_len == 0) { /* host requests no data */
msd->csw.status = CSW_CMD_FAILED;
usb_msd_csw_send();
return (__FALSE);
}
if (msd->cbw->data_transfert_len != Length) {
if ((msd->cbw->flags & 0x80) != 0) { /* stall appropriate EP */
stm32_usb_set_rxep_status (msd->tx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
} else {
stm32_usb_set_rxep_status (msd->rx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
}
msd->csw.status = CSW_CMD_FAILED;
usb_msd_csw_send();
return (__FALSE);
}
return (__TRUE);
}
7:TEST UNIT READY
这个命令没什么好说的,只是看看磁盘准备好没,咱们也不用向host进贡了,高兴一下吧。
/*
Function: usb_msd_scsi_handle_test_unit_ready:
测试磁盘是否准备好
Data in : msd
Data out: NULL
*/
static inline cyg_int32 usb_msd_scsi_handle_test_unit_ready(usb_msd * msd)
{
DBG("usb_msd_scsi_handle_test_unit_ready \n");
if (msd->cbw->data_transfert_len != 0) { /*其实什么也不需要做,只要host发来的长度为0 ,咱们
直接回复一个csw包就好了,数据端全是0*/
if ((msd->cbw->flags& 0x80) != 0) {
stm32_usb_set_rxep_status (msd->tx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
} else {
stm32_usb_set_rxep_status (msd->rx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
}
}
msd->csw.status = CSW_CMD_PASSED;
usb_msd_csw_send();
return 0;
}
/*
Function: usb_msd_scsi_handle_write:
handle the write command
Data in : msd
Data out: NULL
*/
static inline cyg_int32 usb_msd_scsi_handle_write(usb_msd * msd)
{
DBG("usb_msd_scsi_handle_write \n");
if (usb_msd_scsi_rwsetup(msd)) { /*和read情况一样*/
if ((msd->cbw->flags & 0x80) == 0) {
BulkStage = MSC_BS_DATA_OUT;
usb_scsi_setup_status(msd->rx_ep_num);
} else { /* direction mismatch */
stm32_usb_set_rxep_status (msd->tx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
msd->csw.status = CSW_PHASE_ERROR;
usb_msd_csw_send();
}
}
return 0;
}
/*
Function: usb_msd_scsi_handle_write:
handle the verify command
Data in : msd
Data out: NULL
*/
static inline cyg_int32 usb_msd_scsi_handle_verify(usb_msd * msd )
{
DBG("usb_msd_scsi_handle_verify \n");
//usb_msd_scsi_MemoryVerify(msd);
return 0;
}
/*
Function: usb_msd_scsi_handle_cmd:
Handle SCSI command
Data in : msd
Data out: NULL
*/
cyg_int32 usb_msd_scsi_handle_cmd( usb_msd * msd , cyg_uint8 *ctrlep_msg_buffer )
{
cyg_uint32 ret;
bulk_length = strlen((char *)ctrlep_msg_buffer)+1;
msd->cbw =(usb_msd_cbw *)ctrlep_msg_buffer;
cyg_uint8 cmd = msd->cbw->cb.data[0];
usb_scsi_command = cmd;
msd->csw.tag = msd->cbw->tag; //csw tag
msd->csw.data_residue = msd->cbw->data_transfert_len; //csw length
DBG("usb_msd_scsi_handle_cmd cmd = 0x%x msd->csw.data_residue = %d\n" , cmd , msd->csw.data_residue);
switch( cmd )
{
case USBS_SCSI_INQUIRY:
ret = usb_msd_scsi_handle_inquiry(msd);
break;
case USBS_SCSI_READ_CAPACITY:
ret = usb_msd_scsi_handle_capacity( msd );
break;
case USBS_SCSI_READ_10:
ret = usb_msd_scsi_handle_read(msd );
break;
case USBS_SCSI_WRITE_10:
ret = usb_msd_scsi_handle_write( msd );
break;
case USBS_SCSI_REQUEST_SENSE:
//ret = usb_msd_scsi_handle_req_sense( msd);
break;
case USBS_SCSI_SENSE_6:
ret = usb_msd_scsi_handle_sense( msd );
break;
case USBS_SCSI_TEST_UNIT_READY:
ret = usb_msd_scsi_handle_test_unit_ready( msd );
break;
case USBS_SCSI_VERIFY_10:
ret = usb_msd_scsi_handle_verify( msd );
break;
case USBS_SCSI_READ_FORMAT_CAPACITIES:
ret = usb_msd_scsi_read_format_capacities( msd );
break;
case USBS_SCSI_PREVENT_ALLOW_REMOVAL:
//ret = usb_msd_scsi_handle_removal( msd );
break;
default:
// Use for all commands not implemented, not
// supported
DBG("USB Slave MSD: SCSI illegal request %x \n", cmd );
msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
ret = 0;
break;
}
return ret;
}
/*
Function: usb_msd_scsi_bulk_out:
Handle SCSI bulk out event
Data in : ctrlep_msg_buffer , length
Data out: NULL
*/
void usb_msd_scsi_bulk_out(cyg_uint8 *ctrlep_msg_buffer , cyg_uint32 length)
{
cyg_uint32 reg_val;
DBG("usb_msd_scsi_bulk_out length = %d \n" , length);
memset(msd.buffer , 0 , 512);
bulk_length = length;
memcpy(msd.buffer , ctrlep_msg_buffer, bulk_length);
switch (BulkStage) {
case MSC_BS_CBW:
usb_msd_scsi_handle_cmd(&msd , ctrlep_msg_buffer);
break;
case MSC_BS_DATA_OUT:
switch (usb_scsi_command) {
case USBS_SCSI_WRITE_10:
case USBS_SCSI_WRITE_12:
usb_msd_scsi_MemoryWrite(&msd );
usb_scsi_setup_status(msd.rx_ep_num);
break;
case USBS_SCSI_VERIFY_10:
//usb_msd_scsi_MemoryVerify(&msd);
break;
}
break;
case MSC_BS_CSW:
break;
default:
HAL_READ_UINT32 (CYGHWR_HAL_STM32_USB + CYGHWR_HAL_STM32_USB_EPXR (msd.rx_ep_num), reg_val);
stm32_usb_set_rxep_status (msd.rx_ep_num , CYGHWR_HAL_STM32_USB_EPXR_STATRX_STALL
|CYGHWR_HAL_STM32_USB_EPXR_STATTX_STALL);
msd.csw.status = CSW_PHASE_ERROR;
usb_msd_csw_send();
break;
}
}
/*
Function: usb_msd_scsi_bulk_in:
Handle SCSI bulk in event
Data in : NULL
Data out: NULL
*/
void usb_msd_scsi_bulk_in()
{
DBG("usb_msd_scsi_bulk_in \n");
switch (BulkStage) {
case MSC_BS_DATA_IN:
switch (msd.cbw->cb.data[0]) {
case USBS_SCSI_READ_10:
usb_msd_scsi_MemoryRead(&msd );
break;
}
break;
case MSC_BS_DATA_IN_LAST:
usb_msd_csw_send();
break;
case MSC_BS_DATA_IN_LAST_STALL:
usb_msd_csw_send();
break;
case MSC_BS_CSW:
BulkStage = MSC_BS_CBW;
break;
}
}
终于写完了,肩膀都累了。第一次做usb协议,写的不好的见谅,有错希望给予指正。