2273 lines
67 KiB
C
2273 lines
67 KiB
C
/*--------------------------------------------------------------------------
|
||
*
|
||
* Copyright (C) Cyclades Corporation, 1997-2001.
|
||
* All rights reserved.
|
||
*
|
||
* Cyclades-Z Port Driver
|
||
*
|
||
* This file: cyzinit.c
|
||
*
|
||
* Description: This module contains the code related to initialization
|
||
* and unload operations in the Cyclades-Z Port driver.
|
||
*
|
||
* Notes: This code supports Windows 2000 and Windows XP,
|
||
* x86 and IA64 processors.
|
||
*
|
||
* Complies with Cyclades SW Coding Standard rev 1.3.
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*/
|
||
|
||
/*-------------------------------------------------------------------------
|
||
*
|
||
* Change History
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*/
|
||
|
||
#include "precomp.h"
|
||
|
||
//
|
||
// This is the actual definition of CyzDebugLevel.
|
||
// Note that it is only defined if this is a "debug"
|
||
// build.
|
||
//
|
||
#if DBG
|
||
extern ULONG CyzDebugLevel = CYZDBGALL;
|
||
#endif
|
||
|
||
//
|
||
// All our global variables except DebugLevel stashed in one
|
||
// little package
|
||
//
|
||
CYZ_GLOBALS CyzGlobals;
|
||
|
||
static const PHYSICAL_ADDRESS CyzPhysicalZero = {0};
|
||
|
||
//
|
||
// We use this to query into the registry as to whether we
|
||
// should break at driver entry.
|
||
//
|
||
|
||
CYZ_REGISTRY_DATA driverDefaults;
|
||
|
||
//
|
||
// INIT - only needed during init and then can be disposed
|
||
// PAGESRP0 - always paged / never locked
|
||
// PAGESER - must be locked when a device is open, else paged
|
||
//
|
||
//
|
||
// INIT is used for DriverEntry() specific code
|
||
//
|
||
// PAGESRP0 is used for code that is not often called and has nothing
|
||
// to do with I/O performance. An example, IRP_MJ_PNP/IRP_MN_START_DEVICE
|
||
// support functions
|
||
//
|
||
// PAGESER is used for code that needs to be locked after an open for both
|
||
// performance and IRQL reasons.
|
||
//
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
|
||
#pragma alloc_text(PAGESRP0, CyzRemoveDevObj)
|
||
#pragma alloc_text(PAGESRP0, CyzUnload)
|
||
|
||
|
||
//
|
||
// PAGESER handled is keyed off of CyzReset, so CyzReset
|
||
// must remain in PAGESER for things to work properly
|
||
//
|
||
|
||
#pragma alloc_text(PAGESER, CyzReset)
|
||
#pragma alloc_text(PAGESER, CyzCommError)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
/*--------------------------------------------------------------------------
|
||
|
||
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:
|
||
|
||
Always STATUS_SUCCESS
|
||
|
||
--------------------------------------------------------------------------*/
|
||
{
|
||
//
|
||
// Lock the paged code in their frames
|
||
//
|
||
|
||
PVOID lockPtr = MmLockPagableCodeSection(CyzReset);
|
||
|
||
PAGED_CODE();
|
||
|
||
|
||
ASSERT(CyzGlobals.PAGESER_Handle == NULL);
|
||
#if DBG
|
||
CyzGlobals.PAGESER_Count = 0;
|
||
SerialLogInit();
|
||
#endif
|
||
CyzGlobals.PAGESER_Handle = lockPtr;
|
||
|
||
CyzGlobals.RegistryPath.MaximumLength = RegistryPath->MaximumLength;
|
||
CyzGlobals.RegistryPath.Length = RegistryPath->Length;
|
||
CyzGlobals.RegistryPath.Buffer
|
||
= ExAllocatePool(PagedPool, CyzGlobals.RegistryPath.MaximumLength);
|
||
|
||
if (CyzGlobals.RegistryPath.Buffer == NULL) {
|
||
MmUnlockPagableImageSection(lockPtr);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(CyzGlobals.RegistryPath.Buffer,
|
||
CyzGlobals.RegistryPath.MaximumLength);
|
||
RtlMoveMemory(CyzGlobals.RegistryPath.Buffer,
|
||
RegistryPath->Buffer, RegistryPath->Length);
|
||
|
||
KeInitializeSpinLock(&CyzGlobals.GlobalsSpinLock);
|
||
|
||
//
|
||
// Initialize all our globals
|
||
//
|
||
|
||
InitializeListHead(&CyzGlobals.AllDevObjs);
|
||
|
||
//
|
||
// Call to find out default values to use for all the devices that the
|
||
// driver controls, including whether or not to break on entry.
|
||
//
|
||
|
||
CyzGetConfigDefaults(&driverDefaults, RegistryPath);
|
||
|
||
#if DBG
|
||
//
|
||
// Set global debug output level
|
||
//
|
||
CyzDebugLevel = driverDefaults.DebugLevel;
|
||
#endif
|
||
|
||
//
|
||
// Break on entry if requested via registry
|
||
//
|
||
|
||
if (driverDefaults.ShouldBreakOnEntry) {
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
|
||
//
|
||
// Just dump out how big the extension is.
|
||
//
|
||
|
||
CyzDbgPrintEx(DPFLTR_INFO_LEVEL, "The number of bytes in the extension "
|
||
"is: %d\n", sizeof(CYZ_DEVICE_EXTENSION));
|
||
|
||
|
||
//
|
||
// Initialize the Driver Object with driver's entry points
|
||
//
|
||
|
||
DriverObject->DriverUnload = CyzUnload;
|
||
DriverObject->DriverExtension->AddDevice = CyzAddDevice;
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = CyzFlush;
|
||
DriverObject->MajorFunction[IRP_MJ_WRITE] = CyzWrite;
|
||
DriverObject->MajorFunction[IRP_MJ_READ] = CyzRead;
|
||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CyzIoControl;
|
||
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
|
||
= CyzInternalIoControl;
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = CyzCreateOpen;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = CyzClose;
|
||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CyzCleanup;
|
||
DriverObject->MajorFunction[IRP_MJ_PNP] = CyzPnpDispatch;
|
||
DriverObject->MajorFunction[IRP_MJ_POWER] = CyzPowerDispatch;
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]
|
||
= CyzQueryInformationFile;
|
||
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]
|
||
= CyzSetInformationFile;
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]
|
||
= CyzSystemControlDispatch;
|
||
|
||
|
||
//
|
||
// Unlock pageable text
|
||
//
|
||
MmUnlockPagableImageSection(lockPtr);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
|
||
BOOLEAN
|
||
CyzCleanLists(IN PVOID Context)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes a device object from any of the serial linked lists it may
|
||
appear on.
|
||
|
||
Arguments:
|
||
|
||
Context - Actually a PCYZ_DEVICE_EXTENSION (for the devobj being
|
||
removed).
|
||
|
||
Return Value:
|
||
|
||
Always TRUE
|
||
|
||
--*/
|
||
{
|
||
PCYZ_DEVICE_EXTENSION pDevExt = (PCYZ_DEVICE_EXTENSION)Context;
|
||
PCYZ_DISPATCH pDispatch;
|
||
ULONG i;
|
||
|
||
//
|
||
// Remove our entry from the dispatch context
|
||
//
|
||
|
||
pDispatch = (PCYZ_DISPATCH)pDevExt->OurIsrContext;
|
||
|
||
CyzDbgPrintEx(CYZPNPPOWER, "CLEAN: removing multiport isr "
|
||
"ext\n");
|
||
|
||
#ifdef POLL
|
||
if (pDispatch->PollingStarted) {
|
||
pDispatch->Extensions[pDevExt->PortIndex] = NULL;
|
||
|
||
for (i = 0; i < pDispatch->NChannels; i++) {
|
||
|
||
if (pDevExt->OurIsrContext) {
|
||
|
||
if (((PCYZ_DISPATCH)pDevExt->OurIsrContext)->Extensions[i] != NULL) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (i < pDispatch->NChannels) {
|
||
pDevExt->OurIsrContext = NULL;
|
||
} else {
|
||
|
||
BOOLEAN cancelled;
|
||
|
||
pDispatch->PollingStarted = FALSE;
|
||
cancelled = KeCancelTimer(&pDispatch->PollingTimer);
|
||
if (cancelled) {
|
||
pDispatch->PollingDrained = TRUE;
|
||
}
|
||
}
|
||
}
|
||
#else
|
||
pDispatch->Extensions[pDevExt->PortIndex] = NULL;
|
||
|
||
for (i = 0; i < pDispatch->NChannels; i++) {
|
||
if (pDispatch->Extensions[i] != NULL) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i < pDispatch->NChannels) {
|
||
// Others are chained on this interrupt, so we don't want to
|
||
// disconnect it.
|
||
pDevExt->Interrupt = NULL;
|
||
}
|
||
#endif
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
CyzReleaseResources(IN PCYZ_DEVICE_EXTENSION PDevExt)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Releases resources (not pool) stored in the device extension.
|
||
|
||
Arguments:
|
||
|
||
PDevExt - Pointer to the device extension to release resources from.
|
||
|
||
Return Value:
|
||
|
||
VOID
|
||
|
||
--*/
|
||
{
|
||
#ifdef POLL
|
||
KIRQL pollIrql;
|
||
BOOLEAN timerStarted, timerDrained;
|
||
PCYZ_DISPATCH pDispatch = PDevExt->OurIsrContext;
|
||
ULONG pollCount;
|
||
#endif
|
||
KIRQL oldIrql;
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzReleaseResources(%X)\n",
|
||
PDevExt);
|
||
|
||
//
|
||
// AllDevObjs should never be empty since we have a sentinal
|
||
// Note: serial removes device from AllDevObjs list after calling
|
||
// SerialCleanLists. We do it before to make sure no other port will
|
||
// be added to share the polling routine or PDevExt->Interrut that is
|
||
// on the way to be disconnected.
|
||
//
|
||
|
||
KeAcquireSpinLock(&CyzGlobals.GlobalsSpinLock, &oldIrql);
|
||
|
||
ASSERT(!IsListEmpty(&PDevExt->AllDevObjs));
|
||
|
||
RemoveEntryList(&PDevExt->AllDevObjs);
|
||
|
||
KeReleaseSpinLock(&CyzGlobals.GlobalsSpinLock, oldIrql);
|
||
|
||
InitializeListHead(&PDevExt->AllDevObjs);
|
||
|
||
//
|
||
// Remove us from any lists we may be on
|
||
//
|
||
#ifdef POLL
|
||
KeAcquireSpinLock(&pDispatch->PollingLock,&pollIrql); //Changed in 11/09/00
|
||
CyzCleanLists(PDevExt);
|
||
timerStarted = pDispatch->PollingStarted;
|
||
timerDrained = pDispatch->PollingDrained;
|
||
KeReleaseSpinLock(&pDispatch->PollingLock,pollIrql); // Changed in 11/09/00
|
||
|
||
// If we are the last device, free this memory
|
||
if (!timerStarted) {
|
||
// We are the last device, because timer was cancelled.
|
||
// Let's see if no more pending DPC.
|
||
if (!timerDrained) {
|
||
KeWaitForSingleObject(&pDispatch->PendingDpcEvent, Executive,
|
||
KernelMode, FALSE, NULL);
|
||
}
|
||
|
||
KeAcquireSpinLock(&pDispatch->PollingLock,&pollIrql); // needed to wait for PollingDpc end
|
||
pollCount = InterlockedDecrement(&pDispatch->PollingCount);
|
||
KeReleaseSpinLock(&pDispatch->PollingLock,pollIrql);
|
||
if (pollCount == 0) {
|
||
CyzDbgPrintEx(CYZPNPPOWER, "Release - freeing multi context\n");
|
||
if (PDevExt->OurIsrContext != NULL) { // added in DDK build 2072, but
|
||
ExFreePool(PDevExt->OurIsrContext); // we already had the free of OurIsrContext.
|
||
PDevExt->OurIsrContext = NULL; //
|
||
}
|
||
}
|
||
}
|
||
#else
|
||
KeSynchronizeExecution(PDevExt->Interrupt, CyzCleanLists, PDevExt);
|
||
|
||
//
|
||
// Stop servicing interrupts if we are the last device
|
||
//
|
||
|
||
if (PDevExt->Interrupt != NULL) {
|
||
|
||
// Disable interrupts in the PLX
|
||
{
|
||
ULONG intr_reg;
|
||
|
||
intr_reg = CYZ_READ_ULONG(&(PDevExt->Runtime)->intr_ctrl_stat);
|
||
intr_reg &= ~(0x00030B00UL);
|
||
CYZ_WRITE_ULONG(&(PDevExt->Runtime)->intr_ctrl_stat,intr_reg);
|
||
}
|
||
|
||
CyzDbgPrintEx(CYZPNPPOWER, "Release - disconnecting interrupt %X\n",
|
||
PDevExt->Interrupt);
|
||
|
||
IoDisconnectInterrupt(PDevExt->Interrupt);
|
||
PDevExt->Interrupt = NULL;
|
||
|
||
// If we are the last device, free this memory
|
||
|
||
CyzDbgPrintEx(CYZPNPPOWER, "Release - freeing multi context\n");
|
||
if (PDevExt->OurIsrContext != NULL) { // added in DDK build 2072, but
|
||
ExFreePool(PDevExt->OurIsrContext); // we already had the free of OurIsrContext.
|
||
PDevExt->OurIsrContext = NULL; //
|
||
}
|
||
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Stop handling timers
|
||
//
|
||
|
||
CyzCancelTimer(&PDevExt->ReadRequestTotalTimer, PDevExt);
|
||
CyzCancelTimer(&PDevExt->ReadRequestIntervalTimer, PDevExt);
|
||
CyzCancelTimer(&PDevExt->WriteRequestTotalTimer, PDevExt);
|
||
CyzCancelTimer(&PDevExt->ImmediateTotalTimer, PDevExt);
|
||
CyzCancelTimer(&PDevExt->XoffCountTimer, PDevExt);
|
||
CyzCancelTimer(&PDevExt->LowerRTSTimer, PDevExt);
|
||
|
||
//
|
||
// Stop servicing DPC's
|
||
//
|
||
|
||
CyzRemoveQueueDpc(&PDevExt->CompleteWriteDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->CompleteReadDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->TotalReadTimeoutDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->IntervalReadTimeoutDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->TotalWriteTimeoutDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->CommErrorDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->CompleteImmediateDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->TotalImmediateTimeoutDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->CommWaitDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->XoffCountTimeoutDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->XoffCountCompleteDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->StartTimerLowerRTSDpc, PDevExt);
|
||
CyzRemoveQueueDpc(&PDevExt->PerhapsLowerRTSDpc, PDevExt);
|
||
|
||
|
||
|
||
//
|
||
// If necessary, unmap the device registers.
|
||
//
|
||
|
||
// if (PDevExt->BoardMemory) {
|
||
// MmUnmapIoSpace(PDevExt->BoardMemory, PDevExt->BoardMemoryLength);
|
||
// PDevExt->BoardMemory = NULL;
|
||
// }
|
||
|
||
if (PDevExt->BoardCtrl) {
|
||
MmUnmapIoSpace(PDevExt->BoardCtrl, sizeof(struct BOARD_CTRL));
|
||
PDevExt->BoardCtrl = NULL;
|
||
}
|
||
|
||
if (PDevExt->ChCtrl) {
|
||
MmUnmapIoSpace(PDevExt->ChCtrl,sizeof(struct CH_CTRL));
|
||
PDevExt->ChCtrl = NULL;
|
||
}
|
||
|
||
if (PDevExt->BufCtrl) {
|
||
MmUnmapIoSpace(PDevExt->BufCtrl,sizeof(struct BUF_CTRL));
|
||
PDevExt->BufCtrl = NULL;
|
||
}
|
||
|
||
if (PDevExt->TxBufaddr) {
|
||
MmUnmapIoSpace(PDevExt->TxBufaddr,PDevExt->TxBufsize);
|
||
PDevExt->TxBufaddr = NULL;
|
||
}
|
||
|
||
if (PDevExt->RxBufaddr) {
|
||
MmUnmapIoSpace(PDevExt->RxBufaddr,PDevExt->RxBufsize);
|
||
PDevExt->RxBufaddr = NULL;
|
||
}
|
||
|
||
if (PDevExt->PtZfIntQueue) {
|
||
MmUnmapIoSpace(PDevExt->PtZfIntQueue,sizeof(struct INT_QUEUE));
|
||
PDevExt->PtZfIntQueue = NULL;
|
||
}
|
||
|
||
if (PDevExt->Runtime) {
|
||
MmUnmapIoSpace(PDevExt->Runtime,
|
||
PDevExt->RuntimeLength);
|
||
PDevExt->Runtime = NULL;
|
||
}
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzReleaseResources\n");
|
||
}
|
||
|
||
|
||
VOID
|
||
CyzDisableInterfacesResources(IN PDEVICE_OBJECT PDevObj,
|
||
BOOLEAN DisableUART)
|
||
{
|
||
PCYZ_DEVICE_EXTENSION pDevExt
|
||
= (PCYZ_DEVICE_EXTENSION)PDevObj->DeviceExtension;
|
||
|
||
PAGED_CODE();
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzDisableInterfaces(%X, %s)\n",
|
||
PDevObj, DisableUART ? "TRUE" : "FALSE");
|
||
|
||
//
|
||
// Only do these many things if the device has started and still
|
||
// has resources allocated
|
||
//
|
||
|
||
if (pDevExt->Flags & CYZ_FLAGS_STARTED) {
|
||
|
||
if (!(pDevExt->Flags & CYZ_FLAGS_STOPPED)) {
|
||
|
||
if (DisableUART) {
|
||
#ifndef POLL
|
||
//TODO: Synchronize with Interrupt.
|
||
//
|
||
// Mask off interrupts
|
||
//
|
||
CYZ_WRITE_ULONG(&(pDevExt->ChCtrl)->intr_enable,C_IN_DISABLE); //1.0.0.11
|
||
CyzIssueCmd(pDevExt,C_CM_IOCTL,0L,FALSE);
|
||
#endif
|
||
}
|
||
|
||
CyzReleaseResources(pDevExt);
|
||
|
||
}
|
||
|
||
//
|
||
// Remove us from WMI consideration
|
||
//
|
||
|
||
IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_DEREGISTER);
|
||
}
|
||
|
||
//
|
||
// Undo external names
|
||
//
|
||
|
||
CyzUndoExternalNaming(pDevExt);
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzDisableInterfaces\n");
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CyzRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes a serial device object from the system.
|
||
|
||
Arguments:
|
||
|
||
PDevObj - A pointer to the Device Object we want removed.
|
||
|
||
Return Value:
|
||
|
||
Always TRUE
|
||
|
||
--*/
|
||
{
|
||
PCYZ_DEVICE_EXTENSION pDevExt
|
||
= (PCYZ_DEVICE_EXTENSION)PDevObj->DeviceExtension;
|
||
|
||
PAGED_CODE();
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzRemoveDevObj(%X)\n", PDevObj);
|
||
|
||
// Removed by Fanny. These code is called directly from IRP_MN_REMOVE_DEVICE.
|
||
// if (!(pDevExt->DevicePNPAccept & CYZ_PNPACCEPT_SURPRISE_REMOVING)) {
|
||
// //
|
||
// // Disable all external interfaces and release resources
|
||
// //
|
||
//
|
||
// CyzDisableInterfacesResources(PDevObj, TRUE);
|
||
// }
|
||
|
||
IoDetachDevice(pDevExt->LowerDeviceObject);
|
||
|
||
//
|
||
// Free memory allocated in the extension
|
||
//
|
||
|
||
if (pDevExt->NtNameForPort.Buffer != NULL) {
|
||
ExFreePool(pDevExt->NtNameForPort.Buffer);
|
||
}
|
||
|
||
if (pDevExt->DeviceName.Buffer != NULL) {
|
||
ExFreePool(pDevExt->DeviceName.Buffer);
|
||
}
|
||
|
||
if (pDevExt->SymbolicLinkName.Buffer != NULL) {
|
||
ExFreePool(pDevExt->SymbolicLinkName.Buffer);
|
||
}
|
||
|
||
if (pDevExt->DosName.Buffer != NULL) {
|
||
ExFreePool(pDevExt->DosName.Buffer);
|
||
}
|
||
|
||
if (pDevExt->ObjectDirectory.Buffer) {
|
||
ExFreePool(pDevExt->ObjectDirectory.Buffer);
|
||
}
|
||
|
||
//
|
||
// Delete the devobj
|
||
//
|
||
|
||
IoDeleteDevice(PDevObj);
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzRemoveDevObj %X\n",
|
||
STATUS_SUCCESS);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
CyzKillPendingIrps(PDEVICE_OBJECT PDevObj)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine kills any irps pending for the passed device object.
|
||
|
||
Arguments:
|
||
|
||
PDevObj - Pointer to the device object whose irps must die.
|
||
|
||
Return Value:
|
||
|
||
VOID
|
||
|
||
--*/
|
||
{
|
||
PCYZ_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
||
KIRQL oldIrql;
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzKillPendingIrps(%X)\n",
|
||
PDevObj);
|
||
|
||
//
|
||
// First kill all the reads and writes.
|
||
//
|
||
|
||
CyzKillAllReadsOrWrites(PDevObj, &pDevExt->WriteQueue,
|
||
&pDevExt->CurrentWriteIrp);
|
||
|
||
CyzKillAllReadsOrWrites(PDevObj, &pDevExt->ReadQueue,
|
||
&pDevExt->CurrentReadIrp);
|
||
|
||
//
|
||
// Next get rid of purges.
|
||
//
|
||
|
||
CyzKillAllReadsOrWrites(PDevObj, &pDevExt->PurgeQueue,
|
||
&pDevExt->CurrentPurgeIrp);
|
||
|
||
//
|
||
// Get rid of any mask operations.
|
||
//
|
||
|
||
CyzKillAllReadsOrWrites(PDevObj, &pDevExt->MaskQueue,
|
||
&pDevExt->CurrentMaskIrp);
|
||
|
||
//
|
||
// Now get rid a pending wait mask irp.
|
||
//
|
||
|
||
IoAcquireCancelSpinLock(&oldIrql);
|
||
|
||
if (pDevExt->CurrentWaitIrp) {
|
||
|
||
PDRIVER_CANCEL cancelRoutine;
|
||
|
||
cancelRoutine = pDevExt->CurrentWaitIrp->CancelRoutine;
|
||
pDevExt->CurrentWaitIrp->Cancel = TRUE;
|
||
|
||
if (cancelRoutine) {
|
||
|
||
pDevExt->CurrentWaitIrp->CancelIrql = oldIrql;
|
||
pDevExt->CurrentWaitIrp->CancelRoutine = NULL;
|
||
|
||
cancelRoutine(PDevObj, pDevExt->CurrentWaitIrp);
|
||
|
||
} else {
|
||
IoReleaseCancelSpinLock(oldIrql); // Added to fix modem share test 53 freeze
|
||
}
|
||
|
||
} else {
|
||
|
||
IoReleaseCancelSpinLock(oldIrql);
|
||
|
||
}
|
||
|
||
//
|
||
// Cancel any pending wait-wake irps
|
||
//
|
||
|
||
if (pDevExt->PendingWakeIrp != NULL) {
|
||
IoCancelIrp(pDevExt->PendingWakeIrp);
|
||
pDevExt->PendingWakeIrp = NULL;
|
||
}
|
||
|
||
//
|
||
// Finally, dump any stalled IRPS
|
||
//
|
||
|
||
CyzKillAllStalled(PDevObj);
|
||
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzKillPendingIrps\n");
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CyzInitMultiPort(IN PCYZ_DEVICE_EXTENSION PDevExt,
|
||
IN PCONFIG_DATA PConfigData, IN PDEVICE_OBJECT PDevObj)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes a multiport device by adding a port to an existing
|
||
one.
|
||
|
||
Arguments:
|
||
|
||
PDevExt - pointer to the device extension of the root of the multiport
|
||
device.
|
||
|
||
PConfigData - pointer to the config data for the new port
|
||
|
||
PDevObj - pointer to the devobj for the new port
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS on success, appropriate error on failure.
|
||
|
||
--*/
|
||
{
|
||
PCYZ_DEVICE_EXTENSION pNewExt
|
||
= (PCYZ_DEVICE_EXTENSION)PDevObj->DeviceExtension;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzInitMultiPort(%X, %X, %X)\n",
|
||
PDevExt, PConfigData, PDevObj);
|
||
|
||
//
|
||
// Allow him to share OurIsrContext and interrupt object
|
||
//
|
||
|
||
pNewExt->OurIsrContext = PDevExt->OurIsrContext;
|
||
#ifndef POLL
|
||
pNewExt->Interrupt = PDevExt->Interrupt;
|
||
#endif
|
||
//
|
||
// First, see if we can initialize the one we have found
|
||
//
|
||
|
||
status = CyzInitController(PDevObj, PConfigData);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzInitMultiPort (1) %X\n",
|
||
status);
|
||
return status;
|
||
}
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzInitMultiPort (3) %X\n",
|
||
STATUS_SUCCESS);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CyzInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfigData)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Really too many things to mention here. In general initializes
|
||
kernel synchronization structures, allocates the typeahead buffer,
|
||
sets up defaults, etc.
|
||
|
||
Arguments:
|
||
|
||
PDevObj - Device object for the device to be started
|
||
|
||
PConfigData - Pointer to a record for a single port.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status
|
||
otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PCYZ_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
||
|
||
//
|
||
// Holds the NT Status that is returned from each call to the
|
||
// kernel and executive.
|
||
//
|
||
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
BOOLEAN allocedDispatch = FALSE;
|
||
PCYZ_DISPATCH pDispatch = NULL;
|
||
BOOLEAN firstTimeThisBoard;
|
||
|
||
struct FIRM_ID *pt_firm_id;
|
||
struct ZFW_CTRL *zfw_ctrl;
|
||
struct BOARD_CTRL *board_ctrl;
|
||
struct BUF_CTRL *buf_ctrl;
|
||
struct CH_CTRL *ch_ctrl;
|
||
struct INT_QUEUE *zf_int_queue;
|
||
PUCHAR tx_buf;
|
||
PUCHAR rx_buf;
|
||
PUCHAR BoardMemory;
|
||
PHYSICAL_ADDRESS board_ctrl_phys;
|
||
PHYSICAL_ADDRESS buf_ctrl_phys;
|
||
PHYSICAL_ADDRESS ch_ctrl_phys;
|
||
PHYSICAL_ADDRESS zf_int_queue_phys;
|
||
PHYSICAL_ADDRESS tx_buf_phys;
|
||
PHYSICAL_ADDRESS rx_buf_phys;
|
||
|
||
|
||
#ifdef POLL
|
||
BOOLEAN incPoll = FALSE;
|
||
#endif
|
||
|
||
PAGED_CODE();
|
||
|
||
|
||
CyzDbgPrintEx(CYZDIAG1, "Initializing for configuration record of %wZ\n",
|
||
&pDevExt->DeviceName);
|
||
|
||
if (pDevExt->OurIsrContext == NULL) {
|
||
|
||
if ((pDevExt->OurIsrContext
|
||
= ExAllocatePool(NonPagedPool,sizeof(CYZ_DISPATCH))) == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ExtensionCleanup;
|
||
}
|
||
RtlZeroMemory(pDevExt->OurIsrContext,sizeof(CYZ_DISPATCH));
|
||
|
||
allocedDispatch = TRUE;
|
||
firstTimeThisBoard = TRUE;
|
||
} else {
|
||
firstTimeThisBoard = FALSE;
|
||
}
|
||
|
||
//
|
||
// Initialize the timers used to timeout operations.
|
||
//
|
||
|
||
KeInitializeTimer(&pDevExt->ReadRequestTotalTimer);
|
||
KeInitializeTimer(&pDevExt->ReadRequestIntervalTimer);
|
||
KeInitializeTimer(&pDevExt->WriteRequestTotalTimer);
|
||
KeInitializeTimer(&pDevExt->ImmediateTotalTimer);
|
||
KeInitializeTimer(&pDevExt->XoffCountTimer);
|
||
KeInitializeTimer(&pDevExt->LowerRTSTimer);
|
||
|
||
|
||
//
|
||
// Intialialize the dpcs that will be used to complete
|
||
// or timeout various IO operations.
|
||
//
|
||
|
||
KeInitializeDpc(&pDevExt->CompleteWriteDpc, CyzCompleteWrite, pDevExt);
|
||
KeInitializeDpc(&pDevExt->CompleteReadDpc, CyzCompleteRead, pDevExt);
|
||
KeInitializeDpc(&pDevExt->TotalReadTimeoutDpc, CyzReadTimeout, pDevExt);
|
||
KeInitializeDpc(&pDevExt->IntervalReadTimeoutDpc, CyzIntervalReadTimeout,
|
||
pDevExt);
|
||
KeInitializeDpc(&pDevExt->TotalWriteTimeoutDpc, CyzWriteTimeout, pDevExt);
|
||
KeInitializeDpc(&pDevExt->CommErrorDpc, CyzCommError, pDevExt);
|
||
KeInitializeDpc(&pDevExt->CompleteImmediateDpc, CyzCompleteImmediate,
|
||
pDevExt);
|
||
KeInitializeDpc(&pDevExt->TotalImmediateTimeoutDpc, CyzTimeoutImmediate,
|
||
pDevExt);
|
||
KeInitializeDpc(&pDevExt->CommWaitDpc, CyzCompleteWait, pDevExt);
|
||
KeInitializeDpc(&pDevExt->XoffCountTimeoutDpc, CyzTimeoutXoff, pDevExt);
|
||
KeInitializeDpc(&pDevExt->XoffCountCompleteDpc, CyzCompleteXoff, pDevExt);
|
||
KeInitializeDpc(&pDevExt->StartTimerLowerRTSDpc, CyzStartTimerLowerRTS,
|
||
pDevExt);
|
||
KeInitializeDpc(&pDevExt->PerhapsLowerRTSDpc, CyzInvokePerhapsLowerRTS,
|
||
pDevExt);
|
||
KeInitializeDpc(&pDevExt->IsrUnlockPagesDpc, CyzUnlockPages, pDevExt);
|
||
|
||
#if 0 // DBG
|
||
//
|
||
// Init debug stuff
|
||
//
|
||
|
||
pDevExt->DpcQueued[0].Dpc = &pDevExt->CompleteWriteDpc;
|
||
pDevExt->DpcQueued[1].Dpc = &pDevExt->CompleteReadDpc;
|
||
pDevExt->DpcQueued[2].Dpc = &pDevExt->TotalReadTimeoutDpc;
|
||
pDevExt->DpcQueued[3].Dpc = &pDevExt->IntervalReadTimeoutDpc;
|
||
pDevExt->DpcQueued[4].Dpc = &pDevExt->TotalWriteTimeoutDpc;
|
||
pDevExt->DpcQueued[5].Dpc = &pDevExt->CommErrorDpc;
|
||
pDevExt->DpcQueued[6].Dpc = &pDevExt->CompleteImmediateDpc;
|
||
pDevExt->DpcQueued[7].Dpc = &pDevExt->TotalImmediateTimeoutDpc;
|
||
pDevExt->DpcQueued[8].Dpc = &pDevExt->CommWaitDpc;
|
||
pDevExt->DpcQueued[9].Dpc = &pDevExt->XoffCountTimeoutDpc;
|
||
pDevExt->DpcQueued[10].Dpc = &pDevExt->XoffCountCompleteDpc;
|
||
pDevExt->DpcQueued[11].Dpc = &pDevExt->StartTimerLowerRTSDpc;
|
||
pDevExt->DpcQueued[12].Dpc = &pDevExt->PerhapsLowerRTSDpc;
|
||
pDevExt->DpcQueued[13].Dpc = &pDevExt->IsrUnlockPagesDpc;
|
||
|
||
#endif
|
||
|
||
|
||
//
|
||
// Map the memory for the control registers for the serial device
|
||
// into virtual memory.
|
||
//
|
||
pDevExt->Runtime = MmMapIoSpace(PConfigData->TranslatedRuntime,
|
||
PConfigData->RuntimeLength,
|
||
FALSE);
|
||
//******************************
|
||
// Error injection
|
||
//if (pDevExt->Runtime) {
|
||
// MmUnmapIoSpace(pDevExt->Runtime, PConfigData->RuntimeLength);
|
||
// pDevExt->Runtime = NULL;
|
||
//}
|
||
//******************************
|
||
|
||
if (!pDevExt->Runtime) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
pDevExt->DeviceObject,
|
||
PConfigData->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfigData->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_RUNTIME_NOT_MAPPED,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Runtime memory for device "
|
||
"registers for %wZ\n", &pDevExt->DeviceName);
|
||
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
|
||
BoardMemory = MmMapIoSpace(PConfigData->TranslatedBoardMemory,
|
||
PConfigData->BoardMemoryLength,
|
||
FALSE);
|
||
|
||
//******************************
|
||
// Error injection
|
||
//if (pDevExt->BoardMemory) {
|
||
// MmUnmapIoSpace(pDevExt->BoardMemory, PConfigData->BoardMemoryLength);
|
||
// pDevExt->BoardMemory = NULL;
|
||
//}
|
||
//******************************
|
||
|
||
if (!BoardMemory) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
pDevExt->DeviceObject,
|
||
PConfigData->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfigData->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_BOARD_NOT_MAPPED,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory for device "
|
||
"registers for %wZ\n", &pDevExt->DeviceName);
|
||
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
pDevExt->RuntimeAddressSpace = PConfigData->RuntimeAddressSpace;
|
||
pDevExt->OriginalRuntimeMemory = PConfigData->PhysicalRuntime;
|
||
pDevExt->RuntimeLength = PConfigData->RuntimeLength;
|
||
|
||
pDevExt->BoardMemoryAddressSpace = PConfigData->BoardMemoryAddressSpace;
|
||
pDevExt->OriginalBoardMemory = PConfigData->PhysicalBoardMemory;
|
||
pDevExt->BoardMemoryLength = PConfigData->BoardMemoryLength;
|
||
|
||
//
|
||
// Shareable interrupt?
|
||
//
|
||
|
||
#ifndef POLL
|
||
pDevExt->InterruptShareable = TRUE;
|
||
#endif
|
||
|
||
//
|
||
// Save off the interface type and the bus number.
|
||
//
|
||
|
||
pDevExt->InterfaceType = PConfigData->InterfaceType;
|
||
pDevExt->BusNumber = PConfigData->BusNumber;
|
||
pDevExt->PortIndex = PConfigData->PortIndex;
|
||
pDevExt->PPPaware = (BOOLEAN)PConfigData->PPPaware;
|
||
pDevExt->ReturnStatusAfterFwEmpty = (BOOLEAN)PConfigData->WriteComplete;
|
||
|
||
#ifndef POLL
|
||
//
|
||
// Get the translated interrupt vector, level, and affinity
|
||
//
|
||
|
||
pDevExt->OriginalIrql = PConfigData->OriginalIrql;
|
||
pDevExt->OriginalVector = PConfigData->OriginalVector;
|
||
|
||
|
||
//
|
||
// PnP uses the passed translated values rather than calling
|
||
// HalGetInterruptVector()
|
||
//
|
||
|
||
pDevExt->Vector = PConfigData->TrVector;
|
||
pDevExt->Irql = (UCHAR)PConfigData->TrIrql;
|
||
|
||
//
|
||
// Set up the Isr.
|
||
//
|
||
|
||
pDevExt->OurIsr = CyzIsr;
|
||
#endif
|
||
|
||
//
|
||
// Before we test whether the port exists (which will enable the FIFO)
|
||
// convert the rx trigger value to what should be used in the register.
|
||
//
|
||
// If a bogus value was given - crank them down to 1.
|
||
//
|
||
|
||
switch (PConfigData->RxFIFO) {
|
||
|
||
case 1:
|
||
|
||
pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
|
||
break;
|
||
|
||
case 4:
|
||
|
||
pDevExt->RxFifoTrigger = SERIAL_4_BYTE_HIGH_WATER;
|
||
break;
|
||
|
||
case 8:
|
||
|
||
pDevExt->RxFifoTrigger = SERIAL_8_BYTE_HIGH_WATER;
|
||
break;
|
||
|
||
case 14:
|
||
|
||
pDevExt->RxFifoTrigger = SERIAL_14_BYTE_HIGH_WATER;
|
||
break;
|
||
|
||
default:
|
||
|
||
pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
|
||
break;
|
||
|
||
}
|
||
|
||
|
||
if ((PConfigData->TxFIFO > 16) ||
|
||
(PConfigData->TxFIFO < 1)) {
|
||
|
||
pDevExt->TxFifoAmount = 1;
|
||
|
||
} else {
|
||
|
||
pDevExt->TxFifoAmount = PConfigData->TxFIFO;
|
||
|
||
}
|
||
|
||
pt_firm_id = (struct FIRM_ID *) (BoardMemory + ID_ADDRESS);
|
||
zfw_ctrl = (struct ZFW_CTRL *)(BoardMemory + CYZ_READ_ULONG(&pt_firm_id->zfwctrl_addr));
|
||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||
ch_ctrl = &zfw_ctrl->ch_ctrl[pDevExt->PortIndex];
|
||
buf_ctrl = &zfw_ctrl->buf_ctrl[pDevExt->PortIndex];
|
||
tx_buf = BoardMemory + CYZ_READ_ULONG(&buf_ctrl->tx_bufaddr);
|
||
rx_buf = BoardMemory + CYZ_READ_ULONG(&buf_ctrl->rx_bufaddr);
|
||
zf_int_queue = (struct INT_QUEUE *)(BoardMemory +
|
||
CYZ_READ_ULONG(&(board_ctrl)->zf_int_queue_addr));
|
||
|
||
board_ctrl_phys = MmGetPhysicalAddress(board_ctrl);
|
||
ch_ctrl_phys = MmGetPhysicalAddress(ch_ctrl);
|
||
buf_ctrl_phys = MmGetPhysicalAddress(buf_ctrl);
|
||
tx_buf_phys = MmGetPhysicalAddress(tx_buf);
|
||
rx_buf_phys = MmGetPhysicalAddress(rx_buf);
|
||
zf_int_queue_phys = MmGetPhysicalAddress(zf_int_queue);
|
||
|
||
MmUnmapIoSpace(BoardMemory, PConfigData->BoardMemoryLength);
|
||
|
||
pDevExt->BoardCtrl = MmMapIoSpace(board_ctrl_phys,
|
||
sizeof(struct BOARD_CTRL),
|
||
FALSE);
|
||
|
||
if (pDevExt->BoardCtrl == NULL) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
pDevExt->DeviceObject,
|
||
PConfigData->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfigData->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_BOARD_CTRL_NOT_MAPPED,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map BoardCtrl for %wZ\n",
|
||
&pDevExt->DeviceName);
|
||
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
pDevExt->ChCtrl = MmMapIoSpace(ch_ctrl_phys,
|
||
sizeof(struct CH_CTRL),
|
||
FALSE);
|
||
|
||
if (pDevExt->ChCtrl == NULL) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
pDevExt->DeviceObject,
|
||
PConfigData->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfigData->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_CH_CTRL_NOT_MAPPED,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory ChCtrl "
|
||
"for %wZ\n",&pDevExt->DeviceName);
|
||
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
pDevExt->BufCtrl = MmMapIoSpace(buf_ctrl_phys,
|
||
sizeof(struct BUF_CTRL),
|
||
FALSE);
|
||
|
||
if (pDevExt->BufCtrl == NULL) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
pDevExt->DeviceObject,
|
||
PConfigData->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfigData->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_BUF_CTRL_NOT_MAPPED,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory BufCtrl "
|
||
"for %wZ\n",&pDevExt->DeviceName);
|
||
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
buf_ctrl = pDevExt->BufCtrl;
|
||
pDevExt->TxBufsize = CYZ_READ_ULONG(&buf_ctrl->tx_bufsize);
|
||
pDevExt->RxBufsize = CYZ_READ_ULONG(&buf_ctrl->rx_bufsize);
|
||
pDevExt->TxBufaddr = MmMapIoSpace(tx_buf_phys,
|
||
pDevExt->TxBufsize,
|
||
FALSE);
|
||
|
||
if (pDevExt->TxBufaddr == NULL) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
pDevExt->DeviceObject,
|
||
PConfigData->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfigData->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_TX_BUF_NOT_MAPPED,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory TxBuf "
|
||
"for %wZ\n",&pDevExt->DeviceName);
|
||
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
pDevExt->RxBufaddr = MmMapIoSpace(rx_buf_phys,
|
||
pDevExt->RxBufsize,
|
||
FALSE);
|
||
|
||
if (pDevExt->RxBufaddr == NULL) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
pDevExt->DeviceObject,
|
||
PConfigData->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfigData->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_RX_BUF_NOT_MAPPED,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory RxBuf "
|
||
"for %wZ\n",&pDevExt->DeviceName);
|
||
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
pDevExt->PtZfIntQueue = MmMapIoSpace(zf_int_queue_phys,
|
||
sizeof(struct INT_QUEUE),
|
||
FALSE);
|
||
if (pDevExt->PtZfIntQueue == NULL) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
pDevExt->DeviceObject,
|
||
PConfigData->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfigData->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_INT_QUEUE_NOT_MAPPED,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory IntQueue"
|
||
" for %wZ\n",&pDevExt->DeviceName);
|
||
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
if (!CyzDoesPortExist(
|
||
pDevExt,
|
||
&pDevExt->DeviceName
|
||
)) {
|
||
|
||
//
|
||
// We couldn't verify that there was actually a
|
||
// port. No need to log an error as the port exist
|
||
// code will log exactly why.
|
||
//
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "DoesPortExist test failed for "
|
||
"%wZ\n", &pDevExt->DeviceName);
|
||
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// Set up the default device control fields.
|
||
// Note that if the values are changed after
|
||
// the file is open, they do NOT revert back
|
||
// to the old value at file close.
|
||
//
|
||
|
||
pDevExt->SpecialChars.XonChar = CYZ_DEF_XON;
|
||
pDevExt->SpecialChars.XoffChar = CYZ_DEF_XOFF;
|
||
pDevExt->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
|
||
pDevExt->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
|
||
|
||
|
||
//
|
||
// Default Line control protocol. 7E1
|
||
//
|
||
// Seven data bits.
|
||
// Even parity.
|
||
// 1 Stop bits.
|
||
//
|
||
pDevExt->CommParity = C_PR_EVEN;
|
||
pDevExt->CommDataLen = C_DL_CS7 | C_DL_1STOP;
|
||
pDevExt->ValidDataMask = 0x7f;
|
||
pDevExt->CurrentBaud = 1200;
|
||
|
||
|
||
//
|
||
// We set up the default xon/xoff limits.
|
||
//
|
||
// This may be a bogus value. It looks like the BufferSize
|
||
// is not set up until the device is actually opened.
|
||
//
|
||
|
||
pDevExt->HandFlow.XoffLimit = pDevExt->BufferSize >> 3;
|
||
pDevExt->HandFlow.XonLimit = pDevExt->BufferSize >> 1;
|
||
|
||
pDevExt->BufferSizePt8 = ((3*(pDevExt->BufferSize>>2))+
|
||
(pDevExt->BufferSize>>4));
|
||
|
||
CyzDbgPrintEx(CYZDIAG1, " The default interrupt read buffer size is: %d\n"
|
||
"------ The XoffLimit is : %d\n"
|
||
"------ The XonLimit is : %d\n"
|
||
"------ The pt 8 size is : %d\n",
|
||
pDevExt->BufferSize, pDevExt->HandFlow.XoffLimit,
|
||
pDevExt->HandFlow.XonLimit, pDevExt->BufferSizePt8);
|
||
|
||
pDevExt->SupportedBauds = SERIAL_BAUD_075 | SERIAL_BAUD_110 |
|
||
SERIAL_BAUD_134_5 | SERIAL_BAUD_150 | SERIAL_BAUD_300 |
|
||
SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_1800 |
|
||
SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200 |
|
||
SERIAL_BAUD_9600 | SERIAL_BAUD_14400 | SERIAL_BAUD_19200 |
|
||
SERIAL_BAUD_38400 | SERIAL_BAUD_56K | SERIAL_BAUD_57600 |
|
||
SERIAL_BAUD_115200 | SERIAL_BAUD_128K | SERIAL_BAUD_USER;
|
||
|
||
//
|
||
// Mark this device as not being opened by anyone. We keep a
|
||
// variable around so that spurious interrupts are easily
|
||
// dismissed by the ISR.
|
||
//
|
||
|
||
pDevExt->DeviceIsOpened = FALSE;
|
||
|
||
//
|
||
// Store values into the extension for interval timing.
|
||
//
|
||
|
||
//
|
||
// If the interval timer is less than a second then come
|
||
// in with a short "polling" loop.
|
||
//
|
||
// For large (> then 2 seconds) use a 1 second poller.
|
||
//
|
||
|
||
pDevExt->ShortIntervalAmount.QuadPart = -1;
|
||
pDevExt->LongIntervalAmount.QuadPart = -10000000;
|
||
pDevExt->CutOverAmount.QuadPart = 200000000;
|
||
|
||
// Initialize for the Isr Dispatch
|
||
|
||
pDispatch = pDevExt->OurIsrContext;
|
||
#ifndef POLL
|
||
pDispatch->Extensions[pDevExt->PortIndex] = pDevExt;
|
||
pDispatch->PoweredOn[pDevExt->PortIndex] = TRUE;
|
||
#endif
|
||
|
||
if (firstTimeThisBoard) {
|
||
|
||
#ifdef POLL
|
||
ULONG intr_reg;
|
||
ULONG pollingCycle;
|
||
|
||
pollingCycle = 10; // default = 20ms
|
||
pDispatch->PollingTime.LowPart = pollingCycle * 10000;
|
||
pDispatch->PollingTime.HighPart = 0;
|
||
pDispatch->PollingTime = RtlLargeIntegerNegate(pDispatch->PollingTime);
|
||
pDispatch->PollingPeriod = pollingCycle;
|
||
KeInitializeSpinLock(&pDispatch->PollingLock);
|
||
KeInitializeTimer(&pDispatch->PollingTimer);
|
||
KeInitializeDpc(&pDispatch->PollingDpc, CyzPollingDpc, pDispatch);
|
||
KeInitializeEvent(&pDispatch->PendingDpcEvent, SynchronizationEvent, FALSE);
|
||
intr_reg = CYZ_READ_ULONG(&(pDevExt->Runtime)->intr_ctrl_stat);
|
||
//intr_reg |= (0x00030800UL);
|
||
intr_reg |= (0x00030000UL);
|
||
CYZ_WRITE_ULONG(&(pDevExt->Runtime)->intr_ctrl_stat,intr_reg);
|
||
#else
|
||
CyzResetBoard(pDevExt); //Shouldn't we put this line on the POLL version?
|
||
#endif
|
||
pDispatch->NChannels = CYZ_READ_ULONG(&(pDevExt->BoardCtrl)->n_channel);
|
||
|
||
}
|
||
|
||
#ifdef POLL
|
||
InterlockedIncrement(&pDispatch->PollingCount);
|
||
incPoll = TRUE;
|
||
#endif
|
||
|
||
//
|
||
// Common error path cleanup. If the status is
|
||
// bad, get rid of the device extension, device object
|
||
// and any memory associated with it.
|
||
//
|
||
|
||
ExtensionCleanup: ;
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
#ifdef POLL
|
||
if (incPoll) {
|
||
InterlockedDecrement(&pDispatch->PollingCount);
|
||
}
|
||
#else
|
||
if (pDispatch) {
|
||
pDispatch->Extensions[pDevExt->PortIndex] = NULL;
|
||
}
|
||
#endif
|
||
|
||
if (allocedDispatch) {
|
||
ExFreePool(pDevExt->OurIsrContext);
|
||
pDevExt->OurIsrContext = NULL;
|
||
}
|
||
|
||
if (pDevExt->Runtime) {
|
||
MmUnmapIoSpace(pDevExt->Runtime, PConfigData->RuntimeLength);
|
||
pDevExt->Runtime = NULL;
|
||
}
|
||
|
||
if (pDevExt->BoardCtrl) {
|
||
MmUnmapIoSpace(pDevExt->BoardCtrl, sizeof(struct BOARD_CTRL));
|
||
pDevExt->BoardCtrl = NULL;
|
||
}
|
||
|
||
if (pDevExt->ChCtrl) {
|
||
MmUnmapIoSpace(pDevExt->ChCtrl,sizeof(struct CH_CTRL));
|
||
pDevExt->ChCtrl = NULL;
|
||
}
|
||
|
||
if (pDevExt->BufCtrl) {
|
||
MmUnmapIoSpace(pDevExt->BufCtrl,sizeof(struct BUF_CTRL));
|
||
pDevExt->BufCtrl = NULL;
|
||
}
|
||
|
||
if (pDevExt->TxBufaddr) {
|
||
MmUnmapIoSpace(pDevExt->TxBufaddr,pDevExt->TxBufsize);
|
||
pDevExt->TxBufaddr = NULL;
|
||
}
|
||
|
||
if (pDevExt->RxBufaddr) {
|
||
MmUnmapIoSpace(pDevExt->RxBufaddr,pDevExt->RxBufsize);
|
||
pDevExt->RxBufaddr = NULL;
|
||
}
|
||
|
||
if (pDevExt->PtZfIntQueue) {
|
||
MmUnmapIoSpace(pDevExt->PtZfIntQueue,sizeof(struct INT_QUEUE));
|
||
pDevExt->PtZfIntQueue = NULL;
|
||
}
|
||
}
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
CyzDoesPortExist(
|
||
IN PCYZ_DEVICE_EXTENSION Extension,
|
||
IN PUNICODE_STRING InsertString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine examines several of what might be the serial device
|
||
registers. It ensures that the bits that should be zero are zero.
|
||
|
||
In addition, this routine will determine if the device supports
|
||
fifo's. If it does it will enable the fifo's and turn on a boolean
|
||
in the extension that indicates the fifo's presence.
|
||
|
||
NOTE: If there is indeed a serial port at the address specified
|
||
it will absolutely have interrupts inhibited upon return
|
||
from this routine.
|
||
|
||
NOTE: Since this routine should be called fairly early in
|
||
the device driver initialization, the only element
|
||
that needs to be filled in is the base register address.
|
||
|
||
NOTE: These tests all assume that this code is the only
|
||
code that is looking at these ports or this memory.
|
||
|
||
This is a not to unreasonable assumption even on
|
||
multiprocessor systems.
|
||
|
||
Arguments:
|
||
|
||
Extension - A pointer to a serial device extension.
|
||
InsertString - String to place in an error log entry.
|
||
|
||
Return Value:
|
||
|
||
Will return true if the port really exists, otherwise it
|
||
will return false.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
CyzResetBoard( PCYZ_DEVICE_EXTENSION Extension )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine examines several of what might be the serial device
|
||
registers. It ensures that the bits that should be zero are zero.
|
||
|
||
In addition, this routine will determine if the device supports
|
||
fifo's. If it does it will enable the fifo's and turn on a boolean
|
||
in the extension that indicates the fifo's presence.
|
||
|
||
NOTE: If there is indeed a serial port at the address specified
|
||
it will absolutely have interrupts inhibited upon return
|
||
from this routine.
|
||
|
||
NOTE: Since this routine should be called fairly early in
|
||
the device driver initialization, the only element
|
||
that needs to be filled in is the base register address.
|
||
|
||
NOTE: These tests all assume that this code is the only
|
||
code that is looking at these ports or this memory.
|
||
|
||
This is a not to unreasonable assumption even on
|
||
multiprocessor systems.
|
||
|
||
Arguments:
|
||
|
||
Extension - A pointer to a serial device extension.
|
||
InsertString - String to place in an error log entry.
|
||
|
||
Return Value:
|
||
|
||
Will return true if the port really exists, otherwise it
|
||
will return false.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
#ifndef POLL
|
||
//CyzIssueCmd(Extension,C_CM_SETNNDT,20L,FALSE); Removed. Let's firmware calculate NNDT.
|
||
#endif
|
||
|
||
//CyzIssueCmd(Extension,C_CM_RESET,0L,FALSE); // Added in 1.0.0.11
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
CyzReset(
|
||
IN PVOID Context
|
||
)
|
||
/*--------------------------------------------------------------------------
|
||
CyzReset()
|
||
|
||
Routine Description: This places the hardware in a standard
|
||
configuration. This assumes that it is called at interrupt level.
|
||
|
||
Arguments:
|
||
|
||
Context - The device extension for serial device being managed.
|
||
|
||
Return Value: Always FALSE.
|
||
--------------------------------------------------------------------------*/
|
||
{
|
||
PCYZ_DEVICE_EXTENSION extension = Context;
|
||
struct CH_CTRL *ch_ctrl = extension->ChCtrl;
|
||
struct BUF_CTRL *buf_ctrl = extension->BufCtrl;
|
||
CYZ_IOCTL_BAUD s;
|
||
|
||
//For interrupt mode: extension->RxFifoTriggerUsed = FALSE; (from cyyport)
|
||
|
||
// set the line control, modem control, and the baud to what they should be.
|
||
|
||
CyzSetLineControl(extension);
|
||
|
||
CyzSetupNewHandFlow(extension,&extension->HandFlow);
|
||
|
||
CyzHandleModemUpdate(extension,FALSE,0);
|
||
|
||
s.Extension = extension;
|
||
s.Baud = extension->CurrentBaud;
|
||
CyzSetBaud(&s);
|
||
|
||
//This flag is configurable from the Advanced Port Settings.
|
||
//extension->ReturnStatusAfterFwEmpty = TRUE; // We will loose performance, but it will be
|
||
// // closer to serial driver.
|
||
extension->ReturnWriteStatus = FALSE;
|
||
extension->CmdFailureLog = TRUE;
|
||
|
||
// Enable port
|
||
CYZ_WRITE_ULONG(&ch_ctrl->op_mode,C_CH_ENABLE);
|
||
#ifdef POLL
|
||
CYZ_WRITE_ULONG(&ch_ctrl->intr_enable,C_IN_MDCD | C_IN_MCTS | C_IN_MRI
|
||
| C_IN_MDSR | C_IN_RXBRK | C_IN_PR_ERROR
|
||
| C_IN_FR_ERROR | C_IN_OVR_ERROR | C_IN_RXOFL
|
||
| C_IN_IOCTLW | C_IN_TXFEMPTY);
|
||
#else
|
||
//CYZ_WRITE_ULONG(&buf_ctrl->rx_threshold,1024);
|
||
CYZ_WRITE_ULONG(&ch_ctrl->intr_enable,C_IN_MDCD | C_IN_MCTS | C_IN_MRI
|
||
| C_IN_MDSR | C_IN_RXBRK | C_IN_PR_ERROR
|
||
| C_IN_FR_ERROR | C_IN_OVR_ERROR | C_IN_RXOFL
|
||
| C_IN_IOCTLW | C_IN_TXBEMPTY //1.0.0.11: C_IN_TXBEMPTY OR C_IN_TXFEMPTY?
|
||
| C_IN_RXHIWM | C_IN_RXNNDT | C_IN_TXLOWWM);
|
||
#endif
|
||
//ToDo: Enable C_IN_IOCTLW in the interrupt version.
|
||
|
||
CyzIssueCmd(extension,C_CM_IOCTLW,0L,FALSE);
|
||
|
||
extension->HoldingEmpty = TRUE;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
VOID
|
||
CyzUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
/*--------------------------------------------------------------------------
|
||
CyzUnload()
|
||
|
||
Description: Cleans up all of the memory associated with the
|
||
Device Objects created by the driver.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - A pointer to the driver object.
|
||
|
||
Return Value: None.
|
||
--------------------------------------------------------------------------*/
|
||
{
|
||
PVOID lockPtr;
|
||
|
||
PAGED_CODE();
|
||
|
||
lockPtr = MmLockPagableCodeSection(CyzUnload);
|
||
|
||
//
|
||
// Unnecessary since our BSS is going away, but do it anyhow to be safe
|
||
//
|
||
|
||
CyzGlobals.PAGESER_Handle = NULL;
|
||
|
||
if (CyzGlobals.RegistryPath.Buffer != NULL) {
|
||
ExFreePool(CyzGlobals.RegistryPath.Buffer);
|
||
CyzGlobals.RegistryPath.Buffer = NULL;
|
||
}
|
||
|
||
#if DBG
|
||
SerialLogFree();
|
||
#endif
|
||
|
||
CyzDbgPrintEx(CYZDIAG3, "In CyzUnload\n");
|
||
|
||
MmUnlockPagableImageSection(lockPtr);
|
||
|
||
}
|
||
|
||
|
||
CYZ_MEM_COMPARES
|
||
CyzMemCompare(
|
||
IN PHYSICAL_ADDRESS A,
|
||
IN ULONG SpanOfA,
|
||
IN PHYSICAL_ADDRESS B,
|
||
IN ULONG SpanOfB
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compare two phsical address.
|
||
|
||
Arguments:
|
||
|
||
A - One half of the comparison.
|
||
|
||
SpanOfA - In units of bytes, the span of A.
|
||
|
||
B - One half of the comparison.
|
||
|
||
SpanOfB - In units of bytes, the span of B.
|
||
|
||
|
||
Return Value:
|
||
|
||
The result of the comparison.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LARGE_INTEGER a;
|
||
LARGE_INTEGER b;
|
||
|
||
LARGE_INTEGER lower;
|
||
ULONG lowerSpan;
|
||
LARGE_INTEGER higher;
|
||
|
||
//PAGED_CODE(); Non paged because it can be called during CyzLogError, which is non paged now.
|
||
|
||
a = A;
|
||
b = B;
|
||
|
||
if (a.QuadPart == b.QuadPart) {
|
||
|
||
return AddressesAreEqual;
|
||
|
||
}
|
||
|
||
if (a.QuadPart > b.QuadPart) {
|
||
|
||
higher = a;
|
||
lower = b;
|
||
lowerSpan = SpanOfB;
|
||
|
||
} else {
|
||
|
||
higher = b;
|
||
lower = a;
|
||
lowerSpan = SpanOfA;
|
||
|
||
}
|
||
|
||
if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) {
|
||
|
||
return AddressesAreDisjoint;
|
||
|
||
}
|
||
|
||
return AddressesOverlap;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
CyzFindInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfig)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function discovers what type of controller is responsible for
|
||
the given port and initializes the controller and port.
|
||
|
||
Arguments:
|
||
|
||
PDevObj - Pointer to the devobj for the port we are about to init.
|
||
|
||
PConfig - Pointer to configuration data for the port we are about to init.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS on success, appropriate error value on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PCYZ_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
||
PDEVICE_OBJECT pDeviceObject;
|
||
PCYZ_DEVICE_EXTENSION pExtension;
|
||
PHYSICAL_ADDRESS serialPhysicalMax;
|
||
PLIST_ENTRY pCurDevObj;
|
||
NTSTATUS status;
|
||
KIRQL oldIrql;
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzFindInitController(%X, %X)\n",
|
||
PDevObj, PConfig);
|
||
|
||
serialPhysicalMax.LowPart = (ULONG)~0;
|
||
serialPhysicalMax.HighPart = ~0;
|
||
|
||
#ifdef POLL
|
||
CyzDbgPrintEx(CYZDIAG1, "Attempting to init %wZ\n"
|
||
"------- Runtime Memory is %x\n"
|
||
"------- Board Memory is %x\n"
|
||
"------- BusNumber is %d\n"
|
||
"------- BusType is %d\n"
|
||
"------- Runtime AddressSpace is %d\n"
|
||
"------- Board AddressSpace is %d\n",
|
||
&pDevExt->DeviceName,
|
||
PConfig->PhysicalRuntime.LowPart,
|
||
PConfig->PhysicalBoardMemory.LowPart,
|
||
PConfig->BusNumber,
|
||
PConfig->InterfaceType,
|
||
PConfig->RuntimeAddressSpace,
|
||
PConfig->BoardMemoryAddressSpace);
|
||
#else
|
||
CyzDbgPrintEx(CYZDIAG1, "Attempting to init %wZ\n"
|
||
"------- Runtime Memory is %x\n"
|
||
"------- Board Memory is %x\n"
|
||
"------- BusNumber is %d\n"
|
||
"------- BusType is %d\n"
|
||
"------- Runtime AddressSpace is %d\n"
|
||
"------- Board AddressSpace is %d\n"
|
||
"------- Interrupt Mode is %d\n",
|
||
&pDevExt->DeviceName,
|
||
PConfig->PhysicalRuntime.LowPart,
|
||
PConfig->PhysicalBoardMemory.LowPart,
|
||
PConfig->BusNumber,
|
||
PConfig->InterfaceType,
|
||
PConfig->RuntimeAddressSpace,
|
||
PConfig->BoardMemoryAddressSpace,
|
||
PConfig->InterruptMode);
|
||
#endif
|
||
|
||
//
|
||
// We don't support any boards whose memory wraps around
|
||
// the physical address space.
|
||
//
|
||
|
||
//*****************************************************
|
||
// error injection
|
||
// if (CyzMemCompare(
|
||
// PConfig->PhysicalRuntime,
|
||
// PConfig->RuntimeLength,
|
||
// serialPhysicalMax,
|
||
// (ULONG)0
|
||
// ) == AddressesAreDisjoint)
|
||
//*****************************************************
|
||
if (CyzMemCompare(
|
||
PConfig->PhysicalRuntime,
|
||
PConfig->RuntimeLength,
|
||
serialPhysicalMax,
|
||
(ULONG)0
|
||
) != AddressesAreDisjoint) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
NULL,
|
||
PConfig->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfig->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_RUNTIME_MEMORY_TOO_HIGH,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
|
||
"------ Runtime memory wraps around physical memory\n",
|
||
&pDevExt->DeviceName);
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
|
||
}
|
||
|
||
//*****************************************************
|
||
// error injection
|
||
// if (CyzMemCompare(
|
||
// PConfig->PhysicalBoardMemory,
|
||
// PConfig->BoardMemoryLength,
|
||
// serialPhysicalMax,
|
||
// (ULONG)0
|
||
// ) == AddressesAreDisjoint)
|
||
//*****************************************************
|
||
if (CyzMemCompare(
|
||
PConfig->PhysicalBoardMemory,
|
||
PConfig->BoardMemoryLength,
|
||
serialPhysicalMax,
|
||
(ULONG)0
|
||
) != AddressesAreDisjoint) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
NULL,
|
||
PConfig->PhysicalBoardMemory,
|
||
CyzPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfig->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_BOARD_MEMORY_TOO_HIGH,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
|
||
"------ board memory wraps around physical memory\n",
|
||
&pDevExt->DeviceName);
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Make sure that the Runtime memory addresses don't
|
||
// overlap the DP memory addresses for PCI cards
|
||
//
|
||
|
||
if (CyzMemCompare(
|
||
PConfig->PhysicalRuntime,
|
||
PConfig->RuntimeLength,
|
||
CyzPhysicalZero,
|
||
(ULONG)0
|
||
) != AddressesAreEqual) {
|
||
|
||
//*****************************************************
|
||
// error injection
|
||
// if (CyzMemCompare(
|
||
// PConfig->PhysicalRuntime,
|
||
// PConfig->RuntimeLength,
|
||
// PConfig->PhysicalBoardMemory,
|
||
// PConfig->BoardMemoryLength
|
||
// ) == AddressesAreDisjoint)
|
||
//*****************************************************
|
||
if (CyzMemCompare(
|
||
PConfig->PhysicalRuntime,
|
||
PConfig->RuntimeLength,
|
||
PConfig->PhysicalBoardMemory,
|
||
PConfig->BoardMemoryLength
|
||
) != AddressesAreDisjoint) {
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
NULL,
|
||
PConfig->PhysicalBoardMemory,
|
||
PConfig->PhysicalRuntime,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfig->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_BOTH_MEMORY_CONFLICT,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
|
||
"------ Runtime memory wraps around Board memory\n",
|
||
&pDevExt->DeviceName);
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Now, we will check if this is a port on a multiport card.
|
||
// The conditions are same BoardMemory set and same IRQL/Vector
|
||
//
|
||
|
||
//
|
||
// Loop through all previously attached devices
|
||
//
|
||
|
||
KeAcquireSpinLock(&CyzGlobals.GlobalsSpinLock, &oldIrql);
|
||
|
||
if (!IsListEmpty(&CyzGlobals.AllDevObjs)) {
|
||
pCurDevObj = CyzGlobals.AllDevObjs.Flink;
|
||
pExtension = CONTAINING_RECORD(pCurDevObj, CYZ_DEVICE_EXTENSION,
|
||
AllDevObjs);
|
||
} else {
|
||
pCurDevObj = NULL;
|
||
pExtension = NULL;
|
||
}
|
||
|
||
KeReleaseSpinLock(&CyzGlobals.GlobalsSpinLock, oldIrql);
|
||
|
||
//
|
||
// If there is an interrupt status then we
|
||
// loop through the config list again to look
|
||
// for a config record with the same interrupt
|
||
// status (on the same bus).
|
||
//
|
||
|
||
if (pCurDevObj != NULL) {
|
||
|
||
ASSERT(pExtension != NULL);
|
||
|
||
//
|
||
// We have an interrupt status. Loop through all
|
||
// previous records, look for an existing interrupt status
|
||
// the same as the current interrupt status.
|
||
//
|
||
do {
|
||
|
||
//
|
||
// We only care about this list if the elements are on the
|
||
// same bus as this new entry. (Their interrupts must therefore
|
||
// also be the on the same bus. We will check that momentarily).
|
||
//
|
||
// We don't check here for the dissimilar interrupts since that
|
||
// could cause us to miss the error of having the same interrupt
|
||
// status but different interrupts - which is bizzare.
|
||
//
|
||
|
||
if ((pExtension->InterfaceType == PConfig->InterfaceType) &&
|
||
(pExtension->BoardMemoryAddressSpace == PConfig->BoardMemoryAddressSpace) &&
|
||
(pExtension->BusNumber == PConfig->BusNumber)) {
|
||
|
||
//
|
||
// If the board memory is the same, then same card.
|
||
//
|
||
|
||
if (CyzMemCompare(
|
||
pExtension->OriginalBoardMemory,
|
||
pExtension->BoardMemoryLength,
|
||
PConfig->PhysicalBoardMemory,
|
||
PConfig->BoardMemoryLength
|
||
) == AddressesAreEqual) {
|
||
#ifndef POLL
|
||
//
|
||
// Same card. Now make sure that they
|
||
// are using the same interrupt parameters.
|
||
//
|
||
|
||
// BUILD 2128: OriginalIrql replaced by TrIrql and Irql; same for OriginalVector
|
||
if ((PConfig->TrIrql != pExtension->Irql) ||
|
||
(PConfig->TrVector != pExtension->Vector)) {
|
||
|
||
//
|
||
// We won't put this into the configuration
|
||
// list.
|
||
//
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
NULL,
|
||
PConfig->PhysicalBoardMemory,
|
||
pExtension->OriginalBoardMemory,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfig->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_MULTI_INTERRUPT_CONFLICT,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
pExtension->DeviceName.Length
|
||
+ sizeof(WCHAR),
|
||
pExtension->DeviceName.Buffer
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Configuration error "
|
||
"for %wZ\n"
|
||
"------- Same multiport - different "
|
||
"interrupts\n", &pDevExt->DeviceName);
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
|
||
}
|
||
#endif
|
||
//
|
||
// PCI board. Make sure the PCI memory addresses are equal.
|
||
//
|
||
if (CyzMemCompare(
|
||
pExtension->OriginalRuntimeMemory,
|
||
pExtension->RuntimeLength,
|
||
PConfig->PhysicalRuntime,
|
||
PConfig->RuntimeLength
|
||
) != AddressesAreEqual) {
|
||
//*****************************************************
|
||
// error injection
|
||
// if (CyzMemCompare(
|
||
// pExtension->OriginalRuntimeMemory,
|
||
// pExtension->RuntimeLength,
|
||
// PConfig->PhysicalRuntime,
|
||
// PConfig->RuntimeLength
|
||
// ) == AddressesAreEqual)
|
||
//*****************************************************
|
||
|
||
CyzLogError(
|
||
PDevObj->DriverObject,
|
||
NULL,
|
||
PConfig->PhysicalRuntime,
|
||
pExtension->OriginalRuntimeMemory,
|
||
0,
|
||
0,
|
||
0,
|
||
PConfig->PortIndex+1,
|
||
STATUS_SUCCESS,
|
||
CYZ_MULTI_RUNTIME_CONFLICT,
|
||
pDevExt->DeviceName.Length+sizeof(WCHAR),
|
||
pDevExt->DeviceName.Buffer,
|
||
pExtension->DeviceName.Length
|
||
+ sizeof(WCHAR),
|
||
pExtension->DeviceName.Buffer
|
||
);
|
||
|
||
CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Configuration error "
|
||
"for %wZ\n"
|
||
"------- Same multiport - different "
|
||
"Runtime addresses\n", &pDevExt->DeviceName);
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
//
|
||
// We should never get this far on a restart since we don't
|
||
// support stop on ISA multiport devices!
|
||
//
|
||
|
||
ASSERT(pDevExt->PNPState == CYZ_PNP_ADDED);
|
||
|
||
//
|
||
//
|
||
// Initialize the device as part of a multiport board
|
||
//
|
||
|
||
CyzDbgPrintEx(CYZDIAG1, "Aha! It is a multiport node\n");
|
||
CyzDbgPrintEx(CYZDIAG1, "Matched to %x\n", pExtension);
|
||
|
||
status = CyzInitMultiPort(pExtension, PConfig, PDevObj);
|
||
|
||
//
|
||
// A port can be one of two things:
|
||
// A non-root on a multiport
|
||
// A root on a multiport
|
||
//
|
||
// It can only share an interrupt if it is a root.
|
||
// Since this was a non-root we don't need to check
|
||
// if it shares an interrupt and we can return.
|
||
//
|
||
return status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// No match, check some more
|
||
//
|
||
|
||
KeAcquireSpinLock(&CyzGlobals.GlobalsSpinLock, &oldIrql);
|
||
|
||
pCurDevObj = pCurDevObj->Flink;
|
||
if (pCurDevObj != NULL) {
|
||
pExtension = CONTAINING_RECORD(pCurDevObj,CYZ_DEVICE_EXTENSION,
|
||
AllDevObjs);
|
||
}
|
||
|
||
KeReleaseSpinLock(&CyzGlobals.GlobalsSpinLock, oldIrql);
|
||
|
||
} while (pCurDevObj != NULL && pCurDevObj != &CyzGlobals.AllDevObjs);
|
||
}
|
||
|
||
|
||
CyzDbgPrintEx(CYZDIAG1, "Aha! It is a first multi\n");
|
||
|
||
status = CyzInitController(PDevObj, PConfig);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
CyzCommError(
|
||
IN PKDPC Dpc,
|
||
IN PVOID DeferredContext,
|
||
IN PVOID SystemContext1,
|
||
IN PVOID SystemContext2
|
||
)
|
||
/*--------------------------------------------------------------------------
|
||
CyzComError()
|
||
|
||
Routine Description: This routine is invoked at dpc level in response
|
||
to a comm error. All comm errors kill all read and writes
|
||
|
||
Arguments:
|
||
|
||
Dpc - Not Used.
|
||
DeferredContext - points to the device object.
|
||
SystemContext1 - Not Used.
|
||
SystemContext2 - Not Used.
|
||
|
||
Return Value: None.
|
||
--------------------------------------------------------------------------*/
|
||
{
|
||
PCYZ_DEVICE_EXTENSION Extension = DeferredContext;
|
||
|
||
UNREFERENCED_PARAMETER(SystemContext1);
|
||
UNREFERENCED_PARAMETER(SystemContext2);
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzCommError(%X)\n", Extension);
|
||
|
||
CyzKillAllReadsOrWrites(
|
||
Extension->DeviceObject,
|
||
&Extension->WriteQueue,
|
||
&Extension->CurrentWriteIrp
|
||
);
|
||
|
||
CyzKillAllReadsOrWrites(
|
||
Extension->DeviceObject,
|
||
&Extension->ReadQueue,
|
||
&Extension->CurrentReadIrp
|
||
);
|
||
CyzDpcEpilogue(Extension, Dpc);
|
||
|
||
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzCommError\n");
|
||
}
|
||
|