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