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

📄 fmd.cpp

📁 微软提供的Flash驱动程序
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Module Name:    FMD.CPP

Abstract:       FLASH Media Driver Interface Samsung K9F2808UOB NAND Flash Chip
  
Notes:          


-----------------------------------------------------------------------------*/
#include <fmd.h>
#include <ceddk.h>
#include <wdm.h>
#include <ddkreg.h>
#include "nand.h"
#include "ecc.h"                            // Contains code for performing ECC
#include <PCIReg.h>
//  Flags and pointers
#define BADBLOCKMARK                0x00
//  VALIDADDR is 5 << 8
//
//  Explain:    5 means the 6th byte in spare area (517 byte in the sector)
//              Shift 8 bit to the left to form the correct address for 16bit port
//
#define VALIDADDR   0x05

#define OEMADDR     0x04                    // 5th byte in spare area 


#define ECC_SIZE        8

static BYTE ECC[ECC_SIZE];                  // Used to retrieve/store ECC information

DWORD IoAddr=0;
BOOL  bIoMemMapped=FALSE;
DWORD dwDeviceId=0;
WORD g_wPagesPerBlock;
BOOL NEED_EXT_ADDR = TRUE;

/*
    @func   UCHAR | FMD_READ_PORT_UCHAR | READ_PORT_UCHAR wrapper - used to enforce flash access times.
    @rdesc  Data from read returned.
    @comm    
    @xref   
*/
UCHAR
FMD_READ_PORT_UCHAR(PUCHAR Port)
{
    // NOTE: delay can be added here.
    return(READ_PORT_UCHAR(Port));
}

/*
    @func   VOID | FMD_WRITE_PORT_UCHAR | WRITE_PORT_UCHAR wrapper - used to enforce flash access times.
    @rdesc  None.
    @comm    
    @xref   
*/
VOID
FMD_WRITE_PORT_UCHAR(PUCHAR Port, UCHAR Value)
{
    // NOTE: delay can be added here.
    WRITE_PORT_UCHAR(Port, Value);
}

//  CheckStatus()
//
//  Retrieve the status of the Chip. This function accept a loop number, which
//  is used to do the loop if chip is not ready.
//
//  dwLoops: 
//
//  0:          no loop
//  0xffffffff: loop forever
//
UCHAR CheckStatus(DWORD dwLoops)
{
    BOOL    bStop = (dwLoops != (DWORD) -1);
    UCHAR   usStatus;

    // Twb=200ns wait. generate 20 * 30ns wait
    for (volatile int i=0;i<20;i++)
        FMD_READ_PORT_UCHAR((PUCHAR)NAND_BUSY_PORT);
    
    while(1) {
        usStatus = FMD_READ_PORT_UCHAR((PUCHAR)NAND_BUSY_PORT);

        if( usStatus & STATUS_READY ||                  //  Status ready
            (bStop && !dwLoops) )                       //  Non-infinite loop and
                                                        //  we already pay our due
        {
            break;
        }

        dwLoops--;
    }
    // Trr= 20 ns. gernerate 2*30ns Wait.
    FMD_READ_PORT_UCHAR((PUCHAR)NAND_BUSY_PORT);
    FMD_READ_PORT_UCHAR((PUCHAR)NAND_BUSY_PORT);
    
    return usStatus;
}
//  GetStatus()
//
//  Retrieve the status of the Chip. This function accept a loop number, which
//  is used to do the loop if chip is not ready.
//
//  dwLoops: 
//
//  0:          no loop
//  0xffffffff: loop forever
//
UCHAR GetStatus(DWORD dwLoops)
{
    BOOL    bStop = (dwLoops != (DWORD) -1);
    UCHAR   usStatus;

    CheckStatus(dwLoops);
    //  Issue read status command
    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CMD_PORT, (UCHAR) CMD_STATUS);

    while(1) {
        usStatus = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);

        if( usStatus & STATUS_READY ||                  //  Status ready
            (bStop && !dwLoops) )                       //  Non-infinite loop and
                                                        //  we already pay our due
        {
            break;
        }

        dwLoops--;
    }

    //  We need to reset the port back to read mode. Issuing a read (0x00) 
    //  command
    //FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CMD_PORT, (UCHAR) CMD_READ);

    return usStatus;
}
DWORD ReadFlashID()
{
    BYTE data1,data2;

    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CS_PORT,(UCHAR)0);    // enable chip

    CheckStatus((DWORD) -1);    // check ready
    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CMD_PORT, (UCHAR) CMD_READID);
    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_ADDR_PORT, 0x0);

    CheckStatus((DWORD) -1);
    data1 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
    data2 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
    RETAILMSG(1,(TEXT("FMD:ReadID (Maker=%x,Device=%x)\r\n"),data1,data2));

    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CS_PORT,(UCHAR)1);    // disable chip

    return ((DWORD)data1*0x100+data2);
    
}

//
// Put Future Device enhancement here.
// Command 91h, address 0, Read following 3 bytes.
// Extended ID information.
// Character code:
//                    bit 1,0        00 single chip
//                                01 2-chip module
//                                10 4-chip module
//                                11 8-chip module                
//                    bit 3,2        01=MLC       use 64 pages/block
//                                00=Binary  use 32 pages/block
//                    bit 6,5,4    010    device includes x4 multi-block mode
//                    bit 7        0 no 2ndary data cache 
// Organization code:
//                    bit 3,2,1,0    0110  64MByte
//                                0111  128MByte
//                                1000  256MByte
//                                1001  512MByte
//                                1010  1GByte
//                    bit 5,4        00
//                    bit 7,6        01  x8-data-bus width
// Size code:
//                    bit 2,1,0    010 512Bytes-page size
//                    bit 4,3        11  extended page size=16Bytes
//                    bit 7,6,5    001 16KByte
//                                010 32KByte
//                                011 64KByte
//                                100 128KByte
//
UCHAR ReadFlashID2()
{
    BYTE data1,data2,data3;

    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CS_PORT,(UCHAR)0);    // enable chip

    CheckStatus((DWORD) -1);    // check ready
    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CMD_PORT, (UCHAR) CMD_READID2);
    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_ADDR_PORT, 0x0);

    CheckStatus((DWORD) -1);
    data1 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
    data2 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
    data3 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
    RETAILMSG(1,(TEXT("FMD:ReadID2 (Char=%x,Org=%x,Size=%x)\r\n"),data1,data2,data3));

    FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CS_PORT,(UCHAR)1);    // disable chip

    return ((UCHAR)data1 & 0x04);
    
}

/* 
 Here is the statement from SamSung's K9F2808U0B datasheet:
 
 All device locations are erased (FFh) except location where the invalid block(s)
 information is written prior to shipping. The invalid block(s) status is defined
 by the 6th byte in the spare area. Samsung makes sure that either the 1st or 2nd
 page of every invalid block has non-FFh data at the column address of 517. Since 
 the invalid block information is also erasable in most cases, it is impossible to
 recover the information once it has been erased. 
 
 Here is the logic we are taking:
 
 If the block is invalid, non-FFh value in column address of 517, we don't use that
 block anyway. Otherwise, the whole spare area is subject to use by our program. If
 we found additional bad block later on, we don't necessary have to use column 517 
 to represent invalid block. We could use any of the 16 byte spare area. 
 
 But for simplicity, in our current implementation, we avoid to touch column 517. So
 the we allocate SectorInfo as following:
 
  - - - - - - - - - - - - - - - - 
 |R|R|R|R|O|V|R|R|E|E|E|E|E|E|E|E|
  - - - - - - - - - - - - - - - -
  
 Where  Rs are reserved bytes used by the FAL
        O is a byte for use by the OEM
        V is a byte indicating if the block is valid (a.k.a. bad)
        Es are bytes used for ECC
        
 */
//    
// Inline functions
//

//
// Read a DWORD from a device's configuration space
//
__inline static DWORD
PCIConfig_Read(
    ULONG BusNumber,
    ULONG Device,
    ULONG Function,
    ULONG Offset
    )
{
    ULONG RetVal = FALSE;
    PCI_SLOT_NUMBER SlotNumber;

    SlotNumber.u.AsULONG = 0;
    SlotNumber.u.bits.DeviceNumber = Device;
    SlotNumber.u.bits.FunctionNumber = Function;
    
    HalGetBusDataByOffset(PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &RetVal, Offset, sizeof(RetVal));

    return RetVal;
}


//
// Write a DWORD to a device's configuration space
//
__inline static void
PCIConfig_Write(
    ULONG BusNumber,
    ULONG Device,
    ULONG Function,
    ULONG Offset,
    ULONG Value
    )
{
    PCI_SLOT_NUMBER SlotNumber;

    SlotNumber.u.AsULONG = 0;
    SlotNumber.u.bits.DeviceNumber = Device;
    SlotNumber.u.bits.FunctionNumber = Function;

    HalSetBusDataByOffset(PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &Value, Offset, sizeof(Value));
}

//
// Read Base Address Registers and size, populate Info struct with this information
//
BOOL
PCIReadBARs(
    PPCI_REG_INFO pInfo
    )
{   
    DWORD NumberOfRegs;
    DWORD Offset;
    DWORD i;
    DWORD BaseAddress;
    DWORD Size;
    DWORD Reg;
    DWORD IoIndex = 0;
    DWORD MemIndex = 0;

    // Determine number of BARs to examine from header type
    switch (pInfo->Cfg.HeaderType & ~PCI_MULTIFUNCTION) {
    case PCI_DEVICE_TYPE:
        NumberOfRegs = PCI_TYPE0_ADDRESSES;
        break;

    case PCI_BRIDGE_TYPE:
        NumberOfRegs = PCI_TYPE1_ADDRESSES;
        break;

    case PCI_CARDBUS_TYPE:
        NumberOfRegs = PCI_TYPE2_ADDRESSES;
        break;

    default:
        return FALSE;
    }
        
    for (i = 0, Offset = 0x10; i < NumberOfRegs; i++, Offset += 4) {
        // Get base address register value
        Reg = pInfo->Cfg.u.type0.BaseAddresses[i];

        // Get size info
        PCIConfig_Write(pInfo->Bus, pInfo->Device, pInfo->Function, Offset, 0xFFFFFFFF);
        BaseAddress = PCIConfig_Read(pInfo->Bus, pInfo->Device, pInfo->Function, Offset);
        PCIConfig_Write(pInfo->Bus, pInfo->Device, pInfo->Function, Offset, Reg);

        // Re-adjust BaseAddress if upper 16-bits are 0 (this happens on some devices that don't follow
        // the PCI spec, like the Intel UHCI controllers)
        if (((BaseAddress & 0xFFFFFFFC) != 0) && ((BaseAddress & 0xFFFF0000) == 0)) {

⌨️ 快捷键说明

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