Jump to content

How to use DeviceIoControl Function?


Recommended Posts

For example, the following code:

A:

/**********************************************************************
;       Copyright 2005 Summit Soft Consulting
;
;                       RESTRICTED RIGHTS LEGEND
;                       ------------------------
;
; Use, duplication, or disclosure by any commercial industry (public
; or private), private individual, or by any Government Agency without
; a express written consent of release from Summit Soft Consulting
; is subject to restrictions as set forth in paragraph (b) (3) (B) of
; the Rights in Technical Data and Computer Software clause in
; DAR 7-104.9 (a).  Manufacturer is: Summit Soft Consulting,
; 26895 Aliso Creek Rd. Suite B504, Aliso Viejo, CA 92656,
; http://www.SummitSoftConsulting.com
;**********************************************************************/

#include "stdafx.h"
#include <windows.h>
#include <winioctl.h>
#include "PciFunction.h"

DWORD CPciFunction::m_ReadConfigSpaceDword(ULONG ulBus, ULONG ulDevice, ULONG ulFunction, ULONG ulDwordOffset)
{
    READ_CONFIG_SPACE_DWORD_INPARAMS InParams;
    InParams.ulBus = ulBus;
    InParams.ulDevice = ulDevice;
    InParams.ulFunction = ulFunction;
    InParams.ulDwordOffset = ulDwordOffset;

    // These are the out parameters.
    READ_CONFIG_SPACE_DWORD_OUTPARAMS OutParams;

    DWORD dwBytesRead = 0;
    BOOL bSuccess = DeviceIoControl(
                m_hDriver,
                IOCTL_READ_CONFIG_SPACE_DWORD,
                &InParams,
                sizeof(READ_CONFIG_SPACE_DWORD_INPARAMS),
                &OutParams,
                sizeof(READ_CONFIG_SPACE_DWORD_OUTPARAMS),
                &dwBytesRead,
                NULL);
    _ASSERTE(bSuccess);

    // All ok.
    return OutParams.ulData;
}

BOOL CPciFunction::m_ReadConfigSpaceHeader(ULONG ulBus, ULONG ulDevice, ULONG ulFunction, PTYPEX_HEADER pTypeXHeader)
{
    READ_CONFIG_SPACE_HEADER_INPARAMS InParams;
    InParams.ulBus = ulBus;
    InParams.ulDevice = ulDevice;
    InParams.ulFunction = ulFunction;

    // These are the out parameters.
    READ_CONFIG_SPACE_HEADER_OUTPARAMS OutParams;

    DWORD dwBytesRead = 0;
    BOOL bSuccess = DeviceIoControl(
                m_hDriver,
                IOCTL_READ_CONFIG_SPACE_HEADER,
                &InParams,
                sizeof(READ_CONFIG_SPACE_HEADER_INPARAMS),
                &OutParams,
                sizeof(READ_CONFIG_SPACE_HEADER_OUTPARAMS),
                &dwBytesRead,
                NULL);
    _ASSERTE(bSuccess);

    if(bSuccess)
    {
        // Set the out-parameters.
        memcpy(pTypeXHeader, OutParams.Hdr.vulConfig, sizeof(TYPEX_HEADER));
    }

    // All Ok.
    return bSuccess;
}

BOOL CPciFunction::m_WriteConfigSpaceXxx(ULONG ulBus, ULONG ulDevice, ULONG ulFunction, ULONG ulByteOffset, UCHAR ucSize, ULONG ulData)
{
    WRITE_CONFIG_SPACE_XXX_INPARAMS InParams;
    InParams.ulBus = ulBus;
    InParams.ulDevice = ulDevice;
    InParams.ulFunction = ulFunction;
    InParams.ulByteOffset = ulByteOffset;
    InParams.ucSize = ucSize;
    InParams.ulData = ulData;

    DWORD dwBytesRead = 0;
    BOOL bSuccess = DeviceIoControl(
                m_hDriver,
                IOCTL_WRITE_CONFIG_SPACE_XXX,
                &InParams,
                sizeof(WRITE_CONFIG_SPACE_XXX_INPARAMS),
                NULL,
                0,
                &dwBytesRead,
                NULL);
    _ASSERTE(bSuccess);

    return bSuccess;
}

DWORD CPciFunction::m_ReadConfigSpaceXxx(ULONG ulBus, ULONG ulDevice, ULONG ulFunction, ULONG ulByteOffset, UCHAR ucSize)
{
    READ_CONFIG_SPACE_XXX_INPARAMS InParams;
    InParams.ulBus = ulBus;
    InParams.ulDevice = ulDevice;
    InParams.ulFunction = ulFunction;
    InParams.ulByteOffset = ulByteOffset;
    InParams.ucSize = ucSize;

    // These are the out parameters.
    READ_CONFIG_SPACE_XXX_OUTPARAMS OutParams;

    DWORD dwBytesRead = 0;
    BOOL bSuccess = DeviceIoControl(
                m_hDriver,
                IOCTL_READ_CONFIG_SPACE_XXX,
                &InParams,
                sizeof(READ_CONFIG_SPACE_XXX_INPARAMS),
                &OutParams,
                sizeof(READ_CONFIG_SPACE_XXX_OUTPARAMS),
                &dwBytesRead,
                NULL);
    _ASSERTE(bSuccess);

    // All ok.
    return OutParams.ulData;
}

PCAPABILITIES_HEADER CPciFunction::GetFirstCapabilitiesHeader(DWORD *pdwDwordOffset)
{
    // The function only has a capabilities pointer if bit 4 in 
    // the Status Register is 1. The Capabilities pointer itself
    // must also be non-null. Note: We mask out the lower two bits
    // of the Caps Ptr as stated in the PCI spec (DWORD aligned).
    if(!(m_TypeXHeader.Type0Hdr.usStatusRegister & (1<<4)) || 
        !(m_TypeXHeader.Type0Hdr.ucCapabilitiesPointer & 0xfc))
    {
        // The function does not have any capabilities pointer.
        return NULL;
    }

    // Get the first capabilities header.
    DWORD dwDwordOffset = (m_TypeXHeader.Type0Hdr.ucCapabilitiesPointer & 0xfc) / 4;
    PCAPABILITIES_HEADER pCapsHdr = (PCAPABILITIES_HEADER)&m_TypeXHeader.vulConfig[dwDwordOffset];

    // Set the out-parameter.
    if(pdwDwordOffset)
    {
        *pdwDwordOffset = dwDwordOffset;
    }

    // All OK.
    return pCapsHdr;
}

PCAPABILITIES_HEADER CPciFunction::GetNextCapabilitiesHeader(PCAPABILITIES_HEADER pCapsHdr, DWORD *pdwDwordOffset)
{
    // If this is the last Capabilities Header in the list we return NULL.
    if(pCapsHdr->chNextCapabilityOffset == 0)
    {
        return NULL;
    }

    // Get the next capabilities header.
    DWORD dwDwordOffset = (pCapsHdr->chNextCapabilityOffset & 0xfc) / 4;
    PCAPABILITIES_HEADER pNextCapsHdr = (PCAPABILITIES_HEADER)&m_TypeXHeader.vulConfig[dwDwordOffset];

    // Set the out-parameter.
    if(pdwDwordOffset)
    {
        *pdwDwordOffset = dwDwordOffset;
    }
    // All Ok.
    return pNextCapsHdr;
}

CPciFunction::CPciFunction(HANDLE hDriver)
{
    // Save parameters for later use.
    m_hDriver = hDriver;

    // We know that that the host/PCI bridge is on bus 0.
    // The device and function numbers will be initialized 
    // by our m_InitializeAsHostBridge member function.
    m_ulBus = 0;

    // Search the PCI bus for the host bridge function.
    m_InitializeAsHostBridge();

    // Search for all functions on this bus and create objects for them.
    m_EnumerateSecondaryBusFunctions();

    // Save the original config space so we later 
    // know what fields to update in the function.
    m_MakeConfigSpaceCopy();

    // Read in the Device/Vendor information from the "pciDevs.txt" file.
    m_ParsePciDevicesFile();    

    // Read in the BAR sizes from the registry. NOTE: We read the BAR sizes 
    // from the registry because it is not safe to query the BAR registers 
    // while devices are running. Because the BAR sizes never changes this
    // method to determine the BAR sizes is as reliable as directly reading
    // the BARs.
    m_GetBarSizesFromRegistry();
}

CPciFunction::CPciFunction(HANDLE hDriver, ULONG ulBus, ULONG ulDevice, ULONG ulFunction)
{
    // Save the parameters for later use.
    m_hDriver = hDriver;
    m_ulBus = ulBus;
    m_ulDevice = ulDevice;
    m_ulFunction = ulFunction;

    // Read in our information from the PCI bus.
    BOOL bSuccess = m_ReadConfigSpaceHeader(ulBus, ulDevice, ulFunction, &m_TypeXHeader);
    _ASSERTE(bSuccess);

    // If we are a bridge we create CPciFunction objects for all functions found on our secondary bus.
    if(m_TypeXHeader.Type0Hdr.ucClassCode == 6)
    {
        m_EnumerateSecondaryBusFunctions();
    }

    // Save the original config space so we later 
    // know what fields to update in the function.
    m_MakeConfigSpaceCopy();

    // Read in the Device/Vendor information from the "pciDevs.txt" file.
    m_ParsePciDevicesFile();    

    // Read in the BAR sizes from the registry. NOTE: We read the BAR sizes 
    // from the registry because it is not safe to query the BAR registers 
    // while devices are running. Because the BAR sizes never changes this
    // method to determine the BAR sizes is as reliable as directly reading
    // the BARs.
    m_GetBarSizesFromRegistry();
}

CPciFunction::~CPciFunction()
{
    // Delete all our CPciFunction objects.
    for(DWORD dwIndex = 0; dwIndex<m_vectSecondaryBusPciFunctions.size(); dwIndex++)
    {
        delete m_vectSecondaryBusPciFunctions[dwIndex];
    }

    // Delete all stored items;
    m_vectSecondaryBusPciFunctions.clear();
}

void CPciFunction::m_InitializeAsHostBridge()
{
    // This function is called by the Host/PCI bridge constructor.
    // Search all devices and functions on bus 0.
    for(DWORD dwDeviceIndex = 0; dwDeviceIndex<32; dwDeviceIndex++)
        for(DWORD dwFunctionIndex = 0; dwFunctionIndex<8; dwFunctionIndex++)
    {
        // Do we have a function at this bus/device/function combination?
        DWORD dwVendorDeviceIds = m_ReadConfigSpaceDword(0, dwDeviceIndex, dwFunctionIndex, 0);
        if(dwVendorDeviceIds != 0xffffffff)
        {
            // We've found a valid PCI function.
            // Read in the header and new capabilities data.
            TYPEX_HEADER TypeXHeader;
            BOOL bSuccess = m_ReadConfigSpaceHeader(0, dwDeviceIndex, dwFunctionIndex, &TypeXHeader);
            _ASSERTE(bSuccess);
            if(!bSuccess)
            {
                continue;
            }

            // If this is the Host/PCI bridge function we are finished.
            // NOTE: We here assume that the machine only has ONE Host/PCI bridge.
            if(TypeXHeader.Type0Hdr.ucClassCode == 6 && TypeXHeader.Type0Hdr.ucSubClassCode == 0)
            {
                // Save the PCI header for later use.
                memcpy(&m_TypeXHeader, &TypeXHeader, sizeof(TYPEX_HEADER));

                // Also save our device and function index.
                m_ulDevice = dwDeviceIndex;
                m_ulFunction = dwFunctionIndex;

                return;
            }
        }
    }
    
    // If we end up here we didn't find any Host/PCI bridge!
    // This will only happen if the system doesn't have a PCI bus!
    _ASSERTE(FALSE);
}

void CPciFunction::m_EnumerateSecondaryBusFunctions()
{
    // If we are NOT a Host/PCI or PCI/PCI bridge we 
    // don't have any secondary PCI bus to enumerate.
    if(!IsBridge())
    {
        return;
    }

    // Get our secondary bus number.
    // If we are a Host/PCI bridge our secondary bus is always 0.
    // If we are a PCI/PCI bridge we get our secondary bus from the Type1 header.
    UCHAR ucSecondaryBusNumber = 0;
    if(m_TypeXHeader.Type0Hdr.ucSubClassCode == 4)
    {
        ucSecondaryBusNumber = m_TypeXHeader.Type1Hdr.ucSecondaryBusNumber;
    }

    // NOTE: We ignore functions 7..1 in a device if the device is not
    // a multi-function device. Some devices claim configuration transactions
    // directed to the non-zero function although they are single-function devices.
    BOOL bMultiFunctionDevice = FALSE;

    // Search for all devices that reside on our secondary bus and create 
    // in-memory CPciFunction objects that represent the devices found.
    for(DWORD dwDeviceIndex = 0; dwDeviceIndex<32; dwDeviceIndex++)
        for(DWORD dwFunctionIndex = 0; dwFunctionIndex<8; dwFunctionIndex++)
    {
        // If we are the Host/PCI bridge we are enumerating devices on the
        // same bus we are residing on (Bus 0). We must ignore our own device
        // since our object already represents the device in memory.
        if(ucSecondaryBusNumber == m_ulBus && dwDeviceIndex == m_ulDevice && dwFunctionIndex == m_ulFunction)
        {
            continue;
        }

        // Do we have a function at this bus/device/function combination?
        DWORD dwVendorDeviceIds = m_ReadConfigSpaceDword(
            ucSecondaryBusNumber, dwDeviceIndex, dwFunctionIndex, 0);

        if(dwVendorDeviceIds != 0xffffffff)
        {
            // We've found a valid PCI function. Create a new object that will 
            // represent the function. If the function is a bridge it will itself 
            // create CPciFunctions for the functions it finds on its secondary bus.
            CPciFunction * pPciFunction = new CPciFunction(m_hDriver,
                ucSecondaryBusNumber, dwDeviceIndex, dwFunctionIndex);

            // If this is the first function in a device 
            // we check if it's a multifunction device.
            if(dwFunctionIndex == 0)
            {
                bMultiFunctionDevice = (pPciFunction->GetPciHeader()->Type0Hdr.ucHeaderType & (1<<7));
            }
            else
            {
                // We ignore sub-functions if the device is not a multifunction device.
                if(dwFunctionIndex > 0 && !bMultiFunctionDevice)
                {
                    delete pPciFunction;
                    continue;
                }
            }
    
            // Store the CPciFunction object in our local vector for later use.
            m_vectSecondaryBusPciFunctions.push_back(pPciFunction);
        }       
    }
}

void CPciFunction::Dump()
{
    // Print out our most important information.
    printf("Bus/Device/Function: %d/%d/%d - Vendor/Device ID: %x/%x (type %d header)\r\n", 
        m_ulBus, m_ulDevice, m_ulFunction,
        m_TypeXHeader.Type0Hdr.usVendorID,
        m_TypeXHeader.Type0Hdr.usDeviceID,
        m_TypeXHeader.Type0Hdr.ucHeaderType);

    // Dump the info of all functions on our secondary bus.
    for(DWORD dwIndex = 0; dwIndex<m_vectSecondaryBusPciFunctions.size(); dwIndex++)
    {
        m_vectSecondaryBusPciFunctions[dwIndex]->Dump();
    }
}

CPciFunction * CPciFunction::Find(ULONG ulBus, ULONG ulDevice, ULONG ulFunction)
{
    // Are we the searched for device?
    if(ulBus == m_ulBus && ulDevice == m_ulDevice && ulFunction == m_ulFunction)
    {
        // Yes. return a pointer to ourself.
        return this;
    }

    // Recursively search all PCI functions on our secondary bus.
    // If we are not a bridge the array is empty so this does nothing.
    for(DWORD dwIndex = 0; dwIndex<m_vectSecondaryBusPciFunctions.size(); dwIndex++)
    {
        CPciFunction * pPciFunction = m_vectSecondaryBusPciFunctions[dwIndex]->Find(ulBus, ulDevice, ulFunction);
        if(pPciFunction)
        {
            return pPciFunction;
        }
    }

    // No such Bus/Device/Function combination was found.
    return NULL;
}

void CPciFunction::m_MakeConfigSpaceCopy()
{
    memcpy(&m_OriginalTypeXHeader, &m_TypeXHeader, sizeof(TYPEX_HEADER));
}

void CPciFunction::m_WriteIfChanged(DWORD dwHeaderOffset, UCHAR ucFieldSize)
{
    if(memcmp(((char*)&m_TypeXHeader) + dwHeaderOffset, ((char*)&m_OriginalTypeXHeader) + dwHeaderOffset, ucFieldSize) == 0)
    {
        // The original field has not been touched so 
        // we don't have to write it to the PCI device.
        return;
    }

    // Get the data to write from the header.
    ULONG ulData;
    switch(ucFieldSize)
    {
        case 1:
            ulData = *(((char*)&m_TypeXHeader) + dwHeaderOffset);
            break;
        case 2:
            ulData = *(PWORD) (((char*)&m_TypeXHeader) + dwHeaderOffset);
            break;
        case 4:
            ulData = *(PDWORD) (((char*)&m_TypeXHeader) + dwHeaderOffset);
            break;
    }

    // Write the changed field to the PCI device.
    BOOL bSuccess = m_WriteConfigSpaceXxx(m_ulBus, m_ulDevice, m_ulFunction, dwHeaderOffset, ucFieldSize, ulData);
    _ASSERTE(bSuccess);

    // We now need to read back the value that was just written to find out if the value "took".
    // For instance, if the written configuration space register was 'read only' we must make sure
    // that our in-memory representation is consistent with the the PCI function's config header.
    // NOTE that we are here updating both the 'original' and 'normal' copy of the config header 
    // in memory.
    switch(ucFieldSize)
    {
        case 1:
            *(((char*)&m_TypeXHeader) + dwHeaderOffset) = 
            *(((char*)&m_OriginalTypeXHeader) + dwHeaderOffset) = (UCHAR) m_ReadConfigSpaceXxx(
                m_ulBus, m_ulDevice, m_ulFunction, dwHeaderOffset, ucFieldSize);
            break;
        case 2:
            *(PWORD) (((char*)&m_TypeXHeader) + dwHeaderOffset) = 
            *(PWORD) (((char*)&m_OriginalTypeXHeader) + dwHeaderOffset) = (WORD) m_ReadConfigSpaceXxx(
                m_ulBus, m_ulDevice, m_ulFunction, dwHeaderOffset, ucFieldSize);
            break;
        case 4:
            *(PDWORD) (((char*)&m_TypeXHeader) + dwHeaderOffset) = 
            *(PDWORD) (((char*)&m_OriginalTypeXHeader) + dwHeaderOffset) = m_ReadConfigSpaceXxx(
                m_ulBus, m_ulDevice, m_ulFunction, dwHeaderOffset, ucFieldSize);
            break;
    }
}

void CPciFunction::WriteChanges()
{
    // Find out if we are a type 0 (non-bridge) or type 1 (bridge) function.
    if(m_TypeXHeader.Type0Hdr.ucHeaderType == 0)
    {
        // Write changed type 0 header fields to the PCI function.
        m_WriteIfChanged(offsetof(TYPE0_HEADER, usVendorID), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, usDeviceID), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, usCommandRegister), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, usStatusRegister), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucRevisionID), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucProgrammingInterface), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucSubClassCode), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucClassCode), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucCacheLineSize), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucLatencyTimer), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucHeaderType), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucBIST), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulBAR0), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulBAR1), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulBAR2), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulBAR3), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulBAR4), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulBAR5), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulCardBusCisPointer), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, usSubSystemVendorID), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, usSubSystemDeviceID), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulExpansionRomBAR), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucCapabilitiesPointer), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, vucReserved1[3]), 3);
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ulReserved2), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucInterruptLine), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucInterruptPin), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucMinGnt), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE0_HEADER, ucMaxLat), sizeof(UCHAR));
    }
    else if(m_TypeXHeader.Type0Hdr.ucHeaderType == 1)
    {
        // Write changed type 1 header fields to the PCI function.
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usVendorID), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usDeviceID), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usCommandRegister), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usStatusRegister), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucRevisionID), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucProgrammingInterface), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucSubClassCode), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucClassCode), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucCacheLineSize), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucLatencyTimer), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucHeaderType), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucBIST), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ulBAR0), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ulBAR1), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucPrimaryBusNumber), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucSecondaryBusNumber), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucSubordinateBusNumber), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucSecondaryLatencyTimer), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucIoBase), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucIoLimit), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usSecondaryStatus), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usMemoryBase), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usMemoryLimit), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usPrefetchableMemoryBase), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usPrefetchableMemoryLimit), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ulPrefetchableMemoryBaseUpper32), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ulPrefetchableMemoryLimitUpper32), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usIoBaseUpper16), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usIoLimitUpper16), sizeof(USHORT));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucCapabilitiesPointer), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, vucReserved1[3]), 3);
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ulExpansionRomBAR), sizeof(ULONG));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucInterruptLine), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, ucInterruptPin), sizeof(UCHAR));
        m_WriteIfChanged(offsetof(TYPE1_HEADER, usBridgeControl), sizeof(USHORT));
    }
    else
    {
        // Write changed type 2 header fields to the PCI function.
        _ASSERTE(!"Write to type2 PCI function not implemented!");
    }

    // Write out the remaining 48 DWORDs of the configuration space 
    for(DWORD dwIndex=0; dwIndex<48; dwIndex++)
    {
        m_WriteIfChanged(offsetof(TYPE1_HEADER, vulNewCaps) + 4*dwIndex, sizeof(DWORD));
    }
}

BOOL CPciFunction::IsBridge()
{
    UCHAR ucClassCode = m_TypeXHeader.Type0Hdr.ucClassCode;
    UCHAR ucSubClassCode = m_TypeXHeader.Type0Hdr.ucSubClassCode;
    BOOL bHostOrPciBridge = (ucClassCode == 6  && (ucSubClassCode == 0 || ucSubClassCode == 4));

    return bHostOrPciBridge;
}

void CPciFunction::m_ParsePciDevicesFile()
{
    // Try to open the file.
    FILE * fp = fopen("pcidevs.txt", "rt");
    if(!fp)
    {
        // The GetVendorString function will return an empty string.
        return;
    }

    //////////////////////////////////////
    //  Read in the Vendor ID.
    //////////////////////////////////////

    // Read the file one line at the time.
    char szLine[255];
    while(fgets(szLine, 255, fp))
    {
        // Ignore this lines if it does not start with 'V'.
        if(szLine[0] != 'V')
        {
            continue;
        }
        
        // Try to parse out the vendor ID and the vendor ID string from this line.
        DWORD wVendorID = 0xFFFF;
        char szVendorID[512] = {0};
        int iFieldsRead = sscanf(szLine, "V\t%04X\t%[^\r\n]s", &wVendorID, szVendorID);
        if(iFieldsRead < 2)
        {
            // Less than two fields could be converted.
            continue;
        }

        // Does this line contain our vendor ID?
        if(wVendorID == m_TypeXHeader.Type0Hdr.usVendorID)
        {
            // Yes. Save the vendor ID string.
            m_strVendorId = szVendorID;

            // Continue reading in the device ID below.
            break;
        }
    }   

    //////////////////////////////////////
    //  Read in the Device ID.
    //////////////////////////////////////

    // Read the file one line at the time.
    while(fgets(szLine, 255, fp))
    {
        // Ignore this lines if it does not start with 'D'.
        if(szLine[0] != 'D')
        {
            continue;
        }
    
        // Try to parse out the Device ID and the Device ID string from this line.
        DWORD wDeviceID = 0xFFFF;
        char szDeviceID[512] = {0};
        int iFieldsRead = sscanf(szLine, "D\t%04X\t%[^\r\n]s", &wDeviceID, szDeviceID);
        if(iFieldsRead < 2)
        {
            // Less than two fields could be converted.
            continue;
        }

        // Does this line contain our Device ID?
        if(wDeviceID == m_TypeXHeader.Type0Hdr.usDeviceID)
        {
            // Yes. Save the device ID string.
            m_strDeviceId = szDeviceID;

            // We are done.
            break;
        }
    }   

    //////////////////////////////////////
    //  Read in the SubSystem Vendor ID.
    //////////////////////////////////////

    // Rewind the file.
    if(fseek(fp, SEEK_SET, 0) != 0)
        return;

    // Read the file one line at the time.
    while(fgets(szLine, 255, fp))
    {
        // Ignore this lines if it does not start with 'V'.
        if(szLine[0] != 'V')
        {
            continue;
        }
    
        // Try to parse out the vendor ID and the vendor ID string from this line.
        DWORD wVendorID = 0xFFFF;
        char szVendorID[512] = {0};
        int iFieldsRead = sscanf(szLine, "V\t%04X\t%[^\r\n]s", &wVendorID, szVendorID);
        if(iFieldsRead < 2)
        {
            // Less than two fields could be converted.
            continue;
        }

        // Does this line contain our vendor ID?
        if(wVendorID == m_TypeXHeader.Type0Hdr.usSubSystemVendorID)
        {
            // Yes. Save the vendor ID string.
            m_strSubSystemVendorId = szVendorID;

            // Continue reading in the device ID below.
            break;
        }
    }   

    // Close the file.
    fclose(fp);

}

DWORD CPciFunction::m_BarFromBarIndex(DWORD dwBarIndex)
{
    // Get the BAR register from the configuration header based on the BAR index.
    PDWORD pvBARs = (PDWORD) (((char*)&m_TypeXHeader) + offsetof(TYPE0_HEADER, ulBAR0));
    DWORD dwBAR = 0;

    switch(m_TypeXHeader.Type0Hdr.ucHeaderType & 0x7f)
    {
        case 0:
            // Max 6 BAR registers for Type 0 headers.
            if(dwBarIndex > 5)
            {
                return 0;
            }

            // Get the BAR.
            dwBAR = pvBARs[dwBarIndex];
            break;

        case 1:
            // Max 2 BAR registers for Type 1 headers.
            if(dwBarIndex > 1)
            {
                return 0;
            }

            // Get the BAR.
            dwBAR = pvBARs[dwBarIndex];
            break;

        default:
            // NO BAR registers for Type 2 or unknown headers.
            return 0;
    }

    return dwBAR;
}

int CPciFunction::m_BarIndexFromBarValue(DWORD dwBarValue)
{
    // Get the BAR register from the configuration header.
    PDWORD pvBARs = (PDWORD) (((char*)&m_TypeXHeader) + offsetof(TYPE0_HEADER, ulBAR0));

    // Type 2 or higher configuration space headers do not have BARs.
    UCHAR ucHeaderType = m_TypeXHeader.Type0Hdr.ucHeaderType & 0x7f;
    if(ucHeaderType > 1)
    {
        return -1;
    }

    // Get the number of BAR registers to search.
    // Max 6 BAR registers for Type 0 headers.
    // Max 2 BAR registers for Type 1 headers.
    DWORD dwNumBars = ucHeaderType == 0 ? 6 : 2;

    // Get the index of the BAR with the specified value.
    for(DWORD dwBarIndex=0; dwBarIndex<dwNumBars; dwBarIndex++)
    {
        // Is this an I/O BAR?
        BOOL bIoBar = pvBARs[dwBarIndex] & 1;

        // Mask out the control bits in the BAR since the BAR 
        // value passed in does not contain any control bits.
        DWORD dwMaskedBar = bIoBar ? pvBARs[dwBarIndex] & ~3 : pvBARs[dwBarIndex] & ~0xf;

        if(dwMaskedBar == dwBarValue)
        {
            return dwBarIndex;
        }
    }

    // We did not find a BAR with the specified value.
    return -1;
}

BOOL CPciFunction::ReadDeviceData(DWORD dwBarIndex, DWORD dwOffset, PVOID pBuffer, DWORD dwItemSize, DWORD dwItemCount)
{
    // Get the BAR register from the configuration header based on the BAR index.
    DWORD dwBAR = m_BarFromBarIndex(dwBarIndex);

    // Get the base address of the BAR.
    BOOL bMemorySpace = !(dwBAR & (1<<0));
    DWORD dwBaseAddress = bMemorySpace ? dwBAR & 0xfffffff0 : dwBAR & 0xfffffffc;

    // Prepare the parameters for the IOCTL call.
    READ_DEVICE_DATA_INPARAMS InParams;
    InParams.ucMemorySpace = bMemorySpace;
    InParams.ulPhysicalAddress = dwBaseAddress + dwOffset;
    InParams.ulItemSize = dwItemSize;
    InParams.ulItemCount = dwItemCount;

    // Read the data from the device.
    DWORD dwBytesToRead = dwItemSize * dwItemCount;
    DWORD dwBytesRead;
    BOOL bSuccess = DeviceIoControl(
                m_hDriver,
                IOCTL_READ_DEVICE_DATA,
                &InParams,
                sizeof(READ_DEVICE_DATA_INPARAMS),
                pBuffer,
                dwBytesToRead,
                &dwBytesRead,
                NULL);
    _ASSERTE(bSuccess);
    _ASSERTE(dwBytesRead == dwBytesToRead);

    return bSuccess && dwBytesRead == dwBytesToRead;
}

BOOL CPciFunction::WriteDeviceData(DWORD dwBarIndex, DWORD dwOffset, PVOID pBuffer, DWORD dwItemSize, DWORD dwItemCount)
{
    OutputDebugString("CPciFunction::WriteDeviceData\r\n");

    // Get the BAR register from the configuration header based on the BAR index.
    DWORD dwBAR = m_BarFromBarIndex(dwBarIndex);

    // Get the base address of the BAR.
    BOOL bMemorySpace = !(dwBAR & (1<<0));
    DWORD dwBaseAddress = bMemorySpace ? dwBAR & 0xfffffff0 : dwBAR & 0xfffffffc;

    // Prepare a buffer large enough to hold both the WRITE_DEVICE_DATA_INPARAMS 
    // structure and the data that is to be written to the device.
    DWORD dwBytesToWrite = dwItemSize * dwItemCount;
    DWORD dwTotalParamBytes = sizeof(WRITE_DEVICE_DATA_INPARAMS) + dwBytesToWrite;
    PWRITE_DEVICE_DATA_INPARAMS pInParams = (PWRITE_DEVICE_DATA_INPARAMS) new char[dwTotalParamBytes];
    _ASSERTE(pInParams);
    if(!pInParams)
    {
        return FALSE;
    }

    // Prepare the parameters for the IOCTL call.
    pInParams->ucMemorySpace = bMemorySpace;
    pInParams->ulPhysicalAddress = dwBaseAddress + dwOffset;
    pInParams->ulItemSize = dwItemSize;
    pInParams->ulItemCount = dwItemCount;
    memcpy(&pInParams->data, pBuffer, dwBytesToWrite);

    // Write the data to the device.
    DWORD dwDummy;
    BOOL bSuccess = DeviceIoControl(
                m_hDriver,
                IOCTL_WRITE_DEVICE_DATA,
                pInParams,
                dwTotalParamBytes,
                NULL,
                0,
                &dwDummy,
                NULL);
    _ASSERTE(bSuccess);

    // We are done with the temporary in-parameter buffer.
    delete [] pInParams;

    return bSuccess;
}

HKEY m_GetRegistryDeviceNodeKey(
    HKEY hKey, 
    UCHAR ucBusSearched, 
    UCHAR ucDeviceSearched, 
    UCHAR ucFunctionSearched)
{
    ///////////////////////////////////////////////////////////////////////////////////
    // This function searches for a subkey which contains the 'LocationInformation' 
    // value which has a content that matches our searched for bus/device/function. 
    // Example value: "PCI bus 1, device 0, function 0".
    ///////////////////////////////////////////////////////////////////////////////////

    // Search all subkeys.
    DWORD dwIndex = 0;
    LONG lResult = ERROR_SUCCESS;
    while(lResult != ERROR_NO_MORE_ITEMS)
    {
        // Get the name of the next subkey under our key.
        char szSubKeyName[255];
        DWORD dwBufLen = sizeof(szSubKeyName);
        FILETIME ftDummy;
        lResult = RegEnumKeyEx(
            hKey,                   // handle to key to enumerate
            dwIndex++,              // subkey index
            szSubKeyName,           // subkey name
            &dwBufLen,              // size of subkey buffer
            NULL,                   // reserved
            NULL,                   // class string buffer
            NULL,                   // size of class string buffer
            &ftDummy);              // last write time
        
        if(lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA)
        {
            // Open this subkey.
            HKEY hkSubKey;
            lResult = RegOpenKeyEx(
                hKey,                                       // handle to open key
                szSubKeyName,                               // subkey name
                0,                                          // reserved
                KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,   // security access mask
                &hkSubKey);                                 // handle to open key
            _ASSERTE(lResult == ERROR_SUCCESS);

            // Does this subkey contain a 'LocationInformation' value?
            UCHAR szLocationInformation[255];
            DWORD dwBufSize = sizeof(szLocationInformation);
            LONG lResult = RegQueryValueEx(
                hkSubKey,                       // handle to key
                "LocationInformation",          // value name
                NULL,                           // reserved
                NULL,                           // type buffer
                szLocationInformation,          // data buffer
                &dwBufSize);                    // size of data buffer
            
            if(lResult == ERROR_SUCCESS)
            {
                // We found a LocationInformation value.
                // Does the content match our device?
                DWORD dwBusFound;
                DWORD dwDeviceFound;
                DWORD dwFunctionFound;

                if(sscanf(
                    (const char *) szLocationInformation, 
                    "PCI bus %d, device %d, function %d", 
                    &dwBusFound,
                    &dwDeviceFound,
                    &dwFunctionFound) == 3)
                {
                    if(dwBusFound == ucBusSearched && 
                    dwDeviceFound == ucDeviceSearched && 
                    dwFunctionFound == ucFunctionSearched)
                    {
                        // We have found the Registry Device Node of our device.
                        return hkSubKey;
                    }
                }
            }

            // We did not find our device node key. Close 
            // the subkey handle before trying the next one.
            RegCloseKey(hkSubKey);
        }
    }

    // We did not find our device node key.
    return NULL;
}

void CPciFunction::m_GetBarSizesFromRegistry()
{
    // Initialize the default BAR sizes to 0.
    memset(m_vdwBarSizes, 0, sizeof(m_vdwBarSizes));

    // Build the 'Vendor\Device\SubSys\Revision' key string. Example string:
    // "SYSTEM\CurrentControlSet\Enum\PCI\VEN_102B&DEV_0525&SUBSYS_0338102B&REV_04"
    char szVendorDeviceSubSysRecKey[512];
    sprintf(szVendorDeviceSubSysRecKey,
        "SYSTEM\\CurrentControlSet\\Enum\\PCI\\VEN_%04X&DEV_%04X&SUBSYS_%04X%04X&REV_%02X",
        m_TypeXHeader.Type0Hdr.usVendorID,
        m_TypeXHeader.Type0Hdr.usDeviceID,
        m_TypeXHeader.Type0Hdr.usSubSystemDeviceID,
        m_TypeXHeader.Type0Hdr.usSubSystemVendorID,
        m_TypeXHeader.Type0Hdr.ucRevisionID);

    // Open the 'Vendor\Device\SubSys\Revision' key.
    // Our device instance key is one of the subkeys.
    HKEY hKey;
    LONG lResult = RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,                         // handle to open key
        szVendorDeviceSubSysRecKey,                 // subkey name
        0,                                          // reserved
        KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,   // security access mask
        &hKey);                                     // handle to open key

    // If we don't find a matching 'Vendor\Device\SubSys\Revision'
    // key we have not been assigned any resources.
    if(lResult != ERROR_SUCCESS)
    {
        return;
    }

    // Search for our device node key in the registry. Example key name: 
    // "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\PCI\VEN_102B&DEV_0525&SUBSYS_0338102B&REV_04\4&15c4952b&0&0008"
    HKEY hkDeviceNode = m_GetRegistryDeviceNodeKey(
        hKey, m_ulBus,  m_ulDevice, m_ulFunction);

    // NOTE: If this is a single-function device that responds to 
    // PCI transactions to sub-functions we will not be able to 
    // find any device node in the registry (the PCI enumerator 
    // only stores subfunctions in multi-function devices).
    if(!hkDeviceNode)
    {
        return;
    }

    // Open the subkey named 'Control'.
    HKEY hkSubKey;
    lResult = RegOpenKeyEx(
        hkDeviceNode,                               // handle to open key
        "Control",                                  // subkey name
        0,                                          // reserved
        KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,   // security access mask
        &hkSubKey);                                 // handle to open key

    // Devices without resources does not have any 'Control' key.
    if(lResult != ERROR_SUCCESS)
    {
        return;
    }

    // Read in the 'AllocConfig' value from the 'Control' subkey.
    // First query the needed length of the output buffer.
    DWORD dwNeededBufSize;
    lResult = RegQueryValueEx(
        hkSubKey,                       // handle to key
        "AllocConfig",                  // value name
        NULL,                           // reserved
        NULL,                           // type buffer
        NULL,                           // data buffer
        &dwNeededBufSize);              // size of data buffer

    // We should always find an 'AllocConfig' value.
    // If not, we cannot continue so we give up.
//  _ASSERTE(lResult == ERROR_SUCCESS);
    if(lResult != ERROR_SUCCESS)
    {
        return;
    }

    // Allocate a buffer large enough to hold the data in the 'AllocConfig' value.
    PCM_RESOURCE_LIST pResourceList = (PCM_RESOURCE_LIST) new char[dwNeededBufSize];

    // Read in the 'AllocConfig' value.
    lResult = RegQueryValueEx(
        hkSubKey,                       // handle to key
        "AllocConfig",                  // value name
        NULL,                           // reserved
        NULL,                           // type buffer
        (LPBYTE) pResourceList,         // data buffer
        &dwNeededBufSize);              // size of data buffer

    // This call should always succeed.
    // If not, we cannot continue so we give up.
//  _ASSERTE(lResult == ERROR_SUCCESS);
    if(lResult != ERROR_SUCCESS)
    {
        return;
    }

    // Iterate through all resources assigned to this device and make notes of the 
    // resource lengths (i.e. the BAR lengths). 
    for(DWORD dwIndex=0; dwIndex<pResourceList->List->PartialResourceList.Count; dwIndex++)
    {
        // Get the resource descriptor for this resource.
        PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialResourceDescriptor = 
            &pResourceList->List->PartialResourceList.PartialDescriptors[dwIndex];

        // Note: We ignore interrupt and DMA resources since these are 
        // not related to PCI Configuration Space BAR registers.
        if( pPartialResourceDescriptor->Type != CmResourceTypePort && 
            pPartialResourceDescriptor->Type != CmResourceTypeMemory)
        {
            continue;
        }

        // NOTE: The resources we enumerate are not in any particular order.
        // The only way we can map them to the BAR resources is to compare
        // the addresses of the resources with the addresses of our BARs.
        // BugBug: We can only handle 32-bit BARs here! Fix later if needed!
        int iBarIndex = m_BarIndexFromBarValue(pPartialResourceDescriptor->u.Generic.Start.LowPart);
        if(iBarIndex == -1)
        {
            // This resource is not one of our BARs.
            continue;
        }

        // Record the BAR size of this resource.
        _ASSERTE(iBarIndex >=0 && iBarIndex <6);
        m_vdwBarSizes[iBarIndex] = pPartialResourceDescriptor->u.Generic.Length;
    }

    // We are done with the Resource List.   
    delete [] pResourceList;
} 

DWORD CPciFunction::GetBarSizeFromPciDevice(DWORD dwBarIndex)
{
    // Find out how many BARs this PCI function may have.
    DWORD dwMaxBars;
    switch(m_TypeXHeader.Type0Hdr.ucHeaderType & 0x7f)
    {
        case 0:
            dwMaxBars = 6;
            break;
        case 1:
            dwMaxBars = 2;
            break;
        default:
            dwMaxBars = 0;
    }

    // Parameter validation.
    if(dwBarIndex > dwMaxBars)
    {
        return 0;
    }

    ////////////////////////////////////////////////////
    // Read the assigned BAR address from the device.
    // We do this to be able to restore the value once
    // we have determined the BAR size.
    ////////////////////////////////////////////////////

    ULONG ulOffset = offsetof(TYPE0_HEADER, ulBAR0) + dwBarIndex * sizeof(ULONG);
    READ_CONFIG_SPACE_XXX_INPARAMS ReadInParams;
    ReadInParams.ulBus = m_ulBus;
    ReadInParams.ulDevice = m_ulDevice;
    ReadInParams.ulFunction = m_ulFunction;
    ReadInParams.ulByteOffset = ulOffset;
    ReadInParams.ucSize = sizeof(ULONG);

    READ_CONFIG_SPACE_XXX_OUTPARAMS ReadOutParams;
    DWORD dwBytesRead;
    BOOL bSuccess = DeviceIoControl(
        m_hDriver,
        IOCTL_READ_CONFIG_SPACE_XXX,
        &ReadInParams,
        sizeof(ReadInParams),
        &ReadOutParams,
        sizeof(ReadOutParams),
        &dwBytesRead,
        NULL);

    _ASSERTE(bSuccess);
    if(!bSuccess)
    {
        return 0;
    }

    ULONG ulOriginalBarAddress = ReadOutParams.ulData;

    ////////////////////////////////////////////////////
    // Write 0xFFFFFFFF to the BAR.
    ////////////////////////////////////////////////////

    WRITE_CONFIG_SPACE_XXX_INPARAMS WriteInParams = {
            m_ulBus, 
            m_ulDevice, 
            m_ulFunction,
            ulOffset,
            sizeof(ULONG),
            0xFFFFFFFF
    };

    bSuccess =  DeviceIoControl(
        m_hDriver,
        IOCTL_WRITE_CONFIG_SPACE_XXX,
        &WriteInParams,
        sizeof(WriteInParams),
        NULL,
        0,
        &dwBytesRead,
        NULL);

    _ASSERTE(bSuccess);
    if(!bSuccess)
    {
        return 0;
    }

    ////////////////////////////////////////////////////
    // Read the BAR.
    // This will reveal the BAR size.
    ////////////////////////////////////////////////////

    bSuccess = DeviceIoControl(
        m_hDriver,
        IOCTL_READ_CONFIG_SPACE_XXX,
        &ReadInParams,
        sizeof(ReadInParams),
        &ReadOutParams,
        sizeof(ReadOutParams),
        &dwBytesRead,
        NULL);

    _ASSERTE(bSuccess);
    if(!bSuccess)
    {
        return 0;
    }

    ULONG ulResultingBarValue = ReadOutParams.ulData;

    ////////////////////////////////////////////////////
    // Write back the originally assigned BAR address.
    ////////////////////////////////////////////////////
    
    WriteInParams.ulData = ulOriginalBarAddress;

    bSuccess =  DeviceIoControl(
            m_hDriver,
            IOCTL_WRITE_CONFIG_SPACE_XXX,
            &WriteInParams,
            sizeof(WriteInParams),
            NULL,
            0,
            &dwBytesRead,
            NULL);

        _ASSERTE(bSuccess);
        if(!bSuccess)
        {
            return 0;
        }

    ////////////////////////////////////////////////////
    // Finally calculate the BAR size.
    ////////////////////////////////////////////////////

    ULONG ulBarSize;
    
    if(ulResultingBarValue & 0x01)
    {
        // I/O BAR.
        ulBarSize = ~(ulResultingBarValue & ~3) + 1;
        ulBarSize &= 0x0000FFFF;    // MAX 64K I/O space on x86.
    }
    else
    {
        // Memory BAR.
        ulBarSize = ~(ulResultingBarValue & ~0xf) + 1;
    }

    m_vdwBarSizes[dwBarIndex] = ulBarSize;

    return ulBarSize;
}

B:

/**********************************************************************
;       Copyright 2005 Summit Soft Consulting
;
;                       RESTRICTED RIGHTS LEGEND
;                       ------------------------
;
; Use, duplication, or disclosure by any commercial industry (public
; or private), private individual, or by any Government Agency without
; a express written consent of release from Summit Soft Consulting
; is subject to restrictions as set forth in paragraph (b) (3) (B) of
; the Rights in Technical Data and Computer Software clause in
; DAR 7-104.9 (a).  Manufacturer is: Summit Soft Consulting,
; 26895 Aliso Creek Rd. Suite B504, Aliso Viejo, CA 92656,
; http://www.SummitSoftConsulting.com
;**********************************************************************/

#include "stdafx.h"
#include "PciExplorer.h"

#include "PciExplorerDoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

IMPLEMENT_DYNCREATE(CPciExplorerDoc, CDocument)

BEGIN_MESSAGE_MAP(CPciExplorerDoc, CDocument)
END_MESSAGE_MAP()

CPciExplorerDoc::CPciExplorerDoc()
{
    // Open handle to driver.
    m_hDriver = CreateFile(
        _T("\\\\.\\pciexdrvDevice"),
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0,
        0
        );
    _ASSERTE(m_hDriver != INVALID_HANDLE_VALUE);

    if(m_hDriver == INVALID_HANDLE_VALUE)
    {
        MessageBox(NULL, 
            "Failed to open the kernel-mode driver 'pciexdrv.sys'!\r\n\r\n"
            "Please make sure the driver is installed and started\r\n"
            "before restarting PCI Explorer.", 
            "PCI Explorer - Fatal Error!", MB_IConerror | MB_IConstop | MB_OK);
    }

    m_pHostToPciBridge = NULL;
}

CPciExplorerDoc::~CPciExplorerDoc()
{
}

BOOL CPciExplorerDoc::OnNewDocument()
{
    if (!CDocument::OnNewDocument())
        return FALSE;

    return TRUE;
}

void CPciExplorerDoc::Serialize(CArchive& ar)
{
    if (ar.IsStoring())
    {
        // TODO: add storing code here
    }
    else
    {
        // TODO: add loading code here
    }
}


#ifdef _DEBUG
void CPciExplorerDoc::AssertValid() const
{
    CDocument::AssertValid();
}

void CPciExplorerDoc::Dump(CDumpContext& dc) const
{
    CDocument::Dump(dc);
}
#endif //_DEBUG

void CPciExplorerDoc::ScanPciBus()
{
    if(m_hDriver == INVALID_HANDLE_VALUE)
    {
        return;
    }

    // Delete the old Host/PCI bridge if any exist.
    delete m_pHostToPciBridge;

    // Create a new Host/PCI bridge object and scan the PCI bus.
    m_pHostToPciBridge = new CPciFunction(m_hDriver);

    // Update the views with the new information.
    UpdateAllViews(NULL, UPDATE_ALL_PCI_FUNCTIONS, (CObject*) m_pHostToPciBridge);
}

C:

/**********************************************************************
;       Copyright 2005 Summit Soft Consulting
;
;                       RESTRICTED RIGHTS LEGEND
;                       ------------------------
;
; Use, duplication, or disclosure by any commercial industry (public
; or private), private individual, or by any Government Agency without
; a express written consent of release from Summit Soft Consulting
; is subject to restrictions as set forth in paragraph (b) (3) (B) of
; the Rights in Technical Data and Computer Software clause in
; DAR 7-104.9 (a).  Manufacturer is: Summit Soft Consulting,
; 26895 Aliso Creek Rd. Suite B504, Aliso Viejo, CA 92656,
; http://www.SummitSoftConsulting.com
;**********************************************************************/

#ifndef __INTRFACE_H__
#define __INTRFACE_H__

////////////////////////////////////////////////////////////
//  Structures common between the driver and application.
///////////////////////////////////////////////////////////

#pragma pack( push , 1 )

typedef struct _TYPE0_HEADER
{
    USHORT usVendorID;
    USHORT usDeviceID;
    USHORT usCommandRegister;
    USHORT usStatusRegister;
    UCHAR ucRevisionID;
    UCHAR ucProgrammingInterface;
    UCHAR ucSubClassCode;
    UCHAR ucClassCode;
    UCHAR ucCacheLineSize;
    UCHAR ucLatencyTimer;
    UCHAR ucHeaderType;
    UCHAR ucBIST;
    ULONG ulBAR0;
    ULONG ulBAR1;
    ULONG ulBAR2;
    ULONG ulBAR3;
    ULONG ulBAR4;
    ULONG ulBAR5;
    ULONG ulCardBusCisPointer;
    USHORT usSubSystemVendorID;
    USHORT usSubSystemDeviceID;
    ULONG ulExpansionRomBAR;
    UCHAR ucCapabilitiesPointer;
    UCHAR vucReserved1[3];
    ULONG ulReserved2;
    UCHAR ucInterruptLine;
    UCHAR ucInterruptPin;
    UCHAR ucMinGnt;
    UCHAR ucMaxLat;

    ULONG vulNewCaps[48];

}TYPE0_HEADER, *PTYPE0_HEADER;

typedef struct _TYPE1_HEADER
{
    USHORT usVendorID;
    USHORT usDeviceID;
    USHORT usCommandRegister;
    USHORT usStatusRegister;
    UCHAR ucRevisionID;
    UCHAR ucProgrammingInterface;
    UCHAR ucSubClassCode;
    UCHAR ucClassCode;
    UCHAR ucCacheLineSize;
    UCHAR ucLatencyTimer;
    UCHAR ucHeaderType;
    UCHAR ucBIST;
    ULONG ulBAR0;
    ULONG ulBAR1;
    UCHAR ucPrimaryBusNumber;
    UCHAR ucSecondaryBusNumber;
    UCHAR ucSubordinateBusNumber;
    UCHAR ucSecondaryLatencyTimer;
    UCHAR ucIoBase;
    UCHAR ucIoLimit;
    USHORT usSecondaryStatus;
    USHORT usMemoryBase;
    USHORT usMemoryLimit;
    USHORT usPrefetchableMemoryBase;
    USHORT usPrefetchableMemoryLimit;
    ULONG ulPrefetchableMemoryBaseUpper32;
    ULONG ulPrefetchableMemoryLimitUpper32;
    USHORT usIoBaseUpper16;
    USHORT usIoLimitUpper16;
    UCHAR ucCapabilitiesPointer;
    UCHAR vucReserved1[3];
    ULONG ulExpansionRomBAR;
    UCHAR ucInterruptLine;
    UCHAR ucInterruptPin;
    USHORT usBridgeControl;

    ULONG vulNewCaps[48];

}TYPE1_HEADER, *PTYPE1_HEADER;

typedef struct _TYPE2_HEADER
{
    USHORT usVendorID;
    USHORT usDeviceID;
    USHORT usCommandRegister;
    USHORT usStatusRegister;
    UCHAR ucRevisionID;
    UCHAR ucProgrammingInterface;
    UCHAR ucSubClassCode;
    UCHAR ucClassCode;
    UCHAR ucCacheLineSize;
    UCHAR ucLatencyTimer;
    UCHAR ucHeaderType;
    UCHAR ucBIST;
    ULONG ulCardbusSocketRegisters;
    UCHAR vucReserved[2];
    USHORT usSecondaryStatus;
    UCHAR ucPciBusNumber;
    UCHAR ucCardBusBusNumber;
    UCHAR ucSubordinateBusNumber;
    UCHAR ucCardbusLatencyTimer;
    ULONG ulMemoryBaseRegister0;
    ULONG ulMemoryLimitRegister0;
    ULONG ulMemoryBaseRegister1;
    ULONG ulMemoryLimitRegister1;
    USHORT usIoBaseRegisterLower0;
    USHORT usIoBaseRegisterUpper0;
    USHORT usIoLimitRegisterLower0;
    USHORT usIoLimitRegisterUpper0;
    USHORT usIoBaseRegisterLower1;
    USHORT usIoBaseRegisterUpper1;
    USHORT usIoLimitRegisterLower1;
    USHORT usIoLimitRegisterUpper1;
    UCHAR ucInterruptLine;
    UCHAR ucInterruptPin;
    USHORT usBridgeControl;
    USHORT usSubSystemVendorID;
    USHORT usSubSystemDeviceID;
    ULONG ulLegacyModeBaseAddress;
    ULONG vulReserved[14];
    ULONG vulVendorSpecific[32];

}TYPE2_HEADER, *PTYPE2_HEADER;

typedef union _TYPEX_HEADER
{
    TYPE0_HEADER Type0Hdr;  // 'Regular' PCI device.
    TYPE1_HEADER Type1Hdr;  // Pci/Pci Bridge.
    TYPE2_HEADER Type2Hdr;  // CardBus.
    ULONG vulConfig[64];    // Unformatted.

}TYPEX_HEADER, *PTYPEX_HEADER;

#define FILE_DEVICE_PCIEXDRV  0x8000

// Define Interface reference/dereference routines for
// Interfaces exported by IRP_MN_QUERY_INTERFACE

#define PCIEXDRV_IOCTL(index) \
    CTL_CODE(FILE_DEVICE_PCIEXDRV, index, METHOD_BUFFERED, FILE_READ_DATA)

/////////////////////////////////////////////
/// IOCTL_READ_CONFIG_SPACE_DWORD
/////////////////////////////////////////////

#define IOCTL_READ_CONFIG_SPACE_DWORD \
    CTL_CODE(FILE_DEVICE_PCIEXDRV, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)

// In-parameters.
typedef struct _READ_CONFIG_SPACE_DWORD_INPARAMS
{
    ULONG ulBus;
    ULONG ulDevice;
    ULONG ulFunction;
    ULONG ulDwordOffset;    

}READ_CONFIG_SPACE_DWORD_INPARAMS, *PREAD_CONFIG_SPACE_DWORD_INPARAMS;

// Out-parameters.
typedef struct _READ_CONFIG_SPACE_DWORD_OUTPARAMS
{
    ULONG ulData;

}READ_CONFIG_SPACE_DWORD_OUTPARAMS, *PREAD_CONFIG_SPACE_DWORD_OUTPARAMS;

/////////////////////////////////////////////
/// IOCTL_WRITE_CONFIG_SPACE_XXX
/////////////////////////////////////////////

#define IOCTL_WRITE_CONFIG_SPACE_XXX \
    CTL_CODE(FILE_DEVICE_PCIEXDRV, 0x801, METHOD_BUFFERED, FILE_WRITE_ACCESS)

// In-parameters.
typedef struct _WRITE_CONFIG_SPACE_XXX_INPARAMS
{
    ULONG ulBus;
    ULONG ulDevice;
    ULONG ulFunction;
    ULONG ulByteOffset;
    UCHAR ucSize;
    ULONG ulData;

}WRITE_CONFIG_SPACE_XXX_INPARAMS, *PWRITE_CONFIG_SPACE_XXX_INPARAMS;

// No out-parameters.

/////////////////////////////////////////////
/// IOCTL_READ_CONFIG_SPACE_HEADER
/////////////////////////////////////////////

#define IOCTL_READ_CONFIG_SPACE_HEADER \
    CTL_CODE(FILE_DEVICE_PCIEXDRV, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)

// In-parameters.
typedef struct _READ_CONFIG_SPACE_HEADER_INPARAMS
{
    ULONG ulBus;
    ULONG ulDevice;
    ULONG ulFunction;

}READ_CONFIG_SPACE_HEADER_INPARAMS, *PREAD_CONFIG_SPACE_HEADER_INPARAMS;

// Out-parameters.
typedef struct _READ_CONFIG_SPACE_HEADER_OUTPARAMS
{
    TYPEX_HEADER Hdr;

}READ_CONFIG_SPACE_HEADER_OUTPARAMS, *PREAD_CONFIG_SPACE_HEADER_OUTPARAMS;

/////////////////////////////////////////////
/// IOCTL_READ_CONFIG_SPACE_XXX
/////////////////////////////////////////////

#define IOCTL_READ_CONFIG_SPACE_XXX \
    CTL_CODE(FILE_DEVICE_PCIEXDRV, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)

// In-parameters.
typedef struct _READ_CONFIG_SPACE_XXX_INPARAMS
{
    ULONG ulBus;
    ULONG ulDevice;
    ULONG ulFunction;
    ULONG ulByteOffset; 
    UCHAR ucSize;

}READ_CONFIG_SPACE_XXX_INPARAMS, *PREAD_CONFIG_SPACE_XXX_INPARAMS;

// Out-parameters.
typedef struct _READ_CONFIG_SPACE_XXX_OUTPARAMS
{
    ULONG ulData;

}READ_CONFIG_SPACE_XXX_OUTPARAMS, *PREAD_CONFIG_SPACE_XXX_OUTPARAMS;

/////////////////////////////////////////////
/// IOCTL_READ_DEVICE_DATA
/////////////////////////////////////////////

#define IOCTL_READ_DEVICE_DATA \
    CTL_CODE(FILE_DEVICE_PCIEXDRV, 0x804, METHOD_BUFFERED, FILE_READ_ACCESS)

// In-parameters.
typedef struct _READ_DEVICE_DATA_INPARAMS
{
    UCHAR ucMemorySpace;        // 0: I/O Space, 1: Mem Space.
    ULONG ulPhysicalAddress;    // Dword-aligned offset to read from.
    ULONG ulItemSize;           // 1: Byte, 2: Word, 4: Dword.
    ULONG ulItemCount;          // Number of bytes, words or dwords.

}READ_DEVICE_DATA_INPARAMS, *PREAD_DEVICE_DATA_INPARAMS;

// Out-parameters.
typedef struct _READ_DEVICE_DATA_OUTPARAMS
{
    union{
        UCHAR vucDataBuf[1];
        USHORT vusDataBuf[1];
        ULONG vulDataBuf[1];
    }data;

}READ_DEVICE_DATA_OUTPARAMS, *PREAD_DEVICE_DATA_OUTPARAMS;

/////////////////////////////////////////////
/// IOCTL_WRITE_DEVICE_DATA
/////////////////////////////////////////////

#define IOCTL_WRITE_DEVICE_DATA \
    CTL_CODE(FILE_DEVICE_PCIEXDRV, 0x805, METHOD_BUFFERED, FILE_WRITE_ACCESS)

// In-parameters.
typedef struct _WRITE_DEVICE_DATA_INPARAMS
{
    UCHAR ucMemorySpace;        // 0: I/O Space, 1: Mem Space.
    ULONG ulPhysicalAddress;    // Dword-aligned offset to write to.
    ULONG ulItemSize;           // 1: Byte, 2: Word, 4: Dword.
    ULONG ulItemCount;          // Number of bytes, words or dwords.

    union{
        UCHAR vucDataBuf[1];
        USHORT vusDataBuf[1];
        ULONG vulDataBuf[1];
    }data;

}WRITE_DEVICE_DATA_INPARAMS, *PWRITE_DEVICE_DATA_INPARAMS;

// Out-parameters.
// None.

#pragma pack( pop )

#endif // __INTRFACE_H__
Edited by ernesthan
Link to comment
Share on other sites

Some of your posts are just bumps begging for immediate help and an immediate solution. Calm down.

You need to explain what you are doing. Do you even have code that you attempted to write yourself? I just did a google search on autoit forums and there are examples if you understand basic programming language.

Edited by targeter
Link to comment
Share on other sites

I don't understand basic programming language

Then you can't do it.

This forum is here to support people who are learning/using AutoIt. We don't write scripts on request, we just help you learn to write your own. If you don't know the language, and can't/won't learn it, there's no hope for you.

See the Rent-A-Coder link in my sig, and pay someone to do it.

;)

Edited by PsaltyDS
Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...