[bus_pnp] Move bus PnP IRP handling into bus_pnp
[people/sha0/winvblock.git] / src / bus.c
1 /**
2  * Copyright (C) 2009, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  * Copyright 2006-2008, V.
4  * For WinAoE contact information, see http://winaoe.org/
5  *
6  * This file is part of WinVBlock, derived from WinAoE.
7  *
8  * WinVBlock is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * WinVBlock is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23  * @file
24  *
25  * Bus specifics
26  *
27  */
28
29 #include <ntddk.h>
30
31 #include "winvblock.h"
32 #include "portable.h"
33 #include "irp.h"
34 #include "driver.h"
35 #include "disk.h"
36 #include "bus.h"
37 #include "bus_pnp.h"
38 #include "aoe.h"
39 #include "mount.h"
40 #include "debug.h"
41 #include "mdi.h"
42 #include "protocol.h"
43 #include "probe.h"
44
45 /* in this file */
46 static irp__handler_decl (
47   Bus_DispatchNotSupported
48  );
49 static irp__handler_decl (
50   Bus_DispatchPower
51  );
52 winvblock__bool STDCALL Bus_AddChild (
53   IN PDEVICE_OBJECT BusDeviceObject,
54   IN disk__type Disk,
55   IN winvblock__bool Boot
56  );
57
58 typedef struct _BUS_TARGETLIST
59 {
60   MOUNT_TARGET Target;
61   struct _BUS_TARGETLIST *Next;
62 } BUS_TARGETLIST,
63 *PBUS_TARGETLIST;
64
65 static PBUS_TARGETLIST Bus_Globals_TargetList = NULL;
66 static KSPIN_LOCK Bus_Globals_TargetListSpinLock;
67 static ULONG Bus_Globals_NextDisk = 0;
68 PDEVICE_OBJECT bus__fdo = NULL;
69
70 NTSTATUS STDCALL
71 Bus_Start (
72   void
73  )
74 {
75   DBG ( "Entry\n" );
76   KeInitializeSpinLock ( &Bus_Globals_TargetListSpinLock );
77   return STATUS_SUCCESS;
78 }
79
80 VOID STDCALL
81 Bus_Stop (
82   void
83  )
84 {
85   UNICODE_STRING DosDeviceName;
86   PBUS_TARGETLIST Walker,
87    Next;
88   KIRQL Irql;
89
90   DBG ( "Entry\n" );
91   KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
92   Walker = Bus_Globals_TargetList;
93   while ( Walker != NULL )
94     {
95       Next = Walker->Next;
96       ExFreePool ( Walker );
97       Walker = Next;
98     }
99   KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
100   RtlInitUnicodeString ( &DosDeviceName, L"\\DosDevices\\AoE" );
101   IoDeleteSymbolicLink ( &DosDeviceName );
102   bus__fdo = NULL;
103 }
104
105 VOID STDCALL
106 Bus_AddTarget (
107   IN winvblock__uint8_ptr ClientMac,
108   IN winvblock__uint8_ptr ServerMac,
109   winvblock__uint16 Major,
110   winvblock__uint8 Minor,
111   LONGLONG LBASize
112  )
113 {
114   PBUS_TARGETLIST Walker,
115    Last;
116   KIRQL Irql;
117
118   KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
119   Last = Bus_Globals_TargetList;
120   Walker = Bus_Globals_TargetList;
121   while ( Walker != NULL )
122     {
123       if ( ( RtlCompareMemory ( &Walker->Target.ClientMac, ClientMac, 6 ) ==
124              6 )
125            && ( RtlCompareMemory ( &Walker->Target.ServerMac, ServerMac, 6 ) ==
126                 6 ) && Walker->Target.Major == Major
127            && Walker->Target.Minor == Minor )
128         {
129           if ( Walker->Target.LBASize != LBASize )
130             {
131               DBG ( "LBASize changed for e%d.%d " "(%I64u->%I64u)\n", Major,
132                     Minor, Walker->Target.LBASize, LBASize );
133               Walker->Target.LBASize = LBASize;
134             }
135           KeQuerySystemTime ( &Walker->Target.ProbeTime );
136           KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
137           return;
138         }
139       Last = Walker;
140       Walker = Walker->Next;
141     }
142
143   if ( ( Walker =
144          ( PBUS_TARGETLIST ) ExAllocatePool ( NonPagedPool,
145                                               sizeof ( BUS_TARGETLIST ) ) ) ==
146        NULL )
147     {
148       DBG ( "ExAllocatePool Target\n" );
149       KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
150       return;
151     }
152   Walker->Next = NULL;
153   RtlCopyMemory ( Walker->Target.ClientMac, ClientMac, 6 );
154   RtlCopyMemory ( Walker->Target.ServerMac, ServerMac, 6 );
155   Walker->Target.Major = Major;
156   Walker->Target.Minor = Minor;
157   Walker->Target.LBASize = LBASize;
158   KeQuerySystemTime ( &Walker->Target.ProbeTime );
159
160   if ( Last == NULL )
161     {
162       Bus_Globals_TargetList = Walker;
163     }
164   else
165     {
166       Last->Next = Walker;
167     }
168   KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
169 }
170
171 VOID STDCALL
172 Bus_CleanupTargetList (
173   void
174  )
175 {
176 }
177
178 /*
179  * Establish a pointer into the bus device's extension space
180  */
181 bus__type_ptr STDCALL
182 get_bus_ptr (
183   driver__dev_ext_ptr dev_ext_ptr
184  )
185 {
186   winvblock__uint8_ptr tmp = ( winvblock__uint8_ptr ) dev_ext_ptr;
187   bus__type_ptr bus_ptr =
188     ( bus__type_ptr ) ( tmp + sizeof ( driver__dev_ext ) );
189   return bus_ptr;
190 }
191
192 /*
193  * Establish a pointer into the child disk device's extension space
194  */
195 disk__type_ptr STDCALL
196 get_disk_ptr (
197   driver__dev_ext_ptr dev_ext_ptr
198  )
199 {
200   winvblock__uint8_ptr tmp = ( winvblock__uint8_ptr ) dev_ext_ptr;
201   disk__type_ptr disk_ptr =
202     ( disk__type_ptr ) ( tmp + sizeof ( driver__dev_ext ) );
203   return disk_ptr;
204 }
205
206 /**
207  * Add a child node to the bus
208  *
209  * @v BusDeviceObject The bus to add the node to
210  * @v Disk            The disk to add
211  * @v Boot            Is this a boot device?
212  *
213  * Returns TRUE for success, FALSE for failure
214  */
215 winvblock__bool STDCALL
216 Bus_AddChild (
217   IN PDEVICE_OBJECT BusDeviceObject,
218   IN disk__type Disk,
219   IN winvblock__bool Boot
220  )
221 {
222         /**
223    * @v Status              Status of last operation
224    * @v BusDeviceExtension  Shortcut to the bus' device extension
225    * @v DeviceObject        The new node's device object
226    * @v DeviceExtension     The new node's device extension
227    * @v Walker              Walks the child nodes
228    */
229   NTSTATUS Status;
230   PDEVICE_OBJECT DeviceObject;
231   driver__dev_ext_ptr bus_dev_ext_ptr,
232    disk_dev_ext_ptr;
233   bus__type_ptr bus_ptr;
234   size_t new_dev_ext_size;
235   disk__type_ptr disk_ptr,
236    Walker;
237   DEVICE_TYPE DiskType =
238     Disk.DiskType == OpticalDisc ? FILE_DEVICE_CD_ROM : FILE_DEVICE_DISK;
239   ULONG DiskType2 =
240     Disk.DiskType ==
241     OpticalDisc ? FILE_READ_ONLY_DEVICE | FILE_REMOVABLE_MEDIA : Disk.
242     DiskType == FloppyDisk ? FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE : 0;
243
244   DBG ( "Entry\n" );
245   /*
246    * Establish pointers into the bus device's extension space
247    */
248   bus_dev_ext_ptr = ( driver__dev_ext_ptr ) BusDeviceObject->DeviceExtension;
249   bus_ptr = get_bus_ptr ( bus_dev_ext_ptr );
250   /*
251    * Create the child device
252    */
253   new_dev_ext_size =
254     sizeof ( driver__dev_ext ) + sizeof ( disk__type ) +
255     driver__handling_table_size;
256   if ( !NT_SUCCESS
257        ( Status =
258          IoCreateDevice ( bus_dev_ext_ptr->DriverObject, new_dev_ext_size,
259                           NULL, DiskType,
260                           FILE_AUTOGENERATED_DEVICE_NAME |
261                           FILE_DEVICE_SECURE_OPEN | DiskType2, FALSE,
262                           &DeviceObject ) ) )
263     {
264       Error ( "Bus_AddChild IoCreateDevice", Status );
265       return FALSE;
266     }
267   /*
268    * Establish pointers into the child disk device's extension space
269    */
270   disk_dev_ext_ptr = ( driver__dev_ext_ptr ) DeviceObject->DeviceExtension;
271   disk_ptr = get_disk_ptr ( disk_dev_ext_ptr );
272   /*
273    * Clear the extension space and establish parameters
274    */
275   RtlZeroMemory ( disk_dev_ext_ptr, new_dev_ext_size );
276   disk_dev_ext_ptr->IsBus = FALSE;
277   disk_dev_ext_ptr->dispatch = Disk_Dispatch;
278   disk_dev_ext_ptr->Self = DeviceObject;
279   disk_dev_ext_ptr->DriverObject = bus_dev_ext_ptr->DriverObject;
280   disk_dev_ext_ptr->State = NotStarted;
281   disk_dev_ext_ptr->OldState = NotStarted;
282   disk_dev_ext_ptr->irp_handler_stack_ptr =
283     ( winvblock__uint8 * ) disk_dev_ext_ptr + sizeof ( driver__dev_ext ) +
284     sizeof ( disk__type );
285   RtlCopyMemory ( disk_dev_ext_ptr->irp_handler_stack_ptr,
286                   driver__handling_table, driver__handling_table_size );
287   disk_dev_ext_ptr->irp_handler_stack_size =
288     driver__handling_table_size / sizeof ( irp__handling );
289   /*
290    * Copy the provided disk parameters into the disk extension space
291    */
292   RtlCopyMemory ( disk_ptr, &Disk, sizeof ( disk__type ) );
293   disk_ptr->dev_ext_ptr = disk_dev_ext_ptr;
294   disk_ptr->Parent = BusDeviceObject;
295   disk_ptr->next_sibling_ptr = NULL;
296   KeInitializeEvent ( &disk_ptr->SearchEvent, SynchronizationEvent, FALSE );
297   KeInitializeSpinLock ( &disk_ptr->SpinLock );
298   disk_ptr->BootDrive = Boot;
299   disk_ptr->Unmount = FALSE;
300   disk_ptr->DiskNumber = InterlockedIncrement ( &Bus_Globals_NextDisk ) - 1;
301   /*
302    * Some device parameters
303    */
304   DeviceObject->Flags |= DO_DIRECT_IO;  /* FIXME? */
305   DeviceObject->Flags |= DO_POWER_INRUSH;       /* FIXME? */
306   /*
307    * Determine the disk's geometry differently for AoE/MEMDISK
308    */
309   disk_ptr->Initialize ( disk_dev_ext_ptr );
310
311   DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
312   /*
313    * Add the new device's extension to the bus' list of children
314    */
315   if ( bus_ptr->first_child_ptr == NULL )
316     {
317       bus_ptr->first_child_ptr = disk_ptr;
318     }
319   else
320     {
321       Walker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
322       while ( Walker->next_sibling_ptr != NULL )
323         Walker = Walker->next_sibling_ptr;
324       Walker->next_sibling_ptr = disk_ptr;
325     }
326   bus_ptr->Children++;
327   return TRUE;
328 }
329
330 irp__handling handling_table[] = {
331   /*
332    * Major, minor, any major?, any minor?, handler
333    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
334    * Note that the fall-through case must come FIRST!
335    * Why? It sets completion to true, so others won't be called
336    */
337   {IRP_MJ_PNP, 0, FALSE, TRUE, bus_pnp__simple}
338   ,
339   {IRP_MJ_PNP, IRP_MN_START_DEVICE, FALSE, FALSE, bus_pnp__start_dev}
340   ,
341   {IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE, FALSE, FALSE, bus_pnp__remove_dev}
342   ,
343   {IRP_MJ_PNP, IRP_MN_QUERY_DEVICE_RELATIONS, FALSE, FALSE,
344    bus_pnp__query_dev_relations}
345 };
346
347 size_t handling_table_size = sizeof ( handling_table );
348
349 irp__handler_decl ( Bus_DispatchDeviceControl )
350 {
351   NTSTATUS Status;
352   winvblock__uint8_ptr Buffer;
353   ULONG Count;
354   PBUS_TARGETLIST TargetWalker;
355   bus__type_ptr bus_ptr;
356   disk__type_ptr DiskWalker,
357    DiskWalkerPrevious;
358   PMOUNT_TARGETS Targets;
359   PMOUNT_DISKS Disks;
360   KIRQL Irql;
361   disk__type Disk;
362
363   /*
364    * Establish a pointer into the bus device's extension space
365    */
366   bus_ptr = get_bus_ptr ( DeviceExtension );
367
368   switch ( Stack->Parameters.DeviceIoControl.IoControlCode )
369     {
370       case IOCTL_AOE_SCAN:
371         DBG ( "Got IOCTL_AOE_SCAN...\n" );
372         AoE_Start (  );
373         KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
374
375         Count = 0;
376         TargetWalker = Bus_Globals_TargetList;
377         while ( TargetWalker != NULL )
378           {
379             Count++;
380             TargetWalker = TargetWalker->Next;
381           }
382
383         if ( ( Targets =
384                ( PMOUNT_TARGETS ) ExAllocatePool ( NonPagedPool,
385                                                    sizeof ( MOUNT_TARGETS ) +
386                                                    ( Count *
387                                                      sizeof
388                                                      ( MOUNT_TARGET ) ) ) ) ==
389              NULL )
390           {
391             DBG ( "ExAllocatePool Targets\n" );
392             Irp->IoStatus.Information = 0;
393             Status = STATUS_INSUFFICIENT_RESOURCES;
394             break;
395           }
396         Irp->IoStatus.Information =
397           sizeof ( MOUNT_TARGETS ) + ( Count * sizeof ( MOUNT_TARGET ) );
398         Targets->Count = Count;
399
400         Count = 0;
401         TargetWalker = Bus_Globals_TargetList;
402         while ( TargetWalker != NULL )
403           {
404             RtlCopyMemory ( &Targets->Target[Count], &TargetWalker->Target,
405                             sizeof ( MOUNT_TARGET ) );
406             Count++;
407             TargetWalker = TargetWalker->Next;
408           }
409         RtlCopyMemory ( Irp->AssociatedIrp.SystemBuffer, Targets,
410                         ( Stack->Parameters.DeviceIoControl.
411                           OutputBufferLength <
412                           ( sizeof ( MOUNT_TARGETS ) +
413                             ( Count *
414                               sizeof ( MOUNT_TARGET ) ) ) ? Stack->Parameters.
415                           DeviceIoControl.
416                           OutputBufferLength : ( sizeof ( MOUNT_TARGETS ) +
417                                                  ( Count *
418                                                    sizeof
419                                                    ( MOUNT_TARGET ) ) ) ) );
420         ExFreePool ( Targets );
421
422         KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
423         Status = STATUS_SUCCESS;
424         break;
425       case IOCTL_AOE_SHOW:
426         DBG ( "Got IOCTL_AOE_SHOW...\n" );
427
428         Count = 0;
429         DiskWalker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
430         while ( DiskWalker != NULL )
431           {
432             Count++;
433             DiskWalker = DiskWalker->next_sibling_ptr;
434           }
435
436         if ( ( Disks =
437                ( PMOUNT_DISKS ) ExAllocatePool ( NonPagedPool,
438                                                  sizeof ( MOUNT_DISKS ) +
439                                                  ( Count *
440                                                    sizeof ( MOUNT_DISK ) ) ) )
441              == NULL )
442           {
443             DBG ( "ExAllocatePool Disks\n" );
444             Irp->IoStatus.Information = 0;
445             Status = STATUS_INSUFFICIENT_RESOURCES;
446             break;
447           }
448         Irp->IoStatus.Information =
449           sizeof ( MOUNT_DISKS ) + ( Count * sizeof ( MOUNT_DISK ) );
450         Disks->Count = Count;
451
452         Count = 0;
453         DiskWalker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
454         while ( DiskWalker != NULL )
455           {
456             Disks->Disk[Count].Disk = DiskWalker->DiskNumber;
457             RtlCopyMemory ( &Disks->Disk[Count].ClientMac,
458                             &DiskWalker->AoE.ClientMac, 6 );
459             RtlCopyMemory ( &Disks->Disk[Count].ServerMac,
460                             &DiskWalker->AoE.ServerMac, 6 );
461             Disks->Disk[Count].Major = DiskWalker->AoE.Major;
462             Disks->Disk[Count].Minor = DiskWalker->AoE.Minor;
463             Disks->Disk[Count].LBASize = DiskWalker->LBADiskSize;
464             Count++;
465             DiskWalker = DiskWalker->next_sibling_ptr;
466           }
467         RtlCopyMemory ( Irp->AssociatedIrp.SystemBuffer, Disks,
468                         ( Stack->Parameters.DeviceIoControl.
469                           OutputBufferLength <
470                           ( sizeof ( MOUNT_DISKS ) +
471                             ( Count *
472                               sizeof ( MOUNT_DISK ) ) ) ? Stack->Parameters.
473                           DeviceIoControl.
474                           OutputBufferLength : ( sizeof ( MOUNT_DISKS ) +
475                                                  ( Count *
476                                                    sizeof
477                                                    ( MOUNT_DISK ) ) ) ) );
478         ExFreePool ( Disks );
479
480         Status = STATUS_SUCCESS;
481         break;
482       case IOCTL_AOE_MOUNT:
483         Buffer = Irp->AssociatedIrp.SystemBuffer;
484         DBG ( "Got IOCTL_AOE_MOUNT for client: %02x:%02x:%02x:%02x:%02x:%02x "
485               "Major:%d Minor:%d\n", Buffer[0], Buffer[1], Buffer[2],
486               Buffer[3], Buffer[4], Buffer[5],
487               *( winvblock__uint16_ptr ) ( &Buffer[6] ),
488               ( winvblock__uint8 ) Buffer[8] );
489         Disk.Initialize = AoE_SearchDrive;
490         RtlCopyMemory ( Disk.AoE.ClientMac, Buffer, 6 );
491         RtlFillMemory ( Disk.AoE.ServerMac, 6, 0xff );
492         Disk.AoE.Major = *( winvblock__uint16_ptr ) ( &Buffer[6] );
493         Disk.AoE.Minor = ( winvblock__uint8 ) Buffer[8];
494         Disk.AoE.MaxSectorsPerPacket = 1;
495         Disk.AoE.Timeout = 200000;      /* 20 ms. */
496         Disk.IsRamdisk = FALSE;
497         if ( !Bus_AddChild ( DeviceObject, Disk, FALSE ) )
498           {
499             DBG ( "Bus_AddChild() failed\n" );
500           }
501         else
502           {
503             if ( bus_ptr->PhysicalDeviceObject != NULL )
504               IoInvalidateDeviceRelations ( bus_ptr->PhysicalDeviceObject,
505                                             BusRelations );
506           }
507         Irp->IoStatus.Information = 0;
508         Status = STATUS_SUCCESS;
509         break;
510       case IOCTL_AOE_UMOUNT:
511         Buffer = Irp->AssociatedIrp.SystemBuffer;
512         DBG ( "Got IOCTL_AOE_UMOUNT for disk: %d\n", *( PULONG ) Buffer );
513         DiskWalker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
514         DiskWalkerPrevious = DiskWalker;
515         while ( ( DiskWalker != NULL )
516                 && ( DiskWalker->DiskNumber != *( PULONG ) Buffer ) )
517           {
518             DiskWalkerPrevious = DiskWalker;
519             DiskWalker = DiskWalker->next_sibling_ptr;
520           }
521         if ( DiskWalker != NULL )
522           {
523             if ( DiskWalker->BootDrive )
524               {
525                 DBG ( "Cannot unmount a boot drive.\n" );
526                 Irp->IoStatus.Information = 0;
527                 Status = STATUS_INVALID_DEVICE_REQUEST;
528                 break;
529               }
530             DBG ( "Deleting disk %d\n", DiskWalker->DiskNumber );
531             if ( DiskWalker == ( disk__type_ptr ) bus_ptr->first_child_ptr )
532               {
533                 bus_ptr->first_child_ptr =
534                   ( winvblock__uint8_ptr ) DiskWalker->next_sibling_ptr;
535               }
536             else
537               {
538                 DiskWalkerPrevious->next_sibling_ptr =
539                   DiskWalker->next_sibling_ptr;
540               }
541             DiskWalker->Unmount = TRUE;
542             DiskWalker->next_sibling_ptr = NULL;
543             if ( bus_ptr->PhysicalDeviceObject != NULL )
544               IoInvalidateDeviceRelations ( bus_ptr->PhysicalDeviceObject,
545                                             BusRelations );
546           }
547         bus_ptr->Children--;
548         Irp->IoStatus.Information = 0;
549         Status = STATUS_SUCCESS;
550         break;
551       default:
552         Irp->IoStatus.Information = 0;
553         Status = STATUS_INVALID_DEVICE_REQUEST;
554     }
555
556   Irp->IoStatus.Status = Status;
557   IoCompleteRequest ( Irp, IO_NO_INCREMENT );
558   return Status;
559 }
560
561 irp__handler_decl ( Bus_DispatchSystemControl )
562 {
563   bus__type_ptr bus_ptr = get_bus_ptr ( DeviceExtension );
564   DBG ( "...\n" );
565   IoSkipCurrentIrpStackLocation ( Irp );
566   return IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
567 }
568
569 irp__handler_decl ( Bus_Dispatch )
570 {
571   NTSTATUS Status;
572   bus__type_ptr bus_ptr = get_bus_ptr ( DeviceExtension );
573
574   switch ( Stack->MajorFunction )
575     {
576       case IRP_MJ_POWER:
577         PoStartNextPowerIrp ( Irp );
578         IoSkipCurrentIrpStackLocation ( Irp );
579         Status = PoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
580         break;
581       case IRP_MJ_SYSTEM_CONTROL:
582         Status =
583           Bus_DispatchSystemControl ( DeviceObject, Irp, Stack,
584                                       DeviceExtension, completion_ptr );
585         break;
586       case IRP_MJ_DEVICE_CONTROL:
587         Status =
588           Bus_DispatchDeviceControl ( DeviceObject, Irp, Stack,
589                                       DeviceExtension, completion_ptr );
590         break;
591       default:
592         Status = STATUS_NOT_SUPPORTED;
593         Irp->IoStatus.Status = Status;
594         IoCompleteRequest ( Irp, IO_NO_INCREMENT );
595     }
596   return Status;
597 }
598
599 NTSTATUS STDCALL
600 Bus_GetDeviceCapabilities (
601   IN PDEVICE_OBJECT DeviceObject,
602   IN PDEVICE_CAPABILITIES DeviceCapabilities
603  )
604 {
605   IO_STATUS_BLOCK ioStatus;
606   KEVENT pnpEvent;
607   NTSTATUS status;
608   PDEVICE_OBJECT targetObject;
609   PIO_STACK_LOCATION irpStack;
610   PIRP pnpIrp;
611
612   RtlZeroMemory ( DeviceCapabilities, sizeof ( DEVICE_CAPABILITIES ) );
613   DeviceCapabilities->Size = sizeof ( DEVICE_CAPABILITIES );
614   DeviceCapabilities->Version = 1;
615   DeviceCapabilities->Address = -1;
616   DeviceCapabilities->UINumber = -1;
617
618   KeInitializeEvent ( &pnpEvent, NotificationEvent, FALSE );
619   targetObject = IoGetAttachedDeviceReference ( DeviceObject );
620   pnpIrp =
621     IoBuildSynchronousFsdRequest ( IRP_MJ_PNP, targetObject, NULL, 0, NULL,
622                                    &pnpEvent, &ioStatus );
623   if ( pnpIrp == NULL )
624     {
625       status = STATUS_INSUFFICIENT_RESOURCES;
626     }
627   else
628     {
629       pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
630       irpStack = IoGetNextIrpStackLocation ( pnpIrp );
631       RtlZeroMemory ( irpStack, sizeof ( IO_STACK_LOCATION ) );
632       irpStack->MajorFunction = IRP_MJ_PNP;
633       irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
634       irpStack->Parameters.DeviceCapabilities.Capabilities =
635         DeviceCapabilities;
636       status = IoCallDriver ( targetObject, pnpIrp );
637       if ( status == STATUS_PENDING )
638         {
639           KeWaitForSingleObject ( &pnpEvent, Executive, KernelMode, FALSE,
640                                   NULL );
641           status = ioStatus.Status;
642         }
643     }
644   ObDereferenceObject ( targetObject );
645   return status;
646 }
647
648 NTSTATUS STDCALL
649 Bus_AddDevice (
650   IN PDRIVER_OBJECT DriverObject,
651   IN PDEVICE_OBJECT PhysicalDeviceObject
652  )
653 {
654   NTSTATUS Status;
655   UNICODE_STRING DeviceName,
656    DosDeviceName;
657   size_t new_dev_ext_size;
658   driver__dev_ext_ptr bus_dev_ext_ptr;
659   bus__type_ptr bus_ptr;
660
661   DBG ( "Entry\n" );
662   if ( bus__fdo )
663     return STATUS_SUCCESS;
664   RtlInitUnicodeString ( &DeviceName, L"\\Device\\AoE" );
665   RtlInitUnicodeString ( &DosDeviceName, L"\\DosDevices\\AoE" );
666   new_dev_ext_size =
667     sizeof ( driver__dev_ext ) + sizeof ( bus__type ) +
668     driver__handling_table_size + handling_table_size;
669   if ( !NT_SUCCESS
670        ( Status =
671          IoCreateDevice ( DriverObject, new_dev_ext_size, &DeviceName,
672                           FILE_DEVICE_CONTROLLER, FILE_DEVICE_SECURE_OPEN,
673                           FALSE, &bus__fdo ) ) )
674     {
675       return Error ( "Bus_AddDevice IoCreateDevice", Status );
676     }
677   if ( !NT_SUCCESS
678        ( Status = IoCreateSymbolicLink ( &DosDeviceName, &DeviceName ) ) )
679     {
680       IoDeleteDevice ( bus__fdo );
681       return Error ( "Bus_AddDevice IoCreateSymbolicLink", Status );
682     }
683
684   bus_dev_ext_ptr = ( driver__dev_ext_ptr ) bus__fdo->DeviceExtension;
685   RtlZeroMemory ( bus_dev_ext_ptr, new_dev_ext_size );
686   bus_dev_ext_ptr->IsBus = TRUE;
687   bus_dev_ext_ptr->dispatch = Bus_Dispatch;
688   bus_dev_ext_ptr->DriverObject = DriverObject;
689   bus_dev_ext_ptr->Self = bus__fdo;
690   bus_dev_ext_ptr->State = NotStarted;
691   bus_dev_ext_ptr->OldState = NotStarted;
692   bus_dev_ext_ptr->irp_handler_stack_ptr =
693     ( winvblock__uint8 * ) bus_dev_ext_ptr + sizeof ( driver__dev_ext ) +
694     sizeof ( bus__type );
695   RtlCopyMemory ( bus_dev_ext_ptr->irp_handler_stack_ptr,
696                   driver__handling_table, driver__handling_table_size );
697   RtlCopyMemory ( ( winvblock__uint8 * ) bus_dev_ext_ptr->irp_handler_stack_ptr
698                   + driver__handling_table_size, handling_table,
699                   handling_table_size );
700   bus_dev_ext_ptr->irp_handler_stack_size =
701     ( driver__handling_table_size +
702       handling_table_size ) / sizeof ( irp__handling );
703   /*
704    * Establish a pointer into the bus device's extension space
705    */
706   bus_ptr = get_bus_ptr ( bus_dev_ext_ptr );
707   bus_ptr->PhysicalDeviceObject = PhysicalDeviceObject;
708   bus_ptr->Children = 0;
709   bus_ptr->first_child_ptr = NULL;
710   KeInitializeSpinLock ( &bus_ptr->SpinLock );
711   bus__fdo->Flags |= DO_DIRECT_IO;      /* FIXME? */
712   bus__fdo->Flags |= DO_POWER_INRUSH;   /* FIXME? */
713   /*
714    * Add the bus to the device tree
715    */
716   if ( PhysicalDeviceObject != NULL )
717     {
718       if ( ( bus_ptr->LowerDeviceObject =
719              IoAttachDeviceToDeviceStack ( bus__fdo,
720                                            PhysicalDeviceObject ) ) == NULL )
721         {
722           IoDeleteDevice ( bus__fdo );
723           bus__fdo = NULL;
724           return Error ( "AddDevice IoAttachDeviceToDeviceStack",
725                          STATUS_NO_SUCH_DEVICE );
726         }
727     }
728   bus__fdo->Flags &= ~DO_DEVICE_INITIALIZING;
729 #ifdef RIS
730   bus_dev_ext_ptr->State = Started;
731 #endif
732   return STATUS_SUCCESS;
733 }