📄 atacb.c
字号:
//-----------------------------------------------------------------------------
// File: atacb.c
// Contents: ATA CB functionality like ISD-300
//
// indent 3. NO TABS!
//
// Copyright (c) 2003 Cypress Semiconductor
//
// $Workfile: atacb.c $
// $Date: 6/02/05 2:34p $
// $Revision: 4 $
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "gpif.h"
#include "atapi.h"
#include "globals.h"
#if ATACB_ENABLE
//#define BmATACBActionSelect EP2FIFOBUF[CBW_DATA_START+2]
#define BmATACBRegisterSelect EP2FIFOBUF[CBW_DATA_START+3]
//#define bATACBTransferBlockCount EP2FIFOBUF[CBW_DATA_START+4]
#define ATACB_OUT_ATAPI_ALT_STATUS_REG EP2FIFOBUF[CBW_DATA_START+5]
#define ATACB_OUT_ATAPI_ERROR_REG EP2FIFOBUF[CBW_DATA_START+6]
#define ATACB_OUT_ATA_SECTOR_COUNT_REG EP2FIFOBUF[CBW_DATA_START+7]
#define ATACB_OUT_ATA_LBA_LSB_REG EP2FIFOBUF[CBW_DATA_START+8]
#define ATACB_OUT_ATA_LBA_2SB_REG EP2FIFOBUF[CBW_DATA_START+0x9]
#define ATACB_OUT_ATA_LBA_MSB_REG EP2FIFOBUF[CBW_DATA_START+0xa]
#define ATACB_OUT_ATA_DRIVESEL_REG EP2FIFOBUF[CBW_DATA_START+0xb]
#define ATACB_OUT_ATA_COMMAND_REG EP2FIFOBUF[CBW_DATA_START+0xc]
#define ATACB_IN_ATAPI_ALT_STATUS_REG EP6FIFOBUF[0]
#define ATACB_IN_ATAPI_ERROR_REG EP6FIFOBUF[1]
#define ATACB_IN_ATA_SECTOR_COUNT_REG EP6FIFOBUF[2]
#define ATACB_IN_ATA_LBA_LSB_REG EP6FIFOBUF[3]
#define ATACB_IN_ATA_LBA_2SB_REG EP6FIFOBUF[0x4]
#define ATACB_IN_ATA_LBA_MSB_REG EP6FIFOBUF[0x5]
#define ATACB_IN_ATA_DRIVESEL_REG EP6FIFOBUF[0x6]
#define ATACB_IN_ATA_COMMAND_REG EP6FIFOBUF[0x7]
BYTE BmATACBActionSelect;
//-----------------------------------------------------------------------------
// Structure of the command:
// 0-1 -- signature (0x2424)
// 2 -- BmATACBActionSelect
// 3 -- BmATACBRegisterSelect
// 4 -- bATACBTransferBlockCount
// 5-12-- bATACBTaskFileWriteData
//-----------------------------------------------------------------------------
BYTE processATACB()
{
BYTE bATACBTransferBlockCount = EP2FIFOBUF[CBW_DATA_START+4];
BmATACBActionSelect = EP2FIFOBUF[CBW_DATA_START+2];
// Are we reading the registers?
if (BmATACBActionSelect & 1)
{
BYTE i;
AUTOPTRL2 = LSB(EP6FIFOBUF);
// Clear out the EP buffer
for (i = 8; i; i--)
XAUTODAT2 = 0;
writeATA_DRIVESEL_REG();
if (!(BmATACBActionSelect & 4)) // Check for pollAltStatOverride bit
waitForBusyBit();
if (BmATACBRegisterSelect & 0x01)
ATACB_IN_ATAPI_ALT_STATUS_REG = readPIO8(ATAPI_ALT_STATUS_REG);
if (BmATACBRegisterSelect & 0x02)
ATACB_IN_ATAPI_ERROR_REG = readPIO8(ATAPI_ERROR_REG);
if (BmATACBRegisterSelect & 0x04)
ATACB_IN_ATA_SECTOR_COUNT_REG = readPIO8(ATA_SECTOR_COUNT_REG);
if (BmATACBRegisterSelect & 0x08)
ATACB_IN_ATA_LBA_LSB_REG = readPIO8(ATA_LBA_LSB_REG);
if (BmATACBRegisterSelect & 0x10)
ATACB_IN_ATA_LBA_2SB_REG = readPIO8(ATA_LBA_2SB_REG);
if (BmATACBRegisterSelect & 0x20)
ATACB_IN_ATA_LBA_MSB_REG = readPIO8(ATA_LBA_MSB_REG);
if (BmATACBRegisterSelect & 0x40)
ATACB_IN_ATA_DRIVESEL_REG = readPIO8(ATA_DRIVESEL_REG);
if (BmATACBRegisterSelect & 0x80)
ATACB_IN_ATA_COMMAND_REG = readPIO8(ATA_COMMAND_REG);
// Done with the OUT buffer.
EP2BCL = 0x80;
// Send the data to the host
loadEP6BC(8);
return (USBS_PASSED);
}
// Executing the command
else
{
if (!(BmATACBActionSelect & 0x02)) // DeviceSelectionOverride
writePIO8(ATA_DRIVESEL_REG, 0xe0 | ((BYTE)bMasterSlave << 4));
ATACBcheckStatus(); // The ATACBcheckStatus routine waits for BSY
if (BmATACBRegisterSelect & 0x01)
writePIO8(ATAPI_ALT_STATUS_REG, ATACB_OUT_ATAPI_ALT_STATUS_REG);
if (BmATACBRegisterSelect & 0x02)
writePIO8(ATAPI_ERROR_REG, ATACB_OUT_ATAPI_ERROR_REG);
if (BmATACBRegisterSelect & 0x04)
writePIO8(ATA_SECTOR_COUNT_REG, ATACB_OUT_ATA_SECTOR_COUNT_REG);
if (BmATACBRegisterSelect & 0x08)
writePIO8(ATA_LBA_LSB_REG, ATACB_OUT_ATA_LBA_LSB_REG);
if (BmATACBRegisterSelect & 0x10)
writePIO8(ATA_LBA_2SB_REG, ATACB_OUT_ATA_LBA_2SB_REG);
if (BmATACBRegisterSelect & 0x20)
writePIO8(ATA_LBA_MSB_REG, ATACB_OUT_ATA_LBA_MSB_REG);
if (BmATACBRegisterSelect & 0x40)
{
if (BmATACBActionSelect & 0x20) // DEVOverride
writePIO8(ATA_DRIVESEL_REG, ATACB_OUT_ATA_DRIVESEL_REG);
else
writePIO8(ATA_DRIVESEL_REG, 0xe0 | ((BYTE)bMasterSlave << 4));
}
if (BmATACBRegisterSelect & 0x80)
writePIO8(ATA_COMMAND_REG, ATACB_OUT_ATA_COMMAND_REG);
// Give up the command buffer -- Done with BmATACBRegisterSelect
EP2BCL = 0x80;
if (directionIn)
{
BYTE driveStatus = 0;
bit error = 0;
WORD wThisPacketSize;
while (dataTransferLen)
{
//////////////////////////////////////////////////////////
// Data Transfer phase
while (dataTransferLen)
{
if (BmATACBActionSelect & 0x40) // UDMACommand
{
// Break up the transfer into ATACBTransferBlockCount sized chunks.
// use wThisPacketSize as the sector counter
if (!bATACBTransferBlockCount)
wThisPacketSize = 0x100;
else
wThisPacketSize = bATACBTransferBlockCount;
wThisPacketSize = min(wThisPacketSize, dataTransferLen >> 9);
initUdmaRead();
prepUDMA(MSB(wThisPacketSize),LSB(wThisPacketSize),0);
readUDMA(); // Words = sectors * 256
// switch the EP back to manual mode
EP6Manual();
// Clear the interrupt by reading the status reg.
while ((driveStatus = readATAPI_STATUS_REG()) & ATAPI_STATUS_BUSY_BIT)
;
// If there's anything left in the count regs, we've got a problem.
// We will have to STALL in the IN endpoint to stop the host.
if (GPIFTCMSW || GPIFTCLSW)
{
if ((GPIFTCLSW & 0xff)) // Check for short packet already sent
bShortPacketSent = 1;
EP6Manual();
failedIn();
if (ATACBcheckStatus() == USBS_FAILED)
return(USBS_FAILED);
else
return (USBS_PASSED);
}
dataTransferLen -= wThisPacketSize * 0x200L;
}
else // PIO mode
{
ATACBcheckStatus(); // The ATACBcheckStatus routine waits for BSY
driveStatus = readATAPI_STATUS_REG();
if (!(driveStatus & ATAPI_STATUS_DRQ_BIT))
{
goto readDone;
}
// Check for drive ready
if (driveStatus & ATAPI_STATUS_ERROR_BIT) // The ATACBcheckStatus routine waits for BSY
{
goto readDone;
}
// Wait for available IN buffer
waitForInBuffer();
wThisPacketSize = min(wPacketSize, dataTransferLen);
readPIO16(wThisPacketSize);
while (!gpifIdle()) // wait for the read to complete before continuing
;
// Send the data to the host and decrement dataTransferLen
EP6BCH = MSB(wThisPacketSize);
WRITEDELAY();
EP6BCL = LSB(wThisPacketSize);
dataTransferLen -= wThisPacketSize;
}
if (!(BmATACBActionSelect & 4)) // Check for pollAltStatOverride bit
driveStatus = readATAPI_ALT_STATUS_REG();
}
}
readDone:
if (dataTransferLen)
failedIn();
// Check for drive ready
if (ATACBcheckStatus() == USBS_FAILED) // The ATACBcheckStatus routine waits for BSY
{
readPIO8(ATAPI_ERROR_REG);
return(USBS_FAILED);
}
// Check for phase error (H0 < Di, Hi < Di)
if (dataTransferLen)
if (readATAPI_ALT_STATUS_REG() & ATAPI_STATUS_DRQ_BIT)
return(USBS_PHASE_ERROR);
}
////////////////////////////////////////////////////////////////////////////////
else // OUT command
{
WORD wThisPacketSize;
while (dataTransferLen)
{
if (BmATACBActionSelect & 0x40) // UDMACommand
{
// Ignore ATACBTransferBlockCount. Just use the dataTransferLen.
// use wThisPacketSize as the sector counter
wThisPacketSize = dataTransferLen >> 9;
initUdmaWrite();
prepUDMA(MSB(wThisPacketSize),LSB(wThisPacketSize),0);
writeUDMA();
if ((GPIFTCMSW || GPIFTCLSW))
{
stallEP2OUT();
// cancel AUTO OUT mode.
EP2Manual();
if (ATACBcheckStatus() == USBS_FAILED) // The ATACBcheckStatus routine waits for BSY
return(USBS_FAILED);
else
return(USBS_PASSED);
}
dataTransferLen -= wThisPacketSize << 9;
}
else // Data transfer in PIO mode
{
WORD savebc;
if (ATACBcheckStatus() == USBS_FAILED) // The ATACBcheckStatus routine waits for BSY
{
stallEP2OUT();
return(USBS_FAILED);
}
// Wait for host to send data
while(EP2CS & bmEPEMPTY)
;
// Wait for the chip to request data.
if (ATACBcheckStatus() == USBS_FAILED) // The ATACBcheckStatus routine waits for BSY
{
readPIO8(ATAPI_ERROR_REG);
stallEP2OUT();
return(USBS_FAILED);
}
savebc = EP2BC;
EP2BCL = 0; // Release the endpoint buffer to FIFO
writePIO16(savebc);
dataTransferLen -= savebc;
// Short packet detection
if (savebc & (wPacketSize - 1))
{
if (ATACBcheckStatus() == USBS_FAILED) // The ATACBcheckStatus routine waits for BSY
{
return(USBS_FAILED);
}
return(USBS_PASSED);
}
}
} // While (dataTransferLen) loop
// cancel AUTO OUT mode.
EP2Manual();
// Check for phase error (H0 < Di, Hi < Di)
if (dataTransferLen)
if (readATAPI_ALT_STATUS_REG() & ATAPI_STATUS_DRQ_BIT)
return(USBS_PHASE_ERROR);
} // OUT command
}
if (ATACBcheckStatus() == USBS_FAILED) // The ATACBcheckStatus routine waits for BSY
return(USBS_FAILED);
return(USBS_PASSED);
}
bit ATACBcheckStatus()
{
if (!(BmATACBActionSelect & 4)) // Check for pollAltStatOverride bit
{
if (waitForBusyBit() == USBS_FAILED)
if (!(BmATACBActionSelect & 0x8)) // DPErrorOverride
return(USBS_FAILED);
}
else if (readATAPI_ALT_STATUS_REG() & ATAPI_STATUS_ERROR_BIT)
if (!(BmATACBActionSelect & 0x8)) // DPErrorOverride
return(USBS_FAILED);
return(USBS_PASSED);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -