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