diskmain.cpp

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

CPP
1,948
字号
        // an error occurred
        if (dwRetries < HPIOI1_CHECK_STATUS_RETRIES) {
            dwRetries++;
            Sleep(5);
            goto HPIOI1_Check_Status;
         }
         fResult = FALSE;
         goto exit;
    }
    if (bStatus & ATA_STATUS_BUSY) { // BSY=1
        goto HPIOI1_Check_Status;
    }
    if (!(bStatus & ATA_STATUS_BUSY) && (bStatus & ATA_STATUS_DATA_REQ)) { // BSY=0 and DRQ=1
        goto HPIOI2_Transfer_Data;
    }

    // HPIOI2:Transfer_Data
    // --------------------
    // (IDENTIFY [ATAPI] DEVICE only returns a single DRQ data block)
HPIOI2_Transfer_Data:;
    cbIdentifyDeviceData = sizeof(IDENTIFY_DATA);
    DEBUGCHK(cbIdentifyDeviceData <= BYTES_PER_SECTOR);
    // read result of IDENTIFY DEVICE/IDENTIFY PACKET DEVICE
    if (m_f16Bit) {
    
        USHORT temp[sizeof(IDENTIFY_DATA)/2];    
        USHORT value;
        
        cbIdentifyDeviceData /= 2;
        ReadWordBuffer((PWORD)temp, cbIdentifyDeviceData);

        for (DWORD i=0; i<cbIdentifyDeviceData ; i++)
        {
            value = ((*(temp + i)& 0xff00) >> 8) & 0xff;
            value |= ((*(temp + i)& 0xff ) << 8) & 0xff00;
            
            *(((USHORT *)(&m_Id)) + i) = value;
        }
    }
    else {
        ReadByteBuffer((PBYTE)&m_Id, cbIdentifyDeviceData);
    }
    // ignore extraneous data
    while (GetAltStatus() & ATA_STATUS_DATA_REQ ) {
        if (m_f16Bit) {
            ReadWord();
        }
        else {
            ReadByte();
        }
    }

    *((UINT32 *)(m_pATAReg + ATA_CFG)) &= ~(0x40);
    // Return to Host Idle protocol

exit:;

    // clear pending interrupt, if applicable
    GetBaseStatus();

    return fResult;
}

// ----------------------------------------------------------------------------
// Function: Identify
//     This function initiates communication with a device.  If the
//     appropriate device is detected on the current channel, then issue an
//     EXECUTE DEVICE DIAGNOSTIC to determine whether the device is a master
//     or slave and ATA or ATAPI device.  Then, issue an IDENTIFY DEVICE/
//     IDENTIFY PACKET DEVICE and select the appropriate READ/WRITE command.
//     Finally, assemble the device's associated DISK_INFO structure.
//
// Parameters:
//     None
// ----------------------------------------------------------------------------
BOOL CDisk::Identify()
{
    DWORD dwBlockSize = 0; // Size of IDENTIFY DEVICE/IDENTIFY PACKET DEVICE information.
    WORD  wDevType = 0;    // Supported command packet set (e.g., direct-access, CD-ROM, etc.).

    TakeCS();

    // If device isn't present, exit.
    if (FALSE == IsDevicePresent()) {
        ReleaseCS();
        return FALSE;
    }

    // Issue EXECUTE DEVICE DIAGNOSTIC.  Determine whether the device is ATA or
    // ATAPI (ignore the result of this call, as old devices fail to respond
    // correctly).
    BYTE bDiagnosticCode;
    BOOL fIsAtapi;
    SendExecuteDeviceDiagnostic(&bDiagnosticCode, &fIsAtapi);

    // Is this an ATA device?
    if (TRUE == SendIdentifyDevice(FALSE)) { // fIsAtapi=FALSE
        m_fAtapiDevice = FALSE;
        // Some IDE controllers have problems with ATAPI DMA.
        if (2 == m_pPort->m_pDskReg[m_dwDeviceId]->dwDMA) { // 0=PIO, 1=DMA, 2=ATA DMA only
            m_fDMAActive = TRUE;
        }
    }
    // Is this an ATAPI device?
    else if (TRUE == SendIdentifyDevice(TRUE)) { // fIsAtapi=TRUE
        m_fAtapiDevice = TRUE;
    }
    else {
        DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T("Atapi!CDisk::Identify> Device failed to respond to IDENTIFY DEVICE and IDENTIFY PACKET DEVICE\r\n")));
        ReleaseCS();
        return FALSE;
    }

    ReleaseCS();

    // Validate IDENTIFY DEVICE/IDENTIFY PACKET DEVICE signature; an empty
    // channel may return invalid data.

    DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::Identify> ATA-Disk Total Sector Size 0x%x\r\n"), m_Id.TotalUserAddressableSectors));            

    if ((m_Id.GeneralConfiguration == 0) || (m_Id.GeneralConfiguration == 0xffff) ||
        (m_Id.GeneralConfiguration == 0xff7f) ||
        (m_Id.GeneralConfiguration == 0x7fff) ||
       ((m_Id.GeneralConfiguration == m_Id.IntegrityWord) && (m_Id.NumberOfCurrentCylinders == m_Id.IntegrityWord))
    ) {
        DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T(
            "Atapi!CDisk::Identify> General configuration(%04X) not valid; device not present\r\n"
            ), m_Id.GeneralConfiguration));
        return FALSE;
    }
    // Dump IDENTFY DEVICE/IDENTIFY PACKET DEVICE data.
    PIDENTIFY_DATA pId = &m_Id;
    DUMPIDENTIFY(pId);
    DUMPSUPPORTEDTRANSFERMODES(pId);

    // ATA/ATAPI-3 compatible devices store the supported command packet set in
    // bits 12-8 of word 0 of IDENTIFY DEVICE/IDENTIFY PACKET DEVICE data (this
    // information is retired in ATA/ATAPI-6).  Determine which command packet
    // set is implemented by the device.
    wDevType = (m_Id.GeneralConfiguration >> 8) & 0x1F;
    switch (wDevType) {
        case ATA_IDDEVICE_UNKNOWN:
            return FALSE;
        case ATA_IDDEVICE_CDROM:
            m_dwDeviceFlags |= DFLAGS_DEVICE_CDROM;
            break;
        case ATA_IDDEVICE_DISK:
            break;
        case ATA_IDDEVICE_OPTICAL_MEM:
            break;
        default:
            DEBUGMSG(ZONE_INIT, (_T("Atapi!CDisk::Identify> Assuming direct-access device (hard disk drive)\r\n")));
            break;
    }

    // This is redundant, but various routines use this information.
    m_dwDeviceFlags |= DFLAGS_DEVICE_PRESENT;
    m_dwDeviceFlags |= (IsAtapiDevice()) ? DFLAGS_ATAPI_DEVICE : 0;
    m_dwDeviceFlags |= (IsRemoveableDevice()) ? DFLAGS_REMOVABLE_DRIVE : 0;

    // ATA devices support two flavors of read/write commands: READ/WRITE
    // SECTOR(S) and READ/WRITE MULTIPLE.  READ/WRITE SECTOR(S) use a fixed DRQ
    // data block size of 1 sector and READ/WRITE MULTIPLE use a driver-
    // specified (variable) DRQ data block size of up to 255 sectors.
    if (FALSE == IsAtapiDevice()) {
        // Default to READ/WRITE SECTOR(S).
        m_bReadCommand = ATA_CMD_READ;
        m_bWriteCommand = ATA_CMD_WRITE;
        m_bSectorsPerBlock = 1;
        // Is READ/WRITE MULTIPLE supported?
        if (0 != m_Id.MaximumBlockTransfer) {
            // The device supports a variable DRQ data block size.  Set the DRQ
            // data block size to the minimum of the registry-specified DRQ
            // data block size and the maximum DRQ data block size supported by
            // the device.
            if (0 == m_pPort->m_pDskReg[m_dwDeviceId]->dwDrqDataBlockSize) {
                // Use device's maximum DRQ data block size.
                m_bSectorsPerBlock = m_Id.MaximumBlockTransfer;
            }
            else {
                m_bSectorsPerBlock = MIN((BYTE)(m_pPort->m_pDskReg[m_dwDeviceId]->dwDrqDataBlockSize / SECTOR_SIZE), m_Id.MaximumBlockTransfer);
            }
            SelectDevice();
            WriteSectorCount(m_bSectorsPerBlock);
            WriteCommand(ATA_CMD_SET_MULTIPLE);
            if ((FALSE == WaitOnBusy(FALSE)) && (ATA_STATUS_READY & GetAltStatus())) {
                m_bReadCommand = ATA_CMD_MULTIPLE_READ;
                m_bWriteCommand = ATA_CMD_MULTIPLE_WRITE;
                DEBUGMSG(ZONE_INIT, (_T("Atapi!CDisk::Identify> Set DRQ data block size to %d sectors (READ/WRITE MULTIPLE sectors per interrupt)\r\n"), m_bSectorsPerBlock));
            }
            else {
                // Revert DRQ data block size.
                DEBUGMSG(ZONE_INIT, (_T("Atapi!CDisk::Identify> Failed to set DRQ data block size to %d sectors; using READ/WRITE SECTOR(S)\r\n"), m_bSectorsPerBlock));
                m_bSectorsPerBlock = 1;
            }
        }
    }

    m_bDMAReadCommand = ATA_CMD_READ_DMA;
    m_bDMAWriteCommand = ATA_CMD_WRITE_DMA;

    // Assemble DISK_INFO structure.
    m_fLBAMode = (m_Id.Capabilities & 0x0200) ? TRUE : FALSE;
    m_DiskInfo.di_flags = DISK_INFO_FLAG_MBR;
    m_DiskInfo.di_bytes_per_sect = BYTES_PER_SECTOR;
    m_DiskInfo.di_cylinders = m_Id.NumberOfCylinders;
    m_DiskInfo.di_heads = m_Id.NumberOfHeads;
    m_DiskInfo.di_sectors = m_Id.SectorsPerTrack;
    if (m_fLBAMode) {
        m_DiskInfo.di_total_sectors = m_Id.TotalUserAddressableSectors;
        ConfigLBA48(); // set m_fUseLBA48 if applicable
    }
    else {
        m_DiskInfo.di_total_sectors = m_DiskInfo.di_cylinders*m_DiskInfo.di_heads * m_DiskInfo.di_sectors;
    }

    return TRUE;
}


// ----------------------------------------------------------------------------
// Function: ConfigLBA48
//     This is a helper function which is called after the IDENTIFY_DEVICE
//     command has been successfully executed.  It parses the results
//     of the IDENTIFY_DEVICE command to determine if 48-bit LBA is supported
//     by the device.
//
// Parameters:
//     None
// ----------------------------------------------------------------------------

void CDisk::ConfigLBA48(void)
{
    PIDENTIFY_DATA pId = (PIDENTIFY_DATA)&m_Id;

    if (m_pPort->m_pController->m_pIdeReg->dwDisable48BitLBA) 
    {
        m_fUseLBA48 = FALSE;
        return;
    }

    // Word 87 (CommandSetFeatureDefault): 
    //         bit 14 is set and bit 15 is cleared if config data
    //         in word 86 (CommandSetFeatureEnabled2) is valid.
    // Note that this is only valid for non-ATAPI devices
    if ( !IsAtapiDevice() &&
         (pId->CommandSetFeatureDefault & (1 << 14)) &&
         !(pId->CommandSetFeatureDefault & (1 << 15)) &&
         (pId->CommandSetFeatureEnabled2 & (1 << 10)) )
    {
        DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> Device supports 48-bit LBA\r\n")));
        DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> Max LBA Address = 0x%08x%08x"),
                             pId->lMaxLBAAddress[1],
                             pId->lMaxLBAAddress[0]));


        DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> Device supports 48-bit LBA\r\n")));
        DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> Max LBA Address = 0x%08x, 0x%08x"),
                             pId->lMaxLBAAddress[1],
                             pId->lMaxLBAAddress[0]));

        m_fUseLBA48 = TRUE;

        // The CE file system currently supports a maximum of 32-bit sector addresses,
        if (pId->lMaxLBAAddress[1] == 0)
        {
            m_DiskInfo.di_total_sectors = pId->lMaxLBAAddress[0];
            DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> This disk supports LBA48 mode and total sector 0x%x\r\n"), m_DiskInfo.di_total_sectors));            
        }
            
        else
            m_DiskInfo.di_total_sectors = 0xFFFFFFFF; // Couldn't find MAX_DWORD

        ASSERT(pId->lMaxLBAAddress[1] <= 0x10000);

        // CDisk::Identify has determined whether or not the device supports multi-sector transfers
        // Update read/write command to use [READ|WRITE] [SECTORS|MULTIPLE] EXT
        if (m_bReadCommand == ATA_CMD_READ) 
        {
            m_bReadCommand = ATA_CMD_READ_SECTOR_EXT;
            m_bWriteCommand = ATA_CMD_WRITE_SECTOR_EXT;
        }
        else // CDisk::Identify has determined that the devce supports multi-sector transfers
        {
            m_bReadCommand = ATA_CMD_READ_MULTIPLE_EXT;
            m_bWriteCommand = ATA_CMD_WRITE_MULTIPLE_EXT;
        }

        m_bDMAReadCommand = ATA_CMD_READ_DMA_EXT;
        m_bDMAWriteCommand = ATA_CMD_WRITE_DMA_EXT;

    }
    else
    {
        m_fUseLBA48 = FALSE;
    }
}

// ----------------------------------------------------------------------------
// Function: ValidateSg
//     Map embedded pointers
//
// Parameters:
//     pSgReq -
//     InBufLen - The size of the actual buffer as specified by the user.
//                This needs to be cross checked with pSgReq->sr_num_sg to
//                prevent buffer overflows
//     saveoldptrs - Your old pointers are saved here. Must be at least
//                   pSgReq->sr_num_sg in size
// ----------------------------------------------------------------------------

BOOL
CDisk::ValidateSg(
    PSG_REQ pSgReq,
    DWORD InBufLen,
    DWORD dwArgType,
    OUT PUCHAR * saveoldptrs
    )
{
    DWORD dwIndex ;
    PUCHAR ptemp;

    if (NULL == pSgReq) {
        ASSERT(pSgReq);
        return FALSE;
    }

    if (InBufLen < sizeof(SG_REQ)) {
        ASSERT(InBufLen >= sizeof(SG_REQ));
        return FALSE;
    }

    // pSgReq is a sterile copy of the caller's SG_REQ; we're supposed to map
    // the embedded sb_bufs back into the SG_REQ

    if(
        !(pSgReq->sr_num_sg >= 1) ||
        !(pSgReq->sr_num_sg <= MAX_SG_BUF) ||
        !((sizeof(SG_REQ) + sizeof(SG_BUF)*(pSgReq->sr_num_sg-1)) == InBufLen) ||
        !(pSgReq->sr_num_sec > 0))
    {
        ASSERT(pSgReq->sr_num_sg >= 1);
        ASSERT(pSgReq->sr_num_sg <= MAX_SG_BUF);
        ASSERT((sizeof(SG_REQ) + sizeof(SG_BUF)*(pSgReq->sr_num_sg-1)) == InBufLen);
        ASSERT(pSgReq->sr_num_sec > 0);
        return FALSE;
    }

    for (dwIndex = 0; dwIndex < pSgReq->sr_num_sg; dwIndex++) {
        if (
            (NULL == pSgReq->sr_sglist[dwIndex].sb_buf) ||
            (0 == pSgReq->sr_sglist[dwIndex].sb_len)
        ) {
            goto CleanUpLeak;
        }

        // Verify embedded pointer access and map user mode pointers

        if (FAILED(CeOpenCallerBuffer(
                    (PVOID *)&ptemp,
                    (LPVOID)pSgReq->sr_sglist[dwIndex].sb_buf,
                    pSgReq->sr_sglist[dwIndex].sb_len,
                    dwArgType,
                    FALSE)))
        {
            goto CleanUpLeak;
        }

        saveoldptrs[dwIndex] = pSgReq->sr_sglist[dwIndex].sb_buf;
        pSgReq->sr_sglist[dwIndex].sb_buf = ptemp;

        if (NULL == pSgReq->sr_sglist[dwIndex].sb_buf) {
            goto CleanUpLeak;
        }
    }

    return TRUE;

CleanUpLeak:

    if (FAILED(UnmapSg(
                pSgReq->sr_sglist,
                saveoldptrs,
                dwIndex,
                dwArgType)))
    {
        ASSERT(!"Cleanup call to CeCloseCallerBuffer failed unexpectedly");
        return FALSE;
    }

⌨️ 快捷键说明

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