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
);
80 IN PDEVICE_OBJECT DeviceObject
,
81 IN PCM_RESOURCE_LIST ResourceList
,
82 IN PCM_RESOURCE_LIST ResourceListTranslated
)
84 PFDO_DEVICE_EXTENSION DeviceExtension
;
85 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
86 // PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated;
89 DPRINT1("FdcFdoStartDevice called\n");
91 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
93 ASSERT(DeviceExtension
);
95 if (ResourceList
== NULL
||
96 ResourceListTranslated
== NULL
)
98 DPRINT1("No allocated resources sent to driver\n");
99 return STATUS_INSUFFICIENT_RESOURCES
;
102 if (ResourceList
->Count
!= 1)
104 DPRINT1("Wrong number of allocated resources sent to driver\n");
105 return STATUS_INSUFFICIENT_RESOURCES
;
108 if (ResourceList
->List
[0].PartialResourceList
.Version
!= 1 ||
109 ResourceList
->List
[0].PartialResourceList
.Revision
!= 1 ||
110 ResourceListTranslated
->List
[0].PartialResourceList
.Version
!= 1 ||
111 ResourceListTranslated
->List
[0].PartialResourceList
.Revision
!= 1)
113 DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
114 ResourceList
->List
[0].PartialResourceList
.Version
,
115 ResourceList
->List
[0].PartialResourceList
.Revision
,
116 ResourceListTranslated
->List
[0].PartialResourceList
.Version
,
117 ResourceListTranslated
->List
[0].PartialResourceList
.Revision
);
118 return STATUS_REVISION_MISMATCH
;
121 for (i
= 0; i
< ResourceList
->List
[0].PartialResourceList
.Count
; i
++)
123 PartialDescriptor
= &ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
124 // PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i];
126 switch (PartialDescriptor
->Type
)
128 case CmResourceTypePort
:
129 DPRINT1("Port: 0x%lx (%lu)\n",
130 PartialDescriptor
->u
.Port
.Start
.u
.LowPart
,
131 PartialDescriptor
->u
.Port
.Length
);
132 if (PartialDescriptor
->u
.Port
.Length
>= 6)
133 DeviceExtension
->ControllerInfo
.BaseAddress
= (PUCHAR
)PartialDescriptor
->u
.Port
.Start
.u
.LowPart
;
136 case CmResourceTypeInterrupt
:
137 DPRINT1("Interrupt: Level %lu Vector %lu\n",
138 PartialDescriptor
->u
.Interrupt
.Level
,
139 PartialDescriptor
->u
.Interrupt
.Vector
);
141 Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
142 Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
143 Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
144 if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
145 InterruptMode = Latched;
147 InterruptMode = LevelSensitive;
148 ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
152 case CmResourceTypeDma
:
153 DPRINT1("Dma: Channel %lu\n",
154 PartialDescriptor
->u
.Dma
.Channel
);
159 return STATUS_SUCCESS
;
166 FdcFdoConfigCallback(
168 PUNICODE_STRING PathName
,
169 INTERFACE_TYPE BusType
,
171 PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
172 CONFIGURATION_TYPE ControllerType
,
173 ULONG ControllerNumber
,
174 PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
175 CONFIGURATION_TYPE PeripheralType
,
176 ULONG PeripheralNumber
,
177 PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
179 PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor
;
180 PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor
;
181 PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor
;
182 PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor
;
183 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
184 PCM_FLOPPY_DEVICE_DATA FloppyDeviceData
;
185 PFDO_DEVICE_EXTENSION DeviceExtension
;
186 PDRIVE_INFO DriveInfo
;
187 BOOLEAN ControllerFound
= FALSE
;
190 DPRINT1("FdcFdoConfigCallback() called\n");
192 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Context
;
194 /* Get the controller resources */
195 ControllerFullDescriptor
= ControllerInformation
[IoQueryDeviceConfigurationData
];
196 ControllerResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PCHAR
)ControllerFullDescriptor
+
197 ControllerFullDescriptor
->DataOffset
);
199 for(i
= 0; i
< ControllerResourceDescriptor
->PartialResourceList
.Count
; i
++)
201 PartialDescriptor
= &ControllerResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
];
203 if (PartialDescriptor
->Type
== CmResourceTypePort
)
205 if ((PUCHAR
)PartialDescriptor
->u
.Port
.Start
.LowPart
== DeviceExtension
->ControllerInfo
.BaseAddress
)
206 ControllerFound
= TRUE
;
210 /* Leave, if the enumerated controller is not the one represented by the FDO */
211 if (ControllerFound
== FALSE
)
212 return STATUS_SUCCESS
;
214 /* Get the peripheral resources */
215 PeripheralFullDescriptor
= PeripheralInformation
[IoQueryDeviceConfigurationData
];
216 PeripheralResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PCHAR
)PeripheralFullDescriptor
+
217 PeripheralFullDescriptor
->DataOffset
);
219 DeviceExtension
->ControllerInfo
.NumberOfDrives
= 0;
221 /* learn about drives attached to controller */
222 for(i
= 0; i
< PeripheralResourceDescriptor
->PartialResourceList
.Count
; i
++)
224 PartialDescriptor
= &PeripheralResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
];
226 if (PartialDescriptor
->Type
!= CmResourceTypeDeviceSpecific
)
229 FloppyDeviceData
= (PCM_FLOPPY_DEVICE_DATA
)(PartialDescriptor
+ 1);
231 DriveInfo
= &DeviceExtension
->ControllerInfo
.DriveInfo
[i
];
233 DriveInfo
->ControllerInfo
= &DeviceExtension
->ControllerInfo
;
234 DriveInfo
->UnitNumber
= i
;
235 DriveInfo
->PeripheralNumber
= PeripheralNumber
;
237 DriveInfo
->FloppyDeviceData
.MaxDensity
= FloppyDeviceData
->MaxDensity
;
238 DriveInfo
->FloppyDeviceData
.MountDensity
= FloppyDeviceData
->MountDensity
;
239 DriveInfo
->FloppyDeviceData
.StepRateHeadUnloadTime
= FloppyDeviceData
->StepRateHeadUnloadTime
;
240 DriveInfo
->FloppyDeviceData
.HeadLoadTime
= FloppyDeviceData
->HeadLoadTime
;
241 DriveInfo
->FloppyDeviceData
.MotorOffTime
= FloppyDeviceData
->MotorOffTime
;
242 DriveInfo
->FloppyDeviceData
.SectorLengthCode
= FloppyDeviceData
->SectorLengthCode
;
243 DriveInfo
->FloppyDeviceData
.SectorPerTrack
= FloppyDeviceData
->SectorPerTrack
;
244 DriveInfo
->FloppyDeviceData
.ReadWriteGapLength
= FloppyDeviceData
->ReadWriteGapLength
;
245 DriveInfo
->FloppyDeviceData
.FormatGapLength
= FloppyDeviceData
->FormatGapLength
;
246 DriveInfo
->FloppyDeviceData
.FormatFillCharacter
= FloppyDeviceData
->FormatFillCharacter
;
247 DriveInfo
->FloppyDeviceData
.HeadSettleTime
= FloppyDeviceData
->HeadSettleTime
;
248 DriveInfo
->FloppyDeviceData
.MotorSettleTime
= FloppyDeviceData
->MotorSettleTime
;
249 DriveInfo
->FloppyDeviceData
.MaximumTrackValue
= FloppyDeviceData
->MaximumTrackValue
;
250 DriveInfo
->FloppyDeviceData
.DataTransferLength
= FloppyDeviceData
->DataTransferLength
;
252 /* Once it's all set up, acknowledge its existance in the controller info object */
253 DeviceExtension
->ControllerInfo
.NumberOfDrives
++;
256 DeviceExtension
->ControllerInfo
.Populated
= TRUE
;
258 DPRINT1("Detected %lu floppy drives!\n",
259 DeviceExtension
->ControllerInfo
.NumberOfDrives
);
261 return STATUS_SUCCESS
;
267 PciCreateHardwareIDsString(PUNICODE_STRING HardwareIDs
)
270 UNICODE_STRING BufferU
;
274 Index
+= swprintf(&Buffer
[Index
],
275 L
"FDC\\GENERIC_FLOPPY_DRIVE");
278 Buffer
[Index
] = UNICODE_NULL
;
280 BufferU
.Length
= BufferU
.MaximumLength
= (USHORT
) Index
* sizeof(WCHAR
);
281 BufferU
.Buffer
= Buffer
;
283 return DuplicateUnicodeString(0, &BufferU
, HardwareIDs
);
289 PciCreateCompatibleIDsString(PUNICODE_STRING CompatibleIDs
)
292 UNICODE_STRING BufferU
;
296 Index
+= swprintf(&Buffer
[Index
],
300 Buffer
[Index
] = UNICODE_NULL
;
302 BufferU
.Length
= BufferU
.MaximumLength
= (USHORT
)Index
* sizeof(WCHAR
);
303 BufferU
.Buffer
= Buffer
;
305 return DuplicateUnicodeString(0, &BufferU
, CompatibleIDs
);
311 PciCreateInstanceIDString(PUNICODE_STRING InstanceID
,
312 ULONG PeripheralNumber
)
316 swprintf(Buffer
, L
"%02X", PeripheralNumber
& 0xff);
318 return RtlCreateUnicodeString(InstanceID
, Buffer
) ? STATUS_SUCCESS
: STATUS_INSUFFICIENT_RESOURCES
;
324 FdcFdoQueryBusRelations(
325 IN PDEVICE_OBJECT DeviceObject
,
326 OUT PDEVICE_RELATIONS
*DeviceRelations
)
328 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
329 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
330 INTERFACE_TYPE InterfaceType
= Isa
;
331 CONFIGURATION_TYPE ControllerType
= DiskController
;
332 CONFIGURATION_TYPE PeripheralType
= FloppyDiskPeripheral
;
333 PDEVICE_RELATIONS Relations
;
334 PDRIVE_INFO DriveInfo
;
336 WCHAR DeviceNameBuffer
[80];
337 UNICODE_STRING DeviceName
;
338 ULONG DeviceNumber
= 0;
343 DPRINT1("FdcFdoQueryBusRelations() called\n");
345 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
347 Status
= IoQueryDeviceDescription(&InterfaceType
,
353 FdcFdoConfigCallback
,
355 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NO_MORE_ENTRIES
))
358 Size
= sizeof(DEVICE_RELATIONS
) +
359 sizeof(Relations
->Objects
) * (FdoDeviceExtension
->ControllerInfo
.NumberOfDrives
- 1);
360 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
361 if (Relations
== NULL
)
363 return STATUS_INSUFFICIENT_RESOURCES
;
366 Relations
->Count
= FdoDeviceExtension
->ControllerInfo
.NumberOfDrives
;
368 for (i
= 0; i
< FdoDeviceExtension
->ControllerInfo
.NumberOfDrives
; i
++)
370 DriveInfo
= &FdoDeviceExtension
->ControllerInfo
.DriveInfo
[i
];
372 if (DriveInfo
->DeviceObject
== NULL
)
376 swprintf(DeviceNameBuffer
, L
"\\Device\\FloppyPDO%lu", DeviceNumber
++);
377 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
378 DPRINT1("Device name: %S\n", DeviceNameBuffer
);
380 /* Create physical device object */
381 Status
= IoCreateDevice(FdoDeviceExtension
->Common
.DeviceObject
->DriverObject
,
382 sizeof(PDO_DEVICE_EXTENSION
),
384 FILE_DEVICE_MASS_STORAGE
,
385 FILE_DEVICE_SECURE_OPEN
,
389 while (Status
== STATUS_OBJECT_NAME_COLLISION
);
391 if (!NT_SUCCESS(Status
))
393 DPRINT1("PDO creation failed (Status 0x%08lx)\n", Status
);
397 DPRINT1("PDO created: %S\n", DeviceNameBuffer
);
399 DriveInfo
->DeviceObject
= Pdo
;
401 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
402 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
404 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
405 PdoDeviceExtension
->Common
.DeviceObject
= Pdo
;
407 PdoDeviceExtension
->Fdo
= FdoDeviceExtension
->Common
.DeviceObject
;
408 PdoDeviceExtension
->DriveInfo
= DriveInfo
;
410 Pdo
->Flags
|= DO_DIRECT_IO
;
411 Pdo
->Flags
|= DO_POWER_PAGABLE
;
412 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
414 /* Add Device ID string */
415 RtlCreateUnicodeString(&PdoDeviceExtension
->DeviceId
,
416 L
"FDC\\GENERIC_FLOPPY_DRIVE");
417 DPRINT1("DeviceID: %S\n", PdoDeviceExtension
->DeviceId
.Buffer
);
419 /* Add Hardware IDs string */
420 Status
= PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIds
);
421 if (!NT_SUCCESS(Status
))
423 // ErrorStatus = Status;
424 // ErrorOccurred = TRUE;
428 /* Add Compatible IDs string */
429 Status
= PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIds
);
430 if (!NT_SUCCESS(Status
))
432 // ErrorStatus = Status;
433 // ErrorOccurred = TRUE;
437 /* Add Instance ID string */
438 Status
= PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceId
,
439 DriveInfo
->PeripheralNumber
);
440 if (!NT_SUCCESS(Status
))
442 // ErrorStatus = Status;
443 // ErrorOccurred = TRUE;
448 /* Add device description string */
449 Status
= PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
, Device
);
450 if (!NT_SUCCESS(Status
))
452 // ErrorStatus = Status;
453 // ErrorOccurred = TRUE;
457 /* Add device location string */
458 Status
= PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
, Device
);
459 if (!NT_SUCCESS(Status
))
461 // ErrorStatus = Status;
462 // ErrorOccurred = TRUE;
468 ObReferenceObject(DriveInfo
->DeviceObject
);
469 Relations
->Objects
[i
] = DriveInfo
->DeviceObject
;
473 if (NT_SUCCESS(Status
))
475 *DeviceRelations
= Relations
;
479 if (Relations
!= NULL
)
480 ExFreePool(Relations
);
490 IN PDEVICE_OBJECT DeviceObject
,
493 PIO_STACK_LOCATION IrpSp
;
494 PDEVICE_RELATIONS DeviceRelations
= NULL
;
495 ULONG_PTR Information
= 0;
496 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
498 DPRINT1("FdcFdoPnp()\n");
500 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
502 switch (IrpSp
->MinorFunction
)
504 case IRP_MN_START_DEVICE
:
505 DPRINT1(" IRP_MN_START_DEVICE received\n");
506 /* Call lower driver */
507 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
508 if (NT_SUCCESS(Status
))
510 Status
= FdcFdoStartDevice(DeviceObject
,
511 IrpSp
->Parameters
.StartDevice
.AllocatedResources
,
512 IrpSp
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
516 case IRP_MN_QUERY_REMOVE_DEVICE
:
517 DPRINT1(" IRP_MN_QUERY_REMOVE_DEVICE\n");
520 case IRP_MN_REMOVE_DEVICE
:
521 DPRINT1(" IRP_MN_REMOVE_DEVICE received\n");
524 case IRP_MN_CANCEL_REMOVE_DEVICE
:
525 DPRINT1(" IRP_MN_CANCEL_REMOVE_DEVICE\n");
528 case IRP_MN_STOP_DEVICE
:
529 DPRINT1(" IRP_MN_STOP_DEVICE received\n");
532 case IRP_MN_QUERY_STOP_DEVICE
:
533 DPRINT1(" IRP_MN_QUERY_STOP_DEVICE received\n");
536 case IRP_MN_CANCEL_STOP_DEVICE
:
537 DPRINT1(" IRP_MN_CANCEL_STOP_DEVICE\n");
540 case IRP_MN_QUERY_DEVICE_RELATIONS
:
541 DPRINT1(" IRP_MN_QUERY_DEVICE_RELATIONS\n");
543 switch (IrpSp
->Parameters
.QueryDeviceRelations
.Type
)
546 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
547 Status
= FdcFdoQueryBusRelations(DeviceObject
, &DeviceRelations
);
548 Information
= (ULONG_PTR
)DeviceRelations
;
551 case RemovalRelations
:
552 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
553 return ForwardIrpAndForget(DeviceObject
, Irp
);
556 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
557 IrpSp
->Parameters
.QueryDeviceRelations
.Type
);
558 return ForwardIrpAndForget(DeviceObject
, Irp
);
562 case IRP_MN_SURPRISE_REMOVAL
:
563 DPRINT1(" IRP_MN_SURPRISE_REMOVAL received\n");
567 DPRINT(" Unknown IOCTL 0x%lx\n", IrpSp
->MinorFunction
);
568 return ForwardIrpAndForget(DeviceObject
, Irp
);
571 Irp
->IoStatus
.Information
= Information
;
572 Irp
->IoStatus
.Status
= Status
;
573 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);