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

538 lines
15 KiB
C

/*
* $Log: V:/i28f008.c_v $
*
* Rev 1.16 06 Oct 1997 18:37:30 ANDRY
* no COBUX
*
* Rev 1.15 05 Oct 1997 19:11:08 ANDRY
* COBUX (Motorola M68360 16-bit only board)
*
* Rev 1.14 05 Oct 1997 14:35:36 ANDRY
* flNeedVpp() and flDontNeedVpp() are under #ifdef SOCKET_12_VOLTS
*
* Rev 1.13 10 Sep 1997 16:18:10 danig
* Got rid of generic names
*
* Rev 1.12 04 Sep 1997 18:47:20 danig
* Debug messages
*
* Rev 1.11 31 Aug 1997 15:06:40 danig
* Registration routine return status
*
* Rev 1.10 24 Jul 1997 17:52:30 amirban
* FAR to FAR0
*
* Rev 1.9 21 Jul 1997 14:44:06 danig
* No parallelLimit
*
* Rev 1.8 20 Jul 1997 17:17:00 amirban
* No watchDogTimer
*
* Rev 1.7 07 Jul 1997 15:22:06 amirban
* Ver 2.0
*
* Rev 1.6 15 Apr 1997 19:16:40 danig
* Pointer conversions.
*
* Rev 1.5 29 Aug 1996 14:17:48 amirban
* Warnings
*
* Rev 1.4 18 Aug 1996 13:48:44 amirban
* Comments
*
* Rev 1.3 31 Jul 1996 14:31:10 amirban
* Background stuff
*
* Rev 1.2 04 Jul 1996 18:20:06 amirban
* New flag field
*
* Rev 1.1 03 Jun 1996 16:28:58 amirban
* Cobra additions
*
* Rev 1.0 20 Mar 1996 13:33:06 amirban
* Initial revision.
*/
/************************************************************************/
/* */
/* FAT-FTL Lite Software Development Kit */
/* Copyright (C) M-Systems Ltd. 1995-1996 */
/* */
/************************************************************************/
/*----------------------------------------------------------------------*/
/* */
/* This MTD supports the following Flash technologies: */
/* */
/* - Intel 28F008/Cobra 8-mbit devices */
/* - Intel 28F016SA/28016SV/Cobra 16-mbit devices (byte-mode operation) */
/* */
/* And (among else), the following Flash media and cards: */
/* */
/* - Intel Series-2 PCMCIA cards */
/* - Intel Series-2+ PCMCIA cards */
/* - M-Systems ISA/Tiny/PC-104 Flash Disks */
/* - M-Systems NOR PCMCIA cards */
/* - Intel Value-100 cards */
/* */
/*----------------------------------------------------------------------*/
#include "flflash.h"
#ifdef FL_BACKGROUND
#include "backgrnd.h"
#endif
#define flash (*pFlash)
#define SETUP_ERASE 0x20
#define SETUP_WRITE 0x40
#define CLEAR_STATUS 0x50
#define READ_STATUS 0x70
#define READ_ID 0x90
#define SUSPEND_ERASE 0xb0
#define CONFIRM_ERASE 0xd0
#define RESUME_ERASE 0xd0
#define READ_ARRAY 0xff
#define WSM_ERROR 0x38
#define WSM_VPP_ERROR 0x08
#define WSM_SUSPENDED 0x40
#define WSM_READY 0x80
/* JEDEC ids for this MTD */
#define I28F008_FLASH 0x89a2
#define I28F016_FLASH 0x89a0
#define COBRA004_FLASH 0x89a7
#define COBRA008_FLASH 0x89a6
#define COBRA016_FLASH 0x89aa
#define MOBILE_MAX_INLV_4 0x8989
#define LDP_1MB_IN_16BIT_MODE 0x89ff
/* Definition of MTD specific vol.flags bits: */
#define NO_12VOLTS 0x100 /* Card does not need 12 Volts Vpp */
/*----------------------------------------------------------------------*/
/* i 2 8 f 0 0 8 W r i t e */
/* */
/* Write a block of bytes to Flash */
/* */
/* This routine will be registered as the MTD vol.write routine */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* address : Card address to write to */
/* buffer : Address of data to write */
/* length : Number of bytes to write */
/* overwrite : TRUE if overwriting old Flash contents */
/* FALSE if old contents are known to be erased */
/* */
/* Returns: */
/* FLStatus : 0 on success, failed otherwise */
/*----------------------------------------------------------------------*/
FLStatus i28f008Write(FLFlash vol,
CardAddress address,
const VOID FAR1 *buffer,
dword length,
word overwrite)
{
/* Set timeout ot 5 seconds from now */
ULONG writeTimeout = flMsecCounter + 5000;
FLStatus status;
ULONG i, cLength;
FlashPTR flashPtr;
if (flWriteProtected(vol.socket))
return flWriteProtect;
#ifdef SOCKET_12_VOLTS
if (!(vol.flags & NO_12VOLTS))
checkStatus(flNeedVpp(vol.socket));
#endif
flashPtr = (FlashPTR) flMap(vol.socket,address);
cLength = length;
if (vol.interleaving == 1) {
lastByte:
#ifdef __cplusplus
#define bFlashPtr flashPtr
#define bBuffer ((const UCHAR FAR1 * &) buffer)
#else
#define bFlashPtr flashPtr
#define bBuffer ((const UCHAR FAR1 *) buffer)
#endif
while (cLength >= 1) {
tffsWriteByteFlash(bFlashPtr, SETUP_WRITE);
tffsWriteByteFlash(bFlashPtr, *bBuffer);
cLength--;
bBuffer++;
bFlashPtr++;
while (!(tffsReadByteFlash(bFlashPtr-1) & WSM_READY) && flMsecCounter < writeTimeout)
;
}
}
else if (vol.interleaving == 2) {
lastWord:
#ifdef __cplusplus
#define wFlashPtr ((FlashWPTR &) flashPtr)
#define wBuffer ((const USHORT FAR1 * &) buffer)
#else
#define wFlashPtr ((FlashWPTR) flashPtr)
#define wBuffer ((const USHORT FAR1 *) buffer)
#endif
while (cLength >= 2) {
tffsWriteWordFlash(wFlashPtr, SETUP_WRITE * 0x101);
tffsWriteWordFlash(wFlashPtr, *wBuffer);
cLength -= 2;
wBuffer++;
wFlashPtr++;
while ((~(tffsReadWordFlash(wFlashPtr-1)) & (WSM_READY * 0x101)) && flMsecCounter < writeTimeout)
;
}
if (cLength > 0)
goto lastByte;
}
else /* if (vol.interleaving >= 4) */ {
#ifdef __cplusplus
#define dFlashPtr ((FlashDPTR &) flashPtr)
#define dBuffer ((const ULONG FAR1 * &) buffer)
#else
#define dFlashPtr ((FlashDPTR) flashPtr)
#define dBuffer ((const ULONG FAR1 *) buffer)
#endif
while (cLength >= 4) {
tffsWriteDwordFlash(dFlashPtr, SETUP_WRITE * 0x1010101l);
tffsWriteDwordFlash(dFlashPtr, *dBuffer);
cLength -= 4;
dBuffer++;
dFlashPtr++;
while ((~(tffsReadDwordFlash(dFlashPtr-1)) & (WSM_READY * 0x1010101lu)) && flMsecCounter < writeTimeout)
;
}
if (cLength > 0)
goto lastWord;
}
flashPtr -= length;
bBuffer -= length;
status = flOK;
for (i = 0; i < (ULONG)vol.interleaving && i < length; i++) {
if (tffsReadByteFlash(flashPtr + i) & WSM_ERROR) {
DEBUG_PRINT(("Debug: write failed for 8-bit Intel media.\n"));
status = (tffsReadByteFlash(flashPtr + i) & WSM_VPP_ERROR) ? flVppFailure : flWriteFault;
tffsWriteByteFlash(flashPtr + i, CLEAR_STATUS);
}
tffsWriteByteFlash(flashPtr + i, READ_ARRAY);
}
#ifdef SOCKET_12_VOLTS
if (!(vol.flags & NO_12VOLTS))
flDontNeedVpp(vol.socket);
#endif
/* verify the data */
if (status == flOK) {
/* compare double words */
for (;length >= 4; length -= 4, dFlashPtr++, dBuffer++) {
if (tffsReadDwordFlash(dFlashPtr) != *dBuffer) {
DEBUG_PRINT(("Debug: write failed for 8-bit Intel media in verification.\n"));
return flWriteFault;
}
}
/* compare the last bytes */
for (; length; length--, bFlashPtr++, bBuffer++) {
if (tffsReadByteFlash(bFlashPtr) != *bBuffer) {
DEBUG_PRINT(("Debug: write failed for 8-bit Intel media in verification.\n"));
return flWriteFault;
}
}
}
return status;
}
/*----------------------------------------------------------------------*/
/* i 2 8 f 0 0 8 E r a s e */
/* */
/* Erase one or more contiguous Flash erasable blocks */
/* */
/* This routine will be registered as the MTD vol.erase routine */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* firstErasableBlock : Number of first block to erase */
/* numOfErasableBlocks: Number of blocks to erase */
/* */
/* Returns: */
/* FLStatus : 0 on success, failed otherwise */
/*----------------------------------------------------------------------*/
FLStatus i28f008Erase(FLFlash vol,
word firstErasableBlock,
word numOfErasableBlocks)
{
LONG iBlock;
FLStatus status = flOK; /* unless proven otherwise */
if (flWriteProtected(vol.socket))
return flWriteProtect;
#ifdef SOCKET_12_VOLTS
if (!(vol.flags & NO_12VOLTS))
checkStatus(flNeedVpp(vol.socket));
#endif
for (iBlock = 0; iBlock < numOfErasableBlocks && status == flOK; iBlock++) {
LONG j;
FLBoolean finished;
FlashPTR flashPtr = (FlashPTR)
flMap(vol.socket,
(firstErasableBlock + iBlock) * vol.erasableBlockSize);
for (j = 0; j < vol.interleaving; j++) {
tffsWriteByteFlash(flashPtr + j, SETUP_ERASE);
tffsWriteByteFlash(flashPtr + j, CONFIRM_ERASE);
}
do {
#ifdef FL_BACKGROUND
while (flForeground(1) == BG_SUSPEND) { /* suspend */
for (j = 0; j < vol.interleaving; j++) {
tffsWriteByteFlash(flashPtr + j, READ_STATUS);
if (!(tffsReadByteFlash(flashPtr + j) & WSM_READY)) {
tffsWriteByteFlash(flashPtr + j, SUSPEND_ERASE);
tffsWriteByteFlash(flashPtr + j, READ_STATUS);
while (!(tffsReadByteFlash(flashPtr + j) & WSM_READY))
;
}
tffsWriteByteFlash(flashPtr + j, READ_ARRAY);
}
}
#endif
finished = TRUE;
for (j = 0; j < vol.interleaving; j++) {
tffsWriteByteFlash(flashPtr + j, READ_STATUS);
if (tffsReadByteFlash(flashPtr + j) & WSM_SUSPENDED) {
tffsWriteByteFlash(flashPtr + j, RESUME_ERASE);
finished = FALSE;
}
else if (!(tffsReadByteFlash(flashPtr + j) & WSM_READY))
finished = FALSE;
else {
if (tffsReadByteFlash(flashPtr + j) & WSM_ERROR) {
DEBUG_PRINT(("Debug: erase failed for 8-bit Intel media.\n"));
status = (tffsReadByteFlash(flashPtr + j) & WSM_VPP_ERROR) ? flVppFailure : flWriteFault;
tffsWriteByteFlash(flashPtr + j, CLEAR_STATUS);
}
tffsWriteByteFlash(flashPtr + j, READ_ARRAY);
}
flDelayMsecs(10);
}
} while (!finished);
} /* block loop */
#ifdef SOCKET_12_VOLTS
if (!(vol.flags & NO_12VOLTS))
flDontNeedVpp(vol.socket);
#endif
return status;
}
/*----------------------------------------------------------------------*/
/* i 2 8 f 0 0 8 M a p */
/* */
/* Map through buffer. This routine will be registered as the map */
/* routine for this MTD. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* address : Flash address to be mapped. */
/* length : number of bytes to map. */
/* */
/* Returns: */
/* Pointer to the buffer data was mapped to. */
/* */
/*----------------------------------------------------------------------*/
VOID FAR0 *i28f008Map (FLFlash vol, CardAddress address, int length)
{
vol.socket->remapped = TRUE;
return mapThroughBuffer(&vol,address,length);
}
/*----------------------------------------------------------------------*/
/* i 2 8 f 0 0 8 R e a d */
/* */
/* Read some data from the flash. This routine will be registered as */
/* the read routine for this MTD. */
/* */
/* Parameters: */
/* vol : 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. */
/* */
/*----------------------------------------------------------------------*/
FLStatus i28f008Read(FLFlash vol,
CardAddress address,
VOID FAR1 *buffer,
dword length,
word modes)
{
ULONG i;
UCHAR * byteBuffer;
FlashPTR byteFlashPtr;
ULONG * dwordBuffer = (ULONG *)buffer;
FlashDPTR dwordFlashPtr = (FlashDPTR)flMap(vol.socket, address);
for (i = 0; i < length - 4; i += 4, dwordBuffer++, dwordFlashPtr++) {
*dwordBuffer = tffsReadDwordFlash(dwordFlashPtr);
}
byteBuffer = (UCHAR *)dwordBuffer;
byteFlashPtr = (FlashPTR)dwordFlashPtr;
for(; i < length; i++, byteBuffer++, byteFlashPtr++) {
*byteBuffer = tffsReadByteFlash(byteFlashPtr);
}
return flOK ;
}
/*----------------------------------------------------------------------*/
/* i 2 8 f 0 0 8 I d e n t i f y */
/* */
/* Identifies media based on Intel 28F008 and Intel 28F016 and */
/* registers as an MTD for such */
/* */
/* This routine will be placed on the MTD list in custom.h. It must be */
/* an extern routine. */
/* */
/* On successful identification, the Flash structure is filled out and */
/* the write and erase routines registered. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* */
/* Returns: */
/* FLStatus : 0 on positive identificaion, failed otherwise */
/*----------------------------------------------------------------------*/
FLStatus i28f008Identify(FLFlash vol)
{
LONG iChip;
CardAddress idOffset = 0;
DEBUG_PRINT(("Debug: i28f008Identify :entering 8-bit Intel media identification routine.\n"));
flSetWindowBusWidth(vol.socket, 16);/* use 16-bits */
flSetWindowSpeed(vol.socket, 150); /* 120 nsec. */
flSetWindowSize(vol.socket, 2); /* 8 KBytes */
flIntelIdentify(&vol, NULL,0);
if (vol.type == NOT_FLASH) {
/* The flash may be write-protected at offset 0. Try another offset */
idOffset = 0x80000l;
flIntelIdentify(&vol, NULL,idOffset);
}
if (vol.type == LDP_1MB_IN_16BIT_MODE) {
flSetWindowBusWidth(vol.socket, 8); /* use 8-bits */
flIntelIdentify(&vol, NULL,idOffset); /* and try to get a valid id */
}
switch (vol.type) {
case COBRA004_FLASH:
vol.chipSize = 0x80000l;
vol.flags |= SUSPEND_FOR_WRITE | NO_12VOLTS;
break;
case COBRA008_FLASH:
vol.flags |= SUSPEND_FOR_WRITE | NO_12VOLTS;
/* no break */
case MOBILE_MAX_INLV_4:
case I28F008_FLASH:
vol.chipSize = 0x100000l;
break;
case COBRA016_FLASH:
vol.flags |= SUSPEND_FOR_WRITE | NO_12VOLTS;
/* no break */
case I28F016_FLASH:
vol.chipSize = 0x200000l;
break;
default:
DEBUG_PRINT(("Debug: failed to identify 8-bit Intel media.\n"));
return flUnknownMedia; /* not ours */
}
vol.erasableBlockSize = 0x10000l * vol.interleaving;
checkStatus(flIntelSize(&vol, NULL,idOffset));
if (vol.type == MOBILE_MAX_INLV_4)
vol.type = I28F008_FLASH;
for (iChip = 0; iChip < vol.noOfChips; iChip += vol.interleaving) {
LONG i;
FlashPTR flashPtr = (FlashPTR)
flMap(vol.socket,iChip * vol.chipSize);
for (i = 0; i < vol.interleaving; i++)
tffsWriteByteFlash(flashPtr + i, CLEAR_STATUS);
}
/* Register our flash handlers */
vol.write = i28f008Write;
vol.erase = i28f008Erase;
vol.read = i28f008Read;
vol.map = i28f008Map;
DEBUG_PRINT(("Debug: i28f008Identify :identified 8-bit Intel media.\n"));
return flOK;
}
/*----------------------------------------------------------------------*/
/* f l R e g i s t e r I 2 8 F 0 0 8 */
/* */
/* Registers this MTD for use */
/* */
/* Parameters: */
/* None */
/* */
/* Returns: */
/* FLStatus : 0 on success, otherwise failure */
/*----------------------------------------------------------------------*/
FLStatus flRegisterI28F008(VOID)
{
if (noOfMTDs >= MTDS)
return flTooManyComponents;
mtdTable[noOfMTDs++] = i28f008Identify;
return flOK;
}