windows-nt/Source/XPSP1/NT/drivers/parallel/parclass/port.c

462 lines
12 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}