2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Parallel Port Function Driver
4 * FILE: drivers/parallel/parport/fdo.c
5 * PURPOSE: FDO functions
10 /* FUNCTIONS ****************************************************************/
14 AddDeviceInternal(IN PDRIVER_OBJECT DriverObject
,
15 IN PDEVICE_OBJECT Pdo
,
16 IN PULONG pLptPortNumber OPTIONAL
,
17 OUT PDEVICE_OBJECT
* pFdo OPTIONAL
)
19 PFDO_DEVICE_EXTENSION DeviceExtension
= NULL
;
20 PDEVICE_OBJECT Fdo
= NULL
;
21 WCHAR DeviceNameBuffer
[32];
22 UNICODE_STRING DeviceName
;
25 DPRINT("AddDeviceInternal()\n");
30 /* Create new device object */
31 swprintf(DeviceNameBuffer
,
32 L
"\\Device\\ParallelPort%lu",
33 IoGetConfigurationInformation()->ParallelCount
);
34 RtlInitUnicodeString(&DeviceName
,
37 Status
= IoCreateDevice(DriverObject
,
38 sizeof(FDO_DEVICE_EXTENSION
),
40 FILE_DEVICE_PARALLEL_PORT
,
41 FILE_DEVICE_SECURE_OPEN
,
44 if (!NT_SUCCESS(Status
))
46 DPRINT1("IoCreateDevice() failed (Status 0x%08lx)\n", Status
);
51 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
52 RtlZeroMemory(DeviceExtension
,
53 sizeof(FDO_DEVICE_EXTENSION
));
55 DeviceExtension
->Common
.IsFDO
= TRUE
;
56 DeviceExtension
->Common
.PnpState
= dsStopped
;
58 DeviceExtension
->PortNumber
= IoGetConfigurationInformation()->ParallelCount
++;
59 DeviceExtension
->Pdo
= Pdo
;
61 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
,
63 &DeviceExtension
->LowerDevice
);
64 if (!NT_SUCCESS(Status
))
66 DPRINT1("IoAttachDeviceToDeviceStackSafe() failed (Status 0x%08lx)\n", Status
);
70 if (DeviceExtension
->LowerDevice
->Flags
& DO_POWER_PAGABLE
)
71 Fdo
->Flags
|= DO_POWER_PAGABLE
;
73 if (DeviceExtension
->LowerDevice
->Flags
& DO_BUFFERED_IO
)
74 Fdo
->Flags
|= DO_BUFFERED_IO
;
76 if (DeviceExtension
->LowerDevice
->Flags
& DO_DIRECT_IO
)
77 Fdo
->Flags
|= DO_DIRECT_IO
;
79 /* Choose default strategy */
80 if ((Fdo
->Flags
& (DO_BUFFERED_IO
| DO_DIRECT_IO
)) == 0)
81 Fdo
->Flags
|= DO_BUFFERED_IO
;
83 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
90 return STATUS_SUCCESS
;
104 FdoStartDevice(IN PDEVICE_OBJECT DeviceObject
,
105 IN PCM_RESOURCE_LIST ResourceList
,
106 IN PCM_RESOURCE_LIST ResourceListTranslated
)
108 PFDO_DEVICE_EXTENSION DeviceExtension
;
112 // KAFFINITY Affinity = 0;
113 // KINTERRUPT_MODE InterruptMode = Latched;
114 // BOOLEAN ShareInterrupt = TRUE;
116 DPRINT("FdoStartDevice ()\n");
118 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
120 ASSERT(DeviceExtension
);
121 ASSERT(DeviceExtension
->Common
.IsFDO
== TRUE
);
125 DPRINT1("No allocated resources sent to driver\n");
126 return STATUS_INSUFFICIENT_RESOURCES
;
129 if (ResourceList
->Count
!= 1)
131 DPRINT1("Wrong number of allocated resources sent to driver\n");
132 return STATUS_INSUFFICIENT_RESOURCES
;
135 if ((ResourceList
->List
[0].PartialResourceList
.Version
!= 1) ||
136 (ResourceList
->List
[0].PartialResourceList
.Revision
!= 1) ||
137 (ResourceListTranslated
->List
[0].PartialResourceList
.Version
!= 1) ||
138 (ResourceListTranslated
->List
[0].PartialResourceList
.Revision
!= 1))
140 DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
141 ResourceList
->List
[0].PartialResourceList
.Version
,
142 ResourceList
->List
[0].PartialResourceList
.Revision
,
143 ResourceListTranslated
->List
[0].PartialResourceList
.Version
,
144 ResourceListTranslated
->List
[0].PartialResourceList
.Revision
);
145 return STATUS_REVISION_MISMATCH
;
148 DeviceExtension
->BaseAddress
= 0;
150 for (i
= 0; i
< ResourceList
->List
[0].PartialResourceList
.Count
; i
++)
152 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
= &ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
153 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated
= &ResourceListTranslated
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
155 switch (PartialDescriptor
->Type
)
157 case CmResourceTypePort
:
158 DPRINT("Port: BaseAddress 0x%lx Length %lu\n",
159 PartialDescriptor
->u
.Port
.Start
.u
.LowPart
,
160 PartialDescriptor
->u
.Port
.Length
);
162 if (DeviceExtension
->BaseAddress
== 0)
164 if (PartialDescriptor
->u
.Port
.Length
< 4)
165 return STATUS_INSUFFICIENT_RESOURCES
;
167 DeviceExtension
->BaseAddress
= PartialDescriptor
->u
.Port
.Start
.u
.LowPart
;
171 case CmResourceTypeInterrupt
:
172 DPRINT("Interrupt: Level %lu Vector %lu\n",
173 PartialDescriptorTranslated
->u
.Interrupt
.Level
,
174 PartialDescriptorTranslated
->u
.Interrupt
.Vector
);
176 // Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
177 // Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
178 // Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
180 // if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
181 // InterruptMode = Latched;
183 // InterruptMode = LevelSensitive;
185 // ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
189 DPRINT1("Other ressource: \n");
194 DPRINT("New LPT port: Base 0x%lx\n",
195 DeviceExtension
->BaseAddress
);
197 if (!DeviceExtension
->BaseAddress
)
198 return STATUS_INSUFFICIENT_RESOURCES
;
202 return STATUS_INSUFFICIENT_RESOURCES
;
205 DeviceExtension
->Common
.PnpState
= dsStarted
;
208 /* We don't really care if the call succeeded or not... */
210 return STATUS_SUCCESS
;
216 FdoCreateRawParallelPdo(
217 IN PDEVICE_OBJECT DeviceObject
)
219 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
220 PPDO_DEVICE_EXTENSION PdoDeviceExtension
= NULL
;
221 PDEVICE_OBJECT Pdo
= NULL
;
222 WCHAR DeviceNameBuffer
[32];
223 WCHAR LinkNameBuffer
[32];
224 WCHAR LptPortBuffer
[32];
225 UNICODE_STRING DeviceName
;
226 UNICODE_STRING LinkName
;
227 UNICODE_STRING LptPort
;
228 OBJECT_ATTRIBUTES ObjectAttributes
;
229 UNICODE_STRING KeyName
;
233 DPRINT("FdoCreateRawParallelPdo()\n");
235 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
237 /* Create new device object */
238 swprintf(DeviceNameBuffer
,
239 L
"\\Device\\Parallel%lu",
240 FdoDeviceExtension
->PortNumber
);
241 RtlInitUnicodeString(&DeviceName
,
244 Status
= IoCreateDevice(DeviceObject
->DriverObject
,
245 sizeof(PDO_DEVICE_EXTENSION
),
247 FILE_DEVICE_CONTROLLER
,
251 if (!NT_SUCCESS(Status
))
253 DPRINT1("IoCreateDevice() failed with status 0x%08x\n", Status
);
257 Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
258 Pdo
->Flags
|= DO_POWER_PAGABLE
;
260 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
261 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
263 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
264 PdoDeviceExtension
->Common
.PnpState
= dsStopped
;
266 Pdo
->StackSize
= DeviceObject
->StackSize
+ 1;
268 FdoDeviceExtension
->AttachedRawPdo
= Pdo
;
269 PdoDeviceExtension
->AttachedFdo
= DeviceObject
;
271 PdoDeviceExtension
->PortNumber
= FdoDeviceExtension
->PortNumber
;
272 PdoDeviceExtension
->LptPort
= PdoDeviceExtension
->PortNumber
+ 1;
275 /* Create link \DosDevices\LPTX -> \Device\ParallelY */
276 swprintf(LinkNameBuffer
, L
"\\DosDevices\\LPT%lu", PdoDeviceExtension
->LptPort
);
277 RtlInitUnicodeString(&LinkName
, LinkNameBuffer
);
278 Status
= IoCreateSymbolicLink(&LinkName
,
280 if (!NT_SUCCESS(Status
))
282 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08x\n", Status
);
286 swprintf(LptPortBuffer
, L
"LPT%lu", PdoDeviceExtension
->LptPort
);
287 RtlInitUnicodeString(&LptPort
, LptPortBuffer
);
289 /* Write an entry value under HKLM\HARDWARE\DeviceMap\PARALLEL PORTS. */
290 /* This step is not mandatory, so do not exit in case of error. */
291 RtlInitUnicodeString(&KeyName
,
292 L
"\\Registry\\Machine\\HARDWARE\\DeviceMap\\PARALLEL PORTS");
293 InitializeObjectAttributes(&ObjectAttributes
,
295 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
299 Status
= ZwCreateKey(&KeyHandle
,
306 if (NT_SUCCESS(Status
))
308 /* Key = \Device\Parallelx, Value = LPTx */
309 ZwSetValueKey(KeyHandle
,
314 LptPort
.Length
+ sizeof(WCHAR
));
318 Pdo
->Flags
|= DO_BUFFERED_IO
;
319 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
322 if (!NT_SUCCESS(Status
))
326 ASSERT(PdoDeviceExtension
);
337 FdoQueryBusRelations(
338 IN PDEVICE_OBJECT DeviceObject
,
340 PIO_STACK_LOCATION IrpSp
)
342 PFDO_DEVICE_EXTENSION DeviceExtension
;
343 PDEVICE_RELATIONS DeviceRelations
;
349 UNREFERENCED_PARAMETER(IrpSp
);
351 DPRINT("FdoQueryBusRelations()\n");
353 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
354 ASSERT(DeviceExtension
->Common
.IsFDO
);
356 /* TODO: Enumerate parallel devices and create their PDOs */
358 Status
= FdoCreateRawParallelPdo(DeviceObject
);
359 if (!NT_SUCCESS(Status
))
364 /* Allocate a buffer for the device relations */
365 Size
= sizeof(DEVICE_RELATIONS
) + sizeof(PDEVICE_OBJECT
) * (PdoCount
- 1);
366 DeviceRelations
= ExAllocatePoolWithTag(PagedPool
, Size
, PARPORT_TAG
);
367 if (DeviceRelations
== NULL
)
368 return STATUS_INSUFFICIENT_RESOURCES
;
370 /* Fill the buffer */
372 ObReferenceObject(DeviceExtension
->AttachedRawPdo
);
373 DeviceRelations
->Objects
[i
] = DeviceExtension
->AttachedRawPdo
;
374 DeviceRelations
->Count
= 1;
376 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
380 return STATUS_SUCCESS
;
384 /* PUBLIC FUNCTIONS *********************************************************/
388 AddDevice(IN PDRIVER_OBJECT DriverObject
,
389 IN PDEVICE_OBJECT Pdo
)
391 DPRINT("AddDevice(%p %p)\n", DriverObject
, Pdo
);
393 /* Serial.sys is a legacy driver. AddDevice is called once
394 * with a NULL Pdo just after the driver initialization.
395 * Detect this case and return success.
398 return STATUS_SUCCESS
;
400 /* We have here a PDO not null. It represents a real serial
401 * port. So call the internal AddDevice function.
403 return AddDeviceInternal(DriverObject
, Pdo
, NULL
, NULL
);
409 FdoCreate(IN PDEVICE_OBJECT DeviceObject
,
412 PFDO_DEVICE_EXTENSION DeviceExtension
;
413 PIO_STACK_LOCATION Stack
;
414 NTSTATUS Status
= STATUS_SUCCESS
;
416 DPRINT("FdoCreate()\n");
418 Stack
= IoGetCurrentIrpStackLocation(Irp
);
419 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
421 if (Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
423 DPRINT1("Not a directory\n");
424 Status
= STATUS_NOT_A_DIRECTORY
;
428 DPRINT("Open parallel port %lu: successful\n", DeviceExtension
->PortNumber
);
429 DeviceExtension
->OpenCount
++;
432 Irp
->IoStatus
.Status
= Status
;
433 Irp
->IoStatus
.Information
= 0;
434 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
442 FdoClose(IN PDEVICE_OBJECT DeviceObject
,
445 PFDO_DEVICE_EXTENSION pDeviceExtension
;
447 DPRINT("FdoClose()\n");
449 pDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
450 pDeviceExtension
->OpenCount
--;
452 Irp
->IoStatus
.Information
= 0;
453 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
454 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
456 return STATUS_SUCCESS
;
462 FdoCleanup(IN PDEVICE_OBJECT DeviceObject
,
465 DPRINT("FdoCleanup()\n");
467 Irp
->IoStatus
.Information
= 0;
468 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
469 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
471 return STATUS_SUCCESS
;
477 FdoRead(IN PDEVICE_OBJECT DeviceObject
,
480 DPRINT("FdoRead()\n");
482 Irp
->IoStatus
.Information
= 0;
483 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
484 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
485 return STATUS_NOT_SUPPORTED
;
491 FdoWrite(IN PDEVICE_OBJECT DeviceObject
,
494 DPRINT("FdoWrite()\n");
496 Irp
->IoStatus
.Information
= 0;
497 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
498 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
499 return STATUS_NOT_SUPPORTED
;
505 FdoPnp(IN PDEVICE_OBJECT DeviceObject
,
509 PIO_STACK_LOCATION Stack
;
510 ULONG_PTR Information
= 0;
513 DPRINT("FdoPnp()\n");
515 Stack
= IoGetCurrentIrpStackLocation(Irp
);
516 MinorFunction
= Stack
->MinorFunction
;
518 switch (MinorFunction
)
520 /* FIXME: do all these minor functions
521 IRP_MN_QUERY_REMOVE_DEVICE 0x1
522 IRP_MN_REMOVE_DEVICE 0x2
524 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
526 IoReleaseRemoveLockAndWait
527 pass request to DeviceExtension-LowerDriver
529 IoDeleteDevice(Fdo) and/or IoDetachDevice
532 IRP_MN_CANCEL_REMOVE_DEVICE 0x3
533 IRP_MN_STOP_DEVICE 0x4
534 IRP_MN_QUERY_STOP_DEVICE 0x5
535 IRP_MN_CANCEL_STOP_DEVICE 0x6
536 IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) 0x7
537 IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
538 IRP_MN_QUERY_INTERFACE (optional) 0x8
539 IRP_MN_QUERY_CAPABILITIES (optional) 0x9
540 IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) 0xd
541 IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
542 IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
543 IRP_MN_SURPRISE_REMOVAL 0x17
545 case IRP_MN_START_DEVICE
: /* 0x0 */
546 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
548 ASSERT(((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->Common
.PnpState
== dsStopped
);
550 /* Call lower driver */
551 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
552 if (NT_SUCCESS(Status
))
554 Status
= FdoStartDevice(DeviceObject
,
555 Stack
->Parameters
.StartDevice
.AllocatedResources
,
556 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
560 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* (optional) 0x7 */
561 switch (Stack
->Parameters
.QueryDeviceRelations
.Type
)
564 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
565 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, Stack
);
566 Irp
->IoStatus
.Status
= Status
;
567 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
570 case RemovalRelations
:
571 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
572 return ForwardIrpAndForget(DeviceObject
, Irp
);
575 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
576 Stack
->Parameters
.QueryDeviceRelations
.Type
);
577 return ForwardIrpAndForget(DeviceObject
, Irp
);
581 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* (optional) 0xd */
582 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
583 return ForwardIrpAndForget(DeviceObject
, Irp
);
586 DPRINT("Unknown minor function 0x%x\n", MinorFunction
);
587 return ForwardIrpAndForget(DeviceObject
, Irp
);
590 Irp
->IoStatus
.Information
= Information
;
591 Irp
->IoStatus
.Status
= Status
;
592 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
600 FdoPower(IN PDEVICE_OBJECT DeviceObject
,
603 PDEVICE_OBJECT LowerDevice
;
605 DPRINT("FdoPower()\n");
607 LowerDevice
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LowerDevice
;
608 PoStartNextPowerIrp(Irp
);
609 IoSkipCurrentIrpStackLocation(Irp
);
610 return PoCallDriver(LowerDevice
, Irp
);;