462 lines
12 KiB
C
462 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1993 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
port.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the code to acquire and release the port
|
|||
|
from the port driver parport.sys.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Anthony V. Ercolano 1-Aug-1992
|
|||
|
Norbert P. Kusters 22-Oct-1993
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History :
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ParGetPortInfoFromPortDevice(
|
|||
|
IN OUT PDEVICE_EXTENSION Extension
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
ParReleasePortInfoToPortDevice(
|
|||
|
IN PDEVICE_EXTENSION Extension
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
ParFreePort(
|
|||
|
IN PDEVICE_EXTENSION Extension
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ParAllocPortCompletionRoutine(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
ParAllocPort(
|
|||
|
IN PDEVICE_EXTENSION Extension
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ParGetPortInfoFromPortDevice(
|
|||
|
IN OUT PDEVICE_EXTENSION Extension
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will request the port information from the port driver
|
|||
|
and fill it in the device extension.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - Success.
|
|||
|
!STATUS_SUCCESS - Failure.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KEVENT Event;
|
|||
|
PIRP Irp;
|
|||
|
PARALLEL_PORT_INFORMATION PortInfo;
|
|||
|
PARALLEL_PNP_INFORMATION PnpInfo;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Get Parallel Port Info
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(Extension->PortDeviceObject != NULL);
|
|||
|
|
|||
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO,
|
|||
|
Extension->PortDeviceObject,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&PortInfo,
|
|||
|
sizeof(PARALLEL_PORT_INFORMATION),
|
|||
|
TRUE,
|
|||
|
&Event,
|
|||
|
&IoStatus);
|
|||
|
|
|||
|
ASSERT(Irp->StackCount > 0);
|
|||
|
|
|||
|
if (!Irp) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
Status = ParCallDriver(Extension->PortDeviceObject, Irp);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Status = IoStatus.Status;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
Extension->OriginalController = PortInfo.OriginalController;
|
|||
|
Extension->Controller = PortInfo.Controller;
|
|||
|
Extension->SpanOfController = PortInfo.SpanOfController;
|
|||
|
Extension->TryAllocatePort = PortInfo.TryAllocatePort;
|
|||
|
Extension->FreePort = PortInfo.FreePort;
|
|||
|
Extension->QueryNumWaiters = PortInfo.QueryNumWaiters;
|
|||
|
Extension->PortContext = PortInfo.Context;
|
|||
|
|
|||
|
if (Extension->SpanOfController < PARALLEL_REGISTER_SPAN) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get Parallel Pnp Info
|
|||
|
//
|
|||
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO,
|
|||
|
Extension->PortDeviceObject,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&PnpInfo,
|
|||
|
sizeof(PARALLEL_PNP_INFORMATION),
|
|||
|
TRUE,
|
|||
|
&Event,
|
|||
|
&IoStatus);
|
|||
|
|
|||
|
if (!Irp) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
Status = ParCallDriver(Extension->PortDeviceObject, Irp);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Status = IoStatus.Status;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
Extension->EcrController = PnpInfo.EcpController;
|
|||
|
Extension->HardwareCapabilities = PnpInfo.HardwareCapabilities;
|
|||
|
Extension->TrySetChipMode = PnpInfo.TrySetChipMode;
|
|||
|
Extension->ClearChipMode = PnpInfo.ClearChipMode;
|
|||
|
Extension->TrySelectDevice = PnpInfo.TrySelectDevice;
|
|||
|
Extension->DeselectDevice = PnpInfo.DeselectDevice;
|
|||
|
Extension->FifoDepth = PnpInfo.FifoDepth;
|
|||
|
Extension->FifoWidth = PnpInfo.FifoWidth;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// get symbolic link name to use for this end of chain device
|
|||
|
// object from ParPort
|
|||
|
//
|
|||
|
// if anything goes wrong, simply leave Extension->SymbolicLinkName alone
|
|||
|
// as it was cleared to all zeros via an RtlZeroMemory in
|
|||
|
// ParPnpCreateDevice(...) in parpnp.c
|
|||
|
//
|
|||
|
|
|||
|
if( ( 0 == Extension->SymbolicLinkName.Length ) && PnpInfo.PortName ) {
|
|||
|
//
|
|||
|
// If we have no SymbolicLinkName and we have a port name, use the port
|
|||
|
// name to initialize our symbolic link name in our device extension
|
|||
|
//
|
|||
|
UNICODE_STRING pathPrefix;
|
|||
|
UNICODE_STRING portName;
|
|||
|
ULONG length;
|
|||
|
PWSTR buffer;
|
|||
|
|
|||
|
RtlInitUnicodeString(&pathPrefix, (PWSTR)L"\\DosDevices\\");
|
|||
|
RtlInitUnicodeString(&portName, PnpInfo.PortName);
|
|||
|
|
|||
|
length = pathPrefix.Length + portName.Length + sizeof(UNICODE_NULL);
|
|||
|
buffer = ExAllocatePool(PagedPool, length);
|
|||
|
|
|||
|
if(buffer) {
|
|||
|
Extension->SymbolicLinkName.Buffer = buffer;
|
|||
|
Extension->SymbolicLinkName.Length = 0;
|
|||
|
Extension->SymbolicLinkName.MaximumLength = (USHORT)length;
|
|||
|
RtlAppendUnicodeStringToString(&Extension->SymbolicLinkName, &pathPrefix);
|
|||
|
RtlAppendUnicodeStringToString(&Extension->SymbolicLinkName, &portName);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ParDumpV( ("ParGetPortInfoFromPortDevice(...):\n") );
|
|||
|
ParDumpV( (" - ClassName= %wZ , SymbolicLinkName= %wZ , PortDeviceObject= %08x\n",
|
|||
|
&Extension->ClassName, &Extension->SymbolicLinkName, Extension->PortDeviceObject) );
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ParReleasePortInfoToPortDevice(
|
|||
|
IN PDEVICE_EXTENSION Extension
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will release the port information back to the port driver.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// ParPort treats this as a NO-OP in Win2K, so don't bother sending the IOCTL.
|
|||
|
//
|
|||
|
// In follow-on to Win2K parport may use this to page the entire driver as
|
|||
|
// it was originally intended, so we'll turn this back on then.
|
|||
|
//
|
|||
|
|
|||
|
return;
|
|||
|
#if 0
|
|||
|
KEVENT Event;
|
|||
|
PIRP Irp;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_RELEASE_PARALLEL_PORT_INFO,
|
|||
|
Extension->PortDeviceObject,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
TRUE,
|
|||
|
&Event,
|
|||
|
&IoStatus);
|
|||
|
|
|||
|
if (!Irp) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Status = ParCallDriver(Extension->PortDeviceObject, Irp);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ParFreePort(
|
|||
|
IN PDEVICE_EXTENSION Extension
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine calls the internal free port ioctl. This routine
|
|||
|
should be called before completing an IRP that has allocated
|
|||
|
the port.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
// Don't allow multiple releases
|
|||
|
|
|||
|
if (Extension->bAllocated) {
|
|||
|
ParDump2(PARALLOCFREEPORT, ("port::ParFreePort: %x - calling ParPort's FreePort function\n", Extension->Controller) );
|
|||
|
Extension->FreePort(Extension->PortContext);
|
|||
|
} else {
|
|||
|
ParDump2(PARALLOCFREEPORT, ("port::ParFreePort: %x - we don't have the Port!!! (!Ext->bAllocated)\n", Extension->Controller) );
|
|||
|
}
|
|||
|
|
|||
|
Extension->bAllocated = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ParAllocPortCompletionRoutine(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Event
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the completion routine for a port allocate request.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Supplies the device object.
|
|||
|
Irp - Supplies the I/O request packet.
|
|||
|
Context - Supplies the notification event.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_MORE_PROCESSING_REQUIRED - The Irp still requires processing.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UNREFERENCED_PARAMETER( Irp );
|
|||
|
UNREFERENCED_PARAMETER( DeviceObject );
|
|||
|
|
|||
|
KeSetEvent((PKEVENT) Event, 0, FALSE);
|
|||
|
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
ParAllocPort(
|
|||
|
IN PDEVICE_EXTENSION Extension
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine takes the given Irp and sends it down as a port allocate
|
|||
|
request. When this request completes, the Irp will be queued for
|
|||
|
processing.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE - The port was not successfully allocated.
|
|||
|
TRUE - The port was successfully allocated.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION NextSp;
|
|||
|
KEVENT Event;
|
|||
|
PIRP Irp;
|
|||
|
BOOLEAN bAllocated;
|
|||
|
NTSTATUS Status;
|
|||
|
LARGE_INTEGER Timeout;
|
|||
|
/*
|
|||
|
ParDump(PARDUMP_VERBOSE_MAX,
|
|||
|
("PARALLEL: "
|
|||
|
"ParAllocPort(...): %wZ\n",
|
|||
|
&Extension->SymbolicLinkName) );
|
|||
|
|
|||
|
// Don't allow multiple allocations
|
|||
|
if (Extension->bAllocated) {
|
|||
|
ParDump(PARDUMP_VERBOSE_MAX,
|
|||
|
("PARALLEL: "
|
|||
|
"ParAllocPort(...): %wZ\n",
|
|||
|
&Extension->SymbolicLinkName) );
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
*/
|
|||
|
ParDump2(PARALLOCFREEPORT,
|
|||
|
("ParAllocPort: Enter %x\n", Extension->Controller) );
|
|||
|
|
|||
|
// Don't allow multiple allocations
|
|||
|
if (Extension->bAllocated) {
|
|||
|
ParDump2(PARALLOCFREEPORT,
|
|||
|
("ParAllocPort: %x Already allocated\n", Extension->Controller) );
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
Irp = Extension->CurrentOpIrp;
|
|||
|
|
|||
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
NextSp = IoGetNextIrpStackLocation(Irp);
|
|||
|
NextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|||
|
NextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE;
|
|||
|
|
|||
|
IoSetCompletionRoutine(Irp,
|
|||
|
ParAllocPortCompletionRoutine,
|
|||
|
&Event,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE);
|
|||
|
|
|||
|
ParCallDriver(Extension->PortDeviceObject, Irp);
|
|||
|
|
|||
|
Timeout.QuadPart = -((LONGLONG) Extension->TimerStart*10*1000*1000);
|
|||
|
|
|||
|
Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout);
|
|||
|
|
|||
|
if (Status == STATUS_TIMEOUT) {
|
|||
|
|
|||
|
IoCancelIrp(Irp);
|
|||
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|||
|
}
|
|||
|
|
|||
|
bAllocated = (BOOLEAN)NT_SUCCESS(Irp->IoStatus.Status);
|
|||
|
|
|||
|
Extension->bAllocated = bAllocated;
|
|||
|
|
|||
|
if (!bAllocated) {
|
|||
|
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
|
|||
|
ParDump2(PARALLOCFREEPORT,
|
|||
|
("ParAllocPort: %x FAILED - DEVICE_BUSY\n", Extension->Controller) );
|
|||
|
/*
|
|||
|
ParDump(PARDUMP_VERBOSE_MAX,
|
|||
|
("PARALLEL: "
|
|||
|
"ParAllocPort(...): %wZ FAILED - DEVICE_BUSY\n",
|
|||
|
&Extension->SymbolicLinkName) );
|
|||
|
*/
|
|||
|
}
|
|||
|
|
|||
|
return bAllocated;
|
|||
|
}
|