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 PCWSTR Driver, ClassGuid, ImagePath; 57 PWSTR FullImagePath; 58 ULONG dwValue; 59 ULONG Disposition; 60 NTSTATUS Status; 61 BOOLEAN deviceInstalled = FALSE; 62 63 /* Check if we know the hardware */ 64 if (!SpInfFindFirstLine(hInf, L"HardwareIdsDatabase", HardwareId, &Context)) 65 return FALSE; 66 if (!INF_GetDataField(&Context, 1, &Driver)) 67 return FALSE; 68 69 /* Get associated class GUID (if any) */ 70 if (!INF_GetDataField(&Context, 2, &ClassGuid)) 71 ClassGuid = NULL; 72 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)) 80 { 81 INF_FreeData(ClassGuid); 82 INF_FreeData(Driver); 83 return FALSE; 84 } 85 86 if (!INF_GetDataField(&Context, 1, &ImagePath)) 87 { 88 INF_FreeData(ClassGuid); 89 INF_FreeData(Driver); 90 return FALSE; 91 } 92 93 /* Prepare full driver path */ 94 dwValue = PathPrefix.MaximumLength + wcslen(ImagePath) * sizeof(WCHAR); 95 FullImagePath = (PWSTR)RtlAllocateHeap(ProcessHeap, 0, dwValue); 96 if (!FullImagePath) 97 { 98 DPRINT1("RtlAllocateHeap() failed\n"); 99 INF_FreeData(ImagePath); 100 INF_FreeData(ClassGuid); 101 INF_FreeData(Driver); 102 return FALSE; 103 } 104 RtlCopyMemory(FullImagePath, PathPrefix.Buffer, PathPrefix.MaximumLength); 105 ConcatPaths(FullImagePath, dwValue / sizeof(WCHAR), 1, ImagePath); 106 107 DPRINT1("Using driver '%S' for device '%S'\n", ImagePath, DeviceId); 108 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)) 114 { 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); 120 return FALSE; 121 } 122 123 /* Fill service key */ 124 if (Disposition == REG_CREATED_NEW_KEY) 125 { 126 dwValue = 0; 127 NtSetValueKey(hService, 128 &ErrorControlU, 129 0, 130 REG_DWORD, 131 &dwValue, 132 sizeof(dwValue)); 133 134 dwValue = 0; 135 NtSetValueKey(hService, 136 &StartU, 137 0, 138 REG_DWORD, 139 &dwValue, 140 sizeof(dwValue)); 141 142 dwValue = SERVICE_KERNEL_DRIVER; 143 NtSetValueKey(hService, 144 &TypeU, 145 0, 146 REG_DWORD, 147 &dwValue, 148 sizeof(dwValue)); 149 } 150 /* HACK: don't put any path in registry */ 151 NtSetValueKey(hService, 152 &ImagePathU, 153 0, 154 REG_SZ, 155 (PVOID)ImagePath, 156 (wcslen(ImagePath) + 1) * sizeof(WCHAR)); 157 158 INF_FreeData(ImagePath); 159 160 if (ClassGuid &&_wcsicmp(ClassGuid, L"{4D36E96B-E325-11CE-BFC1-08002BE10318}") == 0) 161 { 162 DPRINT1("Installing keyboard class driver for '%S'\n", DeviceId); 163 NtSetValueKey(hDeviceKey, 164 &UpperFiltersU, 165 0, 166 REG_MULTI_SZ, 167 keyboardClass, 168 (wcslen(keyboardClass) + 2) * sizeof(WCHAR)); 169 } 170 171 INF_FreeData(ClassGuid); 172 173 /* Associate device with the service we just filled */ 174 Status = NtSetValueKey(hDeviceKey, 175 &ServiceU, 176 0, 177 REG_SZ, 178 (PVOID)Driver, 179 (wcslen(Driver) + 1) * sizeof(WCHAR)); 180 if (NT_SUCCESS(Status)) 181 { 182 /* Restart the device, so it will use the driver we registered */ 183 deviceInstalled = ResetDevice(DeviceId); 184 } 185 186 INF_FreeData(Driver); 187 188 /* HACK: Update driver path */ 189 NtSetValueKey(hService, 190 &ImagePathU, 191 0, 192 REG_SZ, 193 FullImagePath, 194 (wcslen(FullImagePath) + 1) * sizeof(WCHAR)); 195 RtlFreeHeap(ProcessHeap, 0, FullImagePath); 196 197 NtClose(hService); 198 199 return deviceInstalled; 200 } 201 202 VOID 203 InstallDevice( 204 IN HINF hInf, 205 IN HANDLE hEnum, 206 IN HANDLE hServices, 207 IN LPCWSTR DeviceId) 208 { 209 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID"); 210 UNICODE_STRING CompatibleIDsU = RTL_CONSTANT_STRING(L"CompatibleIDs"); 211 212 UNICODE_STRING DeviceIdU; 213 OBJECT_ATTRIBUTES ObjectAttributes; 214 LPCWSTR HardwareID; 215 PKEY_VALUE_PARTIAL_INFORMATION pPartialInformation = NULL; 216 HANDLE hDeviceKey; 217 ULONG ulRequired; 218 BOOLEAN bDriverInstalled = FALSE; 219 NTSTATUS Status; 220 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)) 225 { 226 DPRINT("Unable to open subkey '%S'\n", DeviceId); 227 return; 228 } 229 230 Status = NtQueryValueKey( 231 hDeviceKey, 232 &HardwareIDU, 233 KeyValuePartialInformation, 234 NULL, 235 0, 236 &ulRequired); 237 if (Status == STATUS_BUFFER_TOO_SMALL) 238 { 239 pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired); 240 if (!pPartialInformation) 241 { 242 DPRINT1("RtlAllocateHeap() failed\n"); 243 NtClose(hDeviceKey); 244 return; 245 } 246 Status = NtQueryValueKey( 247 hDeviceKey, 248 &HardwareIDU, 249 KeyValuePartialInformation, 250 pPartialInformation, 251 ulRequired, 252 &ulRequired); 253 } 254 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 255 { 256 /* Nothing to do */ 257 } 258 else if (!NT_SUCCESS(Status)) 259 { 260 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status); 261 if (pPartialInformation) 262 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 263 NtClose(hDeviceKey); 264 return; 265 } 266 else if (pPartialInformation) 267 { 268 for (HardwareID = (LPCWSTR)pPartialInformation->Data; 269 (PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength 270 && *HardwareID 271 && !bDriverInstalled; 272 HardwareID += wcslen(HardwareID) + 1) 273 { 274 bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID); 275 } 276 } 277 278 if (!bDriverInstalled) 279 { 280 if (pPartialInformation) 281 { 282 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 283 pPartialInformation = NULL; 284 } 285 Status = NtQueryValueKey( 286 hDeviceKey, 287 &CompatibleIDsU, 288 KeyValuePartialInformation, 289 NULL, 290 0, 291 &ulRequired); 292 if (Status == STATUS_BUFFER_TOO_SMALL) 293 { 294 pPartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(ProcessHeap, 0, ulRequired); 295 if (!pPartialInformation) 296 { 297 DPRINT("RtlAllocateHeap() failed\n"); 298 NtClose(hDeviceKey); 299 return; 300 } 301 Status = NtQueryValueKey( 302 hDeviceKey, 303 &CompatibleIDsU, 304 KeyValuePartialInformation, 305 pPartialInformation, 306 ulRequired, 307 &ulRequired); 308 } 309 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 310 { 311 /* Nothing to do */ 312 } 313 else if (!NT_SUCCESS(Status)) 314 { 315 if (pPartialInformation) 316 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 317 NtClose(hDeviceKey); 318 DPRINT1("NtQueryValueKey() failed with status 0x%08x\n", Status); 319 return; 320 } 321 else if (pPartialInformation) 322 { 323 for (HardwareID = (LPCWSTR)pPartialInformation->Data; 324 (PUCHAR)HardwareID < pPartialInformation->Data + pPartialInformation->DataLength 325 && *HardwareID 326 && !bDriverInstalled; 327 HardwareID += wcslen(HardwareID) + 1) 328 { 329 bDriverInstalled = InstallDriver(hInf, hServices,hDeviceKey, DeviceId, HardwareID); 330 } 331 } 332 } 333 if (!bDriverInstalled) 334 DPRINT("No driver available for %S\n", DeviceId); 335 336 RtlFreeHeap(ProcessHeap, 0, pPartialInformation); 337 NtClose(hDeviceKey); 338 } 339 340 NTSTATUS 341 EventThread(IN LPVOID lpParameter) 342 { 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"); 345 346 PPLUGPLAY_EVENT_BLOCK PnpEvent, NewPnpEvent; 347 OBJECT_ATTRIBUTES ObjectAttributes; 348 ULONG PnpEventSize; 349 HINF hInf; 350 HANDLE hEnum, hServices; 351 NTSTATUS Status; 352 353 hInf = *(HINF*)lpParameter; 354 355 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL); 356 Status = NtOpenKey(&hEnum, KEY_QUERY_VALUE, &ObjectAttributes); 357 if (!NT_SUCCESS(Status)) 358 { 359 DPRINT1("NtOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status); 360 return Status; 361 } 362 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)) 366 { 367 DPRINT1("NtCreateKey('%wZ') failed with status 0x%08lx\n", &ServicesU, Status); 368 NtClose(hEnum); 369 return Status; 370 } 371 372 PnpEventSize = 0x1000; 373 PnpEvent = RtlAllocateHeap(ProcessHeap, 0, PnpEventSize); 374 if (PnpEvent == NULL) 375 { 376 Status = STATUS_NO_MEMORY; 377 goto Quit; 378 } 379 380 for (;;) 381 { 382 DPRINT("Calling NtGetPlugPlayEvent()\n"); 383 384 /* Wait for the next PnP event */ 385 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize); 386 387 /* Resize the buffer for the PnP event if it's too small */ 388 if (Status == STATUS_BUFFER_TOO_SMALL) 389 { 390 PnpEventSize += 0x400; 391 NewPnpEvent = RtlReAllocateHeap(ProcessHeap, 0, PnpEvent, PnpEventSize); 392 if (NewPnpEvent == NULL) 393 { 394 Status = STATUS_NO_MEMORY; 395 goto Quit; 396 } 397 PnpEvent = NewPnpEvent; 398 continue; 399 } 400 401 if (!NT_SUCCESS(Status)) 402 { 403 DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status); 404 break; 405 } 406 407 /* Process the PnP event */ 408 DPRINT("Received PnP Event\n"); 409 if (IsEqualIID(&PnpEvent->EventGuid, (REFGUID)&GUID_DEVICE_ENUMERATED)) 410 { 411 DPRINT("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds); 412 InstallDevice(hInf, hEnum, hServices, PnpEvent->TargetDevice.DeviceIds); 413 } 414 else 415 { 416 DPRINT("Unknown event\n"); 417 } 418 419 /* Dequeue the current PnP event and signal the next one */ 420 NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0); 421 } 422 423 Status = STATUS_SUCCESS; 424 425 Quit: 426 if (PnpEvent) 427 RtlFreeHeap(ProcessHeap, 0, PnpEvent); 428 429 NtClose(hServices); 430 NtClose(hEnum); 431 432 return Status; 433 } 434 435 DWORD WINAPI 436 PnpEventThread(IN LPVOID lpParameter) 437 { 438 NTSTATUS Status; 439 Status = EventThread(lpParameter); 440 NtTerminateThread(NtCurrentThread(), Status); 441 return 0; 442 } 443