📄 pcisupport.c
字号:
{
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 + -