diskmain.cpp

来自「6410BSP3」· C++ 代码 · 共 1,948 行 · 第 1/5 页

CPP
1,948
字号
    return FALSE;

}


// ----------------------------------------------------------------------------
// Function: UnmapSg
//     UnMap embedded pointers, previously mapped by ValidateSg.
//     Basically, an SG Array version of CeCloseCallerBuffer
//
// Parameters:
//     sr_sglist - List of mapped SG buffers to unmap
//     saveoldptrs - List of old unmapped pointers
//     sr_sglistlen - The size of sr_sglist
//     dwArgType - ARG_O_PTR/ ARG_I_PTR
//     Return value -  HRESULT from a failed call to CeCloseCallerBuffer
//                     otherwise ERROR_SUCCESS
// ----------------------------------------------------------------------------

HRESULT
CDisk::UnmapSg(
    IN const SG_BUF * sr_sglist,
    IN const PUCHAR * saveoldptrs,
    IN DWORD sr_sglistlen,
    IN DWORD dwArgType
    )
{
    HRESULT dwError = ERROR_SUCCESS;    
    ASSERT(sr_sglistlen <= MAX_SG_BUF);
    
    for (DWORD dwIndex = 0; dwIndex < sr_sglistlen; dwIndex++) {

        HRESULT dwtemp;
        ASSERT(NULL != sr_sglist[dwIndex].sb_buf);
        ASSERT(0 != sr_sglist[dwIndex].sb_len);

        // Close pointers previously mapped in ValidateSg

        dwtemp = CeCloseCallerBuffer(
                    (LPVOID)sr_sglist[dwIndex].sb_buf,
                    (LPVOID)saveoldptrs[dwIndex],
                    sr_sglist[dwIndex].sb_len,
                    dwArgType);
        
        if (FAILED(dwtemp)) {
            ASSERT(!"Cleanup call to CeCloseCallerBuffer failed unexpectedly");
            dwError = dwtemp;
        }
    }

    return dwError;
    
}

// ----------------------------------------------------------------------------
// Function: SendDiskPowerCommand
//     Put the device into a specified power state.  The optional parameter is
//     programmed into the Sector Count register, which is used for the
//     ATA NEW CMD IDLE and ATA CMD STANDBY commands.
//
// Parameters:
//     bCmd -
//     bParam -
// ----------------------------------------------------------------------------

BOOL
CDisk::SendDiskPowerCommand(
    BYTE bCmd,
    BYTE bParam
    )
{
    BYTE bError, bStatus;
    BOOL fOk = TRUE;

    if(ZONE_CELOG) CeLogData(TRUE, CELID_ATAPI_POWERCOMMAND, &bCmd, sizeof(bCmd), 0, CELZONE_ALWAYSON, 0, FALSE);

    // HI:Check_Status (Host Idle); wait until BSY=0 and DRQ=0
    // read Status register
    while (1) {
        bStatus = GetAltStatus();
        if (!(bStatus & (0x80|0x08))) break; // BSY := Bit 7, DRQ := Bit 3
        Sleep(5);
    }

    // HI:Device_Select; select device
    SelectDevice();

    // HI:Check_Status (Host Idle); wait until BSY=0 and DRQ=0
    // read Status register
    while (1) {
        bStatus = GetAltStatus();
        if (!(bStatus & (0x80|0x08))) break; // BSY := Bit 7, DRQ := Bit 3
        Sleep(5);
    }

    // HI:Write_Parameters
    WriteSectorCount(bParam);
    // WriteAltDriveController(0x00); // disable interrupt (nIEN := Bit 1 of Device Control register)

    // HI:Write_Command
    WriteCommand(bCmd);

    // transition to non-data command protocol

    // HND:INTRQ_Wait
    // transition to HND:Check_Status
    // read Status register
    while (1) { // BSY := Bit 7
        bStatus = GetAltStatus();
        bError = GetError();
        if (bError & 0x04) { // ABRT := Bit 2
            // command was aborted
            DEBUGMSG(ZONE_ERROR, (_T(
                "Atapi!CDisk::SendDiskPowerCommand> Failed to send command 0x%x, parameter 0x%x\r\n"
                ), bCmd, bParam));
            fOk = FALSE;
            break;
        }
        if (!(bStatus & 0x80)) break; // BSY := Bit 7
        Sleep(5);
    }

    // transition to host idle protocol

    return fOk;
}

// ----------------------------------------------------------------------------
// Function: GetDiskPowerInterface
//     Return the power management object associated with this device
//
// Parameters:
//     None
// ----------------------------------------------------------------------------

CDiskPower *
CDisk::GetDiskPowerInterface(
    void
    )
{
    CDiskPower *pDiskPower = new CDiskPower;
    return pDiskPower;
}

// ----------------------------------------------------------------------------
// Function: SetDiskPowerState
//     Map a power state to an ATA power management command and issue the
//     command
//
// Parameters:
//     newDx -
// ----------------------------------------------------------------------------

BOOL
CDisk::SetDiskPowerState(
    CEDEVICE_POWER_STATE newDx
    )
{
    BYTE bCmd;

    if (ZONE_CELOG) {
        DWORD dwDx = (DWORD) newDx;
        CeLogData(TRUE, CELID_ATAPI_SETDEVICEPOWER, &dwDx, sizeof(dwDx), 0, CELZONE_ALWAYSON, 0, FALSE);
    }

    // on D0 go to IDLE to minimize latency during disk accesses
    if(newDx == D0 || newDx == D1) {
        bCmd = ATA_CMD_IDLE_IMMEDIATE;
    }
    else if(newDx == D2) {
        bCmd = ATA_CMD_STANDBY_IMMEDIATE;
    }
    else if(newDx == D3 || newDx == D4) {
        bCmd = ATA_CMD_SLEEP;
    }
    else {
        DEBUGMSG(ZONE_WARNING, (_T(
            "CDisk::SetDiskPowerState> Invalid power state value(%u)\r\n"
            ), newDx));
        return FALSE;
    }

    // update the disk power state
    return SendDiskPowerCommand(bCmd);
}

// ----------------------------------------------------------------------------
// Function: WakeUp
//     Wake the device up from sleep
//
// Parameters:
//     None
// ----------------------------------------------------------------------------

BOOL
CDisk::WakeUp(
    )
{
    if (!ResetController(FALSE)) {
        return FALSE;
    }
    return SendIdentifyDevice(IsAtapiDevice());
}

// ----------------------------------------------------------------------------
// Function: MainIoctl
//     Process IOCTL_DISK_ and DISK_IOCTL_ I/O controls
//
// Parameters:
//     pIOReq -
// ----------------------------------------------------------------------------
DWORD CDisk::MainIoctl(PIOREQ pIOReq)
{
    DWORD dwError = ERROR_SUCCESS;

    DEBUGMSG(ZONE_IOCTL, (TEXT("Atapi!CDisk::MainIoctl> IOCTL(%x), device(%x)\r\n"), pIOReq->dwCode, m_dwDeviceId));

    // If device is powering down, then fail.
    if (m_dwDeviceFlags & DFLAGS_DEVICE_PWRDN) {
        SetLastError(ERROR_DEVICE_NOT_AVAILABLE);
        return FALSE;
    }
    switch(pIOReq->dwCode) {
        case IOCTL_DISK_GETINFO:
        case DISK_IOCTL_GETINFO:
            if (IsCDRomDevice()) {
                dwError = ERROR_BAD_COMMAND;
            }
            else {
                dwError = GetDiskInfo(pIOReq);
            }
            break;
        case IOCTL_DISK_DEVICE_INFO:
            dwError = GetDeviceInfo(pIOReq);
            break;
        case DISK_IOCTL_GETNAME:
        case IOCTL_DISK_GETNAME:
            dwError = GetDiskName(pIOReq);
            break;
        case DISK_IOCTL_SETINFO:
        case IOCTL_DISK_SETINFO:
            dwError = SetDiskInfo(pIOReq);
            break;
        case DISK_IOCTL_READ:
        case IOCTL_DISK_READ:
        case DISK_IOCTL_WRITE:
        case IOCTL_DISK_WRITE:
        {
            PSG_REQ pUnsafeInBuf = (PSG_REQ)pIOReq->pInBuf;
            BOOL    fRead = (pIOReq->dwCode == DISK_IOCTL_READ || pIOReq->dwCode == IOCTL_DISK_READ);

            if (!pIOReq->dwInBufSize || !pIOReq->pInBuf) {
                dwError = ERROR_INVALID_PARAMETER;
                break;
            }
            
            if (pIOReq->dwInBufSize >(sizeof(SG_REQ) + ((MAX_SG_BUF) - 1) * sizeof(SG_BUF))) {
                dwError = ERROR_INVALID_PARAMETER;
                // size of m_pSterileIoRequest is sizeof(SG_REQ) + ((MAX_SG_BUF) - 1) * sizeof(SG_BUF))
                break;
            }

            // Copy the caller's SG_REQ.
            if (0 == CeSafeCopyMemory((LPVOID)m_pSterileIoRequest, (LPVOID)pUnsafeInBuf, pIOReq->dwInBufSize)) {
                dwError = ERROR_INVALID_PARAMETER;
                break;
            }

            if (NULL == m_pSterileIoRequest) {
                ASSERT(m_pSterileIoRequest);
                dwError = ERROR_GEN_FAILURE;
                break;
            }

            DWORD dwIndex = 0, mappedbuffers = 0;
            PUCHAR  savedoldptrs[MAX_SG_BUF] ;  // This will hold a copy of the user mode pointers that get overwritten
                                                // ValidateSg


            // Validate the SG_REQ request and map the caller's sb_bufs into
            // the sterile copy,
            if (FALSE == ValidateSg(m_pSterileIoRequest, pIOReq->dwInBufSize, fRead ? ARG_O_PTR : ARG_I_PTR,savedoldptrs)) {
                dwError = ERROR_INVALID_PARAMETER;
                break;
            }

            // Replace the caller's SG_REQ in the I/O request with the sterile
            // copy.
            pIOReq->pInBuf = (PBYTE)m_pSterileIoRequest;
            // Execute the I/O request.
            if (IsDMASupported()) {
                 __try {
                    dwError = ReadWriteDiskDMA(pIOReq, fRead);
                }
                __except(EXCEPTION_EXECUTE_HANDLER) {
//                    AbortDMA();
                    dwError = ERROR_INVALID_PARAMETER;
                    m_pSterileIoRequest->sr_status = ERROR_INVALID_PARAMETER;
                    goto Cleanup;
                }
            }
            else {
                 // Allocate the double buffer, as required.
                if ((NULL == m_rgbDoubleBuffer) && (0 < m_pPort->m_pDskReg[m_dwDeviceId]->dwDoubleBufferSize)) {
                    DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::MainIoctl> 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::MainIoctl> Failed to allocate double buffer\r\n")));
                        dwError = ERROR_OUTOFMEMORY;
                        m_pSterileIoRequest->sr_status = ERROR_OUTOFMEMORY;
                        goto Cleanup;
                    }
                }
                // Perform the I/O.
                if (fRead) {
                    dwError = this->ReadDisk(pIOReq);
                }
                else {
                    dwError = this->WriteDisk(pIOReq);
                }
            }

Cleanup:
            if (FAILED(UnmapSg(
                        m_pSterileIoRequest->sr_sglist,
                        savedoldptrs,
                        m_pSterileIoRequest->sr_num_sg,
                        fRead ? ARG_O_PTR : ARG_I_PTR)))
            {
                ASSERT(!"Cleanup call to CeCloseCallerBuffer failed unexpectedly");
                dwError = ERROR_GEN_FAILURE;
            }
                    
            // Copy sr_status from the sterile SG_REQ to the caller's SG_REQ.
            __try {
                pUnsafeInBuf->sr_status = m_pSterileIoRequest->sr_status;
            }
            __except(EXCEPTION_EXECUTE_HANDLER) {
                dwError = ERROR_INVALID_PARAMETER;
            }
            break;
        }
        case IOCTL_DISK_GET_STORAGEID:
            dwError = GetStorageId(pIOReq);
            break;
        case DISK_IOCTL_FORMAT_MEDIA:
        case IOCTL_DISK_FORMAT_MEDIA:
            dwError = ERROR_SUCCESS;
            break;
        case IOCTL_DISK_FLUSH_CACHE:
            dwError = FlushCache();
            break;
        default:
            dwError = ERROR_NOT_SUPPORTED;
            break;
    }
    return dwError;
}

// ----------------------------------------------------------------------------
// Function: PerformIoctl
//     This is the top-most IOCTL processor and is used to trap IOCTL_POWER_
//     I/O controls to pass to the associated power management object
//
// Parameters:
//     pIOReq -
// ----------------------------------------------------------------------------

BOOL
CDisk::PerformIoctl(
    PIOREQ pIOReq
    )
{
    DWORD dwError = ERROR_SUCCESS;

    DEBUGMSG(ZONE_IOCTL, (TEXT(
        "Atapi!CDisk::PerformIoctl> IOCTL(%x), device(%x)\r\n"
        ), pIOReq->dwCode, m_dwDeviceId));

    if (pIOReq->pBytesReturned) {
        *(pIOReq->pBytesReturned) = 0;
    }

    TakeCS();
    m_pPort->TakeCS();

    if (ZONE_CELOG) CeLogData(TRUE, CELID_ATAPI_STARTIOCTL, pIOReq, sizeof(*pIOReq), 0, CELZONE_ALWAYSON, 0, FALSE);

    __try {

⌨️ 快捷键说明

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