IoCreateDevice(): Fixed missing initialization of 'CreatedDeviceObject->Vpb'
[reactos.git] / ntoskrnl / io / device.c
1 /* $Id$
2  *
3  * COPYRIGHT:      See COPYING in the top level directory
4  * PROJECT:        ReactOS kernel
5  * FILE:           ntoskrnl/io/device.c
6  * PURPOSE:        Manage devices
7  * PROGRAMMER:     David Welch (welch@cwcom.net)
8  * UPDATE HISTORY:
9  *                 15/05/98: Created
10  */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/io.h>
16 #include <internal/po.h>
17 #include <internal/ldr.h>
18 #include <internal/id.h>
19 #include <internal/pool.h>
20 #include <internal/registry.h>
21
22 #include <roscfg.h>
23
24 #define NDEBUG
25 //#define DBG
26 #include <internal/debug.h>
27
28 /* GLOBALS *******************************************************************/
29
30 #define TAG_DRIVER             TAG('D', 'R', 'V', 'R')
31 #define TAG_DRIVER_EXTENSION   TAG('D', 'R', 'V', 'E')
32 #define TAG_DEVICE_EXTENSION   TAG('D', 'E', 'X', 'T')
33
34 #define DRIVER_REGISTRY_KEY_BASENAME  L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
35
36 /* FUNCTIONS ***************************************************************/
37
38 #ifndef LIBCAPTIVE
39
40 NTSTATUS STDCALL
41 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
42                         IN PDEVICE_OBJECT TargetDevice)
43 {
44         PDEVICE_OBJECT AttachedDevice;
45
46         DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
47                SourceDevice,
48                TargetDevice);
49
50         AttachedDevice = IoAttachDeviceToDeviceStack (SourceDevice,
51                                                       TargetDevice);
52         if (AttachedDevice == NULL)
53                 return STATUS_NO_SUCH_DEVICE;
54
55         return STATUS_SUCCESS;
56 }
57
58 #endif /* LIBCAPTIVE */
59
60 VOID STDCALL
61 IoDeleteDevice(PDEVICE_OBJECT DeviceObject)
62 {
63         PDEVICE_OBJECT Previous;
64
65         if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
66                 IoUnregisterShutdownNotification(DeviceObject);
67
68         /* remove the timer if it exists */
69         if (DeviceObject->Timer)
70         {
71 #ifndef LIBCAPTIVE
72                 IoStopTimer(DeviceObject);
73                 ExFreePool(DeviceObject->Timer);
74 #else /* !LIBCAPTIVE */
75                 KeBugCheck(0);
76 #endif /* !LIBCAPTIVE */
77         }
78
79 #ifndef LIBCAPTIVE
80         /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
81          * Undocumented by W32!
82          * See also IoCreateDevice().
83          */
84         /* free device extension */
85         if (DeviceObject->DeviceObjectExtension)
86                 ExFreePool (DeviceObject->DeviceObjectExtension);
87 #endif /* LIBCAPTIVE */
88
89         /* remove device from driver device list */
90         Previous = DeviceObject->DriverObject->DeviceObject;
91         if (Previous == DeviceObject)
92         {
93                 DeviceObject->DriverObject->DeviceObject = DeviceObject->NextDevice;
94         }
95         else
96         {
97                 while (Previous->NextDevice != DeviceObject)
98                         Previous = Previous->NextDevice;
99                 Previous->NextDevice = DeviceObject->NextDevice;
100         }
101
102         ObDereferenceObject (DeviceObject);
103 }
104
105 #ifndef LIBCAPTIVE
106
107 PDEVICE_OBJECT
108 STDCALL
109 IoGetRelatedDeviceObject (
110         IN      PFILE_OBJECT    FileObject
111         )
112 {
113         return (FileObject->DeviceObject);
114 }
115
116
117 NTSTATUS
118 STDCALL
119 IoGetDeviceObjectPointer (
120         IN      PUNICODE_STRING ObjectName,
121         IN      ACCESS_MASK     DesiredAccess,
122         OUT     PFILE_OBJECT    * FileObject,
123         OUT     PDEVICE_OBJECT  * DeviceObject)
124 {
125         OBJECT_ATTRIBUTES ObjectAttributes;
126         IO_STATUS_BLOCK StatusBlock;
127         PFILE_OBJECT LocalFileObject;
128         HANDLE FileHandle;
129         NTSTATUS Status;
130
131         DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
132                ObjectName,
133                DesiredAccess,
134                FileObject,
135                DeviceObject);
136
137         InitializeObjectAttributes (&ObjectAttributes,
138                                     ObjectName,
139                                     0,
140                                     NULL,
141                                     NULL);
142
143         Status = NtOpenFile (&FileHandle,
144                              DesiredAccess,
145                              &ObjectAttributes,
146                              &StatusBlock,
147                              0,
148                              FILE_NON_DIRECTORY_FILE);
149         if (!NT_SUCCESS(Status))
150                 return Status;
151
152         Status = ObReferenceObjectByHandle (FileHandle,
153                                             0,
154                                             IoFileObjectType,
155                                             KernelMode,
156                                             (PVOID*)&LocalFileObject,
157                                             NULL);
158         if (NT_SUCCESS(Status))
159         {
160                 *DeviceObject = IoGetRelatedDeviceObject (LocalFileObject);
161                 *FileObject = LocalFileObject;
162         }
163         NtClose (FileHandle);
164
165         return Status;
166 }
167
168
169 VOID
170 STDCALL
171 IoDetachDevice(PDEVICE_OBJECT TargetDevice)
172 {
173 //   UNIMPLEMENTED;
174    DPRINT("IoDetachDevice(TargetDevice %x) - UNIMPLEMENTED\n", TargetDevice);
175 }
176
177 #endif /* LIBCAPTIVE */
178
179 PDEVICE_OBJECT
180 STDCALL
181 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
182 {
183    PDEVICE_OBJECT Current = DeviceObject;
184    
185 //   DPRINT("IoGetAttachedDevice(DeviceObject %x)\n",DeviceObject);
186    
187    while (Current->AttachedDevice!=NULL)
188      {
189         Current = Current->AttachedDevice;
190 //      DPRINT("Current %x\n",Current);
191      }
192
193 //   DPRINT("IoGetAttachedDevice() = %x\n",DeviceObject);
194    return(Current);
195 }
196
197 #ifndef LIBCAPTIVE
198
199 PDEVICE_OBJECT
200 STDCALL
201 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
202 {
203    PDEVICE_OBJECT Current = DeviceObject;
204
205    while (Current->AttachedDevice!=NULL)
206      {
207         Current = Current->AttachedDevice;
208      }
209
210    ObReferenceObject(Current);
211    return(Current);
212 }
213
214 PDEVICE_OBJECT STDCALL
215 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice,
216                             PDEVICE_OBJECT TargetDevice)
217 {
218    PDEVICE_OBJECT AttachedDevice;
219    
220    DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
221           SourceDevice,TargetDevice);
222
223    AttachedDevice = IoGetAttachedDevice(TargetDevice);
224    AttachedDevice->AttachedDevice = SourceDevice;
225    SourceDevice->AttachedDevice = NULL;
226    SourceDevice->StackSize = AttachedDevice->StackSize + 1;
227    SourceDevice->Vpb = AttachedDevice->Vpb;
228    return(AttachedDevice);
229 }
230
231 VOID STDCALL
232 IoRegisterDriverReinitialization(PDRIVER_OBJECT DriverObject,
233                                  PDRIVER_REINITIALIZE ReinitRoutine,
234                                  PVOID Context)
235 {
236    UNIMPLEMENTED;
237 }
238
239 NTSTATUS STDCALL
240 IopDefaultDispatchFunction(PDEVICE_OBJECT DeviceObject,
241                            PIRP Irp)
242 {
243   Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
244   Irp->IoStatus.Information = 0;
245
246   IoCompleteRequest(Irp, IO_NO_INCREMENT);
247   return(STATUS_NOT_IMPLEMENTED);
248 }
249
250
251 NTSTATUS
252 IopCreateDriverObject(PDRIVER_OBJECT *DriverObject,
253                       PUNICODE_STRING ServiceName,
254                       BOOLEAN FileSystem)
255 {
256   PDRIVER_OBJECT Object;
257   HANDLE DriverHandle = 0;
258   ULONG i;
259   WCHAR NameBuffer[MAX_PATH];
260   UNICODE_STRING DriverName;
261   OBJECT_ATTRIBUTES ObjectAttributes;
262   NTSTATUS Status;
263
264   DPRINT("IopCreateDriverObject(%p '%wZ' %x)\n", DriverObject, ServiceName, FileSystem);
265
266   *DriverObject = NULL;
267
268   /*  Create ModuleName string  */
269   if (ServiceName != NULL)
270     {
271       if (FileSystem == TRUE)
272         wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
273       else
274         wcscpy(NameBuffer, DRIVER_ROOT_NAME);
275       wcscat(NameBuffer, ServiceName->Buffer);
276
277       RtlInitUnicodeString(&DriverName,
278                            NameBuffer);
279       DPRINT("Driver name: '%wZ'\n", &DriverName);
280     }
281
282   /*  Initialize ObjectAttributes for ModuleObject  */
283   InitializeObjectAttributes(&ObjectAttributes,
284                              (ServiceName != NULL)? &DriverName : NULL,
285                              OBJ_PERMANENT,
286                              NULL,
287                              NULL);
288
289   /*  Create module object  */
290   Status = ObCreateObject(&DriverHandle,
291                           STANDARD_RIGHTS_REQUIRED,
292                           &ObjectAttributes,
293                           IoDriverObjectType,
294                           (PVOID*)&Object);
295   if (!NT_SUCCESS(Status))
296     {
297       return(Status);
298     }
299
300   NtClose(DriverHandle);
301
302   /* Create driver extension */
303   Object->DriverExtension = (PDRIVER_EXTENSION)
304     ExAllocatePoolWithTag(NonPagedPool,
305        sizeof(DRIVER_EXTENSION),
306        TAG_DRIVER_EXTENSION);
307   if (Object->DriverExtension == NULL)
308     {
309       ExFreePool(Object);
310       return(STATUS_INSUFFICIENT_RESOURCES);
311     }
312
313   RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION));
314
315   Object->Type = InternalDriverType;
316
317   for (i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++)
318     {
319        Object->MajorFunction[i] = (PDRIVER_DISPATCH) IopDefaultDispatchFunction;
320     }
321
322   *DriverObject = Object;
323
324   return STATUS_SUCCESS;
325 }
326
327 NTSTATUS
328 IopAttachFilterDrivers(PDEVICE_NODE DeviceNode,
329                        BOOLEAN Lower)
330 {
331   return STATUS_SUCCESS;
332 }
333
334 NTSTATUS 
335 IopInitializeDevice(PDEVICE_NODE DeviceNode,
336                     BOOLEAN BootDriversOnly)
337 {
338   IO_STATUS_BLOCK       IoStatusBlock;
339   PDRIVER_OBJECT DriverObject;
340   IO_STACK_LOCATION Stack;
341   PDEVICE_OBJECT Fdo;
342   NTSTATUS Status;
343
344   DriverObject = DeviceNode->DriverObject;
345
346   if (DriverObject->DriverExtension->AddDevice)
347     {
348       /* This is a Plug and Play driver */
349       DPRINT("Plug and Play driver found\n");
350
351       assert(DeviceNode->Pdo);
352
353       DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
354         DriverObject->DriverExtension->AddDevice);
355       Status = DriverObject->DriverExtension->AddDevice(
356         DriverObject, DeviceNode->Pdo);
357       if (!NT_SUCCESS(Status))
358         {
359                 return(Status);
360         }
361
362       IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
363
364       DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
365
366       Fdo = IoGetAttachedDeviceReference(DeviceNode->Pdo);
367
368       if (Fdo == DeviceNode->Pdo)
369         {
370           /* FIXME: What do we do? Unload the driver or just disable the device? */
371           DbgPrint("An FDO was not attached\n");
372           KeBugCheck(0);
373         }
374
375       /* FIXME: Put some resources in the IRP for the device */
376       Stack.Parameters.StartDevice.AllocatedResources = NULL;
377       Stack.Parameters.StartDevice.AllocatedResourcesTranslated = NULL;
378
379       Status = IopInitiatePnpIrp(
380         Fdo,
381         &IoStatusBlock,
382         IRP_MN_START_DEVICE,
383         &Stack);
384       if (!NT_SUCCESS(Status))
385         {
386           DPRINT("IopInitiatePnpIrp() failed\n");
387           ObDereferenceObject(Fdo);
388                 return(Status);
389         }
390
391       if (Fdo->DeviceType == FILE_DEVICE_BUS_EXTENDER)
392         {
393           DPRINT("Bus extender found\n");
394
395           Status = IopInterrogateBusExtender(
396             DeviceNode, Fdo, BootDriversOnly);
397           if (!NT_SUCCESS(Status))
398             {
399               ObDereferenceObject(Fdo);
400                     return(Status);
401             }
402         }
403       else if (Fdo->DeviceType == FILE_DEVICE_ACPI)
404         {
405 #ifdef ACPI
406           static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
407
408           /* There can be only one system power device */
409           if (!SystemPowerDeviceNodeCreated)
410             {
411               PopSystemPowerDeviceNode = DeviceNode;
412               SystemPowerDeviceNodeCreated = TRUE;
413             }
414 #endif /* ACPI */
415         }
416       ObDereferenceObject(Fdo);
417     }
418
419   return STATUS_SUCCESS;
420 }
421
422 NTSTATUS
423 IopInitializeService(
424   PDEVICE_NODE DeviceNode,
425   PUNICODE_STRING ImagePath)
426 {
427   PMODULE_OBJECT ModuleObject;
428   NTSTATUS Status;
429
430   ModuleObject = LdrGetModuleObject(&DeviceNode->ServiceName);
431   if (ModuleObject == NULL)
432   {
433     /* The module is currently not loaded, so load it now */
434
435     Status = LdrLoadModule(ImagePath, &ModuleObject);
436     if (!NT_SUCCESS(Status))
437     {
438       /* FIXME: Log the error */
439       CPRINT("Driver load failed\n");
440       return(Status);
441     }
442
443     Status = IopInitializeDriver(ModuleObject->EntryPoint, DeviceNode, FALSE);
444     if (!NT_SUCCESS(Status))
445     {
446       LdrUnloadModule(ModuleObject);
447
448       /* FIXME: Log the error */
449       CPRINT("A driver failed to initialize\n");
450       return(Status);
451     }
452   }
453
454   Status = IopInitializeDevice(DeviceNode, TRUE);
455
456   return(Status);
457 }
458
459 NTSTATUS
460 IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode)
461 {
462   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
463   UNICODE_STRING ImagePath;
464   HANDLE KeyHandle;
465   NTSTATUS Status;
466
467   Status = RtlpGetRegistryHandle(
468     RTL_REGISTRY_SERVICES,
469           DeviceNode->ServiceName.Buffer,
470                 TRUE,
471                 &KeyHandle);
472   if (!NT_SUCCESS(Status))
473     {
474       DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status);
475       return(Status);
476     }
477
478   RtlZeroMemory(QueryTable, sizeof(QueryTable));
479
480   RtlInitUnicodeString(&ImagePath, NULL);
481
482   QueryTable[0].Name = L"ImagePath";
483   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
484   QueryTable[0].EntryContext = &ImagePath;
485
486   Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
487                                   (PWSTR)KeyHandle,
488                                   QueryTable,
489                                   NULL,
490                                   NULL);
491   NtClose(KeyHandle);
492
493   DPRINT("RtlQueryRegistryValues() returned status %x\n", Status);
494
495   if (NT_SUCCESS(Status))
496     {
497       DPRINT("Got ImagePath %S\n", ImagePath.Buffer);
498
499       Status = IopInitializeService(DeviceNode, &ImagePath);
500
501       RtlFreeUnicodeString(&ImagePath);
502     }
503
504   return(Status);
505 }
506
507 NTSTATUS
508 IopInitializeDriver(PDRIVER_INITIALIZE DriverEntry,
509                     PDEVICE_NODE DeviceNode,
510                     BOOLEAN FileSystemDriver)
511 /*
512  * FUNCTION: Called to initalize a loaded driver
513  * ARGUMENTS:
514  *   DriverEntry = Pointer to driver entry routine
515  *   DeviceNode  = Pointer to device node
516  */
517 {
518   WCHAR RegistryKeyBuffer[MAX_PATH];
519   PDRIVER_OBJECT DriverObject;
520   UNICODE_STRING RegistryKey;
521   NTSTATUS Status;
522
523   DPRINT("IopInitializeDriver(DriverEntry %08lx, DeviceNode %08lx)\n",
524     DriverEntry, DeviceNode);
525
526   Status = IopCreateDriverObject(&DriverObject,
527                                  &DeviceNode->ServiceName,
528                                  FileSystemDriver);
529   if (!NT_SUCCESS(Status))
530     {
531       return(Status);
532     }
533
534   DeviceNode->DriverObject = DriverObject;
535
536   if (DeviceNode->ServiceName.Buffer)
537     {
538       wcscpy(RegistryKeyBuffer, DRIVER_REGISTRY_KEY_BASENAME);
539       wcscat(RegistryKeyBuffer, DeviceNode->ServiceName.Buffer);
540       RtlInitUnicodeString(&RegistryKey, RegistryKeyBuffer);
541     }
542   else
543     {
544       RtlInitUnicodeString(&RegistryKey, NULL);
545     }
546
547   DPRINT("RegistryKey: %wZ\n", &RegistryKey);
548   DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
549
550   Status = DriverEntry(DriverObject, &RegistryKey);
551   if (!NT_SUCCESS(Status))
552     {
553       DeviceNode->DriverObject = NULL;
554       ExFreePool(DriverObject->DriverExtension);
555       ObMakeTemporaryObject(DriverObject);
556       ObDereferenceObject(DriverObject);
557       return(Status);
558     }
559
560   Status = IopInitializeDevice(DeviceNode, TRUE);
561
562   return(Status);
563 }
564
565
566 NTSTATUS STDCALL
567 IoAttachDevice(PDEVICE_OBJECT SourceDevice,
568                PUNICODE_STRING TargetDevice,
569                PDEVICE_OBJECT* AttachedDevice)
570 /*
571  * FUNCTION: Layers a device over the highest device in a device stack
572  * ARGUMENTS:
573  *       SourceDevice = Device to attached
574  *       TargetDevice = Name of the target device
575  *       AttachedDevice (OUT) = Caller storage for the device attached to
576  */
577 {
578   UNIMPLEMENTED;
579 }
580
581 #endif /* LIBCAPTIVE */
582
583 NTSTATUS STDCALL
584 IopCreateDevice(PVOID ObjectBody,
585                 PVOID Parent,
586                 PWSTR RemainingPath,
587                 POBJECT_ATTRIBUTES ObjectAttributes)
588 {
589    
590    DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
591           ObjectBody, Parent, RemainingPath);
592    
593    if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
594      {
595         return(STATUS_UNSUCCESSFUL);
596      }
597    
598    return(STATUS_SUCCESS);
599 }
600
601 NTSTATUS STDCALL
602 IoCreateDevice(PDRIVER_OBJECT DriverObject,
603                ULONG DeviceExtensionSize,
604                PUNICODE_STRING DeviceName,
605                DEVICE_TYPE DeviceType,
606                ULONG DeviceCharacteristics,
607                BOOLEAN Exclusive,
608                PDEVICE_OBJECT* DeviceObject)
609 /*
610  * FUNCTION: Allocates memory for and intializes a device object for use for
611  * a driver
612  * ARGUMENTS:
613  *         DriverObject : Driver object passed by iomgr when the driver was
614  *                        loaded
615  *         DeviceExtensionSize : Number of bytes for the device extension
616  *         DeviceName : Unicode name of device
617  *         DeviceType : Device type
618  *         DeviceCharacteristics : Bit mask of device characteristics
619  *         Exclusive : True if only one thread can access the device at a
620  *                     time
621  * RETURNS:
622  *         Success or failure
623  *         DeviceObject : Contains a pointer to allocated device object
624  *                        if the call succeeded
625  * NOTES: See the DDK documentation for more information
626  */
627 {
628    PDEVICE_OBJECT CreatedDeviceObject;
629    OBJECT_ATTRIBUTES ObjectAttributes;
630    HANDLE DeviceHandle;
631    NTSTATUS Status;
632    
633    assert_irql(PASSIVE_LEVEL);
634    
635    assert(sizeof(CreatedDeviceObject->Queue.Wcb) == 40);
636    assert(sizeof(CreatedDeviceObject->DeviceQueue) == 20);
637    assert(sizeof(CreatedDeviceObject->Dpc) == 32);
638    assert(sizeof(CreatedDeviceObject->DeviceLock) == 16);
639    assert(sizeof(DEVICE_OBJECT) == 184);
640
641    if (DeviceName != NULL)
642      {
643         DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",DriverObject,
644                DeviceName->Buffer);
645      }
646    else
647      {
648         DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject);
649      }
650    
651 #ifdef LIBCAPTIVE
652    /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
653     * Undocumented by W32!
654     * See also IoDeleteDevice().
655     */
656    /* TODO:thread */
657    IoDeviceObjectType->NonpagedPoolCharge = sizeof (DEVICE_OBJECT) + DeviceExtensionSize;
658 #endif /* LIBCAPTIVE */
659
660    if (DeviceName != NULL)
661      {
662         InitializeObjectAttributes(&ObjectAttributes,DeviceName,0,NULL,NULL);
663         Status = ObCreateObject(&DeviceHandle,
664                                 0,
665                                 &ObjectAttributes,
666                                 IoDeviceObjectType,
667                                 (PVOID*)&CreatedDeviceObject);
668      }
669    else
670      {
671         Status = ObCreateObject(&DeviceHandle,
672                                 0,
673                                 NULL,
674                                 IoDeviceObjectType,
675                                 (PVOID*)&CreatedDeviceObject);
676      }
677    
678 #ifdef LIBCAPTIVE
679    /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
680     * Undocumented by W32!
681     * See also IoDeleteDevice().
682     */
683    /* TODO:thread */
684    IoDeviceObjectType->NonpagedPoolCharge = sizeof (DEVICE_OBJECT);     /* restore */
685 #endif /* LIBCAPTIVE */
686
687    *DeviceObject = NULL;
688    
689    if (!NT_SUCCESS(Status))
690      {
691         DPRINT("IoCreateDevice() ObCreateObject failed, status: 0x%08X\n", Status);
692         return(Status);
693      }
694   
695    if (DriverObject->DeviceObject == NULL)
696      {
697         DriverObject->DeviceObject = CreatedDeviceObject;
698         CreatedDeviceObject->NextDevice = NULL;
699      }
700    else
701      {
702         CreatedDeviceObject->NextDevice = DriverObject->DeviceObject;
703         DriverObject->DeviceObject = CreatedDeviceObject;
704      }
705   
706   CreatedDeviceObject->Type = DeviceType;
707   CreatedDeviceObject->Size = sizeof (*CreatedDeviceObject);
708   CreatedDeviceObject->ReferenceCount = 0;      /* or 1? it is floating unused this way */
709   CreatedDeviceObject->DriverObject = DriverObject;
710   CreatedDeviceObject->CurrentIrp = NULL;
711   CreatedDeviceObject->Flags = 0;
712   CreatedDeviceObject->Characteristics = DeviceCharacteristics;
713   CreatedDeviceObject->Timer = NULL;
714   CreatedDeviceObject->Vpb = NULL;
715
716 #ifndef LIBCAPTIVE
717   CreatedDeviceObject->DeviceExtension = 
718     ExAllocatePoolWithTag(NonPagedPool, DeviceExtensionSize,
719                           TAG_DEVICE_EXTENSION);
720 #else /* !LIBCAPTIVE */
721   /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
722    * Undocumented by W32!
723    * See also IoDeleteDevice().
724    */
725   CreatedDeviceObject->DeviceExtension = (void *)(CreatedDeviceObject+1);
726 #endif /* LIBCAPTIVE */
727   if (DeviceExtensionSize > 0 && CreatedDeviceObject->DeviceExtension == NULL)
728     {
729       ExFreePool(CreatedDeviceObject);
730       DPRINT("IoCreateDevice() ExAllocatePoolWithTag failed, returning: 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES);
731       return(STATUS_INSUFFICIENT_RESOURCES);
732     }
733
734   if (DeviceExtensionSize > 0)
735     {
736       RtlZeroMemory(CreatedDeviceObject->DeviceExtension,
737                     DeviceExtensionSize);
738     }
739
740   CreatedDeviceObject->AttachedDevice = NULL;
741   CreatedDeviceObject->DeviceType = DeviceType;
742   CreatedDeviceObject->StackSize = 1;
743   CreatedDeviceObject->AlignmentRequirement = 1;
744   KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
745   
746   KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
747                     SynchronizationEvent,
748                     TRUE);
749   
750   /* FIXME: Do we need to add network drives too?! */
751   if (CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK ||
752       CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ||
753       CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)
754     {
755       IoAttachVpb(CreatedDeviceObject);
756     }
757   
758   *DeviceObject = CreatedDeviceObject;
759   
760   return(STATUS_SUCCESS);
761 }
762
763 #ifndef LIBCAPTIVE
764
765 NTSTATUS
766 STDCALL
767 IoOpenDeviceInstanceKey (
768         DWORD   Unknown0,
769         DWORD   Unknown1,
770         DWORD   Unknown2,
771         DWORD   Unknown3,
772         DWORD   Unknown4
773         )
774 {
775   UNIMPLEMENTED;
776   return(STATUS_NOT_IMPLEMENTED);
777 }
778
779
780 DWORD
781 STDCALL
782 IoQueryDeviceEnumInfo (
783         DWORD   Unknown0,
784         DWORD   Unknown1
785         )
786 {
787   UNIMPLEMENTED;
788   return 0;
789 }
790
791 #endif /* LIBCAPTIVE */
792
793 /* EOF */