VOID VIOSerialPortPnpNotifyWork( IN WDFWORKITEM WorkItem ) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(WorkItem); PVIOSERIAL_PORT pport = pdoData->port; PTARGET_DEVICE_CUSTOM_NOTIFICATION notification; ULONG requiredSize; NTSTATUS status; VIRTIO_PORT_STATUS_CHANGE portStatus = {0}; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); portStatus.Version = 1; portStatus.Reason = pport->HostConnected; status = RtlULongAdd((sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) - sizeof(UCHAR)), sizeof(VIRTIO_PORT_STATUS_CHANGE), &requiredSize); if (NT_SUCCESS(status)) { notification = (PTARGET_DEVICE_CUSTOM_NOTIFICATION) ExAllocatePoolWithTag(NonPagedPool, requiredSize, VIOSERIAL_DRIVER_MEMORY_TAG); if (notification != NULL) { RtlZeroMemory(notification, requiredSize); notification->Version = 1; notification->Size = (USHORT)(requiredSize); notification->FileObject = NULL; notification->NameBufferOffset = -1; notification->Event = GUID_VIOSERIAL_PORT_CHANGE_STATUS; RtlCopyMemory(notification->CustomDataBuffer, &portStatus, sizeof(VIRTIO_PORT_STATUS_CHANGE)); if(WdfDeviceGetDevicePnpState(pport->Device) == WdfDevStatePnpStarted) { status = IoReportTargetDeviceChangeAsynchronous( WdfDeviceWdmGetPhysicalDevice(pport->Device), notification, NULL, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "IoReportTargetDeviceChangeAsynchronous Failed! status = 0x%x\n", status); } } ExFreePoolWithTag(notification, VIOSERIAL_DRIVER_MEMORY_TAG); } } WdfObjectDelete(WorkItem); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); }
NTKERNELAPI NTSTATUS FsRtlNotifyVolumeEvent ( IN PFILE_OBJECT FileObject, IN ULONG EventCode ) /*++ Routine Description: This routine notifies any registered applications that a volume is being locked, unlocked, etc. Arguments: FileeObject - Supplies a file object for the volume being locked. EventCode - Which event is occuring -- e.g. FSRTL_VOLUME_LOCK Return Value: Status of the notification. --*/ { NTSTATUS Status = STATUS_SUCCESS; TARGET_DEVICE_CUSTOM_NOTIFICATION Event; PDEVICE_OBJECT Pdo; // // Retrieve the device object associated with this file object. // Status = IoGetRelatedTargetDevice( FileObject, &Pdo ); if (NT_SUCCESS( Status )) { ASSERT(Pdo != NULL); Event.Version = 1; Event.FileObject = NULL; Event.NameBufferOffset = -1; Event.Size = (USHORT)FIELD_OFFSET( TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer ); switch (EventCode) { case FSRTL_VOLUME_DISMOUNT: RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_DISMOUNT, sizeof( GUID )); break; case FSRTL_VOLUME_DISMOUNT_FAILED: RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_DISMOUNT_FAILED, sizeof( GUID )); break; case FSRTL_VOLUME_LOCK: RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_LOCK, sizeof( GUID )); break; case FSRTL_VOLUME_LOCK_FAILED: RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_LOCK_FAILED, sizeof( GUID )); break; case FSRTL_VOLUME_MOUNT: // // Mount notification is asynchronous to avoid deadlocks when someone // unwittingly causes a mount in the course of handling some other // PnP notification, e.g. MountMgr's device arrival code. // RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_MOUNT, sizeof( GUID )); IoReportTargetDeviceChangeAsynchronous( Pdo, &Event, NULL, NULL ); ObDereferenceObject( Pdo ); return STATUS_SUCCESS; break; case FSRTL_VOLUME_UNLOCK: RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_UNLOCK, sizeof( GUID )); break; default: ObDereferenceObject( Pdo ); return STATUS_INVALID_PARAMETER; } IoReportTargetDeviceChange( Pdo, &Event ); ObDereferenceObject( Pdo ); } return Status; }
/* * @implemented */ VOID MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING DeviceName, IN BOOLEAN ValidateVolume) { PIRP Irp; KEVENT Event; NTSTATUS Status; PLIST_ENTRY NextEntry; PFILE_OBJECT FileObject; PIO_STACK_LOCATION Stack; PDEVICE_OBJECT DeviceObject; IO_STATUS_BLOCK IoStatusBlock; PDEVICE_RELATIONS DeviceRelations; PDEVICE_INFORMATION DeviceInformation; TARGET_DEVICE_CUSTOM_NOTIFICATION DeviceNotification; /* If we have to validate volume */ if (ValidateVolume) { /* Then, ensure we can find the device */ NextEntry = DeviceExtension->DeviceListHead.Flink; while (NextEntry != &(DeviceExtension->DeviceListHead)) { DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); if (RtlCompareUnicodeString(DeviceName, &(DeviceInformation->DeviceName), TRUE) == 0) { break; } } /* No need to notify for a PnP device or if we didn't find the device */ if (NextEntry == &(DeviceExtension->DeviceListHead) || !DeviceInformation->ManuallyRegistered) { return; } } /* Then, get device object */ Status = IoGetDeviceObjectPointer(DeviceName, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); if (!NT_SUCCESS(Status)) { return; } DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); KeInitializeEvent(&Event, NotificationEvent, FALSE); /* Set up empty IRP (yes, yes!) */ Irp = IoBuildDeviceIoControlRequest(0, DeviceObject, NULL, 0, NULL, 0, FALSE, &Event, &IoStatusBlock); if (!Irp) { ObDereferenceObject(DeviceObject); ObDereferenceObject(FileObject); return; } Stack = IoGetNextIrpStackLocation(Irp); Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; Irp->IoStatus.Information = 0; /* Properly set it, we want to query device relations */ Stack->MajorFunction = IRP_MJ_PNP; Stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS; Stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation; Stack->FileObject = FileObject; /* And call driver */ Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } ObDereferenceObject(DeviceObject); ObDereferenceObject(FileObject); if (!NT_SUCCESS(Status)) { return; } /* Validate device return */ DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; if (DeviceRelations->Count < 1) { ExFreePool(DeviceRelations); return; } DeviceObject = DeviceRelations->Objects[0]; ExFreePool(DeviceRelations); /* Set up real notification */ DeviceNotification.Version = 1; DeviceNotification.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION); DeviceNotification.Event = GUID_IO_VOLUME_NAME_CHANGE; DeviceNotification.FileObject = NULL; DeviceNotification.NameBufferOffset = -1; /* And report */ IoReportTargetDeviceChangeAsynchronous(DeviceObject, &DeviceNotification, NULL, NULL); ObDereferenceObject(DeviceObject); return; }