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