📄 diskmain.cpp
字号:
}
DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: SetDiskInfo-\r\n")));
return dwError;
}
// ----------------------------------------------------------------------------
// Function: GetDeviceInfo
// IOCTL_DISK_DEVICE_INFO
//
// Parameters:
// pIOReq -
// ----------------------------------------------------------------------------
DWORD
CDisk::GetDeviceInfo(
PIOREQ pIOReq
)
{
PSTORAGEDEVICEINFO psdi = (PSTORAGEDEVICEINFO)pIOReq->pInBuf;
HKEY hKey;
DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: GetDeviceInfo+\r\n")));
if ((pIOReq->dwInBufSize == 0) || (pIOReq->pInBuf == NULL)) {
return ERROR_INVALID_PARAMETER;
}
if (pIOReq->dwInBufSize < sizeof(STORAGEDEVICEINFO)) {
return ERROR_INSUFFICIENT_BUFFER;
}
if (pIOReq->pBytesReturned) {
*(pIOReq->pBytesReturned) = sizeof(STORAGEDEVICEINFO);
}
psdi->dwDeviceClass = 0;
psdi->dwDeviceType = 0;
psdi->dwDeviceFlags = 0;
PTSTR szProfile = psdi->szProfile;
wcscpy(szProfile, L"Default");
if (ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, m_szDeviceKey, 0, 0, &hKey)) {
hKey = NULL;
}
if (IsAtapiDevice() && IsCDRomDevice()) {
psdi->dwDeviceClass = STORAGE_DEVICE_CLASS_MULTIMEDIA;
psdi->dwDeviceType |= STORAGE_DEVICE_TYPE_REMOVABLE_MEDIA;
psdi->dwDeviceType |= STORAGE_DEVICE_TYPE_ATAPI;
psdi->dwDeviceType |= STORAGE_DEVICE_TYPE_PCIIDE;
psdi->dwDeviceFlags |= STORAGE_DEVICE_FLAG_MEDIASENSE;
psdi->dwDeviceFlags |= STORAGE_DEVICE_FLAG_READONLY;
if (!hKey || !AtaGetRegistryString(hKey, REG_VALUE_CDPROFILE, &szProfile, sizeof(psdi->szProfile))) {
wcscpy(psdi->szProfile, REG_VALUE_CDPROFILE);
}
}
else {
psdi->dwDeviceClass = STORAGE_DEVICE_CLASS_BLOCK;
psdi->dwDeviceType |= STORAGE_DEVICE_TYPE_PCIIDE;
psdi->dwDeviceType |= STORAGE_DEVICE_TYPE_ATA;
psdi->dwDeviceFlags |= STORAGE_DEVICE_FLAG_READWRITE;
if (!hKey || !AtaGetRegistryString(hKey, REG_VALUE_HDPROFILE, &szProfile, sizeof(psdi->szProfile))) {
wcscpy(psdi->szProfile, REG_VALUE_HDPROFILE);
}
}
DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: GetDeviceInfo-\r\n")));
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// Function: GetDiskName
// Implement IOCTL_DISK_GETNAME
//
// Parameters:
// pIOReq -
// ----------------------------------------------------------------------------
DWORD
CDisk::GetDiskName(
PIOREQ pIOReq
)
{
static PTCHAR szDefaultDiscDrive = (_T("External Volume"));
PTCHAR szDiskName = NULL;
DWORD dwSize;
DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: GetDiskName+\r\n")));
// DEBUGMSG(ZONE_IOCTL, (_T("Ata!GeDisktName\r\n")));
if ((pIOReq->pBytesReturned == NULL) || (pIOReq->dwOutBufSize == 0) || (pIOReq->pOutBuf == NULL)) {
return ERROR_INVALID_PARAMETER;
}
*(pIOReq->pBytesReturned) = 0;
if (m_szDiskName) {
if (wcslen(m_szDiskName)) {
szDiskName = m_szDiskName;
}
else {
return ERROR_NOT_SUPPORTED;
}
}
else {
szDiskName = szDefaultDiscDrive;
}
dwSize = (wcslen(szDiskName) + 1) * sizeof(TCHAR);
if (pIOReq->dwOutBufSize < dwSize) {
return ERROR_INSUFFICIENT_BUFFER;
}
wcscpy((PTCHAR) pIOReq->pOutBuf, szDiskName);
*(pIOReq->pBytesReturned) = dwSize;
DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: GetDiskName-\r\n")));
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// Function: ReadWriteDisk
// Implement ATA/ATAPI-6 R3B 8.34 (READ SECTOR(S)) and 8.62 (WRITE SECTOR(S)).
// Implement ATA/ATAPI-6 R3B 9.5 (PIO data-in command protocol) and 9.6
// (PIO data-out command protocol).
// This function reads from/writes to an ATA device.
//
// Parameters:
// pIOReq -
// fRead -
//
// Notes:
// READ SECTOR(S) and WRITE SECTOR(S) can transfer up to 256 sectors; however,
// every transfer is segmented, as per the PIO data-in/out protocol. A segment
// of a multiple-block transfer is called a "DRQ data block" and is the length
// of a sector; see ATA/ATAPI-6 R3B 9.5 and 9.6 for more information.
// ----------------------------------------------------------------------------
DWORD
CDisk::ReadWriteDisk(
PIOREQ pIOReq,
BOOL fRead
)
{
SG_BUF SafeBufferList[MAX_SG_BUF] = {0};
PUCHAR saveoldptrs[MAX_SG_BUF];
PVOID ptemp = 0;
unsigned int i, mappedptrs = 0;
DWORD dwError = ERROR_SUCCESS; // result
PSG_REQ pSgReq = (PSG_REQ) pIOReq->pInBuf; // scatter/gather request
PSG_BUF pSgBuf; // scatter/gather buffer
BYTE bStatus; // device Status register
DWORD dwIntrCount, dwBufferCount;
BYTE bCmd = fRead ? m_bReadCommand : m_bWriteCommand; // command
DWORD dwCurBufNum; // current scatter/gather buffer
DWORD dwCurBufPos; // current position in current scatter/gather buffer
PBYTE pBuffer; // pointer to current address of current scatter/gather buffer
DWORD dwCurDoubleBufPos; // current position in current double buffer
DWORD dwCurDoubleBufLen; // length of current double buffer (for reads)
PBYTE pDoubleBuffer; // pointer to current address of double buffer
DWORD dwCurByte; // current byte (to increment current sector of transfer) of "global" transfer
DWORD dwCurSec; // current sector of "global" transfer
DWORD dwCurDRQDataBlockByte; // current byte of current DRQ data block transfer
BOOL fWriteComplete; // to facilitate PIO data-out protocol, flag transfer complete
DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: ReadWriteDisk+(sr_start:%d, sr_num_sec:%d, start: %d)\r\n"), pSgReq->sr_start, pSgReq->sr_num_sec, GetTickCount()));
// validate arguments
if ((pSgReq == NULL) || (pIOReq->dwInBufSize < sizeof(SG_REQ))) {
return ERROR_INVALID_PARAMETER;
}
if ((pSgReq->sr_num_sec == 0) || (pSgReq->sr_num_sg == 0) || (pSgReq->sr_num_sg > MAX_SG_BUF)) {
return ERROR_INVALID_PARAMETER;
}
if ((pSgReq->sr_start + pSgReq->sr_num_sec) > m_DiskInfo.di_total_sectors) {
return ERROR_SECTOR_NOT_FOUND;
}
// Make a safe copy of the caller's SG_BUF array
if (0 == CeSafeCopyMemory((LPVOID)SafeBufferList, (LPVOID)(pSgReq->sr_sglist), (sizeof(SG_BUF) * pSgReq->sr_num_sg))) {
return ERROR_INVALID_PARAMETER;
}
// Validate and map embedded sb_bufs
for (i = 0; i < pSgReq->sr_num_sg; i++) {
if (
(SafeBufferList[i].sb_len == 0) ||
(SafeBufferList[i].sb_buf == NULL)
) {
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
if (FAILED(CeOpenCallerBuffer(
&ptemp,
SafeBufferList[i].sb_buf,
SafeBufferList[i].sb_len,
fRead ? ARG_O_PTR : ARG_I_PTR,
FALSE)))
{
dwError = ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_ERROR, (TEXT("Ata!CDisk::ReadWriteDisk> CeOpenCallerBuffer(pDestMarshalled=0x%08x,pSrcUnmarshalled=0x%08x) failed!\r\n"),ptemp,SafeBufferList[i].sb_buf));
goto exit;
}
saveoldptrs[i] = SafeBufferList[i].sb_buf;
SafeBufferList[i].sb_buf = (PUCHAR)ptemp;
mappedptrs = i + 1 ;
}
// do we have to allocate the double buffer?
if (NULL == m_rgbDoubleBuffer) {
DEBUGMSG(ZONE_INIT, (TEXT(
"Ata!CDisk::ReadWriteDisk> Allocating double buffer [first use]: %d\r\n"
), m_pPort->m_pDskReg[m_dwDeviceId]->dwDoubleBufferSize));
m_rgbDoubleBuffer = (PBYTE)LocalAlloc(LPTR, m_pPort->m_pDskReg[m_dwDeviceId]->dwDoubleBufferSize);
if (NULL == m_rgbDoubleBuffer) {
DEBUGMSG(ZONE_ERROR, (TEXT(
"Ata!CDisk::ReadWriteDisk> Failed to allocate double buffer\r\n"
)));
dwError = ERROR_OUTOFMEMORY;
goto exit;
}
}
// clear interrupt, if set
// TODO: Is this necessary?
// GetBaseStatus();
GetBaseStatus();
// initialize "global" transfer state
dwCurSec = pSgReq->sr_start;
dwCurByte = 0;
// fetch first scatter/gather buffer
dwCurBufNum = 0;
dwCurBufPos = 0;
pSgBuf = &(SafeBufferList[dwCurBufNum]);
//pSgBuf = &(pSgReq->sr_sglist[0]);
// map nested pointer and test for security violation
pBuffer = (PBYTE)pSgBuf->sb_buf;
if (pSgBuf->sb_buf != NULL && pBuffer == NULL) {
// security violation
DEBUGMSG(ZONE_ERROR, (TEXT(
"Ata!CDisk::ReadWriteDisk> Failed to map pointer to caller\r\n"
)));
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
// is this a read or a write?
if (fRead) {
if (pIOReq->pBytesReturned){
*(pIOReq->pBytesReturned) = 0;
}
// --------------------------------------------------------------------
// ATA/ATAPI-6 R3B 9.5 (PIO data-in protocol)
// --------------------------------------------------------------------
// Host_Idle
// ---------
// issue command
PIO_Data_In_Read_Command:;
//DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: ReadWriteDisk+(PIO_Data_In_Read_Command)\r\n")));
// determine size of transfer
if ((((pSgReq->sr_start + pSgReq->sr_num_sec) - dwCurSec) * m_DiskInfo.di_bytes_per_sect) > m_pPort->m_pDskReg[m_dwDeviceId]->dwDoubleBufferSize) {
dwCurDoubleBufLen = m_pPort->m_pDskReg[m_dwDeviceId]->dwDoubleBufferSize;
}
else {
dwCurDoubleBufLen = ((pSgReq->sr_start + pSgReq->sr_num_sec) - dwCurSec) * m_DiskInfo.di_bytes_per_sect;
}
dwIntrCount = 0;
dwBufferCount = 0;
// issue command
if (!SendIOCommand(dwCurSec, dwCurDoubleBufLen / m_DiskInfo.di_bytes_per_sect, bCmd)) {
DEBUGMSG(ZONE_ERROR, (_T(
"Ata!CDisk::ReadWriteDisk> Failed to issue read/write command\r\n"
)));
dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
goto exit;
}
// initialize double buffer for read
pDoubleBuffer = m_rgbDoubleBuffer;
dwCurDoubleBufPos = 0;
// INTRQ_Wait
// ----------
// wait for interrupt if nIEN=0 (i.e., if interrupt enabled)
HPIOI_INTRQ_Wait:;
// if nIEN=1 (interrupt enabled), wait for interrupt
if (m_fInterruptSupported) {
DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: ReadWriteDisk+(INTRQ: %d, %d)\r\n"), dwIntrCount,dwCurDoubleBufLen));
if((dwIntrCount < dwCurDoubleBufLen) && (dwIntrCount < m_DiskInfo.di_bytes_per_sect * m_Id.MaximumBlockTransfer))
{
if(dwBufferCount >= m_DiskInfo.di_bytes_per_sect && dwBufferCount < dwCurDoubleBufLen)
{
goto HPIOI_Transfer_Data_Setup; // DRQ data block transfer not complete
}
goto HPIOI_Check_Status; // DRQ data block transferred, nIEN=1
}
dwIntrCount = 0;
if (!WaitForInterrupt(m_dwDiskIoTimeOut) || (CheckIntrState() == ATA_INTR_ERROR)) {
DEBUGMSG(ZONE_IO|ZONE_WARNING, (_T(
"Ata!CDisk::ReadWriteDisk> Failed to wait for interrupt (m_dwDeviceId=%d)\r\n"
), m_dwDeviceId));
dwError = ERROR_READ_FAULT;
goto exit;
}
}
// Check_Status
// ------------
// if BSY=0 and DRQ=0, transition to Host_Idle
// if BSY=1, re-enter this state
// if BSY=0 and DRQ=1, transition to Transfer_Data
HPIOI_Check_Status:;
//DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: ReadWriteDisk+(HPIOI_Check_Status)\r\n")));
bStatus = GetAltStatus(); // read Status register
if ((!(bStatus & 0x80)) && (!(bStatus & 0x08))) goto exit; // BSY=0, DRQ=0
if (bStatus & 0x80) goto HPIOI_Check_Status; // BSY=1
if ((!(bStatus & 0x80)) && (bStatus & 0x08)) goto HPIOI_Transfer_Data_Setup; // BSY=0, DRQ=1
DEBUGCHK(FALSE);
goto exit;
// Transfer_Data
// -------------
// if read Data register, DRQ data block transfer not complete, re-enter this state
// if raad Data register, all data for command transferred, transition to Host_Idle
// if read Data register, DRQ data block transferred, all data for command not transferred,
// and nIEN=1, transition to Check_Status
// if read Data register, DRQ data block transferred, all data for command not transferred,
// and nIEN=0, transition to INTRQ_Wait
HPIOI_Transfer_Data_Setup:;
//DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: ReadWriteDisk+(HPIOI_Transfer_Data_Setup)\r\n")));
dwCurDRQDataBlockByte = 0; // reset DRQ data block
HPIOI_Transfer_Data:;
//DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: ReadWriteDisk+(HPIOI_Transfer_Data)\r\n")));
if (m_f16Bit) {
*((PWORD)pDoubleBuffer) = ReadWord(); // read 16-bit Data register
pDoubleBuffer++;
dwCurDRQDataBlockByte += 1; // increment DRQ data block
dwIntrCount += 2;
dwBufferCount += 2;
}
else {
*((PBYTE)pDoubleBuffer) = (BYTE)ReadByte(); // read 8-bit Data register
dwIntrCount ++;
dwBufferCount ++;
}
pDoubleBuffer++;
dwCurDRQDataBlockByte += 1; // increment DRQ data block
// is DRQ data block transferred?
if (dwCurDRQDataBlockByte == m_pPort->m_pDskReg[m_dwDeviceId]->dwDrqDataBlockSize) {
dwCurDoubleBufPos += m_pPort->m_pDskReg[m_dwDeviceId]->dwDrqDataBlockSize;
// has all data for command been transferred?
if (dwCurDoubleBufPos == dwCurDoubleBufLen) goto HPIOI_Empty_Double_Buffer;
// DRQ data block transferred, all data for command not transferred
goto HPIOI_INTRQ_Wait;
}
// DRQ data block transfer not complete
goto HPIOI_Transfer_Data;
HPIOI_Empty_Double_Buffer:;
//DEBUGMSG(ZONE_FUNC, (TEXT("CDisk: ReadWr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -