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