[FDC]
[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 NTSTATUS
76 NTAPI
77 FdcAddDevice(
78 IN PDRIVER_OBJECT DriverObject,
79 IN PDEVICE_OBJECT Pdo)
80 {
81 PFDO_DEVICE_EXTENSION DeviceExtension = NULL;
82 PDEVICE_OBJECT Fdo = NULL;
83 NTSTATUS Status;
84
85 DPRINT1("FdcAddDevice()\n");
86
87 ASSERT(DriverObject);
88 ASSERT(Pdo);
89
90 /* Create functional device object */
91 Status = IoCreateDevice(DriverObject,
92 sizeof(FDO_DEVICE_EXTENSION),
93 NULL,
94 FILE_DEVICE_CONTROLLER,
95 FILE_DEVICE_SECURE_OPEN,
96 FALSE,
97 &Fdo);
98 if (NT_SUCCESS(Status))
99 {
100 DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
101 RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
102
103 DeviceExtension->Common.IsFDO = TRUE;
104
105 DeviceExtension->Fdo = Fdo;
106 DeviceExtension->Pdo = Pdo;
107
108
109 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
110 if (!NT_SUCCESS(Status))
111 {
112 DPRINT1("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
113 IoDeleteDevice(Fdo);
114 return Status;
115 }
116
117
118 Fdo->Flags |= DO_DIRECT_IO;
119 Fdo->Flags |= DO_POWER_PAGABLE;
120
121 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
122 }
123
124 return Status;
125 }
126
127
128 static
129 NTSTATUS
130 FdcFdoStartDevice(
131 IN PDEVICE_OBJECT DeviceObject,
132 IN PCM_RESOURCE_LIST ResourceList,
133 IN PCM_RESOURCE_LIST ResourceListTranslated)
134 {
135 PFDO_DEVICE_EXTENSION DeviceExtension;
136 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
137 // PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated;
138 ULONG i;
139
140 DPRINT1("FdcFdoStartDevice called\n");
141
142 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
143
144 ASSERT(DeviceExtension);
145
146 if (ResourceList == NULL ||
147 ResourceListTranslated == NULL)
148 {
149 DPRINT1("No allocated resources sent to driver\n");
150 return STATUS_INSUFFICIENT_RESOURCES;
151 }
152
153 if (ResourceList->Count != 1)
154 {
155 DPRINT1("Wrong number of allocated resources sent to driver\n");
156 return STATUS_INSUFFICIENT_RESOURCES;
157 }
158
159 if (ResourceList->List[0].PartialResourceList.Version != 1 ||
160 ResourceList->List[0].PartialResourceList.Revision != 1 ||
161 ResourceListTranslated->List[0].PartialResourceList.Version != 1 ||
162 ResourceListTranslated->List[0].PartialResourceList.Revision != 1)
163 {
164 DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
165 ResourceList->List[0].PartialResourceList.Version,
166 ResourceList->List[0].PartialResourceList.Revision,
167 ResourceListTranslated->List[0].PartialResourceList.Version,
168 ResourceListTranslated->List[0].PartialResourceList.Revision);
169 return STATUS_REVISION_MISMATCH;
170 }
171
172 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
173 {
174 PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
175 // PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i];
176
177 switch (PartialDescriptor->Type)
178 {
179 case CmResourceTypePort:
180 DPRINT1("Port: 0x%lx (%lu)\n",
181 PartialDescriptor->u.Port.Start.u.LowPart,
182 PartialDescriptor->u.Port.Length);
183 if (PartialDescriptor->u.Port.Length >= 6)
184 DeviceExtension->ControllerInfo.BaseAddress = (PUCHAR)PartialDescriptor->u.Port.Start.u.LowPart;
185 break;
186
187 case CmResourceTypeInterrupt:
188 DPRINT1("Interrupt: Level %lu Vector %lu\n",
189 PartialDescriptor->u.Interrupt.Level,
190 PartialDescriptor->u.Interrupt.Vector);
191 /*
192 Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
193 Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
194 Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
195 if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
196 InterruptMode = Latched;
197 else
198 InterruptMode = LevelSensitive;
199 ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
200 */
201 break;
202
203 case CmResourceTypeDma:
204 DPRINT1("Dma: Channel %lu\n",
205 PartialDescriptor->u.Dma.Channel);
206 break;
207 }
208 }
209
210 return STATUS_SUCCESS;
211 }
212
213
214 static
215 NTSTATUS
216 NTAPI
217 FdcFdoConfigCallback(
218 PVOID Context,
219 PUNICODE_STRING PathName,
220 INTERFACE_TYPE BusType,
221 ULONG BusNumber,
222 PKEY_VALUE_FULL_INFORMATION *BusInformation,
223 CONFIGURATION_TYPE ControllerType,
224 ULONG ControllerNumber,
225 PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
226 CONFIGURATION_TYPE PeripheralType,
227 ULONG PeripheralNumber,
228 PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
229 {
230 PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor;
231 PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor;
232 PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor;
233 PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor;
234 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
235 PCM_FLOPPY_DEVICE_DATA FloppyDeviceData;
236 PFDO_DEVICE_EXTENSION DeviceExtension;
237 PDRIVE_INFO DriveInfo;
238 BOOLEAN ControllerFound = FALSE;
239 ULONG i;
240
241 DPRINT1("FdcFdoConfigCallback() called\n");
242
243 DeviceExtension = (PFDO_DEVICE_EXTENSION)Context;
244
245 /* Get the controller resources */
246 ControllerFullDescriptor = ControllerInformation[IoQueryDeviceConfigurationData];
247 ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor +
248 ControllerFullDescriptor->DataOffset);
249
250 for(i = 0; i < ControllerResourceDescriptor->PartialResourceList.Count; i++)
251 {
252 PartialDescriptor = &ControllerResourceDescriptor->PartialResourceList.PartialDescriptors[i];
253
254 if (PartialDescriptor->Type == CmResourceTypePort)
255 {
256 if ((PUCHAR)PartialDescriptor->u.Port.Start.LowPart == DeviceExtension->ControllerInfo.BaseAddress)
257 ControllerFound = TRUE;
258 }
259 }
260
261 /* Leave, if the enumerated controller is not the one represented by the FDO */
262 if (ControllerFound == FALSE)
263 return STATUS_SUCCESS;
264
265 /* Get the peripheral resources */
266 PeripheralFullDescriptor = PeripheralInformation[IoQueryDeviceConfigurationData];
267 PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor +
268 PeripheralFullDescriptor->DataOffset);
269
270 DeviceExtension->ControllerInfo.NumberOfDrives = 0;
271
272 /* learn about drives attached to controller */
273 for(i = 0; i < PeripheralResourceDescriptor->PartialResourceList.Count; i++)
274 {
275 PartialDescriptor = &PeripheralResourceDescriptor->PartialResourceList.PartialDescriptors[i];
276
277 if (PartialDescriptor->Type != CmResourceTypeDeviceSpecific)
278 continue;
279
280 FloppyDeviceData = (PCM_FLOPPY_DEVICE_DATA)(PartialDescriptor + 1);
281
282 DriveInfo = &DeviceExtension->ControllerInfo.DriveInfo[i];
283
284 DriveInfo->ControllerInfo = &DeviceExtension->ControllerInfo;
285 DriveInfo->UnitNumber = i;
286
287 DriveInfo->FloppyDeviceData.MaxDensity = FloppyDeviceData->MaxDensity;
288 DriveInfo->FloppyDeviceData.MountDensity = FloppyDeviceData->MountDensity;
289 DriveInfo->FloppyDeviceData.StepRateHeadUnloadTime = FloppyDeviceData->StepRateHeadUnloadTime;
290 DriveInfo->FloppyDeviceData.HeadLoadTime = FloppyDeviceData->HeadLoadTime;
291 DriveInfo->FloppyDeviceData.MotorOffTime = FloppyDeviceData->MotorOffTime;
292 DriveInfo->FloppyDeviceData.SectorLengthCode = FloppyDeviceData->SectorLengthCode;
293 DriveInfo->FloppyDeviceData.SectorPerTrack = FloppyDeviceData->SectorPerTrack;
294 DriveInfo->FloppyDeviceData.ReadWriteGapLength = FloppyDeviceData->ReadWriteGapLength;
295 DriveInfo->FloppyDeviceData.FormatGapLength = FloppyDeviceData->FormatGapLength;
296 DriveInfo->FloppyDeviceData.FormatFillCharacter = FloppyDeviceData->FormatFillCharacter;
297 DriveInfo->FloppyDeviceData.HeadSettleTime = FloppyDeviceData->HeadSettleTime;
298 DriveInfo->FloppyDeviceData.MotorSettleTime = FloppyDeviceData->MotorSettleTime;
299 DriveInfo->FloppyDeviceData.MaximumTrackValue = FloppyDeviceData->MaximumTrackValue;
300 DriveInfo->FloppyDeviceData.DataTransferLength = FloppyDeviceData->DataTransferLength;
301
302 /* Once it's all set up, acknowledge its existance in the controller info object */
303 DeviceExtension->ControllerInfo.NumberOfDrives++;
304 }
305
306 DeviceExtension->ControllerInfo.Populated = TRUE;
307
308 DPRINT1("Detected %lu floppy drives!\n",
309 DeviceExtension->ControllerInfo.NumberOfDrives);
310
311 return STATUS_SUCCESS;
312 }
313
314
315 static
316 NTSTATUS
317 FdcFdoQueryBusRelations(
318 IN PDEVICE_OBJECT DeviceObject,
319 OUT PDEVICE_RELATIONS *DeviceRelations)
320 {
321 PFDO_DEVICE_EXTENSION DeviceExtension;
322 INTERFACE_TYPE InterfaceType = Isa;
323 CONFIGURATION_TYPE ControllerType = DiskController;
324 CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral;
325 NTSTATUS Status;
326
327 DPRINT1("FdcFdoQueryBusRelations() called\n");
328
329 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
330
331 Status = IoQueryDeviceDescription(&InterfaceType,
332 NULL,
333 &ControllerType,
334 NULL,
335 &PeripheralType,
336 NULL,
337 FdcFdoConfigCallback,
338 DeviceExtension);
339 if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND))
340 {
341 return Status;
342 }
343
344 return STATUS_SUCCESS;
345 }
346
347
348 NTSTATUS
349 NTAPI
350 FdcFdoPnp(
351 IN PDEVICE_OBJECT DeviceObject,
352 IN PIRP Irp)
353 {
354 PIO_STACK_LOCATION IrpSp;
355 PDEVICE_RELATIONS DeviceRelations = NULL;
356 ULONG_PTR Information = 0;
357 NTSTATUS Status = STATUS_NOT_SUPPORTED;
358
359 DPRINT1("FdcFdoPnp()\n");
360
361 IrpSp = IoGetCurrentIrpStackLocation(Irp);
362
363 switch (IrpSp->MinorFunction)
364 {
365 case IRP_MN_START_DEVICE:
366 DPRINT1(" IRP_MN_START_DEVICE received\n");
367 /* Call lower driver */
368 Status = ForwardIrpAndWait(DeviceObject, Irp);
369 if (NT_SUCCESS(Status))
370 {
371 Status = FdcFdoStartDevice(DeviceObject,
372 IrpSp->Parameters.StartDevice.AllocatedResources,
373 IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated);
374 }
375 break;
376
377 case IRP_MN_QUERY_REMOVE_DEVICE:
378 DPRINT1(" IRP_MN_QUERY_REMOVE_DEVICE\n");
379 break;
380
381 case IRP_MN_REMOVE_DEVICE:
382 DPRINT1(" IRP_MN_REMOVE_DEVICE received\n");
383 break;
384
385 case IRP_MN_CANCEL_REMOVE_DEVICE:
386 DPRINT1(" IRP_MN_CANCEL_REMOVE_DEVICE\n");
387 break;
388
389 case IRP_MN_STOP_DEVICE:
390 DPRINT1(" IRP_MN_STOP_DEVICE received\n");
391 break;
392
393 case IRP_MN_QUERY_STOP_DEVICE:
394 DPRINT1(" IRP_MN_QUERY_STOP_DEVICE received\n");
395 break;
396
397 case IRP_MN_CANCEL_STOP_DEVICE:
398 DPRINT1(" IRP_MN_CANCEL_STOP_DEVICE\n");
399 break;
400
401 case IRP_MN_QUERY_DEVICE_RELATIONS:
402 DPRINT1(" IRP_MN_QUERY_DEVICE_RELATIONS\n");
403
404 switch (IrpSp->Parameters.QueryDeviceRelations.Type)
405 {
406 case BusRelations:
407 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
408 Status = FdcFdoQueryBusRelations(DeviceObject, &DeviceRelations);
409 Information = (ULONG_PTR)DeviceRelations;
410 break;
411
412 case RemovalRelations:
413 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
414 return ForwardIrpAndForget(DeviceObject, Irp);
415
416 default:
417 DPRINT1(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
418 IrpSp->Parameters.QueryDeviceRelations.Type);
419 return ForwardIrpAndForget(DeviceObject, Irp);
420 }
421 break;
422
423 case IRP_MN_SURPRISE_REMOVAL:
424 DPRINT1(" IRP_MN_SURPRISE_REMOVAL received\n");
425 break;
426
427 default:
428 DPRINT(" Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
429 return ForwardIrpAndForget(DeviceObject, Irp);
430 }
431
432 Irp->IoStatus.Information = Information;
433 Irp->IoStatus.Status = Status;
434 IoCompleteRequest(Irp, IO_NO_INCREMENT);
435
436 return Status;
437 }
438
439 /* EOF */