[PARPORT]

- Add FdoQueryBusRelations to enumerate the 'attached' raw port.
- Create the PDO for the raw port (\Device\ParallelX) and let the symbolic link (\DosDevices\LPTX) point to it.
- Move the open, close and write code from the FDO to the PDO.

svn path=/trunk/; revision=67936
This commit is contained in:
Eric Kohl 2015-05-27 20:18:10 +00:00
parent 556d08c8f1
commit f4494b1b46
5 changed files with 290 additions and 124 deletions

View file

@ -7,37 +7,6 @@
#include "parport.h"
/*
* The following constants describe the various signals of the printer port
* hardware. Note that the hardware inverts some signals and that some
* signals are active low. An example is LP_STROBE, which must be programmed
* with 1 for being active and 0 for being inactive, because the strobe signal
* gets inverted, but it is also active low.
*/
/*
* bit defines for 8255 status port
* base + 1
* accessed with LP_S(minor), which gets the byte...
*/
#define LP_PBUSY 0x80 /* inverted input, active high */
#define LP_PACK 0x40 /* unchanged input, active low */
#define LP_POUTPA 0x20 /* unchanged input, active high */
#define LP_PSELECD 0x10 /* unchanged input, active high */
#define LP_PERRORP 0x08 /* unchanged input, active low */
/*
* defines for 8255 control port
* base + 2
* accessed with LP_C(minor)
*/
#define LP_PINTEN 0x10
#define LP_PSELECP 0x08 /* inverted output, active low */
#define LP_PINITP 0x04 /* unchanged output, active low */
#define LP_PAUTOLF 0x02 /* inverted output, active low */
#define LP_PSTROBE 0x01 /* inverted output, active low */
/* FUNCTIONS ****************************************************************/
NTSTATUS
@ -86,11 +55,7 @@ AddDeviceInternal(IN PDRIVER_OBJECT DriverObject,
DeviceExtension->Common.IsFDO = TRUE;
DeviceExtension->Common.PnpState = dsStopped;
DeviceExtension->ParallelPortNumber = IoGetConfigurationInformation()->ParallelCount++;
if (pLptPortNumber == NULL)
DeviceExtension->LptPort = DeviceExtension->ParallelPortNumber + 1;
else
DeviceExtension->LptPort = *pLptPortNumber;
DeviceExtension->PortNumber = IoGetConfigurationInformation()->ParallelCount++;
DeviceExtension->Pdo = Pdo;
Status = IoAttachDeviceToDeviceStackSafe(Fdo,
@ -141,22 +106,12 @@ FdoStartDevice(IN PDEVICE_OBJECT DeviceObject,
IN PCM_RESOURCE_LIST ResourceListTranslated)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
WCHAR DeviceNameBuffer[32];
WCHAR LinkNameBuffer[32];
WCHAR LptPortBuffer[32];
UNICODE_STRING DeviceName;
UNICODE_STRING LinkName;
UNICODE_STRING LptPort;
ULONG i;
// ULONG Vector = 0;
// KIRQL Dirql = 0;
// KAFFINITY Affinity = 0;
// KINTERRUPT_MODE InterruptMode = Latched;
// BOOLEAN ShareInterrupt = TRUE;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE KeyHandle;
NTSTATUS Status;
DPRINT("FdoStartDevice ()\n");
@ -247,21 +202,89 @@ FdoStartDevice(IN PDEVICE_OBJECT DeviceObject,
return STATUS_INSUFFICIENT_RESOURCES;
#endif
/* Create link \DosDevices\LPTX -> \Device\ParallelPortX */
swprintf(DeviceNameBuffer, L"\\Device\\ParallelPort%lu", DeviceExtension->ParallelPortNumber);
swprintf(LinkNameBuffer, L"\\DosDevices\\LPT%lu", DeviceExtension->LptPort);
swprintf(LptPortBuffer, L"LPT%lu", DeviceExtension->LptPort);
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
DeviceExtension->Common.PnpState = dsStarted;
/* We don't really care if the call succeeded or not... */
return STATUS_SUCCESS;
}
static
NTSTATUS
FdoCreateRawParallelPdo(
IN PDEVICE_OBJECT DeviceObject)
{
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
PPDO_DEVICE_EXTENSION PdoDeviceExtension = NULL;
PDEVICE_OBJECT Pdo = NULL;
WCHAR DeviceNameBuffer[32];
WCHAR LinkNameBuffer[32];
WCHAR LptPortBuffer[32];
UNICODE_STRING DeviceName;
UNICODE_STRING LinkName;
UNICODE_STRING LptPort;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE KeyHandle;
NTSTATUS Status;
DPRINT("FdoCreateRawParallelPdo()\n");
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* Create new device object */
swprintf(DeviceNameBuffer,
L"\\Device\\Parallel%lu",
FdoDeviceExtension->PortNumber);
RtlInitUnicodeString(&DeviceName,
DeviceNameBuffer);
Status = IoCreateDevice(DeviceObject->DriverObject,
sizeof(PDO_DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_CONTROLLER,
0,
FALSE,
&Pdo);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoCreateDevice() failed with status 0x%08x\n", Status);
goto done;
}
Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
Pdo->Flags |= DO_POWER_PAGABLE;
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
PdoDeviceExtension->Common.IsFDO = FALSE;
PdoDeviceExtension->Common.PnpState = dsStopped;
Pdo->StackSize = DeviceObject->StackSize + 1;
FdoDeviceExtension->AttachedRawPdo = Pdo;
PdoDeviceExtension->AttachedFdo = DeviceObject;
PdoDeviceExtension->PortNumber = FdoDeviceExtension->PortNumber;
PdoDeviceExtension->LptPort = PdoDeviceExtension->PortNumber + 1;
/* Create link \DosDevices\LPTX -> \Device\ParallelY */
swprintf(LinkNameBuffer, L"\\DosDevices\\LPT%lu", PdoDeviceExtension->LptPort);
RtlInitUnicodeString(&LinkName, LinkNameBuffer);
RtlInitUnicodeString(&LptPort, LptPortBuffer);
Status = IoCreateSymbolicLink(&LinkName,
&DeviceName);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoCreateSymbolicLink() failed with status 0x%08x\n", Status);
return Status;
goto done;
}
swprintf(LptPortBuffer, L"LPT%lu", PdoDeviceExtension->LptPort);
RtlInitUnicodeString(&LptPort, LptPortBuffer);
/* Write an entry value under HKLM\HARDWARE\DeviceMap\PARALLEL PORTS. */
/* This step is not mandatory, so do not exit in case of error. */
@ -292,10 +315,66 @@ FdoStartDevice(IN PDEVICE_OBJECT DeviceObject,
ZwClose(KeyHandle);
}
DeviceExtension->Common.PnpState = dsStarted;
Pdo->Flags |= DO_BUFFERED_IO;
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
done:
if (!NT_SUCCESS(Status))
{
if (Pdo)
{
ASSERT(PdoDeviceExtension);
IoDeleteDevice(Pdo);
}
}
return Status;
}
/* We don't really care if the call succeeded or not... */
static
NTSTATUS
FdoQueryBusRelations(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
PDEVICE_RELATIONS DeviceRelations;
ULONG Size;
ULONG i;
ULONG PdoCount = 0;
NTSTATUS Status;
UNREFERENCED_PARAMETER(IrpSp);
DPRINT("FdoQueryBusRelations()\n");
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->Common.IsFDO);
/* TODO: Enumerate parallel devices and create their PDOs */
Status = FdoCreateRawParallelPdo(DeviceObject);
if (!NT_SUCCESS(Status))
return Status;
PdoCount++;
/* Allocate a buffer for the device relations */
Size = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (PdoCount - 1);
DeviceRelations = ExAllocatePoolWithTag(PagedPool, Size, PARPORT_TAG);
if (DeviceRelations == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
/* Fill the buffer */
i = 0;
ObReferenceObject(DeviceExtension->AttachedRawPdo);
DeviceRelations->Objects[i] = DeviceExtension->AttachedRawPdo;
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
DPRINT("Done\n");
return STATUS_SUCCESS;
}
@ -345,7 +424,7 @@ FdoCreate(IN PDEVICE_OBJECT DeviceObject,
goto done;
}
DPRINT("Open LPT%lu: successful\n", DeviceExtension->LptPort);
DPRINT("Open parallel port %lu: successful\n", DeviceExtension->PortNumber);
DeviceExtension->OpenCount++;
done:
@ -397,68 +476,11 @@ NTAPI
FdoWrite(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IoStack;
PUCHAR Buffer;
ULONG i;
UCHAR PortStatus;
ULONG ulCount;
DPRINT("FdoWrite()\n");
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
IoStack = IoGetCurrentIrpStackLocation(Irp);
Buffer = GetUserBuffer(Irp);
DPRINT("Length: %lu\n", IoStack->Parameters.Write.Length);
DPRINT("Buffer: %p\n", Buffer);
if (Buffer != NULL)
{
DPRINT("%s\n", Buffer);
}
for (i = 0; i < IoStack->Parameters.Write.Length; i++)
{
DPRINT("%lu: %c\n", i, Buffer[i]);
ulCount = 0;
do
{
KeStallExecutionProcessor(10);
PortStatus = READ_PORT_UCHAR((PUCHAR)(DeviceExtension->BaseAddress + 1));
ulCount++;
}
while (ulCount < 500000 && !(PortStatus & LP_PBUSY));
if (ulCount == 500000)
{
DPRINT1("Timed out\n");
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_TIMEOUT;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_TIMEOUT;
}
/* Write character */
WRITE_PORT_UCHAR((PUCHAR)DeviceExtension->BaseAddress, Buffer[i]);
KeStallExecutionProcessor(10);
WRITE_PORT_UCHAR((PUCHAR)(DeviceExtension->BaseAddress + 2), (LP_PSELECP | LP_PINITP | LP_PSTROBE));
KeStallExecutionProcessor(10);
WRITE_PORT_UCHAR((PUCHAR)(DeviceExtension->BaseAddress + 2), (LP_PSELECP | LP_PINITP));
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
@ -524,26 +546,29 @@ FdoPnp(IN PDEVICE_OBJECT DeviceObject,
switch (Stack->Parameters.QueryDeviceRelations.Type)
{
case BusRelations:
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
Status = FdoQueryBusRelations(DeviceObject, Irp, Stack);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
case RemovalRelations:
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
default:
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
Stack->Parameters.QueryDeviceRelations.Type);
return ForwardIrpAndForget(DeviceObject, Irp);
}
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* (optional) 0xd */
DPRINT1("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
return ForwardIrpAndForget(DeviceObject, Irp);
default:
DPRINT1("Unknown minor function 0x%x\n", MinorFunction);
DPRINT("Unknown minor function 0x%x\n", MinorFunction);
return ForwardIrpAndForget(DeviceObject, Irp);
}

View file

@ -0,0 +1,41 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: Parallel Port Function Driver
* FILE: drivers/parallel/parport/hardware.h
* PURPOSE: Hardware definitions
*/
#ifndef _HARDWARE_H_
#define _HARDWARE_H_
/*
* The following constants describe the various signals of the printer port
* hardware. Note that the hardware inverts some signals and that some
* signals are active low. An example is LP_STROBE, which must be programmed
* with 1 for being active and 0 for being inactive, because the strobe signal
* gets inverted, but it is also active low.
*/
/*
* bit defines for 8255 status port
* base + 1
* accessed with LP_S(minor), which gets the byte...
*/
#define LP_PBUSY 0x80 /* inverted input, active high */
#define LP_PACK 0x40 /* unchanged input, active low */
#define LP_POUTPA 0x20 /* unchanged input, active high */
#define LP_PSELECD 0x10 /* unchanged input, active high */
#define LP_PERRORP 0x08 /* unchanged input, active low */
/*
* defines for 8255 control port
* base + 2
* accessed with LP_C(minor)
*/
#define LP_PINTEN 0x10
#define LP_PSELECP 0x08 /* inverted output, active low */
#define LP_PINITP 0x04 /* unchanged output, active low */
#define LP_PAUTOLF 0x02 /* inverted output, active low */
#define LP_PSTROBE 0x01 /* inverted output, active low */
#endif /* _HARDWARE_H_ */

View file

@ -61,7 +61,10 @@ ForwardIrpAndForget(IN PDEVICE_OBJECT DeviceObject,
{
PDEVICE_OBJECT LowerDevice;
LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
if (((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Common.IsFDO)
LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
else
LowerDevice = ((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedFdo;
ASSERT(LowerDevice);
IoSkipCurrentIrpStackLocation(Irp);

View file

@ -1,6 +1,7 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: Parallel Port Function Driver
* FILE: drivers/parallel/parport/parport.h
* PURPOSE: Parport driver header
*/
@ -12,6 +13,8 @@
#include <ntddpar.h>
#include <stdio.h>
#include "hardware.h"
//#define NDEBUG
#include <debug.h>
@ -37,9 +40,11 @@ typedef struct _FDO_DEVICE_EXTENSION
PDEVICE_OBJECT Pdo;
PDEVICE_OBJECT LowerDevice;
ULONG ParallelPortNumber;
PDEVICE_OBJECT AttachedRawPdo;
PDEVICE_OBJECT AttachedPdo[2];
ULONG PortNumber;
ULONG LptPort;
ULONG OpenCount;
ULONG BaseAddress;
@ -51,8 +56,16 @@ typedef struct _PDO_DEVICE_EXTENSION
{
COMMON_DEVICE_EXTENSION Common;
PDEVICE_OBJECT AttachedFdo;
ULONG PortNumber;
ULONG LptPort;
ULONG OpenCount;
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
#define PARPORT_TAG 'trpP'
/* fdo.c */

View file

@ -14,12 +14,31 @@ NTAPI
PdoCreate(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION Stack;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("PdoCreate()\n");
Stack = IoGetCurrentIrpStackLocation(Irp);
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
if (Stack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
{
DPRINT1("Not a directory\n");
Status = STATUS_NOT_A_DIRECTORY;
goto done;
}
DPRINT("Open LPT%lu: successful\n", DeviceExtension->LptPort);
DeviceExtension->OpenCount++;
done:
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
return Status;
}
@ -28,11 +47,17 @@ NTAPI
PdoClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PPDO_DEVICE_EXTENSION pDeviceExtension;
DPRINT("PdoClose()\n");
pDeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
pDeviceExtension->OpenCount--;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
@ -56,8 +81,67 @@ NTAPI
PdoWrite(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
PIO_STACK_LOCATION IoStack;
PUCHAR Buffer;
ULONG i;
UCHAR PortStatus;
ULONG ulCount;
DPRINT("PdoWrite()\n");
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)PdoDeviceExtension->AttachedFdo->DeviceExtension;
IoStack = IoGetCurrentIrpStackLocation(Irp);
Buffer = GetUserBuffer(Irp);
DPRINT("Length: %lu\n", IoStack->Parameters.Write.Length);
DPRINT("Buffer: %p\n", Buffer);
if (Buffer != NULL)
{
DPRINT("%s\n", Buffer);
}
for (i = 0; i < IoStack->Parameters.Write.Length; i++)
{
DPRINT("%lu: %c\n", i, Buffer[i]);
ulCount = 0;
do
{
KeStallExecutionProcessor(10);
PortStatus = READ_PORT_UCHAR((PUCHAR)(FdoDeviceExtension->BaseAddress + 1));
ulCount++;
}
while (ulCount < 500000 && !(PortStatus & LP_PBUSY));
if (ulCount == 500000)
{
DPRINT("Timed out\n");
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_TIMEOUT;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_TIMEOUT;
}
/* Write character */
WRITE_PORT_UCHAR((PUCHAR)FdoDeviceExtension->BaseAddress, Buffer[i]);
KeStallExecutionProcessor(10);
WRITE_PORT_UCHAR((PUCHAR)(FdoDeviceExtension->BaseAddress + 2), (LP_PSELECP | LP_PINITP | LP_PSTROBE));
KeStallExecutionProcessor(10);
WRITE_PORT_UCHAR((PUCHAR)(FdoDeviceExtension->BaseAddress + 2), (LP_PSELECP | LP_PINITP));
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);