2 * PROJECT: ReactOS Floppy Disk Controller Driver
3 * LICENSE: GNU GPLv2 only as published by the Free Software Foundation
4 * FILE: drivers/storage/fdc/fdc/fdo.c
5 * PURPOSE: Functional Device Object routines
6 * PROGRAMMERS: Eric Kohl
9 /* INCLUDES *******************************************************************/
13 /* FUNCTIONS ******************************************************************/
15 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion
;
20 ForwardIrpAndWaitCompletion(
21 IN PDEVICE_OBJECT DeviceObject
,
25 if (Irp
->PendingReturned
)
26 KeSetEvent((PKEVENT
)Context
, IO_NO_INCREMENT
, FALSE
);
27 return STATUS_MORE_PROCESSING_REQUIRED
;
33 IN PDEVICE_OBJECT DeviceObject
,
36 PDEVICE_OBJECT LowerDevice
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
42 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
43 IoCopyCurrentIrpStackLocationToNext(Irp
);
45 DPRINT("Calling lower device %p\n", LowerDevice
);
46 IoSetCompletionRoutine(Irp
, ForwardIrpAndWaitCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
48 Status
= IoCallDriver(LowerDevice
, Irp
);
49 if (Status
== STATUS_PENDING
)
51 Status
= KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
52 if (NT_SUCCESS(Status
))
53 Status
= Irp
->IoStatus
.Status
;
63 IN PDEVICE_OBJECT DeviceObject
,
66 PDEVICE_OBJECT LowerDevice
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
70 IoSkipCurrentIrpStackLocation(Irp
);
71 return IoCallDriver(LowerDevice
, Irp
);
78 IN PDRIVER_OBJECT DriverObject
,
79 IN PDEVICE_OBJECT Pdo
)
81 PFDO_DEVICE_EXTENSION DeviceExtension
= NULL
;
82 PDEVICE_OBJECT Fdo
= NULL
;
85 DPRINT1("FdcAddDevice()\n");
90 /* Create functional device object */
91 Status
= IoCreateDevice(DriverObject
,
92 sizeof(FDO_DEVICE_EXTENSION
),
94 FILE_DEVICE_CONTROLLER
,
95 FILE_DEVICE_SECURE_OPEN
,
98 if (NT_SUCCESS(Status
))
100 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
101 RtlZeroMemory(DeviceExtension
, sizeof(FDO_DEVICE_EXTENSION
));
103 DeviceExtension
->Common
.IsFDO
= TRUE
;
105 DeviceExtension
->Fdo
= Fdo
;
106 DeviceExtension
->Pdo
= Pdo
;
109 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
110 if (!NT_SUCCESS(Status
))
112 DPRINT1("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
118 Fdo
->Flags
|= DO_DIRECT_IO
;
119 Fdo
->Flags
|= DO_POWER_PAGABLE
;
121 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
131 IN PDEVICE_OBJECT DeviceObject
,
132 IN PCM_RESOURCE_LIST ResourceList
,
133 IN PCM_RESOURCE_LIST ResourceListTranslated
)
135 PFDO_DEVICE_EXTENSION DeviceExtension
;
136 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
137 // PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated;
140 DPRINT1("FdcFdoStartDevice called\n");
142 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
144 ASSERT(DeviceExtension
);
146 if (ResourceList
== NULL
||
147 ResourceListTranslated
== NULL
)
149 DPRINT1("No allocated resources sent to driver\n");
150 return STATUS_INSUFFICIENT_RESOURCES
;
153 if (ResourceList
->Count
!= 1)
155 DPRINT1("Wrong number of allocated resources sent to driver\n");
156 return STATUS_INSUFFICIENT_RESOURCES
;
159 if (ResourceList
->List
[0].PartialResourceList
.Version
!= 1 ||
160 ResourceList
->List
[0].PartialResourceList
.Revision
!= 1 ||
161 ResourceListTranslated
->List
[0].PartialResourceList
.Version
!= 1 ||
162 ResourceListTranslated
->List
[0].PartialResourceList
.Revision
!= 1)
164 DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
165 ResourceList
->List
[0].PartialResourceList
.Version
,
166 ResourceList
->List
[0].PartialResourceList
.Revision
,
167 ResourceListTranslated
->List
[0].PartialResourceList
.Version
,
168 ResourceListTranslated
->List
[0].PartialResourceList
.Revision
);
169 return STATUS_REVISION_MISMATCH
;
172 for (i
= 0; i
< ResourceList
->List
[0].PartialResourceList
.Count
; i
++)
174 PartialDescriptor
= &ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
175 // PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i];
177 switch (PartialDescriptor
->Type
)
179 case CmResourceTypePort
:
180 DPRINT1("Port: 0x%lx (%lu)\n",
181 PartialDescriptor
->u
.Port
.Start
.u
.LowPart
,
182 PartialDescriptor
->u
.Port
.Length
);
183 if (PartialDescriptor
->u
.Port
.Length
>= 6)
184 DeviceExtension
->ControllerInfo
.BaseAddress
= (PUCHAR
)PartialDescriptor
->u
.Port
.Start
.u
.LowPart
;
187 case CmResourceTypeInterrupt
:
188 DPRINT1("Interrupt: Level %lu Vector %lu\n",
189 PartialDescriptor
->u
.Interrupt
.Level
,
190 PartialDescriptor
->u
.Interrupt
.Vector
);
192 Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
193 Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
194 Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
195 if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
196 InterruptMode = Latched;
198 InterruptMode = LevelSensitive;
199 ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
203 case CmResourceTypeDma
:
204 DPRINT1("Dma: Channel %lu\n",
205 PartialDescriptor
->u
.Dma
.Channel
);
210 return STATUS_SUCCESS
;
217 FdcFdoConfigCallback(
219 PUNICODE_STRING PathName
,
220 INTERFACE_TYPE BusType
,
222 PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
223 CONFIGURATION_TYPE ControllerType
,
224 ULONG ControllerNumber
,
225 PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
226 CONFIGURATION_TYPE PeripheralType
,
227 ULONG PeripheralNumber
,
228 PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
230 PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor
;
231 PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor
;
232 PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor
;
233 PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor
;
234 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
235 PCM_FLOPPY_DEVICE_DATA FloppyDeviceData
;
236 PFDO_DEVICE_EXTENSION DeviceExtension
;
237 PDRIVE_INFO DriveInfo
;
238 BOOLEAN ControllerFound
= FALSE
;
241 DPRINT1("FdcFdoConfigCallback() called\n");
243 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Context
;
245 /* Get the controller resources */
246 ControllerFullDescriptor
= ControllerInformation
[IoQueryDeviceConfigurationData
];
247 ControllerResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PCHAR
)ControllerFullDescriptor
+
248 ControllerFullDescriptor
->DataOffset
);
250 for(i
= 0; i
< ControllerResourceDescriptor
->PartialResourceList
.Count
; i
++)
252 PartialDescriptor
= &ControllerResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
];
254 if (PartialDescriptor
->Type
== CmResourceTypePort
)
256 if ((PUCHAR
)PartialDescriptor
->u
.Port
.Start
.LowPart
== DeviceExtension
->ControllerInfo
.BaseAddress
)
257 ControllerFound
= TRUE
;
261 /* Leave, if the enumerated controller is not the one represented by the FDO */
262 if (ControllerFound
== FALSE
)
263 return STATUS_SUCCESS
;
265 /* Get the peripheral resources */
266 PeripheralFullDescriptor
= PeripheralInformation
[IoQueryDeviceConfigurationData
];
267 PeripheralResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PCHAR
)PeripheralFullDescriptor
+
268 PeripheralFullDescriptor
->DataOffset
);
270 DeviceExtension
->ControllerInfo
.NumberOfDrives
= 0;
272 /* learn about drives attached to controller */
273 for(i
= 0; i
< PeripheralResourceDescriptor
->PartialResourceList
.Count
; i
++)
275 PartialDescriptor
= &PeripheralResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
];
277 if (PartialDescriptor
->Type
!= CmResourceTypeDeviceSpecific
)
280 FloppyDeviceData
= (PCM_FLOPPY_DEVICE_DATA
)(PartialDescriptor
+ 1);
282 DriveInfo
= &DeviceExtension
->ControllerInfo
.DriveInfo
[i
];
284 DriveInfo
->ControllerInfo
= &DeviceExtension
->ControllerInfo
;
285 DriveInfo
->UnitNumber
= i
;
287 DriveInfo
->FloppyDeviceData
.MaxDensity
= FloppyDeviceData
->MaxDensity
;
288 DriveInfo
->FloppyDeviceData
.MountDensity
= FloppyDeviceData
->MountDensity
;
289 DriveInfo
->FloppyDeviceData
.StepRateHeadUnloadTime
= FloppyDeviceData
->StepRateHeadUnloadTime
;
290 DriveInfo
->FloppyDeviceData
.HeadLoadTime
= FloppyDeviceData
->HeadLoadTime
;
291 DriveInfo
->FloppyDeviceData
.MotorOffTime
= FloppyDeviceData
->MotorOffTime
;
292 DriveInfo
->FloppyDeviceData
.SectorLengthCode
= FloppyDeviceData
->SectorLengthCode
;
293 DriveInfo
->FloppyDeviceData
.SectorPerTrack
= FloppyDeviceData
->SectorPerTrack
;
294 DriveInfo
->FloppyDeviceData
.ReadWriteGapLength
= FloppyDeviceData
->ReadWriteGapLength
;
295 DriveInfo
->FloppyDeviceData
.FormatGapLength
= FloppyDeviceData
->FormatGapLength
;
296 DriveInfo
->FloppyDeviceData
.FormatFillCharacter
= FloppyDeviceData
->FormatFillCharacter
;
297 DriveInfo
->FloppyDeviceData
.HeadSettleTime
= FloppyDeviceData
->HeadSettleTime
;
298 DriveInfo
->FloppyDeviceData
.MotorSettleTime
= FloppyDeviceData
->MotorSettleTime
;
299 DriveInfo
->FloppyDeviceData
.MaximumTrackValue
= FloppyDeviceData
->MaximumTrackValue
;
300 DriveInfo
->FloppyDeviceData
.DataTransferLength
= FloppyDeviceData
->DataTransferLength
;
302 /* Once it's all set up, acknowledge its existance in the controller info object */
303 DeviceExtension
->ControllerInfo
.NumberOfDrives
++;
306 DeviceExtension
->ControllerInfo
.Populated
= TRUE
;
308 DPRINT1("Detected %lu floppy drives!\n",
309 DeviceExtension
->ControllerInfo
.NumberOfDrives
);
311 return STATUS_SUCCESS
;
317 FdcFdoQueryBusRelations(
318 IN PDEVICE_OBJECT DeviceObject
,
319 OUT PDEVICE_RELATIONS
*DeviceRelations
)
321 PFDO_DEVICE_EXTENSION DeviceExtension
;
322 INTERFACE_TYPE InterfaceType
= Isa
;
323 CONFIGURATION_TYPE ControllerType
= DiskController
;
324 CONFIGURATION_TYPE PeripheralType
= FloppyDiskPeripheral
;
327 DPRINT1("FdcFdoQueryBusRelations() called\n");
329 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
331 Status
= IoQueryDeviceDescription(&InterfaceType
,
337 FdcFdoConfigCallback
,
339 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
))
344 return STATUS_SUCCESS
;
351 IN PDEVICE_OBJECT DeviceObject
,
354 PIO_STACK_LOCATION IrpSp
;
355 PDEVICE_RELATIONS DeviceRelations
= NULL
;
356 ULONG_PTR Information
= 0;
357 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
359 DPRINT1("FdcFdoPnp()\n");
361 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
363 switch (IrpSp
->MinorFunction
)
365 case IRP_MN_START_DEVICE
:
366 DPRINT1(" IRP_MN_START_DEVICE received\n");
367 /* Call lower driver */
368 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
369 if (NT_SUCCESS(Status
))
371 Status
= FdcFdoStartDevice(DeviceObject
,
372 IrpSp
->Parameters
.StartDevice
.AllocatedResources
,
373 IrpSp
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
377 case IRP_MN_QUERY_REMOVE_DEVICE
:
378 DPRINT1(" IRP_MN_QUERY_REMOVE_DEVICE\n");
381 case IRP_MN_REMOVE_DEVICE
:
382 DPRINT1(" IRP_MN_REMOVE_DEVICE received\n");
385 case IRP_MN_CANCEL_REMOVE_DEVICE
:
386 DPRINT1(" IRP_MN_CANCEL_REMOVE_DEVICE\n");
389 case IRP_MN_STOP_DEVICE
:
390 DPRINT1(" IRP_MN_STOP_DEVICE received\n");
393 case IRP_MN_QUERY_STOP_DEVICE
:
394 DPRINT1(" IRP_MN_QUERY_STOP_DEVICE received\n");
397 case IRP_MN_CANCEL_STOP_DEVICE
:
398 DPRINT1(" IRP_MN_CANCEL_STOP_DEVICE\n");
401 case IRP_MN_QUERY_DEVICE_RELATIONS
:
402 DPRINT1(" IRP_MN_QUERY_DEVICE_RELATIONS\n");
404 switch (IrpSp
->Parameters
.QueryDeviceRelations
.Type
)
407 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
408 Status
= FdcFdoQueryBusRelations(DeviceObject
, &DeviceRelations
);
409 Information
= (ULONG_PTR
)DeviceRelations
;
412 case RemovalRelations
:
413 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
414 return ForwardIrpAndForget(DeviceObject
, Irp
);
417 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
418 IrpSp
->Parameters
.QueryDeviceRelations
.Type
);
419 return ForwardIrpAndForget(DeviceObject
, Irp
);
423 case IRP_MN_SURPRISE_REMOVAL
:
424 DPRINT1(" IRP_MN_SURPRISE_REMOVAL received\n");
428 DPRINT(" Unknown IOCTL 0x%lx\n", IrpSp
->MinorFunction
);
429 return ForwardIrpAndForget(DeviceObject
, Irp
);
432 Irp
->IoStatus
.Information
= Information
;
433 Irp
->IoStatus
.Status
= Status
;
434 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);