438 lines
12 KiB
C
438 lines
12 KiB
C
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
parclass.h
|
|
|
|
Abstract:
|
|
|
|
Type definitions and data for the parallel port driver.
|
|
|
|
Author:
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "parallel.h"
|
|
|
|
#if DBG
|
|
#define PARALWAYS ((ULONG)0x00000000)
|
|
#define PARCONFIG ((ULONG)0x00000001)
|
|
#define PARUNLOAD ((ULONG)0x00000002)
|
|
#define PARINITDEV ((ULONG)0x00000004)
|
|
#define PARIRPPATH ((ULONG)0x00000008)
|
|
#define PARSTARTER ((ULONG)0x00000010)
|
|
#define PARPUSHER ((ULONG)0x00000020)
|
|
#define PARERRORS ((ULONG)0x00000040)
|
|
#define PARTHREAD ((ULONG)0x00000080)
|
|
#define PARDEFERED ((ULONG)0x00000100)
|
|
|
|
extern ULONG ParDebugLevel;
|
|
#define ParDump(LEVEL,STRING) \
|
|
do { \
|
|
ULONG _level = (LEVEL); \
|
|
if ((_level == PARALWAYS)||(ParDebugLevel & _level)) { \
|
|
DbgPrint STRING; \
|
|
} \
|
|
} while (0)
|
|
#else
|
|
#define ParDump(LEVEL,STRING) do {NOTHING;} while (0)
|
|
#endif
|
|
|
|
//
|
|
// For the above directory, the serial port will
|
|
// use the following name as the suffix of the serial
|
|
// ports for that directory. It will also append
|
|
// a number onto the end of the name. That number
|
|
// will start at 1.
|
|
//
|
|
#define DEFAULT_PARALLEL_NAME L"LPT"
|
|
|
|
//
|
|
// This is the parallel class name.
|
|
//
|
|
#define DEFAULT_NT_SUFFIX L"Parallel"
|
|
|
|
|
|
#define PARALLEL_DATA_OFFSET 0
|
|
#define PARALLEL_STATUS_OFFSET 1
|
|
#define PARALLEL_CONTROL_OFFSET 2
|
|
#define PARALLEL_REGISTER_SPAN 3
|
|
|
|
typedef struct _DEVICE_EXTENSION {
|
|
|
|
//
|
|
// Points to the device object that contains
|
|
// this device extension.
|
|
//
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
//
|
|
// Points to the port device object that this class device is
|
|
// connected to.
|
|
//
|
|
PDEVICE_OBJECT PortDeviceObject;
|
|
|
|
//
|
|
// Keep a reference to the port device.
|
|
//
|
|
PFILE_OBJECT PortDeviceFileObject;
|
|
|
|
//
|
|
// Queue of irps waiting to be processed.
|
|
//
|
|
LIST_ENTRY WorkQueue;
|
|
|
|
//
|
|
// Handle of the thread doing all the real work.
|
|
//
|
|
PVOID ThreadObjectPointer;
|
|
|
|
KSEMAPHORE RequestSemaphore;
|
|
|
|
//
|
|
// Pointer to the current irp that the thread is working on.
|
|
//
|
|
PIRP CurrentOpIrp;
|
|
|
|
//
|
|
// This holds the current value to initialize a countdown
|
|
// to when an operation starts.
|
|
//
|
|
ULONG TimerStart;
|
|
|
|
//
|
|
// This holds the result of the get parallel port info
|
|
// request to the port driver.
|
|
//
|
|
PHYSICAL_ADDRESS OriginalController;
|
|
PUCHAR Controller;
|
|
ULONG SpanOfController;
|
|
PPARALLEL_FREE_ROUTINE FreePort;
|
|
PPARALLEL_QUERY_WAITERS_ROUTINE QueryNumWaiters;
|
|
PVOID PortContext;
|
|
|
|
//
|
|
// This parameter specifies the number of microseconds to
|
|
// wait after strobing a byte before checking the BUSY line.
|
|
//
|
|
ULONG BusyDelay;
|
|
|
|
//
|
|
// Indicates if the BusyDelay parameter has been computed yet.
|
|
//
|
|
BOOLEAN BusyDelayDetermined;
|
|
|
|
//
|
|
// This specifies whether or not to use processor independant
|
|
// write loop.
|
|
//
|
|
BOOLEAN UsePIWriteLoop;
|
|
|
|
//
|
|
// Set to false whenever we think that the device needs to be
|
|
// initilized.
|
|
//
|
|
BOOLEAN Initialized;
|
|
|
|
//
|
|
// Set to true before the deferred initialization routine is run
|
|
// and false once it has completed. Used to synchronize the deferred
|
|
// initialization worker thread and the parallel port thread
|
|
//
|
|
|
|
BOOLEAN Initializing;
|
|
|
|
//
|
|
// Holds the work item used to defer printer initialization
|
|
//
|
|
|
|
PWORK_QUEUE_ITEM DeferredWorkItem;
|
|
|
|
BOOLEAN TimeToTerminateThread;
|
|
|
|
//
|
|
// Records whether we actually created the symbolic link name
|
|
// at driver load time. If we didn't create it, we won't try
|
|
// to distroy it when we unload.
|
|
//
|
|
BOOLEAN CreatedSymbolicLink;
|
|
|
|
//
|
|
// This points to the symbolic link name that was
|
|
// linked to the actual nt device name.
|
|
//
|
|
UNICODE_STRING SymbolicLinkName;
|
|
|
|
//
|
|
// If the registry entry by the same name is set, run the parallel
|
|
// thread at the priority we used for NT 3.5 - this solves some
|
|
// cases where a dos app spinning for input in the foreground is
|
|
// starving the parallel thread
|
|
//
|
|
|
|
BOOLEAN UseNT35Priority;
|
|
|
|
//
|
|
// Seconds to wait for the device to respond to an initialization request.
|
|
// Note that if no printer is attached, we will spin for the maximum amount
|
|
// of time.
|
|
// Default is 15 seconds - value is overridden by registry entry of the
|
|
// same name.
|
|
//
|
|
|
|
ULONG InitializationTimeout;
|
|
|
|
//
|
|
// Miscelaneous contstants that are cheaper to put here than
|
|
// to put them in bss.
|
|
//
|
|
LARGE_INTEGER AbsoluteOneSecond;
|
|
LARGE_INTEGER OneSecond;
|
|
|
|
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
|
|
|
//
|
|
// Bit Definitions in the status register.
|
|
//
|
|
|
|
#define PAR_STATUS_NOT_ERROR 0x08 //not error on device
|
|
#define PAR_STATUS_SLCT 0x10 //device is selected (on-line)
|
|
#define PAR_STATUS_PE 0x20 //paper empty
|
|
#define PAR_STATUS_NOT_ACK 0x40 //not acknowledge (data transfer was not ok)
|
|
#define PAR_STATUS_NOT_BUSY 0x80 //operation in progress
|
|
|
|
//
|
|
// Bit Definitions in the control register.
|
|
//
|
|
|
|
#define PAR_CONTROL_STROBE 0x01 //to read or write data
|
|
#define PAR_CONTROL_AUTOFD 0x02 //to autofeed continuous form paper
|
|
#define PAR_CONTROL_NOT_INIT 0x04 //begin an initialization routine
|
|
#define PAR_CONTROL_SLIN 0x08 //to select the device
|
|
#define PAR_CONTROL_IRQ_ENB 0x10 //to enable interrupts
|
|
#define PAR_CONTROL_DIR 0x20 //direction = read
|
|
#define PAR_CONTROL_WR_CONTROL 0xc0 //the 2 highest bits of the control
|
|
// register must be 1
|
|
//
|
|
// More bit definitions.
|
|
//
|
|
|
|
#define DATA_OFFSET 0
|
|
#define DSR_OFFSET 1
|
|
#define DCR_OFFSET 2
|
|
|
|
//
|
|
// Bit definitions for the DSR.
|
|
//
|
|
|
|
#define DSR_NOT_BUSY 0x80
|
|
#define DSR_NOT_ACK 0x40
|
|
#define DSR_PERROR 0x20
|
|
#define DSR_SELECT 0x10
|
|
#define DSR_NOT_FAULT 0x08
|
|
|
|
//
|
|
// More bit definitions for the DSR.
|
|
//
|
|
|
|
#define DSR_NOT_PTR_BUSY 0x80
|
|
#define DSR_NOT_PERIPH_ACK 0x80
|
|
#define DSR_WAIT 0x80
|
|
#define DSR_PTR_CLK 0x40
|
|
#define DSR_PERIPH_CLK 0x40
|
|
#define DSR_INTR 0x40
|
|
#define DSR_ACK_DATA_REQ 0x20
|
|
#define DSR_NOT_ACK_REVERSE 0x20
|
|
#define DSR_XFLAG 0x10
|
|
#define DSR_NOT_DATA_AVAIL 0x08
|
|
#define DSR_NOT_PERIPH_REQUEST 0x08
|
|
|
|
//
|
|
// Bit definitions for the DCR.
|
|
//
|
|
|
|
#define DCR_RESERVED 0xC0
|
|
#define DCR_DIRECTION 0x20
|
|
#define DCR_ACKINT_ENABLED 0x10
|
|
#define DCR_SELECT_IN 0x08
|
|
#define DCR_NOT_INIT 0x04
|
|
#define DCR_AUTOFEED 0x02
|
|
#define DCR_STROBE 0x01
|
|
|
|
//
|
|
// More bit definitions for the DCR.
|
|
//
|
|
|
|
#define DCR_NOT_1284_ACTIVE 0x08
|
|
#define DCR_ASTRB 0x08
|
|
#define DCR_NOT_REVERSE_REQUEST 0x04
|
|
#define DCR_NOT_HOST_BUSY 0x02
|
|
#define DCR_NOT_HOST_ACK 0x02
|
|
#define DCR_DSTRB 0x02
|
|
#define DCR_NOT_HOST_CLK 0x01
|
|
#define DCR_WRITE 0x01
|
|
|
|
#define DCR_NEUTRAL (DCR_RESERVED | DCR_SELECT_IN | DCR_NOT_INIT)
|
|
|
|
//
|
|
// not error, not busy, selected.
|
|
//
|
|
#define PAR_ONLINE(Status) ( \
|
|
(Status & PAR_STATUS_NOT_ERROR) && \
|
|
(Status & PAR_STATUS_NOT_BUSY) && \
|
|
((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
|
|
(Status & PAR_STATUS_SLCT) )
|
|
|
|
|
|
//VOID StoreData(
|
|
// IN PUCHAR RegisterBase,
|
|
// IN UCHAR DataByte
|
|
// )
|
|
//Data must be on line before Strobe = 1;
|
|
// Strobe = 1, DIR = 0
|
|
//Strobe = 0
|
|
//
|
|
// We change the port direction to output (and make sure stobe is low).
|
|
//
|
|
// Note that the data must be available at the port for at least
|
|
// .5 microseconds before and after you strobe, and that the strobe
|
|
// must be active for at least 500 nano seconds. We are going
|
|
// to end up stalling for twice as much time as we need to, but, there
|
|
// isn't much we can do about that.
|
|
//
|
|
// We put the data into the port and wait for 1 micro.
|
|
// We strobe the line for at least 1 micro
|
|
// We lower the strobe and again delay for 1 micro
|
|
// We then revert to the original port direction.
|
|
//
|
|
// Thanks to Olivetti for advice.
|
|
//
|
|
|
|
#define StoreData(RegisterBase,DataByte) \
|
|
{ \
|
|
PUCHAR _Address = RegisterBase; \
|
|
UCHAR _Control; \
|
|
_Control = GetControl(_Address); \
|
|
ASSERT(!(_Control & PAR_CONTROL_STROBE)); \
|
|
StoreControl( \
|
|
_Address, \
|
|
(UCHAR)(_Control & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR)) \
|
|
); \
|
|
WRITE_PORT_UCHAR( \
|
|
_Address+PARALLEL_DATA_OFFSET, \
|
|
(UCHAR)DataByte \
|
|
); \
|
|
KeStallExecutionProcessor((ULONG)1); \
|
|
StoreControl( \
|
|
_Address, \
|
|
(UCHAR)((_Control | PAR_CONTROL_STROBE) & ~PAR_CONTROL_DIR) \
|
|
); \
|
|
KeStallExecutionProcessor((ULONG)1); \
|
|
StoreControl( \
|
|
_Address, \
|
|
(UCHAR)(_Control & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR)) \
|
|
); \
|
|
KeStallExecutionProcessor((ULONG)1); \
|
|
StoreControl( \
|
|
_Address, \
|
|
(UCHAR)_Control \
|
|
); \
|
|
}
|
|
|
|
//UCHAR
|
|
//GetControl(
|
|
// IN PUCHAR RegisterBase
|
|
// )
|
|
#define GetControl(RegisterBase) \
|
|
(READ_PORT_UCHAR((RegisterBase)+PARALLEL_CONTROL_OFFSET))
|
|
|
|
|
|
//VOID
|
|
//StoreControl(
|
|
// IN PUCHAR RegisterBase,
|
|
// IN UCHAR ControlByte
|
|
// )
|
|
#define StoreControl(RegisterBase,ControlByte) \
|
|
{ \
|
|
WRITE_PORT_UCHAR( \
|
|
(RegisterBase)+PARALLEL_CONTROL_OFFSET, \
|
|
(UCHAR)ControlByte \
|
|
); \
|
|
}
|
|
|
|
|
|
//UCHAR
|
|
//GetStatus(
|
|
// IN PUCHAR RegisterBase
|
|
// )
|
|
|
|
#define GetStatus(RegisterBase) \
|
|
(READ_PORT_UCHAR((RegisterBase)+PARALLEL_STATUS_OFFSET))
|
|
|
|
ULONG
|
|
ParWriteLoop(
|
|
IN PUCHAR Controller,
|
|
IN PUCHAR WriteBuffer,
|
|
IN ULONG NumBytesToWrite
|
|
);
|
|
|
|
ULONG
|
|
ParWriteLoopPI(
|
|
IN PUCHAR Controller,
|
|
IN PUCHAR WriteBuffer,
|
|
IN ULONG NumBytesToWrite,
|
|
IN ULONG BusyDelay
|
|
);
|
|
|
|
NTSTATUS
|
|
ParCreateOpen(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ParClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ParCleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ParReadWrite(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ParDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ParQueryInformationFile(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ParSetInformationFile(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
ParUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|