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/
6 * This file is part of WinVBlock, derived from WinAoE.
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.
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.
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/>.
31 #include "winvblock.h"
46 static irp__handler_decl (
47 Bus_DispatchNotSupported
49 static irp__handler_decl (
52 winvblock__bool STDCALL Bus_AddChild (
53 IN PDEVICE_OBJECT BusDeviceObject,
55 IN winvblock__bool Boot
58 typedef struct _BUS_TARGETLIST
61 struct _BUS_TARGETLIST *Next;
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;
76 KeInitializeSpinLock ( &Bus_Globals_TargetListSpinLock );
77 return STATUS_SUCCESS;
85 UNICODE_STRING DosDeviceName;
86 PBUS_TARGETLIST Walker,
91 KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
92 Walker = Bus_Globals_TargetList;
93 while ( Walker != NULL )
96 ExFreePool ( Walker );
99 KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
100 RtlInitUnicodeString ( &DosDeviceName, L"\\DosDevices\\AoE" );
101 IoDeleteSymbolicLink ( &DosDeviceName );
107 IN winvblock__uint8_ptr ClientMac,
108 IN winvblock__uint8_ptr ServerMac,
109 winvblock__uint16 Major,
110 winvblock__uint8 Minor,
114 PBUS_TARGETLIST Walker,
118 KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
119 Last = Bus_Globals_TargetList;
120 Walker = Bus_Globals_TargetList;
121 while ( Walker != NULL )
123 if ( ( RtlCompareMemory ( &Walker->Target.ClientMac, ClientMac, 6 ) ==
125 && ( RtlCompareMemory ( &Walker->Target.ServerMac, ServerMac, 6 ) ==
126 6 ) && Walker->Target.Major == Major
127 && Walker->Target.Minor == Minor )
129 if ( Walker->Target.LBASize != LBASize )
131 DBG ( "LBASize changed for e%d.%d " "(%I64u->%I64u)\n", Major,
132 Minor, Walker->Target.LBASize, LBASize );
133 Walker->Target.LBASize = LBASize;
135 KeQuerySystemTime ( &Walker->Target.ProbeTime );
136 KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
140 Walker = Walker->Next;
144 ( PBUS_TARGETLIST ) ExAllocatePool ( NonPagedPool,
145 sizeof ( BUS_TARGETLIST ) ) ) ==
148 DBG ( "ExAllocatePool Target\n" );
149 KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
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 );
162 Bus_Globals_TargetList = Walker;
168 KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
172 Bus_CleanupTargetList (
179 * Establish a pointer into the bus device's extension space
181 bus__type_ptr STDCALL
183 driver__dev_ext_ptr dev_ext_ptr
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 ) );
193 * Establish a pointer into the child disk device's extension space
195 disk__type_ptr STDCALL
197 driver__dev_ext_ptr dev_ext_ptr
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 ) );
207 * Add a child node to the bus
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?
213 * Returns TRUE for success, FALSE for failure
215 winvblock__bool STDCALL
217 IN PDEVICE_OBJECT BusDeviceObject,
219 IN winvblock__bool Boot
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
230 PDEVICE_OBJECT DeviceObject;
231 driver__dev_ext_ptr bus_dev_ext_ptr,
233 bus__type_ptr bus_ptr;
234 size_t new_dev_ext_size;
235 disk__type_ptr disk_ptr,
237 DEVICE_TYPE DiskType =
238 Disk.DiskType == OpticalDisc ? FILE_DEVICE_CD_ROM : FILE_DEVICE_DISK;
241 OpticalDisc ? FILE_READ_ONLY_DEVICE | FILE_REMOVABLE_MEDIA : Disk.
242 DiskType == FloppyDisk ? FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE : 0;
246 * Establish pointers into the bus device's extension space
248 bus_dev_ext_ptr = ( driver__dev_ext_ptr ) BusDeviceObject->DeviceExtension;
249 bus_ptr = get_bus_ptr ( bus_dev_ext_ptr );
251 * Create the child device
254 sizeof ( driver__dev_ext ) + sizeof ( disk__type ) +
255 driver__handling_table_size;
258 IoCreateDevice ( bus_dev_ext_ptr->DriverObject, new_dev_ext_size,
260 FILE_AUTOGENERATED_DEVICE_NAME |
261 FILE_DEVICE_SECURE_OPEN | DiskType2, FALSE,
264 Error ( "Bus_AddChild IoCreateDevice", Status );
268 * Establish pointers into the child disk device's extension space
270 disk_dev_ext_ptr = ( driver__dev_ext_ptr ) DeviceObject->DeviceExtension;
271 disk_ptr = get_disk_ptr ( disk_dev_ext_ptr );
273 * Clear the extension space and establish parameters
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 );
290 * Copy the provided disk parameters into the disk extension space
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;
302 * Some device parameters
304 DeviceObject->Flags |= DO_DIRECT_IO; /* FIXME? */
305 DeviceObject->Flags |= DO_POWER_INRUSH; /* FIXME? */
307 * Determine the disk's geometry differently for AoE/MEMDISK
309 disk_ptr->Initialize ( disk_dev_ext_ptr );
311 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
313 * Add the new device's extension to the bus' list of children
315 if ( bus_ptr->first_child_ptr == NULL )
317 bus_ptr->first_child_ptr = disk_ptr;
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;
330 irp__handling handling_table[] = {
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
337 {IRP_MJ_PNP, 0, FALSE, TRUE, bus_pnp__simple}
339 {IRP_MJ_PNP, IRP_MN_START_DEVICE, FALSE, FALSE, bus_pnp__start_dev}
341 {IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE, FALSE, FALSE, bus_pnp__remove_dev}
343 {IRP_MJ_PNP, IRP_MN_QUERY_DEVICE_RELATIONS, FALSE, FALSE,
344 bus_pnp__query_dev_relations}
347 size_t handling_table_size = sizeof ( handling_table );
349 irp__handler_decl ( Bus_DispatchDeviceControl )
352 winvblock__uint8_ptr Buffer;
354 PBUS_TARGETLIST TargetWalker;
355 bus__type_ptr bus_ptr;
356 disk__type_ptr DiskWalker,
358 PMOUNT_TARGETS Targets;
364 * Establish a pointer into the bus device's extension space
366 bus_ptr = get_bus_ptr ( DeviceExtension );
368 switch ( Stack->Parameters.DeviceIoControl.IoControlCode )
371 DBG ( "Got IOCTL_AOE_SCAN...\n" );
373 KeAcquireSpinLock ( &Bus_Globals_TargetListSpinLock, &Irql );
376 TargetWalker = Bus_Globals_TargetList;
377 while ( TargetWalker != NULL )
380 TargetWalker = TargetWalker->Next;
384 ( PMOUNT_TARGETS ) ExAllocatePool ( NonPagedPool,
385 sizeof ( MOUNT_TARGETS ) +
388 ( MOUNT_TARGET ) ) ) ) ==
391 DBG ( "ExAllocatePool Targets\n" );
392 Irp->IoStatus.Information = 0;
393 Status = STATUS_INSUFFICIENT_RESOURCES;
396 Irp->IoStatus.Information =
397 sizeof ( MOUNT_TARGETS ) + ( Count * sizeof ( MOUNT_TARGET ) );
398 Targets->Count = Count;
401 TargetWalker = Bus_Globals_TargetList;
402 while ( TargetWalker != NULL )
404 RtlCopyMemory ( &Targets->Target[Count], &TargetWalker->Target,
405 sizeof ( MOUNT_TARGET ) );
407 TargetWalker = TargetWalker->Next;
409 RtlCopyMemory ( Irp->AssociatedIrp.SystemBuffer, Targets,
410 ( Stack->Parameters.DeviceIoControl.
412 ( sizeof ( MOUNT_TARGETS ) +
414 sizeof ( MOUNT_TARGET ) ) ) ? Stack->Parameters.
416 OutputBufferLength : ( sizeof ( MOUNT_TARGETS ) +
419 ( MOUNT_TARGET ) ) ) ) );
420 ExFreePool ( Targets );
422 KeReleaseSpinLock ( &Bus_Globals_TargetListSpinLock, Irql );
423 Status = STATUS_SUCCESS;
426 DBG ( "Got IOCTL_AOE_SHOW...\n" );
429 DiskWalker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
430 while ( DiskWalker != NULL )
433 DiskWalker = DiskWalker->next_sibling_ptr;
437 ( PMOUNT_DISKS ) ExAllocatePool ( NonPagedPool,
438 sizeof ( MOUNT_DISKS ) +
440 sizeof ( MOUNT_DISK ) ) ) )
443 DBG ( "ExAllocatePool Disks\n" );
444 Irp->IoStatus.Information = 0;
445 Status = STATUS_INSUFFICIENT_RESOURCES;
448 Irp->IoStatus.Information =
449 sizeof ( MOUNT_DISKS ) + ( Count * sizeof ( MOUNT_DISK ) );
450 Disks->Count = Count;
453 DiskWalker = ( disk__type_ptr ) bus_ptr->first_child_ptr;
454 while ( DiskWalker != NULL )
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;
465 DiskWalker = DiskWalker->next_sibling_ptr;
467 RtlCopyMemory ( Irp->AssociatedIrp.SystemBuffer, Disks,
468 ( Stack->Parameters.DeviceIoControl.
470 ( sizeof ( MOUNT_DISKS ) +
472 sizeof ( MOUNT_DISK ) ) ) ? Stack->Parameters.
474 OutputBufferLength : ( sizeof ( MOUNT_DISKS ) +
477 ( MOUNT_DISK ) ) ) ) );
478 ExFreePool ( Disks );
480 Status = STATUS_SUCCESS;
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 ) )
499 DBG ( "Bus_AddChild() failed\n" );
503 if ( bus_ptr->PhysicalDeviceObject != NULL )
504 IoInvalidateDeviceRelations ( bus_ptr->PhysicalDeviceObject,
507 Irp->IoStatus.Information = 0;
508 Status = STATUS_SUCCESS;
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 ) )
518 DiskWalkerPrevious = DiskWalker;
519 DiskWalker = DiskWalker->next_sibling_ptr;
521 if ( DiskWalker != NULL )
523 if ( DiskWalker->BootDrive )
525 DBG ( "Cannot unmount a boot drive.\n" );
526 Irp->IoStatus.Information = 0;
527 Status = STATUS_INVALID_DEVICE_REQUEST;
530 DBG ( "Deleting disk %d\n", DiskWalker->DiskNumber );
531 if ( DiskWalker == ( disk__type_ptr ) bus_ptr->first_child_ptr )
533 bus_ptr->first_child_ptr =
534 ( winvblock__uint8_ptr ) DiskWalker->next_sibling_ptr;
538 DiskWalkerPrevious->next_sibling_ptr =
539 DiskWalker->next_sibling_ptr;
541 DiskWalker->Unmount = TRUE;
542 DiskWalker->next_sibling_ptr = NULL;
543 if ( bus_ptr->PhysicalDeviceObject != NULL )
544 IoInvalidateDeviceRelations ( bus_ptr->PhysicalDeviceObject,
548 Irp->IoStatus.Information = 0;
549 Status = STATUS_SUCCESS;
552 Irp->IoStatus.Information = 0;
553 Status = STATUS_INVALID_DEVICE_REQUEST;
556 Irp->IoStatus.Status = Status;
557 IoCompleteRequest ( Irp, IO_NO_INCREMENT );
561 irp__handler_decl ( Bus_DispatchSystemControl )
563 bus__type_ptr bus_ptr = get_bus_ptr ( DeviceExtension );
565 IoSkipCurrentIrpStackLocation ( Irp );
566 return IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
569 irp__handler_decl ( Bus_Dispatch )
572 bus__type_ptr bus_ptr = get_bus_ptr ( DeviceExtension );
574 switch ( Stack->MajorFunction )
577 PoStartNextPowerIrp ( Irp );
578 IoSkipCurrentIrpStackLocation ( Irp );
579 Status = PoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
581 case IRP_MJ_SYSTEM_CONTROL:
583 Bus_DispatchSystemControl ( DeviceObject, Irp, Stack,
584 DeviceExtension, completion_ptr );
586 case IRP_MJ_DEVICE_CONTROL:
588 Bus_DispatchDeviceControl ( DeviceObject, Irp, Stack,
589 DeviceExtension, completion_ptr );
592 Status = STATUS_NOT_SUPPORTED;
593 Irp->IoStatus.Status = Status;
594 IoCompleteRequest ( Irp, IO_NO_INCREMENT );
600 Bus_GetDeviceCapabilities (
601 IN PDEVICE_OBJECT DeviceObject,
602 IN PDEVICE_CAPABILITIES DeviceCapabilities
605 IO_STATUS_BLOCK ioStatus;
608 PDEVICE_OBJECT targetObject;
609 PIO_STACK_LOCATION irpStack;
612 RtlZeroMemory ( DeviceCapabilities, sizeof ( DEVICE_CAPABILITIES ) );
613 DeviceCapabilities->Size = sizeof ( DEVICE_CAPABILITIES );
614 DeviceCapabilities->Version = 1;
615 DeviceCapabilities->Address = -1;
616 DeviceCapabilities->UINumber = -1;
618 KeInitializeEvent ( &pnpEvent, NotificationEvent, FALSE );
619 targetObject = IoGetAttachedDeviceReference ( DeviceObject );
621 IoBuildSynchronousFsdRequest ( IRP_MJ_PNP, targetObject, NULL, 0, NULL,
622 &pnpEvent, &ioStatus );
623 if ( pnpIrp == NULL )
625 status = STATUS_INSUFFICIENT_RESOURCES;
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 =
636 status = IoCallDriver ( targetObject, pnpIrp );
637 if ( status == STATUS_PENDING )
639 KeWaitForSingleObject ( &pnpEvent, Executive, KernelMode, FALSE,
641 status = ioStatus.Status;
644 ObDereferenceObject ( targetObject );
650 IN PDRIVER_OBJECT DriverObject,
651 IN PDEVICE_OBJECT PhysicalDeviceObject
655 UNICODE_STRING DeviceName,
657 size_t new_dev_ext_size;
658 driver__dev_ext_ptr bus_dev_ext_ptr;
659 bus__type_ptr bus_ptr;
663 return STATUS_SUCCESS;
664 RtlInitUnicodeString ( &DeviceName, L"\\Device\\AoE" );
665 RtlInitUnicodeString ( &DosDeviceName, L"\\DosDevices\\AoE" );
667 sizeof ( driver__dev_ext ) + sizeof ( bus__type ) +
668 driver__handling_table_size + handling_table_size;
671 IoCreateDevice ( DriverObject, new_dev_ext_size, &DeviceName,
672 FILE_DEVICE_CONTROLLER, FILE_DEVICE_SECURE_OPEN,
673 FALSE, &bus__fdo ) ) )
675 return Error ( "Bus_AddDevice IoCreateDevice", Status );
678 ( Status = IoCreateSymbolicLink ( &DosDeviceName, &DeviceName ) ) )
680 IoDeleteDevice ( bus__fdo );
681 return Error ( "Bus_AddDevice IoCreateSymbolicLink", Status );
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 );
704 * Establish a pointer into the bus device's extension space
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? */
714 * Add the bus to the device tree
716 if ( PhysicalDeviceObject != NULL )
718 if ( ( bus_ptr->LowerDeviceObject =
719 IoAttachDeviceToDeviceStack ( bus__fdo,
720 PhysicalDeviceObject ) ) == NULL )
722 IoDeleteDevice ( bus__fdo );
724 return Error ( "AddDevice IoAttachDeviceToDeviceStack",
725 STATUS_NO_SUCH_DEVICE );
728 bus__fdo->Flags &= ~DO_DEVICE_INITIALIZING;
730 bus_dev_ext_ptr->State = Started;
732 return STATUS_SUCCESS;