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

📄 pcisupport.c

📁 本压缩包为作者截取的PCI9054的WDM官方驱动源码。欢迎下载。
💻 C
📖 第 1 页 / 共 2 页
字号:
{
    U32   function;
    U32   RegSave;
    U32   RegValue;
    KIRQL IrqlSave;


    /***************************************************************
     * Access of a PCI register involves using I/O addresses 0xcf8
     * and 0xcfc. These addresses must be used together and no other
     * process must interrupt.
     *
     * Note:  On Multi-Processor systems, the I/O ports may still be
     *        accessed by another CPU.  Raising the IRQL does not
     *        prevent other CPUs from accessing the ports since
     *        they are not a resource owned by this driver.
     **************************************************************/

    // The function number is specified in the upper 3-bits of the slot
    function = (slot >> 5) & 0x7;

    // Make sure upper 3-bits are cleared
    slot &= 0x1F;

    // Raise the IRQL to prevent context switches during access
    KeRaiseIrql(
        DISPATCH_LEVEL,
        &IrqlSave
        );

    // Save the content of the command register
    RegSave =
        IO_PORT_READ_32(
            0xcf8
            );

    // Configure the command register to access the desired location
    IO_PORT_WRITE_32(
        0xcf8,
        (1 << 31) | (bus << 16) | (slot << 11) | (function << 8) | offset
        );

    // Read the register
    RegValue =
        IO_PORT_READ_32(
            0xcfc
            );

    // Restore the command register
    IO_PORT_WRITE_32(
        0xcf8,
        RegSave
        );

    // Restore IRQL
    KeLowerIrql(
        IrqlSave
        );

    if (pReturnCode != NULL)
        *pReturnCode = ApiSuccess;

    return RegValue;
}




/******************************************************************************
 *
 * Function   :  PlxPciRegisterWrite_Unsupported
 *
 * Description:  Writes to a PCI register by bypassing the OS services
 *
 ******************************************************************************/
RETURN_CODE
PlxPciRegisterWrite_Unsupported(
    DEVICE_EXTENSION *pdx,
    U8                bus,
    U8                slot,
    U16               offset,
    U32               value
    )
{
    U8    function;
    U32   RegSave;
    KIRQL IrqlSave;


    /***************************************************************
     * Access of a PCI register involves using I/O addresses 0xcf8
     * and 0xcfc. These addresses must be used together and no other
     * process must interrupt.
     *
     * Note:  On Multi-Processor systems, the I/O ports may still be
     *        accessed by another CPU.  Raising the IRQL does not
     *        prevent other CPUs from accessing the ports since
     *        they are not a resource owned by this driver.
     **************************************************************/

    // The function number is specified in the upper 3-bits of the slot
    function = (slot >> 5) & 0x7;

    // Make sure upper 3-bits are cleared
    slot &= 0x1F;

    // Raise the IRQL to prevent context switches during access
    KeRaiseIrql(
        DISPATCH_LEVEL,
        &IrqlSave
        );

    // Save the content of the command register
    RegSave =
        IO_PORT_READ_32(
            0xcf8
            );

    // Configure the command register to access the desired location
    IO_PORT_WRITE_32(
        0xcf8,
        (1 << 31) | (bus << 16) | (slot << 11) | (function << 8) | offset
        );

    // Write the register
    IO_PORT_WRITE_32(
        0xcfc,
        value
        );

    // Restore the command register
    IO_PORT_WRITE_32(
        0xcf8,
        RegSave
        );

    // Restore IRQL
    KeLowerIrql(
        IrqlSave
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  GetBusSlotNumber
 *
 * Description:  Get the bus and slot number of a supported device.
 *               This function does not work for the slot number.
 *
 ******************************************************************************/
NTSTATUS
GetBusSlotNumber(
    PDEVICE_OBJECT    pdo,
    DEVICE_EXTENSION *pdx,
    U32               CompareValue
    )
{
    U8       slot;
    U32      ResultLength;
    U32      PropertyBuffer;
    U32      RegValue;
    U32      RegisterSave;
    NTSTATUS status;


    ResultLength = 0;

    // Get the bus number
    status =
        IoGetDeviceProperty(
             pdo,
             DevicePropertyBusNumber,
             sizeof(U32),
             &PropertyBuffer,
             &ResultLength
             );

    if ( !NT_SUCCESS(status) )
    {
        DebugPrintf((
            "ERROR - IoGetDeviceProperty() unable to get bus number, code = %Xh\n",
            status
            ));

        return status;
    }

    // Verify that the function did write back a U32
    if (ResultLength != sizeof(U32))
    {
        DebugPrintf((
            "ERROR - IoGetDeviceProperty() invalid ResultLength (%d)\n",
            ResultLength
            ));

        return STATUS_UNSUCCESSFUL;
    }

    // Store the Bus number
    pdx->Device.BusNumber = (U8)PropertyBuffer;


    /**************************************************************************
     * Now attempt to get the slot number
     *
     * Note: The IoGetDeviceProperty() function is not implemented correctly in
     *       Windows 98.  The code has been left here in case this is fixed in a
     *       future release.  If the IoGetDeviceProperty() function is unsuccessful,
     *       a workaround is provided to retrieve the correct slot number.
     **************************************************************************/

    ResultLength = 0;

    status =
        IoGetDeviceProperty(
            pdo,
            DevicePropertyAddress,
            sizeof(U32),
            &PropertyBuffer,
            &ResultLength
            );

    if ( NT_SUCCESS(status) )
    {
        if (ResultLength != sizeof(U32))
        {
            DebugPrintf((
                "ERROR - IoGetDeviceProperty() invalid ResultLength (%d)\n",
                ResultLength
                ));

            return STATUS_UNSUCCESSFUL;
        }

        pdx->Device.SlotNumber = (U8)(PropertyBuffer >> 16);

        DebugPrintf((
            "Device information - PCI bus %d, slot %d, function %d\n",
            pdx->Device.BusNumber,
            (U8)(PropertyBuffer >> 16),
            (U8)PropertyBuffer
            ));

        return STATUS_SUCCESS;
    }


    /****************************************************************
    * We were unable to get the slot number, so another method is
    * required.  Our workaround is to scan the PCI bus and find the
    * device whose BAR0 matches the current device.
    ****************************************************************/

    DebugPrintf(("WARNING - IoGetDeviceProperty() unable to get slot number, code = "));

    switch (status)
    {
        case STATUS_BUFFER_TOO_SMALL:
            DebugPrintf_NoInfo(("STATUS_BUFFER_TOO_SMALL (req=%d bytes)\n", ResultLength));
            break;

        case STATUS_NOT_IMPLEMENTED:
            DebugPrintf_NoInfo(("STATUS_NOT_IMPLEMENTED\n"));
            break;

        case STATUS_NOT_FOUND:
            DebugPrintf_NoInfo(("STATUS_NOT_FOUND\n"));
            break;

        default:
            DebugPrintf_NoInfo(("%08xh\n", status));
            break;
    }

    DebugPrintf(("NOTE: Implementing workaround to get Slot number\n"));

    // Scan the PCI bus to find our device
    for (slot = 0; slot < MAX_PCI_DEV; slot++)
    {
        // Read the BAR register
        RegValue =
            PlxPciRegisterRead_Unsupported(
                pdx,
                pdx->Device.BusNumber,
                slot,
                CFG_BAR0,
                NULL
                );

        // Compare with our device
        if (RegValue == CompareValue)
        {
            pdx->Device.SlotNumber = slot;

            DebugPrintf((
                "Workaround successful, device information - PCI bus %d, slot %d, function 0\n",
                pdx->Device.BusNumber,
                slot
                ));

            return STATUS_SUCCESS;
        }
    }

    DebugPrintf(("ERROR - Unable to implement workaround to get Slot number\n"));

    pdx->Device.SlotNumber = -1;

    return STATUS_UNSUCCESSFUL;
}




/******************************************************************************
 *
 * Function   :  PlxLockDevice
 *
 * Description:  Lock a device for operation, return FALSE if device is being
 *               removed.
 *
 ******************************************************************************/
BOOLEAN
PlxLockDevice(
    DEVICE_EXTENSION *pdx
    )
{
    S32 usage;


    // Increment use count on our device object
    usage =
        InterlockedIncrement(
            &pdx->usage
            );

    DebugPrintf_NoInfo(("\n"));

    /* 
       If device is about to be removed, restore the use count and return FALSE.
       If a race exists with HandleRemoveDevice (maybe running on another CPU),
       the sequence we've followed is guaranteed to avoid a mistaken deletion of
       the device object. If we test "removing" after HandleRemoveDevice sets 
       it, we'll restore the use count and return FALSE. In the meantime, if
       HandleRemoveDevice decremented count to 0 before we did our increment,
       its thread will have set the remove event. Otherwise, we'll decrement to
       0 and set the event. Either way, HandleRemoveDevice will wake up to 
       finish removing the device, and we'll return FALSE to our caller.

       If, on the other hand, we test "removing" before HandleRemoveDevice sets
       it, we'll have already incremented the use count past 1 and will return 
       TRUE. Our caller will eventually call UnlockDevice, which will decrement
       the use count and might set the event HandleRemoveDevice is waiting on at
       that point.
    */
    if (pdx->removing)
    {
        // Removing device
        if (InterlockedDecrement(&pdx->usage) == 0)
        {
            KeSetEvent(
                &pdx->evRemove,
                0,
                FALSE
                );
        }

        return FALSE;
    }

    return TRUE;
}




/******************************************************************************
 *
 * Function   :  PlxUnlockDevice
 *
 * Description:  Unlock a device
 *
 ******************************************************************************/
VOID
PlxUnlockDevice(
    DEVICE_EXTENSION *pdx
    )
{
    S32 usage;


    usage =
        InterlockedDecrement(
            &pdx->usage
            );

    if (usage == 0)
    {
        // Removing device
        KeSetEvent(
            &pdx->evRemove,
            0,
            FALSE
            );
    }
}

⌨️ 快捷键说明

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