GPIO controller driver with PMIO registers

Hi All,

I am developing a WDF GPIO controller driver for our own ACPI GPIO. However, the ACPI document about the GPIO pins are all marked as PMIO instead of MMIO.

Our Linux team uses inb/outb to read/write the registers. I am wondering how the WDF GPIO controller driver read/write such registers.

From the sample code, the GPIO controller driver would read/write GPIO registers in the way CmResourceTypeMemory and CmResourceTypeCollection. In my case, I think CmResourceTypeCollection would be returned by calling WdfCmResourceListGetDescriptor. Do I need to call READ_PORT_*** API to read the registers?

Thanks,
Marshall

You should be able to do something like this:

   // Walk through the resource list and store each GPIO in `pDevExt->ConnectionIds`.
   resource_count = WdfCmResourceListGetCount(ResourcesTranslated);
   for (index = 0; index < resource_count; ++index)
   {
      descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, index);
      switch (descriptor->Type) 
      {
         // This memory resource supplies the base of the device registers.
         case CmResourceTypeConnection:
            //  Check against expected connection type
            if ((descriptor->u.Connection.Class ==
               CM_RESOURCE_CONNECTION_CLASS_GPIO) &&
               (descriptor->u.Connection.Type ==
                  CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)) 
            {
               pDevExt->ConnectionIds[io_resource_index].LowPart =
                  descriptor->u.Connection.IdLowPart;
               pDevExt->ConnectionIds[io_resource_index].HighPart =
                  descriptor->u.Connection.IdHighPart;
            }
           break;
         default:
           break;
     }
  }

Then when you want to read/write from one you’ll need to find the RESOURCE_HUB request string for the GPIO by doing something like:

   // Find the RESOURCE_HUB request string for this GPIO pin
   RtlInitEmptyUnicodeString(&resource_string,
      resource_string_buffer,
      sizeof(resource_string_buffer));

   status = RESOURCE_HUB_CREATE_PATH_FROM_ID(
      &resource_string,
      pDevExt->ConnectionIds[pin_number].LowPart,
      pDevExt->ConnectionIds[pin_number].HighPart);

Once you have the request string you’ll have to open the IoTarget by name with WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME.
From there you can use WdfIoTargetFormatRequestForIoctl with the IOCTL_GPIO_READ_PINS/IOCTL_GPIO_WRITE_PINS ioctls do the equivalent of your Linux teams inb/outb IO.
Once you’ve formated the request you can use WdfRequestSend to send it.

1 Like

It is difficult for me to believe that any modern product is still using the x86 I/O ports. How do you even handle that on an ARM system that doesn’t have the special instructions?

1 Like