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.
2077 lines
63 KiB
2077 lines
63 KiB
/*----------------------------------------------------------------------
|
|
pnp.c -
|
|
4-18-00 Remove IoStartNextPacket call from PnPBoardFDO function
|
|
4-06-00 Reject irps for query_device_relations if not a bus_relation request
|
|
3-30-99 fix hybernate power on to restore dtr/rts states
|
|
properly, in RestorePortSettings().
|
|
2-15-99 - allow to hibernate with open ports, restore ports when
|
|
comes back up now - kpb.
|
|
11-24-98 - fix power handling to avoid crash,
|
|
allow hibernation if no ports open. kpb
|
|
----------------------------------------------------------------------*/
|
|
#include "precomp.h"
|
|
|
|
#ifdef NT50
|
|
|
|
NTSTATUS PnPBoardFDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp);
|
|
NTSTATUS PnPPortFDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp);
|
|
NTSTATUS PnpPortPDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp);
|
|
NTSTATUS BoardBusRelations(IN PDEVICE_OBJECT devobj, IN PIRP Irp);
|
|
NTSTATUS WaitForLowerPdo(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
|
|
NTSTATUS BoardFilterResReq(IN PDEVICE_OBJECT devobj, IN PIRP Irp);
|
|
|
|
NTSTATUS SerialRemoveFdo(IN PDEVICE_OBJECT pFdo);
|
|
NTSTATUS SerialIoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt,
|
|
PDEVICE_OBJECT PDevObj,
|
|
PIRP PIrp);
|
|
NTSTATUS Serial_PDO_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
|
NTSTATUS Serial_FDO_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
|
NTSTATUS PowerUpDevice(PSERIAL_DEVICE_EXTENSION Ext);
|
|
void RestorePortSettings(PSERIAL_DEVICE_EXTENSION Ext);
|
|
|
|
//NTSTATUS SerialPoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt,
|
|
// PDEVICE_OBJECT PDevObj,
|
|
// PIRP PIrp);
|
|
//NTSTATUS SerialSetPowerD0(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
|
NTSTATUS OurPowerCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
|
|
|
|
NTSTATUS SerialD3Complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
|
|
NTSTATUS SerialStartDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp);
|
|
|
|
NTSTATUS SerialSyncCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PKEVENT SerialSyncEvent
|
|
);
|
|
|
|
NTSTATUS SerialFinishStartDevice(IN PDEVICE_OBJECT Fdo,
|
|
IN PCM_RESOURCE_LIST resourceList,
|
|
IN PCM_RESOURCE_LIST trResourceList);
|
|
static NTSTATUS RocketPortSpecialStartup(PSERIAL_DEVICE_EXTENSION Ext);
|
|
|
|
#if DBG
|
|
static char *power_strs[] = {
|
|
"WAIT_WAKE", // 0x00
|
|
"POWER_SEQUENCE", // 0x01
|
|
"SET_POWER", // 0x02
|
|
"QUERY_POWER", // 0x03
|
|
"UNKNOWN", //
|
|
NULL};
|
|
|
|
static char *pnp_strs[] = {
|
|
"START_DEVICE", // 0x00
|
|
"QUERY_REMOVE_DEVICE", // 0x01
|
|
"REMOVE_DEVICE", // 0x02
|
|
"CANCEL_REMOVE_DEVICE", // 0x03
|
|
"STOP_DEVICE", // 0x04
|
|
"QUERY_STOP_DEVICE", // 0x05
|
|
"CANCEL_STOP_DEVICE", // 0x06
|
|
"QUERY_DEVICE_RELATIONS", // 0x07
|
|
"QUERY_INTERFACE", // 0x08
|
|
"QUERY_CAPABILITIES", // 0x09
|
|
"QUERY_RESOURCES", // 0x0A
|
|
"QUERY_RESOURCE_REQUIREMENTS", // 0x0B
|
|
"QUERY_DEVICE_TEXT", // 0x0C
|
|
"FILTER_RESOURCE_REQUIREMENTS", // 0x0D
|
|
"UNKNOWN", //
|
|
"READ_CONFIG", // 0x0F
|
|
"WRITE_CONFIG", // 0x10
|
|
"EJECT", // 0x11
|
|
"SET_LOCK", // 0x12
|
|
"QUERY_ID", // 0x13
|
|
"QUERY_PNP_DEVICE_STATE", // 0x14
|
|
"QUERY_BUS_INFORMATION", // 0x15
|
|
"PAGING_NOTIFICATION", // 0x16
|
|
NULL};
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------
|
|
SerialPnpDispatch -
|
|
This is a dispatch routine for the IRPs that come to the driver with the
|
|
IRP_MJ_PNP major code (plug-and-play IRPs).
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS SerialPnpDispatch(IN PDEVICE_OBJECT devobj, IN PIRP Irp)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = devobj->DeviceExtension;
|
|
//PDEVICE_OBJECT pdo = Ext->LowerDeviceObject;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
|
BOOLEAN acceptingIRPs;
|
|
int index;
|
|
|
|
// dump out some debug info
|
|
index = irpStack->MinorFunction;
|
|
if (index > 0x16)
|
|
index = 0x0e;
|
|
|
|
#ifdef DO_BUS_EXTENDER
|
|
if (Ext->IsPDO)
|
|
{
|
|
MyKdPrint(D_Pnp,("Port PDO %s PnPIrp:%d,%s\n",
|
|
Ext->SymbolicLinkName, irpStack->MinorFunction,
|
|
pnp_strs[index]))
|
|
InterlockedIncrement(&Ext->PendingIRPCnt);
|
|
return PnpPortPDO(devobj, Irp);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
MyKdPrint(D_Pnp,("Board %s PnPIrp:%d,%s\n",
|
|
Ext->SymbolicLinkName, irpStack->MinorFunction,
|
|
pnp_strs[index]))
|
|
}
|
|
else
|
|
{
|
|
MyKdPrint(D_Pnp,("Port %s PnPIrp:%d,%s\n",
|
|
Ext->SymbolicLinkName, irpStack->MinorFunction,
|
|
pnp_strs[index]))
|
|
}
|
|
|
|
acceptingIRPs = SerialIRPPrologue(Ext);
|
|
|
|
#if 0
|
|
if ((irpStack->MinorFunction != IRP_MN_REMOVE_DEVICE)
|
|
&& (irpStack->MinorFunction != IRP_MN_CANCEL_REMOVE_DEVICE)
|
|
&& (irpStack->MinorFunction != IRP_MN_STOP_DEVICE)
|
|
&& (irpStack->MinorFunction != IRP_MN_CANCEL_STOP_DEVICE)
|
|
&& (acceptingIRPs == FALSE))
|
|
{
|
|
MyKdPrint(D_Pnp,("Removed!\n"))
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
SerialCompleteRequest(Ext, Irp, IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
#endif
|
|
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
return PnPBoardFDO(devobj, Irp);
|
|
}
|
|
else
|
|
{
|
|
//return PnPPortFDO(devobj, Irp);
|
|
return PnPBoardFDO(devobj, Irp);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
PnPBoardFDO - This handles both Board and Port FDO's
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS PnPBoardFDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = devobj->DeviceExtension;
|
|
PDEVICE_OBJECT pdo = Ext->LowerDeviceObject;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
|
ULONG pendingIRPs;
|
|
int pass_down = 1;
|
|
|
|
ASSERT( devobj );
|
|
ASSERT( Ext );
|
|
|
|
#if DBG
|
|
if (* ((BYTE *)(Irp)) != 6) // in signiture of irp
|
|
{
|
|
MyKdPrint(D_Pnp,("bad irp!!!\n"))
|
|
}
|
|
#endif
|
|
|
|
switch (irpStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE: // 0x00
|
|
MyKdPrint(D_Pnp,("StartDevice\n"))
|
|
status = SerialStartDevice(devobj, Irp);
|
|
//
|
|
// Is this were we should register and enable the device, or should it be in
|
|
// the PDO start? (see DoPnpAssoc(Pdo) in pnpadd.c)
|
|
//
|
|
Irp->IoStatus.Status = status;
|
|
pass_down = 0; // already passed down
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE: // 0x04
|
|
// need to unhook from resources so system rebalance resources
|
|
// on the fly.
|
|
MyKdPrint(D_Pnp,("StopDevice\n"))
|
|
//Ext->Flags |= SERIAL_FLAGS_STOPPED;
|
|
|
|
Ext->PNPState = SERIAL_PNP_STOPPING;
|
|
Ext->DevicePNPAccept |= SERIAL_PNPACCEPT_STOPPED;
|
|
Ext->DevicePNPAccept &= ~SERIAL_PNPACCEPT_STOPPING;
|
|
|
|
InterlockedDecrement(&Ext->PendingIRPCnt); // after dec, =1
|
|
|
|
pendingIRPs = InterlockedDecrement(&Ext->PendingIRPCnt); // after dec, =0
|
|
|
|
if (pendingIRPs) {
|
|
KeWaitForSingleObject(&Ext->PendingIRPEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
Ext->FdoStarted = FALSE; // this should stop service of the device
|
|
#ifdef NT50
|
|
|
|
if (Ext->DeviceType != DEV_BOARD) {
|
|
|
|
// Disable the interface
|
|
|
|
status = IoSetDeviceInterfaceState( &Ext->DeviceClassSymbolicName,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
MyKdPrint(D_Error,("Couldn't clear class association for %s\n",
|
|
UToC1(&Ext->DeviceClassSymbolicName)))
|
|
}
|
|
else {
|
|
|
|
MyKdPrint(D_PnpAdd, ("Cleared class association for device: %s\n and ",
|
|
UToC1(&Ext->DeviceClassSymbolicName)))
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Re-increment the count for exit
|
|
InterlockedIncrement(&Ext->PendingIRPCnt); //after inc=1
|
|
InterlockedIncrement(&Ext->PendingIRPCnt); //after inc=2
|
|
// exit this irp decr it to=1
|
|
|
|
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
//Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
//pass_down = 0; // we are failing it
|
|
break;
|
|
|
|
#if 0
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: // 0x7
|
|
if ( irpStack->Parameters.QueryDeviceRelations.Type != BusRelations )
|
|
{
|
|
//
|
|
// Verifier requires pass down is PDO present
|
|
//
|
|
|
|
if ( (Ext->DeviceType == DEV_BOARD) && (pdo == 0) )
|
|
{
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
pass_down = 0;
|
|
};
|
|
break;
|
|
}
|
|
if (!Driver.NoPnpPorts)
|
|
{
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
status = BoardBusRelations(devobj, Irp);
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
#ifdef DO_BUS_EXTENDER
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: // 0x7
|
|
//
|
|
// Verifier requires pass down is PDO present
|
|
//
|
|
|
|
if ( (Ext->DeviceType == DEV_BOARD) && (pdo == 0) )
|
|
{
|
|
pass_down = 0;
|
|
}
|
|
if ( irpStack->Parameters.QueryDeviceRelations.Type != BusRelations ) {
|
|
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
if (!Driver.NoPnpPorts)
|
|
{
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
status = BoardBusRelations(devobj, Irp);
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifdef DO_BRD_FILTER_RES_REQ
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // 0x0D
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
status = BoardFilterResReq(devobj, Irp);
|
|
pass_down = 0; // already passed down
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE: // 0x05
|
|
MyKdPrint(D_Pnp,("QueryStopDevice\n"))
|
|
|
|
status = STATUS_SUCCESS;
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
if (is_board_in_use(Ext))
|
|
status = STATUS_DEVICE_BUSY;
|
|
}
|
|
else
|
|
{
|
|
if (Ext->DeviceIsOpen)
|
|
status = STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
if (status == STATUS_DEVICE_BUSY)
|
|
{
|
|
MyKdPrint(D_Pnp,("Can't Remove, Busy\n"))
|
|
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
|
|
pass_down = 0; // we are failing it out, no need to pass down
|
|
}
|
|
else
|
|
{
|
|
Ext->PNPState = SERIAL_PNP_QSTOP;
|
|
// this is hosing up things(kpb)
|
|
//Ext->DevicePNPAccept |= SERIAL_PNPACCEPT_STOPPING;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE: // 0x06
|
|
MyKdPrint(D_Pnp,("CancelStopDevice\n"))
|
|
if (Ext->PNPState == SERIAL_PNP_QSTOP)
|
|
{
|
|
Ext->PNPState = SERIAL_PNP_STARTED;
|
|
Ext->DevicePNPAccept &= ~SERIAL_PNPACCEPT_STOPPING;
|
|
}
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
MyKdPrint(D_Pnp,("CancelRemoveDevice\n"))
|
|
|
|
// Restore the device state
|
|
|
|
Ext->PNPState = SERIAL_PNP_STARTED;
|
|
Ext->DevicePNPAccept &= ~SERIAL_PNPACCEPT_REMOVING;
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE: // 0x01
|
|
// If we were to fail this call then we would need to complete the
|
|
// IRP here. Since we are not, set the status to SUCCESS and
|
|
// call the next driver.
|
|
MyKdPrint(D_Pnp,("QueryRemoveDevice\n"))
|
|
status = STATUS_SUCCESS;
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
if (is_board_in_use(Ext))
|
|
status = STATUS_DEVICE_BUSY;
|
|
}
|
|
else
|
|
{
|
|
if (Ext->DeviceIsOpen)
|
|
status = STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
if (status == STATUS_DEVICE_BUSY)
|
|
{
|
|
MyKdPrint(D_Pnp,("Can't Remove, Busy\n"))
|
|
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
|
|
pass_down = 0; // we are failing it out, no need to pass down
|
|
}
|
|
else
|
|
{
|
|
Ext->PNPState = SERIAL_PNP_QREMOVE;
|
|
Ext->DevicePNPAccept |= SERIAL_PNPACCEPT_REMOVING;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE: // 0x02
|
|
// If we get this, we have to remove
|
|
// Mark as not accepting requests
|
|
Ext->DevicePNPAccept |= SERIAL_PNPACCEPT_REMOVING;
|
|
|
|
|
|
// Complete all pending requests
|
|
SerialKillPendingIrps(devobj);
|
|
|
|
// Pass the irp down
|
|
//WaitForLowerPdo(devobj, Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
MyKdPrint(D_Pnp,("RemoveDevice\n"))
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
//IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
// We do decrement here because we incremented on entry here.
|
|
//SerialIRPEpilogue(Ext);
|
|
SerialIoCallDriver(Ext, pdo, Irp);
|
|
|
|
// Wait for any pending requests we raced on.
|
|
pendingIRPs = InterlockedDecrement(&Ext->PendingIRPCnt);
|
|
|
|
MyKdPrint(D_Pnp,("Remove, C\n"))
|
|
if (pendingIRPs) {
|
|
MyKdPrint(D_Pnp,("Irp Wait\n"))
|
|
KeWaitForSingleObject(&Ext->PendingIRPEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
// Remove us
|
|
SerialRemoveFdo(devobj);
|
|
status = STATUS_SUCCESS;
|
|
// MyKdPrint(D_Pnp,("End PnPDispatch(Remove)\n"))
|
|
return status; // BAIL
|
|
|
|
|
|
case IRP_MN_QUERY_INTERFACE: // 0x8
|
|
case IRP_MN_QUERY_RESOURCES : // 0x0A
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: // 0x0B
|
|
case IRP_MN_READ_CONFIG: // 0x0f
|
|
case IRP_MN_WRITE_CONFIG: // 0x10
|
|
case IRP_MN_EJECT: // 0x11
|
|
case IRP_MN_SET_LOCK: // 0x12
|
|
//case IRP_MN_PNP_DEVICE_STATE: // 0x14
|
|
case IRP_MN_QUERY_BUS_INFORMATION: // 0x15
|
|
//case IRP_MN_PAGING_NOTIFICATION: // 0x16
|
|
default:
|
|
MyKdPrint(D_Pnp,("Unhandled\n"));
|
|
// all these get passed down, we don't set the status return code
|
|
break;
|
|
} // switch (irpStack->MinorFunction)
|
|
|
|
#if DBG
|
|
if (* ((BYTE *)(Irp)) != 6) // in signiture of irp
|
|
{
|
|
MyKdPrint(D_Pnp,("bad irp b!!!\n"))
|
|
}
|
|
#endif
|
|
if (pass_down)
|
|
{
|
|
MyKdPrint(D_Pnp,(" Send irp down\n"))
|
|
// Pass to driver beneath us
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = SerialIoCallDriver(Ext, pdo, Irp);
|
|
}
|
|
else
|
|
{
|
|
Irp->IoStatus.Status = status;
|
|
//MyKdPrint(D_Pnp,(" Complete irp\n"))
|
|
SerialCompleteRequest(Ext, Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
// MyKdPrint(D_Pnp,(" End PnPDispatch\n"))
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
#ifdef DO_BUS_EXTENDER
|
|
/*----------------------------------------------------------------------
|
|
PnpPortPDO -
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS PnpPortPDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = devobj->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = Irp->IoStatus.Status;
|
|
|
|
switch (irpStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE: // 0x00
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
MyKdPrint(D_Pnp,("Remove PDO\n"))
|
|
// shut down everything, call iodelete device
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES: { // x09
|
|
PDEVICE_CAPABILITIES deviceCapabilities;
|
|
|
|
deviceCapabilities=irpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
MyKdPrint(D_Pnp,("Report Caps.\n"))
|
|
// Set the capabilities.
|
|
deviceCapabilities->Version = 1;
|
|
deviceCapabilities->Size = sizeof (DEVICE_CAPABILITIES);
|
|
|
|
// We cannot wake the system.
|
|
deviceCapabilities->SystemWake = PowerSystemUnspecified;
|
|
deviceCapabilities->DeviceWake = PowerDeviceUnspecified;
|
|
|
|
// We have no latencies
|
|
deviceCapabilities->D1Latency = 0;
|
|
deviceCapabilities->D2Latency = 0;
|
|
deviceCapabilities->D3Latency = 0;
|
|
|
|
// No locking or ejection
|
|
deviceCapabilities->LockSupported = FALSE;
|
|
deviceCapabilities->EjectSupported = FALSE;
|
|
|
|
// Device can be physically removed.
|
|
// Technically there is no physical device to remove, but this bus
|
|
// driver can yank the PDO from the PlugPlay system, when ever it
|
|
// receives an IOCTL_GAMEENUM_REMOVE_PORT device control command.
|
|
//deviceCapabilities->Removable = TRUE;
|
|
// we switch this to FALSE to emulate the stock com port behavior, kpb
|
|
deviceCapabilities->Removable = FALSE;
|
|
|
|
// not Docking device
|
|
deviceCapabilities->DockDevice = FALSE;
|
|
|
|
// BUGBUG: should we do uniqueID???
|
|
deviceCapabilities->UniqueID = FALSE;
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: // 0x7
|
|
if (irpStack->Parameters.QueryDeviceRelations.Type !=
|
|
TargetDeviceRelation)
|
|
break; //
|
|
|
|
{
|
|
PDEVICE_RELATIONS pDevRel;
|
|
|
|
// No one else should respond to this since we are the PDO
|
|
ASSERT(Irp->IoStatus.Information == 0);
|
|
if (Irp->IoStatus.Information != 0) {
|
|
break;
|
|
}
|
|
|
|
pDevRel = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
|
|
|
if (pDevRel == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pDevRel->Count = 1;
|
|
pDevRel->Objects[0] = devobj;
|
|
ObReferenceObject(devobj);
|
|
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR)pDevRel;
|
|
}
|
|
break;
|
|
|
|
case IRP_MN_QUERY_ID: // 0x13
|
|
{
|
|
switch (irpStack->Parameters.QueryId.IdType)
|
|
{
|
|
case BusQueryInstanceID:
|
|
{
|
|
WCHAR *wstr;
|
|
CHAR our_id[40];
|
|
|
|
// Build an instance ID. This is what PnP uses to tell if it has
|
|
// seen this thing before or not.
|
|
// its used to form the ENUM\ key name along with the DeviceID.
|
|
//Sprintf(our_id, "Ctm_%s", Ext->NtNameForPort);
|
|
Sprintf(our_id, "Port%04d", PortExtToIndex(Ext,0));
|
|
MyKdPrint(D_Pnp,("InstanceId:%s\n", our_id))
|
|
wstr = str_to_wstr_dup(our_id, PagedPool);
|
|
if ( wstr ) {
|
|
// as per serenum bus enumerator:
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
Irp->IoStatus.Information = (ULONG)wstr;
|
|
}
|
|
break;
|
|
|
|
case BusQueryDeviceID:
|
|
{
|
|
// This is the name used under ENUM to form the device instance
|
|
// name under which any new PDO nodes will be created.
|
|
// after find new hardware install we find this as an example
|
|
// new port node under ENUM:
|
|
// Enum\CtmPort\RDevice\6&Port0000
|
|
// Enum\CtmPort\RDevice\6&Port0000\Control
|
|
// Enum\CtmPort\RDevice\6&Port0000\Device Parameters
|
|
// Enum\CtmPort\RDevice\6&Port0000\LogConf
|
|
|
|
WCHAR *wstr;
|
|
CHAR our_id[40];
|
|
|
|
#ifdef S_VS
|
|
strcpy(our_id, "CtmPort\\VSPORT");
|
|
#else
|
|
strcpy(our_id, "CtmPort\\RKPORT");
|
|
#endif
|
|
wstr = str_to_wstr_dup(our_id, PagedPool);
|
|
MyKdPrint(D_Pnp,("DevID:%s\n", our_id))
|
|
|
|
Irp->IoStatus.Information = (ULONG)wstr;
|
|
if ( wstr ) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BusQueryHardwareIDs:
|
|
{
|
|
// return a multi WCHAR (null terminated) string (null terminated)
|
|
// array for use in matching hardare ids in inf files;
|
|
WCHAR *wstr;
|
|
CHAR our_id[40];
|
|
|
|
#ifdef S_VS
|
|
Sprintf(our_id, "CtmvPort%04d",
|
|
PortExtToIndex(Ext, 0 /* driver_flag */) );
|
|
#else
|
|
Sprintf(our_id, "CtmPort%04d",
|
|
PortExtToIndex(Ext, 0 /* driver_flag */) );
|
|
#endif
|
|
MyKdPrint(D_Pnp,("HrdwrID:%s\n", our_id))
|
|
wstr = str_to_wstr_dup(our_id, PagedPool);
|
|
Irp->IoStatus.Information = (ULONG)wstr;
|
|
if ( wstr ) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
} //BusQueryHardwareIDs
|
|
break;
|
|
|
|
case BusQueryCompatibleIDs:
|
|
{
|
|
#if 0
|
|
WCHAR *wstr;
|
|
CHAR our_id[40];
|
|
|
|
// The generic ids for installation of this pdo.
|
|
|
|
Sprintf(our_id, "Cpt_CtmPort0001");
|
|
MyKdPrint(D_Pnp,("CompID:%s\n", our_id))
|
|
wstr = str_to_wstr_dup(our_id, PagedPool);
|
|
|
|
Irp->IoStatus.Information = (ULONG)wstr;
|
|
status = STATUS_SUCCESS;
|
|
#endif
|
|
// no compatible id's
|
|
Irp->IoStatus.Information = 0;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
default:
|
|
MyKdPrint(D_Pnp,(" UnHandled\n"))
|
|
// Irp->IoStatus.Information = 0;
|
|
// status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
} // switch IdType
|
|
} // IRP_MN_QUERY_ID
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_TEXT: // 0x0C
|
|
MyKdPrint(D_Pnp,("QueryDevText\n"))
|
|
|
|
if (irpStack->Parameters.QueryDeviceText.DeviceTextType
|
|
!= DeviceTextDescription)
|
|
{
|
|
MyKdPrint(D_Pnp,(" Unhandled Text Type\n"))
|
|
break;
|
|
}
|
|
|
|
{
|
|
// this is put in the Found New Hardware dialog box message.
|
|
WCHAR *wstr;
|
|
#if DBG
|
|
if (Irp->IoStatus.Information != 0)
|
|
{
|
|
MyKdPrint(D_Error,("StrExists!\n"))
|
|
}
|
|
#endif
|
|
|
|
#ifdef S_VS
|
|
wstr = str_to_wstr_dup("Comtrol VS Port", PagedPool);
|
|
#else
|
|
wstr = str_to_wstr_dup("Comtrol Port", PagedPool);
|
|
#endif
|
|
Irp->IoStatus.Information = (ULONG)wstr;
|
|
if ( wstr ) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
break; // IRP_MN_QUERY_DEVICE_TEXT
|
|
|
|
default:
|
|
//MyKdPrint(D_Pnp,(" PDO Unhandled\n"))
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
InterlockedDecrement(&Ext->PendingIRPCnt);
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
MyKdPrint(D_Pnp,(" PDO Dispatch End\n"))
|
|
return status;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
BoardBusRelations - handle IRP_MN_QUERY_DEVICE_RELATIONS: // 0x7
|
|
for our board FDO entity.
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS BoardBusRelations(IN PDEVICE_OBJECT devobj, IN PIRP Irp)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = devobj->DeviceExtension;
|
|
PDEVICE_OBJECT pdo = Ext->LowerDeviceObject;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
|
ULONG i, length, NumPDOs;
|
|
PDEVICE_RELATIONS relations;
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
|
|
ASSERT( devobj );
|
|
|
|
switch (irpStack->Parameters.QueryDeviceRelations.Type)
|
|
{
|
|
case BusRelations:
|
|
MyKdPrint(D_Pnp,("BusRelations\n"))
|
|
// Tell the plug and play system about all the PDOs.
|
|
//
|
|
// There might also be device relations below and above this FDO,
|
|
// so, be sure to propagate the relations from the upper drivers.
|
|
//
|
|
// No Completion routine is needed so long as the status is preset
|
|
// to success. (PDOs complete plug and play irps with the current
|
|
// IoStatus.Status and IoStatus.Information as the default.)
|
|
//
|
|
|
|
NumPDOs = 0; // count the number of pdo's
|
|
// count up pdo's for device
|
|
ext = Ext->port_pdo_ext;
|
|
while (ext != NULL)
|
|
{
|
|
++NumPDOs;
|
|
ext = ext->port_ext;
|
|
}
|
|
// The current number of PDOs
|
|
i = 0;
|
|
if (Irp->IoStatus.Information != 0)
|
|
i = ((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Count;
|
|
|
|
MyKdPrint(D_Pnp, ("Num PDOs:%d + %d\n", i, NumPDOs))
|
|
|
|
length = sizeof(DEVICE_RELATIONS) +
|
|
((NumPDOs + i) * sizeof (PDEVICE_OBJECT));
|
|
|
|
relations = (PDEVICE_RELATIONS) ExAllocatePool (NonPagedPool, length);
|
|
|
|
if (NULL == relations) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Copy in the device objects so far
|
|
if (i) {
|
|
RtlCopyMemory (
|
|
relations->Objects,
|
|
((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Objects,
|
|
i * sizeof (PDEVICE_OBJECT));
|
|
}
|
|
relations->Count = NumPDOs + i;
|
|
|
|
//
|
|
// For each PDO on this bus add a pointer to the device relations
|
|
// buffer, being sure to take out a reference to that object.
|
|
// The PlugPlay system will dereference the object when it is done with
|
|
// it and free the device relations buffer.
|
|
//
|
|
ext = Ext->port_pdo_ext;
|
|
while (ext != NULL)
|
|
{
|
|
relations->Objects[i++] = ext->DeviceObject;
|
|
ObReferenceObject (ext->DeviceObject); // add 1 to lock on this object
|
|
ext = ext->port_ext;
|
|
}
|
|
|
|
// Set up and pass the IRP further down the stack
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
if (0 != Irp->IoStatus.Information) {
|
|
ExFreePool ((PVOID) Irp->IoStatus.Information);
|
|
}
|
|
Irp->IoStatus.Information = (ULONG) relations;
|
|
break;
|
|
|
|
case EjectionRelations:
|
|
MyKdPrint(D_Pnp, ("EjectRelations\n"))
|
|
break;
|
|
|
|
case PowerRelations:
|
|
MyKdPrint(D_Pnp,("PowerRelations\n"))
|
|
break;
|
|
|
|
case RemovalRelations:
|
|
MyKdPrint(D_Pnp,("RemovalRelations\n"))
|
|
break;
|
|
|
|
case TargetDeviceRelation:
|
|
MyKdPrint(D_Pnp,("TargetDeviceRelations\n"))
|
|
break;
|
|
|
|
default:
|
|
MyKdPrint(D_Pnp,("UnknownRelations\n"))
|
|
break;
|
|
} // switch .Type
|
|
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------
|
|
WaitForLowerPdo -
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS WaitForLowerPdo(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = fdo->DeviceExtension;
|
|
PDEVICE_OBJECT pdo = Ext->LowerDeviceObject;
|
|
NTSTATUS status;
|
|
KEVENT Event;
|
|
|
|
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp, SerialSyncCompletion, &Event,
|
|
TRUE, TRUE, TRUE);
|
|
status = IoCallDriver(pdo, Irp);
|
|
|
|
// Wait for lower drivers to be done with the Irp
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
MyKdPrint(D_Pnp,("WaitPend\n"))
|
|
KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE,
|
|
NULL);
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
MyKdPrint(D_Pnp,("WaitErr\n"))
|
|
return status;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
SerialPowerDispatch -
|
|
This is a dispatch routine for the IRPs that come to the driver with the
|
|
IRP_MJ_POWER major code (power IRPs).
|
|
|
|
Arguments:
|
|
DeviceObject - Pointer to the device object for this device
|
|
Irp - Pointer to the IRP for the current request
|
|
|
|
Return Value:
|
|
The function value is the final status of the call
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS SerialPowerDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
BOOLEAN hook_it = FALSE;
|
|
PDEVICE_OBJECT pdo = Ext->LowerDeviceObject;
|
|
BOOLEAN acceptingIRPs = TRUE;
|
|
int index;
|
|
|
|
// dump out some debug info
|
|
index = irpStack->MinorFunction;
|
|
if (index > 0x3)
|
|
index = 0x4;
|
|
|
|
if (Ext->IsPDO)
|
|
{
|
|
#if DBG
|
|
MyKdPrint(D_PnpPower,("Port PDO PowerIrp:%d,%s\n", irpStack->MinorFunction,
|
|
power_strs[index]))
|
|
#endif
|
|
return Serial_PDO_Power (DeviceObject, Irp);
|
|
}
|
|
|
|
// else it's a FDO
|
|
#if DBG
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
MyKdPrint(D_PnpPower,("Board PowerIrp:%d,%s\n", irpStack->MinorFunction,
|
|
power_strs[index]))
|
|
}
|
|
else
|
|
{
|
|
MyKdPrint(D_PnpPower,("Port PowerIrp:%d,%s\n", irpStack->MinorFunction,
|
|
power_strs[index]))
|
|
}
|
|
#endif
|
|
return Serial_FDO_Power (DeviceObject, Irp);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Serial_FDO_Power - Handle board and port FDO power handling.
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS Serial_FDO_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
BOOLEAN hook_it = FALSE;
|
|
PDEVICE_OBJECT pdo = Ext->LowerDeviceObject;
|
|
PDEVICE_OBJECT pPdo = Ext->Pdo;
|
|
BOOLEAN acceptingIRPs = TRUE;
|
|
POWER_STATE powerState;
|
|
POWER_STATE_TYPE powerType;
|
|
int ChangePower = 0;
|
|
int fail_it = 0;
|
|
|
|
powerType = irpStack->Parameters.Power.Type;
|
|
powerState = irpStack->Parameters.Power.State;
|
|
status = STATUS_SUCCESS;
|
|
|
|
acceptingIRPs = SerialIRPPrologue(Ext);
|
|
|
|
if (acceptingIRPs == FALSE)
|
|
{
|
|
MyKdPrint(D_PnpPower,("Removed!\n"))
|
|
status = STATUS_NO_SUCH_DEVICE; // ?????????????
|
|
fail_it = 1;
|
|
}
|
|
else
|
|
{
|
|
switch (irpStack->MinorFunction)
|
|
{
|
|
case IRP_MN_SET_POWER:
|
|
MyKdPrint(D_PnpPower,("SET_POWER Type %d, SysState %d, DevStat %d\n",powerType,powerState.SystemState,powerState.DeviceState));
|
|
// Perform different ops if it was system or device
|
|
switch (irpStack->Parameters.Power.Type)
|
|
{
|
|
case DevicePowerState:
|
|
// do power up & down work on device
|
|
ChangePower = 1;
|
|
break;
|
|
|
|
case SystemPowerState:
|
|
//if (pDevExt->OwnsPowerPolicy != TRUE) {
|
|
// status = STATUS_SUCCESS;
|
|
// goto PowerExit;
|
|
// }
|
|
|
|
|
|
ChangePower = 1;
|
|
switch (irpStack->Parameters.Power.State.SystemState)
|
|
{
|
|
case PowerSystemUnspecified:
|
|
powerState.DeviceState = PowerDeviceUnspecified;
|
|
break;
|
|
|
|
case PowerSystemWorking:
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
break;
|
|
|
|
case PowerSystemSleeping1:
|
|
case PowerSystemSleeping2:
|
|
case PowerSystemSleeping3:
|
|
case PowerSystemHibernate:
|
|
case PowerSystemShutdown:
|
|
case PowerSystemMaximum:
|
|
default:
|
|
powerState.DeviceState = PowerDeviceD3;
|
|
break;
|
|
}
|
|
break; // end case SystemPowerState
|
|
|
|
} // end switch
|
|
|
|
if (ChangePower)
|
|
{
|
|
// If we are already in the requested state, just pass the IRP down
|
|
if (Ext->PowerState == powerState.DeviceState)
|
|
{
|
|
MyKdPrint(D_PnpPower,(" Same\n"))
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
ChangePower = 0;
|
|
}
|
|
}
|
|
|
|
if (ChangePower)
|
|
{
|
|
MyKdPrint(D_PnpPower,("ExtPowerState %d, DeviceState %d\n",Ext->PowerState,powerState.DeviceState));
|
|
switch (powerState.DeviceState)
|
|
{
|
|
case PowerDeviceD0:
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
// powering up board.
|
|
MyKdPrint(D_PnpPower,(" Hook\n"))
|
|
ASSERT(Ext->LowerDeviceObject);
|
|
hook_it = TRUE;
|
|
}
|
|
break;
|
|
|
|
case PowerDeviceD1:
|
|
case PowerDeviceD2:
|
|
case PowerDeviceD3:
|
|
default:
|
|
// we should be doing this on the way up in the hook routine.
|
|
MyKdPrint(D_PnpPower,(" PwDown\n"))
|
|
// Before we power down, call PoSetPowerState
|
|
PoSetPowerState(DeviceObject, powerType, powerState);
|
|
|
|
// Shut it down
|
|
//.....
|
|
//
|
|
|
|
Ext->PowerState = powerState.DeviceState; // PowerDeviceD0;
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
MyKdPrint(D_PnpPower,(" PwDown Board\n"))
|
|
// shut some things down, so it comes back up ok
|
|
#if S_RK
|
|
Ext->config->RocketPortFound = 0; // this tells if its started
|
|
#endif
|
|
Ext->config->HardwareStarted = FALSE;
|
|
}
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
} // switch (IrpSp->Parameters.Power.State.DeviceState)
|
|
} // ChangePower
|
|
break; // SET_POWER
|
|
|
|
case IRP_MN_QUERY_POWER:
|
|
MyKdPrint(D_PnpPower,(" QueryPower SystemState 0x%x\n",irpStack->Parameters.Power.State.SystemState))
|
|
// if they want to go to a power-off state(sleep, hibernate, etc)
|
|
if (irpStack->Parameters.Power.State.SystemState != PowerSystemWorking)
|
|
{
|
|
MyKdPrint(D_PnpPower,(" QueryPower turn off\n"))
|
|
// only handle power logic for the board as a whole
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
MyKdPrint(D_PnpPower,(" PwDown Board\n"))
|
|
// if a port is open and being used, then fail the request
|
|
#if 0
|
|
// try to get the wake up restore of hardware working...
|
|
// kpb, 2-7-99
|
|
if (is_board_in_use(Ext))
|
|
{
|
|
MyKdPrint(D_PnpPower,(" PwDown Board In Use!\n"))
|
|
// if wants to powerdown
|
|
// BUGBUG:, refuse hibernation
|
|
status = STATUS_NO_SUCH_DEVICE; // ?
|
|
fail_it = 1;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
MyKdPrint(D_PnpPower,(" PwDown Board, allow it!\n"))
|
|
#ifdef MTM_CLOSE_NIC_ATTEMPT
|
|
if ( Driver.nics ) {
|
|
for( i=0; i<VS1000_MAX_NICS; i++ ) {
|
|
if ( Driver.nics[i].NICHandle ) {
|
|
MyKdPrint(D_PnpPower,("Closing Nic %d\n",i))
|
|
NicClose( &Driver.nics[i] );
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
if (!fail_it)
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
break;
|
|
//case IRP_MN_WAIT_WAKE:
|
|
// Here is where support for a
|
|
// serial device (like a modem) waking the system when the
|
|
// phone rings.
|
|
//case IRP_MN_POWER_SEQUENCE:
|
|
default:
|
|
break;
|
|
} // switch (irpStack->MinorFunction)
|
|
} // else, handle irp
|
|
|
|
if (fail_it)
|
|
{
|
|
// status assumed set above
|
|
PoStartNextPowerIrp (Irp);
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = status;
|
|
InterlockedDecrement(&Ext->PendingIRPCnt);
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
// Pass to the lower driver
|
|
if (hook_it)
|
|
{
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
MyKdPrint(D_PnpPower,(" Hooked\n"))
|
|
IoSetCompletionRoutine(Irp, OurPowerCompletion, NULL, TRUE, TRUE, TRUE);
|
|
MyKdPrint(D_PnpPower,(" Ready to send Irp 0x%x to PDO 0x%x\n", Irp, pdo))
|
|
status = PoCallDriver(pdo, Irp);
|
|
// hooking proc is responsible for decrementing reference count in ext
|
|
// and calling PoStartNextPowerIrp().
|
|
}
|
|
else
|
|
{
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
/// try this ^ instead ---- IoSkipCurrentIrpStackLocation (Irp);
|
|
MyKdPrint(D_PnpPower,(" Passed\n"))
|
|
PoStartNextPowerIrp(Irp);
|
|
status = PoCallDriver(pdo, Irp);
|
|
SerialIRPEpilogue(Ext);
|
|
}
|
|
|
|
MyKdPrint(D_PnpPower,("End PowerDisp\n"))
|
|
return status;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Serial_PDO_Power - Handle port PDO power handling.
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS Serial_PDO_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
BOOLEAN hook_it = FALSE;
|
|
PDEVICE_OBJECT pdo = Ext->LowerDeviceObject;
|
|
BOOLEAN acceptingIRPs = TRUE;
|
|
POWER_STATE powerState;
|
|
POWER_STATE_TYPE powerType;
|
|
|
|
powerType = irpStack->Parameters.Power.Type;
|
|
powerState = irpStack->Parameters.Power.State;
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
|
switch (irpStack->MinorFunction)
|
|
{
|
|
case IRP_MN_SET_POWER:
|
|
if (powerType == SystemPowerState)
|
|
{
|
|
MyKdPrint(D_PnpPower,(" SysPower\n"))
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
break;
|
|
}
|
|
|
|
if (powerType != DevicePowerState)
|
|
{
|
|
MyKdPrint(D_PnpPower,(" OtherType\n"))
|
|
// They asked for a system power state change which we can't do.
|
|
// Pass it down to the lower driver.
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
break;
|
|
}
|
|
|
|
// If we are already in the requested state, just pass the IRP down
|
|
if (Ext->PowerState == powerState.DeviceState)
|
|
{
|
|
MyKdPrint(D_PnpPower,(" Same\n"))
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
break;
|
|
}
|
|
|
|
MyKdPrint(D_PnpPower,(" Set\n"))
|
|
Ext->PowerState = powerState.DeviceState; // PowerDeviceD0;
|
|
PoSetPowerState(DeviceObject, powerType, powerState);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_POWER:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_WAIT_WAKE:
|
|
case IRP_MN_POWER_SEQUENCE:
|
|
default:
|
|
MyKdPrint(D_PnpPower,("Not Imp!\n"))
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp (Irp);
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
MyKdPrint(D_PnpPower,("End PDO PowerDisp\n"))
|
|
return status;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
SerialStartDevice -
|
|
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:
|
|
|
|
Fdo - Pointer to the functional device object for this device
|
|
Irp - Pointer to the IRP for the current request
|
|
|
|
Return Value:
|
|
Return status
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS SerialStartDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_NOT_IMPLEMENTED;
|
|
PSERIAL_DEVICE_EXTENSION Ext = Fdo->DeviceExtension;
|
|
PDEVICE_OBJECT pdo = Ext->LowerDeviceObject;
|
|
|
|
MyKdPrint(D_Pnp,("SerialStartDevice\n"))
|
|
|
|
// Set up the external naming and create the symbolic link
|
|
// Pass this down to the Pdo
|
|
status = WaitForLowerPdo(Fdo, Irp);
|
|
|
|
status = STATUS_SUCCESS;
|
|
// Do the serial specific items to start the device
|
|
status = SerialFinishStartDevice(Fdo,
|
|
irpStack->Parameters.StartDevice.AllocatedResources,
|
|
irpStack->Parameters.StartDevice.AllocatedResourcesTranslated);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
MyKdPrint(D_Pnp,("End Start Dev\n"))
|
|
return status;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
SerialSyncCompletion -
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS SerialSyncCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PKEVENT SerialSyncEvent
|
|
)
|
|
{
|
|
KeSetEvent(SerialSyncEvent, IO_NO_INCREMENT, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
SerialFinishStartDevice -
|
|
This routine starts driver hardware. On the RocketPort, this is
|
|
a board, or a port. On the VS, this would be the whole VS driver
|
|
(all boxes) or a individual port.
|
|
|
|
A Pnp ADDDEVICE call(in pnpadd.c) should have been seen before this
|
|
to setup the driver. After this, we may see Starts or Stops on the
|
|
hardware, which the OS may start and stop to change resource assignments,
|
|
etc.
|
|
|
|
Arguments:
|
|
|
|
Fdo - Pointer to the Functional Device Object that is starting
|
|
resourceList - Pointer to the untranslated resources needed by this device
|
|
trResourceList - Pointer to the translated resources needed by this device
|
|
PUserData - Pointer to the user-specified resources/attributes
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS on success, something else appropriate on failure
|
|
|----------------------------------------------------------------------*/
|
|
NTSTATUS SerialFinishStartDevice(IN PDEVICE_OBJECT Fdo,
|
|
IN PCM_RESOURCE_LIST resourceList,
|
|
IN PCM_RESOURCE_LIST trResourceList)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION Ext = Fdo->DeviceExtension;
|
|
NTSTATUS status;
|
|
DEVICE_CONFIG *pConfig;
|
|
PSERIAL_DEVICE_EXTENSION newExtension = NULL;
|
|
PDEVICE_OBJECT NewDevObj;
|
|
int ch;
|
|
int is_fdo = 1;
|
|
#ifdef NT50
|
|
PWSTR iBuffer;
|
|
#endif
|
|
|
|
MyKdPrint(D_Pnp,("SerialFinishStartDevice\n"))
|
|
|
|
pConfig = Ext->config;
|
|
|
|
MyKdPrint(D_Pnp,("ChkPt A\n"))
|
|
|
|
if (Ext->DeviceType != DEV_BOARD)
|
|
{
|
|
MyKdPrint(D_Pnp,("Start PnpPort\n"))
|
|
Ext->FdoStarted = TRUE; // i don't thinks this is used on ports
|
|
#ifdef NT50
|
|
// Create a symbolic link with IoRegisterDeviceInterface()
|
|
//
|
|
status = IoRegisterDeviceInterface( Ext->Pdo,
|
|
(LPGUID)&GUID_CLASS_COMPORT,
|
|
NULL,
|
|
&Ext->DeviceClassSymbolicName );
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
MyKdPrint(D_Error,("Couldn't register class association\n"))
|
|
Ext->DeviceClassSymbolicName.Buffer = NULL;
|
|
}
|
|
else {
|
|
|
|
MyKdPrint(D_Init, ("Registering class association for:\n PDO:0x%8x\nSymLink %s\n",
|
|
Ext->Pdo, UToC1(&Ext->DeviceClassSymbolicName)))
|
|
}
|
|
|
|
// Now set the symbolic link for the interface association
|
|
//
|
|
|
|
status = IoSetDeviceInterfaceState( &Ext->DeviceClassSymbolicName,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
MyKdPrint(D_Error,("Couldn't set class association for %s\n",
|
|
UToC1(&Ext->DeviceClassSymbolicName)))
|
|
}
|
|
else {
|
|
|
|
MyKdPrint(D_PnpAdd, ("Enable class association for device: %s\n",
|
|
UToC1(&Ext->DeviceClassSymbolicName)))
|
|
}
|
|
|
|
#if 0
|
|
// Strictly for verification - get the entire list of COM class interfaces
|
|
// for up to 6 COM ports
|
|
|
|
status = IoGetDeviceInterfaces( (LPGUID)&GUID_CLASS_COMPORT,
|
|
NULL, // No PDO - get 'em all
|
|
0,
|
|
&iBuffer );
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
MyKdPrint(D_Error,("Couldn't get interface list for GUID_CLASS_COMPORT\n"))
|
|
}
|
|
else {
|
|
|
|
PWCHAR pwbuf = iBuffer;
|
|
char cbuf[128];
|
|
int j = 0;
|
|
int ofs = 0;
|
|
|
|
while ( (pwbuf != 0) && (j < 8) ){
|
|
|
|
WStrToCStr( cbuf, pwbuf, sizeof(cbuf) );
|
|
|
|
MyKdPrint(D_Pnp, ("COM port interface %d: %s\n", j, cbuf))
|
|
|
|
ofs += strlen(cbuf) + 1;
|
|
pwbuf = &iBuffer[ofs];
|
|
j++;
|
|
}
|
|
ExFreePool(iBuffer);
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
if (Ext->FdoStarted == TRUE)
|
|
{
|
|
MyKdPrint(D_Error,("ReStart PnpBrd\n"))
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
if (!Driver.NoPnpPorts)
|
|
is_fdo = 0; // eject PDOs representing port hardware.
|
|
|
|
// Get the configuration info for the device.
|
|
#ifdef S_RK
|
|
status = RkGetPnpResourceToConfig(Fdo, resourceList, trResourceList,
|
|
pConfig);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
Eprintf("StartErr 1N");
|
|
return status;
|
|
}
|
|
|
|
#ifdef DO_ISA_BUS_ALIAS_IO
|
|
status = Report_Alias_IO(Ext);
|
|
if (status != 0)
|
|
{
|
|
Eprintf("StartErr Alias-IO");
|
|
MyKdPrint(D_Pnp,("Error 1P\n"))
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return status;
|
|
}
|
|
MyKdPrint(D_Pnp,("ChkPt B\n"))
|
|
#endif
|
|
//DELF
|
|
MyKdPrint(D_Pnp,("INIT RCK\n"))
|
|
//END DELF
|
|
status = RocketPortSpecialStartup(Ext);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
Eprintf("StartErr 1J");
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
MyKdPrint(D_Pnp,("ChkPt C\n"))
|
|
|
|
#ifdef S_VS
|
|
status = VSSpecialStartup(Ext);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
Eprintf("StartErr 1J");
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
//----- Create our port devices, if we are doing pnp ports, then
|
|
// create PDO's, if not, then create normal com-port device objects
|
|
// (same as FDO's.)
|
|
for (ch=0; ch<Ext->config->NumPorts; ch++)
|
|
{
|
|
//MyKdPrint(D_Pnp,("FS,ChanInit:%d\n", ch))
|
|
status = CreatePortDevice(
|
|
Driver.GlobalDriverObject,
|
|
Ext, // parent ext.
|
|
&newExtension,
|
|
ch,
|
|
is_fdo);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
Eprintf("StartErr 1Q");
|
|
return status;
|
|
}
|
|
NewDevObj = newExtension->DeviceObject; //return the new device object
|
|
NewDevObj->Flags |= DO_POWER_PAGABLE;
|
|
|
|
if (!is_fdo) // eject PDOs representing port hardware.
|
|
newExtension->IsPDO = 1; // we are a pdo
|
|
|
|
#if S_RK
|
|
if (Ext->config->RocketPortFound) // if started(not delayed isa)
|
|
#endif
|
|
{
|
|
status = StartPortHardware(newExtension,
|
|
ch); // channel num, port index
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
Eprintf("StartErr 1O");
|
|
return status;
|
|
}
|
|
}
|
|
} // for ports
|
|
|
|
#ifdef S_RK
|
|
if (Ext->config->RocketPortFound) // if started(not delayed isa)
|
|
#endif
|
|
{
|
|
Ext->config->HardwareStarted = TRUE;
|
|
|
|
// send ROW configuration to SocketModems
|
|
InitSocketModems(Ext);
|
|
#ifdef S_RK
|
|
InitRocketModemII (Ext);
|
|
#endif
|
|
}
|
|
MyKdPrint(D_Pnp,("ChkPt D\n"))
|
|
|
|
//---- start up the timer
|
|
if (!Driver.TimerCreated)
|
|
{
|
|
#ifdef S_RK
|
|
Driver.SetupIrq = 0;
|
|
#endif
|
|
//MyKdPrint(D_Pnp,("before rcktinitpolltimer\n"))
|
|
RcktInitPollTimer();
|
|
//MyKdPrint(D_Pnp,("after rcktinitpolltimer\n"))
|
|
|
|
KeSetTimer(&Driver.PollTimer,
|
|
Driver.PollIntervalTime,
|
|
&Driver.TimerDpc);
|
|
}
|
|
MyKdPrint(D_Pnp,("ChkPt F, after\n"))
|
|
|
|
Ext->FdoStarted = TRUE;
|
|
|
|
//if (Drier.VerboseLog)
|
|
// Eprintf("Success start dev");
|
|
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
#ifdef S_RK
|
|
/*-----------------------------------------------------------------------
|
|
RocketPortSpecialStartup -
|
|
|-----------------------------------------------------------------------*/
|
|
static NTSTATUS RocketPortSpecialStartup(PSERIAL_DEVICE_EXTENSION Ext)
|
|
|
|
{
|
|
int ch;
|
|
int start_isa_flag;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PSERIAL_DEVICE_EXTENSION tmpExt;
|
|
PSERIAL_DEVICE_EXTENSION newExt;
|
|
|
|
if (Ext->config->BusType == Isa)
|
|
{
|
|
MyKdPrint(D_PnpPower,("pnp- ISA brd Index:%d\n",
|
|
Ext->config->ISABrdIndex))
|
|
|
|
if (Ext->config->ISABrdIndex == 0)
|
|
start_isa_flag = 1;
|
|
else if (is_first_isa_card_started())
|
|
start_isa_flag = 1;
|
|
else
|
|
{
|
|
MyKdPrint(D_PnpPower,("Delay 2ndary ISA card start\n"))
|
|
start_isa_flag = 0;
|
|
}
|
|
}
|
|
|
|
//----- Init the RocketPort hardware
|
|
if ((Ext->config->BusType == Isa) && (!start_isa_flag))
|
|
status = 0; // skip, can't start until we get the first board
|
|
else
|
|
{
|
|
status = InitController(Ext); // this sets RocketPortFound = TRUE if ok
|
|
if (status != 0)
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
MyKdPrint(D_Error,("Brd failed startup\n"))
|
|
|
|
//if (Driver.VerboseLog)
|
|
// Eprintf("Error InitCtrl");
|
|
return status;
|
|
}
|
|
MyKdPrint(D_PnpPower,("Brd started\n"))
|
|
}
|
|
|
|
if ((Ext->config->BusType == Isa) && (is_first_isa_card_started()) &&
|
|
(is_isa_cards_pending_start()) )
|
|
{
|
|
MyKdPrint(D_Pnp,("Do Pending\n"))
|
|
tmpExt = Driver.board_ext;
|
|
while (tmpExt)
|
|
{
|
|
if ((tmpExt->config->BusType == Isa) &&
|
|
(!tmpExt->config->RocketPortFound)) // this tells if its started
|
|
{
|
|
MyKdPrint(D_Pnp,("Pending 1A\n"))
|
|
status = InitController(tmpExt); // this sets RocketPortFound = TRUE if ok
|
|
|
|
if (status != 0)
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
if (Driver.VerboseLog)
|
|
Eprintf("Error 5C");
|
|
return status;
|
|
}
|
|
|
|
MyKdPrint(D_Pnp,("Pend 2A\n"))
|
|
//----- Find and initialize the controller ports
|
|
newExt = tmpExt->port_ext;
|
|
ch=0;
|
|
while (newExt)
|
|
{
|
|
status = StartPortHardware(newExt,
|
|
ch); // channel num, port index
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
Eprintf("StartErr 1N");
|
|
return status;
|
|
}
|
|
newExt = newExt->port_ext;
|
|
++ch;
|
|
}
|
|
tmpExt->config->HardwareStarted = TRUE;
|
|
|
|
// send ROW configuration to SocketModems
|
|
InitSocketModems(tmpExt);
|
|
|
|
MyKdPrint(D_Pnp,("Pending OK\n"))
|
|
}
|
|
tmpExt = tmpExt->board_ext;
|
|
}
|
|
} // if isa boards to startup
|
|
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
/*-----------------------------------------------------------------------
|
|
|
|
This routine kills any irps pending for the passed device object.
|
|
|
|
Arguments:
|
|
DeviceObject - Pointer to the device object whose irps must die.
|
|
|
|
Return Value:
|
|
VOID
|
|
|-----------------------------------------------------------------------*/
|
|
VOID SerialKillPendingIrps(PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
KIRQL oldIrql;
|
|
|
|
//PAGED_CODE();
|
|
//SerialDump (SERTRACECALLS,("SERIAL: Enter SerialKillPendingIrps\n"));
|
|
|
|
// this is for the FDO, which currently is the BOARD, so we have to
|
|
// do all ports for this board.(THIS IS NOT A PORT EXTENSION!!!!!)
|
|
|
|
// First kill all the reads and writes.
|
|
SerialKillAllReadsOrWrites(
|
|
DeviceObject,
|
|
&extension->WriteQueue,
|
|
&extension->CurrentWriteIrp
|
|
);
|
|
|
|
SerialKillAllReadsOrWrites(
|
|
DeviceObject,
|
|
&extension->ReadQueue,
|
|
&extension->CurrentReadIrp
|
|
);
|
|
|
|
// Next get rid of purges.
|
|
SerialKillAllReadsOrWrites(
|
|
DeviceObject,
|
|
&extension->PurgeQueue,
|
|
&extension->CurrentPurgeIrp
|
|
);
|
|
|
|
// Now get rid a pending wait mask irp.
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
if (extension->CurrentWaitIrp) {
|
|
|
|
PDRIVER_CANCEL cancelRoutine;
|
|
|
|
cancelRoutine = extension->CurrentWaitIrp->CancelRoutine;
|
|
extension->CurrentWaitIrp->Cancel = TRUE;
|
|
|
|
if (cancelRoutine) {
|
|
|
|
extension->CurrentWaitIrp->CancelIrql = oldIrql;
|
|
extension->CurrentWaitIrp->CancelRoutine = NULL;
|
|
|
|
cancelRoutine(
|
|
DeviceObject,
|
|
extension->CurrentWaitIrp
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
}
|
|
//SerialDump (SERTRACECALLS,("SERIAL: Leave SerialKillPendingIrps\n"));
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
|
|
This function must be called at any IRP dispatch entry point. It,
|
|
with SerialIRPPrologue(), keeps track of all pending IRP's for the given
|
|
PDevObj.
|
|
|
|
Arguments:
|
|
PDevObj - Pointer to the device object we are tracking pending IRP's for.
|
|
|
|
Return Value:
|
|
None.
|
|
|-----------------------------------------------------------------------*/
|
|
VOID SerialIRPEpilogue(IN PSERIAL_DEVICE_EXTENSION PDevExt)
|
|
{
|
|
ULONG pendingCnt;
|
|
|
|
pendingCnt = InterlockedDecrement(&PDevExt->PendingIRPCnt);
|
|
|
|
#if DBG
|
|
//MyKdPrint(D_Pnp,("Exit PendingIrpCnt:%d\n", PDevExt->PendingIRPCnt))
|
|
#endif
|
|
|
|
if (pendingCnt == 0)
|
|
{
|
|
MyKdPrint(D_Pnp,("Set PendingIRPEvent\n"))
|
|
KeSetEvent(&PDevExt->PendingIRPEvent, IO_NO_INCREMENT, FALSE);
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
SerialIoCallDriver -
|
|
|-----------------------------------------------------------------------*/
|
|
NTSTATUS SerialIoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt,
|
|
PDEVICE_OBJECT PDevObj,
|
|
PIRP PIrp)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT( PDevObj );
|
|
|
|
status = IoCallDriver(PDevObj, PIrp);
|
|
SerialIRPEpilogue(PDevExt);
|
|
return status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
SerialPoCallDriver -
|
|
|-----------------------------------------------------------------------*/
|
|
NTSTATUS SerialPoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt,
|
|
PDEVICE_OBJECT PDevObj,
|
|
PIRP PIrp)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = PoCallDriver(PDevObj, PIrp);
|
|
SerialIRPEpilogue(PDevExt);
|
|
return status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
This routine is a completion handler that is called after the COM port
|
|
has been powered up. It sets the COM port in a known state by calling
|
|
SerialReset, SerialMarkClose, SerialClrRTS, and SerialClrDTR. The it
|
|
does a PoCompleteRequest to finish off the power Irp.
|
|
|
|
Arguments:
|
|
DeviceObject - Pointer to the device object for this device
|
|
Irp - Pointer to the IRP for the current request
|
|
Context - None
|
|
|
|
Return Value:
|
|
Return status in IRP when being called (if not STATUS_SUCCESS) or
|
|
STATUS_SUCCESS.
|
|
|-----------------------------------------------------------------------*/
|
|
NTSTATUS OurPowerCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
|
|
{
|
|
NTSTATUS status = Irp->IoStatus.Status;
|
|
PSERIAL_DEVICE_EXTENSION Ext = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
POWER_STATE powerState;
|
|
POWER_STATE_TYPE powerType;
|
|
|
|
powerType = irpStack->Parameters.Power.Type;
|
|
powerState = irpStack->Parameters.Power.State;
|
|
|
|
MyKdPrint(D_PnpPower,("In OurPowerCompletion\n"))
|
|
|
|
if (irpStack->MinorFunction == IRP_MN_SET_POWER)
|
|
{
|
|
if (powerState.DeviceState == PowerDeviceD0)
|
|
{
|
|
MyKdPrint(D_PnpPower,("Restoring to Power On State D0\n"))
|
|
|
|
status = STATUS_SUCCESS;
|
|
// set hardware to known power up state
|
|
Ext->PowerState = powerState.DeviceState; // PowerDeviceD0;
|
|
|
|
if (Ext->DeviceType == DEV_BOARD)
|
|
{
|
|
status = PowerUpDevice(Ext);
|
|
} // board device
|
|
else if (Ext->DeviceType == DEV_PORT)
|
|
{
|
|
Ext->config->HardwareStarted = TRUE;
|
|
}
|
|
|
|
PoSetPowerState(DeviceObject, powerType, powerState);
|
|
}
|
|
else // if (powerState.DeviceState == PowerDeviceD3)
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
// Clear the flag saying we are waiting for a power down
|
|
Ext->ReceivedQueryD3 = FALSE;
|
|
|
|
Ext->PowerState = PowerDeviceD3;
|
|
}
|
|
}
|
|
|
|
InterlockedDecrement(&Ext->PendingIRPCnt);
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
return status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
RestorePortSettings - Try to restore port hardware settings. Called
|
|
after power-off sleep mode.
|
|
|-----------------------------------------------------------------------*/
|
|
void RestorePortSettings(PSERIAL_DEVICE_EXTENSION Ext)
|
|
{
|
|
SERIAL_HANDFLOW TempHandFlow;
|
|
DWORD TempDTRRTSStatus;
|
|
DWORD xorDTRRTSStatus;
|
|
|
|
#ifdef S_RK
|
|
// remember what the status of pins are coming into this
|
|
// so we can try to put them back to what they were prior to
|
|
// hardware re-initialization.
|
|
TempDTRRTSStatus = Ext->DTRRTSStatus; // SERIAL_DTR_STATE;
|
|
|
|
if(sGetChanStatus(Ext->ChP) & STATMODE)
|
|
{ // Take channel out of statmode if necessary
|
|
sDisRxStatusMode(Ext->ChP);
|
|
}
|
|
// pDisLocalLoopback(Ext->Port);
|
|
// Clear any pending modem changes
|
|
sGetChanIntID(Ext->ChP);
|
|
sEnRxFIFO(Ext->ChP); // Enable Rx
|
|
sEnTransmit(Ext->ChP); // Enable Tx
|
|
sSetRxTrigger(Ext->ChP,TRIG_1); // always trigger
|
|
sEnInterrupts(Ext->ChP, Ext->IntEnables);// allow interrupts
|
|
|
|
ForceExtensionSettings(Ext);
|
|
|
|
// make a temp. copy of handflow struct
|
|
memcpy(&TempHandFlow, &Ext->HandFlow, sizeof(TempHandFlow));
|
|
|
|
// force updates in SerialSetHandFlow, which looks for delta change.
|
|
Ext->HandFlow.ControlHandShake = ~TempHandFlow.ControlHandShake;
|
|
Ext->HandFlow.FlowReplace = ~TempHandFlow.FlowReplace;
|
|
|
|
SerialSetHandFlow(Ext, &TempHandFlow); // in ioctl.c
|
|
|
|
// program hardware baudrate
|
|
ProgramBaudRate(Ext, Ext->BaudRate);
|
|
|
|
xorDTRRTSStatus = Ext->DTRRTSStatus ^ TempDTRRTSStatus;
|
|
|
|
// try to restore the actual dtr & rts outputs
|
|
if (xorDTRRTSStatus & SERIAL_DTR_STATE) // changed
|
|
{
|
|
// if not auto-handshake dtr mode
|
|
if (!((Ext->HandFlow.ControlHandShake & SERIAL_DTR_MASK) ==
|
|
SERIAL_DTR_HANDSHAKE ))
|
|
{
|
|
if (TempDTRRTSStatus & SERIAL_DTR_STATE) // was on
|
|
{
|
|
sSetDTR(Ext->ChP);
|
|
}
|
|
else
|
|
{
|
|
sClrDTR(Ext->ChP);
|
|
}
|
|
} // not auto-dtr flow
|
|
} // chg in dtr
|
|
|
|
if (xorDTRRTSStatus & SERIAL_RTS_STATE) // changed
|
|
{
|
|
// if not auto-flow control rts
|
|
if (!((Ext->HandFlow.ControlHandShake & SERIAL_RTS_MASK) ==
|
|
SERIAL_RTS_HANDSHAKE))
|
|
{
|
|
if (TempDTRRTSStatus & SERIAL_RTS_STATE) // was on
|
|
{
|
|
sSetRTS(Ext->ChP);
|
|
}
|
|
else
|
|
{
|
|
sClrRTS(Ext->ChP);
|
|
}
|
|
} // chg in rts
|
|
Ext->DTRRTSStatus = TempDTRRTSStatus;
|
|
}
|
|
#endif
|
|
// the VS boxes will not be powered off, and will hold their state
|
|
// so no hardware re-initialization is needed. The box will have
|
|
// probably timed out the connection, and force a re-sync operation,
|
|
// we might want to pro-actively start this so there is a smaller
|
|
// delay...
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
PowerUpDevice - Used to bring power back on after turning it off.
|
|
|-----------------------------------------------------------------------*/
|
|
NTSTATUS PowerUpDevice(PSERIAL_DEVICE_EXTENSION Ext)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION port_ext;
|
|
int ch;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
#ifdef S_RK
|
|
MyKdPrint(D_PnpPower,("RocketPort Init %d\n",Ext->config->HardwareStarted))
|
|
status = RocketPortSpecialStartup(Ext);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
MyKdPrint(D_Error,("RocketPort Init Failed\n"))
|
|
//return status;
|
|
}
|
|
if (Ext->config->RocketPortFound) // if started(not delayed isa)
|
|
Ext->config->HardwareStarted = TRUE;
|
|
#endif
|
|
|
|
#ifdef S_VS
|
|
MyKdPrint(D_PnpPower,("VS Init\n"))
|
|
status = VSSpecialStartup(Ext);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
MyKdPrint(D_Error,("VS Init Failed\n"))
|
|
//return status;
|
|
}
|
|
Ext->config->HardwareStarted = TRUE;
|
|
#endif
|
|
|
|
if (Ext->config->HardwareStarted == TRUE)
|
|
{
|
|
if (Ext->port_ext == NULL)
|
|
{MyKdPrint(D_Error,("No Ports\n")) }
|
|
|
|
//----- Find and initialize the controller ports
|
|
port_ext = Ext->port_ext;
|
|
ch=0;
|
|
while (port_ext)
|
|
{
|
|
MyKdPrint(D_PnpPower,("PowerUp Port %d\n", ch))
|
|
status = StartPortHardware(port_ext,
|
|
ch); // channel num, port index
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
|
|
MyKdPrint(D_Error,("PortPowerUp Err1\n"))
|
|
return status;
|
|
}
|
|
MyKdPrint(D_PnpPower,("PowerUp Port %d Restore\n", ch))
|
|
RestorePortSettings(port_ext);
|
|
|
|
port_ext = port_ext->port_ext;
|
|
++ch;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MyKdPrint(D_Error,("Not started\n"))
|
|
}
|
|
// send ROW configuration to SocketModems
|
|
//InitSocketModems(Ext);
|
|
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
SerialRemoveFdo -
|
|
|-----------------------------------------------------------------------*/
|
|
NTSTATUS SerialRemoveFdo(IN PDEVICE_OBJECT pFdo)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION extension = pFdo->DeviceExtension;
|
|
|
|
MyKdPrint(D_Pnp,("SerialRemoveFdo\n"))
|
|
|
|
// Only do these things if the device has started
|
|
//(comment out 8-15-98) if (extension->FdoStarted)
|
|
{
|
|
if (extension->DeviceType == DEV_BOARD)
|
|
{
|
|
// BUGBUG, shut down this board(are we deallocating resources?)!!!
|
|
RcktDeleteBoard(extension);
|
|
if (Driver.board_ext == NULL) // no more boards, so delete driver obj
|
|
{
|
|
// Delete Driver obj
|
|
RcktDeleteDriverObj(Driver.driver_ext);
|
|
Driver.driver_ext = NULL; // no more boards
|
|
#ifdef S_VS
|
|
// to allow the driver to unload from nt50, we need to
|
|
// stop the nic-binding thread, shut down the nic
|
|
// cards and the protocol from ndis
|
|
init_stop(); // unload thread, ndis nic cards, etc
|
|
#endif
|
|
{
|
|
PDEVICE_OBJECT currentDevice = Driver.GlobalDriverObject->DeviceObject;
|
|
int i;
|
|
|
|
i = 0;
|
|
while(currentDevice)
|
|
{
|
|
currentDevice = currentDevice->NextDevice;
|
|
if (currentDevice)
|
|
++i;
|
|
}
|
|
if (i != 0)
|
|
{
|
|
MyKdPrint(D_Pnp,("Err, %d Devices still remain\n",i))
|
|
}
|
|
else
|
|
{
|
|
MyKdPrint(D_Pnp,("Ok remove\n"))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RcktDeletePort(extension);
|
|
// must be a port fdo, kill it
|
|
}
|
|
}
|
|
|
|
MyKdPrint(D_Pnp,("End SerialRemoveFdo\n"))
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#endif // NT50
|
|
|
|
/*-----------------------------------------------------------------------
|
|
|
|
This function must be called at any IRP dispatch entry point. It,
|
|
with SerialIRPEpilogue(), keeps track of all pending IRP's for the given
|
|
PDevObj.
|
|
|
|
Arguments:
|
|
PDevObj - Pointer to the device object we are tracking pending IRP's for.
|
|
|
|
Return Value:
|
|
TRUE if the device can accept IRP's.
|
|
|-----------------------------------------------------------------------*/
|
|
BOOLEAN SerialIRPPrologue(IN PSERIAL_DEVICE_EXTENSION PDevExt)
|
|
{
|
|
InterlockedIncrement(&PDevExt->PendingIRPCnt);
|
|
#ifdef NT50
|
|
return PDevExt->DevicePNPAccept == SERIAL_PNPACCEPT_OK ? TRUE : FALSE;
|
|
#else
|
|
return TRUE;
|
|
#endif
|
|
}
|