Question

rohit_12 on Tue, 22 May 2018 18:32:57


Hi,

I'm trying to develop a Peripheral driver for an SerCx2 based controller driver to use the High-Speed UART interface on and Intel Atom E3845 based platform.

The driver is able to install as a legacy device and I see a new port, COM10 in the device manager. However, any attempts to use this port (in ExtraPutty, TeraTerm etc.) lead to an error in accessing the device.

Using WPP Tracing, I found that the size of ResourcesRaw and ResourcesTranslated list passed to the EVT_WDF_DEVICE_PREPARE_HARDWARE callback function was 0. 

I'm not sure what is happening or where to specify the resources my driver is supposed to be used for. The ACPI table and the INF file look okay to me and I see a node for the UART controller in the device tree. I know the hardware works because  I was able to use Resource Hub Proxy to test the communication on that port without using the peripheral driver.

How does WDF/PnPManager know which resources are to be assigned to the driver?

Any tips/suggestions/advice is really appreciated.

Thanks & Regards,

Rohit


Sponsored



Replies

Doron Holan [MSFT] on Tue, 22 May 2018 20:35:50


How did you install the driver? If you used devcon install it created a root enumerated device without resources and you need to use devcon update instead.

rohit_12 on Tue, 22 May 2018 20:59:08


Thanks for responding, what you described matches pretty closely to what I'm observing.

I had to install it using the "Action -> Add Legacy hardware" menu in the device manager because clicking on install from the right-click menu of the inf file didn't seem to do anything.

When using devcon update to do the install, it fails with the error (C:\WINDOWS\INF\setupapi.dev)

    ndv: Install flags: 0x00000001  

    ndv: Unable to find any matching devices."

Also, no matter how I install it, the installed device shows up at the root level when I click "View-> view Devices by Connection" in the device manager.

-Rohit

Doron Holan [MSFT] on Wed, 23 May 2018 03:20:24


Add legacy hardware creates a root device too. You need to match on the hardware id of the controller in your inf if you want the controller resources in your driver. IOW you need to replace the driver which owns them on the pnp device itself.

rohit_12 on Wed, 23 May 2018 13:00:11


Thanks, that makes sense, adding the legacy hardware just creates a root device regardless of the hwid in the INF file.

However, the driver I'm trying to get working is meant to be a peripheral driver that interfaces with UART Controller driver to allow communication on HS-UART ports. Shouldn't I be using the HWID of my peripheral that's declared under the controller in the ACPI table?

I thought the ACPI table will be enough to make sure the Peripheral driver shows up as a child of the Controller driver.

Thanks & Regards,

Rohit

Doron Holan [MSFT] on Wed, 23 May 2018 18:18:24


yes, you should use the HWID as described in the ACPI table.  From what I remember about this type of driver, you don't get the controller resources assigned to your driver, rather you must open the resource hub and ask for access to these resources at runtime.

rohit_12 on Wed, 23 May 2018 20:49:17


Thanks, yes, I believe my driver is using Resource Hub to access the port. It's passed 2 Resource Lists by the Plug and Play Manager in the EVT_WDF_DEVICE_PREPARE_HARDWARE call, which it then parses to find the Serial/UART and interrupt resources it's been assigned. Then, it generates the Device Path for the Serial Resources using the RESOURCE_HUB_CREATE_PATH_FROM_ID call.

The trouble is, the Resource Lists I'm getting are empty. I'm not sure how to get the plug and play manager to assign the resources to my driver.

Also, I've been plenty of samples for controller drivers, but I haven't been able to find any samples for any UMDF serial peripheral drivers that connect to an SerCx2 based UART controller. 

Thanks & Regards,

Rohit

Doron Holan [MSFT] on Wed, 23 May 2018 22:17:27


something is not quite right in your ACPI table if the described resources are not being included in your resource list

PeterGV on Thu, 24 May 2018 11:58:34


I agree with what Doron wrote about your ASL probably not being correct.  Getting the ASL written and installed is typically the "weakest link" in folks getting SPB/Async/GPIO connected devices working, in my experience.  There isn't enough documentation, there aren't enough good examples, and people who understand and work with ACPI are... ah... neither numerous nor typically gifted with knowledge that's both broad and deep.

So, just to be sure: You're specifically setting up this device in your ASL, right?  That is, you're not using the default ASL and/or setting it up in the ASL to be a traditional PC serial port?

Can you post the ASL that you're using to describe your device, please?  MAYBE we can go from there.

Peter
OSR
@OSRDrivers
http://www.osr.com

rohit_12 on Thu, 24 May 2018 13:28:51


Thanks for responding. Here's the ACPI table. Please let me know if anything stands out and you have any suggestions.

I think it's pretty much the same as Intel's default table for this processor, with additional nodes included to support Resource Hub Proxy.

//
// HS-UART #1
//
Device(URT1)
{
  Name (_ADR, 0)
  Name (_HID, "80860F0A")
  Name (_CID, "80860F0A")
  Name (_DDN, "Intel(R) HS-UART Controller #1 - 80860F0A")
  Name (_UID, 1)

  Name (RBUF, ResourceTemplate ()
  {
    Memory32Fixed (ReadWrite, 0x00000000, 0x00001000, BAR0)

    Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive, , , ) {39}  // HS-UART #1 IRQ

    FixedDMA(0x2, 0x2, Width32Bit, )
    FixedDMA(0x3, 0x3, Width32Bit, )
  })

  Method (_HRV, 0x0, NotSerialized)
  {
    Return (SOCS)
  }

  Method (_CRS, 0x0, NotSerialized)
  {
    CreateDwordField(^RBUF, ^BAR0._BAS, B0BA)
    CreateDwordField(^RBUF, ^BAR0._LEN, B0LN)
    Store(U10A, B0BA)
    Store(U10L, B0LN)
    Return (RBUF)
  }

  Method (_STA, 0x0, NotSerialized)
  {
    If (LOr(LEqual(U10A, 0), LEqual(L13D, 1)))
    {
      Return (0x0)
    }
    Return (0xF)
  }

  Method (_PS3, 0, NotSerialized)
  {
    OR(PSAT, 0x00000003, PSAT)
    OR(PSAT, 0X00000000, PSAT)
  }

  Method (_PS0, 0, NotSerialized)
  {
    And(PSAT, 0xfffffffC, PSAT)
    OR(PSAT, 0X00000000, PSAT)
  }

  OperationRegion (KEYS, SystemMemory, U11A, 0x100)
  Field (KEYS, DWordAcc, NoLock, WriteAsZeros)
  {
    Offset (0x84),
           PSAT,   32
  }

  Device (VUT1)
  {
    Name (_HID, "INT3511")

    Method (_STA, 0x0, NotSerialized)
    {
      If(LEqual(HLPS, 0))
      {
        Return(0x0)
      }
      Return(0xF)
    }

    Method(_CRS, 0x0, NotSerialized)
    {
      Name(SBUF, ResourceTemplate ()
      {
        UARTSerialBus(115200,       // InitialBaudRate: in bits ber second
                      ,             // BitsPerByte: default to 8 bits
                      ,             // StopBits: Defaults to one bit
                      0xFC,         // LinesInUse: 8 1-bit flags to declare line enabled
                      ,             // IsBigEndian: default to LittleEndian
                      ,             // Parity: Defaults to no parity
                      ,             // FlowControl: Defaults to no flow control
                      32,           // ReceiveBufferSize
                      32,           // TransmitBufferSize
                      "\\_SB.URT1", // ResourceSource: UART bus controller name
                      ,)            // DescriptorName: creates name for offset of resource descriptor
      })
      Return (SBUF)
    }
  }
}

//
// LPIO1 HS-UART #2
//
Device(URT2)
{
  Name (_ADR, 0)
  Name (_HID, "80860F0A")
  Name (_CID, "80860F0A")
  Name (_DDN, "Intel(R) HS-UART Controller #2 - 80860F0C")
  Name (_UID, 2)

  Name (RBUF, ResourceTemplate ()
  {
    Memory32Fixed (ReadWrite, 0x00000000, 0x00001000, BAR0)

    Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive, , , ) {40}  // HS-UART #2 IRQ

    FixedDMA(0x4, 0x4, Width32Bit, )
    FixedDMA(0x5, 0x5, Width32Bit, )
  })

  Method (_HRV, 0x0, NotSerialized)
  {
    Return (SOCS)
  }

  Method (_CRS, 0x0, NotSerialized)
  {
    CreateDwordField(^RBUF, ^BAR0._BAS, B0BA)
    CreateDwordField(^RBUF, ^BAR0._LEN, B0LN)
    Store(U20A, B0BA)
    Store(U20L, B0LN)
    Return (RBUF)
  }

  Method (_STA, 0x0, NotSerialized)
  {
    If (LOr(LEqual(U20A, 0), LEqual(L14D, 1)))
    {
      Return (0x0)
    }
    Return (0xF)
  }

  Method (_PS3, 0, NotSerialized)
  {
    OR(PSAT, 0x00000003, PSAT)
    OR(PSAT, 0X00000000, PSAT)
  }

  Method (_PS0, 0, NotSerialized)
  {
    And(PSAT, 0xfffffffC, PSAT)
    OR(PSAT, 0X00000000, PSAT)
  }

  OperationRegion (KEYS, SystemMemory, U21A, 0x100)
  Field (KEYS, DWordAcc, NoLock, WriteAsZeros)
  {
    Offset (0x84),
           PSAT,   32
  }

  Device (VUT2)
  {
    Name (_HID, "INT3512")
    Method (_STA, 0x0, NotSerialized)
    {
      If(LEqual(HLPS, 0))
      {
        Return(0x0)
      }
      Return(0xF)
    }

    Method(_CRS, 0x0, NotSerialized)
    {
      Name(SBUF, ResourceTemplate ()
      {
        UARTSerialBus(115200,       // InitialBaudRate: in bits ber second
                      ,             // BitsPerByte: default to 8 bits
                      ,             // StopBits: Defaults to one bit
                      0xFC,         // LinesInUse: 8 1-bit flags to declare line enabled
                      ,             // IsBigEndian: default to LittleEndian
                      ,             // Parity: Defaults to no parity
                      ,             // FlowControl: Defaults to no flow control
                      32,           // ReceiveBufferSize
                      32,           // TransmitBufferSize
                      "\\_SB.URT2", // ResourceSource: UART bus controller name
                      ,)            // DescriptorName: creates name for offset of resource descriptor
      })
      Return (SBUF)
    }
  }
}

Device(IOTD)
{
  Name(_HID, "MSFT8000")
  Name(_CID, "MSFT8000")
  
  Name(_CRS, ResourceTemplate()
  {
    // Index 0 
    SPISerialBus(          // SPI device
      1,                     // Device selection
      PolarityLow,           // Device selection polarity
      FourWireMode,          // wiremode
      8,                     // databit len
      ControllerInitiated,   // slave mode
      8000000,               // Connection speed
      ClockPolarityLow,      // Clock polarity
      ClockPhaseSecond,      // clock phase
      "\\_SB.SPI1",          // ResourceSource: SPI bus controller name
      0,                     // ResourceSourceIndex
      ResourceConsumer,      // Resource usage
      JSPI,                  // DescriptorName: creates name for offset of resource descriptor
      )                      // Vendor Data  
    
    // Index 1
    I2CSerialBus(          // I2C0 device
      0x00,                  // SlaveAddress: bus address (TBD)
      ,                      // SlaveMode: default to ControllerInitiated
      400000,                // ConnectionSpeed: in Hz
      ,                      // Addressing Mode: default to 7 bit
      "\\_SB.I2C1",          // ResourceSource: I2C bus controller name
      ,
      ,
      JIC1,                  // Descriptor Name: creates name for offset of resource descriptor
      )                      // VendorData
    
    // Index 2     
    I2CSerialBus(          // I2C1 device
      0x00,                  // SlaveAddress: bus address (TBD)
      ,                      // SlaveMode: default to ControllerInitiated
      400000,                // ConnectionSpeed: in Hz
      ,                      // Addressing Mode: default to 7 bit
      "\\_SB.I2C2",          // ResourceSource: I2C bus controller name
      ,
      ,
      JIC2,                  // Descriptor Name: creates name for offset of resource descriptor
      )                      // VendorData
    
    // Index 3     
    I2CSerialBus(          // I2C2 device
      0x00,                  // SlaveAddress: bus address (TBD)
      ,                      // SlaveMode: default to ControllerInitiated
      400000,                // ConnectionSpeed: in Hz
      ,                      // Addressing Mode: default to 7 bit
      "\\_SB.I2C3",          // ResourceSource: I2C bus controller name
      ,
      ,
      JIC3,                  // Descriptor Name: creates name for offset of resource descriptor
      )                      // VendorData
    
    // Index 4     
    I2CSerialBus(          // I2C3 device
      0x00,                  // SlaveAddress: bus address (TBD)
      ,                      // SlaveMode: default to ControllerInitiated
      400000,                // ConnectionSpeed: in Hz
      ,                      // Addressing Mode: default to 7 bit
      "\\_SB.I2C4",          // ResourceSource: I2C bus controller name
      ,
      ,
      JIC4,                  // Descriptor Name: creates name for offset of resource descriptor
      )                      // VendorData
    
    // Index 5     
    I2CSerialBus(          // I2C4 device
      0x00,                  // SlaveAddress: bus address (TBD)
      ,                      // SlaveMode: default to ControllerInitiated
      400000,                // ConnectionSpeed: in Hz
      ,                      // Addressing Mode: default to 7 bit
      "\\_SB.I2C5",          // ResourceSource: I2C bus controller name
      ,
      ,
      JIC5,                  // Descriptor Name: creates name for offset of resource descriptor
      )                      // VendorData
    
    // Index 6     
    I2CSerialBus(          // I2C5 device
      0x00,                  // SlaveAddress: bus address (TBD)
      ,                      // SlaveMode: default to ControllerInitiated
      400000,                // ConnectionSpeed: in Hz
      ,                      // Addressing Mode: default to 7 bit
      "\\_SB.I2C6",          // ResourceSource: I2C bus controller name
      ,
      ,
      JIC6,                  // Descriptor Name: creates name for offset of resource descriptor
      )                      // VendorData
    
    // Index 7     
    I2CSerialBus(          // I2C6 device
      0x00,                  // SlaveAddress: bus address (TBD)
      ,                      // SlaveMode: default to ControllerInitiated
      400000,                // ConnectionSpeed: in Hz
      ,                      // Addressing Mode: default to 7 bit
      "\\_SB.I2C7",          // ResourceSource: I2C bus controller name
      ,
      ,
      JIC7,                  // Descriptor Name: creates name for offset of resource descriptor
      )                      // VendorData

    // Index 8
    UARTSerialBus(         // HSUART0 device
      115200,                // InitialBaudRate: in bits ber second
      ,                      // BitsPerByte: default to 8 bits
      ,                      // StopBits: Defaults to one bit
      0xfc,                  // LinesInUse: 8 1-bit flags to declare line enabled
      ,                      // IsBigEndian: default to LittleEndian
      ,                      // Parity: Defaults to no parity
      ,                      // FlowControl: Defaults to no flow control
      32,                    // ReceiveBufferSize
      32,                    // TransmitBufferSize
      "\\_SB.URT1",          // ResourceSource: UART bus controller name
      ,
      ,
      UAR1,                  // DescriptorName: creates name for offset of resource descriptor
      )                      
    
    // Index 9
    UARTSerialBus(         // HSUART1 device
      115200,                // InitialBaudRate: in bits ber second
      ,                      // BitsPerByte: default to 8 bits
      ,                      // StopBits: Defaults to one bit
      0xfc,                  // LinesInUse: 8 1-bit flags to declare line enabled
      ,                      // IsBigEndian: default to LittleEndian
      ,                      // Parity: Defaults to no parity
      ,                      // FlowControl: Defaults to no flow control
      32,                    // ReceiveBufferSize
      32,                    // TransmitBufferSize
      "\\_SB.URT2",          // ResourceSource: UART bus controller name
      ,
      ,
      UAR2,                  // DescriptorName: creates name for offset of resource descriptor
      )                      
  })
    
  Name(_DSD, Package()
  {
    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
    Package()
    {
      // SPI Mapping
      Package(2) { "bus-SPI-SPI0", Package() { 0 } },
      Package(2) { "SPI0-MinClockInHz", 100000 },
      Package(2) { "SPI0-MaxClockInHz", 15000000 },
      Package(2) { "SPI0-SupportedDataBitLengths", Package() { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 } },

      // I2C Mappings
      Package(2) { "bus-I2C-I2C0", Package() { 1 } },
      Package(2) { "bus-I2C-I2C1", Package() { 2 } },
      Package(2) { "bus-I2C-I2C2", Package() { 3 } },
      Package(2) { "bus-I2C-I2C3", Package() { 4 } },
      Package(2) { "bus-I2C-I2C4", Package() { 5 } },
      Package(2) { "bus-I2C-I2C5", Package() { 6 } },
      Package(2) { "bus-I2C-I2C6", Package() { 7 } },

      // HS-UART Mappings
      Package(2) { "bus-UART-UART1", Package() { 8 } },
      Package(2) { "bus-UART-UART2", Package() { 9 } },
    }
  })
}

Thanks & Regards,

Rohit

PeterGV on Thu, 24 May 2018 20:49:17


Hmmmmm...

OK... so this is IoT we're talking about, right?  Not a Windows Desktop system?

Let me start by saying that I am not an ACPI wizard, I merely know enough to get by. But... 

Are you trying to expose these resources to usermode?  If so, they're going to be claimed by RhProxy and not by some other driver, right?

I spent quite a bit of time looking at this;  A lot of it looks like it comes directly from the examples (which is not a bad thing, necessarily).  But I'm sorry to say I just don't know enough to say something here is wrong.  It's not exactly the way *I* would have written it, but I can't say it's incorrect.  For example, technically, the HID for the device shouldn't be "MSFT8000"... the CID should be, and the HID should be something unique to you.  But, that definitely isn't your problem.

You've got the RHP stuff there, and it *looks* to me like the indexes in the DSD (8 and 9) match.

Sorry I can't be more help.  I'm a bit confused by what you're trying to do, but that could be because my direct experience with surfacing non-traditional PC serial-port connected devices is limited.


Peter

OSR

@OSRDrivers -- http://www.osr.com

Designers, implementers, and teachers of Windows drivers for more than 20 years


rohit_12 on Thu, 24 May 2018 21:41:37


Thank you so much Peter.

The MSFT8000 node pretty much came straight out of Microsoft's example to declare the ACPI node for Resource Hub Proxy (link [1]), but I can tweak it with your recommendation. The way we have it right now seems to work for I2C but the HS-UART won't receive more than 64 bytes of data.

So I switched to using a UMDF peripheral driver that interfaces with Intel's SerCX2 driver and exposes the port to User applications. The UMDF driver is where I'm having these issues. 

I have also tried removing the UART declaration from the MSFT8000 node, in case it was conflicting with my UMDF driver, but didn't see any difference in behavior.

I'm pretty much out of ideas and would really appreciate if you had any pointers or areas I can look at to see what's going on.

Thanks & Regards,

Rohit

[1]:https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/enable-usermode-access

PeterGV on Thu, 24 May 2018 23:55:18


Yes... But you realize that IF the device is available to user mode (that is, like available to access from C#)... the device will be claimed by RHP. So, the device resources will NOT be available to your driver. One device can’t be claimed simultaneously by two drivers (your UMDF druver and RHProxy). Could that be what’s happening?

Peter OSR @OSRDrivers -- http://www.osr.com Designers, implementers, and teachers of Windows drivers for more than 20 years