//
// Copyright (c) Samsung Electronics. Co. LTD.  All rights reserved.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

*/

#include <windows.h>
#include <bldver.h>
#include <windev.h>
#include <types.h>
#include <excpt.h>
#include <tchar.h>
#include <devload.h>
#include <diskio.h>
#include <storemgr.h>
#include <pm.h>

#include <hsmmcdrv.h>
#include <bsp.h>
#include <ceddk.h>

/**
 *  Debug Definitions
 */
#define BIBDRV_RTL_PRINT(x) RETAILMSG(1,x)

#define BIBDRV_INF_MSG_ON   0
#define BIBDRV_ERR_MSG_ON   1
#define BIBDRV_LOG_MSG_ON   0

#if BIBDRV_ERR_MSG_ON
#define BIBDRV_ERR_PRINT(x) BIBDRV_RTL_PRINT(x)
#else
#define BIBDRV_ERR_PRINT(x)
#endif  // BIBDRV_ERR_MSG_ON

#if BIBDRV_LOG_MSG_ON
#define BIBDRV_LOG_PRINT(x) BIBDRV_RTL_PRINT(x)
#else
#define BIBDRV_LOG_PRINT(x)
#endif  // BIBDRV_LOG_MSG_ON

#if BIBDRV_INF_MSG_ON
#define BIBDRV_INF_PRINT(x) BIBDRV_RTL_PRINT(x)
#else
#define BIBDRV_INF_PRINT(x)
#endif  // BIBDRV_INF_MSG_ON


/**
 *  Global Variables
 */

/**
 *  Debug Zones
 */
#ifdef DEBUG

    #define DBG_INIT        0x0001
    #define DBG_OPEN        0x0002
    #define DBG_READ        0x0004
    #define DBG_WRITE       0x0008
    #define DBG_CLOSE       0x0010
    #define DBG_IOCTL       0x0020
    #define DBG_THREAD      0x0040
    #define DBG_EVENTS      0x0080
    #define DBG_CRITSEC     0x0100
    #define DBG_FLOW        0x0200
    #define DBG_IR          0x0400
    #define DBG_NOTHING     0x0800
    #define DBG_ALLOC       0x1000
    #define DBG_FUNCTION    0x2000
    #define DBG_WARNING     0x4000
    #define DBG_ERROR       0x8000

DBGPARAM dpCurSettings = {
    TEXT("Serial"), { TEXT("Init"),
                      TEXT("Open"),
                      TEXT("Read"),
                      TEXT("Write"),
                      TEXT("Close"),
                      TEXT("Ioctl"),
                      TEXT("Error")},
    0
};
#endif  // DEBUG


/**
 *  Imported variable declarations
 */


/**
 *  Imported function declarations
 */


/**
 *  Local #define
 */
#define MAX_READ_WRITE_SECTOR   (0x40)


#define USE_DMA 0

/**
 *  Local constant definitions
 */


/**
 *  Local typedefs
 */

typedef struct _DISK
{
    struct _DISK *pd_next;
    CRITICAL_SECTION d_DiskCardCrit;    // guard access to global state and card
    HANDLE hDevice;                     // activate Handle
    DISK_INFO d_DiskInfo;               // for DISK_IOCTL_GET/SETINFO
    DWORD d_OpenCount;                  // open ref count
    LPWSTR d_ActivePath;                // registry path to active key for this device
} DISK, *PDISK;


/**
 *  Local variables
 */

static CRITICAL_SECTION gDiskCrit;
static PDISK gDiskList;
HANDLE g_hMutex;

#if USE_DMA
PHYSICAL_ADDRESS g_PhyDMABufferAddr;
PVOID g_pVirtDMABufferAddr;
#endif


/**
 *  Local function prototypes
 */
static  HKEY    OpenDriverKey(LPTSTR ActiveKey);
static  BOOL    GetFolderName(PDISK pDisk, LPWSTR FolderName, DWORD cBytes, DWORD *pcBytes);
static  BOOL    GetFSDName(PDISK pDisk, LPWSTR FSDName, DWORD cBytes, DWORD *pcBytes);
static  BOOL    GetDeviceInfo(PDISK pDisk, PSTORAGEDEVICEINFO psdi);
static  VOID    CloseDisk(PDISK pDisk);
static  DWORD   DoDiskRead(PDISK pDisk, PVOID pData);
static  DWORD   GetDiskInfo(PDISK pDisk, PDISK_INFO pInfo);
static  DWORD   SetDiskInfo(PDISK pDisk, PDISK_INFO pInfo);
static  PDISK   CreateDiskObject(VOID);
static  BOOL    IsValidDisk(PDISK pDisk);
static  BOOL    InitializeNAND(PDISK pDisk);
static  BOOL    InitDisk(PDISK pDisk, LPTSTR ActiveKey);

extern  HANDLE  InitMutex(LPCTSTR name);
extern  DWORD   GetMutex(HANDLE handle);


/**
 *  Extern variables
 */
extern UINT32 g_dwSectorCount;
extern UINT32 g_dwIsSDHC;


/**
 *  @anchor OpenDriverKey
 *
 *  @brief  This function opens the driver key specified by the active key.
 *
 *  @param  ActiveKey   Handle to a currently open key or any of the
 *                      following predefined reserved handle values.
 *
 *  @return HKEY  HKEY value of "[ActiveKey]\[Key]", The caller is
 *                responsible for closing the returned HKEY
 */
static HKEY
OpenDriverKey(LPTSTR ActiveKey)
{
    TCHAR DevKey[256] = {0,};
    HKEY hDevKey = NULL;
    HKEY hActive = NULL;
    DWORD ValType = 0;
    DWORD ValLen = 0;
    DWORD status = 0;

    // Get the device key from active device registry key
    //
    status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,   // Handle to a currently open key
                        ActiveKey,              // Pointer to subkey
                        0,                      // Option : Reserved - set to 0
                        0,                      // samDesired : Not supported - set to 0
                        &hActive);              // Pointer for receved handele

    if (ERROR_SUCCESS != status)
    {
        BIBDRV_RTL_PRINT((TEXT("BIBDRV:OpenDriverKey RegOpenKeyEx(HLM\\%s) returned %d!!!\r\n"),
                        ActiveKey, status));
        return NULL;
    }

    hDevKey = NULL;
    ValLen  = sizeof(DevKey);

    status = RegQueryValueEx(hActive,               // Handle to a currently open key
                            DEVLOAD_DEVKEY_VALNAME, // Pointer to quary
                            NULL,                   // Reserved - set to NULL
                            &ValType,               // Pointer to type of data
                            (PUCHAR)DevKey,         // Pointer to data
                            &ValLen);               // the Length of data

    if (ERROR_SUCCESS != status)
    {
        BIBDRV_RTL_PRINT((TEXT("BIBDRV:OpenDriverKey - RegQueryValueEx(%s) returned %d\r\n"),
                        DEVLOAD_DEVKEY_VALNAME, status));

        RegCloseKey(hActive);
        return hDevKey;
    }

    // Get the geometry values from the device key
    //
    status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,   // Handle to a currently open key
                        DevKey,                 // Pointer to subkey
                        0,                      // Option : Reserved - set to 0
                        0,                      // samDesired : Not supported - set to 0
                        &hDevKey);              // Pointer for receved handele

    if (ERROR_SUCCESS != status)
    {
        hDevKey = NULL;
        BIBDRV_RTL_PRINT((TEXT("BIBDRV:OpenDriverKey RegOpenKeyEx - DevKey(HLM\\%s) returned %d!!!\r\n"),
                        DevKey, status));
    }

    RegCloseKey(hActive);

    return hDevKey;
}


/**
 *  @anchor GetFolderName
 *
 *  @brief  Function to retrieve the folder name value from the driver key
 *          The folder name is used by File System Driver to name this disk volume.
 *
 *  @param  pDisk   BIBDRV driver own structure pointer
 *  @param  FolderName
 *  @param  cBytes
 *  @param  pcBytes
 *
 *  @return TRUE    GetFolderName is completed.
 *  @return FALSE   GetFolderName is failed.
 */
static BOOL
GetFolderName(PDISK pDisk,
            LPWSTR FolderName,
            DWORD cBytes,
            DWORD *pcBytes)
{
    HKEY DriverKey = NULL;
    DWORD ValType = 0;
    DWORD status = 0;

    DriverKey = OpenDriverKey(pDisk->d_ActivePath);

    if (NULL != DriverKey)
    {
        *pcBytes = cBytes;
        status = RegQueryValueEx(DriverKey,     // Handle to a currently open key
                                TEXT("Folder"), // Pointer to quary
                                NULL,           // Reserved - set to NULL
                                &ValType,       // Pointer to type of data
                                (PUCHAR)FolderName, // Pointer to data
                                pcBytes);       // the Length of data

        if (ERROR_SUCCESS != status)
        {
            BIBDRV_RTL_PRINT((TEXT("BIBDRV:GetFolderName - RegQueryValueEx(Folder) returned %d\r\n"),
                            status));

            *pcBytes = 0;
        }
        else
        {
            BIBDRV_RTL_PRINT((TEXT("BIBDRV:GetFolderName - FolderName = %s, length = %d\r\n"),
                            FolderName, *pcBytes));

            *pcBytes += sizeof(WCHAR); // account for terminating 0.
        }

        RegCloseKey(DriverKey);

        if ((ERROR_SUCCESS != status) || (0 == *pcBytes))
        {
            return FALSE;
        }

        return TRUE;
    }

    return FALSE;
}


/**
 *  @anchor GetFSDName
 *
 *  @brief  Function to retrieve the FSD(file system driver) value from the
 *          driver key. The FSD is used to load file system driver.
 *
 *  @param  pDisk   BIBDRV driver own structure pointer
 *  @param  FSDName
 *  @param  cBytes
 *  @param  pcBytes
 *
 *  @return TRUE    GetFSDName is completed.
 *  @return FALSE   GetFSDName is failed.
 */
static BOOL
GetFSDName(PDISK pDisk,
         LPWSTR FSDName,
         DWORD cBytes,
         DWORD *pcBytes)
{
    HKEY DriverKey = NULL;
    DWORD ValType = 0;
    DWORD status = 0;

    DriverKey = OpenDriverKey(pDisk->d_ActivePath);

    if (NULL != DriverKey)
    {
        *pcBytes = cBytes;
        status = RegQueryValueEx(DriverKey,     // Handle to a currently open key
                                TEXT("FSD"),    // Pointer to quary
                                NULL,           // Reserved - set to NULL
                                &ValType,       // Pointer to type of data
                                (PUCHAR)FSDName,// Pointer to data
                                pcBytes);       // the Length of data

        if (ERROR_SUCCESS != status)
        {
            BIBDRV_RTL_PRINT((TEXT("BIBDRV:GetFSDName - RegQueryValueEx(FSD) returned %d\r\n"),
                            status));
            *pcBytes = 0;
        }
        else
        {
            BIBDRV_RTL_PRINT((TEXT("BIBDRV:GetFSDName - FSDName = %s, length = %d\r\n"),
                            FSDName, *pcBytes));

            *pcBytes += sizeof(WCHAR); // account for terminating 0.
        }

        RegCloseKey(DriverKey);

        if ((ERROR_SUCCESS != status) || (0 == *pcBytes))
        {
            return FALSE;
        }

        return TRUE;
    }

    return FALSE;
}


static BOOL
GetDeviceInfo(PDISK pDisk,
            PSTORAGEDEVICEINFO psdi)
{
    HKEY DriverKey = NULL;
    DWORD ValType = 0;
    DWORD status = 0;
    DWORD dwSize = 0;

    DriverKey = OpenDriverKey(pDisk->d_ActivePath);

    if (DriverKey)
    {
        dwSize = sizeof(psdi->szProfile);
        status = RegQueryValueEx(DriverKey,     // Handle to a currently open key
                                TEXT("Profile"),// Pointer to query
                                NULL,           // Reserved - set to NULL
                                &ValType,       // Pointer to type of data
                                (LPBYTE)psdi->szProfile,    // Pointer to data
                                &dwSize);       // the Length of data

        if ((status != ERROR_SUCCESS) || (dwSize > sizeof(psdi->szProfile)))
        {
            BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] GetFolderName - RegQueryValueEx(Profile) returned %d\r\n"),
                            status));
            wcscpy( psdi->szProfile, L"Default");
        }
        else
        {
            BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] GetProfileName - Profile = %s, length = %d\r\n"),
                            psdi->szProfile, dwSize));
        }
        RegCloseKey(DriverKey);
    }

    psdi->cbSize        = sizeof(STORAGEDEVICEINFO);
    psdi->dwDeviceClass = STORAGE_DEVICE_CLASS_BLOCK;
    psdi->dwDeviceType  = STORAGE_DEVICE_TYPE_ATA;
    psdi->dwDeviceFlags = STORAGE_DEVICE_FLAG_READWRITE;

    return TRUE;
}


/**
 *  @anchor CloseDisk
 *
 *  @brief  free all resources associated with the specified disk.
 *
 *  @param  pDisk   BIBDRV driver own structure pointer
 */
static VOID
CloseDisk(PDISK pDisk)
{
    PDISK pd = NULL;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++CloseDisk() pDisk=0x%x\r\n"), pDisk));

    // Remove it from the global list of disks
    //
    EnterCriticalSection(&gDiskCrit);

    if (pDisk == gDiskList)
    {
        gDiskList = pDisk->pd_next;
    }
    else
    {
        pd = gDiskList;
        while (pd->pd_next != NULL)
        {
            if (pd->pd_next == pDisk)
            {
                pd->pd_next = pDisk->pd_next;
                break;
            }
            pd = pd->pd_next;
        }
    }

    LeaveCriticalSection(&gDiskCrit);

    // Try to ensure this is the only thread holding the disk crit sec
    //
    Sleep(50);
    EnterCriticalSection(&(pDisk->d_DiskCardCrit));
    LeaveCriticalSection(&(pDisk->d_DiskCardCrit));
    DeleteCriticalSection(&(pDisk->d_DiskCardCrit));
    LocalFree(pDisk);

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --CloseDisk() pDisk=0x%x\r\n"), pDisk));
}


static void
ViewPage(UCHAR *pBuf)
{
    UINT nIdx1 = 0, nIdx2 = 0;

    BIBDRV_RTL_PRINT((TEXT("=======================================================================\r\n")));
    for (nIdx1 = 0; nIdx1 < (512/16); nIdx1 ++)
    {
        BIBDRV_RTL_PRINT((TEXT("%02X : "), nIdx1));
        for (nIdx2 = 0; nIdx2 < 16; nIdx2 ++)
        {
            BIBDRV_RTL_PRINT((TEXT("%02X "), pBuf[nIdx1 * 16 + nIdx2]));
        }
        BIBDRV_RTL_PRINT((TEXT("\r\n"), nIdx1));
    }
    BIBDRV_RTL_PRINT((TEXT("=======================================================================\r\n")));
}


/**
 *  @anchor DoDiskRead
 *
 *  @brief  Do read operation from SD/MMC memory.
 *
 *  @param  pDisk   BIBDRV driver own structure pointer
 *  @param  pData   PSQ_REQ structure pointer,it contains request information
 *                  for read operations
 *
 *  @return ERROR_SUCCESS   DoDiskRead is completed.
 */
static DWORD
DoDiskRead(PDISK pDisk,
           PVOID pData)
{
    DWORD status = ERROR_SUCCESS;
    DWORD num_sg = 0;
    DWORD bytes_this_sg = 0;
    PSG_REQ pSgr = NULL;
    PSG_BUF pSg = NULL;
    PUCHAR pBuf = NULL;
    UINT nSecCount = 0;
    UINT32 nCount = 0;
    static UINT nAccessCnt = 0;
    PUCHAR tempBuf = NULL;
    UINT32 i = 0;
	DWORD dwStartSector = 0;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++DoDiskRead()\r\n")));

    pSgr = (PSG_REQ) pData;

    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  ========= DoDiskRead Request Info ========= \r\n")));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSgr->sr_start    = %d(0x%x)\r\n"), pSgr->sr_start, pSgr->sr_start));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSgr->sr_num_sec  = %d\r\n"),       pSgr->sr_num_sec));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSgr->sr_num_sg   = %d\r\n"),       pSgr->sr_num_sg));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tlast sector num   = %d\r\n"),       pSgr->sr_start + pSgr->sr_num_sec - 1));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSgr->sr_status   = 0x%x\r\n"),     pSgr->sr_status));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  =========================================== \r\n")));

    // Scatter/Gather buffer Bound Check
    if (pSgr->sr_num_sg > MAX_SG_BUF)
    {
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] Scatter/Gather buffer Bound Check Fail (Too many buffers)\r\n")));
        status = ERROR_INVALID_PARAMETER;
        goto ddi_exit;
    }

    status = ERROR_SUCCESS;
    num_sg = pSgr->sr_num_sg;
    pSg = &(pSgr->sr_sglist[0]);

    if (num_sg > 1)
    {
        bytes_this_sg = 0 ;

        for (i = 0; i < num_sg; i++)
            bytes_this_sg += (pSgr->sr_sglist[i]).sb_len;

        nSecCount = ((bytes_this_sg - 1) / pDisk->d_DiskInfo.di_bytes_per_sect) + 1;
    }
	else if (num_sg == 1)
    {
	    bytes_this_sg = pSg->sb_len;
	    pBuf = MapPtrToProcess((LPVOID)pSg->sb_buf, GetCallerProcess());
        nSecCount = ((bytes_this_sg - 1) / pDisk->d_DiskInfo.di_bytes_per_sect) + 1;
    }

    if ((pSgr->sr_start + pSgr->sr_num_sec - 1) > pDisk->d_DiskInfo.di_total_sectors)
    {
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] DoDiskRead::Request Sector OOB Check Fail(sector exceeded)\r\n")));
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] - Disk Totol Sectors        = 0x%xd\r\n"), pDisk->d_DiskInfo.di_total_sectors + MBRSTARTSECTOR));
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] - Requested pSgr->sr_start  = 0x%x\r\n"), pSgr->sr_start));
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] - Requested pSgr->sr_num_sec= 0x%x\r\n"), pSgr->sr_num_sec));
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] - Requested last sector num = 0x%x\r\n"), pSgr->sr_start + pSgr->sr_num_sec - 1));
       status = ERROR_INVALID_PARAMETER;

        goto ddi_exit;
    }
	if (num_sg > 1)
	{
        pBuf = (PUCHAR)malloc(nSecCount * 512);
	}

    if (bytes_this_sg == 0)
    {
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] WRITE::Buffer length is 0.\r\n")));
        status = ERROR_INVALID_PARAMETER;
        goto ddi_exit;
    }


	dwStartSector   = (pSgr->sr_start + MBRSTARTSECTOR);

    /**
     *  Read sectors from disk.
     */
    do
    {

        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  ----------------------------------- \r\n")));
        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tnum_sg        = %d\r\n"),     num_sg));
        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSg           = 0x%08x\r\n"), pSg));
        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tbytes_this_sg = %d\r\n"),     bytes_this_sg));
        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSg->sb_buf   = 0x%08x\r\n"), pSg->sb_buf));
        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpBuf          = 0x%08x\r\n"), pBuf));
        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  ----------------------------------- \r\n")));

        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] DoDiskRead StartSector=%d, nNumOfScts=%d, bytes_this_sg=%d\r\n"),
                        pSgr->sr_start, nSecCount, bytes_this_sg));

        if (nSecCount <= MAX_READ_WRITE_SECTOR)
        {
            status = ERROR_SUCCESS;

            GetMutex(g_hMutex);

            #if USE_DMA
            while (SDHC_READ_DMA(dwStartSector, nSecCount, (UINT32)g_PhyDMABufferAddr.LowPart) != TRUE)
            #else
            while (SDHC_READ(dwStartSector, nSecCount, (UINT32)pBuf) != TRUE)
            #endif  // USE_DMA
            {
                if (status == ERROR_SUCCESS)
                {
                    status = ERROR_INVALID_PARAMETER;
                    while(!SDHC_INIT())
                    {
                    }
                }
                else
                {
                    ReleaseMutex(g_hMutex);
                    goto ddi_exit;
                }
            }

            ReleaseMutex(g_hMutex);

            #if USE_DMA
            memcpy(pBuf, g_pVirtDMABufferAddr, bytes_this_sg);
            #endif  // USE_DMA

            status = ERROR_SUCCESS;

        }
        else
        {
            #if USE_DMA
            tempBuf = pBuf; // to copy data from DMA buffer repeatedly.
            #endif  // USE_DMA

            BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] trans sec count is bigger than MAX\r\n")));

            for (nCount = 0; nSecCount >= MAX_READ_WRITE_SECTOR ; nCount++, nSecCount -= MAX_READ_WRITE_SECTOR )
            {
                status = ERROR_SUCCESS;

                GetMutex(g_hMutex);

                #if USE_DMA
                while (SDHC_READ_DMA(dwStartSector + (nCount * MAX_READ_WRITE_SECTOR), MAX_READ_WRITE_SECTOR, (UINT32)g_PhyDMABufferAddr.LowPart) != TRUE)
                #else
                while (SDHC_READ(dwStartSector + (nCount * MAX_READ_WRITE_SECTOR), MAX_READ_WRITE_SECTOR, (UINT32)pBuf + (UINT32)(nCount * MAX_READ_WRITE_SECTOR * 512)) != TRUE)
                #endif  // USE_DMA
                {
                    if (status == ERROR_SUCCESS)
                    {
                        status = ERROR_INVALID_PARAMETER;
	                    while(!SDHC_INIT())
	                    {
	                    }
                    }
                    else
                    {
                        ReleaseMutex(g_hMutex);
                        goto ddi_exit;
                    }
                }

                #if USE_DMA
                memcpy(tempBuf, g_pVirtDMABufferAddr, MAX_READ_WRITE_SECTOR * 512);
                (UINT32)(tempBuf) = (UINT32)(tempBuf) + (UINT32)(MAX_READ_WRITE_SECTOR * 512);
                #endif  // USE_DMA

                ReleaseMutex(g_hMutex);
            }
            if (nSecCount != 0)
            {
                status = ERROR_SUCCESS;

                GetMutex(g_hMutex);

                #if USE_DMA
                while (SDHC_READ_DMA(dwStartSector + (nCount * MAX_READ_WRITE_SECTOR), nSecCount, (UINT32)g_PhyDMABufferAddr.LowPart) != TRUE)
                #else
                while (SDHC_READ(dwStartSector + (nCount * MAX_READ_WRITE_SECTOR), nSecCount, (UINT32)pBuf + (UINT32)(nCount * MAX_READ_WRITE_SECTOR * 512)) != TRUE)
                #endif  // USE_DMA
                {
                    if (status == ERROR_SUCCESS)
                    {
                        status = ERROR_INVALID_PARAMETER;
	                    while(!SDHC_INIT())
	                    {
	                    }
                    }
                    else
                    {
                        if (num_sg > 1)
                        {

                        }
                        ReleaseMutex(g_hMutex);
                        goto ddi_exit;
                    }
                }

                #if USE_DMA
                memcpy(tempBuf, g_pVirtDMABufferAddr, nSecCount * 512);
                #endif  // USE_DMA

                ReleaseMutex(g_hMutex);
            }

            status = ERROR_SUCCESS;
        }

        if (num_sg > 1)
        {
            tempBuf = pBuf;
            for (i = 0; i < num_sg; i++)
            {
                memcpy(MapPtrToProcess((LPVOID)((pSgr->sr_sglist[i]).sb_buf), GetCallerProcess()), tempBuf,
                    (pSgr->sr_sglist[i]).sb_len);
                tempBuf += (pSgr->sr_sglist[i]).sb_len;
            }

            free(pBuf);
        }

    } while (0);

ddi_exit:

    if ((num_sg > 1) && (status != ERROR_SUCCESS))
    {
        free(pBuf);
    }

    pSgr->sr_status = status;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --DoDiskRead()\r\n")));

    return status;
}


/**
 *  @anchor DoDiskWrite
 *
 *  @brief  Do Write operation To SD/MMC memory
 *
 *  @param  pDisk   BIBDRV driver own structure pointer
 *  @param  pData   PSQ_REQ structure pointer,it contains request information
 *                  for read operations
 *
 *  @return ERROR_SUCCESS   DoDiskWrite is completed.
 */
static DWORD
DoDiskWrite(PDISK pDisk,
            PVOID pData)
{
    DWORD status = ERROR_SUCCESS;
    DWORD num_sg = 0, i = 0;
    DWORD bytes_this_sg = 0;
    PSG_REQ pSgr = NULL;
    PSG_BUF pSg = NULL;
    PUCHAR pBuf = NULL;
    UINT nSecCount = 0;
    UINT32 nCount = 0;
    static UINT nAccessCnt = 0;
    PUCHAR tempBuf = NULL;
	DWORD dwStartSector = 0;

    pSgr = (PSG_REQ) pData;

    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  ========= DoDiskWrite Request Info ========= \r\n")));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSgr->sr_start    = %d(0x%x)\r\n"), pSgr->sr_start, pSgr->sr_start));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSgr->sr_num_sec  = %d\r\n"),       pSgr->sr_num_sec));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSgr->sr_num_sg   = %d\r\n"),       pSgr->sr_num_sg));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tlast sector num   = %d\r\n"),       pSgr->sr_start + pSgr->sr_num_sec - 1));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  \tpSgr->sr_status   = 0x%x\r\n"),     pSgr->sr_status));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  =========================================== \r\n")));

    // Scatter/Gather buffer Bound Check
    if (pSgr->sr_num_sg > MAX_SG_BUF)
    {
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] Scatter/Gather buffer Bound Check Fail (Too many buffers)\r\n")));
        status = ERROR_INVALID_PARAMETER;
        goto ddi_exit;
    }

    status = ERROR_SUCCESS;
    num_sg = pSgr->sr_num_sg;
    pSg = &(pSgr->sr_sglist[0]);

    BIBDRV_INF_PRINT((TEXT("[SDMMC:INF]  ----------------------------------- \r\n")));
    BIBDRV_INF_PRINT((TEXT("[SDMMC:INF]  \tnum_sg        = %d\r\n"),     num_sg));
    BIBDRV_INF_PRINT((TEXT("[SDMMC:INF]  \tpSg           = 0x%08x\r\n"), pSg));
    BIBDRV_INF_PRINT((TEXT("[SDMMC:INF]  \tbytes_this_sg = %d\r\n"),     bytes_this_sg));
    BIBDRV_INF_PRINT((TEXT("[SDMMC:INF]  \tpSg->sb_buf   = 0x%08x\r\n"), pSg->sb_buf));
    BIBDRV_INF_PRINT((TEXT("[SDMMC:INF]  \tpBuf          = 0x%08x\r\n"), pBuf));
    BIBDRV_INF_PRINT((TEXT("[SDMMC:INF]  ----------------------------------- \r\n")));

    if (num_sg > 1)
    {
        bytes_this_sg = 0 ;

        for (i = 0; i < num_sg; i++)
            bytes_this_sg += (pSgr->sr_sglist[i]).sb_len;

        nSecCount = ((bytes_this_sg - 1) / pDisk->d_DiskInfo.di_bytes_per_sect) + 1;
    }
	else if (num_sg == 1)
    {
	    bytes_this_sg = pSg->sb_len;
	    pBuf = MapPtrToProcess((LPVOID)pSg->sb_buf, GetCallerProcess());
        nSecCount = ((bytes_this_sg - 1) / pDisk->d_DiskInfo.di_bytes_per_sect) + 1;
    }

    /**
     * Make sure request doesn't exceed the disk
     */
    if ((pSgr->sr_start + nSecCount - 1) > pDisk->d_DiskInfo.di_total_sectors)
    {
        BIBDRV_ERR_PRINT((TEXT("[SDMMC:ERR]  Request Sector OOB Check Fail(sector exceeded)\r\n")));
        BIBDRV_ERR_PRINT((TEXT("[SDMMC:ERR]  - Disk Totol Sectors        = %d\r\n"), pDisk->d_DiskInfo.di_total_sectors));
        BIBDRV_ERR_PRINT((TEXT("[SDMMC:ERR]  - Requested pSgr->sr_start  = %d\r\n"), pSgr->sr_start));
        BIBDRV_ERR_PRINT((TEXT("[SDMMC:ERR]  - Requested pSgr->sr_num_sec= %d\r\n"), pSgr->sr_num_sec));
        BIBDRV_ERR_PRINT((TEXT("[SDMMC:ERR]  - Requested last sector num = %d\r\n"), pSgr->sr_start + pSgr->sr_num_sec - 1));
        status = ERROR_INVALID_PARAMETER;
        goto ddi_exit;
    }

	if (num_sg > 1)
	{
        pBuf = (PUCHAR)malloc(nSecCount * 512);
        tempBuf = pBuf;

        for (i = 0; i < num_sg; i++)
        {
            memcpy(tempBuf, MapPtrToProcess((LPVOID)((pSgr->sr_sglist[i]).sb_buf), GetCallerProcess()),
                (pSgr->sr_sglist[i]).sb_len);
            tempBuf += (pSgr->sr_sglist[i]).sb_len;
        }
	}

    if (bytes_this_sg == 0)
    {
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR] WRITE::Buffer length is 0.\r\n")));
        status = ERROR_INVALID_PARAMETER;
        goto ddi_exit;
    }

    dwStartSector = pSgr->sr_start + MBRSTARTSECTOR;

    /**
     *  Read sectors from disk.
     */
    do
    {
        if (nSecCount <= MAX_READ_WRITE_SECTOR)
        {
            status = ERROR_SUCCESS;

            #if USE_DMA
            memcpy(g_pVirtDMABufferAddr, pBuf, bytes_this_sg);
            #endif  // USE_DMA

            GetMutex(g_hMutex);

            #if USE_DMA
            while (SDHC_WRITE_DMA(dwStartSector, nSecCount, (UINT32)g_PhyDMABufferAddr.LowPart) != TRUE)
            #else
            while (SDHC_WRITE(dwStartSector, nSecCount, (UINT32)pBuf) != TRUE)
            #endif  // USE_DMA
            {
                if (status == ERROR_SUCCESS)
                {
                    status = ERROR_INVALID_PARAMETER;
                    while(!SDHC_INIT())
                    {
                    }
                }
                else
                {
                    ReleaseMutex(g_hMutex);
                    goto ddi_exit;
                }
            }

            ReleaseMutex(g_hMutex);

            status = ERROR_SUCCESS;
        }
        else
        {
            for (nCount = 0; nSecCount >= MAX_READ_WRITE_SECTOR; nCount++, nSecCount -= MAX_READ_WRITE_SECTOR)
            {
                status = ERROR_SUCCESS;

                #if USE_DMA
                memcpy(g_pVirtDMABufferAddr, pBuf + (nCount * MAX_READ_WRITE_SECTOR*512), MAX_READ_WRITE_SECTOR * 512);
                #endif  // USE_DMA

                GetMutex(g_hMutex);

                #if USE_DMA
                while (SDHC_WRITE_DMA(dwStartSector + (nCount * MAX_READ_WRITE_SECTOR), MAX_READ_WRITE_SECTOR, (UINT32)g_PhyDMABufferAddr.LowPart) != TRUE)
                #else
                while (SDHC_WRITE(dwStartSector + (nCount * MAX_READ_WRITE_SECTOR), MAX_READ_WRITE_SECTOR, (UINT32)pBuf + (UINT32)(nCount * MAX_READ_WRITE_SECTOR * 512)) != TRUE)
                #endif
                {
                    if ( status == ERROR_SUCCESS )
                    {
                        status = ERROR_INVALID_PARAMETER;
	                    while(!SDHC_INIT())
	                    {
	                    }
					}
                    else
                    {
                        ReleaseMutex(g_hMutex);
                        goto ddi_exit;
                    }
                }

                ReleaseMutex(g_hMutex);
            }

            if (nSecCount != 0)
            {
                status = ERROR_SUCCESS;

                #if USE_DMA
                memcpy(g_pVirtDMABufferAddr, pBuf + (nCount * MAX_READ_WRITE_SECTOR * 512), nSecCount * 512);
                #endif  // USE_DMA

                GetMutex(g_hMutex);

                #if USE_DMA
                while (SDHC_WRITE_DMA(dwStartSector + (nCount * MAX_READ_WRITE_SECTOR), nSecCount, (UINT32)g_PhyDMABufferAddr.LowPart) != TRUE)
                #else
                while (SDHC_WRITE(dwStartSector + (nCount * MAX_READ_WRITE_SECTOR), nSecCount, (UINT32)pBuf+(UINT32)(nCount * MAX_READ_WRITE_SECTOR * 512)) != TRUE)
                #endif  // USE_DMA
                {
                    if ( status == ERROR_SUCCESS )
                    {
                        status = ERROR_INVALID_PARAMETER;
	                    while(!SDHC_INIT())
	                    {
	                    }
                    }
                    else
                    {
                        ReleaseMutex(g_hMutex);
                        goto ddi_exit;
                    }
                }

                ReleaseMutex(g_hMutex);
            }

            status = ERROR_SUCCESS;
        }

        if (num_sg > 1)
        {
            free(pBuf);
        }
    }  while (0);

ddi_exit:

    if ( (status != ERROR_SUCCESS) && (num_sg > 1) )
        free(pBuf);

    pSgr->sr_status = status;

    BIBDRV_INF_PRINT((TEXT("[BIBDRV:OUT] --DoDiskWrtie()\r\n")));

    return status;
}


/**
 *  @anchor GetDiskInfo
 *
 *  @brief  Get disk information from pDisk structure.
 *
 *  @param  pDisk   BIBDRV driver own structure pointer
 *  @param  pInfo   DISK Information structure pointer
 *
 *  @return ERROR_SUCCESS   GetDiskInfo is completed.
 */
static DWORD
GetDiskInfo(PDISK pDisk,
            PDISK_INFO pInfo)
{
    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++GetDiskInfo()\r\n")));

    memcpy(pInfo, &(pDisk->d_DiskInfo), sizeof(DISK_INFO));
    pInfo->di_flags &= ~DISK_INFO_FLAG_UNFORMATTED;

    BIBDRV_INF_PRINT((TEXT("[BIBDrv:INF:GetDiskInfo] \tpInfo->di_total_sectors    =%d\r\n"), pInfo->di_total_sectors));
    BIBDRV_INF_PRINT((TEXT("[BIBDrv:INF:GetDiskInfo] \tpInfo->di_bytes_per_sect   =%d\r\n"), pInfo->di_bytes_per_sect));
    BIBDRV_INF_PRINT((TEXT("[BIBDrv:INF:GetDiskInfo] \tpInfo->di_cylinders        =%d\r\n"), pInfo->di_cylinders));
    BIBDRV_INF_PRINT((TEXT("[BIBDrv:INF:GetDiskInfo] \tpInfo->di_heads            =%d\r\n"), pInfo->di_heads));
    BIBDRV_INF_PRINT((TEXT("[BIBDrv:INF:GetDiskInfo] \tpInfo->di_sectors          =%d\r\n"), pInfo->di_sectors));
    BIBDRV_INF_PRINT((TEXT("[BIBDrv:INF:GetDiskInfo] \tpInfo->di_flags            =%X\r\n"), pInfo->di_flags));

    // The device supports demand paging.
    // Read and write requests are synchronous and do not involve
    // memory manager calls, loader operations, or thread switches.
    //pInfo->di_flags |= DISK_INFO_FLAG_PAGEABLE;

    // The device does not support CHS addressing;
    // values for di_cylinders, di_heads, and di_sectors may be simulations,
    // estimations, or not provided.
    //pInfo->di_flags |= DISK_INFO_FLAG_CHS_UNCERTAIN;

    // The device requires a low-level format with the IOCTL_DISK_FORMAT_MEDIA.
    // The FAT file system currently ignores this flag.

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --GetDiskInfo()\r\n")));

    return ERROR_SUCCESS;
}


/**
 *  @anchor SetDiskInfo
 *
 *  @brief  Set disk information to pDisk structure.
 *
 *  @param  pDisk   BIBDRV driver own structure pointer
 *  @param  pInfo   DISK Information structure pointer
 *
 *  @return ERROR_SUCCESS   SetDiskInfo is completed.
 */
static DWORD
SetDiskInfo(PDISK pDisk,
            PDISK_INFO pInfo)
{
    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++SetDiskInfo()\r\n")));

    pDisk->d_DiskInfo = *pInfo;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --SetDiskInfo()\r\n")));

    return ERROR_SUCCESS;
}


/**
 *  @anchor CreateDiskObject
 *
 *  @brief  Create a DISK structure, init some fields and link it.
 *
 *  @return PDISK   new DISK structure pointer
 */
static PDISK
CreateDiskObject(VOID)
{
    PDISK pDisk = NULL;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++CreateDiskObject()\r\n")));

    pDisk = LocalAlloc(LPTR, sizeof(DISK));

    if (pDisk != NULL)
    {
        pDisk->hDevice = NULL;
        pDisk->d_OpenCount = 0;
        pDisk->d_ActivePath = NULL;

        // Initialize CiriticalSection for Disk Object
        InitializeCriticalSection(&(pDisk->d_DiskCardCrit));

        EnterCriticalSection(&gDiskCrit);
        pDisk->pd_next = gDiskList;
        gDiskList = pDisk;
        LeaveCriticalSection(&gDiskCrit);
    }

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --CreateDiskObject()\r\n")));

    return pDisk;
}


/**
 *  @anchor IsValidDisk
 *
 *  @brief  This function checks Disk validatio.
 *
 *  @param  pDisk   Pinter to disk handle
 *
 *  @return TRUE    pDisk is valid.
 *  @return FALSE   pDisk is invalid.
 */
static BOOL
IsValidDisk(PDISK pDisk)
{
#if 0
    PDISK   pd;
    BOOL    bRet = FALSE;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++IsValidDisk()\r\n")));

    EnterCriticalSection(&gDiskCrit);

    pd = gDiskList;
    while (pd)
    {
        if (pd == pDisk)
        {
            bRet = TRUE;
            break;
        }
        pd = pd->pd_next;
    }

    LeaveCriticalSection(&gDiskCrit);

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --IsValidDisk()\r\n")));

    return bRet;
#endif

    return TRUE;
}


/**
 *  @anchor BIBDRV_Entry
 *
 *  @brief  This function is BIBDRV.dll Entry Point
 *
 *  @param  DllInstance
 *  @param  Reason
 *  @param  Reserved
 *
 *  @return TRUE    BIBDRV_Entry is completed.
 */
BOOL WINAPI
BIBDRV_Entry(HINSTANCE DllInstance,
            INT Reason,
            LPVOID Reserved)
{
    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++BIBDRVEntry()\r\n")));

    switch(Reason) {
        case DLL_PROCESS_ATTACH:
            BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF]  DLL_PROCESS_ATTACH\r\n")));
            DEBUGREGISTER(DllInstance);
            break;

        case DLL_PROCESS_DETACH:
            BIBDRV_ERR_PRINT((TEXT("[BIBDRV:INF]  DLL_PROCESS_DETACH\r\n")));
            DeleteCriticalSection(&gDiskCrit);
            break;
    }

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --BIBDRVEntry()\r\n")));
    return TRUE;
}


/**
 *  @anchor GetROPartitionInfo
 *
 *  @brief  This function prints MBR contents.
 *
 *  @param  pDisk   Disk handle
 */
#include <Bootpart.h>
#define NUM_PARTS           (4)
#define SIZE_END_SIG        (2)
#define PARTTABLE_OFFSET    (512 - SIZE_END_SIG - (sizeof(PARTENTRY) * NUM_PARTS))

void
GetROPartitionInfo(PDISK pDisk)
{
    UCHAR aBuf[528] = {0,};
    UCHAR *pBuf = NULL;
    PARTENTRY *pPartEntry = NULL;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] ++GetROPartitionInfo()\r\n")));

    pBuf = &aBuf[0];
    pPartEntry = (PARTENTRY *)(pBuf + PARTTABLE_OFFSET);

    do {
        SDHC_READ(MBRSTARTSECTOR,1,(UINT32)pBuf);

        /**
         *  g_pbMBRSector[0] = 0xE9;
         *  g_pbMBRSector[1] = 0xfd;
         *  g_pbMBRSector[2] = 0xff;
         *  g_pbMBRSector[SECTOR_SIZE-2] = 0x55;
         *  g_pbMBRSector[SECTOR_SIZE-1] = 0xAA;
         */
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] MBR MAGIC CODE (First): 0x%x,0x%x,0x%x\r\n"), aBuf[0], aBuf[1], aBuf[2]));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] MBR MAGIC CODE (Last) : 0x%x,0x%x\r\n"),      aBuf[512 - 2], aBuf[512 - 1]));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_BootInd      = 0x%X\r\n"), pPartEntry[0].Part_BootInd));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstHead    = 0x%X\r\n"), pPartEntry[0].Part_FirstHead));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstSector  = 0x%X\r\n"), pPartEntry[0].Part_FirstSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstTrack   = 0x%X\r\n"), pPartEntry[0].Part_FirstTrack));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FileSystem   = 0x%X\r\n"), pPartEntry[0].Part_FileSystem));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastHead     = 0x%X\r\n"), pPartEntry[0].Part_LastHead));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastSector   = 0x%X\r\n"), pPartEntry[0].Part_LastSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastTrack    = 0x%X\r\n"), pPartEntry[0].Part_LastTrack));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_StartSector  = 0x%X\r\n"),   pPartEntry[0].Part_StartSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_TotalSectors = 0x%X\r\n"),   pPartEntry[0].Part_TotalSectors));

        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_BootInd      = 0x%X\r\n"), pPartEntry[1].Part_BootInd));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstHead    = 0x%X\r\n"), pPartEntry[1].Part_FirstHead));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstSector  = 0x%X\r\n"), pPartEntry[1].Part_FirstSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstTrack   = 0x%X\r\n"), pPartEntry[1].Part_FirstTrack));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FileSystem   = 0x%X\r\n"), pPartEntry[1].Part_FileSystem));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastHead     = 0x%X\r\n"), pPartEntry[1].Part_LastHead));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastSector   = 0x%X\r\n"), pPartEntry[1].Part_LastSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastTrack    = 0x%X\r\n"), pPartEntry[1].Part_LastTrack));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_StartSector  = 0x%X\r\n"),   pPartEntry[1].Part_StartSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_TotalSectors = 0x%X\r\n"),   pPartEntry[1].Part_TotalSectors));

        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_BootInd      = 0x%X\r\n"), pPartEntry[2].Part_BootInd));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstHead    = 0x%X\r\n"), pPartEntry[2].Part_FirstHead));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstSector  = 0x%X\r\n"), pPartEntry[2].Part_FirstSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstTrack   = 0x%X\r\n"), pPartEntry[2].Part_FirstTrack));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FileSystem   = 0x%X\r\n"), pPartEntry[2].Part_FileSystem));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastHead     = 0x%X\r\n"), pPartEntry[2].Part_LastHead));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastSector   = 0x%X\r\n"), pPartEntry[2].Part_LastSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastTrack    = 0x%X\r\n"), pPartEntry[2].Part_LastTrack));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_StartSector  = 0x%X\r\n"),   pPartEntry[2].Part_StartSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_TotalSectors = 0x%X\r\n"),   pPartEntry[2].Part_TotalSectors));

        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_BootInd      = 0x%X\r\n"), pPartEntry[3].Part_BootInd));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstHead    = 0x%X\r\n"), pPartEntry[3].Part_FirstHead));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstSector  = 0x%X\r\n"), pPartEntry[3].Part_FirstSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FirstTrack   = 0x%X\r\n"), pPartEntry[3].Part_FirstTrack));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_FileSystem   = 0x%X\r\n"), pPartEntry[3].Part_FileSystem));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastHead     = 0x%X\r\n"), pPartEntry[3].Part_LastHead));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastSector   = 0x%X\r\n"), pPartEntry[3].Part_LastSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_LastTrack    = 0x%X\r\n"), pPartEntry[3].Part_LastTrack));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_StartSector  = 0x%X\r\n"),   pPartEntry[3].Part_StartSector));
        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] Part_TotalSectors = 0x%X\r\n"),   pPartEntry[3].Part_TotalSectors));

        BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] MBR Start Sector = 0x%x\r\n"),  MBRSTARTSECTOR));

    } while(0);

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --GetROPartitionInfo()\r\n")));
}


/**
 *  @anchor InitDisk
 *
 *  @brief  This function initializes Disk handle.
 *
 *  @param  pDisk       Disk handle
 *  @param  ActiveKey   Pointer to active key
 *
 *  @return TRUE    InitDisk is completed.
 *  @return FALSE   InitDisk is failed.
 *
 *  @note   this function is called by DSK_Init.
 */
static BOOL
InitDisk(PDISK pDisk,
        LPTSTR ActiveKey)
{
    BOOL bRet = FALSE;

    #if USE_DMA
    DMA_ADAPTER_OBJECT Adapter;
    #endif  // USE_DMA

    g_hMutex = InitMutex(TEXT("HSMMC"));

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++InitDisk() Entered\r\n")));

    BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] SDHC_INIT++\n")));
    GetMutex(g_hMutex);
    while (!SDHC_INIT());
    ReleaseMutex(g_hMutex);
    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:INF] SDHC_INIT--\n")));

    pDisk->d_DiskInfo.di_total_sectors  = SECTOROFIMAGE + SECTOROFMBR;
    pDisk->d_DiskInfo.di_bytes_per_sect = 512;
    pDisk->d_DiskInfo.di_cylinders      = 1;
    pDisk->d_DiskInfo.di_heads          = 1;
    pDisk->d_DiskInfo.di_sectors        = pDisk->d_DiskInfo.di_total_sectors;
    pDisk->d_DiskInfo.di_flags          = DISK_INFO_FLAG_PAGEABLE | DISK_INFO_FLAG_CHS_UNCERTAIN;

    BIBDRV_RTL_PRINT((TEXT("[BIBDRV:INF] total_sectors    = 0x%x\r\n"), pDisk->d_DiskInfo.di_total_sectors));

    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] total_sectors    = %d\r\n"), pDisk->d_DiskInfo.di_total_sectors));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] bytes_per_sect   = %d\r\n"), pDisk->d_DiskInfo.di_bytes_per_sect));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] di_cylinders     = %d\r\n"), pDisk->d_DiskInfo.di_cylinders));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] di_heads         = %d\r\n"), pDisk->d_DiskInfo.di_heads));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] di_sectors       = %d\r\n"), pDisk->d_DiskInfo.di_sectors));
    BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] storage size     = %d bytes\r\n"),
                    pDisk->d_DiskInfo.di_total_sectors * pDisk->d_DiskInfo.di_bytes_per_sect));

    #if USE_DMA
	memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
	Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
	Adapter.InterfaceType = Internal;

	// Allocate DMA Buffer
	g_pVirtDMABufferAddr = HalAllocateCommonBuffer(&Adapter, MAX_READ_WRITE_SECTOR * 512, &g_PhyDMABufferAddr, FALSE);
	if (g_pVirtDMABufferAddr == NULL)
	{
		BIBDRV_ERR_PRINT((_T("[BIBDRV:ERR] MapDMABuffers() : DMA Buffer Allocation Failed\n\r")));
		bRet = FALSE;
	}
    BIBDRV_RTL_PRINT((_T("[BIBDRV:INF] This Driver is using DMA\n\r")));
    #endif  // USE_DMA

    bRet = TRUE;

    GetMutex(g_hMutex);
    GetROPartitionInfo(pDisk);

    ReleaseMutex(g_hMutex);

    return bRet;
}


/**
 *  @anchor DSK_Init
 *
 *  @brief  Create Disk Object, Initialize Disk Object
 *
 *  @param  dwContext   BIBDRV driver own structure pointer
 *
 *  @return context data for this Init instance
 */
DWORD
DSK_Init(DWORD dwContext)
{
    PDISK pDisk = NULL;
    LPWSTR ActivePath  = (LPWSTR)dwContext;
    LPWSTR ActivePath2 = (LPWSTR)dwContext;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++DSK_Init() Entered\r\n")));

    if (gDiskList == NULL)
    {
        InitializeCriticalSection(&gDiskCrit);
    }

    pDisk = CreateDiskObject();

    if (pDisk == NULL)
    {
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR]  LocalAlloc(PDISK) failed %d\r\n"), GetLastError()));

        return 0;
    }

    if (ActivePath)
    {
        if(FAILED(CeOpenCallerBuffer(
            (PVOID*) &ActivePath2,
            (LPVOID)ActivePath,
            wcslen(ActivePath) * sizeof(WCHAR) + sizeof(WCHAR),
            ARG_IO_PTR, FALSE)))
        {
            RETAILMSG(1, (TEXT("DSK_Init : CeOpenCallerBuffer Error \r\n")));
        }

        if (NULL != ActivePath2)
        {
            ActivePath = ActivePath2;
        }

        if (pDisk->d_ActivePath = LocalAlloc(LPTR, (wcslen(ActivePath) * sizeof(WCHAR)) + sizeof(WCHAR)))
        {
            // Copy Active Path to Dist structure
            wcscpy(pDisk->d_ActivePath, ActivePath);
        }

        BIBDRV_INF_PRINT((TEXT("[BIBDRV:INF] ActiveKey (copy) = %s (@ 0x%08X)\r\n"),
                        pDisk->d_ActivePath, pDisk->d_ActivePath));
    }

    EnterCriticalSection(&gDiskCrit);

    if (InitDisk(pDisk, ActivePath) != TRUE)
    {
        // If pDisk already memory allocated, it should be deallocated
        if (pDisk)
        {
            if (pDisk->d_ActivePath)
            {
                // Counter function of LocalAlloc
                LocalFree(pDisk->d_ActivePath);
                pDisk->d_ActivePath = NULL;
            }
            CloseDisk(pDisk);
        }
        LeaveCriticalSection(&gDiskCrit);
        return 0;
    }

    LeaveCriticalSection(&gDiskCrit);

    if(FAILED(CeCloseCallerBuffer(
            ActivePath2,
            ActivePath,
            wcslen(ActivePath) * sizeof(WCHAR) + sizeof(WCHAR),
            ARG_IO_PTR)))
    {
        RETAILMSG(1, (TEXT("DSK_Init : CeOpenCloseBuffer Error \r\n")));
    }

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --DSK_Init() returning pDisk=0x%x\r\n"), pDisk));

    return (DWORD)pDisk;
}


/**
 *  @anchor DSK_Close
 *
 *  @brief  This function Close Dis.
 *
 *  @param  Handle  Disk Handle
 *
 *  @return TRUE    DSK_Close is completed.
 *  @return FALSE   DSK_Close is failed.
 *
 *  @note   This function is called by DSK_Deinit.
 */
BOOL
DSK_Close(DWORD Handle)
{
    PDISK pDisk = (PDISK)Handle;
    BOOL bClose = FALSE;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++DSK_Close()\r\n")));

    do {
        if (!IsValidDisk(pDisk))
        {
            break;
        }

        EnterCriticalSection(&(pDisk->d_DiskCardCrit));

        pDisk->d_OpenCount--;

        if (pDisk->d_OpenCount <= 0)
        {
            pDisk->d_OpenCount = 0;
        }

        LeaveCriticalSection(&(pDisk->d_DiskCardCrit));

        bClose = TRUE;

    } while(0);

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --DSK_Close\r\n")));

    return bClose;
}


/**
 *  @anchor DSK_Deinit
 *
 *  @brief  This function deinitializes Disk.
 *
 *  @param  dwContext   Disk Handle
 *
 *  @return TRUE    DSK_Deinit is completed.
 *
 *  @note
 *      Device deinit - devices are expected to close down.
 *      The device manager does not check the return code.
 */
BOOL
DSK_Deinit(DWORD dwContext)
{
    PDISK pDisk = (PDISK)dwContext;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++DSK_Deinit()\r\n")));

    DSK_Close(dwContext);
    CloseDisk((PDISK)dwContext);

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --DSK_Deinit()\r\n")));

    return TRUE;
}


/**
 *  @anchor DSK_Open
 *
 *  @brief  This function opens Disk.
 *
 *  @param  dwData      Disk handle
 *  @param  dwAccess    Not used
 *  @param  dwShareMode Not used
 *
 *  @return Pointer of pDisk(disk handle)
 */
DWORD
DSK_Open(DWORD dwData,
         DWORD dwAccess,
         DWORD dwShareMode)
{
    PDISK pDisk = (PDISK)dwData;
    DWORD dwRet = 0;

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++DSK_Open(0x%x)\r\n"),dwData));

    do {
        if (IsValidDisk(pDisk) == FALSE)
        {
            BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR]  DSK_Open - Passed invalid disk handle\r\n")));
            break;
        }

        EnterCriticalSection(&(pDisk->d_DiskCardCrit));
        {
            pDisk->d_OpenCount++;
        }
        LeaveCriticalSection(&(pDisk->d_DiskCardCrit));

        dwRet = (DWORD)pDisk;

    } while(0);

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --DSK_Open(0x%x) returning %d\r\n"),dwData, dwRet));

    return dwRet;
}


/**
 *  @anchor DSK_IOControl
 *
 *  @brief  This function is Disk IO Control.
 *
 *  @param  Handle          Disk handle
 *  @param  dwIoControlCode IO Control Code
 *  @param  pInBuf          Pointer to input buffer
 *  @param  nInBufSize      Size of input buffer
 *  @param  pOutBuf         Pointer to output buffer
 *  @param  nOutBufSize     Size of output buffer
 *  @param  pBytesReturned  Pointer to byte returned
 *
 *  @return TRUE    DSK_IOControl is completed.
 *  @return FALSE   DSK_IOControl is failed.
 *
 *  @note
 *      I/O Control function - responds to info, read and write control codes
 *      The read and write take a scatter/gather list in pInBuf
 */
BOOL
DSK_IOControl(DWORD Handle,
            DWORD dwIoControlCode,
            PBYTE pInBuf,
            DWORD nInBufSize,
            PBYTE pOutBuf,
            DWORD nOutBufSize,
            PDWORD pBytesReturned)
{
    PSG_REQ pSG = NULL;
    PDISK pDisk = (PDISK)Handle;
    BOOL bRes  = TRUE;
    BOOL bPrintFlg = TRUE;

    EnterCriticalSection(&gDiskCrit);

    BIBDRV_LOG_PRINT((TEXT("[BIBDRV: IN] ++DSK_IOControl() (IO code=%x) 0x%x\r\n"), dwIoControlCode, Handle));

    // Disk Handle(pDisk) validation check
    if (IsValidDisk(pDisk) == FALSE)
    {
        SetLastError(ERROR_INVALID_HANDLE);
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR]  Invalid Disk\r\n")));
        bRes = FALSE;

        goto IOControlError;
    }

    // dwIoControlCode Print
    switch (dwIoControlCode)
    {
    case DISK_IOCTL_READ:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = DISK_IOCTL_READ\r\n")));
        break;

    case IOCTL_DISK_READ:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = IOCTL_DISK_READ\r\n")));
        break;

    case DISK_IOCTL_WRITE:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = DISK_IOCTL_WRITE\r\n")));
        break;

    case IOCTL_DISK_WRITE:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = IOCTL_DISK_WRITE\r\n")));
        break;

    case DISK_IOCTL_GETINFO:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = DISK_IOCTL_GETINFO\r\n")));
        break;

    case DISK_IOCTL_SETINFO:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = DISK_IOCTL_SETINFO\r\n")));
        break;

    case DISK_IOCTL_INITIALIZED:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = DISK_IOCTL_INITIALIZED\r\n")));
        break;

    case DISK_IOCTL_GETNAME:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = DISK_IOCTL_GETNAME\r\n")));
        break;

    case IOCTL_DISK_GETINFO:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = IOCTL_DISK_GETINFO\r\n")));
        break;

    case IOCTL_DISK_DEVICE_INFO:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = IOCTL_DISK_DEVICE_INFO\r\n")));
        break;

    case DISK_IOCTL_FORMAT_MEDIA:
    case IOCTL_DISK_FORMAT_MEDIA:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = IOCTL_DISK_FORMAT_MEDIA\r\n")));
    	SetLastError(ERROR_SUCCESS);
    	goto IOControlError;
        break;

    case IOCTL_DISK_FLUSH_CACHE:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = IOCTL_DISK_FLUSH_CACHE\r\n")));
        break;

    case IOCTL_DISK_DELETE_SECTORS:
        BIBDRV_LOG_PRINT((TEXT("[BIBDRV:LOG]  dwIoControlCode = IOCTL_DISK_DELETE_SECTORS\r\n")));
        break;
    }

    /**
     *  Check parameters
     */
    switch (dwIoControlCode)
    {
    case DISK_IOCTL_WRITE:
    case IOCTL_DISK_WRITE:
 	case DISK_IOCTL_READ:
    case IOCTL_DISK_READ:
    case DISK_IOCTL_GETINFO:
    case DISK_IOCTL_SETINFO:
    case DISK_IOCTL_INITIALIZED:
        if (nInBufSize == 0)
        {
            BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR]  DISK_IOCTL InBufSize is NULL\r\n")));
            SetLastError(ERROR_INVALID_PARAMETER);
            bRes = FALSE;
            goto IOControlError;
        }
        if (pInBuf == NULL)
        {
            BIBDRV_ERR_PRINT((TEXT("[BIBDRV:ERR]  DISK_IOCTL InBuf is NULL\r\n")));
            SetLastError(ERROR_INVALID_PARAMETER);
            bRes = FALSE;
            goto IOControlError;
        }
        break;

    case DISK_IOCTL_GETNAME:
    case IOCTL_DISK_GETINFO:
        if (pOutBuf == NULL)
        {
            SetLastError(ERROR_INVALID_PARAMETER);
            bRes = FALSE;
            goto IOControlError;
        }
        break;

    case IOCTL_DISK_DEVICE_INFO:
        if(!pInBuf || nInBufSize != sizeof(STORAGEDEVICEINFO))
        {
            SetLastError(ERROR_INVALID_PARAMETER);
            bRes = FALSE;
            goto IOControlError;
        }
        break;

    case IOCTL_DISK_GET_STORAGEID:
        ((PSTORAGE_IDENTIFICATION)pOutBuf)->dwSize = 0;//sizeof(STORAGE_IDENTIFICATION);
        ((PSTORAGE_IDENTIFICATION)pOutBuf)->dwFlags = SERIALNUM_INVALID;
        ((PSTORAGE_IDENTIFICATION)pOutBuf)->dwFlags |= MANUFACTUREID_INVALID;
        ((PSTORAGE_IDENTIFICATION)pOutBuf)->dwManufactureIDOffset=0;
        ((PSTORAGE_IDENTIFICATION)pOutBuf)->dwSerialNumOffset=0;
        bRes = TRUE;
		goto IOControlError;
        break;

    case IOCTL_DISK_FLUSH_CACHE:
        bRes = TRUE;
        goto IOControlError;

    case IOCTL_DISK_DELETE_SECTORS:
        bRes = TRUE;
        if (pInBuf == NULL || nInBufSize != sizeof(DELETE_SECTOR_INFO))
        {
            BIBDRV_LOG_PRINT((TEXT("[BIBDRV:ERR]  DISK_IOCTL IOCTL_DISK_DELETE_SECTORS(buffer is insufficient!!)\r\n")));
            SetLastError(ERROR_INVALID_PARAMETER);
            goto IOControlError;
        }
        SetLastError(ERROR_NOT_SUPPORTED);
        goto IOControlError;

    case IOCTL_DISK_FORMAT_MEDIA:
        bRes = TRUE;
        goto IOControlError;
		break;

    default:
        BIBDRV_ERR_PRINT((TEXT("[BIBDRV:MSG]  DSK_IOControl unkonwn code(%04x)\r\n"), dwIoControlCode));
        SetLastError(ERROR_INVALID_PARAMETER);
        bRes = FALSE;
        goto IOControlError;
    }

    // Execute dwIoControlCode
    //
    switch (dwIoControlCode)
    {
    case DISK_IOCTL_READ:
    case IOCTL_DISK_READ:
        pSG = (PSG_REQ)pInBuf;

        DoDiskRead(pDisk, (PVOID) pSG);
        if (ERROR_SUCCESS != pSG->sr_status)
        {
            SetLastError(pSG->sr_status);
            bRes = FALSE;
        }
        else
        {
            bRes = TRUE;
            if (pBytesReturned)
                *(pBytesReturned) = pDisk->d_DiskInfo.di_bytes_per_sect;
        }


        break;

    case DISK_IOCTL_WRITE:
    case IOCTL_DISK_WRITE:

        pSG = (PSG_REQ)pInBuf;

        DoDiskWrite(pDisk, (PVOID) pSG);
        if (ERROR_SUCCESS != pSG->sr_status)
        {
            SetLastError(pSG->sr_status);
            RETAILMSG(1,(TEXT("Write Error with error Code %d\n"),pSG->sr_status));
            bRes = FALSE;
        }
        else
        {
            bRes = TRUE;
            if (pBytesReturned)
                *(pBytesReturned) = pDisk->d_DiskInfo.di_bytes_per_sect;
        }
		break;

    case DISK_IOCTL_GETINFO:
        GetDiskInfo(pDisk, (PDISK_INFO) pInBuf);
        if (pBytesReturned)
            *(pBytesReturned) = sizeof(DISK_INFO);
        bRes = TRUE;
        break;

    case IOCTL_DISK_GETINFO:
        GetDiskInfo(pDisk, (PDISK_INFO) pOutBuf);
        if (pBytesReturned)
            *(pBytesReturned) = sizeof(DISK_INFO);
        bRes = TRUE;
        break;

    case DISK_IOCTL_SETINFO:
        SetDiskInfo(pDisk, (PDISK_INFO)pInBuf);
        if (pBytesReturned)
            *(pBytesReturned) = sizeof(DISK_INFO);
        bRes = TRUE;
        break;

    case DISK_IOCTL_GETNAME:
        bRes = GetFolderName(pDisk, (LPWSTR)pOutBuf, nOutBufSize, pBytesReturned);
        break;

    case IOCTL_DISK_DEVICE_INFO: // new ioctl for disk info
        bRes = GetDeviceInfo(pDisk, (PSTORAGEDEVICEINFO)pInBuf);
        if (pBytesReturned)
            *(pBytesReturned) = sizeof(STORAGEDEVICEINFO);
        break;
    case DISK_IOCTL_INITIALIZED:
        bRes = TRUE;
        break;

    default:
        RETAILMSG(1, (TEXT("-DSK_IOControl (default:0x%x) \r\n"), dwIoControlCode));
        SetLastError(ERROR_INVALID_PARAMETER);
        bRes = FALSE;
        break;
    }

IOControlError:
    LeaveCriticalSection(&gDiskCrit);
    BIBDRV_LOG_PRINT((TEXT("[BIBDRV:OUT] --DSK_IOControl()\r\n")));

    return bRes;
}


DWORD
DSK_Read(DWORD Handle, LPVOID pBuffer, DWORD dwNumBytes)
{
    BIBDRV_LOG_PRINT((TEXT("DSK_Read\r\n")));
    return 0;
}

DWORD
DSK_Write(DWORD Handle, LPCVOID pBuffer, DWORD dwNumBytes)
{
    BIBDRV_LOG_PRINT((TEXT("DSK_Write\r\n")));
    return 0;
}

DWORD
DSK_Seek(DWORD Handle, long lDistance, DWORD dwMoveMethod)
{
    BIBDRV_LOG_PRINT((TEXT("DSK_Seek\r\n")));
    return 0;
}

void
DSK_PowerUp(void)
{
}

void
DSK_PowerDown(void)
{
}

