2772 lines
108 KiB
C
2772 lines
108 KiB
C
/*
|
||
* $Log: V:/Flite/archives/TrueFFS5/Src/DISKONC.C_V $
|
||
*
|
||
* Rev 1.33 Apr 15 2002 07:35:04 oris
|
||
* Changed usage and logic of checkToggle to be more intuitive.
|
||
* Added support for new access layer (docsys). MTD now initializes the
|
||
* access layer accessing the DiskOnChip registers.
|
||
* Bug fix - doc2write did not report write faults in case runtime verify
|
||
* write was not required.
|
||
* Bug fix - bad compilation ifdef in readBBT routine might cause a write
|
||
* operation while FL_READ_ONLY is defined or to compile the
|
||
* reconstruct BBT code even if MTD_RECONSTRUCT_BBT is
|
||
* not defined.
|
||
*
|
||
* Rev 1.32 Jan 29 2002 20:07:30 oris
|
||
* Changed sanity check of write IPL modes.
|
||
*
|
||
* Rev 1.31 Jan 28 2002 21:23:58 oris
|
||
* Removed the use of back-slashes in macro definitions.
|
||
* Added FL_IPL_DOWNLOAD flag to writeIPL routine in order to control whether the IPL will be reloaded after the update.
|
||
* Bug fix - writeIPL routine did not support buffers smaller then 1024 bytes.
|
||
* Bug fix - writeIPL routine did not write the second copy of the IPL correctly (for both 512 bytes).
|
||
* Changed docwrite and docset calls to separate DiskOnChip base window pointer and IO registers offset (for address shifting).
|
||
* Replaced FLFlash argument with DiskOnChip memory base pointer in calls to docwrite , docset and docread.
|
||
* Removed win_io initialization (one of FLFlash record fields).
|
||
* Improved check for flSuspend.
|
||
*
|
||
* Rev 1.30 Jan 23 2002 23:31:04 oris
|
||
* Added writeIPL routine (copied from blockdev.c).
|
||
* Made writeIPL and download routines available even when MTD_STANDALONE is defined.
|
||
* Bug fix - checkErase routine was unreasonably slow.
|
||
* Changed DFORMAT_PRINT syntax.
|
||
*
|
||
* Rev 1.29 Jan 21 2002 20:43:50 oris
|
||
* Compilation errors for MTD_STANDALONE with BDK_VERIFY_WRITE.
|
||
* Bug fix - PARTIAL_EDC flag to doc2read was negated prior to readOneSector.
|
||
*
|
||
* Rev 1.28 Jan 20 2002 20:57:00 oris
|
||
* physicalToPointer was called with wrong size argument.
|
||
*
|
||
* Rev 1.27 Jan 20 2002 20:28:06 oris
|
||
* Changed doc2000FreeWindow return type to remove warnings.
|
||
*
|
||
* Rev 1.26 Jan 17 2002 22:57:56 oris
|
||
* Replaced vol with *flash.
|
||
* Removed flPreInit memory access routines.
|
||
* Added new memory access routine implementation.
|
||
* Compilation problems fixed with VERIFY_ERASE
|
||
* Added support for flSuspendMode environment variable.
|
||
*
|
||
* Rev 1.25 Nov 21 2001 11:39:10 oris
|
||
* Changed FL_WITH_VERIFY_WRITE and FL_WITHOUT_VERIFY_WRITE to FL_ON and FL_OFF.
|
||
*
|
||
* Rev 1.24 Nov 20 2001 20:24:58 oris
|
||
* Removed warnings.
|
||
*
|
||
* Rev 1.23 Nov 16 2001 00:19:38 oris
|
||
* Compilation problem for FL_READ_ONLY.
|
||
*
|
||
* Rev 1.22 Nov 08 2001 10:44:30 oris
|
||
* Added run-time control over verify write mode.
|
||
* Added support for more up to 64K units - erase / readbbt
|
||
* Restricted BBT block search to BBT_MAX_DISTANCE and not the entire floor.
|
||
* Bug fix - Replacing a DiskOnChip Millennium with DiskOnChip 2000 failed identifying DiskOnChip2000 (gang).
|
||
*
|
||
* Rev 1.21 Sep 24 2001 18:23:08 oris
|
||
* Removed warnings.
|
||
*
|
||
* Rev 1.20 Sep 15 2001 23:44:42 oris
|
||
* Placed YIELD_CPU definition under ifdef to prevent redeclaration.
|
||
* Changed doc2erase to support up to 64K erase blocks.
|
||
* Added reconstruct flag to readBBT routine - stating whether to reconstruct BBT if it is not available.
|
||
* Added support for block multiplication in readBBT - several erase blocks in a single unit.
|
||
* Added support for 128MB flashes.
|
||
*
|
||
* Rev 1.19 Jul 29 2001 16:14:06 oris
|
||
* Support for number of units per floor not power of 2
|
||
*
|
||
* Rev 1.18 Jul 16 2001 22:47:58 oris
|
||
* Compilation error when using the FL_READ_ONLY compilation flag.
|
||
*
|
||
* Rev 1.17 Jul 15 2001 20:44:48 oris
|
||
* Removed warnings.
|
||
* Bug fix - virgin card dformat print was repeated for DiskOnChip with several floors.
|
||
*
|
||
* Rev 1.16 Jul 13 2001 00:59:42 oris
|
||
* Added docsys.h include.
|
||
* Improved VERIFY_WRITE support - added socket readBack buffer.
|
||
* Added PARTIAL_EDC read flag to the read routine.
|
||
* Revised checkErase routine to include extra area.
|
||
* Revised readBBT routine not to use MTD buffer.
|
||
* Added dformat debug print massages.
|
||
* Changed firstUsable block to 0 for DOC2000 tsop.
|
||
*
|
||
* Rev 1.15 Jun 17 2001 08:17:02 oris
|
||
* Added brackets to remove warnnings.
|
||
* Changed NO_READ_BBT_CODE to MTD_NO_READ_BBT_CODE.
|
||
*
|
||
* Rev 1.14 May 16 2001 21:16:32 oris
|
||
* Removed warnings.
|
||
* Changed code variable name to flCode (avoid name clashes).
|
||
*
|
||
* Rev 1.13 May 09 2001 00:31:28 oris
|
||
* Changed the DOC2000_TSOP_SUPPORT and READ_BBT_CODE compilation flags to NO_READ_BBT_CODE.
|
||
*
|
||
* Rev 1.12 May 07 2001 10:00:04 oris
|
||
* Compilation problems under MTD_STANDLAONE compilation flag.
|
||
*
|
||
* Rev 1.11 May 06 2001 22:41:22 oris
|
||
* Added the READ_BBT_CODE to allow reading the BBT even in the MTD_STANDALONE mode.
|
||
* Removed warnings.
|
||
*
|
||
* Rev 1.10 May 02 2001 06:44:38 oris
|
||
* Bug fix - readBBT routine.
|
||
* Removed the lastUsableBlock variable.
|
||
*
|
||
* Rev 1.9 Apr 30 2001 17:58:18 oris
|
||
* Added EDC check when reading the BBT.
|
||
*
|
||
* Rev 1.8 Apr 24 2001 17:06:22 oris
|
||
* Removed warrnings.
|
||
* Added lastUsableBlock initialization field in the FLFlash record.
|
||
*
|
||
* Rev 1.7 Apr 16 2001 13:04:20 oris
|
||
* Removed warrnings.
|
||
*
|
||
* Rev 1.6 Apr 12 2001 06:49:06 oris
|
||
* Added forceDownload routine
|
||
* Changed checkWinForDoc routine to be under ifndef MTD_STANDALONE.
|
||
*
|
||
* Rev 1.5 Apr 10 2001 16:39:16 oris
|
||
* Added multiple floor support for readbbt routine.
|
||
* Added call for docSocketInit which initializes the socket routines.
|
||
* Added validity check after flMap call in order to support pccard premoutn routine.
|
||
*
|
||
* Rev 1.4 Apr 09 2001 14:58:40 oris
|
||
* Removed debug buffer from readBBT routine.
|
||
* Bug fix in doc2000Identify if ASIC id was not mdoc 8 is was assumed to be doc2000.
|
||
* Added if_cfg field initialization in doc2000Identify.
|
||
*
|
||
* Rev 1.3 Apr 01 2001 07:38:58 oris
|
||
* Moved include diskonc.h from docsys.h.
|
||
* Removed waitForReadyWithYieldCPU for MTD_STANDALONE configuration.
|
||
* Removed NO_PPP compilation flag support.
|
||
* Left alligned all # directives.
|
||
* Moved pageSize,noOfFloors filed from the MTDs internal stucture to FLFlash record.
|
||
* Changed writeOneSector,doc2Write,readOneSector,doc2Read prototype.
|
||
* Added readbbt routine for alon.
|
||
* Removed pageAndTailSize from mtdVars record.
|
||
*
|
||
* Rev 1.2 Mar 01 2001 14:15:56 vadimk
|
||
* Add proper MDOC and DOC2300 support
|
||
*
|
||
* Rev 1.1 Feb 07 2001 18:28:38 oris
|
||
* Bug fix - restored antialise mechanizm to flDocWindowBaseAddress
|
||
* Added seperetaed floors compilation flag
|
||
* Changed mdoc \ alon distingishing algorithm
|
||
* Removed checkWinForDoc routine under the mtd_standalone comilation flag
|
||
* removed MAX_FLASH_DEVICES_MDOC define since alone DiskOnChips can support 16 chips just like doc2000
|
||
*
|
||
* Rev 1.0 Feb 02 2001 15:35:38 oris
|
||
* Initial revision.
|
||
*
|
||
*/
|
||
|
||
/************************************************************************/
|
||
/* */
|
||
/* FAT-FTL Lite Software Development Kit */
|
||
/* Copyright (C) M-Systems Ltd. 1995-2001 */
|
||
/* */
|
||
/************************************************************************/
|
||
|
||
#include "reedsol.h"
|
||
#include "diskonc.h"
|
||
|
||
extern NFDC21Vars docMtdVars[SOCKETS];
|
||
|
||
/* When the MTD is used as a standalone package some of the routine */
|
||
/* are replaced with the following macroes */
|
||
|
||
#ifdef MTD_STANDALONE
|
||
|
||
#define flReadBackBufferOf(a) &(globalReadBack[a][0])
|
||
|
||
#define flSocketNoOf(volume) 0 /* currently we support only a single device */
|
||
|
||
#define flMap(socket,address) addToFarPointer(socket->base,address & (socket->size - 1));
|
||
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
/* Yield CPU time in msecs */
|
||
#ifndef YIELD_CPU
|
||
#define YIELD_CPU 10
|
||
#endif /* YIELD_CPU */
|
||
|
||
/* maximum waiting time in msecs */
|
||
#define MAX_WAIT 30
|
||
|
||
#ifndef NO_EDC_MODE
|
||
|
||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.*/
|
||
/* EDC control */
|
||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.*/
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* e c c O N r e a d */
|
||
/* */
|
||
/* Enable ECC in read mode and reset it. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void eccONread (FLFlash * flash)
|
||
{
|
||
flWrite8bitReg(flash,NECCconfig,ECC_RESET);
|
||
flWrite8bitReg(flash,NECCconfig,ECC_EN);
|
||
}
|
||
#ifndef FL_READ_ONLY
|
||
/*----------------------------------------------------------------------*/
|
||
/* e c c O n w r i t e */
|
||
/* */
|
||
/* Enable ECC in write mode and reset it. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
static void eccONwrite (FLFlash * flash)
|
||
{
|
||
flWrite8bitReg(flash,NECCconfig,ECC_RESET);
|
||
flWrite8bitReg(flash,NECCconfig,(ECC_RW | ECC_EN));
|
||
}
|
||
#endif /* FL_READ_ONLY */
|
||
#endif
|
||
/*----------------------------------------------------------------------*/
|
||
/* e c c O F F */
|
||
/* */
|
||
/* Disable ECC. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void eccOFF (FLFlash * flash)
|
||
{
|
||
flWrite8bitReg(flash,NECCconfig,ECC_RESERVED);
|
||
}
|
||
|
||
#ifndef NO_EDC_MODE
|
||
/*----------------------------------------------------------------------*/
|
||
/* e c c E r r o r */
|
||
/* */
|
||
/* Check for EDC error. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
static FLBoolean eccError (FLFlash * flash)
|
||
{
|
||
register int i;
|
||
volatile Reg8bitType junk = 0;
|
||
Reg8bitType ret;
|
||
|
||
if( NFDC21thisVars->flags & MDOC_ASIC ) {
|
||
for(i=0;( i < 2 ); i++)
|
||
junk += flRead8bitReg(flash,NECCconfig);
|
||
ret = flRead8bitReg(flash,NECCconfig);
|
||
}
|
||
else {
|
||
for(i=0;( i < 2 ); i++)
|
||
junk += flRead8bitReg(flash,NECCstatus);
|
||
ret = flRead8bitReg(flash,NECCstatus);
|
||
}
|
||
ret &= ECC_ERROR;
|
||
return ((FLBoolean)ret);
|
||
|
||
}
|
||
|
||
#endif
|
||
|
||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.*/
|
||
/* Miscellaneous routines */
|
||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.*/
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* m a k e C o m m a n d */
|
||
/* */
|
||
/* Set Page Pointer to Area A, B or C in page. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* cmd : receives command relevant to area */
|
||
/* addr : receives the address to the right area. */
|
||
/* modes : mode of operation (EXTRA ...) */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void makeCommand ( FLFlash * flash, PointerOp *cmd,
|
||
CardAddress *addr, int modes )
|
||
{
|
||
dword offset;
|
||
|
||
#ifdef BIG_PAGE_ENABLED
|
||
if ( !(flash->flags & BIG_PAGE) )
|
||
{ /* 2 Mb components */
|
||
if( modes & EXTRA )
|
||
{
|
||
offset = (*addr) & (SECTOR_SIZE - 1);
|
||
*cmd = AREA_C;
|
||
if( offset < EXTRA_LEN ) /* First half of extra area */
|
||
*addr += 0x100; /* ... assigned to 2nd page */
|
||
else /* Second half of extra area */
|
||
*addr -= EXTRA_LEN; /* ... assigned to 1st page */
|
||
}
|
||
else
|
||
*cmd = AREA_A;
|
||
}
|
||
else
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
{ /* 4 Mb components */
|
||
offset = (word)(*addr) & NFDC21thisVars->pageMask; /* offset within device Page */
|
||
*addr -= offset; /* align at device Page */
|
||
|
||
if(modes & EXTRA)
|
||
offset += SECTOR_SIZE;
|
||
|
||
if( offset < NFDC21thisVars->pageAreaSize ) /* starting in area A */
|
||
*cmd = AREA_A;
|
||
else if( offset < flash->pageSize ) /* starting in area B */
|
||
*cmd = AREA_B;
|
||
else /* got into area C */
|
||
*cmd = AREA_C;
|
||
|
||
offset &= (NFDC21thisVars->pageAreaSize - 1); /* offset within area of device Page */
|
||
*addr += offset;
|
||
}
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* b u s y */
|
||
/* */
|
||
/* Check if the selected flash device is ready. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/* Returns: */
|
||
/* Zero is ready. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
static FLBoolean busy (FLFlash * flash)
|
||
{
|
||
register int i;
|
||
Reg8bitType stat;
|
||
volatile Reg8bitType junk = 0;
|
||
Reg8bitType ret;
|
||
/* before polling for BUSY status perform 4 read operations from
|
||
CDSN_control_reg */
|
||
|
||
for(i=0;( i < 4 ); i++ )
|
||
junk += flRead8bitReg(flash,NNOPreg);
|
||
|
||
/* read BUSY status */
|
||
|
||
stat = flRead8bitReg(flash,Nsignals);
|
||
|
||
/* after BUSY status is obtained perform 2 read operations from
|
||
CDSN_control_reg */
|
||
|
||
for(i=0;( i < 2 ); i++ )
|
||
junk += flRead8bitReg(flash,NNOPreg);
|
||
ret = (!(stat & (Reg8bitType)RB));
|
||
return ((FLBoolean)ret);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* w a i t F o r R e a d y */
|
||
/* */
|
||
/* Wait until flash device is ready or timeout. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* Returns: */
|
||
/* FALSE if timeout error, otherwise TRUE. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLBoolean waitForReady (FLFlash * flash)
|
||
{
|
||
int i;
|
||
for(i=0;( i < BUSY_DELAY ); i++)
|
||
{
|
||
if( busy(flash) )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
return( TRUE ); /* ready at last.. */
|
||
}
|
||
|
||
DEBUG_PRINT(("Debug: timeout error in NFDC 2148.\r\n"));
|
||
return( FALSE );
|
||
}
|
||
|
||
#ifndef MTD_STANDALONE
|
||
#ifndef DO_NOT_YIELD_CPU
|
||
/*----------------------------------------------------------------------*/
|
||
/* w a i t F o r R e a d y W i t h Y i e l d C P U */
|
||
/* */
|
||
/* Wait until flash device is ready or timeout. */
|
||
/* The function yields CPU while it waits till flash is ready */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* Returns: */
|
||
/* FALSE if timeout error, otherwise TRUE. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLBoolean waitForReadyWithYieldCPU (FLFlash * flash,
|
||
int millisecToSleep)
|
||
{
|
||
int i;
|
||
|
||
for (i=0; i < (millisecToSleep / YIELD_CPU); i++) {
|
||
#ifndef NT5PORT
|
||
flsleep(YIELD_CPU);
|
||
#endif /*NT5PORT*/
|
||
if( busy(flash) )
|
||
continue;
|
||
return( TRUE ); /* ready at last.. */
|
||
}
|
||
|
||
return( FALSE );
|
||
}
|
||
#endif /* DO_NOT_YIELD_CPU */
|
||
#endif /* MTD_STANDALONE */
|
||
/*----------------------------------------------------------------------*/
|
||
/* w r i t e S i g n a l s */
|
||
/* */
|
||
/* Write to CDSN_control_reg. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* val : Value to write to register */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void writeSignals (FLFlash * flash, Reg8bitType val)
|
||
{
|
||
register int i;
|
||
volatile Reg8bitType junk = 0;
|
||
|
||
flWrite8bitReg(flash,Nsignals,val);
|
||
|
||
/* after writing to CDSN_control perform 2 reads from there */
|
||
|
||
for(i = 0;( i < 2 ); i++ )
|
||
junk += flRead8bitReg(flash,NNOPreg);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* s e l e c t C h i p */
|
||
/* */
|
||
/* Write to deviceSelector register. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* dev : Chip to select. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void selectChip (FLFlash * flash, Reg8bitType dev)
|
||
{
|
||
flWrite8bitReg(flash,NdeviceSelector,dev);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* c h k A S I C m o d e */
|
||
/* */
|
||
/* Check mode of ASIC and if RESET set to NORMAL. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void chkASICmode (FLFlash * flash)
|
||
{
|
||
if( flRead8bitReg(flash,NDOCstatus) == ASIC_CHECK_RESET ) {
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_NORMAL_MODE);
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_NORMAL_MODE);
|
||
#ifndef SEPARATED_CASCADED
|
||
NFDC21thisVars->currentFloor = 0;
|
||
#endif /* SEPARATED_CASCADED */
|
||
}
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* s e t A S I C m o d e */
|
||
/* */
|
||
/* Set mode of ASIC. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* mode : mode to set. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void setASICmode (FLFlash * flash, Reg8bitType mode)
|
||
{
|
||
NDOC2window p = (NDOC2window)flMap(flash->socket, 0);
|
||
if (p!=NULL)
|
||
{
|
||
flWrite8bitReg(flash,NDOCcontrol,mode);
|
||
flWrite8bitReg(flash,NDOCcontrol,mode);
|
||
#ifdef SEPARATED_CASCADED
|
||
flWrite8bitReg(flash,NASICselect,NFDC21thisVars->currentFloor);
|
||
#endif /* SEPARATED_CASCADED */
|
||
}
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* c h e c k T o g g l e */
|
||
/* */
|
||
/* Check DiskOnChip toggle bit. Verify this is not simple RAM. */
|
||
/* */
|
||
/* Note : This routine assumes that the memory access routines have */
|
||
/* already been initialized by the called routine. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* FLFlash : Pointer to flash structure. */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus: TRUE if the bit toggles verifing that this is indeed */
|
||
/* a DiskOnChip device, otherwise FALSE. */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLBoolean checkToggle(FLFlash * flash)
|
||
{
|
||
volatile Reg8bitType toggle1;
|
||
volatile Reg8bitType toggle2;
|
||
|
||
if(flRead8bitReg(flash,NchipId) == CHIP_ID_MDOC ) {
|
||
toggle1 = flRead8bitReg(flash,NECCconfig);
|
||
toggle2 = toggle1 ^ flRead8bitReg(flash,NECCconfig);
|
||
}
|
||
else {
|
||
toggle1 = flRead8bitReg(flash,NECCstatus);
|
||
toggle2 = toggle1 ^ flRead8bitReg(flash,NECCstatus);
|
||
}
|
||
if( (toggle2 & TOGGLE) == 0 )
|
||
return FALSE;
|
||
return TRUE;
|
||
}
|
||
|
||
#ifndef MTD_STANDALONE
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* c h e c k W i n F o r D O C */
|
||
/* */
|
||
/* Check for a DiskOnChip on a specific socket and memory windows */
|
||
/* */
|
||
/* Parameters: */
|
||
/* socketNo : Number of socket to check. */
|
||
/* memWinPtr : Pointer to DiskOnChip memory window. */
|
||
/* */
|
||
/* Returns: TRUE if this is an MDOCP, otherwise FALSE. */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
FLBoolean checkWinForDOC(unsigned socketNo, NDOC2window memWinPtr)
|
||
{
|
||
FLFlash * flash = flFlashOf(socketNo);
|
||
|
||
/* Initialize socket memory access routine */
|
||
flash->win = memWinPtr;
|
||
|
||
#ifndef FL_NO_USE_FUNC
|
||
if(setBusTypeOfFlash(flash, flBusConfig[socketNo] |
|
||
FL_8BIT_DOC_ACCESS | FL_8BIT_FLASH_ACCESS))
|
||
return FALSE;
|
||
#endif /* FL_NO_USE_FUNC */
|
||
|
||
/* set ASIC to RESET MODE */
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_RESET_MODE);
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_RESET_MODE);
|
||
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_NORMAL_MODE);
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_NORMAL_MODE);
|
||
|
||
if( (flRead8bitReg(flash,NchipId) != CHIP_ID_DOC ) &&
|
||
(flRead8bitReg(flash,NchipId) != CHIP_ID_MDOC))
|
||
return FALSE;
|
||
|
||
return checkToggle(flash);
|
||
}
|
||
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
#ifndef NO_IPL_CODE
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* f o r c e D o w n l o a d */
|
||
/* */
|
||
/* Force download of IPL code. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus forceDownLoad(FLFlash * flash)
|
||
{
|
||
flWrite8bitReg(flash, NfoudaryTest, 0x36);
|
||
flWrite8bitReg(flash, NfoudaryTest, 0x63);
|
||
flDelayMsecs(1000);
|
||
return flOK;
|
||
}
|
||
|
||
#ifndef FL_READ_ONLY
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* w r i t e I P L */
|
||
/* */
|
||
/* Write new IPL. */
|
||
/* */
|
||
/* Note : Can not start write operation from middle of IPL , unless */
|
||
/* previous operation started from offset 0. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive. */
|
||
/* buffer : buffer to write from. */
|
||
/* length : number of bytes to write - must use full 512 bytes. */
|
||
/* offset : sector number to start from. */
|
||
/* flags : Modes to write IPL : */
|
||
/* FL_IPL_MODE_NORMAL - Normal mode (none Strong Arm). */
|
||
/* FL_IPL_DOWNLOAD - Download new IPL when done */
|
||
/* FL_IPL_MODE_SA - Strong Arm IPL mode */
|
||
/* FL_IPL_MODE_XSCALE - X-Scale IPL mode */
|
||
/* */
|
||
/* Returns: */
|
||
/* flOK on success, none zero otherwise. */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus writeIPL(FLFlash * flash, const void FAR1 * buffer,
|
||
word length,byte offset, unsigned flags)
|
||
{
|
||
dword curWrite;
|
||
dword addrOffset = (dword)offset << SECTOR_SIZE_BITS;
|
||
|
||
if((flags & (FL_IPL_MODE_SA | FL_IPL_MODE_XSCALE)) != 0)
|
||
{
|
||
DFORMAT_PRINT(("ERROR - DiskOnChip does not support this IPL mode.\r\n"));
|
||
return flFeatureNotSupported;
|
||
}
|
||
|
||
if ((flash->erase != NULL)||(flash->write != NULL))
|
||
{
|
||
if ((length + addrOffset > 1024) || /* required length to long */
|
||
(offset>1) ) /* only single sector or none */
|
||
{
|
||
DFORMAT_PRINT(("ERROR - IPL size or offset are too big for this DiskOnChip.\r\n"));
|
||
return flBadLength;
|
||
}
|
||
if((length % SECTOR_SIZE) != 0)
|
||
{
|
||
DFORMAT_PRINT(("ERROR - IPL size must be a multiplication of 512 bytes.\r\n"));
|
||
return flBadLength;
|
||
}
|
||
|
||
if(offset==0) /* Erase only if offset is 0 */
|
||
checkStatus(flash->erase(flash,0,1));
|
||
|
||
for (addrOffset = addrOffset << 1 ; length > 0 ;
|
||
addrOffset += (SECTOR_SIZE<<1))
|
||
{
|
||
curWrite = TFFSMIN(length,SECTOR_SIZE);
|
||
checkStatus(flash->write(flash,addrOffset,buffer,curWrite,PARTIAL_EDC));
|
||
checkStatus(flash->write(flash,addrOffset+SECTOR_SIZE,buffer,curWrite,PARTIAL_EDC));
|
||
buffer = (byte FAR1 *)BYTE_ADD_FAR(buffer,SECTOR_SIZE);
|
||
length -= (word)curWrite;
|
||
}
|
||
if((flags & FL_IPL_DOWNLOAD) == 0)
|
||
return flOK;
|
||
|
||
if(flash->download != NULL)
|
||
return flash->download(flash);
|
||
DFORMAT_PRINT(("ERROR - IPL was not downloaded since MTD does not support the feature\r\n"));
|
||
}
|
||
DFORMAT_PRINT(("ERROR - IPL was not written since MTD is in read only mode\r\n"));
|
||
return flFeatureNotSupported;
|
||
}
|
||
|
||
#endif /* FL_READ_ONLY */
|
||
#endif /* NO_IPL_CODE */
|
||
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* f l D o c W i n d o w B a s e A d d r e s s */
|
||
/* */
|
||
/* Return the host base address of the window. */
|
||
/* If the window base address is programmable, this routine selects */
|
||
/* where the base address will be programmed to. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* socketNo FLite socket No (0..SOCKETS-1) */
|
||
/* lowAddress, */
|
||
/* highAddress : host memory range to search for DiskOnChip 2000 */
|
||
/* memory window */
|
||
/* */
|
||
/* Returns: */
|
||
/* Host physical address of window divided by 4 KB */
|
||
/* nextAddress : The address of the next DiskOnChip. */
|
||
/*----------------------------------------------------------------------*/
|
||
static unsigned flDocWindowBaseAddress(byte socketNo, dword lowAddress,
|
||
dword highAddress, dword *nextAddress)
|
||
{
|
||
#ifndef NT5PORT
|
||
FLBoolean stopSearch = FALSE;
|
||
volatile byte deviceSearch;
|
||
dword winSize;
|
||
FLFlash *flash;
|
||
|
||
|
||
#ifdef SEPARATED_CASCADED
|
||
/* This flag is used to seperate the cascaded devices into SEPARATED volumes */
|
||
/* Only the first floor responds therfore once it is found all the others are */
|
||
/* reported without searching */
|
||
|
||
static byte noOfFloors = 0; /* floor counter of the cascaded device */
|
||
static socketOfFirstFloor = 0; /* Number of sockets already found */
|
||
static dword savedNextAddress; /* Next search address (skipping aliases */
|
||
|
||
switch ( noOfFloors )
|
||
{
|
||
case 0 : /* First access to a device */
|
||
socketOfFirstFloor = noOfSockets;
|
||
break;
|
||
|
||
case 1 : /* Last floor of a cascaded device */
|
||
*nextAddress = savedNextAddress;
|
||
|
||
default : /* One of a cascaded device floors */
|
||
docMtdVars[noOfSockets].currentFloor = noOfSockets - socketOfFirstFloor;
|
||
noOfFloors--;
|
||
return((unsigned)(lowAddress >> 12));
|
||
}
|
||
#endif /* SEPARATED_CASCADED */
|
||
|
||
/* if memory range to search for DiskOnChip 2000 window is not specified */
|
||
/* assume the standard x86 PC architecture where DiskOnChip 2000 appears */
|
||
/* in a memory range reserved for BIOS expansions */
|
||
if (lowAddress == 0x0L) {
|
||
lowAddress = START_ADR;
|
||
highAddress = STOP_ADR;
|
||
}
|
||
|
||
flash = flFlashOf(socketNo);
|
||
|
||
#ifndef FL_NO_USE_FUNC
|
||
/* Initialize socket memory access routine */
|
||
if(setBusTypeOfFlash(flash, flBusConfig[socketNo] |
|
||
FL_8BIT_DOC_ACCESS | FL_8BIT_FLASH_ACCESS))
|
||
return ( 0 );
|
||
#endif /* FL_NO_USE_FUNC */
|
||
|
||
winSize = DOC_WIN;
|
||
|
||
/* set all possible controllers to RESET MODE */
|
||
|
||
for(*nextAddress = lowAddress ; *nextAddress <= highAddress ;
|
||
*nextAddress += winSize)
|
||
{
|
||
flash->win = (NDOC2window )physicalToPointer(*nextAddress,winSize,socketNo);
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_RESET_MODE);
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_RESET_MODE);
|
||
}
|
||
|
||
/* set controller (ASIC) to NORMAL MODE and try and detect it */
|
||
*nextAddress = lowAddress; /* current address initialization */
|
||
for( ; *nextAddress <= highAddress; *nextAddress += winSize)
|
||
{
|
||
flash->win = (NDOC2window)physicalToPointer(*nextAddress,winSize,socketNo);
|
||
/* set controller (ASIC) to NORMAL MODE */
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_NORMAL_MODE);
|
||
flWrite8bitReg(flash,NDOCcontrol,ASIC_NORMAL_MODE);
|
||
|
||
if( (flRead8bitReg(flash,NchipId) != CHIP_ID_DOC &&
|
||
flRead8bitReg(flash,NchipId) != CHIP_ID_MDOC))
|
||
{
|
||
if( stopSearch == TRUE ) /* DiskOnChip was found */
|
||
break;
|
||
else continue;
|
||
}
|
||
if( stopSearch == FALSE ) {
|
||
/* detect card - identify bit toggles on consequitive reads */
|
||
if(checkToggle(flash) == FALSE)
|
||
continue;
|
||
/* DiskOnChip found */
|
||
if( flRead8bitReg(flash,NchipId)) {
|
||
flWrite8bitReg(flash,NaliasResolution,ALIAS_RESOLUTION);
|
||
}
|
||
else {
|
||
flWrite8bitReg(flash,NdeviceSelector,ALIAS_RESOLUTION);
|
||
}
|
||
stopSearch = TRUE;
|
||
lowAddress = *nextAddress; /* save DiskOnChip address */
|
||
}
|
||
else { /* DiskOnChip found, continue to skip aliases */
|
||
if( (flRead8bitReg(flash,NchipId) != CHIP_ID_DOC) &&
|
||
(flRead8bitReg(flash,NchipId) != CHIP_ID_MDOC) )
|
||
break;
|
||
/* detect card - identify bit toggles on consequitive reads */
|
||
if(checkToggle(flash) == FALSE)
|
||
break;
|
||
/* check for Alias */
|
||
deviceSearch = (byte)((flRead8bitReg(flash,NchipId) == CHIP_ID_MDOC) ?
|
||
flRead8bitReg(flash,NaliasResolution) :
|
||
flRead8bitReg(flash,NdeviceSelector));
|
||
if( deviceSearch != ALIAS_RESOLUTION )
|
||
break;
|
||
}
|
||
}
|
||
if( stopSearch == FALSE ) /* DiskOnChip 2000 memory window not found */
|
||
return( 0 );
|
||
|
||
#ifdef SEPARATED_CASCADED
|
||
/* count the number of floors cascaded to this address */
|
||
|
||
flash->win = (NDOC2window)physicalToPointer(lowAddress,winSize,socketNo);
|
||
for ( noOfFloors=1; noOfFloors < MAX_FLASH_DEVICES_DOC ;noOfFloors++)
|
||
{
|
||
flWrite8bitReg(flash,NASICselect,noOfFloors);
|
||
if(checkToggle(flash) == FALSE)
|
||
break;
|
||
}
|
||
/* If there are more then 1 floor on this address save the next device address and report
|
||
that the next device is actualy on the same address as the current */
|
||
|
||
if ( noOfFloors > 1)
|
||
{
|
||
flWrite8bitReg(flash,NASICselect,0);
|
||
savedNextAddress = *nextAddress;
|
||
*nextAddress = lowAddress;
|
||
}
|
||
noOfFloors--;
|
||
#endif /* SEPARATED_CASCADED */
|
||
return((unsigned)(lowAddress >> 12));
|
||
#else /*NT5PORT*/
|
||
DEBUG_PRINT(("Tffsport mdocplus.c :flDocWindowBaseAddress(): Before returning baseAddress()\n"));
|
||
return (unsigned)(((ULONG_PTR)pdriveInfo[socketNo].winBase)>> 12);
|
||
#endif /*NT5PORT*/
|
||
|
||
}
|
||
/*----------------------------------------------------------------------*/
|
||
/* s e t A d d r e s s */
|
||
/* */
|
||
/* Latch address to selected flash device. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : address to set. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void setAddress (FLFlash * flash, CardAddress address)
|
||
{
|
||
address &= (flash->chipSize * flash->interleaving - 1); /* address within flash device */
|
||
|
||
#ifdef BIG_PAGE_ENABLED
|
||
if ( flash->flags & BIG_PAGE )
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
{
|
||
/*
|
||
bits 0..7 stays as are
|
||
bit 8 is thrown away from address
|
||
bits 31..9 -> bits 30..8
|
||
*/
|
||
address = ((address >> 9) << 8) | ((byte)address);
|
||
}
|
||
|
||
writeSignals (flash, FLASH_IO | ALE | CE);
|
||
|
||
#ifdef SLOW_IO_FLAG
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)address);
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)address);
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)(address >> 8));
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(address >> 8));
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)(address >> 16));
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(address >> 16));
|
||
if( flash->flags & BIG_ADDR ) {
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)(address >> 24));
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(address >> 24));
|
||
}
|
||
#else
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)address);
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(address >> 8));
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(address >> 16));
|
||
if( flash->flags & BIG_ADDR )
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(address >> 24));
|
||
#endif
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,(Reg8bitType)0);
|
||
|
||
writeSignals (flash, ECC_IO | FLASH_IO | CE);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* c o m m a n d */
|
||
/* */
|
||
/* Latch command byte to selected flash device. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* code : Command to set. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void command(FLFlash * flash, Reg8bitType flCode)
|
||
{
|
||
writeSignals (flash, FLASH_IO | CLE | CE);
|
||
|
||
#ifdef SLOW_IO_FLAG
|
||
flWrite8bitReg(flash,NslowIO,flCode);
|
||
#endif
|
||
|
||
flWrite8bitReg(flash,NFDC21thisIO,flCode);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,flCode);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* s e l e c t F l o o r */
|
||
/* */
|
||
/* Select floor (0 .. totalFloors-1). */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : Select floor for this address. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
#ifndef SEPARATED_CASCADED
|
||
|
||
static void selectFloor (FLFlash * flash, CardAddress *address)
|
||
{
|
||
if( flash->noOfFloors > 1 )
|
||
{
|
||
byte floorToUse = (byte)((*address) / NFDC21thisVars->floorSize);
|
||
|
||
NFDC21thisVars->currentFloor = floorToUse;
|
||
flWrite8bitReg(flash,NASICselect,floorToUse);
|
||
*address -= (floorToUse * NFDC21thisVars->floorSize);
|
||
}
|
||
}
|
||
|
||
#endif /* SEPARATED_CASCADED */
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* m a p W i n */
|
||
/* */
|
||
/* Map window to selected flash device. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : Map window to this address. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void mapWin (FLFlash * flash, CardAddress *address)
|
||
{
|
||
/* NOTE: normally both ways to obtain DOC 2000 window segment should
|
||
return the same value. */
|
||
NFDC21thisWin = (NDOC2window)flMap(flash->socket, 0);
|
||
#ifndef SEPARATED_CASCADED
|
||
selectFloor (flash, address);
|
||
#else
|
||
flWrite8bitReg(flash,NASICselect,NFDC21thisVars->currentFloor);
|
||
#endif /* SEPARATED_CASCADED */
|
||
/* select chip within floor */
|
||
selectChip (flash, (Reg8bitType)((*address) / (flash->chipSize * flash->interleaving))) ;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* r d B u f */
|
||
/* */
|
||
/* Auxiliary routine for Read(), read from page. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* buf : Buffer to read into. */
|
||
/* howmany : Number of bytes to read. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void rdBuf (FLFlash * flash, byte FAR1 *buf, word howmany)
|
||
{
|
||
volatile Reg8bitType junk = 0;
|
||
register word i;
|
||
#ifdef SLOW_IO_FLAG
|
||
/* slow flash requires first read to be done from CDSN_Slow_IO
|
||
and only second one from CDSN_IO - this extends read access */
|
||
|
||
for( i = 0 ;( i < howmany ); i++ ) {
|
||
junk = flRead8bitReg(flash,NslowIO);
|
||
buf[i] = (byte)flRead8bitReg(flash,NFDC21thisIO+(i & 0x01));
|
||
}
|
||
#else
|
||
if( NFDC21thisVars->flags & MDOC_ASIC ) {
|
||
junk += flRead8bitReg(flash,NreadPipeInit);
|
||
howmany--;
|
||
i = TFFSMIN( howmany, MDOC_ALIAS_RANGE );
|
||
docread(flash->win,NFDC21thisIO,buf,i);
|
||
}
|
||
else i = 0;
|
||
if( howmany > i )
|
||
docread(flash->win,NFDC21thisIO,buf+i,(word)(howmany-i));
|
||
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
buf[howmany] = flRead8bitReg(flash,NreadLastData);
|
||
#endif
|
||
}
|
||
#ifndef FL_READ_ONLY
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* w r B u f */
|
||
/* */
|
||
/* Auxiliary routine for Write(), write to page from buffer. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* buf : Buffer to write from. */
|
||
/* howmany : Number of bytes to write. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void wrBuf (FLFlash * flash, const byte FAR1 *buf, word howmany )
|
||
{
|
||
#ifdef SLOW_IO_FLAG
|
||
register int i;
|
||
/* slow flash requires first write go to CDSN_Slow_IO and
|
||
only second one to CDSN_IO - this extends write access */
|
||
|
||
for ( i = 0 ;( i < howmany ); i++ ) {
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)buf[i]);
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)buf[i]);
|
||
}
|
||
#else
|
||
docwrite(flash->win,NFDC21thisIO,(byte FAR1 *)buf,howmany);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,(Reg8bitType)0);
|
||
#endif
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* w r S e t */
|
||
/* */
|
||
/* Auxiliary routine for Write(), set page data. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* ch : Set page to this byte */
|
||
/* howmany : Number of bytes to set. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void wrSet (FLFlash * flash, const Reg8bitType ch, word howmany )
|
||
{
|
||
#ifdef SLOW_IO_FLAG
|
||
register int i;
|
||
/* slow flash requires first write go to CDSN_Slow_IO and
|
||
only second one to CDSN_IO - this extends write access */
|
||
|
||
for (i = 0 ;( i < howmany ); i++ ) {
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)ch);
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)ch);
|
||
}
|
||
#else
|
||
docset(flash->win,NFDC21thisIO,howmany,ch);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,(Reg8bitType)0);
|
||
#endif
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* r e a d S t a t u s */
|
||
/* */
|
||
/* Read status of selected flash device. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/* Returns: */
|
||
/* Chip status. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static Reg8bitType readStatus (FLFlash * flash)
|
||
{
|
||
Reg8bitType chipStatus;
|
||
volatile Reg8bitType junk = 0;
|
||
|
||
flWrite8bitReg(flash,NFDC21thisIO,READ_STATUS);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,READ_STATUS);
|
||
writeSignals (flash, FLASH_IO | CE | WP);
|
||
|
||
if( NFDC21thisVars->flags & MDOC_ASIC ) {
|
||
junk += flRead8bitReg(flash,NreadPipeInit); /* load first data into pipeline */
|
||
chipStatus = flRead8bitReg(flash,NreadLastData); /* read flash status */
|
||
}
|
||
else {
|
||
junk += flRead8bitReg(flash,NslowIO);
|
||
chipStatus = flRead8bitReg(flash,NFDC21thisIO);
|
||
}
|
||
return chipStatus;
|
||
}
|
||
#endif /* FL_READ_ONLY */
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* r e a d C o m m a n d */
|
||
/* */
|
||
/* Issue read command. */
|
||
/* */
|
||
/* Parametes: */
|
||
/* flash : Pointer identifying drive */
|
||
/* cmd : Command to issue (according to area). */
|
||
/* addr : address to read from. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void readCommand (FLFlash * flash, PointerOp cmd, CardAddress addr)
|
||
{
|
||
command (flash, (Reg8bitType)cmd); /* move flash pointer to respective area of the page */
|
||
setAddress (flash, addr);
|
||
waitForReady(flash);
|
||
}
|
||
#ifndef FL_READ_ONLY
|
||
/*----------------------------------------------------------------------*/
|
||
/* w r i t e C o m m a n d */
|
||
/* */
|
||
/* Issue write command. */
|
||
/* */
|
||
/* Parametes: */
|
||
/* flash : Pointer identifying drive */
|
||
/* cmd : Command to issue (according to area). */
|
||
/* addr : address to write to. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void writeCommand (FLFlash * flash, PointerOp cmd, CardAddress addr)
|
||
{
|
||
if( flash->flags & FULL_PAGE ) {
|
||
command (flash, RESET_FLASH);
|
||
waitForReady(flash);
|
||
if( cmd != AREA_A ) {
|
||
#ifdef SLOW_IO_FLAG
|
||
flWrite8bitReg(flash,NslowIO,(byte)cmd);
|
||
#endif
|
||
flWrite8bitReg(flash,NFDC21thisIO,(byte)cmd);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,(byte)cmd);
|
||
}
|
||
}
|
||
else
|
||
command (flash, (Reg8bitType)cmd); /* move flash pointer to respective area of the page */
|
||
|
||
#ifdef SLOW_IO_FLAG
|
||
flWrite8bitReg(flash,NslowIO,SERIAL_DATA_INPUT);
|
||
#endif
|
||
|
||
flWrite8bitReg(flash,NFDC21thisIO,SERIAL_DATA_INPUT);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,SERIAL_DATA_INPUT);
|
||
|
||
setAddress (flash, addr);
|
||
|
||
waitForReady(flash);
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* w r i t e E x e c u t e */
|
||
/* */
|
||
/* Execute write. */
|
||
/* */
|
||
/* Parametes: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, otherwise failed. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus writeExecute (FLFlash * flash)
|
||
{
|
||
command (flash, SETUP_WRITE); /* execute page program */
|
||
waitForReady(flash);
|
||
|
||
if( readStatus(flash) & (byte)(FAIL) ) {
|
||
DEBUG_PRINT(("Debug: NFDC 2148 write failed.\r\n"));
|
||
return( flWriteFault );
|
||
}
|
||
|
||
return( flOK );
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* w r i t e O n e S e c t o r */
|
||
/* */
|
||
/* Write data in one 512-byte block to flash. */
|
||
/* Assuming that EDC mode never requested on partial block writes. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : Address of sector to write to. */
|
||
/* buffer : buffer to write from. */
|
||
/* length : number of bytes to write (up to sector size). */
|
||
/* modes : OVERWRITE, EDC flags etc. */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, otherwise failed. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus writeOneSector(FLFlash * flash,
|
||
CardAddress address,
|
||
const void FAR1 *buffer,
|
||
word length,
|
||
word modes)
|
||
{
|
||
byte FAR1 *pbuffer = (byte FAR1 *)buffer; /* to write from */
|
||
FLStatus status;
|
||
#ifndef NO_EDC_MODE
|
||
byte syndrom[SYNDROM_BYTES];
|
||
static byte anandMark[2] = { 0x55, 0x55 };
|
||
#endif
|
||
PointerOp cmd = AREA_A ;
|
||
word prePad;
|
||
#ifdef BIG_PAGE_ENABLED
|
||
word toFirstPage = 0, toSecondPage = 0;
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
|
||
#ifndef MTD_STANDALONE
|
||
if (flWriteProtected(flash->socket))
|
||
return( flWriteProtect );
|
||
#endif
|
||
|
||
mapWin(flash, &address); /* select flash device */
|
||
|
||
/* move flash pointer to areas A,B or C of page */
|
||
makeCommand(flash, &cmd, &address, modes);
|
||
|
||
if( (flash->flags & FULL_PAGE) && (cmd == AREA_B) ) {
|
||
prePad = (word)(2 + ((word) address & NFDC21thisVars->pageMask));
|
||
writeCommand(flash, AREA_A, address + NFDC21thisVars->pageAreaSize - prePad);
|
||
wrSet(flash, 0xFF, prePad);
|
||
}
|
||
else
|
||
writeCommand(flash, cmd, address);
|
||
|
||
#ifndef NO_EDC_MODE
|
||
if( modes & EDC )
|
||
eccONwrite(flash); /* ECC ON for write */
|
||
#endif
|
||
|
||
#ifdef BIG_PAGE_ENABLED
|
||
if( !(flash->flags & BIG_PAGE) ) /* 2M on INLV=1 */
|
||
{
|
||
/* write up to two pages separately */
|
||
if( modes & EXTRA )
|
||
toFirstPage = EXTRA_LEN - ((word)address & (EXTRA_LEN-1));
|
||
else
|
||
toFirstPage = CHIP_PAGE_SIZE - ((word)address & (CHIP_PAGE_SIZE-1));
|
||
|
||
if(toFirstPage > length)
|
||
toFirstPage = length;
|
||
toSecondPage = length - toFirstPage;
|
||
|
||
wrBuf(flash, pbuffer, toFirstPage); /* starting page .. */
|
||
|
||
if ( toSecondPage > 0 )
|
||
{
|
||
if (toFirstPage > 0) /* started on 1st page */
|
||
checkStatus( writeExecute(flash) ); /* done with 1st page */
|
||
if( modes & EXTRA )
|
||
address -= (CHIP_PAGE_SIZE + ((word)address & (EXTRA_LEN-1)));
|
||
writeCommand(flash, cmd, address + toFirstPage);
|
||
wrBuf (flash, pbuffer + toFirstPage, toSecondPage); /* user data */
|
||
}
|
||
}
|
||
else /* 4M or 8M */
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
|
||
wrBuf (flash, pbuffer, length); /* user data */
|
||
|
||
#ifndef NO_EDC_MODE
|
||
if(modes & EDC)
|
||
{
|
||
register int i;
|
||
|
||
writeSignals (flash, ECC_IO | CE ); /* disable flash access */
|
||
/* 3 dummy zero-writes to clock the data through pipeline */
|
||
if( NFDC21thisVars->flags & MDOC_ASIC ) {
|
||
for( i = 0;( i < 3 ); i++ ) {
|
||
flWrite8bitReg(flash,NNOPreg,(Reg8bitType)0);
|
||
}
|
||
}
|
||
else {
|
||
wrSet (flash, 0x00, 3 );
|
||
}
|
||
writeSignals (flash, ECC_IO | FLASH_IO | CE ); /* enable flash access */
|
||
|
||
docread(flash->win,Nsyndrom,syndrom,SYNDROM_BYTES);
|
||
#ifdef D2TST
|
||
tffscpy(saveSyndromForDumping,syndrom,SYNDROM_BYTES);
|
||
#endif
|
||
eccOFF(flash); /* ECC OFF */
|
||
|
||
wrBuf (flash, (const byte FAR1 *)syndrom, SYNDROM_BYTES);
|
||
|
||
wrBuf (flash, (const byte FAR1 *)anandMark, sizeof(anandMark) );
|
||
}
|
||
#endif /* NO_EDC_MODE */
|
||
|
||
status = writeExecute(flash); /* abort if write failure */
|
||
if(status != flOK)
|
||
return status;
|
||
|
||
writeSignals(flash, FLASH_IO | WP);
|
||
|
||
#ifdef VERIFY_WRITE
|
||
|
||
#ifndef MTD_STANDALONE
|
||
if (flash->socket->verifyWrite==FL_OFF)
|
||
return status;
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
/* Read back after write and verify */
|
||
|
||
if( modes & OVERWRITE )
|
||
pbuffer = (byte FAR1 *) buffer; /* back to original data */
|
||
|
||
readCommand (flash, cmd, address); /* move flash pointer to areas A,B or C of page */
|
||
|
||
#ifdef BIG_PAGE_ENABLED
|
||
|
||
if( !(flash->flags & BIG_PAGE) )
|
||
{
|
||
rdBuf (flash, NFDC21thisVars->readBackBuffer, toFirstPage);
|
||
|
||
if(tffscmp (pbuffer, NFDC21thisVars->readBackBuffer, toFirstPage) ) {
|
||
DEBUG_PRINT(("Debug: NFDC 2148 write failed in verification.\r\n"));
|
||
return( flWriteFault );
|
||
}
|
||
|
||
if ( toSecondPage > 0 )
|
||
{
|
||
readCommand (flash, AREA_A, address + toFirstPage);
|
||
|
||
rdBuf (flash, NFDC21thisVars->readBackBuffer + toFirstPage, toSecondPage);
|
||
|
||
if( tffscmp (pbuffer + toFirstPage, NFDC21thisVars->readBackBuffer + toFirstPage, toSecondPage)) {
|
||
DEBUG_PRINT(("Debug: NFDC 2148 write failed in verification.\r\n"));
|
||
return( flWriteFault );
|
||
}
|
||
}
|
||
}
|
||
else
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
{
|
||
rdBuf (flash, NFDC21thisVars->readBackBuffer, length);
|
||
|
||
if( tffscmp (pbuffer, NFDC21thisVars->readBackBuffer, length) ) {
|
||
DEBUG_PRINT(("Debug: NFDC 2148 write failed in verification.\r\n"));
|
||
return( flWriteFault );
|
||
}
|
||
}
|
||
/* then ECC and special ANAND mark */
|
||
|
||
#ifndef NO_EDC_MODE
|
||
if( modes & EDC )
|
||
{
|
||
rdBuf (flash, NFDC21thisVars->readBackBuffer, SYNDROM_BYTES);
|
||
if( tffscmp (syndrom, NFDC21thisVars->readBackBuffer, SYNDROM_BYTES) )
|
||
return( flWriteFault );
|
||
|
||
rdBuf (flash, NFDC21thisVars->readBackBuffer, sizeof(anandMark));
|
||
if( tffscmp (anandMark, NFDC21thisVars->readBackBuffer, sizeof(anandMark)) )
|
||
return( flWriteFault );
|
||
}
|
||
#endif /* NO_EDC_MODE */
|
||
|
||
writeSignals (flash, FLASH_IO | WP);
|
||
waitForReady(flash); /* Serial Read Cycle Entry */
|
||
#endif /* VERIFY_WRITE */
|
||
|
||
return( flOK );
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* d o c 2 W r i t e */
|
||
/* */
|
||
/* Write some data to the flash. This routine will be registered as the */
|
||
/* write routine for this MTD. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : Address of sector to write to. */
|
||
/* buffer : buffer to write from. */
|
||
/* length : number of bytes to write (up to sector size). */
|
||
/* modes : OVERWRITE, EDC flags etc. */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, otherwise failed. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus doc2Write(FLFlash * flash,
|
||
CardAddress address,
|
||
const void FAR1 *buffer,
|
||
dword length,
|
||
word modes)
|
||
{
|
||
char FAR1 *temp = (char FAR1 *)buffer;
|
||
FLStatus status;
|
||
#ifdef BIG_PAGE_ENABLED
|
||
word block = (word)((modes & EXTRA) ? EXTRA_LEN : SECTOR_SIZE);
|
||
#else
|
||
word block = (word)((modes & EXTRA) ? SECTOR_EXTRA_LEN : SECTOR_SIZE);
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
word writeNow = block - ((word)address & (block - 1));
|
||
|
||
#ifdef ENVIRONMENT_VARS
|
||
if(flSuspendMode & FL_SUSPEND_WRITE)
|
||
return flIOCommandBlocked;
|
||
#endif /* ENVIRONMENT_VARS */
|
||
|
||
/* write in BLOCKs; first and last might be partial */
|
||
chkASICmode(flash);
|
||
|
||
while( length > 0 )
|
||
{
|
||
if(writeNow > length)
|
||
writeNow = (word)length;
|
||
/* turn off EDC on partial block write */
|
||
|
||
status = writeOneSector(flash, address, temp, writeNow,
|
||
(word)((writeNow != SECTOR_SIZE) ? (modes &= ~EDC) : modes) );
|
||
if(status!=flOK)
|
||
return status;
|
||
|
||
length -= writeNow;
|
||
address += writeNow;
|
||
temp += writeNow;
|
||
writeNow = block; /* align at BLOCK */
|
||
}
|
||
return( flOK );
|
||
}
|
||
#endif /* FL_READ_ONLY */
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* r e a d O n e S e c t o r */
|
||
/* */
|
||
/* Read up to one 512-byte block from flash. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : Address to read from. */
|
||
/* buffer : buffer to read to. */
|
||
/* length : number of bytes to read (up to sector size). */
|
||
/* modes : EDC flag etc. */
|
||
/* */
|
||
/* Notes: big_page_enabled does not support PARTIAL_EDC FLAG */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, otherwise failed. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus readOneSector (FLFlash * flash,
|
||
CardAddress address,
|
||
void FAR1 *buffer,
|
||
word length,
|
||
word modes)
|
||
{
|
||
#ifndef NO_EDC_MODE
|
||
byte extraBytes[SYNDROM_BYTES];
|
||
#ifdef MTD_STANDALONE
|
||
int index;
|
||
#endif
|
||
#endif
|
||
FLStatus stat = flOK;
|
||
PointerOp cmd = AREA_A; /* default for .... */
|
||
CardAddress addr = address; /* .... KM29N16000 */
|
||
#ifdef BIG_PAGE_ENABLED
|
||
int toFirstPage, toSecondPage;
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
|
||
mapWin(flash, &addr);
|
||
|
||
makeCommand(flash, &cmd, &addr, modes); /* move flash pointer to areas A,B or C of page */
|
||
|
||
readCommand(flash, cmd, addr);
|
||
|
||
#ifndef NO_EDC_MODE
|
||
if( modes & EDC )
|
||
eccONread(flash);
|
||
#endif
|
||
#ifdef BIG_PAGE_ENABLED
|
||
if( !(flash->flags & BIG_PAGE) )
|
||
{
|
||
/* read up to two pages separately */
|
||
if( modes & EXTRA )
|
||
toFirstPage = EXTRA_LEN - ((word)addr & (EXTRA_LEN-1));
|
||
else
|
||
toFirstPage = CHIP_PAGE_SIZE - ((word)addr & (CHIP_PAGE_SIZE-1));
|
||
|
||
if(toFirstPage > length)
|
||
toFirstPage = length;
|
||
toSecondPage = length - toFirstPage;
|
||
|
||
rdBuf (flash, (byte FAR1 *)buffer, toFirstPage ); /* starting page */
|
||
|
||
if ( toSecondPage > 0 ) /* next page */
|
||
{
|
||
if( modes & EXTRA )
|
||
addr -= (CHIP_PAGE_SIZE + ((word)addr & (EXTRA_LEN-1)));
|
||
readCommand (flash, cmd, addr + toFirstPage);
|
||
rdBuf(flash, (byte FAR1 *)buffer + toFirstPage, toSecondPage );
|
||
}
|
||
}
|
||
else
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
{
|
||
rdBuf(flash, (byte FAR1 *)buffer, length );
|
||
|
||
#ifndef NO_EDC_MODE
|
||
if((modes & PARTIAL_EDC) &&
|
||
(((word)address & NFDC21thisVars->pageMask) == 0))
|
||
{
|
||
/* Partial page read with EDC must let rest of page through
|
||
the HW edc mechanism */
|
||
|
||
word unreadBytes;
|
||
|
||
for (unreadBytes = SECTOR_SIZE - length;unreadBytes > 0;unreadBytes--)
|
||
{
|
||
cmd = (PointerOp)flRead8bitReg(flash, NFDC21thisIO);
|
||
}
|
||
}
|
||
#endif /* NO_EDC_MODE */
|
||
}
|
||
|
||
#ifndef NO_EDC_MODE
|
||
if( modes & EDC )
|
||
{ /* read syndrom to let it through the ECC unit */
|
||
|
||
rdBuf(flash, extraBytes, SYNDROM_BYTES );
|
||
|
||
if( eccError(flash) ) /* An EDC error was found */
|
||
{
|
||
#ifdef MTD_STANDALONE
|
||
/* Check if all of the EDC bytes are FF's. If so ignore the EDC */
|
||
/* assuming that it has'nt been used due to programing of less then */
|
||
/* 512 bytes */
|
||
|
||
for(index=0;index<SYNDROM_BYTES;index++)
|
||
{
|
||
if (extraBytes[index]!=0xFF)
|
||
break;
|
||
}
|
||
|
||
if (index!=SYNDROM_BYTES) /* not all of the EDC bytes are FF's */
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
{
|
||
/* try to fix ECC error */
|
||
if ( modes & NO_SECOND_TRY ) /* 2nd try */
|
||
{
|
||
byte syndrom[SYNDROM_BYTES];
|
||
byte tmp;
|
||
|
||
docread(flash->win,Nsyndrom,syndrom,SYNDROM_BYTES);
|
||
tmp = syndrom[0]; /* Swap 1 and 3 words */
|
||
syndrom[0] = syndrom[4];
|
||
syndrom[4] = tmp;
|
||
tmp = syndrom[1];
|
||
syndrom[1] = syndrom[5];
|
||
syndrom[5] = tmp;
|
||
|
||
if( flCheckAndFixEDC( (char FAR1 *)buffer, (char*)syndrom, 1) != NO_EDC_ERROR)
|
||
{
|
||
DEBUG_PRINT(("Debug: EDC error for NFDC 2148.\r\n"));
|
||
stat = flDataError;
|
||
}
|
||
}
|
||
else /* 1st try - try once more */
|
||
return( readOneSector( flash, address, buffer, length,
|
||
(word)(modes | NO_SECOND_TRY) ) );
|
||
}
|
||
}
|
||
eccOFF(flash);
|
||
}
|
||
#endif /* NO_EDC_MODE */
|
||
|
||
writeSignals (flash, FLASH_IO | WP);
|
||
if( (modes & EXTRA) && /* Serial Read Cycle Entry */
|
||
((length + (((word)addr) & (NFDC21thisVars->tailSize - 1)))
|
||
== NFDC21thisVars->tailSize) )
|
||
waitForReady(flash);
|
||
|
||
return( stat );
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* d o c 2 R e a d */
|
||
/* */
|
||
/* Read some data from the flash. This routine will be registered as */
|
||
/* the read routine for this MTD. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : Address to read from. */
|
||
/* buffer : buffer to read to. */
|
||
/* length : number of bytes to read (up to sector size). */
|
||
/* modes : EDC flag etc. */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, otherwise failed. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus doc2Read(FLFlash * flash,
|
||
CardAddress address,
|
||
void FAR1 *buffer,
|
||
dword length,
|
||
word modes)
|
||
{
|
||
char FAR1 *temp = (char FAR1 *)buffer;
|
||
FLStatus status;
|
||
word readNow;
|
||
|
||
#ifdef BIG_PAGE_ENABLED
|
||
word block = (word)(( modes & EXTRA ) ? EXTRA_LEN : SECTOR_SIZE );
|
||
#else
|
||
word block = (word)(( modes & EXTRA ) ? SECTOR_EXTRA_LEN : SECTOR_SIZE );
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
|
||
#ifdef ENVIRONMENT_VARS
|
||
if((flSuspendMode & FL_SUSPEND_IO) == FL_SUSPEND_IO)
|
||
return flIOCommandBlocked;
|
||
#endif /* ENVIRONMENT_VARS */
|
||
|
||
chkASICmode(flash);
|
||
/* read in BLOCKs; first and last might be partial */
|
||
|
||
readNow = block - ((word)address & (block - 1));
|
||
|
||
while( length > 0 ) {
|
||
if( readNow > length )
|
||
readNow = (word)length;
|
||
/* turn off EDC on partial block read */
|
||
status = readOneSector(flash, address, temp, readNow, (word)(
|
||
((readNow != SECTOR_SIZE) && (modes != PARTIAL_EDC)) ?
|
||
modes &=~PARTIAL_EDC : modes));
|
||
if(status != flOK)
|
||
return status;
|
||
|
||
length -= readNow;
|
||
address += readNow;
|
||
temp += readNow;
|
||
readNow = block; /* align at BLOCK */
|
||
}
|
||
return( flOK );
|
||
}
|
||
|
||
#ifndef FL_READ_ONLY
|
||
|
||
#if (defined(VERIFY_ERASE) || defined(MTD_RECONSTRUCT_BBT))
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* c h e c k E r a s e */
|
||
/* */
|
||
/* Check if media is truly erased (main areas of page only). */
|
||
/* */
|
||
/* Note to save on memory consumption the 1k read back buffer is used */
|
||
/* Only when the VERIFY_ERASE compilation flag is set. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : Address of page to check. */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 if page is erased, otherwise writeFault. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus checkErase( FLFlash * flash, CardAddress address )
|
||
{
|
||
register int i, j;
|
||
word inc = READ_BACK_BUFFER_SIZE;
|
||
dword * bufPtr = (dword *)NFDC21thisVars->readBackBuffer;
|
||
CardAddress curAddress = address;
|
||
word block = (word)(flash->erasableBlockSize / inc);
|
||
dword * endBufPtr = bufPtr+(inc / sizeof(dword));
|
||
dword * curBufPtr;
|
||
|
||
/* Check main area */
|
||
for ( i = 0 ; i < block ; i++, curAddress += inc )
|
||
{
|
||
if ( doc2Read(flash,curAddress,(void FAR1 *)bufPtr,(dword)inc,0) != flOK )
|
||
return( flWriteFault );
|
||
|
||
for ( curBufPtr = bufPtr ;
|
||
curBufPtr < endBufPtr ; curBufPtr++)
|
||
if ( *bufPtr != 0xFFFFFFFFL )
|
||
return( flWriteFault );
|
||
}
|
||
|
||
/* Check extra area */
|
||
for ( i = 0 ; i < NFDC21thisVars->pagesPerBlock ; i++,address+=SECTOR_SIZE)
|
||
{
|
||
if ( doc2Read(flash,address,(void FAR1 *)bufPtr,
|
||
NFDC21thisVars->tailSize, EXTRA) != flOK )
|
||
return( flWriteFault );
|
||
|
||
for (j=0;j<(NFDC21thisVars->tailSize>>2);j++)
|
||
{
|
||
if (bufPtr[j] != 0xFFFFFFFFL)
|
||
return( flWriteFault );
|
||
}
|
||
}
|
||
return( flOK );
|
||
}
|
||
|
||
#endif /* VERIFY_ERASE or MTD_RECONSTRUCT_BBT */
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* d o c 2 E r a s e */
|
||
/* */
|
||
/* Erase number of blocks. This routine will be registered as the */
|
||
/* erase routine for this MTD. */
|
||
/* */
|
||
/* Note - can not erase all units of 1GB DiskOnChip. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* blockNo : First block to erase. */
|
||
/* blocksToErase : Number of blocks to erase. */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, otherwise failed. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLStatus doc2Erase(FLFlash * flash,
|
||
word blockNo,
|
||
word blocksToErase)
|
||
{
|
||
FLStatus status = flOK;
|
||
word floorToUse;
|
||
word nextFloorBlockNo, i;
|
||
CardAddress startAddress = (CardAddress)blockNo * flash->erasableBlockSize;
|
||
CardAddress address = startAddress;
|
||
|
||
#ifdef ENVIRONMENT_VARS
|
||
if(flSuspendMode & FL_SUSPEND_WRITE)
|
||
return flIOCommandBlocked;
|
||
#endif /* ENVIRONMENT_VARS */
|
||
|
||
#ifndef MTD_STANDALONE
|
||
if (flWriteProtected(flash->socket))
|
||
return( flWriteProtect );
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
if( (dword)((dword)blockNo + (dword)blocksToErase) >
|
||
(dword)((dword)NFDC21thisVars->noOfBlocks * (dword)flash->noOfChips))
|
||
return( flWriteFault ); /* out of media */
|
||
|
||
chkASICmode(flash);
|
||
/* handle erase accross floors */
|
||
#ifndef SEPARATED_CASCADED
|
||
floorToUse = (word)(startAddress / NFDC21thisVars->floorSize) + 1;
|
||
|
||
if (floorToUse != flash->noOfFloors)
|
||
{
|
||
nextFloorBlockNo = (word)(floorToUse * (NFDC21thisVars->floorSize /
|
||
flash->erasableBlockSize));
|
||
|
||
if( blockNo + blocksToErase > nextFloorBlockNo )
|
||
{ /* erase on higher floors */
|
||
status = ( doc2Erase( flash, nextFloorBlockNo,
|
||
(word)(blocksToErase - (nextFloorBlockNo - blockNo))) );
|
||
blocksToErase = nextFloorBlockNo - blockNo;
|
||
if(status!=flOK)
|
||
return status;
|
||
}
|
||
}
|
||
#endif /* SEPARATED_CASCADED */
|
||
|
||
/* erase on this floor */
|
||
|
||
mapWin (flash, &address);
|
||
|
||
for (i = 0; i < blocksToErase ; i++, blockNo++ ) {
|
||
dword pageNo = ((dword)blockNo * NFDC21thisVars->pagesPerBlock);
|
||
|
||
command(flash, RESET_FLASH);
|
||
writeSignals (flash, FLASH_IO | CE);
|
||
waitForReady(flash);
|
||
|
||
command(flash, SETUP_ERASE);
|
||
|
||
writeSignals (flash, FLASH_IO | ALE | CE);
|
||
#ifdef SLOW_IO_FLAG
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)pageNo);
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)pageNo);
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)(pageNo >> 8));
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(pageNo >> 8));
|
||
if( flash->flags & BIG_ADDR ) {
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)(pageNo >> 16));
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(pageNo >> 16));
|
||
}
|
||
#else
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)pageNo);
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(pageNo >> 8));
|
||
if( flash->flags & BIG_ADDR )
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)(pageNo >> 16));
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,(Reg8bitType)0);
|
||
#endif /* SLOW_IO_FLAG */
|
||
writeSignals(flash, FLASH_IO | CE);
|
||
|
||
/* if only one block may be erase at a time then do it */
|
||
/* otherwise leave it for later */
|
||
|
||
command(flash, CONFIRM_ERASE);
|
||
|
||
#ifndef MTD_STANDALONE
|
||
#ifndef DO_NOT_YIELD_CPU
|
||
if(waitForReadyWithYieldCPU(flash,MAX_WAIT)==FALSE)
|
||
#endif /* DO_NOT_YIELD_CPU */
|
||
#endif /* MTD_STANDALONE */
|
||
{
|
||
waitForReady(flash);
|
||
}
|
||
if ( readStatus(flash) & (byte)(FAIL) ) { /* erase operation failed */
|
||
DEBUG_PRINT(("Debug: NFDC 2148 erase failed.\r\n"));
|
||
status = flWriteFault;
|
||
|
||
/* reset flash device and abort */
|
||
|
||
command(flash, RESET_FLASH);
|
||
waitForReady(flash);
|
||
|
||
break;
|
||
}
|
||
else { /* no failure reported */
|
||
#ifdef VERIFY_ERASE
|
||
|
||
if ( checkErase( flash, startAddress + i * flash->erasableBlockSize) != flOK ) {
|
||
DEBUG_PRINT(("Debug: NFDC 2148 erase failed in verification.\r\n"));
|
||
return flWriteFault ;
|
||
}
|
||
|
||
#endif /* VERIFY_ERASE */
|
||
}
|
||
} /* block loop */
|
||
|
||
#ifdef MULTI_ERASE
|
||
/* do multiple block erase as was promised */
|
||
|
||
command(flash, CONFIRM_ERASE);
|
||
#ifndef MTD_STANDALONE
|
||
#ifndef DO_NOT_YIELD_CPU
|
||
waitForReadyWithYieldCPU(flash,MAX_WAIT);
|
||
#endif /* DO_NOT_YIELD_CPU */
|
||
#endif /* MTD_STANDALONE */
|
||
if ( readStatus(flash) & (byte)(FAIL) ) { /* erase operation failed */
|
||
DEBUG_PRINT(("Debug: NFDC 2148 erase failed.\r\n"));
|
||
status = flWriteFault;
|
||
|
||
/* reset flash device and abort */
|
||
|
||
command(flash, RESET_FLASH);
|
||
waitForReady(flash);
|
||
}
|
||
#endif /* MULTI_ERASE */
|
||
|
||
writeSignals (flash, FLASH_IO | WP);
|
||
return( status );
|
||
}
|
||
#endif /* FL_READ_ONLY */
|
||
|
||
#ifndef MTD_STANDALONE
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* d o c 2 M a p */
|
||
/* */
|
||
/* Map through buffer. This routine will be registered as the map */
|
||
/* routine for this MTD. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* address : Flash address to be mapped. */
|
||
/* length : number of bytes to map. */
|
||
/* */
|
||
/* Returns: */
|
||
/* Pointer to the buffer data was mapped to. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static void FAR0 *doc2Map ( FLFlash * flash, CardAddress address, int length )
|
||
{
|
||
doc2Read(flash,address,NFDC21thisBuffer,length, 0);
|
||
/* Force remapping of internal catched sector */
|
||
flash->socket->remapped = TRUE;
|
||
return( (void FAR0 *)NFDC21thisBuffer );
|
||
}
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
#ifdef MTD_READ_BBT
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* R e a d B B T */
|
||
/* */
|
||
/* Read the media Bad Blocks Table to a user buffer. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* unitNo : indicated which unit number to start checking from. */
|
||
/* unitToRead : indicating how many units to check */
|
||
/* buffer : buffer to read into. */
|
||
/* reconstruct : TRUE for reconstruct BBT from virgin card */
|
||
/* */
|
||
/* Note: blocks is a minimal flash erasable area. */
|
||
/* Note: unit can contain several blocks. */
|
||
/* Note: There is no current implementation of a unit that contains */
|
||
/* more then a single block. */
|
||
/* Note: The format of the BBT is byte per unit 0 for bad any other */
|
||
/* value for good. */
|
||
/* Note: global variables changed at doc2Read: */
|
||
/* global variable NFDC21thisVars->currentFloor is updated */
|
||
/* flash->socket.window.currentPage = pageToMap; */
|
||
/* flash->socket.remapped = TRUE; */
|
||
/* Note: At least 4 bytes must be read */
|
||
/* */
|
||
/* RETURNS: */
|
||
/* flOK on success */
|
||
/* flBadLength if one of the units is out of the units range */
|
||
/* flBadBBT on read fault */
|
||
/*----------------------------------------------------------------------*/
|
||
static FLStatus readBBT(FLFlash * flash, dword unitNo, dword unitsToRead,
|
||
byte blockMultiplier, byte FAR1 * buffer,
|
||
FLBoolean reconstruct)
|
||
{
|
||
CardAddress bbtAddr,floorEndAddr;
|
||
CardAddress addr,floorStartAddr,alignAddr;
|
||
dword unitsPerFloor = NFDC21thisVars->floorSize >> flash->erasableBlockSizeBits;
|
||
word curRead,actualRead;
|
||
CardAddress mediaSize = (CardAddress)flash->chipSize*flash->noOfChips;
|
||
FLStatus status = flOK;
|
||
dword unitOffset;
|
||
dword sizeOfBBT;
|
||
word counter;
|
||
|
||
byte FAR1* bufPtr = buffer;
|
||
#if (defined (MTD_RECONSTRUCT_BBT) && !defined(FL_READ_ONLY))
|
||
CardAddress bbtCurAddr;
|
||
dword i;
|
||
byte reconstructBBT = 0;
|
||
#endif /* MTD_RECONSTRUCT_BBT && not FL_READ_ONLY */
|
||
|
||
/* Arg sanity check */
|
||
if (((dword)(unitNo+unitsToRead) <<
|
||
(blockMultiplier+flash->erasableBlockSizeBits)) > mediaSize)
|
||
return flBadParameter;
|
||
|
||
/* Calculate size of BBT blocks */
|
||
for(sizeOfBBT = flash->erasableBlockSize;
|
||
sizeOfBBT < unitsPerFloor ;sizeOfBBT = sizeOfBBT<<1);
|
||
#ifndef MTD_STANDALONE
|
||
/* Force remapping of internal catched sector */
|
||
flash->socket->remapped = TRUE;
|
||
#endif /* MTD_STANDALONE */
|
||
/* Adjust no' of blocks per floor according to blocks multiplier */
|
||
unitsPerFloor = unitsPerFloor >> blockMultiplier;
|
||
/* Mark all user buffer as good units */
|
||
tffsset(buffer,BBT_GOOD_UNIT,unitsToRead);
|
||
|
||
/* Loop over all of the floors */
|
||
for (floorStartAddr = 0 ; (floorStartAddr < mediaSize) && (unitsToRead > 0);
|
||
floorStartAddr += NFDC21thisVars->floorSize)
|
||
{
|
||
floorEndAddr = TFFSMIN(floorStartAddr+NFDC21thisVars->floorSize,mediaSize);
|
||
/* Look for bbt signature in extra area start looking from last unit */
|
||
for(bbtAddr = floorEndAddr - sizeOfBBT,
|
||
counter = BBT_MAX_DISTANCE;
|
||
(bbtAddr > floorStartAddr) && (counter > 0);
|
||
bbtAddr -= flash->erasableBlockSize , counter--)
|
||
{
|
||
status = doc2Read(flash,bbtAddr+8,NFDC21thisBuffer,BBT_SIGN_SIZE,EXTRA);
|
||
if (status != flOK)
|
||
return flBadBBT;
|
||
if(tffscmp(NFDC21thisBuffer,BBT_SIGN,BBT_SIGN_SIZE)==0)
|
||
break;
|
||
}
|
||
|
||
/* No BBT was found virgin card */
|
||
|
||
if((bbtAddr==floorStartAddr) || (counter == 0))
|
||
{
|
||
#if (defined (MTD_RECONSTRUCT_BBT) && !defined(FL_READ_ONLY))
|
||
if (reconstruct == TRUE)
|
||
{
|
||
reconstructBBT++;
|
||
if (reconstructBBT == 1)
|
||
DFORMAT_PRINT(("\rVirgin card rebuilding unit map.\r\n\n"));
|
||
|
||
/* Find good unit for BBT */
|
||
|
||
for(bbtAddr = floorEndAddr - sizeOfBBT ;
|
||
bbtAddr > floorStartAddr ;
|
||
bbtAddr -= flash->erasableBlockSize , status = flOK)
|
||
{
|
||
/* Find enough consequtive units for the BBT */
|
||
for(i=0;(status == flOK)&&(i<sizeOfBBT);i+=flash->erasableBlockSize)
|
||
{
|
||
status = checkErase(flash, bbtAddr+i);
|
||
}
|
||
if(status == flOK)
|
||
break;
|
||
}
|
||
if (bbtAddr == floorStartAddr) /* Could not find place for BBT */
|
||
{
|
||
DFORMAT_PRINT(("Debug: no good block found.\r\n"));
|
||
return flBadBBT;
|
||
}
|
||
|
||
/* Search and mark the entire floor BBT (512 at a time) */
|
||
|
||
bbtCurAddr = bbtAddr;
|
||
for (addr=floorStartAddr;
|
||
addr<floorEndAddr; bbtCurAddr+=SECTOR_SIZE)
|
||
{
|
||
/* Mark all blocks as good */
|
||
tffsset(NFDC21thisBuffer,BBT_GOOD_UNIT,SECTOR_SIZE);
|
||
/* Mark IPL as unused */
|
||
for (i=0;i<SECTOR_SIZE;i++,addr+=flash->erasableBlockSize)
|
||
{
|
||
#ifndef NT5PORT
|
||
DFORMAT_PRINT(("Checking block %u\r",(word)(addr>>flash->erasableBlockSizeBits)));
|
||
#endif// NT5PORT
|
||
/* Bad block table is marked as unavailable */
|
||
if ((addr>=bbtAddr) && (addr<bbtAddr+sizeOfBBT))
|
||
{
|
||
NFDC21thisBuffer[i] = BBT_UNAVAIL_UNIT;
|
||
}
|
||
else /* The unerased blocks are marked as bad */
|
||
{
|
||
if(checkErase(flash, addr) != flOK)
|
||
{
|
||
NFDC21thisBuffer[i] = BBT_BAD_UNIT;
|
||
}
|
||
}
|
||
}
|
||
if(addr == (flash->erasableBlockSize<<SECTOR_SIZE_BITS))
|
||
{
|
||
/* If IPL unit is good mark it as unavailable */
|
||
if(NFDC21thisBuffer[0] != BBT_BAD_UNIT)
|
||
NFDC21thisBuffer[0] = BBT_UNAVAIL_UNIT;
|
||
}
|
||
status = doc2Write(flash,bbtCurAddr,NFDC21thisBuffer,SECTOR_SIZE,EDC);
|
||
if (status != flOK)
|
||
{
|
||
DFORMAT_PRINT(("ERROR - Failed writting bad block table.\r\n"));
|
||
return flBadBBT;
|
||
}
|
||
}
|
||
/* Mark bad blocks table with special mark */
|
||
status = doc2Write(flash,bbtAddr+8,BBT_SIGN, BBT_SIGN_SIZE,EXTRA);
|
||
}
|
||
else
|
||
#endif /* MTD_RECONSTRUCT_BBT && not FL_READ_ONLY */
|
||
{
|
||
return flBadBBT;
|
||
}
|
||
}
|
||
|
||
/* Return only blocks that are in this floor */
|
||
addr = floorStartAddr >> (flash->erasableBlockSizeBits + blockMultiplier);
|
||
|
||
if ((unitNo >= addr) && (unitNo < addr + unitsPerFloor))
|
||
{
|
||
unitOffset = (unitNo % unitsPerFloor);
|
||
curRead = ((word)TFFSMIN(unitsToRead,unitsPerFloor - unitOffset));
|
||
unitsToRead -= curRead;
|
||
|
||
/* Convert to real number of bytes to read and address */
|
||
unitOffset <<= blockMultiplier;
|
||
curRead <<= blockMultiplier;
|
||
alignAddr = ((bbtAddr + unitOffset) >> SECTOR_SIZE_BITS)<<SECTOR_SIZE_BITS;
|
||
|
||
do /* Read and copy into buffer 512 blocks at a time */
|
||
{
|
||
if (doc2Read(flash,alignAddr, NFDC21thisBuffer,SECTOR_SIZE,EDC) != flOK)
|
||
return flBadBBT;
|
||
|
||
unitOffset = unitOffset % SECTOR_SIZE;
|
||
actualRead = (word)TFFSMIN(SECTOR_SIZE - unitOffset,curRead);
|
||
curRead -= actualRead;
|
||
/* Copy relevant blocks into user buffer */
|
||
for (actualRead += (word)unitOffset ;
|
||
unitOffset < actualRead ;
|
||
bufPtr = BYTE_ADD_FAR(bufPtr,1)) /* increment buffer */
|
||
{
|
||
for (counter = 1 << blockMultiplier ; counter > 0 ;
|
||
counter-- , unitOffset++)
|
||
{
|
||
if (NFDC21thisBuffer[unitOffset] != BBT_GOOD_UNIT)
|
||
{
|
||
*bufPtr = NFDC21thisBuffer[unitOffset];
|
||
}
|
||
}
|
||
}
|
||
alignAddr+=SECTOR_SIZE;
|
||
}while(curRead > 0);
|
||
|
||
if (unitsToRead > 0)
|
||
unitNo = addr + unitsPerFloor;
|
||
}
|
||
}
|
||
|
||
#if (defined (MTD_RECONSTRUCT_BBT) && !defined(FL_READ_ONLY))
|
||
if (reconstructBBT > 0)
|
||
DFORMAT_PRINT(("\rMedia has been scanned. \r\n"));
|
||
#endif /* MTD_RECONSTRUCT_BBT && not FL_READ_ONLY */
|
||
|
||
return flOK;
|
||
}
|
||
#endif /* MTD_READ_BBT */
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* i s K n o w n M e d i a */
|
||
/* */
|
||
/* Check if this flash media is supported. Initialize relevant fields */
|
||
/* in data structures. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* vendorId_P : vendor ID read from chip. */
|
||
/* chipId_p : chip ID read from chip. */
|
||
/* dev : dev chips were accessed before this one. */
|
||
/* */
|
||
/* Returns: */
|
||
/* TRUE if this media is supported, FALSE otherwise. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static FLBoolean isKnownMedia( FLFlash * flash, Reg8bitType vendorId_p, Reg8bitType chipId_p, int dev )
|
||
{
|
||
if((dev == 0)
|
||
#ifndef SEPARATED_CASCADED
|
||
&& (NFDC21thisVars->currentFloor == 0)
|
||
#endif /* SEPARATED_CASCADED */
|
||
) { /* First Identification */
|
||
NFDC21thisVars->vendorID = (word)vendorId_p; /* remember for next chips */
|
||
NFDC21thisVars->chipID = (word)chipId_p;
|
||
NFDC21thisVars->pagesPerBlock = PAGES_PER_BLOCK;
|
||
flash->maxEraseCycles = 1000000L;
|
||
flash->flags |= BIG_PAGE;
|
||
flash->pageSize = 0x200;
|
||
switch( (byte)vendorId_p ) {
|
||
case 0xEC : /* Samsung */
|
||
switch( (byte)chipId_p ) {
|
||
#ifdef BIG_PAGE_ENABLED
|
||
case 0x64 : /* 2 Mb */
|
||
case 0xEA :
|
||
flash->type = KM29N16000_FLASH;
|
||
flash->pageSize = 0x100;
|
||
flash->chipSize = 0x200000L;
|
||
flash->flags &= ~BIG_PAGE;
|
||
break;
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
case 0xE3 : /* 4 Mb */
|
||
case 0xE5 :
|
||
flash->type = KM29N32000_FLASH;
|
||
flash->chipSize = 0x400000L;
|
||
break;
|
||
|
||
case 0xE6 : /* 8 Mb */
|
||
flash->type = KM29V64000_FLASH;
|
||
flash->chipSize = 0x800000L;
|
||
break;
|
||
|
||
case 0x73 : /* 16 Mb */
|
||
flash->type = KM29V128000_FLASH;
|
||
flash->chipSize = 0x1000000L;
|
||
NFDC21thisVars->pagesPerBlock *= 2;
|
||
break;
|
||
|
||
case 0x75 : /* 32 Mb */
|
||
flash->type = KM29V256000_FLASH;
|
||
flash->chipSize = 0x2000000L;
|
||
NFDC21thisVars->pagesPerBlock *= 2;
|
||
break;
|
||
|
||
case 0x76 : /* 64 Mb */
|
||
flash->type = KM29V512000_FLASH;
|
||
flash->chipSize = 0x4000000L;
|
||
flash->flags |= BIG_ADDR;
|
||
NFDC21thisVars->pagesPerBlock *= 2;
|
||
break;
|
||
|
||
default : /* Undefined Flash */
|
||
return(FALSE);
|
||
}
|
||
break;
|
||
|
||
case 0x98 : /* Toshiba */
|
||
switch( chipId_p ) {
|
||
#ifdef BIG_PAGE_ENABLED
|
||
case 0x64 : /* 2 Mb */
|
||
case 0xEA :
|
||
flash->type = TC5816_FLASH;
|
||
flash->pageSize = 0x100;
|
||
flash->chipSize = 0x200000L;
|
||
flash->flags &= ~BIG_PAGE;
|
||
break;
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
case 0x6B : /* 4 Mb */
|
||
case 0xE5 :
|
||
flash->type = TC5832_FLASH;
|
||
flash->chipSize = 0x400000L;
|
||
break;
|
||
|
||
case 0xE6 : /* 8 Mb */
|
||
flash->type = TC5864_FLASH;
|
||
flash->chipSize = 0x800000L;
|
||
break;
|
||
|
||
case 0x73 : /* 16 Mb */
|
||
flash->type = TC58128_FLASH;
|
||
flash->chipSize = 0x1000000L;
|
||
NFDC21thisVars->pagesPerBlock *= 2;
|
||
break;
|
||
|
||
case 0x75 : /* 32 Mb */
|
||
flash->type = TC58256_FLASH;
|
||
flash->chipSize = 0x2000000L;
|
||
NFDC21thisVars->pagesPerBlock *= 2;
|
||
break;
|
||
|
||
case 0x76 : /* 64 Mb */
|
||
flash->type = TC58512_FLASH;
|
||
flash->chipSize = 0x4000000L;
|
||
flash->flags |= BIG_ADDR;
|
||
NFDC21thisVars->pagesPerBlock *= 2;
|
||
break;
|
||
|
||
case 0x79: /* 128 Mb */
|
||
flash->type = TC581024_FLASH;
|
||
flash->chipSize = 0x8000000L;
|
||
flash->flags |= BIG_ADDR;
|
||
NFDC21thisVars->pagesPerBlock *= 2;
|
||
break;
|
||
|
||
default : /* Undefined Flash */
|
||
return( FALSE );
|
||
}
|
||
flash->flags |= FULL_PAGE; /* no partial page programming */
|
||
break;
|
||
|
||
default : /* Undefined Flash */
|
||
return( FALSE );
|
||
}
|
||
return( TRUE );
|
||
}
|
||
else /* dev != 0 */
|
||
if( (vendorId_p == NFDC21thisVars->vendorID) && (chipId_p == NFDC21thisVars->chipID) )
|
||
return( TRUE );
|
||
|
||
return( FALSE );
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* r e a d F l a s h I D */
|
||
/* */
|
||
/* Read vendor and chip IDs, count flash devices. Initialize relevant */
|
||
/* fields in data structures. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* dev : dev chips were accessed before this one. */
|
||
/* */
|
||
/* Returns: */
|
||
/* TRUE if this media is supported, FALSE otherwise. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
static int readFlashID ( FLFlash * flash, int dev )
|
||
{
|
||
byte vendorId_p, chipId_p;
|
||
register int i;
|
||
volatile Reg8bitType junk = 0;
|
||
|
||
command (flash, READ_ID);
|
||
|
||
writeSignals (flash, FLASH_IO | ALE | CE | WP);
|
||
#ifdef SLOW_IO_FLAG
|
||
flWrite8bitReg(flash,NslowIO,(Reg8bitType)0);
|
||
#endif
|
||
flWrite8bitReg(flash,NFDC21thisIO,(Reg8bitType)0);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC )
|
||
flWrite8bitReg(flash,NwritePipeTerm,(Reg8bitType)0);
|
||
writeSignals (flash, FLASH_IO | CE | WP);
|
||
|
||
/* read vendor ID */
|
||
|
||
flDelayMsecs( 10 ); /* 10 microsec delay */
|
||
for( i = 0;( i < 2 ); i++ ) /* perform 2 reads from NOP reg for delay */
|
||
junk += flRead8bitReg(flash,NNOPreg);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC ) {
|
||
junk += flRead8bitReg(flash,NreadPipeInit); /* load first data into pipeline */
|
||
vendorId_p = flRead8bitReg(flash,NreadLastData); /* finally read vendor ID */
|
||
}
|
||
else {
|
||
junk += flRead8bitReg(flash,NslowIO); /* read CDSN_slow_IO ignoring the data */
|
||
vendorId_p = flRead8bitReg(flash,NFDC21thisIO); /* finally read vendor ID */
|
||
}
|
||
|
||
/* read chip ID */
|
||
|
||
flDelayMsecs( 10 ); /* 10 microsec delay */
|
||
for( i = 0;( i < 2 ); i++ ) /* perform 2 reads from NOP reg for delay */
|
||
junk += flRead8bitReg(flash,NNOPreg);
|
||
if( NFDC21thisVars->flags & MDOC_ASIC ) {
|
||
junk += flRead8bitReg(flash,NreadPipeInit); /* load first data into pipeline */
|
||
chipId_p = flRead8bitReg(flash,NreadLastData); /* finally read chip ID */
|
||
}
|
||
else {
|
||
junk += flRead8bitReg(flash,NslowIO); /* read CDSN_slow_IO ignoring the data */
|
||
chipId_p = flRead8bitReg(flash,NFDC21thisIO); /* finally read chip ID */
|
||
}
|
||
|
||
if ( isKnownMedia(flash, vendorId_p, chipId_p, dev) != TRUE ) /* no chip or diff. */
|
||
return( FALSE ); /* type of flash */
|
||
|
||
flash->noOfChips++;
|
||
|
||
writeSignals (flash, FLASH_IO);
|
||
|
||
/* set flash parameters */
|
||
if((dev == 0)
|
||
#ifndef SEPARATED_CASCADED
|
||
&& (NFDC21thisVars->currentFloor == 0)
|
||
#endif /* SEPARATED_CASCADED */
|
||
)
|
||
{
|
||
NFDC21thisVars->pageAreaSize = 0x100;
|
||
|
||
#ifdef BIG_PAGE_ENABLED
|
||
if ( !(flash->flags & BIG_PAGE) )
|
||
NFDC21thisVars->tailSize = EXTRA_LEN; /* = 8 */
|
||
else
|
||
#endif /* BIG_PAGE_ENABLED */
|
||
NFDC21thisVars->tailSize = SECTOR_EXTRA_LEN; /* = 16 */
|
||
|
||
NFDC21thisVars->pageMask = (word)(flash->pageSize - 1);
|
||
flash->erasableBlockSize = NFDC21thisVars->pagesPerBlock * flash->pageSize;
|
||
NFDC21thisVars->noOfBlocks = (word)( flash->chipSize / flash->erasableBlockSize );
|
||
NFDC21thisVars->if_cfg = 8;
|
||
}
|
||
|
||
return( TRUE );
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* d o c 2 I d e n t i f y */
|
||
/* */
|
||
/* Identify flash. This routine will be registered as the */
|
||
/* identification routine for this MTD. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* flash : Pointer identifying drive */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, flUnknownMedia failed. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
#ifndef MTD_STANDALONE
|
||
static
|
||
#endif
|
||
FLStatus doc2000Identify(FLFlash * flash)
|
||
{
|
||
dword address = 0L;
|
||
int maxDevs, dev;
|
||
volatile Reg8bitType toggle1;
|
||
volatile Reg8bitType toggle2;
|
||
byte floorCnt = 0;
|
||
byte floor = 0;
|
||
|
||
#ifdef NT5PORT
|
||
byte socketNo = (byte)flSocketNoOf(flash->socket);
|
||
#else
|
||
byte socketNo = flSocketNoOf(flash->socket);
|
||
#endif NT5PORT
|
||
|
||
|
||
DEBUG_PRINT(("Debug: entering NFDC 2148 identification routine.\r\n"));
|
||
|
||
flash->mtdVars = &docMtdVars[socketNo];
|
||
|
||
#ifndef FL_NO_USE_FUNC
|
||
/* Initialize socket memory access routine */
|
||
if(setBusTypeOfFlash(flash, flBusConfig[socketNo] |
|
||
FL_8BIT_DOC_ACCESS | FL_8BIT_FLASH_ACCESS))
|
||
return flUnknownMedia;
|
||
#endif /* FL_NO_USE_FUNC */
|
||
|
||
|
||
#if (defined(VERIFY_WRITE) || defined(VERIFY_ERASE) || defined(MTD_RECONSTRUCT_BBT))
|
||
/* Get pointer to read back buffer */
|
||
NFDC21thisVars->readBackBuffer = flReadBackBufferOf(socketNo);
|
||
#endif /* VERIFY_WRITE || VERIFY_ERASE || MTD_RECONSTRUCT_BBT */
|
||
|
||
#ifndef MTD_STANDALONE
|
||
/* get pointer to buffer (we assume SINGLE_BUFFER is not defined) */
|
||
NFDC21thisVars->buffer = flBufferOf(socketNo);
|
||
|
||
flSetWindowBusWidth(flash->socket, 16);/* use 8-bits */
|
||
flSetWindowSpeed(flash->socket, 250); /* 250 nsec. */
|
||
#else
|
||
#ifdef MTD_READ_BBT
|
||
NFDC21thisVars->buffer = &globalMTDBuffer;
|
||
#endif /* MTD_READ_BBT */
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
/* assume flash parameters for KM29N16000 */
|
||
|
||
NFDC21thisVars->floorSize = 1L;
|
||
#ifdef SEPARATED_CASCADED
|
||
/* NFDC21thisVars->currentFloor = flSocketNoOf(flash->socket);*/
|
||
#else
|
||
flash->noOfFloors = MAX_FLOORS;
|
||
NFDC21thisVars->currentFloor = MAX_FLOORS;
|
||
#endif /* SEPARATED_CASCADED */
|
||
flash->noOfChips = 0;
|
||
flash->chipSize = 0x200000L; /* Assume something ... */
|
||
flash->interleaving = 1; /* unimportant for now */
|
||
|
||
/* detect card - identify bit toggles on consequitive reads */
|
||
|
||
NFDC21thisWin = (NDOC2window)flMap(flash->socket, 0);
|
||
flash->win = NFDC21thisWin;
|
||
if (NFDC21thisWin == NULL)
|
||
return flUnknownMedia;
|
||
|
||
setASICmode (flash, ASIC_RESET_MODE);
|
||
setASICmode (flash, ASIC_NORMAL_MODE);
|
||
|
||
switch (flRead8bitReg(flash,NchipId))
|
||
{
|
||
case CHIP_ID_MDOC:
|
||
/* Mdoc and alon asics have the same ID only on
|
||
the forth read distigushes them */
|
||
for(dev=0;dev<3;dev++)
|
||
toggle1 = flRead8bitReg(flash,NchipId);
|
||
if (toggle1 != CHIP_ID_MDOC)
|
||
{
|
||
flash->mediaType = DOC2000TSOP_TYPE;
|
||
}
|
||
else
|
||
{
|
||
flash->mediaType = MDOC_TYPE;
|
||
}
|
||
NFDC21thisVars->flags |= MDOC_ASIC;
|
||
NFDC21thisVars->win_io = NIPLpart2;
|
||
break;
|
||
|
||
case CHIP_ID_DOC: /* Doc2000 */
|
||
NFDC21thisVars->flags &= ~MDOC_ASIC;
|
||
NFDC21thisVars->win_io = Nio;
|
||
flash->mediaType = DOC_TYPE;
|
||
break;
|
||
|
||
default:
|
||
DEBUG_PRINT(("Debug: failed to identify NFDC 2148.\r\n"));
|
||
return( flUnknownMedia );
|
||
}
|
||
mapWin (flash, &address);
|
||
|
||
if( NFDC21thisVars->flags & MDOC_ASIC ) {
|
||
toggle1 = flRead8bitReg(flash,NECCconfig);
|
||
toggle2 = toggle1 ^ flRead8bitReg(flash,NECCconfig);
|
||
}
|
||
else {
|
||
toggle1 = flRead8bitReg(flash,NECCstatus);
|
||
toggle2 = toggle1 ^ flRead8bitReg(flash,NECCstatus);
|
||
}
|
||
if ( (toggle2 & TOGGLE) == 0 ) {
|
||
DEBUG_PRINT(("Debug: failed to identify NFDC 2148.\r\n"));
|
||
return( flUnknownMedia );
|
||
}
|
||
|
||
/* reset all flash devices */
|
||
maxDevs = MAX_FLASH_DEVICES_DOC;
|
||
|
||
#ifndef SEPARATED_CASCADED
|
||
for ( NFDC21thisVars->currentFloor = 0 ;
|
||
NFDC21thisVars->currentFloor < MAX_FLOORS ;
|
||
NFDC21thisVars->currentFloor++ )
|
||
{
|
||
/* select floor */
|
||
flWrite8bitReg(flash,NASICselect,(Reg8bitType)NFDC21thisVars->currentFloor);
|
||
#endif /* SEPARATED_CASCADED */
|
||
for ( dev = 0 ; dev < maxDevs ; dev++ ) {
|
||
selectChip(flash, (Reg8bitType)dev );
|
||
command(flash, RESET_FLASH);
|
||
}
|
||
#ifndef SEPARATED_CASCADED
|
||
}
|
||
|
||
NFDC21thisVars->currentFloor = (byte)0;
|
||
/* back to ground floor */
|
||
flWrite8bitReg(flash,NASICselect,(Reg8bitType)NFDC21thisVars->currentFloor);
|
||
#endif /* SEPARATED_CASCADED */
|
||
writeSignals (flash, FLASH_IO | WP);
|
||
|
||
/* identify and count flash chips, figure out flash parameters */
|
||
#ifndef SEPARATED_CASCADED
|
||
for( floor = 0; floor < MAX_FLOORS; floor++ )
|
||
#endif /* SEPARATED_CASCADED */
|
||
for ( dev = 0; dev < maxDevs; dev++ )
|
||
{
|
||
dword addr = address;
|
||
|
||
mapWin(flash, &addr);
|
||
|
||
if ( readFlashID(flash, dev) == TRUE ) /* identified OK */
|
||
{
|
||
floorCnt = (byte)(floor + 1);
|
||
#ifndef SEPARATED_CASCADED
|
||
if (floor == 0)
|
||
#endif /* SEPARATED_CASCADED */
|
||
NFDC21thisVars->floorSize += flash->chipSize * flash->interleaving;
|
||
address += flash->chipSize * flash->interleaving;
|
||
}
|
||
else
|
||
{
|
||
#ifndef SEPARATED_CASCADED
|
||
if (floor != 0)
|
||
{
|
||
dev = maxDevs;
|
||
floor = MAX_FLOORS;
|
||
}
|
||
else
|
||
#endif /* SEPARATED_CASCADED */
|
||
{
|
||
maxDevs = dev;
|
||
NFDC21thisVars->floorSize = maxDevs * flash->chipSize * flash->interleaving;
|
||
}
|
||
}
|
||
}
|
||
#ifndef SEPARATED_CASCADED
|
||
NFDC21thisVars->currentFloor = (byte)0;
|
||
#endif /* SEPARATED_CASCADED */
|
||
flWrite8bitReg(flash,NASICselect,(Reg8bitType)NFDC21thisVars->currentFloor); /* back to ground floor */
|
||
|
||
if (flash->noOfChips == 0) {
|
||
DEBUG_PRINT(("Debug: failed to identify NFDC 2148.\r\n"));
|
||
return( flUnknownMedia );
|
||
}
|
||
|
||
address = 0L;
|
||
mapWin (flash, &address);
|
||
|
||
flash->noOfFloors = floorCnt;
|
||
|
||
eccOFF(flash);
|
||
|
||
/* Register our flash handlers */
|
||
#ifndef FL_READ_ONLY
|
||
flash->write = doc2Write;
|
||
flash->erase = doc2Erase;
|
||
#else
|
||
flash->erase = NULL;
|
||
flash->write = NULL;
|
||
#endif
|
||
flash->read = doc2Read;
|
||
#ifndef MTD_STANDALONE
|
||
flash->map = doc2Map;
|
||
#else
|
||
flash->map = NULL;
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
/* doc2000 tsop uses INFTL instead of NFTL , does not use
|
||
* the last block and has a readBBT routine
|
||
*/
|
||
|
||
if (flash->mediaType == DOC2000TSOP_TYPE)
|
||
{
|
||
#ifdef MTD_READ_BBT
|
||
flash->readBBT = readBBT;
|
||
#endif /* MTD_READ_BBT */
|
||
#ifndef NO_IPL_CODE
|
||
flash->download = forceDownLoad;
|
||
#ifndef FL_READ_ONLY
|
||
flash->writeIPL = writeIPL;
|
||
#endif /* FL_READ_ONLY */
|
||
#endif /* NO_IPL_CODE */
|
||
flash->flags |= INFTL_ENABLED;
|
||
}
|
||
else
|
||
{
|
||
flash->flags |= NFTL_ENABLED;
|
||
}
|
||
#ifndef SEPARATED_CASCADED
|
||
if (flash->mediaType == MDOC_TYPE)
|
||
flash->flags |= EXTERNAL_EPROM; /* Supports external eprom */
|
||
#endif /* SEPARATED_CASCADED */
|
||
|
||
DEBUG_PRINT(("Debug: identified NFDC 2148.\r\n"));
|
||
return( flOK );
|
||
}
|
||
|
||
#ifndef MTD_STANDALONE
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* f l R e g i s t e r D O C S O C */
|
||
/* */
|
||
/* Installs routines for DiskOnChip 2000 family. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* lowAddress, */
|
||
/* highAddress : host memory range to search for DiskOnChip */
|
||
/* 2000 memory window */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, otherwise failure */
|
||
/*----------------------------------------------------------------------*/
|
||
#ifndef NT5PORT
|
||
FLStatus flRegisterDOCSOC(dword lowAddress, dword highAddress)
|
||
{
|
||
int serialNo;
|
||
|
||
if( noOfSockets >= SOCKETS )
|
||
return flTooManyComponents;
|
||
|
||
for(serialNo=0;( noOfSockets < SOCKETS );serialNo++,noOfSockets++)
|
||
{
|
||
FLSocket * socket = flSocketOf(noOfSockets);
|
||
|
||
socket->volNo = noOfSockets;
|
||
|
||
docSocketInit(socket);
|
||
|
||
/* call DiskOnChip MTD's routine to search for memory window */
|
||
|
||
flSetWindowSize(socket, 2); /* 4 KBytes */
|
||
|
||
socket->window.baseAddress = flDocWindowBaseAddress
|
||
((byte)socket->volNo, lowAddress, highAddress, &lowAddress);
|
||
|
||
if (socket->window.baseAddress == 0) /* DiskOnChip not detected */
|
||
break;
|
||
}
|
||
if( serialNo == 0 )
|
||
return flAdapterNotFound;
|
||
|
||
return flOK;
|
||
}
|
||
#endif /*NT5PORT*/
|
||
#else /* MTD_STANDALONE */
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* d o c 2 0 0 0 S e a r c h F o r W i n d o w */
|
||
/* */
|
||
/* Search for the DiskOnChip ASIC in a given memory range and */
|
||
/* initialize the given socket record. */
|
||
/* */
|
||
/* Parameters: */
|
||
/* socket : Record used to store the sockets parameters */
|
||
/* lowAddress : host memory range to search for DiskOnChip 2000 */
|
||
/* highAddress : memory window */
|
||
/* */
|
||
/* Output: initialize the following fields in the FLFlash record: */
|
||
/* */
|
||
/* base - Pointer to DiskOnChip window */
|
||
/* size - DiskOnChip window size usualy 8K */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, flDriveNotAvailable on failure. */
|
||
/* */
|
||
/* NOTE: This routine is not used by OSAK. It is used by standalone */
|
||
/* applications using the MTD (BDK for example) as a replacement */
|
||
/* for the OSAK DOCSOC.C file. */
|
||
/* The FLSocket record used by this function is not the one used */
|
||
/* by OSAK defined in flsocket.h but a replacement record defined */
|
||
/* in flflash.h. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
FLStatus doc2000SearchForWindow(FLSocket * socket,
|
||
dword lowAddress,
|
||
dword highAddress)
|
||
{
|
||
dword baseAddress; /* Physical base as a 4K page */
|
||
|
||
socket->size = 2 * 0x1000L; /* 4 KBytes */
|
||
baseAddress = (dword) flDocWindowBaseAddress(0, lowAddress, highAddress, &lowAddress);
|
||
socket->base = physicalToPointer(baseAddress << 12, socket->size,0);
|
||
if (baseAddress) /* DiskOnChip detected */
|
||
return flOK;
|
||
else /* DiskOnChip not detected */
|
||
return flDriveNotAvailable;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* d o c 2 0 0 0 F r e e W i n d o w */
|
||
/* */
|
||
/* Free any resources used for the DiskOnChip window */
|
||
/* */
|
||
/* Parameters: */
|
||
/* socket : Record used to store the sockets parameters */
|
||
/* */
|
||
/* Returns: None */
|
||
/* */
|
||
/* NOTE: This routine is used only by virtual memory systems in order */
|
||
/* to unmap the DiskOnChip window. */
|
||
/* */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
void doc2000FreeWindow(FLSocket * socket)
|
||
{
|
||
freePointer(socket->base,DOC_WIN);
|
||
}
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
/*----------------------------------------------------------------------*/
|
||
/* f l R e g i s t e r D O C 2 0 0 0 */
|
||
/* */
|
||
/* Registers this MTD for use */
|
||
/* */
|
||
/* Parameters: */
|
||
/* None */
|
||
/* */
|
||
/* Returns: */
|
||
/* FLStatus : 0 on success, otherwise failure */
|
||
/*----------------------------------------------------------------------*/
|
||
|
||
FLStatus flRegisterDOC2000(void)
|
||
{
|
||
if (noOfMTDs >= MTDS)
|
||
return( flTooManyComponents );
|
||
|
||
#ifdef MTD_STANDALONE
|
||
socketTable[noOfMTDs] = doc2000SearchForWindow;
|
||
freeTable[noOfMTDs] = doc2000FreeWindow;
|
||
#endif /* MTD_STANDALONE */
|
||
|
||
mtdTable[noOfMTDs++] = doc2000Identify;
|
||
|
||
return( flOK );
|
||
}
|