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

📄 diskmain.cpp

📁 三星2410,WinCE5.0下的硬盤IDE驅動.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
        psdi->dwDeviceFlags |= STORAGE_DEVICE_FLAG_READWRITE;

        if (!hKey || !AtaGetRegistryString(hKey, REG_VALUE_HDPROFILE, &szProfile, sizeof(psdi->szProfile))) {
            wcscpy(psdi->szProfile, REG_VALUE_HDPROFILE);
        }

    }

    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_IOCTL, (_T("Atapi!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;

    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
    )
{
    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

    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

    // 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)) {
        return  ERROR_INVALID_PARAMETER;
    }
    if ((pSgReq->sr_start + pSgReq->sr_num_sec) > m_DiskInfo.di_total_sectors) {
        return ERROR_SECTOR_NOT_FOUND;
    }

    // do we have to allocate the double buffer?
    if (NULL == m_rgbDoubleBuffer) {
        DEBUGMSG(ZONE_INIT, (TEXT(
            "Atapi!CDisk::ReadWriteDisk> Allocating double buffer [first use]\r\n"
            )));
        m_rgbDoubleBuffer = (PBYTE)LocalAlloc(LPTR, m_pPort->m_pDskReg[m_dwDeviceId]->dwDoubleBufferSize);
        if (NULL == m_rgbDoubleBuffer) {
            DEBUGMSG(ZONE_ERROR, (TEXT(
                "Atapi!CDisk::ReadWriteDisk> Failed to allocate double buffer\r\n"
                )));
            dwError = ERROR_OUTOFMEMORY;
            goto exit;
        }
    }

    // clear interrupt, if set
    // TODO: Is this necessary?
    // GetBaseStatus();

    // initialize "global" transfer state
    dwCurSec = pSgReq->sr_start;
    dwCurByte = 0;

    // fetch first scatter/gather buffer
    dwCurBufNum = 0;
    dwCurBufPos = 0;
    pSgBuf = &(pSgReq->sr_sglist[0]);
    // map nested pointer and test for security violation
    pBuffer = (PBYTE)MapCallerPtr((LPVOID)pSgBuf->sb_buf, pSgBuf->sb_len);
    if (pSgBuf->sb_buf != NULL && pBuffer == NULL) {
        // security violation
        DEBUGMSG(ZONE_ERROR, (TEXT(
            "Atapi!CDisk::ReadWriteDisk> Failed to map pointer to caller\r\n"
            )));
        return ERROR_INVALID_PARAMETER;
    }

    // is this a read or a write?
    if (fRead) {

        // --------------------------------------------------------------------
        // ATA/ATAPI-6 R3B 9.5 (PIO data-in protocol)
        // --------------------------------------------------------------------

        // Host_Idle
        // ---------
        // issue command
PIO_Data_In_Read_Command:;
        // 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;
        }
        // issue command
        if (!SendIOCommand(dwCurSec, dwCurDoubleBufLen / m_DiskInfo.di_bytes_per_sect, bCmd)) {
            DEBUGMSG(ZONE_ERROR, (_T(
                "Atapi!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=0 (interrupt enabled), wait for interrupt
        if (m_fInterruptSupported) {
            if (!WaitForInterrupt(m_dwDiskIoTimeOut) || (CheckIntrState() == ATA_INTR_ERROR)) {
                DEBUGMSG(ZONE_IO|ZONE_WARNING, (_T(
                    "Atapi!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:;
        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:;
        dwCurDRQDataBlockByte = 0;                      // reset DRQ data block
HPIOI_Transfer_Data:;
        if (m_f16Bit) {
            *((PWORD)pDoubleBuffer) = ReadWord();       // read 16-bit Data register
            pDoubleBuffer++;
            dwCurDRQDataBlockByte += 1;                 // increment DRQ data block
        }
        else {
            *((PBYTE)pDoubleBuffer) = (BYTE)ReadByte(); // read 8-bit Data register
        }
        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:;

        // the double buffer has been filled, i.e., a read command has been
        // completed; distribute double buffer to scatter/gather buffers

        // initialize double buffer for empty
        pDoubleBuffer = m_rgbDoubleBuffer;
        dwCurDoubleBufPos = 0;
        // empty current double buffer into current scatter/gather buffer
HPIOI_Distribute_Double_Buffer:;
        // copy a byte from the double buffer to the current scatter/gather buffer
        *pBuffer = m_rgbDoubleBuffer[dwCurDoubleBufPos];
        pBuffer++;
        dwCurBufPos += 1;
        dwCurDoubleBufPos += 1;
        // increment current sector, if necessary
        dwCurByte += 1;
        if (dwCurByte == m_DiskInfo.di_bytes_per_sect) {
            dwCurSec += 1;
            dwCurByte = 0;
        }
        // have we filled the current scatter/gather buffer?
        if (dwCurBufPos == pSgBuf->sb_len) {
            // have we filled the scatter/gather request?
            if ((dwCurBufNum + 1) == pSgReq->sr_num_sg) goto exit;
            // fetch next scatter/gather buffer
            dwCurBufNum += 1;
            dwCurBufPos = 0;
            pSgBuf = &(pSgReq->sr_sglist[dwCurBufNum]);
            pBuffer = (PBYTE)MapCallerPtr((LPVOID)pSgBuf->sb_buf, pSgBuf->sb_len);
            if (pSgBuf->sb_buf != NULL && pBuffer == NULL) {
                // security violation
                DEBUGMSG(ZONE_ERROR, (TEXT(
                    "Atapi!CDisk::ReadWriteDisk> Failed to map pointer to caller\r\n"
                    )));
                return ERROR_INVALID_PARAMETER;
            }
        }
        // have we emptied the double buffer?
        if (dwCurDoubleBufPos == dwCurDoubleBufLen) goto PIO_Data_In_Read_Command;
        goto HPIOI_Distribute_Double_Buffer;
    }
    else {

        // --------------------------------------------------------------------
        // ATA/ATAPI-6 R3B 9.6 (PIO data-out protocol)
        // --------------------------------------------------------------------

        // Host_Idle
        // ---------
        // issue command
PIO_Data_In_Write_Command:;
        // 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;
        }
        // issue command
        if (!SendIOCommand(dwCurSec, dwCurDoubleBufLen / m_DiskInfo.di_bytes_per_sect, bCmd)) {
            DEBUGMSG(ZONE_ERROR, (_T(
                "Atapi!CDisk::ReadWriteDisk> Failed to issue read/write command\r\n"
                )));
            dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
            goto exit;
        }

        fWriteComplete = FALSE; // mark write as in progress

        // the double buffer is empty, i.e., a write command is about to be
        // issued; fill the double buffer from the scatter/gather buffers

        // initialize double buffer for fill
        pDoubleBuffer = m_rgbDoubleBuffer;
        dwCurDoubleBufPos = 0;
        // fill current double buffer from current scatter/gather buffer
        while (1) {
            // copy a byte from the scatter/gather buffer to the double buffer
            PREFAST_DEBUGCHK(pBuffer);
            m_rgbDoubleBuffer[dwCurDoubleBufPos] = *pBuffer;
            pBuffer++;
            dwCurDoubleBufPos += 1;
            dwCurBufPos += 1;
            // increment current sector, if necessary
            dwCurByte++;
            if (dwCurByte == m_DiskInfo.di_bytes_per_sect) {
                dwCurSec += 1;
                dwCurByte = 0;
            }
            // have we emptied the current scatter/gather buffer?
            if (dwCurBufPos == pSgBuf->sb_len) {
                // have we emptied the scatter/gather request?
                if ((dwCurBufNum + 1) == pSgReq->sr_num_sg) {
                    fWriteComplete = TRUE; // mark write as complete
                    break;
                }
                // fetch next scatter/gather buffer
                dwCurBufNum += 1;
                dwCurBufPos = 0;
                pSgBuf = &(pSgReq->sr_sglist[dwCurBufNum]);
                pBuffer = (PBYTE)MapCallerPtr((LPVOID)pSgBuf->sb_buf, pSgBuf->sb_len);
                if (pSgBuf->sb_buf != NULL && pBuffer == NULL) {
                    // security violation
                    DEBUGMSG(ZONE_ERROR, (TEXT(
                        "Atapi!CDisk::ReadWriteDisk> Failed to map pointer to caller\r\n"
                        )));
                    return ERROR_INVALID_PARAMETER;
                }
            }
            // have we filled the double buffer?
            if (dwCurDoubleBufPos == m_pPort->m_pDskReg[m_dwDeviceId]->dwDoubleBufferSize) break;
        } // while

        // initialize current double buffer for empty
        pDoubleBuffer = m_rgbDoubleBuffer;

        // 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
HPIOO_Check_Status:;
        bStatus = GetAltStatus();                         // read Status register
        if ((!(bStatus & 0x80)) && (!(bStatus & 0x08))) { // BSY=0, DRQ=0
            if (fWriteComplete) goto exit;                // if the entire write is complete, exit
            goto PIO_Data_In_Write_Command;               // entire write is not complete, issue next transfer
        }
        if (bStatus & 0x80) goto HPIOO_Check_Status;      // BSY=1
        if ((!(bStatus & 0x80)) && (bStatus & 0x08)) goto HPIOO_Transfer_Data_Reset_DRQ_Data_Block; // BSY=0, DRQ=1
        DEBUGCHK(FALSE);
        goto exit;

        // Transfer_Data
        // -------------
        // if write Data register,

⌨️ 快捷键说明

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