[I8042PRT] Apply a workaround for Dell Latitude D610
[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 VOID
230 NTAPI
231 i8042InitializeHwHacks(
232 VOID)
233 {
234 NTSTATUS Status;
235 PVOID DataBlockObject;
236 PWNODE_ALL_DATA AllData;
237 ULONG BufferSize;
238
239 /* Open the data block object for the SMBIOS table */
240 Status = IoWMIOpenBlock(&MSSmBios_RawSMBiosTables_GUID,
241 WMIGUID_QUERY,
242 &DataBlockObject);
243 if (!NT_SUCCESS(Status))
244 {
245 DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
246 return;
247 }
248
249 /* Query the required buffer size */
250 BufferSize = 0;
251 Status = IoWMIQueryAllData(DataBlockObject, &BufferSize, NULL);
252 if (!NT_SUCCESS(Status))
253 {
254 DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
255 return;
256 }
257
258 AllData = ExAllocatePoolWithTag(PagedPool, BufferSize, 'BTMS');
259 if (AllData == NULL)
260 {
261 DPRINT1("Failed to allocate %lu bytes for SMBIOS tables\n", BufferSize);
262 return;
263 }
264
265 /* Query the buffer data */
266 Status = IoWMIQueryAllData(DataBlockObject, &BufferSize, AllData);
267 if (!NT_SUCCESS(Status))
268 {
269 DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
270 ExFreePoolWithTag(AllData, 'BTMS');
271 return;
272 }
273
274 /* Parse the table */
275 i8042ParseSMBiosTables(AllData + 1,
276 AllData->WnodeHeader.BufferSize);
277
278 /* Free the buffer */
279 ExFreePoolWithTag(AllData, 'BTMS');
280 }
281