PCIe to I2C Bridge Windows Driver

@Tim_Roberts said:

Right, because there IS no pre-defined device class for I2C adapters. Any driver you write for this will be a custom device with a custom API.

i2c host controller is not a custom device in Windows 10. i2c host controller is a supported type of device.
SPB Framework Extension (SpbCx)
For example Intel implemented i2c host controller connected to PCIe on Core-i5 based board.

00:15.0 Signal processing controller: Intel Corporation Sunrise Point-LP Serial IO I2C Controller #0 (rev 21)
Subsystem: Intel Corporation Device 7270
Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- SERR- <PERR- INTx-
Interrupt: pin A routed to IRQ 16

Therefore a PCIe card with a proprietary ic2 host controller could be nicely supported by a proper driver into a well formed i2c class device on Windows 10

Yes, well… that’s true. I2C controllers, in general, are backplane bus type devices (supported by PCI.SYS).

However, the issue is that… regardless of how the Controller is interfaced, the Client devices still need to be listed in the ACPI BIOS, because the I2C bus is not dynamically enumerable.

And, as I said earlier… it’s not typically a matter of JUST I2C. I2C (and SPI) connected devices are often designed to connect to one or more GPIOs to allow them to signal conditions.

Anyhow… your project is turning into something that’s feeling far too complicated to reasonably design via forum posts.

Good luck with your project. It’s an interesting one, for sure.

Peter

Hi Peter and others,

Thanks for spending time in helping me out here. Looks like I triggered a ruckus here ;). I am still a fair bit away from understanding the entire Windows driver architecture. I will go through the suggestions and comments from everyone here and try to progress. I will keep you guys updated in case I break through this.

Thanks again for your time :slight_smile:

Ganesh.

HI All,

I am back :slight_smile:

We had a discussion with marketing and finally we agreed that our I2C/SPI drivers need to be compliant to SPB framework and thus it was also agreed to have the ACPI table of the system to be updated to add our device.

Now that this is fixed and done, I have another query. We have a SPI controller on one of the PCIe endpoint as I pointed out earlier. There are 2 instances of the controller in the same PCIe endpoint. So logically it should be 2 SPB controller driver instances with 2 separate set of registers. So I thought of calling the WDFDeviceCreate and SPB related functions twice in the OnDeviceAdd callback function to create 2 separate instances of SPI controller. But the 2nd WDFDeviceCreate is failing since the FxDeviceInit object is not free.

Since this is a PCIe device, we hit the OnDeviceAdd only once upon the device detection but the requirement is to have 2 SPI controller instances registered to the SPB framework.

Is there a simple way to achieve this?

Thanks in advance,
Ganesh

Hmmmm… so, you have a PCIe device, that provides TWO SPI controllers, with separate sets of registers… but ONE PCIe function? Who designed THAT device? Cuz it’s not PCIe compliant. Does the device do anything ELSE?

Is there a simple way to achieve this?

Simple? No. Can it be done? Yes, and it’s not TOO difficult.

You need to write a bus driver that enumerates each of the SPI controllers, and creates one PDO for each. As a result of reporting these PDO during normal PnP processing, the function driver for the controller will be instantiated on each PDO. Hence EvtDriverDeciceAdd in the function driver will be called twice, once for each controller.

With all due respect, if your company’s major goal is for all this to work properly on Windows, I strongly suggest you hire a consultant who understands how all these pieces fit together… before you design and build hardware and try to write drivers that make life difficult. You’ll likely save yourself a ton of time and effort. You don’t know what you don’t know.

Peter

Something around mf.sys with a resource map? Is this still supported on win10?
https://docs.microsoft.com/en-us/windows-hardware/drivers/multifunction/creating-varying-resource-maps

What I don’t understand at all… if SPB devices must have ACPI descriptors - who enumerates them: ACPI or PCI? Or PCI with ACPI as upper filter?

– pa

It’s not clear to me how it is possible to have an SPB device on a PCI bus. SPB is supposed to include I2C, SPI, MIPI, and UART devices, none of which have any PnP capabilities at all, so ACPI is the only way to expose those devices. I’m not convinced that the PCI bus driver knows how to expose an SPB-like device.

@“Peter_Viscarola_(OSR)” said:
Hmmmm… so, you have a PCIe device, that provides TWO SPI controllers, with separate sets of registers… but ONE PCIe function? Who designed THAT device? Cuz it’s not PCIe compliant. Does the device do anything ELSE?

I am not sure if this is PCIe compliant or not but, I have seen similar posts w.r.t many UARTs being shared in the same PCIe function. Isn’t this similar to that?
Yes this device also has a I2C and UART in separate endpoints. So as a whole this is a PCIe multifunction device considering UART, I2C, SPI being present in the same endpoint but having their own config spaces.

You need to write a bus driver that enumerates each of the SPI controllers, and creates one PDO for each. As a result of reporting these PDO during normal PnP processing, the function driver for the controller will be instantiated on each PDO. Hence EvtDriverDeciceAdd in the function driver will be called twice, once for each controller.

So you mean to say its similar to using the mf.sys? Can I use mf.sys here to take care of creating the PDOs for me?

With all due respect, if your company’s major goal is for all this to work properly on Windows, I strongly suggest you hire a consultant who understands how all these pieces fit together… before you design and build hardware and try to write drivers that make life difficult. You’ll likely save yourself a ton of time and effort. You don’t know what you don’t know.

I can certainly convey this message but i think the ship sailed beyond that point.

@Pavel_A said:
Something around mf.sys with a resource map? Is this still supported on win10?
https://docs.microsoft.com/en-us/windows-hardware/drivers/multifunction/creating-varying-resource-maps

So you are saying that I can use the default mf.sys itself for my device?
The documentation regarding the resource map is not that clear. This is my understanding till now:

  1. Provide an inf for mf.sys which contains the actual PCIe HW IDs, MSI interrupts.
  2. Allocate resources to each of the child some resources of the parent in the parent inf. Like BAR0 - 0 - 200 → SPI1, BAR0 200 - 400 SPI2.
  3. Create two child infs for each of the SPI controller. I am not sure what to put in these INFs apart from the pointers to .sys and cat files.

here comes my doubt, we will have only one .sys file, should i create 2 INFs for 2 SPI controllers?
Is my understanding correct?

What I don’t understand at all… if SPB devices must have ACPI descriptors - who enumerates them: ACPI or PCI? Or PCI with ACPI as upper filter?

My understanding is that the enumeration will be done by the PCI driver and the logical connections between SPB controller and SPB peripherals will be maintained by the ACPI.

Thanks,
Ganesh.

I’m not convinced that the PCI bus driver knows how to expose an SPB-like device.

Well, it doesn’t. The OP said in his most recent post that his card has SPB controllers which are typically just standard PCIE backplane bus architecture devices.

if SPB devices must have ACPI descriptors - who enumerates them: ACPI or PCI?

Here, we’re talking about the client devices I assume. The system developer manually creates entries… one per device… is the SSDT. The entries are enumerated by ACPI — ACPI is the enumerator and bus driver for all things SPB. Because devices on the buses are not dynamically discoverable.

you are saying that I can use the default mf.sys itself

Forget about it. Just write a bus driver using KMDF. Enumerate each of the devices on your card. Then the function driver will load for each of those devices. If the I2C and SPI controllers are “standard” controllers, you could use the in-box drivers for those. Which would be good, because writing drivers for those won’t be easy.

This design still isn’t a “done deal.” I’m not sure how you’re going to describe the controllers in the ACPI SSDT. Remember, they need to be described, too.

I’m really not sure how or if this whole project will work… at all. I’m sure there’s a lot that you haven’t told us. If what you’re trying to do is build an add-in card to allow random users to attach I2C or SPI devices to a Windows machine… forget it: That’s not supported by the OS at this point (it should be, but it’s not). I you’re trying to create an add-in card that OEMs would use, say, in a laptop or an embedded system to attach I2C and SPI devices, you might have a chance. But, as I said, I don’t know how you make that work in ACPI — you’ll need someone who knows a lot more about ACPI than I do, that’s for sure, to tell you how to do this.

Peter

@“Peter_Viscarola_(OSR)” said:

you are saying that I can use the default mf.sys itself

Forget about it. Just write a bus driver using KMDF. Enumerate each of the devices on your card. Then the function driver will load for each of those devices. If the I2C and SPI controllers are “standard” controllers, you could use the in-box drivers for those. Which would be good, because writing drivers for those won’t be easy.

Ok. I am yet to go through Windows documentation for writing a bus driver. Any pointers?

This design still isn’t a “done deal.” I’m not sure how you’re going to describe the controllers in the ACPI SSDT. Remember, they need to be described, too.

Yes. I thought of doing it this way:
_DefinitionBlock (“”, “SSDT”, 2, “OEMID”, "SPBSSDT ", 0x00)
{
//PCI port below which our PCIe controller resides
Scope (_SB.PCI0)
{
Device (SPI0)
{
//0x00010003 → device, function number of the PCIe
Name (ADR, 0x00010003)
}
}
}

Won’t this work? This was before this multiple instance issue came up. Will this require a change if we introduce a bus driver in between?

I’m really not sure how or if this whole project will work… at all. I’m sure there’s a lot that you haven’t told us. If what you’re trying to do is build an add-in card to allow random users to attach I2C or SPI devices to a Windows machine… forget it: That’s not supported by the OS at this point (it should be, but it’s not). I you’re trying to create an add-in card that OEMs would use, say, in a laptop or an embedded system to attach I2C and SPI devices, you might have a chance. But, as I said, I don’t know how you make that work in ACPI — you’ll need someone who knows a lot more about ACPI than I do, that’s for sure, to tell you how to do this.

Sorry I forgot to add one more point. we spoke to Marketing team and they conveyed that this PCIe device cannot be a pluggable module. Its present by default in a system upon bootup. So that’s one less problem. Let me give a gist of the product without revealing too much. Its a PCIe device that has one multi-function endpoint where we have UART,SPI,I2C and GPIO controllers. Each of these is an independent function. i.e. they have their own config space. Here in case of SPI alone, there are 2 SPI controller instances shared in the same function.

Also there are cases where we need user apps to directly interact with our controller drivers to control the peripherals beneath I2C/SPI without a peripheral driver. I went through this link which says its feasible through a RHProxy driver:
https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/enable-usermode-access

Understood that even this needs ACPI entry beneath a RHProxy node. Anyway we are fine to go with editing the ACPI table.

What do you think?

Ganesh.

this PCIe device cannot be a pluggable module.

Well, that makes all the difference, actually. That makes this “just another I2C and SPI controller”… which is no big thing.

PCIe device that has one multi-function endpoint where we have UART,SPI,I2C and GPIO controllers.

Wait. One multifunction endpoint? That means it surfaces separate devices for each of the controllers, and this will be automatically handled by the PCI bus driver.

You therefore have no work to do.

Peter

As someone who’s done a fair amount of hooking up strange devices to PC’s, its looking like you’re starting to drift into the weeds a bit (actually your first post was the most clear). I would take a step back and determine

a) what is the target hardware (commercial off the shelf, like a laptop) or customizable (you’ll order something from Wistron or WiPro)
b) what exactly are you trying to accomplish … you’ve mentioned a lot of things here: on the I2C network are you trying to be a master, a slave or a monitor? Same on SPI; master, slave or monitor? GPIO are you trying to read from a GPIO expander (which would mean I2C) or are you really going to have some wires that you can toggle? For UART is this RS232, RS485 or something else and are you going to be a master, a slave or a monitor?
c) what is the end user going to be … is this targeted for a system integrator (who will likely want to interact with this at the device level) or at a user level (something similar to ReadWriteEverything, or the SIV64 display?
d) what is the timeframe that you’re looking at, hours/ days/ weeks/ months?

Generally, I have found that letting a PC be a PC, Windows be Windows and keeping everything at arms length works best. You’ve got several technologies here (I2C, SPI and GPIO) which really aren’t found on regular hardware and you’re asking Windows to do some things that it’s really not designed to do (such as directly accessing hardware) … that all spells trouble, especially when a new version of Windows comes out every six months and you get to retest everything

If I had a similar request (I2C/ SPI/ GPIO/ UART on the back end) I would spec out a PCIe card which would be plugged into an m2 connector (which most motherboards and laptops have) and have two FPGA’s on that: one FPGA for the PCIe IP and one FPGA to handle all of the strange stuff. Write a single KMDF PCIe function driver which can interact with that card and you’re done … that way all of the I2C/ SPI/ GPIO/ UART stuff is handled by the back end FPGA (which is programmed by the front end FPGA, so you can customize it as you wish), the front end FPGA handles the PCIe stuff and all you need to do is expose some BAR’s and interrupts for the KMDF driver to handle as needed …

But again, a clear idea of what you’re wanting to do, what it’s running on and who’s going to be using it will help you immeasurably …

1 Like

You therefore have no work to do.
But he still has two SPIs in one PCIe function. However if ACPI can describe SPB devices as children of given PCI bus/device/function then the ACPI patch is all what is remaining. No tinkering with mf.sys.

But he still has two SPIs in one PCIe function

That’s not clear. Nothing the OP writes is definitively clear, at least to me.

@craig_howard: The OPs requirements seem to have evolved very dramatically since his initial post. Last we heard, he now had a multifunction PCIe endpoint that was permanently attached to the main board that provided one SPI, one I2C, one UART and one GPIO controller. Or, that’s what I understand at least. I can’t exactly envision what that would look like, or how it would get permanently attached, but perhaps that’s from my lack of experience as a system builder.

Peter

@“Peter_Viscarola_(OSR)” said:

But he still has two SPIs in one PCIe function

That’s not clear. Nothing the OP writes is definitively clear, at least to me.

@craig_howard: The OPs requirements seem to have evolved very dramatically since his initial post. Last we heard, he now had a multifunction PCIe endpoint that was permanently attached to the main board that provided one SPI, one I2C, one UART and one GPIO controller. Or, that’s what I understand at least. I can’t exactly envision what that would look like, or how it would get permanently attached, but perhaps that’s from my lack of experience as a system builder.

Sorry for not being clear. I think I dint have the clarity when I first started this thread. But right now I have more clarity on what is needed. Let me list it down by answering @craig_howard’s questionnaire

a) what is the target hardware (commercial off the shelf, like a laptop) or customizable (you’ll order something from Wistron or WiPro)

Ours is a PCIe switch that’s going to be plugged into embedded board like imx.8 which has PCIe slot (M.2 I think). So most likely Windows IoT could be flavor. It has one PCIe Downstream Port and one PCIe multifunction endpoint which has 4 separate functions (4 separate config space for each function).
DS Port 0 : PCIe DS port
DS Port 1: 4 Functions
Function 1: one UART
Function 2: one I2C controller
Function 3: two SPI controllers
Function 4: GPIO controller.

b) what exactly are you trying to accomplish … you’ve mentioned a lot of things here: on the I2C network are you trying to be a master, a slave or a monitor? Same on SPI; master, slave or monitor? GPIO are you trying to read from a GPIO expander (which would mean I2C) or are you really going to have some wires that you can toggle? For UART is this RS232, RS485 or something else and are you going to be a master, a slave or a monitor?

I2C → Master controller
SPI → Master controller
UART → I guess its RS485
GPIO → Generic GPIO controller that exposes around 60 GPIOs.

c) what is the end user going to be … is this targeted for a system integrator (who will likely want to interact with this at the device level) or at a user level (something similar to ReadWriteEverything, or the SIV64 display?

There are 2 use cases:

  1. There can be other kernel peripheral drivers that can use our Master Controllers to control their peripherals. example: connecting a I2C temperature sensor or a SPI based LCD display.
  2. There will be no kernel peripheral drivers. The user space application will directly send commands to our controller drivers to control anything that is connected. Example : Connecting a I2C eeprom and sending commands from user space to program that EEPROM. We know that native SPBCx doesn’t allow that but we came across this below link that helps us achieve this.
    https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/enable-usermode-access

d) what is the timeframe that you’re looking at, hours/ days/ weeks/ months?

May be next 3 months

Generally, I have found that letting a PC be a PC, Windows be Windows and keeping everything at arms length works best. You’ve got several technologies here (I2C, SPI and GPIO) which really aren’t found on regular hardware and you’re asking Windows to do some things that it’s really not designed to do (such as directly accessing hardware) … that all spells trouble, especially when a new version of Windows comes out every six months and you get to retest everything

I dont have an answer for this.

Question 1:
W.r.t I2C, UART, GPIO controllers we are not using the Mf.sys for the multifunction devices even though we are compliant at this level to PCI multi-function standard. I don’t see any advantage of using Mf.sys for the UART,I2C, SPI, GPIO controllers. What’s the need to use Mf.sys at this level? Can’t we live without that?

Question 2:
With respect to the I2C, UART, GPIO controllers I dont have any issues since these are one instance and I can register them as normal drivers.
So the trouble I have here is with the SPI controller. Since there are 2 SPI controllers on a single config space, I am finding it difficult to enable these 2 SPI controllers upon a single EvtDriverDeviceAdd callback.
For this,
Suggestion from Peter was to write a bus driver on top this SPI controller and enumerate each of the SPI controller.
Suggestion from Pavel was to use the mf.sys and use Varying resource map as mentioned in
https://docs.microsoft.com/en-us/windows-hardware/drivers/multifunction/creating-varying-resource-maps

With this description in mind, is there a clear pointer for me?

Is there anymore ambiguity? I can explain specific things better if needed.

Thanks,
Ganesh.

MUCH more clear. Thank you.

Yay for supporting the i.MX SoC! Long live NXP! Do they (NXP) even still support Windows IoT core?

Forget about my.sys, which is old junk… just write a bus driver for the SPI function. It should be reasonably simple, relative to everything else you’re doing, and assuming the register sets are separate.

If you have to write your own controller drivers for these devices, that will be a bit difficult. I’m not aware of any examples available.

But as I said: If the SPI, I2C, and GPIO controllers use standard register layouts… there’s probably already a driver written for them… and you won’t have to write it yourself.

Peter

Hi Peter,

Forget about my.sys, which is old junk… just write a bus driver for the SPI function. It should be reasonably simple, relative to everything else you’re doing, and assuming the register sets are separate.

Thank you for pointing me in the right direction. I am pretty new to Windows so have little to no experience w.r.t bus drivers. From my understanding following are the responsibilities of the bus driver:

  1. Since this is a PCIe device, the bus driver’s EvtDeviceAdd would be called upon device attach.
  2. Need to create PDOs for the 2 SPI controllers.
  3. I would get the PCIe BAR resources in the bus driver.
  4. Need to allocate some part of the BAR to SPI controller 1 and another part to SPI controller 2.
  5. Similarly interrupts MSI interrupts need to be allocated.

Following are my questions:

  1. How and when does the child devices’ EvtDeviceAdd would be called?
  2. How the linkage between the bus driver and the child driver occurs.
  3. Also I have little confusion how the INFs of the bus driver and the SPI child devices would be.

Is there a sample driver that I can refer for this? That would be really helpful.

  1. Need to allocate some part of the BAR to SPI controller 1 and another part to SPI controller 2.
    You would need to do this allocation internally. You should not be reporting these as hardware resource requirements to pnp,

Following are my questions:

  1. How and when does the child devices’ EvtDeviceAdd would be called?
    PDOs do not have EvtDeviceAdd called. If you are using a static WDFCHILDLIST (you should) you create and initialize them whenver is appropriate. You can do this in the parent’s EvtDeviceAdd
  1. How the linkage between the bus driver and the child driver occurs.
    The linkage occurs naturally by creating the child WDFDEVICEs

How and when does the child devices’ EvtDeviceAdd would be called?

As Doron noted, it’s not called in the BUS driver… The child device’s EvtDriverDeviceAdd Event Processing Callback is called in the FUNCTION driver when it is loaded on top of the PDO that your Bus Driver creates, and it (the FUNCTION driver) subsequently creates the FDO.

Is there a sample driver that I can refer for this

I know that the “Toaster” series of samples in the WDK has a sample bus driver. I’ve never reviewed it… I just know it exists. But it’ll at least give you a place to start.

You could do Static Enumeration with this bus driver… though, frankly, it doesn’t save you much effort.

Peter

@“Peter_Viscarola_(OSR)” said:
MUCH more clear. Thank you.

Yay for supporting the i.MX SoC! Long live NXP! Do they (NXP) even still support Windows IoT core?

They were, iMX7 was supported at least in 2020