📄 cfcard.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 + -