|
|
/*++
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; }
|