Accessing device interface from userspace app

First time poster, hopefully someone can provide pointers on my newbie issue.
Trying to open “FOO” device interface from userspace test app, and register for PnP events on same. Cannot seem to successfully open handle on interface, have tried various approaches but keep getting unknown path errors. My KMDF driver exists and interface created without error. Below is significant portion of code being used. Can someone suggest what might be wrong, and/or point to a suitable example for similar usecase?
Thanks,
Andrew

// {8A38B6CD-8C69-4142-A722-80B7BFAE570E}
static const GUID FOO_INTERFACE_GUID =
{ 0x8a38b6cd, 0x8c69, 0x4142, { 0xa7, 0x22, 0x80, 0xb7, 0xbf, 0xae, 0x57, 0xe } };

#define FOO_NTDEVICE_NAME_STRING L"\Device\FOO"

DWORD __callback CALLBACK
CMNotifyCb(
In HCMNOTIFICATION hNotify,
In_opt PVOID Context,
In CM_NOTIFY_ACTION Action,
In_reads_bytes(EventDataSize) PCM_NOTIFY_EVENT_DATA EventData,
In DWORD EventDataSize
)
{
PAPP_STATE_TYPE pAppState = (PAPP_STATE_TYPE)Context;
DWORD size;
UNREFERENCED_PARAMETER(hNotify);

if (!pAppState)
return ERROR_INVALID_ADDRESS;

wprintf(L"CMNotify callback: Action[%d] Data[%S]\n", Action, EventData->u.DeviceInterface.SymbolicLink);

// determine size of just symbolic link array
size = (EventDataSize - ((UINT_PTR)EventData->u.DeviceInterface.SymbolicLink - (UINT_PTR)EventData));

switch (Action) {
case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL:
memcpy_s(pAppState->SymbolicLink, sizeof(pAppState->SymbolicLink),
EventData->u.DeviceInterface.SymbolicLink, size);
pAppState->IfaceExists = TRUE;
break;
case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL:
pAppState->IfaceExists = FALSE;
break;
default:
// Do nothing
break;
}

return SUCCESS;
}

DWORD
RegisterInterface(PAPP_STATE_TYPE pAppState)
{
CM_NOTIFY_FILTER CMfilter;
CONFIGRET ret;
HANDLE handle;
DWORD status = SUCCESS;

// Register for interface state changes

// initialize CM filter
memset(&CMfilter, 0x0, sizeof(CMfilter));
CMfilter.cbSize = sizeof(CMfilter);
CMfilter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
CMfilter.u.DeviceInterface.ClassGuid = FOO_INTERFACE_GUID;

ret = CM_Register_Notification(&CMfilter, pAppState, CMNotifyCb, &pAppState->hCMNotify);
if (CR_SUCCESS != ret) {
wprintf(L"Failed on CM_Register_Notification!\n");
status = FAILURE;
goto ON_EXIT;
}

ON_EXIT:
return status;
}

DWORD
OpenDevice(PAPP_STATE_TYPE pAppState)
{
HANDLE hDevice = INVALID_HANDLE_VALUE;
DWORD status = SUCCESS;

#if 0
wprintf(L"Opening file: %ws\n", pAppState->SymbolicLink);
hDevice = CreateFileW(pAppState->SymbolicLink, // name
(GENERIC_READ|GENERIC_WRITE), // access
0, // share mode
NULL, // default security attributes
OPEN_EXISTING, // disposition
FILE_FLAG_OVERLAPPED, // file attributes
NULL); // do not copy file attributes
#else
{
WCHAR ntDeviceName[60] = {0,};
// WCHAR ntDeviceName[60] = L"\";

wcscat_s(ntDeviceName, sizeof(ntDeviceName), FOO_NTDEVICE_NAME_STRING);
wprintf(L"Opening file: %ws\n", ntDeviceName);
hDevice = CreateFileW(ntDeviceName, // name
(GENERIC_READ | GENERIC_WRITE), // access
0, // share mode
NULL, // default security attributes
OPEN_EXISTING, // disposition
FILE_FLAG_OVERLAPPED, // file attributes
NULL); // do not copy file attributes

}
#endif // 0
if (INVALID_HANDLE_VALUE == hDevice) {
DWORD err = GetLastError();
wprintf(L"Failed on CreateFile! status = %d\n", err);
status = FAILURE;
goto ON_EXIT;
}
pAppState->hDevice = hDevice;

ON_EXIT:
return status;
}

int
_tmain(int argc, _TCHAR* argv)
{
DWORD status = 0;
BOOL ret = FALSE;
APP_STATE_TYPE AppState = { 0, };

// Register for FOO interface notifications
status = RegisterInterface (&AppState);
if (SUCCESS != status) {
wprintf(L"Failed on RegisterInterface!\n");
goto ON_EXIT;
}

#if 0
// wait on FOO interface arrival
wprintf(L"Waiting for FOO interface…\n");
status = WaitForSingleObject(AppState.hEvent, 1000); // msec
if (WAIT_OBJECT_0 != status) {
wprintf(L"Failed on WaitForSingleObject!\n");
goto ON_EXIT;
}

ResetEvent(AppState.hEvent);
#else
Sleep(1000); // msec
#endif // 0

// open device interface
status = OpenDevice(&AppState);
if (SUCCESS != status) {
wprintf(L"Failed on OpenDevice!\n");
goto ON_EXIT;
}

// send IOCTL
ret = DeviceIoControl(AppState.hDevice,
(DWORD)IOCTL_FOO_POWER_UP,
NULL, 0, // Input buffer
NULL, 0, // Output buffer
NULL, // Bytes returned
NULL); // Overlapped
if (TRUE!= ret) {
wprintf(L"Failed on DeviceIoControl!\n");
status = FAILURE;
goto ON_EXIT;
}

ON_EXIT:
// close device interface
if (AppState.hDevice && !CloseHandle(AppState.hDevice)) {
wprintf(L"Failed on hDevice CloseHandle!\n");
}
if (AppState.hEvent && !CloseHandle(AppState.hEvent)) {
wprintf(L"Failed on hEvent CloseHandle!\n");
}

return status;
}

xxxxx@qti.qualcomm.com wrote:

First time poster, hopefully someone can provide pointers on my newbie issue.
Trying to open “FOO” device interface from userspace test app, and register for PnP events on same. Cannot seem to successfully open handle on interface, have tried various approaches but keep getting unknown path errors. My KMDF driver exists and interface created without error. Below is significant portion of code being used. Can someone suggest what might be wrong, and/or point to a suitable example for similar usecase?

The \Device namespace is only accessible from kernel mode. You can’t
open \Device\FOO directly.

Assuming you really are creating a device interface in the driver for
your FOO_INTERFACE_GUID, then you need to use the rather wordy SetupDi
APIs to go find the path to your device. You’ll use
SetupDiGetClassDevs( YOUR_GUID, NULL, NULL,
DIGCF_PRESENT|DIGCF_DEVICEINTERFACE)
to fetch all of the devices that expose your device interface. Then you
use SetupDiEnumDeviceInterfaces to fetch the first device in that list.
Then you call SetupDiGetDeviceInterfaceDetail twice, once to find out
how much data it will return, then again to fetch a
SP_DEVICE_INTERFACE_DETAIL_DATA structure. That structure contains a
DevicePath element, which is a string you can pass to CreateFile.

If you search for those APIs, you can find a number of samples that do
this dance, including this one:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb204769.aspx

That SHOULD be the same path you get from CM_Register_Notification, but
of course that only gets called when the interface changes state. If
the driver is already running, you won’t get a notification.

Save your boilerplate. You’ll use it again and again.


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

The enum.exe project in the toaster project shows you how to enumerate all existing instances of a device interface (via SetupDiGetClassDevs). Modify the guid in the sample and see if it finds your FOO

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Monday, July 7, 2014 11:44 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Accessing device interface from userspace app

xxxxx@qti.qualcomm.com wrote:

First time poster, hopefully someone can provide pointers on my newbie issue.
Trying to open “FOO” device interface from userspace test app, and register for PnP events on same. Cannot seem to successfully open handle on interface, have tried various approaches but keep getting unknown path errors. My KMDF driver exists and interface created without error. Below is significant portion of code being used. Can someone suggest what might be wrong, and/or point to a suitable example for similar usecase?

The \Device namespace is only accessible from kernel mode. You can’t open \Device\FOO directly.

Assuming you really are creating a device interface in the driver for your FOO_INTERFACE_GUID, then you need to use the rather wordy SetupDi APIs to go find the path to your device. You’ll use
SetupDiGetClassDevs( YOUR_GUID, NULL, NULL,
DIGCF_PRESENT|DIGCF_DEVICEINTERFACE)
to fetch all of the devices that expose your device interface. Then you use SetupDiEnumDeviceInterfaces to fetch the first device in that list.
Then you call SetupDiGetDeviceInterfaceDetail twice, once to find out how much data it will return, then again to fetch a SP_DEVICE_INTERFACE_DETAIL_DATA structure. That structure contains a DevicePath element, which is a string you can pass to CreateFile.

If you search for those APIs, you can find a number of samples that do this dance, including this one:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb204769.aspx

That SHOULD be the same path you get from CM_Register_Notification, but of course that only gets called when the interface changes state. If the driver is already running, you won’t get a notification.

Save your boilerplate. You’ll use it again and again.


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


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Thank you for the information. Unfortunately, this is on Windows Phone platform, which does not seem to have the SetupDi* APIs available as the DLL is not present in the WDK (I tried this approach, and now have separate thread with Microsoft on this missing DLL issue). Is there any alternative to SetupDi* approach?

xxxxx@qti.qualcomm.com wrote:

Thank you for the information. Unfortunately, this is on Windows Phone platform, which does not seem to have the SetupDi* APIs available as the DLL is not present in the WDK (I tried this approach, and now have separate thread with Microsoft on this missing DLL issue). Is there any alternative to SetupDi* approach?

The DLL is a standard part of the operating system. The export library
for the DLL (setupapi.lib) is part of the SDK, not the SDK.
SetupAPI.lib for x86, x64, and ARM are all present in the 8.1 SDK.

Seriously. If Device Manager is there, then setupapi.dll is there.

Now, that doesn’t mean you can GET to the DLL. A modern/store app, for
example, can’t just open arbitrary devices. You have to use a
privileged Windows Store Device App as a go-between.


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

Hi Andrew,

On platforms that do not have SetupAPI, you can use the cfgmgr32 CM_ API set to enumerate devices and device interfaces.

CM_Get_Device_Interface_List will fill in a buffer with a multi-sz list of any device interfaces that exist for the specified device interface class, optionally filtered to a specific device instance ID.

This is the equivalent of calling SetupDiGetClassDevs with the DIGCF_DEVICEINTERFACE flag, an interface ClassGuid (and optionally, a device instance ID string in the Enumerator parameter).

If you can find a sample of using SetupDiGetClassDevs to do this, or are familiar with the kernel IoGetDeviceInterfaces routine, the mapping to this CM API should be pretty straight forward.

Also, don’t forget to use CM_Get_Device_Interface_List_Size first to determine the size of buffer to allocate for the list. Since device interfaces can be registered at any time on a live system, the size required can change between your two calls, so you should also still handle a CR_BUFFER_SMALL buffer small condition even after querying for the size of the list. Just requery and try again.

CM_Get_Device_Interface_List
http://msdn.microsoft.com/en-us/library/windows/hardware/ff538463.aspx

CM_Get_Device_Interface_List_Size
http://msdn.microsoft.com/en-us/library/windows/hardware/ff538471.aspx

Hope this helps,
Jim.