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

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
Loading
Loading
Loading
Loading
+80 −91
Original line number Diff line number Diff line
@@ -1483,114 +1483,103 @@ 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);
	val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
	if (!(val & INTCSR_INTR_ASSERTED))
		return IRQ_NONE;

	/* 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) {
	val = z8536_read(dev, APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
	if ((val & 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);
		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) {
				i_RegValue = z8536_read(dev,
					APCI1500_RW_PORT_A_SPECIFICATION);
			val = z8536_read(dev, APCI1500_RW_PORT_A_SPECIFICATION);

				i_RegValue = z8536_read(dev,
			val = z8536_read(dev,
					 APCI1500_RW_PORT_A_INTERRUPT_CONTROL);

				i_InputChannel = 1 + (i_RegValue >> 1);
			i_InputChannel = 1 + (val >> 1);

		} else {
			i_InputChannel = 0;
		}
	}

		i_RegValue = z8536_read(dev,
					APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
		if ((i_RegValue & 0x60) == 0x60) {
	val = z8536_read(dev, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
	if ((val & 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);
		val &= 0x0f;
		val |= 0x20;
		z8536_write(dev, val, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);

			i_RegValue = i_RegValue & 0xC0;
		/* Reads port B */
		val = inb(dev->iobase + APCI1500_Z8536_PORTB_REG);
		val &= 0xc0;
		/* Tests if this is an external error */

			if (i_RegValue) {
		if (val) {
			/* 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;
				}
			if (val & 0x80)
				i_InterruptMask |= 0x40;

				if (i_RegValue & 0x40) {
					i_InterruptMask =
						i_InterruptMask | 0x80;
			if (val & 0x40) {
				i_InterruptMask |= 0x80;
			}
		} else {
				i_InterruptMask = i_InterruptMask | 2;
			i_InterruptMask |= 0x02;
		}
	}

		i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR1_CMD_STATUS);
		if ((i_RegValue & 0x60) == 0x60) {
	val = z8536_read(dev, APCI1500_RW_CPT_TMR1_CMD_STATUS);
	if ((val & 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 &= 0x0f;
		val |= 0x20;
		z8536_write(dev, val, APCI1500_RW_CPT_TMR1_CMD_STATUS);

		i_InterruptMask |= 0x04;
	}

		i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR2_CMD_STATUS);
		if ((i_RegValue & 0x60) == 0x60) {
	val = z8536_read(dev, APCI1500_RW_CPT_TMR2_CMD_STATUS);
	if ((val & 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 &= 0x0f;
		val |= 0x20;
		z8536_write(dev, val, APCI1500_RW_CPT_TMR2_CMD_STATUS);

		i_InterruptMask |= 0x08;
	}

		i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR3_CMD_STATUS);
		if ((i_RegValue & 0x60) == 0x60) {
	val = z8536_read(dev, APCI1500_RW_CPT_TMR3_CMD_STATUS);
	if ((val & 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);
		val &= 0x0f;
		val |= 0x20;
		z8536_write(dev, val, APCI1500_RW_CPT_TMR3_CMD_STATUS);

		if (i_CounterLogic == APCI1500_COUNTER)
				i_InterruptMask = i_InterruptMask | 0x10;
			i_InterruptMask |= 0x10;
		else
				i_InterruptMask = i_InterruptMask | 0x20;
			i_InterruptMask |= 0x20;
	}

		send_sig(SIGIO, devpriv->tsk_Current, 0);	/*  send signal to the sample */
	/* 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);
	} else {
		dev_warn(dev->class_dev,
			"Interrupt from unknown source\n");

	}

	return IRQ_HANDLED;
}