Generate port driver Interrupt Interface and used by bus driver

Hi,

I am currently working with PCI hardware that utilizes a WDF bus driver and statically generates serial ports.

I have created a WDF interrupt in the bus driver and verified that the ISR routine moved in from port driver is entered normally.

Since the port driver cannot access the interrupt information, I modified the port driver's ISR routine to use Context instead of Interrupt and MessageID and change it to normal function.
Additionally, I created an interface via WdfDeviceAddQueryInterface to be used by the bus's ISR routine.

Reference: INTERFACEs can contain both input and output parameters…and not just function pointers | Microsoft Learn

I discovered that WdfFdoQueryForInterface cannot be used at the IRQL level in the ISR routine. Consequently, I placed it in the interruptConfig.EvtInterruptEnable callback. However, I encountered an error with WdfFdoQueryForInterface failing with status 0xc00000bb.

I would like to ask if this design is feasible or if I have misunderstood something. Where should WdfFdoQueryForInterface and dereference be placed?

Many thanks.

Best Regards,
Luke Chen

I’d probably put it in EvtDevicePrepareHardware, personally.

But I don’t think I fully understand your question.

More about using bus interfaces here, if that’s helpful:

It would be your bus driver that creates the interface, and the client drivers above it that query for the interface. The client drivers are not going to have ISRs, because they aren't actually handling interrupts. They're just handling notification callbacks from the bus driver. Right?

Hi Peter, Tim,

Many thanks for your reply. I will read the article you suggested carefully.

I think I'm still a little confused about the architecture. The current situation is that I have a combination of WDM bus and port, and I want to try converting it to WDF.

In WDM, the ISR routine is managed by the port driver, which uses some parameters and registers to determine which ports are currently being transmitted (having multiple ports).

However, my current understanding of WDF is that interrupts must be moved to the bus. Therefore, I am considering changing the ISR content of the original port driver into a regular function and creating an interface for the bus driver to use this interface when an interrupt is detected. The expectation is that if it can successfully call the original ISR content of the port driver, some of the port's status and parameters can be directly used.

Since English is not my native language, I might have some misunderstandings. So I would like to ask if the communication of interrupts is as I imagined, or is it generally done by establishing an interface on the bus or in some other way?

Many thanks.

Best Regards,
Luke Chen

Typically a bus driver does nothing more to enumerate the devices connected to it. And if devices could be added or removed dynamically handle that too.

Many multi-port cards (Ethernet, FiberChanel etc.) use a bus driver and expose each port as a separate device. Unless those devices need to co-operate in some way (i.e. 1 interrupt shared between 2 or more ports) the bus driver is usually simple

Thank you, MBonds2, for your reply. I apologize for not explaining clearly earlier. I am currently dealing with a Legacy interrupt, and the 8 serial ports need to share a single interrupt.

Here is my question rephrased:

  1. Is it feasible for the port driver to establish an interface for the bus driver to use?
  2. What is the common approach for handling interrupts between the bus driver and port driver?
  3. If there is only one interrupt, what potential issues might arise from this design?

I am really troubled by the use of interrupts. I have been searching for some time but haven't found relevant samples. I would appreciate any help.

Many thanks.

In general, services should be offered by the lower driver and used by the upper driver, and not the other way around.

If there is only one interrupt, then the upper level drivers don't use the kernel interrupt APIs at all. The bus driver owns and handles the interrupt, and notifies the appropriate port driver using an interface callback or a pended ioctl.

1 Like

Hi Tim,

Sorry, I think I'm a bit stuck and need to clarify a few things. My current understanding of WDF is still that communication between different drivers can only rely on interfaces. Also, from previous responses, I understand that interfaces are initiated by the bus driver for the port driver to use.

Currently, because interfaces are established on the bus, I would need the bus to initiate actions (using functions from the port). However, the port driver cannot establish an interface for the bus to use. How can I achieve communication between the two in this situation? Could you please explain in more detail what behaviors the callback you mentioned might involve? Thank you very much.

Sincerely,
Luke Chen

The interface from your bus driver provides a method for your port driver to register its interrupt callback function. The bus driver then calls that function as appropriate.

There are other details you need to work out, but that is the basic concept.

Mark Roddy

1 Like

Sorry, I have an additional question I would like to ask. If Driver A creates an interface and Driver B queries it, can Driver A get the modified content if Driver B changes the content of a struct within the interface?

For example, there is an INT parameter with a value of 1 in the interface created by Driver A. After Driver B queries it and changes the parameter to 999, can Driver A get this value of 999?

I found in my experiments that this is not possible, but I am not sure if it is because of a mistake in my method or if it is inherently not possible.

Currently, I want to create an interface on the bus, with a struct containing a parameter:

typedef BOOLEAN(*PFN_FUNCTION_ISR)(PVOID Context);
PFN_FUNCTION_ISR IsrCallback;

The port successfully queried the interface and passed the desired ISR function into IsrCallback, but the bus driver cannot use this function.

Many thanks.

Sincerely,
Luke

Look at any of the standard bus interfaces. They provide pointers to functions implemented by the bus driver that you can call.

Your bus interface could provide a pointer to a ‘register isr’ function (and a deregister isr function). The parameters would provide the port driver isr address and some context value.

2 Likes