NTSTATUS NTAPI StreamClassAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) { PSTREAM_CLASS_DRIVER_EXTENSION DriverObjectExtension; PDEVICE_OBJECT DeviceObject, LowerDeviceObject; PSTREAM_DEVICE_EXTENSION DeviceExtension; PKSOBJECT_CREATE_ITEM ItemList; NTSTATUS Status; /* Fetch driver object extension */ DriverObjectExtension = IoGetDriverObjectExtension(DriverObject, (PVOID)StreamClassAddDevice); if (!DriverObjectExtension) { /* Failed to get driver extension */ return STATUS_DEVICE_DOES_NOT_EXIST; } /* Allocate Create Item */ ItemList = ExAllocatePool(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM)); if (!ItemList) { /* Failed to allocated Create Item */ return STATUS_INSUFFICIENT_RESOURCES; } /* Create the FDO */ Status = IoCreateDevice(DriverObject, DriverObjectExtension->Data.DeviceExtensionSize + sizeof(STREAM_DEVICE_EXTENSION), NULL, FILE_DEVICE_KS, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, 0, &DeviceObject); if (!NT_SUCCESS(Status)) { /* Failed to create the FDO */ ExFreePool(ItemList); return Status; } /* Attach to device stack */ LowerDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); if (!LowerDeviceObject) { /* Failed to attach */ IoDeleteDevice(DeviceObject); ExFreePool(ItemList); return STATUS_UNSUCCESSFUL; } /* Zero Create item */ RtlZeroMemory(ItemList, sizeof(KSOBJECT_CREATE_ITEM)); /* Setup object class */ RtlInitUnicodeString(&ItemList->ObjectClass, L"GLOBAL"); /* Setup CreateDispatch routine */ ItemList->Create = StreamClassCreateFilter; /* Get device extension */ DeviceExtension = (PSTREAM_DEVICE_EXTENSION)DeviceObject->DeviceExtension; /* Zero device extension */ RtlZeroMemory(DeviceExtension, sizeof(STREAM_DEVICE_EXTENSION)); /* Initialize Ks streaming */ Status = KsAllocateDeviceHeader(&DeviceExtension->Header, 1, ItemList); if (!NT_SUCCESS(Status)) { /* Cleanup resources */ IoDetachDevice(LowerDeviceObject); IoDeleteDevice(DeviceObject); ExFreePool(ItemList); return Status; } /* Store lower device object */ DeviceExtension->LowerDeviceObject = LowerDeviceObject; /* Store physical device object */ DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject; /* Store driver object extension */ DeviceExtension->DriverExtension = DriverObjectExtension; /* Initialize memory list */ InitializeListHead(&DeviceExtension->MemoryResourceList); /* Setup device extension */ DeviceExtension->DeviceExtension = (PVOID) (DeviceExtension + 1); /* Init interrupt dpc */ KeInitializeDpc(&DeviceExtension->InterruptDpc, StreamClassInterruptDpc, (PVOID)DeviceExtension); /* Set device transfer method */ DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; /* Clear init flag */ DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING; return Status; }
NTSTATUS Bus_FDO_PnP(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PFDO_DEVICE_DATA DeviceData) { NTSTATUS status; ULONG length, prevcount, numPdosPresent, numPdosMissing; PLIST_ENTRY entry, listHead, nextEntry; PPDO_DEVICE_DATA pdoData; PDEVICE_RELATIONS relations, oldRelations; PAGED_CODE(); Bus_IncIoCount(DeviceData); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: status = Bus_SendIrpSynchronously(DeviceData->NextLowerDriver, Irp); if (NT_SUCCESS(status)) { status = Bus_StartFdo (DeviceData, Irp); } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount(DeviceData); return status; case IRP_MN_QUERY_STOP_DEVICE: SET_NEW_PNP_STATE(DeviceData, StopPending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: if (StopPending == DeviceData->DevicePnPState) { RESTORE_PREVIOUS_PNP_STATE(DeviceData); ASSERT(DeviceData->DevicePnPState == Started); } Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_STOP_DEVICE: Bus_DecIoCount(DeviceData); KeWaitForSingleObject(&DeviceData->StopEvent, Executive, KernelMode, FALSE, NULL); Bus_IncIoCount(DeviceData); SET_NEW_PNP_STATE(DeviceData, Stopped); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: SET_NEW_PNP_STATE(DeviceData, RemovePending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: if (DeviceData->DevicePnPState == RemovePending) { RESTORE_PREVIOUS_PNP_STATE(DeviceData); } Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_SURPRISE_REMOVAL: SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); Bus_RemoveFdo(DeviceData); ExAcquireFastMutex(&DeviceData->Mutex); { listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry, nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); RemoveEntryList(&pdoData->Link); InitializeListHead(&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; } } ExReleaseFastMutex(&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: if (DeviceData->DevicePnPState != SurpriseRemovePending) { Bus_RemoveFdo(DeviceData); } SET_NEW_PNP_STATE(DeviceData, Deleted); Bus_DecIoCount(DeviceData); Bus_DecIoCount(DeviceData); KeWaitForSingleObject(&DeviceData->RemoveEvent, Executive, KernelMode, FALSE, NULL); ExAcquireFastMutex(&DeviceData->Mutex); { listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry, nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); RemoveEntryList(&pdoData->Link); if (pdoData->DevicePnPState == SurpriseRemovePending) { Bus_KdPrint(("\tFound a surprise removed device: 0x%p\n", pdoData->Self)); InitializeListHead(&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; continue; } Bus_DestroyPdo(pdoData->Self, pdoData); } } ExReleaseFastMutex(&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(DeviceData->NextLowerDriver, Irp); IoDetachDevice(DeviceData->NextLowerDriver); Bus_KdPrint(("\tDeleting FDO: 0x%p\n", DeviceObject)); IoDeleteDevice(DeviceObject); return status; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint(("\tQueryDeviceRelation Type: %s\n", DbgDeviceRelationString(IrpStack->Parameters.QueryDeviceRelations.Type))); if (IrpStack->Parameters.QueryDeviceRelations.Type != BusRelations) { break; } ExAcquireFastMutex(&DeviceData->Mutex); oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information; if (oldRelations) { prevcount = oldRelations->Count; if (!DeviceData->NumPDOs) { ExReleaseFastMutex(&DeviceData->Mutex); break; } } else { prevcount = 0; } numPdosPresent = 0; numPdosMissing = 0; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) numPdosPresent++; } length = sizeof(DEVICE_RELATIONS) + ((numPdosPresent + prevcount) * sizeof (PDEVICE_OBJECT)) - 1; relations = (PDEVICE_RELATIONS) ExAllocatePoolWithTag(PagedPool, length, BUSENUM_POOL_TAG); if (relations == NULL) { ExReleaseFastMutex(&DeviceData->Mutex); Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); Bus_DecIoCount(DeviceData); return status; } if (prevcount) { RtlCopyMemory(relations->Objects, oldRelations->Objects, prevcount * sizeof (PDEVICE_OBJECT)); } relations->Count = prevcount + numPdosPresent; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) { relations->Objects[prevcount] = pdoData->Self; ObReferenceObject(pdoData->Self); prevcount++; } else { pdoData->ReportedMissing = TRUE; numPdosMissing++; } } Bus_KdPrint(("#PDOS Present = %d, Reported = %d, Missing = %d, Listed = %d", numPdosPresent, relations->Count, numPdosMissing, DeviceData->NumPDOs)); if (oldRelations) { ExFreePool(oldRelations); } Irp->IoStatus.Information = (ULONG_PTR) relations; ExReleaseFastMutex(&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; break; default: break; } IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(DeviceData->NextLowerDriver, Irp); Bus_DecIoCount(DeviceData); return status; }
NTSTATUS Bus_AddDevice( __in PDRIVER_OBJECT DriverObject, __in PDEVICE_OBJECT PhysicalDeviceObject ) /*++ Routine Description. Our Toaster bus has been found. Attach our FDO to it. Allocate any required resources. Set things up. And be prepared for the ``start device'' Arguments: DriverObject - pointer to driver object. PhysicalDeviceObject - Device object representing the bus to which we will attach a new FDO. --*/ { NTSTATUS status; PDEVICE_OBJECT deviceObject = NULL; PFDO_DEVICE_DATA deviceData = NULL; PWCHAR deviceName = NULL; ULONG nameLength; PKTIMER timer; PKDPC dpc; PAGED_CODE (); Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Add Device: 0x%p\n", PhysicalDeviceObject)); status = IoCreateDevice ( DriverObject, // our driver object sizeof (FDO_DEVICE_DATA), // device object extension size NULL, // FDOs do not have names FILE_DEVICE_BUS_EXTENDER, // We are a bus FILE_DEVICE_SECURE_OPEN, // TRUE, // our FDO is exclusive &deviceObject); // The device object created if (!NT_SUCCESS (status)) { goto End; } deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension; RtlZeroMemory (deviceData, sizeof (FDO_DEVICE_DATA)); // // Set the initial state of the FDO // INITIALIZE_PNP_STATE(deviceData); deviceData->DebugLevel = BusEnumDebugLevel; deviceData->IsFDO = TRUE; deviceData->Self = deviceObject; ExInitializeFastMutex (&deviceData->Mutex); InitializeListHead (&deviceData->ListOfPDOs); // Set the PDO for use with PlugPlay functions deviceData->UnderlyingPDO = PhysicalDeviceObject; // // Set the initial powerstate of the FDO // deviceData->DevicePowerState = PowerDeviceUnspecified; deviceData->SystemPowerState = PowerSystemWorking; // // Biased to 1. Transition to zero during remove device // means IO is finished. Transition to 1 means the device // can be stopped. // deviceData->OutstandingIO = 1; // // Initialize the remove event to Not-Signaled. This event // will be set when the OutstandingIO will become 0. // KeInitializeEvent(&deviceData->RemoveEvent, SynchronizationEvent, FALSE); // // Initialize the stop event to Signaled: // there are no Irps that prevent the device from being // stopped. This event will be set when the OutstandingIO // will become 0. // KeInitializeEvent(&deviceData->StopEvent, SynchronizationEvent, TRUE); deviceObject->Flags |= DO_POWER_PAGABLE|DO_BUFFERED_IO; // // Tell the Plug & Play system that this device will need a // device interface. // status = IoRegisterDeviceInterface ( PhysicalDeviceObject, (LPGUID) &GUID_DEVINTERFACE_BUSENUM_TOASTER, NULL, &deviceData->InterfaceName); if (!NT_SUCCESS (status)) { Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR, ("AddDevice: IoRegisterDeviceInterface failed (%x)", status)); goto End; } // // Attach our FDO to the device stack. // The return value of IoAttachDeviceToDeviceStack is the top of the // attachment chain. This is where all the IRPs should be routed. // deviceData->NextLowerDriver = IoAttachDeviceToDeviceStack ( deviceObject, PhysicalDeviceObject); if (NULL == deviceData->NextLowerDriver) { status = STATUS_NO_SUCH_DEVICE; goto End; } #if DBG // // We will demonstrate here the step to retrieve the name of the PDO // status = IoGetDeviceProperty (PhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &nameLength); if (status != STATUS_BUFFER_TOO_SMALL) { Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR, ("AddDevice:IoGDP failed (0x%x)\n", status)); goto End; } deviceName = ExAllocatePoolWithTag (NonPagedPool, nameLength, BUSENUM_POOL_TAG); if (NULL == deviceName) { Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR, ("AddDevice: no memory to alloc for deviceName(0x%x)\n", nameLength)); status = STATUS_INSUFFICIENT_RESOURCES; goto End; } status = IoGetDeviceProperty (PhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, nameLength, deviceName, &nameLength); if (!NT_SUCCESS (status)) { Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR, ("AddDevice:IoGDP(2) failed (0x%x)", status)); goto End; } Bus_KdPrint (deviceData, BUS_DBG_SS_TRACE, ("AddDevice: %p to %p->%p (%ws) \n", deviceObject, deviceData->NextLowerDriver, PhysicalDeviceObject, deviceName)); #endif // // We are done with initializing, so let's indicate that and return. // This should be the final step in the AddDevice process. // deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; End: if (deviceName){ ExFreePool(deviceName); } if (!NT_SUCCESS(status) && deviceObject){ if (deviceData && deviceData->NextLowerDriver){ IoDetachDevice (deviceData->NextLowerDriver); } IoDeleteDevice (deviceObject); } return status; }
NTSTATUS Bus_FDO_PnP ( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PFDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the Plug & Play system for the BUS itself --*/ { NTSTATUS status; ULONG length, prevcount, numPdosPresent; PLIST_ENTRY entry, listHead, nextEntry; PPDO_DEVICE_DATA pdoData; PDEVICE_RELATIONS relations, oldRelations; PAGED_CODE (); Bus_IncIoCount (DeviceData); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // Send the Irp down and wait for it to come back. // Do not touch the hardware until then. // status = Bus_SendIrpSynchronously (DeviceData->NextLowerDriver, Irp); if (NT_SUCCESS(status)) { // // Initialize your device with the resources provided // by the PnP manager to your device. // status = Bus_StartFdo (DeviceData, Irp); } // // We must now complete the IRP, since we stopped it in the // completion routine with MORE_PROCESSING_REQUIRED. // Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (DeviceData); return status; case IRP_MN_QUERY_STOP_DEVICE: // // The PnP manager is trying to stop the device // for resource rebalancing. Fail this now if you // cannot stop the device in response to STOP_DEVICE. // SET_NEW_PNP_STATE(DeviceData, StopPending); Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP. break; case IRP_MN_CANCEL_STOP_DEVICE: // // The PnP Manager sends this IRP, at some point after an // IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a // device that the device will not be stopped for // resource reconfiguration. // // // 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); ASSERT(DeviceData->DevicePnPState == Started); } Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP. break; case IRP_MN_STOP_DEVICE: // // Stop device means that the resources given during Start device // are now revoked. Note: You must not fail this Irp. // But before you relieve resources make sure there are no I/O in // progress. Wait for the existing ones to be finished. // To do that, first we will decrement this very operation. // When the counter goes to 1, Stop event is set. // Bus_DecIoCount(DeviceData); KeWaitForSingleObject( &DeviceData->StopEvent, Executive, // Waiting reason of a driver KernelMode, // Waiting in kernel mode FALSE, // No allert NULL); // No timeout // // Increment the counter back because this IRP has to // be sent down to the lower stack. // Bus_IncIoCount (DeviceData); // // Free resources given by start device. // SET_NEW_PNP_STATE(DeviceData, Stopped); // // We don't need a completion routine so fire and forget. // // Set the current stack location to the next stack location and // call the next device object. // Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: // // 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. // SET_NEW_PNP_STATE(DeviceData, RemovePending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // 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. // // // 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); } Irp->IoStatus.Status = STATUS_SUCCESS;// You must not fail the IRP. break; case IRP_MN_SURPRISE_REMOVAL: // // The device has been unexpectedly removed from the machine // and is no longer available for I/O. Bus_RemoveFdo clears // all the resources, frees the interface and de-registers // with WMI, but it doesn't delete the FDO. That's done // later in Remove device query. // SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); Bus_RemoveFdo(DeviceData); ExAcquireFastMutex (&DeviceData->Mutex); listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry,nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); RemoveEntryList (&pdoData->Link); InitializeListHead (&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; } ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP. break; case IRP_MN_REMOVE_DEVICE: // // The Plug & Play system has dictated the removal of this device. // We have no choice but to detach and delete the device object. // // // Check the state flag to see whether you are surprise removed // if (DeviceData->DevicePnPState != SurpriseRemovePending) { Bus_RemoveFdo(DeviceData); } SET_NEW_PNP_STATE(DeviceData, Deleted); // // Wait for all outstanding requests to complete. // We need two decrements here, one for the increment in // the beginning of this function, the other for the 1-biased value of // OutstandingIO. // Bus_DecIoCount (DeviceData); // // The requestCount is at least one here (is 1-biased) // Bus_DecIoCount (DeviceData); KeWaitForSingleObject ( &DeviceData->RemoveEvent, Executive, KernelMode, FALSE, NULL); // // Typically the system removes all the children before // removing the parent FDO. If for any reason child Pdos are // still present we will destroy them explicitly, with one exception - // we will not delete the PDOs that are in SurpriseRemovePending state. // ExAcquireFastMutex (&DeviceData->Mutex); listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry,nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); RemoveEntryList (&pdoData->Link); if (SurpriseRemovePending == pdoData->DevicePnPState) { // // We will reinitialize the list head so that we // wouldn't barf when we try to delink this PDO from // the parent's PDOs list, when the system finally // removes the PDO. Let's also not forget to set the // ReportedMissing flag to cause the deletion of the PDO. // Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO, ("\tFound a surprise removed device: 0x%p\n", pdoData->Self)); InitializeListHead (&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; continue; } DeviceData->NumPDOs--; Bus_DestroyPdo (pdoData->Self, pdoData); } ExReleaseFastMutex (&DeviceData->Mutex); // // We need to send the remove down the stack before we detach, // but we don't need to wait for the completion of this operation // (and to register a completion routine). // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); // // Detach from the underlying devices. // IoDetachDevice (DeviceData->NextLowerDriver); Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO, ("\tDeleting FDO: 0x%p\n", DeviceObject)); IoDeleteDevice (DeviceObject); return status; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceRelation Type: %s\n", DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type))); if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) { // // We don't support any other Device Relations // break; } // // 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.) // ExAcquireFastMutex (&DeviceData->Mutex); oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information; if (oldRelations) { prevcount = oldRelations->Count; if (!DeviceData->NumPDOs) { // // There is a device relations struct already present and we have // nothing to add to it, so just call IoSkip and IoCall // ExReleaseFastMutex (&DeviceData->Mutex); break; } } else { prevcount = 0; } // // Calculate the number of PDOs actually present on the bus // numPdosPresent = 0; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) numPdosPresent++; } // // Need to allocate a new relations structure and add our // PDOs to it. // length = sizeof(DEVICE_RELATIONS) + ((numPdosPresent + prevcount) * sizeof (PDEVICE_OBJECT)) -1; relations = (PDEVICE_RELATIONS) ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (NULL == relations) { // // Fail the IRP // ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (DeviceData); return status; } // // Copy in the device objects so far // if (prevcount) { RtlCopyMemory (relations->Objects, oldRelations->Objects, prevcount * sizeof (PDEVICE_OBJECT)); } relations->Count = prevcount + numPdosPresent; // // For each PDO present on this bus add a pointer to the device relations // buffer, being sure to take out a reference to that object. // The Plug & Play system will dereference the object when it is done // with it and free the device relations buffer. // for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) { relations->Objects[prevcount] = pdoData->Self; ObReferenceObject (pdoData->Self); prevcount++; } else { pdoData->ReportedMissing = TRUE; } } Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\t#PDOS present = %d\n\t#PDOs reported = %d\n", DeviceData->NumPDOs, relations->Count)); // // Replace the relations structure in the IRP with the new // one. // if (oldRelations) { ExFreePool (oldRelations); } Irp->IoStatus.Information = (ULONG_PTR) relations; ExReleaseFastMutex (&DeviceData->Mutex); // // Set up and pass the IRP further down the stack // Irp->IoStatus.Status = STATUS_SUCCESS; break; default: // // In the default case we merely call the next driver. // We must not modify Irp->IoStatus.Status or complete the IRP. // break; } IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); Bus_DecIoCount (DeviceData); return status; }
NTSTATUS DPDispatchPnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { //用来指向过滤设备的设备扩展的指针 PDP_FILTER_DEV_EXTENSION DevExt = DeviceObject->DeviceExtension; //返回值 NTSTATUS ntStatus = STATUS_SUCCESS; //用来指向irp stack的指针 PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp); switch(irpsp->MinorFunction) { case IRP_MN_REMOVE_DEVICE: //如果是PnP manager发过来的移除设备的irp,将进入这里 { //这里主要做一些清理工作 if (DevExt->ThreadTermFlag != TRUE && NULL != DevExt->ThreadHandle) { //如果线程还在运行的话需要停止它,这里通过设置线程停止运行的标志并且发送事件信息,让线程自己终止运行 DevExt->ThreadTermFlag = TRUE; KeSetEvent( &DevExt->ReqEvent, (KPRIORITY) 0, FALSE ); //等待线程结束 KeWaitForSingleObject( DevExt->ThreadHandle, Executive, KernelMode, FALSE, NULL ); //解除引用线程对象 ObDereferenceObject(DevExt->ThreadHandle); } if (NULL != DevExt->Bitmap) { //如果还有位图,就释放 DPBitmapFree(DevExt->Bitmap); } if (NULL != DevExt->LowerDevObj) { //如果存在着下层设备,就先去掉挂接 IoDetachDevice(DevExt->LowerDevObj); } if (NULL != DevExt->FltDevObj) { //如果存在过滤设备,就要删除它 IoDeleteDevice(DevExt->FltDevObj); } break; } //这个是PnP 管理器用来询问设备能否支持特殊文件的irp,作为卷的过滤驱动,我们必须处理 case IRP_MN_DEVICE_USAGE_NOTIFICATION: { BOOLEAN setPagable; //如果是询问是否支持休眠文件和dump文件,则直接下发给下层设备去处理 if (irpsp->Parameters.UsageNotification.Type != DeviceUsageTypePaging) { ntStatus = DPSendToNextDriver( DevExt->LowerDevObj, Irp); return ntStatus; } //这里等一下分页计数事件 ntStatus = KeWaitForSingleObject( &DevExt->PagingPathCountEvent, Executive, KernelMode, FALSE, NULL); //setPagable初始化为假,是没有设置过DO_POWER_PAGABLE的意思 setPagable = FALSE; if (!irpsp->Parameters.UsageNotification.InPath && DevExt->PagingPathCount == 1 ) { //如果是PnP manager通知我们将要删去分页文件,且我们目前只剩下最后一个分页文件的时候会进入这里 if (DeviceObject->Flags & DO_POWER_INRUSH) {} else { //到这里说明没有分页文件在这个设备上了,需要设置DO_POWER_PAGABLE这一位了 DeviceObject->Flags |= DO_POWER_PAGABLE; setPagable = TRUE; } } //到这里肯定是关于分页文件的是否可建立查询,或者是删除的通知,我们交给下层设备去做。这里需要用同步的方式给下层设备,也就是说要等待下层设备的返回 ntStatus = DPForwardIrpSync(DevExt->LowerDevObj,Irp); if (NT_SUCCESS(ntStatus)) { //如果发给下层设备的请求成功了,说明下层设备支持这个操作,会执行到这里 //在成功的条件下我们来改变我们自己的计数值,这样就能记录我们现在这个设备上到底有多少个分页文件 IoAdjustPagingPathCount( &DevExt->PagingPathCount, irpsp->Parameters.UsageNotification.InPath); if (irpsp->Parameters.UsageNotification.InPath) { if (DevExt->PagingPathCount == 1) { //如果这个请求是一个建立分页文件的查询请求,并且下层设备支持这个请求,而且这是第一个在这个设备上的分页文件,那么我们需要清除DO_POWER_PAGABLE位 DeviceObject->Flags &= ~DO_POWER_PAGABLE; } } } else { //到这里说明给下层设备发请求失败了,下层设备不支持这个请求,这时候我们需要把之前做过的操作还原 if (setPagable == TRUE) { //根据setPagable变量的值来判断我们之前是否做过对DO_POWER_PAGABLE的设置,如果有的话就清楚这个设置 DeviceObject->Flags &= ~DO_POWER_PAGABLE; setPagable = FALSE; } } //设置分页计数事件 KeSetEvent( &DevExt->PagingPathCountEvent, IO_NO_INCREMENT, FALSE ); //到这里我们就可以完成这个irp请求了 IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } default: break; } return DPSendToNextDriver( DevExt->LowerDevObj, Irp); }
// add device NTSTATUS AddDevice(PDRIVER_OBJECT pDriver,PDEVICE_OBJECT pPhysicalDeviceObject) { NTSTATUS status; PDEVICE_OBJECT pDevice = NULL; PFdoExt pFdoExt = NULL; __try { UNICODE_STRING busFdoName; RtlInitUnicodeString(&busFdoName,BUS_FDO_NAME); status = IoCreateDevice(pDriver,sizeof(FdoExt),&busFdoName,FILE_DEVICE_BUS_EXTENDER,FILE_DEVICE_SECURE_OPEN, FALSE,&pDevice); if(!NT_SUCCESS(status)) ExRaiseStatus(status); pFdoExt = static_cast<PFdoExt>(pDevice->DeviceExtension); RtlZeroMemory(pFdoExt,sizeof(FdoExt)); status = IoRegisterDeviceInterface(pPhysicalDeviceObject,&GUID_TIAMO_BUS,NULL,&pFdoExt->m_symbolicName); if(!NT_SUCCESS(status)) ExRaiseStatus(status); KeInitializeEvent(&pFdoExt->m_evRemove,SynchronizationEvent,FALSE); KeInitializeEvent(&pFdoExt->m_evStop,SynchronizationEvent,TRUE); ExInitializeFastMutex (&pFdoExt->m_mutexEnumPdo); pFdoExt->m_sysPowerState = PowerSystemWorking; pFdoExt->m_devPowerState = PowerDeviceD3; pFdoExt->m_bFdo = TRUE; pFdoExt->m_pPhysicalDevice = pPhysicalDeviceObject; pFdoExt->m_pLowerDevice = IoAttachDeviceToDeviceStack(pDevice,pPhysicalDeviceObject); pFdoExt->m_ulCurrentPnpState = -1; pFdoExt->m_ulPrevPnpState = -1; pFdoExt->m_ulOutstandingIO = 1; //pDevice->Flags |= DO_POWER_PAGABLE; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pDevice,DevicePowerState,state); pDevice->Flags &= ~DO_DEVICE_INITIALIZING; devDebugPrint(DRIVER_NAME"*******AddDevice called,fdo createed.\n"); } __except(EXCEPTION_EXECUTE_HANDLER) { if(pFdoExt && pFdoExt->m_pLowerDevice) { IoDetachDevice(pFdoExt->m_pLowerDevice); RtlFreeUnicodeString(&pFdoExt->m_symbolicName); } if(pDevice) { IoDeleteDevice(pDevice); } } return status; }
NTSTATUS NTAPI PciIdeXAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo) { PPCIIDEX_DRIVER_EXTENSION DriverExtension; PFDO_DEVICE_EXTENSION DeviceExtension; PDEVICE_OBJECT Fdo; ULONG BytesRead; PCI_COMMON_CONFIG PciConfig; NTSTATUS Status; DPRINT("PciIdeXAddDevice(%p %p)\n", DriverObject, Pdo); DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); ASSERT(DriverExtension); Status = IoCreateDevice( DriverObject, sizeof(FDO_DEVICE_EXTENSION) + DriverExtension->MiniControllerExtensionSize, NULL, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, TRUE, &Fdo); if (!NT_SUCCESS(Status)) { DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status); return Status; } DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension; RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION)); DeviceExtension->Common.IsFDO = TRUE; Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice); if (!NT_SUCCESS(Status)) { DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status); return Status; } Status = GetBusInterface(DeviceExtension); if (!NT_SUCCESS(Status)) { DPRINT("GetBusInterface() failed with status 0x%08lx\n", Status); IoDetachDevice(DeviceExtension->LowerDevice); return Status; } BytesRead = (*DeviceExtension->BusInterface->GetBusData)( DeviceExtension->BusInterface->Context, PCI_WHICHSPACE_CONFIG, &PciConfig, 0, PCI_COMMON_HDR_LENGTH); if (BytesRead != PCI_COMMON_HDR_LENGTH) { DPRINT("BusInterface->GetBusData() failed()\n"); ReleaseBusInterface(DeviceExtension); IoDetachDevice(DeviceExtension->LowerDevice); return STATUS_IO_DEVICE_ERROR; } DeviceExtension->VendorId = PciConfig.VendorID; DeviceExtension->DeviceId = PciConfig.DeviceID; Fdo->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; }
/** * PnP Request handler. * * @param pDevObj Device object. * @param pIrp Request packet. */ NTSTATUS vboxguestwinPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp) { PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension; PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp); #ifdef LOG_ENABLED static char* aszFnctName[] = { "IRP_MN_START_DEVICE", "IRP_MN_QUERY_REMOVE_DEVICE", "IRP_MN_REMOVE_DEVICE", "IRP_MN_CANCEL_REMOVE_DEVICE", "IRP_MN_STOP_DEVICE", "IRP_MN_QUERY_STOP_DEVICE", "IRP_MN_CANCEL_STOP_DEVICE", "IRP_MN_QUERY_DEVICE_RELATIONS", "IRP_MN_QUERY_INTERFACE", "IRP_MN_QUERY_CAPABILITIES", "IRP_MN_QUERY_RESOURCES", "IRP_MN_QUERY_RESOURCE_REQUIREMENTS", "IRP_MN_QUERY_DEVICE_TEXT", "IRP_MN_FILTER_RESOURCE_REQUIREMENTS", "", "IRP_MN_READ_CONFIG", "IRP_MN_WRITE_CONFIG", "IRP_MN_EJECT", "IRP_MN_SET_LOCK", "IRP_MN_QUERY_ID", "IRP_MN_QUERY_PNP_DEVICE_STATE", "IRP_MN_QUERY_BUS_INFORMATION", "IRP_MN_DEVICE_USAGE_NOTIFICATION", "IRP_MN_SURPRISE_REMOVAL", }; Log(("VBoxGuest::vboxguestwinGuestPnp: MinorFunction: %s\n", pStack->MinorFunction < (sizeof(aszFnctName) / sizeof(aszFnctName[0])) ? aszFnctName[pStack->MinorFunction] : "Unknown")); #endif NTSTATUS rc = STATUS_SUCCESS; switch (pStack->MinorFunction) { case IRP_MN_START_DEVICE: { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE); if ( NT_SUCCESS(rc) && NT_SUCCESS(pIrp->IoStatus.Status)) { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n", pStack->Parameters.StartDevice.AllocatedResources)); if (!pStack->Parameters.StartDevice.AllocatedResources) { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n", pDevExt, pDevExt ? pDevExt->win.s.pNextLowerDriver : NULL)); rc = STATUS_UNSUCCESSFUL; } else { rc = vboxguestwinInit(pDevObj, pIrp); } } if (NT_ERROR(rc)) { Log(("VBoxGuest::vboxguestwinGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc)); /* Need to unmap memory in case of errors ... */ vboxguestwinUnmapVMMDevMemory(pDevExt); } break; } case IRP_MN_CANCEL_REMOVE_DEVICE: { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE); if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGREMOVE) { /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */ pDevExt->win.s.devState = pDevExt->win.s.prevDevState; } /* Complete the IRP. */ break; } case IRP_MN_SURPRISE_REMOVAL: { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, SURPRISEREMOVED); /* Do nothing here actually. Cleanup is done in IRP_MN_REMOVE_DEVICE. * This request is not expected for VBoxGuest. */ LogRel(("VBoxGuest: unexpected device removal\n")); /* Pass to the lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp); /* Do not complete the IRP. */ return rc; } case IRP_MN_QUERY_REMOVE_DEVICE: { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_REMOVE_DEVICE\n")); #ifdef VBOX_REBOOT_ON_UNINSTALL Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n")); rc = STATUS_UNSUCCESSFUL; #endif /* VBOX_REBOOT_ON_UNINSTALL */ if (NT_SUCCESS(rc)) { VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGREMOVE); /* This IRP passed down to lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp); Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); /* we must not do anything the IRP after doing IoSkip & CallDriver * since the driver below us will complete (or already have completed) the IRP. * I.e. just return the status we got from IoCallDriver */ return rc; } /* Complete the IRP on failure. */ break; } case IRP_MN_REMOVE_DEVICE: { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: REMOVE_DEVICE\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED); /* Free hardware resources. */ /* @todo this should actually free I/O ports, interrupts, etc. */ rc = vboxguestwinCleanup(pDevObj); Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: vboxguestwinCleanup rc = 0x%08X\n", rc)); /* * We need to send the remove down the stack before we detach, * but we don't need to wait for the completion of this operation * (and to register a completion routine). */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp); Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); IoDetachDevice(pDevExt->win.s.pNextLowerDriver); Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Removing device ...\n")); /* Destroy device extension and clean up everything else. */ VBoxGuestDeleteDevExt(pDevExt); /* Remove DOS device + symbolic link. */ UNICODE_STRING win32Name; RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS); IoDeleteSymbolicLink(&win32Name); Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Deleting device ...\n")); /* Last action: Delete our device! pDevObj is *not* failed * anymore after this call! */ IoDeleteDevice(pDevObj); Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Device removed!\n")); /* Propagating rc from IoCallDriver. */ return rc; /* Make sure that we don't do anything below here anymore! */ } case IRP_MN_CANCEL_STOP_DEVICE: { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_STOP_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vboxguestwinSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE); if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGSTOP) { /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */ pDevExt->win.s.devState = pDevExt->win.s.prevDevState; } /* Complete the IRP. */ break; } case IRP_MN_QUERY_STOP_DEVICE: { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_STOP_DEVICE\n")); #ifdef VBOX_REBOOT_ON_UNINSTALL Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n")); pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; #endif /* VBOX_REBOOT_ON_UNINSTALL */ if (NT_SUCCESS(rc)) { VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGSTOP); /* This IRP passed down to lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp); Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); /* we must not do anything with the IRP after doing IoSkip & CallDriver * since the driver below us will complete (or already have completed) the IRP. * I.e. just return the status we got from IoCallDriver */ return rc; } /* Complete the IRP on failure. */ break; } case IRP_MN_STOP_DEVICE: { Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: STOP_DEVICE\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED); /* Free hardware resources. */ /* @todo this should actually free I/O ports, interrupts, etc. */ rc = vboxguestwinCleanup(pDevObj); Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc)); /* Pass to the lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp); Log(("VBoxGuest::vboxguestwinGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); return rc; } default: { IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp); return rc; } } pIrp->IoStatus.Status = rc; IoCompleteRequest(pIrp, IO_NO_INCREMENT); Log(("VBoxGuest::vboxguestwinGuestPnp: Returning with rc = 0x%x\n", rc)); return rc; }
//------------------------------------------------------------------------------------------------- NTSTATUS CHCDController::Initialize( IN PROOTHDCCONTROLLER RootHCDController, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) { NTSTATUS Status; PCOMMON_DEVICE_EXTENSION DeviceExtension; // // create usb hardware // Status = CreateUSBHardware(&m_Hardware); if (!NT_SUCCESS(Status)) { // // failed to create hardware object // DPRINT1("Failed to create hardware object\n"); return STATUS_INSUFFICIENT_RESOURCES; } // // initialize members // m_DriverObject = DriverObject; m_PhysicalDeviceObject = PhysicalDeviceObject; m_RootController = RootHCDController; // // create FDO // Status = CreateFDO(m_DriverObject, &m_FunctionalDeviceObject); if (!NT_SUCCESS(Status)) { // // failed to create PDO // return Status; } // // now attach to device stack // m_NextDeviceObject = IoAttachDeviceToDeviceStack(m_FunctionalDeviceObject, m_PhysicalDeviceObject); if (!m_NextDeviceObject) { // // failed to attach to device stack // IoDeleteDevice(m_FunctionalDeviceObject); m_FunctionalDeviceObject = 0; return STATUS_NO_SUCH_DEVICE; } // // initialize hardware object // Status = m_Hardware->Initialize(m_DriverObject, m_FunctionalDeviceObject, m_PhysicalDeviceObject, m_NextDeviceObject); if (!NT_SUCCESS(Status)) { DPRINT1("[%s] Failed to initialize hardware object %x\n", m_Hardware->GetUSBType(), Status); // // failed to initialize hardware object, detach from device stack // IoDetachDevice(m_NextDeviceObject); // // now delete the device // IoDeleteDevice(m_FunctionalDeviceObject); // // nullify pointers :) // m_FunctionalDeviceObject = 0; m_NextDeviceObject = 0; return Status; } // // get usb controller type // m_USBType = m_Hardware->GetUSBType(); // // set device flags // m_FunctionalDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; // // get device extension // DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_FunctionalDeviceObject->DeviceExtension; PC_ASSERT(DeviceExtension); // // initialize device extension // DeviceExtension->IsFDO = TRUE; DeviceExtension->IsHub = FALSE; DeviceExtension->Dispatcher = PDISPATCHIRP(this); // // device is initialized // m_FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; // // is there a root controller // if (m_RootController) { // // add reference // m_RootController->AddRef(); // // register with controller // m_RootController->RegisterHCD(this); } // // done // return STATUS_SUCCESS; }
NTSTATUS FdoPnpControl( PDEVICE_OBJECT DeviceObject, PIRP Irp) /* * FUNCTION: Handle Plug and Play IRPs for the PCI device object * ARGUMENTS: * DeviceObject = Pointer to functional device object of the PCI driver * Irp = Pointer to IRP that should be handled * RETURNS: * Status */ { PFDO_DEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IrpSp; NTSTATUS Status = Irp->IoStatus.Status; DPRINT("Called\n"); DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; IrpSp = IoGetCurrentIrpStackLocation(Irp); switch (IrpSp->MinorFunction) { #if 0 case IRP_MN_CANCEL_REMOVE_DEVICE: Status = STATUS_NOT_IMPLEMENTED; break; case IRP_MN_CANCEL_STOP_DEVICE: Status = STATUS_NOT_IMPLEMENTED; break; case IRP_MN_DEVICE_USAGE_NOTIFICATION: Status = STATUS_NOT_IMPLEMENTED; break; case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: Status = STATUS_NOT_IMPLEMENTED; break; #endif case IRP_MN_QUERY_DEVICE_RELATIONS: if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations) break; Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp); Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; #if 0 case IRP_MN_QUERY_PNP_DEVICE_STATE: Status = STATUS_NOT_IMPLEMENTED; break; case IRP_MN_QUERY_REMOVE_DEVICE: Status = STATUS_NOT_IMPLEMENTED; break; #endif case IRP_MN_START_DEVICE: DPRINT("IRP_MN_START_DEVICE received\n"); Status = ForwardIrpAndWait(DeviceObject, Irp); if (NT_SUCCESS(Status)) Status = FdoStartDevice(DeviceObject, Irp); Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; case IRP_MN_QUERY_STOP_DEVICE: /* We don't support stopping yet */ Status = STATUS_UNSUCCESSFUL; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; case IRP_MN_STOP_DEVICE: /* We can't fail this one so we fail the QUERY_STOP request that precedes it */ break; #if 0 case IRP_MN_SURPRISE_REMOVAL: Status = STATUS_NOT_IMPLEMENTED; break; #endif case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: break; case IRP_MN_REMOVE_DEVICE: /* Detach the device object from the device stack */ IoDetachDevice(DeviceExtension->Ldo); /* Delete the device object */ IoDeleteDevice(DeviceObject); /* Return success */ Status = STATUS_SUCCESS; break; default: DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction); break; } Irp->IoStatus.Status = Status; IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(DeviceExtension->Ldo, Irp); DPRINT("Leaving. Status 0x%X\n", Status); return Status; }
NTSTATUS CHCDController::HandlePnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IoStack; PCOMMON_DEVICE_EXTENSION DeviceExtension; PCM_RESOURCE_LIST RawResourceList; PCM_RESOURCE_LIST TranslatedResourceList; PDEVICE_RELATIONS DeviceRelations; NTSTATUS Status; // // get device extension // DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // PC_ASSERT(DeviceExtension->IsFDO); // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); switch(IoStack->MinorFunction) { case IRP_MN_START_DEVICE: { DPRINT("[%s] HandlePnp IRP_MN_START FDO\n", m_USBType); // // first start lower device object // Status = SyncForwardIrp(m_NextDeviceObject, Irp); if (NT_SUCCESS(Status)) { // // operation succeeded, lets start the device // RawResourceList = IoStack->Parameters.StartDevice.AllocatedResources; TranslatedResourceList = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated; if (m_Hardware) { // // start the hardware // Status = m_Hardware->PnpStart(RawResourceList, TranslatedResourceList); } // // enable symbolic link // Status = SetSymbolicLink(TRUE); } DPRINT("[%s] HandlePnp IRP_MN_START FDO: Status %x\n", m_USBType ,Status); break; } case IRP_MN_QUERY_DEVICE_RELATIONS: { DPRINT("[%s] HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", m_USBType, IoStack->Parameters.QueryDeviceRelations.Type); if (m_HubController == NULL) { // // create hub controller // Status = CreateHubController(&m_HubController); if (!NT_SUCCESS(Status)) { // // failed to create hub controller // break; } // // initialize hub controller // Status = m_HubController->Initialize(m_DriverObject, PHCDCONTROLLER(this), m_Hardware, TRUE, 0 /* FIXME*/); if (!NT_SUCCESS(Status)) { // // failed to initialize hub controller // break; } // // add reference to prevent it from getting deleting while hub driver adds / removes references // m_HubController->AddRef(); } if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations) { // // allocate device relations // DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS)); if (!DeviceRelations) { // // no memory // Status = STATUS_INSUFFICIENT_RESOURCES; break; } // // init device relations // DeviceRelations->Count = 1; Status = m_HubController->GetHubControllerDeviceObject(&DeviceRelations->Objects [0]); // // sanity check // PC_ASSERT(Status == STATUS_SUCCESS); ObReferenceObject(DeviceRelations->Objects [0]); // // store result // Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; Status = STATUS_SUCCESS; } else { // // not supported // Status = STATUS_NOT_SUPPORTED; } break; } case IRP_MN_STOP_DEVICE: { DPRINT("[%s] HandlePnp IRP_MN_STOP_DEVICE\n", m_USBType); if (m_Hardware) { // // stop the hardware // Status = m_Hardware->PnpStop(); } else { // // fake success // Status = STATUS_SUCCESS; } if (NT_SUCCESS(Status)) { // // stop lower device // Status = SyncForwardIrp(m_NextDeviceObject, Irp); } break; } case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: { #if 0 // // sure // Irp->IoStatus.Status = STATUS_SUCCESS; // // forward irp to next device object // IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(m_NextDeviceObject, Irp); #else DPRINT1("[%s] Denying controller removal due to reinitialization bugs\n", m_USBType); Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; #endif } case IRP_MN_REMOVE_DEVICE: { DPRINT("[%s] HandlePnp IRP_MN_REMOVE_DEVICE FDO\n", m_USBType); // // delete the symbolic link // SetSymbolicLink(FALSE); // // forward irp to next device object // IoSkipCurrentIrpStackLocation(Irp); IoCallDriver(m_NextDeviceObject, Irp); // // detach device from device stack // IoDetachDevice(m_NextDeviceObject); // // delete device // IoDeleteDevice(m_FunctionalDeviceObject); return STATUS_SUCCESS; } default: { // // forward irp to next device object // IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(m_NextDeviceObject, Irp); } } // // store result and complete request // Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }
NTSTATUS Serenum_FDO_PnP ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION IrpStack, IN PFDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the PlugPlay system for the BUS itself NB: the various Minor functions of the PlugPlay system will not be overlapped and do not have to be reentrant --*/ { NTSTATUS status; KEVENT event; ULONG length; ULONG i; PDEVICE_RELATIONS relations; PIO_STACK_LOCATION stack; PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL; ULONG DebugLevelDefault = SER_DEFAULT_DEBUG_OUTPUT_LEVEL; PAGED_CODE(); status = Serenum_IncIoCount (DeviceData); if (!NT_SUCCESS (status)) { Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } stack = IoGetCurrentIrpStackLocation (Irp); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // BEFORE you are allowed to ``touch'' the device object to which // the FDO is attached (that send an irp from the bus to the Device // object to which the bus is attached). You must first pass down // the start IRP. It might not be powered on, or able to access or // something. // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Start Device\n")); if (DeviceData->Started) { Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Device already started\n")); status = STATUS_SUCCESS; break; } KeInitializeEvent (&event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext (Irp); IoSetCompletionRoutine (Irp, SerenumSyncCompletion, &event, TRUE, TRUE, TRUE); status = IoCallDriver (DeviceData->TopOfStack, Irp); if (STATUS_PENDING == status) { // wait for it... status = KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, // Not allertable NULL); // No timeout structure ASSERT (STATUS_SUCCESS == status); status = Irp->IoStatus.Status; } if (NT_SUCCESS(status)) { // // Now we can touch the lower device object as it is now started. // // // Get the debug level from the registry // if (NULL == (QueryTable = ExAllocatePool( PagedPool, sizeof(RTL_QUERY_REGISTRY_TABLE)*2 ))) { Serenum_KdPrint (DeviceData, SER_DBG_PNP_ERROR, ("Failed to allocate memory to query registy\n")); DeviceData->DebugLevel = DebugLevelDefault; } else { RtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE)*2 ); QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[0].EntryContext = &DeviceData->DebugLevel; QueryTable[0].Name = L"DebugLevel"; QueryTable[0].DefaultType = REG_DWORD; QueryTable[0].DefaultData = &DebugLevelDefault; QueryTable[0].DefaultLength= sizeof(ULONG); // CIMEXCIMEX: The rest of the table isn't filled in! if (!NT_SUCCESS(RtlQueryRegistryValues( RTL_REGISTRY_SERVICES, L"Serenum", QueryTable, NULL, NULL))) { Serenum_KdPrint (DeviceData,SER_DBG_PNP_ERROR, ("Failed to get debug level from registry. " "Using default\n")); DeviceData->DebugLevel = DebugLevelDefault; } ExFreePool( QueryTable ); } Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Start Device: Device started successfully\n")); DeviceData->Started = TRUE; } // // We must now complete the IRP, since we stopped it in the // completetion routine with MORE_PROCESSING_REQUIRED. // break; case IRP_MN_QUERY_STOP_DEVICE: Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Stop Device\n")); // // Test to see if there are any PDO created as children of this FDO // If there are then conclude the device is busy and fail the // query stop. // // CIMEXCIMEX // We could do better, by seing if the children PDOs are actually // currently open. If they are not then we could stop, get new // resouces, fill in the new resouce values, and then when a new client // opens the PDO use the new resources. But this works for now. // if (DeviceData->AttachedPDO || (DeviceData->EnumFlags & SERENUM_ENUMFLAG_PENDING)) { status = STATUS_UNSUCCESSFUL; } else { status = STATUS_SUCCESS; } Irp->IoStatus.Status = status; if (NT_SUCCESS(status)) { IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); } else { IoCompleteRequest(Irp, IO_NO_INCREMENT); } Serenum_DecIoCount (DeviceData); return status; case IRP_MN_CANCEL_STOP_DEVICE: // // We always succeed a cancel stop // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Cancel Stop Device\n")); Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; case IRP_MN_STOP_DEVICE: Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Stop Device\n")); // // Wait for the enum thread to complete if it's running // SerenumWaitForEnumThreadTerminate(DeviceData); // // After the start IRP has been sent to the lower driver object, the // bus may NOT send any more IRPS down ``touch'' until another START // has occured. // What ever access is required must be done before the Irp is passed // on. // // Stop device means that the resources given durring Start device // are no revoked. So we need to stop using them // DeviceData->Started = FALSE; // // We don't need a completion routine so fire and forget. // // Set the current stack location to the next stack location and // call the next device object. // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; case IRP_MN_REMOVE_DEVICE: Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Remove Device\n")); // // The PlugPlay system has detected the removal of this device. We // have no choice but to detach and delete the device object. // (If we wanted to express and interest in preventing this removal, // we should have filtered the query remove and query stop routines.) // // Note! we might receive a remove WITHOUT first receiving a stop. // ASSERT (!DeviceData->Removed); // // Synchronize with the enum thread if it is running and wait // for it to finish // SerenumWaitForEnumThreadTerminate(DeviceData); // We will accept no new requests // DeviceData->Removed = TRUE; // // Complete any outstanding IRPs queued by the driver here. // // // Make the DCA go away. Some drivers may choose to remove the DCA // when they receive a stop or even a query stop. We just don't care. // (void)IoSetDeviceInterfaceState (&DeviceData->DevClassAssocName, FALSE); // // Here if we had any outstanding requests in a personal queue we should // complete them all now. // // Note, the device is guarenteed stopped, so we cannot send it any non- // PNP IRPS. // // // Fire and forget // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); // // Wait for any outstanding threads to complete // // // Wait for all outstanding requests to complete // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Waiting for outstanding requests\n")); i = InterlockedDecrement ((volatile LONG*)&DeviceData->OutstandingIO); ASSERT (0 < i); if (0 != InterlockedDecrement ((volatile LONG*)&DeviceData->OutstandingIO)) { Serenum_KdPrint (DeviceData, SER_DBG_PNP_INFO, ("Remove Device waiting for request to complete\n")); KeWaitForSingleObject (&DeviceData->RemoveEvent, Executive, KernelMode, FALSE, // Not Alertable NULL); // No timeout } // // Free the associated resources // // // Detach from the underlying devices. // Serenum_KdPrint(DeviceData, SER_DBG_PNP_INFO, ("IoDetachDevice: 0x%x\n", DeviceData->TopOfStack)); IoDetachDevice (DeviceData->TopOfStack); // // Clean up any resources here // ExFreePool (DeviceData->DevClassAssocName.Buffer); Serenum_KdPrint(DeviceData, SER_DBG_PNP_INFO, ("IoDeleteDevice: 0x%x\n", DeviceObject)); // // Remove any PDO's we ejected // if (DeviceData->AttachedPDO != NULL) { ASSERT(DeviceData->NumPDOs == 1); Serenum_PnPRemove(DeviceData->AttachedPDO, DeviceData->PdoData); DeviceData->PdoData = NULL; DeviceData->AttachedPDO = NULL; DeviceData->NumPDOs = 0; } IoDeleteDevice(DeviceObject); return status; case IRP_MN_QUERY_DEVICE_RELATIONS: if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) { // // We don't support this // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Device Relations - Non bus\n")); goto SER_FDO_PNP_DEFAULT; } Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Bus Relations\n")); status = SerenumCheckEnumerations(DeviceData); // // 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.) // //KeAcquireSpinLock (&DeviceData->Spin, &oldIrq); i = (0 == Irp->IoStatus.Information) ? 0 : ((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Count; // The current number of PDOs in the device relations structure Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("#PDOS = %d + %d\n", i, DeviceData->NumPDOs)); length = sizeof(DEVICE_RELATIONS) + ((DeviceData->NumPDOs + i) * sizeof (PDEVICE_OBJECT)); relations = (PDEVICE_RELATIONS) ExAllocatePool (NonPagedPool, length); if (NULL == relations) { Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); Serenum_DecIoCount(DeviceData); 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 = DeviceData->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. // if (DeviceData->NumPDOs) { relations->Objects[relations->Count-1] = DeviceData->AttachedPDO; ObReferenceObject (DeviceData->AttachedPDO); } // // 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_PTR)relations; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; case IRP_MN_QUERY_REMOVE_DEVICE: // // 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. // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Remove Device\n")); // // Wait for the enum thread to complete if it's running // SerenumWaitForEnumThreadTerminate(DeviceData); Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; case IRP_MN_QUERY_CAPABILITIES: { PIO_STACK_LOCATION irpSp; // // Send this down to the PDO first // KeInitializeEvent (&event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext (Irp); IoSetCompletionRoutine (Irp, SerenumSyncCompletion, &event, TRUE, TRUE, TRUE); status = IoCallDriver (DeviceData->TopOfStack, Irp); if (STATUS_PENDING == status) { // wait for it... status = KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, // Not allertable NULL); // No timeout structure ASSERT (STATUS_SUCCESS == status); status = Irp->IoStatus.Status; } if (NT_SUCCESS(status)) { irpSp = IoGetCurrentIrpStackLocation(Irp); DeviceData->SystemWake = irpSp->Parameters.DeviceCapabilities.Capabilities->SystemWake; DeviceData->DeviceWake = irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceWake; } break; } SER_FDO_PNP_DEFAULT: default: // // In the default case we merely call the next driver since // we don't know what to do. // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Default Case\n")); // // Fire and Forget // IoSkipCurrentIrpStackLocation (Irp); // // Done, do NOT complete the IRP, it will be processed by the lower // device object, which will complete the IRP // status = IoCallDriver (DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Serenum_DecIoCount (DeviceData); return status; }
NTSTATUS Serenum_AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT BusPhysicalDeviceObject) /*++ Routine Description. A bus has been found. Attach our FDO to it. Allocate any required resources. Set things up. And be prepared for the first ``start device.'' Arguments: BusPhysicalDeviceObject - Device object representing the bus. That to which we attach a new FDO. DriverObject - This very self referenced driver. --*/ { NTSTATUS status; PDEVICE_OBJECT deviceObject; PFDO_DEVICE_DATA pDeviceData; HANDLE keyHandle; ULONG actualLength; PAGED_CODE(); Serenum_KdPrint_Def(SER_DBG_PNP_TRACE, ("Add Device: 0x%x\n", BusPhysicalDeviceObject)); // // Create our FDO // status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_DATA), NULL, FILE_DEVICE_BUS_EXTENDER, 0, TRUE, &deviceObject); if (NT_SUCCESS(status)) { pDeviceData = (PFDO_DEVICE_DATA)deviceObject->DeviceExtension; RtlFillMemory (pDeviceData, sizeof (FDO_DEVICE_DATA), 0); pDeviceData->IsFDO = TRUE; pDeviceData->DebugLevel = SER_DEFAULT_DEBUG_OUTPUT_LEVEL; pDeviceData->Self = deviceObject; pDeviceData->AttachedPDO = NULL; pDeviceData->NumPDOs = 0; pDeviceData->DeviceState = PowerDeviceD0; pDeviceData->SystemState = PowerSystemWorking; pDeviceData->PDOForcedRemove = FALSE; pDeviceData->SystemWake=PowerSystemUnspecified; pDeviceData->DeviceWake=PowerDeviceUnspecified; pDeviceData->Removed = FALSE; // // Set the PDO for use with PlugPlay functions // pDeviceData->UnderlyingPDO = BusPhysicalDeviceObject; // // Attach our filter driver to the device stack. // the return value of IoAttachDeviceToDeviceStack is the top of the // attachment chain. This is where all the IRPs should be routed. // // Our filter will send IRPs to the top of the stack and use the PDO // for all PlugPlay functions. // pDeviceData->TopOfStack = IoAttachDeviceToDeviceStack(deviceObject, BusPhysicalDeviceObject); if (!pDeviceData->TopOfStack) { Serenum_KdPrint(pDeviceData, SER_DBG_PNP_ERROR, ("AddDevice: IoAttach failed (%x)", status)); IoDeleteDevice(deviceObject); return STATUS_UNSUCCESSFUL; } // // Set the type of IO we do // if (pDeviceData->TopOfStack->Flags & DO_BUFFERED_IO) { deviceObject->Flags |= DO_BUFFERED_IO; } else if (pDeviceData->TopOfStack->Flags & DO_DIRECT_IO) { deviceObject->Flags |= DO_DIRECT_IO; } // // Bias outstanding request to 1 so that we can look for a // transition to zero when processing the remove device PlugPlay IRP. // pDeviceData->OutstandingIO = 1; KeInitializeEvent(&pDeviceData->RemoveEvent, SynchronizationEvent, FALSE); KeInitializeSemaphore(&pDeviceData->CreateSemaphore, 1, 1); KeInitializeSpinLock(&pDeviceData->EnumerationLock); // // Tell the PlugPlay system that this device will need an interface // device class shingle. // // It may be that the driver cannot hang the shingle until it starts // the device itself, so that it can query some of its properties. // (Aka the shingles guid (or ref string) is based on the properties // of the device.) // status = IoRegisterDeviceInterface(BusPhysicalDeviceObject, (LPGUID)&GUID_SERENUM_BUS_ENUMERATOR, NULL, &pDeviceData->DevClassAssocName); if (!NT_SUCCESS(status)) { Serenum_KdPrint(pDeviceData, SER_DBG_PNP_ERROR, ("AddDevice: IoRegisterDCA failed (%x)", status)); IoDetachDevice(pDeviceData->TopOfStack); IoDeleteDevice(deviceObject); return status; } // // If for any reason you need to save values in a safe location that // clients of this DeviceClassAssociate might be interested in reading // here is the time to do so, with the function // IoOpenDeviceClassRegistryKey // the symbolic link name used is was returned in // pDeviceData->DevClassAssocName (the same name which is returned by // IoGetDeviceClassAssociations and the SetupAPI equivs. // #if DBG { PWCHAR deviceName = NULL; ULONG nameLength = 0; status = IoGetDeviceProperty(BusPhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &nameLength); if ((nameLength != 0) && (status == STATUS_BUFFER_TOO_SMALL)) { deviceName = ExAllocatePool(NonPagedPool, nameLength); if (NULL == deviceName) { goto someDebugStuffExit; } IoGetDeviceProperty(BusPhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, nameLength, deviceName, &nameLength); Serenum_KdPrint(pDeviceData, SER_DBG_PNP_TRACE, ("AddDevice: %x to %x->%x (%ws) \n", deviceObject, pDeviceData->TopOfStack, BusPhysicalDeviceObject, deviceName)); } someDebugStuffExit: ; if (deviceName != NULL) { ExFreePool(deviceName); } } #endif // DBG // // Turn on the shingle and point it to the given device object. // status = IoSetDeviceInterfaceState(&pDeviceData->DevClassAssocName, TRUE); if (!NT_SUCCESS(status)) { Serenum_KdPrint(pDeviceData, SER_DBG_PNP_ERROR, ("AddDevice: IoSetDeviceClass failed (%x)", status)); return status; } // // Open the registry and read in our settings // status = IoOpenDeviceRegistryKey(pDeviceData->UnderlyingPDO, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); if (status == STATUS_SUCCESS) { status = Serenum_GetRegistryKeyValue(keyHandle, L"SkipEnumerations", sizeof(L"SkipEnumerations"), &pDeviceData->SkipEnumerations, sizeof(pDeviceData->SkipEnumerations), &actualLength); if ((status != STATUS_SUCCESS) || (actualLength != sizeof(pDeviceData->SkipEnumerations))) { pDeviceData->SkipEnumerations = 0; status = STATUS_SUCCESS; } ZwClose(keyHandle); } } if (NT_SUCCESS(status)) { deviceObject->Flags |= DO_POWER_PAGABLE; deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; } return status; }
NTSTATUS Bus_AddDevice(__in PDRIVER_OBJECT DriverObject, __in PDEVICE_OBJECT PhysicalDeviceObject) { NTSTATUS status; PDEVICE_OBJECT deviceObject = NULL; PFDO_DEVICE_DATA deviceData = NULL; PWCHAR deviceName = NULL; ULONG nameLength; UNREFERENCED_PARAMETER(nameLength); PAGED_CODE(); Bus_KdPrint(("Add Device: 0x%p\n", PhysicalDeviceObject)); status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_DATA), NULL, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, TRUE, &deviceObject); if (!NT_SUCCESS (status)) { goto End; } deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension; RtlZeroMemory(deviceData, sizeof (FDO_DEVICE_DATA)); INITIALIZE_PNP_STATE(deviceData); deviceData->IsFDO = TRUE; deviceData->Self = deviceObject; ExInitializeFastMutex(&deviceData->Mutex); InitializeListHead(&deviceData->ListOfPDOs); deviceData->UnderlyingPDO = PhysicalDeviceObject; deviceData->DevicePowerState = PowerDeviceUnspecified; deviceData->SystemPowerState = PowerSystemWorking; deviceData->OutstandingIO = 1; KeInitializeEvent(&deviceData->RemoveEvent, SynchronizationEvent, FALSE); KeInitializeEvent(&deviceData->StopEvent, SynchronizationEvent, TRUE); deviceObject->Flags |= DO_POWER_PAGABLE; status = IoRegisterDeviceInterface(PhysicalDeviceObject, (LPGUID) &GUID_DEVINTERFACE_SCPVBUS, NULL, &deviceData->InterfaceName); if (!NT_SUCCESS(status)) { Bus_KdPrint(("AddDevice: IoRegisterDeviceInterface failed (%x)", status)); goto End; } deviceData->NextLowerDriver = IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject); if (deviceData->NextLowerDriver == NULL) { status = STATUS_NO_SUCH_DEVICE; goto End; } deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; End: if (deviceName) { ExFreePool(deviceName); } if (!NT_SUCCESS(status) && deviceObject) { if (deviceData && deviceData->NextLowerDriver) { IoDetachDevice(deviceData->NextLowerDriver); } IoDeleteDevice(deviceObject); } return status; }
static NTSTATUS NTAPI V4vDispatchPnP(PDEVICE_OBJECT fdo, PIRP irp) { NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION isl = IoGetCurrentIrpStackLocation(irp); PXENV4V_EXTENSION pde = V4vGetDeviceExtension(fdo); KEVENT kev; TraceVerbose(("====> '%s'.\n", __FUNCTION__)); TraceVerbose((" =PnP= 0x%x\n", isl->MinorFunction)); status = IoAcquireRemoveLock(&pde->removeLock, irp); if (!NT_SUCCESS(status)) { TraceError(("failed to acquire IO lock - error: 0x%x\n", status)); return V4vSimpleCompleteIrp(irp, status); } switch (isl->MinorFunction) { case IRP_MN_START_DEVICE: KeInitializeEvent(&kev, NotificationEvent, FALSE); // Send the start down and wait for it to complete IoCopyCurrentIrpStackLocationToNext(irp); IoSetCompletionRoutine(irp, V4vStartDeviceIoCompletion, &kev, TRUE, TRUE, TRUE); status = IoCallDriver(pde->ldo, irp); if (status == STATUS_PENDING) { // Wait for everything underneath us to complete TraceVerbose(("Device start waiting for lower device.\n")); KeWaitForSingleObject(&kev, Executive, KernelMode, FALSE, NULL); TraceVerbose(("Device start wait finished.\n")); } status = irp->IoStatus.Status; if (!NT_SUCCESS(status)) { TraceError(("Failed to start lower drivers: %x.\n", status)); IoCompleteRequest(irp, IO_NO_INCREMENT); break; } status = STATUS_SUCCESS; // Connect our interrupt (ec). status = V4vInitializeEventChannel(fdo); if (NT_SUCCESS(status)) { InterlockedExchange(&pde->state, XENV4V_DEV_STARTED); } else { TraceError(("failed to initialize event channel - error: 0x%x\n", status)); } irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_NO_INCREMENT); break; case IRP_MN_STOP_DEVICE: // Stop our device's IO processing V4vStopDevice(fdo, pde); // Pass it down irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); break; case IRP_MN_REMOVE_DEVICE: // Stop our device's IO processing V4vStopDevice(fdo, pde); // Cleanup anything here that locks for IO IoReleaseRemoveLockAndWait(&pde->removeLock, irp); // Pass it down first IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); // Then detach and cleanup our device xenbus_change_state(XBT_NIL, pde->frontendPath, "state", XENBUS_STATE_CLOSED); IoDetachDevice(pde->ldo); ExDeleteNPagedLookasideList(&pde->destLookasideList); XmFreeMemory(pde->frontendPath); IoDeleteSymbolicLink(&pde->symbolicLink); IoDeleteDevice(fdo); InterlockedAnd(&g_deviceCreated, 0); return status; default: // Pass it down TraceVerbose(("IRP_MJ_PNP MinorFunction %d passed down\n", isl->MinorFunction)); IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); }; // Everybody but REMOVE IoReleaseRemoveLock(&pde->removeLock, irp); TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return status; }
void MalwFind_FastIoDetachDevice( IN PDEVICE_OBJECT pSourceDevice, IN PDEVICE_OBJECT pTargetDevice ) { PFLT_EXTENSION pDevExt = NULL; PFAST_IO_DISPATCH pFastIoDispatch = NULL; NAME_BUFFER FullPath = {0}; ASSERT( pSourceDevice && pTargetDevice ); if(!pSourceDevice || !pTargetDevice) return; if(!MmIsAddressValid( pSourceDevice ) || !MmIsAddressValid( pTargetDevice )) return; __try { if(IS_MALFIND_DEVICE_OBJECT( pSourceDevice )) { pDevExt = (PFLT_EXTENSION)pSourceDevice->DeviceExtension; if(pDevExt) KdPrint(("MalwFind_DeviceObject--MalwFind_FastIoDetachDevice: [ %c:\\ ] \n", pDevExt->wcVol )); else KdPrint(("MalwFind_DeviceObject--MalwFind_FastIoDetachDevice: \n")); ALLOCATE_N_POOL( FullPath ); if(FullPath.pBuffer) { SET_POOL_ZERO( FullPath ); FullPath.pBuffer[0] = pDevExt->wcVol; FullPath.pBuffer[1] = L':'; FullPath.pBuffer[2] = L'\\'; FullPath.pBuffer[3] = L'\0'; FREE_N_POOL( FullPath ); } FsdCleanupMountDevice( pSourceDevice ); IoDetachDevice( pTargetDevice ); IoDeleteDevice( pSourceDevice ); pSourceDevice = NULL; return; } /* pDevExt = (PFLT_EXTENSION)pSourceDevice->DeviceExtension; ASSERT( pDevExt ); if(!pDevExt) return; pFastIoDispatch = pDevExt->pLowerDeviceObject->DriverObject->FastIoDispatch; ASSERT( pFastIoDispatch ); if(!pFastIoDispatch) return; if(VALID_FAST_IO( pFastIoDispatch, FastIoDetachDevice )) { (pFastIoDispatch->FastIoDetachDevice)( pSourceDevice, pTargetDevice ); } */ } __except(EXCEPTION_EXECUTE_HANDLER) { KdPrint(("MalwFind_FastIoDetachDevice Exception Occured. \n")); } }
static NTSTATUS V4vAddDevice(PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING deviceName; PDEVICE_OBJECT fdo = NULL; PXENV4V_EXTENSION pde = NULL; LONG val; BOOLEAN symlink = FALSE; LARGE_INTEGER seed; WCHAR *szSddl = NULL; UNICODE_STRING sddlString; CHAR *szFpath = NULL; TraceVerbose(("====> '%s'.\n", __FUNCTION__)); // We only allow one instance of this device type. If more than on pdo is created we need val = InterlockedCompareExchange(&g_deviceCreated, 1, 0); if (val != 0) { TraceWarning(("cannot instantiate more that one v4v device node.\n")); return STATUS_UNSUCCESSFUL; } do { // Create our device RtlInitUnicodeString(&deviceName, V4V_DEVICE_NAME); szSddl = g_win5Sddl; RtlInitUnicodeString(&sddlString, szSddl); status = IoCreateDeviceSecure(driverObject, sizeof(XENV4V_EXTENSION), &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &sddlString, (LPCGUID)&GUID_SD_XENV4V_CONTROL_OBJECT, &fdo); if (!NT_SUCCESS(status)) { TraceError(("failed to create device object - error: 0x%x\n", status)); fdo = NULL; break; } pde = (PXENV4V_EXTENSION)fdo->DeviceExtension; RtlZeroMemory(pde, sizeof(XENV4V_EXTENSION)); RtlStringCchCopyW(pde->symbolicLinkText, XENV4V_SYM_NAME_LEN, V4V_SYMBOLIC_NAME); RtlInitUnicodeString(&pde->symbolicLink, pde->symbolicLinkText); // Create our symbolic link status = IoCreateSymbolicLink(&pde->symbolicLink, &deviceName); if (!NT_SUCCESS(status)) { TraceError(("failed to create symbolic - error: 0x%x\n", status)); break; } symlink = TRUE; // Get our xenstore path szFpath = xenbus_find_frontend(pdo); if (szFpath == NULL) { status = STATUS_NO_SUCH_DEVICE; TraceError(("failed to locate XenStore front end path\n")); break; } // Setup the extension pde->magic = XENV4V_MAGIC; pde->pdo = pdo; pde->fdo = fdo; IoInitializeRemoveLock(&pde->removeLock, 'v4vx', 0, 0); pde->frontendPath = szFpath; szFpath = NULL; pde->state = XENV4V_DEV_STOPPED; // wait for start pde->lastPoState = PowerSystemWorking; pde->virqPort = null_EVTCHN_PORT(); KeInitializeDpc(&pde->virqDpc, V4vVirqNotifyDpc, fdo); KeInitializeSpinLock(&pde->virqLock); KeInitializeSpinLock(&pde->dpcLock); KeInitializeTimerEx(&pde->timer, NotificationTimer); KeInitializeDpc(&pde->timerDpc, V4vConnectTimerDpc, fdo); KeInitializeSpinLock(&pde->timerLock); pde->timerCounter = 0; InitializeListHead(&pde->contextList); KeInitializeSpinLock(&pde->contextLock); pde->contextCount = 0; InitializeListHead(&pde->ringList); KeInitializeSpinLock(&pde->ringLock); InitializeListHead(&pde->pendingIrpQueue); pde->pendingIrpCount = 0; KeInitializeSpinLock(&pde->queueLock); IoCsqInitializeEx(&pde->csqObject, V4vCsqInsertIrpEx, V4vCsqRemoveIrp, V4vCsqPeekNextIrp, V4vCsqAcquireLock, V4vCsqReleaseLock, V4vCsqCompleteCanceledIrp); InitializeListHead(&pde->destList); pde->destCount = 0; ExInitializeNPagedLookasideList(&pde->destLookasideList, NULL, NULL, 0, sizeof(XENV4V_DESTINATION), XENV4V_TAG, 0); KeQueryTickCount(&seed); pde->seed = seed.u.LowPart; // Now attach us to the stack pde->ldo = IoAttachDeviceToDeviceStack(fdo, pdo); if (pde->ldo == NULL) { TraceError(("failed to attach device to stack - error: 0x%x\n", status)); status = STATUS_NO_SUCH_DEVICE; break; } // Use direct IO and let the IO manager directly map user buffers; clear the init flag fdo->Flags |= DO_DIRECT_IO; fdo->Flags &= ~DO_DEVICE_INITIALIZING; // Made it here, go to connected state to be consistent xenbus_change_state(XBT_NIL, pde->frontendPath, "state", XENBUS_STATE_CONNECTED); } while (FALSE); if (!NT_SUCCESS(status)) { if (fdo != NULL) { if ((pde != NULL)&&(pde->ldo != NULL)) { IoDetachDevice(pde->ldo); } if (szFpath != NULL) { XmFreeMemory(szFpath); } if (symlink) { IoDeleteSymbolicLink(&pde->symbolicLink); } IoDeleteDevice(fdo); } } TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return status; }
NTSTATUS FDO_HandlePnp( PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION IoStack; NTSTATUS Status; PFDO_DEVICE_EXTENSION FDODeviceExtension; /* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO); /* Get stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp); DPRINT("[USBCCGP] PnP Minor %x\n", IoStack->MinorFunction); switch(IoStack->MinorFunction) { case IRP_MN_REMOVE_DEVICE: { // Unconfigure device */ DPRINT1("[USBCCGP] FDO IRP_MN_REMOVE\n"); FDO_CloseConfiguration(DeviceObject); /* Send the IRP down the stack */ Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp); if (NT_SUCCESS(Status)) { /* Detach from the device stack */ IoDetachDevice(FDODeviceExtension->NextDeviceObject); /* Delete the device object */ IoDeleteDevice(DeviceObject); } /* Request completed */ break; } case IRP_MN_START_DEVICE: { /* Start the device */ Status = FDO_StartDevice(DeviceObject, Irp); break; } case IRP_MN_QUERY_DEVICE_RELATIONS: { /* Handle device relations */ Status = FDO_DeviceRelations(DeviceObject, Irp); break; } case IRP_MN_QUERY_CAPABILITIES: { /* Copy capabilities */ RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES)); Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp); if (NT_SUCCESS(Status)) { /* Surprise removal ok */ IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE; } break; } case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: { /* Sure */ Irp->IoStatus.Status = STATUS_SUCCESS; /* Forward irp to next device object */ IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp); } default: { /* Forward irp to next device object */ IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp); } } /* Complete request */ Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }
NTSTATUS DPAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject ) { //NTSTATUS类型的函数返回值 NTSTATUS ntStatus = STATUS_SUCCESS; //用来指向过滤设备的设备扩展的指针 PDP_FILTER_DEV_EXTENSION DevExt = NULL; //过滤设备的下层设备的指针对象 PDEVICE_OBJECT LowerDevObj = NULL; //过滤设备的设备指针的指针对象 PDEVICE_OBJECT FltDevObj = NULL; //过滤设备的处理线程的线程句柄 HANDLE ThreadHandle = NULL; //建立一个过滤设备,这个设备是FILE_DEVICE_DISK类型的设备并且具有DP_FILTER_DEV_EXTENSION类型的设备扩展 ntStatus = IoCreateDevice( DriverObject, sizeof(DP_FILTER_DEV_EXTENSION), NULL, FILE_DEVICE_DISK, FILE_DEVICE_SECURE_OPEN, FALSE, &FltDevObj); if (!NT_SUCCESS(ntStatus)) goto ERROUT; //将DevExt指向过滤设备的设备扩展指针 DevExt = FltDevObj->DeviceExtension; //清空过滤设备的设备扩展 RtlZeroMemory(DevExt,sizeof(DP_FILTER_DEV_EXTENSION)); //将刚刚建立的过滤设备附加到这个卷设备的物理设备上 LowerDevObj = IoAttachDeviceToDeviceStack( FltDevObj, PhysicalDeviceObject); if (NULL == LowerDevObj) { ntStatus = STATUS_NO_SUCH_DEVICE; goto ERROUT; } //初始化这个卷设备的分页路径计数的计数事件 KeInitializeEvent( &DevExt->PagingPathCountEvent, NotificationEvent, TRUE); //对过滤设备的设备属性进行初始化,过滤设备的设备属性应该和它的下层设备相同 FltDevObj->Flags = LowerDevObj->Flags; //给过滤设备的设备属性加上电源可分页的属性 FltDevObj->Flags |= DO_POWER_PAGABLE; //对过滤设备进行设备初始化 FltDevObj->Flags &= ~DO_DEVICE_INITIALIZING; //将过滤设备对应的设备扩展中的相应变量进行初始化 //卷设备的过滤设备对象 DevExt->FltDevObj = FltDevObj; //卷设备的物理设备对象 DevExt->PhyDevObj = PhysicalDeviceObject; //卷设备的下层设备对象 DevExt->LowerDevObj = LowerDevObj; //初始化这个卷的请求处理队列 InitializeListHead(&DevExt->ReqList); //初始化请求处理队列的锁 KeInitializeSpinLock(&DevExt->ReqLock); //初始化请求处理队列的同步事件 KeInitializeEvent( &DevExt->ReqEvent, SynchronizationEvent, FALSE ); //初始化终止处理线程标志 DevExt->ThreadTermFlag = FALSE; //建立用来处理这个卷的请求的处理线程,线程函数的参数则是设备扩展 ntStatus = PsCreateSystemThread( &ThreadHandle, (ACCESS_MASK)0L, NULL, NULL, NULL, DPReadWriteThread, DevExt ); if (!NT_SUCCESS(ntStatus)) goto ERROUT; //获取处理线程的对象 ntStatus = ObReferenceObjectByHandle( ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &DevExt->ThreadHandle, NULL ); if (!NT_SUCCESS(ntStatus)) { DevExt->ThreadTermFlag = TRUE; KeSetEvent( &DevExt->ReqEvent, (KPRIORITY)0, FALSE ); goto ERROUT; } ERROUT: if (!NT_SUCCESS(ntStatus)) { //如果上面有不成功的地方,首先需要解除可能存在的附加 if (NULL != LowerDevObj) { IoDetachDevice(LowerDevObj); DevExt->LowerDevObj = NULL; } //然后删除可能建立的过滤设备 if (NULL != FltDevObj) { IoDeleteDevice(FltDevObj); DevExt->FltDevObj = NULL; } } //关闭线程句柄,我们今后不会用到它,所有对线程的引用都通过线程对象来进行了 if (NULL != ThreadHandle) ZwClose(ThreadHandle); //返回状态值 return ntStatus; }