[I8042PRT] Dump SMBIOS tables into registry for usermode access
[reactos.git] / drivers / input / i8042prt / hwhacks.c
1 /*
2 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/input/i8042prt/hwhacks.c
5 * PURPOSE: Mouse specific functions
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
7 * REFERENCES: - http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
8 * -
9 */
10
11 #include "i8042prt.h"
12 #include <wmiguid.h>
13 #include <wmidata.h>
14 #include <wmistr.h>
15 #include "dmi.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20 const GUID MSSmBios_RawSMBiosTables_GUID = SMBIOS_DATA_GUID;
21 PVOID i8042SMBiosTables;
22 ULONG i8042HwFlags;
23
24 enum _ID_STRINGS
25 {
26 ID_NONE = 0,
27 BIOS_VENDOR,
28 BIOS_VERSION,
29 BIOS_DATE,
30 SYS_VENDOR,
31 SYS_PRODUCT,
32 SYS_VERSION,
33 SYS_SERIAL,
34 BOARD_VENDOR,
35 BOARD_NAME,
36 BOARD_VERSION,
37 BOARD_SERIAL,
38 BOARD_ASSET_TAG,
39
40 ID_STRINGS_MAX,
41 };
42
43 typedef struct _MATCHENTRY
44 {
45 ULONG Type;
46 PCHAR String;
47 } MATCHENTRY;
48
49 #define MAX_MATCH_ENTRIES 3
50 typedef struct _HARDWARE_TABLE
51 {
52 MATCHENTRY MatchEntries[MAX_MATCH_ENTRIES];
53 ULONG Flags;
54 } HARDWARE_TABLE;
55
56 const HARDWARE_TABLE i8042HardwareTable[] =
57 {
58 // { {{BOARD_VENDOR, "RIOWORKS"}, {BOARD_NAME, "HDAMB"}, {BOARD_VERSION, "Rev E"}}, FL_NOLOOP },
59 // { {{BOARD_VENDOR, "ASUSTeK Computer Inc."}, {BOARD_NAME, "G1S"}, {BOARD_VERSION, "1.0"}}, FL_NOLOOP },
60
61 { {{SYS_VENDOR, "Microsoft Corporation"}, {SYS_PRODUCT, "Virtual Machine"}}, FL_INITHACK },
62 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Inspiron 6000 "}}, FL_INITHACK },
63 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D430 "}}, FL_INITHACK },
64 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D530 "}}, FL_INITHACK },
65 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D531 "}}, FL_INITHACK },
66 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D600 "}}, FL_INITHACK },
67 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D610 "}}, FL_INITHACK },
68 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D620 "}}, FL_INITHACK },
69 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D630 "}}, FL_INITHACK },
70 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D810 "}}, FL_INITHACK },
71 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude E4300 "}}, FL_INITHACK },
72 { {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude E4310 "}}, FL_INITHACK },
73
74 };
75
76
77
78 static
79 PCHAR
80 GetDmiString(
81 _In_ PDMI_HEADER Header,
82 _In_ ULONG FieldOffset)
83 {
84 ULONG StringIndex;
85 PCHAR String;
86
87 StringIndex = ((PUCHAR)Header)[FieldOffset];
88 if (StringIndex == 0)
89 {
90 return NULL;
91 }
92
93 String = (PCHAR)Header + Header->Length;
94
95 while (--StringIndex != 0)
96 {
97 while (*String != 0)
98 String++;
99
100 String++;
101 }
102
103 return String;
104 }
105
106
107 static
108 VOID
109 i8042ParseSMBiosTables(
110 _In_reads_bytes_(TableSize) PVOID SMBiosTables,
111 _In_ ULONG TableSize)
112 {
113 PMSSmBios_RawSMBiosTables BiosTablesHeader = SMBiosTables;
114 PDMI_HEADER Header;
115 ULONG Remaining, i, j;
116 PCHAR Data;
117 PCHAR Strings[ID_STRINGS_MAX] = { 0 };
118
119 Header = (PDMI_HEADER)(&BiosTablesHeader->SMBiosData);
120 Remaining = BiosTablesHeader->Size;
121
122 while (Remaining >= sizeof(*Header))
123 {
124
125 if (Header->Type == DMI_ENTRY_END_OF_TABLE)
126 break;
127
128 switch (Header->Type)
129 {
130 case DMI_ENTRY_BIOS:
131 if (Remaining < DMI_BIOS_SIZE)
132 return;
133 Strings[BIOS_VENDOR] = GetDmiString(Header, DMI_BIOS_VENDOR);
134 Strings[BIOS_VERSION] = GetDmiString(Header, DMI_BIOS_VERSION);
135 Strings[BIOS_DATE] = GetDmiString(Header, DMI_BIOS_DATE);
136 break;
137
138 case DMI_ENTRY_SYSTEM:
139 if (Remaining < DMI_SYS_SIZE)
140 return;
141 Strings[SYS_VENDOR] = GetDmiString(Header, DMI_SYS_VENDOR);
142 Strings[SYS_PRODUCT] = GetDmiString(Header, DMI_SYS_PRODUCT);
143 Strings[SYS_VERSION] = GetDmiString(Header, DMI_SYS_VERSION);
144 Strings[SYS_SERIAL] = GetDmiString(Header, DMI_SYS_SERIAL);
145 break;
146
147 case DMI_ENTRY_BASEBOARD:
148 if (Remaining < DMI_BOARD_SIZE)
149 return;
150 Strings[BOARD_VENDOR] = GetDmiString(Header, DMI_BOARD_VENDOR);
151 Strings[BOARD_NAME] = GetDmiString(Header, DMI_BOARD_NAME);
152 Strings[BOARD_VERSION] = GetDmiString(Header, DMI_BOARD_VERSION);
153 Strings[BOARD_SERIAL] = GetDmiString(Header, DMI_BOARD_SERIAL);
154 Strings[BOARD_ASSET_TAG] = GetDmiString(Header, DMI_BOARD_ASSET_TAG);
155 break;
156
157 case DMI_ENTRY_CHASSIS:
158 case DMI_ENTRY_ONBOARD_DEVICE:
159 case DMI_ENTRY_OEMSTRINGS:
160 // DMI_ENTRY_IPMI_DEV?
161 // DMI_ENTRY_ONBOARD_DEV_EXT?
162 break;
163 }
164
165 Remaining -= Header->Length;
166 Data = (PCHAR)Header + Header->Length;
167
168 /* Now loop until we find 2 zeroes */
169 while ((Remaining >= 2) && ((Data[0] != 0) || (Data[1] != 0)))
170 {
171 Data++;
172 Remaining--;
173 }
174
175 if (Remaining < 2)
176 break;
177
178 /* Go to the next header */
179 Remaining -= 2;
180 Header = (PDMI_HEADER)((PUCHAR)Data + 2);
181 }
182
183 #if 0 // DBG
184 DbgPrint("i8042prt: Dumping DMI data:\n");
185 DbgPrint("BIOS_VENDOR: %s\n", Strings[BIOS_VENDOR]);
186 DbgPrint("BIOS_VERSION: %s\n", Strings[BIOS_VERSION]);
187 DbgPrint("BIOS_DATE: %s\n", Strings[BIOS_DATE]);
188 DbgPrint("SYS_VENDOR: %s\n", Strings[SYS_VENDOR]);
189 DbgPrint("SYS_PRODUCT: %s\n", Strings[SYS_PRODUCT]);
190 DbgPrint("SYS_VERSION: %s\n", Strings[SYS_VERSION]);
191 DbgPrint("SYS_SERIAL: %s\n", Strings[SYS_SERIAL]);
192 DbgPrint("BOARD_VENDOR: %s\n", Strings[BOARD_VENDOR]);
193 DbgPrint("BOARD_NAME: %s\n", Strings[BOARD_NAME]);
194 DbgPrint("BOARD_VERSION: %s\n", Strings[BOARD_VERSION]);
195 DbgPrint("BOARD_SERIAL: %s\n", Strings[BOARD_SERIAL]);
196 DbgPrint("BOARD_ASSET_TAG: %s\n", Strings[BOARD_ASSET_TAG]);
197 #endif
198
199 /* Now loop the hardware table to find a match */
200 for (i = 0; i < ARRAYSIZE(i8042HardwareTable); i++)
201 {
202 for (j = 0; j < MAX_MATCH_ENTRIES; j++)
203 {
204 ULONG Type = i8042HardwareTable[i].MatchEntries[j].Type;
205
206 if (Type != ID_NONE)
207 {
208 /* Check for a match */
209 if ((Strings[Type] == NULL) ||
210 strcmp(i8042HardwareTable[i].MatchEntries[j].String,
211 Strings[i8042HardwareTable[i].MatchEntries[j].Type]))
212 {
213 /* Does not match, try next entry */
214 break;
215 }
216 }
217 }
218
219 if (j == MAX_MATCH_ENTRIES)
220 {
221 /* All items matched! */
222 i8042HwFlags = i8042HardwareTable[i].Flags;
223 DPRINT("Found match for hw table index %u\n", i);
224 break;
225 }
226 }
227 }
228
229 static
230 VOID
231 i8042StoreSMBiosTables(
232 _In_reads_bytes_(TableSize) PVOID SMBiosTables,
233 _In_ ULONG TableSize)
234 {
235 static UNICODE_STRING mssmbiosKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\mssmbios");
236 static UNICODE_STRING DataName = RTL_CONSTANT_STRING(L"Data");
237 static UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SMBiosData");
238 OBJECT_ATTRIBUTES ObjectAttributes;
239 HANDLE KeyHandle = NULL, SubKeyHandle = NULL;
240 NTSTATUS Status;
241
242 /* Create registry key */
243 InitializeObjectAttributes(&ObjectAttributes,
244 &mssmbiosKeyName,
245 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
246 NULL,
247 NULL);
248 Status = ZwCreateKey(&KeyHandle,
249 KEY_WRITE,
250 &ObjectAttributes,
251 0,
252 NULL,
253 REG_OPTION_VOLATILE,
254 NULL);
255
256 if (!NT_SUCCESS(Status))
257 {
258 return;
259 }
260
261 /* Create sub key */
262 InitializeObjectAttributes(&ObjectAttributes,
263 &DataName,
264 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
265 KeyHandle,
266 NULL);
267 Status = ZwCreateKey(&SubKeyHandle,
268 KEY_WRITE,
269 &ObjectAttributes,
270 0,
271 NULL,
272 REG_OPTION_VOLATILE,
273 NULL);
274
275 if (!NT_SUCCESS(Status))
276 {
277 ZwClose(KeyHandle);
278 return;
279 }
280
281 /* Write value */
282 ZwSetValueKey(SubKeyHandle,
283 &ValueName,
284 0,
285 REG_BINARY,
286 SMBiosTables,
287 TableSize);
288
289 ZwClose(SubKeyHandle);
290 ZwClose(KeyHandle);
291 }
292
293 VOID
294 NTAPI
295 i8042InitializeHwHacks(
296 VOID)
297 {
298 NTSTATUS Status;
299 PVOID DataBlockObject;
300 PWNODE_ALL_DATA AllData;
301 ULONG BufferSize;
302
303 /* Open the data block object for the SMBIOS table */
304 Status = IoWMIOpenBlock(&MSSmBios_RawSMBiosTables_GUID,
305 WMIGUID_QUERY,
306 &DataBlockObject);
307 if (!NT_SUCCESS(Status))
308 {
309 DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
310 return;
311 }
312
313 /* Query the required buffer size */
314 BufferSize = 0;
315 Status = IoWMIQueryAllData(DataBlockObject, &BufferSize, NULL);
316 if (!NT_SUCCESS(Status))
317 {
318 DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
319 return;
320 }
321
322 AllData = ExAllocatePoolWithTag(PagedPool, BufferSize, 'BTMS');
323 if (AllData == NULL)
324 {
325 DPRINT1("Failed to allocate %lu bytes for SMBIOS tables\n", BufferSize);
326 return;
327 }
328
329 /* Query the buffer data */
330 Status = IoWMIQueryAllData(DataBlockObject, &BufferSize, AllData);
331 if (!NT_SUCCESS(Status))
332 {
333 DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
334 ExFreePoolWithTag(AllData, 'BTMS');
335 return;
336 }
337
338 /* FIXME: This function should be removed once the mssmbios driver is implemented */
339 /* Store SMBios data in registry */
340 i8042StoreSMBiosTables(AllData + 1,
341 AllData->FixedInstanceSize);
342 DPRINT1("SMBiosTables HACK, see CORE-14867\n");
343
344 /* Parse the table */
345 i8042ParseSMBiosTables(AllData + 1,
346 AllData->WnodeHeader.BufferSize);
347
348 /* Free the buffer */
349 ExFreePoolWithTag(AllData, 'BTMS');
350 }
351