⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsicmd.c

📁 SdCard_V2.1TinyFatFs.rar是单片机实现SD卡功能的FAT文件系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
**********************************************************************************************
* 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 BYTE SenseKey;
xdata BYTE AddSenseCode;
xdata BYTE AddSenseCodeQ;
xdata bool ScsiMediaChange[MAX_DEVICE_NUM];
/*************************************************
   Local Variables
*************************************************/
static xdata BYTE ScsiWriteProtect[MAX_DEVICE_NUM];
static xdata bool ScsiWriteProtectChange[MAX_DEVICE_NUM];
//static xdata UINT32 CapacityInfo[2];
static xdata BYTE ScsiLoadStatus[MAX_DEVICE_NUM];

/*BYTE RequestSenseData[REQUEST_SENSE_DATA_LEN] = 
{ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00
};*/  

code BYTE ModeParamHeader6[MODE_PARAM_HEADER_LEN] = 
{ 0x00, 0x00, 0x00, 0x00 };

// Mode Page #1     Read-Write Error Recovery
code BYTE ModePage_1[] = 
{ 0x01, 0x0A, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 
  0x03, 0x00, 0x00, 0x00
};
// Mode Page #5   
/*code BYTE ModePage_5[] = 
{ 0x05, 0x1e, 0x13, 0x88, 0x08, 0x20, 0x02, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68,
  0x00, 0x00, };
// Mode Page #1B
code BYTE ModePage_1B[] = 
{ 0x1B, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// Mode Page #1C   
code BYTE ModePage_1C[] = 
{ 0x1C, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00 };
*/
xdata MODE_PAGE_TABLE ModePageArray[] = 
{
  { ModePage_1, sizeof(ModePage_1) },
// Reduce XDATA Size so don't return more mode pages.  
//  { ModePage_5, sizeof(ModePage_5) },
//  { ModePage_1B, sizeof(ModePage_1B) },
//  { ModePage_1C, sizeof(ModePage_1C) },
  { NULL, 0 }
};  

//----------------------------------------------------------------------------
// Detect the write protect on the storage media.(Shared)
//----------------------------------------------------------------------------
bool ScsiDetectWriteProtect(BYTE Lun)
{
  if (ScsiWriteProtect[Lun])
  {
    SenseKey      = DATA_PROTECT;
    AddSenseCode  = HW_WRITE_PROTECT;
    return true;
  }
  return false;
}

//----------------------------------------------------------------------------
// Set Command Error.(INVALID_FIELD_IN_CDB)
//----------------------------------------------------------------------------
void ScsiInvalidFieldError(BYTE Lun) // To be replaced
{
	Lun=Lun;
    CmdStatus     = PHASE_ERROR;  
    SenseKey      = ILLEGAL_REQUEST;
    AddSenseCode  = INVALID_FIELD_IN_CDB;   
    AddSenseCodeQ = 0x00;  	
}

void SetSenseErrOpCode()
{
    CmdStatus     = PHASE_ERROR;  
    SenseKey      = 0x05; // INVALID COMMAND OPERATION CODE
    AddSenseCode  = 0x20;
    AddSenseCodeQ = 0x00;
}

void SetSenseErrCmdField()
{
    CmdStatus     = PHASE_ERROR;  
    SenseKey      = 0x05; // INVALID FIELD IN COMMAND PACKET
    AddSenseCode  = 0x24;
    AddSenseCodeQ = 0x00;
}

/*void SetSenseErrCmdPara()
{
    CmdStatus     = PHASE_ERROR;  
    SenseKey      = 0x05; // PARAMETER VALUE INVALID
    AddSenseCode  = 0x26;
    AddSenseCodeQ = 0x02;
}*/

void ScsiModifySenseWord(BYTE Lun, BYTE Status)
{
	Lun=Lun;
    switch (Status)
    {
        case STATUS_SUCCESS:      // NO SENSE
            SenseKey      = 0x00;
            AddSenseCode  = 0x00;    
            AddSenseCodeQ = 0x00;  	
            break; 	
         
        case STATUS_NO_MEDIA:     // MEDIUM NOT PRESENT
            SenseKey      = 0x02;
            AddSenseCode  = 0x3A;   
            AddSenseCodeQ = 0x00;  	
            break; 	     
         
        case STATUS_MEDIA_CHANGE: // NOT READY TO READY TRANSITION 
            SenseKey      = 0x06; // - MEDIA CHANGED
            AddSenseCode  = 0x28;   
            AddSenseCodeQ = 0x00;  	
            break; 	
   
        default:                  // UNKNOWN ERROR
            SenseKey      = 0x02;
            AddSenseCode  = 0xFF;
            AddSenseCodeQ = 0xFF;
            break;           
    }	
}  

void SetSenseDataWr(BYTE Status)
{
    switch (Status)
    {
        case STATUS_SUCCESS:      // NO SENSE
            SenseKey      = 0x00;
            AddSenseCode  = 0x00;
            AddSenseCodeQ = 0x00;
            break;

        case STATUS_NO_MEDIA:     // MEDIUM NOT PRESENT
            SenseKey      = 0x02;
            AddSenseCode  = 0x3A;
            AddSenseCodeQ = 0x00;
            break;

        case STATUS_MEDIA_CHANGE: // NOT READY TO READY TRANSITION 
            SenseKey      = 0x06; // - MEDIA CHANGED
            AddSenseCode  = 0x28;   
            AddSenseCodeQ = 0x00;
            break;

        case STATUS_WRITE_PROTECT:// WRITE PROTECTED MEDIA
            SenseKey      = 0x07; 
            AddSenseCode  = 0x27;   
            AddSenseCodeQ = 0x00;
            break;
        
        case STATUS_FLASH_ERROR:  // WRITE FAULT
        case STATUS_NO_BLOCK:     // WRITE FAULT
            SenseKey      = 0x03; //
            AddSenseCode  = 0x03;
            AddSenseCodeQ = 0x00;
            break;

        default:                  // UNKNOWN ERROR
            SenseKey      = 0x02;
            AddSenseCode  = 0xFF;
            AddSenseCodeQ = 0xFF;
         break;
    }
}

void SetSenseDataRd(BYTE Status)
{
    switch (Status)
    {
        case STATUS_SUCCESS:      // NO SENSE
            SenseKey      = 0x00;
            AddSenseCode  = 0x00;
            AddSenseCodeQ = 0x00;
            break;
        
        case STATUS_NO_MEDIA:     // MEDIUM NOT PRESENT
            SenseKey      = 0x02;
            AddSenseCode  = 0x3A;
            AddSenseCodeQ = 0x00;
            break;

        case STATUS_MEDIA_CHANGE: // NOT READY TO READY TRANSITION 
            SenseKey      = 0x06; // - MEDIUM CHANGED
            AddSenseCode  = 0x28;   
            AddSenseCodeQ = 0x00;
            break;

        case STATUS_FLASH_ERROR:  // UNRECOVERED READ ERROR
        case STATUS_ECC_2ERROR:   // UNRECOVERED READ ERROR
            SenseKey      = 0x03;
            AddSenseCode  = 0x11;
            AddSenseCodeQ = 0x00;
            break;

        default:                  // UNKNOWN ERROR
            SenseKey      = 0x02;
            AddSenseCode  = 0xFF;
            AddSenseCodeQ = 0xFF;
         break;
    }
}

//----------------------------------------------------------------------------
// Get the LUN capcity
//  Description: Write those capacity informations to the global variable
//               CapacityInfo[]. 
//----------------------------------------------------------------------------
void ScsiGetLunCapacity()
{
  BYTE Status;

  Status = QueryDevice();
    *(UINT32 xdata *)(FIFO_ADDRESS_IN + 0)   = DeviceInfo.TotalBlocks;
    *(UINT32 xdata *)(FIFO_ADDRESS_IN + 4)   = (UINT32)DeviceInfo.BlockSize;

}

//----------------------------------------------------------------------------
// Check Vaild Logic Unit Number
//  Description: If not valid, change Sense Parameters.
//----------------------------------------------------------------------------
void ScsiLunValidCheck()
{
    BYTE Status;

    if(ScsiLun > LastDevice)
    {
        CmdStatus = PHASE_ERROR;
        return;
    }

    Status = QueryDevice();
 
    if(ScsiWriteProtect[ScsiLun] != DeviceInfo.WriteProtect)
    {
        ScsiWriteProtectChange[ScsiLun] = true;
        ScsiWriteProtect[ScsiLun] = DeviceInfo.WriteProtect;
    }
    
    if((Status == STATUS_SUCCESS) || 
       (Status == STATUS_MEDIA_CHANGE))
    {
        if((ScsiLoadStatus[ScsiLun] & SCSI_LAST_QUERY_MASK) == 0)
            ScsiLoadStatus[ScsiLun] |= SCSI_LOAD_STATUS_MASK;

        ScsiLoadStatus[ScsiLun] |= SCSI_LAST_QUERY_MASK;
    }
    else
        ScsiLoadStatus[ScsiLun] &= ~SCSI_LAST_QUERY_MASK;

    if(Status == STATUS_SUCCESS)
        return;

    ScsiModifySenseWord(ScsiLun, Status);
    CmdStatus = COMMAND_FAILED;
} 

//----------------------------------------------------------------------------
// Make Mode Page Data Ready
//----------------------------------------------------------------------------
void ScsiPrepareModePage(BYTE PageCode, UINT16 XferLength)
{
  UINT16 TotalPageLen = 0;
  BYTE i = 0;
  PBYTE Page;
  BYTE PageLen;
  
  while((Page = ModePageArray[i].PagePtr) != NULL)
  {
    PageLen = 0;
    if ( (PageCode == 0x3f) || (PageCode == Page[0]) )
    {
      PageLen = ModePageArray[i].Size;
            memcpy((BYTE xdata *)(FIFO_ADDRESS_IN + MODE_PARAM_HEADER_LEN \
              + TotalPageLen), (void *)Page, PageLen);  
    }
    TotalPageLen += PageLen;   
    i++;
  }
  TotalPageLen += MODE_PARAM_HEADER_LEN; 
    memcpy((BYTE xdata *)(FIFO_ADDRESS_IN), (void *)ModeParamHeader6, \
            MODE_PARAM_HEADER_LEN);
  // Length field.(1 Byte)  
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 0) = (BYTE)(TotalPageLen - 1);
// (Device-Specific-Parameter)It is write protect reference for WinXP & Win2K.
  QueryDevice();

    *(BYTE xdata *)(FIFO_ADDRESS_IN + 2) = DeviceInfo.WriteProtect ? 0x80: 0x00;
  if (XferLength > TotalPageLen)
    XferLength = TotalPageLen;
  
  UsbDmaTotalLength = XferLength;    
}

//--------------------------------------------------------------------
// Prepare Disk Info. 
//--------------------------------------------------------------------
void ScsiPrepareDiskInfo()
{
    memset((BYTE xdata *)(FIFO_ADDRESS_IN), 0, SCSI_INFO_START_OFFSET);

    *(BYTE xdata *)(FIFO_ADDRESS_IN + 1)     = 0x80;
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 3)     = 0x01;
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 4)     = 0x1F;

    // Vendor Information
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 8)     = 'F';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 9)     = 'a';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 10)    = 'm';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 11)    = 'e';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 12)    = 'G';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 13)    = ' ';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 14)    = ' ';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 15)    = ' ';

    // Product Identification
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 16)    = 'U';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 17)    = 'S';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 18)    = 'B';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 19)    = ' ';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 20)    = '2';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 21)    = '.';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 22)    = '0';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 23)    = ' ';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 24)    = 'D';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 25)    = 'i';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 26)    = 's';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 27)    = 'k';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 28)    = ' ';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 29)    = ' ';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 30)    = ' ';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 31)    = ' ';

    // Revision Field.
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 32)    = '1';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 33)    = '.';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 34)    = '0';
    *(BYTE xdata *)(FIFO_ADDRESS_IN + 35)    = '0';
}	
  
/***************************************************************************
  Notes of SCSI Command
  1. Ignore Checking Valid CbwcbLen 
***************************************************************************/

//----------------------------------------------------------------------------
// ScsiCmdTestUnitReady
//----------------------------------------------------------------------------	
void ScsiCmdTestUnitReady()
{
  if (ConvertEndian32(BlockWrapper->DataXsferLen) != 0) 
    ScsiInvalidFieldError(ScsiLun); 

  if (ScsiMediaChange[ScsiLun])
  {
    ScsiMediaChange[ScsiLun] = false;
    ScsiModifySenseWord(ScsiLun, STATUS_MEDIA_CHANGE);
    CmdStatus = COMMAND_FAILED;
  }
  else if (ScsiWriteProtectChange[ScsiLun])
  {
    ScsiWriteProtectChange[ScsiLun] = false;
    ScsiModifySenseWord(ScsiLun, STATUS_MEDIA_CHANGE);
    CmdStatus = COMMAND_FAILED;
  }
  else if(!(ScsiLoadStatus[ScsiLun] & SCSI_LOAD_STATUS_MASK)) 
  {
    ScsiModifySenseWord(ScsiLun, STATUS_NO_MEDIA);	
    CmdStatus = COMMAND_FAILED;  	
  }	

  BulkFreeBuffer();  //.
  
  if (CmdStatus == PHASE_ERROR)
  {
    BulkInStall();
    BulkState = STALL_IN_COMPLETED;   
  }  
  else
    BulkPrepareCSW(CmdStatus);
}  

//----------------------------------------------------------------------------
// ScsiCmdInquiry
//----------------------------------------------------------------------------	
void ScsiCmdInquiry()
{
  BYTE i;

  // Scsi command start.
  for(i = 0; i < MAX_DEVICE_NUM; i++) 
    ScsiLoadStatus[i] = 0;
  if (UsbDmaTotalLength > STANDARD_INQUIRY_DATA_LEN)
    UsbDmaTotalLength = STANDARD_INQUIRY_DATA_LEN;
  // Don't care LUN's value, we return the same Inquiry Data.
  CmdStatus = COMMAND_PASSED;  //
  if (!(0x80 & BlockWrapper->Flags))
    ScsiInvalidFieldError(ScsiLun); 
  BulkFreeBuffer();  //
  // Prepare Data.
  
  if (CmdStatus != PHASE_ERROR)
  { 
	SetBulkInFull();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -