📄 supportfunc.c
字号:
/*******************************************************************************
* Copyright (c) 2006 PLX Technology, Inc.
*
* PLX Technology Inc. licenses this software under specific terms and
* conditions. Use of any of the software or derviatives thereof in any
* product without a PLX Technology chip is strictly prohibited.
*
* PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY,
* EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. PLX makes no guarantee
* or representations regarding the use of, or the results of the use of,
* the software and documentation in terms of correctness, accuracy,
* reliability, currentness, or otherwise; and you rely on the software,
* documentation and results solely at your own risk.
*
* IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
* LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
* OF ANY KIND. IN NO EVENT SHALL PLX'S TOTAL LIABILITY EXCEED THE SUM
* PAID TO PLX FOR THE PRODUCT LICENSED HEREUNDER.
*
******************************************************************************/
/******************************************************************************
*
* File Name:
*
* SupportFunc.c
*
* Description:
*
* Additional support functions
*
* Revision History:
*
* 03-01-06 : PCI SDK v4.40
*
******************************************************************************/
#include "ApiFunctions.h"
#include "CommonApi.h"
#include "GlobalVars.h"
#include "PciSupport.h"
#include "SupportFunc.h"
/*********************************************************************
*
* Function : PlxSynchronizedRegisterModify
*
* Description: Register modify to be called with KeSynchronizeExecution()
*
********************************************************************/
BOOLEAN
PlxSynchronizedRegisterModify(
PLX_REG_DATA *pRegData
)
{
U32 RegValue;
RegValue =
PLX_REG_READ(
pRegData->pdx,
pRegData->offset
);
RegValue |= pRegData->BitsToSet;
RegValue &= ~(pRegData->BitsToClear);
PLX_REG_WRITE(
pRegData->pdx,
pRegData->offset,
RegValue
);
return TRUE;
}
/******************************************************************************
*
* Function : PlxSignalNotifications
*
* Description: Called by the ISR to signal any notification events
*
* Note : This is expected to be called at DPC level
*
******************************************************************************/
VOID
PlxSignalNotifications(
DEVICE_EXTENSION *pdx,
U32 IntSource
)
{
PLIST_ENTRY pEntry;
PLX_WAIT_OBJECT *pWaitObject;
KeAcquireSpinLockAtDpcLevel(
&(pdx->Lock_WaitObjectsList)
);
// Get the interrupt wait list
pEntry = pdx->List_WaitObjects.Flink;
// Traverse wait objects and wake-up processes
while (pEntry != &(pdx->List_WaitObjects))
{
// Get the wait object
pWaitObject =
CONTAINING_RECORD(
pEntry,
PLX_WAIT_OBJECT,
ListEntry
);
// Check if waiting for active interrupt
if (pWaitObject->NotifyOnInterrupt & IntSource)
{
DebugPrintf((
"DPC signaling wait object (%p)\n",
pWaitObject
));
// Save the new interrupt source in case later requested
pWaitObject->IntSource |= pWaitObject->NotifyOnInterrupt & IntSource;
// Signal wait object
KeSetEvent(
pWaitObject->pKEvent,
IO_NO_INCREMENT,
FALSE
);
}
// Jump to next item in the list
pEntry = pEntry->Flink;
}
KeReleaseSpinLockFromDpcLevel(
&(pdx->Lock_WaitObjectsList)
);
}
/*********************************************************************
*
* Function : PlxRegistryInformationGet
*
* Description: Gets driver configuration information from the registry
*
********************************************************************/
VOID
PlxRegistryInformationGet(
UNICODE_STRING *pRegistryPath,
REGISTRY_INFORMATION *pRegistryInfo
)
{
NTSTATUS status;
RTL_QUERY_REGISTRY_TABLE RegTable[2];
#if defined(PLX_NT_DRIVER)
U32 *marker;
WCHAR slBuffer[200];
UNICODE_STRING supportedList;
UNICODE_STRING fragment;
#endif
RtlZeroMemory(
RegTable,
sizeof(RegTable)
);
RegTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
// Get Common DMA buffer size
RegTable[0].Name = L"CommonBufferSize";
RegTable[0].EntryContext = &(pRegistryInfo->CommonBufferSize);
status =
RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
pRegistryPath->Buffer,
RegTable,
NULL,
NULL
);
if ( !NT_SUCCESS(status) )
{
pRegistryInfo->CommonBufferSize = DEFAULT_SIZE_COMMON_BUFFER;
}
// Get cacheability of physical memory buffers
RegTable[0].Name = L"PhysicalMemoryCacheable";
RegTable[0].EntryContext = &(pRegistryInfo->PhysicalMemoryCacheable);
status =
RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
pRegistryPath->Buffer,
RegTable,
NULL,
NULL
);
if ( !NT_SUCCESS(status) )
{
pRegistryInfo->PhysicalMemoryCacheable = DEFAULT_PHYS_MEM_CACHE_ENABLED;
}
else
{
if (pRegistryInfo->PhysicalMemoryCacheable == 0)
{
pRegistryInfo->PhysicalMemoryCacheable = FALSE;
}
else
{
pRegistryInfo->PhysicalMemoryCacheable = TRUE;
}
}
#if defined(PLX_NT_DRIVER)
// Get list of Valid IDs
supportedList.MaximumLength = sizeof(slBuffer);
supportedList.Buffer = slBuffer;
RegTable[0].Name = L"SupportedIDs";
RegTable[0].EntryContext = &supportedList;
status =
RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
pRegistryPath->Buffer,
RegTable,
NULL,
NULL
);
if ( !NT_SUCCESS(status) )
{
DebugPrintf((
"ERROR - Unable to read %ws registry entry\n",
RegTable[0].Name
));
pRegistryInfo->ValidIdList[0] = PLX_DEFAULT_DEV_VEN_ID;
pRegistryInfo->IdListSize = 1;
}
else
{
// Now parse the unicode list and place the ID values into the array
marker = pRegistryInfo->ValidIdList;
pRegistryInfo->IdListSize = 0;
fragment.Buffer = supportedList.Buffer;
fragment.MaximumLength = sizeof(WCHAR) * 8;
fragment.Length = sizeof(WCHAR) * 8;
while (1)
{
RtlUnicodeStringToInteger(
&fragment,
0x10,
marker
);
fragment.Buffer += 9; /* must skip to next value +1 for space */
marker++;
(pRegistryInfo->IdListSize) += 1;
if ((U32)fragment.Buffer >= (U32)supportedList.Buffer + (U32)supportedList.Length)
break;
}
}
#endif
}
/******************************************************************************
*
* Function : GetBarIndex
*
* Description: Associate a h/w resource with a bar number
*
******************************************************************************/
U8
GetBarIndex(
PHYSICAL_ADDRESS address,
PCI_COMMON_CONFIG *pPciRegs
)
{
U8 i;
U32 CompareAddress;
// Compare the physical address with each BAR
for (i = 0; i < PCI_NUM_BARS_TYPE_00; i++)
{
if (pPciRegs->u.type0.BaseAddresses[i] & 0x1)
CompareAddress = pPciRegs->u.type0.BaseAddresses[i] & 0xFFFFFFFC;
else
CompareAddress = pPciRegs->u.type0.BaseAddresses[i] & 0xFFFFFFF0;
if (address.u.LowPart == CompareAddress)
return i;
}
// Unable to find the BAR index
DebugPrintf((
"ERROR - GetBarIndex() unable to match BAR value (0x%08lx)\n",
address
));
return (U8)-1;
}
/******************************************************************************
*
* Function : PlxCompleteIrp
*
* Description: Complete an IRP
*
******************************************************************************/
NTSTATUS
PlxCompleteIrp(
PIRP pIrp,
NTSTATUS status
)
{
pIrp->IoStatus.Status = status;
IoCompleteRequest(
pIrp,
IO_NO_INCREMENT
);
if (status == STATUS_CANCELLED)
DebugPrintf(("...Cancelled IRP (0x%p)\n", pIrp));
else
DebugPrintf(("...Completed IRP (0x%p)\n", pIrp));
return status;
}
/******************************************************************************
*
* Function : PlxCompleteIrpWithInformation
*
* Description: Complete an IRP including modification of the Information field
*
******************************************************************************/
NTSTATUS
PlxCompleteIrpWithInformation(
PIRP pIrp,
NTSTATUS status,
PLX_UINT_PTR Info
)
{
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = Info;
IoCompleteRequest(
pIrp,
IO_NO_INCREMENT
);
if (status == STATUS_CANCELLED)
DebugPrintf(("...Cancelled IRP (0x%p)\n", pIrp));
else
DebugPrintf(("...Completed IRP (0x%p)\n", pIrp));
return status;
}
/******************************************************************************
*
* Function : Plx_sleep
*
* Description: Function as a normal sleep. Parameter is in millisecond
*
******************************************************************************/
VOID
Plx_sleep(
U32 delay
)
{
LARGE_INTEGER liTime;
/* Convert milliseconds to 100-nanosecond increments using:
*
* 1 ns = 10 ^ -9 sec
* 100 ns = 10 ^ -7 sec (1 timer interval)
* 1 ms = 10 ^ -3 sec
* 1 ms = (1 timer interval) * 10^4
*/
delay = delay * 10000;
// Negative value means relative time, not absolute
liTime =
RtlConvertLongToLargeInteger(
-(LONG)delay
);
KeDelayExecutionThread(
KernelMode,
TRUE,
&liTime
);
}
/******************************************************************************
*
* Function : PlxPciBarResourceMap
*
* Description: Maps a PCI BAR resource into kernel space
*
******************************************************************************/
NTSTATUS
PlxPciBarResourceMap(
DEVICE_EXTENSION *pdx,
U8 BarIndex
)
{
U32 SizeToMap;
U32 SizeRemain;
VOID *pVa;
PMDL pMdl;
PMDL pMdl_Previous;
// Map into Kernel Virtual Space
pdx->PciBar[BarIndex].pVa =
MmMapIoSpace(
pdx->PciBar[BarIndex].Physical,
pdx->PciBar[BarIndex].Size,
MmNonCached
);
if (pdx->PciBar[BarIndex].pVa == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/******************************************************************
* A future mapping into user space will require an MDL. Although
* it is not documented in the Windows DDK, a single MDL is limited
* to describing just under 64MB. This is because IoAllocateMdl
* only allocates 64k for the MDL, which includes space for the
* physical page addresses that follow the MDL.
*
* In that case, we must allocate multiple MDLs and connect them
* by using the "Next" field of the MDL.
*****************************************************************/
// Set initial values
pVa = pdx->PciBar[BarIndex].pVa;
SizeRemain = pdx->PciBar[BarIndex].Size;
while (SizeRemain != 0)
{
// Determine size for MDL
if (SizeRemain <= MAX_MDL_SIZE)
{
SizeToMap = SizeRemain;
}
else
{
SizeToMap = MAX_MDL_SIZE;
}
// Get an MDL for future mapping into user space
pMdl =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -