windows-nt/Source/XPSP1/NT/drivers/storage/tffsport/flflash.c
2020-09-26 16:20:57 +08:00

528 lines
20 KiB
C

/*
* $Log: V:/Flite/archives/TrueFFS5/Src/FLFLASH.C_V $
*
* Rev 1.12 Apr 15 2002 07:36:38 oris
* Bug fix - do not initialize access routines in case of user defined routines - as a result docsys must be included.
*
* Rev 1.11 Jan 28 2002 21:24:38 oris
* Changed memWinowSize to memWindowSize.
*
* Rev 1.10 Jan 17 2002 23:09:30 oris
* Added flFlashOf() routine to allow the use of a single FLFlash record per socket .
* Added memory access routines initialization for FLFlash.
* Bug fix - if M+ device was registered after 8-bit DiskOnChip and the M+ had a bad download problem , the error would not be reported, but only flUnknown media.
*
* Rev 1.9 Sep 15 2001 23:46:00 oris
* Changed erase routine to support up to 64K erase blocks.
*
* Rev 1.8 Jul 13 2001 01:04:38 oris
* Added new field initialization in FLFlash record - Max Erase Cycles of the flash.
*
* Rev 1.7 May 16 2001 21:18:24 oris
* Removed warnings.
*
* Rev 1.6 May 02 2001 06:41:26 oris
* Removed the lastUsableBlock variable.
*
* Rev 1.5 Apr 24 2001 17:07:52 oris
* Bug fix - missing NULL initialization for several compilation flags.
* Added lastUsableBlock field defualt initialization.
*
* Rev 1.4 Apr 16 2001 13:39:14 oris
* Bug fix read and write default routines were not initialized.
* Initialize the firstUsableBlock.
* Removed warrnings.
*
* Rev 1.3 Apr 12 2001 06:50:22 oris
* Added initialization of download routine pointer.
*
* Rev 1.2 Apr 09 2001 15:09:04 oris
* End with an empty line.
*
* Rev 1.1 Apr 01 2001 07:54:08 oris
* copywrite notice.
* Changed prototype of :flashRead.
* Removed interface b initialization (experimental MTD interface for mdocp).
* Spelling mistake "changableProtectedAreas".
* Added check for bad download in flash recognition.
*
* Rev 1.0 Feb 04 2001 11:21:16 oris
* Initial revision.
*
*/
/***********************************************************************************/
/* M-Systems Confidential */
/* Copyright (C) M-Systems Flash Disk Pioneers Ltd. 1995-2001 */
/* All Rights Reserved */
/***********************************************************************************/
/* NOTICE OF M-SYSTEMS OEM */
/* SOFTWARE LICENSE AGREEMENT */
/* */
/* THE USE OF THIS SOFTWARE IS GOVERNED BY A SEPARATE LICENSE */
/* AGREEMENT BETWEEN THE OEM AND M-SYSTEMS. REFER TO THAT AGREEMENT */
/* FOR THE SPECIFIC TERMS AND CONDITIONS OF USE, */
/* OR CONTACT M-SYSTEMS FOR LICENSE ASSISTANCE: */
/* E-MAIL = info@m-sys.com */
/***********************************************************************************/
#include "flflash.h"
#include "docsys.h"
#define READ_ID 0x90
#define INTEL_READ_ARRAY 0xff
#define AMD_READ_ARRAY 0xf0
/* MTD registration information */
int noOfMTDs = 0;
MTDidentifyRoutine mtdTable[MTDS];
static FLFlash vols[SOCKETS];
FLStatus dataErrorObject;
/*----------------------------------------------------------------------*/
/* f l F l a s h O f */
/* */
/* Gets the flash connected to a volume no. */
/* */
/* Parameters: */
/* volNo : Volume no. for which to get flash */
/* */
/* Returns: */
/* flash of volume no. */
/*----------------------------------------------------------------------*/
FLFlash *flFlashOf(unsigned volNo)
{
return &vols[volNo];
}
/*----------------------------------------------------------------------*/
/* f l a s h M a p */
/* */
/* Default flash map method: Map through socket window. */
/* This method is applicable for all NOR Flash */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* address : Card address to map */
/* length : Length to map (irrelevant here) */
/* */
/* Returns: */
/* Pointer to required card address */
/*----------------------------------------------------------------------*/
static void FAR0 *flashMap(FLFlash vol, CardAddress address, int length)
{
return flMap(vol.socket,address);
}
/*----------------------------------------------------------------------*/
/* f l a s h R e a d */
/* */
/* Default flash read method: Read by copying from mapped address */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* address : Card address to read */
/* buffer : Area to read into */
/* length : Length to read */
/* */
/*----------------------------------------------------------------------*/
static FLStatus flashRead(FLFlash vol,
CardAddress address,
void FAR1 *buffer,
dword length,
word mode)
{
tffscpy(buffer,vol.map(&vol,address,(word)length),(word)length);
return flOK;
}
/*----------------------------------------------------------------------*/
/* f l a s h N o W r i t e */
/* */
/* Default flash write method: Write not allowed (read-only mode) */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* address : Card address to write */
/* buffer : Area to write from */
/* length : Length to write */
/* */
/* Returns: */
/* Write-protect error */
/*----------------------------------------------------------------------*/
static FLStatus flashNoWrite(FLFlash vol,
CardAddress address,
const void FAR1 *from,
dword length,
word mode)
{
return flWriteProtect;
}
/*----------------------------------------------------------------------*/
/* f l a s h N o E r a s e */
/* */
/* Default flash erase method: Erase not allowed (read-only mode) */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* firstBlock : No. of first erase block */
/* noOfBlocks : No. of contiguous blocks to erase */
/* */
/* Returns: */
/* Write-protect error */
/*----------------------------------------------------------------------*/
static FLStatus flashNoErase(FLFlash vol,
word firstBlock,
word noOfBlocks)
{
return flWriteProtect;
}
/*----------------------------------------------------------------------*/
/* s e t N o C a l l b a c k */
/* */
/* Register power on callback routine. Default: no routine is */
/* registered. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* */
/*----------------------------------------------------------------------*/
static void setNoCallback(FLFlash vol)
{
flSetPowerOnCallback(vol.socket,NULL,NULL);
}
/*----------------------------------------------------------------------*/
/* f l I n t e l I d e n t i f y */
/* */
/* Identify the Flash type and interleaving for Intel-style Flash. */
/* Sets the value of vol.type (JEDEC id) & vol.interleaving. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* amdCmdRoutine : Routine to read-id AMD/Fujitsu style at */
/* a specific location. If null, Intel procedure */
/* is used. */
/* idOffset : Chip offset to use for identification */
/* */
/* Returns: */
/* FLStatus : 0 = OK, otherwise failed (invalid Flash array)*/
/*----------------------------------------------------------------------*/
void flIntelIdentify(FLFlash vol,
void (*amdCmdRoutine)(FLFlash vol, CardAddress,
unsigned char, FlashPTR),
CardAddress idOffset)
{
int inlv;
unsigned char vendorId = 0;
FlashPTR flashPtr = (FlashPTR) flMap(vol.socket,idOffset);
unsigned char firstByte = 0;
unsigned char resetCmd = amdCmdRoutine ? AMD_READ_ARRAY : INTEL_READ_ARRAY;
for (inlv = 0; inlv < 15; inlv++) { /* Increase interleaving until failure */
flashPtr[inlv] = resetCmd; /* Reset the chip */
flashPtr[inlv] = resetCmd; /* Once again for luck */
if (inlv == 0)
firstByte = flashPtr[0]; /* Remember byte on 1st chip */
if (amdCmdRoutine) /* AMD: use unlock sequence */
amdCmdRoutine(&vol,idOffset + inlv, READ_ID, flashPtr);
else
flashPtr[inlv] = READ_ID; /* Read chip id */
if (inlv == 0)
vendorId = flashPtr[0]; /* Assume first chip responded */
else if (flashPtr[inlv] != vendorId || firstByte != flashPtr[0]) {
/* All chips should respond in the same way. We know interleaving = n */
/* when writing to chip n affects chip 0. */
/* Get full JEDEC id signature */
vol.type = (FlashType) ((vendorId << 8) | flashPtr[inlv]);
flashPtr[inlv] = resetCmd;
break;
}
flashPtr[inlv] = resetCmd;
}
if (inlv & (inlv - 1))
vol.type = NOT_FLASH; /* not a power of 2, no way ! */
else
#ifndef NT5PORT
vol.interleaving = inlv;
#else
vol.interleaving = (Sword)inlv;
#endif /*NT5PORT*/
}
/*----------------------------------------------------------------------*/
/* i n t e l S i z e */
/* */
/* Identify the card size for Intel-style Flash. */
/* Sets the value of vol.noOfChips. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* amdCmdRoutine : Routine to read-id AMD/Fujitsu style at */
/* a specific location. If null, Intel procedure */
/* is used. */
/* idOffset : Chip offset to use for identification */
/* */
/* Returns: */
/* FLStatus : 0 = OK, otherwise failed (invalid Flash array)*/
/*----------------------------------------------------------------------*/
FLStatus flIntelSize(FLFlash vol,
void (*amdCmdRoutine)(FLFlash vol, CardAddress,
unsigned char, FlashPTR),
CardAddress idOffset)
{
unsigned char resetCmd = amdCmdRoutine ? AMD_READ_ARRAY : INTEL_READ_ARRAY;
FlashPTR flashPtr = (FlashPTR) vol.map(&vol,idOffset,0);
if (amdCmdRoutine) /* AMD: use unlock sequence */
amdCmdRoutine(&vol,0,READ_ID, flashPtr);
else
flashPtr[0] = READ_ID;
/* We leave the first chip in Read ID mode, so that we can */
/* discover an address wraparound. */
for (vol.noOfChips = 0; /* Scan the chips */
vol.noOfChips < 2000; /* Big enough ? */
vol.noOfChips += vol.interleaving) {
int i;
flashPtr = (FlashPTR) vol.map(&vol,vol.noOfChips * vol.chipSize + idOffset,0);
/* Check for address wraparound to the first chip */
if (vol.noOfChips > 0 &&
(FlashType) ((flashPtr[0] << 8) | flashPtr[vol.interleaving]) == vol.type)
goto noMoreChips; /* wraparound */
/* Check if chip displays the same JEDEC id and interleaving */
for (i = (vol.noOfChips ? 0 : 1); i < vol.interleaving; i++) {
if (amdCmdRoutine) /* AMD: use unlock sequence */
amdCmdRoutine(&vol,vol.noOfChips * vol.chipSize + idOffset + i,
READ_ID, flashPtr);
else
flashPtr[i] = READ_ID;
if ((FlashType) ((flashPtr[i] << 8) | flashPtr[i + vol.interleaving]) !=
vol.type)
goto noMoreChips; /* This "chip" doesn't respond correctly, so we're done */
flashPtr[i] = resetCmd;
}
}
noMoreChips:
flashPtr = (FlashPTR) vol.map(&vol,idOffset,0);
flashPtr[0] = resetCmd; /* reset the original chip */
return (vol.noOfChips == 0) ? flUnknownMedia : flOK;
}
/*----------------------------------------------------------------------*/
/* i s R A M */
/* */
/* Checks if the card memory behaves like RAM */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* */
/* Returns: */
/* 0 = not RAM-like, other = memory is apparently RAM */
/*----------------------------------------------------------------------*/
static FLBoolean isRAM(FLFlash vol)
{
#ifndef NT5PORT
FlashPTR flashPtr = (FlashPTR) flMap(vol.socket,0);
unsigned char firstByte = flashPtr[0];
char writeChar = (firstByte != 0) ? 0 : 0xff;
volatile int zero=0;
#else
FlashPTR flashPtr = (FlashPTR) flMap(vol.socket,0);
unsigned char firstByte;
char writeChar;
volatile int zero=0;
if(flashPtr == NULL){
DEBUG_PRINT(("Debug:isRAM(): NULL Pointer.\n"));
}
firstByte = flashPtr[0];
writeChar = (firstByte != 0) ? 0 : 0xff;
#endif //NT5PORT
flashPtr[zero] = writeChar; /* Write something different */
if (flashPtr[zero] == writeChar) { /* Was it written ? */
flashPtr[zero] = firstByte; /* must be RAM, undo the damage */
DEBUG_PRINT(("Debug: error, socket window looks like RAM.\r\n"));
return TRUE;
}
return FALSE;
}
/*----------------------------------------------------------------------*/
/* f l I d e n t i f y F l a s h */
/* */
/* Identify the current Flash medium and select an MTD for it */
/* */
/* Parameters: */
/* socket : Socket of flash */
/* vol : New volume pointer */
/* */
/* Returns: */
/* FLStatus : 0 = Flash was identified */
/* other = identification failed */
/*----------------------------------------------------------------------*/
FLStatus flIdentifyFlash(FLSocket *socket, FLFlash vol)
{
FLStatus status = flUnknownMedia;
int iMTD;
dword blockSize;
vol.socket = socket;
#ifndef FIXED_MEDIA
/* Check that we have a media */
flResetCardChanged(vol.socket); /* we're mounting anyway */
checkStatus(flMediaCheck(vol.socket));
#endif
#ifdef ENVIRONMENT_VARS
if(flUseisRAM==1)
{
#endif
if ( isRAM(&vol))
return flUnknownMedia; /* if it looks like RAM, leave immediately */
#ifdef ENVIRONMENT_VARS
}
#endif
/* Install default methods */
vol.type = NOT_FLASH;
vol.mediaType = NOT_DOC_TYPE;
vol.pageSize = 0;
vol.flags = 0;
vol.map = flashMap;
vol.read = flashRead;
vol.setPowerOnCallback = setNoCallback;
vol.erase = flashNoErase;
vol.write = flashNoWrite;
vol.readBBT = NULL;
vol.writeIPL = NULL;
vol.readIPL = NULL;
#ifdef HW_OTP
vol.otpSize = NULL;
vol.readOTP = NULL;
vol.writeOTP = NULL;
vol.getUniqueId = NULL;
#endif /* HW_OTP */
#ifdef HW_PROTECTION
vol.protectionBoundries = NULL;
vol.protectionKeyInsert = NULL;
vol.protectionKeyRemove = NULL;
vol.protectionType = NULL;
vol.protectionSet = NULL;
#endif /* HW_PROTECTION */
vol.download = NULL;
vol.enterDeepPowerDownMode = NULL;
#ifndef FL_NO_USE_FUNC
if(flBusConfig[flSocketNoOf(socket)] != FL_ACCESS_USER_DEFINED);
{
vol.memRead = NULL;
vol.memWrite = NULL;
vol.memSet = NULL;
vol.memRead8bit = NULL;
vol.memWrite8bit = NULL;
vol.memRead16bit = NULL;
vol.memWrite16bit = NULL;
vol.memWindowSize = NULL;
}
#endif /* FL_NO_USE_FUNC */
/* Setup arbitrary parameters for read-only mount */
vol.chipSize = 0x100000L;
vol.erasableBlockSize = 0x1000L;
vol.noOfChips = 1;
vol.interleaving = 1;
vol.noOfFloors = 1;
vol.totalProtectedAreas = 0;
vol.changeableProtectedAreas = 0;
vol.ppp = 5;
vol.firstUsableBlock = 0;
vol.maxEraseCycles = 100000L; /* Defaul for NOR */
#ifdef NT5PORT
vol.readBufferSize = 0;
vol.readBuffer = NULL;
#endif /*NT5PORT*/
/* Attempt all MTD's */
for (iMTD = 0; (iMTD < noOfMTDs) && (status != flOK) &&
(status != flBadDownload); iMTD++)
status = mtdTable[iMTD](&vol);
if (status == flBadDownload)
{
DEBUG_PRINT(("Debug: Flash media reported bad download error.\r\n"));
return flBadDownload;
}
if (status != flOK) /* No MTD recognition */
{
DEBUG_PRINT(("Debug: did not identify flash media.\r\n"));
return flUnknownMedia;
}
/* Calculate erasable Block Size Bits */
for(blockSize = vol.erasableBlockSize>>1,vol.erasableBlockSizeBits = 0;
blockSize>0; vol.erasableBlockSizeBits++,blockSize = blockSize >> 1);
return flOK;
}
#ifdef NT5PORT
VOID * mapThroughBuffer(FLFlash vol, CardAddress address, LONG length)
{
if ((ULONG) length > vol.readBufferSize) {
vol.readBufferSize = 0;
if (vol.readBuffer) {
FREE(vol.readBuffer);
}
vol.readBuffer = MALLOC(length);
if (vol.readBuffer == NULL) {
return vol.readBuffer;
}
vol.readBufferSize = length;
}
vol.read(&vol,address,vol.readBuffer,length,0);
return vol.readBuffer;
}
#endif /* NT5PORT */