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)
16 #include <libs/umpnpmgr/sysguid.h>
22 PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData
;
25 RtlInitUnicodeString(&ResetDeviceData
.DeviceInstance
, DeviceId
);
26 Status
= NtPlugPlayControl(PlugPlayControlResetDevice
, &ResetDeviceData
, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA
));
27 if (!NT_SUCCESS(Status
))
29 DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status
);
41 IN LPCWSTR HardwareId
)
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";
52 UNICODE_STRING StringU
;
53 OBJECT_ATTRIBUTES ObjectAttributes
;
56 PCWSTR Driver
, ClassGuid
, ImagePath
;
61 BOOLEAN deviceInstalled
= FALSE
;
63 /* Check if we know the hardware */
64 if (!SpInfFindFirstLine(hInf
, L
"HardwareIdsDatabase", HardwareId
, &Context
))
66 if (!INF_GetDataField(&Context
, 1, &Driver
))
69 /* Get associated class GUID (if any) */
70 if (!INF_GetDataField(&Context
, 2, &ClassGuid
))
73 /* Find associated driver name */
74 /* FIXME: check in other sections too! */
75 if (!SpInfFindFirstLine(hInf
, L
"BootBusExtenders.Load", Driver
, &Context
)
76 && !SpInfFindFirstLine(hInf
, L
"BusExtenders.Load", Driver
, &Context
)
77 && !SpInfFindFirstLine(hInf
, L
"SCSI.Load", Driver
, &Context
)
78 && !SpInfFindFirstLine(hInf
, L
"InputDevicesSupport.Load", Driver
, &Context
)
79 && !SpInfFindFirstLine(hInf
, L
"Keyboard.Load", Driver
, &Context
))
81 INF_FreeData(ClassGuid
);
86 if (!INF_GetDataField(&Context
, 1, &ImagePath
))
88 INF_FreeData(ClassGuid
);
93 /* Prepare full driver path */
94 dwValue
= PathPrefix
.MaximumLength
+ wcslen(ImagePath
) * sizeof(WCHAR
);
95 FullImagePath
= (PWSTR
)RtlAllocateHeap(ProcessHeap
, 0, dwValue
);
98 DPRINT1("RtlAllocateHeap() failed\n");
99 INF_FreeData(ImagePath
);
100 INF_FreeData(ClassGuid
);
101 INF_FreeData(Driver
);
104 RtlCopyMemory(FullImagePath
, PathPrefix
.Buffer
, PathPrefix
.MaximumLength
);
105 ConcatPaths(FullImagePath
, dwValue
/ sizeof(WCHAR
), 1, ImagePath
);
107 DPRINT1("Using driver '%S' for device '%S'\n", ImagePath
, DeviceId
);
109 /* Create service key */
110 RtlInitUnicodeString(&StringU
, Driver
);
111 InitializeObjectAttributes(&ObjectAttributes
, &StringU
, OBJ_CASE_INSENSITIVE
, hServices
, NULL
);
112 Status
= NtCreateKey(&hService
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_NON_VOLATILE
, &Disposition
);
113 if (!NT_SUCCESS(Status
))
115 DPRINT1("NtCreateKey('%wZ') failed with status 0x%08x\n", &StringU
, Status
);
116 RtlFreeHeap(ProcessHeap
, 0, FullImagePath
);
117 INF_FreeData(ImagePath
);
118 INF_FreeData(ClassGuid
);
119 INF_FreeData(Driver
);
123 /* Fill service key */
124 if (Disposition
== REG_CREATED_NEW_KEY
)
127 NtSetValueKey(hService
,
135 NtSetValueKey(hService
,
142 dwValue
= SERVICE_KERNEL_DRIVER
;
143 NtSetValueKey(hService
,
150 /* HACK: don't put any path in registry */
151 NtSetValueKey(hService
,
156 (wcslen(ImagePath
) + 1) * sizeof(WCHAR
));
158 INF_FreeData(ImagePath
);
160 if (ClassGuid
&&_wcsicmp(ClassGuid
, L
"{4D36E96B-E325-11CE-BFC1-08002BE10318}") == 0)
162 DPRINT1("Installing keyboard class driver for '%S'\n", DeviceId
);
163 NtSetValueKey(hDeviceKey
,
168 (wcslen(keyboardClass
) + 2) * sizeof(WCHAR
));
171 INF_FreeData(ClassGuid
);
173 /* Associate device with the service we just filled */
174 Status
= NtSetValueKey(hDeviceKey
,
179 (wcslen(Driver
) + 1) * sizeof(WCHAR
));
180 if (NT_SUCCESS(Status
))
182 /* Restart the device, so it will use the driver we registered */
183 deviceInstalled
= ResetDevice(DeviceId
);
186 INF_FreeData(Driver
);
188 /* HACK: Update driver path */
189 NtSetValueKey(hService
,
194 (wcslen(FullImagePath
) + 1) * sizeof(WCHAR
));
195 RtlFreeHeap(ProcessHeap
, 0, FullImagePath
);
199 return deviceInstalled
;
209 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
210 UNICODE_STRING CompatibleIDsU
= RTL_CONSTANT_STRING(L
"CompatibleIDs");
212 UNICODE_STRING DeviceIdU
;
213 OBJECT_ATTRIBUTES ObjectAttributes
;
215 PKEY_VALUE_PARTIAL_INFORMATION pPartialInformation
= NULL
;
218 BOOLEAN bDriverInstalled
= FALSE
;
221 RtlInitUnicodeString(&DeviceIdU
, DeviceId
);
222 InitializeObjectAttributes(&ObjectAttributes
, &DeviceIdU
, OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
223 Status
= NtOpenKey(&hDeviceKey
, KEY_QUERY_VALUE
| KEY_SET_VALUE
, &ObjectAttributes
);
224 if (!NT_SUCCESS(Status
))
226 DPRINT("Unable to open subkey '%S'\n", DeviceId
);
230 Status
= NtQueryValueKey(
233 KeyValuePartialInformation
,
237 if (Status
== STATUS_BUFFER_TOO_SMALL
)
239 pPartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)RtlAllocateHeap(ProcessHeap
, 0, ulRequired
);
240 if (!pPartialInformation
)
242 DPRINT1("RtlAllocateHeap() failed\n");
246 Status
= NtQueryValueKey(
249 KeyValuePartialInformation
,
254 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
258 else if (!NT_SUCCESS(Status
))
260 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status
);
261 if (pPartialInformation
)
262 RtlFreeHeap(ProcessHeap
, 0, pPartialInformation
);
266 else if (pPartialInformation
)
268 for (HardwareID
= (LPCWSTR
)pPartialInformation
->Data
;
269 (PUCHAR
)HardwareID
< pPartialInformation
->Data
+ pPartialInformation
->DataLength
271 && !bDriverInstalled
;
272 HardwareID
+= wcslen(HardwareID
) + 1)
274 bDriverInstalled
= InstallDriver(hInf
, hServices
,hDeviceKey
, DeviceId
, HardwareID
);
278 if (!bDriverInstalled
)
280 if (pPartialInformation
)
282 RtlFreeHeap(ProcessHeap
, 0, pPartialInformation
);
283 pPartialInformation
= NULL
;
285 Status
= NtQueryValueKey(
288 KeyValuePartialInformation
,
292 if (Status
== STATUS_BUFFER_TOO_SMALL
)
294 pPartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)RtlAllocateHeap(ProcessHeap
, 0, ulRequired
);
295 if (!pPartialInformation
)
297 DPRINT("RtlAllocateHeap() failed\n");
301 Status
= NtQueryValueKey(
304 KeyValuePartialInformation
,
309 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
313 else if (!NT_SUCCESS(Status
))
315 if (pPartialInformation
)
316 RtlFreeHeap(ProcessHeap
, 0, pPartialInformation
);
318 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status
);
321 else if (pPartialInformation
)
323 for (HardwareID
= (LPCWSTR
)pPartialInformation
->Data
;
324 (PUCHAR
)HardwareID
< pPartialInformation
->Data
+ pPartialInformation
->DataLength
326 && !bDriverInstalled
;
327 HardwareID
+= wcslen(HardwareID
) + 1)
329 bDriverInstalled
= InstallDriver(hInf
, hServices
,hDeviceKey
, DeviceId
, HardwareID
);
333 if (!bDriverInstalled
)
334 DPRINT("No driver available for %S\n", DeviceId
);
336 RtlFreeHeap(ProcessHeap
, 0, pPartialInformation
);
341 EventThread(IN LPVOID lpParameter
)
343 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
344 UNICODE_STRING ServicesU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
346 PPLUGPLAY_EVENT_BLOCK PnpEvent
, NewPnpEvent
;
347 OBJECT_ATTRIBUTES ObjectAttributes
;
350 HANDLE hEnum
, hServices
;
353 hInf
= *(HINF
*)lpParameter
;
355 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
356 Status
= NtOpenKey(&hEnum
, KEY_QUERY_VALUE
, &ObjectAttributes
);
357 if (!NT_SUCCESS(Status
))
359 DPRINT1("NtOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
363 InitializeObjectAttributes(&ObjectAttributes
, &ServicesU
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
364 Status
= NtCreateKey(&hServices
, KEY_ALL_ACCESS
, &ObjectAttributes
, 0, NULL
, REG_OPTION_NON_VOLATILE
, NULL
);
365 if (!NT_SUCCESS(Status
))
367 DPRINT1("NtCreateKey('%wZ') failed with status 0x%08lx\n", &ServicesU
, Status
);
372 PnpEventSize
= 0x1000;
373 PnpEvent
= RtlAllocateHeap(ProcessHeap
, 0, PnpEventSize
);
374 if (PnpEvent
== NULL
)
376 Status
= STATUS_NO_MEMORY
;
382 DPRINT("Calling NtGetPlugPlayEvent()\n");
384 /* Wait for the next PnP event */
385 Status
= NtGetPlugPlayEvent(0, 0, PnpEvent
, PnpEventSize
);
387 /* Resize the buffer for the PnP event if it's too small */
388 if (Status
== STATUS_BUFFER_TOO_SMALL
)
390 PnpEventSize
+= 0x400;
391 NewPnpEvent
= RtlReAllocateHeap(ProcessHeap
, 0, PnpEvent
, PnpEventSize
);
392 if (NewPnpEvent
== NULL
)
394 Status
= STATUS_NO_MEMORY
;
397 PnpEvent
= NewPnpEvent
;
401 if (!NT_SUCCESS(Status
))
403 DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status
);
407 /* Process the PnP event */
408 DPRINT("Received PnP Event\n");
409 if (IsEqualIID(&PnpEvent
->EventGuid
, (REFGUID
)&GUID_DEVICE_ENUMERATED
))
411 DPRINT("Device arrival event: %S\n", PnpEvent
->TargetDevice
.DeviceIds
);
412 InstallDevice(hInf
, hEnum
, hServices
, PnpEvent
->TargetDevice
.DeviceIds
);
416 DPRINT("Unknown event\n");
419 /* Dequeue the current PnP event and signal the next one */
420 NtPlugPlayControl(PlugPlayControlUserResponse
, NULL
, 0);
423 Status
= STATUS_SUCCESS
;
427 RtlFreeHeap(ProcessHeap
, 0, PnpEvent
);
436 PnpEventThread(IN LPVOID lpParameter
)
439 Status
= EventThread(lpParameter
);
440 NtTerminateThread(NtCurrentThread(), Status
);