📄 mscuser.c
字号:
/*----------------------------------------------------------------------------
* U S B - K e r n e l
*----------------------------------------------------------------------------
* Name: mscuser.c
* Purpose: Mass Storage Class Custom User Module
* Version: V1.20
*----------------------------------------------------------------------------
* This software is supplied "AS IS" without any warranties, express,
* implied or statutory, including but not limited to the implied
* warranties of fitness for purpose, satisfactory quality and
* noninfringement. Keil extends you a royalty-free right to reproduce
* and distribute executable files created using this software for use
* on NXP Semiconductors LPC family microcontroller devices only. Nothing
* else gives you the right to use this software.
*
* Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
*----------------------------------------------------------------------------
* History:
* V1.20 Added SCSI_READ12, SCSI_WRITE12
* V1.00 Initial Version
*----------------------------------------------------------------------------*/
#include "type.h"
#include "usb.h"
#include "msc.h"
#include "usbcfg.h"
#include "usbhw.h"
#include "usbcore.h"
#include "mscuser.h"
#include "memory.h"
uint8_t Memory[MSC_MemorySize]; /* MSC RAM */
uint32_t MemOK; /* Memory OK */
uint32_t Offset; /* R/W Offset */
uint32_t Length; /* R/W Length */
uint8_t BulkStage; /* Bulk Stage */
#if USB_DMA
#pragma arm section zidata = "USB_RAM" // data located in USB RAM (neccessry for DMA)
// see file DMA.sct
uint8_t BulkBuf[MSC_MAX_PACKET]; /* Bulk In/Out Buffer */
MSC_CBW CBW; /* Command Block Wrapper */
MSC_CSW CSW; /* Command Status Wrapper */
#pragma arm section zidata
#else
uint8_t BulkBuf[MSC_MAX_PACKET]; /* Bulk In/Out Buffer */
MSC_CBW CBW; /* Command Block Wrapper */
MSC_CSW CSW; /* Command Status Wrapper */
#endif
uint8_t BulkLen; /* Bulk In/Out Length */
/*
* Set Stall for MSC Endpoint
* Parameters: EPNum: Endpoint Number
* EPNum.0..3: Address
* EPNum.7: Dir
* Return Value: None
*/
void MSC_SetStallEP (uint32_t EPNum) { /* set EP halt status according stall status */
USB_SetStallEP(EPNum);
USB_EndPointHalt |= (EPNum & 0x80) ? ((1 << 16) << (EPNum & 0x0F)) : (1 << EPNum);
}
/*
* MSC Mass Storage Reset Request Callback
* Called automatically on Mass Storage Reset Request
* Parameters: None (global SetupPacket and EP0Buf)
* Return Value: TRUE - Success, FALSE - Error
*/
uint32_t MSC_Reset (void) {
USB_EndPointStall = 0x00000000; /* EP must stay stalled */
CSW.dSignature = 0; /* invalid signature */
BulkStage = MSC_BS_CBW;
return (TRUE);
}
/*
* MSC Get Max LUN Request Callback
* Called automatically on Get Max LUN Request
* Parameters: None (global SetupPacket and EP0Buf)
* Return Value: TRUE - Success, FALSE - Error
*/
uint32_t MSC_GetMaxLUN (void) {
EP0Buf[0] = 0; /* No LUN associated with this device */
return (TRUE);
}
/*
* MSC Memory Read Callback
* Called automatically on Memory Read Event
* Parameters: None (global variables)
* Return Value: None
*/
void MSC_MemoryRead (void) {
uint32_t n;
#if USB_DMA
uint32_t i;
#endif
if (Length > MSC_MAX_PACKET) {
n = MSC_MAX_PACKET;
} else {
n = Length;
}
if ((Offset + n) > MSC_MemorySize) {
n = MSC_MemorySize - Offset;
BulkStage = MSC_BS_DATA_IN_LAST_STALL;
}
#if USB_DMA
if (USB_DMA_IsUsed (MSC_EP_IN)) { // Check if EP is used for DMA
for (i = 0; i < n; i++) // copy data to USB DMA RAM
BulkBuf[i] = Memory[Offset+i]; // would be better if data is already in USB DMA RAM
USB_WriteEP(MSC_EP_IN, BulkBuf, n);
} else
USB_WriteEP(MSC_EP_IN, &Memory[Offset], n);
#else
USB_WriteEP(MSC_EP_IN, &Memory[Offset], n);
#endif
Offset += n;
Length -= n;
CSW.dDataResidue -= n;
if (Length == 0) {
BulkStage = MSC_BS_DATA_IN_LAST;
}
if (BulkStage != MSC_BS_DATA_IN) {
CSW.bStatus = CSW_CMD_PASSED;
}
}
/*
* MSC Memory Write Callback
* Called automatically on Memory Write Event
* Parameters: None (global variables)
* Return Value: None
*/
void MSC_MemoryWrite (void) {
uint32_t n;
if ((Offset + BulkLen) > MSC_MemorySize) {
BulkLen = MSC_MemorySize - Offset;
BulkStage = MSC_BS_CSW;
MSC_SetStallEP(MSC_EP_OUT);
}
for (n = 0; n < BulkLen; n++) {
Memory[Offset + n] = BulkBuf[n];
}
Offset += BulkLen;
Length -= BulkLen;
CSW.dDataResidue -= BulkLen;
if ((Length == 0) || (BulkStage == MSC_BS_CSW)) {
CSW.bStatus = CSW_CMD_PASSED;
MSC_SetCSW();
}
}
/*
* MSC Memory Verify Callback
* Called automatically on Memory Verify Event
* Parameters: None (global variables)
* Return Value: None
*/
void MSC_MemoryVerify (void) {
uint32_t n;
if ((Offset + BulkLen) > MSC_MemorySize) {
BulkLen = MSC_MemorySize - Offset;
BulkStage = MSC_BS_CSW;
MSC_SetStallEP(MSC_EP_OUT);
}
for (n = 0; n < BulkLen; n++) {
if (Memory[Offset + n] != BulkBuf[n]) {
MemOK = FALSE;
break;
}
}
Offset += BulkLen;
Length -= BulkLen;
CSW.dDataResidue -= BulkLen;
if ((Length == 0) || (BulkStage == MSC_BS_CSW)) {
CSW.bStatus = (MemOK) ? CSW_CMD_PASSED : CSW_CMD_FAILED;
MSC_SetCSW();
}
}
/*
* MSC SCSI Read/Write Setup Callback
* Parameters: None (global variables)
* Return Value: TRUE - Success, FALSE - Error
*/
uint32_t MSC_RWSetup (void) {
uint32_t n;
/* Logical Block Address of First Block */
n = (CBW.CB[2] << 24) |
(CBW.CB[3] << 16) |
(CBW.CB[4] << 8) |
(CBW.CB[5] << 0);
Offset = n * MSC_BlockSize;
/* Number of Blocks to transfer */
switch (CBW.CB[0]) {
case SCSI_READ10:
case SCSI_WRITE10:
case SCSI_VERIFY10:
n = (CBW.CB[7] << 8) |
(CBW.CB[8] << 0);
break;
case SCSI_READ12:
case SCSI_WRITE12:
n = (CBW.CB[6] << 24) |
(CBW.CB[7] << 16) |
(CBW.CB[8] << 8) |
(CBW.CB[9] << 0);
break;
}
Length = n * MSC_BlockSize;
if (CBW.dDataLength == 0) { /* host requests no data */
CSW.bStatus = CSW_CMD_FAILED;
MSC_SetCSW();
return (FALSE);
}
if (CBW.dDataLength != Length) {
if ((CBW.bmFlags & 0x80) != 0) { /* stall appropriate EP */
MSC_SetStallEP(MSC_EP_IN);
} else {
MSC_SetStallEP(MSC_EP_OUT);
}
CSW.bStatus = CSW_CMD_FAILED;
MSC_SetCSW();
return (FALSE);
}
return (TRUE);
}
/*
* Check Data IN Format
* Parameters: None (global variables)
* Return Value: TRUE - Success, FALSE - Error
*/
uint32_t DataInFormat (void) {
if (CBW.dDataLength == 0) {
CSW.bStatus = CSW_PHASE_ERROR;
MSC_SetCSW();
return (FALSE);
}
if ((CBW.bmFlags & 0x80) == 0) {
MSC_SetStallEP(MSC_EP_OUT);
CSW.bStatus = CSW_PHASE_ERROR;
MSC_SetCSW();
return (FALSE);
}
return (TRUE);
}
/*
* Perform Data IN Transfer
* Parameters: None (global variables)
* Return Value: TRUE - Success, FALSE - Error
*/
void DataInTransfer (void) {
if (BulkLen >= CBW.dDataLength) {
BulkLen = CBW.dDataLength;
BulkStage = MSC_BS_DATA_IN_LAST;
}
else {
BulkStage = MSC_BS_DATA_IN_LAST_STALL; /* short or zero packet */
}
USB_WriteEP(MSC_EP_IN, BulkBuf, BulkLen);
CSW.dDataResidue -= BulkLen;
CSW.bStatus = CSW_CMD_PASSED;
}
/*
* MSC SCSI Test Unit Ready Callback
* Parameters: None (global variables)
* Return Value: None
*/
void MSC_TestUnitReady (void) {
if (CBW.dDataLength != 0) {
if ((CBW.bmFlags & 0x80) != 0) {
MSC_SetStallEP(MSC_EP_IN);
} else {
MSC_SetStallEP(MSC_EP_OUT);
}
}
CSW.bStatus = CSW_CMD_PASSED;
MSC_SetCSW();
}
/*
* MSC SCSI Request Sense Callback
* Parameters: None (global variables)
* Return Value: None
*/
void MSC_RequestSense (void) {
if (!DataInFormat()) return;
BulkBuf[ 0] = 0x70; /* Response Code */
BulkBuf[ 1] = 0x00;
BulkBuf[ 2] = 0x02; /* Sense Key */
BulkBuf[ 3] = 0x00;
BulkBuf[ 4] = 0x00;
BulkBuf[ 5] = 0x00;
BulkBuf[ 6] = 0x00;
BulkBuf[ 7] = 0x0A; /* Additional Length */
BulkBuf[ 8] = 0x00;
BulkBuf[ 9] = 0x00;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -