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