UMDFv2 ACPI driver example

Hi,
my collegue and me are trying to implement a UMDFv2 driver able to communicate with an ACPI device (in particular to interpose it into the driver stack above an existing driver for the device).

We have looked around for an example of UMDFv2 ACPI driver but we are able only to find KMDF drivers. We already have a UMDFv2 driver able to load for the specific device (not stacked however...) but we are not able to send ACPI commands to the device because the documentation about this topic is missing. Do you know any resource about this specific topic? We ha implemented a IOCTL like this one but it does not work

case IOCTL_ACPINJECTOR_SIMPLE_INTEGER: {
		DbgPrintEx(0, 0, "ACPInjector: Executing IOCTL PING...\n");

		WDFDEVICE device = WdfIoQueueGetDevice(Queue);
		WDFIOTARGET device_target = WdfDeviceGetIoTarget(device);
		
		WDF_IO_TARGET_OPEN_PARAMS device_target_open_params;
		WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_FILE(&device_target_open_params, NULL);

		status = WdfIoTargetOpen(device_target, &device_target_open_params);

		if (!NT_SUCCESS(status)) {
			DbgPrintEx(0, 0, "ACPInjector: WdfIoTargetOpen failed (error 0x%x).\n", status);
			goto end;
		}

		ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER acpi_input;
		ACPI_EVAL_OUTPUT_BUFFER acpi_output = { 0 };

		WDF_MEMORY_DESCRIPTOR acpi_input_mem_desc;
		WDFMEMORY acpi_input_mem = NULL;
		ULONG acpi_input_size = sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER);

		status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES, PagedPool, ACPI_INJECTOR_POOL_TAG, acpi_input_size, &acpi_input_mem, (PVOID*)&acpi_input);

		if (!NT_SUCCESS(status)) {
			DbgPrintEx(0, 0, "ACPInjector: Retrieve output buffer failed.\n");
			goto end_acpi;
		}

		acpi_input.Signature = ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE;
		acpi_input.MethodNameAsUlong = (ULONG)'TPFN';
		acpi_input.IntegerArgument = 0;

		DbgPrintEx(0, 0, "Method name as ulong: 0x%x.\n", 'TPFN');

		WDF_MEMORY_DESCRIPTOR acpi_output_mem_desc;


		WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&acpi_input_mem_desc, acpi_input_mem, 0);

		WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&acpi_output_mem_desc, &acpi_output, sizeof(acpi_output));

		ULONG acpi_res;
		status = WdfIoTargetSendIoctlSynchronously(
			device_target,
			WDF_NO_HANDLE,
			IOCTL_ACPI_EVAL_METHOD_EX,
			&acpi_input_mem_desc,
			&acpi_output_mem_desc,
			NULL,
			(PULONG_PTR)  & acpi_res
		);

		if (!NT_SUCCESS(status)) {
			DbgPrintEx(0, 0, "ACPInjector: SendIoctlSynchronously failed: 0x%x (0x%x).\n", status, GetLastError());
			goto end_acpi;
		}

		DbgPrintEx(0, 0, "ACPInjector: ABC Executing IOCTL ACPI Integer Simple Done.\n");

	end_acpi:
		WdfIoTargetClose(device_target);

		break;
	}

Where, exactly, is your driver in the driver stack? To send ACPI ioctls, you have to send them to the PDO of the APCI device itself.

Also, remember that you don't want to have a driver stack that goes kernel -> user -> kernel. That used to be forbidden. I believe it's allowed in some circumstances, but the performance penalty is considerable as you do so many transitions.

I want to put my UMDFv2 driver on top of an existing driver (my driver -> existing driver -> kernel -> device).

You have to send those ioctls to the ACPI driver. You can't have another function driver in between. Is that where you are? If so, what you're doing should basically work.

Ok, I'm a little bit confused. What we want to do is to send ACPI command to a device which is already assigned to a KMDF driver using a UMDFv2 driver stacked in some way (maybe a UMDFv2 filter driver?). Is it possible in your opinion?

Not easily. As I said, to send ACPI ioctls, you have to be talking to the PDO created by acpi.sys, since that's the entity that handles those ioctls. That means you need to be a filter driver just above acpi.sys or just below the function driver for the device.

Originally, for performance reasons, once a driver stack flipped to user mode it had to stay in user mode. I think some of that has been eased, but it's still going to have performance impact.

Since UMDFv2 and KMDF are practically the same, why not do it in KMDF?

You mean that is not suggested to mix user and kernel driver stacks for performance reasons or that is forbidden by the OS architecture? (Sorry we came from Linux world and we are not experts of Windows internals)

I mean originally it was prohibited. Today, I believe it is possible, but there is performance impact to consider, if this is a device that gets many requests.