|
|
/*****************************************************************************
`* * 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>
NTSTATUS GetComPortNtDeviceName( IN PUNICODE_STRING SerialDosName, IN OUT PUNICODE_STRING NtDevName );
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, GetComPortNtDeviceName)
#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; }
NTSTATUS GetComPortNtDeviceName(IN PUNICODE_STRING SerialDosName, IN OUT PUNICODE_STRING NtDevName) /*++
Routine Description:
Retrieves the NT device name (\device\serial0) for a given COM port.
Arguments:
SerialDosName - identifies the port, i.e. COM1 NtDevName - Allocates a buffer (if necessary) and returns the associated nt device name.
Return Value:
STATUS_SUCCESS or error code.
--*/ { UNICODE_STRING registryPath; OBJECT_ATTRIBUTES objectAttributes; HANDLE hKey = 0; PKEY_VALUE_PARTIAL_INFORMATION pKeyValuePartialInfo = 0; PKEY_VALUE_BASIC_INFORMATION pKeyValueBasicInfo = 0; NTSTATUS status = STATUS_SUCCESS; int i; ULONG resultLength; UNICODE_STRING serialTmpString;
DEBUGMSG(DBG_OUT, ("IRSIR: Retrieving NT device name for %wZ\n", SerialDosName));
RtlInitUnicodeString( ®istryPath, L"\\Registry\\Machine\\Hardware\\DeviceMap\\SerialComm" );
//
// Initialize the serial device object name in the context of
// our ir device object.
//
if (!NtDevName->Buffer) { NtDevName->Buffer = MyMemAlloc(MAX_SERIAL_NAME_SIZE); } NtDevName->MaximumLength = MAX_SERIAL_NAME_SIZE; NtDevName->Length = 0;
InitializeObjectAttributes( &objectAttributes, ®istryPath, OBJ_CASE_INSENSITIVE, NULL, NULL );
hKey = NULL;
status = ZwOpenKey( &hKey, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &objectAttributes );
if (status != STATUS_SUCCESS) { //DEBUGMSG(DBG_ERR, (" ZwOpenKey failed = 0x%.8x\n", status));
goto error10; }
pKeyValuePartialInfo = MyMemAlloc(sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256); pKeyValueBasicInfo = MyMemAlloc(sizeof(KEY_VALUE_BASIC_INFORMATION) + 256);
if (pKeyValuePartialInfo && pKeyValueBasicInfo) { for (i = 0; ; i++) { NdisZeroMemory( pKeyValuePartialInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 );
NdisZeroMemory( pKeyValueBasicInfo, sizeof(KEY_VALUE_BASIC_INFORMATION) + 256 );
status = ZwEnumerateValueKey( hKey, i, KeyValuePartialInformation, pKeyValuePartialInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256, &resultLength );
if (status != STATUS_SUCCESS) { if (status != STATUS_NO_MORE_ENTRIES) { DEBUGMSG(DBG_ERR, (" ZwEnumerateValueKey failed = 0x%.8x\n", status)); } else { DEBUGMSG(DBG_ERR, (" Valid comm port not found.\n")); status = NDIS_STATUS_ADAPTER_NOT_FOUND; }
break; }
pKeyValuePartialInfo->Data[pKeyValuePartialInfo->DataLength/sizeof(WCHAR)] = UNICODE_NULL;
RtlInitUnicodeString( &serialTmpString, (PCWSTR)pKeyValuePartialInfo->Data );
DEBUGMSG(DBG_OUT, (" Value found = %wZ\n", &serialTmpString));
if (RtlCompareUnicodeString( &serialTmpString, SerialDosName, TRUE) // ignore case
== 0)
{ //
// We have found the comm port. Now we need to get the
// name like SerialX.
//
status = ZwEnumerateValueKey( hKey, i, KeyValueBasicInformation, pKeyValueBasicInfo, sizeof(KEY_VALUE_BASIC_INFORMATION) + 256, &resultLength );
if (status != STATUS_SUCCESS) { if (status != STATUS_NO_MORE_ENTRIES) { DEBUGMSG(DBG_ERR, (" ZwEnumerateValueKey failed = 0x%.8x\n", status)); } else { DEBUGMSG(DBG_ERR, (" COMx != Serial?.\n")); }
break; }
//
// We have our key name.
//
if (pKeyValueBasicInfo->Name[0]!=L'\\') { //
// The key name needs to start with \Device\,
// and apparently this one doesn't. Add it.
//
RtlAppendUnicodeToString(NtDevName, L"\\Device\\"); }
//
// Append the name.
//
status = RtlAppendUnicodeToString( NtDevName, pKeyValueBasicInfo->Name );
if (status != STATUS_SUCCESS) { DEBUGMSG(DBG_ERR, (" RtlAppendUnicodeToString failed = 0x%.8x\n", status)); }
break; } // if RtlCompareUnicodeString
} // for
}
//
// NOTE: This path is not necessarily STATUS_SUCCESS.
//
if (pKeyValueBasicInfo) { MyMemFree( pKeyValueBasicInfo, sizeof(KEY_VALUE_BASIC_INFORMATION) + 256 ); } if (pKeyValuePartialInfo) { MyMemFree( pKeyValuePartialInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 ); } if (hKey) { ZwClose(hKey); } error10:; 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[32];
DosFileName.Length = 0; DosFileName.MaximumLength = sizeof(DosFileNameBuffer); DosFileName.Buffer = DosFileNameBuffer;
RtlAppendUnicodeToString(&DosFileName, L"\\DosDevices\\"); RtlAppendUnicodeStringToString(&DosFileName, &pThisDev->serialDosName);
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;
}
|