[PATCH] staging: comedi: addi_apci_1500: rewrite the subdevice support functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This driver is a mess. It violates the comedi API so much that I doubt
anything actually works.

Drop the addi-data/hwdrv_apci1500.c file and rewrite the subdevice support
functions.

This board has 16 digital inputs (subdevice 0) and 16 digital outputs
(subdevice 1).

It also has three 16-bit timer/counters provided by a Z8536 CIO chip
(subdevice 2). The Z8536 chip is also used to support pattern match
interrupt detection of the first 14 digital input channels.

Signed-off-by: H Hartley Sweeten <hsweeten@xxxxxxxxxxxxxxxxxxx>
Cc: Ian Abbott <abbotti@xxxxxxxxx>
Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
 .../comedi/drivers/addi-data/hwdrv_apci1500.c      | 1620 --------------------
 drivers/staging/comedi/drivers/addi_apci_1500.c    |  812 +++++++++-
 drivers/staging/comedi/drivers/z8536.h             |  202 +++
 3 files changed, 974 insertions(+), 1660 deletions(-)
 delete mode 100644 drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
 create mode 100644 drivers/staging/comedi/drivers/z8536.h

diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
deleted file mode 100644
index 5bf943d..0000000
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
+++ /dev/null
@@ -1,1620 +0,0 @@
-/*
- * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
- *
- *	ADDI-DATA GmbH
- *	Dieselstrasse 3
- *	D-77833 Ottersweier
- *	Tel: +19(0)7223/9493-0
- *	Fax: +49(0)7223/9493-92
- *	http://www.addi-data.com
- *	info@xxxxxxxxxxxxx
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- */
-
-/* DIGITAL INPUT-OUTPUT DEFINE */
-
-#define APCI1500_AND			2
-#define APCI1500_OR			4
-#define APCI1500_OR_PRIORITY		6
-#define COUNTER1			0
-#define COUNTER2			1
-#define COUNTER3			2
-#define APCI1500_COUNTER		0x20
-#define APCI1500_TIMER			0
-#define APCI1500_WATCHDOG		0
-#define APCI1500_SINGLE			0
-#define APCI1500_CONTINUOUS		0x80
-#define APCI1500_DISABLE		0
-#define APCI1500_ENABLE			1
-#define APCI1500_SOFTWARE_TRIGGER	0x4
-#define APCI1500_HARDWARE_TRIGGER	0x10
-#define APCI1500_SOFTWARE_GATE		0
-#define APCI1500_HARDWARE_GATE		0x8
-#define START				0
-#define STOP				1
-#define TRIGGER				2
-
-/*
- * Z8536 CIO Internal Address
- */
-enum {
-	APCI1500_RW_MASTER_INTERRUPT_CONTROL,
-	APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-	APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
-	APCI1500_RW_PORT_B_INTERRUPT_CONTROL,
-	APCI1500_RW_TIMER_COUNTER_INTERRUPT_VECTOR,
-	APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
-	APCI1500_RW_PORT_C_DATA_DIRECTION,
-	APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
-
-	APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-	APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-	APCI1500_RW_CPT_TMR1_CMD_STATUS,
-	APCI1500_RW_CPT_TMR2_CMD_STATUS,
-	APCI1500_RW_CPT_TMR3_CMD_STATUS,
-	APCI1500_RW_PORT_A_DATA,
-	APCI1500_RW_PORT_B_DATA,
-	APCI1500_RW_PORT_C_DATA,
-
-	APCI1500_R_CPT_TMR1_VALUE_HIGH,
-	APCI1500_R_CPT_TMR1_VALUE_LOW,
-	APCI1500_R_CPT_TMR2_VALUE_HIGH,
-	APCI1500_R_CPT_TMR2_VALUE_LOW,
-	APCI1500_R_CPT_TMR3_VALUE_HIGH,
-	APCI1500_R_CPT_TMR3_VALUE_LOW,
-	APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
-	APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
-	APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
-	APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
-	APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
-	APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
-	APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
-	APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
-	APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
-	APCI1500_R_CURRENT_VECTOR,
-
-	APCI1500_RW_PORT_A_SPECIFICATION,
-	APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
-	APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
-	APCI1500_RW_PORT_A_DATA_DIRECTION,
-	APCI1500_RW_PORT_A_SPECIAL_IO_CONTROL,
-	APCI1500_RW_PORT_A_PATTERN_POLARITY,
-	APCI1500_RW_PORT_A_PATTERN_TRANSITION,
-	APCI1500_RW_PORT_A_PATTERN_MASK,
-
-	APCI1500_RW_PORT_B_SPECIFICATION,
-	APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
-	APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
-	APCI1500_RW_PORT_B_DATA_DIRECTION,
-	APCI1500_RW_PORT_B_SPECIAL_IO_CONTROL,
-	APCI1500_RW_PORT_B_PATTERN_POLARITY,
-	APCI1500_RW_PORT_B_PATTERN_TRANSITION,
-	APCI1500_RW_PORT_B_PATTERN_MASK
-};
-
-static int i_TimerCounter1Init;
-static int i_TimerCounter2Init;
-static int i_WatchdogCounter3Init;
-static int i_Event1Status, i_Event2Status;
-static int i_TimerCounterWatchdogInterrupt;
-static int i_Logic, i_CounterLogic;
-static int i_InterruptMask;
-static int i_InputChannel;
-static int i_TimerCounter1Enabled, i_TimerCounter2Enabled,
-	   i_WatchdogCounter3Enabled;
-
-static unsigned int z8536_read(struct comedi_device *dev, unsigned int reg)
-{
-	unsigned long flags;
-	unsigned int val;
-
-	spin_lock_irqsave(&dev->spinlock, flags);
-	outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
-	val = inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
-	spin_unlock_irqrestore(&dev->spinlock, flags);
-
-	return val;
-}
-
-static void z8536_write(struct comedi_device *dev,
-			unsigned int val, unsigned int reg)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->spinlock, flags);
-	outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
-	outb(val, dev->iobase + APCI1500_Z8536_CTRL_REG);
-	spin_unlock_irqrestore(&dev->spinlock, flags);
-}
-
-static void z8536_reset(struct comedi_device *dev)
-{
-	unsigned long flags;
-
-	/*
-	 * Even if the state of the Z8536 is not known, the following
-	 * sequence will reset it and put it in State 0.
-	 */
-	spin_lock_irqsave(&dev->spinlock, flags);
-	inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
-	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
-	inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
-	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
-	outb(1, dev->iobase + APCI1500_Z8536_CTRL_REG);
-	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
-	spin_unlock_irqrestore(&dev->spinlock, flags);
-
-	z8536_write(dev, 0xf4, APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-	z8536_write(dev, 0x10, APCI1500_RW_PORT_A_SPECIFICATION);
-	/* High level of port A means 1 */
-	z8536_write(dev, 0xff, APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY);
-	/* All bits used as inputs */
-	z8536_write(dev, 0xff, APCI1500_RW_PORT_A_DATA_DIRECTION);
-	/* Deletes IP and IUS */
-	z8536_write(dev, 0x20, APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
-	/* Deactivates the interrupt management of port A */
-	z8536_write(dev, 0xe0, APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
-	/* Deletes the register */
-	z8536_write(dev, 0x00, APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION);
-
-	z8536_write(dev, 0x10, APCI1500_RW_PORT_B_SPECIFICATION);
-	/* A high level of port B means 1 */
-	z8536_write(dev, 0x7f, APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY);
-	/* All bits used as inputs */
-	z8536_write(dev, 0xff, APCI1500_RW_PORT_B_DATA_DIRECTION);
-	/* Deletes IP and IUS */
-	z8536_write(dev, 0x20, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
-	/* Deactivates the interrupt management of port B */
-	z8536_write(dev, 0xe0, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
-	/* Deletes the register */
-	z8536_write(dev, 0x00, APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION);
-
-	/* High level of port C means 1 */
-	z8536_write(dev, 0x09, APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY);
-	/* All bits used as inputs except channel 1 */
-	z8536_write(dev, 0x0e, APCI1500_RW_PORT_C_DATA_DIRECTION);
-	/* Deletes it */
-	z8536_write(dev, 0x00, APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL);
-
-	/* Deletes IP and IUS */
-	z8536_write(dev, 0x20, APCI1500_RW_CPT_TMR1_CMD_STATUS);
-	/* Deactivates the interrupt management of timer 1 */
-	z8536_write(dev, 0xe0, APCI1500_RW_CPT_TMR1_CMD_STATUS);
-
-	/* Deletes IP and IUS */
-	z8536_write(dev, 0x20, APCI1500_RW_CPT_TMR2_CMD_STATUS);
-	/* Deactivates Timer 2 interrupt management */
-	z8536_write(dev, 0xe0, APCI1500_RW_CPT_TMR2_CMD_STATUS);
-
-	/* Deletes IP and IUS */
-	z8536_write(dev, 0x20, APCI1500_RW_CPT_TMR3_CMD_STATUS);
-	/* Deactivates interrupt management of timer 3 */
-	z8536_write(dev, 0xe0, APCI1500_RW_CPT_TMR3_CMD_STATUS);
-
-	/* Deletes all interrupts */
-	z8536_write(dev, 0x00, APCI1500_RW_MASTER_INTERRUPT_CONTROL);
-}
-
-/*
- * An event can be generated for each port. The first event is related to the
- * first 8 channels (port 1) and the second to the following 6 channels (port 2)
- * An interrupt is generated when one or both events have occurred.
- *
- * data[0] Number of the input port on which the event will take place (1 or 2)
- * data[1] The event logic for port 1 has three possibilities:
- *	APCI1500_AND		This logic links the inputs with an AND logic.
- *	APCI1500_OR		This logic links the inputs with a OR logic.
- *	APCI1500_OR_PRIORITY	This logic links the inputs with a priority OR
- *				logic. Input 1 has the highest priority level
- *				and input 8 the	smallest.
- *	For the second port the user has 1 possibility:
- *	APCI1500_OR	This logic links the inputs with a polarity OR logic
- * data[2] These 8-character word for port1 and 6-character word for port 2
- *	   give the mask of the event. Each place gives the state of the input
- *	   channels and can have one of these six characters
- *	0 This input must be on 0
- *	1 This input must be on 1
- *	2 This input reacts to a falling edge
- *	3 This input reacts to a rising edge
- *	4 This input reacts to both edges
- *	5 This input is not used for event
- */
-static int apci1500_di_config(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn,
-			      unsigned int *data)
-{
-	int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0;
-	int i_MaxChannel = 0, i_Count = 0, i_EventMask = 0;
-	int i_PatternTransitionCount = 0, i_RegValue;
-	int i;
-
-	/* Disables the main interrupt on the board */
-	z8536_write(dev, 0x00, APCI1500_RW_MASTER_INTERRUPT_CONTROL);
-
-	if (data[0] == 1) {
-		i_MaxChannel = 8;
-	} else {
-		if (data[0] == 2) {
-			i_MaxChannel = 6;
-		} else {
-			dev_warn(dev->class_dev,
-				"The specified port event does not exist\n");
-			return -EINVAL;
-		}
-	}
-	switch (data[1]) {
-	case 0:
-		data[1] = APCI1500_AND;
-		break;
-	case 1:
-		data[1] = APCI1500_OR;
-		break;
-	case 2:
-		data[1] = APCI1500_OR_PRIORITY;
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			"The specified interrupt logic does not exist\n");
-		return -EINVAL;
-	}
-
-	i_Logic = data[1];
-	for (i_Count = i_MaxChannel, i = 0; i_Count > 0; i_Count--, i++) {
-		i_EventMask = data[2 + i];
-		switch (i_EventMask) {
-		case 0:
-			i_PatternMask =
-				i_PatternMask | (1 << (i_MaxChannel - i_Count));
-			break;
-		case 1:
-			i_PatternMask =
-				i_PatternMask | (1 << (i_MaxChannel - i_Count));
-			i_PatternPolarity =
-				i_PatternPolarity | (1 << (i_MaxChannel -
-					i_Count));
-			break;
-		case 2:
-			i_PatternMask =
-				i_PatternMask | (1 << (i_MaxChannel - i_Count));
-			i_PatternTransition =
-				i_PatternTransition | (1 << (i_MaxChannel -
-					i_Count));
-			break;
-		case 3:
-			i_PatternMask =
-				i_PatternMask | (1 << (i_MaxChannel - i_Count));
-			i_PatternPolarity =
-				i_PatternPolarity | (1 << (i_MaxChannel -
-					i_Count));
-			i_PatternTransition =
-				i_PatternTransition | (1 << (i_MaxChannel -
-					i_Count));
-			break;
-		case 4:
-			i_PatternTransition =
-				i_PatternTransition | (1 << (i_MaxChannel -
-					i_Count));
-			break;
-		case 5:
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"The option indicated in the event mask does not exist\n");
-			return -EINVAL;
-		}
-	}
-
-	if (data[0] == 1) {
-		/* Test the interrupt logic */
-
-		if (data[1] == APCI1500_AND ||
-			data[1] == APCI1500_OR ||
-			data[1] == APCI1500_OR_PRIORITY) {
-			/* Tests if a transition was declared */
-			/* for a OR PRIORITY logic            */
-
-			if (data[1] == APCI1500_OR_PRIORITY
-				&& i_PatternTransition != 0) {
-				dev_warn(dev->class_dev,
-					"Transition error on an OR PRIORITY logic\n");
-				return -EINVAL;
-			}
-
-			/* Tests if more than one transition */
-			/* was declared for an AND logic     */
-
-			if (data[1] == APCI1500_AND) {
-				for (i_Count = 0; i_Count < 8; i_Count++) {
-					i_PatternTransitionCount =
-						i_PatternTransitionCount +
-						((i_PatternTransition >>
-							i_Count) & 0x1);
-
-				}
-
-				if (i_PatternTransitionCount > 1) {
-					dev_warn(dev->class_dev,
-						"Transition error on an AND logic\n");
-					return -EINVAL;
-				}
-			}
-
-			/* Disable Port A */
-			z8536_write(dev, 0xf0,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-			z8536_write(dev, i_PatternPolarity,
-				    APCI1500_RW_PORT_A_PATTERN_POLARITY);
-			z8536_write(dev, i_PatternMask,
-				    APCI1500_RW_PORT_A_PATTERN_MASK);
-			z8536_write(dev, i_PatternTransition,
-				    APCI1500_RW_PORT_A_PATTERN_TRANSITION);
-
-			/* Port A new mode    */
-			i_RegValue = z8536_read(dev,
-					APCI1500_RW_PORT_A_SPECIFICATION);
-			i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9;
-			z8536_write(dev, i_RegValue,
-				    APCI1500_RW_PORT_A_SPECIFICATION);
-
-			i_Event1Status = 1;
-
-			/* Enable Port A */
-			z8536_write(dev, 0xf4,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-		} else {
-			dev_warn(dev->class_dev,
-				"The choice for interrupt logic does not exist\n");
-			return -EINVAL;
-		}
-	}
-
-	/* Test if event setting for port 2 */
-
-	if (data[0] == 2) {
-		/* Test the event logic */
-
-		if (data[1] == APCI1500_OR) {
-			/* Disable Port B */
-			z8536_write(dev, 0x74,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-			i_RegValue = z8536_read(dev,
-					APCI1500_RW_PORT_B_SPECIFICATION);
-			i_RegValue = i_RegValue & 0xF9;
-			z8536_write(dev, i_RegValue,
-				    APCI1500_RW_PORT_B_SPECIFICATION);
-
-			/* Selects error channels 1 and 2 */
-			i_PatternMask = (i_PatternMask | 0xC0);
-			i_PatternPolarity = (i_PatternPolarity | 0xC0);
-			i_PatternTransition = (i_PatternTransition | 0xC0);
-
-			z8536_write(dev, i_PatternPolarity,
-				    APCI1500_RW_PORT_B_PATTERN_POLARITY);
-			z8536_write(dev, i_PatternTransition,
-				    APCI1500_RW_PORT_B_PATTERN_TRANSITION);
-			z8536_write(dev, i_PatternMask,
-				    APCI1500_RW_PORT_B_PATTERN_MASK);
-
-			i_RegValue = z8536_read(dev,
-					APCI1500_RW_PORT_B_SPECIFICATION);
-			i_RegValue = (i_RegValue & 0xF9) | 4;
-			z8536_write(dev, i_RegValue,
-				    APCI1500_RW_PORT_B_SPECIFICATION);
-
-			i_Event2Status = 1;
-
-			/* Enable Port B */
-			z8536_write(dev, 0xf4,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-		} else {
-			dev_warn(dev->class_dev,
-				"The choice for interrupt logic does not exist\n");
-			return -EINVAL;
-		}
-	}
-
-	return insn->n;
-}
-
-/*
- * Allows or disallows a port event
- *
- * data[0] 0 = Start input event, 1 = Stop input event
- * data[1] Number of port (1 or 2)
- */
-static int apci1500_di_write(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn,
-			     unsigned int *data)
-{
-	int i_Event1InterruptStatus = 0, i_Event2InterruptStatus =
-		0, i_RegValue;
-
-	switch (data[0]) {
-	case START:
-		/* Tests the port number */
-
-		if (data[1] == 1 || data[1] == 2) {
-			/* Test if port 1 selected */
-
-			if (data[1] == 1) {
-				/* Test if event initialised */
-				if (i_Event1Status == 1) {
-					/* Disable Port A */
-					z8536_write(dev, 0xf0,
-					    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-					/* Allows the pattern interrupt      */
-					z8536_write(dev, 0xc0,
-					    APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
-					/* Enable Port A */
-					z8536_write(dev, 0xf4,
-					    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-					i_Event1InterruptStatus = 1;
-
-					i_RegValue = z8536_read(dev,
-					    APCI1500_RW_PORT_A_SPECIFICATION);
-
-					/* Authorizes the main interrupt on the board */
-					z8536_write(dev, 0xd0,
-					    APCI1500_RW_MASTER_INTERRUPT_CONTROL);
-				} else {
-					dev_warn(dev->class_dev,
-						"Event 1 not initialised\n");
-					return -EINVAL;
-				}
-			}
-			if (data[1] == 2) {
-
-				if (i_Event2Status == 1) {
-					/* Disable Port B */
-					z8536_write(dev, 0x74,
-					    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-					/* Allows the pattern interrupt      */
-					z8536_write(dev, 0xc0,
-					    APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
-					/* Enable Port B */
-					z8536_write(dev, 0xf4,
-					    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-					/* Authorizes the main interrupt on the board */
-					z8536_write(dev, 0xd0,
-					    APCI1500_RW_MASTER_INTERRUPT_CONTROL);
-
-					i_Event2InterruptStatus = 1;
-				} else {
-					dev_warn(dev->class_dev,
-						"Event 2 not initialised\n");
-					return -EINVAL;
-				}
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"The port parameter is in error\n");
-			return -EINVAL;
-		}
-
-		break;
-
-	case STOP:
-		/* Tests the port number */
-
-		if (data[1] == 1 || data[1] == 2) {
-			/* Test if port 1 selected */
-
-			if (data[1] == 1) {
-				/* Test if event initialised */
-				if (i_Event1Status == 1) {
-					/* Disable Port A */
-					z8536_write(dev, 0xf0,
-					    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-					/* Inhibits the pattern interrupt */
-					z8536_write(dev, 0xe0,
-					    APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
-					/* Enable Port A */
-					z8536_write(dev, 0xf4,
-					    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-					i_Event1InterruptStatus = 0;
-				} else {
-					dev_warn(dev->class_dev,
-						"Event 1 not initialised\n");
-					return -EINVAL;
-				}
-			}
-			if (data[1] == 2) {
-				/* Test if event initialised */
-				if (i_Event2Status == 1) {
-					/* Disable Port B */
-					z8536_write(dev, 0x74,
-					    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-					/* Inhibits the pattern interrupt      */
-					z8536_write(dev, 0xe0,
-					    APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
-					/* Enable Port B */
-					z8536_write(dev, 0xf4,
-					    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-					i_Event2InterruptStatus = 0;
-				} else {
-
-					dev_warn(dev->class_dev,
-						"Event 2 not initialised\n");
-					return -EINVAL;
-				}
-			}
-
-		} else {
-			dev_warn(dev->class_dev,
-				"The port parameter is in error\n");
-			return -EINVAL;
-		}
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			"The option of START/STOP logic does not exist\n");
-		return -EINVAL;
-	}
-
-	return insn->n;
-}
-
-/*
- * Return the status of the digital input
- */
-static int apci1500_di_read(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn,
-			    unsigned int *data)
-{
-	/* Software reset */
-	z8536_reset(dev);
-
-	return insn->n;
-}
-
-static int apci1500_di_insn_bits(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn,
-				 unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-
-	data[1] = inw(devpriv->addon + APCI1500_DI_REG);
-
-	return insn->n;
-}
-
-/*
- * Configures the digital output memory and the digital output error interrupt
- *
- * data[1] 1 = Enable the voltage error interrupt
- *	   2 = Disable the voltage error interrupt
- */
-static int apci1500_do_config(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn,
-			      unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-
-	devpriv->b_OutputMemoryStatus = data[0];
-	return insn->n;
-}
-
-/*
- * Writes port value to the selected port
- */
-static int apci1500_do_write(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn,
-			     unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	static unsigned int ui_Temp;
-	unsigned int ui_Temp1;
-	unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec);	/*  get the channel */
-
-	if (!devpriv->b_OutputMemoryStatus)
-		ui_Temp = 0;
-
-	if (data[3] == 0) {
-		if (data[1] == 0) {
-			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
-			outw(data[0], devpriv->addon + APCI1500_DO_REG);
-		} else {
-			if (data[1] == 1) {
-				switch (ui_NoOfChannel) {
-
-				case 2:
-					data[0] =
-						(data[0] << (2 *
-							data[2])) | ui_Temp;
-					break;
-
-				case 4:
-					data[0] =
-						(data[0] << (4 *
-							data[2])) | ui_Temp;
-					break;
-
-				case 8:
-					data[0] =
-						(data[0] << (8 *
-							data[2])) | ui_Temp;
-					break;
-
-				case 15:
-					data[0] = data[0] | ui_Temp;
-					break;
-
-				default:
-					dev_err(dev->class_dev,
-						"chan spec wrong\n");
-					return -EINVAL;	/*  "sorry channel spec wrong " */
-
-				}
-
-				outw(data[0], devpriv->addon + APCI1500_DO_REG);
-			} else {
-				dev_warn(dev->class_dev,
-					"Specified channel not supported\n");
-				return -EINVAL;
-			}
-		}
-	} else {
-		if (data[3] == 1) {
-			if (data[1] == 0) {
-				data[0] = ~data[0] & 0x1;
-				ui_Temp1 = 1;
-				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
-				ui_Temp = ui_Temp | ui_Temp1;
-				data[0] =
-					(data[0] << ui_NoOfChannel) ^
-					0xffffffff;
-				data[0] = data[0] & ui_Temp;
-				outw(data[0], devpriv->addon + APCI1500_DO_REG);
-			} else {
-				if (data[1] == 1) {
-					switch (ui_NoOfChannel) {
-
-					case 2:
-						data[0] = ~data[0] & 0x3;
-						ui_Temp1 = 3;
-						ui_Temp1 =
-							ui_Temp1 << 2 * data[2];
-						ui_Temp = ui_Temp | ui_Temp1;
-						data[0] =
-							((data[0] << (2 *
-									data
-									[2])) ^
-							0xffffffff) & ui_Temp;
-						break;
-
-					case 4:
-						data[0] = ~data[0] & 0xf;
-						ui_Temp1 = 15;
-						ui_Temp1 =
-							ui_Temp1 << 4 * data[2];
-						ui_Temp = ui_Temp | ui_Temp1;
-						data[0] =
-							((data[0] << (4 *
-									data
-									[2])) ^
-							0xffffffff) & ui_Temp;
-						break;
-
-					case 8:
-						data[0] = ~data[0] & 0xff;
-						ui_Temp1 = 255;
-						ui_Temp1 =
-							ui_Temp1 << 8 * data[2];
-						ui_Temp = ui_Temp | ui_Temp1;
-						data[0] =
-							((data[0] << (8 *
-									data
-									[2])) ^
-							0xffffffff) & ui_Temp;
-						break;
-
-					case 15:
-						break;
-
-					default:
-						dev_err(dev->class_dev,
-							"chan spec wrong\n");
-						return -EINVAL;	/*  "sorry channel spec wrong " */
-
-					}
-
-					outw(data[0],
-					     devpriv->addon + APCI1500_DO_REG);
-				} else {
-					dev_warn(dev->class_dev,
-						"Specified channel not supported\n");
-					return -EINVAL;
-				}
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"Specified functionality does not exist\n");
-			return -EINVAL;
-		}
-	}
-	ui_Temp = data[0];
-	return insn->n;
-}
-
-/*
- * Configures The Watchdog
- *
- * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ
- * data[1] 0 = Counter1/Timer1, 1 =  Counter2/Timer2, 2 = Counter3/Watchdog
- * data[2] 0 = Counter, 1 = Timer/Watchdog
- * data[3] This parameter has two meanings. If the counter/timer is used as
- *	a counter the limit value of the counter is given. If the counter/timer
- *	is used as a timer, the divider factor for the output is given.
- * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE
- * data[5] 0 = Software Trigger, 1 = Hardware Trigger
- * data[6] 0 = Software gate, 1 = Hardware gate
- * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable
- */
-static int apci1500_timer_config(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn,
-				 unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_TimerCounterMode, i_MasterConfiguration;
-
-	devpriv->tsk_Current = current;
-
-	/* Selection of the input clock */
-	if (data[0] == 0 || data[0] == 1 || data[0] == 2) {
-		outw(data[0], devpriv->addon + APCI1500_CLK_SEL_REG);
-	} else {
-		if (data[0] != 3) {
-			dev_warn(dev->class_dev,
-				"The option for input clock selection does not exist\n");
-			return -EINVAL;
-		}
-	}
-	/* Select the counter/timer */
-	switch (data[1]) {
-	case COUNTER1:
-		/* selecting counter or timer */
-		switch (data[2]) {
-		case 0:
-			data[2] = APCI1500_COUNTER;
-			break;
-		case 1:
-			data[2] = APCI1500_TIMER;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice is not a timer nor a counter\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  single or continuous mode */
-		switch (data[4]) {
-		case 0:
-			data[4] = APCI1500_CONTINUOUS;
-			break;
-		case 1:
-			data[4] = APCI1500_SINGLE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This option for single/continuous mode does not exist\n");
-			return -EINVAL;
-		}
-
-		i_TimerCounterMode = data[2] | data[4] | 7;
-		/* Test the reload value */
-
-		if ((data[3] >= 0) && (data[3] <= 65535)) {
-			if (data[7] == APCI1500_ENABLE ||
-			    data[7] == APCI1500_DISABLE) {
-				/* Writes the new mode */
-				z8536_write(dev, i_TimerCounterMode,
-				    APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION);
-
-				/* Writes the low value */
-				z8536_write(dev, data[3],
-					    APCI1500_RW_CPT_TMR1_TIME_CST_LOW);
-				/* Writes the high value  */
-				data[3] = data[3] >> 8;
-				z8536_write(dev, data[3],
-					    APCI1500_RW_CPT_TMR1_TIME_CST_HIGH);
-
-				/* Enables timer/counter 1 and triggers timer/counter 1 */
-				i_MasterConfiguration = z8536_read(dev,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-				i_MasterConfiguration =
-					i_MasterConfiguration | 0x40;
-				z8536_write(dev, i_MasterConfiguration,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-				/* Disable timer/counter 1 */
-				z8536_write(dev, 0x00,
-					    APCI1500_RW_CPT_TMR1_CMD_STATUS);
-				/* Trigger timer/counter 1 */
-				z8536_write(dev, 0x02,
-					    APCI1500_RW_CPT_TMR1_CMD_STATUS);
-			} else {
-				dev_warn(dev->class_dev,
-					"Error in selection of interrupt enable or disable\n");
-				return -EINVAL;
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"Error in selection of reload value\n");
-			return -EINVAL;
-		}
-		i_TimerCounterWatchdogInterrupt = data[7];
-		i_TimerCounter1Init = 1;
-		break;
-
-	case COUNTER2:		/* selecting counter or timer */
-		switch (data[2]) {
-		case 0:
-			data[2] = APCI1500_COUNTER;
-			break;
-		case 1:
-			data[2] = APCI1500_TIMER;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice is not a timer nor a counter\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  single or continuous mode */
-		switch (data[4]) {
-		case 0:
-			data[4] = APCI1500_CONTINUOUS;
-			break;
-		case 1:
-			data[4] = APCI1500_SINGLE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This option for single/continuous mode does not exist\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  software or hardware trigger */
-		switch (data[5]) {
-		case 0:
-			data[5] = APCI1500_SOFTWARE_TRIGGER;
-			break;
-		case 1:
-			data[5] = APCI1500_HARDWARE_TRIGGER;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice for software or hardware trigger does not exist\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  software or hardware gate */
-		switch (data[6]) {
-		case 0:
-			data[6] = APCI1500_SOFTWARE_GATE;
-			break;
-		case 1:
-			data[6] = APCI1500_HARDWARE_GATE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice for software or hardware gate does not exist\n");
-			return -EINVAL;
-		}
-
-		i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7;
-
-		/* Test the reload value */
-
-		if ((data[3] >= 0) && (data[3] <= 65535)) {
-			if (data[7] == APCI1500_ENABLE ||
-			    data[7] == APCI1500_DISABLE) {
-				/* Writes the new mode */
-				z8536_write(dev, i_TimerCounterMode,
-				    APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION);
-
-				/* Writes the low value */
-				z8536_write(dev, data[3],
-					    APCI1500_RW_CPT_TMR2_TIME_CST_LOW);
-				/* Writes the high value */
-				data[3] = data[3] >> 8;
-				z8536_write(dev, data[3],
-					    APCI1500_RW_CPT_TMR2_TIME_CST_HIGH);
-
-				/* Enables timer/counter 2 and triggers timer/counter 2 */
-				i_MasterConfiguration = z8536_read(dev,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-				i_MasterConfiguration =
-					i_MasterConfiguration | 0x20;
-				z8536_write(dev, i_MasterConfiguration,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-				/* Disable timer/counter 2 */
-				z8536_write(dev, 0x00,
-					    APCI1500_RW_CPT_TMR2_CMD_STATUS);
-				/* Trigger timer/counter 1 */
-				z8536_write(dev, 0x02,
-					    APCI1500_RW_CPT_TMR2_CMD_STATUS);
-			} else {
-				dev_warn(dev->class_dev,
-					"Error in selection of interrupt enable or disable\n");
-				return -EINVAL;
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"Error in selection of reload value\n");
-			return -EINVAL;
-		}
-		i_TimerCounterWatchdogInterrupt = data[7];
-		i_TimerCounter2Init = 1;
-		break;
-
-	case COUNTER3:		/* selecting counter or watchdog */
-		switch (data[2]) {
-		case 0:
-			data[2] = APCI1500_COUNTER;
-			break;
-		case 1:
-			data[2] = APCI1500_WATCHDOG;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice is not a watchdog nor a counter\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  single or continuous mode */
-		switch (data[4]) {
-		case 0:
-			data[4] = APCI1500_CONTINUOUS;
-			break;
-		case 1:
-			data[4] = APCI1500_SINGLE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This option for single/continuous mode does not exist\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  software or hardware gate */
-		switch (data[6]) {
-		case 0:
-			data[6] = APCI1500_SOFTWARE_GATE;
-			break;
-		case 1:
-			data[6] = APCI1500_HARDWARE_GATE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice for software or hardware gate does not exist\n");
-			return -EINVAL;
-		}
-
-		/* Test if used for watchdog */
-
-		if (data[2] == APCI1500_WATCHDOG) {
-			/* - Enables the output line */
-			/* - Enables retrigger       */
-			/* - Pulses output           */
-			i_TimerCounterMode = data[2] | data[4] | 0x54;
-		} else {
-			i_TimerCounterMode = data[2] | data[4] | data[6] | 7;
-		}
-		/* Test the reload value */
-
-		if ((data[3] >= 0) && (data[3] <= 65535)) {
-			if (data[7] == APCI1500_ENABLE ||
-			    data[7] == APCI1500_DISABLE) {
-				/* Writes the new mode */
-				z8536_write(dev, i_TimerCounterMode,
-				    APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION);
-
-				/* Writes the low value  */
-				z8536_write(dev, data[3],
-					    APCI1500_RW_CPT_TMR3_TIME_CST_LOW);
-				/* Writes the high value  */
-				data[3] = data[3] >> 8;
-				z8536_write(dev, data[3],
-					    APCI1500_RW_CPT_TMR3_TIME_CST_HIGH);
-
-				/* Enables watchdog/counter 3 and triggers watchdog/counter 3 */
-				i_MasterConfiguration = z8536_read(dev,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-				i_MasterConfiguration =
-					i_MasterConfiguration | 0x10;
-				z8536_write(dev, i_MasterConfiguration,
-				    APCI1500_RW_MASTER_CONFIGURATION_CONTROL);
-
-				/* Test if COUNTER */
-				if (data[2] == APCI1500_COUNTER) {
-					/* Disable the  watchdog/counter 3 and starts it */
-					z8536_write(dev, 0x00,
-					    APCI1500_RW_CPT_TMR3_CMD_STATUS);
-					/* Trigger the  watchdog/counter 3 and starts it */
-					z8536_write(dev, 0x02,
-					    APCI1500_RW_CPT_TMR3_CMD_STATUS);
-				}
-
-			} else {
-
-				dev_warn(dev->class_dev,
-					"Error in selection of interrupt enable or disable\n");
-				return -EINVAL;
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"Error in selection of reload value\n");
-			return -EINVAL;
-		}
-		i_TimerCounterWatchdogInterrupt = data[7];
-		i_WatchdogCounter3Init = 1;
-		break;
-
-	default:
-		dev_warn(dev->class_dev,
-			"The specified counter/timer option does not exist\n");
-		return -EINVAL;
-	}
-	i_CounterLogic = data[2];
-	return insn->n;
-}
-
-/*
- * Start / Stop or trigger the timer counter or Watchdog
- *
- * data[0] 0 = Counter1/Timer1, 1 =  Counter2/Timer2, 2 = Counter3/Watchdog
- * data[1] 0 = Start, 1 = Stop, 2 = Trigger
- * data[2] 0 = Counter, 1 = Timer/Watchdog
- */
-static int apci1500_timer_write(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn,
-				unsigned int *data)
-{
-	int i_CommandAndStatusValue;
-
-	switch (data[0]) {
-	case COUNTER1:
-		switch (data[1]) {
-		case START:
-			if (i_TimerCounter1Init == 1) {
-				if (i_TimerCounterWatchdogInterrupt == 1)
-					i_CommandAndStatusValue = 0xC4;	/* Enable the interrupt */
-				else
-					i_CommandAndStatusValue = 0xE4;	/* disable the interrupt */
-
-				/* Starts timer/counter 1 */
-				i_TimerCounter1Enabled = 1;
-				z8536_write(dev, i_CommandAndStatusValue,
-					    APCI1500_RW_CPT_TMR1_CMD_STATUS);
-			} else {
-				dev_warn(dev->class_dev,
-					"Counter/Timer1 not configured\n");
-				return -EINVAL;
-			}
-			break;
-
-		case STOP:
-			/* Stop timer/counter 1 */
-			z8536_write(dev, 0x00, APCI1500_RW_CPT_TMR1_CMD_STATUS);
-			i_TimerCounter1Enabled = 0;
-			break;
-
-		case TRIGGER:
-			if (i_TimerCounter1Init == 1) {
-				if (i_TimerCounter1Enabled == 1) {
-					/* Set Trigger and gate */
-
-					i_CommandAndStatusValue = 0x6;
-				} else {
-					/* Set Trigger */
-
-					i_CommandAndStatusValue = 0x2;
-				}
-				z8536_write(dev, i_CommandAndStatusValue,
-					    APCI1500_RW_CPT_TMR1_CMD_STATUS);
-			} else {
-				dev_warn(dev->class_dev,
-					"Counter/Timer1 not configured\n");
-				return -EINVAL;
-			}
-			break;
-
-		default:
-			dev_warn(dev->class_dev,
-				"The specified option for start/stop/trigger does not exist\n");
-			return -EINVAL;
-		}
-		break;
-
-	case COUNTER2:
-		switch (data[1]) {
-		case START:
-			if (i_TimerCounter2Init == 1) {
-				if (i_TimerCounterWatchdogInterrupt == 1)
-					i_CommandAndStatusValue = 0xC4;	/* Enable the interrupt */
-				else
-					i_CommandAndStatusValue = 0xE4;	/* disable the interrupt */
-
-				/* Starts timer/counter 2 */
-				i_TimerCounter2Enabled = 1;
-				z8536_write(dev, i_CommandAndStatusValue,
-					    APCI1500_RW_CPT_TMR2_CMD_STATUS);
-			} else {
-				dev_warn(dev->class_dev,
-					"Counter/Timer2 not configured\n");
-				return -EINVAL;
-			}
-			break;
-
-		case STOP:
-			/* Stop timer/counter 2 */
-			z8536_write(dev, 0x00, APCI1500_RW_CPT_TMR2_CMD_STATUS);
-			i_TimerCounter2Enabled = 0;
-			break;
-		case TRIGGER:
-			if (i_TimerCounter2Init == 1) {
-				if (i_TimerCounter2Enabled == 1) {
-					/* Set Trigger and gate */
-
-					i_CommandAndStatusValue = 0x6;
-				} else {
-					/* Set Trigger */
-
-					i_CommandAndStatusValue = 0x2;
-				}
-				z8536_write(dev, i_CommandAndStatusValue,
-					    APCI1500_RW_CPT_TMR2_CMD_STATUS);
-			} else {
-				dev_warn(dev->class_dev,
-					"Counter/Timer2 not configured\n");
-				return -EINVAL;
-			}
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"The specified option for start/stop/trigger does not exist\n");
-			return -EINVAL;
-		}
-		break;
-	case COUNTER3:
-		switch (data[1]) {
-		case START:
-			if (i_WatchdogCounter3Init == 1) {
-
-				if (i_TimerCounterWatchdogInterrupt == 1)
-					i_CommandAndStatusValue = 0xC4;	/* Enable the interrupt */
-				else
-					i_CommandAndStatusValue = 0xE4;	/* disable the interrupt */
-
-				/* Starts Watchdog/counter 3 */
-				i_WatchdogCounter3Enabled = 1;
-				z8536_write(dev, i_CommandAndStatusValue,
-					    APCI1500_RW_CPT_TMR3_CMD_STATUS);
-			} else {
-				dev_warn(dev->class_dev,
-					"Watchdog/Counter3 not configured\n");
-				return -EINVAL;
-			}
-			break;
-
-		case STOP:
-			/* Stop Watchdog/counter 3 */
-			z8536_write(dev, 0x00, APCI1500_RW_CPT_TMR3_CMD_STATUS);
-			i_WatchdogCounter3Enabled = 0;
-			break;
-
-		case TRIGGER:
-			switch (data[2]) {
-			case 0:	/* triggering counter 3 */
-				if (i_WatchdogCounter3Init == 1) {
-					if (i_WatchdogCounter3Enabled == 1) {
-						/* Set Trigger and gate */
-
-						i_CommandAndStatusValue = 0x6;
-					} else {
-						/* Set Trigger */
-
-						i_CommandAndStatusValue = 0x2;
-					}
-					z8536_write(dev, i_CommandAndStatusValue,
-					    APCI1500_RW_CPT_TMR3_CMD_STATUS);
-				} else {
-					dev_warn(dev->class_dev,
-						"Counter3 not configured\n");
-					return -EINVAL;
-				}
-				break;
-			case 1:
-				/* triggering Watchdog 3 */
-				if (i_WatchdogCounter3Init == 1) {
-					z8536_write(dev, 0x06,
-					    APCI1500_RW_CPT_TMR3_CMD_STATUS);
-				} else {
-					dev_warn(dev->class_dev,
-						"Watchdog 3 not configured\n");
-					return -EINVAL;
-				}
-				break;
-			default:
-				dev_warn(dev->class_dev,
-					"Wrong choice of watchdog/counter3\n");
-				return -EINVAL;
-			}
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"The specified option for start/stop/trigger does not exist\n");
-			return -EINVAL;
-		}
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			"The specified choice for counter/watchdog/timer does not exist\n");
-		return -EINVAL;
-	}
-	return insn->n;
-}
-
-/*
- * Read The Watchdog
- *
- * data[0] 0 = Counter1/Timer1, 1 =  Counter2/Timer2, 2 = Counter3/Watchdog
- */
-static int apci1500_timer_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn,
-			       unsigned int *data)
-{
-	int i_CommandAndStatusValue;
-
-	switch (data[0]) {
-	case COUNTER1:
-		/* Read counter/timer1 */
-		if (i_TimerCounter1Init == 1) {
-			if (i_TimerCounter1Enabled == 1) {
-				/* Set RCC and gate */
-
-				i_CommandAndStatusValue = 0xC;
-			} else {
-				/* Set RCC */
-
-				i_CommandAndStatusValue = 0x8;
-			}
-			z8536_write(dev, i_CommandAndStatusValue,
-				    APCI1500_RW_CPT_TMR1_CMD_STATUS);
-
-			data[0] = z8536_read(dev,
-					     APCI1500_R_CPT_TMR1_VALUE_HIGH);
-			data[0] = data[0] << 8;
-			data[0] = data[0] & 0xff00;
-			data[0] |= z8536_read(dev,
-					      APCI1500_R_CPT_TMR1_VALUE_LOW);
-		} else {
-			dev_warn(dev->class_dev,
-				"Timer/Counter1 not configured\n");
-			return -EINVAL;
-		}
-		break;
-	case COUNTER2:
-		/* Read counter/timer2 */
-		if (i_TimerCounter2Init == 1) {
-			if (i_TimerCounter2Enabled == 1) {
-				/* Set RCC and gate */
-
-				i_CommandAndStatusValue = 0xC;
-			} else {
-				/* Set RCC */
-
-				i_CommandAndStatusValue = 0x8;
-			}
-			z8536_write(dev, i_CommandAndStatusValue,
-				    APCI1500_RW_CPT_TMR2_CMD_STATUS);
-
-			data[0] = z8536_read(dev,
-					     APCI1500_R_CPT_TMR2_VALUE_HIGH);
-			data[0] = data[0] << 8;
-			data[0] = data[0] & 0xff00;
-			data[0] |= z8536_read(dev,
-					      APCI1500_R_CPT_TMR2_VALUE_LOW);
-		} else {
-			dev_warn(dev->class_dev,
-				"Timer/Counter2 not configured\n");
-			return -EINVAL;
-		}
-		break;
-	case COUNTER3:
-		/* Read counter/watchdog2 */
-		if (i_WatchdogCounter3Init == 1) {
-			if (i_WatchdogCounter3Enabled == 1) {
-				/* Set RCC and gate */
-
-				i_CommandAndStatusValue = 0xC;
-			} else {
-				/* Set RCC */
-
-				i_CommandAndStatusValue = 0x8;
-			}
-			z8536_write(dev, i_CommandAndStatusValue,
-				    APCI1500_RW_CPT_TMR3_CMD_STATUS);
-
-			data[0] = z8536_read(dev,
-					     APCI1500_R_CPT_TMR3_VALUE_HIGH);
-			data[0] = data[0] << 8;
-			data[0] = data[0] & 0xff00;
-			data[0] |= z8536_read(dev,
-					      APCI1500_R_CPT_TMR3_VALUE_LOW);
-		} else {
-			dev_warn(dev->class_dev,
-				"WatchdogCounter3 not configured\n");
-			return -EINVAL;
-		}
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			"The choice of timer/counter/watchdog does not exist\n");
-		return -EINVAL;
-	}
-
-	return insn->n;
-}
-
-/*
- * Read the interrupt mask
- *
- * data[0] The interrupt mask value
- * data[1] Channel Number
- */
-static int apci1500_timer_read(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn,
-			       unsigned int *data)
-{
-	data[0] = i_InterruptMask;
-	data[1] = i_InputChannel;
-	i_InterruptMask = 0;
-	return insn->n;
-}
-
-/*
- * Configures the interrupt registers
- */
-static int apci1500_do_bits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn,
-			    unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_RegValue;
-	int i_Constant;
-
-	devpriv->tsk_Current = current;
-	outl(0x0, devpriv->amcc + AMCC_OP_REG_INTCSR);
-	if (data[0] == 1) {
-		i_Constant = 0xC0;
-	} else {
-		if (data[0] == 0) {
-			i_Constant = 0x00;
-		} else {
-			dev_warn(dev->class_dev,
-				"The parameter passed to driver is in error for enabling the voltage interrupt\n");
-			return -EINVAL;
-		}
-	}
-
-	/* Writes the new configuration (APCI1500_OR) */
-	i_RegValue = z8536_read(dev, APCI1500_RW_PORT_B_SPECIFICATION);
-	i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR;
-	z8536_write(dev, i_RegValue, APCI1500_RW_PORT_B_SPECIFICATION);
-
-	/* Authorises the interrupt on the board */
-	z8536_write(dev, 0xc0, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
-
-	z8536_write(dev, i_Constant, APCI1500_RW_PORT_B_PATTERN_POLARITY);
-	z8536_write(dev, i_Constant, APCI1500_RW_PORT_B_PATTERN_TRANSITION);
-	z8536_write(dev, i_Constant, APCI1500_RW_PORT_B_PATTERN_MASK);
-
-	/* Deletes the interrupt of port A */
-	i_RegValue = z8536_read(dev, APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	z8536_write(dev, i_RegValue, APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
-
-	/* Deletes the interrupt of port B */
-	i_RegValue = z8536_read(dev, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	z8536_write(dev, i_RegValue, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
-
-	/* Deletes the interrupt of timer 1 */
-	i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR1_CMD_STATUS);
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	z8536_write(dev, i_RegValue, APCI1500_RW_CPT_TMR1_CMD_STATUS);
-
-	/* Deletes the interrupt of timer 2 */
-	i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR2_CMD_STATUS);
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	z8536_write(dev, i_RegValue, APCI1500_RW_CPT_TMR2_CMD_STATUS);
-
-	/* Deletes the interrupt of timer 3 */
-	i_RegValue = z8536_read(dev, APCI1500_RW_CPT_TMR3_CMD_STATUS);
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	z8536_write(dev, i_RegValue, APCI1500_RW_CPT_TMR3_CMD_STATUS);
-
-	/* Authorizes the main interrupt on the board */
-	z8536_write(dev, 0xd0, APCI1500_RW_MASTER_INTERRUPT_CONTROL);
-
-	/* Enables the PCI interrupt */
-	outl(0x2000 | INTCSR_INBOX_FULL_INT,
-	     devpriv->amcc + AMCC_OP_REG_INTCSR);
-	inl(devpriv->amcc + AMCC_OP_REG_IMB1);
-	inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
-	outl(INTCSR_INBOX_INTR_STATUS | 0x2000 | INTCSR_INBOX_FULL_INT,
-	     devpriv->amcc + AMCC_OP_REG_INTCSR);
-
-	return insn->n;
-}
-
-static irqreturn_t apci1500_interrupt(int irq, void *d)
-{
-
-	struct comedi_device *dev = d;
-	struct apci1500_private *devpriv = dev->private;
-	unsigned int val;
-
-	/* Clear the interrupt mask */
-	i_InterruptMask = 0;
-
-	val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
-	if (!(val & INTCSR_INTR_ASSERTED))
-		return IRQ_NONE;
-
-	/* 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);
-
-			val = z8536_read(dev,
-					 APCI1500_RW_PORT_A_INTERRUPT_CONTROL);
-
-			i_InputChannel = 1 + (val >> 1);
-
-		} else {
-			i_InputChannel = 0;
-		}
-	}
-
-	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;
-		}
-	}
-
-	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_InterruptMask |= 0x04;
-	}
-
-	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);
-
-		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;
-}
-
-static int apci1500_reset(struct comedi_device *dev)
-{
-	struct apci1500_private *devpriv = dev->private;
-
-	i_TimerCounter1Init = 0;
-	i_TimerCounter2Init = 0;
-	i_WatchdogCounter3Init = 0;
-	i_Event1Status = 0;
-	i_Event2Status = 0;
-	i_TimerCounterWatchdogInterrupt = 0;
-	i_Logic = 0;
-	i_CounterLogic = 0;
-	i_InterruptMask = 0;
-	i_InputChannel = 0;
-	i_TimerCounter1Enabled = 0;
-	i_TimerCounter2Enabled = 0;
-	i_WatchdogCounter3Enabled = 0;
-
-	/* Software reset */
-	z8536_reset(dev);
-
-	/* reset all the digital outputs */
-	outw(0x0, devpriv->addon + APCI1500_DO_REG);
-
-	/* Deactivates all interrupts */
-	z8536_write(dev, 0x00, APCI1500_RW_MASTER_INTERRUPT_CONTROL);
-	z8536_write(dev, 0x00, APCI1500_RW_PORT_A_COMMAND_AND_STATUS);
-	z8536_write(dev, 0x00, APCI1500_RW_PORT_B_COMMAND_AND_STATUS);
-	z8536_write(dev, 0x00, APCI1500_RW_CPT_TMR1_CMD_STATUS);
-	z8536_write(dev, 0x00, APCI1500_RW_CPT_TMR2_CMD_STATUS);
-	z8536_write(dev, 0x00, APCI1500_RW_CPT_TMR3_CMD_STATUS);
-
-	return 0;
-}
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index 6892c0a..fc7db1d 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -1,11 +1,34 @@
+/*
+ * addi_apci_1500.c
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data.com
+ *	info@xxxxxxxxxxxxx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/sched.h>
 #include <linux/interrupt.h>
 
 #include "../comedidev.h"
 #include "comedi_fc.h"
 #include "amcc_s5933.h"
+#include "z8536.h"
 
 /*
  * PCI Bar 0 Register map (devpriv->amcc)
@@ -14,6 +37,7 @@
 
 /*
  * PCI Bar 1 Register map (dev->iobase)
+ * see z8536.h for Z8536 internal registers and bit defines
  */
 #define APCI1500_Z8536_PORTC_REG	0x00
 #define APCI1500_Z8536_PORTB_REG	0x01
@@ -30,11 +54,702 @@
 struct apci1500_private {
 	unsigned long amcc;
 	unsigned long addon;
-	unsigned char b_OutputMemoryStatus;
-	struct task_struct *tsk_Current;
+
+	unsigned int clk_src;
+
+	/* Digital trigger configuration [0]=AND [1]=OR */
+	unsigned int pm[2];	/* Pattern Mask */
+	unsigned int pt[2];	/* Pattern Transition */
+	unsigned int pp[2];	/* Pattern Polarity */
 };
 
-#include "addi-data/hwdrv_apci1500.c"
+static unsigned int z8536_read(struct comedi_device *dev, unsigned int reg)
+{
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+	outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	val = inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+
+	return val;
+}
+
+static void z8536_write(struct comedi_device *dev,
+			unsigned int val, unsigned int reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+	outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(val, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+}
+
+static void z8536_reset(struct comedi_device *dev)
+{
+	unsigned long flags;
+
+	/*
+	 * Even if the state of the Z8536 is not known, the following
+	 * sequence will reset it and put it in State 0.
+	 */
+	spin_lock_irqsave(&dev->spinlock, flags);
+	inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(1, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+
+	/* Disable all Ports and Counter/Timers */
+	z8536_write(dev, 0x00, Z8536_CFG_CTRL_REG);
+
+	/*
+	 * Port A is connected to Ditial Input channels 0-7.
+	 * Configure the port to allow interrupt detection.
+	 */
+	z8536_write(dev, Z8536_PAB_MODE_PTS_BIT |
+			 Z8536_PAB_MODE_SB |
+			 Z8536_PAB_MODE_PMS_DISABLE,
+		    Z8536_PA_MODE_REG);
+	z8536_write(dev, 0xff, Z8536_PB_DPP_REG);
+	z8536_write(dev, 0xff, Z8536_PA_DD_REG);
+
+	/*
+	 * Port B is connected to Ditial Input channels 8-13.
+	 * Configure the port to allow interrupt detection.
+	 *
+	 * NOTE: Bits 7 and 6 of Port B are connected to internal
+	 * diagnostic signals and bit 7 is inverted.
+	 */
+	z8536_write(dev, Z8536_PAB_MODE_PTS_BIT |
+			 Z8536_PAB_MODE_SB |
+			 Z8536_PAB_MODE_PMS_DISABLE,
+		    Z8536_PB_MODE_REG);
+	z8536_write(dev, 0x7f, Z8536_PB_DPP_REG);
+	z8536_write(dev, 0xff, Z8536_PB_DD_REG);
+
+	/*
+	 * Not sure what Port C is connected to...
+	 */
+	z8536_write(dev, 0x09, Z8536_PC_DPP_REG);
+	z8536_write(dev, 0x0e, Z8536_PC_DD_REG);
+
+	/*
+	 * Clear and disable all interrupt sources.
+	 *
+	 * Just in case, the reset of the Z8536 should have already
+	 * done this.
+	 */
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PA_CMDSTAT_REG);
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG);
+
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PB_CMDSTAT_REG);
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG);
+
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(0));
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(0));
+
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(1));
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(1));
+
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(2));
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(2));
+
+	/* Disable all interrupts */
+	z8536_write(dev, 0x00, Z8536_INT_CTRL_REG);
+}
+
+static void apci1500_port_enable(struct comedi_device *dev, bool enable)
+{
+	unsigned int cfg;
+
+	cfg = z8536_read(dev, Z8536_CFG_CTRL_REG);
+	if (enable)
+		cfg |= (Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE);
+	else
+		cfg &= ~(Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE);
+	z8536_write(dev, cfg, Z8536_CFG_CTRL_REG);
+}
+
+static void apci1500_timer_enable(struct comedi_device *dev,
+				  unsigned int chan, bool enable)
+{
+	unsigned int bit;
+	unsigned int cfg;
+
+	if (chan == 0)
+		bit = Z8536_CFG_CTRL_CT1E;
+	else if (chan == 1)
+		bit = Z8536_CFG_CTRL_CT2E;
+	else
+		bit = Z8536_CFG_CTRL_PCE_CT3E;
+
+	cfg = z8536_read(dev, Z8536_CFG_CTRL_REG);
+	if (enable) {
+		cfg |= bit;
+	} else {
+		cfg &= ~bit;
+		z8536_write(dev, 0x00, Z8536_CT_CMDSTAT_REG(chan));
+	}
+	z8536_write(dev, cfg, Z8536_CFG_CTRL_REG);
+}
+
+static bool apci1500_ack_irq(struct comedi_device *dev,
+			     unsigned int reg)
+{
+	unsigned int val;
+
+	val = z8536_read(dev, reg);
+	if ((val & Z8536_STAT_IE_IP) == Z8536_STAT_IE_IP) {
+		val &= 0x0f;			/* preserve any write bits */
+		val |= Z8536_CMD_CLR_IP_IUS;
+		z8536_write(dev, val, reg);
+
+		return true;
+	}
+	return false;
+}
+
+static irqreturn_t apci1500_interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	struct apci1500_private *devpriv = dev->private;
+	struct comedi_subdevice *s = dev->read_subdev;
+	unsigned int status = 0;
+	unsigned int val;
+
+	val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
+	if (!(val & INTCSR_INTR_ASSERTED))
+		return IRQ_NONE;
+
+	if (apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG))
+		status |= 0x01;	/* port a event (inputs 0-7) */
+
+	if (apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG)) {
+		/* Tests if this is an external error */
+		val = inb(dev->iobase + APCI1500_Z8536_PORTB_REG);
+		val &= 0xc0;
+		if (val) {
+			if (val & 0x80)	/* voltage error */
+				status |= 0x40;
+			if (val & 0x40)	/* short circuit error */
+				status |= 0x80;
+		} else {
+			status |= 0x02;	/* port b event (inputs 8-13) */
+		}
+	}
+
+	/*
+	 * NOTE: The 'status' returned by the sample matches the
+	 * interrupt mask information from the APCI-1500 Users Manual.
+	 *
+	 *    Mask     Meaning
+	 * ----------  ------------------------------------------
+	 * 0x00000001  Event 1 has occured
+	 * 0x00000010  Event 2 has occured
+	 * 0x00000100  Counter/timer 1 has run down (not implemented)
+	 * 0x00001000  Counter/timer 2 has run down (not implemented)
+	 * 0x00010000  Counter 3 has run down (not implemented)
+	 * 0x00100000  Watchdog has run down (not implemented)
+	 * 0x01000000  Voltage error
+	 * 0x10000000  Short-circuit error
+	 */
+	comedi_buf_write_samples(s, &status, 1);
+	comedi_handle_events(dev, s);
+
+	return IRQ_HANDLED;
+}
+
+static int apci1500_di_cancel(struct comedi_device *dev,
+			      struct comedi_subdevice *s)
+{
+	/* Disables the main interrupt on the board */
+	z8536_write(dev, 0x00, Z8536_INT_CTRL_REG);
+
+	/* Disable Ports A & B */
+	apci1500_port_enable(dev, false);
+
+	/* Ack any pending interrupts */
+	apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG);
+	apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG);
+
+	/* Disable pattern interrupts */
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG);
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG);
+
+	/* Enable Ports A & B */
+	apci1500_port_enable(dev, true);
+
+	return 0;
+}
+
+static int apci1500_di_inttrig_start(struct comedi_device *dev,
+				     struct comedi_subdevice *s,
+				     unsigned int trig_num)
+{
+	struct apci1500_private *devpriv = dev->private;
+	struct comedi_cmd *cmd = &s->async->cmd;
+	unsigned int pa_mode = Z8536_PAB_MODE_PMS_DISABLE;
+	unsigned int pb_mode = Z8536_PAB_MODE_PMS_DISABLE;
+	unsigned int pa_trig = trig_num & 0x01;
+	unsigned int pb_trig = trig_num & 0x02;
+	bool valid_trig = false;
+	unsigned int val;
+
+	if (trig_num != cmd->start_arg)
+		return -EINVAL;
+
+	/* Disable Ports A & B */
+	apci1500_port_enable(dev, false);
+
+	/* Set Port A for selected trigger pattern */
+	z8536_write(dev, devpriv->pm[pa_trig] & 0xff, Z8536_PA_PM_REG);
+	z8536_write(dev, devpriv->pt[pa_trig] & 0xff, Z8536_PA_PT_REG);
+	z8536_write(dev, devpriv->pp[pa_trig] & 0xff, Z8536_PA_PP_REG);
+
+	/* Set Port B for selected trigger pattern */
+	z8536_write(dev, (devpriv->pm[pb_trig] >> 8) & 0xff, Z8536_PB_PM_REG);
+	z8536_write(dev, (devpriv->pt[pb_trig] >> 8) & 0xff, Z8536_PB_PT_REG);
+	z8536_write(dev, (devpriv->pp[pb_trig] >> 8) & 0xff, Z8536_PB_PP_REG);
+
+	/* Set Port A trigger mode (if enabled) and enable interrupt */
+	if (devpriv->pm[pa_trig] & 0xff) {
+		pa_mode = pa_trig ? Z8536_PAB_MODE_PMS_AND
+				  : Z8536_PAB_MODE_PMS_OR;
+
+		val = z8536_read(dev, Z8536_PA_MODE_REG);
+		val &= ~Z8536_PAB_MODE_PMS_MASK;
+		val |= (pa_mode | Z8536_PAB_MODE_IMO);
+		z8536_write(dev, val, Z8536_PA_MODE_REG);
+
+		z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PA_CMDSTAT_REG);
+
+		valid_trig = true;
+
+		dev_dbg(dev->class_dev,
+			"Port A configured for %s mode pattern detection\n",
+			pa_trig ? "AND" : "OR");
+	}
+
+	/* Set Port B trigger mode (if enabled) and enable interrupt */
+	if (devpriv->pm[pb_trig] & 0xff00) {
+		pb_mode = pb_trig ? Z8536_PAB_MODE_PMS_AND
+				  : Z8536_PAB_MODE_PMS_OR;
+
+		val = z8536_read(dev, Z8536_PB_MODE_REG);
+		val &= ~Z8536_PAB_MODE_PMS_MASK;
+		val |= (pb_mode | Z8536_PAB_MODE_IMO);
+		z8536_write(dev, val, Z8536_PB_MODE_REG);
+
+		z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PB_CMDSTAT_REG);
+
+		valid_trig = true;
+
+		dev_dbg(dev->class_dev,
+			"Port B configured for %s mode pattern detection\n",
+			pb_trig ? "AND" : "OR");
+	}
+
+	/* Enable Ports A & B */
+	apci1500_port_enable(dev, true);
+
+	if (!valid_trig) {
+		dev_dbg(dev->class_dev,
+			"digital trigger %d is not configured\n", trig_num);
+		return -EINVAL;
+	}
+
+	/* Authorizes the main interrupt on the board */
+	z8536_write(dev, Z8536_INT_CTRL_MIE | Z8536_INT_CTRL_DLC,
+		    Z8536_INT_CTRL_REG);
+
+	return 0;
+}
+
+static int apci1500_di_cmd(struct comedi_device *dev,
+			   struct comedi_subdevice *s)
+{
+	s->async->inttrig = apci1500_di_inttrig_start;
+
+	return 0;
+}
+
+static int apci1500_di_cmdtest(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_cmd *cmd)
+{
+	int err = 0;
+
+	/* Step 1 : check if triggers are trivially valid */
+
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
+
+	if (err)
+		return 1;
+
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
+
+	/* Step 3: check if arguments are trivially valid */
+
+	/*
+	 * Internal start source triggers:
+	 *
+	 *   0	AND mode for Port A (digital inputs 0-7)
+	 *	AND mode for Port B (digital inputs 8-13 and internal signals)
+	 *
+	 *   1	OR mode for Port A (digital inputs 0-7)
+	 *	AND mode for Port B (digital inputs 8-13 and internal signals)
+	 *
+	 *   2	AND mode for Port A (digital inputs 0-7)
+	 *	OR mode for Port B (digital inputs 8-13 and internal signals)
+	 *
+	 *   3	OR mode for Port A (digital inputs 0-7)
+	 *	OR mode for Port B (digital inputs 8-13 and internal signals)
+	 */
+	err |= cfc_check_trigger_arg_max(&cmd->start_arg, 3);
+
+	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+	err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+	if (err)
+		return 3;
+
+	/* Step 4: fix up any arguments */
+
+	/* Step 5: check channel list if it exists */
+
+	return 0;
+}
+
+/*
+ * The pattern-recognition logic must be configured before the digital
+ * input async command is started.
+ *
+ * Digital input channels 0 to 13 can generate interrupts. Channels 14
+ * and 15 are connected to internal board status/diagnostic signals.
+ *
+ * Channel 14 - Voltage error (the external supply is < 5V)
+ * Channel 15 - Short-circuit/overtemperature error
+ *
+ *	data[0] : INSN_CONFIG_DIGITAL_TRIG
+ *	data[1] : trigger number
+ *		  0 = AND mode
+ *		  1 = OR mode
+ *	data[2] : configuration operation:
+ *	          COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
+ *	          COMEDI_DIGITAL_TRIG_ENABLE_EDGES = edge interrupts
+ *	          COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = level interrupts
+ *	data[3] : left-shift for data[4] and data[5]
+ *	data[4] : rising-edge/high level channels
+ *	data[5] : falling-edge/low level channels
+ */
+static int apci1500_di_cfg_trig(struct comedi_device *dev,
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn,
+				unsigned int *data)
+{
+	struct apci1500_private *devpriv = dev->private;
+	unsigned int trig = data[1];
+	unsigned int shift = data[3];
+	unsigned int hi_mask = data[4] << shift;
+	unsigned int lo_mask = data[5] << shift;
+	unsigned int chan_mask = hi_mask | lo_mask;
+	unsigned int old_mask = (1 << shift) - 1;
+	unsigned int pm = devpriv->pm[trig] & old_mask;
+	unsigned int pt = devpriv->pt[trig] & old_mask;
+	unsigned int pp = devpriv->pp[trig] & old_mask;
+
+	if (trig > 1) {
+		dev_dbg(dev->class_dev,
+			"invalid digital trigger number (0=AND, 1=OR)\n");
+		return -EINVAL;
+	}
+
+	if (chan_mask > 0xffff) {
+		dev_dbg(dev->class_dev, "invalid digital trigger channel\n");
+		return -EINVAL;
+	}
+
+	switch (data[2]) {
+	case COMEDI_DIGITAL_TRIG_DISABLE:
+		/* clear trigger configuration */
+		pm = 0;
+		pt = 0;
+		pp = 0;
+		break;
+	case COMEDI_DIGITAL_TRIG_ENABLE_EDGES:
+		pm |= chan_mask;	/* enable channels */
+		pt |= chan_mask;	/* enable edge detection */
+		pp |= hi_mask;		/* rising-edge channels */
+		pp &= ~lo_mask;		/* falling-edge channels */
+		break;
+	case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS:
+		pm |= chan_mask;	/* enable channels */
+		pt &= ~chan_mask;	/* enable level detection */
+		pp |= hi_mask;		/* high level channels */
+		pp &= ~lo_mask;		/* low level channels */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * The AND mode trigger can only have one channel (max) enabled
+	 * for edge detection.
+	 */
+	if (trig == 0) {
+		int ret = 0;
+		unsigned int src;
+
+		src = pt & 0xff;
+		if (src)
+			ret |= cfc_check_trigger_is_unique(src);
+
+		src = (pt >> 8) & 0xff;
+		if (src)
+			ret |= cfc_check_trigger_is_unique(src);
+
+		if (ret) {
+			dev_dbg(dev->class_dev,
+				"invalid AND trigger configuration\n");
+			return ret;
+		}
+	}
+
+	/* save the trigger configuration */
+	devpriv->pm[trig] = pm;
+	devpriv->pt[trig] = pt;
+	devpriv->pp[trig] = pp;
+
+	return insn->n;
+}
+
+static int apci1500_di_insn_config(struct comedi_device *dev,
+				   struct comedi_subdevice *s,
+				   struct comedi_insn *insn,
+				   unsigned int *data)
+{
+	switch (data[0]) {
+	case INSN_CONFIG_DIGITAL_TRIG:
+		return apci1500_di_cfg_trig(dev, s, insn, data);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int apci1500_di_insn_bits(struct comedi_device *dev,
+				 struct comedi_subdevice *s,
+				 struct comedi_insn *insn,
+				 unsigned int *data)
+{
+	struct apci1500_private *devpriv = dev->private;
+
+	data[1] = inw(devpriv->addon + APCI1500_DI_REG);
+
+	return insn->n;
+}
+
+static int apci1500_do_insn_bits(struct comedi_device *dev,
+				 struct comedi_subdevice *s,
+				 struct comedi_insn *insn,
+				 unsigned int *data)
+{
+	struct apci1500_private *devpriv = dev->private;
+
+	if (comedi_dio_update_state(s, data))
+		outw(s->state, devpriv->addon + APCI1500_DO_REG);
+
+	data[1] = s->state;
+
+	return insn->n;
+}
+
+static int apci1500_timer_insn_config(struct comedi_device *dev,
+				      struct comedi_subdevice *s,
+				      struct comedi_insn *insn,
+				      unsigned int *data)
+{
+	struct apci1500_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int val;
+
+	switch (data[0]) {
+	case INSN_CONFIG_ARM:
+		val = data[1] & s->maxdata;
+		z8536_write(dev, val & 0xff, Z8536_CT_RELOAD_LSB_REG(chan));
+		z8536_write(dev, (val >> 8) & 0xff,
+			    Z8536_CT_RELOAD_MSB_REG(chan));
+
+		apci1500_timer_enable(dev, chan, true);
+		z8536_write(dev, Z8536_CT_CMDSTAT_GCB,
+			    Z8536_CT_CMDSTAT_REG(chan));
+		break;
+	case INSN_CONFIG_DISARM:
+		apci1500_timer_enable(dev, chan, false);
+		break;
+
+	case INSN_CONFIG_GET_COUNTER_STATUS:
+		data[1] = 0;
+		val = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+		if (val & Z8536_CT_STAT_CIP)
+			data[1] |= COMEDI_COUNTER_COUNTING;
+		if (val & Z8536_CT_CMDSTAT_GCB)
+			data[1] |= COMEDI_COUNTER_ARMED;
+		if (val & Z8536_STAT_IP) {
+			data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
+			apci1500_ack_irq(dev, Z8536_CT_CMDSTAT_REG(chan));
+		}
+		data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
+			  COMEDI_COUNTER_TERMINAL_COUNT;
+		break;
+
+	case INSN_CONFIG_SET_COUNTER_MODE:
+		/* Simulate the 8254 timer modes */
+		switch (data[1]) {
+		case I8254_MODE0:
+			/* Interrupt on Terminal Count */
+			val = Z8536_CT_MODE_ECE |
+			      Z8536_CT_MODE_DCS_ONESHOT;
+			break;
+		case I8254_MODE1:
+			/* Hardware Retriggerable One-Shot */
+			val = Z8536_CT_MODE_ETE |
+			      Z8536_CT_MODE_DCS_ONESHOT;
+			break;
+		case I8254_MODE2:
+			/* Rate Generator */
+			val = Z8536_CT_MODE_CSC |
+			      Z8536_CT_MODE_DCS_PULSE;
+			break;
+		case I8254_MODE3:
+			/* Square Wave Mode */
+			val = Z8536_CT_MODE_CSC |
+			      Z8536_CT_MODE_DCS_SQRWAVE;
+			break;
+		case I8254_MODE4:
+			/* Software Triggered Strobe */
+			val = Z8536_CT_MODE_REB |
+			      Z8536_CT_MODE_DCS_PULSE;
+			break;
+		case I8254_MODE5:
+			/* Hardware Triggered Strobe (watchdog) */
+			val = Z8536_CT_MODE_EOE |
+			      Z8536_CT_MODE_ETE |
+			      Z8536_CT_MODE_REB |
+			      Z8536_CT_MODE_DCS_PULSE;
+			break;
+		default:
+			return -EINVAL;
+		}
+		apci1500_timer_enable(dev, chan, false);
+		z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
+		break;
+
+	case INSN_CONFIG_SET_CLOCK_SRC:
+		if (data[1] > 2)
+			return -EINVAL;
+		devpriv->clk_src = data[1];
+		if (devpriv->clk_src == 2)
+			devpriv->clk_src = 3;
+		outw(devpriv->clk_src, devpriv->addon + APCI1500_CLK_SEL_REG);
+		break;
+	case INSN_CONFIG_GET_CLOCK_SRC:
+		switch (devpriv->clk_src) {
+		case 0:
+			data[1] = 0;		/* 111.86 kHz / 2 */
+			data[2] = 17879;	/* 17879 ns (approx) */
+			break;
+		case 1:
+			data[1] = 1;		/* 3.49 kHz / 2 */
+			data[2] = 573066;	/* 573066 ns (approx) */
+			break;
+		case 3:
+			data[1] = 2;		/* 1.747 kHz / 2 */
+			data[2] = 1164822;	/* 1164822 ns (approx) */
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case INSN_CONFIG_SET_GATE_SRC:
+		if (chan == 0)
+			return -EINVAL;
+
+		val = z8536_read(dev, Z8536_CT_MODE_REG(chan));
+		val &= Z8536_CT_MODE_EGE;
+		if (data[1] == 1)
+			val |= Z8536_CT_MODE_EGE;
+		else if (data[1] > 1)
+			return -EINVAL;
+		z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
+		break;
+	case INSN_CONFIG_GET_GATE_SRC:
+		if (chan == 0)
+			return -EINVAL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return insn->n;
+}
+
+static int apci1500_timer_insn_write(struct comedi_device *dev,
+				     struct comedi_subdevice *s,
+				     struct comedi_insn *insn,
+				     unsigned int *data)
+{
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int cmd;
+
+	cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+	cmd &= Z8536_CT_CMDSTAT_GCB;	/* preserve gate */
+	cmd |= Z8536_CT_CMD_TCB;	/* set trigger */
+
+	/* software trigger a timer, it only makes sense to do one write */
+	if (insn->n)
+		z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan));
+
+	return insn->n;
+}
+
+static int apci1500_timer_insn_read(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
+{
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int cmd;
+	unsigned int val;
+	int i;
+
+	cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+	cmd &= Z8536_CT_CMDSTAT_GCB;	/* preserve gate */
+	cmd |= Z8536_CT_CMD_RCC;	/* set RCC */
+
+	for (i = 0; i < insn->n; i++) {
+		z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan));
+
+		val = z8536_read(dev, Z8536_CT_VAL_MSB_REG(chan)) << 8;
+		val |= z8536_read(dev, Z8536_CT_VAL_LSB_REG(chan));
+
+		data[i] = val;
+	}
+
+	return insn->n;
+}
 
 static int apci1500_auto_attach(struct comedi_device *dev,
 				unsigned long context)
@@ -56,6 +771,8 @@ static int apci1500_auto_attach(struct comedi_device *dev,
 	devpriv->amcc = pci_resource_start(pcidev, 0);
 	devpriv->addon = pci_resource_start(pcidev, 2);
 
+	z8536_reset(dev);
+
 	if (pcidev->irq > 0) {
 		ret = request_irq(pcidev->irq, apci1500_interrupt, IRQF_SHARED,
 				  dev->board_name, dev);
@@ -67,51 +784,66 @@ static int apci1500_auto_attach(struct comedi_device *dev,
 	if (ret)
 		return ret;
 
-	/*  Allocate and Initialise DI Subdevice Structures */
+	/* Digital Input subdevice */
 	s = &dev->subdevices[0];
-	s->type = COMEDI_SUBD_DI;
-	s->subdev_flags = SDF_READABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_config = apci1500_di_config;
-	s->insn_read = apci1500_di_read;
-	s->insn_write = apci1500_di_write;
-	s->insn_bits = apci1500_di_insn_bits;
-
-	/*  Allocate and Initialise DO Subdevice Structures */
+	s->type		= COMEDI_SUBD_DI;
+	s->subdev_flags	= SDF_READABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= apci1500_di_insn_bits;
+	if (dev->irq) {
+		dev->read_subdev = s;
+		s->subdev_flags |= SDF_CMD_READ;
+		s->len_chanlist	= 1;
+		s->insn_config	= apci1500_di_insn_config;
+		s->do_cmdtest	= apci1500_di_cmdtest;
+		s->do_cmd	= apci1500_di_cmd;
+		s->cancel	= apci1500_di_cancel;
+	}
+
+	/* Digital Output subdevice */
 	s = &dev->subdevices[1];
-	s->type = COMEDI_SUBD_DO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_config = apci1500_do_config;
-	s->insn_write = apci1500_do_write;
-	s->insn_bits = apci1500_do_bits;
-
-	/*  Allocate and Initialise Timer Subdevice Structures */
+	s->type		= COMEDI_SUBD_DO;
+	s->subdev_flags	= SDF_WRITABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= apci1500_do_insn_bits;
+
+	/* reset all the digital outputs */
+	outw(0x0, devpriv->addon + APCI1500_DO_REG);
+
+	/* Counter/Timer(Watchdog) subdevice */
 	s = &dev->subdevices[2];
-	s->type = COMEDI_SUBD_TIMER;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = 1;
-	s->maxdata = 0;
-	s->len_chanlist = 1;
-	s->range_table = &range_digital;
-	s->insn_write = apci1500_timer_write;
-	s->insn_read = apci1500_timer_read;
-	s->insn_config = apci1500_timer_config;
-	s->insn_bits = apci1500_timer_bits;
-
-	apci1500_reset(dev);
+	s->type		= COMEDI_SUBD_TIMER;
+	s->subdev_flags	= SDF_WRITABLE | SDF_READABLE;
+	s->n_chan	= 3;
+	s->maxdata	= 0xffff;
+	s->range_table	= &range_unknown;
+	s->insn_config	= apci1500_timer_insn_config;
+	s->insn_write	= apci1500_timer_insn_write;
+	s->insn_read	= apci1500_timer_insn_read;
+
+	/* Enable the PCI interrupt */
+	if (dev->irq) {
+		outl(0x2000 | INTCSR_INBOX_FULL_INT,
+		     devpriv->amcc + AMCC_OP_REG_INTCSR);
+		inl(devpriv->amcc + AMCC_OP_REG_IMB1);
+		inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
+		outl(INTCSR_INBOX_INTR_STATUS | 0x2000 | INTCSR_INBOX_FULL_INT,
+		     devpriv->amcc + AMCC_OP_REG_INTCSR);
+	}
 
 	return 0;
 }
 
 static void apci1500_detach(struct comedi_device *dev)
 {
-	if (dev->iobase)
-		apci1500_reset(dev);
+	struct apci1500_private *devpriv = dev->private;
+
+	if (devpriv->amcc)
+		outl(0x0, devpriv->amcc + AMCC_OP_REG_INTCSR);
 	comedi_pci_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/z8536.h b/drivers/staging/comedi/drivers/z8536.h
new file mode 100644
index 0000000..7be5310
--- /dev/null
+++ b/drivers/staging/comedi/drivers/z8536.h
@@ -0,0 +1,202 @@
+/*
+ * Z8536 CIO Internal registers
+ */
+
+#ifndef _Z8536_H
+#define _Z8536_H
+
+/* Master Interrupt Control register */
+#define Z8536_INT_CTRL_REG		0x00
+#define Z8536_INT_CTRL_MIE		BIT(7)	/* Master Interrupt Enable */
+#define Z8536_INT_CTRL_DLC		BIT(6)	/* Disable Lower Chain */
+#define Z8536_INT_CTRL_NV		BIT(5)	/* No Vector */
+#define Z8536_INT_CTRL_PA_VIS		BIT(4)	/* Port A Vect Inc Status */
+#define Z8536_INT_CTRL_PB_VIS		BIT(3)	/* Port B Vect Inc Status */
+#define Z8536_INT_CTRL_VT_VIS		BIT(2)	/* C/T Vect Inc Status */
+#define Z8536_INT_CTRL_RJA		BIT(1)	/* Right Justified Addresses */
+#define Z8536_INT_CTRL_RESET		BIT(0)	/* Reset */
+
+/* Master Configuration Control register */
+#define Z8536_CFG_CTRL_REG		0x01
+#define Z8536_CFG_CTRL_PBE		BIT(7)	/* Port B Enable */
+#define Z8536_CFG_CTRL_CT1E		BIT(6)	/* C/T 1 Enable */
+#define Z8536_CFG_CTRL_CT2E		BIT(5)	/* C/T 2 Enable */
+#define Z8536_CFG_CTRL_PCE_CT3E		BIT(4)	/* Port C & C/T 3 Enable */
+#define Z8536_CFG_CTRL_PLC		BIT(3)	/* Port A/B Link Control */
+#define Z8536_CFG_CTRL_PAE		BIT(2)	/* Port A Enable */
+#define Z8536_CFG_CTRL_LC_INDEP		(0 << 0)/* C/Ts Independent */
+#define Z8536_CFG_CTRL_LC_GATE		(1 << 0)/* C/T 1 Out Gates C/T 2 */
+#define Z8536_CFG_CTRL_LC_TRIG		(2 << 0)/* C/T 1 Out Triggers C/T 2 */
+#define Z8536_CFG_CTRL_LC_CLK		(3 << 0)/* C/T 1 Out Clocks C/T 2 */
+#define Z8536_CFG_CTRL_LC_MASK		(3 << 0)/* C/T Link Control mask */
+
+/* Interrupt Vector registers */
+#define Z8536_PA_INT_VECT_REG		0x02
+#define Z8536_PB_INT_VECT_REG		0x03
+#define Z8536_CT_INT_VECT_REG		0x04
+#define Z8536_CURR_INT_VECT_REG		0x1f
+
+/* Port A/B & Counter/Timer 1/2/3 Command and Status registers */
+#define Z8536_PA_CMDSTAT_REG		0x08
+#define Z8536_PB_CMDSTAT_REG		0x09
+#define Z8536_CT1_CMDSTAT_REG		0x0a
+#define Z8536_CT2_CMDSTAT_REG		0x0b
+#define Z8536_CT3_CMDSTAT_REG		0x0c
+#define Z8536_CT_CMDSTAT_REG(x)		(0x0a + (x))
+#define Z8536_CMD_NULL			(0 << 5)/* Null Code */
+#define Z8536_CMD_CLR_IP_IUS		(1 << 5)/* Clear IP & IUS */
+#define Z8536_CMD_SET_IUS		(2 << 5)/* Set IUS */
+#define Z8536_CMD_CLR_IUS		(3 << 5)/* Clear IUS */
+#define Z8536_CMD_SET_IP		(4 << 5)/* Set IP */
+#define Z8536_CMD_CLR_IP		(5 << 5)/* Clear IP */
+#define Z8536_CMD_SET_IE		(6 << 5)/* Set IE */
+#define Z8536_CMD_CLR_IE		(7 << 5)/* Clear IE */
+#define Z8536_CMD_MASK			(7 << 5)
+
+#define Z8536_STAT_IUS			BIT(7)	/* Interrupt Under Service */
+#define Z8536_STAT_IE			BIT(6)	/* Interrupt Enable */
+#define Z8536_STAT_IP			BIT(5)	/* Interrupt Pending */
+#define Z8536_STAT_ERR			BIT(4)	/* Interrupt Error */
+#define Z8536_STAT_IE_IP		(Z8536_STAT_IE | Z8536_STAT_IP)
+
+#define Z8536_PAB_STAT_ORE		BIT(3)	/* Output Register Empty */
+#define Z8536_PAB_STAT_IRF		BIT(2)	/* Input Register Full */
+#define Z8536_PAB_STAT_PMF		BIT(1)	/* Pattern Match Flag */
+#define Z8536_PAB_CMDSTAT_IOE		BIT(0)	/* Interrupt On Error */
+
+#define Z8536_CT_CMD_RCC		BIT(3)	/* Read Counter Control */
+#define Z8536_CT_CMDSTAT_GCB		BIT(2)	/* Gate Command Bit */
+#define Z8536_CT_CMD_TCB		BIT(1)	/* Trigger Command Bit */
+#define Z8536_CT_STAT_CIP		BIT(0)	/* Count In Progress */
+
+/* Port Data registers */
+#define Z8536_PA_DATA_REG		0x0d
+#define Z8536_PB_DATA_REG		0x0e
+#define Z8536_PC_DATA_REG		0x0f
+
+/* Counter/Timer 1/2/3 Current Count registers */
+#define Z8536_CT1_VAL_MSB_REG		0x10
+#define Z8536_CT1_VAL_LSB_REG		0x11
+#define Z8536_CT2_VAL_MSB_REG		0x12
+#define Z8536_CT2_VAL_LSB_REG		0x13
+#define Z8536_CT3_VAL_MSB_REG		0x14
+#define Z8536_CT3_VAL_LSB_REG		0x15
+#define Z8536_CT_VAL_MSB_REG(x)		(0x10 + ((x) * 2))
+#define Z8536_CT_VAL_LSB_REG(x)		(0x11 + ((x) * 2))
+
+/* Counter/Timer 1/2/3 Time Constant registers */
+#define Z8536_CT1_RELOAD_MSB_REG	0x16
+#define Z8536_CT1_RELOAD_LSB_REG	0x17
+#define Z8536_CT2_RELOAD_MSB_REG	0x18
+#define Z8536_CT2_RELOAD_LSB_REG	0x19
+#define Z8536_CT3_RELOAD_MSB_REG	0x1a
+#define Z8536_CT3_RELOAD_LSB_REG	0x1b
+#define Z8536_CT_RELOAD_MSB_REG(x)	(0x16 + ((x) * 2))
+#define Z8536_CT_RELOAD_LSB_REG(x)	(0x17 + ((x) * 2))
+
+/* Counter/Timer 1/2/3 Mode Specification registers */
+#define Z8536_CT1_MODE_REG		0x1c
+#define Z8536_CT2_MODE_REG		0x1d
+#define Z8536_CT3_MODE_REG		0x1e
+#define Z8536_CT_MODE_REG(x)		(0x1c + (x))
+#define Z8536_CT_MODE_CSC		BIT(7)	/* Continuous/Single Cycle */
+#define Z8536_CT_MODE_EOE		BIT(6)	/* External Output Enable */
+#define Z8536_CT_MODE_ECE		BIT(5)	/* External Count Enable */
+#define Z8536_CT_MODE_ETE		BIT(4)	/* External Trigger Enable */
+#define Z8536_CT_MODE_EGE		BIT(3)	/* External Gate Enable */
+#define Z8536_CT_MODE_REB		BIT(2)	/* Retrigger Enable Bit */
+#define Z8536_CT_MODE_DCS_PULSE		(0 << 0)/* Duty Cycle - Pulse */
+#define Z8536_CT_MODE_DCS_ONESHOT	(1 << 0)/* Duty Cycle - One-Shot */
+#define Z8536_CT_MODE_DCS_SQRWAVE	(2 << 0)/* Duty Cycle - Square Wave */
+#define Z8536_CT_MODE_DCS_DO_NOT_USE	(3 << 0)/* Duty Cycle - Do Not Use */
+#define Z8536_CT_MODE_DCS_MASK		(3 << 0)/* Duty Cycle mask */
+
+/* Port A/B Mode Specification registers */
+#define Z8536_PA_MODE_REG		0x20
+#define Z8536_PB_MODE_REG		0x28
+#define Z8536_PAB_MODE_PTS_BIT		(0 << 6)/* Bit Port */
+#define Z8536_PAB_MODE_PTS_INPUT	(1 << 6)/* Input Port */
+#define Z8536_PAB_MODE_PTS_OUTPUT	(2 << 6)/* Output Port */
+#define Z8536_PAB_MODE_PTS_BIDIR	(3 << 6)/* Bidirectional Port */
+#define Z8536_PAB_MODE_PTS_MASK		(3 << 6)/* Port Type Select mask */
+#define Z8536_PAB_MODE_ITB		BIT(5)	/* Interrupt on Two Bytes */
+#define Z8536_PAB_MODE_SB		BIT(4)	/* Single Buffered mode */
+#define Z8536_PAB_MODE_IMO		BIT(3)	/* Interrupt on Match Only */
+#define Z8536_PAB_MODE_PMS_DISABLE	(0 << 1)/* Disable Pattern Match */
+#define Z8536_PAB_MODE_PMS_AND		(1 << 1)/* "AND" mode */
+#define Z8536_PAB_MODE_PMS_OR		(2 << 1)/* "OR" mode */
+#define Z8536_PAB_MODE_PMS_OR_PEV	(3 << 1)/* "OR-Priority" mode */
+#define Z8536_PAB_MODE_PMS_MASK		(3 << 1)/* Pattern Mode mask */
+#define Z8536_PAB_MODE_LPM		BIT(0)	/* Latch on Pattern Match */
+#define Z8536_PAB_MODE_DTE		BIT(0)	/* Deskew Timer Enabled */
+
+/* Port A/B Handshake Specification registers */
+#define Z8536_PA_HANDSHAKE_REG		0x21
+#define Z8536_PB_HANDSHAKE_REG		0x29
+#define Z8536_PAB_HANDSHAKE_HST_INTER	(0 << 6)/* Interlocked Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_STROBED	(1 << 6)/* Strobed Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_PULSED	(2 << 6)/* Pulsed Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_3WIRE	(3 << 6)/* Three-Wire Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_MASK	(3 << 6)/* Handshake Type mask */
+#define Z8536_PAB_HANDSHAKE_RWS_DISABLE	(0 << 3)/* Req/Wait Disabled */
+#define Z8536_PAB_HANDSHAKE_RWS_OUTWAIT	(1 << 3)/* Output Wait */
+#define Z8536_PAB_HANDSHAKE_RWS_INWAIT	(3 << 3)/* Input Wait */
+#define Z8536_PAB_HANDSHAKE_RWS_SPREQ	(4 << 3)/* Special Request */
+#define Z8536_PAB_HANDSHAKE_RWS_OUTREQ	(5 << 4)/* Output Request */
+#define Z8536_PAB_HANDSHAKE_RWS_INREQ	(7 << 3)/* Input Request */
+#define Z8536_PAB_HANDSHAKE_RWS_MASK	(7 << 3)/* Req/Wait mask */
+#define Z8536_PAB_HANDSHAKE_DESKEW(x)	((x) << 0)/* Deskew Time */
+#define Z8536_PAB_HANDSHAKE_DESKEW_MASK	(3 << 0)/* Deskew Time mask */
+
+/*
+ * Port A/B/C Data Path Polarity registers
+ *
+ *	0 = Non-Inverting
+ *	1 = Inverting
+ */
+#define Z8536_PA_DPP_REG		0x22
+#define Z8536_PB_DPP_REG		0x2a
+#define Z8536_PC_DPP_REG		0x05
+
+/*
+ * Port A/B/C Data Direction registers
+ *
+ *	0 = Output bit
+ *	1 = Input bit
+ */
+#define Z8536_PA_DD_REG			0x23
+#define Z8536_PB_DD_REG			0x2b
+#define Z8536_PC_DD_REG			0x06
+
+/*
+ * Port A/B/C Special I/O Control registers
+ *
+ *	0 = Normal Input or Output
+ *	1 = Output with open drain or Input with 1's catcher
+ */
+#define Z8536_PA_SIO_REG		0x24
+#define Z8536_PB_SIO_REG		0x2c
+#define Z8536_PC_SIO_REG		0x07
+
+/*
+ * Port A/B Pattern Polarity/Transition/Mask registers
+ *
+ *	PM PT PP  Pattern Specification
+ *	-- -- --  -------------------------------------
+ *	 0  0  x  Bit masked off
+ *	 0  1  x  Any transition
+ *	 1  0  0  Zero (low-level)
+ *	 1  0  1  One (high-level)
+ *	 1  1  0  One-to-zero transition (falling-edge)
+ *	 1  1  1  Zero-to-one transition (rising-edge)
+ */
+#define Z8536_PA_PP_REG			0x25
+#define Z8536_PB_PP_REG			0x2d
+
+#define Z8536_PA_PT_REG			0x26
+#define Z8536_PB_PT_REG			0x2e
+
+#define Z8536_PA_PM_REG			0x27
+#define Z8536_PB_PM_REG			0x2f
+
+#endif	/* _Z8536_H */
-- 
2.0.3

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel



[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux