mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1447 lines
39 KiB
1447 lines
39 KiB
/*****************************************************************************
|
|
*
|
|
* Copyright (c) 1996-1999 Microsoft Corporation
|
|
*
|
|
* @doc
|
|
* @module irsir.c | IrSIR NDIS Miniport Driver
|
|
* @comm
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Author: Scott Holden (sholden)
|
|
*
|
|
* Date: 10/3/1996 (created)
|
|
*
|
|
* Contents:
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "irsir.h"
|
|
|
|
VOID
|
|
ResetCallback(
|
|
PIR_WORK_ITEM pWorkItem
|
|
);
|
|
|
|
NDIS_STATUS
|
|
ResetIrDevice(
|
|
PIR_DEVICE pThisDev
|
|
);
|
|
|
|
VOID
|
|
StopWorkerThread(
|
|
PIR_DEVICE pThisDev
|
|
);
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
DriverEntry(
|
|
PDRIVER_OBJECT DriverObject,
|
|
PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
#pragma NDIS_INIT_FUNCTION(DriverEntry)
|
|
|
|
#pragma alloc_text(PAGE,ResetCallback)
|
|
#pragma alloc_text(PAGE,IrsirHalt)
|
|
#pragma alloc_text(PAGE,ResetIrDevice)
|
|
#pragma alloc_text(PAGE,IrsirInitialize)
|
|
#pragma alloc_text(PAGE,IrsirHalt)
|
|
#pragma alloc_text(PAGE,PassiveLevelThread)
|
|
#pragma alloc_text(PAGE,SetIrFunctions)
|
|
#pragma alloc_text(PAGE,StopWorkerThread)
|
|
|
|
|
|
//
|
|
// Global list of device objects and a spin lock to interleave access
|
|
// to the global queue.
|
|
//
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
int DbgSettings =
|
|
//DBG_PNP |
|
|
//DBG_TIME |
|
|
//DBG_DBG |
|
|
//DBG_STAT |
|
|
//DBG_FUNCTION |
|
|
DBG_ERROR |
|
|
DBG_WARN |
|
|
//DBG_OUT |
|
|
0;
|
|
|
|
#endif
|
|
|
|
// We use these timeouts when we just have to return soon.
|
|
SERIAL_TIMEOUTS SerialTimeoutsInit =
|
|
{
|
|
30, // ReadIntervalTimeout
|
|
0, // ReadTotalTimeoutMultiplier
|
|
250, // ReadTotalTimeoutConstant
|
|
0, // WriteTotalTimeoutMultiplier
|
|
20*1000 // WriteTotalTimeoutConstant
|
|
};
|
|
|
|
// We use the timeouts while we're running, and we want to return less frequently.
|
|
SERIAL_TIMEOUTS SerialTimeoutsIdle =
|
|
{
|
|
MAXULONG, // ReadIntervalTimeout
|
|
0, // ReadTotalTimeoutMultiplier
|
|
10, // ReadTotalTimeoutConstant
|
|
0, // WriteTotalTimeoutMultiplier
|
|
20*1000 // WriteTotalTimeoutConstant
|
|
};
|
|
#if IRSIR_EVENT_DRIVEN
|
|
// We use the timeouts while we're running, and we want to return less frequently.
|
|
SERIAL_TIMEOUTS SerialTimeoutsActive =
|
|
{
|
|
MAXULONG, // ReadIntervalTimeout
|
|
0, // ReadTotalTimeoutMultiplier
|
|
0, // ReadTotalTimeoutConstant
|
|
0, // WriteTotalTimeoutMultiplier
|
|
0 // WriteTotalTimeoutConstant
|
|
};
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: DriverEntry
|
|
*
|
|
* Synopsis: register driver entry functions with NDIS
|
|
*
|
|
* Arguments: DriverObject - the driver object being initialized
|
|
* RegistryPath - registry path of the driver
|
|
*
|
|
* Returns: value returned by NdisMRegisterMiniport
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
* This routine runs at IRQL PASSIVE_LEVEL.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
//
|
|
// Mark the DriverEntry function to run once during initialization.
|
|
//
|
|
|
|
|
|
|
|
#ifndef MAX_PATH
|
|
#define MAX_PATH 2048
|
|
#endif
|
|
|
|
|
|
NDIS_STATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT pDriverObject,
|
|
IN PUNICODE_STRING pRegistryPath
|
|
)
|
|
{
|
|
NDIS_STATUS status;
|
|
#if NDIS_MAJOR_VERSION < 5
|
|
NDIS40_MINIPORT_CHARACTERISTICS characteristics;
|
|
#else
|
|
NDIS50_MINIPORT_CHARACTERISTICS characteristics;
|
|
#endif
|
|
NDIS_HANDLE hWrapper;
|
|
|
|
#if MEM_CHECKING
|
|
InitMemory();
|
|
#endif
|
|
DEBUGMSG(DBG_FUNC, ("+DriverEntry(irsir)\n"));
|
|
|
|
NdisMInitializeWrapper(
|
|
&hWrapper,
|
|
pDriverObject,
|
|
pRegistryPath,
|
|
NULL
|
|
);
|
|
|
|
NdisZeroMemory(&characteristics, sizeof(characteristics));
|
|
|
|
characteristics.MajorNdisVersion = (UCHAR)NDIS_MAJOR_VERSION;
|
|
characteristics.MinorNdisVersion = (UCHAR)NDIS_MINOR_VERSION;
|
|
characteristics.Reserved = 0;
|
|
|
|
characteristics.HaltHandler = IrsirHalt;
|
|
characteristics.InitializeHandler = IrsirInitialize;
|
|
characteristics.QueryInformationHandler = IrsirQueryInformation;
|
|
characteristics.SetInformationHandler = IrsirSetInformation;
|
|
characteristics.ResetHandler = IrsirReset;
|
|
|
|
//
|
|
// For now we will allow NDIS to send only one packet at a time.
|
|
//
|
|
|
|
characteristics.SendHandler = IrsirSend;
|
|
characteristics.SendPacketsHandler = NULL;
|
|
|
|
//
|
|
// We don't use NdisMIndicateXxxReceive function, so we will
|
|
// need a ReturnPacketHandler to retrieve our packet resources.
|
|
//
|
|
|
|
characteristics.ReturnPacketHandler = IrsirReturnPacket;
|
|
characteristics.TransferDataHandler = NULL;
|
|
|
|
//
|
|
// NDIS never calls the ReconfigureHandler.
|
|
//
|
|
|
|
characteristics.ReconfigureHandler = NULL;
|
|
|
|
//
|
|
// Let NDIS handle the hangs for now.
|
|
//
|
|
// If a CheckForHangHandler is supplied, NDIS will call it every two
|
|
// seconds (by default) or at a driver specified interval.
|
|
//
|
|
// When not supplied, NDIS will conclude that the miniport is hung:
|
|
// 1) a send packet has been pending longer than twice the
|
|
// timeout period
|
|
// 2) a request to IrsirQueryInformation or IrsirSetInformation
|
|
// is not completed in a period equal to twice the timeout
|
|
// period.
|
|
// NDIS will keep track of the NdisMSendComplete calls and probably do
|
|
// a better job of ensuring the miniport is not hung.
|
|
//
|
|
// If NDIS detects that the miniport is hung, NDIS calls
|
|
// IrsirReset.
|
|
//
|
|
|
|
characteristics.CheckForHangHandler = NULL;
|
|
|
|
//
|
|
// This miniport driver does not handle interrupts.
|
|
//
|
|
|
|
characteristics.HandleInterruptHandler = NULL;
|
|
characteristics.ISRHandler = NULL;
|
|
characteristics.DisableInterruptHandler = NULL;
|
|
characteristics.EnableInterruptHandler = NULL;
|
|
|
|
//
|
|
// This miniport does not control a busmaster DMA with
|
|
// NdisMAllocateShareMemoryAsysnc, AllocateCompleteHandler won't be
|
|
// called from NDIS.
|
|
//
|
|
|
|
characteristics.AllocateCompleteHandler = NULL;
|
|
|
|
//
|
|
// Need to initialize the ir device object queue and the spin lock
|
|
// to interleave access to the queue at this point, since after we
|
|
// return, the driver will only deal with the device level.
|
|
//
|
|
|
|
|
|
status = NdisMRegisterMiniport(
|
|
hWrapper,
|
|
(PNDIS_MINIPORT_CHARACTERISTICS)&characteristics,
|
|
sizeof(characteristics)
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" NdisMRegisterMiniport failed. Returned 0x%.8x.\n", status));
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC, ("-DriverEntry(irsir)\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
// Provide some default functions for dongle handling.
|
|
|
|
NDIS_STATUS UnknownDongleInit(PDEVICE_OBJECT NotUsed)
|
|
{
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
NDIS_STATUS UnknownDongleQueryCaps(PDONGLE_CAPABILITIES NotUsed)
|
|
{
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
void UnknownDongleDeinit(PDEVICE_OBJECT NotUsed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NDIS_STATUS UnknownDongleSetSpeed(PDEVICE_OBJECT pSerialDevObj,
|
|
UINT bitsPerSec,
|
|
UINT currentSpeed
|
|
)
|
|
{
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
|
|
NTSTATUS SetIrFunctions(PIR_DEVICE pThisDev)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
//
|
|
// Need to initialize the dongle code.
|
|
//
|
|
switch (pThisDev->transceiverType)
|
|
{
|
|
case STANDARD_UART:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- UART\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = StdUart_QueryCaps;
|
|
pThisDev->dongle.Initialize = StdUart_Init;
|
|
pThisDev->dongle.SetSpeed = StdUart_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = StdUart_Deinit;
|
|
|
|
break;
|
|
|
|
case ESI_9680:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- ESI_9680\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = ESI_QueryCaps;
|
|
pThisDev->dongle.Initialize = ESI_Init;
|
|
pThisDev->dongle.SetSpeed = ESI_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = ESI_Deinit;
|
|
|
|
break;
|
|
|
|
case PARALLAX:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- PARALLAX\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = PARALLAX_QueryCaps;
|
|
pThisDev->dongle.Initialize = PARALLAX_Init;
|
|
pThisDev->dongle.SetSpeed = PARALLAX_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = PARALLAX_Deinit;
|
|
|
|
break;
|
|
|
|
case ACTISYS_200L:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- ACTISYS 200L\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = ACT200L_QueryCaps;
|
|
pThisDev->dongle.Initialize = ACT200L_Init;
|
|
pThisDev->dongle.SetSpeed = ACT200L_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = ACT200L_Deinit;
|
|
|
|
break;
|
|
|
|
case ACTISYS_220L:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- ACTISYS 220L\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = ACT220L_QueryCaps;
|
|
pThisDev->dongle.Initialize = ACT220L_Init;
|
|
pThisDev->dongle.SetSpeed = ACT220L_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = ACT220L_Deinit;
|
|
|
|
break;
|
|
|
|
case ACTISYS_220LPLUS:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- ACTISYS 220L\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = ACT220LPlus_QueryCaps;
|
|
pThisDev->dongle.Initialize = ACT220L_Init;
|
|
pThisDev->dongle.SetSpeed = ACT220L_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = ACT220L_Deinit;
|
|
|
|
break;
|
|
|
|
case TEKRAM_IRMATE_210:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- TEKRAM IRMATE 210 or PUMA\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = TEKRAM_QueryCaps;
|
|
pThisDev->dongle.Initialize = TEKRAM_Init;
|
|
pThisDev->dongle.SetSpeed = TEKRAM_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = TEKRAM_Deinit;
|
|
|
|
break;
|
|
|
|
|
|
case AMP_PHASIR:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- AMP PHASIR or CRYSTAL\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = Crystal_QueryCaps;
|
|
pThisDev->dongle.Initialize = Crystal_Init;
|
|
pThisDev->dongle.SetSpeed = Crystal_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = Crystal_Deinit;
|
|
|
|
break;
|
|
|
|
case TEMIC_TOIM3232:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- TEMIC TOIM3232\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = TEMIC_QueryCaps;
|
|
pThisDev->dongle.Initialize = TEMIC_Init;
|
|
pThisDev->dongle.SetSpeed = TEMIC_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = TEMIC_Deinit;
|
|
|
|
break;
|
|
|
|
case GIRBIL:
|
|
DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- GIRBIL\n", pThisDev->transceiverType));
|
|
pThisDev->dongle.QueryCaps = GIRBIL_QueryCaps;
|
|
pThisDev->dongle.Initialize = GIRBIL_Init;
|
|
pThisDev->dongle.SetSpeed = GIRBIL_SetSpeed;
|
|
pThisDev->dongle.Deinitialize = GIRBIL_Deinit;
|
|
|
|
break;
|
|
|
|
// case ADAPTEC:
|
|
// case CRYSTAL:
|
|
// case NSC_DEMO_BD:
|
|
|
|
default:
|
|
DEBUGMSG(DBG_ERROR, (" Failure: Tranceiver type is NOT supported!\n"));
|
|
|
|
pThisDev->dongle.QueryCaps = UnknownDongleQueryCaps;
|
|
pThisDev->dongle.Initialize = UnknownDongleInit;
|
|
pThisDev->dongle.SetSpeed = UnknownDongleSetSpeed;
|
|
pThisDev->dongle.Deinitialize = UnknownDongleDeinit;
|
|
// The dongle functions have already been set to stubs in
|
|
// InitializeDevice().
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: IrsirInitialize
|
|
*
|
|
* Synopsis: Initializes the NIC (serial.sys) and allocates all resources
|
|
* required to carry out network io operations.
|
|
*
|
|
* Arguments: OpenErrorStatus - allows IrsirInitialize to return additional
|
|
* status code NDIS_STATUS_xxx if returning
|
|
* NDIS_STATUS_OPEN_FAILED
|
|
* SelectedMediumIndex - specifies to NDIS the medium type the
|
|
* driver uses
|
|
* MediumArray - array of NdisMediumXXX the driver can choose
|
|
* MediumArraySize
|
|
* MiniportAdapterHandle - handle identifying miniport's NIC
|
|
* WrapperConfigurationContext - used with Ndis config and init
|
|
* routines
|
|
*
|
|
* Returns: NDIS_STATUS_SUCCESS if properly configure and resources allocated
|
|
* NDIS_STATUS_FAILURE, otherwise
|
|
* more specific failures:
|
|
* NDIS_STATUS_UNSUPPORTED_MEDIA - driver can't support any medium
|
|
* NDIS_STATUS_ADAPTER_NOT_FOUND - NdisOpenConfiguration or
|
|
* NdisReadConfiguration failed
|
|
* NDIS_STATUS_OPEN_FAILED - failed to open serial.sys
|
|
* NDIS_STATUS_NOT_ACCEPTED - serial.sys does not accept the
|
|
* configuration
|
|
* NDIS_STATUS_RESOURCES - could not claim sufficient
|
|
* resources
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes: NDIS will not submit requests until this is complete.
|
|
*
|
|
* This routine runs at IRQL PASSIVE_LEVEL.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
|
|
NDIS_STATUS
|
|
IrsirInitialize(
|
|
OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE NdisAdapterHandle,
|
|
IN NDIS_HANDLE WrapperConfigurationContext
|
|
)
|
|
{
|
|
UINT i;
|
|
PIR_DEVICE pThisDev = NULL;
|
|
SERIAL_LINE_CONTROL serialLineControl;
|
|
SERIAL_TIMEOUTS serialTimeouts;
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
ULONG bitsPerSec = 9600;
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+IrsirInitialize\n"));
|
|
|
|
//
|
|
// Search for the irda medium in the medium array.
|
|
//
|
|
|
|
for (i = 0; i < MediumArraySize; i++)
|
|
{
|
|
if (MediumArray[i] == NdisMediumIrda)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i < MediumArraySize)
|
|
{
|
|
*SelectedMediumIndex = i;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Irda medium not found.
|
|
//
|
|
|
|
DEBUGMSG(DBG_ERROR, (" Failure: NdisMediumIrda not found!\n"));
|
|
status = NDIS_STATUS_UNSUPPORTED_MEDIA;
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Allocate a device object and zero memory.
|
|
//
|
|
|
|
pThisDev = NewDevice();
|
|
|
|
if (pThisDev == NULL)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" NewDevice failed.\n"));
|
|
status = NDIS_STATUS_RESOURCES;
|
|
|
|
goto done;
|
|
}
|
|
|
|
pThisDev->dongle.Initialize = UnknownDongleInit;
|
|
pThisDev->dongle.SetSpeed = UnknownDongleSetSpeed;
|
|
pThisDev->dongle.Deinitialize = UnknownDongleDeinit;
|
|
pThisDev->dongle.QueryCaps = UnknownDongleQueryCaps;
|
|
|
|
//
|
|
// Initialize device object and resources.
|
|
// All the queues and buffer/packets etc. are allocated here.
|
|
//
|
|
|
|
status = InitializeDevice(pThisDev);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" InitializeDevice failed. Returned 0x%.8x\n",
|
|
status));
|
|
|
|
goto done;
|
|
}
|
|
|
|
|
|
//
|
|
// Record the NdisAdapterHandle.
|
|
//
|
|
|
|
pThisDev->hNdisAdapter = NdisAdapterHandle;
|
|
|
|
//
|
|
// NdisMSetAttributes will associate our adapter handle with the wrapper's
|
|
// adapter handle. The wrapper will then always use our handle
|
|
// when calling us. We use a pointer to the device object as the context.
|
|
//
|
|
|
|
NdisMSetAttributesEx(NdisAdapterHandle,
|
|
(NDIS_HANDLE)pThisDev,
|
|
0,
|
|
NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND |
|
|
NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT |
|
|
NDIS_ATTRIBUTE_DESERIALIZE, // Magic bullet
|
|
NdisInterfaceInternal);
|
|
|
|
//
|
|
// Initialize a notification event for signalling PassiveLevelThread.
|
|
//
|
|
|
|
KeInitializeEvent(
|
|
&pThisDev->eventPassiveThread,
|
|
SynchronizationEvent, // auto-clearing event
|
|
FALSE // event initially non-signalled
|
|
);
|
|
|
|
KeInitializeEvent(
|
|
&pThisDev->eventKillThread,
|
|
SynchronizationEvent, // auto-clearing event
|
|
FALSE // event initially non-signalled
|
|
);
|
|
|
|
//
|
|
// Create a thread to run at IRQL PASSIVE_LEVEL.
|
|
//
|
|
|
|
status = (NDIS_STATUS) PsCreateSystemThread(
|
|
&pThisDev->hPassiveThread,
|
|
(ACCESS_MASK) 0L,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
PassiveLevelThread,
|
|
DEV_TO_CONTEXT(pThisDev)
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" PsCreateSystemThread failed. Returned 0x%.8x\n", status));
|
|
|
|
goto done;
|
|
}
|
|
// At this point we've done everything but actually touch the serial
|
|
// port. We do so now.
|
|
|
|
//
|
|
// Get device configuration from the registry settings.
|
|
// We are getting the transceiver type and which serial
|
|
// device object to access.
|
|
// The information which we get from the registry will outlast
|
|
// any NIC resets.
|
|
//
|
|
|
|
status = GetDeviceConfiguration(
|
|
pThisDev,
|
|
WrapperConfigurationContext
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" GetDeviceConfiguration failed. Returned 0x%.8x\n",
|
|
status));
|
|
|
|
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Open the serial device object specified in the registry.
|
|
//
|
|
|
|
status = SerialOpen(pThisDev);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SerialOpen failed. Returned 0x%.8x\n", status));
|
|
|
|
status = NDIS_STATUS_SUCCESS; // We'll get the port later.
|
|
}
|
|
|
|
if (pThisDev->pSerialDevObj)
|
|
{
|
|
{
|
|
//
|
|
// Set the minimum port buffering.
|
|
//
|
|
|
|
SERIAL_QUEUE_SIZE QueueSize;
|
|
|
|
QueueSize.InSize = 3*1024; // 1.5 packet size
|
|
QueueSize.OutSize = 0;
|
|
|
|
// Ignore failure. We'll still work, just not as well.
|
|
(void)SerialSetQueueSize(pThisDev->pSerialDevObj, &QueueSize);
|
|
}
|
|
|
|
#if 0
|
|
{
|
|
SERIAL_HANDFLOW Handflow;
|
|
|
|
SerialGetHandflow(pThisDev->pSerialDevObj, &Handflow);
|
|
DEBUGMSG(DBG_PNP, ("IRSIR: Serial Handflow was: %x %x %x %x\n",
|
|
Handflow.ControlHandShake,
|
|
Handflow.FlowReplace,
|
|
Handflow.XonLimit,
|
|
Handflow.XoffLimit));
|
|
Handflow.ControlHandShake = 0;
|
|
Handflow.FlowReplace = 0;
|
|
SerialSetHandflow(pThisDev->pSerialDevObj, &Handflow);
|
|
}
|
|
#endif
|
|
//
|
|
// Must set the timeout value of the serial port
|
|
// for a read.
|
|
//
|
|
|
|
status = (NDIS_STATUS) SerialSetTimeouts(pThisDev->pSerialDevObj,
|
|
&SerialTimeoutsInit);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SerialSetTimeouts failed. Returned 0x%.8x\n", status));
|
|
status = NDIS_STATUS_FAILURE;
|
|
|
|
goto done;
|
|
}
|
|
|
|
(void)SerialSetBaudRate(pThisDev->pSerialDevObj, &bitsPerSec);
|
|
|
|
serialLineControl.StopBits = STOP_BIT_1;
|
|
serialLineControl.Parity = NO_PARITY ;
|
|
serialLineControl.WordLength = 8;
|
|
|
|
status = (NDIS_STATUS) SerialSetLineControl(
|
|
pThisDev->pSerialDevObj,
|
|
&serialLineControl
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SerialSetLineControl failed. Returned 0x%.8x\n", status));
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
status = SetIrFunctions(pThisDev);
|
|
if (status!=STATUS_SUCCESS)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
if (pThisDev->pSerialDevObj)
|
|
{
|
|
//
|
|
// Now that a serial device object is open, we can initialize the
|
|
// dongle and set the speed of the dongle to the default.
|
|
//
|
|
|
|
if (pThisDev->dongle.Initialize(pThisDev->pSerialDevObj)!=NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" IRSIR: dongle failed to init!\n"));
|
|
status = NDIS_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
pThisDev->dongle.QueryCaps(&pThisDev->dongleCaps);
|
|
|
|
if (pThisDev->pSerialDevObj)
|
|
{
|
|
//
|
|
// Set the speed of the uart and the dongle.
|
|
//
|
|
|
|
status = (NDIS_STATUS) SetSpeed(pThisDev);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" IRSIR: Setspeed failed. Returned 0x%.8x\n", status));
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Create an irp and do an MJ_READ to begin our receives.
|
|
// NOTE: All other receive processing will be done in the read completion
|
|
// routine which is done set from this MJ_READ.
|
|
//
|
|
|
|
status = InitializeReceive(pThisDev);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" InitializeReceive failed. Returned 0x%.8x\n", status));
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
|
|
if (status != NDIS_STATUS_SUCCESS) {
|
|
|
|
DEBUGMSG(DBG_ERR, ("IRSIR: IrsirInitialize failed %x\n", status));
|
|
|
|
if (pThisDev != NULL) {
|
|
|
|
if (pThisDev->hPassiveThread) {
|
|
|
|
pThisDev->fPendingHalt = TRUE;
|
|
|
|
StopWorkerThread(pThisDev);
|
|
}
|
|
|
|
if (pThisDev->pSerialDevObj != NULL) {
|
|
|
|
if (pThisDev->dongle.Deinitialize) {
|
|
|
|
pThisDev->dongle.Deinitialize(pThisDev->pSerialDevObj);
|
|
}
|
|
|
|
SerialClose(pThisDev);
|
|
}
|
|
|
|
DeinitializeDevice(pThisDev);
|
|
FreeDevice(pThisDev);
|
|
}
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC, ("-IrsirInitialize\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: IrsirHalt
|
|
*
|
|
* Synopsis: Deallocates resources when the NIC is removed and halts the
|
|
* NIC.
|
|
*
|
|
* Arguments: Context - pointer to the ir device object
|
|
*
|
|
* Returns:
|
|
*
|
|
* Algorithm: Mirror image of IrsirInitialize...undoes everything initialize
|
|
* did.
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/8/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
* This routine runs at IRQL PASSIVE_LEVEL.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
VOID
|
|
IrsirHalt(
|
|
IN NDIS_HANDLE Context
|
|
)
|
|
{
|
|
PIR_DEVICE pThisDev;
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+IrsirHalt\n"));
|
|
|
|
pThisDev = CONTEXT_TO_DEV(Context);
|
|
|
|
//
|
|
// Let the send completion and receive completion routine know that there
|
|
// is a pending halt.
|
|
//
|
|
|
|
pThisDev->fPendingHalt = TRUE;
|
|
|
|
//
|
|
// We want to wait until all pending receives and sends to the
|
|
// serial device object. We call serial purge to cancel any
|
|
// irps. Wait until sends and receives have stopped.
|
|
//
|
|
|
|
SerialPurge(pThisDev->pSerialDevObj);
|
|
|
|
PausePacketProcessing(&pThisDev->SendPacketQueue,TRUE);
|
|
|
|
FlushQueuedPackets(&pThisDev->SendPacketQueue,pThisDev->hNdisAdapter);
|
|
|
|
|
|
|
|
while(
|
|
(pThisDev->fReceiving == TRUE)
|
|
)
|
|
{
|
|
//
|
|
// Sleep for 20 milliseconds.
|
|
//
|
|
|
|
NdisMSleep(20000);
|
|
}
|
|
|
|
//
|
|
// Deinitialize the dongle.
|
|
//
|
|
|
|
ASSERT(pThisDev->packetsHeldByProtocol==0);
|
|
|
|
pThisDev->dongle.Deinitialize(
|
|
pThisDev->pSerialDevObj
|
|
);
|
|
|
|
//
|
|
// Close the serial device object.
|
|
//
|
|
|
|
SerialClose(pThisDev);
|
|
|
|
//
|
|
// Need to terminate our worker threadxs. However, the thread
|
|
// needs to call PsTerminateSystemThread itself. Therefore,
|
|
// we will signal it.
|
|
//
|
|
|
|
StopWorkerThread(pThisDev);
|
|
|
|
|
|
//
|
|
// Deinitialize our own ir device object.
|
|
//
|
|
|
|
DeinitializeDevice(pThisDev);
|
|
|
|
//
|
|
// Free the device names.
|
|
//
|
|
|
|
if (pThisDev->serialDosName.Buffer)
|
|
{
|
|
MyMemFree(pThisDev->serialDosName.Buffer,
|
|
MAX_SERIAL_NAME_SIZE
|
|
);
|
|
pThisDev->serialDosName.Buffer = NULL;
|
|
}
|
|
if (pThisDev->serialDevName.Buffer)
|
|
{
|
|
MyMemFree(
|
|
pThisDev->serialDevName.Buffer,
|
|
MAX_SERIAL_NAME_SIZE
|
|
);
|
|
pThisDev->serialDevName.Buffer = NULL;
|
|
}
|
|
|
|
//
|
|
// Free our own ir device object.
|
|
//
|
|
|
|
FreeDevice(pThisDev);
|
|
|
|
|
|
DEBUGMSG(DBG_FUNC, ("-IrsirHalt\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ResetCallback(
|
|
PIR_WORK_ITEM pWorkItem
|
|
)
|
|
{
|
|
PIR_DEVICE pThisDev = pWorkItem->pIrDevice;
|
|
NDIS_STATUS status;
|
|
BOOLEAN fSwitchSuccessful;
|
|
NDIS_HANDLE hSwitchToMiniport;
|
|
|
|
//
|
|
// Reset this device by request of IrsirReset.
|
|
//
|
|
|
|
DEBUGMSG(DBG_STAT, (" primPassive = PASSIVE_RESET_DEVICE\n"));
|
|
|
|
ASSERT(pThisDev->fPendingReset == TRUE);
|
|
|
|
if (pThisDev->pSerialDevObj) {
|
|
|
|
SerialPurge(pThisDev->pSerialDevObj);
|
|
}
|
|
|
|
PausePacketProcessing(&pThisDev->SendPacketQueue,TRUE);
|
|
|
|
FlushQueuedPackets(&pThisDev->SendPacketQueue,pThisDev->hNdisAdapter);
|
|
|
|
|
|
|
|
status = ResetIrDevice(pThisDev);
|
|
|
|
#if DBG
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" ResetIrDevice failed = 0x%.8x\n", status));
|
|
}
|
|
|
|
#endif //DBG
|
|
|
|
//
|
|
//
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
NdisWriteErrorLogEntry(pThisDev->hNdisAdapter,
|
|
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
|
1,
|
|
status);
|
|
status = NDIS_STATUS_HARD_ERRORS;
|
|
}
|
|
|
|
NdisMResetComplete(
|
|
pThisDev->hNdisAdapter,
|
|
(NDIS_STATUS)status,
|
|
TRUE
|
|
);
|
|
|
|
FreeWorkItem(pWorkItem);
|
|
|
|
ActivatePacketProcessing(&pThisDev->SendPacketQueue);
|
|
|
|
pThisDev->fPendingReset = FALSE;
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: IrsirReset
|
|
*
|
|
* Synopsis: Resets the drivers software state.
|
|
*
|
|
* Arguments: AddressingReset - return arg. If set to TRUE, NDIS will call
|
|
* MiniportSetInformation to restore addressing
|
|
* information to the current values.
|
|
* Context - pointer to ir device object
|
|
*
|
|
* Returns: NDIS_STATUS_PENDING
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/9/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
* Runs at IRQL_DISPATCH_LEVEL, therefore we need to call a thread at
|
|
* passive level to perform the reset.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NDIS_STATUS
|
|
IrsirReset(
|
|
OUT PBOOLEAN AddressingReset,
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
{
|
|
PIR_DEVICE pThisDev;
|
|
NDIS_STATUS status;
|
|
|
|
DEBUGMSG(DBG_STAT, ("+IrsirReset\n"));
|
|
|
|
pThisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
|
|
|
|
//
|
|
// Let the receive completion routine know that there
|
|
// is a pending reset.
|
|
//
|
|
|
|
pThisDev->fPendingReset = TRUE;
|
|
|
|
|
|
*AddressingReset = TRUE;
|
|
|
|
if (ScheduleWorkItem(PASSIVE_RESET_DEVICE, pThisDev,
|
|
ResetCallback, NULL, 0) != NDIS_STATUS_SUCCESS)
|
|
{
|
|
status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
DEBUGMSG(DBG_STAT, ("-IrsirReset\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ResetIrDevice
|
|
*
|
|
* Synopsis:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/17/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
* The following elements of the ir device object outlast the reset:
|
|
*
|
|
* eventPassiveThread
|
|
* hPassiveThread
|
|
* primPassive
|
|
*
|
|
* serialDevName
|
|
* pSerialDevObj
|
|
* TransceiverType
|
|
* dongle
|
|
*
|
|
* hNdisAdapter
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NDIS_STATUS
|
|
ResetIrDevice(
|
|
PIR_DEVICE pThisDev
|
|
)
|
|
{
|
|
SERIAL_LINE_CONTROL serialLineControl;
|
|
SERIAL_TIMEOUTS serialTimeouts;
|
|
NDIS_STATUS status;
|
|
ULONG bitsPerSec = 9600;
|
|
|
|
DEBUGMSG(DBG_STAT, ("+ResetIrDeviceThread\n"));
|
|
|
|
//
|
|
// We need to wait for the completion of all pending sends and receives
|
|
// to the serial driver.
|
|
//
|
|
|
|
//
|
|
// We can speed up by purging the serial driver.
|
|
//
|
|
|
|
if (pThisDev->pSerialDevObj) {
|
|
|
|
SerialPurge(pThisDev->pSerialDevObj);
|
|
|
|
while(
|
|
(pThisDev->fReceiving == TRUE)
|
|
)
|
|
{
|
|
//
|
|
// Sleep for 20 milliseconds.
|
|
//
|
|
|
|
NdisMSleep(20000);
|
|
}
|
|
|
|
//
|
|
// Deinit the dongle.
|
|
//
|
|
|
|
pThisDev->dongle.Deinitialize(pThisDev->pSerialDevObj);
|
|
|
|
} else {
|
|
//
|
|
// we were not able to open the serial driver when the miniport first initialized.
|
|
// The thread will call this routine to attempt to open the device every 3 seconds.
|
|
//
|
|
status = SerialOpen(pThisDev);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SerialOpen failed. Returned 0x%.8x\n", status));
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (pThisDev->pSerialDevObj)
|
|
{
|
|
{
|
|
//
|
|
// Set the minimum port buffering.
|
|
//
|
|
|
|
SERIAL_QUEUE_SIZE QueueSize;
|
|
|
|
QueueSize.InSize = 3*1024; // 1.5 packet size
|
|
QueueSize.OutSize = 0;
|
|
|
|
// Ignore failure. We'll still work, just not as well.
|
|
(void)SerialSetQueueSize(pThisDev->pSerialDevObj, &QueueSize);
|
|
}
|
|
|
|
//
|
|
// Must set the timeout value of the serial port
|
|
// for a read.
|
|
//
|
|
|
|
status = (NDIS_STATUS) SerialSetTimeouts(pThisDev->pSerialDevObj,
|
|
&SerialTimeoutsInit);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SerialSetTimeouts failed. Returned 0x%.8x\n", status));
|
|
status = NDIS_STATUS_FAILURE;
|
|
|
|
goto done;
|
|
}
|
|
|
|
(void)SerialSetBaudRate(pThisDev->pSerialDevObj, &bitsPerSec);
|
|
|
|
serialLineControl.StopBits = STOP_BIT_1;
|
|
serialLineControl.Parity = NO_PARITY ;
|
|
serialLineControl.WordLength = 8;
|
|
|
|
status = (NDIS_STATUS) SerialSetLineControl(
|
|
pThisDev->pSerialDevObj,
|
|
&serialLineControl
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SerialSetLineControl failed. Returned 0x%.8x\n", status));
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
|
|
status = SetIrFunctions(pThisDev);
|
|
if (status!=STATUS_SUCCESS)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Initialize the dongle.
|
|
//
|
|
|
|
status = (NDIS_STATUS) SerialSetTimeouts(pThisDev->pSerialDevObj,
|
|
&SerialTimeoutsInit);
|
|
|
|
pThisDev->dongle.Initialize(pThisDev->pSerialDevObj);
|
|
|
|
pThisDev->dongle.QueryCaps(&pThisDev->dongleCaps);
|
|
//
|
|
// Set the speed of the uart and the dongle.
|
|
//
|
|
|
|
status = (NDIS_STATUS) SetSpeed(pThisDev);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SetSpeed failed. Returned 0x%.8x\n", status));
|
|
|
|
// goto done;
|
|
}
|
|
|
|
serialLineControl.StopBits = STOP_BIT_1;
|
|
serialLineControl.Parity = NO_PARITY ;
|
|
serialLineControl.WordLength = 8;
|
|
|
|
status = (NDIS_STATUS) SerialSetLineControl(
|
|
pThisDev->pSerialDevObj,
|
|
&serialLineControl
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SerialSetLineControl failed. Returned 0x%.8x\n", status));
|
|
|
|
// goto done;
|
|
}
|
|
|
|
//
|
|
// Must set the timeout value of the serial port
|
|
// for a read.
|
|
//
|
|
|
|
|
|
status = (NDIS_STATUS) SerialSetTimeouts(
|
|
pThisDev->pSerialDevObj,
|
|
&SerialTimeoutsInit
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" SerialSetTimeouts failed. Returned 0x%.8x\n", status));
|
|
status = NDIS_STATUS_FAILURE;
|
|
|
|
// goto done;
|
|
}
|
|
|
|
//
|
|
// Initialize receive loop.
|
|
//
|
|
|
|
status = InitializeReceive(pThisDev);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, (" InitializeReceive failed. Returned 0x%.8x\n", status));
|
|
status = NDIS_STATUS_FAILURE;
|
|
|
|
// goto done;
|
|
}
|
|
|
|
done:
|
|
DEBUGMSG(DBG_STAT, ("-ResetIrDeviceThread\n"));
|
|
|
|
return status;
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* Function: PassiveLevelThread
|
|
*
|
|
* Synopsis: Thread running at IRQL PASSIVE_LEVEL.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/22/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
* Any PASSIVE_PRIMITIVE that can be called must be serialized.
|
|
* i.e. when IrsirReset is called, NDIS will not make any other
|
|
* requests of the miniport until NdisMResetComplete is called.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
VOID
|
|
PassiveLevelThread(
|
|
IN OUT PVOID Context
|
|
)
|
|
{
|
|
PIR_DEVICE pThisDev;
|
|
NTSTATUS ntStatus;
|
|
PLIST_ENTRY pListEntry;
|
|
PKEVENT EventList[2];
|
|
LARGE_INTEGER Timeout;
|
|
ULONG ulSerialOpenAttempts = 100;
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+PassiveLevelThread\n"));
|
|
|
|
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
|
|
|
|
pThisDev = CONTEXT_TO_DEV(Context);
|
|
|
|
Timeout.QuadPart = -10000 * 1000 * 3; // 3 second relative delay
|
|
|
|
EventList[0] = &pThisDev->eventPassiveThread;
|
|
EventList[1] = &pThisDev->eventKillThread;
|
|
|
|
while (1) {
|
|
//
|
|
// The eventPassiveThread is an auto-clearing event, so
|
|
// we don't need to reset the event.
|
|
//
|
|
|
|
ntStatus = KeWaitForMultipleObjects(2,
|
|
EventList,
|
|
WaitAny,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(pThisDev->pSerialDevObj ? NULL : &Timeout),
|
|
NULL);
|
|
|
|
if (ntStatus==0 || ntStatus==STATUS_TIMEOUT) {
|
|
//
|
|
// either the first event was signaled or a timeout occurred
|
|
//
|
|
if (!pThisDev->pSerialDevObj) {
|
|
//
|
|
// we have not opened the serial driver yet, try again
|
|
//
|
|
ResetIrDevice(pThisDev);
|
|
|
|
if ((pThisDev->pSerialDevObj == NULL) && (--ulSerialOpenAttempts == 0)) {
|
|
//
|
|
// still could not open the device, tell ndis to remove it
|
|
//
|
|
NdisMRemoveMiniport(pThisDev->hNdisAdapter);
|
|
}
|
|
}
|
|
while (pListEntry = MyInterlockedRemoveHeadList(&pThisDev->leWorkItems,
|
|
&pThisDev->slWorkItem))
|
|
{
|
|
PIR_WORK_ITEM pWorkItem = CONTAINING_RECORD(pListEntry,
|
|
IR_WORK_ITEM,
|
|
ListEntry);
|
|
|
|
pWorkItem->Callback(pWorkItem);
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ntStatus==1) {
|
|
//
|
|
// the second event was signaled, this means that the thread should exit
|
|
//
|
|
DEBUGMSG(DBG_STAT, (" Thread: HALT\n"));
|
|
|
|
// Free any pending requests
|
|
|
|
while (pListEntry = MyInterlockedRemoveHeadList(&pThisDev->leWorkItems,
|
|
&pThisDev->slWorkItem))
|
|
{
|
|
PIR_WORK_ITEM pWorkItem = CONTAINING_RECORD(pListEntry,
|
|
IR_WORK_ITEM,
|
|
ListEntry);
|
|
|
|
DEBUGMSG(DBG_WARN, ("IRSIR: Releasing work item %08x\n", pWorkItem->Callback));
|
|
FreeWorkItem(pWorkItem);
|
|
}
|
|
|
|
ASSERT(pThisDev->fPendingHalt == TRUE);
|
|
|
|
//
|
|
// out of loop
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC, ("-PassiveLevelThread\n"));
|
|
|
|
|
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
StopWorkerThread(
|
|
PIR_DEVICE pThisDev
|
|
)
|
|
|
|
{
|
|
PVOID ThreadObject;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// get an object handle fomr the thread handle
|
|
//
|
|
Status=ObReferenceObjectByHandle(
|
|
pThisDev->hPassiveThread,
|
|
0,
|
|
NULL,
|
|
KernelMode,
|
|
&ThreadObject,
|
|
NULL
|
|
);
|
|
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
//
|
|
// tell the thread to exit
|
|
//
|
|
KeSetEvent(
|
|
&pThisDev->eventKillThread,
|
|
0,
|
|
FALSE
|
|
);
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
KeWaitForSingleObject(
|
|
ThreadObject,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
ObDereferenceObject(ThreadObject);
|
|
ThreadObject=NULL;
|
|
}
|
|
|
|
//
|
|
// close the thread handle
|
|
//
|
|
ZwClose(pThisDev->hPassiveThread);
|
|
pThisDev->hPassiveThread = NULL;
|
|
|
|
return;
|
|
}
|