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

📄 diskmain.cpp

📁 WinCE5.0BSP for Renesas SH7770
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    }

    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
//     This function reads from/writes to an ATA device.
//
// Parameters:
//     pIOReq -
//     fRead -
//
// Notes:
// ----------------------------------------------------------------------------

DWORD CDisk::ReadWriteDisk(PIOREQ pIOReq, BOOL fRead)
{
    DWORD dwError = ERROR_SUCCESS;
    PBYTE pBuffer;
    PSG_REQ pSgReq = (PSG_REQ)pIOReq->pInBuf;
    DWORD dwStartSector, dwNumSectors, dwSectorsToTransfer, dwSectorsPerBlock, dwSgLeft, dwSgLen;
    DWORD dwMaxPerBlock = m_bSectorsPerBlock > 1 ? m_bSectorsPerBlock >> 1 : m_bSectorsPerBlock;

    PSG_BUF pSgBuf;

 
    BYTE bCmd = fRead ? m_bReadCommand : m_bWriteCommand;
    DEBUGMSG( ZONE_IOCTL, (TEXT("ATAPI:ReadWriteDisk Entered\r\n")));
    
    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;
    }       
    
    GetBaseStatus(); // Clear Interrupt if it is already set 

#ifdef SECTOR_CHECK_ENABLE
    if ( ( pSgReq->sr_start + pSgReq->sr_num_sec) >= m_DiskInfo.di_total_sectors ) {
        dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;	
        return dwError;
    }
#endif

    dwSgLeft = pSgReq->sr_num_sg;           //  The number of SG segments 
    dwNumSectors = pSgReq->sr_num_sec;
    dwStartSector = pSgReq->sr_start;   // Get the Start Sector 
    pSgBuf = &(pSgReq->sr_sglist[0]);
    pBuffer = (PBYTE)MapPtrToProcess((LPVOID)pSgBuf->sb_buf, GetCallerProcess());
    

    m_wNextByte = 0xFFFF;

    DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadWriteDisk StartSector=%ld NumSectors=%ld NumSg=%ld\r\n"), dwStartSector, dwNumSectors, dwSgLeft));
    
    while(dwNumSectors) {
        if (dwNumSectors > dwMaxPerBlock)    
            dwSectorsToTransfer = dwMaxPerBlock;
        else    
            dwSectorsToTransfer = dwNumSectors;

        dwNumSectors -= dwSectorsToTransfer;

        if (!SendIOCommand(dwStartSector,dwSectorsToTransfer, bCmd)) {
            dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
            break;
        }

        dwStartSector += dwSectorsToTransfer;

        //  The read command expects an interrupt before data transfer.
        //  The write command, on the other side, expects an interrupt after

        dwSectorsPerBlock = dwMaxPerBlock;

        while(dwSectorsToTransfer && (dwSgLeft > 0)) {
            
            if (dwSectorsPerBlock > dwSectorsToTransfer)
                    dwSectorsPerBlock = dwSectorsToTransfer;

            dwSectorsToTransfer -= dwSectorsPerBlock;
            
            if (fRead && m_fInterruptSupported) {       
                if (!WaitForInterrupt(m_dwDiskIoTimeOut) || (CheckIntrState() == ATA_INTR_ERROR)) {  
                    DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadWrite- WaitforInterrupt failed (DevId %x) \r\n"),m_dwDeviceId));
                    dwError = ERROR_READ_FAULT;
                    break;
                } 
            }   
            if (!WaitForDRQ()) {
                DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadWrite- WaitforDRQ failed (DevId %x) \r\n"),m_dwDeviceId));
                dwError = ERROR_READ_FAULT;
                break;
            }

            DWORD dwBytesPerBlock = dwSectorsPerBlock * m_DiskInfo.di_bytes_per_sect;

            dwSgLen = pSgBuf->sb_len;

            while ((dwBytesPerBlock>0) && (dwSgLeft >0))
            {
                DWORD dwIndex = (dwSgLen < dwBytesPerBlock) ? dwSgLen : dwBytesPerBlock;
                dwSgLen -= dwIndex;
                dwBytesPerBlock -= dwIndex;

                fRead ? ReadBuffer(pBuffer,dwIndex) : WriteBuffer(pBuffer,dwIndex);
                    
                pBuffer += dwIndex; // 

                // Go to the next scatter/gather if no more space left

                if ((dwSgLen == 0) && ( --dwSgLeft > 0)) {
                    pSgBuf++;
                    pBuffer = (PBYTE)MapPtrToProcess((LPVOID)pSgBuf->sb_buf, GetCallerProcess());
                    dwSgLen = pSgBuf->sb_len;
                }
            }   

            if (fRead) {
                while (dwBytesPerBlock > 0)  {
                    (void) ReadWord();
                    dwBytesPerBlock-=2 ;            
                }
            }
                
        }
        
        if (ERROR_SUCCESS != dwError)
            break;

        //  In case of write command an interrupt is generated upon each block.
        //  We can either wait for the interrupt or simply ignore it.
        //  However this is danger because an interrupt is pending and blocks all
        //  other interrupts on the same or lower level.

        if ( !fRead && m_fInterruptSupported) {     
            if (!WaitForInterrupt(m_dwDiskIoTimeOut) || (CheckIntrState() == ATA_INTR_ERROR)) {  
                DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadWrite- WaitforInterrupt failed (DevId %x) \r\n"),m_dwDeviceId));
                dwError = ERROR_READ_FAULT;
                break;
            } 
        }            
    }
    
    if (ERROR_SUCCESS != dwError) {
        ResetController();
        if (!(m_Id.Capabilities & 0x0200) && m_fLBAMode) {
            m_fLBAMode = FALSE;
            dwError = ReadWriteDisk(pIOReq, fRead);
        } else {
        }   
    }    
    pSgReq->sr_status = dwError;
    return dwError;

}

// ----------------------------------------------------------------------------
// Function: ReadWriteDiskDMA
//     This function reads from/writes to an ATA device
//
// Parameters:
//     pIOReq -
//     fRead -
// ----------------------------------------------------------------------------

DWORD
CDisk::ReadWriteDiskDMA(
    PIOREQ pIOReq,
    BOOL fRead
    )
{
    DWORD dwError = ERROR_SUCCESS;
    PSG_REQ pSgReq = (PSG_REQ)pIOReq->pInBuf;
    DWORD dwSectorsToTransfer;
    SG_BUF CurBuffer[MAX_SG_BUF];
    BYTE bCmd;
    SG_BUF                  SgBufTemp;

    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;
    }

    DEBUGMSG(ZONE_IO, (_T(
        "Atapi!ReadWriteDiskDMA> sr_start(%ld), sr_num_sec(%ld), sr_num_sg(%ld)\r\n"
        ), pSgReq->sr_start, pSgReq->sr_num_sec, pSgReq->sr_num_sg));

    GetBaseStatus(); // clear pending interrupt

    DWORD dwStartBufferNum = 0, dwEndBufferNum = 0, dwEndBufferOffset = 0;
    DWORD dwNumSectors = pSgReq->sr_num_sec;
    DWORD dwStartSector = pSgReq->sr_start;
	DWORD dwSectorsToTransferMax = (ATAPI_BUFFER_SIZE / BYTES_PER_SECTOR) > MAX_SECT_PER_COMMAND ? MAX_SECT_PER_COMMAND : (ATAPI_BUFFER_SIZE / BYTES_PER_SECTOR);

    // process scatter/gather buffers in groups of MAX_SEC_PER_COMMAND sectors
    // each DMA request handles a new SG_BUF array which is a subset of the
    // original request, and may start/stop in the middle of the original buffer

    while (dwNumSectors) {
        // determine number of sectors to transfer
        dwSectorsToTransfer = (dwNumSectors > dwSectorsToTransferMax) ? dwSectorsToTransferMax : dwNumSectors;

        // determine size (in bytes) of transfer
        DWORD dwBufferLeft = dwSectorsToTransfer * BYTES_PER_SECTOR;

        DWORD dwNumSg = 0;

        // while the transfer is not complete
        while (dwBufferLeft) {

            // determine the size of the current scatter/gather buffer
            DWORD dwCurBufferLen = pSgReq->sr_sglist[dwEndBufferNum].sb_len - dwEndBufferOffset;

            if (dwBufferLeft < dwCurBufferLen) {
                CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_buf = pSgReq->sr_sglist[dwEndBufferNum].sb_buf + dwEndBufferOffset;
                CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_len = dwBufferLeft;
                dwEndBufferOffset += dwBufferLeft;
                dwBufferLeft = 0;
            }
            else {
                CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_buf = pSgReq->sr_sglist[dwEndBufferNum].sb_buf + dwEndBufferOffset;
                CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_len = dwCurBufferLen;
                dwEndBufferOffset = 0;
                dwEndBufferNum++;
                dwBufferLeft -= dwCurBufferLen;
            }
            dwNumSg++;
        }

        bCmd = fRead ? ATA_CMD_READ_DMA : ATA_CMD_WRITE_DMA;

        WaitForInterrupt(0);

	    SgBufTemp.sb_len = dwSectorsToTransfer * BYTES_PER_SECTOR;
	    SgBufTemp.sb_buf = CurBuffer[0].sb_buf;

        // setup the DMA transfer
		if (!SetupDMA( &SgBufTemp, 1, fRead)) {
            dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
            goto ExitFailure;
        }

        // write the read/write command
        if (!SendIOCommand(dwStartSector, dwSectorsToTransfer, bCmd)) {
            dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
            AbortDMA();
            goto ExitFailure;
        }

        // start the DMA transfer
        if (BeginDMA(fRead)) {
            if (m_fInterruptSupported) {
                if (!WaitForInterrupt(m_dwDiskIoTimeOut) || (CheckIntrState() == ATA_INTR_ERROR)) {
                    DEBUGMSG(ZONE_IO || ZONE_WARNING, (_T(
                        "Atapi!CDisk::ReadWriteDiskDMA> Failed to wait for interrupt; device(%d)\r\n"
                        ), m_dwDeviceId));
                    dwError = ERROR_READ_FAULT;
                    AbortDMA();
                    goto ExitFailure;
                }
            }
            // stop the DMA transfer
            if (EndDMA()) {
                WaitOnBusy(FALSE);
                CompleteDMA(CurBuffer, dwNumSg, fRead);
            }
/*
			else{
	            dwError = fRead ? ERROR_READ_FAULT : ERROR_WRITE_FAULT;
	            AbortDMA();
	            goto ExitFailure;
			}
*/
        }

        // update transfer
        dwStartSector += dwSectorsToTransfer;
        dwStartBufferNum = dwEndBufferNum;
        dwNumSectors -= dwSectorsToTransfer;
    }

ExitFailure:
    if (ERROR_SUCCESS != dwError) {
        ResetController();
    }
    pSgReq->sr_status = dwError;
    return dwError;
}

// ----------------------------------------------------------------------------
// Function: GetStorageId
//     Implement IOCTL_DISK_GET_STORAGEID
//
// Parameters:
//     pIOReq -
// ----------------------------------------------------------------------------

DWORD
CDisk::GetStorageId(
    PIOREQ pIOReq
    )
{
    DWORD dwBytesLeft;
    PBYTE pDstOffset;
    PSTORAGE_IDENTIFICATION pStorageId = (PSTORAGE_IDENTIFICATION)pIOReq->pOutBuf;

    // validate arguments
    if (!pStorageId || (pIOReq->dwOutBufSize < sizeof(STORAGE_IDENTIFICATION)) || !pIOReq->pBytesReturned) {
        return ERROR_INVALID_PARAMETER;
    }

    // prepare return structure
    pStorageId->dwSize = sizeof(STORAGE_IDENTIFICATION);
    pStorageId->dwFlags = 0; // {MANUFACTUREID,SERIALNUM}_INVALID

    // prepare return structure indicies, for write
    dwBytesLeft = pIOReq->dwOutBufSize - sizeof(STORAGE_IDENTIFICATION);
    pDstOffset = (PBYTE)(pStorageId + 1);
    pStorageId->dwManufactureIDOffset = pDstOffset - (PBYTE)pStorageId;

    SetLastError(ERROR_SUCCESS);

    // fetch manufacturer ID
    if (!ATAParseIdString((PBYTE)m_Id.ModelNumber, sizeof(m_Id.ModelNumber), &(pStorageId->dwManufactureIDOffset), &pDstOffset, &dwBytesLeft)) {
        pStorageId->dwFlags |= MANUFACTUREID_INVALID;
    }
    pStorageId->dwSerialNumOffset = pDstOffset - (PBYTE)pStorageId;
    // fetch serial number
    if (!ATAParseIdString((PBYTE)m_Id.SerialNumber, sizeof(m_Id.SerialNumber), &(pStorageId->dwSerialNumOffset), &pDstOffset, &dwBytesLeft)) {
        pStorageId->dwFlags |= SERIALNUM_INVALID;
    }
    pStorageId->dwSize = pDstOffset - (PBYTE)pStorageId;

    // store bytes written
    *(pIOReq->pBytesReturned)= min(pStorageId->dwSize, pIOReq->dwOutBufSize);

    return GetLastError();
}

// ----------------------------------------------------------------------------
// Function: SetWriteCacheMode
//     Issue SET FEATURES enable write cache command
//
// Parameters:
//     fEnable -
// ----------------------------------------------------------------------------

BOOL
CDisk::SetWriteCacheMode(
    BOOL fEnable
    )
{
    BYTE bError, bStatus;

    // select device
    SelectDevice();

    // wait for device to acknowledge selection
    WaitForDisc(WAIT_TYPE_NOT_BUSY, 100);
    WaitForDisc(WAIT_TYPE_READY, 1000);
    WaitOnBusy(TRUE);

    // write command
    SelectDevice();
    WriteFeature(fEnable ? ATA_ENABLE_WRITECACHE : ATA_DISABLE_WRITECACHE);
    WriteCommand(ATAPI_CMD_SET_FEATURES);

    // wait for device to respond to command
    SelectDevice();
    WaitOnBusy(TRUE);
    SelectDevice();
    WaitForDisc(WAIT_TYPE_NOT_BUSY, 200);

    // check response
    bStatus = GetBaseStatus();
    bError = GetError();
    if ((bStatus & ATA_STATUS_ERROR) && (bError & ATA_ERROR_ABORTED)) {
        DEBUGMSG(ZONE_ERROR, (_T(
            "Atapi!CDisk::SetWriteCacheMode> Failed to enable write cache; status(%02X), error(%02X)\r\n"
            ), bStatus, bEr

⌨️ 快捷键说明

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