windows-nt/Source/XPSP1/NT/drivers/wdm/input/samples/hidmini/pnp.c
2020-09-26 16:20:57 +08:00

629 lines
14 KiB
C

/*++
Copyright (c) 1996,1997 Microsoft Corporation
Module Name:
pnp.c
Abstract: Human Input Device (HID) minidriver that creates an example
device.
--*/
#include <WDM.H>
#include <USBDI.H>
#include <HIDPORT.H>
#include <HIDMINI.H>
NTSTATUS
HidMiniPnP(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the PnP IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus;
PIO_STACK_LOCATION IrpStack;
PIO_STACK_LOCATION NextStack;
PDEVICE_EXTENSION DeviceExtension;
DBGPrint(("'HIDMINI.SYS: HidMiniPlugnPlay Enter\n"));
DBGPrint(("'HIDMINI.SYS: DeviceObject = %x\n", DeviceObject));
//
// Get a pointer to the device extension
//
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
//
// Get a pointer to the current location in the Irp
//
IrpStack = IoGetCurrentIrpStackLocation (Irp);
DBGPrint(("'HIDMINI.SYS: IoGetCurrentIrpStackLocation (Irp) = %x\n", IrpStack));
switch(IrpStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
DBGPrint(("'HIDMINI.SYS: IRP_MN_START_DEVICE\n"));
ntStatus = HidMiniStartDevice(DeviceObject);
break;
case IRP_MN_STOP_DEVICE:
DBGPrint(("'HIDMINI.SYS: IRP_MN_STOP_DEVICE\n"));
ntStatus = HidMiniStopDevice(DeviceObject);
break;
case IRP_MN_REMOVE_DEVICE:
DBGPrint(("'HIDMINI.SYS: IRP_MN_REMOVE_DEVICE\n"));
ntStatus = HidMiniRemoveDevice(DeviceObject);
break;
case IRP_MN_QUERY_ID:
DBGPrint(("'HIDMINI.SYS: IRP_MN_QUERY_ID\n"));
(PWCHAR)Irp->IoStatus.Information = NULL;
ntStatus = STATUS_SUCCESS;
break;
default:
ntStatus = STATUS_SUCCESS;
DBGPrint(("'HIDMINI.SYS: Unknown PNP IRP Parameter (%lx)\n", IrpStack->MinorFunction));
}
//
// Set the status of the Irp
//
Irp->IoStatus.Status = ntStatus;
if (NT_SUCCESS(ntStatus)) {
//
// Set next stack location
//
NextStack = IoGetNextIrpStackLocation(Irp);
ASSERT(NextStack != NULL);
//
// Copy the Irp to the next stack location
//
RtlCopyMemory(NextStack, IrpStack, sizeof(IO_STACK_LOCATION));
IoMarkIrpPending(Irp);
//
// Set our own completion routine or disable completion
// routine of caller
//
switch(IrpStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
IoSetCompletionRoutine( Irp,
HidMiniStartCompletion,
DeviceExtension, // reference data
TRUE, // call on success
TRUE, // call on failure
TRUE ); // call on cancel
break;
case IRP_MN_STOP_DEVICE:
IoSetCompletionRoutine( Irp,
HidMiniStopCompletion,
DeviceExtension, // reference data
TRUE, // call on success
TRUE, // call on failure
TRUE ); // call on cancel
break;
case IRP_MN_QUERY_ID:
IoSetCompletionRoutine( Irp,
HidMiniQueryIDCompletion,
DeviceExtension, // reference data
TRUE, // call on success
TRUE, // call on failure
TRUE ); // call on cancel
break;
default:
NextStack->Control = 0;
break;
}
//
// Pass it down to the Next Device Object
//
DBGPrint(("'HIDMINI.SYS: Passing PnP Irp down to next object\n"));
ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
} else {
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// NOTE: Real status returned in Irp->IoStatus.Status
//
ntStatus = STATUS_SUCCESS;
}
DBGPrint(("'HIDMINI.SYS: HidMiniPlugnPlay Exit = %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
HidMiniStartDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Begins initialization a given instance of a HID device. Work done here occurs before
the parent node gets to do anything.
Arguments:
DeviceObject - pointer to the device object for this instance.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS ntStatus;
PUSB_DEVICE_DESCRIPTOR DeviceDesc = NULL;
DBGPrint(("'HIDMINI.SYS: HidMiniStartDevice Enter\n"));
//
// Get a pointer to the device extension
//
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
//
// Start the device
//
DeviceExtension->DeviceState = DEVICE_STATE_STARTING;
ntStatus = STATUS_SUCCESS;
DBGPrint(("'HIDMINI.SYS: HidMiniStartDevice Exit = %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
HidMiniStartCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Completes initialization a given instance of a HID device. Work done here occurs
after the parent node has done its StartDevice.
Arguments:
DeviceObject - pointer to the device object for this instance.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS ntStatus;
PUSB_DEVICE_DESCRIPTOR DeviceDesc = NULL;
DBGPrint(("'HIDMINI.SYS: HidMiniStartCompletion Enter\n"));
//
// Get a pointer to the device extension
//
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
ntStatus = Irp->IoStatus.Status;
if(NT_SUCCESS(ntStatus)) {
DeviceExtension->DeviceState = DEVICE_STATE_RUNNING;
IsRunning = TRUE;
DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) was started!\n", DeviceObject));
ntStatus = HidMiniInitDevice(DeviceObject);
if(NT_SUCCESS(ntStatus)) {
DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) was configured!\n", DeviceObject));
} else {
DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) configuration failed!\n", DeviceObject));
DeviceExtension->DeviceState = DEVICE_STATE_STOPPING;
IsRunning = FALSE;
}
} else {
//
// The PnP call failed!
//
DeviceExtension->DeviceState = DEVICE_STATE_STOPPING;
IsRunning = FALSE;
DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) failed to start!\n", DeviceObject));
}
DBGPrint(("'HIDMINI.SYS: HidMiniStartCompletion Exit = %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
HidMiniInitDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Get the device information and attempt to initialize a configuration
for a device. If we cannot identify this as a valid HID device or
configure the device, our start device function is failed.
Arguments:
DeviceObject - pointer to a device object.
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension;
DBGPrint(("'HIDMINI.SYS: HidMiniInitDevice Entry\n"));
//
// Get a pointer to the device extension
//
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
//
// Get config, hid, etc. descriptors
//
DeviceExtension->HidDescriptor = MyHidDescriptor;
DeviceExtension->StringDescriptor = MyStringDescriptor;
DeviceExtension->PhysicalDescriptor = MyPhysicalDescriptor;
DeviceExtension->ReportDescriptor = MyReportDescriptor;
InitializeListHead(&HidMini_ReadIrpHead);
InitializeListHead(&HidMini_WriteIrpHead);
DBGPrint(("'HIDMINI.SYS: HidMiniInitDevice Exit = 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
HidMiniStopDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Stops a given instance of a device. Work done here occurs before the parent
does its stop device.
Arguments:
DeviceObject - pointer to the device object.
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension;
DBGPrint(("'HIDMINI.SYS: HidMiniStopDevice Enter\n"));
//
// Get a pointer to the device extension
//
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
DeviceExtension->DeviceState = DEVICE_STATE_STOPPING;
IsRunning = FALSE;
//
// Stop the device
//
//
// Perform a synchronous abort of all pending requests for this
// device.
//
HidMiniAbortPendingRequests( DeviceObject );
DBGPrint(("'HIDMINI.SYS: HidMiniStopDevice = %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
HidMiniAbortPendingRequests(
IN PDEVICE_OBJECT DeviceObject
)
{
PNODE Node;
//
// Dispose of any Irps, free up all the NODEs waiting in the queues.
//
while ((Node = (PNODE)ExInterlockedRemoveHeadList(&HidMini_ReadIrpHead, &HidMini_IrpReadLock))) {
Node->Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(Node->Irp, IO_NO_INCREMENT);
ExFreePool(Node);
}
return STATUS_SUCCESS;
}
NTSTATUS
HidMiniStopCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Stops a given instance of a device. Work done here occurs after the parent
has done its stop device.
Arguments:
DeviceObject - pointer to the device object.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS ntStatus;
PUSB_DEVICE_DESCRIPTOR DeviceDesc = NULL;
DBGPrint(("'HIDMINI.SYS: HidMiniStopCompletion Enter\n"));
//
// Get a pointer to the device extension
//
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
ntStatus = Irp->IoStatus.Status;
if(!NT_SUCCESS(ntStatus)) {
DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) was stopped!\n", DeviceObject));
} else {
//
// The PnP call failed!
//
DBGPrint(("'HIDMINI.SYS: DeviceObject (%x) failed to stop!\n", DeviceObject));
}
DeviceExtension->DeviceState = DEVICE_STATE_STOPPED;
IsRunning = FALSE;
DBGPrint(("'HIDMINI.SYS: HidMiniStopCompletion Exit = %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
HidMiniQueryIDCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Fills in a dummy ID
Arguments:
DeviceObject - pointer to the device object.
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus;
DBGPrint(("'HIDMINI.SYS: HidMiniQueryIDCompletion Enter\n"));
//
// If this wasn't filled in below us, fill it in with a dummy value
//
if ((PWCHAR)Irp->IoStatus.Information == NULL) {
//
// Here's the dummy value, allocate a buffer to copy it to.
//
static WCHAR MyBusID[] = L"HIDMINI_Device\0";
PWCHAR Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, sizeof(MyBusID));
if (Buffer) {
//
// Do the copy, store the buffer in the Irp
//
RtlCopyMemory(Buffer, MyBusID, sizeof(MyBusID));
Irp->IoStatus.Information = (ULONG)Buffer;
ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
} else {
//
// No memory
//
ntStatus = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
//
// Return with whatever we got below us.
//
ntStatus = Irp->IoStatus.Status;
}
DBGPrint(("'HIDMINI.SYS: HidMiniQueryIDCompletion Exit = %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
HidMiniRemoveDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Removes a given instance of a device.
Arguments:
DeviceObject - pointer to the device object.
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension;
ULONG oldDeviceState;
DBGPrint(("'HIDMINI.SYS: HidMiniRemoveDevice Enter\n"));
//
// Get a pointer to the device extension
//
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
DBGPrint(("'HIDMINI.SYS: DeviceExtension = %x\n", DeviceExtension));
oldDeviceState = DeviceExtension->DeviceState;
DeviceExtension->DeviceState = DEVICE_STATE_REMOVING;
IsRunning = FALSE;
//
// Cancel any outstanding IRPs if the device was running
//
if(oldDeviceState == DEVICE_STATE_RUNNING)
{
ntStatus = HidMiniAbortPendingRequests( DeviceObject );
DBGPrint(("'HIDMINI.SYS: HidMiniAbortPendingRequests() = %x\n", ntStatus));
} else {
ASSERT( DeviceExtension->NumPendingRequests == 0 );
}
ntStatus = STATUS_SUCCESS;
DBGPrint(("'HIDSAMHIDMINI.SYS: HidMiniRemoveDevice = %x\n", ntStatus));
return ntStatus;
}