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