Skip to content

Commit 89207c0

Browse files
committed
Add device tree enumeration
1 parent b4bb368 commit 89207c0

File tree

11 files changed

+203
-78
lines changed

11 files changed

+203
-78
lines changed

docs/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ This command exports system, disk, SMBIOS, and network information to `report.js
114114
Print audio devices.
115115
- --gpu
116116
Print GPU usage.
117+
- --device[=`TYPE`]
118+
Print device tree.
119+
`TYPE` specifies the type of the devices, e.g. `ACPI`, `SWD`, `PCI` or `USB`.
117120

118121
### System Information
119122

libnw/devtree.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// SPDX-License-Identifier: Unlicense
2+
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <windows.h>
6+
#include <initguid.h>
7+
#include <devpkey.h>
8+
9+
#include "libnw.h"
10+
#include "utils.h"
11+
#include "devtree.h"
12+
13+
WCHAR* NWL_GetDevStrProp(DEVINST devInst, const DEVPROPKEY* pKey)
14+
{
15+
DEVPROPTYPE propType;
16+
ULONG propSize = 0;
17+
CONFIGRET cr = CM_Get_DevNode_PropertyW(devInst, pKey, &propType, NULL, &propSize, 0);
18+
19+
if (cr != CR_BUFFER_SMALL)
20+
return NULL;
21+
22+
BYTE* buffer = (BYTE*)malloc(propSize);
23+
if (!buffer)
24+
return NULL;
25+
26+
cr = CM_Get_DevNode_PropertyW(devInst, pKey, &propType, buffer, &propSize, 0);
27+
if (cr != CR_SUCCESS)
28+
{
29+
free(buffer);
30+
return NULL;
31+
}
32+
33+
// Check if it's a string or list of strings before returning
34+
if (propType == DEVPROP_TYPE_STRING || propType == DEVPROP_TYPE_STRING_LIST)
35+
return (WCHAR*)buffer;
36+
37+
free(buffer);
38+
return NULL;
39+
}
40+
41+
static void
42+
GetDeviceInfoDefault(PNODE node, void* data, DEVINST devInst, LPCWSTR instanceId)
43+
{
44+
(void)data;
45+
NWL_NodeAttrSet(node, "HWID", NWL_Ucs2ToUtf8(instanceId), 0);
46+
47+
WCHAR* name = NWL_GetDevStrProp(devInst, &DEVPKEY_NAME);
48+
if (name)
49+
{
50+
NWL_NodeAttrSet(node, "Name", NWL_Ucs2ToUtf8(name), 0);
51+
free(name);
52+
}
53+
}
54+
55+
static PNODE AppendDevices(PNODE parent, const char* hub)
56+
{
57+
if (parent->Flags & NFLG_TABLE)
58+
return parent;
59+
PNODE ret = NWL_NodeGetChild(parent, hub);
60+
if (ret)
61+
return ret;
62+
return NWL_NodeAppendNew(parent, hub, NFLG_TABLE);
63+
}
64+
65+
void
66+
NWL_EnumerateDevices(PNODE parent, DEVTREE_ENUM_CTX* ctx, DEVINST devInst)
67+
{
68+
PNODE node = parent;
69+
DEVINST childInst;
70+
WCHAR* instanceId = NWL_GetDevStrProp(devInst, &DEVPKEY_Device_InstanceId);
71+
72+
if (instanceId)
73+
{
74+
if (ctx->filter[0] == L'\0' || _wcsnicmp(instanceId, ctx->filter, ctx->filterLen) == 0)
75+
{
76+
node = NWL_NodeAppendNew(AppendDevices(parent, ctx->hub), "Device", NFLG_TABLE_ROW);
77+
ctx->GetDeviceInfo(node, ctx->data, devInst, instanceId);
78+
}
79+
free(instanceId);
80+
}
81+
82+
if (CM_Get_Child(&childInst, devInst, 0) == CR_SUCCESS)
83+
{
84+
NWL_EnumerateDevices(node, ctx, childInst);
85+
DEVINST siblingInst = childInst;
86+
while (CM_Get_Sibling(&siblingInst, siblingInst, 0) == CR_SUCCESS)
87+
NWL_EnumerateDevices(node, ctx, siblingInst);
88+
}
89+
}
90+
91+
PNODE NW_DevTree(VOID)
92+
{
93+
DEVTREE_ENUM_CTX ctx =
94+
{
95+
.filter = L"\0",
96+
.data = NULL,
97+
.hub = "Devices",
98+
.GetDeviceInfo = GetDeviceInfoDefault,
99+
};
100+
DEVINST devRoot;
101+
CONFIGRET cr;
102+
PNODE node = NWL_NodeAlloc("Device Tree", NFLG_TABLE);
103+
if (NWLC->DevTree)
104+
NWL_NodeAppendChild(NWLC->NwRoot, node);
105+
106+
if (NWLC->DevTreeFilter)
107+
{
108+
wcscpy_s(ctx.filter, 32, NWL_Utf8ToUcs2(NWLC->DevTreeFilter));
109+
ctx.filterLen = wcslen(ctx.filter);
110+
}
111+
112+
cr = CM_Locate_DevNodeW(&devRoot, NULL, CM_LOCATE_DEVNODE_NORMAL);
113+
if (cr != CR_SUCCESS)
114+
{
115+
NWL_NodeAppendMultiSz(&NWLC->ErrLog, "CM_Locate_DevNodeW failed");
116+
goto fail;
117+
}
118+
119+
NWL_EnumerateDevices(node, &ctx, devRoot);
120+
121+
fail:
122+
return node;
123+
}

libnw/devtree.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: Unlicense
2+
#pragma once
3+
4+
#define VC_EXTRALEAN
5+
#include <windows.h>
6+
#include <cfgmgr32.h>
7+
#include "format.h"
8+
9+
//typedef void* DEVTREE_CTX;
10+
11+
typedef struct _DEVTREE_ENUM_CTX
12+
{
13+
WCHAR filter[32];
14+
size_t filterLen;
15+
const char* hub;
16+
void* data;
17+
void (*GetDeviceInfo)(PNODE node, void* data, DEVINST devInst, LPCWSTR instanceId);
18+
} DEVTREE_ENUM_CTX;
19+
20+
WCHAR* NWL_GetDevStrProp(DEVINST devInst, const DEVPROPKEY* pKey);
21+
22+
void
23+
NWL_EnumerateDevices(PNODE parent, DEVTREE_ENUM_CTX* ctx, DEVINST devInst);

libnw/libnw.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ VOID NW_Print(LPCSTR lpFileName)
9292
NW_Gpu();
9393
if (NWLC->FontInfo)
9494
NW_Font();
95+
if (NWLC->DevTree)
96+
NW_DevTree();
9597
NW_Libinfo();
9698
NW_Export(NWLC->NwRoot, NWLC->NwFile);
9799
}

libnw/libnw.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ typedef struct _NWLIB_CONTEXT
4747
BOOL ProductPolicyInfo;
4848
BOOL GpuInfo;
4949
BOOL FontInfo;
50+
BOOL DevTree;
5051

5152
BOOL Debug;
5253
BOOL HideSensitive;
5354

55+
LPCSTR DevTreeFilter;
5456
DWORD AcpiTable;
5557
UINT8 SmbiosType;
5658
LPCSTR PciClass;
@@ -170,6 +172,7 @@ PNODE NW_PublicIp(VOID);
170172
PNODE NW_ProductPolicy(VOID);
171173
PNODE NW_Gpu(VOID);
172174
PNODE NW_Font(VOID);
175+
PNODE NW_DevTree(VOID);
173176

174177
VOID NWL_GetUptime(CHAR* szUptime, DWORD dwSize);
175178
VOID NWL_GetHostname(CHAR* szHostname);

libnw/libnw.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
<ClInclude Include="..\libcdi\libcdi.h" />
135135
<ClInclude Include="acpi.h" />
136136
<ClInclude Include="audio.h" />
137+
<ClInclude Include="devtree.h" />
137138
<ClInclude Include="disk.h" />
138139
<ClInclude Include="efivars.h" />
139140
<ClInclude Include="format.h" />
@@ -150,6 +151,7 @@
150151
<ClCompile Include="audio_nw.c" />
151152
<ClCompile Include="battery.c" />
152153
<ClCompile Include="cpuid.c" />
154+
<ClCompile Include="devtree.c" />
153155
<ClCompile Include="disk.c" />
154156
<ClCompile Include="display.c" />
155157
<ClCompile Include="efivars.c" />

libnw/libnw.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
<ClInclude Include="vbr.h">
5555
<Filter>Header Files</Filter>
5656
</ClInclude>
57+
<ClInclude Include="devtree.h">
58+
<Filter>Header Files</Filter>
59+
</ClInclude>
5760
</ItemGroup>
5861
<ItemGroup>
5962
<ClCompile Include="acpi.c">
@@ -140,6 +143,9 @@
140143
<ClCompile Include="table.c">
141144
<Filter>Source Files</Filter>
142145
</ClCompile>
146+
<ClCompile Include="devtree.c">
147+
<Filter>Source Files</Filter>
148+
</ClCompile>
143149
</ItemGroup>
144150
<ItemGroup>
145151
<None Include="packages.config" />

libnw/usb.c

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88

99
#include "libnw.h"
1010
#include "utils.h"
11+
#include "devtree.h"
12+
13+
typedef struct _DEVTREE_CTX
14+
{
15+
CHAR* ids;
16+
DWORD idsSize;
17+
} DEVTREE_CTX;
1118

1219
static WCHAR* GetUsbDiskName(DEVINST usbDevInst)
1320
{
@@ -77,82 +84,59 @@ ParseHwClass(PNODE nd, CHAR* ids, DWORD idsSize, LPCWSTR compId)
7784
}
7885

7986
static void
80-
GetDeviceInfo(PNODE nusb, CHAR* ids, DWORD idsSize, DEVINST devInst, LPCWSTR instanceId)
87+
GetDeviceInfoUsb(PNODE node, void* data, DEVINST devInst, LPCWSTR instanceId)
8188
{
82-
NWL_NodeAttrSet(nusb, "HWID", NWL_Ucs2ToUtf8(instanceId), 0);
89+
DEVTREE_CTX* ctx = (DEVTREE_CTX*)data;
90+
NWL_NodeAttrSet(node, "HWID", NWL_Ucs2ToUtf8(instanceId), 0);
8391

84-
NWL_ParseHwid(nusb, ids, idsSize, instanceId, 1);
92+
NWL_ParseHwid(node, ctx->ids, ctx->idsSize, instanceId, 1);
8593

8694
// Parse hardware class if available
8795
WCHAR* compatibleIds = NWL_GetDevStrProp(devInst, &DEVPKEY_Device_CompatibleIds);
8896
if (compatibleIds)
8997
{
90-
ParseHwClass(nusb, ids, idsSize, compatibleIds);
98+
ParseHwClass(node, ctx->ids, ctx->idsSize, compatibleIds);
9199
free(compatibleIds);
92100
}
93101

94102
// Get and print device name using DEVPKEY_NAME
95103
WCHAR* name = NWL_GetDevStrProp(devInst, &DEVPKEY_NAME);
96104
if (name)
97105
{
98-
NWL_NodeAttrSet(nusb, "Name", NWL_Ucs2ToUtf8(name), 0);
106+
NWL_NodeAttrSet(node, "Name", NWL_Ucs2ToUtf8(name), 0);
99107
free(name);
100108
}
101109

102110
// Check if it's a Mass Storage Device and get disk name
103111
WCHAR* diskName = GetUsbDiskName(devInst);
104112
if (diskName)
105113
{
106-
NWL_NodeAttrSet(nusb, "Disk", NWL_Ucs2ToUtf8(diskName), 0);
114+
NWL_NodeAttrSet(node, "Disk", NWL_Ucs2ToUtf8(diskName), 0);
107115
free(diskName);
108116
}
109117
}
110118

111-
static inline PNODE AppendUsbHub(PNODE parent)
112-
{
113-
if (parent->Flags & NFLG_TABLE)
114-
return parent; // Already a table, return as is
115-
PNODE ret = NWL_NodeGetChild(parent, "USB Hub");
116-
if (ret)
117-
return ret; // Found existing USB Hub node
118-
// Create a new USB Hub node
119-
return NWL_NodeAppendNew(parent, "USB Hub", NFLG_TABLE);
120-
}
121-
122-
static void EnumerateUsbDevices(PNODE parent, CHAR* ids, DWORD idsSize, DEVINST devInst)
123-
{
124-
PNODE nusb = parent;
125-
DEVINST childInst;
126-
WCHAR* instanceId = NWL_GetDevStrProp(devInst, &DEVPKEY_Device_InstanceId);
127-
if (instanceId)
128-
{
129-
if (wcsncmp(instanceId, L"USB\\", 4) == 0)
130-
{
131-
nusb = NWL_NodeAppendNew(AppendUsbHub(parent), "Device", NFLG_TABLE_ROW);
132-
GetDeviceInfo(nusb, ids, idsSize, devInst, instanceId);
133-
}
134-
free(instanceId);
135-
}
136-
137-
if (CM_Get_Child(&childInst, devInst, 0) == CR_SUCCESS)
138-
{
139-
EnumerateUsbDevices(nusb, ids, idsSize, childInst);
140-
DEVINST siblingInst = childInst;
141-
while (CM_Get_Sibling(&siblingInst, siblingInst, 0) == CR_SUCCESS)
142-
EnumerateUsbDevices(nusb, ids, idsSize, siblingInst);
143-
}
144-
}
145-
146119
PNODE NW_Usb(VOID)
147120
{
148121
DEVINST devRoot;
149122
CONFIGRET cr;
150-
CHAR* ids = NULL;
151-
DWORD idsSize = 0;
123+
DEVTREE_CTX data =
124+
{
125+
.ids = NULL,
126+
.idsSize = 0,
127+
};
128+
DEVTREE_ENUM_CTX ctx =
129+
{
130+
.filter = L"USB\\",
131+
.filterLen = 4, // Length of "USB\\"
132+
.data = &data,
133+
.hub = "USB Hub",
134+
.GetDeviceInfo = GetDeviceInfoUsb,
135+
};
152136
PNODE node = NWL_NodeAlloc("USB", NFLG_TABLE);
153137
if (NWLC->UsbInfo)
154138
NWL_NodeAppendChild(NWLC->NwRoot, node);
155-
ids = NWL_LoadIdsToMemory(L"usb.ids", &idsSize);
139+
data.ids = NWL_LoadIdsToMemory(L"usb.ids", &data.idsSize);
156140

157141
cr = CM_Locate_DevNodeW(&devRoot, NULL, CM_LOCATE_DEVNODE_NORMAL);
158142
if (cr != CR_SUCCESS)
@@ -161,9 +145,9 @@ PNODE NW_Usb(VOID)
161145
goto fail;
162146
}
163147

164-
EnumerateUsbDevices(node, ids, idsSize, devRoot);
148+
NWL_EnumerateDevices(node, &ctx, devRoot);
165149

166150
fail:
167-
free(ids);
151+
free(data.ids);
168152
return node;
169-
}
153+
}

libnw/utils.c

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -503,34 +503,6 @@ NWL_GetMonitorFromName(LPCWSTR lpDevice)
503503
return ctx.hMonitor;
504504
}
505505

506-
WCHAR* NWL_GetDevStrProp(DEVINST devInst, const DEVPROPKEY* pKey)
507-
{
508-
DEVPROPTYPE propType;
509-
ULONG propSize = 0;
510-
CONFIGRET cr = CM_Get_DevNode_PropertyW(devInst, pKey, &propType, NULL, &propSize, 0);
511-
512-
if (cr != CR_BUFFER_SMALL)
513-
return NULL;
514-
515-
BYTE* buffer = (BYTE*)malloc(propSize);
516-
if (!buffer)
517-
return NULL;
518-
519-
cr = CM_Get_DevNode_PropertyW(devInst, pKey, &propType, buffer, &propSize, 0);
520-
if (cr != CR_SUCCESS)
521-
{
522-
free(buffer);
523-
return NULL;
524-
}
525-
526-
// Check if it's a string or list of strings before returning
527-
if (propType == DEVPROP_TYPE_STRING || propType == DEVPROP_TYPE_STRING_LIST)
528-
return (WCHAR*)buffer;
529-
530-
free(buffer);
531-
return NULL;
532-
}
533-
534506
#define SECPERMIN 60
535507
#define SECPERHOUR (60*SECPERMIN)
536508
#define SECPERDAY (24*SECPERHOUR)

0 commit comments

Comments
 (0)