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

📄 diskio.c

📁 WinCE下的ATADISK驱动
💻 C
📖 第 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.
//
/*++
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.

Module Name:  

    diskio.c

Abstract:  

    WINCE driver for PCMCIA ATA Disk cards

Functions:

Notes:


--*/
#include <windows.h>
#include <types.h>
#include <tchar.h>
#include <excpt.h>
#include <cardserv.h>
#include <cardapi.h>
#include <atapi.h>
#include <diskio.h>
#include <atadisk.h>
#include <devload.h>
#include <ceddk.h>

//
// This module contains the functions:
//  CloseDisk
//  ATAWaitForDisk
//  ATASetSector
//  ATARead
//  ATAWrite
//  DoDiskIO
//  PcmciaIntr
//  ATAIssueIdentify
//  GetDiskInfo
//  SetDiskInfo
//  ATAInitController
//  OpenDriverKey
//  GetFolderName
//  GetGeometry
//  UseCHSMode
//  InitDisk
//

//#define USE_INTERRUPT 1

#ifdef x86
#define ATA_READ_UCHAR(f,p) ((f & ATADISK_FLAG_MEMORY_MAPPED) ? READ_REGISTER_UCHAR(p) : READ_PORT_UCHAR(p))
#define ATA_READ_USHORT(f,p) ((f & ATADISK_FLAG_MEMORY_MAPPED) ? READ_REGISTER_USHORT(p) : READ_PORT_USHORT(p))
#define ATA_WRITE_UCHAR(f,p,b) ((f & ATADISK_FLAG_MEMORY_MAPPED) ? WRITE_REGISTER_UCHAR(p,b) : WRITE_PORT_UCHAR(p,b))
#define ATA_WRITE_USHORT(f,p,w) ((f & ATADISK_FLAG_MEMORY_MAPPED) ? WRITE_REGISTER_USHORT(p,w) : WRITE_PORT_USHORT(p,w))
#else
#define ATA_READ_UCHAR(f,p) READ_PORT_UCHAR(p)
#define ATA_READ_USHORT(f,p) READ_PORT_USHORT(p)
#define ATA_WRITE_UCHAR(f,p,b) WRITE_PORT_UCHAR(p,b)
#define ATA_WRITE_USHORT(f,p,w) WRITE_PORT_USHORT(p,w)
#endif

#define MIN(x,y) ((x < y) ? x : y)
#define MAX_SECT_CNT 64

BOOL IsCardInserted(CARD_SOCKET_HANDLE hSock);

//
// CloseDisk - finish and free all outstanding requests and free other resources
// associated with the specified disk
//
VOID
CloseDisk(
    PDISK pDisk
    )
{
    PDISK pd;

    DEBUGMSG(ZONE_IO, (TEXT("ATADISK:CloseDisk closing 0x%x\r\n"), pDisk));

    //
    // Remove it from the global list of disks
    //
    EnterCriticalSection(&v_DiskCrit);
    if (pDisk == v_DiskList) {
        v_DiskList = pDisk->d_next;
    } else {
        pd = v_DiskList;
        while (pd->d_next != NULL) {
            if (pd->d_next == pDisk) {
                pd->d_next = pDisk->d_next;
                break;
            }
            pd = pd->d_next;
        }
    }
    LeaveCriticalSection(&v_DiskCrit);

    DEBUGMSG(ZONE_IO, (TEXT("ATADISK:CloseDisk - freeing PCMCIA resources\r\n")));

    v_pfnCardReleaseConfiguration(pDisk->d_hPcmcia, pDisk->d_hSock);
    v_pfnCardReleaseIRQ(pDisk->d_hPcmcia, pDisk->d_hSock);
    SetEvent(pDisk->d_IRQEvent);
    pDisk->lPwrOff = -1;
    SetEvent( pDisk->hPwrEvent);
    Sleep(250);
    CloseHandle(pDisk->d_IRQEvent);
    CloseHandle(pDisk->hPwrEvent);
    v_pfnCardDeregisterClient(pDisk->d_hPcmcia);
    DeleteCriticalSection(&(pDisk->d_DiskCardCrit));
    if (pDisk->d_ActivePath) {
        LocalFree(pDisk->d_ActivePath);
    }
    LocalFree(pDisk);
    DEBUGMSG(ZONE_IO, (TEXT("ATADISK:CloseDisk done with 0x%x\r\n"), pDisk));
}    // CloseDisk


#ifdef DEBUG
LPTSTR WaitTypes[6] = {
    TEXT("WAIT_TYPE_BUSY"),
    TEXT("WAIT_TYPE_NOT_BUSY"),
    TEXT("WAIT_TYPE_READY"),
    TEXT("WAIT_TYPE_DRQ"),
    TEXT("WAIT_TYPE_DRQ_NOERR"),
    TEXT("WAIT_TYPE_RDY_NOERR")
};
#endif

#define WAIT_TYPE_BUSY      1
#define WAIT_TYPE_NOT_BUSY  2
#define WAIT_TYPE_READY     3
#define WAIT_TYPE_DRQ       4   // wait for data request
#define WAIT_TYPE_DRQ_NOERR 5   // wait for DRQ but ignore the error status bit
#define WAIT_TYPE_RDY_NOERR 6   // wait for ready, but ignore error status bit

#define WAIT_TIME_NORMAL    9000
#define WAIT_TIME_LONG      30000

//
// ATAWaitForDisk
//
DWORD
ATAWaitForDisk(
    PDISK pDisk,
    DWORD Times,
    UCHAR Type
    )
{
    UCHAR ata_status = 0;
    DWORD error = ERROR_SUCCESS;
    DWORD start = GetTickCount();

    DEBUGMSG(ZONE_IO, (TEXT("ATADISK:ATAWFD(%s)\r\n"), WaitTypes[Type-1]));

    do {
        try {
            ata_status = ATA_READ_UCHAR(pDisk->d_Flags, (UCHAR*)pDisk->d_pATARegAlt + ATA_REG_ALT_STATUS);
        } except (GetExceptionCode() == STATUS_ACCESS_VIOLATION ?
                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
            DEBUGMSG(ZONE_IO|ZONE_ERROR, (TEXT("ATADISK:ATAWaitForDisk - exception!\r\n")));
            error = ERROR_ACCESS_DENIED;
        }
        if (error != ERROR_SUCCESS) {
            return error;
        }
//        DEBUGMSG(ZONE_IO,
//                 (TEXT("ATADISK:ATAWaitForDisk - ata_status = 0x%x\r\n"), ata_status));
        if (ata_status & ATA_STATUS_BUSY) {
           // No other status bits are valid; if this is what we want, return; else poll
           if (Type == WAIT_TYPE_BUSY) {
              DEBUGMSG(ZONE_IO, (TEXT("ATADISK:ATAWaitForDisk - ATA_STATUS_BUSY\r\n")));
              goto awfd_done;
           }
        } else if (Type == WAIT_TYPE_NOT_BUSY) {
           // We don't care about the error status of the last command here
           // because we're only waiting on the busy status (and because we
           // only do this when we're preparing to submit a new command).
           goto awfd_done;
        } else {
           if (Type == WAIT_TYPE_DRQ_NOERR) {
              // This condition is special - ignore the error bit iff DRQ is set.
              // Use this for write operations because the error bit may still be
              // set from the last operation; we have to complete a new operation
              // before the bit gets cleared (or it might be errored again in which
              // case the bit will stay set but DRQ won't be asserted).
              if (ata_status & ATA_STATUS_DATA_REQ)
                 goto awfd_done;
           }
           if (Type == WAIT_TYPE_RDY_NOERR) {
              if (ata_status & ATA_STATUS_READY)
                 goto awfd_done;
           }
           // Now we check the error condition!
           if (ata_status & ATA_STATUS_ERROR) {
              error = ATA_READ_UCHAR(pDisk->d_Flags, (UCHAR*)pDisk->d_pATAReg + ATA_REG_ERROR);
              DEBUGMSG(ZONE_IO|ZONE_ERROR, (TEXT("ATADISK:ATAWaitForDisk - op error 0x%x\r\n"), error));
              if (error & ATA_ERROR_BAD_SECT_NUM)
                 return ERROR_SECTOR_NOT_FOUND;
              if (error & (ATA_ERROR_BAD_BLOCK|ATA_ERROR_UNCORRECTABLE))
                 return ERROR_INVALID_BLOCK;
              return ERROR_DISK_OPERATION_FAILED;
           }
           switch (Type) {
             case WAIT_TYPE_READY:
               if (ata_status & ATA_STATUS_READY) {
                  DEBUGMSG(ZONE_IO,
                           (TEXT("ATADISK:ATAWaitForDisk - ATA_STATUS_READY 0x%x\r\n"),
                            ata_status));
                  goto awfd_done;
               }
               Sleep(10);  // waiting for READY can take a while
               break;
               
             case WAIT_TYPE_DRQ: 
               if (ata_status & ATA_STATUS_DATA_REQ) {
                  goto awfd_done;
               }
               break;
           }
        }

        //
        // Since Sleep(1) can be as long as a time slice (~25ms), 
        // this loop is limited by looking at the milliseconds elapsed.
        //
        if ((GetTickCount() - start) >= Times) {
            Times = 0;
        }
    } while (Times); // end of do-loop

awfd_done:
    if (Times == 0) {
        DEBUGMSG(ZONE_IO|ZONE_ERROR,
           (TEXT("ATADISK:ATAWaitForDisk - %s wait timed out\r\n"),
           WaitTypes[Type-1]));
        return ERROR_GEN_FAILURE;
    } else {
        return ERROR_SUCCESS;
    }
}   // ATAWaitForDisk


//
// ATASetSector - write a sector number to the appropriate ATA registers taking
//        into account for the mode being used (LBA or CHS).  Also write the next
//        command.
//
DWORD
ATASetSector(
    PDISK pDisk,
    DWORD sectno,
    DWORD cnt,
    DWORD cmd
    )
{
    volatile UCHAR* base;
    DWORD sectors;
    DWORD heads;

    if (ATAWaitForDisk(
            pDisk,
            WAIT_TIME_NORMAL,
            WAIT_TYPE_RDY_NOERR) != CERR_SUCCESS) {
        return ERROR_GEN_FAILURE;
    }

    base = pDisk->d_pATAReg;

    if (!cnt) {
        DEBUGMSG(1, (TEXT("ATADISK: Requesting 0 Sectors at %d\n"), sectno));
    }
    DEBUGMSG(ZONE_IO, (TEXT("ATADISK: Requesting %d sectors at %d\n"), cnt, sectno));

    
    ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base + ATA_REG_SECT_CNT, (UCHAR)cnt);
    if (pDisk->d_fLBAMode == TRUE) {
        ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base + ATA_REG_SECT_NUM, (UCHAR)sectno);
        ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base + ATA_REG_CYL_LOW, (UCHAR)(sectno >> 8));
        ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base + ATA_REG_CYL_HIGH, (UCHAR)(sectno >> 16));
        ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base + ATA_REG_DRV_HEAD,
            (UCHAR)(((UCHAR)(sectno>>24))|ATA_HEAD_LBA_MODE|ATA_HEAD_DRIVE_1));

    } else {    // translate LBA to CHS format
        sectors = pDisk->d_DiskInfo.di_sectors;
        heads = pDisk->d_DiskInfo.di_heads;

        ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base+ATA_REG_SECT_NUM, (UCHAR)((sectno%sectors)+1));
        ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base+ATA_REG_CYL_LOW, (UCHAR)(sectno/(sectors*heads)));
        ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base+ATA_REG_CYL_HIGH,
                                      (UCHAR)((sectno/(sectors*heads)) >> 8));
        ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base + ATA_REG_DRV_HEAD,
                            (UCHAR)(((sectno/sectors)%heads)|ATA_HEAD_DRIVE_1));
    }
    ATA_WRITE_UCHAR(pDisk->d_Flags, (UCHAR*)base + ATA_REG_COMMAND, (UCHAR)cmd);
    return ERROR_SUCCESS;
}    // ATASetSector


//
// ATARead - fulfill one scatter/gather read request
//
DWORD
ATARead(
    PDISK pDisk,
    PSG_REQ pSgr
    )
{
    DWORD i;
    DWORD num_sg;
    DWORD bytes_this_int;
    DWORD bytes_this_sg;
    PSG_BUF pSg;
    volatile USHORT *pData16;
    PUCHAR pBuf;
    volatile UCHAR *pData;
    DWORD sectno;
    DWORD nextsec;
    DWORD endsect;
    DWORD error;
    WORD  nextbyte=0xFFFF;
    int tries = 0;

    union {
        WORD us;
        BYTE  uc[2];
    }unisc;

    num_sg = pSgr->sr_num_sg;
    pSg = &(pSgr->sr_sglist[0]);
    bytes_this_sg = pSg->sb_len;

    // Map address and check for security violation
    pBuf = (LPBYTE)MapCallerPtr((LPVOID)pSg->sb_buf, pSg->sb_len);
    if (pSg->sb_buf != NULL && pBuf == NULL) {
        // Security violation
        DEBUGMSG(ZONE_ERROR, (TEXT(
            "ATARead>Failed to map pointer to caller\r\n"
            )));
        return ERROR_ACCESS_DENIED;
    }

    pData = (volatile UCHAR*)pData16 = pDisk->d_pATAReg;
    sectno = pSgr->sr_start;
    endsect = sectno + pSgr->sr_num_sec;
    error = ERROR_SUCCESS;
    nextsec = 0;

    //
    // This loop reads multiple sectors into multiple scatter/gather buffers.
    // The scatter/gather buffers may be bigger or smaller or same size as a
    // sector.
    //
    while (num_sg) {
        DEBUGMSG(ZONE_IO, 
            (TEXT("ATADISK:ATARead - reading sector %d\r\n"), sectno));

#ifdef USE_INTERRUPT
        ResetEvent(pDisk->d_IRQEvent);
#endif

ata_read0:
        if (!nextsec) {
            nextsec = MIN(MAX_SECT_CNT, endsect - sectno);
            try {
                error = ATASetSector(pDisk, sectno, nextsec, ATA_CMD_READ);
            } except (GetExceptionCode() == STATUS_ACCESS_VIOLATION ?
                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
                DEBUGMSG(ZONE_IO|ZONE_ERROR, (TEXT("ATADISK:ATARead - exception 1\r\n")));
                error = ERROR_READ_FAULT;
            }
            if (error != ERROR_SUCCESS) {
                return error;
            }
        }

#ifdef USE_INTERRUPT
        if (!(pDisk->d_Flags & ATADISK_FLAG_MEMORY_MAPPED)) {
            WaitForSingleObject(pDisk->d_IRQEvent, DISK_IO_TIME_OUT);
        }
#endif
        error = ATAWaitForDisk(pDisk, WAIT_TIME_NORMAL, WAIT_TYPE_DRQ);
        if (error != ERROR_SUCCESS) {
            tries++;
            nextsec = 0;
            Sleep(10);
            DEBUGMSG(ZONE_ERROR, (TEXT("ATAREAD: error during WaitForDisk\r\n")));
            if (tries < 6)
                goto ata_read0;
            return error;
        }
        tries = 0;
        sectno++;
        nextsec--;
        bytes_this_int = pDisk->d_DiskInfo.di_bytes_per_sect;

ar_continue_sector:
        i = (bytes_this_sg < bytes_this_int) ? bytes_this_sg : bytes_this_int;
        bytes_this_sg -= i;
        bytes_this_int -= i;

        try {

⌨️ 快捷键说明

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