SetupDiGetDeviceInterfaceDetail Function & DevicePath

I am creating a DLL to utilize the Intel I2C Driver for the Atom E3800 processor. This will allow me to access devices on the specific I2C bus.

Everything appears to be working as expected until I try to execute CreateFile with the path provided by the SetupDiGetDeviceInterfaceDetail function. The DevicePath provided by this call is:

L"\\?\pci#ven_8086&dev_0f41&subsys_72708086&rev_11#3&11583659&0&c1#{4d36e97d-e325-11ce-bfc1-08002be10318}"

In device manager the Device Instance Path is
PCI\VEN_8086&DEV_0F41&SUBSYS_72708086&REV_11\3&11583659&0&C1

These obviously do not match. Questions:

  1. Should they match?
  2. Do I need to manipulate the DevicePath? According to MSDN, I should not have to.
  3. Am I missing something?

Here is the code in question:

while (SetupDiEnumDeviceInfo(DeviceInfoSet, Index, &DeviceInfoData))
{
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
SetupDiCreateDeviceInterface(DeviceInfoSet, &DeviceInfoData, &DeviceInfoData.ClassGuid, NULL, 0, &DeviceInterfaceData);

// call the first time to get required buffer size
SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &DeviceInterfaceData, NULL, 0, &requiredSize, NULL);

// allocate required buffer
if ((DeviceInterfaceDetailData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(requiredSize)) == NULL)
{
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return status = INSUFFICIENT_MEMORY;
}

// call the second time to get detailed info
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &DeviceInterfaceData, DeviceInterfaceDetailData, requiredSize, 0, &DeviceInfoData);

// check for i2c controller #1
if(wcsstr(DeviceInterfaceDetailData->DevicePath, i2cDevice) != NULL)
break;

Index++;
}

tempHandle = CreateFile(DeviceInterfaceDetailData->DevicePath,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);

Thanks.

I should have mentioned that I get a ERROR_FILE_NOT_FOUND error code when the CreateFile call fails.

1 no they shouldn’t match
2 no, you don’t need to alter the string
3 you should be checking the return value from SetupDiGetDeviceInterfaceDetail both times

Are you sure the driver allows handles to be open against it?

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@winsystems.com xxxxx@lists.osr.com
Sent: Monday, August 7, 2017 12:59 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] SetupDiGetDeviceInterfaceDetail Function & DevicePath

I am creating a DLL to utilize the Intel I2C Driver for the Atom E3800 processor. This will allow me to access devices on the specific I2C bus.

Everything appears to be working as expected until I try to execute CreateFile with the path provided by the SetupDiGetDeviceInterfaceDetail function. The DevicePath provided by this call is:

L"\\?\pci#ven_8086&dev_0f41&subsys_72708086&rev_11#3&11583659&0&c1#{4d36e97d-e325-11ce-bfc1-08002be10318}"

In device manager the Device Instance Path is
PCI\VEN_8086&DEV_0F41&SUBSYS_72708086&REV_11\3&11583659&0&C1

These obviously do not match. Questions:

1. Should they match?
2. Do I need to manipulate the DevicePath? According to MSDN, I should not have to.
3. Am I missing something?

Here is the code in question:

while (SetupDiEnumDeviceInfo(DeviceInfoSet, Index, &DeviceInfoData))
{
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
SetupDiCreateDeviceInterface(DeviceInfoSet, &DeviceInfoData, &DeviceInfoData.ClassGuid, NULL, 0, &DeviceInterfaceData);

// call the first time to get required buffer size
SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &DeviceInterfaceData, NULL, 0, &requiredSize, NULL);

// allocate required buffer
if ((DeviceInterfaceDetailData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(requiredSize)) == NULL)
{
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return status = INSUFFICIENT_MEMORY;
}

// call the second time to get detailed info
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, &DeviceInterfaceData, DeviceInterfaceDetailData, requiredSize, 0, &DeviceInfoData);

// check for i2c controller #1
if(wcsstr(DeviceInterfaceDetailData->DevicePath, i2cDevice) != NULL)
break;

Index++;
}

tempHandle = CreateFile(DeviceInterfaceDetailData->DevicePath,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);

Thanks.


NTDEV is sponsored by OSR

Visit the list online at: https:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at https:

To unsubscribe, visit the List Server section of OSR Online at https:</https:></https:></https:>

This is from the Intel? AtomTM Processor E3800 Windows 7 IO Driver Software Developer?s Manual that came with the driver:

The I2C driver is opened using the Win32 CreateFile API. To get the device name, use GUID interface exposed by the driver: I2C_LPSS_INTERFACE_GUID, defined in public.h. A device interface class is a way of exporting device and driver functionality to other system components, including other drivers, as well as user-mode applications. A driver can register a device interface class, and then enable an instance of the class for each device object to which user-mode I/O requests might be sent.
Device interfaces are available to both kernel-mode components and user-mode applications. Usermode code can use SetupDiXxx functions to find out about registered, enabled device interfaces. Please refer the following site to get the details about SetupDiXxx functions.
http://msdn.microsoft.com/en-us/library/dd406734.aspx
Since there are more than one I2C controller in BYT-I platform, and they share the same GUID, when user-mode applications open I2C device using SetupDiXxx, they will get a device name list of all I2C controller interfaces. At this time, they should also compare the hardware ID they need to each item of that list, so as to be able open the correct controller they need.

Could it be some kind of permissions issue?

Iirc, DeviceInterfaceDetailData->DevicePath is always a WCHAR string. So, if your app project is using ASCII characters, CreateFile is CreateFileA, which is the ASCII version of CreateFile.

Your code should explicitly call CreateFileW when the path is always a WCHAR string.

Could it be some kind of permissions issue?

Yes it could be, but you get an error like ERROR_ACCESS_DENIED in that case.

You can use the WinObj utility to view the device object security properties. The device Manager can give you the “PDO Name”, a property which is a path like “\Device\00000015”. When you have the path of the PDO (bottom of the stack), you can get the DEVICE_OBJECT address with the “!devobj \Device\00000015” extension of WinDbg and the device stack with the “!devstack” extension.

With the DRIVER_OBJECT address, you can get the address of the IRP_MJ_CREATE handler and break with WinDbg when a handle to the device is requested, for instance with CreateFileW.

xxxxx@winsystems.com xxxxx@lists.osr.com wrote:

Since there are more than one I2C controller in BYT-I platform, and they share the same GUID, when user-mode applications open I2C device using SetupDiXxx, they will get a device name list of all I2C controller interfaces. At this time, they should also compare the hardware ID they need to each item of that list, so as to be able open the correct controller they need.

Yes, but the way you do that is to call SetupDiGetDeviceRegistryProperty
with SPDRP_HARDWAREID, because the format of the hardware ID is stable.
The format of the DevicePath is internal and not guaranteed

// check for i2c controller #1
if(wcsstr(DeviceInterfaceDetailData->DevicePath, i2cDevice) != NULL)
break;

What is “i2cDevice” here, and where did you get it? Is it in the
filename format, as opposed to the hardware ID format?

Could it be some kind of permissions issue?

Unlikely, if the error is “file not found”.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

WCHAR *i2cDevice = L"0f41".

I will try to sue the SetupDiGetDeviceRegistryProperty() function.

Using SetupDiGetDeviceRegistryProperty() did not help.

Any other suggestions?

Is your application running elevated?

Bent from my phone


From: xxxxx@lists.osr.com on behalf of xxxxx@winsystems.com xxxxx@lists.osr.com
Sent: Wednesday, August 9, 2017 8:02:06 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] SetupDiGetDeviceInterfaceDetail Function & DevicePath

Using SetupDiGetDeviceRegistryProperty() did not help.

Any other suggestions?


NTDEV is sponsored by OSR

Visit the list online at: https:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at https:

To unsubscribe, visit the List Server section of OSR Online at https:</https:></https:></https:>

I am running the application in an administrator console window.

xxxxx@winsystems.com xxxxx@lists.osr.com wrote:

Using SetupDiGetDeviceRegistryProperty() did not help.

What does that mean? Are you getting a devicePath? Does the devicePath
look right? You’ve double-checked the Unicode/ANSI status of your
CreateFile call? Are you sure the driver exposes a user-mode interface?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Using SetupDiGetDeviceInterfaceDetail, I get the following structure returned. This includes the DevicePath that I am using unchanged in the CreateFile call.

DeviceInterfaceDetailData
cbSize=0x00000008
DevicePath=L"\\?\pci#ven_8086&dev_0f41&subsys_72708086&rev_11#3&11583659&0&c1#{4d36e97d-e325-11ce-bfc1-08002be10318}"

Using SetupDiGetDeviceRegistryProperty, I have to recast the buffer as type LPCTSTR which gives me the following:

PropertyBuffer=“PCI\VEN_8086&DEV_0F47&SUBSYS_72708086&REV_11”

This also does not work. Do I need to manipulate this string before I can use it in CreateFile?

xxxxx@winsystems.com xxxxx@lists.osr.com wrote:

Using SetupDiGetDeviceInterfaceDetail, I get the following structure returned. This includes the DevicePath that I am using unchanged in the CreateFile call.

DeviceInterfaceDetailData
cbSize=0x00000008
DevicePath=L"\\?\pci#ven_8086&dev_0f41&subsys_72708086&rev_11#3&11583659&0&c1#{4d36e97d-e325-11ce-bfc1-08002be10318}"

Using SetupDiGetDeviceRegistryProperty, I have to recast the buffer as type LPCTSTR which gives me the following:

PropertyBuffer=“PCI\VEN_8086&DEV_0F47&SUBSYS_72708086&REV_11”

This also does not work. Do I need to manipulate this string before I can use it in CreateFile?

For the record, I’m suggesting using the hardware ID property as your
search criteria, not your DevicePath. It is still the DevicePath that
has to be passed to CreateFile.

Also, you do need to understand that DevicePath is a Unicode string. If
you are not doing a Unicode build, then you will need to call
CreateFileW, not just CreateFile.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I have changed the code to use CreateFileW but still get the same error. The DevicePath returned appears valid so I will assume my code is performing properly. Will look into other possibilities for why the CreateFile does not work. Thanks to all who helped.

xxxxx@winsystems.com xxxxx@lists.osr.com wrote:

I have changed the code to use CreateFileW but still get the same error. The DevicePath returned appears valid so I will assume my code is performing properly. Will look into other possibilities for why the CreateFile does not work. Thanks to all who helped.

So, again, just to be sure, if you do
printf( “%ws\s”, DeviceInterfaceDetailData->DevicePath );
immediately before
CreateFile( DeviceInterfaceDetailData->DevicePath, …

you see the \?\ string you showed us before?

L"\\?\pci#ven_8086&dev_0f41&subsys_72708086&rev_11#3&11583659&0&c1#{4d36e97d-e325-11ce-bfc1-08002be10318}"

And the CreateFile returns INVALID_HANDLE_VALUE, and GetLastError
returns ERROR_FILE_NOT_FOUND?

One thing you have not showed us is how you are creating the
DeviceInfoSet. The GUID in that file name is the device class for the
“System” devices. I thought you had some code that was specifically
iterating through I2C resources. What leads you to believe that this
particular device has a driver at all?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.