You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
785 lines
22 KiB
785 lines
22 KiB
/*--------------------------------------------------------------------------
|
|
*
|
|
* Copyright (C) Cyclades Corporation, 1996-2001.
|
|
* All rights reserved.
|
|
*
|
|
* Cyclom-Y Port Driver
|
|
*
|
|
* This file: cyyopcl.c
|
|
*
|
|
* Description: This module contains the code related to opening,
|
|
* closing and cleaning up in the Cyclom-Y Port driver.
|
|
*
|
|
* Notes: This code supports Windows 2000 and Windows XP,
|
|
* x86 and IA64 processors.
|
|
*
|
|
* Complies with Cyclades SW Coding Standard rev 1.3.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*-------------------------------------------------------------------------
|
|
*
|
|
* Change History
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
BOOLEAN
|
|
CyyMarkOpen(
|
|
IN PVOID Context
|
|
);
|
|
|
|
BOOLEAN
|
|
CyyNullSynch(
|
|
IN PVOID Context
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGESER,CyyGetCharTime)
|
|
#pragma alloc_text(PAGESER,CyyMarkClose)
|
|
#pragma alloc_text(PAGESER,CyyCleanup)
|
|
#pragma alloc_text(PAGESER,CyyClose)
|
|
#pragma alloc_text(PAGESER,CyyMarkClose)
|
|
#pragma alloc_text(PAGESER,CyyMarkOpen)
|
|
|
|
//
|
|
// Always paged
|
|
//
|
|
|
|
#pragma alloc_text(PAGESRP0,CyyCreateOpen)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
BOOLEAN
|
|
CyyNullSynch(
|
|
IN PVOID Context
|
|
)
|
|
/*------------------------------------------------------------------------
|
|
Just a bogus little routine to synch with the ISR.
|
|
------------------------------------------------------------------------*/
|
|
{
|
|
UNREFERENCED_PARAMETER(Context);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CyyCreateOpen(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*--------------------------------------------------------------------------
|
|
CyyCreateOpen()
|
|
|
|
Description: We connect up to the interrupt for the create/open
|
|
and initialize the structures needed to maintain an open for a
|
|
device.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this device
|
|
Irp - Pointer to the IRP for the current request
|
|
|
|
Return Value: The function value is the final status of the call
|
|
--------------------------------------------------------------------------*/
|
|
{
|
|
PCYY_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
NTSTATUS localStatus;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (extension->PNPState != CYY_PNP_STARTED) {
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Lock out changes to PnP state until we have our open state decided
|
|
//
|
|
|
|
ExAcquireFastMutex(&extension->OpenMutex);
|
|
|
|
if ((localStatus = CyyIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
|
|
ExReleaseFastMutex(&extension->OpenMutex);
|
|
if(localStatus != STATUS_PENDING) {
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
}
|
|
return localStatus;
|
|
}
|
|
|
|
if (InterlockedIncrement(&extension->OpenCount) != 1) {
|
|
ExReleaseFastMutex(&extension->OpenMutex);
|
|
InterlockedDecrement(&extension->OpenCount);
|
|
Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
CyyDbgPrintEx(CYYIRPPATH, "Dispatch entry for: %x\n", Irp);
|
|
|
|
CyyDbgPrintEx(CYYDIAG3, "In CyyCreateOpen\n");
|
|
|
|
// Before we do anything, let's make sure they aren't trying
|
|
// to create a directory. This is a silly, but what's a driver to do!?
|
|
|
|
if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options &
|
|
FILE_DIRECTORY_FILE) {
|
|
ExReleaseFastMutex(&extension->OpenMutex);
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
InterlockedDecrement(&extension->OpenCount);
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_NOT_A_DIRECTORY;
|
|
}
|
|
|
|
// Create a buffer for the RX data when no reads are outstanding.
|
|
|
|
extension->InterruptReadBuffer = NULL;
|
|
extension->BufferSize = 0;
|
|
|
|
// Try to allocate large buffers, whether the system is MmLargeSystem,
|
|
// MmMediumSystem or MmSmallSystem.
|
|
|
|
extension->BufferSize = 4096;
|
|
extension->InterruptReadBuffer =
|
|
ExAllocatePool(NonPagedPool,extension->BufferSize);
|
|
if (!extension->InterruptReadBuffer) {
|
|
extension->BufferSize = 2048;
|
|
extension->InterruptReadBuffer =
|
|
ExAllocatePool(NonPagedPool,extension->BufferSize);
|
|
if (!extension->InterruptReadBuffer) {
|
|
extension->BufferSize = 1024;
|
|
extension->InterruptReadBuffer =
|
|
ExAllocatePool(NonPagedPool,extension->BufferSize);
|
|
if (!extension->InterruptReadBuffer) {
|
|
extension->BufferSize = 128;
|
|
extension->InterruptReadBuffer =
|
|
ExAllocatePool(NonPagedPool,extension->BufferSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
switch (MmQuerySystemSize()) {
|
|
case MmLargeSystem: {
|
|
extension->BufferSize = 4096;
|
|
extension->InterruptReadBuffer =
|
|
ExAllocatePool(NonPagedPool,extension->BufferSize);
|
|
if (extension->InterruptReadBuffer)
|
|
break;
|
|
}
|
|
default: {
|
|
extension->BufferSize = 1024;
|
|
extension->InterruptReadBuffer =
|
|
ExAllocatePool(NonPagedPool,extension->BufferSize);
|
|
if (extension->InterruptReadBuffer) break;
|
|
|
|
extension->BufferSize = 128;
|
|
extension->InterruptReadBuffer =
|
|
ExAllocatePool(NonPagedPool,extension->BufferSize);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!extension->InterruptReadBuffer) {
|
|
ExReleaseFastMutex(&extension->OpenMutex);
|
|
|
|
extension->BufferSize = 0;
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
InterlockedDecrement(&extension->OpenCount);
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Ok, it looks like we really are going to open. Lock down the
|
|
// driver.
|
|
//
|
|
CyyLockPagableSectionByHandle(CyyGlobals.PAGESER_Handle);
|
|
|
|
//
|
|
// Power up the stack
|
|
//
|
|
|
|
(void)CyyGotoPowerState(DeviceObject, extension, PowerDeviceD0);
|
|
|
|
//
|
|
// Not currently waiting for wake up
|
|
//
|
|
|
|
extension->SendWaitWake = FALSE;
|
|
|
|
|
|
// "flush" the read queue by initializing the count of characters.
|
|
|
|
extension->CharsInInterruptBuffer = 0;
|
|
extension->LastCharSlot = extension->InterruptReadBuffer +
|
|
(extension->BufferSize - 1);
|
|
extension->ReadBufferBase = extension->InterruptReadBuffer;
|
|
extension->CurrentCharSlot = extension->InterruptReadBuffer;
|
|
extension->FirstReadableChar = extension->InterruptReadBuffer;
|
|
extension->TotalCharsQueued = 0;
|
|
|
|
// set up the default xon/xoff limits.
|
|
|
|
extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
|
|
extension->HandFlow.XonLimit = extension->BufferSize >> 1;
|
|
|
|
extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit;
|
|
extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;
|
|
|
|
extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
|
|
(extension->BufferSize>>4));
|
|
|
|
//
|
|
// Mark the device as busy for WMI
|
|
//
|
|
|
|
extension->WmiCommData.IsBusy = TRUE;
|
|
|
|
extension->IrpMaskLocation = NULL;
|
|
extension->HistoryMask = 0;
|
|
extension->IsrWaitMask = 0;
|
|
|
|
|
|
#if !DBG
|
|
// Clear out the statistics.
|
|
|
|
KeSynchronizeExecution(extension->Interrupt,CyyClearStats,extension);
|
|
#endif
|
|
|
|
extension->EscapeChar = 0;
|
|
|
|
// Synchronize with the ISR and mark the device as open
|
|
KeSynchronizeExecution(extension->Interrupt,CyyMarkOpen,extension);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// We have been marked open, so now the PnP state can change
|
|
//
|
|
|
|
ExReleaseFastMutex(&extension->OpenMutex);
|
|
|
|
localStatus = Irp->IoStatus.Status;
|
|
Irp->IoStatus.Information=0L;
|
|
|
|
if (!NT_SUCCESS(localStatus)) {
|
|
if (extension->InterruptReadBuffer != NULL) {
|
|
ExFreePool(extension->InterruptReadBuffer);
|
|
extension->InterruptReadBuffer = NULL;
|
|
}
|
|
|
|
InterlockedDecrement(&extension->OpenCount);
|
|
}
|
|
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
return localStatus;
|
|
}
|
|
|
|
//TODO FANNY: DO WE NEED THIS?
|
|
#if 0
|
|
VOID
|
|
SerialDrainUART(IN PSERIAL_DEVICE_EXTENSION PDevExt,
|
|
IN PLARGE_INTEGER PDrainTime)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Wait until all characters have been emptied out of the hardware.
|
|
//
|
|
|
|
while ((READ_LINE_STATUS(PDevExt->Controller) &
|
|
(SERIAL_LSR_THRE | SERIAL_LSR_TEMT))
|
|
!= (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
|
|
|
|
KeDelayExecutionThread(KernelMode, FALSE, PDrainTime);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
CyyClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*--------------------------------------------------------------------------
|
|
CyyClose()
|
|
|
|
Description: We simply disconnect the interrupt for now.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this device
|
|
Irp - Pointer to the IRP for the current request
|
|
|
|
Return Value: The function value is the final status of the call
|
|
--------------------------------------------------------------------------*/
|
|
{
|
|
LARGE_INTEGER tenCharDelay;
|
|
LARGE_INTEGER charTime;
|
|
PCYY_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
ULONG i;
|
|
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Number of opens still active
|
|
//
|
|
|
|
LONG openCount;
|
|
|
|
//
|
|
// Number of DPC's still pending
|
|
//
|
|
|
|
ULONG pendingDPCs;
|
|
|
|
ULONG flushCount;
|
|
|
|
//
|
|
// Grab a mutex
|
|
//
|
|
|
|
ExAcquireFastMutex(&extension->CloseMutex);
|
|
|
|
|
|
//
|
|
// We succeed a close on a removing device
|
|
//
|
|
|
|
if ((status = CyyIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
|
|
CyyDbgPrintEx(DPFLTR_INFO_LEVEL, "Close prologue failed for: %x\n",
|
|
Irp);
|
|
if (status == STATUS_DELETE_PENDING) {
|
|
extension->BufferSize = 0;
|
|
ExFreePool(extension->InterruptReadBuffer);
|
|
extension->InterruptReadBuffer = NULL;
|
|
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (status != STATUS_PENDING) {
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
openCount = InterlockedDecrement(&extension->OpenCount);
|
|
ASSERT(openCount == 0);
|
|
}
|
|
ExReleaseFastMutex(&extension->CloseMutex);
|
|
return status;
|
|
}
|
|
|
|
ASSERT(extension->OpenCount >= 1);
|
|
|
|
if (extension->OpenCount < 1) {
|
|
CyyDbgPrintEx(DPFLTR_ERROR_LEVEL, "Close open count bad for: 0x%x\n",
|
|
Irp);
|
|
CyyDbgPrintEx(DPFLTR_ERROR_LEVEL, "Count: %x Addr: 0x%x\n",
|
|
extension->OpenCount, &extension->OpenCount);
|
|
ExReleaseFastMutex(&extension->CloseMutex);
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
CyyDbgPrintEx(CYYIRPPATH, "Dispatch entry for: %x\n", Irp);
|
|
CyyDbgPrintEx(CYYDIAG3, "In CyyClose\n");
|
|
|
|
charTime.QuadPart = -CyyGetCharTime(extension).QuadPart;
|
|
|
|
extension->DeviceIsOpened = FALSE;
|
|
|
|
// Turn break off in case it is on
|
|
|
|
//Call of CyyTurnOffBreak removed, because as DeviceIsOpened will be
|
|
//FALSE in the ISR, the Stop Break cannot be executed. Anyway, any
|
|
//char (other than Send Break) sent to the FIFO will stop the Break.
|
|
//KeSynchronizeExecution(extension->Interrupt,CyyTurnOffBreak,extension);
|
|
|
|
// Wait until all characters have been emptied out of the hardware.
|
|
|
|
for(i = 0 ; i < MAX_CHAR_FIFO ; i++) {
|
|
KeDelayExecutionThread(KernelMode,FALSE,&charTime);
|
|
}
|
|
|
|
// TODO FANNY: SHOULD WE CALL SerialMarkHardwareBroken()? SEE LATER...
|
|
|
|
// Synchronize with the ISR to let it know that interrupts are
|
|
// no longer important.
|
|
|
|
KeSynchronizeExecution(extension->Interrupt,CyyMarkClose,extension);
|
|
|
|
// If the driver has automatically transmitted an Xoff in
|
|
// the context of automatic receive flow control then we
|
|
// should transmit an Xon.
|
|
|
|
if (extension->RXHolding & CYY_RX_XOFF) {
|
|
//volatile unsigned char *pt_chip = extension->Controller;
|
|
//ULONG index = extension->BusIndex;
|
|
//
|
|
//cy_wreg(CAR,extension->CdChannel & 0x03);
|
|
|
|
PUCHAR chip = extension->Cd1400;
|
|
ULONG bus = extension->IsPci;
|
|
|
|
CD1400_WRITE(chip,bus,CAR,extension->CdChannel & 0x03);
|
|
CyyCDCmd(extension,CCR_SENDSC_SCHR1);
|
|
|
|
//TODO FANNY: SHOULD WE CALL SerialMarkHardwareBroken()? SEE LATER...
|
|
}
|
|
|
|
// The hardware is hopefully empty. Delay 10 chars before dropping DTR.
|
|
|
|
tenCharDelay.QuadPart = charTime.QuadPart * 10;
|
|
KeDelayExecutionThread(KernelMode,TRUE,&tenCharDelay);
|
|
CyyClrDTR(extension);
|
|
|
|
// We have to be very careful how we clear the RTS line.
|
|
// Transmit toggling might have been on at some point.
|
|
//
|
|
// We know that there is nothing left that could start
|
|
// out the "polling" execution path. We need to
|
|
// check the counter that indicates that the execution
|
|
// path is active. If it is then we loop delaying one
|
|
// character time. After each delay we check to see if
|
|
// the counter has gone to zero. When it has we know that
|
|
// the execution path should be just about finished. We
|
|
// make sure that we still aren't in the routine that
|
|
// synchronized execution with the ISR by synchronizing
|
|
// ourselve with the ISR.
|
|
|
|
if (extension->CountOfTryingToLowerRTS) {
|
|
do {
|
|
KeDelayExecutionThread(KernelMode,FALSE,&charTime);
|
|
} while (extension->CountOfTryingToLowerRTS);
|
|
|
|
KeSynchronizeExecution(extension->Interrupt,CyyNullSynch,NULL);
|
|
}
|
|
|
|
CyyClrRTS(extension);
|
|
|
|
// Clean out the holding reasons (since we are closed).
|
|
|
|
extension->RXHolding = 0;
|
|
extension->TXHolding = 0;
|
|
|
|
//
|
|
// Mark device as not busy for WMI
|
|
//
|
|
|
|
extension->WmiCommData.IsBusy = FALSE;
|
|
|
|
// Release the buffers.
|
|
|
|
extension->BufferSize = 0;
|
|
if (extension->InterruptReadBuffer != NULL) { // added in DDK build 2072
|
|
ExFreePool(extension->InterruptReadBuffer);
|
|
}
|
|
extension->InterruptReadBuffer = NULL;
|
|
|
|
//
|
|
// Stop waiting for wakeup
|
|
//
|
|
|
|
extension->SendWaitWake = FALSE;
|
|
|
|
if (extension->PendingWakeIrp != NULL) {
|
|
IoCancelIrp(extension->PendingWakeIrp);
|
|
}
|
|
|
|
//
|
|
// Power down our device stack
|
|
//
|
|
|
|
(void)CyyGotoPowerState(DeviceObject, extension, PowerDeviceD3);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information=0L;
|
|
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
//
|
|
// Unlock the pages. If this is the last reference to the section
|
|
// then the driver code will be flushed out.
|
|
//
|
|
|
|
//
|
|
// First, we have to let the DPC's drain. No more should be queued
|
|
// since we aren't taking interrupts now....
|
|
//
|
|
|
|
pendingDPCs = InterlockedDecrement(&extension->DpcCount);
|
|
LOGENTRY(LOG_CNT, 'DpD7', 0, extension->DpcCount, 0); // Added in build 2128
|
|
|
|
if (pendingDPCs) {
|
|
CyyDbgPrintEx(CYYDIAG1,"Draining DPC's: %x\n", Irp);
|
|
KeWaitForSingleObject(&extension->PendingDpcEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "DPC's drained: %x\n", Irp);
|
|
|
|
|
|
|
|
//
|
|
// Pages must be locked to release the mutex, so don't unlock
|
|
// them until after we release the mutex
|
|
//
|
|
|
|
ExReleaseFastMutex(&extension->CloseMutex);
|
|
|
|
//
|
|
// Reset for next open
|
|
//
|
|
|
|
InterlockedIncrement(&extension->DpcCount);
|
|
LOGENTRY(LOG_CNT, 'DpI6', 0, extension->DpcCount, 0); // Added in build 2128
|
|
|
|
openCount = InterlockedDecrement(&extension->OpenCount);
|
|
|
|
//
|
|
// Open count may be non-zero if someone was trying to open
|
|
// at the same time we decremented
|
|
//
|
|
|
|
// ASSERT(openCount == 0);
|
|
|
|
CyyUnlockPagableImageSection(CyyGlobals.PAGESER_Handle);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
CyyMarkOpen(
|
|
IN PVOID Context
|
|
)
|
|
/*------------------------------------------------------------------------
|
|
CyyMarkOpen()
|
|
|
|
Routine Description: This routine mark the fact that somebody opened
|
|
the device and its worthwhile to pay attention to interrupts.
|
|
|
|
Arguments:
|
|
|
|
Context - Really a pointer to the device extension.
|
|
|
|
Return Value: This routine always returns FALSE.
|
|
------------------------------------------------------------------------*/
|
|
{
|
|
PCYY_DEVICE_EXTENSION extension = Context;
|
|
|
|
CyyReset(extension);
|
|
|
|
extension->DeviceIsOpened = TRUE;
|
|
extension->ErrorWord = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
CyyDisableCd1400Channel(IN PVOID Context)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine disables the UART and puts it in a "safe" state when
|
|
not in use (like a close or powerdown).
|
|
|
|
Arguments:
|
|
|
|
Context - Really a pointer to the device extension.
|
|
|
|
Return Value:
|
|
|
|
This routine always returns FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCYY_DEVICE_EXTENSION extension = Context;
|
|
PCYY_DISPATCH pDispatch;
|
|
PUCHAR chip = extension->Cd1400;
|
|
ULONG bus = extension->IsPci;
|
|
ULONG i;
|
|
|
|
//
|
|
// Prepare for the closing by stopping interrupts.
|
|
//
|
|
CD1400_WRITE(chip,bus,CAR,extension->CdChannel & 0x03);
|
|
CD1400_WRITE(chip,bus,SRER,0x00); // Disable MdmCh, RxData, TxRdy
|
|
|
|
// Flush TX FIFO
|
|
//CD1400_WRITE(chip,bus,CAR,extension->CdChannel & 0x03);
|
|
CyyCDCmd(extension,CCR_FLUSH_TXFIFO);
|
|
|
|
pDispatch = (PCYY_DISPATCH)extension->OurIsrContext;
|
|
pDispatch->Cd1400[extension->PortIndex] = NULL;
|
|
|
|
for (i = 0; i < CYY_MAX_PORTS; i++) {
|
|
if (pDispatch->Cd1400[extension->PortIndex] != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == CYY_MAX_PORTS) {
|
|
// This was the last port, we can clear any pending interrupt.
|
|
CYY_CLEAR_INTERRUPT(extension->BoardMemory,bus);
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CyyMarkClose(
|
|
IN PVOID Context
|
|
)
|
|
/*------------------------------------------------------------------------
|
|
CyyMarkClose()
|
|
|
|
Routine Description: This routine merely sets a boolean to false to
|
|
mark the fact that somebody closed the device and it's no longer
|
|
worthwhile to pay attention to interrupts.
|
|
|
|
Arguments:
|
|
|
|
Context - Really a pointer to the device extension.
|
|
|
|
Return Value: This routine always returns FALSE.
|
|
------------------------------------------------------------------------*/
|
|
{
|
|
PCYY_DEVICE_EXTENSION extension = Context;
|
|
|
|
CyyDisableCd1400Channel(Context);
|
|
|
|
extension->DeviceIsOpened = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
CyyCleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*------------------------------------------------------------------------
|
|
CyyCleanup()
|
|
|
|
Routine Description: This function is used to kill all longstanding
|
|
IO operations.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this device
|
|
Irp - Pointer to the IRP for the current request
|
|
|
|
Return Value: The function value is the final status of the call
|
|
------------------------------------------------------------------------*/
|
|
{
|
|
PCYY_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
NTSTATUS status;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// We succeed a cleanup on a removing device
|
|
//
|
|
|
|
if ((status = CyyIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
|
|
if (status == STATUS_DELETE_PENDING) {
|
|
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
if (status != STATUS_PENDING) {
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
CyyDbgPrintEx(CYYIRPPATH, "Dispatch entry for: %x\n", Irp);
|
|
|
|
CyyKillPendingIrps(DeviceObject);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information=0L;
|
|
|
|
CyyCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
LARGE_INTEGER
|
|
CyyGetCharTime(
|
|
IN PCYY_DEVICE_EXTENSION Extension
|
|
)
|
|
/*------------------------------------------------------------------------
|
|
CyyGetCharTime()
|
|
|
|
Routine Description: return the number of 100 nanosecond intervals
|
|
there are in one character time.
|
|
|
|
Arguments:
|
|
|
|
Extension - Just what it says.
|
|
|
|
Return Value: 100 nanosecond intervals in a character time.
|
|
------------------------------------------------------------------------*/
|
|
{
|
|
ULONG dataSize;
|
|
ULONG paritySize;
|
|
ULONG stopSize;
|
|
ULONG charTime;
|
|
ULONG bitTime;
|
|
LARGE_INTEGER tmp;
|
|
|
|
if ((Extension->cor1 & COR1_DATA_MASK) == COR1_5_DATA) {
|
|
dataSize = 5;
|
|
} else if ((Extension->cor1 & COR1_DATA_MASK) == COR1_6_DATA) {
|
|
dataSize = 6;
|
|
} else if ((Extension->cor1 & COR1_DATA_MASK) == COR1_7_DATA) {
|
|
dataSize = 7;
|
|
} else {
|
|
dataSize = 8;
|
|
}
|
|
|
|
paritySize = 1;
|
|
if ((Extension->cor1 & COR1_PARITY_MASK) == COR1_NONE_PARITY) {
|
|
paritySize = 0;
|
|
}
|
|
|
|
if ((Extension->cor1 & COR1_STOP_MASK) == COR1_1_STOP) {
|
|
|
|
stopSize = 1;
|
|
|
|
} else {
|
|
|
|
stopSize = 2;
|
|
|
|
}
|
|
|
|
//
|
|
// First we calculate the number of 100 nanosecond intervals
|
|
// are in a single bit time (Approximately).
|
|
//
|
|
|
|
bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud;
|
|
charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime);
|
|
|
|
tmp.QuadPart = charTime;
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|