1441 lines
39 KiB
C
1441 lines
39 KiB
C
/*****************************************************************************
|
|
`*
|
|
* Copyright (c) 1996-1999 Microsoft Corporation
|
|
*
|
|
* @doc
|
|
* @module openclos.c | IrSIR NDIS Miniport Driver
|
|
* @comm
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Author: Scott Holden (sholden)
|
|
*
|
|
* Date: 10/3/1996 (created)
|
|
*
|
|
* Contents: open and close functions for the device
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "irsir.h"
|
|
|
|
#include <ntddmodm.h>
|
|
|
|
PIRP
|
|
BuildSynchronousCreateCloseRequest(
|
|
IN PDEVICE_OBJECT pSerialDevObj,
|
|
IN ULONG MajorFunction,
|
|
IN PKEVENT pEvent,
|
|
OUT PIO_STATUS_BLOCK pIosb
|
|
);
|
|
|
|
NTSTATUS
|
|
CheckForModemPort(
|
|
PFILE_OBJECT FileObject
|
|
);
|
|
|
|
|
|
|
|
#pragma alloc_text(PAGE, SerialClose)
|
|
#pragma alloc_text(PAGE, GetDeviceConfiguration)
|
|
#pragma alloc_text(PAGE, BuildSynchronousCreateCloseRequest)
|
|
|
|
#if 0
|
|
NTSTATUS PortNotificationCallback(PVOID NotificationStructure, PVOID Context)
|
|
{
|
|
DEVICE_INTERFACE_CHANGE_NOTIFICATION *Notification = NotificationStructure;
|
|
PIR_DEVICE pThisDev = Context;
|
|
NDIS_STATUS Status;
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("+PortNotificationCallback\n"));
|
|
|
|
DEBUGMSG(DBG_PNP, ("New port:%wZ\n", Notification->SymbolicLinkName));
|
|
|
|
Status = GetComPortNtDeviceName(&pThisDev->serialDosName,
|
|
&pThisDev->serialDevName);
|
|
|
|
if (Status==NDIS_STATUS_SUCCESS)
|
|
{
|
|
// We found our port. Initialize.
|
|
|
|
Status = ResetIrDevice(pThisDev);
|
|
|
|
if (Status!=NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, ("IRSIR:ResetIrDevice failed in PortNotificationCallback (0x%x)\n", Status));
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(DBG_PNP, ("IRSIR:Successfully opened port after delay.\n"));
|
|
Status = IoUnregisterPlugPlayNotification(pThisDev->PnpNotificationEntry);
|
|
ASSERT(Status==NDIS_STATUS_SUCCESS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We didn't find it. Wait for the next notification.
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("-PortNotificationCallback\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: InitializeDevice
|
|
*
|
|
* Synopsis: allocate resources for a single ir device object
|
|
*
|
|
* Arguments: pThisDev - ir device object to open
|
|
*
|
|
* Returns: NDIS_STATUS_SUCCESS - if device is successfully opened
|
|
* NDIS_STATUS_RESOURCES - could not claim sufficient
|
|
* resources
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
* we do alot of stuff in this open device function
|
|
* - allocate packet pool
|
|
* - allocate buffer pool
|
|
* - allocate packets/buffers/memory and chain together
|
|
* (only one buffer per packet)
|
|
* - initialize send queue
|
|
*
|
|
* This function should be called with device lock held.
|
|
*
|
|
* We don't initialize the following ir device object entries, since
|
|
* these values will outlast an IrsirReset.
|
|
* serialDevName
|
|
* pSerialDevObj
|
|
* hNdisAdapter
|
|
* transceiverType
|
|
* dongle
|
|
* dongleCaps
|
|
* fGotFilterIndication
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NDIS_STATUS
|
|
InitializeDevice(
|
|
IN OUT PIR_DEVICE pThisDev)
|
|
{
|
|
int i;
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("+InitializeDevice\n"));
|
|
|
|
ASSERT(pThisDev != NULL);
|
|
|
|
pThisDev->pSerialDevObj = NULL;
|
|
|
|
//
|
|
// Will set speed to 9600 baud initially.
|
|
//
|
|
|
|
pThisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];
|
|
|
|
//
|
|
// Current speed is unknown, SetSpeed will update this.
|
|
//
|
|
|
|
pThisDev->currentSpeed = 0;
|
|
|
|
//
|
|
// Init statistical info.
|
|
//
|
|
|
|
pThisDev->packetsReceived = 0;
|
|
pThisDev->packetsReceivedDropped = 0;
|
|
pThisDev->packetsReceivedOverflow = 0;
|
|
pThisDev->packetsSent = 0;
|
|
pThisDev->packetsSentDropped = 0;
|
|
|
|
InitializePacketQueue(
|
|
&pThisDev->SendPacketQueue,
|
|
pThisDev,
|
|
SendPacketToSerial
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// Set fMediaBusy to TRUE initially. That way, we won't
|
|
// IndicateStatus to the protocol in the receive poll loop
|
|
// unless the protocol has expressed interest by clearing this flag
|
|
// via IrsirSetInformation(OID_IRDA_MEDIA_BUSY).
|
|
//
|
|
|
|
pThisDev->fMediaBusy = TRUE;
|
|
|
|
pThisDev->fReceiving = FALSE;
|
|
|
|
pThisDev->fRequireMinTurnAround = TRUE;
|
|
|
|
pThisDev->fPendingSetSpeed = FALSE;
|
|
|
|
pThisDev->fPendingHalt = FALSE;
|
|
|
|
pThisDev->fPendingReset = FALSE;
|
|
|
|
//
|
|
// Initialize spin locks
|
|
//
|
|
|
|
NdisAllocateSpinLock(&(pThisDev->mediaBusySpinLock));
|
|
NdisAllocateSpinLock(&(pThisDev->slWorkItem));
|
|
|
|
//
|
|
// Initialize the queues.
|
|
//
|
|
|
|
NdisInitializeListHead(&(pThisDev->rcvFreeQueue));
|
|
|
|
NdisInitializeListHead(&(pThisDev->leWorkItems));
|
|
|
|
//
|
|
// Initialize the spin lock for the two above queues.
|
|
//
|
|
|
|
NdisAllocateSpinLock(&(pThisDev->rcvQueueSpinLock));
|
|
|
|
//
|
|
// Initialize the receive information buffer.
|
|
//
|
|
|
|
pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
|
|
pThisDev->rcvInfo.rcvBufPos = 0;
|
|
pThisDev->rcvInfo.pRcvBuffer = NULL;
|
|
|
|
//
|
|
// Allocate the NDIS packet and NDIS buffer pools
|
|
// for this device's RECEIVE buffer queue.
|
|
// Our receive packets must only contain one buffer apiece,
|
|
// so #buffers == #packets.
|
|
//
|
|
|
|
NdisAllocatePacketPool(
|
|
&status, // return status
|
|
&pThisDev->hPacketPool, // handle to the packet pool
|
|
NUM_RCV_BUFS, // number of packet descriptors
|
|
16 // number of bytes reserved for
|
|
); // ProtocolReserved field
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" NdisAllocatePacketPool failed. Returned 0x%.8x\n",
|
|
status));
|
|
|
|
goto done;
|
|
}
|
|
|
|
NdisAllocateBufferPool(
|
|
&status, // return status
|
|
&pThisDev->hBufferPool,// handle to the buffer pool
|
|
NUM_RCV_BUFS // number of buffer descriptors
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" NdisAllocateBufferPool failed. Returned 0x%.8x\n",
|
|
status));
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Initialize each of the RECEIVE objects for this device.
|
|
//
|
|
|
|
for (i = 0; i < NUM_RCV_BUFS; i++)
|
|
{
|
|
PNDIS_BUFFER pBuffer = NULL;
|
|
PRCV_BUFFER pRcvBuf = &pThisDev->rcvBufs[i];
|
|
|
|
//
|
|
// Allocate a data buffer
|
|
//
|
|
// This buffer gets swapped with the one on comPortInfo
|
|
// and must be the same size.
|
|
//
|
|
|
|
pRcvBuf->dataBuf = MyMemAlloc(RCV_BUFFER_SIZE);
|
|
|
|
if (pRcvBuf->dataBuf == NULL)
|
|
{
|
|
status = NDIS_STATUS_RESOURCES;
|
|
|
|
goto done;
|
|
}
|
|
|
|
NdisZeroMemory(
|
|
pRcvBuf->dataBuf,
|
|
RCV_BUFFER_SIZE
|
|
);
|
|
|
|
pRcvBuf->dataLen = 0;
|
|
|
|
//
|
|
// Allocate the NDIS_PACKET.
|
|
//
|
|
|
|
NdisAllocatePacket(
|
|
&status, // return status
|
|
&pRcvBuf->packet, // return pointer to allocated descriptor
|
|
pThisDev->hPacketPool // handle to packet pool
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" NdisAllocatePacket failed. Returned 0x%.8x\n",
|
|
status));
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Allocate the NDIS_BUFFER.
|
|
//
|
|
|
|
NdisAllocateBuffer(
|
|
&status, // return status
|
|
&pBuffer, // return pointer to allocated descriptor
|
|
pThisDev->hBufferPool, // handle to buffer pool
|
|
pRcvBuf->dataBuf, // virtual address mapped to descriptor
|
|
RCV_BUFFER_SIZE // number of bytes mapped
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" NdisAllocateBuffer failed. Returned 0x%.8x\n",
|
|
status));
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Need to chain the buffer to the packet.
|
|
//
|
|
|
|
NdisChainBufferAtFront(
|
|
pRcvBuf->packet, // packet descriptor
|
|
pBuffer // buffer descriptor to add to chain
|
|
);
|
|
|
|
//
|
|
// For future convenience, set the MiniportReserved portion of the packet
|
|
// to the index of the rcv buffer that contains it.
|
|
// This will be used in IrsirReturnPacket.
|
|
//
|
|
|
|
{
|
|
PPACKET_RESERVED_BLOCK PacketReserved;
|
|
|
|
PacketReserved=(PPACKET_RESERVED_BLOCK)&pRcvBuf->packet->MiniportReservedEx[0];
|
|
|
|
PacketReserved->Context=pRcvBuf;
|
|
}
|
|
|
|
|
|
//
|
|
// Add the receive buffer to the free queue.
|
|
//
|
|
|
|
MyInterlockedInsertTailList(
|
|
&(pThisDev->rcvFreeQueue),
|
|
&pRcvBuf->linkage,
|
|
&(pThisDev->rcvQueueSpinLock)
|
|
);
|
|
}
|
|
|
|
pThisDev->pRcvIrpBuffer = ExAllocatePoolWithTag(
|
|
NonPagedPoolCacheAligned,
|
|
SERIAL_RECEIVE_BUFFER_LENGTH,
|
|
IRSIR_TAG
|
|
);
|
|
|
|
if (pThisDev->pRcvIrpBuffer == NULL)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" ExAllocatePool failed.\n"));
|
|
status = NDIS_STATUS_RESOURCES;
|
|
|
|
goto done;
|
|
}
|
|
|
|
pThisDev->pSendIrpBuffer = ExAllocatePoolWithTag(
|
|
NonPagedPoolCacheAligned,
|
|
MAX_IRDA_DATA_SIZE,
|
|
IRSIR_TAG
|
|
);
|
|
|
|
if (pThisDev->pSendIrpBuffer == NULL)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" ExAllocatePool failed.\n"));
|
|
status = NDIS_STATUS_RESOURCES;
|
|
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
|
|
//
|
|
// If we didn't complete the init successfully, then we should clean
|
|
// up what we did allocate.
|
|
//
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DeinitializeDevice(pThisDev);
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("-InitializeDevice()\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: DeinitializeDevice
|
|
*
|
|
* Synopsis: deallocate the resources of the ir device object
|
|
*
|
|
* Arguments: pThisDev - the ir device object to close
|
|
*
|
|
* Returns: none
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
* Called for shutdown and reset.
|
|
* Don't clear hNdisAdapter, since we might just be resetting.
|
|
* This function should be called with device lock held.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NDIS_STATUS
|
|
DeinitializeDevice(
|
|
IN OUT PIR_DEVICE pThisDev
|
|
)
|
|
{
|
|
UINT i;
|
|
NDIS_HANDLE hSwitchToMiniport;
|
|
BOOLEAN fSwitchSuccessful;
|
|
NDIS_STATUS status;
|
|
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("+DeinitializeDevice\n"));
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
|
|
ASSERT(pThisDev != NULL);
|
|
|
|
pThisDev->linkSpeedInfo = NULL;
|
|
|
|
NdisFreeSpinLock(&(pThisDev->rcvQueueSpinLock));
|
|
NdisFreeSpinLock(&(pThisDev->sendSpinLock));
|
|
|
|
//
|
|
// Free all resources for the RECEIVE buffer queue.
|
|
//
|
|
|
|
for (i = 0; i < NUM_RCV_BUFS; i++)
|
|
{
|
|
PNDIS_BUFFER pBuffer = NULL;
|
|
PRCV_BUFFER pRcvBuf = &pThisDev->rcvBufs[i];
|
|
|
|
//
|
|
// Need to unchain the packet and buffer combo.
|
|
//
|
|
|
|
if (pRcvBuf->packet)
|
|
{
|
|
NdisUnchainBufferAtFront(
|
|
pRcvBuf->packet,
|
|
&pBuffer
|
|
);
|
|
}
|
|
|
|
//
|
|
// free the buffer, packet and data
|
|
//
|
|
|
|
if (pBuffer != NULL)
|
|
{
|
|
NdisFreeBuffer(pBuffer);
|
|
}
|
|
|
|
if (pRcvBuf->packet != NULL)
|
|
{
|
|
NdisFreePacket(pRcvBuf->packet);
|
|
pRcvBuf->packet = NULL;
|
|
}
|
|
|
|
if (pRcvBuf->dataBuf != NULL)
|
|
{
|
|
MyMemFree(pRcvBuf->dataBuf, RCV_BUFFER_SIZE);
|
|
pRcvBuf->dataBuf = NULL;
|
|
}
|
|
|
|
pRcvBuf->dataLen = 0;
|
|
}
|
|
|
|
//
|
|
// Free the packet and buffer pool handles for this device.
|
|
//
|
|
|
|
if (pThisDev->hPacketPool)
|
|
{
|
|
NdisFreePacketPool(pThisDev->hPacketPool);
|
|
pThisDev->hPacketPool = NULL;
|
|
}
|
|
|
|
if (pThisDev->hBufferPool)
|
|
{
|
|
NdisFreeBufferPool(pThisDev->hBufferPool);
|
|
pThisDev->hBufferPool = NULL;
|
|
}
|
|
|
|
//
|
|
// Free all resources for the SEND buffer queue.
|
|
//
|
|
FlushQueuedPackets(&pThisDev->SendPacketQueue,pThisDev->hNdisAdapter);
|
|
|
|
//
|
|
// Deallocate the irp buffers.
|
|
//
|
|
|
|
if (pThisDev->pRcvIrpBuffer != NULL)
|
|
{
|
|
ExFreePool(pThisDev->pRcvIrpBuffer);
|
|
pThisDev->pRcvIrpBuffer = NULL;
|
|
}
|
|
if (pThisDev->pSendIrpBuffer != NULL)
|
|
{
|
|
ExFreePool(pThisDev->pSendIrpBuffer);
|
|
pThisDev->pSendIrpBuffer = NULL;
|
|
}
|
|
|
|
pThisDev->fMediaBusy = FALSE;
|
|
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("-DeinitializeDevice\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: GetDeviceConfiguration
|
|
*
|
|
* Synopsis: get the configuration from the registry
|
|
*
|
|
* Arguments: pThisDev - pointer to the ir device object
|
|
*
|
|
* Returns: NDIS_STATUS_SUCCESS - if device retrieves configuration
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NDIS_STATUS
|
|
GetDeviceConfiguration(
|
|
IN OUT PIR_DEVICE pThisDev,
|
|
IN NDIS_HANDLE WrapperConfigurationContext
|
|
)
|
|
{
|
|
NDIS_STATUS status, tmpStatus;
|
|
NDIS_HANDLE hConfig;
|
|
PNDIS_CONFIGURATION_PARAMETER configParamPtr;
|
|
UNICODE_STRING serialCommString;
|
|
UNICODE_STRING serialTmpString;
|
|
UNICODE_STRING NetCfgInstanceID;
|
|
UNICODE_STRING registryPath;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
HANDLE hKey;
|
|
PKEY_VALUE_PARTIAL_INFORMATION pKeyValuePartialInfo;
|
|
PKEY_VALUE_BASIC_INFORMATION pKeyValueBasicInfo;
|
|
ULONG resultLength;
|
|
int i;
|
|
|
|
NDIS_STRING regKeyPortString = NDIS_STRING_CONST("PORT");
|
|
NDIS_STRING regKeyIRTransceiverString = NDIS_STRING_CONST("InfraredTransceiverType");
|
|
NDIS_STRING regKeySerialBasedString = NDIS_STRING_CONST("SerialBased");
|
|
NDIS_STRING regKeyMaxConnectString = NDIS_STRING_CONST("MaxConnectRate");
|
|
NDIS_STRING regKeyNetCfgInstance = NDIS_STRING_CONST("NetCfgInstanceID");
|
|
NDIS_STRING ComPortStr = NDIS_STRING_CONST("COM1");
|
|
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("+GetDeviceConfiguration\n"));
|
|
|
|
//
|
|
// Set the default value.
|
|
//
|
|
|
|
pThisDev->transceiverType = STANDARD_UART;
|
|
|
|
//
|
|
// Open up the registry with our WrapperConfigurationContext.
|
|
//
|
|
// HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\
|
|
// ?DriverName?[instance]\Parameters\
|
|
//
|
|
|
|
NdisOpenConfiguration(
|
|
&status, // return status
|
|
&hConfig, // configuration handle
|
|
WrapperConfigurationContext // handle input to IrsirInitialize
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" NdisOpenConfiguration failed. Returned 0x%.8x\n",
|
|
status));
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Attempt to read the registry for transceiver string.
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&tmpStatus, // return status
|
|
&configParamPtr, // return reg data
|
|
hConfig, // handle to open reg configuration
|
|
®KeyIRTransceiverString,// keyword to look for in reg
|
|
NdisParameterInteger // we want a integer
|
|
);
|
|
|
|
if (tmpStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pThisDev->transceiverType =
|
|
(IR_TRANSCEIVER_TYPE)configParamPtr->ParameterData.IntegerData;
|
|
DEBUGMSG(DBG_OUT|DBG_PNP, ("TransceiverType:%d\n\n", pThisDev->transceiverType));
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" NdisReadConfiguration(TransceiverStr) failed. Returned 0x%.8x\n",
|
|
status));
|
|
DEBUGMSG(DBG_OUT|DBG_PNP, ("Using default TransceiverType:%d\n\n", pThisDev->transceiverType));
|
|
}
|
|
|
|
//
|
|
// Attempt to read the registry for transceiver string.
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&tmpStatus, // return status
|
|
&configParamPtr, // return reg data
|
|
hConfig, // handle to open reg configuration
|
|
®KeyMaxConnectString, // keyword to look for in reg
|
|
NdisParameterInteger // we want a integer
|
|
);
|
|
|
|
if (tmpStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pThisDev->AllowedSpeedsMask = 0;
|
|
switch (configParamPtr->ParameterData.IntegerData)
|
|
{
|
|
default:
|
|
case 115200:
|
|
pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_115200;
|
|
case 57600:
|
|
pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_57600;
|
|
case 38400:
|
|
pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_38400;
|
|
case 19200:
|
|
pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_19200;
|
|
case 2400: // Always allow 9600
|
|
pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_2400;
|
|
case 9600:
|
|
pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_9600;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pThisDev->AllowedSpeedsMask = ALL_SLOW_IRDA_SPEEDS;
|
|
}
|
|
|
|
//
|
|
// Attempt to read the registry to determine if we've been PNPed
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&tmpStatus, // return status
|
|
&configParamPtr, // return reg data
|
|
hConfig, // handle to open reg configuration
|
|
®KeySerialBasedString, // keyword to look for in reg
|
|
NdisParameterInteger // we want a integer
|
|
);
|
|
|
|
if (tmpStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pThisDev->SerialBased =
|
|
(BOOLEAN)configParamPtr->ParameterData.IntegerData;
|
|
}
|
|
else
|
|
{
|
|
pThisDev->SerialBased = TRUE;
|
|
}
|
|
DEBUGMSG(DBG_OUT|DBG_PNP, ("IRSIR: Adapter is%s serial-based.\n", (pThisDev->SerialBased ? "" : " NOT")));
|
|
|
|
if (pThisDev->SerialBased)
|
|
{
|
|
if (!pThisDev->serialDosName.Buffer)
|
|
{
|
|
pThisDev->serialDosName.Buffer = MyMemAlloc(MAX_SERIAL_NAME_SIZE);
|
|
}
|
|
pThisDev->serialDosName.MaximumLength = MAX_SERIAL_NAME_SIZE;
|
|
pThisDev->serialDosName.Length = 0;
|
|
//
|
|
// Attempt to read the registry for PORT...we want something
|
|
// like COM1
|
|
//
|
|
|
|
NdisReadConfiguration(
|
|
&tmpStatus, // return status
|
|
&configParamPtr, // return reg data
|
|
hConfig, // handle to open reg configuration
|
|
®KeyPortString, // keyword to look for in reg
|
|
NdisParameterString // we want a string
|
|
);
|
|
|
|
if (tmpStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
RtlInitUnicodeString(
|
|
&serialCommString,
|
|
configParamPtr->ParameterData.StringData.Buffer
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString(
|
|
&serialCommString,
|
|
ComPortStr.Buffer
|
|
);
|
|
DEBUGMSG(DBG_OUT|DBG_PNP, ("Using default port\n"));
|
|
}
|
|
|
|
RtlAppendUnicodeStringToString(
|
|
&pThisDev->serialDosName,
|
|
&configParamPtr->ParameterData.StringData
|
|
);
|
|
|
|
DEBUGMSG(DBG_OUT, (" Port = %wZ\n", &serialCommString));
|
|
|
|
#if 0
|
|
status = GetComPortNtDeviceName(&pThisDev->serialDosName,
|
|
&pThisDev->serialDevName);
|
|
if (status!=STATUS_SUCCESS)
|
|
{
|
|
#if 0
|
|
// This would have been a nice mechanism to use, but it notifies us
|
|
// before the SERIALCOMM entries are made. It looks like this has
|
|
// the potential to change, so we'll leave this code in and disabled
|
|
// and revisit it later. - StanA
|
|
NTSTATUS TmpStatus;
|
|
//
|
|
// The port isn't there yet, and we want to know when it is.
|
|
// Register for PNP notifications.
|
|
//
|
|
TmpStatus = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
|
|
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
|
|
(GUID*)&GUID_DEVCLASS_PORTS,
|
|
DriverObject,
|
|
PortNotificationCallback,
|
|
pThisDev,
|
|
&pThisDev->PnpNotificationEntry);
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
else // ! SerialBased
|
|
{
|
|
NDIS_STRING IoBaseAddress = NDIS_STRING_CONST("IoBaseAddress");
|
|
NDIS_STRING Interrupt = NDIS_STRING_CONST("InterruptNumber");
|
|
|
|
NdisReadConfiguration(&tmpStatus,
|
|
&configParamPtr,
|
|
hConfig,
|
|
&IoBaseAddress,
|
|
NdisParameterHexInteger);
|
|
DEBUGMSG(DBG_OUT|DBG_PNP, ("IRSIR: IoBaseAddress:%x\n", configParamPtr->ParameterData.IntegerData));
|
|
|
|
NdisReadConfiguration(&tmpStatus,
|
|
&configParamPtr,
|
|
hConfig,
|
|
&Interrupt,
|
|
NdisParameterHexInteger);
|
|
DEBUGMSG(DBG_OUT|DBG_PNP, ("IRSIR: Interrupt:%x\n", configParamPtr->ParameterData.IntegerData));
|
|
|
|
}
|
|
|
|
status = SetIrFunctions(pThisDev);
|
|
if (status!=STATUS_SUCCESS)
|
|
{
|
|
goto error10;
|
|
}
|
|
|
|
status = pThisDev->dongle.QueryCaps(&pThisDev->dongleCaps);
|
|
if (status!=STATUS_SUCCESS)
|
|
{
|
|
goto error10;
|
|
}
|
|
|
|
|
|
|
|
NdisCloseConfiguration(hConfig);
|
|
|
|
goto done;
|
|
|
|
error10:
|
|
NdisCloseConfiguration(hConfig);
|
|
|
|
done:
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("-GetDeviceConfiguration\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SyncOpenCloseCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PVOID Context)
|
|
{
|
|
IoFreeIrp(pIrp);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: BuildSynchronousCreateRequest
|
|
*
|
|
* Synopsis:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
* this is pretty much stolen from IoBuildDeviceIoControlRequest
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PIRP
|
|
BuildSynchronousCreateCloseRequest(
|
|
IN PDEVICE_OBJECT pSerialDevObj,
|
|
IN ULONG MajorFunction,
|
|
IN PKEVENT pEvent,
|
|
OUT PIO_STATUS_BLOCK pIosb
|
|
)
|
|
{
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
//
|
|
// Begin by allocating the IRP for this request.
|
|
//
|
|
|
|
pIrp = IoAllocateIrp(pSerialDevObj->StackSize, FALSE);
|
|
|
|
if (pIrp == NULL)
|
|
{
|
|
return pIrp;
|
|
}
|
|
|
|
//
|
|
// Get a pointer to the stack location of the first driver which will be
|
|
// invoked. This is where the function codes and the parameters are set.
|
|
//
|
|
|
|
irpSp = IoGetNextIrpStackLocation( pIrp );
|
|
|
|
//
|
|
// Set the major function code.
|
|
//
|
|
|
|
irpSp->MajorFunction = (UCHAR)MajorFunction;
|
|
|
|
//
|
|
// Set the appropriate irp fields.
|
|
//
|
|
|
|
if (MajorFunction == IRP_MJ_CREATE)
|
|
{
|
|
pIrp->Flags = IRP_CREATE_OPERATION;
|
|
}
|
|
else
|
|
{
|
|
pIrp->Flags = IRP_CLOSE_OPERATION;
|
|
}
|
|
|
|
pIrp->AssociatedIrp.SystemBuffer = NULL;
|
|
pIrp->UserBuffer = NULL;
|
|
|
|
//
|
|
// Finally, set the address of the I/O status block and the address of
|
|
// the kernel event object. Note that I/O completion will not attempt
|
|
// to dereference the event since there is no file object associated
|
|
// with this operation.
|
|
//
|
|
|
|
pIrp->UserIosb = pIosb;
|
|
pIrp->UserEvent = pEvent;
|
|
|
|
IoSetCompletionRoutine(pIrp,
|
|
SyncOpenCloseCompletion,
|
|
NULL,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
//
|
|
// Simply return a pointer to the packet.
|
|
//
|
|
|
|
return pIrp;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: SerialOpen
|
|
*
|
|
* Synopsis: open up the serial port
|
|
*
|
|
* Arguments: pThisDev - ir device object
|
|
*
|
|
* Returns: NDIS_STATUS_SUCCESS
|
|
* NDIS_STATUS_OPEN_FAILED - serial port can't be opened
|
|
* NDIS_STATUS_NOT_ACCEPTED - serial.sys does not accept the
|
|
* configuration
|
|
* NDIS_STATUS_FAILURE
|
|
* NDIS_STATUS_RESOURCES - irp not allocated
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
* Converting from NTSTATUS to NDIS_STATUS is relatively pain free, since the
|
|
* important codes remain the same.
|
|
* NDIS_STATUS_PENDING = STATUS_PENDING
|
|
* NDIS_STATUS_SUCCESS = STATUS_SUCCESS
|
|
* NDIS_STATUS_FAILURE = STATUS_UNSUCCESSFUL
|
|
* NDIS_STATUS_RESOURCES = STATUS_INSUFFICIENT_RESOURCES
|
|
*
|
|
* IoGetDeviceObjectPointer could return an error code which is
|
|
* NOT mapped by an NDIS_STATUS code
|
|
* STATUS_OBJECT_TYPE_MISMATCH
|
|
* STATUS_INVALID_PARAMETER
|
|
* STATUS_PRIVILEGE_NOT_HELD
|
|
* STATUS_OBJECT_NAME_INVALID
|
|
* These will be mapped to NDIS_STATUS_NOT_ACCEPTED.
|
|
*
|
|
* If IoCallDriver fails, NDIS_STATUS_OPEN_FAILED will be returned.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NDIS_STATUS
|
|
SerialOpen(
|
|
IN PIR_DEVICE pThisDev
|
|
)
|
|
{
|
|
PIRP pIrp;
|
|
NTSTATUS status = NDIS_STATUS_SUCCESS;
|
|
KEVENT eventComplete;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
PAGED_CODE();
|
|
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("+SerialOpen\n"));
|
|
|
|
if (!pThisDev->SerialBased)
|
|
{
|
|
PDEVICE_OBJECT PhysicalDeviceObject;
|
|
PDEVICE_OBJECT FunctionalDeviceObject;
|
|
PDEVICE_OBJECT NextDeviceObject;
|
|
PCM_RESOURCE_LIST AllocatedResources;
|
|
PCM_RESOURCE_LIST AllocatedResourcesTranslated;
|
|
|
|
|
|
NdisMGetDeviceProperty(pThisDev->hNdisAdapter,
|
|
&PhysicalDeviceObject,
|
|
&FunctionalDeviceObject,
|
|
&NextDeviceObject,
|
|
&AllocatedResources,
|
|
&AllocatedResourcesTranslated);
|
|
|
|
pThisDev->pSerialDevObj = NextDeviceObject;
|
|
|
|
DEBUGMSG(DBG_OUT|DBG_PNP, ("IRSIR: NdisMGetDeviceProperty returns:\n"));
|
|
DBG_X(DBG_OUT|DBG_PNP, PhysicalDeviceObject);
|
|
DBG_X(DBG_OUT|DBG_PNP, FunctionalDeviceObject);
|
|
DBG_X(DBG_OUT|DBG_PNP, NextDeviceObject);
|
|
DBG_X(DBG_OUT|DBG_PNP, AllocatedResources);
|
|
DBG_X(DBG_OUT|DBG_PNP, AllocatedResourcesTranslated);
|
|
|
|
//
|
|
// Event to wait for completion of serial driver.
|
|
//
|
|
|
|
KeInitializeEvent(
|
|
&eventComplete,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Build an irp to send to the serial driver with IRP_MJ_CREATE.
|
|
//
|
|
|
|
//
|
|
// Irp is released by io manager.
|
|
//
|
|
|
|
pIrp = BuildSynchronousCreateCloseRequest(
|
|
pThisDev->pSerialDevObj,
|
|
IRP_MJ_CREATE,
|
|
&eventComplete,
|
|
&ioStatusBlock
|
|
);
|
|
|
|
DEBUGMSG(DBG_OUT, (" BuildSynchronousCreateCloseReqest\n"));
|
|
|
|
if (pIrp == NULL)
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
DEBUGMSG(DBG_OUT, (" IoAllocateIrp() failed.\n"));
|
|
|
|
goto error10;
|
|
}
|
|
|
|
status = IoCallDriver(pThisDev->pSerialDevObj, pIrp);
|
|
|
|
//
|
|
// If IoCallDriver returns STATUS_PENDING, we need to wait for the event.
|
|
//
|
|
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" IoCallDriver(MJ_CREATE) PENDING.\n"));
|
|
|
|
KeWaitForSingleObject(
|
|
&eventComplete, // object to wait for
|
|
Executive, // reason to wait
|
|
KernelMode, // processor mode
|
|
FALSE, // alertable
|
|
NULL // timeout
|
|
);
|
|
|
|
//
|
|
// We can get the status of the IoCallDriver from the io status
|
|
// block.
|
|
//
|
|
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
//
|
|
// If IoCallDriver returns something other that STATUS_PENDING, then it
|
|
// is the same as what the serial driver set in ioStatusBlock.Status.
|
|
//
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" IoCallDriver(MJ_CREATE) failed. Returned = 0x%.8x\n", status));
|
|
status = (NTSTATUS)NDIS_STATUS_OPEN_FAILED;
|
|
|
|
goto error10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
UNICODE_STRING DosFileName;
|
|
WCHAR DosFileNameBuffer[MAX_SERIAL_NAME_SIZE+15];
|
|
|
|
DosFileName.Length = 0;
|
|
DosFileName.MaximumLength = sizeof(DosFileNameBuffer);
|
|
DosFileName.Buffer = DosFileNameBuffer;
|
|
|
|
status = RtlAppendUnicodeToString(&DosFileName, L"\\DosDevices\\");
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" RtlAppendUnicodeToString() failed. Returned = 0x%.8x\n", status));
|
|
goto error10;
|
|
}
|
|
status = RtlAppendUnicodeStringToString(&DosFileName, &pThisDev->serialDosName);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" RtlAppendUnicodeStringToString() failed. Returned = 0x%.8x\n", status));
|
|
goto error10;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&DosFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
NdisZeroMemory(&IoStatusBlock, sizeof(IO_STATUS_BLOCK));
|
|
|
|
// We use NtOpenFile in the non-pnp case because it is much easier
|
|
// than trying to map COM1 to \device\serial0. It requires some
|
|
// extra work, because we really need to extract the device object.
|
|
|
|
status = ZwOpenFile(&pThisDev->serialHandle,
|
|
FILE_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
0,
|
|
0);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" NtOpenFile() failed. Returned = 0x%.8x\n", status));
|
|
status = (NTSTATUS)NDIS_STATUS_NOT_ACCEPTED;
|
|
goto error10;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the device object handle to the serial device object.
|
|
//
|
|
status = ObReferenceObjectByHandle(pThisDev->serialHandle,
|
|
FILE_ALL_ACCESS,
|
|
NULL,
|
|
KernelMode,
|
|
&pThisDev->pSerialFileObj,
|
|
NULL);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ObReferenceObjectByHandle() failed. Returned = 0x%.8x\n", status));
|
|
status = (NTSTATUS)NDIS_STATUS_NOT_ACCEPTED;
|
|
|
|
goto error10;
|
|
}
|
|
|
|
//
|
|
// see if we are connected to a com port exposed by a modem.
|
|
// if so fail
|
|
//
|
|
status=CheckForModemPort(pThisDev->pSerialFileObj);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DEBUGMSG(DBG_ERR, (" CheckForModemPort() failed. Returned = 0x%.8x\n", status));
|
|
status = (NTSTATUS)NDIS_STATUS_NOT_ACCEPTED;
|
|
|
|
goto error10;
|
|
}
|
|
|
|
|
|
pThisDev->pSerialDevObj = IoGetRelatedDeviceObject(pThisDev->pSerialFileObj);
|
|
|
|
|
|
status = ObReferenceObjectByPointer(pThisDev->pSerialDevObj,
|
|
FILE_ALL_ACCESS,
|
|
NULL,
|
|
KernelMode);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ObReferenceObjectByPointer() failed. Returned = 0x%.8x\n", status));
|
|
|
|
status = (NTSTATUS)NDIS_STATUS_NOT_ACCEPTED;
|
|
|
|
goto error10;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
error10:
|
|
if (pThisDev->pSerialDevObj)
|
|
{
|
|
if (pThisDev->SerialBased)
|
|
{
|
|
ObDereferenceObject(pThisDev->pSerialDevObj);
|
|
}
|
|
pThisDev->pSerialDevObj = NULL;
|
|
}
|
|
if (pThisDev->pSerialFileObj)
|
|
{
|
|
ObDereferenceObject(pThisDev->pSerialFileObj);
|
|
pThisDev->pSerialFileObj = NULL;
|
|
}
|
|
if (pThisDev->serialHandle)
|
|
{
|
|
NtClose(pThisDev->serialHandle);
|
|
pThisDev->serialHandle = 0;
|
|
}
|
|
|
|
done:
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("-SerialOpen\n"));
|
|
return((NDIS_STATUS)status);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: SerialClose
|
|
*
|
|
* Synopsis: close the serial port
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/8/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NDIS_STATUS
|
|
SerialClose(
|
|
PIR_DEVICE pThisDev
|
|
)
|
|
{
|
|
PIRP pIrp;
|
|
KEVENT eventComplete;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
NDIS_STATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!pThisDev->pSerialDevObj)
|
|
{
|
|
DEBUGMSG(DBG_ERROR, ("IRSIR: SerialDevObj==NULL\n"));
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+SerialClose\n"));
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
|
|
if (!pThisDev->SerialBased)
|
|
{
|
|
//
|
|
// Event to wait for completion of serial driver.
|
|
//
|
|
|
|
KeInitializeEvent(
|
|
&eventComplete,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Send an irp to close the serial device object.
|
|
//
|
|
|
|
//
|
|
// Irp is released by io manager.
|
|
//
|
|
|
|
pIrp = BuildSynchronousCreateCloseRequest(
|
|
pThisDev->pSerialDevObj,
|
|
IRP_MJ_CLOSE,
|
|
&eventComplete,
|
|
&ioStatusBlock
|
|
);
|
|
|
|
if (pIrp == NULL)
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
DEBUGMSG(DBG_OUT, (" IoAllocateIrp failed.\n"));
|
|
|
|
goto done;
|
|
}
|
|
|
|
status = IoCallDriver(pThisDev->pSerialDevObj, pIrp);
|
|
|
|
//
|
|
// If IoCallDriver returns STATUS_PENDING, we need to wait for the event.
|
|
//
|
|
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" IoCallDriver(MJ_CLOSE) PENDING.\n"));
|
|
|
|
KeWaitForSingleObject(
|
|
&eventComplete, // object to wait for
|
|
Executive, // reason to wait
|
|
KernelMode, // processor mode
|
|
FALSE, // alertable
|
|
NULL // timeout
|
|
);
|
|
|
|
//
|
|
// We can get the status of the IoCallDriver from the io status
|
|
// block.
|
|
//
|
|
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
|
|
//
|
|
// If IoCallDriver returns something other that STATUS_PENDING, then it
|
|
// is the same as what the serial driver set in ioStatusBlock.Status.
|
|
//
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_OUT, (" IoCallDriver(MJ_CLOSE) failed. Returned = 0x%.8x\n", status));
|
|
status = (NTSTATUS)NDIS_STATUS_OPEN_FAILED;
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
|
|
if (pThisDev->SerialBased)
|
|
{
|
|
if (pThisDev->pSerialDevObj)
|
|
{
|
|
//
|
|
// Derefence the serial device object.
|
|
//
|
|
ObDereferenceObject(pThisDev->pSerialDevObj);
|
|
pThisDev->pSerialDevObj = NULL;
|
|
}
|
|
if (pThisDev->pSerialFileObj)
|
|
{
|
|
ObDereferenceObject(pThisDev->pSerialFileObj);
|
|
pThisDev->pSerialFileObj = NULL;
|
|
}
|
|
if (pThisDev->serialHandle)
|
|
{
|
|
NtClose(pThisDev->serialHandle);
|
|
pThisDev->serialHandle = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
DEBUGMSG(DBG_FUNC|DBG_PNP, ("-SerialClose\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CheckForModemPort(
|
|
PFILE_OBJECT FileObject
|
|
)
|
|
|
|
{
|
|
|
|
PIRP TempIrp;
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
DeviceObject=IoGetRelatedDeviceObject(FileObject);
|
|
|
|
KeInitializeEvent(
|
|
&Event,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// build an IRP to send to the attched to driver to see if modem
|
|
// is in the stack.
|
|
//
|
|
TempIrp=IoBuildDeviceIoControlRequest(
|
|
IOCTL_MODEM_CHECK_FOR_MODEM,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
FALSE,
|
|
&Event,
|
|
&IoStatus
|
|
);
|
|
|
|
if (TempIrp == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
PIO_STACK_LOCATION NextSp = IoGetNextIrpStackLocation(TempIrp);
|
|
NextSp->FileObject=FileObject;
|
|
|
|
status = IoCallDriver(DeviceObject, TempIrp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject(
|
|
&Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
status=IoStatus.Status;
|
|
}
|
|
|
|
TempIrp=NULL;
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
//
|
|
// if success, then modem.sys is layered under us, fail
|
|
//
|
|
status = STATUS_PORT_DISCONNECTED;
|
|
|
|
} else {
|
|
//
|
|
// it didn't succeed so modem must not be below us
|
|
//
|
|
status=STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|