- Add registry property constants.
[reactos.git] / reactos / services / umpnpmgr / umpnpmgr.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: services/umpnpmgr/umpnpmgr.c
23 * PURPOSE: User-mode Plug and Play manager
24 * PROGRAMMER: Eric Kohl
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include <windows.h>
30 #define NTOS_MODE_USER
31 #include <ndk/ntndk.h>
32 #include <ndk/sysguid.h>
33 #include <ddk/wdmguid.h>
34 #include <ddk/cfgmgr32.h>
35
36 #include <rpc.h>
37 #include <rpcdce.h>
38
39 #include "pnp_c.h"
40
41 #define NDEBUG
42 #include <debug.h>
43
44 /* GLOBALS ******************************************************************/
45
46 static VOID CALLBACK
47 ServiceMain(DWORD argc, LPTSTR *argv);
48
49 static SERVICE_TABLE_ENTRY ServiceTable[2] =
50 {
51 {TEXT("PlugPlay"), ServiceMain},
52 {NULL, NULL}
53 };
54
55 static WCHAR szRootDeviceId[] = L"HTREE\\ROOT\\0";
56
57 static HKEY hEnumKey = NULL;
58 static HKEY hClassKey = NULL;
59
60 /* FUNCTIONS *****************************************************************/
61
62 static DWORD WINAPI
63 RpcServerThread(LPVOID lpParameter)
64 {
65 RPC_STATUS Status;
66
67 DPRINT("RpcServerThread() called\n");
68
69 Status = RpcServerUseProtseqEpW(L"ncacn_np",
70 20,
71 L"\\pipe\\umpnpmgr",
72 NULL); // Security descriptor
73 if (Status != RPC_S_OK)
74 {
75 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
76 return 0;
77 }
78
79 Status = RpcServerRegisterIf(pnp_v1_0_s_ifspec,
80 NULL,
81 NULL);
82 if (Status != RPC_S_OK)
83 {
84 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
85 return 0;
86 }
87
88 Status = RpcServerListen(1,
89 20,
90 FALSE);
91 if (Status != RPC_S_OK)
92 {
93 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
94 return 0;
95 }
96
97 DPRINT("RpcServerThread() done\n");
98
99 return 0;
100 }
101
102
103 void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
104 {
105 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
106 }
107
108
109 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
110 {
111 HeapFree(GetProcessHeap(), 0, ptr);
112 }
113
114
115 CONFIGRET
116 PNP_GetVersion(handle_t BindingHandle,
117 unsigned short *Version)
118 {
119 *Version = 0x0400;
120 return CR_SUCCESS;
121 }
122
123
124 CONFIGRET
125 PNP_GetGlobalState(handle_t BindingHandle,
126 unsigned long *State,
127 unsigned long Flags)
128 {
129 *State = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
130 return CR_SUCCESS;
131 }
132
133
134 CONFIGRET
135 PNP_ValidateDeviceInstance(handle_t BindingHandle,
136 wchar_t *DeviceInstance,
137 unsigned long Flags)
138 {
139 CONFIGRET ret = CR_SUCCESS;
140 HKEY hEnumKey = NULL;
141 HKEY hDeviceKey = NULL;
142
143 DPRINT("PNP_ValidateDeviceInstance(%S %lx) called\n",
144 DeviceInstance, Flags);
145
146 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
147 L"System\\CurrentControlSet\\Enum",
148 0,
149 KEY_ALL_ACCESS,
150 &hEnumKey))
151 {
152 DPRINT("Could not open the Enum Key!\n");
153 ret = CR_FAILURE;
154 goto Done;
155 }
156
157 if (RegOpenKeyExW(hEnumKey,
158 DeviceInstance,
159 0,
160 KEY_READ,
161 &hDeviceKey))
162 {
163 DPRINT("Could not open the Device Key!\n");
164 ret = CR_NO_SUCH_DEVNODE;
165 goto Done;
166 }
167
168 /* FIXME: add more tests */
169
170 Done:
171 if (hDeviceKey != NULL)
172 RegCloseKey(hDeviceKey);
173
174 if (hEnumKey != NULL)
175 RegCloseKey(hEnumKey);
176
177 DPRINT("PNP_ValidateDeviceInstance() done (returns %lx)\n", ret);
178
179 return ret;
180 }
181
182
183 CONFIGRET
184 PNP_GetRootDeviceInstance(handle_t BindingHandle,
185 wchar_t *DeviceInstance,
186 unsigned long Length)
187 {
188 CONFIGRET ret = CR_SUCCESS;
189
190 DPRINT("PNP_GetRootDeviceInstance() called\n");
191
192 if (Length < lstrlenW(szRootDeviceId) + 1)
193 {
194 ret = CR_BUFFER_SMALL;
195 goto Done;
196 }
197
198 lstrcpyW(DeviceInstance,
199 szRootDeviceId);
200
201 Done:
202 DPRINT("PNP_GetRootDeviceInstance() done (returns %lx)\n", ret);
203
204 return ret;
205 }
206
207
208 CONFIGRET
209 PNP_GetRelatedDeviceInstance(handle_t BindingHandle,
210 unsigned long Relationship,
211 wchar_t *DeviceId,
212 wchar_t *RelatedDeviceId,
213 unsigned long Length,
214 unsigned long Flags)
215 {
216 PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData;
217 CONFIGRET ret = CR_SUCCESS;
218 NTSTATUS Status;
219
220 DPRINT("PNP_GetRelatedDeviceInstance() called\n");
221 DPRINT(" Relationship %ld\n", Relationship);
222 DPRINT(" DeviceId %S\n", DeviceId);
223
224 RtlInitUnicodeString(&PlugPlayData.TargetDeviceInstance,
225 DeviceId);
226
227 PlugPlayData.Relation = Relationship;
228
229 PlugPlayData.RelatedDeviceInstance.Length = 0;
230 PlugPlayData.RelatedDeviceInstance.MaximumLength = Length;
231 PlugPlayData.RelatedDeviceInstance.Buffer = RelatedDeviceId;
232
233 Status = NtPlugPlayControl(PlugPlayControlGetRelatedDevice,
234 (PVOID)&PlugPlayData,
235 sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA));
236 if (!NT_SUCCESS(Status))
237 {
238 /* FIXME: Map Status to ret */
239 ret = CR_FAILURE;
240 }
241
242 DPRINT("PNP_GetRelatedDeviceInstance() done (returns %lx)\n", ret);
243 if (ret == CR_SUCCESS)
244 {
245 DPRINT("RelatedDevice: %wZ\n", &PlugPlayData.RelatedDeviceInstance);
246 }
247
248 return ret;
249 }
250
251
252 CONFIGRET
253 PNP_EnumerateSubKeys(handle_t BindingHandle,
254 unsigned long Branch,
255 unsigned long Index,
256 wchar_t *Buffer,
257 unsigned long Length,
258 unsigned long *RequiredLength,
259 DWORD Flags)
260 {
261 CONFIGRET ret = CR_SUCCESS;
262 HKEY hKey;
263 DWORD dwError;
264
265 DPRINT1("PNP_EnumerateSubKeys() called\n");
266
267 switch (Branch)
268 {
269 case 1:
270 hKey = hEnumKey;
271 break;
272
273 case 2:
274 hKey = hClassKey;
275 break;
276
277 default:
278 return CR_FAILURE;
279 }
280
281 *RequiredLength = Length;
282 dwError = RegEnumKeyExW(hKey,
283 Index,
284 Buffer,
285 RequiredLength,
286 NULL,
287 NULL,
288 NULL,
289 NULL);
290 if (dwError != ERROR_SUCCESS)
291 {
292 ret = CR_FAILURE;
293 }
294
295 DPRINT1("PNP_EnumerateSubKeys() done (returns %lx)\n", ret);
296 if (ret == CR_SUCCESS)
297 {
298 DPRINT1("Sub key: %S\n", Buffer);
299 }
300
301 return ret;
302 }
303
304
305 CONFIGRET
306 PNP_GetDepth(handle_t BindingHandle,
307 wchar_t *DeviceInstance,
308 unsigned long *Depth,
309 DWORD Flags)
310 {
311 PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData;
312 CONFIGRET ret = CR_SUCCESS;
313 NTSTATUS Status;
314
315 DPRINT("PNP_GetDepth() called\n");
316
317 RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
318 DeviceInstance);
319
320 Status = NtPlugPlayControl(PlugPlayControlGetDeviceDepth,
321 (PVOID)&PlugPlayData,
322 sizeof(PLUGPLAY_CONTROL_DEPTH_DATA));
323 if (NT_SUCCESS(Status))
324 {
325 *Depth = PlugPlayData.Depth;
326 }
327 else
328 {
329 ret = CR_FAILURE; /* FIXME */
330 }
331
332 DPRINT("PNP_GetDepth() done (returns %lx)\n", ret);
333
334 return ret;
335 }
336
337
338 CONFIGRET
339 PNP_SetDeviceRegProp(handle_t BindingHandle,
340 wchar_t *DeviceId,
341 unsigned long Property,
342 unsigned long DataType,
343 char *Buffer,
344 unsigned long Length,
345 unsigned long Flags)
346 {
347 CONFIGRET ret = CR_SUCCESS;
348 LPWSTR lpValueName = NULL;
349 HKEY hKey = 0;
350
351 DPRINT("PNP_SetDeviceRegProp() called\n");
352
353 DPRINT("DeviceId: %S\n", DeviceId);
354 DPRINT("Property: %lu\n", Property);
355 DPRINT("DataType: %lu\n", DataType);
356 DPRINT("Length: %lu\n", Length);
357
358 switch (Property)
359 {
360 case CM_DRP_DEVICEDESC:
361 lpValueName = L"DeviceDesc";
362 break;
363
364 case CM_DRP_HARDWAREID:
365 lpValueName = L"HardwareID";
366 break;
367
368 case CM_DRP_COMPATIBLEIDS:
369 lpValueName = L"CompatibleIDs";
370 break;
371
372 case CM_DRP_SERVICE:
373 lpValueName = L"Service";
374 break;
375
376 case CM_DRP_CLASS:
377 lpValueName = L"Class";
378 break;
379
380 case CM_DRP_CLASSGUID:
381 lpValueName = L"ClassGUID";
382 break;
383
384 case CM_DRP_DRIVER:
385 lpValueName = L"Driver";
386 break;
387
388 case CM_DRP_CONFIGFLAGS:
389 lpValueName = L"ConfigFlags";
390 break;
391
392 case CM_DRP_MFG:
393 lpValueName = L"Mfg";
394 break;
395
396 case CM_DRP_FRIENDLYNAME:
397 lpValueName = L"FriendlyName";
398 break;
399
400 case CM_DRP_LOCATION_INFORMATION:
401 lpValueName = L"LocationInformation";
402 break;
403
404 case CM_DRP_UPPERFILTERS:
405 lpValueName = L"UpperFilters";
406 break;
407
408 case CM_DRP_LOWERFILTERS:
409 lpValueName = L"LowerFilters";
410 break;
411
412 default:
413 return CR_INVALID_PROPERTY;
414 }
415
416 DPRINT("Value name: %S\n", lpValueName);
417
418 if (RegOpenKeyExW(hEnumKey,
419 DeviceId,
420 0,
421 KEY_ALL_ACCESS,
422 &hKey))
423 return CR_INVALID_DEVNODE;
424
425 if (Length == 0)
426 {
427 if (RegDeleteValueW(hKey,
428 lpValueName))
429 ret = CR_REGISTRY_ERROR;
430 }
431 else
432 {
433 if (RegSetValueExW(hKey,
434 lpValueName,
435 0,
436 DataType,
437 Buffer,
438 Length))
439 ret = CR_REGISTRY_ERROR;
440 }
441
442 RegCloseKey(hKey);
443
444 DPRINT("PNP_SetDeviceRegProp() done (returns %lx)\n", ret);
445
446 return ret;
447 }
448
449
450 CONFIGRET
451 PNP_GetDeviceRegProp(handle_t BindingHandle,
452 wchar_t *DeviceInstance,
453 unsigned long Property,
454 unsigned long *DataType,
455 char *Buffer,
456 unsigned long *TransferLen,
457 unsigned long *Length,
458 DWORD Flags)
459 {
460 CONFIGRET ret = CR_SUCCESS;
461 LPWSTR lpValueName = NULL;
462 ULONG Data;
463
464 DPRINT1("PNP_GetDeviceRegProp() called\n");
465
466 switch (Property)
467 {
468 case CM_DRP_DEVICEDESC:
469 lpValueName = L"DeviceDesc";
470 break;
471
472 case CM_DRP_HARDWAREID:
473 lpValueName = L"HardwareID";
474 break;
475
476 case CM_DRP_COMPATIBLEIDS:
477 lpValueName = L"CompatibleIDs";
478 break;
479
480 case CM_DRP_SERVICE:
481 lpValueName = L"Service";
482 break;
483
484 case CM_DRP_CLASS:
485 lpValueName = L"Class";
486 break;
487
488 case CM_DRP_CLASSGUID:
489 lpValueName = L"ClassGUID";
490 break;
491
492 case CM_DRP_DRIVER:
493 lpValueName = L"Driver";
494 break;
495
496 case CM_DRP_CONFIGFLAGS:
497 lpValueName = L"ConfigFlags";
498 break;
499
500 case CM_DRP_MFG:
501 lpValueName = L"Mfg";
502 break;
503
504 case CM_DRP_FRIENDLYNAME:
505 lpValueName = L"FriendlyName";
506 break;
507
508 case CM_DRP_LOCATION_INFORMATION:
509 lpValueName = L"LocationInformation";
510 break;
511
512 case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
513 lpValueName = NULL;
514 break;
515
516 case CM_DRP_CAPABILITIES:
517 lpValueName = L"Capabilities";
518 break;
519
520 case CM_DRP_UI_NUMBER:
521 break;
522
523 case CM_DRP_UPPERFILTERS:
524 lpValueName = L"UpperFilters";
525 break;
526
527 case CM_DRP_LOWERFILTERS:
528 lpValueName = L"LowerFilters";
529 break;
530
531 case CM_DRP_BUSTYPEGUID:
532 break;
533
534 case CM_DRP_LEGACYBUSTYPE:
535 break;
536
537 case CM_DRP_BUSNUMBER:
538 break;
539
540 case CM_DRP_ENUMERATOR_NAME:
541 break;
542
543 default:
544 return CR_INVALID_PROPERTY;
545 }
546
547 DPRINT1("Value name: %S\n", lpValueName);
548
549 if (lpValueName)
550 {
551 /* Retrieve information from the Registry */
552
553 }
554 else
555 {
556 /* Retrieve information from the Device Node */
557
558 }
559
560
561 Data = 0xbaadf00d;
562 memcpy(Buffer, &Data, sizeof(ULONG));
563 *Length = sizeof(ULONG);
564
565 DPRINT1("PNP_GetDeviceRegProp() done (returns %lx)\n", ret);
566
567 return ret;
568 }
569
570
571 CONFIGRET
572 PNP_GetDeviceStatus(handle_t BindingHandle,
573 wchar_t *DeviceInstance,
574 unsigned long *pStatus,
575 unsigned long *pProblem,
576 DWORD Flags)
577 {
578 PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
579 CONFIGRET ret = CR_SUCCESS;
580 NTSTATUS Status;
581
582 DPRINT("PNP_GetDeviceStatus() called\n");
583
584 RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
585 DeviceInstance);
586 PlugPlayData.Operation = 0; /* Get status */
587
588 Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
589 (PVOID)&PlugPlayData,
590 sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
591 if (NT_SUCCESS(Status))
592 {
593 *pStatus = PlugPlayData.DeviceStatus;
594 *pProblem = PlugPlayData.DeviceProblem;
595 }
596 else
597 {
598 ret = CR_FAILURE; /* FIXME */
599 }
600
601 DPRINT("PNP_GetDeviceStatus() done (returns %lx)\n", ret);
602
603 return ret;
604 }
605
606
607 CONFIGRET
608 PNP_SetDeviceProblem(handle_t BindingHandle,
609 wchar_t *DeviceInstance,
610 unsigned long Problem,
611 DWORD Flags)
612 {
613 CONFIGRET ret = CR_SUCCESS;
614
615 DPRINT1("PNP_SetDeviceProblem() called\n");
616
617 /* FIXME */
618
619 DPRINT1("PNP_SetDeviceProblem() done (returns %lx)\n", ret);
620
621 return ret;
622 }
623
624
625 static DWORD WINAPI
626 PnpEventThread(LPVOID lpParameter)
627 {
628 PPLUGPLAY_EVENT_BLOCK PnpEvent;
629 ULONG PnpEventSize;
630 NTSTATUS Status;
631 RPC_STATUS RpcStatus;
632
633 PnpEventSize = 0x1000;
634 PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize);
635 if (PnpEvent == NULL)
636 return ERROR_OUTOFMEMORY;
637
638 for (;;)
639 {
640 DPRINT("Calling NtGetPlugPlayEvent()\n");
641
642 /* Wait for the next pnp event */
643 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize);
644
645 /* Resize the buffer for the PnP event if it's too small. */
646 if (Status == STATUS_BUFFER_TOO_SMALL)
647 {
648 PnpEventSize += 0x400;
649 PnpEvent = HeapReAlloc(GetProcessHeap(), 0, PnpEvent, PnpEventSize);
650 if (PnpEvent == NULL)
651 return ERROR_OUTOFMEMORY;
652 continue;
653 }
654
655 if (!NT_SUCCESS(Status))
656 {
657 DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status);
658 break;
659 }
660
661 DPRINT("Received PnP Event\n");
662 if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
663 {
664 DPRINT1("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds);
665 }
666 else
667 {
668 DPRINT1("Unknown event\n");
669 }
670
671 /* FIXME: Process the pnp event */
672
673 /* Dequeue the current pnp event and signal the next one */
674 NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0);
675 }
676
677 HeapFree(GetProcessHeap(), 0, PnpEvent);
678
679 return ERROR_SUCCESS;
680 }
681
682
683 static VOID CALLBACK
684 ServiceMain(DWORD argc, LPTSTR *argv)
685 {
686 HANDLE hThread;
687 DWORD dwThreadId;
688
689 DPRINT("ServiceMain() called\n");
690
691 hThread = CreateThread(NULL,
692 0,
693 PnpEventThread,
694 NULL,
695 0,
696 &dwThreadId);
697 if (hThread != NULL)
698 CloseHandle(hThread);
699
700 hThread = CreateThread(NULL,
701 0,
702 RpcServerThread,
703 NULL,
704 0,
705 &dwThreadId);
706 if (hThread != NULL)
707 CloseHandle(hThread);
708
709 DPRINT("ServiceMain() done\n");
710 }
711
712
713 int
714 main(int argc, char *argv[])
715 {
716 DWORD dwError;
717
718 DPRINT("Umpnpmgr: main() started\n");
719
720 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
721 L"System\\CurrentControlSet\\Enum",
722 0,
723 KEY_ALL_ACCESS,
724 &hEnumKey);
725 if (dwError != ERROR_SUCCESS)
726 {
727 DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError);
728 return dwError;
729 }
730
731 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
732 L"System\\CurrentControlSet\\Control\\Class",
733 0,
734 KEY_ALL_ACCESS,
735 &hClassKey);
736 if (dwError != ERROR_SUCCESS)
737 {
738 DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError);
739 return dwError;
740 }
741
742 StartServiceCtrlDispatcher(ServiceTable);
743
744 DPRINT("Umpnpmgr: main() done\n");
745
746 ExitThread(0);
747
748 return 0;
749 }
750
751 /* EOF */