📄 diskio.c
字号:
//
// 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 + -