NTSTATUS PPJoyBus_PnP_Joy (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS ntStatus; PIO_STACK_LOCATION IrpStack; PJOY_DEVICE_DATA JoyDeviceData; WCHAR LinkNameBuffer[128]; UNICODE_STRING LinkName; PAGED_CODE(); PPJOY_DBGPRINT (FILE_PNP|PPJOY_FENTRY,("PPJoyBus_PnP_Joy(DeviceObject=0x%p,Irp=0x%p)",DeviceObject,Irp) ); IrpStack = IoGetCurrentIrpStackLocation (Irp); JoyDeviceData= (PJOY_DEVICE_DATA)DeviceObject->DeviceExtension; switch(IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_START_DEVICE") ); ntStatus= PPJoyBus_JoyStartDevice (JoyDeviceData,Irp); goto CompleteIRP; case IRP_MN_STOP_DEVICE: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_STOP_DEVICE") ); PPJoyBus_JoyStopDevice (JoyDeviceData,Irp); /* This routine must always return success. */ ntStatus= STATUS_SUCCESS; goto CompleteIRP; case IRP_MN_QUERY_STOP_DEVICE: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_QUERY_STOP_DEVICE") ); /* Always accept stop device request */ ntStatus= STATUS_SUCCESS; goto CompleteIRP; case IRP_MN_CANCEL_STOP_DEVICE: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_CANCEL_STOP_DEVICE") ); /* Canceling stop requests always successful */ ntStatus= STATUS_SUCCESS; goto CompleteIRP; case IRP_MN_QUERY_REMOVE_DEVICE: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_QUERY_REMOVE_DEVICE") ); /* Always accept remove requests */ ntStatus= STATUS_SUCCESS; goto CompleteIRP; case IRP_MN_CANCEL_REMOVE_DEVICE: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_CANCEL_REMOVE_DEVICE") ); /* Cancelling remove requests always successful */ ntStatus= STATUS_SUCCESS; goto CompleteIRP; case IRP_MN_QUERY_CAPABILITIES: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_QUERY_CAPABILITIES") ); ntStatus= PPJoyBus_JoyQueryCaps (JoyDeviceData,Irp); goto CompleteIRP; case IRP_MN_QUERY_DEVICE_RELATIONS: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_QUERY_DEVICE_RELATIONS type %s",DbgDeviceRelationString(IrpStack->Parameters.QueryDeviceRelations.Type)) ); ntStatus= PPJoyBus_JoyDevRelations (JoyDeviceData,Irp); goto CompleteIRP; case IRP_MN_QUERY_RESOURCES: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_QUERY_RESOURCES") ); /* Simply copy the status of the incoming IRP to return back */ ntStatus= Irp->IoStatus.Status; goto CompleteIRP; #if 0 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_QUERY_RESOURCE_REQUIREMENTS") ); ntStatus= PPJoyBus_JoyQueryResourceRequirements (JoyDeviceData,Irp); goto CompleteIRP; #endif case IRP_MN_DEVICE_USAGE_NOTIFICATION: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_DEVICE_USAGE_NOTIFICATION") ); ntStatus= STATUS_UNSUCCESSFUL; goto CompleteIRP; case IRP_MN_SURPRISE_REMOVAL: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_SURPRISE_REMOVAL") ); /* Simply say request was successful */ ntStatus= STATUS_SUCCESS; goto CompleteIRP; case IRP_MN_REMOVE_DEVICE: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_REMOVE_DEVICE") ); /* We stop the device if it wasn't done before the remove */ if (JoyDeviceData->Flags&PPJFLAGS_STARTED) PPJoyBus_JoyStopDevice (JoyDeviceData,Irp); /* Set the DeviceExtension flag to say that our device is removed */ JoyDeviceData->Flags|= PPJFLAGS_REMOVED; /* Leave request to decrease requests counter. Event should be */ /* signaled when last request leaves. Then we will return a */ /* successful status. */ PPJoyBus_LeaveRequest((PCOMMON_DATA)JoyDeviceData); KeWaitForSingleObject (&JoyDeviceData->RemoveEvent,Executive,KernelMode,FALSE,NULL); PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE2, ("KeWaitForSingleObject on RemoveEvent completed.") ); /* If our Joystick is unplugged (via control panel applet) then we */ /* delete the device object for it as well. Else we only mark it */ /* as being removed. (Can later be AddDevice and START'ed again) */ if (JoyDeviceData->Flags&PPJFLAGS_UNPLUGGED) { /* Remove the PDO from joystick list. */ ExAcquireFastMutex (&Globals.Mutex); RemoveEntryList (&JoyDeviceData->ListEntry); ExReleaseFastMutex (&Globals.Mutex); PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE2, ("Device unplugged so we will delete the PDO.") ); /* Then nuke the PDO out of existance */ IoDeleteDevice (JoyDeviceData->Self); } /* The hardware is still physically present. We are ready to be */ /* started again - so clear the REMOVED flag. Should work. */ JoyDeviceData->Flags&= ~PPJFLAGS_REMOVED; /* After all that indicate that the request was successful */ ntStatus= STATUS_SUCCESS; goto CompleteIRP; case IRP_MN_QUERY_ID: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_QUERY_ID type %s",DbgDeviceIDString(IrpStack->Parameters.QueryId.IdType)) ); ntStatus= PPJoyBus_JoyQueryIDs (JoyDeviceData,Irp); goto CompleteIRP; case IRP_MN_QUERY_DEVICE_TEXT: PPJOY_DBGPRINT (FILE_PNP|PPJOY_BABBLE, ("PPJoyBus_PnP_Joy: IRP_MN_QUERY_DEVICE_TEXT") ); ntStatus= PPJoyBus_JoyQueryDevText (JoyDeviceData,Irp); goto CompleteIRP; default: PPJOY_DBGPRINT (FILE_PNP|PPJOY_WARN,("PPJoyBus_PnP_Joy: IrpStack->MinorFunction Not handled %s (0x%x)",PnPMinorFunctionString (IrpStack->MinorFunction),IrpStack->MinorFunction) ); /* Simply copy the status of the incoming IRP to return back */ ntStatus= Irp->IoStatus.Status; goto CompleteIRP; } CompleteIRP: Irp->IoStatus.Status = ntStatus; IoCompleteRequest (Irp, IO_NO_INCREMENT); goto Exit; Exit: PPJOY_EXITPROC (FILE_PNP|PPJOY_FEXIT, "PPJoyBus_PnP_Joy",ntStatus ); return ntStatus; }
NTSTATUS Bus_PDO_PnP ( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PPDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the Plug & Play system for the devices on the BUS --*/ { NTSTATUS status; PAGED_CODE (); // // NB: Because we are a bus enumerator, we have no one to whom we could // defer these irps. Therefore we do not pass them down but merely // return them. // switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // Here we do what ever initialization and ``turning on'' that is // required to allow others to access this device. // Power up the device. // DeviceData->DevicePowerState = PowerDeviceD0; SET_NEW_PNP_STATE(DeviceData, Started); status = STATUS_SUCCESS; break; case IRP_MN_STOP_DEVICE: // // Here we shut down the device and give up and unmap any resources // we acquired for the device. // SET_NEW_PNP_STATE(DeviceData, Stopped); status = STATUS_SUCCESS; break; case IRP_MN_QUERY_STOP_DEVICE: // // No reason here why we can't stop the device. // If there were a reason we should speak now, because answering success // here may result in a stop device irp. // SET_NEW_PNP_STATE(DeviceData, StopPending); status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: // // The stop was canceled. Whatever state we set, or resources we put // on hold in anticipation of the forthcoming STOP device IRP should be // put back to normal. Someone, in the long list of concerned parties, // has failed the stop device query. // // // First check to see whether you have received cancel-stop // without first receiving a query-stop. This could happen if someone // above us fails a query-stop and passes down the subsequent // cancel-stop. // if (StopPending == DeviceData->DevicePnPState) { // // We did receive a query-stop, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); } status = STATUS_SUCCESS;// We must not fail this IRP. break; case IRP_MN_QUERY_REMOVE_DEVICE: // // Check to see whether the device can be removed safely. // If not fail this request. This is the last opportunity // to do so. // if (DeviceData->ToasterInterfaceRefCount){ // // Somebody is still using our interface. // We must fail remove. // status = STATUS_UNSUCCESSFUL; break; } SET_NEW_PNP_STATE(DeviceData, RemovePending); status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // Clean up a remove that did not go through. // // // First check to see whether you have received cancel-remove // without first receiving a query-remove. This could happen if // someone above us fails a query-remove and passes down the // subsequent cancel-remove. // if (RemovePending == DeviceData->DevicePnPState) { // // We did receive a query-remove, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); } status = STATUS_SUCCESS; // We must not fail this IRP. break; case IRP_MN_SURPRISE_REMOVAL: // // We should stop all access to the device and relinquish all the // resources. Let's just mark that it happened and we will do // the cleanup later in IRP_MN_REMOVE_DEVICE. // SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: // // Present is set to true when the pdo is exposed via PlugIn IOCTL. // It is set to FALSE when a UnPlug IOCTL is received. // We will delete the PDO only after we have reported to the // Plug and Play manager that it's missing. // if (DeviceData->ReportedMissing) { PFDO_DEVICE_DATA fdoData; SET_NEW_PNP_STATE(DeviceData, Deleted); // // Remove the PDO from the list and decrement the count of PDO. // Don't forget to synchronize access to the FDO data. // If the parent FDO is deleted before child PDOs, the ParentFdo // pointer will be NULL. This could happen if the child PDO // is in a SurpriseRemovePending state when the parent FDO // is removed. // if (DeviceData->ParentFdo) { fdoData = FDO_FROM_PDO(DeviceData); ExAcquireFastMutex (&fdoData->Mutex); RemoveEntryList (&DeviceData->Link); fdoData->NumPDOs--; ExReleaseFastMutex (&fdoData->Mutex); } // // Free up resources associated with PDO and delete it. // status = Bus_DestroyPdo(DeviceObject, DeviceData); break; } if (DeviceData->Present) { // // When the device is disabled, the PDO transitions from // RemovePending to NotStarted. We shouldn't delete // the PDO because a) the device is still present on the bus, // b) we haven't reported missing to the PnP manager. // SET_NEW_PNP_STATE(DeviceData, NotStarted); status = STATUS_SUCCESS; } else { ASSERT(DeviceData->Present); status = STATUS_SUCCESS; } break; case IRP_MN_QUERY_CAPABILITIES: // // Return the capabilities of a device, such as whether the device // can be locked or ejected..etc // status = Bus_PDO_QueryDeviceCaps(DeviceData, Irp); break; case IRP_MN_QUERY_ID: // Query the IDs of the device Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryId Type: %s\n", DbgDeviceIDString(IrpStack->Parameters.QueryId.IdType))); status = Bus_PDO_QueryDeviceId(DeviceData, Irp); break; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceRelation Type: %s\n",DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type))); status = Bus_PDO_QueryDeviceRelations(DeviceData, Irp); break; case IRP_MN_QUERY_DEVICE_TEXT: status = Bus_PDO_QueryDeviceText(DeviceData, Irp); break; case IRP_MN_QUERY_RESOURCES: status = Bus_PDO_QueryResources(DeviceData, Irp); break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: status = Bus_PDO_QueryResourceRequirements(DeviceData, Irp); break; case IRP_MN_QUERY_BUS_INFORMATION: status = Bus_PDO_QueryBusInformation(DeviceData, Irp); break; case IRP_MN_DEVICE_USAGE_NOTIFICATION: // // OPTIONAL for bus drivers. // This bus drivers any of the bus's descendants // (child device, child of a child device, etc.) do not // contain a memory file namely paging file, dump file, // or hibernation file. So we fail this Irp. // status = STATUS_UNSUCCESSFUL; break; case IRP_MN_EJECT: // // For the device to be ejected, the device must be in the D3 // device power state (off) and must be unlocked // (if the device supports locking). Any driver that returns success // for this IRP must wait until the device has been ejected before // completing the IRP. // DeviceData->Present = FALSE; status = STATUS_SUCCESS; break; case IRP_MN_QUERY_INTERFACE: // // This request enables a driver to export a direct-call // interface to other drivers. A bus driver that exports // an interface must handle this request for its child // devices (child PDOs). // status = Bus_PDO_QueryInterface(DeviceData, Irp); break; case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // // OPTIONAL for bus drivers. // The PnP Manager sends this IRP to a device // stack so filter and function drivers can adjust the // resources required by the device, if appropriate. // //break; //case IRP_MN_QUERY_PNP_DEVICE_STATE: // // OPTIONAL for bus drivers. // The PnP Manager sends this IRP after the drivers for // a device return success from the IRP_MN_START_DEVICE // request. The PnP Manager also sends this IRP when a // driver for the device calls IoInvalidateDeviceState. // // break; //case IRP_MN_READ_CONFIG: //case IRP_MN_WRITE_CONFIG: // // Bus drivers for buses with configuration space must handle // this request for their child devices. Our devices don't // have a config space. // // break; //case IRP_MN_SET_LOCK: // // Our device is not a lockable device // so we don't support this Irp. // // break; default: // //Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE,("\t Not handled\n")); // For PnP requests to the PDO that we do not understand we should // return the IRP WITHOUT setting the status or information fields. // These fields may have already been set by a filter (eg acpi). status = Irp->IoStatus.Status; break; } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }