:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / ntoskrnl / io / pnproot.c
1 /* $Id$
2  *
3  * COPYRIGHT:      See COPYING in the top level directory
4  * PROJECT:        ReactOS kernel
5  * FILE:           ntoskrnl/io/pnproot.c
6  * PURPOSE:        PnP manager root device
7  * PROGRAMMER:     Casper S. Hornstrup (chorns@users.sourceforge.net)
8  * UPDATE HISTORY:
9  *  16/04/2001 CSH Created
10  */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/io.h>
16 #include <internal/registry.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* GLOBALS *******************************************************************/
22
23 #define ENUM_NAME_ROOT L"Root"
24
25 /* DATA **********************************************************************/
26
27 typedef struct _PNPROOT_DEVICE {
28   // Entry on device list
29   LIST_ENTRY ListEntry;
30   // Physical Device Object of device
31   PDEVICE_OBJECT Pdo;
32   // Service name
33   UNICODE_STRING ServiceName;
34   // Device ID
35   UNICODE_STRING DeviceID;
36   // Instance ID
37   UNICODE_STRING InstanceID;
38   // Device description
39   UNICODE_STRING DeviceDescription;
40 } PNPROOT_DEVICE, *PPNPROOT_DEVICE;
41
42 typedef enum {
43   dsStopped,
44   dsStarted,
45   dsPaused,
46   dsRemoved,
47   dsSurpriseRemoved
48 } PNPROOT_DEVICE_STATE;
49
50
51 typedef struct _PNPROOT_COMMON_DEVICE_EXTENSION
52 {
53   // Pointer to device object, this device extension is associated with
54   PDEVICE_OBJECT DeviceObject;
55   // Wether this device extension is for an FDO or PDO
56   BOOLEAN IsFDO;
57   // Wether the device is removed
58   BOOLEAN Removed;
59   // Current device power state for the device
60   DEVICE_POWER_STATE DevicePowerState;
61 } __attribute((packed)) PNPROOT_COMMON_DEVICE_EXTENSION, *PPNPROOT_COMMON_DEVICE_EXTENSION;
62
63 /* Physical Device Object device extension for a child device */
64 typedef struct _PNPROOT_PDO_DEVICE_EXTENSION
65 {
66   // Common device data
67   PNPROOT_COMMON_DEVICE_EXTENSION Common;
68   // Device ID
69   UNICODE_STRING DeviceID;
70   // Instance ID
71   UNICODE_STRING InstanceID;
72 } __attribute((packed)) PNPROOT_PDO_DEVICE_EXTENSION, *PPNPROOT_PDO_DEVICE_EXTENSION;
73
74 /* Functional Device Object device extension for the PCI driver device object */
75 typedef struct _PNPROOT_FDO_DEVICE_EXTENSION
76 {
77   // Common device data
78   PNPROOT_COMMON_DEVICE_EXTENSION Common;
79   // Physical Device Object
80   PDEVICE_OBJECT Pdo;
81   // Lower device object
82   PDEVICE_OBJECT Ldo;
83   // Current state of the driver
84   PNPROOT_DEVICE_STATE State;
85   // Namespace device list
86   LIST_ENTRY DeviceListHead;
87   // Number of (not removed) devices in device list
88   ULONG DeviceListCount;
89   // Lock for namespace device list
90   // FIXME: Use fast mutex instead?
91   KSPIN_LOCK DeviceListLock;
92 } __attribute((packed)) PNPROOT_FDO_DEVICE_EXTENSION, *PPNPROOT_FDO_DEVICE_EXTENSION;
93
94
95 PDEVICE_OBJECT PnpRootDeviceObject;
96
97
98 /* FUNCTIONS *****************************************************************/
99
100 /* Physical Device Object routines */
101
102 NTSTATUS
103 PnpRootCreateDevice(
104   PDEVICE_OBJECT *PhysicalDeviceObject)
105 {
106   PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
107   PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
108   PPNPROOT_DEVICE Device;
109   NTSTATUS Status;
110
111   /* This function should be obsoleted soon */
112
113   DPRINT("Called\n");
114
115   DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension;
116
117   Device = (PPNPROOT_DEVICE)ExAllocatePool(PagedPool, sizeof(PNPROOT_DEVICE));
118   if (!Device)
119     return STATUS_INSUFFICIENT_RESOURCES;
120
121   RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
122
123   Status = IoCreateDevice(
124     PnpRootDeviceObject->DriverObject,
125     sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
126     NULL,
127     FILE_DEVICE_CONTROLLER,
128     0,
129     FALSE,
130     &Device->Pdo);
131   if (!NT_SUCCESS(Status)) {
132     DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
133     ExFreePool(Device);
134     return Status;
135   }
136
137   Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
138
139   Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
140
141   //Device->Pdo->Flags |= DO_POWER_PAGABLE;
142
143   PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
144
145   RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
146
147   PdoDeviceExtension->Common.IsFDO = FALSE;
148
149   PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
150
151   PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
152
153   if (!IopCreateUnicodeString(
154     &PdoDeviceExtension->DeviceID,
155     ENUM_NAME_ROOT \
156     L"\\LEGACY_UNKNOWN",
157     PagedPool))
158   {
159     /* FIXME: */
160     DPRINT("IopCreateUnicodeString() failed\n");
161   }
162
163   if (!IopCreateUnicodeString(
164     &PdoDeviceExtension->InstanceID,
165     L"0000",
166     PagedPool))
167   {
168     /* FIXME: */
169     DPRINT("IopCreateUnicodeString() failed\n");
170   }
171
172   ExInterlockedInsertTailList(
173     &DeviceExtension->DeviceListHead,
174     &Device->ListEntry,
175     &DeviceExtension->DeviceListLock);
176
177   DeviceExtension->DeviceListCount++;
178
179   *PhysicalDeviceObject = Device->Pdo;
180
181   return STATUS_SUCCESS;
182 }
183
184
185 NTSTATUS
186 PdoQueryId(
187   IN PDEVICE_OBJECT DeviceObject,
188   IN PIRP Irp,
189   PIO_STACK_LOCATION IrpSp)
190 {
191   PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
192   UNICODE_STRING String;
193   NTSTATUS Status;
194
195   DPRINT("Called\n");
196
197   DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
198
199 //  Irp->IoStatus.Information = 0;
200
201   Status = STATUS_SUCCESS;
202
203   RtlInitUnicodeString(&String, NULL);
204
205   switch (IrpSp->Parameters.QueryId.IdType) {
206     case BusQueryDeviceID:
207       Status = IopCreateUnicodeString(
208         &String,
209         DeviceExtension->DeviceID.Buffer,
210         PagedPool);
211
212       DPRINT("DeviceID: %S\n", String.Buffer);
213
214       Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
215       break;
216
217     case BusQueryHardwareIDs:
218     case BusQueryCompatibleIDs:
219       Status = STATUS_NOT_IMPLEMENTED;
220       break;
221
222     case BusQueryInstanceID:
223       Status = IopCreateUnicodeString(
224         &String,
225         DeviceExtension->InstanceID.Buffer,
226         PagedPool);
227
228       DPRINT("InstanceID: %S\n", String.Buffer);
229
230       Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
231       break;
232
233     case BusQueryDeviceSerialNumber:
234     default:
235       Status = STATUS_NOT_IMPLEMENTED;
236   }
237
238   return Status;
239 }
240
241
242 NTSTATUS
243 PnpRootPdoPnpControl(
244   PDEVICE_OBJECT DeviceObject,
245   PIRP Irp)
246 /*
247  * FUNCTION: Handle Plug and Play IRPs for the child device
248  * ARGUMENTS:
249  *     DeviceObject = Pointer to physical device object of the child device
250  *     Irp          = Pointer to IRP that should be handled
251  * RETURNS:
252  *     Status
253  */
254 {
255   PIO_STACK_LOCATION IrpSp;
256   NTSTATUS Status;
257
258   DPRINT("Called\n");
259
260   Status = Irp->IoStatus.Status;
261
262   IrpSp = IoGetCurrentIrpStackLocation(Irp);
263
264   switch (IrpSp->MinorFunction) {
265 #if 0
266   case IRP_MN_CANCEL_REMOVE_DEVICE:
267     break;
268
269   case IRP_MN_CANCEL_STOP_DEVICE:
270     break;
271
272   case IRP_MN_DEVICE_USAGE_NOTIFICATION:
273     break;
274
275   case IRP_MN_EJECT:
276     break;
277
278   case IRP_MN_QUERY_BUS_INFORMATION:
279     break;
280
281   case IRP_MN_QUERY_CAPABILITIES:
282     break;
283
284   case IRP_MN_QUERY_DEVICE_RELATIONS:
285     /* FIXME: Possibly handle for RemovalRelations */
286     break;
287
288   case IRP_MN_QUERY_DEVICE_TEXT:
289     break;
290 #endif
291   case IRP_MN_QUERY_ID:
292     Status = PdoQueryId(DeviceObject, Irp, IrpSp);
293     break;
294 #if 0
295   case IRP_MN_QUERY_PNP_DEVICE_STATE:
296     break;
297
298   case IRP_MN_QUERY_REMOVE_DEVICE:
299     break;
300
301   case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
302     break;
303
304   case IRP_MN_QUERY_RESOURCES:
305     break;
306
307   case IRP_MN_QUERY_STOP_DEVICE:
308     break;
309
310   case IRP_MN_REMOVE_DEVICE:
311     break;
312
313   case IRP_MN_SET_LOCK:
314     break;
315
316   case IRP_MN_START_DEVICE:
317     break;
318
319   case IRP_MN_STOP_DEVICE:
320     break;
321
322   case IRP_MN_SURPRISE_REMOVAL:
323     break;
324 #endif
325   default:
326     DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
327     break;
328   }
329
330   Irp->IoStatus.Status = Status;
331   IoCompleteRequest(Irp, IO_NO_INCREMENT);
332
333   DPRINT("Leaving. Status 0x%X\n", Status);
334
335   return Status;
336 }
337
338 NTSTATUS
339 PnpRootPdoPowerControl(
340   PDEVICE_OBJECT DeviceObject,
341   PIRP Irp)
342 /*
343  * FUNCTION: Handle power management IRPs for the child device
344  * ARGUMENTS:
345  *     DeviceObject = Pointer to physical device object of the child device
346  *     Irp          = Pointer to IRP that should be handled
347  * RETURNS:
348  *     Status
349  */
350 {
351   PIO_STACK_LOCATION IrpSp;
352   NTSTATUS Status;
353
354   DPRINT("Called\n");
355
356   Status = Irp->IoStatus.Status;
357
358   IrpSp = IoGetCurrentIrpStackLocation(Irp);
359
360   switch (IrpSp->MinorFunction) {
361   default:
362     DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
363     break;
364   }
365
366   Irp->IoStatus.Status = Status;
367   IoCompleteRequest(Irp, IO_NO_INCREMENT);
368
369   DPRINT("Leaving. Status 0x%X\n", Status);
370
371   return Status;
372 }
373
374
375 /* Functional Device Object routines */
376
377 NTSTATUS
378 PnpRootFdoReadDeviceInfo(
379   PPNPROOT_DEVICE Device)
380 {
381   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
382   PUNICODE_STRING DeviceDesc;
383   WCHAR KeyName[MAX_PATH];
384   HANDLE KeyHandle;
385   NTSTATUS Status;
386
387   DPRINT("Called\n");
388
389   /* Retrieve configuration from Enum key */
390
391   DeviceDesc = &Device->DeviceDescription;
392
393   wcscpy(KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
394   wcscat(KeyName, ENUM_NAME_ROOT);
395   wcscat(KeyName, L"\\");
396   wcscat(KeyName, Device->ServiceName.Buffer);
397   wcscat(KeyName, L"\\");
398   wcscat(KeyName, Device->InstanceID.Buffer);
399
400   DPRINT("KeyName %S\n", KeyName);
401
402   Status = RtlpGetRegistryHandle(
403     RTL_REGISTRY_ABSOLUTE,
404           KeyName,
405                 FALSE,
406                 &KeyHandle);
407   if (!NT_SUCCESS(Status))
408   {
409     DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status);
410     return Status;
411   }
412
413   RtlZeroMemory(QueryTable, sizeof(QueryTable));
414
415   RtlInitUnicodeString(DeviceDesc, NULL);
416
417   QueryTable[0].Name = L"DeviceDesc";
418   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
419   QueryTable[0].EntryContext = DeviceDesc;
420
421   Status = RtlQueryRegistryValues(
422     RTL_REGISTRY_HANDLE,
423                 (PWSTR)KeyHandle,
424                 QueryTable,
425                 NULL,
426                 NULL);
427
428   NtClose(KeyHandle);
429
430   DPRINT("RtlQueryRegistryValues() returned status %x\n", Status);
431
432   if (!NT_SUCCESS(Status))
433   {
434     /* FIXME: */
435   }
436
437   DPRINT("Got device description: %S\n", DeviceDesc->Buffer);
438
439   return STATUS_SUCCESS;
440 }
441
442
443 NTSTATUS
444 PnpRootFdoEnumerateDevices(
445   PDEVICE_OBJECT DeviceObject)
446 {
447   PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
448   OBJECT_ATTRIBUTES ObjectAttributes;
449   PKEY_BASIC_INFORMATION KeyInfo;
450   UNICODE_STRING KeyName;
451   PPNPROOT_DEVICE Device;
452   WCHAR Buffer[MAX_PATH];
453   HANDLE KeyHandle;
454   ULONG BufferSize;
455   ULONG ResultSize;
456   NTSTATUS Status;
457   ULONG Index;
458
459   DPRINT("Called\n");
460
461   DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
462
463   BufferSize = sizeof(KEY_BASIC_INFORMATION) + (MAX_PATH+1) * sizeof(WCHAR);
464   KeyInfo = ExAllocatePool(PagedPool, BufferSize);
465   if (!KeyInfo)
466   {
467     return STATUS_INSUFFICIENT_RESOURCES;
468   }
469
470   RtlInitUnicodeStringFromLiteral(
471     &KeyName,
472     L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\" \
473     ENUM_NAME_ROOT);
474
475   InitializeObjectAttributes(
476     &ObjectAttributes,
477                 &KeyName,
478                 OBJ_CASE_INSENSITIVE,
479                 NULL,
480                 NULL);
481
482   Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
483   if (!NT_SUCCESS(Status))
484   {
485     DPRINT("NtOpenKey() failed (Status %x)\n", Status);
486     ExFreePool(KeyInfo);
487     return Status;
488   }
489
490   /* FIXME: Disabled due to still using the old method of auto loading drivers e.g.
491             there are more entries in the list than found in the registry as some 
492             drivers are passed on the command line */
493 //  DeviceExtension->DeviceListCount = 0;
494
495   Index = 0;
496   do {
497     Status = ZwEnumerateKey(
498       KeyHandle,
499       Index,
500       KeyBasicInformation,
501       KeyInfo,
502       BufferSize,
503       &ResultSize);
504     if (!NT_SUCCESS(Status))
505     {
506       DPRINT("ZwEnumerateKey() (Status %x)\n", Status);
507       break;
508     }
509
510     /* Terminate the string */
511     KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
512
513     Device = (PPNPROOT_DEVICE)ExAllocatePool(PagedPool, sizeof(PNPROOT_DEVICE));
514     if (!Device)
515     {
516       /* FIXME: */
517       break;
518     }
519
520     RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
521
522     if (!IopCreateUnicodeString(&Device->ServiceName, KeyInfo->Name, PagedPool))
523     {
524       /* FIXME: */
525       DPRINT("IopCreateUnicodeString() failed\n");
526     }
527
528     wcscpy(Buffer, ENUM_NAME_ROOT);
529     wcscat(Buffer, L"\\");
530     wcscat(Buffer, KeyInfo->Name);
531
532     if (!IopCreateUnicodeString(&Device->DeviceID, Buffer, PagedPool))
533     {
534       /* FIXME: */
535       DPRINT("IopCreateUnicodeString() failed\n");
536     }
537
538     DPRINT("Got entry: %S\n", Device->DeviceID.Buffer);
539
540     if (!IopCreateUnicodeString(
541       &Device->InstanceID,
542       L"0000",
543       PagedPool))
544     {
545       /* FIXME: */
546       DPRINT("IopCreateUnicodeString() failed\n");
547     }
548
549     Status = PnpRootFdoReadDeviceInfo(Device);
550     if (!NT_SUCCESS(Status))
551     {
552       DPRINT("PnpRootFdoReadDeviceInfo() failed with status %x\n", Status);
553       /* FIXME: */      
554     }
555
556     ExInterlockedInsertTailList(
557       &DeviceExtension->DeviceListHead,
558       &Device->ListEntry,
559       &DeviceExtension->DeviceListLock);
560
561     DeviceExtension->DeviceListCount++;
562
563     Index++;
564   } while (TRUE);
565
566   DPRINT("Entries found: %d\n", Index);
567
568   NtClose(KeyHandle);
569
570   ExFreePool(KeyInfo);
571
572   return STATUS_SUCCESS;
573 }
574
575
576 NTSTATUS
577 PnpRootQueryBusRelations(
578   IN PDEVICE_OBJECT DeviceObject,
579   IN PIRP Irp,
580   IN PIO_STACK_LOCATION IrpSp)
581 {
582   PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
583   PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
584   PDEVICE_RELATIONS Relations;
585   PLIST_ENTRY CurrentEntry;
586   PPNPROOT_DEVICE Device;
587   NTSTATUS Status;
588   ULONG Size;
589   ULONG i;
590
591   DPRINT("Called\n");
592
593   Status = PnpRootFdoEnumerateDevices(DeviceObject);
594   if (!NT_SUCCESS(Status))
595     return Status;
596
597   DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
598
599   if (Irp->IoStatus.Information)
600   {
601     /* FIXME: Another bus driver has already created a DEVICE_RELATIONS 
602               structure so we must merge this structure with our own */
603   }
604
605   Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
606     (DeviceExtension->DeviceListCount - 1);  
607
608   Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
609   if (!Relations)
610     return STATUS_INSUFFICIENT_RESOURCES;
611
612   Relations->Count = DeviceExtension->DeviceListCount;
613
614   i = 0;
615   CurrentEntry = DeviceExtension->DeviceListHead.Flink;
616   while (CurrentEntry != &DeviceExtension->DeviceListHead)
617   {
618     Device = CONTAINING_RECORD(CurrentEntry, PNPROOT_DEVICE, ListEntry);
619
620     if (!Device->Pdo)
621     {
622       /* Create a physical device object for the
623          device as it does not already have one */
624       Status = IoCreateDevice(
625         DeviceObject->DriverObject,
626         sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
627         NULL,
628         FILE_DEVICE_CONTROLLER,
629         0,
630         FALSE,
631         &Device->Pdo);
632       if (!NT_SUCCESS(Status))
633       {
634         DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
635         ExFreePool(Relations);
636         return Status;
637       }
638
639       DPRINT("Created PDO %x\n", Device->Pdo);
640
641       Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
642
643       Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
644
645       //Device->Pdo->Flags |= DO_POWER_PAGABLE;
646
647       PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
648
649       RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
650
651       PdoDeviceExtension->Common.IsFDO = FALSE;
652
653       PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
654
655       PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
656
657       if (!IopCreateUnicodeString(
658         &PdoDeviceExtension->DeviceID,
659         Device->DeviceID.Buffer,
660         PagedPool))
661       {
662         DPRINT("Insufficient resources\n");
663         /* FIXME: */
664       }
665
666       DPRINT("DeviceID: %S  PDO %x\n",
667         PdoDeviceExtension->DeviceID.Buffer,
668         Device->Pdo);
669
670       if (!IopCreateUnicodeString(
671         &PdoDeviceExtension->InstanceID,
672         Device->InstanceID.Buffer,
673         PagedPool))
674       {
675         DPRINT("Insufficient resources\n");
676         /* FIXME: */
677       }
678
679     }
680
681     /* Reference the physical device object. The PnP manager
682        will dereference it again when it is no longer needed */
683     ObReferenceObject(Device->Pdo);
684
685     Relations->Objects[i] = Device->Pdo;
686
687     i++;
688
689     CurrentEntry = CurrentEntry->Flink;
690   }
691
692   if (NT_SUCCESS(Status))
693   {
694     Irp->IoStatus.Information = (ULONG_PTR)Relations;
695   }
696   else
697   {
698     Irp->IoStatus.Information = 0;
699   }
700
701   return Status;
702 }
703
704
705 NTSTATUS
706 PnpRootQueryDeviceRelations(
707   IN PDEVICE_OBJECT DeviceObject,
708   IN PIRP Irp,
709   IN PIO_STACK_LOCATION IrpSp)
710 {
711   NTSTATUS Status;
712
713   DPRINT("Called\n");
714
715   switch (IrpSp->Parameters.QueryDeviceRelations.Type) {
716   case BusRelations:
717     Status = PnpRootQueryBusRelations(DeviceObject, Irp, IrpSp);
718     break;
719
720   default:
721     Status = STATUS_NOT_IMPLEMENTED;
722   }
723
724   return Status;
725 }
726
727
728 NTSTATUS
729 STDCALL
730 PnpRootFdoPnpControl(
731   IN PDEVICE_OBJECT DeviceObject,
732   IN PIRP Irp)
733 /*
734  * FUNCTION: Handle Plug and Play IRPs for the root bus device object
735  * ARGUMENTS:
736  *     DeviceObject = Pointer to functional device object of the root bus driver
737  *     Irp          = Pointer to IRP that should be handled
738  * RETURNS:
739  *     Status
740  */
741 {
742   PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
743   PIO_STACK_LOCATION IrpSp;
744   NTSTATUS Status;
745
746   DPRINT("Called\n");
747
748   DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
749
750   Status = Irp->IoStatus.Status;
751
752   IrpSp = IoGetCurrentIrpStackLocation(Irp);
753
754   switch (IrpSp->MinorFunction) {
755   case IRP_MN_QUERY_DEVICE_RELATIONS:
756     Status = PnpRootQueryDeviceRelations(DeviceObject, Irp, IrpSp);
757     break;
758
759   case IRP_MN_START_DEVICE:
760     DeviceExtension->State = dsStarted;
761     Status = STATUS_SUCCESS;
762     break;
763
764   case IRP_MN_STOP_DEVICE:
765     /* Root device cannot be stopped */
766     Status = STATUS_UNSUCCESSFUL;
767     break;
768
769   default:
770     DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
771     Status = STATUS_NOT_IMPLEMENTED;
772     break;
773   }
774
775   if (Status != STATUS_PENDING) {
776     Irp->IoStatus.Status = Status;
777     IoCompleteRequest(Irp, IO_NO_INCREMENT);
778   }
779
780   DPRINT("Leaving. Status 0x%X\n", Status);
781
782   return Status;
783 }
784
785
786 NTSTATUS
787 STDCALL
788 PnpRootFdoPowerControl(
789   IN PDEVICE_OBJECT DeviceObject,
790   IN PIRP Irp)
791 /*
792  * FUNCTION: Handle power management IRPs for the root bus device object
793  * ARGUMENTS:
794  *     DeviceObject = Pointer to functional device object of the root bus driver
795  *     Irp          = Pointer to IRP that should be handled
796  * RETURNS:
797  *     Status
798  */
799 {
800   PIO_STACK_LOCATION IrpSp;
801   NTSTATUS Status;
802
803   DPRINT("Called\n");
804
805   IrpSp = IoGetCurrentIrpStackLocation(Irp);
806
807   switch (IrpSp->MinorFunction) {
808   default:
809     DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
810     Status = STATUS_NOT_IMPLEMENTED;
811     break;
812   }
813
814   if (Status != STATUS_PENDING) {
815     Irp->IoStatus.Status = Status;
816     IoCompleteRequest(Irp, IO_NO_INCREMENT);
817   }
818
819   DPRINT("Leaving. Status 0x%X\n", Status);
820
821   return Status;
822 }
823
824
825 NTSTATUS
826 STDCALL
827 PnpRootPnpControl(
828   IN PDEVICE_OBJECT DeviceObject,
829   IN PIRP Irp)
830 /*
831  * FUNCTION: Handle Plug and Play IRPs
832  * ARGUMENTS:
833  *     DeviceObject = Pointer to PDO or FDO
834  *     Irp          = Pointer to IRP that should be handled
835  * RETURNS:
836  *     Status
837  */
838 {
839   PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension;
840   NTSTATUS Status;
841
842   DeviceExtension = (PPNPROOT_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
843
844   DPRINT("DeviceObject %x  DeviceExtension %x  IsFDO %d\n",
845     DeviceObject,
846     DeviceExtension,
847     DeviceExtension->IsFDO);
848
849   if (DeviceExtension->IsFDO) {
850     Status = PnpRootFdoPnpControl(DeviceObject, Irp);
851   } else {
852     Status = PnpRootPdoPnpControl(DeviceObject, Irp);
853   }
854
855   return Status;
856 }
857
858
859 NTSTATUS
860 STDCALL
861 PnpRootPowerControl(
862   IN PDEVICE_OBJECT DeviceObject,
863   IN PIRP Irp)
864 /*
865  * FUNCTION: Handle power management IRPs
866  * ARGUMENTS:
867  *     DeviceObject = Pointer to PDO or FDO
868  *     Irp          = Pointer to IRP that should be handled
869  * RETURNS:
870  *     Status
871  */
872 {
873   PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension;
874   NTSTATUS Status;
875
876   DeviceExtension = (PPNPROOT_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
877
878   if (DeviceExtension->IsFDO) {
879     Status = PnpRootFdoPowerControl(DeviceObject, Irp);
880   } else {
881     Status = PnpRootPdoPowerControl(DeviceObject, Irp);
882   }
883
884   return Status;
885 }
886
887
888 NTSTATUS
889 STDCALL
890 PnpRootAddDevice(
891   IN PDRIVER_OBJECT DriverObject,
892   IN PDEVICE_OBJECT PhysicalDeviceObject)
893 {
894   PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
895   NTSTATUS Status;
896
897   DPRINT("Called\n");
898
899   Status = IoCreateDevice(
900     DriverObject,
901     sizeof(PNPROOT_FDO_DEVICE_EXTENSION),
902     NULL,
903     FILE_DEVICE_BUS_EXTENDER,
904     FILE_DEVICE_SECURE_OPEN,
905     TRUE,
906     &PnpRootDeviceObject);
907   if (!NT_SUCCESS(Status)) {
908     CPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
909     KeBugCheck(PHASE1_INITIALIZATION_FAILED);
910   }
911
912   DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension;
913
914   RtlZeroMemory(DeviceExtension, sizeof(PNPROOT_FDO_DEVICE_EXTENSION));
915
916   DeviceExtension->Common.IsFDO = TRUE;
917
918   DeviceExtension->State = dsStopped;
919
920   DeviceExtension->Ldo = IoAttachDeviceToDeviceStack(
921     PnpRootDeviceObject,
922     PhysicalDeviceObject);
923
924   if (!PnpRootDeviceObject) {
925     CPRINT("PnpRootDeviceObject 0x%X\n", PnpRootDeviceObject);
926     KeBugCheck(PHASE1_INITIALIZATION_FAILED);
927   }
928
929   if (!PhysicalDeviceObject) {
930     CPRINT("PhysicalDeviceObject 0x%X\n", PhysicalDeviceObject);
931     KeBugCheck(PHASE1_INITIALIZATION_FAILED);
932   }
933
934   InitializeListHead(&DeviceExtension->DeviceListHead);
935
936   DeviceExtension->DeviceListCount = 0;
937
938   KeInitializeSpinLock(&DeviceExtension->DeviceListLock);
939
940   PnpRootDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
941
942   //PnpRootDeviceObject->Flags |= DO_POWER_PAGABLE;
943
944   DPRINT("Done AddDevice()\n");
945
946   return STATUS_SUCCESS;
947 }
948
949
950 NTSTATUS
951 STDCALL
952 PnpRootDriverEntry(
953   IN PDRIVER_OBJECT DriverObject,
954   IN PUNICODE_STRING RegistryPath)
955 {
956   DPRINT("Called\n");
957
958   DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH) PnpRootPnpControl;
959   DriverObject->MajorFunction[IRP_MJ_POWER] = (PDRIVER_DISPATCH) PnpRootPowerControl;
960   DriverObject->DriverExtension->AddDevice = PnpRootAddDevice;
961
962   return STATUS_SUCCESS;
963 }
964
965 /* EOF */