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

📄 cfcard.c

📁 这项工程将让您把自己的MP3播放器平台
💻 C
字号:
//++
//cfcard.c - MP3 Player Compact Flash Card functions
//
// Copyright (C) 2005 by Spare Time Gizmos.  All rights reserved.
//
// This file is part of the Spare Time Gizmos' MP3 Player firmware.
//
// This firmware is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA  02111-1307  USA.
//
//DESCRIPTION:
//   This module contains basic interface functions for the Compact Flash
// memory card.  The function set provided is admittedly a little lopsided,
// but remember that an MP3 player only needs to read CF cards;  it never
// writes to them!  
//
//REVISION HISTORY:
// dd-mmm-yy    who     description
// 20-May-05	RLA	New file.
// 12-Oct-05	RLA	Make card data static globals for SDCC
//			Truncate trailing spaces from g_szCardName
// 19-Oct-05	RLA	Add STACKSLOCS hack to IdentifyCard() for SDCC.
//			The code in ReadIDE for setting the drive address registers
//			 has dependencies on the byte ordering, which differs between
//			 C51 and SDCC.  Rewrite it to be more portable...
//--

// Include files...
#include <stdio.h>		// needed so DBGOUT(()) can find printf!
#include <string.h>		// strcpy(), etc...
#include "standard.h"		// standard types - BYTE, WORD, BOOL, etc
#include "reg66x.h"		// declarations for Philips 89C66x processors
#include "player.h"		// project wide (hardware configuration) declarations
#include "debug.h"		// debugging stuff and ResetWDT()
#include "post.h"		// POST codes for Fail()
#include "timer.h"		// define the DelayMS() routine
#include "buffer.h"		// disk buffer free pool
#include "cfcard.h"		// declarations for this module


//   In the original C51 version, these items were automatic variables in another
// module (player.c) and passed as parameters to IdentifyCard()  SDCC, however, isn't
// all that swift at dealing with parameters and local variables, so they were
// converted to globals in the interest of simplicity...  Note that none of these
// quantities are used very often, so there's no sense in wasting DATA/IDATA space
// on them!
PUBLIC XDATA char g_szCardName[CARD_NAME_LENGTH];// Card name and manufacturer
PUBLIC XDATA LONG g_lCardSectors;		 // Card size (in sectors)
PUBLIC XDATA WORD g_wCardSize;			 //   "   "   (in megabytes)
PUBLIC XDATA WORD g_wCardAttributes;		 // CompactFlash card atributes


//++
//   Return TRUE if a CompactFlash card is installed in the socket...  CF cards
// provide not one but two pins (CARD DETECT 1 and 2) that are connected to
// ground internally to the card.  When no card is present this pin is pulled
// high, and goes low when the card is inserted.
//--
PUBLIC BOOL IsCardInserted (void)
{
  // Note that the CARD_DETECT input is active LOW!!!
  if (CARD_DETECT) return FALSE;
  DelayMS(40);
  if (CARD_DETECT) return FALSE;
  //DBGOUT(("Card inserted...\n"));
  return TRUE;
}


//++
//   This routine is used to wait for the drive (oops, Compact Flash card) to
// complete an operation.  We can tell that the card's done when the READY flag
// is set and the BUSY flag is cleared in the drive status register, and that's
// the combination we wait for.  If this routine sees the error (ERR) bit set in
// the status register, it will stop waiting and return immediately regardless
// of the READY/BUSY flags.  Regardless of the reason for exiting, the function
// always returns the 8 bit contents of the drive status register.
//
//   To ensure that we don't wait forever on a broken drive, this routine also
// implements a simple time out.  If the time out expires before the drive
// finishes, then this routine will return with a value of zero.  Since we
// normally return the contents of the status register, and since we usually
// only return when either ERR or READY is set, the return value can never
// be zero except in case of a timeout.
//--
PRIVATE BYTE WaitReady (void)
{
  BYTE bStatus;  WORD wTimeout = 0;
  while (TRUE) {
    bStatus = ReadIDE(IDE_REG_STATUS);
    if ((bStatus & IDE_STATUS_ERR) != 0) return bStatus;
    if ((bStatus & (IDE_STATUS_BSY|IDE_STATUS_DRDY)) == IDE_STATUS_DRDY) return bStatus;
    if (++wTimeout == 0) return 0;
  }
}


//++
// ReadSector
//   This routine reads one physical sector (always 512 bytes for practical
// purposes) from the Compact Flash and stores it in the buffer specified.
// We always use LBA addressing, so the sector is indicated by a single 28
// bit logical block address.  This routine returns TRUE if it reads the
// sector successfully, and FALSE if any drive error occurs.
//--
PUBLIC BOOL ReadSector (LONG lLBN, PXBYTE pxBuffer)
{
  WORD wCount;  BYTE bStatus;
  // The drive should be idle now, but let's make sure just in case...
  if ((WaitReady() & IDE_STATUS_ERR) != 0)  return FALSE;

  //   Set up the transfer count (always 1 sector), the LBA, and then load the
  // READ SECTOR command.  Note that the LBA is actually 28 bits and we need to
  // break it down into individual 8 bit bytes.  The rather round about method
  // used (with the wAddr temporary and pointer and such) generates the best
  // machine code.
  WriteIDE(IDE_REG_COUNT, 1);
  WriteIDE(IDE_REG_SECTOR,     (BYTE) ( lLBN      & 0xFF));
  WriteIDE(IDE_REG_CYLINDER_L, (BYTE) ((lLBN>> 8) & 0xFF));
  WriteIDE(IDE_REG_CYLINDER_H, (BYTE) ((lLBN>>16) & 0xFF));
  WriteIDE(IDE_REG_SELECT,   ( (BYTE) ((lLBN>>24) & 0xFF) ) | 0xA0 | IDE_LBA_MODE);
  //DBGOUT(("CF: Read Sector Count=0x%02bx, Sector=0x%02bx %02bx %02bx %02bx\n",
  //  ReadIDE(IDE_REG_COUNT), ReadIDE(IDE_REG_SELECT), ReadIDE(IDE_REG_CYLINDER_H),
  //  ReadIDE(IDE_REG_CYLINDER_L), ReadIDE(IDE_REG_SECTOR)));
  WriteIDE(IDE_REG_COMMAND, IDE_CMD_READ_SECTOR);

  //   Now wait for the drive to finish.  If WaitReady() returns with the error bit
  // set, then something has gone wrong and it's time to bail out.  Otherwise we
  // should see the DRQ bit set on return, indicating that the drive wants to transfer
  // data.  We call the ReadIDEBuffer() routine to transfer all 512 bytes in short
  // order, and then we're done!
  bStatus = WaitReady();
  //DBGOUT(("IDE read sector, LBN=%ld, status=0x%02X\n", lLBN, bStatus));
  if ((bStatus & IDE_STATUS_ERR) != 0) return FALSE;
  ASSERT(((bStatus & IDE_STATUS_DRQ) != 0), ("?Read Sector didn't set DRQ"));
  wCount = ReadIDEBuffer(pxBuffer, IDE_SECTOR_SIZE);
  ASSERT( (wCount == IDE_SECTOR_SIZE), ("??Read Sector returned %d bytes\n", wCount));
  if (wCount != IDE_SECTOR_SIZE) return FALSE;
  return TRUE;
}

//++
//   This routine sends an ATA IDENTIFY DEVICE command to the Compact Flash
// card.  The drive will return 512 bytes of data (most of which are useless!)
// which we read into the temporary disk buffer.  We extract three useful pieces
// of information from the IDENTIFY DEVICE data, the drive attributes (this
// identifies the type of the CF Card and should be 0x848A for Compact Flash
// memory); the drive capacity (in 512 byte sectors, which we then convert to
// megabytes), and the manufacturer name and model number (an ASCIZ string).
//--
PUBLIC BOOL IdentifyCard (void) STACKSLOCS
{
  BYTE i, bStatus;  WORD wCount;  PIBCB pBCB;

  //   Allocate a temporary buffer for disk I/O.  Once this is done (successfully)
  // we don't dare return without releasing the buffer first!
  memset(g_szCardName, 0, CARD_NAME_LENGTH);  g_wCardSize = 0;
  ALLOCATE_BUFFER(pBCB);
  if (pBCB == NULL) return FALSE;

  //   Send the IDENTIFY DEVICE command (which requires no parameters) and
  // then wait for the drive to finish.  Transfer the drive's data buffer
  // (which should always hold 512 bytes) to our temporary disk buffer for
  // further parsing...
  WriteIDE(IDE_REG_COMMAND, IDE_CMD_IDENTIFY_DEVICE);
  bStatus = WaitReady();
  //DBGOUT(("IDE identify device, status=0x%02bX\n", bStatus));
  if ((bStatus & IDE_STATUS_ERR) != 0) goto Fail;
  ASSERT(((bStatus & IDE_STATUS_DRQ) != 0), ("??Identify Device didn't set DRQ"));
  wCount = ReadIDEBuffer(pBCB->pbBuffer, IDE_SECTOR_SIZE);
  ASSERT( (wCount == IDE_SECTOR_SIZE), ("??Identify Device returned %d bytes\n", wCount));
  if (wCount != IDE_SECTOR_SIZE) goto Fail;

  //   The 80x86 (aka the PC) and the 8051 are both little endian processors
  // (This should suprise no one, since they were both invented by Intel!), so
  // the ReadIDESector routine transfers bytes from the drive to 8051 memory
  // WITHOUT changing the order.  This all fine, however for whatever reason, 
  // the ATA IDENTIFY DEVICE command returns all binary values in big endian
  // format.  This includes character strings, which will have the members of
  // each pair of characters swapped.  Unfortunately, there's nothing that can
  // be done about this except to swap the bytes around, the hard way, right here!
  strncpy(g_szCardName, (char *) &(pBCB->pbBuffer[2*27]), CARD_NAME_LENGTH-1);
  g_szCardName[CARD_NAME_LENGTH-1] = 0;
  for (i = 0;  i < CARD_NAME_LENGTH;  i += 2)
    {BYTE t = g_szCardName[i];  g_szCardName[i] = g_szCardName[i+1];  g_szCardName[i+1] = t;}
  for (i=CARD_NAME_LENGTH-2; (i>0) && (g_szCardName[i]==' '); --i) g_szCardName[i] = 0;
  g_wCardAttributes = MKWORD(pBCB->pbBuffer[1], pBCB->pbBuffer[0]);
  g_lCardSectors = MKLONG(
    MKWORD(pBCB->pbBuffer[2*61+1], pBCB->pbBuffer[2*61]),
    MKWORD(pBCB->pbBuffer[2*60+1], pBCB->pbBuffer[2*60]));
  g_wCardSize = (WORD) (g_lCardSectors>>11);
  DBGOUT(("Detected card \"%s\" type 0x%04X, sectors %ld, %uMb ...\n", g_szCardName, g_wCardAttributes, g_lCardSectors, g_wCardSize));

  //   We're done with the buffer now, so we can return it to the free pool.
  // At this point we're successful as long as the card attributes match those
  // for a Compact Flash memory card - this test is just in case some fool tries
  // to stick a non-memory (e.g. WiFi, modem, etc) card in the socket!
  RELEASE_BUFFER(pBCB);
  return (g_wCardAttributes == FLASH_MEMORY_CARD);

  // Here if we fail for any reason - free the buffer and return FALSE...
Fail:
  RELEASE_BUFFER(pBCB);
  return FALSE;
}



//++
//--
PUBLIC BOOL InitializeCard (void)
{
  BYTE bStatus;
  // Initialize CS1FX and CS3FX (both active low) ...
  CARD_CS1FX = 1;  CARD_CS3FX = 1;  CARD_RESET = 1;

  //   As the very first thing, blindly set the unit select register to zero,
  // since the onboard CF card is always the IDE "master" drive.  We have to
  // do this before anything else, including something as simple as reading a
  // register, because the drive (card) won't respond unless it is selected!
  WriteIDE(IDE_REG_SELECT, 0xA0 | IDE_LBA_MODE);

  //   Now do some simple tests to make sure that IDE register set is real
  // and addressible.  The cylinder, sector and count registers can all be
  // read and written with no ill effect as long as no command is issued!
  WriteIDE(IDE_REG_SECTOR, 0xAA);  WriteIDE(IDE_REG_COUNT, 0x55);
  //DBGOUT(("IDE register test - sector=0x%02bX, count=0x%02bX\n",
  //  ReadIDE(IDE_REG_SECTOR), ReadIDE(IDE_REG_COUNT)));
  if (ReadIDE(IDE_REG_SECTOR) != 0xAA) return FALSE;
  if (ReadIDE(IDE_REG_COUNT)  != 0x55) return FALSE;

  //   Set the software RESET bit, wait a microsecond or two (the ATA spec says
  // only 500ns are required) and then clear it, then wait for the drive to go
  // ready.
  WriteIDE(IDE_REG_CONTROL, IDE_SOFTWARE_RESET);
  WriteIDE(IDE_REG_CONTROL, 0);  bStatus = WaitReady();
  //DBGOUT(("IDE software reset, status=0x%02bX\n", bStatus));
  if ((bStatus == 0) || ((bStatus & IDE_STATUS_ERR) != 0)) return FALSE;
  
  // Select 8 bit mode...
  WriteIDE(IDE_REG_FEATURES, IDE_FEATURE_8BIT);
  WriteIDE(IDE_REG_COMMAND, IDE_CMD_SET_FEATURES);
  bStatus = WaitReady();
  //DBGOUT(("IDE set features, status=0x%02bX\n", bStatus));
  if ((bStatus == 0) || ((bStatus & IDE_STATUS_ERR) != 0)) return FALSE;
  DBGOUT(("CompactFlash card initialized ...\n"));
  return TRUE;
}

⌨️ 快捷键说明

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