|
|
/*++
Module Name:
openclos.c
Environment:
Kernel mode
Revision History :
--*/
#include "precomp.h"
NTSTATUS MoxaGetPortPropertyFromRegistry(IN PMOXA_DEVICE_EXTENSION extension) {
NTSTATUS status; HANDLE keyHandle; ULONG data=0,dataLen;
extension->RxFifoTrigger = 3; // for 550C UART
extension->TxFifoAmount = 16; // for 550C UART
extension->PortFlag = 0;
status = IoOpenDeviceRegistryKey(extension->Pdo, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle);
if (!NT_SUCCESS(status)) { //
// This is a fatal error. If we can't get to our registry key,
// we are sunk.
//
return (status); } status = MoxaGetRegistryKeyValue( keyHandle, L"DisableFiFo", sizeof(L"DisableFiFo"), &data, sizeof(ULONG), &dataLen); if (NT_SUCCESS(status)) { if (data) { extension->RxFifoTrigger = 0; extension->TxFifoAmount = 1; } } MoxaKdPrint(MX_DBG_TRACE, ("TxFifoSize/RxFifoTrig=%x/%x\n", extension->TxFifoAmount ,extension->RxFifoTrigger )); status = MoxaGetRegistryKeyValue( keyHandle, L"TxMode", sizeof(L"TxMode"), &data, sizeof(ULONG), &dataLen);
if (NT_SUCCESS(status) && data ) extension->PortFlag = NORMAL_TX_MODE; MoxaKdPrint(MX_DBG_TRACE, ("TxMode=%x/%x\n", extension->PortFlag ,status));
ZwClose(keyHandle);
return (status); }
NTSTATUS MoxaCreateOpen( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) {
PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; NTSTATUS status;
MoxaKdPrint(MX_DBG_TRACE,("MoxaCreateOpen\n")); if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options & FILE_DIRECTORY_FILE) {
Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY; Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT ); MoxaKdPrint(MX_DBG_TRACE,("Is a directory,open failed\n")); return STATUS_NOT_A_DIRECTORY;
}
if (extension->ControlDevice) { extension->ErrorWord = 0; extension->DeviceIsOpened = TRUE; Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS; }
if (!extension->PortExist) {
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT ); MoxaKdPrint(MX_DBG_TRACE,("No such device,open failed\n")); return STATUS_NO_SUCH_DEVICE;
}
if (extension->PNPState != SERIAL_PNP_STARTED) { Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); MoxaKdPrint(MX_DBG_TRACE,("Device is not started,open failed\n")); return STATUS_INSUFFICIENT_RESOURCES; }
//
// Lock out changes to PnP state until we have our open state decided
//
ExAcquireFastMutex(&extension->OpenMutex);
if ((status = MoxaIRPPrologue(Irp, extension)) != STATUS_SUCCESS) { ExReleaseFastMutex(&extension->OpenMutex); MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT); MoxaKdPrint(MX_DBG_TRACE,("MoxaIRPPrologue status=%x,open failed\n",status)); return status; }
if (InterlockedIncrement(&extension->OpenCount) != 1) { ExReleaseFastMutex(&extension->OpenMutex); InterlockedDecrement(&extension->OpenCount); Irp->IoStatus.Status = STATUS_ACCESS_DENIED; MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT); MoxaKdPrint(MX_DBG_TRACE,("Open count greater than 1,open failed\n",status)); return STATUS_ACCESS_DENIED; }
//
// Ok, it looks like we really are going to open. Lock down the
// driver.
//
// MoxaLockPagableSectionByHandle(MoxaGlobalsData->PAGESER_Handle);
//
// Retreive the properties of port
//
MoxaGetPortPropertyFromRegistry(extension);
//
// Power up the stack
//
// (void)MoxaGotoPowerState(DeviceObject, extension, PowerDeviceD0);
if ((extension->PowerState != PowerDeviceD0)|| (MoxaGlobalData->BoardReady[extension->BoardNo] == FALSE)) { MoxaKdPrint(MX_DBG_TRACE,("Board is not ready,open failed\n")); ExReleaseFastMutex(&extension->OpenMutex); InterlockedDecrement(&extension->OpenCount); Irp->IoStatus.Status = STATUS_ACCESS_DENIED; MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT); return STATUS_ACCESS_DENIED; }
MoxaKdPrint(MX_DBG_TRACE,("Device Opened,TxFiFo=%d,RxFiFo=%d,PortFlag=%x\n", extension->TxFifoAmount,extension->RxFifoTrigger,extension->PortFlag));
//
// Not currently waiting for wake up
//
extension->SendWaitWake = FALSE;
extension->HandFlow.XoffLimit = extension->RxBufferSize >> 3; extension->HandFlow.XonLimit = extension->RxBufferSize >> 1;
extension->BufferSizePt8 = ((3*(extension->RxBufferSize>>2))+ (extension->RxBufferSize>>4));
extension->WriteLength = 0; extension->ReadLength = 0;
extension->TotalCharsQueued = 0;
extension->IrpMaskLocation = NULL; extension->HistoryMask = 0; extension->IsrWaitMask = 0;
extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit; extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;
//
// Clear out the statistics.
//
KeSynchronizeExecution( extension->Interrupt, MoxaClearStats, extension );
extension->EscapeChar = 0; extension->ErrorWord = 0;
MoxaReset(extension);
MoxaFuncWithLock(extension, FC_SetTxFIFOCnt, extension->TxFifoAmount); MoxaFuncWithLock(extension, FC_SetRxFIFOTrig,extension->RxFifoTrigger);
MoxaFuncWithLock(extension, FC_EnableCH, Magic_code); /* 6-1-1998 by William */ /* 4-26-99 by William */ MoxaFuncWithLock(extension, FC_SetLineIrq,Magic_code); /* 5-31-1998 by William
MoxaFuncWithLock(extension, FC_GetAll, 0); extension->ModemStatus = *(PUSHORT)(extension->PortOfs + FuncArg + 2); */ extension->ModemStatus = *(PUSHORT)(extension->PortOfs + FlagStat) >> 4;
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0L;
extension->DeviceIsOpened = TRUE; //
// Mark the device as busy for WMI
//
extension->WmiCommData.IsBusy = TRUE;
//
// 7-20-01 by William
//
MoxaAddTimeOutProc(extension);
ExReleaseFastMutex(&extension->OpenMutex);
MoxaCompleteRequest( extension, Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
VOID MoxaReset( IN PMOXA_DEVICE_EXTENSION Extension ) { SHORT divisor; PUCHAR ofs; MOXA_IOCTL_SYNC S;
ofs = Extension->PortOfs;
MoxaKdPrint (MX_DBG_TRACE, ("Enter MoxaReset\n")); MoxaFuncWithLock(Extension, FC_ChannelReset, Magic_code); MoxaFuncWithLock(Extension, FC_SetDataMode, Extension->DataMode); MoxaGetDivisorFromBaud( Extension->ClockType, Extension->CurrentBaud, &divisor );
MoxaFuncWithLock(Extension, FC_SetBaud, divisor); S.Extension = Extension; S.Data = &Extension->HandFlow;
MoxaSetupNewHandFlow( &S ); *(PUSHORT)(ofs + Tx_trigger) = (USHORT)MoxaTxLowWater; }
NTSTATUS MoxaClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; LARGE_INTEGER allSentDelay; LARGE_INTEGER charTime; PUCHAR ofs; LONG count,count1; ULONG openCount,pendingDPCs; NTSTATUS status;
// MoxaKdPrint(MX_DBG_TRACE,("%ws,Closing ...\n",extension->DosName));
if (extension->ControlDevice) { MoxaKdPrint(MX_DBG_TRACE,("Control Device Closed\n")); Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information=0L; extension->DeviceIsOpened = FALSE;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS; }
//
// Grab a mutex
//
ExAcquireFastMutex(&extension->CloseMutex);
//
// We succeed a close on a removing device
//
//
// 7-20-01 by William
//
MoxaDelTimeOutProc(extension);
if ((status = MoxaIRPPrologue(Irp, extension)) != STATUS_SUCCESS) { MoxaKdPrint (MX_DBG_ERROR,("Close prologue failed for: %x\n",Irp)); if (status == STATUS_DELETE_PENDING) { status = Irp->IoStatus.Status = STATUS_SUCCESS; }
MoxaCompleteRequest(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) { MoxaKdPrint (MX_DBG_ERROR,("Close open count bad for: 0x%x\n",Irp)); MoxaKdPrint (MX_DBG_ERROR,("------: Count: %x Addr: 0x%x\n", extension->OpenCount, &extension->OpenCount)); ExReleaseFastMutex(&extension->CloseMutex); Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT); return STATUS_INVALID_DEVICE_REQUEST; }
charTime = RtlLargeIntegerNegate(MoxaGetCharTime(extension));
extension->DeviceIsOpened = FALSE; //
// Mark device as not busy for WMI
//
extension->WmiCommData.IsBusy = FALSE;
ofs = extension->PortOfs;
if (extension->SendBreak) { MoxaFuncWithLock(extension, FC_StopBreak, Magic_code); extension->SendBreak = FALSE; }
if (*(ofs + FlagStat) & Rx_xoff) MoxaFuncWithLock(extension, FC_SendXon, 0);
/* 7-21-99 by William
count = GetDeviceTxQueueWithLock(extension); count += extension->TotalCharsQueued;
//
// Wait data all sent
//
count += 10;
allSentDelay = RtlExtendedIntegerMultiply( charTime, count );
KeDelayExecutionThread( KernelMode, TRUE, &allSentDelay ); */
//
// Wait data all sent
//
count1 = 0; while (TRUE) {
count = GetDeviceTxQueueWithLock(extension); count += extension->TotalCharsQueued; if (count == count1) break; else count1 = count; allSentDelay = RtlExtendedIntegerMultiply( charTime, count + 10 );
KeDelayExecutionThread( KernelMode, TRUE, &allSentDelay ); }
MoxaFuncWithLock(extension, FC_SetFlowCtl, 0); MoxaFuncWithLock(extension, FC_DTRcontrol, 0); /* clear DTR */ MoxaFuncWithLock(extension, FC_RTScontrol, 0); /* clear RTS */ MoxaFuncWithLock(extension, FC_ClrLineIrq, Magic_code); MoxaFlagBit[extension->PortNo] &= 0xFC;
*(PUSHORT)(ofs + HostStat) = 0;
MoxaFuncWithLock(extension, FC_DisableCH, Magic_code); //
// Stop waiting for wakeup
//
extension->SendWaitWake = FALSE;
if (extension->PendingWakeIrp != NULL) { IoCancelIrp(extension->PendingWakeIrp); }
//
// Power down our device stack
//
// (void)MoxaGotoPowerState(DeviceObject, extension, PowerDeviceD3);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information=0L;
MoxaCompleteRequest(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); if (pendingDPCs) { MoxaKdPrint(MX_DBG_TRACE,("DpcCount = %d\n",extension->DpcCount)); MoxaKdPrint(MX_DBG_TRACE,("Drainging DPC's: %x\n",Irp)); KeWaitForSingleObject(&extension->PendingDpcEvent, Executive, KernelMode, FALSE, NULL); }
//
// 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);
openCount = InterlockedDecrement(&extension->OpenCount);
//ASSERT(openCount == 0);
// MoxaKdPrint(MX_DBG_TRACE,("%ws,close completed.\n",extension->DosName));
// MoxaUnlockPagableImageSection(MoxaGlobalsData->PAGESER_Handle);
return STATUS_SUCCESS; }
LARGE_INTEGER MoxaGetCharTime( IN PMOXA_DEVICE_EXTENSION Extension ) {
ULONG dataSize; ULONG paritySize; ULONG stopSize; ULONG charTime; ULONG bitTime;
if ((Extension->DataMode & MOXA_DATA_MASK) == MOXA_5_DATA) { dataSize = 5; } else if ((Extension->DataMode & MOXA_DATA_MASK) == MOXA_6_DATA) { dataSize = 6; } else if ((Extension->DataMode & MOXA_DATA_MASK) == MOXA_7_DATA) { dataSize = 7; } else if ((Extension->DataMode & MOXA_DATA_MASK) == MOXA_8_DATA) { dataSize = 8; } else { dataSize = 8; }
paritySize = 1; if ((Extension->DataMode & MOXA_PARITY_MASK) == MOXA_NONE_PARITY) {
paritySize = 0;
}
if (Extension->DataMode & MOXA_STOP_MASK) {
//
// Even if it is 1.5, for sanities sake were going
// to say 2.
//
stopSize = 2;
} else {
stopSize = 1;
}
//
// 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);
return RtlConvertUlongToLargeInteger(charTime);
}
NTSTATUS MoxaCleanup( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; KIRQL oldIrql; NTSTATUS status;
if ((!extension->ControlDevice)&&(extension->DeviceIsOpened == TRUE)) {
//
// We succeed a cleanup on a removing device
//
if ((status = MoxaIRPPrologue(Irp, extension)) != STATUS_SUCCESS) { if (status == STATUS_DELETE_PENDING) { status = Irp->IoStatus.Status = STATUS_SUCCESS; } MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT); return status; }
//
// First kill all the reads and writes.
//
MoxaKillAllReadsOrWrites( DeviceObject, &extension->WriteQueue, &extension->CurrentWriteIrp );
MoxaKillAllReadsOrWrites( DeviceObject, &extension->ReadQueue, &extension->CurrentReadIrp );
//
// Next get rid of purges.
//
MoxaKillAllReadsOrWrites( DeviceObject, &extension->PurgeQueue, &extension->CurrentPurgeIrp );
//
// Get rid of any mask operations.
//
MoxaKillAllReadsOrWrites( DeviceObject, &extension->MaskQueue, &extension->CurrentMaskIrp );
//
// Now get rid a pending wait mask irp.
//
IoAcquireCancelSpinLock(&oldIrql);
if (extension->CurrentWaitIrp) {
PDRIVER_CANCEL cancelRoutine;
cancelRoutine = extension->CurrentWaitIrp->CancelRoutine; extension->CurrentWaitIrp->Cancel = TRUE;
if (cancelRoutine) {
extension->CurrentWaitIrp->CancelIrql = oldIrql; extension->CurrentWaitIrp->CancelRoutine = NULL;
cancelRoutine( DeviceObject, extension->CurrentWaitIrp );
} /* 8-30-01 by William */ else IoReleaseCancelSpinLock(oldIrql);
} else
IoReleaseCancelSpinLock(oldIrql);
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information=0L; MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT); } else { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information=0L; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return STATUS_SUCCESS;
}
|