1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "fdc.h"
12
13 #include <stdio.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS ******************************************************************/
18
19 NTSTATUS
20 NTAPI
ForwardIrpAndForget(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)21 ForwardIrpAndForget(
22 IN PDEVICE_OBJECT DeviceObject,
23 IN PIRP Irp)
24 {
25 PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
26
27 ASSERT(LowerDevice);
28
29 IoSkipCurrentIrpStackLocation(Irp);
30 return IoCallDriver(LowerDevice, Irp);
31 }
32
33
34 static
35 NTSTATUS
FdcFdoStartDevice(IN PDEVICE_OBJECT DeviceObject,IN PCM_RESOURCE_LIST ResourceList,IN PCM_RESOURCE_LIST ResourceListTranslated)36 FdcFdoStartDevice(
37 IN PDEVICE_OBJECT DeviceObject,
38 IN PCM_RESOURCE_LIST ResourceList,
39 IN PCM_RESOURCE_LIST ResourceListTranslated)
40 {
41 PFDO_DEVICE_EXTENSION DeviceExtension;
42 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
43 // PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated;
44 ULONG i;
45
46 DPRINT("FdcFdoStartDevice called\n");
47
48 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
49
50 ASSERT(DeviceExtension);
51
52 if (ResourceList == NULL ||
53 ResourceListTranslated == NULL)
54 {
55 DPRINT1("No allocated resources sent to driver\n");
56 return STATUS_INSUFFICIENT_RESOURCES;
57 }
58
59 if (ResourceList->Count != 1)
60 {
61 DPRINT1("Wrong number of allocated resources sent to driver\n");
62 return STATUS_INSUFFICIENT_RESOURCES;
63 }
64
65 if (ResourceList->List[0].PartialResourceList.Version != 1 ||
66 ResourceList->List[0].PartialResourceList.Revision != 1 ||
67 ResourceListTranslated->List[0].PartialResourceList.Version != 1 ||
68 ResourceListTranslated->List[0].PartialResourceList.Revision != 1)
69 {
70 DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
71 ResourceList->List[0].PartialResourceList.Version,
72 ResourceList->List[0].PartialResourceList.Revision,
73 ResourceListTranslated->List[0].PartialResourceList.Version,
74 ResourceListTranslated->List[0].PartialResourceList.Revision);
75 return STATUS_REVISION_MISMATCH;
76 }
77
78 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
79 {
80 PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
81 // PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i];
82
83 switch (PartialDescriptor->Type)
84 {
85 case CmResourceTypePort:
86 DPRINT("Port: 0x%lx (%lu)\n",
87 PartialDescriptor->u.Port.Start.u.LowPart,
88 PartialDescriptor->u.Port.Length);
89 if (PartialDescriptor->u.Port.Length >= 6)
90 DeviceExtension->ControllerInfo.BaseAddress = (PUCHAR)(ULONG_PTR)PartialDescriptor->u.Port.Start.QuadPart;
91 break;
92
93 case CmResourceTypeInterrupt:
94 DPRINT("Interrupt: Level %lu Vector %lu\n",
95 PartialDescriptor->u.Interrupt.Level,
96 PartialDescriptor->u.Interrupt.Vector);
97 /*
98 Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
99 Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
100 Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
101 if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
102 InterruptMode = Latched;
103 else
104 InterruptMode = LevelSensitive;
105 ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
106 */
107 break;
108
109 case CmResourceTypeDma:
110 DPRINT("Dma: Channel %lu\n",
111 PartialDescriptor->u.Dma.Channel);
112 break;
113 }
114 }
115
116 return STATUS_SUCCESS;
117 }
118
119
120 static
121 NTSTATUS
122 NTAPI
FdcFdoConfigCallback(PVOID Context,PUNICODE_STRING PathName,INTERFACE_TYPE BusType,ULONG BusNumber,PKEY_VALUE_FULL_INFORMATION * BusInformation,CONFIGURATION_TYPE ControllerType,ULONG ControllerNumber,PKEY_VALUE_FULL_INFORMATION * ControllerInformation,CONFIGURATION_TYPE PeripheralType,ULONG PeripheralNumber,PKEY_VALUE_FULL_INFORMATION * PeripheralInformation)123 FdcFdoConfigCallback(
124 PVOID Context,
125 PUNICODE_STRING PathName,
126 INTERFACE_TYPE BusType,
127 ULONG BusNumber,
128 PKEY_VALUE_FULL_INFORMATION *BusInformation,
129 CONFIGURATION_TYPE ControllerType,
130 ULONG ControllerNumber,
131 PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
132 CONFIGURATION_TYPE PeripheralType,
133 ULONG PeripheralNumber,
134 PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
135 {
136 PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor;
137 PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor;
138 PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor;
139 PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor;
140 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
141 PCM_FLOPPY_DEVICE_DATA FloppyDeviceData;
142 PFDO_DEVICE_EXTENSION DeviceExtension;
143 PDRIVE_INFO DriveInfo;
144 BOOLEAN ControllerFound = FALSE;
145 ULONG i;
146
147 DPRINT("FdcFdoConfigCallback() called\n");
148
149 DeviceExtension = (PFDO_DEVICE_EXTENSION)Context;
150
151 /* Get the controller resources */
152 ControllerFullDescriptor = ControllerInformation[IoQueryDeviceConfigurationData];
153 ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor +
154 ControllerFullDescriptor->DataOffset);
155
156 for(i = 0; i < ControllerResourceDescriptor->PartialResourceList.Count; i++)
157 {
158 PartialDescriptor = &ControllerResourceDescriptor->PartialResourceList.PartialDescriptors[i];
159
160 if (PartialDescriptor->Type == CmResourceTypePort)
161 {
162 if ((PUCHAR)(ULONG_PTR)PartialDescriptor->u.Port.Start.QuadPart == DeviceExtension->ControllerInfo.BaseAddress)
163 ControllerFound = TRUE;
164 }
165 }
166
167 /* Leave, if the enumerated controller is not the one represented by the FDO */
168 if (ControllerFound == FALSE)
169 return STATUS_SUCCESS;
170
171 /* Get the peripheral resources */
172 PeripheralFullDescriptor = PeripheralInformation[IoQueryDeviceConfigurationData];
173 PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor +
174 PeripheralFullDescriptor->DataOffset);
175
176 /* learn about drives attached to controller */
177 for(i = 0; i < PeripheralResourceDescriptor->PartialResourceList.Count; i++)
178 {
179 PartialDescriptor = &PeripheralResourceDescriptor->PartialResourceList.PartialDescriptors[i];
180
181 if (PartialDescriptor->Type != CmResourceTypeDeviceSpecific)
182 continue;
183
184 FloppyDeviceData = (PCM_FLOPPY_DEVICE_DATA)(PartialDescriptor + 1);
185
186 DriveInfo = &DeviceExtension->ControllerInfo.DriveInfo[DeviceExtension->ControllerInfo.NumberOfDrives];
187
188 DriveInfo->ControllerInfo = &DeviceExtension->ControllerInfo;
189 DriveInfo->UnitNumber = DeviceExtension->ControllerInfo.NumberOfDrives;
190 DriveInfo->PeripheralNumber = PeripheralNumber;
191
192 DriveInfo->FloppyDeviceData.MaxDensity = FloppyDeviceData->MaxDensity;
193 DriveInfo->FloppyDeviceData.MountDensity = FloppyDeviceData->MountDensity;
194 DriveInfo->FloppyDeviceData.StepRateHeadUnloadTime = FloppyDeviceData->StepRateHeadUnloadTime;
195 DriveInfo->FloppyDeviceData.HeadLoadTime = FloppyDeviceData->HeadLoadTime;
196 DriveInfo->FloppyDeviceData.MotorOffTime = FloppyDeviceData->MotorOffTime;
197 DriveInfo->FloppyDeviceData.SectorLengthCode = FloppyDeviceData->SectorLengthCode;
198 DriveInfo->FloppyDeviceData.SectorPerTrack = FloppyDeviceData->SectorPerTrack;
199 DriveInfo->FloppyDeviceData.ReadWriteGapLength = FloppyDeviceData->ReadWriteGapLength;
200 DriveInfo->FloppyDeviceData.FormatGapLength = FloppyDeviceData->FormatGapLength;
201 DriveInfo->FloppyDeviceData.FormatFillCharacter = FloppyDeviceData->FormatFillCharacter;
202 DriveInfo->FloppyDeviceData.HeadSettleTime = FloppyDeviceData->HeadSettleTime;
203 DriveInfo->FloppyDeviceData.MotorSettleTime = FloppyDeviceData->MotorSettleTime;
204 DriveInfo->FloppyDeviceData.MaximumTrackValue = FloppyDeviceData->MaximumTrackValue;
205 DriveInfo->FloppyDeviceData.DataTransferLength = FloppyDeviceData->DataTransferLength;
206
207 /* Once it's all set up, acknowledge its existence in the controller info object */
208 DeviceExtension->ControllerInfo.NumberOfDrives++;
209 }
210
211 DeviceExtension->ControllerInfo.Populated = TRUE;
212
213 DPRINT("Detected %lu floppy drives!\n",
214 DeviceExtension->ControllerInfo.NumberOfDrives);
215
216 return STATUS_SUCCESS;
217 }
218
219
220 static
221 NTSTATUS
PciCreateHardwareIDsString(PUNICODE_STRING HardwareIDs)222 PciCreateHardwareIDsString(PUNICODE_STRING HardwareIDs)
223 {
224 WCHAR Buffer[256];
225 UNICODE_STRING BufferU;
226 ULONG Index;
227
228 Index = 0;
229 Index += swprintf(&Buffer[Index],
230 L"FDC\\GENERIC_FLOPPY_DRIVE");
231 Index++;
232
233 Buffer[Index] = UNICODE_NULL;
234
235 BufferU.Length = BufferU.MaximumLength = (USHORT) Index * sizeof(WCHAR);
236 BufferU.Buffer = Buffer;
237
238 return DuplicateUnicodeString(0, &BufferU, HardwareIDs);
239 }
240
241
242 static
243 NTSTATUS
PciCreateCompatibleIDsString(PUNICODE_STRING CompatibleIDs)244 PciCreateCompatibleIDsString(PUNICODE_STRING CompatibleIDs)
245 {
246 WCHAR Buffer[256];
247 UNICODE_STRING BufferU;
248 ULONG Index;
249
250 Index = 0;
251 Index += swprintf(&Buffer[Index],
252 L"GenFloppyDisk");
253 Index++;
254
255 Buffer[Index] = UNICODE_NULL;
256
257 BufferU.Length = BufferU.MaximumLength = (USHORT)Index * sizeof(WCHAR);
258 BufferU.Buffer = Buffer;
259
260 return DuplicateUnicodeString(0, &BufferU, CompatibleIDs);
261 }
262
263
264 static
265 NTSTATUS
PciCreateInstanceIDString(PUNICODE_STRING InstanceID,ULONG PeripheralNumber)266 PciCreateInstanceIDString(PUNICODE_STRING InstanceID,
267 ULONG PeripheralNumber)
268 {
269 WCHAR Buffer[3];
270
271 swprintf(Buffer, L"%02X", PeripheralNumber & 0xff);
272
273 return RtlCreateUnicodeString(InstanceID, Buffer) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
274 }
275
276
277 static
278 NTSTATUS
FdcFdoQueryBusRelations(IN PDEVICE_OBJECT DeviceObject,OUT PDEVICE_RELATIONS * DeviceRelations)279 FdcFdoQueryBusRelations(
280 IN PDEVICE_OBJECT DeviceObject,
281 OUT PDEVICE_RELATIONS *DeviceRelations)
282 {
283 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
284 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
285 INTERFACE_TYPE InterfaceType = Isa;
286 CONFIGURATION_TYPE ControllerType = DiskController;
287 CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral;
288 PDEVICE_RELATIONS Relations;
289 PDRIVE_INFO DriveInfo;
290 PDEVICE_OBJECT Pdo;
291 WCHAR DeviceNameBuffer[80];
292 UNICODE_STRING DeviceName;
293 ULONG DeviceNumber = 0;
294 ULONG Size;
295 ULONG i;
296 NTSTATUS Status;
297
298 DPRINT("FdcFdoQueryBusRelations() called\n");
299
300 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
301
302 Status = IoQueryDeviceDescription(&InterfaceType,
303 NULL,
304 &ControllerType,
305 NULL,
306 &PeripheralType,
307 NULL,
308 FdcFdoConfigCallback,
309 FdoDeviceExtension);
310 if (!NT_SUCCESS(Status) && (Status != STATUS_NO_MORE_ENTRIES))
311 return Status;
312
313 Size = sizeof(DEVICE_RELATIONS) +
314 sizeof(Relations->Objects) * (FdoDeviceExtension->ControllerInfo.NumberOfDrives - 1);
315 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
316 if (Relations == NULL)
317 {
318 return STATUS_INSUFFICIENT_RESOURCES;
319 }
320
321 Relations->Count = FdoDeviceExtension->ControllerInfo.NumberOfDrives;
322
323 for (i = 0; i < FdoDeviceExtension->ControllerInfo.NumberOfDrives; i++)
324 {
325 DriveInfo = &FdoDeviceExtension->ControllerInfo.DriveInfo[i];
326
327 if (DriveInfo->DeviceObject == NULL)
328 {
329 do
330 {
331 swprintf(DeviceNameBuffer, L"\\Device\\FloppyPDO%lu", DeviceNumber++);
332 RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
333 DPRINT("Device name: %S\n", DeviceNameBuffer);
334
335 /* Create physical device object */
336 Status = IoCreateDevice(FdoDeviceExtension->Common.DeviceObject->DriverObject,
337 sizeof(PDO_DEVICE_EXTENSION),
338 &DeviceName,
339 FILE_DEVICE_MASS_STORAGE,
340 FILE_DEVICE_SECURE_OPEN,
341 FALSE,
342 &Pdo);
343 }
344 while (Status == STATUS_OBJECT_NAME_COLLISION);
345
346 if (!NT_SUCCESS(Status))
347 {
348 DPRINT1("PDO creation failed (Status 0x%08lx)\n", Status);
349 goto done;
350 }
351
352 DPRINT("PDO created: %S\n", DeviceNameBuffer);
353
354 DriveInfo->DeviceObject = Pdo;
355
356 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
357 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
358
359 PdoDeviceExtension->Common.IsFDO = FALSE;
360 PdoDeviceExtension->Common.DeviceObject = Pdo;
361
362 PdoDeviceExtension->Fdo = FdoDeviceExtension->Common.DeviceObject;
363 PdoDeviceExtension->DriveInfo = DriveInfo;
364
365 Pdo->Flags |= DO_DIRECT_IO;
366 Pdo->Flags |= DO_POWER_PAGABLE;
367 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
368
369 /* Add Device ID string */
370 RtlCreateUnicodeString(&PdoDeviceExtension->DeviceId,
371 L"FDC\\GENERIC_FLOPPY_DRIVE");
372 DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceId.Buffer);
373
374 /* Add Hardware IDs string */
375 Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIds);
376 if (!NT_SUCCESS(Status))
377 {
378 // ErrorStatus = Status;
379 // ErrorOccurred = TRUE;
380 break;
381 }
382
383 /* Add Compatible IDs string */
384 Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIds);
385 if (!NT_SUCCESS(Status))
386 {
387 // ErrorStatus = Status;
388 // ErrorOccurred = TRUE;
389 break;
390 }
391
392 /* Add Instance ID string */
393 Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceId,
394 DriveInfo->PeripheralNumber);
395 if (!NT_SUCCESS(Status))
396 {
397 // ErrorStatus = Status;
398 // ErrorOccurred = TRUE;
399 break;
400 }
401
402 #if 0
403 /* Add device description string */
404 Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device);
405 if (!NT_SUCCESS(Status))
406 {
407 // ErrorStatus = Status;
408 // ErrorOccurred = TRUE;
409 break;
410 }
411
412 /* Add device location string */
413 Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device);
414 if (!NT_SUCCESS(Status))
415 {
416 // ErrorStatus = Status;
417 // ErrorOccurred = TRUE;
418 break;
419 }
420 #endif
421 }
422
423 ObReferenceObject(DriveInfo->DeviceObject);
424 Relations->Objects[i] = DriveInfo->DeviceObject;
425 }
426
427 done:
428 if (NT_SUCCESS(Status))
429 {
430 *DeviceRelations = Relations;
431 }
432 else
433 {
434 if (Relations != NULL)
435 ExFreePool(Relations);
436 }
437
438 return Status;
439 }
440
441
442 NTSTATUS
443 NTAPI
FdcFdoPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)444 FdcFdoPnp(
445 IN PDEVICE_OBJECT DeviceObject,
446 IN PIRP Irp)
447 {
448 PFDO_DEVICE_EXTENSION FdoExtension;
449 PIO_STACK_LOCATION IrpSp;
450 PDEVICE_RELATIONS DeviceRelations = NULL;
451 ULONG_PTR Information = 0;
452 NTSTATUS Status = STATUS_NOT_SUPPORTED;
453
454 DPRINT("FdcFdoPnp()\n");
455
456 IrpSp = IoGetCurrentIrpStackLocation(Irp);
457
458 switch (IrpSp->MinorFunction)
459 {
460 case IRP_MN_START_DEVICE:
461 DPRINT(" IRP_MN_START_DEVICE received\n");
462
463 /* Call lower driver */
464 Status = STATUS_UNSUCCESSFUL;
465 FdoExtension = DeviceObject->DeviceExtension;
466
467 if (IoForwardIrpSynchronously(FdoExtension->LowerDevice, Irp))
468 {
469 Status = Irp->IoStatus.Status;
470 if (NT_SUCCESS(Status))
471 {
472 Status = FdcFdoStartDevice(DeviceObject,
473 IrpSp->Parameters.StartDevice.AllocatedResources,
474 IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated);
475 }
476 }
477
478 break;
479
480 case IRP_MN_QUERY_REMOVE_DEVICE:
481 DPRINT(" IRP_MN_QUERY_REMOVE_DEVICE\n");
482 break;
483
484 case IRP_MN_REMOVE_DEVICE:
485 DPRINT(" IRP_MN_REMOVE_DEVICE received\n");
486 break;
487
488 case IRP_MN_CANCEL_REMOVE_DEVICE:
489 DPRINT(" IRP_MN_CANCEL_REMOVE_DEVICE\n");
490 break;
491
492 case IRP_MN_STOP_DEVICE:
493 DPRINT(" IRP_MN_STOP_DEVICE received\n");
494 break;
495
496 case IRP_MN_QUERY_STOP_DEVICE:
497 DPRINT(" IRP_MN_QUERY_STOP_DEVICE received\n");
498 break;
499
500 case IRP_MN_CANCEL_STOP_DEVICE:
501 DPRINT(" IRP_MN_CANCEL_STOP_DEVICE\n");
502 break;
503
504 case IRP_MN_QUERY_DEVICE_RELATIONS:
505 DPRINT(" IRP_MN_QUERY_DEVICE_RELATIONS\n");
506
507 switch (IrpSp->Parameters.QueryDeviceRelations.Type)
508 {
509 case BusRelations:
510 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
511 Status = FdcFdoQueryBusRelations(DeviceObject, &DeviceRelations);
512 Information = (ULONG_PTR)DeviceRelations;
513 break;
514
515 case RemovalRelations:
516 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
517 return ForwardIrpAndForget(DeviceObject, Irp);
518
519 default:
520 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
521 IrpSp->Parameters.QueryDeviceRelations.Type);
522 return ForwardIrpAndForget(DeviceObject, Irp);
523 }
524 break;
525
526 case IRP_MN_SURPRISE_REMOVAL:
527 DPRINT(" IRP_MN_SURPRISE_REMOVAL received\n");
528 break;
529
530 default:
531 DPRINT(" Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
532 return ForwardIrpAndForget(DeviceObject, Irp);
533 }
534
535 Irp->IoStatus.Information = Information;
536 Irp->IoStatus.Status = Status;
537 IoCompleteRequest(Irp, IO_NO_INCREMENT);
538
539 return Status;
540 }
541
542 /* EOF */
543