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
,
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
;
375 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
379 return STATUS_SUCCESS
;
383 /* PUBLIC FUNCTIONS *********************************************************/
387 AddDevice(IN PDRIVER_OBJECT DriverObject
,
388 IN PDEVICE_OBJECT Pdo
)
390 DPRINT("AddDevice(%p %p)\n", DriverObject
, Pdo
);
392 /* Serial.sys is a legacy driver. AddDevice is called once
393 * with a NULL Pdo just after the driver initialization.
394 * Detect this case and return success.
397 return STATUS_SUCCESS
;
399 /* We have here a PDO not null. It represents a real serial
400 * port. So call the internal AddDevice function.
402 return AddDeviceInternal(DriverObject
, Pdo
, NULL
, NULL
);
408 FdoCreate(IN PDEVICE_OBJECT DeviceObject
,
411 PFDO_DEVICE_EXTENSION DeviceExtension
;
412 PIO_STACK_LOCATION Stack
;
413 NTSTATUS Status
= STATUS_SUCCESS
;
415 DPRINT("FdoCreate()\n");
417 Stack
= IoGetCurrentIrpStackLocation(Irp
);
418 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
420 if (Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
422 DPRINT1("Not a directory\n");
423 Status
= STATUS_NOT_A_DIRECTORY
;
427 DPRINT("Open parallel port %lu: successful\n", DeviceExtension
->PortNumber
);
428 DeviceExtension
->OpenCount
++;
431 Irp
->IoStatus
.Status
= Status
;
432 Irp
->IoStatus
.Information
= 0;
433 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
441 FdoClose(IN PDEVICE_OBJECT DeviceObject
,
444 PFDO_DEVICE_EXTENSION pDeviceExtension
;
446 DPRINT("FdoClose()\n");
448 pDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
449 pDeviceExtension
->OpenCount
--;
451 Irp
->IoStatus
.Information
= 0;
452 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
453 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
455 return STATUS_SUCCESS
;
461 FdoCleanup(IN PDEVICE_OBJECT DeviceObject
,
464 DPRINT("FdoCleanup()\n");
466 Irp
->IoStatus
.Information
= 0;
467 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
468 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
470 return STATUS_SUCCESS
;
476 FdoRead(IN PDEVICE_OBJECT DeviceObject
,
479 DPRINT("FdoRead()\n");
481 Irp
->IoStatus
.Information
= 0;
482 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
483 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
484 return STATUS_NOT_SUPPORTED
;
490 FdoWrite(IN PDEVICE_OBJECT DeviceObject
,
493 DPRINT("FdoWrite()\n");
495 Irp
->IoStatus
.Information
= 0;
496 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
497 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
498 return STATUS_NOT_SUPPORTED
;
504 FdoPnp(IN PDEVICE_OBJECT DeviceObject
,
508 PIO_STACK_LOCATION Stack
;
509 ULONG_PTR Information
= 0;
512 DPRINT("FdoPnp()\n");
514 Stack
= IoGetCurrentIrpStackLocation(Irp
);
515 MinorFunction
= Stack
->MinorFunction
;
517 switch (MinorFunction
)
519 /* FIXME: do all these minor functions
520 IRP_MN_QUERY_REMOVE_DEVICE 0x1
521 IRP_MN_REMOVE_DEVICE 0x2
523 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
525 IoReleaseRemoveLockAndWait
526 pass request to DeviceExtension-LowerDriver
528 IoDeleteDevice(Fdo) and/or IoDetachDevice
531 IRP_MN_CANCEL_REMOVE_DEVICE 0x3
532 IRP_MN_STOP_DEVICE 0x4
533 IRP_MN_QUERY_STOP_DEVICE 0x5
534 IRP_MN_CANCEL_STOP_DEVICE 0x6
535 IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) 0x7
536 IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
537 IRP_MN_QUERY_INTERFACE (optional) 0x8
538 IRP_MN_QUERY_CAPABILITIES (optional) 0x9
539 IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) 0xd
540 IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
541 IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
542 IRP_MN_SURPRISE_REMOVAL 0x17
544 case IRP_MN_START_DEVICE
: /* 0x0 */
545 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
547 ASSERT(((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->Common
.PnpState
== dsStopped
);
549 /* Call lower driver */
550 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
551 if (NT_SUCCESS(Status
))
553 Status
= FdoStartDevice(DeviceObject
,
554 Stack
->Parameters
.StartDevice
.AllocatedResources
,
555 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
559 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* (optional) 0x7 */
560 switch (Stack
->Parameters
.QueryDeviceRelations
.Type
)
563 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
564 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, Stack
);
565 Irp
->IoStatus
.Status
= Status
;
566 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
569 case RemovalRelations
:
570 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
571 return ForwardIrpAndForget(DeviceObject
, Irp
);
574 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
575 Stack
->Parameters
.QueryDeviceRelations
.Type
);
576 return ForwardIrpAndForget(DeviceObject
, Irp
);
580 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* (optional) 0xd */
581 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
582 return ForwardIrpAndForget(DeviceObject
, Irp
);
585 DPRINT("Unknown minor function 0x%x\n", MinorFunction
);
586 return ForwardIrpAndForget(DeviceObject
, Irp
);
589 Irp
->IoStatus
.Information
= Information
;
590 Irp
->IoStatus
.Status
= Status
;
591 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
599 FdoPower(IN PDEVICE_OBJECT DeviceObject
,
602 DPRINT("FdoPower()\n");
604 Irp
->IoStatus
.Information
= 0;
605 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
606 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
608 return STATUS_SUCCESS
;