- Move IopInitialize/StartDevice to PnP Manager

- I/O Packet APIs fixes Part 1:
  - Clear the current IRP before parsing the Device Queues
  - Respect Cancelable parameter in IoStartNextPacket(ByKey) instead of ignoring it (acquire the cancel lock when it's requested)
  - Raise IRQL to DISPATCH_LEVEL in IoStartPacket instead of expecting the caller to do it and crashing. Also only use Cancel Lock if a Cancel Function was specified.
  - Actually handle the case where the IRP Was cancelled right after insert and the Cancel Routine has to be called.

svn path=/trunk/; revision=22744
This commit is contained in:
Alex Ionescu 2006-07-01 18:56:09 +00:00
parent 036139907e
commit 51989fa847
2 changed files with 226 additions and 206 deletions

View file

@ -82,111 +82,6 @@ IoShutdownRegisteredDevices(VOID)
} }
} }
NTSTATUS
FASTCALL
IopInitializeDevice(PDEVICE_NODE DeviceNode,
PDRIVER_OBJECT DriverObject)
{
PDEVICE_OBJECT Fdo;
NTSTATUS Status;
BOOLEAN IsPnpDriver = FALSE;
if (DriverObject->DriverExtension->AddDevice)
{
/* This is a Plug and Play driver */
DPRINT("Plug and Play driver found\n");
ASSERT(DeviceNode->PhysicalDeviceObject);
DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
DriverObject->DriverExtension->AddDevice);
IsPnpDriver = !IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER);
Status = DriverObject->DriverExtension->AddDevice(
DriverObject, IsPnpDriver ? DeviceNode->PhysicalDeviceObject : NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
if (IsPnpDriver)
{
Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
if (Fdo == DeviceNode->PhysicalDeviceObject)
{
/* FIXME: What do we do? Unload the driver or just disable the device? */
DbgPrint("An FDO was not attached\n");
IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
return STATUS_UNSUCCESSFUL;
}
if (Fdo->DeviceType == FILE_DEVICE_ACPI)
{
static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
/* There can be only one system power device */
if (!SystemPowerDeviceNodeCreated)
{
PopSystemPowerDeviceNode = DeviceNode;
SystemPowerDeviceNodeCreated = TRUE;
}
}
ObDereferenceObject(Fdo);
}
IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
}
return STATUS_SUCCESS;
}
NTSTATUS
IopStartDevice(
PDEVICE_NODE DeviceNode)
{
IO_STATUS_BLOCK IoStatusBlock;
IO_STACK_LOCATION Stack;
PDEVICE_OBJECT Fdo;
NTSTATUS Status;
DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList;
Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated;
Status = IopInitiatePnpIrp(
Fdo,
&IoStatusBlock,
IRP_MN_START_DEVICE,
&Stack);
if (!NT_SUCCESS(Status))
{
DPRINT("IopInitiatePnpIrp() failed\n");
}
else
{
if (IopDeviceNodeHasFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY))
{
DPRINT("Device needs enumeration, invalidating bus relations\n");
Status = IopInvalidateDeviceRelations(DeviceNode, BusRelations);
IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
}
}
ObDereferenceObject(Fdo);
if (NT_SUCCESS(Status))
DeviceNode->Flags |= DN_STARTED;
return Status;
}
NTSTATUS NTSTATUS
NTAPI NTAPI
IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
@ -1247,137 +1142,157 @@ IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject,
/* /*
* @implemented * @implemented
*
* FUNCTION: Dequeues the next packet from the given device object's
* associated device queue according to a specified sort-key value and calls
* the drivers StartIo routine with that IRP
* ARGUMENTS:
* DeviceObject = Device object for which the irp is to dequeued
* Cancelable = True if IRPs in the key can be canceled
* Key = Sort key specifing which entry to remove from the queue
*/ */
VOID VOID
STDCALL NTAPI
IoStartNextPacketByKey(PDEVICE_OBJECT DeviceObject, IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
BOOLEAN Cancelable, IN BOOLEAN Cancelable,
ULONG Key) IN ULONG Key)
{ {
PKDEVICE_QUEUE_ENTRY entry; PKDEVICE_QUEUE_ENTRY Entry;
PIRP Irp; PIRP Irp;
KIRQL OldIrql;
entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, /* Acquire the cancel lock if this is cancelable */
Key); if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
if (entry != NULL) /* Clear the current IRP */
{ DeviceObject->CurrentIrp = NULL;
Irp = CONTAINING_RECORD(entry,
IRP, /* Remove an entry from the queue */
Tail.Overlay.DeviceQueueEntry); Entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, Key);
if (Entry)
{
/* Get the IRP and set it */
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
DeviceObject->CurrentIrp = Irp; DeviceObject->CurrentIrp = Irp;
DPRINT("Next irp is 0x%p\n", Irp);
DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); /* Release the cancel lock if we had acquired it */
} if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
else
{ /* Call the Start I/O Routine */
DPRINT("No next irp\n"); DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
DeviceObject->CurrentIrp = NULL; }
} else
{
/* Otherwise, release the cancel lock if we had acquired it */
if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
}
} }
/* /*
* @implemented * @implemented
*
* FUNCTION: Removes the next packet from the device's queue and calls
* the driver's StartIO
* ARGUMENTS:
* DeviceObject = Device
* Cancelable = True if irps in the queue can be canceled
*/ */
VOID VOID
STDCALL NTAPI
IoStartNextPacket(PDEVICE_OBJECT DeviceObject, IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
BOOLEAN Cancelable) IN BOOLEAN Cancelable)
{ {
PKDEVICE_QUEUE_ENTRY entry; PKDEVICE_QUEUE_ENTRY Entry;
PIRP Irp; PIRP Irp;
KIRQL OldIrql;
DPRINT("IoStartNextPacket(DeviceObject 0x%p, Cancelable %d)\n", /* Acquire the cancel lock if this is cancelable */
DeviceObject, Cancelable); if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue); /* Clear the current IRP */
DeviceObject->CurrentIrp = NULL;
if (entry!=NULL) /* Remove an entry from the queue */
{ Entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
Irp = CONTAINING_RECORD(entry,IRP,Tail.Overlay.DeviceQueueEntry); if (Entry)
{
/* Get the IRP and set it */
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
DeviceObject->CurrentIrp = Irp; DeviceObject->CurrentIrp = Irp;
DeviceObject->DriverObject->DriverStartIo(DeviceObject,Irp);
} /* Call the Start I/O Routine */
else DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
{ }
DeviceObject->CurrentIrp = NULL; else
} {
/* Otherwise, release the cancel lock if we had acquired it */
if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
}
} }
/* /*
* @implemented * @implemented
*
* FUNCTION: Either call the device's StartIO routine with the packet or,
* if the device is busy, queue it.
* ARGUMENTS:
* DeviceObject = Device to start the packet on
* Irp = Irp to queue
* Key = Where to insert the irp
* If zero then insert in the tail of the queue
* CancelFunction = Optional function to cancel the irqp
*/ */
VOID VOID
STDCALL NTAPI
IoStartPacket(PDEVICE_OBJECT DeviceObject, IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
PIRP Irp, IN PIRP Irp,
PULONG Key, IN PULONG Key,
PDRIVER_CANCEL CancelFunction) IN PDRIVER_CANCEL CancelFunction)
{ {
BOOLEAN stat; BOOLEAN Stat;
KIRQL oldirql; KIRQL OldIrql, CancelIrql;
DPRINT("IoStartPacket(Irp 0x%p)\n", Irp); /* Raise to dispatch level */
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
ASSERT_IRQL(DISPATCH_LEVEL); /* Check if we should acquire the cancel lock */
if (CancelFunction)
{
/* Acquire and set it */
IoAcquireCancelSpinLock(&CancelIrql);
Irp->CancelRoutine = CancelFunction;
}
IoAcquireCancelSpinLock(&oldirql); /* Check if we have a key */
if (Key)
{
/* Insert by key */
Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry,
*Key);
}
else
{
/* Insert without a key */
Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry);
}
if (CancelFunction != NULL) /* Check if this was a first insert */
{ if (!Stat)
Irp->CancelRoutine = CancelFunction; {
} /* Set the IRP */
if (Key!=0)
{
stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry,
*Key);
}
else
{
stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry);
}
if (!stat)
{
IoReleaseCancelSpinLock(DISPATCH_LEVEL);
DeviceObject->CurrentIrp = Irp; DeviceObject->CurrentIrp = Irp;
DeviceObject->DriverObject->DriverStartIo(DeviceObject,Irp);
if (oldirql < DISPATCH_LEVEL) /* Release the cancel lock if we had a cancel function */
{ if (CancelFunction) IoReleaseCancelSpinLock(CancelIrql);
KeLowerIrql(oldirql);
/* Call the Start I/O function */
DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
}
else
{
/* The packet was inserted... check if we have a cancel function */
if (CancelFunction)
{
/* Check if the IRP got cancelled */
if (Irp->Cancel)
{
/*
* Set the cancel IRQL, clear the currnet cancel routine and
* call ours
*/
Irp->CancelIrql = CancelIrql;
Irp->CancelRoutine = NULL;
CancelFunction(DeviceObject, Irp);
}
else
{
/* Otherwise, release the lock */
IoReleaseCancelSpinLock(CancelIrql);
}
} }
} }
else
{ /* Return back to previous IRQL */
IoReleaseCancelSpinLock(oldirql); KeLowerIrql(OldIrql);
}
} }
/* EOF */ /* EOF */

View file

@ -44,6 +44,111 @@ IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode; return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
} }
NTSTATUS
FASTCALL
IopInitializeDevice(PDEVICE_NODE DeviceNode,
PDRIVER_OBJECT DriverObject)
{
PDEVICE_OBJECT Fdo;
NTSTATUS Status;
BOOLEAN IsPnpDriver = FALSE;
if (DriverObject->DriverExtension->AddDevice)
{
/* This is a Plug and Play driver */
DPRINT("Plug and Play driver found\n");
ASSERT(DeviceNode->PhysicalDeviceObject);
DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
DriverObject->DriverExtension->AddDevice);
IsPnpDriver = !IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER);
Status = DriverObject->DriverExtension->AddDevice(
DriverObject, IsPnpDriver ? DeviceNode->PhysicalDeviceObject : NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
if (IsPnpDriver)
{
Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
if (Fdo == DeviceNode->PhysicalDeviceObject)
{
/* FIXME: What do we do? Unload the driver or just disable the device? */
DbgPrint("An FDO was not attached\n");
IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
return STATUS_UNSUCCESSFUL;
}
if (Fdo->DeviceType == FILE_DEVICE_ACPI)
{
static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
/* There can be only one system power device */
if (!SystemPowerDeviceNodeCreated)
{
PopSystemPowerDeviceNode = DeviceNode;
SystemPowerDeviceNodeCreated = TRUE;
}
}
ObDereferenceObject(Fdo);
}
IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
}
return STATUS_SUCCESS;
}
NTSTATUS
IopStartDevice(
PDEVICE_NODE DeviceNode)
{
IO_STATUS_BLOCK IoStatusBlock;
IO_STACK_LOCATION Stack;
PDEVICE_OBJECT Fdo;
NTSTATUS Status;
DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList;
Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated;
Status = IopInitiatePnpIrp(
Fdo,
&IoStatusBlock,
IRP_MN_START_DEVICE,
&Stack);
if (!NT_SUCCESS(Status))
{
DPRINT("IopInitiatePnpIrp() failed\n");
}
else
{
if (IopDeviceNodeHasFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY))
{
DPRINT("Device needs enumeration, invalidating bus relations\n");
Status = IopInvalidateDeviceRelations(DeviceNode, BusRelations);
IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
}
}
ObDereferenceObject(Fdo);
if (NT_SUCCESS(Status))
DeviceNode->Flags |= DN_STARTED;
return Status;
}
NTSTATUS NTSTATUS
STDCALL STDCALL
IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode, IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,