aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/ni_labpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/ni_labpc.c')
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c2448
1 files changed, 1055 insertions, 1393 deletions
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index f957b8859b3d..3d978f34d212 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -1,79 +1,66 @@
/*
- comedi/drivers/ni_labpc.c
- Driver for National Instruments Lab-PC series boards and compatibles
- Copyright (C) 2001, 2002, 2003 Frank Mori Hess <fmhess@users.sourceforge.net>
-
- 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.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-************************************************************************
-*/
-/*
-Driver: ni_labpc
-Description: National Instruments Lab-PC (& compatibles)
-Author: Frank Mori Hess <fmhess@users.sourceforge.net>
-Devices: [National Instruments] Lab-PC-1200 (labpc-1200),
- Lab-PC-1200AI (labpc-1200ai), Lab-PC+ (lab-pc+), PCI-1200 (ni_labpc)
-Status: works
-
-Tested with lab-pc-1200. For the older Lab-PC+, not all input ranges
-and analog references will work, the available ranges/arefs will
-depend on how you have configured the jumpers on your board
-(see your owner's manual).
-
-Kernel-level ISA plug-and-play support for the lab-pc-1200
-boards has not
-yet been added to the driver, mainly due to the fact that
-I don't know the device id numbers. If you have one
-of these boards,
-please file a bug report at http://comedi.org/
-so I can get the necessary information from you.
-
-The 1200 series boards have onboard calibration dacs for correcting
-analog input/output offsets and gains. The proper settings for these
-caldacs are stored on the board's eeprom. To read the caldac values
-from the eeprom and store them into a file that can be then be used by
-comedilib, use the comedi_calibrate program.
-
-Configuration options - ISA boards:
- [0] - I/O port base address
- [1] - IRQ (optional, required for timed or externally triggered conversions)
- [2] - DMA channel (optional)
-
-Configuration options - PCI boards:
- [0] - bus (optional)
- [1] - slot (optional)
-
-The Lab-pc+ has quirky chanlist requirements
-when scanning multiple channels. Multiple channel scan
-sequence must start at highest channel, then decrement down to
-channel 0. The rest of the cards can scan down like lab-pc+ or scan
-up from channel zero. Chanlists consisting of all one channel
-are also legal, and allow you to pace conversions in bursts.
-
-*/
+ * comedi/drivers/ni_labpc.c
+ * Driver for National Instruments Lab-PC series boards and compatibles
+ * Copyright (C) 2001-2003 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
/*
+ * Driver: ni_labpc
+ * Description: National Instruments Lab-PC (& compatibles)
+ * Devices: (National Instruments) Lab-PC-1200 [lab-pc-1200]
+ * (National Instruments) Lab-PC-1200AI [lab-pc-1200ai]
+ * (National Instruments) Lab-PC+ [lab-pc+]
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Status: works
+ *
+ * Configuration options - ISA boards:
+ * [0] - I/O port base address
+ * [1] - IRQ (optional, required for timed or externally triggered
+ * conversions)
+ * [2] - DMA channel (optional)
+ *
+ * Tested with lab-pc-1200. For the older Lab-PC+, not all input
+ * ranges and analog references will work, the available ranges/arefs
+ * will depend on how you have configured the jumpers on your board
+ * (see your owner's manual).
+ *
+ * Kernel-level ISA plug-and-play support for the lab-pc-1200 boards
+ * has not yet been added to the driver, mainly due to the fact that
+ * I don't know the device id numbers. If you have one of these boards,
+ * please file a bug report at http://comedi.org/ so I can get the
+ * necessary information from you.
+ *
+ * The 1200 series boards have onboard calibration dacs for correcting
+ * analog input/output offsets and gains. The proper settings for these
+ * caldacs are stored on the board's eeprom. To read the caldac values
+ * from the eeprom and store them into a file that can be then be used
+ * by comedilib, use the comedi_calibrate program.
+ *
+ * The Lab-pc+ has quirky chanlist requirements when scanning multiple
+ * channels. Multiple channel scan sequence must start at highest channel,
+ * then decrement down to channel 0. The rest of the cards can scan down
+ * like lab-pc+ or scan up from channel zero. Chanlists consisting of all
+ * one channel are also legal, and allow you to pace conversions in bursts.
+ *
+ * NI manuals:
+ * 341309a (labpc-1200 register manual)
+ * 320502b (lab-pc+)
+ */
-NI manuals:
-341309a (labpc-1200 register manual)
-340914a (pci-1200)
-320502b (lab-pc+)
-
-*/
-
-#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/io.h>
@@ -85,128 +72,79 @@ NI manuals:
#include "8253.h"
#include "8255.h"
-#include "mite.h"
#include "comedi_fc.h"
#include "ni_labpc.h"
-#define DRV_NAME "ni_labpc"
-
-/* size of io region used by board */
-#define LABPC_SIZE 32
-/* 2 MHz master clock */
-#define LABPC_TIMER_BASE 500
-
-/* Registers for the lab-pc+ */
-
-/* write-only registers */
-#define COMMAND1_REG 0x0
-#define ADC_GAIN_MASK (0x7 << 4)
-#define ADC_CHAN_BITS(x) ((x) & 0x7)
-/* enables multi channel scans */
-#define ADC_SCAN_EN_BIT 0x80
-#define COMMAND2_REG 0x1
-/* enable pretriggering (used in conjunction with SWTRIG) */
-#define PRETRIG_BIT 0x1
-/* enable paced conversions on external trigger */
-#define HWTRIG_BIT 0x2
-/* enable paced conversions */
-#define SWTRIG_BIT 0x4
-/* use two cascaded counters for pacing */
-#define CASCADE_BIT 0x8
-#define DAC_PACED_BIT(channel) (0x40 << ((channel) & 0x1))
-#define COMMAND3_REG 0x2
-/* enable dma transfers */
-#define DMA_EN_BIT 0x1
-/* enable interrupts for 8255 */
-#define DIO_INTR_EN_BIT 0x2
-/* enable dma terminal count interrupt */
-#define DMATC_INTR_EN_BIT 0x4
-/* enable timer interrupt */
-#define TIMER_INTR_EN_BIT 0x8
-/* enable error interrupt */
-#define ERR_INTR_EN_BIT 0x10
-/* enable fifo not empty interrupt */
-#define ADC_FNE_INTR_EN_BIT 0x20
-#define ADC_CONVERT_REG 0x3
-#define DAC_LSB_REG(channel) (0x4 + 2 * ((channel) & 0x1))
-#define DAC_MSB_REG(channel) (0x5 + 2 * ((channel) & 0x1))
-#define ADC_CLEAR_REG 0x8
-#define DMATC_CLEAR_REG 0xa
-#define TIMER_CLEAR_REG 0xc
-/* 1200 boards only */
-#define COMMAND6_REG 0xe
-/* select ground or common-mode reference */
-#define ADC_COMMON_BIT 0x1
-/* adc unipolar */
-#define ADC_UNIP_BIT 0x2
-/* dac unipolar */
-#define DAC_UNIP_BIT(channel) (0x4 << ((channel) & 0x1))
-/* enable fifo half full interrupt */
-#define ADC_FHF_INTR_EN_BIT 0x20
-/* enable interrupt on end of hardware count */
-#define A1_INTR_EN_BIT 0x40
-/* scan up from channel zero instead of down to zero */
-#define ADC_SCAN_UP_BIT 0x80
-#define COMMAND4_REG 0xf
-/* enables 'interval' scanning */
-#define INTERVAL_SCAN_EN_BIT 0x1
-/* enables external signal on counter b1 output to trigger scan */
-#define EXT_SCAN_EN_BIT 0x2
-/* chooses direction (output or input) for EXTCONV* line */
-#define EXT_CONVERT_OUT_BIT 0x4
-/* chooses differential inputs for adc (in conjunction with board jumper) */
-#define ADC_DIFF_BIT 0x8
-#define EXT_CONVERT_DISABLE_BIT 0x10
-/* 1200 boards only, calibration stuff */
-#define COMMAND5_REG 0x1c
-/* enable eeprom for write */
-#define EEPROM_WRITE_UNPROTECT_BIT 0x4
-/* enable dithering */
-#define DITHER_EN_BIT 0x8
-/* load calibration dac */
-#define CALDAC_LOAD_BIT 0x10
-/* serial clock - rising edge writes, falling edge reads */
-#define SCLOCK_BIT 0x20
-/* serial data bit for writing to eeprom or calibration dacs */
-#define SDATA_BIT 0x40
-/* enable eeprom for read/write */
-#define EEPROM_EN_BIT 0x80
-#define INTERVAL_COUNT_REG 0x1e
-#define INTERVAL_LOAD_REG 0x1f
-#define INTERVAL_LOAD_BITS 0x1
-
-/* read-only registers */
-#define STATUS1_REG 0x0
-/* data is available in fifo */
-#define DATA_AVAIL_BIT 0x1
-/* overrun has occurred */
-#define OVERRUN_BIT 0x2
-/* fifo overflow */
-#define OVERFLOW_BIT 0x4
-/* timer interrupt has occurred */
-#define TIMER_BIT 0x8
-/* dma terminal count has occurred */
-#define DMATC_BIT 0x10
-/* external trigger has occurred */
-#define EXT_TRIG_BIT 0x40
-/* 1200 boards only */
-#define STATUS2_REG 0x1d
-/* programmable eeprom serial output */
-#define EEPROM_OUT_BIT 0x1
-/* counter A1 terminal count */
-#define A1_TC_BIT 0x2
-/* fifo not half full */
-#define FNHF_BIT 0x4
-#define ADC_FIFO_REG 0xa
-
-#define DIO_BASE_REG 0x10
-#define COUNTER_A_BASE_REG 0x14
-#define COUNTER_A_CONTROL_REG (COUNTER_A_BASE_REG + 0x3)
-/* check modes put conversion pacer output in harmless state (a0 mode 2) */
-#define INIT_A0_BITS 0x14
-/* put hardware conversion counter output in harmless state (a1 mode 0) */
-#define INIT_A1_BITS 0x70
-#define COUNTER_B_BASE_REG 0x18
+/*
+ * Register map (all registers are 8-bit)
+ */
+#define STAT1_REG 0x00 /* R: Status 1 reg */
+#define STAT1_DAVAIL (1 << 0)
+#define STAT1_OVERRUN (1 << 1)
+#define STAT1_OVERFLOW (1 << 2)
+#define STAT1_CNTINT (1 << 3)
+#define STAT1_GATA0 (1 << 5)
+#define STAT1_EXTGATA0 (1 << 6)
+#define CMD1_REG 0x00 /* W: Command 1 reg */
+#define CMD1_MA(x) (((x) & 0x7) << 0)
+#define CMD1_TWOSCMP (1 << 3)
+#define CMD1_GAIN_MASK (7 << 4)
+#define CMD1_SCANEN (1 << 7)
+#define CMD2_REG 0x01 /* W: Command 2 reg */
+#define CMD2_PRETRIG (1 << 0)
+#define CMD2_HWTRIG (1 << 1)
+#define CMD2_SWTRIG (1 << 2)
+#define CMD2_TBSEL (1 << 3)
+#define CMD2_2SDAC0 (1 << 4)
+#define CMD2_2SDAC1 (1 << 5)
+#define CMD2_LDAC(x) (1 << (6 + (x)))
+#define CMD3_REG 0x02 /* W: Command 3 reg */
+#define CMD3_DMAEN (1 << 0)
+#define CMD3_DIOINTEN (1 << 1)
+#define CMD3_DMATCINTEN (1 << 2)
+#define CMD3_CNTINTEN (1 << 3)
+#define CMD3_ERRINTEN (1 << 4)
+#define CMD3_FIFOINTEN (1 << 5)
+#define ADC_START_CONVERT_REG 0x03 /* W: Start Convert reg */
+#define DAC_LSB_REG(x) (0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */
+#define DAC_MSB_REG(x) (0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */
+#define ADC_FIFO_CLEAR_REG 0x08 /* W: A/D FIFO Clear reg */
+#define ADC_FIFO_REG 0x0a /* R: A/D FIFO reg */
+#define DMATC_CLEAR_REG 0x0a /* W: DMA Interrupt Clear reg */
+#define TIMER_CLEAR_REG 0x0c /* W: Timer Interrupt Clear reg */
+#define CMD6_REG 0x0e /* W: Command 6 reg */
+#define CMD6_NRSE (1 << 0)
+#define CMD6_ADCUNI (1 << 1)
+#define CMD6_DACUNI(x) (1 << (2 + (x)))
+#define CMD6_HFINTEN (1 << 5)
+#define CMD6_DQINTEN (1 << 6)
+#define CMD6_SCANUP (1 << 7)
+#define CMD4_REG 0x0f /* W: Command 3 reg */
+#define CMD4_INTSCAN (1 << 0)
+#define CMD4_EOIRCV (1 << 1)
+#define CMD4_ECLKDRV (1 << 2)
+#define CMD4_SEDIFF (1 << 3)
+#define CMD4_ECLKRCV (1 << 4)
+#define DIO_BASE_REG 0x10 /* R/W: 8255 DIO base reg */
+#define COUNTER_A_BASE_REG 0x14 /* R/W: 8253 Counter A base reg */
+#define COUNTER_B_BASE_REG 0x18 /* R/W: 8253 Counter B base reg */
+#define CMD5_REG 0x1c /* W: Command 5 reg */
+#define CMD5_WRTPRT (1 << 2)
+#define CMD5_DITHEREN (1 << 3)
+#define CMD5_CALDACLD (1 << 4)
+#define CMD5_SCLK (1 << 5)
+#define CMD5_SDATA (1 << 6)
+#define CMD5_EEPROMCS (1 << 7)
+#define STAT2_REG 0x1d /* R: Status 2 reg */
+#define STAT2_PROMOUT (1 << 0)
+#define STAT2_OUTA1 (1 << 1)
+#define STAT2_FIFONHF (1 << 2)
+#define INTERVAL_COUNT_REG 0x1e /* W: Interval Counter Data reg */
+#define INTERVAL_STROBE_REG 0x1f /* W: Interval Counter Strobe reg */
+
+#define LABPC_SIZE 0x20 /* size of ISA io region */
+#define LABPC_TIMER_BASE 500 /* 2 MHz master clock */
+#define LABPC_ADC_TIMEOUT 1000
enum scan_mode {
MODE_SINGLE_CHAN,
@@ -215,187 +153,63 @@ enum scan_mode {
MODE_MULT_CHAN_DOWN,
};
-static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static irqreturn_t labpc_interrupt(int irq, void *d);
-static int labpc_drain_fifo(struct comedi_device *dev);
-#ifdef CONFIG_ISA_DMA_API
-static void labpc_drain_dma(struct comedi_device *dev);
-static void handle_isa_dma(struct comedi_device *dev);
-#endif
-static void labpc_drain_dregs(struct comedi_device *dev);
-static int labpc_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_calib_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_calib_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_eeprom_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_eeprom_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
- enum scan_mode scan_mode);
-#ifdef CONFIG_ISA_DMA_API
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd);
-#endif
-static int labpc_dio_mem_callback(int dir, int port, int data,
- unsigned long arg);
-static void labpc_serial_out(struct comedi_device *dev, unsigned int value,
- unsigned int num_bits);
-static unsigned int labpc_serial_in(struct comedi_device *dev);
-static unsigned int labpc_eeprom_read(struct comedi_device *dev,
- unsigned int address);
-static unsigned int labpc_eeprom_read_status(struct comedi_device *dev);
-static int labpc_eeprom_write(struct comedi_device *dev,
- unsigned int address,
- unsigned int value);
-static void write_caldac(struct comedi_device *dev, unsigned int channel,
- unsigned int value);
-
-/* analog input ranges */
-#define NUM_LABPC_PLUS_AI_RANGES 16
-/* indicates unipolar ranges */
-static const int labpc_plus_is_unipolar[NUM_LABPC_PLUS_AI_RANGES] = {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
-};
-
-/* map range index to gain bits */
-static const int labpc_plus_ai_gain_bits[NUM_LABPC_PLUS_AI_RANGES] = {
- 0x00,
- 0x10,
- 0x20,
- 0x30,
- 0x40,
- 0x50,
- 0x60,
- 0x70,
- 0x00,
- 0x10,
- 0x20,
- 0x30,
- 0x40,
- 0x50,
- 0x60,
- 0x70,
+static const int labpc_plus_ai_gain_bits[] = {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
};
static const struct comedi_lrange range_labpc_plus_ai = {
- NUM_LABPC_PLUS_AI_RANGES,
- {
- BIP_RANGE(5),
- BIP_RANGE(4),
- BIP_RANGE(2.5),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.25),
- BIP_RANGE(0.1),
- BIP_RANGE(0.05),
- UNI_RANGE(10),
- UNI_RANGE(8),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE(0.5),
- UNI_RANGE(0.2),
- UNI_RANGE(0.1),
- }
+ 16, {
+ BIP_RANGE(5),
+ BIP_RANGE(4),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(10),
+ UNI_RANGE(8),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
};
-#define NUM_LABPC_1200_AI_RANGES 14
-/* indicates unipolar ranges */
-const int labpc_1200_is_unipolar[NUM_LABPC_1200_AI_RANGES] = {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
-};
-EXPORT_SYMBOL_GPL(labpc_1200_is_unipolar);
-
-/* map range index to gain bits */
-const int labpc_1200_ai_gain_bits[NUM_LABPC_1200_AI_RANGES] = {
- 0x00,
- 0x20,
- 0x30,
- 0x40,
- 0x50,
- 0x60,
- 0x70,
- 0x00,
- 0x20,
- 0x30,
- 0x40,
- 0x50,
- 0x60,
- 0x70,
+const int labpc_1200_ai_gain_bits[] = {
+ 0x00, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x00, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
};
EXPORT_SYMBOL_GPL(labpc_1200_ai_gain_bits);
const struct comedi_lrange range_labpc_1200_ai = {
- NUM_LABPC_1200_AI_RANGES,
- {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.25),
- BIP_RANGE(0.1),
- BIP_RANGE(0.05),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE(0.5),
- UNI_RANGE(0.2),
- UNI_RANGE(0.1),
- }
+ 14, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
};
EXPORT_SYMBOL_GPL(range_labpc_1200_ai);
-/* analog output ranges */
-#define AO_RANGE_IS_UNIPOLAR 0x1
static const struct comedi_lrange range_labpc_ao = {
- 2,
- {
- BIP_RANGE(5),
- UNI_RANGE(10),
- }
+ 2, {
+ BIP_RANGE(5),
+ UNI_RANGE(10)
+ }
};
/* functions that do inb/outb and readb/writeb so we can use
@@ -420,413 +234,417 @@ static inline void labpc_writeb(unsigned int byte, unsigned long address)
writeb(byte, (void __iomem *)address);
}
-static const struct labpc_board_struct labpc_boards[] = {
- {
- .name = "lab-pc-1200",
- .ai_speed = 10000,
- .bustype = isa_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 0,
- },
+#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA)
+static const struct labpc_boardinfo labpc_boards[] = {
{
- .name = "lab-pc-1200ai",
- .ai_speed = 10000,
- .bustype = isa_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 0,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 0,
- },
- {
- .name = "lab-pc+",
- .ai_speed = 12000,
- .bustype = isa_bustype,
- .register_layout = labpc_plus_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_plus_ai,
- .ai_range_code = labpc_plus_ai_gain_bits,
- .ai_range_is_unipolar = labpc_plus_is_unipolar,
- .ai_scan_up = 0,
- .memory_mapped_io = 0,
- },
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
- {
- .name = "pci-1200",
- .device_id = 0x161,
- .ai_speed = 10000,
- .bustype = pci_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 1,
- },
-/* dummy entry so pci board works when comedi_config is passed driver name */
- {
- .name = DRV_NAME,
- .bustype = pci_bustype,
- },
-#endif
+ .name = "lab-pc-1200",
+ .ai_speed = 10000,
+ .register_layout = labpc_1200_layout,
+ .has_ao = 1,
+ .ai_range_table = &range_labpc_1200_ai,
+ .ai_range_code = labpc_1200_ai_gain_bits,
+ .ai_scan_up = 1,
+ }, {
+ .name = "lab-pc-1200ai",
+ .ai_speed = 10000,
+ .register_layout = labpc_1200_layout,
+ .ai_range_table = &range_labpc_1200_ai,
+ .ai_range_code = labpc_1200_ai_gain_bits,
+ .ai_scan_up = 1,
+ }, {
+ .name = "lab-pc+",
+ .ai_speed = 12000,
+ .register_layout = labpc_plus_layout,
+ .has_ao = 1,
+ .ai_range_table = &range_labpc_plus_ai,
+ .ai_range_code = labpc_plus_ai_gain_bits,
+ },
};
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((struct labpc_board_struct *)dev->board_ptr)
+#endif
/* size in bytes of dma buffer */
static const int dma_buffer_size = 0xff00;
/* 2 bytes per sample */
static const int sample_size = 2;
-static inline int labpc_counter_load(struct comedi_device *dev,
- unsigned long base_address,
- unsigned int counter_number,
- unsigned int count, unsigned int mode)
+static int labpc_counter_load(struct comedi_device *dev,
+ unsigned long base_address,
+ unsigned int counter_number,
+ unsigned int count, unsigned int mode)
{
- if (thisboard->memory_mapped_io)
+ const struct labpc_boardinfo *board = comedi_board(dev);
+
+ if (board->has_mmio)
return i8254_mm_load((void __iomem *)base_address, 0,
counter_number, count, mode);
else
return i8254_load(base_address, 0, counter_number, count, mode);
}
-int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
- unsigned int irq, unsigned int dma_chan)
+static int labpc_counter_set_mode(struct comedi_device *dev,
+ unsigned long base_address,
+ unsigned int counter_number,
+ unsigned int mode)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+
+ if (board->has_mmio)
+ return i8254_mm_set_mode((void __iomem *)base_address, 0,
+ counter_number, mode);
+ else
+ return i8254_set_mode(base_address, 0, counter_number, mode);
+}
+
+static bool labpc_range_is_unipolar(struct comedi_subdevice *s,
+ unsigned int range)
+{
+ return s->range_table->range[range].min >= 0;
+}
+
+static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- int i;
- unsigned long isr_flags;
-#ifdef CONFIG_ISA_DMA_API
- unsigned long dma_flags;
-#endif
- short lsb, msb;
- int ret;
+ unsigned long flags;
- dev_info(dev->class_dev, "ni_labpc: %s\n", thisboard->name);
- if (iobase == 0) {
- dev_err(dev->class_dev, "io base address is zero!\n");
- return -EINVAL;
- }
- /* request io regions for isa boards */
- if (thisboard->bustype == isa_bustype) {
- /* check if io addresses are available */
- if (!request_region(iobase, LABPC_SIZE, DRV_NAME)) {
- dev_err(dev->class_dev, "I/O port conflict\n");
- return -EIO;
- }
- }
- dev->iobase = iobase;
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG);
+ devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
- if (thisboard->memory_mapped_io) {
- devpriv->read_byte = labpc_readb;
- devpriv->write_byte = labpc_writeb;
- } else {
- devpriv->read_byte = labpc_inb;
- devpriv->write_byte = labpc_outb;
- }
- /* initialize board's command registers */
- devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
- devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
- if (thisboard->register_layout == labpc_1200_layout) {
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
- }
+ devpriv->cmd3 = 0;
+ devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG);
- /* grab our IRQ */
- if (irq) {
- isr_flags = 0;
- if (thisboard->bustype == pci_bustype
- || thisboard->bustype == pcmcia_bustype)
- isr_flags |= IRQF_SHARED;
- if (request_irq(irq, labpc_interrupt, isr_flags,
- DRV_NAME, dev)) {
- dev_err(dev->class_dev, "unable to allocate irq %u\n",
- irq);
- return -EINVAL;
- }
- }
- dev->irq = irq;
+ return 0;
+}
-#ifdef CONFIG_ISA_DMA_API
- /* grab dma channel */
- if (dma_chan > 3) {
- dev_err(dev->class_dev, "invalid dma channel %u\n", dma_chan);
- return -EINVAL;
- } else if (dma_chan) {
- /* allocate dma buffer */
- devpriv->dma_buffer = kmalloc(dma_buffer_size,
- GFP_KERNEL | GFP_DMA);
- if (devpriv->dma_buffer == NULL)
- return -ENOMEM;
+static void labpc_ai_set_chan_and_gain(struct comedi_device *dev,
+ enum scan_mode mode,
+ unsigned int chan,
+ unsigned int range,
+ unsigned int aref)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
- if (request_dma(dma_chan, DRV_NAME)) {
- dev_err(dev->class_dev,
- "failed to allocate dma channel %u\n",
- dma_chan);
- return -EINVAL;
- }
- devpriv->dma_chan = dma_chan;
- dma_flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
- release_dma_lock(dma_flags);
- }
-#endif
+ /* munge channel bits for differential/scan disabled mode */
+ if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) &&
+ aref == AREF_DIFF)
+ chan *= 2;
+ devpriv->cmd1 = CMD1_MA(chan);
+ devpriv->cmd1 |= board->ai_range_code[range];
- dev->board_name = thisboard->name;
+ devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG);
+}
- ret = comedi_alloc_subdevices(dev, 5);
- if (ret)
- return ret;
+static void labpc_setup_cmd6_reg(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ enum scan_mode mode,
+ enum transfer_type xfer,
+ unsigned int range,
+ unsigned int aref,
+ bool ena_intr)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
- /* analog input subdevice */
- s = &dev->subdevices[0];
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags =
- SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
- s->n_chan = 8;
- s->len_chanlist = 8;
- s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
- s->range_table = thisboard->ai_range_table;
- s->do_cmd = labpc_ai_cmd;
- s->do_cmdtest = labpc_ai_cmdtest;
- s->insn_read = labpc_ai_rinsn;
- s->cancel = labpc_cancel;
+ if (board->register_layout != labpc_1200_layout)
+ return;
- /* analog output */
- s = &dev->subdevices[1];
- if (thisboard->has_ao) {
- /*
- * Could provide command support, except it only has a
- * one sample hardware buffer for analog output and no
- * underrun flag.
- */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
- s->n_chan = NUM_AO_CHAN;
- s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
- s->range_table = &range_labpc_ao;
- s->insn_read = labpc_ao_rinsn;
- s->insn_write = labpc_ao_winsn;
- /* initialize analog outputs to a known value */
- for (i = 0; i < s->n_chan; i++) {
- devpriv->ao_value[i] = s->maxdata / 2;
- lsb = devpriv->ao_value[i] & 0xff;
- msb = (devpriv->ao_value[i] >> 8) & 0xff;
- devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i));
- devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i));
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
+ /* reference inputs to ground or common? */
+ if (aref != AREF_GROUND)
+ devpriv->cmd6 |= CMD6_NRSE;
+ else
+ devpriv->cmd6 &= ~CMD6_NRSE;
- /* 8255 dio */
- s = &dev->subdevices[2];
- /* if board uses io memory we have to give a custom callback
- * function to the 8255 driver */
- if (thisboard->memory_mapped_io)
- subdev_8255_init(dev, s, labpc_dio_mem_callback,
- (unsigned long)(dev->iobase + DIO_BASE_REG));
+ /* bipolar or unipolar range? */
+ if (labpc_range_is_unipolar(s, range))
+ devpriv->cmd6 |= CMD6_ADCUNI;
else
- subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG);
+ devpriv->cmd6 &= ~CMD6_ADCUNI;
- /* calibration subdevices for boards that have one */
- s = &dev->subdevices[3];
- if (thisboard->register_layout == labpc_1200_layout) {
- s->type = COMEDI_SUBD_CALIB;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = 16;
- s->maxdata = 0xff;
- s->insn_read = labpc_calib_read_insn;
- s->insn_write = labpc_calib_write_insn;
+ /* interrupt on fifo half full? */
+ if (xfer == fifo_half_full_transfer)
+ devpriv->cmd6 |= CMD6_HFINTEN;
+ else
+ devpriv->cmd6 &= ~CMD6_HFINTEN;
- for (i = 0; i < s->n_chan; i++)
- write_caldac(dev, i, s->maxdata / 2);
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ /* enable interrupt on counter a1 terminal count? */
+ if (ena_intr)
+ devpriv->cmd6 |= CMD6_DQINTEN;
+ else
+ devpriv->cmd6 &= ~CMD6_DQINTEN;
- /* EEPROM */
- s = &dev->subdevices[4];
- if (thisboard->register_layout == labpc_1200_layout) {
- s->type = COMEDI_SUBD_MEMORY;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = EEPROM_SIZE;
- s->maxdata = 0xff;
- s->insn_read = labpc_eeprom_read_insn;
- s->insn_write = labpc_eeprom_write_insn;
-
- for (i = 0; i < EEPROM_SIZE; i++)
- devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ /* are we scanning up or down through channels? */
+ if (mode == MODE_MULT_CHAN_UP)
+ devpriv->cmd6 |= CMD6_SCANUP;
+ else
+ devpriv->cmd6 &= ~CMD6_SCANUP;
- return 0;
+ devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG);
}
-EXPORT_SYMBOL_GPL(labpc_common_attach);
-static const struct labpc_board_struct *
-labpc_pci_find_boardinfo(struct pci_dev *pcidev)
+static unsigned int labpc_read_adc_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+ unsigned int msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+
+ return (msb << 8) | lsb;
+}
+
+static void labpc_clear_adc_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
+ labpc_read_adc_fifo(dev);
+}
+
+static int labpc_ai_wait_for_data(struct comedi_device *dev,
+ int timeout)
{
- unsigned int device_id = pcidev->device;
- unsigned int n;
-
- for (n = 0; n < ARRAY_SIZE(labpc_boards); n++) {
- const struct labpc_board_struct *board = &labpc_boards[n];
- if (board->bustype == pci_bustype &&
- board->device_id == device_id)
- return board;
+ struct labpc_private *devpriv = dev->private;
+ int i;
+
+ for (i = 0; i < timeout; i++) {
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+ if (devpriv->stat1 & STAT1_DAVAIL)
+ return 0;
+ udelay(1);
}
- return NULL;
+ return -ETIME;
}
-static int labpc_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+static int labpc_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct labpc_private *devpriv;
- unsigned long iobase;
- unsigned int irq;
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int aref = CR_AREF(insn->chanspec);
int ret;
+ int i;
- if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS))
- return -ENODEV;
+ /* disable timed conversions, interrupt generation and dma */
+ labpc_cancel(dev, s);
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
+ labpc_ai_set_chan_and_gain(dev, MODE_SINGLE_CHAN, chan, range, aref);
- dev->board_ptr = labpc_pci_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
- devpriv->mite = mite_alloc(pcidev);
- if (!devpriv->mite)
- return -ENOMEM;
- ret = mite_setup(devpriv->mite);
- if (ret < 0)
+ labpc_setup_cmd6_reg(dev, s, MODE_SINGLE_CHAN, fifo_not_empty_transfer,
+ range, aref, false);
+
+ /* setup cmd4 register */
+ devpriv->cmd4 = 0;
+ devpriv->cmd4 |= CMD4_ECLKRCV;
+ /* single-ended/differential */
+ if (aref == AREF_DIFF)
+ devpriv->cmd4 |= CMD4_SEDIFF;
+ devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG);
+
+ /* initialize pacer counter to prevent any problems */
+ ret = labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG,
+ 0, I8254_MODE2);
+ if (ret)
return ret;
- iobase = (unsigned long)devpriv->mite->daq_io_addr;
- irq = mite_irq(devpriv->mite);
- return labpc_common_attach(dev, iobase, irq, 0);
+
+ labpc_clear_adc_fifo(dev);
+
+ for (i = 0; i < insn->n; i++) {
+ /* trigger conversion */
+ devpriv->write_byte(0x1, dev->iobase + ADC_START_CONVERT_REG);
+
+ ret = labpc_ai_wait_for_data(dev, LABPC_ADC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ data[i] = labpc_read_adc_fifo(dev);
+ }
+
+ return insn->n;
}
-static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+#ifdef CONFIG_ISA_DMA_API
+/* utility function that suggests a dma transfer size in bytes */
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
{
- struct labpc_private *devpriv;
- unsigned long iobase = 0;
- unsigned int irq = 0;
- unsigned int dma_chan = 0;
+ unsigned int size;
+ unsigned int freq;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
+ if (cmd->convert_src == TRIG_TIMER)
+ freq = 1000000000 / cmd->convert_arg;
+ /* return some default value */
+ else
+ freq = 0xffffffff;
- /* get base address, irq etc. based on bustype */
- switch (thisboard->bustype) {
- case isa_bustype:
-#ifdef CONFIG_ISA_DMA_API
- iobase = it->options[0];
- irq = it->options[1];
- dma_chan = it->options[2];
-#else
- dev_err(dev->class_dev,
- "ni_labpc driver has not been built with ISA DMA support.\n");
- return -EINVAL;
-#endif
- break;
- case pci_bustype:
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
- dev_err(dev->class_dev,
- "manual configuration of PCI board '%s' is not supported\n",
- thisboard->name);
- return -EINVAL;
-#else
- dev_err(dev->class_dev,
- "ni_labpc driver has not been built with PCI support.\n");
- return -EINVAL;
+ /* make buffer fill in no more than 1/3 second */
+ size = (freq / 3) * sample_size;
+
+ /* set a minimum and maximum size allowed */
+ if (size > dma_buffer_size)
+ size = dma_buffer_size - dma_buffer_size % sample_size;
+ else if (size < sample_size)
+ size = sample_size;
+
+ return size;
+}
#endif
- break;
- default:
- dev_err(dev->class_dev,
- "ni_labpc: bug! couldn't determine board type\n");
- return -EINVAL;
- break;
- }
- return labpc_common_attach(dev, iobase, irq, dma_chan);
+static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
+{
+ if (mode == MODE_SINGLE_CHAN || cmd->scan_begin_src == TRIG_FOLLOW)
+ return true;
+
+ return false;
}
-void labpc_common_detach(struct comedi_device *dev)
+static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
- struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s;
+ if (cmd->convert_src != TRIG_TIMER)
+ return 0;
+
+ if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
+ return cmd->scan_begin_arg;
- if (!thisboard)
+ return cmd->convert_arg;
+}
+
+static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
+{
+ if (cmd->convert_src != TRIG_TIMER)
return;
- if (dev->subdevices) {
- s = &dev->subdevices[2];
- subdev_8255_cleanup(dev, s);
- }
-#ifdef CONFIG_ISA_DMA_API
- /* only free stuff if it has been allocated by _attach */
- kfree(devpriv->dma_buffer);
- if (devpriv->dma_chan)
- free_dma(devpriv->dma_chan);
-#endif
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (thisboard->bustype == isa_bustype && dev->iobase)
- release_region(dev->iobase, LABPC_SIZE);
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
- if (devpriv->mite) {
- mite_unsetup(devpriv->mite);
- mite_free(devpriv->mite);
- }
-#endif
-};
-EXPORT_SYMBOL_GPL(labpc_common_detach);
-static void labpc_clear_adc_fifo(const struct comedi_device *dev)
+ if (mode == MODE_SINGLE_CHAN &&
+ cmd->scan_begin_src == TRIG_TIMER) {
+ cmd->scan_begin_arg = ns;
+ if (cmd->convert_arg > cmd->scan_begin_arg)
+ cmd->convert_arg = cmd->scan_begin_arg;
+ } else
+ cmd->convert_arg = ns;
+}
+
+static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
- struct labpc_private *devpriv = dev->private;
+ if (cmd->scan_begin_src != TRIG_TIMER)
+ return 0;
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
+ return 0;
+
+ return cmd->scan_begin_arg;
}
-static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
+static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
+{
+ if (cmd->scan_begin_src != TRIG_TIMER)
+ return;
+
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
+ return;
+
+ cmd->scan_begin_arg = ns;
+}
+
+/* figures out what counter values to use based on command */
+static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
struct labpc_private *devpriv = dev->private;
- unsigned long flags;
+ /* max value for 16 bit counter in mode 2 */
+ const int max_counter_value = 0x10000;
+ /* min value for 16 bit counter in mode 2 */
+ const int min_counter_value = 2;
+ unsigned int base_period;
+ unsigned int scan_period;
+ unsigned int convert_period;
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
+ /*
+ * if both convert and scan triggers are TRIG_TIMER, then they
+ * both rely on counter b0
+ */
+ convert_period = labpc_ai_convert_period(cmd, mode);
+ scan_period = labpc_ai_scan_period(cmd, mode);
+ if (convert_period && scan_period) {
+ /*
+ * pick the lowest b0 divisor value we can (for maximum input
+ * clock speed on convert and scan counters)
+ */
+ devpriv->divisor_b0 = (scan_period - 1) /
+ (LABPC_TIMER_BASE * max_counter_value) + 1;
+ if (devpriv->divisor_b0 < min_counter_value)
+ devpriv->divisor_b0 = min_counter_value;
+ if (devpriv->divisor_b0 > max_counter_value)
+ devpriv->divisor_b0 = max_counter_value;
- devpriv->command3_bits = 0;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ base_period = LABPC_TIMER_BASE * devpriv->divisor_b0;
- return 0;
+ /* set a0 for conversion frequency and b1 for scan frequency */
+ switch (cmd->flags & TRIG_ROUND_MASK) {
+ default:
+ case TRIG_ROUND_NEAREST:
+ devpriv->divisor_a0 =
+ (convert_period + (base_period / 2)) / base_period;
+ devpriv->divisor_b1 =
+ (scan_period + (base_period / 2)) / base_period;
+ break;
+ case TRIG_ROUND_UP:
+ devpriv->divisor_a0 =
+ (convert_period + (base_period - 1)) / base_period;
+ devpriv->divisor_b1 =
+ (scan_period + (base_period - 1)) / base_period;
+ break;
+ case TRIG_ROUND_DOWN:
+ devpriv->divisor_a0 = convert_period / base_period;
+ devpriv->divisor_b1 = scan_period / base_period;
+ break;
+ }
+ /* make sure a0 and b1 values are acceptable */
+ if (devpriv->divisor_a0 < min_counter_value)
+ devpriv->divisor_a0 = min_counter_value;
+ if (devpriv->divisor_a0 > max_counter_value)
+ devpriv->divisor_a0 = max_counter_value;
+ if (devpriv->divisor_b1 < min_counter_value)
+ devpriv->divisor_b1 = min_counter_value;
+ if (devpriv->divisor_b1 > max_counter_value)
+ devpriv->divisor_b1 = max_counter_value;
+ /* write corrected timings to command */
+ labpc_set_ai_convert_period(cmd, mode,
+ base_period * devpriv->divisor_a0);
+ labpc_set_ai_scan_period(cmd, mode,
+ base_period * devpriv->divisor_b1);
+ /*
+ * if only one TRIG_TIMER is used, we can employ the generic
+ * cascaded timing functions
+ */
+ } else if (scan_period) {
+ /*
+ * calculate cascaded counter values
+ * that give desired scan timing
+ */
+ i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
+ &(devpriv->divisor_b1),
+ &(devpriv->divisor_b0),
+ &scan_period,
+ cmd->flags & TRIG_ROUND_MASK);
+ labpc_set_ai_scan_period(cmd, mode, scan_period);
+ } else if (convert_period) {
+ /*
+ * calculate cascaded counter values
+ * that give desired conversion timing
+ */
+ i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
+ &(devpriv->divisor_a0),
+ &(devpriv->divisor_b0),
+ &convert_period,
+ cmd->flags & TRIG_ROUND_MASK);
+ labpc_set_ai_convert_period(cmd, mode, convert_period);
+ }
}
static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
@@ -923,72 +741,10 @@ static int labpc_ai_chanlist_invalid(const struct comedi_device *dev,
return 0;
}
-static int labpc_use_continuous_mode(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (mode == MODE_SINGLE_CHAN)
- return 1;
-
- if (cmd->scan_begin_src == TRIG_FOLLOW)
- return 1;
-
- return 0;
-}
-
-static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (cmd->convert_src != TRIG_TIMER)
- return 0;
-
- if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
- return cmd->scan_begin_arg;
-
- return cmd->convert_arg;
-}
-
-static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
- enum scan_mode mode, unsigned int ns)
-{
- if (cmd->convert_src != TRIG_TIMER)
- return;
-
- if (mode == MODE_SINGLE_CHAN &&
- cmd->scan_begin_src == TRIG_TIMER) {
- cmd->scan_begin_arg = ns;
- if (cmd->convert_arg > cmd->scan_begin_arg)
- cmd->convert_arg = cmd->scan_begin_arg;
- } else
- cmd->convert_arg = ns;
-}
-
-static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (cmd->scan_begin_src != TRIG_TIMER)
- return 0;
-
- if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
- return 0;
-
- return cmd->scan_begin_arg;
-}
-
-static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
- enum scan_mode mode, unsigned int ns)
-{
- if (cmd->scan_begin_src != TRIG_TIMER)
- return;
-
- if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
- return;
-
- cmd->scan_begin_arg = ns;
-}
-
static int labpc_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
+ const struct labpc_boardinfo *board = comedi_board(dev);
int err = 0;
int tmp, tmp2;
unsigned int stop_mask;
@@ -1003,7 +759,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
stop_mask = TRIG_COUNT | TRIG_NONE;
- if (thisboard->register_layout == labpc_1200_layout)
+ if (board->register_layout == labpc_1200_layout)
stop_mask |= TRIG_EXT;
err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask);
@@ -1037,7 +793,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
if (cmd->convert_src == TRIG_TIMER)
err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- thisboard->ai_speed);
+ board->ai_speed);
/* make sure scan timing is not too fast */
if (cmd->scan_begin_src == TRIG_TIMER) {
@@ -1045,7 +801,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
cmd->convert_arg * cmd->chanlist_len);
err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- thisboard->ai_speed * cmd->chanlist_len);
+ board->ai_speed * cmd->chanlist_len);
}
switch (cmd->stop_src) {
@@ -1086,34 +842,23 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct labpc_boardinfo *board = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
- int channel, range, aref;
-#ifdef CONFIG_ISA_DMA_API
- unsigned long irq_flags;
-#endif
- int ret;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
+ enum scan_mode mode = labpc_ai_scan_mode(cmd);
+ unsigned int chanspec = (mode == MODE_MULT_CHAN_UP)
+ ? cmd->chanlist[cmd->chanlist_len - 1]
+ : cmd->chanlist[0];
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int aref = CR_AREF(chanspec);
enum transfer_type xfer;
- enum scan_mode mode;
unsigned long flags;
-
- if (!dev->irq) {
- comedi_error(dev, "no irq assigned, cannot perform command");
- return -1;
- }
-
- range = CR_RANGE(cmd->chanlist[0]);
- aref = CR_AREF(cmd->chanlist[0]);
+ int ret;
/* make sure board is disabled before setting up acquisition */
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- devpriv->command3_bits = 0;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ labpc_cancel(dev, s);
/* initialize software conversion count */
if (cmd->stop_src == TRIG_COUNT)
@@ -1126,17 +871,17 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* (pc+ manual says this is minimum allowed) using mode 0
*/
ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
- 1, 3, 0);
- if (ret < 0) {
- comedi_error(dev, "error loading counter a1");
- return -1;
- }
- } else /*
- * otherwise, just put a1 in mode 0
- * with no count to set its output low
- */
- devpriv->write_byte(INIT_A1_BITS,
- dev->iobase + COUNTER_A_CONTROL_REG);
+ 1, 3, I8254_MODE0);
+ } else {
+ /* just put counter a1 in mode 0 to set its output low */
+ ret = labpc_counter_set_mode(dev,
+ dev->iobase + COUNTER_A_BASE_REG,
+ 1, I8254_MODE0);
+ }
+ if (ret) {
+ comedi_error(dev, "error loading counter a1");
+ return ret;
+ }
#ifdef CONFIG_ISA_DMA_API
/* figure out what method we will use to transfer data */
@@ -1145,14 +890,12 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* dma unsafe at RT priority,
* and too much setup time for TRIG_WAKE_EOS for
*/
- (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0 &&
- /* only available on the isa boards */
- thisboard->bustype == isa_bustype) {
+ (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0) {
xfer = isa_dma_transfer;
/* pc-plus has no fifo-half full interrupt */
} else
#endif
- if (thisboard->register_layout == labpc_1200_layout &&
+ if (board->register_layout == labpc_1200_layout &&
/* wake-end-of-scan should interrupt on fifo not empty */
(cmd->flags & TRIG_WAKE_EOS) == 0 &&
/* make sure we are taking more than just a few points */
@@ -1161,76 +904,34 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
} else
xfer = fifo_not_empty_transfer;
devpriv->current_transfer = xfer;
- mode = labpc_ai_scan_mode(cmd);
- /* setup command6 register for 1200 boards */
- if (thisboard->register_layout == labpc_1200_layout) {
- /* reference inputs to ground or common? */
- if (aref != AREF_GROUND)
- devpriv->command6_bits |= ADC_COMMON_BIT;
- else
- devpriv->command6_bits &= ~ADC_COMMON_BIT;
- /* bipolar or unipolar range? */
- if (thisboard->ai_range_is_unipolar[range])
- devpriv->command6_bits |= ADC_UNIP_BIT;
- else
- devpriv->command6_bits &= ~ADC_UNIP_BIT;
- /* interrupt on fifo half full? */
- if (xfer == fifo_half_full_transfer)
- devpriv->command6_bits |= ADC_FHF_INTR_EN_BIT;
- else
- devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
- /* enable interrupt on counter a1 terminal count? */
- if (cmd->stop_src == TRIG_EXT)
- devpriv->command6_bits |= A1_INTR_EN_BIT;
- else
- devpriv->command6_bits &= ~A1_INTR_EN_BIT;
- /* are we scanning up or down through channels? */
- if (mode == MODE_MULT_CHAN_UP)
- devpriv->command6_bits |= ADC_SCAN_UP_BIT;
- else
- devpriv->command6_bits &= ~ADC_SCAN_UP_BIT;
- /* write to register */
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
- }
+ labpc_ai_set_chan_and_gain(dev, mode, chan, range, aref);
+
+ labpc_setup_cmd6_reg(dev, s, mode, xfer, range, aref,
+ (cmd->stop_src == TRIG_EXT));
- /* setup channel list, etc (command1 register) */
- devpriv->command1_bits = 0;
- if (mode == MODE_MULT_CHAN_UP)
- channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
- else
- channel = CR_CHAN(cmd->chanlist[0]);
- /* munge channel bits for differential / scan disabled mode */
- if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) &&
- aref == AREF_DIFF)
- channel *= 2;
- devpriv->command1_bits |= ADC_CHAN_BITS(channel);
- devpriv->command1_bits |= thisboard->ai_range_code[range];
- devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
/* manual says to set scan enable bit on second pass */
if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) {
- devpriv->command1_bits |= ADC_SCAN_EN_BIT;
+ devpriv->cmd1 |= CMD1_SCANEN;
/* need a brief delay before enabling scan, or scan
* list will get screwed when you switch
* between scan up to scan down mode - dunno why */
udelay(1);
- devpriv->write_byte(devpriv->command1_bits,
- dev->iobase + COMMAND1_REG);
+ devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG);
}
devpriv->write_byte(cmd->chanlist_len,
dev->iobase + INTERVAL_COUNT_REG);
/* load count */
- devpriv->write_byte(INTERVAL_LOAD_BITS,
- dev->iobase + INTERVAL_LOAD_REG);
+ devpriv->write_byte(0x1, dev->iobase + INTERVAL_STROBE_REG);
- if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) {
+ if (cmd->convert_src == TRIG_TIMER ||
+ cmd->scan_begin_src == TRIG_TIMER) {
/* set up pacing */
labpc_adc_timing(dev, cmd, mode);
/* load counter b0 in mode 3 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
- 0, devpriv->divisor_b0, 3);
+ 0, devpriv->divisor_b0, I8254_MODE3);
if (ret < 0) {
comedi_error(dev, "error loading counter b0");
return -1;
@@ -1240,20 +941,23 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (labpc_ai_convert_period(cmd, mode)) {
/* load counter a0 in mode 2 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
- 0, devpriv->divisor_a0, 2);
- if (ret < 0) {
- comedi_error(dev, "error loading counter a0");
- return -1;
- }
- } else
- devpriv->write_byte(INIT_A0_BITS,
- dev->iobase + COUNTER_A_CONTROL_REG);
+ 0, devpriv->divisor_a0, I8254_MODE2);
+ } else {
+ /* initialize pacer counter to prevent any problems */
+ ret = labpc_counter_set_mode(dev,
+ dev->iobase + COUNTER_A_BASE_REG,
+ 0, I8254_MODE2);
+ }
+ if (ret) {
+ comedi_error(dev, "error loading counter a0");
+ return ret;
+ }
/* set up scan pacing */
if (labpc_ai_scan_period(cmd, mode)) {
/* load counter b1 in mode 2 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
- 1, devpriv->divisor_b1, 2);
+ 1, devpriv->divisor_b1, I8254_MODE2);
if (ret < 0) {
comedi_error(dev, "error loading counter b1");
return -1;
@@ -1265,6 +969,8 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
#ifdef CONFIG_ISA_DMA_API
/* set up dma transfer */
if (xfer == isa_dma_transfer) {
+ unsigned long irq_flags;
+
irq_flags = claim_dma_lock();
disable_dma(devpriv->dma_chan);
/* clear flip-flop to make sure 2-byte registers for
@@ -1283,197 +989,54 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
enable_dma(devpriv->dma_chan);
release_dma_lock(irq_flags);
/* enable board's dma */
- devpriv->command3_bits |= DMA_EN_BIT | DMATC_INTR_EN_BIT;
+ devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
} else
- devpriv->command3_bits &= ~DMA_EN_BIT & ~DMATC_INTR_EN_BIT;
+ devpriv->cmd3 &= ~(CMD3_DMAEN | CMD3_DMATCINTEN);
#endif
/* enable error interrupts */
- devpriv->command3_bits |= ERR_INTR_EN_BIT;
+ devpriv->cmd3 |= CMD3_ERRINTEN;
/* enable fifo not empty interrupt? */
if (xfer == fifo_not_empty_transfer)
- devpriv->command3_bits |= ADC_FNE_INTR_EN_BIT;
+ devpriv->cmd3 |= CMD3_FIFOINTEN;
else
- devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ devpriv->cmd3 &= ~CMD3_FIFOINTEN;
+ devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG);
- /* setup any external triggering/pacing (command4 register) */
- devpriv->command4_bits = 0;
+ /* setup any external triggering/pacing (cmd4 register) */
+ devpriv->cmd4 = 0;
if (cmd->convert_src != TRIG_EXT)
- devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
+ devpriv->cmd4 |= CMD4_ECLKRCV;
/* XXX should discard first scan when using interval scanning
* since manual says it is not synced with scan clock */
- if (labpc_use_continuous_mode(cmd, mode) == 0) {
- devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT;
+ if (!labpc_use_continuous_mode(cmd, mode)) {
+ devpriv->cmd4 |= CMD4_INTSCAN;
if (cmd->scan_begin_src == TRIG_EXT)
- devpriv->command4_bits |= EXT_SCAN_EN_BIT;
+ devpriv->cmd4 |= CMD4_EOIRCV;
}
/* single-ended/differential */
if (aref == AREF_DIFF)
- devpriv->command4_bits |= ADC_DIFF_BIT;
- devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
+ devpriv->cmd4 |= CMD4_SEDIFF;
+ devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG);
/* startup acquisition */
- /* command2 reg */
- /* use 2 cascaded counters for pacing */
spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits |= CASCADE_BIT;
- switch (cmd->start_src) {
- case TRIG_EXT:
- devpriv->command2_bits |= HWTRIG_BIT;
- devpriv->command2_bits &= ~PRETRIG_BIT & ~SWTRIG_BIT;
- break;
- case TRIG_NOW:
- devpriv->command2_bits |= SWTRIG_BIT;
- devpriv->command2_bits &= ~PRETRIG_BIT & ~HWTRIG_BIT;
- break;
- default:
- comedi_error(dev, "bug with start_src");
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return -1;
- break;
- }
- switch (cmd->stop_src) {
- case TRIG_EXT:
- devpriv->command2_bits |= HWTRIG_BIT | PRETRIG_BIT;
- break;
- case TRIG_COUNT:
- case TRIG_NONE:
- break;
- default:
- comedi_error(dev, "bug with stop_src");
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return -1;
- }
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- return 0;
-}
-
-/* interrupt service routine */
-static irqreturn_t labpc_interrupt(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async;
- struct comedi_cmd *cmd;
-
- if (dev->attached == 0) {
- comedi_error(dev, "premature interrupt");
- return IRQ_HANDLED;
- }
-
- async = s->async;
- cmd = &async->cmd;
- async->events = 0;
-
- /* read board status */
- devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
- if (thisboard->register_layout == labpc_1200_layout)
- devpriv->status2_bits =
- devpriv->read_byte(dev->iobase + STATUS2_REG);
-
- if ((devpriv->status1_bits & (DMATC_BIT | TIMER_BIT | OVERFLOW_BIT |
- OVERRUN_BIT | DATA_AVAIL_BIT)) == 0
- && (devpriv->status2_bits & A1_TC_BIT) == 0
- && (devpriv->status2_bits & FNHF_BIT)) {
- return IRQ_NONE;
- }
-
- if (devpriv->status1_bits & OVERRUN_BIT) {
- /* clear error interrupt */
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- comedi_error(dev, "overrun");
- return IRQ_HANDLED;
- }
-
-#ifdef CONFIG_ISA_DMA_API
- if (devpriv->current_transfer == isa_dma_transfer) {
- /*
- * if a dma terminal count of external stop trigger
- * has occurred
- */
- if (devpriv->status1_bits & DMATC_BIT ||
- (thisboard->register_layout == labpc_1200_layout
- && devpriv->status2_bits & A1_TC_BIT)) {
- handle_isa_dma(dev);
- }
- } else
-#endif
- labpc_drain_fifo(dev);
-
- if (devpriv->status1_bits & TIMER_BIT) {
- comedi_error(dev, "handled timer interrupt?");
- /* clear it */
- devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG);
- }
-
- if (devpriv->status1_bits & OVERFLOW_BIT) {
- /* clear error interrupt */
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- comedi_error(dev, "overflow");
- return IRQ_HANDLED;
- }
- /* handle external stop trigger */
- if (cmd->stop_src == TRIG_EXT) {
- if (devpriv->status2_bits & A1_TC_BIT) {
- labpc_drain_dregs(dev);
- labpc_cancel(dev, s);
- async->events |= COMEDI_CB_EOA;
- }
- }
-
- /* TRIG_COUNT end of acquisition */
- if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->count == 0) {
- labpc_cancel(dev, s);
- async->events |= COMEDI_CB_EOA;
- }
- }
- comedi_event(dev, s);
- return IRQ_HANDLED;
-}
+ /* use 2 cascaded counters for pacing */
+ devpriv->cmd2 |= CMD2_TBSEL;
-/* read all available samples from ai fifo */
-static int labpc_drain_fifo(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int lsb, msb;
- short data;
- struct comedi_async *async = dev->read_subdev->async;
- const int timeout = 10000;
- unsigned int i;
+ devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG);
+ if (cmd->start_src == TRIG_EXT)
+ devpriv->cmd2 |= CMD2_HWTRIG;
+ else
+ devpriv->cmd2 |= CMD2_SWTRIG;
+ if (cmd->stop_src == TRIG_EXT)
+ devpriv->cmd2 |= (CMD2_HWTRIG | CMD2_PRETRIG);
- devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
+ devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG);
- for (i = 0; (devpriv->status1_bits & DATA_AVAIL_BIT) && i < timeout;
- i++) {
- /* quit if we have all the data we want */
- if (async->cmd.stop_src == TRIG_COUNT) {
- if (devpriv->count == 0)
- break;
- devpriv->count--;
- }
- lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- data = (msb << 8) | lsb;
- cfc_write_to_buffer(dev->read_subdev, data);
- devpriv->status1_bits =
- devpriv->read_byte(dev->iobase + STATUS1_REG);
- }
- if (i == timeout) {
- comedi_error(dev, "ai timeout, fifo never empties");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- return -1;
- }
+ spin_unlock_irqrestore(&dev->spinlock, flags);
return 0;
}
@@ -1489,7 +1052,7 @@ static void labpc_drain_dma(struct comedi_device *dev)
unsigned int max_points, num_points, residue, leftover;
int i;
- status = devpriv->status1_bits;
+ status = devpriv->stat1;
flags = claim_dma_lock();
disable_dma(devpriv->dma_chan);
@@ -1546,6 +1109,38 @@ static void handle_isa_dma(struct comedi_device *dev)
}
#endif
+/* read all available samples from ai fifo */
+static int labpc_drain_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ short data;
+ struct comedi_async *async = dev->read_subdev->async;
+ const int timeout = 10000;
+ unsigned int i;
+
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+
+ for (i = 0; (devpriv->stat1 & STAT1_DAVAIL) && i < timeout;
+ i++) {
+ /* quit if we have all the data we want */
+ if (async->cmd.stop_src == TRIG_COUNT) {
+ if (devpriv->count == 0)
+ break;
+ devpriv->count--;
+ }
+ data = labpc_read_adc_fifo(dev);
+ cfc_write_to_buffer(dev->read_subdev, data);
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+ }
+ if (i == timeout) {
+ comedi_error(dev, "ai timeout, fifo never empties");
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ return -1;
+ }
+
+ return 0;
+}
+
/* makes sure all data acquired by board is transferred to comedi (used
* when acquisition is terminated by stop_src == TRIG_EXT). */
static void labpc_drain_dregs(struct comedi_device *dev)
@@ -1560,99 +1155,102 @@ static void labpc_drain_dregs(struct comedi_device *dev)
labpc_drain_fifo(dev);
}
-static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+/* interrupt service routine */
+static irqreturn_t labpc_interrupt(int irq, void *d)
{
+ struct comedi_device *dev = d;
+ const struct labpc_boardinfo *board = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
- int i, n;
- int chan, range;
- int lsb, msb;
- int timeout = 1000;
- unsigned long flags;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async;
+ struct comedi_cmd *cmd;
- /* disable timed conversions */
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
+ if (!dev->attached) {
+ comedi_error(dev, "premature interrupt");
+ return IRQ_HANDLED;
+ }
- /* disable interrupt generation and dma */
- devpriv->command3_bits = 0;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ async = s->async;
+ cmd = &async->cmd;
+ async->events = 0;
- /* set gain and channel */
- devpriv->command1_bits = 0;
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
- devpriv->command1_bits |= thisboard->ai_range_code[range];
- /* munge channel bits for differential/scan disabled mode */
- if (CR_AREF(insn->chanspec) == AREF_DIFF)
- chan *= 2;
- devpriv->command1_bits |= ADC_CHAN_BITS(chan);
- devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
-
- /* setup command6 register for 1200 boards */
- if (thisboard->register_layout == labpc_1200_layout) {
- /* reference inputs to ground or common? */
- if (CR_AREF(insn->chanspec) != AREF_GROUND)
- devpriv->command6_bits |= ADC_COMMON_BIT;
- else
- devpriv->command6_bits &= ~ADC_COMMON_BIT;
- /* bipolar or unipolar range? */
- if (thisboard->ai_range_is_unipolar[range])
- devpriv->command6_bits |= ADC_UNIP_BIT;
- else
- devpriv->command6_bits &= ~ADC_UNIP_BIT;
- /* don't interrupt on fifo half full */
- devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
- /* don't enable interrupt on counter a1 terminal count? */
- devpriv->command6_bits &= ~A1_INTR_EN_BIT;
- /* write to register */
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
+ /* read board status */
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+ if (board->register_layout == labpc_1200_layout)
+ devpriv->stat2 = devpriv->read_byte(dev->iobase + STAT2_REG);
+
+ if ((devpriv->stat1 & (STAT1_GATA0 | STAT1_CNTINT | STAT1_OVERFLOW |
+ STAT1_OVERRUN | STAT1_DAVAIL)) == 0
+ && (devpriv->stat2 & STAT2_OUTA1) == 0
+ && (devpriv->stat2 & STAT2_FIFONHF)) {
+ return IRQ_NONE;
}
- /* setup command4 register */
- devpriv->command4_bits = 0;
- devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
- /* single-ended/differential */
- if (CR_AREF(insn->chanspec) == AREF_DIFF)
- devpriv->command4_bits |= ADC_DIFF_BIT;
- devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
- /*
- * initialize pacer counter output to make sure it doesn't
- * cause any problems
- */
- devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG);
+ if (devpriv->stat1 & STAT1_OVERRUN) {
+ /* clear error interrupt */
+ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ comedi_event(dev, s);
+ comedi_error(dev, "overrun");
+ return IRQ_HANDLED;
+ }
- labpc_clear_adc_fifo(dev);
+#ifdef CONFIG_ISA_DMA_API
+ if (devpriv->current_transfer == isa_dma_transfer) {
+ /*
+ * if a dma terminal count of external stop trigger
+ * has occurred
+ */
+ if (devpriv->stat1 & STAT1_GATA0 ||
+ (board->register_layout == labpc_1200_layout
+ && devpriv->stat2 & STAT2_OUTA1)) {
+ handle_isa_dma(dev);
+ }
+ } else
+#endif
+ labpc_drain_fifo(dev);
- for (n = 0; n < insn->n; n++) {
- /* trigger conversion */
- devpriv->write_byte(0x1, dev->iobase + ADC_CONVERT_REG);
+ if (devpriv->stat1 & STAT1_CNTINT) {
+ comedi_error(dev, "handled timer interrupt?");
+ /* clear it */
+ devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG);
+ }
- for (i = 0; i < timeout; i++) {
- if (devpriv->read_byte(dev->iobase +
- STATUS1_REG) & DATA_AVAIL_BIT)
- break;
- udelay(1);
+ if (devpriv->stat1 & STAT1_OVERFLOW) {
+ /* clear error interrupt */
+ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ comedi_event(dev, s);
+ comedi_error(dev, "overflow");
+ return IRQ_HANDLED;
+ }
+ /* handle external stop trigger */
+ if (cmd->stop_src == TRIG_EXT) {
+ if (devpriv->stat2 & STAT2_OUTA1) {
+ labpc_drain_dregs(dev);
+ labpc_cancel(dev, s);
+ async->events |= COMEDI_CB_EOA;
}
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
+ }
+
+ /* TRIG_COUNT end of acquisition */
+ if (cmd->stop_src == TRIG_COUNT) {
+ if (devpriv->count == 0) {
+ labpc_cancel(dev, s);
+ async->events |= COMEDI_CB_EOA;
}
- lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- data[n] = (msb << 8) | lsb;
}
- return n;
+ comedi_event(dev, s);
+ return IRQ_HANDLED;
}
-/* analog output insn */
-static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int labpc_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ const struct labpc_boardinfo *board = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
int channel, range;
unsigned long flags;
@@ -1664,20 +1262,19 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* note: hardware bug in daqcard-1200 means pacing cannot
* be independently enabled/disabled for its the two channels */
spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~DAC_PACED_BIT(channel);
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
+ devpriv->cmd2 &= ~CMD2_LDAC(channel);
+ devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
/* set range */
- if (thisboard->register_layout == labpc_1200_layout) {
+ if (board->register_layout == labpc_1200_layout) {
range = CR_RANGE(insn->chanspec);
- if (range & AO_RANGE_IS_UNIPOLAR)
- devpriv->command6_bits |= DAC_UNIP_BIT(channel);
+ if (labpc_range_is_unipolar(s, range))
+ devpriv->cmd6 |= CMD6_DACUNI(channel);
else
- devpriv->command6_bits &= ~DAC_UNIP_BIT(channel);
+ devpriv->cmd6 &= ~CMD6_DACUNI(channel);
/* write to register */
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
+ devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG);
}
/* send data */
lsb = data[0] & 0xff;
@@ -1691,9 +1288,10 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
return 1;
}
-/* analog output readback insn */
-static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int labpc_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct labpc_private *devpriv = dev->private;
@@ -1702,183 +1300,7 @@ static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return 1;
}
-static int labpc_calib_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
-
- data[0] = devpriv->caldac[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int labpc_calib_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int channel = CR_CHAN(insn->chanspec);
-
- write_caldac(dev, channel, data[0]);
- return 1;
-}
-
-static int labpc_eeprom_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
-
- data[0] = devpriv->eeprom_data[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int labpc_eeprom_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int channel = CR_CHAN(insn->chanspec);
- int ret;
-
- /* only allow writes to user area of eeprom */
- if (channel < 16 || channel > 127) {
- dev_dbg(dev->class_dev,
- "eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)\n");
- return -EINVAL;
- }
-
- ret = labpc_eeprom_write(dev, channel, data[0]);
- if (ret < 0)
- return ret;
-
- return 1;
-}
-
-#ifdef CONFIG_ISA_DMA_API
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
-{
- unsigned int size;
- unsigned int freq;
-
- if (cmd->convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd->convert_arg;
- /* return some default value */
- else
- freq = 0xffffffff;
-
- /* make buffer fill in no more than 1/3 second */
- size = (freq / 3) * sample_size;
-
- /* set a minimum and maximum size allowed */
- if (size > dma_buffer_size)
- size = dma_buffer_size - dma_buffer_size % sample_size;
- else if (size < sample_size)
- size = sample_size;
-
- return size;
-}
-#endif
-
-/* figures out what counter values to use based on command */
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- struct labpc_private *devpriv = dev->private;
- /* max value for 16 bit counter in mode 2 */
- const int max_counter_value = 0x10000;
- /* min value for 16 bit counter in mode 2 */
- const int min_counter_value = 2;
- unsigned int base_period;
- unsigned int scan_period;
- unsigned int convert_period;
-
- /*
- * if both convert and scan triggers are TRIG_TIMER, then they
- * both rely on counter b0
- */
- convert_period = labpc_ai_convert_period(cmd, mode);
- scan_period = labpc_ai_scan_period(cmd, mode);
- if (convert_period && scan_period) {
- /*
- * pick the lowest b0 divisor value we can (for maximum input
- * clock speed on convert and scan counters)
- */
- devpriv->divisor_b0 = (scan_period - 1) /
- (LABPC_TIMER_BASE * max_counter_value) + 1;
- if (devpriv->divisor_b0 < min_counter_value)
- devpriv->divisor_b0 = min_counter_value;
- if (devpriv->divisor_b0 > max_counter_value)
- devpriv->divisor_b0 = max_counter_value;
-
- base_period = LABPC_TIMER_BASE * devpriv->divisor_b0;
-
- /* set a0 for conversion frequency and b1 for scan frequency */
- switch (cmd->flags & TRIG_ROUND_MASK) {
- default:
- case TRIG_ROUND_NEAREST:
- devpriv->divisor_a0 =
- (convert_period + (base_period / 2)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period / 2)) / base_period;
- break;
- case TRIG_ROUND_UP:
- devpriv->divisor_a0 =
- (convert_period + (base_period - 1)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period - 1)) / base_period;
- break;
- case TRIG_ROUND_DOWN:
- devpriv->divisor_a0 = convert_period / base_period;
- devpriv->divisor_b1 = scan_period / base_period;
- break;
- }
- /* make sure a0 and b1 values are acceptable */
- if (devpriv->divisor_a0 < min_counter_value)
- devpriv->divisor_a0 = min_counter_value;
- if (devpriv->divisor_a0 > max_counter_value)
- devpriv->divisor_a0 = max_counter_value;
- if (devpriv->divisor_b1 < min_counter_value)
- devpriv->divisor_b1 = min_counter_value;
- if (devpriv->divisor_b1 > max_counter_value)
- devpriv->divisor_b1 = max_counter_value;
- /* write corrected timings to command */
- labpc_set_ai_convert_period(cmd, mode,
- base_period * devpriv->divisor_a0);
- labpc_set_ai_scan_period(cmd, mode,
- base_period * devpriv->divisor_b1);
- /*
- * if only one TRIG_TIMER is used, we can employ the generic
- * cascaded timing functions
- */
- } else if (scan_period) {
- /*
- * calculate cascaded counter values
- * that give desired scan timing
- */
- i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
- &(devpriv->divisor_b1),
- &(devpriv->divisor_b0),
- &scan_period,
- cmd->flags & TRIG_ROUND_MASK);
- labpc_set_ai_scan_period(cmd, mode, scan_period);
- } else if (convert_period) {
- /*
- * calculate cascaded counter values
- * that give desired conversion timing
- */
- i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
- &(devpriv->divisor_a0),
- &(devpriv->divisor_b0),
- &convert_period,
- cmd->flags & TRIG_ROUND_MASK);
- labpc_set_ai_convert_period(cmd, mode, convert_period);
- }
-}
-
-static int labpc_dio_mem_callback(int dir, int port, int data,
- unsigned long iobase)
+static int labpc_8255_mmio(int dir, int port, int data, unsigned long iobase)
{
if (dir) {
writeb(data, (void __iomem *)(iobase + port));
@@ -1897,20 +1319,18 @@ static void labpc_serial_out(struct comedi_device *dev, unsigned int value,
for (i = 1; i <= value_width; i++) {
/* clear serial clock */
- devpriv->command5_bits &= ~SCLOCK_BIT;
+ devpriv->cmd5 &= ~CMD5_SCLK;
/* send bits most significant bit first */
if (value & (1 << (value_width - i)))
- devpriv->command5_bits |= SDATA_BIT;
+ devpriv->cmd5 |= CMD5_SDATA;
else
- devpriv->command5_bits &= ~SDATA_BIT;
+ devpriv->cmd5 &= ~CMD5_SDATA;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* set clock to load bit */
- devpriv->command5_bits |= SCLOCK_BIT;
+ devpriv->cmd5 |= CMD5_SCLK;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
}
}
@@ -1924,20 +1344,17 @@ static unsigned int labpc_serial_in(struct comedi_device *dev)
for (i = 1; i <= value_width; i++) {
/* set serial clock */
- devpriv->command5_bits |= SCLOCK_BIT;
+ devpriv->cmd5 |= CMD5_SCLK;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* clear clock bit */
- devpriv->command5_bits &= ~SCLOCK_BIT;
+ devpriv->cmd5 &= ~CMD5_SCLK;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* read bits most significant bit first */
udelay(1);
- devpriv->status2_bits =
- devpriv->read_byte(dev->iobase + STATUS2_REG);
- if (devpriv->status2_bits & EEPROM_OUT_BIT)
+ devpriv->stat2 = devpriv->read_byte(dev->iobase + STAT2_REG);
+ if (devpriv->stat2 & STAT2_PROMOUT)
value |= 1 << (value_width - i);
}
@@ -1955,12 +1372,12 @@ static unsigned int labpc_eeprom_read(struct comedi_device *dev,
const int write_length = 8;
/* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* send read instruction */
labpc_serial_out(dev, read_instruction, write_length);
@@ -1970,9 +1387,37 @@ static unsigned int labpc_eeprom_read(struct comedi_device *dev,
value = labpc_serial_in(dev);
/* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+
+ return value;
+}
+
+static unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int value;
+ const int read_status_instruction = 0x5;
+ const int write_length = 8; /* 8 bit write lengths to eeprom */
+
+ /* enable read/write to eeprom */
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
+ udelay(1);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+
+ /* send read status instruction */
+ labpc_serial_out(dev, read_status_instruction, write_length);
+ /* read result */
+ value = labpc_serial_in(dev);
+
+ /* disable read/write to eeprom */
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
return value;
}
@@ -2002,68 +1447,40 @@ static int labpc_eeprom_write(struct comedi_device *dev,
devpriv->eeprom_data[address] = value;
/* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* send write_enable instruction */
labpc_serial_out(dev, write_enable_instruction, write_length);
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* send write instruction */
- devpriv->command5_bits |= EEPROM_EN_BIT;
+ devpriv->cmd5 |= CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
labpc_serial_out(dev, write_instruction, write_length);
/* send 8 bit address to write to */
labpc_serial_out(dev, address, write_length);
/* write value */
labpc_serial_out(dev, value, write_length);
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
return 0;
}
-static unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int value;
- const int read_status_instruction = 0x5;
- const int write_length = 8; /* 8 bit write lengths to eeprom */
-
- /* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
-
- /* send read status instruction */
- labpc_serial_out(dev, read_status_instruction, write_length);
- /* read result */
- value = labpc_serial_in(dev);
-
- /* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
-
- return value;
-}
-
/* writes to 8 bit calibration dacs */
static void write_caldac(struct comedi_device *dev, unsigned int channel,
unsigned int value)
@@ -2075,10 +1492,9 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel,
devpriv->caldac[channel] = value;
/* clear caldac load bit and make sure we don't write to eeprom */
- devpriv->command5_bits &=
- ~CALDAC_LOAD_BIT & ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->cmd5 &= ~(CMD5_CALDACLD | CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* write 4 bit channel */
labpc_serial_out(dev, channel, 4);
@@ -2086,49 +1502,295 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel,
labpc_serial_out(dev, value, 8);
/* set and clear caldac bit to load caldac value */
- devpriv->command5_bits |= CALDAC_LOAD_BIT;
+ devpriv->cmd5 |= CMD5_CALDACLD;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits &= ~CALDAC_LOAD_BIT;
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->cmd5 &= ~CMD5_CALDACLD;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
}
-static struct comedi_driver labpc_driver = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = labpc_attach,
- .auto_attach = labpc_auto_attach,
- .detach = labpc_common_detach,
- .num_names = ARRAY_SIZE(labpc_boards),
- .board_name = &labpc_boards[0].name,
- .offset = sizeof(struct labpc_board_struct),
-};
+static int labpc_calib_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
-static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)},
- {0}
-};
-MODULE_DEVICE_TABLE(pci, labpc_pci_table);
+ /*
+ * Only write the last data value to the caldac. Preceding
+ * data would be overwritten anyway.
+ */
+ if (insn->n > 0)
+ write_caldac(dev, chan, data[insn->n - 1]);
+
+ return insn->n;
+}
-static int labpc_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int labpc_calib_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- return comedi_pci_auto_config(dev, &labpc_driver);
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->caldac[chan];
+
+ return insn->n;
}
-static struct pci_driver labpc_pci_driver = {
- .name = DRV_NAME,
- .id_table = labpc_pci_table,
- .probe = labpc_pci_probe,
- .remove = comedi_pci_auto_unconfig,
+static int labpc_eeprom_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int ret;
+
+ /* only allow writes to user area of eeprom */
+ if (chan < 16 || chan > 127)
+ return -EINVAL;
+
+ /*
+ * Only write the last data value to the eeprom. Preceding
+ * data would be overwritten anyway.
+ */
+ if (insn->n > 0) {
+ ret = labpc_eeprom_write(dev, chan, data[insn->n - 1]);
+ if (ret)
+ return ret;
+ }
+
+ return insn->n;
+}
+
+static int labpc_eeprom_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->eeprom_data[chan];
+
+ return insn->n;
+}
+
+int labpc_common_attach(struct comedi_device *dev,
+ unsigned int irq, unsigned long isr_flags)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s;
+ int ret;
+ int i;
+
+ if (board->has_mmio) {
+ devpriv->read_byte = labpc_readb;
+ devpriv->write_byte = labpc_writeb;
+ } else {
+ devpriv->read_byte = labpc_inb;
+ devpriv->write_byte = labpc_outb;
+ }
+
+ /* initialize board's command registers */
+ devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG);
+ devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG);
+ devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG);
+ devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG);
+ if (board->register_layout == labpc_1200_layout) {
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG);
+ }
+
+ if (irq) {
+ ret = request_irq(irq, labpc_interrupt, isr_flags,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = irq;
+ }
+
+ ret = comedi_alloc_subdevices(dev, 5);
+ if (ret)
+ return ret;
+
+ /* analog input subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;
+ s->n_chan = 8;
+ s->len_chanlist = 8;
+ s->maxdata = 0x0fff;
+ s->range_table = board->ai_range_table;
+ s->insn_read = labpc_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->do_cmd = labpc_ai_cmd;
+ s->do_cmdtest = labpc_ai_cmdtest;
+ s->cancel = labpc_cancel;
+ }
+
+ /* analog output */
+ s = &dev->subdevices[1];
+ if (board->has_ao) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = NUM_AO_CHAN;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_labpc_ao;
+ s->insn_read = labpc_ao_insn_read;
+ s->insn_write = labpc_ao_insn_write;
+
+ /* initialize analog outputs to a known value */
+ for (i = 0; i < s->n_chan; i++) {
+ short lsb, msb;
+
+ devpriv->ao_value[i] = s->maxdata / 2;
+ lsb = devpriv->ao_value[i] & 0xff;
+ msb = (devpriv->ao_value[i] >> 8) & 0xff;
+ devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i));
+ devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i));
+ }
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /* 8255 dio */
+ s = &dev->subdevices[2];
+ ret = subdev_8255_init(dev, s,
+ (board->has_mmio) ? labpc_8255_mmio : NULL,
+ dev->iobase + DIO_BASE_REG);
+ if (ret)
+ return ret;
+
+ /* calibration subdevices for boards that have one */
+ s = &dev->subdevices[3];
+ if (board->register_layout == labpc_1200_layout) {
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 16;
+ s->maxdata = 0xff;
+ s->insn_read = labpc_calib_insn_read;
+ s->insn_write = labpc_calib_insn_write;
+
+ for (i = 0; i < s->n_chan; i++)
+ write_caldac(dev, i, s->maxdata / 2);
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
+
+ /* EEPROM */
+ s = &dev->subdevices[4];
+ if (board->register_layout == labpc_1200_layout) {
+ s->type = COMEDI_SUBD_MEMORY;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = EEPROM_SIZE;
+ s->maxdata = 0xff;
+ s->insn_read = labpc_eeprom_insn_read;
+ s->insn_write = labpc_eeprom_insn_write;
+
+ for (i = 0; i < s->n_chan; i++)
+ devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(labpc_common_attach);
+
+void labpc_common_detach(struct comedi_device *dev)
+{
+ comedi_spriv_free(dev, 2);
+}
+EXPORT_SYMBOL_GPL(labpc_common_detach);
+
+#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA)
+static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct labpc_private *devpriv;
+ unsigned int irq = it->options[1];
+ unsigned int dma_chan = it->options[2];
+ int ret;
+
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
+
+ ret = comedi_request_region(dev, it->options[0], LABPC_SIZE);
+ if (ret)
+ return ret;
+
+ ret = labpc_common_attach(dev, irq, 0);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_ISA_DMA_API
+ if (dev->irq && (dma_chan == 1 || dma_chan == 3)) {
+ devpriv->dma_buffer = kmalloc(dma_buffer_size,
+ GFP_KERNEL | GFP_DMA);
+ if (devpriv->dma_buffer) {
+ ret = request_dma(dma_chan, dev->board_name);
+ if (ret == 0) {
+ unsigned long dma_flags;
+
+ devpriv->dma_chan = dma_chan;
+ dma_flags = claim_dma_lock();
+ disable_dma(devpriv->dma_chan);
+ set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
+ release_dma_lock(dma_flags);
+ } else {
+ kfree(devpriv->dma_buffer);
+ }
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static void labpc_detach(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ labpc_common_detach(dev);
+
+ if (devpriv) {
+ kfree(devpriv->dma_buffer);
+ if (devpriv->dma_chan)
+ free_dma(devpriv->dma_chan);
+ }
+ comedi_legacy_detach(dev);
+}
+
+static struct comedi_driver labpc_driver = {
+ .driver_name = "ni_labpc",
+ .module = THIS_MODULE,
+ .attach = labpc_attach,
+ .detach = labpc_detach,
+ .num_names = ARRAY_SIZE(labpc_boards),
+ .board_name = &labpc_boards[0].name,
+ .offset = sizeof(struct labpc_boardinfo),
};
-module_comedi_pci_driver(labpc_driver, labpc_pci_driver);
-#else
module_comedi_driver(labpc_driver);
-#endif
+#else
+static int __init labpc_common_init(void)
+{
+ return 0;
+}
+module_init(labpc_common_init);
+static void __exit labpc_common_exit(void)
+{
+}
+module_exit(labpc_common_exit);
+#endif
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");