📄 initunlo.cpp
字号:
#include "precomp.h"
NTSTATUS SerialItemCallBack(QUERY_RESULT* Results, PVOID Context);
NTSTATUS SerialConfigCallBack(QUERY_RESULT* Results, PVOID Context);
// This is exported from the kernel. It is used to point
// to the address that the kernel debugger is using.
extern "C"
{
extern PUCHAR *KdComPortInUse;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
/*++
Routine Description:
The entry point that the system point calls to initialize
any driver.
This routine will gather the configuration information,
report resource usage, attempt to initialize all serial
devices, connect to interrupts for ports. If the above
goes reasonably well it will fill in the dispatch points,
reset the serial devices and then return to the system.
Arguments:
DriverObject - Just what it says, really of little use
to the driver itself, it is something that the IO system
cares more about.
PathToRegistry - points to the entry for this driver
in the current control set of the registry.
Return Value:
STATUS_SUCCESS if we could initialize a single device,
otherwise STATUS_SERIAL_NO_DEVICE_INITED.
--*/
{
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
new KdSerialDriver(Status, DriverObject, RegistryPath);
if (!NT_SUCCESS(Status) && KdDriver::Driver())
KdDriver::Driver()->Unload();
return Status;
}
// Initialization of our driver.
KdSerialDriver::KdSerialDriver(NTSTATUS &Status, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING puniRegistryPath):
KdDriver(Status, pDriverObject, puniRegistryPath)
{
if (!NT_SUCCESS(Status))
{
DebugDump(DBG_ERRORS , ("ERROR KdDriver::KdDriver() FAILED!\n") );
return;
}
// Pointer to a device object in the device object chain
// hanging off of the driver object.
PKdSerialDevice pCurrentDevice;
// Holds a pointer to a ulong that the Io system maintains
// of the count of serial devices.
PULONG countSoFar;
// We use this to query into the registry as to whether we
// should break at driver entry.
KdRegistry Registry;
ULONG debugLevel;
ULONG shouldBreak;
ULONG forceFifoEnableDefault;
ULONG rxFIFODefault;
ULONG txFIFODefault;
ULONG permitShareDefault;
ULONG logFifoDefault;
ULONG notThereDefault = 1234567;
// Since the registry path parameter is a "counted" UNICODE string, it
// might not be zero terminated. For a very short time allocate memory
// to hold the registry path zero terminated so that we can use it to
// delve into the registry.
//
// NOTE NOTE!!!! This is not an architected way of breaking into
// a driver. It happens to work for this driver because the author
// likes to do things this way.
if (!NT_SUCCESS(Registry.Init()))
{
shouldBreak = 0;
debugLevel = 0;
}
else
{
Registry.QueryDWORD(L"BreakOnEntry", &shouldBreak);
Registry.QueryDWORD(L"DebugLevel", &debugLevel);
Registry.QueryDWORD(L"ForceFifoEnable", &forceFifoEnableDefault, notThereDefault);
Registry.QueryDWORD(L"RxFIFO", &rxFIFODefault, notThereDefault);
Registry.QueryDWORD(L"TxFIFO", &txFIFODefault, notThereDefault);
Registry.QueryDWORD(L"PermitShare", &permitShareDefault, notThereDefault);
Registry.QueryDWORD(L"LogFifo", &logFifoDefault, notThereDefault);
}
DriverDebugLevel = debugLevel;
if (shouldBreak)
DbgBreakPoint();
// Check to see if there was a forcefifo or an rxfifo size.
// If there isn't then write out values so that they could
// be adjusted later.
if (forceFifoEnableDefault==notThereDefault)
{
forceFifoEnableDefault = 1;
Registry.SetDWORD(L"ForceFifoEnable", forceFifoEnableDefault);
}
if (rxFIFODefault==notThereDefault)
{
rxFIFODefault = 8;
Registry.SetDWORD(L"RxFIFO", rxFIFODefault);
}
if (txFIFODefault==notThereDefault)
{
txFIFODefault = 1;
Registry.SetDWORD(L"TxFIFO", txFIFODefault);
}
if (permitShareDefault==notThereDefault)
{
permitShareDefault = 0;
// Only share if the user actual changes switch.
Registry.SetDWORD(L"PermitShare", permitShareDefault);
}
if (logFifoDefault==notThereDefault)
{
// Wasn't there. After this load don't log
// the message anymore. However this first
// time log the message.
Registry.SetDWORD(L"LogFifo", 0);
logFifoDefault = 1;
}
// Just dump out how big the device is.
DebugDump(DBG_DIAG1, ("The number of bytes in the device is: %d\n",
sizeof(KdSerialDevice)) );
countSoFar = &IoGetConfigurationInformation()->SerialCount;
KdConfigList ConfigList(CONFIG_LIST_OFFSET);
GetConfigInfo(
forceFifoEnableDefault,
rxFIFODefault,
txFIFODefault,
permitShareDefault,
logFifoDefault,
&ConfigList
);
// Initialize each item in the list of configuration records.
while (!ConfigList.IsEmpty())
InitializeRootInterrupt(ConfigList.RemoveHead());
// We've initialized all of the hardware that this driver
// will ever know about. All of the hardware that we know
// about is set up to NOT interrupt. We now go through
// all of the devices and connect an interrupt object for
// all.
pCurrentDevice = (PKdSerialDevice) GetFirstDevice();
while (pCurrentDevice)
{
// This loop will only connect the interrupt for the
// "root" controller. When we initialize a root controller
// we then propagate that interrupt object to all associate
// controllers. If a device doesn't already have an interrupt
// and it has an isr then we attempt to connect to the
// interrupt. Note that if we fail to connect to an interrupt
// we will delete all of the associated devices.
if ((!pCurrentDevice->m_KdInterrupt.IsConnected()) &&
(pCurrentDevice->m_Isr.pFunction!=NULL))
{
DebugDump(DBG_DIAG5, ("About to connect to interrupt for port %ws\n"
"------- address of device is %x\n",
pCurrentDevice->DeviceName(), pCurrentDevice) );
NTSTATUS status = pCurrentDevice->m_KdInterrupt.Connect(&pCurrentDevice->m_Isr);
if (!NT_SUCCESS(status))
{
// Hmmm, how'd that happen? Somebody either
// didn't report their resources, or they
// sneaked in since the last time I looked.
//
// Oh well, delete this device as well as
// any of the devices that were hoping to
// share this interrupt.
DebugDump(DBG_ERRORS, ("Couldn't connect to interrupt for %ws\n",
pCurrentDevice->DeviceName()));
LogError(
1,
status,
SERIAL_UNREPORTED_IRQL_CONFLICT,
pCurrentDevice,
pCurrentDevice->m_OriginalController,
pCurrentDevice->m_sSymbolicLinkName
);
delete pCurrentDevice;
// The above call deleted all the associated
// device objects. Who knows what the device
// list looks like now! Start over from
// the beginning of the device list.
pCurrentDevice = (PKdSerialDevice) GetFirstDevice();
}
else
{
pCurrentDevice->PropagateDeleteSharers(countSoFar, pCurrentDevice->m_KdInterrupt);
pCurrentDevice = (PKdSerialDevice) GetFirstDevice();
}
}
else
{
// We've already done this device. We can go on
// to the next device.
pCurrentDevice = (PKdSerialDevice)pCurrentDevice->GetNextDevice();
}
}
// Well if we connected to any interrupts then we should
// have some device objects. Go through all of the devices
// and reset each device.
pCurrentDevice = (PKdSerialDevice) GetFirstDevice();
while (pCurrentDevice)
{
PKdSerialDevice pNextDevice = (PKdSerialDevice)pCurrentDevice->GetNextDevice();
// While the device isn't open, disable all interrupts.
DISABLE_ALL_INTERRUPTS(pCurrentDevice->m_pController);
if (pCurrentDevice->m_Jensen)
pCurrentDevice->m_pController->WriteByte(MODEM_CONTROL_REGISTER, (UCHAR)SERIAL_MCR_OUT2);
else
pCurrentDevice->m_pController->WriteByte(MODEM_CONTROL_REGISTER, (UCHAR)0);
// This should set up everything as it should be when
// a device is to be opened. We do need to lower the
// modem lines, and disable the stupid fifo so that it
// will show up if the user boots to dos.
pCurrentDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) pCurrentDevice->Reset);
//Disables the fifo
pCurrentDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) pCurrentDevice->MarkClose);
pCurrentDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) pCurrentDevice->ClrRTS);
pCurrentDevice->m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) pCurrentDevice->ClrDTR);
pCurrentDevice = pNextDevice;
}
if (Driver()->GetFirstDevice()) // Cheack if that at least one device was created
Status = STATUS_SUCCESS;
else
Status = STATUS_UNSUCCESSFUL;
}
VOID KdSerialDevice::PropagateDeleteSharers(PULONG CountSoFar, PKINTERRUPT Interrupt)
/*++
Routine Description:
This routine will either propagate the interrupt object
to all devices sharing the same interrupt, or it will
delete all devices sharing the same interrupt.
Arguments:
CountSoFar - If interrupt is present and this is present,
we will increment the longword pointed to
by this pointer for each device
we stick the interrupt into.
If interrupt is *not* present and this
pointer *is* present, we will decrement the
longword pointed to by this value for
each device we delete.
If this isn't present, well, then, I guess
we won't do anything with it.
Interrupt - If this is present, we propagate it to
all devices on that want to share the interrupt.
--*/
{
ASSERT(m_Isr.pFunction!=NULL);
DebugDump(DBG_DIAG3, ("In SerialPropagateDeleteSharers\n"
"------- device: %x CountSoFar: %d Interrupt: %x\n",
this, CountSoFar ? *CountSoFar : 0, Interrupt) );
if (Interrupt)
{
PLIST_ENTRY currentEntry;
PLIST_ENTRY firstEntry;
DebugDump(DBG_DIAG5, ("In the report propagate RegistryPath\n") );
// Were supposed to place the interrupt object
// in every associated device object.
currentEntry = &m_CommonInterruptObject;
firstEntry = currentEntry;
do
{
PKdSerialDevice pCurrentDevice;
pCurrentDevice = CONTAINING_RECORD(currentEntry, KdSerialDevice, m_CommonInterruptObject);
pCurrentDevice->m_KdInterrupt = m_KdInterrupt;
if (CountSoFar)
*CountSoFar += 1;
currentEntry = pCurrentDevice->m_CommonInterruptObject.Flink;
} while (currentEntry != firstEntry);
return;
}
LIST_ENTRY listHead;
// We are supposed to delete all of the devices in the linked list.
//
// First we make a local list head that doesn't have the current device as part of the list.
// Then we cleanup and delete the "root" device.
//
// The we traverse all of the associated devices and null out the interrupt object
// (this way subsequent cleanup code won't attempt to disconnect the interrupt object) then we
// cleanup and delete the device.
DebugDump(DBG_DIAG5, ("In the deletion/unreport RegistryPath\n") );
InitializeListHead(&listHead);
if (!IsListEmpty(&m_CommonInterruptObject))
{
PLIST_ENTRY old = m_CommonInterruptObject.Flink;
RemoveEntryList(&m_CommonInterruptObject);
InsertTailList(old, &listHead);
}
if (CountSoFar)
*CountSoFar -= 1;
while (!IsListEmpty(&listHead))
{
PLIST_ENTRY head;
PKdSerialDevice pCurrentDevice;
head = RemoveHeadList(&listHead);
pCurrentDevice = CONTAINING_RECORD(head, KdSerialDevice, m_CommonInterruptObject);
if (CountSoFar)
*CountSoFar -= 1;
delete pCurrentDevice;
}
}
VOID KdSerialDriver::InitializeRootInterrupt(PCONFIG_DATA ConfigData)
/*++
Routine Description:
This routine attempts to build a list suitable for dispatching
to multiple devices for devices that want to share an interrupt.
Note that this includes the degenerate case of a single port who
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -