📄 dpc.c
字号:
// Tricky user...
//
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrSetupCurrentPriorityReceive: Buffer size specified in "\
"structure is too large. Buffer Size: 0x%x - Overall "\
"buffer size: 0x%x",
capturedByteCount, actualBufferLength));
return STATUS_INVALID_BUFFER_SIZE;
}
PriorityRLCReceiver->CurrentIrReceiveRequest = PriorityReceiveRequest;
PriorityRLCReceiver->ReceiveBuffer
= (PUCHAR)priorityReceiveParams->Data;
PriorityRLCReceiver->PriorityReceiveParams = priorityReceiveParams;
PriorityRLCReceiver->ReceiveBufferSize = capturedByteCount;
//
// We'll be hanging this out there for a while,
// so need to set a cancel routine.
//
WdfRequestMarkCancelable(PriorityReceiveRequest,
IrPriorityReceiveInProgressCancel);
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_RECEIVE_INFO,
("IrSetupCurrentPriorityReceive: Request 0x%p now current request",
PriorityReceiveRequest));
return STATUS_SUCCESS;
}
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrSetupCurrentPriorityReceive: WdfRequestRetrieveOutputBuffer "\
"failed - 0x%x", status));
return status;
}
VOID
SmscIrContinueBlasting(
IN PSMSCIR_DATA DeviceData,
OUT WDFREQUEST *TxRequestToComplete,
OUT PNTSTATUS CompletionStatus
) {
/*++
Routine Description.
This routine continues the current blasting operation.
It will move bytes into the FIFO and start the transmit
or it will return a request to complete
Must be called with the *TxFifoDataLock* held
Arguments:
DeviceData - Our device context
TxRequestToComplete - Request to complete with STATUS_SUCCESS
by the caller once the lock is dropped
--*/
BIRCC2_LINE_CONTROL lc;
BIRCC2_INTERRUPT_ID_OR_ENABLE txIntEnable;
PSMSCIR_TX_FIFO_DATA txFifoData = NULL;
*TxRequestToComplete = NULL;
if (!DeviceData->CurrentTxFifoData) {
//
// No current request...Someone beat us to it
//
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("SmscIrContinueBlasting: No more data to blast"));
return;
}
//
// Check to make sure the user doesn't want this request
// cancelled. If she does, we'll abort.
//
if (WdfRequestIsCanceled(DeviceData->CurrentTxRequest)) {
//
// User aborted...Fail request
//
*TxRequestToComplete = DeviceData->CurrentTxRequest;
*CompletionStatus = STATUS_CANCELLED;
DeviceData->CurrentTxFifoData = NULL;
DeviceData->CurrentTxRequest = NULL;
//
// Need to clean out the list of remaing FIFO
// data.
//
while (!IsListEmpty(&DeviceData->TxFifoDataList)) {
txFifoData
= (PSMSCIR_TX_FIFO_DATA)
RemoveHeadList(&DeviceData->TxFifoDataList);
ExFreePool(txFifoData);
}
return;
}
//
// Tx processing to do...Continue blasting.
//
txFifoData = DeviceData->CurrentTxFifoData;
//
// Done with this portion?
//
if (txFifoData->CurrentOffset == txFifoData->FifoBufferLength) {
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("SmscIrContinueBlasting: Finished blasting sample"));
txFifoData->TimesRepeated++;
//
// Repeated it as many times as necessary?
//
if (txFifoData->TimesRepeated < txFifoData->RepeatCount) {
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("SmscIrContinueBlasting: Repeating previous sample"));
//
// Nope, we'll do it again.
//
txFifoData->CurrentOffset = 0;
} else {
RemoveEntryList(&txFifoData->ListEntry);
ExFreePool(txFifoData);
//
// More to blast?
//
if (!IsListEmpty(&DeviceData->TxFifoDataList)) {
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("SmscIrContinueBlasting: Blasting next sample"));
//
// Yup, move on to the next one.
//
txFifoData = (PSMSCIR_TX_FIFO_DATA)
RemoveHeadList(&DeviceData->TxFifoDataList);
DeviceData->CurrentTxFifoData = txFifoData;
} else {
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("SmscIrContinueBlasting: Blasted final piece"));
//
// Done! Return the request to the caller
//
*TxRequestToComplete = DeviceData->CurrentTxRequest;
*CompletionStatus = STATUS_SUCCESS;
DeviceData->CurrentTxFifoData = NULL;
DeviceData->CurrentTxRequest = NULL;
return;
}
}
}
//
// If we're here, we're not done..
//
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("SmscIrContinueBlasting: Writing %d bytes starting at 0x%x",
SMSCIR_FIFO_SIZE, txFifoData->CurrentOffset));
//
// The data is guaranteed to always be a multiple of SMSCIR_FIFO_SIZE,
// so we can just blindly assume that there's at least that
// many bytes remaining
//
WRITE_TRANSMIT_BUFFER_UCHAR(
DeviceData,
BIRCC2_DATA_ADDR,
&txFifoData->FifoBuffer[txFifoData->CurrentOffset],
SMSCIR_FIFO_SIZE);
txFifoData->CurrentOffset += SMSCIR_FIFO_SIZE;
//
// Enable FIFO interrupts...
//
txIntEnable.AsUChar = 0;
txIntEnable.Fifo = TRUE;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_INTERRUPT_ENABLE_ADDR,
txIntEnable.AsUChar);
//
// Enable the transmitter
//
lc.AsUChar = 0;
lc.TxEnable = 1;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_LINE_CONTROL_ADDR,
lc.AsUChar);
//
// Record when we sent this. Our deadman might need to come along
// and poke the device if we don't hear back
//
KeQuerySystemTime(&DeviceData->LastBlastSentTime);
}
VOID
SmscIrEvtDeadManTimerForTransmit(
IN WDFTIMER Timer
) {
/*++
Routine Description.
This is our timer routine that fires once every SMSCIR_DEADMAN_TIMER_PERIOD
milliseconds to check if the transmitter has stopped. This should happen
very infrequently, but the possibility is there when the system is
under heavy load
Arguments:
Timer - Our deadman timer
--*/
PSMSCIR_DATA deviceData;
LINE_STATUS_READ lsr;
BIRCC2_LINE_CONTROL txLc;
LARGE_INTEGER currentTime;
LARGE_INTEGER lastBlast;
LINE_CONTROL_B lcb;
LINE_CONTROL_A lca;
MASTER_BLOCK_CONTROL mbc;
INTERRUPT_ID_OR_ENABLE intEnable;
deviceData = (PSMSCIR_DATA)GetIrData(WdfTimerGetParentObject(Timer));
lastBlast = deviceData->LastBlastSentTime;
KeQuerySystemTime(¤tTime);
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("SmscIrEvtDeadManTimerForTransmit: Entered"));
//
// It should NOT take a second to send data. If it's been a second
// since we last saw a FIFO blast complete reset the device
//
if ((currentTime.QuadPart - lastBlast.QuadPart) >= SECONDS(1)) {
//
// We're blasting and it's been a while since we last heard from the
// device...Check for errors.
//
WdfInterruptAcquireLock(deviceData->Interrupt);
//
// A bum blast can throw off our receiver. Check for any
// error conditions there
//
lsr.AsUChar = READ_HARDWARE_UCHAR(deviceData,
CIRCC2_LINE_STATUS_R);
if (lsr.AsUChar) {
//
// Some sort of receiver error...
//
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("SmscIrEvtDeadManTimerForTransmit: Errors on receive fifo"));
//
// Shut the receiver off.
//
lcb.AsUChar = 0;
WRITE_HARDWARE_UCHAR(deviceData,
CIRCC2_LINE_CONTROL_B,
lcb.AsUChar);
//
// Dump any potential leftovers from the FIFO.
//
lca.AsUChar = 0;
lca.FifoReset = TRUE;
WRITE_HARDWARE_UCHAR(deviceData,
CIRCC2_LINE_CONTROL_A,
lca.AsUChar);
mbc.AsUChar = 0;
mbc.ErrorReset = TRUE;
WRITE_HARDWARE_UCHAR(deviceData,
CIRCC2_MASTER_BLOCK_CONTROL,
mbc.AsUChar);
mbc.AsUChar = 0;
mbc.MasterInterruptEnable = TRUE;
WRITE_HARDWARE_UCHAR(deviceData,
CIRCC2_MASTER_BLOCK_CONTROL,
mbc.AsUChar);
intEnable.AsUChar = 0;
intEnable.Fifo = TRUE;
WRITE_HARDWARE_UCHAR(deviceData,
CIRCC2_INTERRUPT_ENABLE,
intEnable.AsUChar);
//
// Set the device to receive.
//
lcb.AsUChar = 0;
lcb.SCEModeBits = SCE_MODE_RECEIVE;
WRITE_HARDWARE_UCHAR(deviceData,
CIRCC2_LINE_CONTROL_B,
lcb.AsUChar);
}
txLc.AsUChar = READ_TRANSMIT_UCHAR(deviceData,
BIRCC2_LINE_CONTROL_ADDR);
if (txLc.FifoNotEmpty && !txLc.TxEnable) {
//
// Errors on the device.
//
//
// Reset the FIFO, this will generate a FIFO interrupt
// and we'll continue blasting
//
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("SmscIrEvtDeadManTimerForTransmit: Errors on transmit fifo"));
txLc.FifoReset = TRUE;
WRITE_TRANSMIT_UCHAR(deviceData,
BIRCC2_LINE_CONTROL_ADDR,
txLc.AsUChar);
}
WdfInterruptReleaseLock(deviceData->Interrupt);
}
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("SmscIrEvtDeadManTimerForTransmit: Exited"));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -