📄 isr.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright 2005 OSR, Open Systems Resources, Inc. All rights Reserved.
//
// Module Name:
//
// isr.c
//
// Abstract:
//
// Contains routines for interrupts
//
// Author:
//
// Revision History:
//
#include "smscir.h"
#ifdef WPP_TRACING
#include "isr.tmh"
#endif
//
// Forward declarations
//
VOID
SmscIrEnableReceiveInterrupts(
PSMSCIR_DATA DeviceData
);
VOID
SmscIrEnableTransmitInterrupts(
PSMSCIR_DATA DeviceData
);
VOID
SmscIrEnqueueFifoByte(
IN PSMSCIR_DATA FdoData,
UCHAR Byte,
IN BOOLEAN DataEnd
);
BOOLEAN
SmscIrProcessRxInterrupt(
PSMSCIR_DATA DeviceData,
PINTERRUPT_ID_OR_ENABLE RxIntId
);
BOOLEAN
SmscIrProcessTxInterrupt(
PSMSCIR_DATA DeviceData,
PBIRCC2_INTERRUPT_ID_OR_ENABLE TxIntId
);
NTSTATUS
SmscIrEvtInterruptEnable(
IN WDFINTERRUPT Interrupt,
IN WDFDEVICE Device
) {
/*++
Routine Description.
Called here to enable interrupts on the device.
Arguments:
Interrupt - Our interrupt object
Device - The device to enable interrupts on
--*/
PSMSCIR_DATA deviceData;
UNREFERENCED_PARAMETER(Interrupt);
SmscIrTracePrint(TRACE_LEVEL_VERBOSE,
SMSCDBG_INIT_INFO,
("SmscIrEvtInterruptEnable: Entered"));
deviceData = (PSMSCIR_DATA)GetIrData(Device);
//
// Setup the device for RECEIVE interrupts
//
SmscIrEnableReceiveInterrupts(deviceData);
//
// Setup the device for TRANSMIT interrupts
//
SmscIrEnableTransmitInterrupts(deviceData);
SmscIrTracePrint(TRACE_LEVEL_VERBOSE,
SMSCDBG_INIT_INFO,
("SmscIrEvtInterruptEnable: Exited"));
return STATUS_SUCCESS;
}
VOID
SmscIrEnableReceiveInterrupts(
PSMSCIR_DATA DeviceData
) {
/*++
Routine Description.
Helper routine to enable receive interrupts
Arguments:
DeviceData - The device extension
--*/
MASTER_BLOCK_CONTROL mbc;
INTERRUPT_ID_OR_ENABLE intEnable;
LINE_CONTROL_B lcb;
LINE_CONTROL_A lca;
CONSUMER_IR_CTRL irCtrl;
//
// First thing is first, reset the device...
//
mbc.AsUChar = 0;
mbc.MasterReset = TRUE;
mbc.ErrorReset = TRUE;
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_MASTER_BLOCK_CONTROL,
mbc.AsUChar);
mbc.AsUChar = 0;
mbc.RegisterBlockSelect = 1;
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_MASTER_BLOCK_CONTROL,
mbc.AsUChar);
//
// Setup the receive threshold. We'll get an interrupt
// when FIFO_THRESHOLD_FOR_RECEIVE bytes are in the
// FIFO
//
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_FIFO_THRESHOLD,
FIFO_THRESHOLD_FOR_RECEIVE);
mbc.AsUChar = 0;
mbc.RegisterBlockSelect = 2;
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_MASTER_BLOCK_CONTROL,
mbc.AsUChar);
irCtrl.AsUChar = 0;
irCtrl.CarrierOff = TRUE;
irCtrl.ReceiveSync = TRUE;
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_CONSUMER_IR_CTRL,
irCtrl.AsUChar);
//
// RC6 uses a 36kHz carrier, which is the standard
// that the class driver uses. So, not matter
// what device the IR is coming from the class driver
// wants the data modulated at 36kHz
//
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_CONSUMER_IR_CARRIER,
SMSCIR_RC6_CARRIER_DIVIDER);
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_CONSUMER_IR_BIT_RATE,
SMSCIR_BIT_RATE_DIVIDER);
//
// Back to register block 0...
//
mbc.AsUChar = 0;
mbc.RegisterBlockSelect = 0;
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_MASTER_BLOCK_CONTROL,
mbc.AsUChar);
//
// It appears that in some cases the master reset
// doesn't dump out FIFO garbage, do that now...
//
lca.AsUChar = 0;
lca.FifoReset = TRUE;
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_LINE_CONTROL_A,
lca.AsUChar);
//
// Enable interrupt support on the device
//
mbc.AsUChar = 0;
mbc.MasterInterruptEnable = TRUE;
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_MASTER_BLOCK_CONTROL,
mbc.AsUChar);
//
// Enable FIFO interrupts.
//
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);
return;
}
VOID
SmscIrEnableTransmitInterrupts(
PSMSCIR_DATA DeviceData
) {
/*++
Routine Description.
Helper routine to enable transmit interrupts
Arguments:
DeviceData - The device extension
--*/
BIRCC2_MASTER_BLOCK_CONTROL txMbc;
BIRCC2_MODE txMode;
//
// First thing is first, reset the device...
//
txMbc.AsUChar = 0;
txMbc.MasterReset = TRUE;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_MASTER_BLOCK_CONTROL_ADDR,
txMbc.AsUChar);
//
// Now setup the FIFO threshold, which happens in register 1
//
txMbc.AsUChar = 0;
txMbc.RegisterBlockSelect = 1;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_MASTER_BLOCK_CONTROL_ADDR,
txMbc.AsUChar);
//
// Setup the Tx FIFO threshold
//
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_FIFO_THRESHOLD_ADDR,
FIFO_THRESHOLD_FOR_TRANSMIT);
//
// Default to the RC6 carrier
//
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_CONSUMER_IR_CARRIER,
SMSCIR_RC6_CARRIER_DIVIDER);
//
// And the standard bit rate divider (to make 50usec
// samples)
//
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_CONSUMER_IR_BIT_RATE,
SMSCIR_BIT_RATE_DIVIDER);
txMode.AsUChar = 0;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_MODE_ADDR,
txMode.AsUChar);
//
// Back to block zero to set the appropriate interrupt
// enable bits
//
txMbc.AsUChar = 0;
txMbc.RegisterBlockSelect = 0;
txMbc.MasterInterruptEnable = TRUE;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_MASTER_BLOCK_CONTROL_ADDR,
txMbc.AsUChar);
}
BOOLEAN
SmscIrEvtInterruptIsr(
IN WDFINTERRUPT Interrupt,
IN ULONG MessageID
) {
/*++
Routine Description.
The interrupt service routine for the
SMSC CIRCC2 device. This ISR fires every
time there is a FIFO interrupt, which means
that there is data to receive in Rx mode
or that more data needs to be moved into the
FIFO in Tx mode
Arguments:
Interrupt - Our interrupt object
MessageID - For MSI interrupts. Not used.
--*/
PSMSCIR_DATA deviceData;
INTERRUPT_ID_OR_ENABLE rxIntId;
BOOLEAN requestDpc = FALSE;
BIRCC2_INTERRUPT_ID_OR_ENABLE txIntId;
UNREFERENCED_PARAMETER(MessageID);
deviceData = (PSMSCIR_DATA)GetIrData(WdfInterruptGetDevice(Interrupt));
//
// Check for Rx interrupt
//
rxIntId.AsUChar = READ_HARDWARE_UCHAR(deviceData,
CIRCC2_INTERRUPT_ID);
//
// Receive interrupt?
//
if (SmscIrProcessRxInterrupt(deviceData, &rxIntId)) {
//
// We'll need a DPC to complete any outstanding
// receive requests that his might fulfill...
//
requestDpc = TRUE;
}
//
// And check for Tx interrupt
//
txIntId.AsUChar = READ_TRANSMIT_UCHAR(deviceData,
BIRCC2_INTERRUPT_ID_ADDR);
if (SmscIrProcessTxInterrupt(deviceData, &txIntId)) {
//
// We'll need a DPC to continue the blasting...
//
requestDpc = TRUE;
}
if (requestDpc) {
WdfInterruptQueueDpcForIsr(Interrupt);
}
//
// We're an ISA interrupt and therefore we are NOT
// shared. If we're interrupting here then it
// was definitely our interrupt...
//
return TRUE;
}
BOOLEAN
__forceinline
SmscIrProcessRxInterrupt(
PSMSCIR_DATA DeviceData,
PINTERRUPT_ID_OR_ENABLE RxIntId
) {
/*++
Routine Description.
Helper routine to check for and process receive interrupts
one the device.
returns TRUE if the RX interrupt is active and a DPC is
required.
Arguments:
DeviceData - Our device extension
RxIntId - The contents of the CIRCC2_INTERRUPT_ID register
--*/
LINE_CONTROL_B lcb;
MASTER_BLOCK_CONTROL mbc;
INTERRUPT_ID_OR_ENABLE intEnable;
LINE_CONTROL_A lca;
LINE_STATUS_READ lsr;
UCHAR byte;
BOOLEAN bytesDequeued;
UCHAR carrierMeasure;
CARRIER_CAPTURE_CONTROL captureControl;
if (RxIntId->Fifo) {
//
// Clear the FIFO interrupt by disabling FIFO
// interrupts. We'll enable it again before we
// leave
//
intEnable.AsUChar = 0;
intEnable.Fifo = FALSE;
WRITE_HARDWARE_UCHAR(DeviceData,
CIRCC2_INTERRUPT_ENABLE,
intEnable.AsUChar);
//
// We set the trigger to fire when there is SIZE-1 bytes in the
// FIFO (cuz that's the highest watermark allowed). Copy all
// of those bytes out.
//
for (bytesDequeued = 0;
bytesDequeued < (SMSCIR_FIFO_SIZE-1);
bytesDequeued++) {
byte = READ_HARDWARE_UCHAR(DeviceData,
CIRCC2_DATA);
//
// Enqueue the byte to be picked up by the DPC. FALSE
// because this is not a data end
//
SmscIrEnqueueFifoByte(DeviceData,
byte,
FALSE);
//
// Do we have an FF?
//
if (byte == 0xFF) {
//
// Update the number that we've seen so far...
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -