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