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 *******************************************************************/
17 /* FUNCTIONS ******************************************************************/
19 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion
;
24 ForwardIrpAndWaitCompletion(
25 IN PDEVICE_OBJECT DeviceObject
,
29 if (Irp
->PendingReturned
)
30 KeSetEvent((PKEVENT
)Context
, IO_NO_INCREMENT
, FALSE
);
31 return STATUS_MORE_PROCESSING_REQUIRED
;
37 IN PDEVICE_OBJECT DeviceObject
,
40 PDEVICE_OBJECT LowerDevice
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
46 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
47 IoCopyCurrentIrpStackLocationToNext(Irp
);
49 DPRINT("Calling lower device %p\n", LowerDevice
);
50 IoSetCompletionRoutine(Irp
, ForwardIrpAndWaitCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
52 Status
= IoCallDriver(LowerDevice
, Irp
);
53 if (Status
== STATUS_PENDING
)
55 Status
= KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
56 if (NT_SUCCESS(Status
))
57 Status
= Irp
->IoStatus
.Status
;
67 IN PDEVICE_OBJECT DeviceObject
,
70 PDEVICE_OBJECT LowerDevice
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
74 IoSkipCurrentIrpStackLocation(Irp
);
75 return IoCallDriver(LowerDevice
, Irp
);
84 IN PDEVICE_OBJECT DeviceObject
,
85 IN PCM_RESOURCE_LIST ResourceList
,
86 IN PCM_RESOURCE_LIST ResourceListTranslated
)
88 PFDO_DEVICE_EXTENSION DeviceExtension
;
89 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
90 // PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated;
93 DPRINT("FdcFdoStartDevice called\n");
95 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
97 ASSERT(DeviceExtension
);
99 if (ResourceList
== NULL
||
100 ResourceListTranslated
== NULL
)
102 DPRINT1("No allocated resources sent to driver\n");
103 return STATUS_INSUFFICIENT_RESOURCES
;
106 if (ResourceList
->Count
!= 1)
108 DPRINT1("Wrong number of allocated resources sent to driver\n");
109 return STATUS_INSUFFICIENT_RESOURCES
;
112 if (ResourceList
->List
[0].PartialResourceList
.Version
!= 1 ||
113 ResourceList
->List
[0].PartialResourceList
.Revision
!= 1 ||
114 ResourceListTranslated
->List
[0].PartialResourceList
.Version
!= 1 ||
115 ResourceListTranslated
->List
[0].PartialResourceList
.Revision
!= 1)
117 DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
118 ResourceList
->List
[0].PartialResourceList
.Version
,
119 ResourceList
->List
[0].PartialResourceList
.Revision
,
120 ResourceListTranslated
->List
[0].PartialResourceList
.Version
,
121 ResourceListTranslated
->List
[0].PartialResourceList
.Revision
);
122 return STATUS_REVISION_MISMATCH
;
125 for (i
= 0; i
< ResourceList
->List
[0].PartialResourceList
.Count
; i
++)
127 PartialDescriptor
= &ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
128 // PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i];
130 switch (PartialDescriptor
->Type
)
132 case CmResourceTypePort
:
133 DPRINT("Port: 0x%lx (%lu)\n",
134 PartialDescriptor
->u
.Port
.Start
.u
.LowPart
,
135 PartialDescriptor
->u
.Port
.Length
);
136 if (PartialDescriptor
->u
.Port
.Length
>= 6)
137 DeviceExtension
->ControllerInfo
.BaseAddress
= (PUCHAR
)PartialDescriptor
->u
.Port
.Start
.u
.LowPart
;
140 case CmResourceTypeInterrupt
:
141 DPRINT("Interrupt: Level %lu Vector %lu\n",
142 PartialDescriptor
->u
.Interrupt
.Level
,
143 PartialDescriptor
->u
.Interrupt
.Vector
);
145 Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
146 Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
147 Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
148 if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
149 InterruptMode = Latched;
151 InterruptMode = LevelSensitive;
152 ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
156 case CmResourceTypeDma
:
157 DPRINT("Dma: Channel %lu\n",
158 PartialDescriptor
->u
.Dma
.Channel
);
163 return STATUS_SUCCESS
;
170 FdcFdoConfigCallback(
172 PUNICODE_STRING PathName
,
173 INTERFACE_TYPE BusType
,
175 PKEY_VALUE_FULL_INFORMATION
*BusInformation
,
176 CONFIGURATION_TYPE ControllerType
,
177 ULONG ControllerNumber
,
178 PKEY_VALUE_FULL_INFORMATION
*ControllerInformation
,
179 CONFIGURATION_TYPE PeripheralType
,
180 ULONG PeripheralNumber
,
181 PKEY_VALUE_FULL_INFORMATION
*PeripheralInformation
)
183 PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor
;
184 PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor
;
185 PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor
;
186 PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor
;
187 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
188 PCM_FLOPPY_DEVICE_DATA FloppyDeviceData
;
189 PFDO_DEVICE_EXTENSION DeviceExtension
;
190 PDRIVE_INFO DriveInfo
;
191 BOOLEAN ControllerFound
= FALSE
;
194 DPRINT("FdcFdoConfigCallback() called\n");
196 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Context
;
198 /* Get the controller resources */
199 ControllerFullDescriptor
= ControllerInformation
[IoQueryDeviceConfigurationData
];
200 ControllerResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PCHAR
)ControllerFullDescriptor
+
201 ControllerFullDescriptor
->DataOffset
);
203 for(i
= 0; i
< ControllerResourceDescriptor
->PartialResourceList
.Count
; i
++)
205 PartialDescriptor
= &ControllerResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
];
207 if (PartialDescriptor
->Type
== CmResourceTypePort
)
209 if ((PUCHAR
)PartialDescriptor
->u
.Port
.Start
.LowPart
== DeviceExtension
->ControllerInfo
.BaseAddress
)
210 ControllerFound
= TRUE
;
214 /* Leave, if the enumerated controller is not the one represented by the FDO */
215 if (ControllerFound
== FALSE
)
216 return STATUS_SUCCESS
;
218 /* Get the peripheral resources */
219 PeripheralFullDescriptor
= PeripheralInformation
[IoQueryDeviceConfigurationData
];
220 PeripheralResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)((PCHAR
)PeripheralFullDescriptor
+
221 PeripheralFullDescriptor
->DataOffset
);
223 /* learn about drives attached to controller */
224 for(i
= 0; i
< PeripheralResourceDescriptor
->PartialResourceList
.Count
; i
++)
226 PartialDescriptor
= &PeripheralResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
];
228 if (PartialDescriptor
->Type
!= CmResourceTypeDeviceSpecific
)
231 FloppyDeviceData
= (PCM_FLOPPY_DEVICE_DATA
)(PartialDescriptor
+ 1);
233 DriveInfo
= &DeviceExtension
->ControllerInfo
.DriveInfo
[DeviceExtension
->ControllerInfo
.NumberOfDrives
];
235 DriveInfo
->ControllerInfo
= &DeviceExtension
->ControllerInfo
;
236 DriveInfo
->UnitNumber
= DeviceExtension
->ControllerInfo
.NumberOfDrives
;
237 DriveInfo
->PeripheralNumber
= PeripheralNumber
;
239 DriveInfo
->FloppyDeviceData
.MaxDensity
= FloppyDeviceData
->MaxDensity
;
240 DriveInfo
->FloppyDeviceData
.MountDensity
= FloppyDeviceData
->MountDensity
;
241 DriveInfo
->FloppyDeviceData
.StepRateHeadUnloadTime
= FloppyDeviceData
->StepRateHeadUnloadTime
;
242 DriveInfo
->FloppyDeviceData
.HeadLoadTime
= FloppyDeviceData
->HeadLoadTime
;
243 DriveInfo
->FloppyDeviceData
.MotorOffTime
= FloppyDeviceData
->MotorOffTime
;
244 DriveInfo
->FloppyDeviceData
.SectorLengthCode
= FloppyDeviceData
->SectorLengthCode
;
245 DriveInfo
->FloppyDeviceData
.SectorPerTrack
= FloppyDeviceData
->SectorPerTrack
;
246 DriveInfo
->FloppyDeviceData
.ReadWriteGapLength
= FloppyDeviceData
->ReadWriteGapLength
;
247 DriveInfo
->FloppyDeviceData
.FormatGapLength
= FloppyDeviceData
->FormatGapLength
;
248 DriveInfo
->FloppyDeviceData
.FormatFillCharacter
= FloppyDeviceData
->FormatFillCharacter
;
249 DriveInfo
->FloppyDeviceData
.HeadSettleTime
= FloppyDeviceData
->HeadSettleTime
;
250 DriveInfo
->FloppyDeviceData
.MotorSettleTime
= FloppyDeviceData
->MotorSettleTime
;
251 DriveInfo
->FloppyDeviceData
.MaximumTrackValue
= FloppyDeviceData
->MaximumTrackValue
;
252 DriveInfo
->FloppyDeviceData
.DataTransferLength
= FloppyDeviceData
->DataTransferLength
;
254 /* Once it's all set up, acknowledge its existence in the controller info object */
255 DeviceExtension
->ControllerInfo
.NumberOfDrives
++;
258 DeviceExtension
->ControllerInfo
.Populated
= TRUE
;
260 DPRINT("Detected %lu floppy drives!\n",
261 DeviceExtension
->ControllerInfo
.NumberOfDrives
);
263 return STATUS_SUCCESS
;
269 PciCreateHardwareIDsString(PUNICODE_STRING HardwareIDs
)
272 UNICODE_STRING BufferU
;
276 Index
+= swprintf(&Buffer
[Index
],
277 L
"FDC\\GENERIC_FLOPPY_DRIVE");
280 Buffer
[Index
] = UNICODE_NULL
;
282 BufferU
.Length
= BufferU
.MaximumLength
= (USHORT
) Index
* sizeof(WCHAR
);
283 BufferU
.Buffer
= Buffer
;
285 return DuplicateUnicodeString(0, &BufferU
, HardwareIDs
);
291 PciCreateCompatibleIDsString(PUNICODE_STRING CompatibleIDs
)
294 UNICODE_STRING BufferU
;
298 Index
+= swprintf(&Buffer
[Index
],
302 Buffer
[Index
] = UNICODE_NULL
;
304 BufferU
.Length
= BufferU
.MaximumLength
= (USHORT
)Index
* sizeof(WCHAR
);
305 BufferU
.Buffer
= Buffer
;
307 return DuplicateUnicodeString(0, &BufferU
, CompatibleIDs
);
313 PciCreateInstanceIDString(PUNICODE_STRING InstanceID
,
314 ULONG PeripheralNumber
)
318 swprintf(Buffer
, L
"%02X", PeripheralNumber
& 0xff);
320 return RtlCreateUnicodeString(InstanceID
, Buffer
) ? STATUS_SUCCESS
: STATUS_INSUFFICIENT_RESOURCES
;
326 FdcFdoQueryBusRelations(
327 IN PDEVICE_OBJECT DeviceObject
,
328 OUT PDEVICE_RELATIONS
*DeviceRelations
)
330 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
331 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
332 INTERFACE_TYPE InterfaceType
= Isa
;
333 CONFIGURATION_TYPE ControllerType
= DiskController
;
334 CONFIGURATION_TYPE PeripheralType
= FloppyDiskPeripheral
;
335 PDEVICE_RELATIONS Relations
;
336 PDRIVE_INFO DriveInfo
;
338 WCHAR DeviceNameBuffer
[80];
339 UNICODE_STRING DeviceName
;
340 ULONG DeviceNumber
= 0;
345 DPRINT("FdcFdoQueryBusRelations() called\n");
347 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
349 Status
= IoQueryDeviceDescription(&InterfaceType
,
355 FdcFdoConfigCallback
,
357 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_NO_MORE_ENTRIES
))
360 Size
= sizeof(DEVICE_RELATIONS
) +
361 sizeof(Relations
->Objects
) * (FdoDeviceExtension
->ControllerInfo
.NumberOfDrives
- 1);
362 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
363 if (Relations
== NULL
)
365 return STATUS_INSUFFICIENT_RESOURCES
;
368 Relations
->Count
= FdoDeviceExtension
->ControllerInfo
.NumberOfDrives
;
370 for (i
= 0; i
< FdoDeviceExtension
->ControllerInfo
.NumberOfDrives
; i
++)
372 DriveInfo
= &FdoDeviceExtension
->ControllerInfo
.DriveInfo
[i
];
374 if (DriveInfo
->DeviceObject
== NULL
)
378 swprintf(DeviceNameBuffer
, L
"\\Device\\FloppyPDO%lu", DeviceNumber
++);
379 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
380 DPRINT("Device name: %S\n", DeviceNameBuffer
);
382 /* Create physical device object */
383 Status
= IoCreateDevice(FdoDeviceExtension
->Common
.DeviceObject
->DriverObject
,
384 sizeof(PDO_DEVICE_EXTENSION
),
386 FILE_DEVICE_MASS_STORAGE
,
387 FILE_DEVICE_SECURE_OPEN
,
391 while (Status
== STATUS_OBJECT_NAME_COLLISION
);
393 if (!NT_SUCCESS(Status
))
395 DPRINT1("PDO creation failed (Status 0x%08lx)\n", Status
);
399 DPRINT("PDO created: %S\n", DeviceNameBuffer
);
401 DriveInfo
->DeviceObject
= Pdo
;
403 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
404 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
406 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
407 PdoDeviceExtension
->Common
.DeviceObject
= Pdo
;
409 PdoDeviceExtension
->Fdo
= FdoDeviceExtension
->Common
.DeviceObject
;
410 PdoDeviceExtension
->DriveInfo
= DriveInfo
;
412 Pdo
->Flags
|= DO_DIRECT_IO
;
413 Pdo
->Flags
|= DO_POWER_PAGABLE
;
414 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
416 /* Add Device ID string */
417 RtlCreateUnicodeString(&PdoDeviceExtension
->DeviceId
,
418 L
"FDC\\GENERIC_FLOPPY_DRIVE");
419 DPRINT("DeviceID: %S\n", PdoDeviceExtension
->DeviceId
.Buffer
);
421 /* Add Hardware IDs string */
422 Status
= PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIds
);
423 if (!NT_SUCCESS(Status
))
425 // ErrorStatus = Status;
426 // ErrorOccurred = TRUE;
430 /* Add Compatible IDs string */
431 Status
= PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIds
);
432 if (!NT_SUCCESS(Status
))
434 // ErrorStatus = Status;
435 // ErrorOccurred = TRUE;
439 /* Add Instance ID string */
440 Status
= PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceId
,
441 DriveInfo
->PeripheralNumber
);
442 if (!NT_SUCCESS(Status
))
444 // ErrorStatus = Status;
445 // ErrorOccurred = TRUE;
450 /* Add device description string */
451 Status
= PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
, Device
);
452 if (!NT_SUCCESS(Status
))
454 // ErrorStatus = Status;
455 // ErrorOccurred = TRUE;
459 /* Add device location string */
460 Status
= PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
, Device
);
461 if (!NT_SUCCESS(Status
))
463 // ErrorStatus = Status;
464 // ErrorOccurred = TRUE;
470 ObReferenceObject(DriveInfo
->DeviceObject
);
471 Relations
->Objects
[i
] = DriveInfo
->DeviceObject
;
475 if (NT_SUCCESS(Status
))
477 *DeviceRelations
= Relations
;
481 if (Relations
!= NULL
)
482 ExFreePool(Relations
);
492 IN PDEVICE_OBJECT DeviceObject
,
495 PIO_STACK_LOCATION IrpSp
;
496 PDEVICE_RELATIONS DeviceRelations
= NULL
;
497 ULONG_PTR Information
= 0;
498 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
500 DPRINT("FdcFdoPnp()\n");
502 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
504 switch (IrpSp
->MinorFunction
)
506 case IRP_MN_START_DEVICE
:
507 DPRINT(" IRP_MN_START_DEVICE received\n");
508 /* Call lower driver */
509 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
510 if (NT_SUCCESS(Status
))
512 Status
= FdcFdoStartDevice(DeviceObject
,
513 IrpSp
->Parameters
.StartDevice
.AllocatedResources
,
514 IrpSp
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
518 case IRP_MN_QUERY_REMOVE_DEVICE
:
519 DPRINT(" IRP_MN_QUERY_REMOVE_DEVICE\n");
522 case IRP_MN_REMOVE_DEVICE
:
523 DPRINT(" IRP_MN_REMOVE_DEVICE received\n");
526 case IRP_MN_CANCEL_REMOVE_DEVICE
:
527 DPRINT(" IRP_MN_CANCEL_REMOVE_DEVICE\n");
530 case IRP_MN_STOP_DEVICE
:
531 DPRINT(" IRP_MN_STOP_DEVICE received\n");
534 case IRP_MN_QUERY_STOP_DEVICE
:
535 DPRINT(" IRP_MN_QUERY_STOP_DEVICE received\n");
538 case IRP_MN_CANCEL_STOP_DEVICE
:
539 DPRINT(" IRP_MN_CANCEL_STOP_DEVICE\n");
542 case IRP_MN_QUERY_DEVICE_RELATIONS
:
543 DPRINT(" IRP_MN_QUERY_DEVICE_RELATIONS\n");
545 switch (IrpSp
->Parameters
.QueryDeviceRelations
.Type
)
548 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
549 Status
= FdcFdoQueryBusRelations(DeviceObject
, &DeviceRelations
);
550 Information
= (ULONG_PTR
)DeviceRelations
;
553 case RemovalRelations
:
554 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
555 return ForwardIrpAndForget(DeviceObject
, Irp
);
558 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
559 IrpSp
->Parameters
.QueryDeviceRelations
.Type
);
560 return ForwardIrpAndForget(DeviceObject
, Irp
);
564 case IRP_MN_SURPRISE_REMOVAL
:
565 DPRINT(" IRP_MN_SURPRISE_REMOVAL received\n");
569 DPRINT(" Unknown IOCTL 0x%lx\n", IrpSp
->MinorFunction
);
570 return ForwardIrpAndForget(DeviceObject
, Irp
);
573 Irp
->IoStatus
.Information
= Information
;
574 Irp
->IoStatus
.Status
= Status
;
575 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);