📄 bulkcmd.c
字号:
/*
**********************************************************************************************
* Project: FS7805 SD CARD READER
* File: main.c
* Contents:
* The main function is SD and MMC card reader.
*
* $Date: 12/15/06 Derek V1.0
*
* Coments: This is the SD/MMC card reader firmware.
* When read sector,the 512 pingpong FIFO mechanism
* is used to improve performance.But when write sector,
* only single FIFO is used.
*
* Copyright (c) 2006 Fameg, Inc. All rights reserved
*
*
***********************************************************************************************
*/
#include "include\Include.h"
/*************************************************
Global Variables
*************************************************/
xdata PCMD_BLOCK_WRAPPER BlockWrapper;
BYTE CmdStatus = COMMAND_PASSED;
BYTE BulkState = CBW_GET_COMPLETED;
bool ScsiCmdSTALLed = false;
BYTE ScsiLun;
xdata UINT32 SectorStart = 0;
xdata UINT16 SectorCount = 0;
xdata UINT32 WrapperTag = 0;
xdata UINT32 UsbDmaTotalLength = 0;
bit FirstWrite = false;
extern bit BusResetFlag ;
/*************************************************
Local Variables
*************************************************/
static bit BulkCmdRunning = false;
/*************************************************
For pingpong FIFO control
*************************************************/
volatile BYTE SW_IN_FIFO_Toggle = 0;
volatile INT16U FIFO_ADDRESS_IN;
volatile BYTE SW_OUT_FIFO_Toggle = 0;
volatile INT16U FIFO_ADDRESS_OUT;
/*
*********************************************************************************************************
* BulkFreeBuffer()
*
* Description: Clear FIFO_FULL bit that get data,set FIFO_TOG and
* and SW_OUT_FIFO_Toggle value for next OUT transaction.
*
* Arguments : none
*
* Returns : none
*********************************************************************************************************
*/
void BulkFreeBuffer(void)
{
if(FIFO_ADDRESS_OUT == DMA_FIFOA0)//if data in DMA_FIFOA0
{
EPAFIFOCS = (EPAFIFOCS | bmFIFO_TOG_WE) | (bmFIFO_TOG);//set FIFO_TOG
EPAFIFOCS = (EPAFIFOCS | bmFIFO0_FULL_WE) & (~bmFIFO0_FULL);//clear FIFO0_FULL bit
SW_OUT_FIFO_Toggle = 1;//set SW_OUT_FIFO_Toggle value
}
else // FULL_1 = 1
{
EPAFIFOCS = (EPAFIFOCS | bmFIFO_TOG_WE) & (~bmFIFO_TOG);//
EPAFIFOCS = (EPAFIFOCS | bmFIFO1_FULL_WE) & (~bmFIFO1_FULL);
SW_OUT_FIFO_Toggle = 0;
}
BulkSetDmaOut();
}
//----------------------------------------------------------------------------
// Wait OUT Packet.
//----------------------------------------------------------------------------
void BulkWaitOutDataReady() //
{
while (1)
{
while ((EPINT & bmEPAINT) == 0);
// Clear OUT IRQ.
EPINT&=~bmEPAINT;
if (!BulkOutTogErr())
break;
}
}
//----------------------------------------------------------------------------
void BulkReportHandle()
{
if (BulkCmdRunning)
{
BulkPrepareCSW(CmdStatus);
}
}
#pragma OPTIMIZE(4)
/*
*********************************************************************************************************
* BulkSetDmaIn()
*
* Description: Send data to host.
*
* Arguments : DmaLen,IN packet length.
*
* Returns : none
*********************************************************************************************************
*/
void BulkSetDmaIn(UINT16 DmaLen)
{
if (FIFO_ADDRESS_IN == DMA_FIFOB0)//If DMA_FIFOB0 is selected.
{
EPBFIFOCS = (EPBFIFOCS | bmFIFO0_FULL_WE) | bmFIFO0_FULL;//2007.01.09
EPBCNT0L = DmaLen & 0xFF; // Write count low byte
EPBCNTH = (DmaLen >> 8) | bmCNT0HWEN; // Write count high byte
SW_IN_FIFO_Toggle = 1;
}
else
{
EPBFIFOCS = (EPBFIFOCS | bmFIFO1_FULL_WE) | bmFIFO1_FULL;//2007.01.09
EPBCNT1L = DmaLen & 0xFF; // Write count low byte
EPBCNTH = ((DmaLen >> 8) << 4) | bmCNT1HWEN; // Write count high byte
SW_IN_FIFO_Toggle = 0;
}
EPBCS = EPBCS | bmEP_RXTXEN; // Enable RXTX
}
//------------------------------------
//
//------------------------------------
void SelectInFifo(void)
{
if ((!(EPBFIFOCS & bmFIFO0_FULL)) && (!(EPBFIFOCS & bmFIFO1_FULL)))
{
if (SW_IN_FIFO_Toggle==0)//根据软件toggle位来判断从哪个FIFO 取数据。
{
FIFO_ADDRESS_IN= DMA_FIFOB0;
}
else
{
FIFO_ADDRESS_IN= DMA_FIFOB1;
}
}
else if (!(EPBFIFOCS & bmFIFO0_FULL))
{
FIFO_ADDRESS_IN= DMA_FIFOB0;
}
else if (!(EPBFIFOCS & bmFIFO1_FULL))
{
FIFO_ADDRESS_IN= DMA_FIFOB1;
}
}
//----------------------------------------------------------------------------
// Description: Select one of PINGPONG FIFOS for IN transaction.
//
//----------------------------------------------------------------------------
void SetBulkInFull (void)
{
while ((EPBFIFOCS & bmFIFO0_FULL) && (EPBFIFOCS & bmFIFO1_FULL));
SelectInFifo();//
}
//----------------------------------------------------------------------------
// Description: 专门处理读扇区,对bus reset做了特别处理.
//
//----------------------------------------------------------------------------
void SetBulkInFullForReadSector(void)
{
while ((EPBFIFOCS&bmFIFO0_FULL)&&(EPBFIFOCS & bmFIFO1_FULL)&&((STINT&bmUSBRSTINT)==0));
//等待至少一个FIFO_FULL为0,或者BUS RESET的发生~!2007.01.22
if(STINT&bmUSBRSTINT) {
BusResetDeal();
BusResetFlagCnt = 1;
return;
}
SelectInFifo();//
}
//----------------------------------------------------------------------------
// Description: Check which one of PINGPONG FIFOS the OUT packet is in.
//
//----------------------------------------------------------------------------
void SelectOutFifo(void)
{
if ((EPAFIFOCS & bmFIFO0_FULL) && (EPAFIFOCS & bmFIFO1_FULL))
{ // FULL_0 = 1 and FULL_1 = 1
if (SW_OUT_FIFO_Toggle == 0)//如果两个FULL位都是1,根据软件toggle位判断.
{
FIFO_ADDRESS_OUT = DMA_FIFOA0;
}
else
{
FIFO_ADDRESS_OUT = DMA_FIFOA1;
}
}
else if (EPAFIFOCS & bmFIFO0_FULL) // FULL_0 = 1
{
FIFO_ADDRESS_OUT = DMA_FIFOA0;
}
else if (EPAFIFOCS & bmFIFO1_FULL) // FULL_1 = 1
{
FIFO_ADDRESS_OUT = DMA_FIFOA1;
}
}
#pragma OPTIMIZE(4)
//----------------------------------------------------------------------------
// Prepare CSW
//----------------------------------------------------------------------------
void BulkPrepareCSW(BYTE Status)
{
PCMD_STATUS_WRAPPER StatusWrapper;
BulkCmdRunning = false;
SetBulkInFull();
StatusWrapper = (CMD_STATUS_WRAPPER xdata *)(FIFO_ADDRESS_IN);
// 1. Set CSW.
StatusWrapper->Sign = CSW_SIGNATURE;
StatusWrapper->Tag = WrapperTag;
StatusWrapper->DataResidueLen = 0;
StatusWrapper->Status = Status;
// 2. Set DMA related parameters and enable.
BulkSetDmaIn(CSW_LENGTH);
// 3. Wait for replying CSW.
BulkState = CSW_REPLY_COMPLETED;
}
//----------------------------------------------------------------------------
void InitBulkPipe()
{
BulkState = CBW_GET_COMPLETED;
CmdStatus = COMMAND_PASSED;
// Init Scsi Used Params.
ScsiInit();
}
//----------------------------------------------------------------------------
void UsbBulkIntHandler(BYTE IntEvent)
{
STATUS Status;
bool GoodCBW = true;
UINT16 CmdLen;
if(IntEvent & bmEPAINT)
{
if(BusResetFlag)//如果有bus reset发生
{
//BulkState = CBW_GET_COMPLETED;
//CmdStatus = COMMAND_PASSED;
Status = SdStopCmd();
SdCtrlReset();
BusResetFlag = false;
}
}
switch (BulkState)
{
case CBW_GET_COMPLETED:
case CSW_REPLY_COMPLETED:
BulkState = CBW_GET_COMPLETED;
if((IntEvent & bmEPAINT)==0) //
{
break;
}
SelectOutFifo();//Derek 12.26
if(FIFO_ADDRESS_OUT == DMA_FIFOA0)
{ //Derek 12.26
((TDataCast *)&CmdLen)->ucByte[0] = EPACNTH & 0x07;
((TDataCast *)&CmdLen)->ucByte[1] = EPACNT0L;
} else {
((TDataCast *)&CmdLen)->ucByte[0] = (EPACNTH & 0x70) >> 4;
((TDataCast *)&CmdLen)->ucByte[1] = EPACNT1L;
}
if(BulkOutTogErr()) //是否发生DATA toggle错误
{
BulkFreeBuffer();
break;
}
if((CmdLen != CBW_LENGTH) && //CBW必须是31或32字节
(CmdLen != CBW_LENGTH_98))
{
BulkFreeBuffer();
break;
}
BulkCmdRunning = true;
ScsiCheckCmd();
break;
case BULK_DMA_IN_COMPLETED:
if((IntEvent & bmEPBINT) == 0)
break;
if(SectorCount == 0)
{
BulkPrepareCSW(CmdStatus);
}
else
{
Status = ReadNextSector();
if(Status != STATUS_SUCCESS)
{
CmdStatus = COMMAND_FAILED;
SetSenseDataRd(Status);
BulkInStall();
BulkState = STALL_IN_COMPLETED;
}
}
break;
case BULK_DMA_OUT_COMPLETED:
if((IntEvent & bmEPAINT) == 0)
break;
Status = STATUS_SUCCESS;
if(BulkOutTogErr())
{
SelectOutFifo();//SelectOutfifo()和BulkFreeBuffer配对使用!切记!
BulkFreeBuffer();
break;
}
if(ScsiDetectWriteProtect(ScsiLun))
{
Status = STATUS_WRITE_PROTECT;
CmdStatus = COMMAND_FAILED;
SelectOutFifo();//SelectOutfifo()和BulkFreeBuffer配对使用!切记!
BulkFreeBuffer();
}
else
{
if(FirstWrite)
{
Status = WriteSector();
FirstWrite = false;
}
else
Status = WriteNextSector();
}
if(Status != STATUS_SUCCESS)
{
CmdStatus = COMMAND_FAILED;
SetSenseDataWr(Status);
BulkInStall();
BulkState = STALL_IN_COMPLETED;
break;
}
if(SectorCount == 0)
BulkPrepareCSW(CmdStatus);
break;
case STALL_IN_COMPLETED: //读写过程有错后,进入此状态
if (IntEvent & bmEPAINT) // Keep receving out packets.
{ SelectOutFifo(); //SelectOutfifo()和BulkFreeBuffer配对使用!切记!
BulkFreeBuffer(); //Derek 2007.01.11
}
if(EPBCS & bmTX0_SESTALL) //如果IN EP的STALL位被置1
{
if(CmdStatus == PHASE_ERROR)
CmdStatus = COMMAND_PASSED;
BulkState = CBW_GET_COMPLETED;
ScsiCmdSTALLed = true; //STALL标志变量置1
// Set RXTXEN to receive next OUT packet.
if(!(EPACS & bmEP_RXTXEN))
BulkSetDmaOut(); //允许OUT 端点再次接收数据,为下次传输做准备
}
break;
default:
BulkInStall();
BulkState = STALL_IN_COMPLETED;
break;
}
}
//-----------------------
//用作BUS RESET后的处理
//-----------------------
void BusResetDeal(void)//2007.01.22
{
STINT = STINT & (~bmUSBRSTINT);
while (!(USBGCTRL & bmHS_DETECTED)); // detect USB speed
HighSpeed = USBGCTRL & bmSPEED; // High speed
//无论低速高速,reset后都要将FIFO_TOGGLE位清零。
if (HighSpeed)
{
EPAFIFOCS = 0xF0; //06.08.28
EPBFIFOCS = 0xF0; //06.08.28
}else
{ //如果是低速主机接口-06.08.28//Derek
EPAFIFOCS = 0xF2; //06.08.28
EPBFIFOCS = 0xF2; //06.08.28
}
SW_RST |= bmUSB_RST; //USB software reset Derek 10.23
UsbInit(); //重新配置端点属性
BusResetFlag = true; //Derek 09.06
SW_IN_FIFO_Toggle = 0; //12.29 software toggle bit reset
SW_OUT_FIFO_Toggle = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -