|
|
/*****************************************************************************
* * 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; }
|