Commit d6dc9aa6 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: addi_apci_1500: handle shared interrupt

The interrupt used by this driver is shared. If the board did not cause
the interrupt the driver should return IRQ_NONE so that another driver
can handle it. Fix the interrupt handler so this happens.

Tidy up the interrupt handler a bit.
Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent eae27ff7
......@@ -1483,115 +1483,104 @@ static irqreturn_t apci1500_interrupt(int irq, void *d)
struct comedi_device *dev = d;
struct apci1500_private *devpriv = dev->private;
unsigned int status;
int i_RegValue = 0;
unsigned int val;
/* Clear the interrupt mask */
i_InterruptMask = 0;
/* Read the board interrupt status */
status = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
/* Test if board generated a interrupt */
if (status & INTCSR_INTR_ASSERTED) {
/* Disable all Interrupt */
/* Selects the master interrupt control register */
/* Disables the main interrupt on the board */
i_RegValue = z8536_read(dev,
APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
if ((i_RegValue & 0x60) == 0x60) {
/* Deletes the interrupt of port A */
i_RegValue = (i_RegValue & 0x0F) | 0x20;
z8536_write(dev, i_RegValue,
APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
i_InterruptMask = i_InterruptMask | 1;
if (i_Logic == APCI1500_OR_PRIORITY) {
i_RegValue = z8536_read(dev,
APCI1500_RW_PORT_A_SPECIFICATION);
val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
if (!(val & INTCSR_INTR_ASSERTED))
return IRQ_NONE;
i_RegValue = z8536_read(dev,
APCI1500_RW_PORT_A_INTERRUPT_CONTROL);
/* Disable all Interrupt */
/* Selects the master interrupt control register */
/* Disables the main interrupt on the board */
val = z8536_read(dev, APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
if ((val & 0x60) == 0x60) {
/* Deletes the interrupt of port A */
val &= 0x0f;
val |= 0x20;
z8536_write(dev, val, APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
i_InterruptMask = i_InterruptMask | 1;
if (i_Logic == APCI1500_OR_PRIORITY) {
val = z8536_read(dev, APCI1500_RW_PORT_A_SPECIFICATION);
i_InputChannel = 1 + (i_RegValue >> 1);
val = z8536_read(dev,
APCI1500_RW_PORT_A_INTERRUPT_CONTROL);
} else {
i_InputChannel = 0;
}
}
i_RegValue = z8536_read(dev,
APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
if ((i_RegValue & 0x60) == 0x60) {
/* Deletes the interrupt of port B */
i_RegValue = (i_RegValue & 0x0F) | 0x20;
z8536_write(dev, i_RegValue,
APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
/* Reads port B */
i_RegValue = inb(dev->iobase +
APCI1500_Z8536_PORTB_REG);
i_RegValue = i_RegValue & 0xC0;
/* Tests if this is an external error */
if (i_RegValue) {
/* Disable the interrupt */
/* Selects the command and status register of port B */
outl(0x0, devpriv->amcc + AMCC_OP_REG_INTCSR);
if (i_RegValue & 0x80) {
i_InterruptMask =
i_InterruptMask | 0x40;
}
i_InputChannel = 1 + (val >> 1);
if (i_RegValue & 0x40) {
i_InterruptMask =
i_InterruptMask | 0x80;
}
} else {
i_InterruptMask = i_InterruptMask | 2;
}
} else {
i_InputChannel = 0;
}
}
i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR1_CMD_STATUS);
if ((i_RegValue & 0x60) == 0x60) {
/* Deletes the interrupt of timer 1 */
i_RegValue = (i_RegValue & 0x0F) | 0x20;
z8536_write(dev, i_RegValue,
APCI1500_RW_CPT_TMR1_CMD_STATUS);
i_InterruptMask = i_InterruptMask | 4;
val = z8536_read(dev, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
if ((val & 0x60) == 0x60) {
/* Deletes the interrupt of port B */
val &= 0x0f;
val |= 0x20;
z8536_write(dev, val, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
/* Reads port B */
val = inb(dev->iobase + APCI1500_Z8536_PORTB_REG);
val &= 0xc0;
/* Tests if this is an external error */
if (val) {
/* Disable the interrupt */
/* Selects the command and status register of port B */
outl(0x0, devpriv->amcc + AMCC_OP_REG_INTCSR);
if (val & 0x80)
i_InterruptMask |= 0x40;
if (val & 0x40) {
i_InterruptMask |= 0x80;
}
} else {
i_InterruptMask |= 0x02;
}
}
i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR2_CMD_STATUS);
if ((i_RegValue & 0x60) == 0x60) {
/* Deletes the interrupt of timer 2 */
i_RegValue = (i_RegValue & 0x0F) | 0x20;
z8536_write(dev, i_RegValue,
APCI1500_RW_CPT_TMR2_CMD_STATUS);
i_InterruptMask = i_InterruptMask | 8;
}
val = z8536_read(dev, APCI1500_RW_CPT_TMR1_CMD_STATUS);
if ((val & 0x60) == 0x60) {
/* Deletes the interrupt of timer 1 */
val &= 0x0f;
val |= 0x20;
z8536_write(dev, val, APCI1500_RW_CPT_TMR1_CMD_STATUS);
i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR3_CMD_STATUS);
if ((i_RegValue & 0x60) == 0x60) {
/* Deletes the interrupt of timer 3 */
i_RegValue = (i_RegValue & 0x0F) | 0x20;
z8536_write(dev, i_RegValue,
APCI1500_RW_CPT_TMR3_CMD_STATUS);
if (i_CounterLogic == APCI1500_COUNTER)
i_InterruptMask = i_InterruptMask | 0x10;
else
i_InterruptMask = i_InterruptMask | 0x20;
}
i_InterruptMask |= 0x04;
}
send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
val = z8536_read(dev, APCI1500_RW_CPT_TMR2_CMD_STATUS);
if ((val & 0x60) == 0x60) {
/* Deletes the interrupt of timer 2 */
val &= 0x0f;
val |= 0x20;
z8536_write(dev, val, APCI1500_RW_CPT_TMR2_CMD_STATUS);
/* Authorizes the main interrupt on the board */
z8536_write(dev, 0xd0, APCI1500_RW_MASTER_INTERRUPT_CONTROL);
} else {
dev_warn(dev->class_dev,
"Interrupt from unknown source\n");
i_InterruptMask |= 0x08;
}
val = z8536_read(dev, APCI1500_RW_CPT_TMR3_CMD_STATUS);
if ((val & 0x60) == 0x60) {
/* Deletes the interrupt of timer 3 */
val &= 0x0f;
val |= 0x20;
z8536_write(dev, val, APCI1500_RW_CPT_TMR3_CMD_STATUS);
if (i_CounterLogic == APCI1500_COUNTER)
i_InterruptMask |= 0x10;
else
i_InterruptMask |= 0x20;
}
/* send signal to the sample */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Authorizes the main interrupt on the board */
z8536_write(dev, 0xd0, APCI1500_RW_MASTER_INTERRUPT_CONTROL);
return IRQ_HANDLED;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment