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;
|
||
}
|