You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1975 lines
56 KiB
1975 lines
56 KiB
/*++
|
|
|
|
Module Name:
|
|
|
|
Pnp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that handles the plug and play
|
|
IRPs for the serial driver.
|
|
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
#if 0
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text(PAGEMX0, MoxaCreateDevObj)
|
|
#pragma alloc_text(PAGEMX0, MoxaAddDevice)
|
|
#pragma alloc_text(PAGEMX0, MoxaPnpDispatch)
|
|
#pragma alloc_text(PAGEMX0, MoxaStartDevice)
|
|
#pragma alloc_text(PAGEMX0, MoxaFinishStartDevice)
|
|
#pragma alloc_text(PAGEMX0, MoxaGetPortInfo)
|
|
#pragma alloc_text(PAGEMX0, MoxaDoExternalNaming)
|
|
#pragma alloc_text(PAGEMX0, MoxaUndoExternalNaming)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
#endif
|
|
|
|
//
|
|
// Instantiate the GUID
|
|
//
|
|
|
|
#if !defined(FAR)
|
|
#define FAR
|
|
#endif // !defined(FAR)
|
|
|
|
#include <initguid.h>
|
|
|
|
DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08,
|
|
0x00, 0x3e, 0x30, 0x1f, 0x73);
|
|
|
|
|
|
#if DBG
|
|
|
|
UCHAR *SerSystemCapString[] = {
|
|
"PowerSystemUnspecified",
|
|
"PowerSystemWorking",
|
|
"PowerSystemSleeping1",
|
|
"PowerSystemSleeping2",
|
|
"PowerSystemSleeping3",
|
|
"PowerSystemHibernate",
|
|
"PowerSystemShutdown",
|
|
"PowerSystemMaximum"
|
|
};
|
|
|
|
UCHAR *SerDeviceCapString[] = {
|
|
"PowerDeviceUnspecified",
|
|
"PowerDeviceD0",
|
|
"PowerDeviceD1",
|
|
"PowerDeviceD2",
|
|
"PowerDeviceD3",
|
|
"PowerDeviceMaximum"
|
|
};
|
|
|
|
#endif // DBG
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaSyncCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
|
|
IN PKEVENT MoxaSyncEvent)
|
|
{
|
|
|
|
KeSetEvent(MoxaSyncEvent, IO_NO_INCREMENT, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaCreateDevObj(IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING pDeviceObjName,
|
|
IN PDEVICE_SETTINGS pSettings,
|
|
OUT PDEVICE_OBJECT *NewDeviceObject)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will create and initialize a functional device object to
|
|
be attached to a Serial controller PDO.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the driver object this is created under
|
|
NewDeviceObject - a location to store the pointer to the new device object
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if everything was successful
|
|
reason for failure otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
PMOXA_DEVICE_EXTENSION pDevExt = NULL;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE pnpKey;
|
|
ULONG maxBaud,rxBufferSize,txBufferSize;
|
|
|
|
// PAGED_CODE ();
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Enter MoxaCreateDevObj\n"));
|
|
|
|
if (pDeviceObjName == NULL) {
|
|
MoxaLogError(DriverObject, NULL, MoxaPhysicalZero, MoxaPhysicalZero,
|
|
0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
MoxaKdPrint(MX_DBG_ERROR,("MoxaCreateDevice: Couldn't allocate memory for device name\n"));
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Create the device object
|
|
//
|
|
MoxaKdPrint(MX_DBG_TRACE,("Create the device object\n"));
|
|
|
|
status = IoCreateDevice(DriverObject, sizeof(MOXA_DEVICE_EXTENSION),
|
|
pDeviceObjName, FILE_DEVICE_SERIAL_PORT, 0, TRUE,
|
|
&deviceObject);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
MoxaKdPrint(MX_DBG_ERROR,("MoxaAddDevice: Create device failed - %x \n",
|
|
status));
|
|
goto MoxaCreateDevObjError;
|
|
}
|
|
|
|
//ASSERT(deviceObject != NULL);
|
|
|
|
|
|
//
|
|
// The device object has a pointer to an area of non-paged
|
|
// pool allocated for this device. This will be the device
|
|
// extension. Zero it out.
|
|
//
|
|
|
|
pDevExt = deviceObject->DeviceExtension;
|
|
RtlZeroMemory(pDevExt, sizeof(MOXA_DEVICE_EXTENSION));
|
|
|
|
|
|
//
|
|
// Allocate Pool and save the nt device name in the device extension.
|
|
//
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Allocate Pool and save the nt device name in the device extension\n"));
|
|
pDevExt->DeviceName.Buffer =
|
|
ExAllocatePool(PagedPool, pDeviceObjName->Length + sizeof(WCHAR));
|
|
|
|
if (!pDevExt->DeviceName.Buffer) {
|
|
|
|
MoxaLogError(
|
|
DriverObject,
|
|
NULL,
|
|
MoxaPhysicalZero,
|
|
MoxaPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
19,
|
|
STATUS_SUCCESS,
|
|
SERIAL_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
MoxaKdPrint(MX_DBG_ERROR,
|
|
("MoxaAddDevice: Couldn't allocate memory for DeviceName\n"));
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto MoxaCreateDevObjError;
|
|
}
|
|
|
|
pDevExt->DeviceName.MaximumLength = pDeviceObjName->Length
|
|
+ sizeof(WCHAR);
|
|
|
|
//
|
|
// Zero fill it.
|
|
//
|
|
|
|
RtlZeroMemory(pDevExt->DeviceName.Buffer,
|
|
pDevExt->DeviceName.MaximumLength);
|
|
|
|
RtlAppendUnicodeStringToString(&pDevExt->DeviceName, pDeviceObjName);
|
|
|
|
|
|
//
|
|
// Set up the device extension.
|
|
//
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Set up the device extension\n"));
|
|
|
|
pDevExt->PortBase = pSettings->BaseAddress;
|
|
pDevExt->PortOfs = pSettings->BaseAddress + Extern_table + Extern_size * pSettings->PortIndex;
|
|
|
|
pDevExt->DeviceObject = deviceObject;
|
|
pDevExt->DriverObject = DriverObject;
|
|
|
|
switch (pSettings->BoardType) {
|
|
case C218ISA :
|
|
case C218PCI :
|
|
case CP204J :
|
|
maxBaud = 921600L;
|
|
rxBufferSize = C218rx_size;
|
|
txBufferSize = C218tx_size;
|
|
break;
|
|
default :
|
|
maxBaud = 460800L;
|
|
switch (pSettings->NumPorts) {
|
|
case 8 :
|
|
rxBufferSize = C320p8rx_size;
|
|
txBufferSize = C320p8tx_size;
|
|
break;
|
|
case 16 :
|
|
rxBufferSize = C320p16rx_size;
|
|
txBufferSize = C320p16tx_size;
|
|
break;
|
|
case 24 :
|
|
rxBufferSize = C320p24rx_size;
|
|
txBufferSize = C320p24tx_size;
|
|
break;
|
|
case 32 :
|
|
rxBufferSize = C320p32rx_size;
|
|
txBufferSize = C320p32tx_size;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
MoxaKdPrint(MX_DBG_TRACE,("Init port,%d,%d,%d\n",rxBufferSize,txBufferSize,maxBaud));
|
|
InitPort(pDevExt,rxBufferSize ,txBufferSize ,maxBaud);
|
|
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
*NewDeviceObject = deviceObject;
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Leave MoxaCreateDevObj\n") );
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
MoxaCreateDevObjError:
|
|
|
|
MoxaKdPrint(MX_DBG_ERROR,("MoxaCreateDevObj Error, Cleaning up\n") );
|
|
|
|
//
|
|
// Free the allocated strings for the NT and symbolic names if they exist.
|
|
//
|
|
|
|
if (pDevExt) {
|
|
if (pDevExt->DeviceName.Buffer != NULL) {
|
|
ExFreePool(pDevExt->DeviceName.Buffer);
|
|
}
|
|
}
|
|
if (deviceObject) {
|
|
IoDeleteDevice(deviceObject);
|
|
}
|
|
|
|
|
|
*NewDeviceObject = NULL;
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Leave MoxaCreateDevObj\n") );
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MoxaAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PPdo)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a functional device object for com ports in the
|
|
system and attaches them to the physical device objects for the ports
|
|
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the object for this driver
|
|
|
|
PPdo - a pointer to the PDO in the stack we need to attach to
|
|
|
|
Return Value:
|
|
|
|
status from device creation and initialization
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_OBJECT pNewDevObj = NULL;
|
|
PDEVICE_OBJECT pLowerDevObj = NULL;
|
|
NTSTATUS status;
|
|
PMOXA_DEVICE_EXTENSION pDevExt;
|
|
HANDLE keyHandle;
|
|
UNICODE_STRING deviceObjName;
|
|
DEVICE_SETTINGS settings;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
KEVENT event;
|
|
ULONG comNo,i;
|
|
WCHAR comName[8];
|
|
|
|
|
|
|
|
//PAGED_CODE();
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Enter MoxaAddDevice with PPdo 0x%x\n", PPdo));
|
|
|
|
if (PPdo == NULL) {
|
|
//
|
|
// Return no more devices
|
|
//
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("NO_MORE_ENTRIES\n"));
|
|
|
|
return (STATUS_NO_MORE_ENTRIES);
|
|
}
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("MoxaIoSyncIoctlEx\n"));
|
|
|
|
status = MoxaIoSyncIoctlEx(IOCTL_MOXA_INTERNAL_BASIC_SETTINGS, TRUE,
|
|
PPdo, &event, &IoStatusBlock,
|
|
NULL, 0, &settings,
|
|
sizeof(DEVICE_SETTINGS));
|
|
MoxaKdPrint(MX_DBG_TRACE,("status=%x\n",status));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
MoxaKdPrint (MX_DBG_TRACE,("Get settings Fail\n"));
|
|
status = STATUS_UNSUCCESSFUL;
|
|
return(status);
|
|
}
|
|
|
|
|
|
status = IoOpenDeviceRegistryKey(PPdo, PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_READ, &keyHandle);
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// This is a fatal error. If we can't get to our registry key,
|
|
// we are sunk.
|
|
//
|
|
MoxaKdPrint (MX_DBG_TRACE,
|
|
("IoOpenDeviceRegistryKey failed - %x\n", status));
|
|
return (status);
|
|
|
|
}
|
|
|
|
status = MoxaGetRegistryKeyValue(
|
|
keyHandle,
|
|
L"PortName",
|
|
sizeof(L"PortName"),
|
|
comName,
|
|
sizeof(comName),
|
|
&i);
|
|
|
|
ZwClose(keyHandle);
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
comName[i >>1] = (WCHAR )0;
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Get settings OK\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE,("BoardIndex = %x\n",settings.BoardIndex));
|
|
MoxaKdPrint (MX_DBG_TRACE,("PortIndex = %x\n",settings.PortIndex));
|
|
MoxaKdPrint (MX_DBG_TRACE,("InterfaceType = %x\n",settings.InterfaceType));
|
|
MoxaKdPrint (MX_DBG_TRACE,("BusNumber = %x\n",settings.BusNumber));
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("OriginalBaseAddress = %x\n",settings.OriginalBaseAddress.LowPart));
|
|
MoxaKdPrint (MX_DBG_TRACE,("OriginalAckPort = %x\n",settings.OriginalAckPort.LowPart));
|
|
MoxaKdPrint (MX_DBG_TRACE,("BaseAddress = %x\n",settings.BaseAddress));
|
|
MoxaKdPrint (MX_DBG_TRACE,("AckPort = %x\n",settings.AckPort));
|
|
MoxaKdPrint (MX_DBG_TRACE,("InterruptVector = %x\n",settings.Interrupt.Vector));
|
|
MoxaKdPrint (MX_DBG_TRACE,("InterruptLevel = %x\n",settings.Interrupt.Level));
|
|
MoxaKdPrint (MX_DBG_TRACE,("InterruptAffinity = %x\n",settings.Interrupt.Affinity));
|
|
|
|
// MoxaKdPrint (MX_DBG_TRACE,("ComName = %ws\n",comName));
|
|
|
|
|
|
}
|
|
else {
|
|
MoxaKdPrint (MX_DBG_TRACE,("Get settings Fail\n"));
|
|
status = STATUS_UNSUCCESSFUL;
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Zero out allocated memory pointers so we know if they must be freed
|
|
//
|
|
|
|
deviceObjName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR)
|
|
+ sizeof(WCHAR);
|
|
|
|
deviceObjName.Buffer = ExAllocatePool(PagedPool,deviceObjName.MaximumLength);
|
|
if (deviceObjName.Buffer == NULL) {
|
|
MoxaKdPrint(MX_DBG_ERROR,("Unable to allocate buffer for device object name\n"));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return (status);
|
|
}
|
|
|
|
|
|
RtlZeroMemory(deviceObjName.Buffer,deviceObjName.MaximumLength);
|
|
deviceObjName.Length = 0;
|
|
|
|
RtlAppendUnicodeToString(&deviceObjName, L"\\Device\\MxcardB00P000");
|
|
|
|
deviceObjName.Buffer[15] = (WCHAR)('0' + settings.BoardIndex / 10);
|
|
deviceObjName.Buffer[16] = (WCHAR)('0' + settings.BoardIndex % 10);
|
|
deviceObjName.Buffer[18] = (WCHAR)('0' + settings.PortIndex / 100);
|
|
deviceObjName.Buffer[19] = (WCHAR)('0' + (settings.PortIndex % 100)/10);
|
|
deviceObjName.Buffer[20] = (WCHAR)('0' + (settings.PortIndex % 100)%10);
|
|
// MoxaKdPrint(MX_DBG_TRACE,("Device->%ws\n",deviceObjName.Buffer));
|
|
|
|
//
|
|
// create and initialize the new device object
|
|
//
|
|
|
|
status = MoxaCreateDevObj(DriverObject, &deviceObjName,&settings,&pNewDevObj);
|
|
|
|
if (deviceObjName.Buffer)
|
|
ExFreePool(deviceObjName.Buffer);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
MoxaKdPrint(MX_DBG_ERROR,
|
|
("MoxaAddDevice - error creating new devobj [%#08lx]\n",
|
|
status));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//
|
|
// Layer our DO on top of the lower device object
|
|
// The return value is a pointer to the device object to which the
|
|
// DO is actually attached.
|
|
//
|
|
|
|
pLowerDevObj = IoAttachDeviceToDeviceStack(pNewDevObj, PPdo);
|
|
|
|
|
|
//
|
|
// No status. Do the best we can.
|
|
//
|
|
//ASSERT(pLowerDevObj != NULL);
|
|
|
|
|
|
pDevExt = pNewDevObj->DeviceExtension;
|
|
pDevExt->LowerDeviceObject = pLowerDevObj;
|
|
pDevExt->Pdo = PPdo;
|
|
|
|
//
|
|
// Make the device visible via a device association as well.
|
|
// The reference string is the eight digit device index
|
|
//
|
|
status = IoRegisterDeviceInterface(PPdo, (LPGUID)&GUID_CLASS_COMPORT,
|
|
NULL, &pDevExt->DeviceClassSymbolicName);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
/*
|
|
MoxaKdPrint (MX_DBG_ERROR,("Couldn't register class association\n"
|
|
"------- for port %wZ\n",
|
|
&pDevExt->DeviceName));
|
|
|
|
*/
|
|
pDevExt->DeviceClassSymbolicName.Buffer = NULL;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Specify that this driver only supports buffered IO. This basically
|
|
// means that the IO system copies the users data to and from
|
|
// system supplied buffers.
|
|
//
|
|
// Also specify that we are power pagable.
|
|
//
|
|
|
|
pNewDevObj->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
|
|
|
|
//
|
|
// Fill in global data
|
|
//
|
|
|
|
for (i = 0; i < MAX_CARD; i++)
|
|
if ((MoxaGlobalData->CardType[i])
|
|
&&(MoxaGlobalData->BoardIndex[i] == settings.BoardIndex))
|
|
break;
|
|
if (i == MAX_CARD) {
|
|
for (i = 0; i < MAX_CARD; i++)
|
|
if (!MoxaGlobalData->CardType[i])
|
|
break;
|
|
MoxaGlobalData->BoardIndex[i] = settings.BoardIndex;
|
|
}
|
|
pDevExt->BoardNo = i;
|
|
MoxaKdPrint(MX_DBG_TRACE,("Board Number = %d\n",pDevExt->BoardNo));
|
|
if (!MoxaGlobalData->CardType[pDevExt->BoardNo]) {
|
|
MoxaGlobalData->PciBusNum[pDevExt->BoardNo] = (USHORT)settings.BusNumber;
|
|
// USHORT PciDevNum[MAX_CARD];
|
|
MoxaGlobalData->InterfaceType[pDevExt->BoardNo] = settings.InterfaceType;
|
|
MoxaGlobalData->IntVector[pDevExt->BoardNo]= settings.Interrupt.Vector;
|
|
RtlCopyMemory(&MoxaGlobalData->PciIntAckPort[pDevExt->BoardNo],&settings.OriginalAckPort,sizeof(PHYSICAL_ADDRESS));
|
|
RtlCopyMemory(&MoxaGlobalData->BankAddr[pDevExt->BoardNo],&settings.OriginalBaseAddress,sizeof(PHYSICAL_ADDRESS));
|
|
MoxaGlobalData->PciIntAckBase[pDevExt->BoardNo] = settings.AckPort;
|
|
MoxaGlobalData->CardType[pDevExt->BoardNo] = settings.BoardType;
|
|
|
|
MoxaGlobalData->CardBase[pDevExt->BoardNo] = settings.BaseAddress;
|
|
MoxaGlobalData->IntNdx[pDevExt->BoardNo] = (PUSHORT)(settings.BaseAddress + IRQindex);
|
|
MoxaGlobalData->IntPend[pDevExt->BoardNo] = settings.BaseAddress + IRQpending;
|
|
MoxaGlobalData->IntTable[pDevExt->BoardNo] = settings.BaseAddress + IRQtable;
|
|
MoxaGlobalData->NumPorts[pDevExt->BoardNo] = settings.NumPorts;
|
|
MoxaKdPrint(MX_DBG_TRACE,("Int ndx,pend,table = %x,%x,%x\n",
|
|
MoxaGlobalData->IntNdx[pDevExt->BoardNo],
|
|
MoxaGlobalData->IntPend[pDevExt->BoardNo],
|
|
MoxaGlobalData->IntTable[pDevExt->BoardNo])
|
|
);
|
|
}
|
|
|
|
pDevExt->PortIndex = settings.PortIndex;
|
|
pDevExt->PortNo = pDevExt->BoardNo*MAXPORT_PER_CARD + settings.PortIndex;
|
|
RtlZeroMemory(pDevExt->DosName,
|
|
sizeof(pDevExt->DosName));
|
|
RtlCopyMemory(pDevExt->DosName,
|
|
comName,
|
|
wcslen(comName)*sizeof(WCHAR)
|
|
);
|
|
|
|
|
|
comNo = wcslen(comName);
|
|
if (comNo >= 4) {
|
|
comNo -= 3;
|
|
if (comNo >= 3) {
|
|
comNo = (comName[5] - '0') +
|
|
(comName[4] - '0')*10 +
|
|
(comName[3] - '0')*100;
|
|
}
|
|
else if (comNo >= 2) {
|
|
comNo = (comName[4] - '0') +
|
|
(comName[3] - '0')*10;
|
|
|
|
}
|
|
else if (comNo >= 1) {
|
|
comNo = (comName[3] - '0');
|
|
}
|
|
|
|
}
|
|
MoxaKdPrint(MX_DBG_TRACE,("ComNo=%d/len=%d\n",comNo,wcslen(comName)));
|
|
if ((comNo > 0) && (comNo <= MAX_COM)) {
|
|
MoxaExtension[comNo] = pDevExt;
|
|
MoxaGlobalData->ComNo[pDevExt->BoardNo][pDevExt->PortIndex] = (USHORT)comNo;
|
|
}
|
|
else
|
|
comNo = 0;
|
|
MoxaGlobalData->Extension[pDevExt->PortNo] = pDevExt;
|
|
MoxaKdPrint(MX_DBG_TRACE,("Leave MoxaAddDevice\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MoxaFinishStartDevice(IN PDEVICE_OBJECT PDevObj)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does serial-specific procedures to start a device. It
|
|
does this either for a legacy device detected by its registry entries,
|
|
or for a PnP device after the start IRP has been sent down the stack.
|
|
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the devobj that is starting
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS on success, something else appropriate on failure
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE pnpKey;
|
|
ULONG i,com,one = 1;
|
|
PKINTERRUPT moxaInterrupt;
|
|
ULONG systemVector;
|
|
KIRQL irql;
|
|
KAFFINITY processorAffinity;
|
|
PMOXA_CISR_SW cisrsw;
|
|
PMOXA_MULTIPORT_DISPATCH dispatch;
|
|
|
|
|
|
|
|
//PAGED_CODE();
|
|
|
|
//
|
|
// See if this is a restart, and if so don't reallocate the world
|
|
//
|
|
|
|
if (pDevExt->Flags & SERIAL_FLAGS_STOPPED) {
|
|
|
|
MoxaClearFlags(pDevExt, SERIAL_FLAGS_STOPPED);
|
|
|
|
pDevExt->PNPState = SERIAL_PNP_RESTARTING;
|
|
|
|
}
|
|
|
|
//
|
|
// See if we are in the proper power state.
|
|
//
|
|
|
|
|
|
if (pDevExt->PowerState != PowerDeviceD0) {
|
|
|
|
status = MoxaGotoPowerState(pDevExt->Pdo, pDevExt, PowerDeviceD0);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto MoxaFinishStartDeviceError;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The hardware that is set up to NOT interrupt, connect an interrupt.
|
|
//
|
|
|
|
if (!(MoxaGlobalData->Interrupt[pDevExt->BoardNo])
|
|
&& MoxaGlobalData->IntVector[pDevExt->BoardNo]) {
|
|
|
|
KINTERRUPT_MODE interruptMode;
|
|
|
|
/*
|
|
MoxaKdPrint(MX_DBG_ERROR,("About to connect to interrupt for port %wZ\n"
|
|
"------- address of extension is %x\n"
|
|
"------- interface of device is %x\n"
|
|
"------- bus number of device is %x\n"
|
|
"------- int. vector of device is %x\n"
|
|
"------- type of device is %d\n",
|
|
&pDevExt->DeviceName, pDevExt,
|
|
MoxaGlobalData->InterfaceType[pDevExt->BoardNo],
|
|
MoxaGlobalData->PciBusNum[pDevExt->BoardNo],
|
|
MoxaGlobalData->IntVector[pDevExt->BoardNo],
|
|
MoxaGlobalData->CardType[pDevExt->BoardNo])
|
|
);
|
|
*/
|
|
cisrsw = ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof(MOXA_CISR_SW)
|
|
);
|
|
|
|
if (!cisrsw) {
|
|
/*
|
|
MoxaKdPrint(MX_DBG_ERROR,("Couldn't allocate CISR_SW for "
|
|
"%wZ\n", &pDevExt->DeviceName));
|
|
*/
|
|
status = SERIAL_INSUFFICIENT_RESOURCES;
|
|
MoxaLogError(PDevObj->DriverObject, NULL,
|
|
MoxaPhysicalZero,
|
|
MoxaPhysicalZero, 0, 0, 0, 1, status,
|
|
SERIAL_INSUFFICIENT_RESOURCES,
|
|
pDevExt->DeviceName.Length + sizeof(WCHAR),
|
|
pDevExt->DeviceName.Buffer, 0, NULL);
|
|
|
|
|
|
goto MoxaFinishStartDeviceError;
|
|
}
|
|
dispatch = &cisrsw->Dispatch;
|
|
|
|
dispatch->BoardNo = pDevExt->BoardNo;
|
|
dispatch->GlobalData = MoxaGlobalData;
|
|
|
|
for (i = 0; i < MAX_CARD; i++)
|
|
if ((MoxaGlobalData->Interrupt[i]) &&
|
|
(MoxaGlobalData->IntVector[i] == MoxaGlobalData->IntVector[pDevExt->BoardNo])&&
|
|
(MoxaGlobalData->InterfaceType[i] == MoxaGlobalData->InterfaceType[pDevExt->BoardNo]))
|
|
break;
|
|
|
|
if (i != MAX_CARD) {
|
|
MoxaGlobalData->Interrupt[pDevExt->BoardNo] =
|
|
pDevExt->Interrupt = MoxaGlobalData->Interrupt[i];
|
|
MoxaGlobalData->Irql[pDevExt->BoardNo] = MoxaGlobalData->Irql[i];
|
|
MoxaGlobalData->ProcessorAffinity[pDevExt->BoardNo] = MoxaGlobalData->ProcessorAffinity[i];
|
|
pDevExt->InterruptShareList=
|
|
MoxaGlobalData->InterruptShareList[pDevExt->BoardNo] = MoxaGlobalData->InterruptShareList[i];
|
|
InsertTailList(pDevExt->InterruptShareList,&cisrsw->SharerList);
|
|
MoxaKdPrint(MX_DBG_ERROR,("Interrupt share with %d/%x\n",i,
|
|
pDevExt->InterruptShareList));
|
|
|
|
|
|
|
|
}
|
|
else {
|
|
/* for debug
|
|
PLIST_ENTRY interruptEntry;
|
|
PMOXA_CISR_SW cisrsw1;
|
|
*/
|
|
|
|
MoxaGlobalData->InterruptShareList[pDevExt->BoardNo] = ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof(LIST_ENTRY)
|
|
);
|
|
|
|
if (!MoxaGlobalData->InterruptShareList[pDevExt->BoardNo]) {
|
|
/*
|
|
MoxaKdPrint(MX_DBG_ERROR,("Couldn't allocate InterruptShareList for "
|
|
"%wZ\n", &pDevExt->DeviceName));
|
|
*/
|
|
ExFreePool(cisrsw);
|
|
status = SERIAL_INSUFFICIENT_RESOURCES;
|
|
MoxaLogError(PDevObj->DriverObject, NULL,
|
|
MoxaPhysicalZero,
|
|
MoxaPhysicalZero, 0, 0, 0, 1, status,
|
|
SERIAL_INSUFFICIENT_RESOURCES,
|
|
pDevExt->DeviceName.Length + sizeof(WCHAR),
|
|
pDevExt->DeviceName.Buffer, 0, NULL);
|
|
|
|
|
|
goto MoxaFinishStartDeviceError;
|
|
}
|
|
|
|
pDevExt->InterruptShareList=MoxaGlobalData->InterruptShareList[pDevExt->BoardNo];
|
|
|
|
InitializeListHead(pDevExt->InterruptShareList);
|
|
|
|
InsertTailList(pDevExt->InterruptShareList,&cisrsw->SharerList);
|
|
/*
|
|
interruptEntry = interruptEntry->Flink;
|
|
MoxaKdPrint(MX_DBG_ERROR,("list entry %x/%x/%x\n",interruptEntry,interruptEntry->Flink,
|
|
interruptEntry->Blink));
|
|
interruptEntry = pDevExt->InterruptShareList;
|
|
MoxaKdPrint(MX_DBG_ERROR,("list head %x/%x/%x\n",interruptEntry,interruptEntry->Flink,
|
|
interruptEntry->Blink));
|
|
|
|
|
|
if (IsListEmpty(MoxaGlobalData->InterruptShareList[pDevExt->BoardNo]))
|
|
MoxaKdPrint(MX_DBG_ERROR,("list empty\n"));
|
|
cisrsw1 = CONTAINING_RECORD( interruptEntry,
|
|
MOXA_CISR_SW,
|
|
SharerList
|
|
);
|
|
MoxaKdPrint(MX_DBG_ERROR,("cisrsw %x/%x\n",cisrsw,cisrsw1));
|
|
|
|
|
|
|
|
*/
|
|
|
|
systemVector = HalGetInterruptVector(
|
|
(ULONG)MoxaGlobalData->InterfaceType[pDevExt->BoardNo],
|
|
(ULONG)MoxaGlobalData->PciBusNum[pDevExt->BoardNo],
|
|
MoxaGlobalData->IntVector[pDevExt->BoardNo],
|
|
MoxaGlobalData->IntVector[pDevExt->BoardNo],
|
|
&irql,
|
|
&processorAffinity
|
|
);
|
|
|
|
MoxaKdPrint(MX_DBG_ERROR,("System Vector = %x,%x,%x,%x\n",systemVector,irql,processorAffinity,
|
|
MoxaGlobalData->InterruptShareList[pDevExt->BoardNo]));
|
|
|
|
if (MoxaGlobalData->InterfaceType[pDevExt->BoardNo] == PCIBus)
|
|
interruptMode = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
|
else
|
|
interruptMode = CM_RESOURCE_INTERRUPT_LATCHED;
|
|
|
|
status = IoConnectInterrupt(
|
|
&moxaInterrupt,
|
|
MoxaISR,
|
|
MoxaGlobalData->InterruptShareList[pDevExt->BoardNo],
|
|
NULL,
|
|
systemVector,
|
|
irql,
|
|
irql,
|
|
interruptMode,
|
|
TRUE,
|
|
processorAffinity,
|
|
FALSE
|
|
);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
/*
|
|
MoxaKdPrint(MX_DBG_ERROR,("Couldn't connect to interrupt for "
|
|
"%wZ(status=%x)\n", &pDevExt->DeviceName,status));
|
|
*/
|
|
ExFreePool(cisrsw);
|
|
|
|
status = SERIAL_UNREPORTED_IRQL_CONFLICT;
|
|
MoxaLogError(PDevObj->DriverObject, NULL,
|
|
MoxaPhysicalZero,
|
|
MoxaPhysicalZero, 0, 0, 0, 1, status,
|
|
SERIAL_UNREPORTED_IRQL_CONFLICT,
|
|
pDevExt->DeviceName.Length + sizeof(WCHAR),
|
|
pDevExt->DeviceName.Buffer, 0, NULL);
|
|
|
|
|
|
goto MoxaFinishStartDeviceError;
|
|
}
|
|
MoxaGlobalData->Interrupt[pDevExt->BoardNo] =
|
|
pDevExt->Interrupt = moxaInterrupt;
|
|
MoxaGlobalData->Irql[pDevExt->BoardNo] = irql;
|
|
MoxaGlobalData->ProcessorAffinity[pDevExt->BoardNo] = processorAffinity;
|
|
}
|
|
|
|
}
|
|
else {
|
|
pDevExt->Interrupt = MoxaGlobalData->Interrupt[pDevExt->BoardNo];
|
|
pDevExt->InterruptShareList=MoxaGlobalData->InterruptShareList[pDevExt->BoardNo];
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Add the PDevObj to the master list
|
|
//
|
|
|
|
// InsertTailList(&MoxaGlobalData->AllDevObjs, &pDevExt->AllDevObjs);
|
|
|
|
|
|
//
|
|
// This should set up everything as it should be when
|
|
// a device is to be opened. We do need to lower the
|
|
// modem lines, and disable the recalcitrant fifo
|
|
// so that it will show up if the user boots to dos.
|
|
//
|
|
/*
|
|
|
|
KeSynchronizeExecution( //Disables the fifo.
|
|
pDevExt->Interrupt,
|
|
SerialMarkClose,
|
|
pDevExt
|
|
);
|
|
*/
|
|
|
|
if (pDevExt->PNPState == SERIAL_PNP_ADDED ) {
|
|
|
|
//
|
|
// Do the external naming now that the device is accessible.
|
|
//
|
|
|
|
status = MoxaDoExternalNaming(pDevExt, pDevExt->DeviceObject->
|
|
DriverObject);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
MoxaKdPrint(MX_DBG_ERROR,("External Naming Failed - Status %x\n",
|
|
status));
|
|
|
|
//
|
|
// Allow the device to start anyhow
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
// goto MoxaFinishStartDeviceError;
|
|
|
|
}
|
|
|
|
} else {
|
|
MoxaKdPrint(MX_DBG_ERROR,("Not doing external naming -- state is %x\n",
|
|
pDevExt->PNPState));
|
|
}
|
|
|
|
|
|
MoxaFinishStartDeviceError:;
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Cleaning up failed start\n"));
|
|
|
|
//
|
|
// Resources created by this routine will be cleaned up by the remove
|
|
//
|
|
|
|
if (pDevExt->PNPState == SERIAL_PNP_RESTARTING) {
|
|
//
|
|
// Kill all that lives and breathes -- we'll clean up the
|
|
// rest on the impending remove
|
|
//
|
|
|
|
MoxaKillPendingIrps(PDevObj);
|
|
|
|
//
|
|
// In fact, pretend we're removing so we don't take any
|
|
// more irps
|
|
//
|
|
|
|
MoxaSetAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING);
|
|
MoxaClearFlags(pDevExt, SERIAL_FLAGS_STARTED);
|
|
}
|
|
} else { // SUCCESS
|
|
|
|
//
|
|
// Fill in WMI hardware data
|
|
//
|
|
|
|
pDevExt->WmiHwData.IrqNumber = MoxaGlobalData->Irql[pDevExt->BoardNo];
|
|
pDevExt->WmiHwData.IrqLevel = MoxaGlobalData->Irql[pDevExt->BoardNo];
|
|
pDevExt->WmiHwData.IrqVector = MoxaGlobalData->IntVector[pDevExt->BoardNo];
|
|
pDevExt->WmiHwData.IrqAffinityMask =MoxaGlobalData->ProcessorAffinity[pDevExt->BoardNo];
|
|
pDevExt->WmiHwData.InterruptType = SERIAL_WMI_INTTYPE_LATCHED;
|
|
pDevExt->WmiHwData.BaseIOAddress = (ULONGLONG)MoxaGlobalData->BankAddr[pDevExt->BoardNo].LowPart;
|
|
|
|
|
|
//
|
|
// Fill in WMI device state data (as defaults)
|
|
//
|
|
|
|
pDevExt->WmiCommData.BaudRate = pDevExt->CurrentBaud;
|
|
switch (pDevExt->DataMode & MOXA_DATA_MASK) {
|
|
case MOXA_5_DATA :
|
|
pDevExt->WmiCommData.BitsPerByte = 5;
|
|
break;
|
|
case MOXA_6_DATA :
|
|
pDevExt->WmiCommData.BitsPerByte = 6;
|
|
break;
|
|
case MOXA_7_DATA :
|
|
pDevExt->WmiCommData.BitsPerByte = 7;
|
|
break;
|
|
case MOXA_8_DATA :
|
|
default :
|
|
pDevExt->WmiCommData.BitsPerByte = 8;
|
|
break;
|
|
}
|
|
pDevExt->WmiCommData.ParityCheckEnable = (pDevExt->DataMode & MOXA_NONE_PARITY)
|
|
? FALSE : TRUE;
|
|
|
|
switch (pDevExt->DataMode & MOXA_PARITY_MASK) {
|
|
case MOXA_NONE_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;
|
|
break;
|
|
|
|
case MOXA_ODD_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD;
|
|
break;
|
|
|
|
case MOXA_EVEN_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN;
|
|
break;
|
|
|
|
case MOXA_MARK_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK;
|
|
break;
|
|
|
|
case MOXA_SPACE_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE;
|
|
break;
|
|
|
|
default:
|
|
ASSERTMSG(0, "SERIAL: Illegal Parity setting for WMI");
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;
|
|
break;
|
|
}
|
|
|
|
switch (pDevExt->DataMode & MOXA_STOP_MASK) {
|
|
|
|
case MOXA_1_5_STOP :
|
|
pDevExt->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5;
|
|
break;
|
|
case MOXA_2_STOP :
|
|
pDevExt->WmiCommData.StopBits = SERIAL_WMI_STOP_2;
|
|
break;
|
|
case MOXA_1_STOP :
|
|
default :
|
|
pDevExt->WmiCommData.StopBits = SERIAL_WMI_STOP_1;
|
|
break;
|
|
}
|
|
|
|
|
|
pDevExt->WmiCommData.XoffCharacter = pDevExt->SpecialChars.XoffChar;
|
|
pDevExt->WmiCommData.XoffXmitThreshold = pDevExt->HandFlow.XoffLimit;
|
|
pDevExt->WmiCommData.XonCharacter = pDevExt->SpecialChars.XonChar;
|
|
pDevExt->WmiCommData.XonXmitThreshold = pDevExt->HandFlow.XonLimit;
|
|
pDevExt->WmiCommData.MaximumBaudRate
|
|
= pDevExt->MaxBaud;
|
|
pDevExt->WmiCommData.MaximumOutputBufferSize = pDevExt->TxBufferSize;
|
|
pDevExt->WmiCommData.MaximumInputBufferSize = pDevExt->RxBufferSize;
|
|
pDevExt->WmiCommData.Support16BitMode = FALSE;
|
|
pDevExt->WmiCommData.SupportDTRDSR = TRUE;
|
|
pDevExt->WmiCommData.SupportIntervalTimeouts = TRUE;
|
|
pDevExt->WmiCommData.SupportParityCheck = TRUE;
|
|
pDevExt->WmiCommData.SupportRTSCTS = TRUE;
|
|
pDevExt->WmiCommData.SupportXonXoff = TRUE;
|
|
pDevExt->WmiCommData.SettableBaudRate = TRUE;
|
|
pDevExt->WmiCommData.SettableDataBits = TRUE;
|
|
pDevExt->WmiCommData.SettableFlowControl = TRUE;
|
|
pDevExt->WmiCommData.SettableParity = TRUE;
|
|
pDevExt->WmiCommData.SettableParityCheck = TRUE;
|
|
pDevExt->WmiCommData.SettableStopBits = TRUE;
|
|
pDevExt->WmiCommData.IsBusy = FALSE;
|
|
|
|
|
|
if (pDevExt->PNPState == SERIAL_PNP_ADDED) {
|
|
PULONG countSoFar = &IoGetConfigurationInformation()->SerialCount;
|
|
(*countSoFar)++;
|
|
|
|
//
|
|
// Register for WMI
|
|
//
|
|
|
|
pDevExt->WmiLibInfo.GuidCount = sizeof(MoxaWmiGuidList) /
|
|
sizeof(WMIGUIDREGINFO);
|
|
pDevExt->WmiLibInfo.GuidList = MoxaWmiGuidList;
|
|
|
|
pDevExt->WmiLibInfo.QueryWmiRegInfo = MoxaQueryWmiRegInfo;
|
|
pDevExt->WmiLibInfo.QueryWmiDataBlock = MoxaQueryWmiDataBlock;
|
|
pDevExt->WmiLibInfo.SetWmiDataBlock = MoxaSetWmiDataBlock;
|
|
pDevExt->WmiLibInfo.SetWmiDataItem = MoxaSetWmiDataItem;
|
|
pDevExt->WmiLibInfo.ExecuteWmiMethod = NULL;
|
|
pDevExt->WmiLibInfo.WmiFunctionControl = NULL;
|
|
|
|
IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_REGISTER);
|
|
|
|
}
|
|
|
|
if (pDevExt->PNPState == SERIAL_PNP_RESTARTING) {
|
|
//
|
|
// Release the stalled IRP's
|
|
//
|
|
|
|
MoxaUnstallIrps(pDevExt);
|
|
}
|
|
|
|
pDevExt->PNPState = SERIAL_PNP_STARTED;
|
|
MoxaClearAccept(pDevExt, ~SERIAL_PNPACCEPT_OK);
|
|
MoxaSetFlags(pDevExt, SERIAL_FLAGS_STARTED);
|
|
/*
|
|
MoxaLogError(PDevObj->DriverObject, NULL,
|
|
MoxaPhysicalZero,
|
|
MoxaPhysicalZero, 0, 0, 0, 1, status,
|
|
SERIAL_PORT_FOUND,
|
|
pDevExt->DosName.Length + sizeof(WCHAR),
|
|
pDevExt->DosName.Buffer, 0, NULL);
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("leaving MoxaFinishStartDevice\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaStartDevice(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine first passes the start device Irp down the stack then
|
|
it picks up the resources for the device, ititializes, puts it on any
|
|
appropriate lists (i.e shared interrupt or interrupt status) and
|
|
connects the interrupt.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object for this device
|
|
|
|
PIrp - Pointer to the IRP for the current request
|
|
|
|
Return Value:
|
|
|
|
Return status
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
NTSTATUS status = STATUS_NOT_IMPLEMENTED;
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
|
|
PKEVENT pStartEvent;
|
|
|
|
|
|
//PAGED_CODE();
|
|
|
|
|
|
pStartEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
|
|
|
|
if (pStartEvent == NULL) {
|
|
PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
KeInitializeEvent(pStartEvent, SynchronizationEvent, FALSE);
|
|
|
|
//
|
|
// Pass this down to the next device object
|
|
//
|
|
|
|
KeInitializeEvent(pStartEvent, SynchronizationEvent,
|
|
FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
IoSetCompletionRoutine(PIrp, MoxaSyncCompletion,
|
|
pStartEvent, TRUE, TRUE, TRUE);
|
|
|
|
status = IoCallDriver(pLowerDevObj, PIrp);
|
|
|
|
|
|
//
|
|
// Wait for lower drivers to be done with the Irp
|
|
//
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject (pStartEvent, Executive, KernelMode,
|
|
FALSE, NULL);
|
|
|
|
status = PIrp->IoStatus.Status;
|
|
}
|
|
|
|
ExFreePool(pStartEvent);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("error with IoCallDriver %x\n", status));
|
|
return status;
|
|
}
|
|
|
|
|
|
//
|
|
// Do the serial specific items to start the device
|
|
//
|
|
|
|
status = MoxaFinishStartDevice(PDevObj);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaDoExternalNaming(IN PMOXA_DEVICE_EXTENSION PDevExt,
|
|
IN PDRIVER_OBJECT PDrvObj)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be used to create a symbolic link
|
|
to the driver name in the given object directory.
|
|
|
|
It will also create an entry in the device map for
|
|
this device - IF we could create the symbolic link.
|
|
|
|
Arguments:
|
|
|
|
Extension - Pointer to the device extension.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
UNICODE_STRING linkName;
|
|
PDEVICE_OBJECT pLowerDevObj, pDevObj;
|
|
ULONG bufLen,i;
|
|
|
|
|
|
//PAGED_CODE();
|
|
|
|
pDevObj = PDevExt->DeviceObject;
|
|
pLowerDevObj = PDevExt->LowerDeviceObject;
|
|
RtlZeroMemory(&linkName, sizeof(UNICODE_STRING));
|
|
|
|
linkName.MaximumLength = SYMBOLIC_NAME_LENGTH*sizeof(WCHAR);
|
|
linkName.Buffer = ExAllocatePool(PagedPool, linkName.MaximumLength
|
|
+ sizeof(WCHAR));
|
|
if (linkName.Buffer == NULL) {
|
|
MoxaLogError(PDrvObj, pDevObj, MoxaPhysicalZero, MoxaPhysicalZero,
|
|
0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
MoxaKdPrint (MX_DBG_ERROR, ("Couldn't allocate memory for device name"
|
|
"\n"));
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto MoxaDoExternalNamingError;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(linkName.Buffer, linkName.MaximumLength + sizeof(WCHAR));
|
|
|
|
|
|
|
|
|
|
bufLen = wcslen(PDevExt->DosName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
|
|
|
PDevExt->WmiIdentifier.Buffer = ExAllocatePool(PagedPool, bufLen);
|
|
|
|
if (PDevExt->WmiIdentifier.Buffer == NULL) {
|
|
MoxaLogError(PDrvObj, pDevObj, MoxaPhysicalZero, MoxaPhysicalZero,
|
|
0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
MoxaKdPrint (MX_DBG_ERROR,
|
|
(" Couldn't allocate memory for WMI name\n"));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto MoxaDoExternalNamingError;
|
|
}
|
|
|
|
RtlZeroMemory(PDevExt->WmiIdentifier.Buffer, bufLen);
|
|
|
|
PDevExt->WmiIdentifier.Length = 0;
|
|
PDevExt->WmiIdentifier.MaximumLength = (USHORT)bufLen;
|
|
RtlAppendUnicodeToString(&PDevExt->WmiIdentifier, PDevExt->DosName);
|
|
|
|
|
|
//
|
|
// Create the "\\DosDevices\\<symbolicName>" string
|
|
//
|
|
RtlAppendUnicodeToString(&linkName, L"\\");
|
|
RtlAppendUnicodeToString(&linkName, DEFAULT_DIRECTORY);
|
|
RtlAppendUnicodeToString(&linkName, L"\\");
|
|
RtlAppendUnicodeToString(&linkName, PDevExt->DosName);
|
|
|
|
//
|
|
// Allocate Pool and save the symbolic link name in the device extension.
|
|
//
|
|
PDevExt->SymbolicLinkName.MaximumLength = linkName.Length + sizeof(WCHAR);
|
|
PDevExt->SymbolicLinkName.Buffer
|
|
= ExAllocatePool(PagedPool, PDevExt->SymbolicLinkName.MaximumLength);
|
|
|
|
if (!PDevExt->SymbolicLinkName.Buffer) {
|
|
|
|
MoxaLogError(PDrvObj, pDevObj, MoxaPhysicalZero, MoxaPhysicalZero,
|
|
0, 0, 0, 19, STATUS_SUCCESS, SERIAL_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
MoxaKdPrint (MX_DBG_ERROR,
|
|
("Couldn't allocate memory for symbolic link name\n"));
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto MoxaDoExternalNamingError;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Zero fill it.
|
|
//
|
|
|
|
RtlZeroMemory(PDevExt->SymbolicLinkName.Buffer,
|
|
PDevExt->SymbolicLinkName.MaximumLength);
|
|
|
|
RtlAppendUnicodeStringToString(&PDevExt->SymbolicLinkName,
|
|
&linkName);
|
|
|
|
|
|
|
|
// MoxaKdPrint (MX_DBG_ERROR,("DosName is %ws\n",
|
|
// &PDevExt->DosName));
|
|
|
|
//
|
|
|
|
|
|
status = IoCreateSymbolicLink (&PDevExt->SymbolicLinkName,
|
|
&PDevExt->DeviceName);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Oh well, couldn't create the symbolic link. No point
|
|
// in trying to create the device map entry.
|
|
//
|
|
|
|
MoxaLogError(PDrvObj, pDevObj, MoxaPhysicalZero, MoxaPhysicalZero,
|
|
0, 0, 0, 52, status, SERIAL_NO_SYMLINK_CREATED,
|
|
PDevExt->DeviceName.Length + sizeof(WCHAR),
|
|
PDevExt->DeviceName.Buffer, 0, NULL);
|
|
/*
|
|
MoxaKdPrint (MX_DBG_ERROR,
|
|
("Couldn't create the symbolic link\n"
|
|
"------- for port %wZ\n",
|
|
&PDevExt->DeviceName)
|
|
);
|
|
*/
|
|
goto MoxaDoExternalNamingError;
|
|
|
|
}
|
|
|
|
PDevExt->CreatedSymbolicLink = TRUE;
|
|
|
|
|
|
status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"SERIALCOMM",
|
|
PDevExt->DeviceName.Buffer, REG_SZ,
|
|
PDevExt->DosName,
|
|
wcslen(PDevExt->DosName)*sizeof(WCHAR) + sizeof(WCHAR));
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
MoxaLogError(PDrvObj, pDevObj, MoxaPhysicalZero, MoxaPhysicalZero,
|
|
0, 0, 0, 53, status, SERIAL_NO_DEVICE_MAP_CREATED,
|
|
PDevExt->DeviceName.Length + sizeof(WCHAR),
|
|
PDevExt->DeviceName.Buffer, 0, NULL);
|
|
/*
|
|
MoxaKdPrint (MX_DBG_ERROR,("Couldn't create the device map entry\n"
|
|
"------- for port %wZ\n", &PDevExt->DeviceName));
|
|
*/
|
|
goto MoxaDoExternalNamingError;
|
|
}
|
|
|
|
PDevExt->CreatedSerialCommEntry = TRUE;
|
|
|
|
|
|
//
|
|
// Now set the symbolic link for the association
|
|
//
|
|
|
|
status = IoSetDeviceInterfaceState(&PDevExt->DeviceClassSymbolicName,
|
|
TRUE);
|
|
/*
|
|
if (!NT_SUCCESS(status)) {
|
|
MoxaKdPrint (MX_DBG_ERROR,("Couldn't set class association\n"
|
|
"------- for port %wZ\n",
|
|
&PDevExt->DeviceName));
|
|
}
|
|
*/
|
|
MoxaDoExternalNamingError:;
|
|
|
|
//
|
|
// Clean up error conditions
|
|
//
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
if (PDevExt->CreatedSymbolicLink == TRUE) {
|
|
IoDeleteSymbolicLink(&PDevExt->SymbolicLinkName);
|
|
PDevExt->CreatedSymbolicLink = FALSE;
|
|
}
|
|
|
|
if (PDevExt->SymbolicLinkName.Buffer != NULL) {
|
|
ExFreePool(PDevExt->SymbolicLinkName.Buffer);
|
|
PDevExt->SymbolicLinkName.Buffer = NULL;
|
|
}
|
|
|
|
if (PDevExt->DeviceName.Buffer != NULL) {
|
|
RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
|
|
PDevExt->DeviceName.Buffer);
|
|
}
|
|
|
|
if (PDevExt->DeviceClassSymbolicName.Buffer) {
|
|
IoSetDeviceInterfaceState (&PDevExt->DeviceClassSymbolicName, FALSE);
|
|
}
|
|
|
|
if (PDevExt->WmiIdentifier.Buffer != NULL) {
|
|
ExFreePool(PDevExt->WmiIdentifier.Buffer);
|
|
PDevExt->WmiIdentifier.Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Always clean up our temp buffers.
|
|
//
|
|
|
|
if (linkName.Buffer != NULL) {
|
|
ExFreePool(linkName.Buffer);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
MoxaUndoExternalNaming(IN PMOXA_DEVICE_EXTENSION Extension)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be used to delete a symbolic link
|
|
to the driver name in the given object directory.
|
|
|
|
It will also delete an entry in the device map for
|
|
this device if the symbolic link had been created.
|
|
|
|
Arguments:
|
|
|
|
Extension - Pointer to the device extension.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
|
|
//PAGED_CODE();
|
|
/*
|
|
MoxaKdPrint (MX_DBG_ERROR,("In MoxaUndoExternalNaming for\n"
|
|
"------- extension: %x of port %wZ\n",
|
|
Extension,&Extension->DeviceName)
|
|
);
|
|
*/
|
|
|
|
//
|
|
// We're cleaning up here. One reason we're cleaning up
|
|
// is that we couldn't allocate space for the directory
|
|
// name or the symbolic link.
|
|
//
|
|
|
|
if (Extension->SymbolicLinkName.Buffer &&
|
|
Extension->CreatedSymbolicLink) {
|
|
|
|
if (Extension->DeviceClassSymbolicName.Buffer) {
|
|
status = IoSetDeviceInterfaceState (&Extension->
|
|
DeviceClassSymbolicName,
|
|
FALSE);
|
|
|
|
//
|
|
// IoRegisterDeviceClassInterface() allocated this string for us,
|
|
// and we no longer need it.
|
|
//
|
|
|
|
ExFreePool( Extension->DeviceClassSymbolicName.Buffer );
|
|
}
|
|
|
|
|
|
IoDeleteSymbolicLink (&Extension->SymbolicLinkName);
|
|
|
|
}
|
|
|
|
if (Extension->WmiIdentifier.Buffer) {
|
|
ExFreePool(Extension->WmiIdentifier.Buffer);
|
|
Extension->WmiIdentifier.MaximumLength
|
|
= Extension->WmiIdentifier.Length = 0;
|
|
Extension->WmiIdentifier.Buffer = NULL;
|
|
}
|
|
|
|
//
|
|
// We're cleaning up here. One reason we're cleaning up
|
|
// is that we couldn't allocate space for the NtNameOfPort.
|
|
//
|
|
|
|
if ((Extension->DeviceName.Buffer != NULL)
|
|
&& Extension->CreatedSerialCommEntry) {
|
|
|
|
status = RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
|
|
Extension->DeviceName.Buffer);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
MoxaLogError(
|
|
Extension->DeviceObject->DriverObject,
|
|
Extension->DeviceObject,
|
|
MoxaPhysicalZero,
|
|
MoxaPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
55,
|
|
status,
|
|
SERIAL_NO_DEVICE_MAP_DELETED,
|
|
Extension->DeviceName.Length+sizeof(WCHAR),
|
|
Extension->DeviceName.Buffer,
|
|
0,
|
|
NULL
|
|
);
|
|
/*
|
|
MoxaKdPrint (MX_DBG_ERROR,("Couldn't delete value entry %wZ\n",
|
|
&Extension->DeviceName)
|
|
);
|
|
*/
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaPnpDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a dispatch routine for the IRPs that come to the driver with the
|
|
IRP_MJ_PNP major code (plug-and-play IRPs).
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object for this device
|
|
|
|
PIrp - Pointer to the IRP for the current request
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status of the call
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
|
|
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
NTSTATUS status;
|
|
PDEVICE_CAPABILITIES pDevCaps;
|
|
|
|
|
|
//PAGED_CODE();
|
|
if (pDevExt->ControlDevice) { // Control Device
|
|
|
|
status = STATUS_CANCELLED;
|
|
PIrp->IoStatus.Information = 0L;
|
|
PIrp->IoStatus.Status = status;
|
|
IoCompleteRequest(
|
|
PIrp,
|
|
0
|
|
);
|
|
return status;
|
|
}
|
|
|
|
if ((status = MoxaIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) {
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
switch (pIrpStack->MinorFunction) {
|
|
case IRP_MN_QUERY_CAPABILITIES: {
|
|
PKEVENT pQueryCapsEvent;
|
|
SYSTEM_POWER_STATE cap;
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Got IRP_MN_QUERY_DEVICE_CAPABILITIES "
|
|
"IRP\n"));
|
|
|
|
pQueryCapsEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
|
|
|
|
if (pQueryCapsEvent == NULL) {
|
|
PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
KeInitializeEvent(pQueryCapsEvent, SynchronizationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
IoSetCompletionRoutine(PIrp, MoxaSyncCompletion, pQueryCapsEvent,
|
|
TRUE, TRUE, TRUE);
|
|
|
|
status = IoCallDriver(pLowerDevObj, PIrp);
|
|
|
|
|
|
//
|
|
// Wait for lower drivers to be done with the Irp
|
|
//
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(pQueryCapsEvent, Executive, KernelMode, FALSE,
|
|
NULL);
|
|
}
|
|
|
|
ExFreePool(pQueryCapsEvent);
|
|
|
|
status = PIrp->IoStatus.Status;
|
|
|
|
if (pIrpStack->Parameters.DeviceCapabilities.Capabilities == NULL) {
|
|
goto errQueryCaps;
|
|
}
|
|
|
|
//
|
|
// Save off their power capabilities
|
|
//
|
|
|
|
MoxaKdPrint (MX_DBG_ERROR,("SERIAL: Mapping power capabilities\n"));
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
|
|
pDevCaps = pIrpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
for (cap = PowerSystemSleeping1; cap < PowerSystemMaximum;
|
|
cap++) {
|
|
#if DBG
|
|
MoxaKdPrint (MX_DBG_ERROR, (" SERIAL: %d: %s <--> %s\n",
|
|
cap, SerSystemCapString[cap],
|
|
SerDeviceCapString[pDevCaps->DeviceState[cap]]
|
|
));
|
|
#endif
|
|
|
|
pDevExt->DeviceStateMap[cap] = pDevCaps->DeviceState[cap];
|
|
}
|
|
|
|
pDevExt->DeviceStateMap[PowerSystemUnspecified]
|
|
= PowerDeviceUnspecified;
|
|
|
|
pDevExt->DeviceStateMap[PowerSystemWorking]
|
|
= PowerDeviceD0;
|
|
|
|
pDevExt->SystemWake = pDevCaps->SystemWake;
|
|
pDevExt->DeviceWake = pDevCaps->DeviceWake;
|
|
|
|
errQueryCaps:;
|
|
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
//
|
|
// We just pass this down -- serenum enumerates our bus for us.
|
|
//
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Got IRP_MN_QUERY_DEVICE_RELATIONS "
|
|
"Irp\n"));
|
|
|
|
switch (pIrpStack->Parameters.QueryDeviceRelations.Type) {
|
|
case BusRelations:
|
|
MoxaKdPrint (MX_DBG_TRACE,("------- BusRelations Query\n"));
|
|
break;
|
|
|
|
case EjectionRelations:
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------- EjectionRelations Query\n"));
|
|
break;
|
|
|
|
case PowerRelations:
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------- PowerRelations Query\n"));
|
|
break;
|
|
|
|
case RemovalRelations:
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------- RemovalRelations Query\n"));
|
|
break;
|
|
|
|
case TargetDeviceRelation:
|
|
MoxaKdPrint (MX_DBG_TRACE,("------- TargetDeviceRelation Query\n"));
|
|
break;
|
|
|
|
default:
|
|
MoxaKdPrint (MX_DBG_TRACE,("------- Unknown Query\n"));
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case IRP_MN_START_DEVICE: {
|
|
PVOID startLockPtr;
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Got IRP_MN_START_DEVICE Irp\n"));
|
|
|
|
//
|
|
// MoxaStartDevice will pass this Irp to the next driver,
|
|
// and process it as completion so just complete it here.
|
|
//
|
|
// to be finish
|
|
// MoxaLockPagableSectionByHandle(MoxaGlobalData->PAGESER_Handle);
|
|
|
|
//
|
|
// Make sure the stack is powered up
|
|
//
|
|
|
|
// status = MoxaGotoPowerState(PDevObj, pDevExt, PowerDeviceD0);
|
|
|
|
// if (status == STATUS_SUCCESS) {
|
|
status = MoxaStartDevice(PDevObj, PIrp);
|
|
// }
|
|
|
|
// MoxaUnlockPagableImageSection(MoxaGlobalData->PAGESER_Handle);
|
|
|
|
|
|
PIrp->IoStatus.Status = status;
|
|
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
{
|
|
MoxaKdPrint (MX_DBG_TRACE,("Got IRP_MN_QUERY_PNP_DEVICE_STATE Irp\n"));
|
|
|
|
if (pDevExt->Flags & SERIAL_FLAGS_BROKENHW) {
|
|
(PNP_DEVICE_STATE)PIrp->IoStatus.Information |= PNP_DEVICE_FAILED;
|
|
status = PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return MoxaIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
}
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
{
|
|
ULONG pendingIRPs;
|
|
KIRQL oldIrql;
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Got IRP_MN_STOP_DEVICE Irp\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------- for device %x\n", pLowerDevObj));
|
|
|
|
|
|
MoxaSetFlags(pDevExt, SERIAL_FLAGS_STOPPED);
|
|
MoxaSetAccept(pDevExt,SERIAL_PNPACCEPT_STOPPED);
|
|
MoxaClearAccept(pDevExt, SERIAL_PNPACCEPT_STOPPING);
|
|
|
|
pDevExt->PNPState = SERIAL_PNP_STOPPING;
|
|
|
|
//
|
|
// From this point on all non-PNP IRP's will be queued
|
|
//
|
|
|
|
//
|
|
// Decrement for entry here
|
|
//
|
|
|
|
InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// Decrement for stopping
|
|
//
|
|
|
|
pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
if (pendingIRPs) {
|
|
KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
//
|
|
// Re-increment the count for later
|
|
//
|
|
|
|
InterlockedIncrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// We need to free resources...basically this is a remove
|
|
// without the detach from the stack.
|
|
//
|
|
|
|
// if (pDevExt->Flags & SERIAL_FLAGS_STARTED) {
|
|
MoxaReleaseResources(pDevExt);
|
|
// }
|
|
|
|
//
|
|
// Pass the irp down
|
|
//
|
|
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
|
|
return IoCallDriver(pLowerDevObj, PIrp);
|
|
|
|
}
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Got "
|
|
"IRP_MN_CANCEL_STOP_DEVICE Irp\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------- for device %x\n", pLowerDevObj));
|
|
|
|
if (pDevExt->PNPState == SERIAL_PNP_QSTOP) {
|
|
//
|
|
// Restore the device state
|
|
//
|
|
pDevExt->PNPState = SERIAL_PNP_STARTED;
|
|
MoxaClearAccept(pDevExt, SERIAL_PNPACCEPT_STOPPING);
|
|
}
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return MoxaIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Got "
|
|
"IRP_MN_CANCEL_REMOVE_DEVICE Irp\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------- for device %x\n", pLowerDevObj));
|
|
|
|
//
|
|
// Restore the device state
|
|
//
|
|
|
|
pDevExt->PNPState = SERIAL_PNP_STARTED;
|
|
MoxaClearAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING);
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return MoxaIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Got "
|
|
"IRP_MN_QUERY_REMOVE_DEVICE Irp\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE,("------- for device %x\n", pLowerDevObj));
|
|
|
|
ExAcquireFastMutex(&pDevExt->OpenMutex);
|
|
|
|
//
|
|
// See if we should succeed a remove query
|
|
//
|
|
|
|
if (pDevExt->DeviceIsOpened) {
|
|
ExReleaseFastMutex(&pDevExt->OpenMutex);
|
|
status = PIrp->IoStatus.Status = STATUS_DEVICE_BUSY;
|
|
MoxaKdPrint (MX_DBG_TRACE,("------- failing; device open\n"));
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
pDevExt->PNPState = SERIAL_PNP_QREMOVE;
|
|
MoxaSetAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING);
|
|
ExReleaseFastMutex(&pDevExt->OpenMutex);
|
|
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
return MoxaIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
}
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
{
|
|
ULONG pendingIRPs;
|
|
KIRQL oldIrql;
|
|
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Got IRP_MN_SURPRISE_REMOVAL Irp\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE,("------- for device %x\n", pLowerDevObj));
|
|
//
|
|
// Prevent any new I/O to the device
|
|
//
|
|
|
|
MoxaSetAccept(pDevExt, SERIAL_PNPACCEPT_SURPRISE_REMOVING);
|
|
|
|
//
|
|
// Dismiss all pending requests
|
|
//
|
|
|
|
MoxaKillPendingIrps(PDevObj);
|
|
|
|
//
|
|
// Wait for any pending requests we raced on.
|
|
//
|
|
|
|
//
|
|
// Decrement once for ourselves
|
|
//
|
|
|
|
InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// Decrement for the remove
|
|
//
|
|
|
|
pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
if (pendingIRPs) {
|
|
KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
//
|
|
// Reset for subsequent remove
|
|
//
|
|
|
|
InterlockedIncrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// Remove any external interfaces and release resources
|
|
//
|
|
|
|
MoxaDisableInterfacesResources(PDevObj, FALSE); // to be finish
|
|
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
return MoxaIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
|
|
{
|
|
ULONG pendingIRPs;
|
|
KIRQL oldIrql;
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,(" Got IRP_MN_REMOVE_DEVICE Irp\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------- for device %x\n", pLowerDevObj));
|
|
|
|
//
|
|
// If we get this, we have to remove
|
|
//
|
|
|
|
//
|
|
// Mark as not accepting requests
|
|
//
|
|
|
|
MoxaSetAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING);
|
|
|
|
//
|
|
// Complete all pending requests
|
|
//
|
|
|
|
MoxaKillPendingIrps(PDevObj);
|
|
|
|
|
|
//
|
|
// Pass the irp down
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
|
|
|
|
|
|
//
|
|
// We do decrement here because we incremented on entry here.
|
|
//
|
|
|
|
status = MoxaIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
//
|
|
// Wait for any pending requests we raced on.
|
|
//
|
|
|
|
pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
if (pendingIRPs) {
|
|
KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
//
|
|
// Remove us
|
|
//
|
|
|
|
MoxaRemoveDevObj(PDevObj);
|
|
return status;
|
|
}
|
|
|
|
default:
|
|
MoxaKdPrint (MX_DBG_TRACE,
|
|
(" Got PNP IRP %x,we don't process it and just pass it down.\n",
|
|
pIrpStack->MinorFunction));
|
|
break;
|
|
|
|
|
|
|
|
} // switch (pIrpStack->MinorFunction)
|
|
|
|
//
|
|
// Pass to driver beneath us
|
|
//
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
status = MoxaIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|