|
|
/*++
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; }
|