3a8dec424d8adc8b44e78da84f6d828efea3275f
[reactos.git] / base / setup / usetup / devinst.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS text-mode setup
4 * FILE: base/setup/usetup/devinst.c
5 * PURPOSE: Device installation
6 * PROGRAMMER: Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 #include <usetup.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #define INITGUID
15 #include <guiddef.h>
16 #include <libs/umpnpmgr/sysguid.h>
17
18 BOOLEAN
19 ResetDevice(
20 IN LPCWSTR DeviceId)
21 {
22 PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
23 NTSTATUS Status;
24
25 RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DeviceId);
26 Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
27 if (!NT_SUCCESS(Status))
28 {
29 DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status);
30 return FALSE;
31 }
32 return TRUE;
33 }
34
35 BOOLEAN
36 InstallDriver(
37 IN HINF hInf,
38 IN HANDLE hServices,
39 IN HANDLE hDeviceKey,
40 IN LPCWSTR DeviceId,
41 IN LPCWSTR HardwareId)
42 {
43 UNICODE_STRING PathPrefix = RTL_CONSTANT_STRING(L"System32\\DRIVERS\\");
44 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service");
45 UNICODE_STRING ErrorControlU = RTL_CONSTANT_STRING(L"ErrorControl");
46 UNICODE_STRING ImagePathU = RTL_CONSTANT_STRING(L"ImagePath");
47 UNICODE_STRING StartU = RTL_CONSTANT_STRING(L"Start");
48 UNICODE_STRING TypeU = RTL_CONSTANT_STRING(L"Type");
49 UNICODE_STRING UpperFiltersU = RTL_CONSTANT_STRING(L"UpperFilters");
50 PWSTR keyboardClass = L"kbdclass\0";
51
52 UNICODE_STRING StringU;
53 OBJECT_ATTRIBUTES ObjectAttributes;
54 HANDLE hService;
55 INFCONTEXT Context;
56 PWSTR Driver, ClassGuid, ImagePath, FullImagePath;
57 ULONG dwValue;
58 ULONG Disposition;
59 NTSTATUS Status;
60 BOOLEAN deviceInstalled = FALSE;
61
62 /* Check if we know the hardware */
63 if (!SetupFindFirstLineW(hInf, L"HardwareIdsDatabase", HardwareId, &Context))
64 return FALSE;
65 if (!INF_GetDataField(&Context, 1, &Driver))
66 return FALSE;
67
68 /* Get associated class GUID (if any) */
69 if (!INF_GetDataField(&Context, 2, &ClassGuid))
70 ClassGuid = NULL;
71
72 /* Find associated driver name */
73 /* FIXME: check in other sections too! */
74 if (!SetupFindFirstLineW(hInf, L"BootBusExtenders.Load", Driver, &Context)
75 && !SetupFindFirstLineW(hInf, L"BusExtenders.Load", Driver, &Context)
76 && !SetupFindFirstLineW(hInf, L"SCSI.Load", Driver, &Context)
77 && !SetupFindFirstLineW(hInf, L"InputDevicesSupport.Load", Driver, &Context)
78 && !SetupFindFirstLineW(hInf, L"Keyboard.Load", Driver, &Context))
79 {
80 INF_FreeData(ClassGuid);
81 INF_FreeData(Driver);
82 return FALSE;
83 }
84
85 if (!INF_GetDataField(&Context, 1, &ImagePath))
86 {
87 INF_FreeData(ClassGuid);
88 INF_FreeData(Driver);
89 return FALSE;
90 }
91
92 /* Prepare full driver path */
93 dwValue = PathPrefix.MaximumLength + wcslen(ImagePath) * sizeof(WCHAR);
94 FullImagePath = (PWSTR)RtlAllocateHeap(ProcessHeap, 0, dwValue);
95 if (!FullImagePath)
96 {
97 DPRINT1("RtlAllocateHeap() failed\n");
98 INF_FreeData(ImagePath);
99 INF_FreeData(ClassGuid);
100 INF_FreeData(Driver);
101 return FALSE;
102 }
103 RtlCopyMemory(FullImagePath, PathPrefix.Buffer, PathPrefix.MaximumLength);
104 ConcatPaths(FullImagePath, dwValue / sizeof(WCHAR), 1, ImagePath);
105
106 DPRINT1("Using driver '%S' for device '%S'\n", ImagePath, DeviceId);
107
108 /* Create service key */
109 RtlInitUnicodeString(&StringU, Driver);
110 InitializeObjectAttributes(&ObjectAttributes, &StringU, 0, hServices, NULL);
111 Status = NtCreateKey(&hService, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &Disposition);
112 if (!NT_SUCCESS(Status))
113 {
114 DPRINT1("NtCreateKey('%wZ') failed with status 0x%08x\n", &StringU, Status);
115 RtlFreeHeap(ProcessHeap, 0, FullImagePath);
116 INF_FreeData(ImagePath);
117 INF_FreeData(ClassGuid);
118 INF_FreeData(Driver);
119 return FALSE;
120 }
121
122 /* Fill service key */
123 if (Disposition == REG_CREATED_NEW_KEY)
124 {
125 dwValue = 0;
126 NtSetValueKey(hService,
127 &ErrorControlU,
128 0,
129 REG_DWORD,
130 &dwValue,
131 sizeof(dwValue));
132
133 dwValue = 0;
134 NtSetValueKey(hService,
135 &StartU,
136 0,
137 REG_DWORD,
138 &dwValue,
139 sizeof(dwValue));
140
141 dwValue = SERVICE_KERNEL_DRIVER;
142 NtSetValueKey(hService,
143 &TypeU,
144 0,
145 REG_DWORD,
146 &dwValue,
147 sizeof(dwValue));
148 }
149 /* HACK: don't put any path in registry */
150 NtSetValueKey(hService,
151 &ImagePathU,
152 0,
153 REG_SZ,
154 ImagePath,
155 (wcslen(ImagePath) + 1) * sizeof(WCHAR));
156
157 INF_FreeData(ImagePath);
158
159 if (ClassGuid &&_wcsicmp(ClassGuid, L"{4D36E96B-E325-11CE-BFC1-08002BE10318}") == 0)
160 {
161 DPRINT1("Installing keyboard class driver for '%S'\n", DeviceId);
162 NtSetValueKey(hDeviceKey,
163 &UpperFiltersU,
164 0,
165 REG_MULTI_SZ,
166 keyboardClass,
167 (wcslen(keyboardClass) + 2) * sizeof(WCHAR));
168 }
169
170 INF_FreeData(ClassGuid);
171
172 /* Associate device with the service we just filled */
173 Status = NtSetValueKey(hDeviceKey,
174 &ServiceU,
175 0,
176 REG_SZ,
177 Driver,
178 (wcslen(Driver) + 1) * sizeof(WCHAR));
179 if (NT_SUCCESS(Status))
180 {
181 /* Restart the device, so it will use the driver we registered */
182 deviceInstalled = ResetDevice(DeviceId);
183 }
184
185 INF_FreeData(Driver);
186
187 /* HACK: Update driver path */
188 NtSetValueKey(hService,
189 &ImagePathU,
190 0,
191 REG_SZ,
192 FullImagePath,
193 (wcslen(FullImagePath) + 1) * sizeof(WCHAR));
194 RtlFreeHeap(ProcessHeap, 0, FullImagePath);
195
196 NtClose(hService);
197
198 return deviceInstalled;
199 }
200
201 VOID
202 InstallDevice(
203 IN HINF hInf,
204 IN HANDLE hEnum,
205 IN HANDLE hServices,
206 IN LPCWSTR DeviceId)
207 {
208 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
209 UNICODE_STRING CompatibleIDsU = RTL_CONSTANT_STRING(L"CompatibleIDs");
210
211 UNICODE_STRING DeviceIdU;
212 OBJECT_ATTRIBUTES ObjectAttributes;
213 LPCWSTR HardwareID;
214 PKEY_VALUE_PARTIAL_INFORMATION pPartialInformation = NULL;
215 HANDLE hDeviceKey;
216 ULONG ulRequired;
217 BOOLEAN bDriverInstalled = FALSE;
218 NTSTATUS Status;
219
220 RtlInitUnicodeString(&DeviceIdU, DeviceId);
221 InitializeObjectAttributes(&ObjectAttributes, &DeviceIdU, 0, hEnum, NULL);
222 Status = NtOpenKey(&hDeviceKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes);
223 if (!NT_SUCCESS(Status))
224 {
225 DPRINT("Unable to open subkey '%S'\n", DeviceId);
226 return;
227 }
228
229 Status = NtQueryValueKey(
230 hDeviceKey,
231 &HardwareIDU,
232 KeyValuePartialInformation,
233 NULL,
234 0,
235 &ulRequired);
236 if (Status == STATUS_BUFFER_TOO_SMALL)
237 {
238 pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired);
239 if (!pPartialInformation)
240 {
241 DPRINT1("RtlAllocateHeap() failed\n");
242 NtClose(hDeviceKey);
243 return;
244 }
245 Status = NtQueryValueKey(
246 hDeviceKey,
247 &HardwareIDU,
248 KeyValuePartialInformation,
249 pPartialInformation,
250 ulRequired,
251 &ulRequired);
252 }
253 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
254 {
255 /* Nothing to do */
256 }
257 else if (!NT_SUCCESS(Status))
258 {
259 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status);
260 if (pPartialInformation)
261 RtlFreeHeap(ProcessHeap, 0, pPartialInformation);
262 NtClose(hDeviceKey);
263 return;
264 }
265 else if (pPartialInformation)
266 {
267 for (HardwareID = (LPCWSTR)pPartialInformation->Data;
268 (PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength
269 && *HardwareID
270 && !bDriverInstalled;
271 HardwareID += wcslen(HardwareID) + 1)
272 {
273 bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID);
274 }
275 }
276
277 if (!bDriverInstalled)
278 {
279 if (pPartialInformation)
280 {
281 RtlFreeHeap(ProcessHeap, 0, pPartialInformation);
282 pPartialInformation = NULL;
283 }
284 Status = NtQueryValueKey(
285 hDeviceKey,
286 &CompatibleIDsU,
287 KeyValuePartialInformation,
288 NULL,
289 0,
290 &ulRequired);
291 if (Status == STATUS_BUFFER_TOO_SMALL)
292 {
293 pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired);
294 if (!pPartialInformation)
295 {
296 DPRINT("RtlAllocateHeap() failed\n");
297 NtClose(hDeviceKey);
298 return;
299 }
300 Status = NtQueryValueKey(
301 hDeviceKey,
302 &CompatibleIDsU,
303 KeyValuePartialInformation,
304 pPartialInformation,
305 ulRequired,
306 &ulRequired);
307 }
308 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
309 {
310 /* Nothing to do */
311 }
312 else if (!NT_SUCCESS(Status))
313 {
314 if (pPartialInformation)
315 RtlFreeHeap(ProcessHeap, 0, pPartialInformation);
316 NtClose(hDeviceKey);
317 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status);
318 return;
319 }
320 else if (pPartialInformation)
321 {
322 for (HardwareID = (LPCWSTR)pPartialInformation->Data;
323 (PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength
324 && *HardwareID
325 && !bDriverInstalled;
326 HardwareID += wcslen(HardwareID) + 1)
327 {
328 bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID);
329 }
330 }
331 }
332 if (!bDriverInstalled)
333 DPRINT("No driver available for %S\n", DeviceId);
334
335 RtlFreeHeap(ProcessHeap, 0, pPartialInformation);
336 NtClose(hDeviceKey);
337 }
338
339 NTSTATUS
340 EventThread(IN LPVOID lpParameter)
341 {
342 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
343 UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
344
345 PPLUGPLAY_EVENT_BLOCK PnpEvent, NewPnpEvent;
346 OBJECT_ATTRIBUTES ObjectAttributes;
347 ULONG PnpEventSize;
348 HINF hInf;
349 HANDLE hEnum, hServices;
350 NTSTATUS Status;
351
352 hInf = *(HINF*)lpParameter;
353
354 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL);
355 Status = NtOpenKey(&hEnum, KEY_QUERY_VALUE, &ObjectAttributes);
356 if (!NT_SUCCESS(Status))
357 {
358 DPRINT1("NtOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
359 return Status;
360 }
361
362 InitializeObjectAttributes(&ObjectAttributes, &ServicesU, OBJ_CASE_INSENSITIVE, NULL, NULL);
363 Status = NtCreateKey(&hServices, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
364 if (!NT_SUCCESS(Status))
365 {
366 DPRINT1("NtCreateKey('%wZ') failed with status 0x%08lx\n", &ServicesU, Status);
367 NtClose(hEnum);
368 return Status;
369 }
370
371 PnpEventSize = 0x1000;
372 PnpEvent = RtlAllocateHeap(ProcessHeap, 0, PnpEventSize);
373 if (PnpEvent == NULL)
374 {
375 Status = STATUS_NO_MEMORY;
376 goto Quit;
377 }
378
379 for (;;)
380 {
381 DPRINT("Calling NtGetPlugPlayEvent()\n");
382
383 /* Wait for the next PnP event */
384 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize);
385
386 /* Resize the buffer for the PnP event if it's too small */
387 if (Status == STATUS_BUFFER_TOO_SMALL)
388 {
389 PnpEventSize += 0x400;
390 NewPnpEvent = RtlReAllocateHeap(ProcessHeap, 0, PnpEvent, PnpEventSize);
391 if (NewPnpEvent == NULL)
392 {
393 Status = STATUS_NO_MEMORY;
394 goto Quit;
395 }
396 PnpEvent = NewPnpEvent;
397 continue;
398 }
399
400 if (!NT_SUCCESS(Status))
401 {
402 DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status);
403 break;
404 }
405
406 /* Process the PnP event */
407 DPRINT("Received PnP Event\n");
408 if (IsEqualIID(&PnpEvent->EventGuid, (REFGUID)&GUID_DEVICE_ENUMERATED))
409 {
410 DPRINT("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds);
411 InstallDevice(hInf, hEnum, hServices, PnpEvent->TargetDevice.DeviceIds);
412 }
413 else
414 {
415 DPRINT("Unknown event\n");
416 }
417
418 /* Dequeue the current PnP event and signal the next one */
419 NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0);
420 }
421
422 Status = STATUS_SUCCESS;
423
424 Quit:
425 if (PnpEvent)
426 RtlFreeHeap(ProcessHeap, 0, PnpEvent);
427
428 NtClose(hServices);
429 NtClose(hEnum);
430
431 return Status;
432 }
433
434 DWORD WINAPI
435 PnpEventThread(IN LPVOID lpParameter)
436 {
437 NTSTATUS Status;
438 Status = EventThread(lpParameter);
439 NtTerminateThread(NtCurrentThread(), Status);
440 return 0;
441 }