aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/cb_pcidas64.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/cb_pcidas64.c')
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c3009
1 files changed, 1516 insertions, 1493 deletions
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 0472a9088abe..d72b46cc06bc 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -36,53 +36,57 @@
************************************************************************/
/*
-
-Driver: cb_pcidas64
-Description: MeasurementComputing PCI-DAS64xx, 60XX, and 4020 series with the PLX 9080 PCI controller
-Author: Frank Mori Hess <fmhess@users.sourceforge.net>
-Status: works
-Updated: 2002-10-09
-Devices: [Measurement Computing] PCI-DAS6402/16 (cb_pcidas64),
- PCI-DAS6402/12, PCI-DAS64/M1/16, PCI-DAS64/M2/16,
- PCI-DAS64/M3/16, PCI-DAS6402/16/JR, PCI-DAS64/M1/16/JR,
- PCI-DAS64/M2/16/JR, PCI-DAS64/M3/16/JR, PCI-DAS64/M1/14,
- PCI-DAS64/M2/14, PCI-DAS64/M3/14, PCI-DAS6013, PCI-DAS6014,
- PCI-DAS6023, PCI-DAS6025, PCI-DAS6030,
- PCI-DAS6031, PCI-DAS6032, PCI-DAS6033, PCI-DAS6034,
- PCI-DAS6035, PCI-DAS6036, PCI-DAS6040, PCI-DAS6052,
- PCI-DAS6070, PCI-DAS6071, PCI-DAS4020/12
-
-Configuration options:
- [0] - PCI bus of device (optional)
- [1] - PCI slot of device (optional)
-
-These boards may be autocalibrated with the comedi_calibrate utility.
-
-To select the bnc trigger input on the 4020 (instead of the dio input),
-specify a nonzero channel in the chanspec. If you wish to use an external
-master clock on the 4020, you may do so by setting the scan_begin_src
-to TRIG_OTHER, and using an INSN_CONFIG_TIMER_1 configuration insn
-to configure the divisor to use for the external clock.
-
-Some devices are not identified because the PCI device IDs are not yet
-known. If you have such a board, please file a bug report at
-https://bugs.comedi.org.
-
-*/
+ * Driver: cb_pcidas64
+ * Description: MeasurementComputing PCI-DAS64xx, 60XX, and 4020 series
+ * with the PLX 9080 PCI controller
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Status: works
+ * Updated: Fri, 02 Nov 2012 18:58:55 +0000
+ * Devices: [Measurement Computing] PCI-DAS6402/16 (cb_pcidas64),
+ * PCI-DAS6402/12, PCI-DAS64/M1/16, PCI-DAS64/M2/16,
+ * PCI-DAS64/M3/16, PCI-DAS6402/16/JR, PCI-DAS64/M1/16/JR,
+ * PCI-DAS64/M2/16/JR, PCI-DAS64/M3/16/JR, PCI-DAS64/M1/14,
+ * PCI-DAS64/M2/14, PCI-DAS64/M3/14, PCI-DAS6013, PCI-DAS6014,
+ * PCI-DAS6023, PCI-DAS6025, PCI-DAS6030,
+ * PCI-DAS6031, PCI-DAS6032, PCI-DAS6033, PCI-DAS6034,
+ * PCI-DAS6035, PCI-DAS6036, PCI-DAS6040, PCI-DAS6052,
+ * PCI-DAS6070, PCI-DAS6071, PCI-DAS4020/12
+ *
+ * Configuration options:
+ * None.
+ *
+ * Manual attachment of PCI cards with the comedi_config utility is not
+ * supported by this driver; they are attached automatically.
+ *
+ * These boards may be autocalibrated with the comedi_calibrate utility.
+ *
+ * To select the bnc trigger input on the 4020 (instead of the dio input),
+ * specify a nonzero channel in the chanspec. If you wish to use an external
+ * master clock on the 4020, you may do so by setting the scan_begin_src
+ * to TRIG_OTHER, and using an INSN_CONFIG_TIMER_1 configuration insn
+ * to configure the divisor to use for the external clock.
+ *
+ * Some devices are not identified because the PCI device IDs are not yet
+ * known. If you have such a board, please let the maintainers know.
+ */
/*
TODO:
make it return error if user attempts an ai command that uses the
- external queue, and an ao command simultaneously
- user counter subdevice
+ external queue, and an ao command simultaneously user counter subdevice
there are a number of boards this driver will support when they are
- fully released, but does not yet since the pci device id numbers
- are not yet available.
- support prescaled 100khz clock for slow pacing (not available on 6000 series?)
+ fully released, but does not yet since the pci device id numbers
+ are not yet available.
+
+ support prescaled 100khz clock for slow pacing (not available on 6000
+ series?)
+
make ao fifo size adjustable like ai fifo
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "../comedidev.h"
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -96,17 +100,17 @@ TODO:
/* #define PCIDAS64_DEBUG enable debugging code */
#ifdef PCIDAS64_DEBUG
-#define DEBUG_PRINT(format, args...) printk(format , ## args)
+#define DEBUG_PRINT(format, args...) pr_debug(format, ## args)
#else
-#define DEBUG_PRINT(format, args...)
+#define DEBUG_PRINT(format, args...) no_printk(format, ## args)
#endif
#define TIMER_BASE 25 /* 40MHz master clock */
-#define PRESCALED_TIMER_BASE 10000 /* 100kHz 'prescaled' clock for slow acquisition, maybe I'll support this someday */
+/* 100kHz 'prescaled' clock for slow acquisition,
+ * maybe I'll support this someday */
+#define PRESCALED_TIMER_BASE 10000
#define DMA_BUFFER_SIZE 0x1000
-#define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
-
/* maximum value that can be loaded into board's 24-bit counters*/
static const int max_counter_value = 0xffffff;
@@ -119,7 +123,7 @@ enum base_address_regions {
DIO_COUNTER_BADDRINDEX = 3,
};
-/* priv(dev)->main_iobase registers */
+/* devpriv->main_iobase registers */
enum write_only_registers {
INTR_ENABLE_REG = 0x0, /* interrupt enable register */
HW_CONFIG_REG = 0x2, /* hardware config register */
@@ -128,26 +132,36 @@ enum write_only_registers {
ADC_CONTROL0_REG = 0x10, /* adc control register 0 */
ADC_CONTROL1_REG = 0x12, /* adc control register 1 */
CALIBRATION_REG = 0x14,
- ADC_SAMPLE_INTERVAL_LOWER_REG = 0x16, /* lower 16 bits of adc sample interval counter */
- ADC_SAMPLE_INTERVAL_UPPER_REG = 0x18, /* upper 8 bits of adc sample interval counter */
- ADC_DELAY_INTERVAL_LOWER_REG = 0x1a, /* lower 16 bits of delay interval counter */
- ADC_DELAY_INTERVAL_UPPER_REG = 0x1c, /* upper 8 bits of delay interval counter */
- ADC_COUNT_LOWER_REG = 0x1e, /* lower 16 bits of hardware conversion/scan counter */
- ADC_COUNT_UPPER_REG = 0x20, /* upper 8 bits of hardware conversion/scan counter */
+ /* lower 16 bits of adc sample interval counter */
+ ADC_SAMPLE_INTERVAL_LOWER_REG = 0x16,
+ /* upper 8 bits of adc sample interval counter */
+ ADC_SAMPLE_INTERVAL_UPPER_REG = 0x18,
+ /* lower 16 bits of delay interval counter */
+ ADC_DELAY_INTERVAL_LOWER_REG = 0x1a,
+ /* upper 8 bits of delay interval counter */
+ ADC_DELAY_INTERVAL_UPPER_REG = 0x1c,
+ /* lower 16 bits of hardware conversion/scan counter */
+ ADC_COUNT_LOWER_REG = 0x1e,
+ /* upper 8 bits of hardware conversion/scan counter */
+ ADC_COUNT_UPPER_REG = 0x20,
ADC_START_REG = 0x22, /* software trigger to start acquisition */
ADC_CONVERT_REG = 0x24, /* initiates single conversion */
ADC_QUEUE_CLEAR_REG = 0x26, /* clears adc queue */
ADC_QUEUE_LOAD_REG = 0x28, /* loads adc queue */
ADC_BUFFER_CLEAR_REG = 0x2a,
- ADC_QUEUE_HIGH_REG = 0x2c, /* high channel for internal queue, use adc_chan_bits() inline above */
+ /* high channel for internal queue, use adc_chan_bits() inline above */
+ ADC_QUEUE_HIGH_REG = 0x2c,
DAC_CONTROL0_REG = 0x50, /* dac control register 0 */
DAC_CONTROL1_REG = 0x52, /* dac control register 0 */
- DAC_SAMPLE_INTERVAL_LOWER_REG = 0x54, /* lower 16 bits of dac sample interval counter */
- DAC_SAMPLE_INTERVAL_UPPER_REG = 0x56, /* upper 8 bits of dac sample interval counter */
+ /* lower 16 bits of dac sample interval counter */
+ DAC_SAMPLE_INTERVAL_LOWER_REG = 0x54,
+ /* upper 8 bits of dac sample interval counter */
+ DAC_SAMPLE_INTERVAL_UPPER_REG = 0x56,
DAC_SELECT_REG = 0x60,
DAC_START_REG = 0x64,
DAC_BUFFER_CLEAR_REG = 0x66, /* clear dac buffer */
};
+
static inline unsigned int dac_convert_reg(unsigned int channel)
{
return 0x70 + (2 * (channel & 0x1));
@@ -164,7 +178,9 @@ static inline unsigned int dac_msb_4020_reg(unsigned int channel)
}
enum read_only_registers {
- HW_STATUS_REG = 0x0, /* hardware status register, reading this apparently clears pending interrupts as well */
+ /* hardware status register,
+ * reading this apparently clears pending interrupts as well */
+ HW_STATUS_REG = 0x0,
PIPE1_READ_REG = 0x4,
ADC_READ_PNTR_REG = 0x8,
LOWER_XFER_REG = 0x10,
@@ -174,12 +190,14 @@ enum read_only_registers {
enum read_write_registers {
I8255_4020_REG = 0x48, /* 8255 offset, for 4020 only */
- ADC_QUEUE_FIFO_REG = 0x100, /* external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG */
+ /* external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG */
+ ADC_QUEUE_FIFO_REG = 0x100,
ADC_FIFO_REG = 0x200, /* adc data fifo */
- DAC_FIFO_REG = 0x300, /* dac data fifo, has weird interactions with external channel queue */
+ /* dac data fifo, has weird interactions with external channel queue */
+ DAC_FIFO_REG = 0x300,
};
-/* priv(dev)->dio_counter_iobase registers */
+/* devpriv->dio_counter_iobase registers */
enum dio_counter_registers {
DIO_8255_OFFSET = 0x0,
DO_REG = 0x20,
@@ -191,13 +209,13 @@ enum dio_counter_registers {
/* bit definitions for write-only registers */
enum intr_enable_contents {
- ADC_INTR_SRC_MASK = 0x3, /* bits that set adc interrupt source */
- ADC_INTR_QFULL_BITS = 0x0, /* interrupt fifo quater full */
+ ADC_INTR_SRC_MASK = 0x3, /* adc interrupt source mask */
+ ADC_INTR_QFULL_BITS = 0x0, /* interrupt fifo quarter full */
ADC_INTR_EOC_BITS = 0x1, /* interrupt end of conversion */
ADC_INTR_EOSCAN_BITS = 0x2, /* interrupt end of scan */
- ADC_INTR_EOSEQ_BITS = 0x3, /* interrupt end of sequence (probably wont use this it's pretty fancy) */
+ ADC_INTR_EOSEQ_BITS = 0x3, /* interrupt end of sequence mask */
EN_ADC_INTR_SRC_BIT = 0x4, /* enable adc interrupt source */
- EN_ADC_DONE_INTR_BIT = 0x8, /* enable adc acquisition done interrupt */
+ EN_ADC_DONE_INTR_BIT = 0x8, /* enable adc acquisition done intr */
DAC_INTR_SRC_MASK = 0x30,
DAC_INTR_QEMPTY_BITS = 0x0,
DAC_INTR_HIGH_CHAN_BITS = 0x10,
@@ -211,25 +229,33 @@ enum intr_enable_contents {
};
enum hw_config_contents {
- MASTER_CLOCK_4020_MASK = 0x3, /* bits that specify master clock source for 4020 */
- INTERNAL_CLOCK_4020_BITS = 0x1, /* use 40 MHz internal master clock for 4020 */
+ MASTER_CLOCK_4020_MASK = 0x3, /* master clock source mask for 4020 */
+ INTERNAL_CLOCK_4020_BITS = 0x1, /* use 40 MHz internal master clock */
BNC_CLOCK_4020_BITS = 0x2, /* use BNC input for master clock */
EXT_CLOCK_4020_BITS = 0x3, /* use dio input for master clock */
- EXT_QUEUE_BIT = 0x200, /* use external channel/gain queue (more versatile than internal queue) */
- SLOW_DAC_BIT = 0x400, /* use 225 nanosec strobe when loading dac instead of 50 nanosec */
- HW_CONFIG_DUMMY_BITS = 0x2000, /* bit with unknown function yet given as default value in pci-das64 manual */
- DMA_CH_SELECT_BIT = 0x8000, /* bit selects channels 1/0 for analog input/output, otherwise 0/1 */
- FIFO_SIZE_REG = 0x4, /* allows adjustment of fifo sizes */
+ EXT_QUEUE_BIT = 0x200, /* use external channel/gain queue */
+ /* use 225 nanosec strobe when loading dac instead of 50 nanosec */
+ SLOW_DAC_BIT = 0x400,
+ /* bit with unknown function yet given as default value in pci-das64
+ * manual */
+ HW_CONFIG_DUMMY_BITS = 0x2000,
+ /* bit selects channels 1/0 for analog input/output, otherwise 0/1 */
+ DMA_CH_SELECT_BIT = 0x8000,
+ FIFO_SIZE_REG = 0x4, /* allows adjustment of fifo sizes */
DAC_FIFO_SIZE_MASK = 0xff00, /* bits that set dac fifo size */
- DAC_FIFO_BITS = 0xf800, /* 8k sample ao fifo */
+ DAC_FIFO_BITS = 0xf800, /* 8k sample ao fifo */
};
#define DAC_FIFO_SIZE 0x2000
enum daq_atrig_low_4020_contents {
- EXT_AGATE_BNC_BIT = 0x8000, /* use trig/ext clk bnc input for analog gate signal */
- EXT_STOP_TRIG_BNC_BIT = 0x4000, /* use trig/ext clk bnc input for external stop trigger signal */
- EXT_START_TRIG_BNC_BIT = 0x2000, /* use trig/ext clk bnc input for external start trigger signal */
+ /* use trig/ext clk bnc input for analog gate signal */
+ EXT_AGATE_BNC_BIT = 0x8000,
+ /* use trig/ext clk bnc input for external stop trigger signal */
+ EXT_STOP_TRIG_BNC_BIT = 0x4000,
+ /* use trig/ext clk bnc input for external start trigger signal */
+ EXT_START_TRIG_BNC_BIT = 0x2000,
};
+
static inline uint16_t analog_trig_low_threshold_bits(uint16_t threshold)
{
return threshold & 0xfff;
@@ -247,14 +273,17 @@ enum adc_control0_contents {
ADC_START_TRIG_ANALOG_BITS = 0x30,
ADC_START_TRIG_MASK = 0x30,
ADC_START_TRIG_FALLING_BIT = 0x40, /* trig 1 uses falling edge */
- ADC_EXT_CONV_FALLING_BIT = 0x800, /* external pacing uses falling edge */
- ADC_SAMPLE_COUNTER_EN_BIT = 0x1000, /* enable hardware scan counter */
+ /* external pacing uses falling edge */
+ ADC_EXT_CONV_FALLING_BIT = 0x800,
+ /* enable hardware scan counter */
+ ADC_SAMPLE_COUNTER_EN_BIT = 0x1000,
ADC_DMA_DISABLE_BIT = 0x4000, /* disables dma */
ADC_ENABLE_BIT = 0x8000, /* master adc enable */
};
enum adc_control1_contents {
- ADC_QUEUE_CONFIG_BIT = 0x1, /* should be set for boards with > 16 channels */
+ /* should be set for boards with > 16 channels */
+ ADC_QUEUE_CONFIG_BIT = 0x1,
CONVERT_POLARITY_BIT = 0x10,
EOC_POLARITY_BIT = 0x20,
ADC_SW_GATE_BIT = 0x40, /* software gate of adc */
@@ -263,10 +292,11 @@ enum adc_control1_contents {
ADC_LO_CHANNEL_4020_MASK = 0x300,
ADC_HI_CHANNEL_4020_MASK = 0xc00,
TWO_CHANNEL_4020_BITS = 0x1000, /* two channel mode for 4020 */
- FOUR_CHANNEL_4020_BITS = 0x2000, /* four channel mode for 4020 */
+ FOUR_CHANNEL_4020_BITS = 0x2000, /* four channel mode for 4020 */
CHANNEL_MODE_4020_MASK = 0x3000,
ADC_MODE_MASK = 0xf000,
};
+
static inline uint16_t adc_lo_chan_4020_bits(unsigned int channel)
{
return (channel & 0x3) << 8;
@@ -289,9 +319,10 @@ enum calibration_contents {
CAL_EN_64XX_BIT = 0x40, /* calibration enable for 64xx series */
SERIAL_DATA_IN_BIT = 0x80,
SERIAL_CLOCK_BIT = 0x100,
- CAL_EN_60XX_BIT = 0x200, /* calibration enable for 60xx series */
+ CAL_EN_60XX_BIT = 0x200, /* calibration enable for 60xx series */
CAL_GAIN_BIT = 0x800,
};
+
/* calibration sources for 6025 are:
* 0 : ground
* 1 : 10V
@@ -302,6 +333,7 @@ enum calibration_contents {
* 6 : dac channel 0
* 7 : dac channel 1
*/
+
static inline uint16_t adc_src_bits(unsigned int source)
{
return (source & 0xf) << 3;
@@ -315,10 +347,12 @@ static inline uint16_t adc_convert_chan_4020_bits(unsigned int channel)
enum adc_queue_load_contents {
UNIP_BIT = 0x800, /* unipolar/bipolar bit */
ADC_SE_DIFF_BIT = 0x1000, /* single-ended/ differential bit */
- ADC_COMMON_BIT = 0x2000, /* non-referenced single-ended (common-mode input) */
+ /* non-referenced single-ended (common-mode input) */
+ ADC_COMMON_BIT = 0x2000,
QUEUE_EOSEQ_BIT = 0x4000, /* queue end of sequence */
QUEUE_EOSCAN_BIT = 0x8000, /* queue end of scan */
};
+
static inline uint16_t adc_chan_bits(unsigned int channel)
{
return channel & 0x3f;
@@ -365,6 +399,7 @@ enum hw_status_contents {
EXT_INTR_PENDING_BIT = 0x100,
ADC_STOP_BIT = 0x200,
};
+
static inline uint16_t pipe_full_bits(uint16_t hw_status_bits)
{
return (hw_status_bits >> 10) & 0x3;
@@ -393,9 +428,12 @@ enum i2c_addresses {
};
enum range_cal_i2c_contents {
- ADC_SRC_4020_MASK = 0x70, /* bits that set what source the adc converter measures */
- BNC_TRIG_THRESHOLD_0V_BIT = 0x80, /* make bnc trig/ext clock threshold 0V instead of 2.5V */
+ /* bits that set what source the adc converter measures */
+ ADC_SRC_4020_MASK = 0x70,
+ /* make bnc trig/ext clock threshold 0V instead of 2.5V */
+ BNC_TRIG_THRESHOLD_0V_BIT = 0x80,
};
+
static inline uint8_t adc_src_4020_bits(unsigned int source)
{
return (source << 4) & ADC_SRC_4020_MASK;
@@ -562,11 +600,12 @@ struct pcidas64_board {
const struct comedi_lrange *ai_range_table;
int ao_nchan; /* number of analog out channels */
int ao_bits; /* analog output resolution */
- int ao_scan_speed; /* analog output speed (for a scan, not conversion) */
+ int ao_scan_speed; /* analog output scan speed */
const struct comedi_lrange *ao_range_table;
const int *ao_range_code;
const struct hw_fifo_info *const ai_fifo;
- enum register_layout layout; /* different board families have slightly different registers */
+ /* different board families have slightly different registers */
+ enum register_layout layout;
unsigned has_8255:1;
};
@@ -596,7 +635,7 @@ static const struct hw_fifo_info ai_fifo_60xx = {
#define MAX_AI_DMA_RING_COUNT (0x80000 / DMA_BUFFER_SIZE)
#define MIN_AI_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE)
#define AO_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE)
-static inline unsigned int ai_dma_ring_count(struct pcidas64_board *board)
+static inline unsigned int ai_dma_ring_count(const struct pcidas64_board *board)
{
if (board->layout == LAYOUT_4020)
return MAX_AI_DMA_RING_COUNT;
@@ -1025,24 +1064,23 @@ static const struct pcidas64_board pcidas64_boards[] = {
#endif
};
-static inline struct pcidas64_board *board(const struct comedi_device *dev)
-{
- return (struct pcidas64_board *)dev->board_ptr;
-}
-
static inline unsigned short se_diff_bit_6xxx(struct comedi_device *dev,
int use_differential)
{
- if ((board(dev)->layout == LAYOUT_64XX && !use_differential) ||
- (board(dev)->layout == LAYOUT_60XX && use_differential))
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+
+ if ((thisboard->layout == LAYOUT_64XX && !use_differential) ||
+ (thisboard->layout == LAYOUT_60XX && use_differential))
return ADC_SE_DIFF_BIT;
else
return 0;
};
struct ext_clock_info {
- unsigned int divisor; /* master clock divisor to use for scans with external master clock */
- unsigned int chanspec; /* chanspec for master clock input when used as scan begin src */
+ /* master clock divisor to use for scans with external master clock */
+ unsigned int divisor;
+ /* chanspec for master clock input when used as scan begin src */
+ unsigned int chanspec;
};
/* this structure is for data unique to this hardware driver. */
@@ -1058,30 +1096,52 @@ struct pcidas64_private {
/* local address (used by dma controller) */
uint32_t local0_iobase;
uint32_t local1_iobase;
- volatile unsigned int ai_count; /* number of analog input samples remaining */
- uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT]; /* dma buffers for analog input */
- dma_addr_t ai_buffer_bus_addr[MAX_AI_DMA_RING_COUNT]; /* physical addresses of ai dma buffers */
- struct plx_dma_desc *ai_dma_desc; /* array of ai dma descriptors read by plx9080, allocated to get proper alignment */
- dma_addr_t ai_dma_desc_bus_addr; /* physical address of ai dma descriptor array */
- volatile unsigned int ai_dma_index; /* index of the ai dma descriptor/buffer that is currently being used */
- uint16_t *ao_buffer[AO_DMA_RING_COUNT]; /* dma buffers for analog output */
- dma_addr_t ao_buffer_bus_addr[AO_DMA_RING_COUNT]; /* physical addresses of ao dma buffers */
+ /* number of analog input samples remaining */
+ volatile unsigned int ai_count;
+ /* dma buffers for analog input */
+ uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT];
+ /* physical addresses of ai dma buffers */
+ dma_addr_t ai_buffer_bus_addr[MAX_AI_DMA_RING_COUNT];
+ /* array of ai dma descriptors read by plx9080,
+ * allocated to get proper alignment */
+ struct plx_dma_desc *ai_dma_desc;
+ /* physical address of ai dma descriptor array */
+ dma_addr_t ai_dma_desc_bus_addr;
+ /* index of the ai dma descriptor/buffer
+ * that is currently being used */
+ volatile unsigned int ai_dma_index;
+ /* dma buffers for analog output */
+ uint16_t *ao_buffer[AO_DMA_RING_COUNT];
+ /* physical addresses of ao dma buffers */
+ dma_addr_t ao_buffer_bus_addr[AO_DMA_RING_COUNT];
struct plx_dma_desc *ao_dma_desc;
dma_addr_t ao_dma_desc_bus_addr;
- volatile unsigned int ao_dma_index; /* keeps track of buffer where the next ao sample should go */
- volatile unsigned long ao_count; /* number of analog output samples remaining */
- volatile unsigned int ao_value[2]; /* remember what the analog outputs are set to, to allow readback */
+ /* keeps track of buffer where the next ao sample should go */
+ volatile unsigned int ao_dma_index;
+ /* number of analog output samples remaining */
+ volatile unsigned long ao_count;
+ /* remember what the analog outputs are set to, to allow readback */
+ volatile unsigned int ao_value[2];
unsigned int hw_revision; /* stc chip hardware revision number */
- volatile unsigned int intr_enable_bits; /* last bits sent to INTR_ENABLE_REG register */
- volatile uint16_t adc_control1_bits; /* last bits sent to ADC_CONTROL1_REG register */
- volatile uint16_t fifo_size_bits; /* last bits sent to FIFO_SIZE_REG register */
- volatile uint16_t hw_config_bits; /* last bits sent to HW_CONFIG_REG register */
+ /* last bits sent to INTR_ENABLE_REG register */
+ volatile unsigned int intr_enable_bits;
+ /* last bits sent to ADC_CONTROL1_REG register */
+ volatile uint16_t adc_control1_bits;
+ /* last bits sent to FIFO_SIZE_REG register */
+ volatile uint16_t fifo_size_bits;
+ /* last bits sent to HW_CONFIG_REG register */
+ volatile uint16_t hw_config_bits;
volatile uint16_t dac_control1_bits;
- volatile uint32_t plx_control_bits; /* last bits written to plx9080 control register */
- volatile uint32_t plx_intcsr_bits; /* last bits written to plx interrupt control and status register */
- volatile int calibration_source; /* index of calibration source readable through ai ch0 */
- volatile uint8_t i2c_cal_range_bits; /* bits written to i2c calibration/range register */
- volatile unsigned int ext_trig_falling; /* configure digital triggers to trigger on falling edge */
+ /* last bits written to plx9080 control register */
+ volatile uint32_t plx_control_bits;
+ /* last bits written to plx interrupt control and status register */
+ volatile uint32_t plx_intcsr_bits;
+ /* index of calibration source readable through ai ch0 */
+ volatile int calibration_source;
+ /* bits written to i2c calibration/range register */
+ volatile uint8_t i2c_cal_range_bits;
+ /* configure digital triggers to trigger on falling edge */
+ volatile unsigned int ext_trig_falling;
/* states of various devices stored to enable read-back */
unsigned int ad8402_state[2];
unsigned int caldac_state[8];
@@ -1091,93 +1151,12 @@ struct pcidas64_private {
short ao_bounce_buffer[DAC_FIFO_SIZE];
};
-/* inline function that makes it easier to
- * access the private structure.
- */
-static inline struct pcidas64_private *priv(struct comedi_device *dev)
-{
- return dev->private;
-}
-
-static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ao_readback_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int ao_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *subdev, unsigned int trig_num);
-static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static irqreturn_t handle_interrupt(int irq, void *d);
-static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int dio_callback(int dir, int port, int data, unsigned long arg);
-static int dio_callback_4020(int dir, int port, int data, unsigned long arg);
-static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dio_60xx_config_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int calib_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int calib_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ad8402_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static void ad8402_write(struct comedi_device *dev, unsigned int channel,
- unsigned int value);
-static int ad8402_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int eeprom_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd);
-static unsigned int get_divisor(unsigned int ns, unsigned int flags);
-static void i2c_write(struct comedi_device *dev, unsigned int address,
- const uint8_t *data, unsigned int length);
-static void caldac_write(struct comedi_device *dev, unsigned int channel,
- unsigned int value);
-static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
- uint8_t value);
-/* static int dac_1590_write(struct comedi_device *dev, unsigned int dac_a, unsigned int dac_b); */
-static int caldac_i2c_write(struct comedi_device *dev,
- unsigned int caldac_channel, unsigned int value);
-static void abort_dma(struct comedi_device *dev, unsigned int channel);
-static void disable_plx_interrupts(struct comedi_device *dev);
-static int set_ai_fifo_size(struct comedi_device *dev,
- unsigned int num_samples);
-static unsigned int ai_fifo_size(struct comedi_device *dev);
-static int set_ai_fifo_segment_length(struct comedi_device *dev,
- unsigned int num_entries);
-static void disable_ai_pacing(struct comedi_device *dev);
-static void disable_ai_interrupts(struct comedi_device *dev);
-static void enable_ai_interrupts(struct comedi_device *dev,
- const struct comedi_cmd *cmd);
-static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags);
-static void load_ao_dma(struct comedi_device *dev,
- const struct comedi_cmd *cmd);
-
static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
unsigned int range_index)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
const struct comedi_krange *range =
- &board(dev)->ai_range_table->range[range_index];
+ &thisboard->ai_range_table->range[range_index];
unsigned int bits = 0;
switch (range->max) {
@@ -1220,7 +1199,9 @@ static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
static unsigned int hw_revision(const struct comedi_device *dev,
uint16_t hw_status_bits)
{
- if (board(dev)->layout == LAYOUT_4020)
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+
+ if (thisboard->layout == LAYOUT_4020)
return (hw_status_bits >> 13) & 0x7;
return (hw_status_bits >> 12) & 0xf;
@@ -1230,7 +1211,8 @@ static void set_dac_range_bits(struct comedi_device *dev,
volatile uint16_t *bits, unsigned int channel,
unsigned int range)
{
- unsigned int code = board(dev)->ao_range_code[range];
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ unsigned int code = thisboard->ao_range_code[range];
if (channel > 1)
comedi_error(dev, "bug! bad channel?");
@@ -1246,20 +1228,86 @@ static inline int ao_cmd_is_supported(const struct pcidas64_board *board)
return board->ao_nchan && board->layout != LAYOUT_4020;
}
+static void abort_dma(struct comedi_device *dev, unsigned int channel)
+{
+ struct pcidas64_private *devpriv = dev->private;
+ unsigned long flags;
+
+ /* spinlock for plx dma control/status reg */
+ spin_lock_irqsave(&dev->spinlock, flags);
+
+ plx9080_abort_dma(devpriv->plx9080_iobase, channel);
+
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+}
+
+static void disable_plx_interrupts(struct comedi_device *dev)
+{
+ struct pcidas64_private *devpriv = dev->private;
+
+ devpriv->plx_intcsr_bits = 0;
+ writel(devpriv->plx_intcsr_bits,
+ devpriv->plx9080_iobase + PLX_INTRCS_REG);
+}
+
+static void disable_ai_interrupts(struct comedi_device *dev)
+{
+ struct pcidas64_private *devpriv = dev->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->intr_enable_bits &=
+ ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT &
+ ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT &
+ ~EN_ADC_OVERRUN_BIT & ~ADC_INTR_SRC_MASK;
+ writew(devpriv->intr_enable_bits,
+ devpriv->main_iobase + INTR_ENABLE_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ DEBUG_PRINT("intr enable bits 0x%x\n", devpriv->intr_enable_bits);
+}
+
+static void enable_ai_interrupts(struct comedi_device *dev,
+ const struct comedi_cmd *cmd)
+{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
+ uint32_t bits;
+ unsigned long flags;
+
+ bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT |
+ EN_ADC_ACTIVE_INTR_BIT | EN_ADC_STOP_INTR_BIT;
+ /* Use pio transfer and interrupt on end of conversion
+ * if TRIG_WAKE_EOS flag is set. */
+ if (cmd->flags & TRIG_WAKE_EOS) {
+ /* 4020 doesn't support pio transfers except for fifo dregs */
+ if (thisboard->layout != LAYOUT_4020)
+ bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT;
+ }
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->intr_enable_bits |= bits;
+ writew(devpriv->intr_enable_bits,
+ devpriv->main_iobase + INTR_ENABLE_REG);
+ DEBUG_PRINT("intr enable bits 0x%x\n", devpriv->intr_enable_bits);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+}
+
/* initialize plx9080 chip */
static void init_plx9080(struct comedi_device *dev)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
uint32_t bits;
- void __iomem *plx_iobase = priv(dev)->plx9080_iobase;
+ void __iomem *plx_iobase = devpriv->plx9080_iobase;
- priv(dev)->plx_control_bits =
- readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG);
+ devpriv->plx_control_bits =
+ readl(devpriv->plx9080_iobase + PLX_CONTROL_REG);
/* plx9080 dump */
DEBUG_PRINT(" plx interrupt status 0x%x\n",
readl(plx_iobase + PLX_INTRCS_REG));
DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG));
- DEBUG_PRINT(" plx control reg 0x%x\n", priv(dev)->plx_control_bits);
+ DEBUG_PRINT(" plx control reg 0x%x\n", devpriv->plx_control_bits);
DEBUG_PRINT(" plx mode/arbitration reg 0x%x\n",
readl(plx_iobase + PLX_MARB_REG));
DEBUG_PRINT(" plx region0 reg 0x%x\n",
@@ -1292,7 +1340,7 @@ static void init_plx9080(struct comedi_device *dev)
#else
bits = 0;
#endif
- writel(bits, priv(dev)->plx9080_iobase + PLX_BIGEND_REG);
+ writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG);
disable_plx_interrupts(dev);
@@ -1307,9 +1355,11 @@ static void init_plx9080(struct comedi_device *dev)
bits |= PLX_EN_BTERM_BIT;
/* enable dma chaining */
bits |= PLX_EN_CHAIN_BIT;
- /* enable interrupt on dma done (probably don't need this, since chain never finishes) */
+ /* enable interrupt on dma done
+ * (probably don't need this, since chain never finishes) */
bits |= PLX_EN_DMA_DONE_INTR_BIT;
- /* don't increment local address during transfers (we are transferring from a fixed fifo register) */
+ /* don't increment local address during transfers
+ * (we are transferring from a fixed fifo register) */
bits |= PLX_LOCAL_ADDR_CONST_BIT;
/* route dma interrupt to pci bus */
bits |= PLX_DMA_INTR_PCI_BIT;
@@ -1318,324 +1368,235 @@ static void init_plx9080(struct comedi_device *dev)
/* enable local burst mode */
bits |= PLX_DMA_LOCAL_BURST_EN_BIT;
/* 4020 uses 32 bit dma */
- if (board(dev)->layout == LAYOUT_4020) {
+ if (thisboard->layout == LAYOUT_4020)
bits |= PLX_LOCAL_BUS_32_WIDE_BITS;
- } else { /* localspace0 bus is 16 bits wide */
+ else /* localspace0 bus is 16 bits wide */
bits |= PLX_LOCAL_BUS_16_WIDE_BITS;
- }
writel(bits, plx_iobase + PLX_DMA1_MODE_REG);
- if (ao_cmd_is_supported(board(dev)))
+ if (ao_cmd_is_supported(thisboard))
writel(bits, plx_iobase + PLX_DMA0_MODE_REG);
/* enable interrupts on plx 9080 */
- priv(dev)->plx_intcsr_bits |=
+ devpriv->plx_intcsr_bits |=
ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE |
ICS_DMA0_E | ICS_DMA1_E;
- writel(priv(dev)->plx_intcsr_bits,
- priv(dev)->plx9080_iobase + PLX_INTRCS_REG);
+ writel(devpriv->plx_intcsr_bits,
+ devpriv->plx9080_iobase + PLX_INTRCS_REG);
}
-/* Allocate and initialize the subdevice structures.
- */
-static int setup_subdevices(struct comedi_device *dev)
+static void disable_ai_pacing(struct comedi_device *dev)
{
- struct comedi_subdevice *s;
- void __iomem *dio_8255_iobase;
- int i;
- int ret;
+ struct pcidas64_private *devpriv = dev->private;
+ unsigned long flags;
- ret = comedi_alloc_subdevices(dev, 10);
- if (ret)
- return ret;
+ disable_ai_interrupts(dev);
- s = &dev->subdevices[0];
- /* analog input subdevice */
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DITHER | SDF_CMD_READ;
- if (board(dev)->layout == LAYOUT_60XX)
- s->subdev_flags |= SDF_COMMON | SDF_DIFF;
- else if (board(dev)->layout == LAYOUT_64XX)
- s->subdev_flags |= SDF_DIFF;
- /* XXX Number of inputs in differential mode is ignored */
- s->n_chan = board(dev)->ai_se_chans;
- s->len_chanlist = 0x2000;
- s->maxdata = (1 << board(dev)->ai_bits) - 1;
- s->range_table = board(dev)->ai_range_table;
- s->insn_read = ai_rinsn;
- s->insn_config = ai_config_insn;
- s->do_cmd = ai_cmd;
- s->do_cmdtest = ai_cmdtest;
- s->cancel = ai_cancel;
- if (board(dev)->layout == LAYOUT_4020) {
- uint8_t data;
- /* set adc to read from inputs (not internal calibration sources) */
- priv(dev)->i2c_cal_range_bits = adc_src_4020_bits(4);
- /* set channels to +-5 volt input ranges */
- for (i = 0; i < s->n_chan; i++)
- priv(dev)->i2c_cal_range_bits |= attenuate_bit(i);
- data = priv(dev)->i2c_cal_range_bits;
- i2c_write(dev, RANGE_CAL_I2C_ADDR, &data, sizeof(data));
- }
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->adc_control1_bits &= ~ADC_SW_GATE_BIT;
+ writew(devpriv->adc_control1_bits,
+ devpriv->main_iobase + ADC_CONTROL1_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
- /* analog output subdevice */
- s = &dev->subdevices[1];
- if (board(dev)->ao_nchan) {
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags =
- SDF_READABLE | SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
- s->n_chan = board(dev)->ao_nchan;
- s->maxdata = (1 << board(dev)->ao_bits) - 1;
- s->range_table = board(dev)->ao_range_table;
- s->insn_read = ao_readback_insn;
- s->insn_write = ao_winsn;
- if (ao_cmd_is_supported(board(dev))) {
- dev->write_subdev = s;
- s->do_cmdtest = ao_cmdtest;
- s->do_cmd = ao_cmd;
- s->len_chanlist = board(dev)->ao_nchan;
- s->cancel = ao_cancel;
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
+ /* disable pacing, triggering, etc */
+ writew(ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT,
+ devpriv->main_iobase + ADC_CONTROL0_REG);
+}
- /* digital input */
- s = &dev->subdevices[2];
- if (board(dev)->layout == LAYOUT_64XX) {
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 4;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = di_rbits;
- } else
- s->type = COMEDI_SUBD_UNUSED;
+static int set_ai_fifo_segment_length(struct comedi_device *dev,
+ unsigned int num_entries)
+{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
+ static const int increment_size = 0x100;
+ const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
+ unsigned int num_increments;
+ uint16_t bits;
- /* digital output */
- if (board(dev)->layout == LAYOUT_64XX) {
- s = &dev->subdevices[3];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 4;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = do_wbits;
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ if (num_entries < increment_size)
+ num_entries = increment_size;
+ if (num_entries > fifo->max_segment_length)
+ num_entries = fifo->max_segment_length;
- /* 8255 */
- s = &dev->subdevices[4];
- if (board(dev)->has_8255) {
- if (board(dev)->layout == LAYOUT_4020) {
- dio_8255_iobase =
- priv(dev)->main_iobase + I8255_4020_REG;
- subdev_8255_init(dev, s, dio_callback_4020,
- (unsigned long)dio_8255_iobase);
- } else {
- dio_8255_iobase =
- priv(dev)->dio_counter_iobase + DIO_8255_OFFSET;
- subdev_8255_init(dev, s, dio_callback,
- (unsigned long)dio_8255_iobase);
- }
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ /* 1 == 256 entries, 2 == 512 entries, etc */
+ num_increments = (num_entries + increment_size / 2) / increment_size;
- /* 8 channel dio for 60xx */
- s = &dev->subdevices[5];
- if (board(dev)->layout == LAYOUT_60XX) {
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_config = dio_60xx_config_insn;
- s->insn_bits = dio_60xx_wbits;
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ bits = (~(num_increments - 1)) & fifo->fifo_size_reg_mask;
+ devpriv->fifo_size_bits &= ~fifo->fifo_size_reg_mask;
+ devpriv->fifo_size_bits |= bits;
+ writew(devpriv->fifo_size_bits,
+ devpriv->main_iobase + FIFO_SIZE_REG);
- /* caldac */
- s = &dev->subdevices[6];
- s->type = COMEDI_SUBD_CALIB;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = 8;
- if (board(dev)->layout == LAYOUT_4020)
- s->maxdata = 0xfff;
- else
- s->maxdata = 0xff;
- s->insn_read = calib_read_insn;
- s->insn_write = calib_write_insn;
- for (i = 0; i < s->n_chan; i++)
- caldac_write(dev, i, s->maxdata / 2);
+ devpriv->ai_fifo_segment_length = num_increments * increment_size;
- /* 2 channel ad8402 potentiometer */
- s = &dev->subdevices[7];
- if (board(dev)->layout == LAYOUT_64XX) {
- s->type = COMEDI_SUBD_CALIB;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = 2;
- s->insn_read = ad8402_read_insn;
- s->insn_write = ad8402_write_insn;
- s->maxdata = 0xff;
- for (i = 0; i < s->n_chan; i++)
- ad8402_write(dev, i, s->maxdata / 2);
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ DEBUG_PRINT("set hardware fifo segment length to %i\n",
+ devpriv->ai_fifo_segment_length);
- /* serial EEPROM, if present */
- s = &dev->subdevices[8];
- if (readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG) & CTL_EECHK) {
- s->type = COMEDI_SUBD_MEMORY;
- s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
- s->n_chan = 128;
- s->maxdata = 0xffff;
- s->insn_read = eeprom_read_insn;
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ return devpriv->ai_fifo_segment_length;
+}
- /* user counter subd XXX */
- s = &dev->subdevices[9];
- s->type = COMEDI_SUBD_UNUSED;
+/* adjusts the size of hardware fifo (which determines block size for dma xfers) */
+static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples)
+{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ unsigned int num_fifo_entries;
+ int retval;
+ const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
- return 0;
+ num_fifo_entries = num_samples / fifo->sample_packing_ratio;
+
+ retval = set_ai_fifo_segment_length(dev,
+ num_fifo_entries /
+ fifo->num_segments);
+ if (retval < 0)
+ return retval;
+
+ num_samples = retval * fifo->num_segments * fifo->sample_packing_ratio;
+
+ DEBUG_PRINT("set hardware fifo size to %i\n", num_samples);
+
+ return num_samples;
}
-static void disable_plx_interrupts(struct comedi_device *dev)
+/* query length of fifo */
+static unsigned int ai_fifo_size(struct comedi_device *dev)
{
- priv(dev)->plx_intcsr_bits = 0;
- writel(priv(dev)->plx_intcsr_bits,
- priv(dev)->plx9080_iobase + PLX_INTRCS_REG);
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
+
+ return devpriv->ai_fifo_segment_length *
+ thisboard->ai_fifo->num_segments *
+ thisboard->ai_fifo->sample_packing_ratio;
}
static void init_stc_registers(struct comedi_device *dev)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
uint16_t bits;
unsigned long flags;
spin_lock_irqsave(&dev->spinlock, flags);
- /* bit should be set for 6025, although docs say boards with <= 16 chans should be cleared XXX */
+ /* bit should be set for 6025,
+ * although docs say boards with <= 16 chans should be cleared XXX */
if (1)
- priv(dev)->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT;
- writew(priv(dev)->adc_control1_bits,
- priv(dev)->main_iobase + ADC_CONTROL1_REG);
+ devpriv->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT;
+ writew(devpriv->adc_control1_bits,
+ devpriv->main_iobase + ADC_CONTROL1_REG);
/* 6402/16 manual says this register must be initialized to 0xff? */
- writew(0xff, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
+ writew(0xff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
bits = SLOW_DAC_BIT | DMA_CH_SELECT_BIT;
- if (board(dev)->layout == LAYOUT_4020)
+ if (thisboard->layout == LAYOUT_4020)
bits |= INTERNAL_CLOCK_4020_BITS;
- priv(dev)->hw_config_bits |= bits;
- writew(priv(dev)->hw_config_bits,
- priv(dev)->main_iobase + HW_CONFIG_REG);
+ devpriv->hw_config_bits |= bits;
+ writew(devpriv->hw_config_bits,
+ devpriv->main_iobase + HW_CONFIG_REG);
- writew(0, priv(dev)->main_iobase + DAQ_SYNC_REG);
- writew(0, priv(dev)->main_iobase + CALIBRATION_REG);
+ writew(0, devpriv->main_iobase + DAQ_SYNC_REG);
+ writew(0, devpriv->main_iobase + CALIBRATION_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
/* set fifos to maximum size */
- priv(dev)->fifo_size_bits |= DAC_FIFO_BITS;
+ devpriv->fifo_size_bits |= DAC_FIFO_BITS;
set_ai_fifo_segment_length(dev,
- board(dev)->ai_fifo->max_segment_length);
+ thisboard->ai_fifo->max_segment_length);
- priv(dev)->dac_control1_bits = DAC_OUTPUT_ENABLE_BIT;
- priv(dev)->intr_enable_bits = /* EN_DAC_INTR_SRC_BIT | DAC_INTR_QEMPTY_BITS | */
- EN_DAC_DONE_INTR_BIT | EN_DAC_UNDERRUN_BIT;
- writew(priv(dev)->intr_enable_bits,
- priv(dev)->main_iobase + INTR_ENABLE_REG);
+ devpriv->dac_control1_bits = DAC_OUTPUT_ENABLE_BIT;
+ devpriv->intr_enable_bits =
+ /* EN_DAC_INTR_SRC_BIT | DAC_INTR_QEMPTY_BITS | */
+ EN_DAC_DONE_INTR_BIT | EN_DAC_UNDERRUN_BIT;
+ writew(devpriv->intr_enable_bits,
+ devpriv->main_iobase + INTR_ENABLE_REG);
disable_ai_pacing(dev);
};
static int alloc_and_init_dma_members(struct comedi_device *dev)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct pcidas64_private *devpriv = dev->private;
int i;
/* alocate pci dma buffers */
- for (i = 0; i < ai_dma_ring_count(board(dev)); i++) {
- priv(dev)->ai_buffer[i] =
- pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
- &priv(dev)->ai_buffer_bus_addr[i]);
- if (priv(dev)->ai_buffer[i] == NULL)
+ for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
+ devpriv->ai_buffer[i] =
+ pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
+ &devpriv->ai_buffer_bus_addr[i]);
+ if (devpriv->ai_buffer[i] == NULL)
return -ENOMEM;
}
for (i = 0; i < AO_DMA_RING_COUNT; i++) {
- if (ao_cmd_is_supported(board(dev))) {
- priv(dev)->ao_buffer[i] =
- pci_alloc_consistent(pcidev,
- DMA_BUFFER_SIZE,
- &priv(dev)->
- ao_buffer_bus_addr[i]);
- if (priv(dev)->ao_buffer[i] == NULL)
+ if (ao_cmd_is_supported(thisboard)) {
+ devpriv->ao_buffer[i] =
+ pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
+ &devpriv->
+ ao_buffer_bus_addr[i]);
+ if (devpriv->ao_buffer[i] == NULL)
return -ENOMEM;
}
}
/* allocate dma descriptors */
- priv(dev)->ai_dma_desc =
- pci_alloc_consistent(pcidev,
- sizeof(struct plx_dma_desc) *
- ai_dma_ring_count(board(dev)),
- &priv(dev)->ai_dma_desc_bus_addr);
- if (priv(dev)->ai_dma_desc == NULL)
+ devpriv->ai_dma_desc =
+ pci_alloc_consistent(pcidev, sizeof(struct plx_dma_desc) *
+ ai_dma_ring_count(thisboard),
+ &devpriv->ai_dma_desc_bus_addr);
+ if (devpriv->ai_dma_desc == NULL)
return -ENOMEM;
- DEBUG_PRINT("ai dma descriptors start at bus addr 0x%x\n",
- priv(dev)->ai_dma_desc_bus_addr);
- if (ao_cmd_is_supported(board(dev))) {
- priv(dev)->ao_dma_desc =
- pci_alloc_consistent(pcidev,
- sizeof(struct plx_dma_desc) *
- AO_DMA_RING_COUNT,
- &priv(dev)->ao_dma_desc_bus_addr);
- if (priv(dev)->ao_dma_desc == NULL)
+ DEBUG_PRINT("ai dma descriptors start at bus addr 0x%llx\n",
+ (unsigned long long)devpriv->ai_dma_desc_bus_addr);
+ if (ao_cmd_is_supported(thisboard)) {
+ devpriv->ao_dma_desc =
+ pci_alloc_consistent(pcidev,
+ sizeof(struct plx_dma_desc) *
+ AO_DMA_RING_COUNT,
+ &devpriv->ao_dma_desc_bus_addr);
+ if (devpriv->ao_dma_desc == NULL)
return -ENOMEM;
- DEBUG_PRINT("ao dma descriptors start at bus addr 0x%x\n",
- priv(dev)->ao_dma_desc_bus_addr);
+ DEBUG_PRINT("ao dma descriptors start at bus addr 0x%llx\n",
+ (unsigned long long)devpriv->ao_dma_desc_bus_addr);
}
/* initialize dma descriptors */
- for (i = 0; i < ai_dma_ring_count(board(dev)); i++) {
- priv(dev)->ai_dma_desc[i].pci_start_addr =
- cpu_to_le32(priv(dev)->ai_buffer_bus_addr[i]);
- if (board(dev)->layout == LAYOUT_4020)
- priv(dev)->ai_dma_desc[i].local_start_addr =
- cpu_to_le32(priv(dev)->local1_iobase +
- ADC_FIFO_REG);
+ for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
+ devpriv->ai_dma_desc[i].pci_start_addr =
+ cpu_to_le32(devpriv->ai_buffer_bus_addr[i]);
+ if (thisboard->layout == LAYOUT_4020)
+ devpriv->ai_dma_desc[i].local_start_addr =
+ cpu_to_le32(devpriv->local1_iobase +
+ ADC_FIFO_REG);
else
- priv(dev)->ai_dma_desc[i].local_start_addr =
- cpu_to_le32(priv(dev)->local0_iobase +
- ADC_FIFO_REG);
- priv(dev)->ai_dma_desc[i].transfer_size = cpu_to_le32(0);
- priv(dev)->ai_dma_desc[i].next =
- cpu_to_le32((priv(dev)->ai_dma_desc_bus_addr + ((i +
- 1) %
- ai_dma_ring_count
- (board
- (dev))) *
- sizeof(priv(dev)->ai_dma_desc[0])) |
- PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT |
- PLX_XFER_LOCAL_TO_PCI);
+ devpriv->ai_dma_desc[i].local_start_addr =
+ cpu_to_le32(devpriv->local0_iobase +
+ ADC_FIFO_REG);
+ devpriv->ai_dma_desc[i].transfer_size = cpu_to_le32(0);
+ devpriv->ai_dma_desc[i].next =
+ cpu_to_le32((devpriv->ai_dma_desc_bus_addr +
+ ((i + 1) % ai_dma_ring_count(thisboard)) *
+ sizeof(devpriv->ai_dma_desc[0])) |
+ PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT |
+ PLX_XFER_LOCAL_TO_PCI);
}
- if (ao_cmd_is_supported(board(dev))) {
+ if (ao_cmd_is_supported(thisboard)) {
for (i = 0; i < AO_DMA_RING_COUNT; i++) {
- priv(dev)->ao_dma_desc[i].pci_start_addr =
- cpu_to_le32(priv(dev)->ao_buffer_bus_addr[i]);
- priv(dev)->ao_dma_desc[i].local_start_addr =
- cpu_to_le32(priv(dev)->local0_iobase +
- DAC_FIFO_REG);
- priv(dev)->ao_dma_desc[i].transfer_size =
- cpu_to_le32(0);
- priv(dev)->ao_dma_desc[i].next =
- cpu_to_le32((priv(dev)->ao_dma_desc_bus_addr +
- ((i + 1) % (AO_DMA_RING_COUNT)) *
- sizeof(priv(dev)->ao_dma_desc[0])) |
- PLX_DESC_IN_PCI_BIT |
- PLX_INTR_TERM_COUNT);
+ devpriv->ao_dma_desc[i].pci_start_addr =
+ cpu_to_le32(devpriv->ao_buffer_bus_addr[i]);
+ devpriv->ao_dma_desc[i].local_start_addr =
+ cpu_to_le32(devpriv->local0_iobase +
+ DAC_FIFO_REG);
+ devpriv->ao_dma_desc[i].transfer_size = cpu_to_le32(0);
+ devpriv->ao_dma_desc[i].next =
+ cpu_to_le32((devpriv->ao_dma_desc_bus_addr +
+ ((i + 1) % (AO_DMA_RING_COUNT)) *
+ sizeof(devpriv->ao_dma_desc[0])) |
+ PLX_DESC_IN_PCI_BIT |
+ PLX_INTR_TERM_COUNT);
}
}
return 0;
@@ -1649,216 +1610,140 @@ static inline void warn_external_queue(struct comedi_device *dev)
"Use internal AI channel queue (channels must be consecutive and use same range/aref)");
}
-static struct pci_dev *cb_pcidas64_find_pci_dev(struct comedi_device *dev,
- struct comedi_devconfig *it)
+/* Their i2c requires a huge delay on setting clock or data high for some reason */
+static const int i2c_high_udelay = 1000;
+static const int i2c_low_udelay = 10;
+
+/* set i2c data line high or low */
+static void i2c_set_sda(struct comedi_device *dev, int state)
{
- struct pci_dev *pcidev = NULL;
- int bus = it->options[0];
- int slot = it->options[1];
- int i;
+ struct pcidas64_private *devpriv = dev->private;
+ static const int data_bit = CTL_EE_W;
+ void __iomem *plx_control_addr = devpriv->plx9080_iobase +
+ PLX_CONTROL_REG;
- for_each_pci_dev(pcidev) {
- if (bus || slot) {
- if (bus != pcidev->bus->number ||
- slot != PCI_SLOT(pcidev->devfn))
- continue;
- }
- if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
- continue;
-
- for (i = 0; i < ARRAY_SIZE(pcidas64_boards); i++) {
- if (pcidas64_boards[i].device_id != pcidev->device)
- continue;
- dev->board_ptr = pcidas64_boards + i;
- return pcidev;
- }
+ if (state) {
+ /* set data line high */
+ devpriv->plx_control_bits &= ~data_bit;
+ writel(devpriv->plx_control_bits, plx_control_addr);
+ udelay(i2c_high_udelay);
+ } else { /* set data line low */
+
+ devpriv->plx_control_bits |= data_bit;
+ writel(devpriv->plx_control_bits, plx_control_addr);
+ udelay(i2c_low_udelay);
}
- dev_err(dev->class_dev,
- "No supported board found! (req. bus %d, slot %d)\n",
- bus, slot);
- return NULL;
}
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board.
- */
-static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
+/* set i2c clock line high or low */
+static void i2c_set_scl(struct comedi_device *dev, int state)
{
- struct pci_dev *pcidev;
- uint32_t local_range, local_decode;
- int retval;
-
-/*
- * Allocate the private structure area.
- */
- if (alloc_private(dev, sizeof(struct pcidas64_private)) < 0)
- return -ENOMEM;
+ struct pcidas64_private *devpriv = dev->private;
+ static const int clock_bit = CTL_USERO;
+ void __iomem *plx_control_addr = devpriv->plx9080_iobase +
+ PLX_CONTROL_REG;
- pcidev = cb_pcidas64_find_pci_dev(dev, it);
- if (!pcidev)
- return -EIO;
- comedi_set_hw_dev(dev, &pcidev->dev);
+ if (state) {
+ /* set clock line high */
+ devpriv->plx_control_bits &= ~clock_bit;
+ writel(devpriv->plx_control_bits, plx_control_addr);
+ udelay(i2c_high_udelay);
+ } else { /* set clock line low */
- if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
- dev_warn(dev->class_dev,
- "failed to enable PCI device and request regions\n");
- return -EIO;
+ devpriv->plx_control_bits |= clock_bit;
+ writel(devpriv->plx_control_bits, plx_control_addr);
+ udelay(i2c_low_udelay);
}
- pci_set_master(pcidev);
-
- /* Initialize dev->board_name */
- dev->board_name = board(dev)->name;
+}
- dev->iobase = pci_resource_start(pcidev, MAIN_BADDRINDEX);
+static void i2c_write_byte(struct comedi_device *dev, uint8_t byte)
+{
+ uint8_t bit;
+ unsigned int num_bits = 8;
- priv(dev)->plx9080_phys_iobase =
- pci_resource_start(pcidev, PLX9080_BADDRINDEX);
- priv(dev)->main_phys_iobase = dev->iobase;
- priv(dev)->dio_counter_phys_iobase =
- pci_resource_start(pcidev, DIO_COUNTER_BADDRINDEX);
+ DEBUG_PRINT("writing to i2c byte 0x%x\n", byte);
- /* remap, won't work with 2.0 kernels but who cares */
- priv(dev)->plx9080_iobase = ioremap(priv(dev)->plx9080_phys_iobase,
- pci_resource_len(pcidev,
- PLX9080_BADDRINDEX));
- priv(dev)->main_iobase =
- ioremap(priv(dev)->main_phys_iobase,
- pci_resource_len(pcidev, MAIN_BADDRINDEX));
- priv(dev)->dio_counter_iobase =
- ioremap(priv(dev)->dio_counter_phys_iobase,
- pci_resource_len(pcidev, DIO_COUNTER_BADDRINDEX));
-
- if (!priv(dev)->plx9080_iobase || !priv(dev)->main_iobase
- || !priv(dev)->dio_counter_iobase) {
- dev_warn(dev->class_dev, "failed to remap io memory\n");
- return -ENOMEM;
+ for (bit = 1 << (num_bits - 1); bit; bit >>= 1) {
+ i2c_set_scl(dev, 0);
+ if ((byte & bit))
+ i2c_set_sda(dev, 1);
+ else
+ i2c_set_sda(dev, 0);
+ i2c_set_scl(dev, 1);
}
+}
- DEBUG_PRINT(" plx9080 remapped to 0x%p\n", priv(dev)->plx9080_iobase);
- DEBUG_PRINT(" main remapped to 0x%p\n", priv(dev)->main_iobase);
- DEBUG_PRINT(" diocounter remapped to 0x%p\n",
- priv(dev)->dio_counter_iobase);
-
- /* figure out what local addresses are */
- local_range =
- readl(priv(dev)->plx9080_iobase + PLX_LAS0RNG_REG) & LRNG_MEM_MASK;
- local_decode =
- readl(priv(dev)->plx9080_iobase +
- PLX_LAS0MAP_REG) & local_range & LMAP_MEM_MASK;
- priv(dev)->local0_iobase =
- ((uint32_t) priv(dev)->main_phys_iobase & ~local_range) |
- local_decode;
- local_range =
- readl(priv(dev)->plx9080_iobase + PLX_LAS1RNG_REG) & LRNG_MEM_MASK;
- local_decode =
- readl(priv(dev)->plx9080_iobase +
- PLX_LAS1MAP_REG) & local_range & LMAP_MEM_MASK;
- priv(dev)->local1_iobase =
- ((uint32_t) priv(dev)->dio_counter_phys_iobase & ~local_range) |
- local_decode;
-
- DEBUG_PRINT(" local 0 io addr 0x%x\n", priv(dev)->local0_iobase);
- DEBUG_PRINT(" local 1 io addr 0x%x\n", priv(dev)->local1_iobase);
-
- retval = alloc_and_init_dma_members(dev);
- if (retval < 0)
- return retval;
-
- priv(dev)->hw_revision =
- hw_revision(dev, readw(priv(dev)->main_iobase + HW_STATUS_REG));
- dev_dbg(dev->class_dev, "stc hardware revision %i\n",
- priv(dev)->hw_revision);
- init_plx9080(dev);
- init_stc_registers(dev);
- /* get irq */
- if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
- "cb_pcidas64", dev)) {
- dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
- pcidev->irq);
- return -EINVAL;
- }
- dev->irq = pcidev->irq;
- dev_dbg(dev->class_dev, "irq %u\n", dev->irq);
+/* we can't really read the lines, so fake it */
+static int i2c_read_ack(struct comedi_device *dev)
+{
+ i2c_set_scl(dev, 0);
+ i2c_set_sda(dev, 1);
+ i2c_set_scl(dev, 1);
- retval = setup_subdevices(dev);
- if (retval < 0)
- return retval;
+ return 0; /* return fake acknowledge bit */
+}
+/* send start bit */
+static void i2c_start(struct comedi_device *dev)
+{
+ i2c_set_scl(dev, 1);
+ i2c_set_sda(dev, 1);
+ i2c_set_sda(dev, 0);
+}
- return 0;
+/* send stop bit */
+static void i2c_stop(struct comedi_device *dev)
+{
+ i2c_set_scl(dev, 0);
+ i2c_set_sda(dev, 0);
+ i2c_set_scl(dev, 1);
+ i2c_set_sda(dev, 1);
}
-static void detach(struct comedi_device *dev)
+static void i2c_write(struct comedi_device *dev, unsigned int address,
+ const uint8_t *data, unsigned int length)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct pcidas64_private *devpriv = dev->private;
unsigned int i;
+ uint8_t bitstream;
+ static const int read_bit = 0x1;
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (priv(dev)) {
- if (pcidev) {
- if (priv(dev)->plx9080_iobase) {
- disable_plx_interrupts(dev);
- iounmap(priv(dev)->plx9080_iobase);
- }
- if (priv(dev)->main_iobase)
- iounmap(priv(dev)->main_iobase);
- if (priv(dev)->dio_counter_iobase)
- iounmap(priv(dev)->dio_counter_iobase);
- /* free pci dma buffers */
- for (i = 0; i < ai_dma_ring_count(board(dev)); i++) {
- if (priv(dev)->ai_buffer[i])
- pci_free_consistent(pcidev,
- DMA_BUFFER_SIZE,
- priv(dev)->
- ai_buffer[i],
- priv
- (dev)->ai_buffer_bus_addr
- [i]);
- }
- for (i = 0; i < AO_DMA_RING_COUNT; i++) {
- if (priv(dev)->ao_buffer[i])
- pci_free_consistent(pcidev,
- DMA_BUFFER_SIZE,
- priv(dev)->
- ao_buffer[i],
- priv
- (dev)->ao_buffer_bus_addr
- [i]);
- }
- /* free dma descriptors */
- if (priv(dev)->ai_dma_desc)
- pci_free_consistent(pcidev,
- sizeof(struct plx_dma_desc)
- *
- ai_dma_ring_count(board
- (dev)),
- priv(dev)->ai_dma_desc,
- priv(dev)->
- ai_dma_desc_bus_addr);
- if (priv(dev)->ao_dma_desc)
- pci_free_consistent(pcidev,
- sizeof(struct plx_dma_desc)
- * AO_DMA_RING_COUNT,
- priv(dev)->ao_dma_desc,
- priv(dev)->
- ao_dma_desc_bus_addr);
- }
- }
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[4]);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
+ /* XXX need mutex to prevent simultaneous attempts to access
+ * eeprom and i2c bus */
+
+ /* make sure we dont send anything to eeprom */
+ devpriv->plx_control_bits &= ~CTL_EE_CS;
+
+ i2c_stop(dev);
+ i2c_start(dev);
+
+ /* send address and write bit */
+ bitstream = (address << 1) & ~read_bit;
+ i2c_write_byte(dev, bitstream);
- pci_dev_put(pcidev);
+ /* get acknowledge */
+ if (i2c_read_ack(dev) != 0) {
+ comedi_error(dev, "i2c write failed: no acknowledge");
+ i2c_stop(dev);
+ return;
}
+ /* write data bytes */
+ for (i = 0; i < length; i++) {
+ i2c_write_byte(dev, data[i]);
+ if (i2c_read_ack(dev) != 0) {
+ comedi_error(dev, "i2c write failed: no acknowledge");
+ i2c_stop(dev);
+ return;
+ }
+ }
+ i2c_stop(dev);
}
static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
unsigned int bits = 0, n, i;
unsigned int channel, range, aref;
unsigned long flags;
@@ -1875,35 +1760,37 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
spin_lock_irqsave(&dev->spinlock, flags);
if (insn->chanspec & CR_ALT_FILTER)
- priv(dev)->adc_control1_bits |= ADC_DITHER_BIT;
+ devpriv->adc_control1_bits |= ADC_DITHER_BIT;
else
- priv(dev)->adc_control1_bits &= ~ADC_DITHER_BIT;
- writew(priv(dev)->adc_control1_bits,
- priv(dev)->main_iobase + ADC_CONTROL1_REG);
+ devpriv->adc_control1_bits &= ~ADC_DITHER_BIT;
+ writew(devpriv->adc_control1_bits,
+ devpriv->main_iobase + ADC_CONTROL1_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
- if (board(dev)->layout != LAYOUT_4020) {
+ if (thisboard->layout != LAYOUT_4020) {
/* use internal queue */
- priv(dev)->hw_config_bits &= ~EXT_QUEUE_BIT;
- writew(priv(dev)->hw_config_bits,
- priv(dev)->main_iobase + HW_CONFIG_REG);
+ devpriv->hw_config_bits &= ~EXT_QUEUE_BIT;
+ writew(devpriv->hw_config_bits,
+ devpriv->main_iobase + HW_CONFIG_REG);
/* ALT_SOURCE is internal calibration reference */
if (insn->chanspec & CR_ALT_SOURCE) {
unsigned int cal_en_bit;
DEBUG_PRINT("reading calibration source\n");
- if (board(dev)->layout == LAYOUT_60XX)
+ if (thisboard->layout == LAYOUT_60XX)
cal_en_bit = CAL_EN_60XX_BIT;
else
cal_en_bit = CAL_EN_64XX_BIT;
- /* select internal reference source to connect to channel 0 */
+ /* select internal reference source to connect
+ * to channel 0 */
writew(cal_en_bit |
- adc_src_bits(priv(dev)->calibration_source),
- priv(dev)->main_iobase + CALIBRATION_REG);
+ adc_src_bits(devpriv->calibration_source),
+ devpriv->main_iobase + CALIBRATION_REG);
} else {
- /* make sure internal calibration source is turned off */
- writew(0, priv(dev)->main_iobase + CALIBRATION_REG);
+ /* make sure internal calibration source
+ * is turned off */
+ writew(0, devpriv->main_iobase + CALIBRATION_REG);
}
/* load internal queue */
bits = 0;
@@ -1916,56 +1803,56 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
bits |= adc_chan_bits(channel);
/* set stop channel */
writew(adc_chan_bits(channel),
- priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG);
+ devpriv->main_iobase + ADC_QUEUE_HIGH_REG);
/* set start channel, and rest of settings */
- writew(bits, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);
+ writew(bits, devpriv->main_iobase + ADC_QUEUE_LOAD_REG);
} else {
- uint8_t old_cal_range_bits = priv(dev)->i2c_cal_range_bits;
+ uint8_t old_cal_range_bits = devpriv->i2c_cal_range_bits;
- priv(dev)->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;
+ devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;
if (insn->chanspec & CR_ALT_SOURCE) {
DEBUG_PRINT("reading calibration source\n");
- priv(dev)->i2c_cal_range_bits |=
- adc_src_4020_bits(priv(dev)->calibration_source);
+ devpriv->i2c_cal_range_bits |=
+ adc_src_4020_bits(devpriv->calibration_source);
} else { /* select BNC inputs */
- priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits(4);
+ devpriv->i2c_cal_range_bits |= adc_src_4020_bits(4);
}
/* select range */
if (range == 0)
- priv(dev)->i2c_cal_range_bits |= attenuate_bit(channel);
+ devpriv->i2c_cal_range_bits |= attenuate_bit(channel);
else
- priv(dev)->i2c_cal_range_bits &=
- ~attenuate_bit(channel);
- /* update calibration/range i2c register only if necessary, as it is very slow */
- if (old_cal_range_bits != priv(dev)->i2c_cal_range_bits) {
- uint8_t i2c_data = priv(dev)->i2c_cal_range_bits;
+ devpriv->i2c_cal_range_bits &= ~attenuate_bit(channel);
+ /* update calibration/range i2c register only if necessary,
+ * as it is very slow */
+ if (old_cal_range_bits != devpriv->i2c_cal_range_bits) {
+ uint8_t i2c_data = devpriv->i2c_cal_range_bits;
i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data,
sizeof(i2c_data));
}
- /* 4020 manual asks that sample interval register to be set before writing to convert register.
- * Using somewhat arbitrary setting of 4 master clock ticks = 0.1 usec */
- writew(0,
- priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
- writew(2,
- priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG);
+ /* 4020 manual asks that sample interval register to be set
+ * before writing to convert register.
+ * Using somewhat arbitrary setting of 4 master clock ticks
+ * = 0.1 usec */
+ writew(0, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
+ writew(2, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG);
}
for (n = 0; n < insn->n; n++) {
/* clear adc buffer (inside loop for 4020 sake) */
- writew(0, priv(dev)->main_iobase + ADC_BUFFER_CLEAR_REG);
+ writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG);
/* trigger conversion, bits sent only matter for 4020 */
writew(adc_convert_chan_4020_bits(CR_CHAN(insn->chanspec)),
- priv(dev)->main_iobase + ADC_CONVERT_REG);
+ devpriv->main_iobase + ADC_CONVERT_REG);
/* wait for data */
for (i = 0; i < timeout; i++) {
- bits = readw(priv(dev)->main_iobase + HW_STATUS_REG);
+ bits = readw(devpriv->main_iobase + HW_STATUS_REG);
DEBUG_PRINT(" pipe bits 0x%x\n", pipe_full_bits(bits));
- if (board(dev)->layout == LAYOUT_4020) {
- if (readw(priv(dev)->main_iobase +
+ if (thisboard->layout == LAYOUT_4020) {
+ if (readw(devpriv->main_iobase +
ADC_WRITE_PNTR_REG))
break;
} else {
@@ -1977,16 +1864,14 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
DEBUG_PRINT(" looped %i times waiting for data\n", i);
if (i == timeout) {
comedi_error(dev, " analog input read insn timed out");
- printk(" status 0x%x\n", bits);
+ dev_info(dev->class_dev, "status 0x%x\n", bits);
return -ETIME;
}
- if (board(dev)->layout == LAYOUT_4020)
- data[n] =
- readl(priv(dev)->dio_counter_iobase +
- ADC_FIFO_REG) & 0xffff;
+ if (thisboard->layout == LAYOUT_4020)
+ data[n] = readl(devpriv->dio_counter_iobase +
+ ADC_FIFO_REG) & 0xffff;
else
- data[n] =
- readw(priv(dev)->main_iobase + PIPE1_READ_REG);
+ data[n] = readw(devpriv->main_iobase + PIPE1_READ_REG);
}
return n;
@@ -1995,10 +1880,12 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
static int ai_config_calibration_source(struct comedi_device *dev,
unsigned int *data)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
unsigned int source = data[1];
int num_calibration_sources;
- if (board(dev)->layout == LAYOUT_60XX)
+ if (thisboard->layout == LAYOUT_60XX)
num_calibration_sources = 16;
else
num_calibration_sources = 8;
@@ -2009,23 +1896,24 @@ static int ai_config_calibration_source(struct comedi_device *dev,
}
DEBUG_PRINT("setting calibration source to %i\n", source);
- priv(dev)->calibration_source = source;
+ devpriv->calibration_source = source;
return 2;
}
static int ai_config_block_size(struct comedi_device *dev, unsigned int *data)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
int fifo_size;
- const struct hw_fifo_info *const fifo = board(dev)->ai_fifo;
+ const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
unsigned int block_size, requested_block_size;
int retval;
requested_block_size = data[1];
if (requested_block_size) {
- fifo_size =
- requested_block_size * fifo->num_segments / bytes_in_sample;
+ fifo_size = requested_block_size * fifo->num_segments /
+ bytes_in_sample;
retval = set_ai_fifo_size(dev, fifo_size);
if (retval < 0)
@@ -2043,6 +1931,7 @@ static int ai_config_block_size(struct comedi_device *dev, unsigned int *data)
static int ai_config_master_clock_4020(struct comedi_device *dev,
unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int divisor = data[4];
int retval = 0;
@@ -2053,8 +1942,8 @@ static int ai_config_master_clock_4020(struct comedi_device *dev,
switch (data[1]) {
case COMEDI_EV_SCAN_BEGIN:
- priv(dev)->ext_clock.divisor = divisor;
- priv(dev)->ext_clock.chanspec = data[2];
+ devpriv->ext_clock.divisor = divisor;
+ devpriv->ext_clock.chanspec = data[2];
break;
default:
return -EINVAL;
@@ -2069,8 +1958,9 @@ static int ai_config_master_clock_4020(struct comedi_device *dev,
/* XXX could add support for 60xx series */
static int ai_config_master_clock(struct comedi_device *dev, unsigned int *data)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
- switch (board(dev)->layout) {
+ switch (thisboard->layout) {
case LAYOUT_4020:
return ai_config_master_clock_4020(dev, data);
break;
@@ -2104,9 +1994,84 @@ static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
return -EINVAL;
}
+/* Gets nearest achievable timing given master clock speed, does not
+ * take into account possible minimum/maximum divisor values. Used
+ * by other timing checking functions. */
+static unsigned int get_divisor(unsigned int ns, unsigned int flags)
+{
+ unsigned int divisor;
+
+ switch (flags & TRIG_ROUND_MASK) {
+ case TRIG_ROUND_UP:
+ divisor = (ns + TIMER_BASE - 1) / TIMER_BASE;
+ break;
+ case TRIG_ROUND_DOWN:
+ divisor = ns / TIMER_BASE;
+ break;
+ case TRIG_ROUND_NEAREST:
+ default:
+ divisor = (ns + TIMER_BASE / 2) / TIMER_BASE;
+ break;
+ }
+ return divisor;
+}
+
+/* utility function that rounds desired timing to an achievable time, and
+ * sets cmd members appropriately.
+ * adc paces conversions from master clock by dividing by (x + 3) where x is 24 bit number
+ */
+static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
+{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ unsigned int convert_divisor = 0, scan_divisor;
+ static const int min_convert_divisor = 3;
+ static const int max_convert_divisor =
+ max_counter_value + min_convert_divisor;
+ static const int min_scan_divisor_4020 = 2;
+ unsigned long long max_scan_divisor, min_scan_divisor;
+
+ if (cmd->convert_src == TRIG_TIMER) {
+ if (thisboard->layout == LAYOUT_4020) {
+ cmd->convert_arg = 0;
+ } else {
+ convert_divisor = get_divisor(cmd->convert_arg,
+ cmd->flags);
+ if (convert_divisor > max_convert_divisor)
+ convert_divisor = max_convert_divisor;
+ if (convert_divisor < min_convert_divisor)
+ convert_divisor = min_convert_divisor;
+ cmd->convert_arg = convert_divisor * TIMER_BASE;
+ }
+ } else if (cmd->convert_src == TRIG_NOW) {
+ cmd->convert_arg = 0;
+ }
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ scan_divisor = get_divisor(cmd->scan_begin_arg, cmd->flags);
+ if (cmd->convert_src == TRIG_TIMER) {
+ /* XXX check for integer overflows */
+ min_scan_divisor = convert_divisor * cmd->chanlist_len;
+ max_scan_divisor =
+ (convert_divisor * cmd->chanlist_len - 1) +
+ max_counter_value;
+ } else {
+ min_scan_divisor = min_scan_divisor_4020;
+ max_scan_divisor = max_counter_value + min_scan_divisor;
+ }
+ if (scan_divisor > max_scan_divisor)
+ scan_divisor = max_scan_divisor;
+ if (scan_divisor < min_scan_divisor)
+ scan_divisor = min_scan_divisor;
+ cmd->scan_begin_arg = scan_divisor * TIMER_BASE;
+ }
+
+ return;
+}
+
static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
int err = 0;
unsigned int tmp_arg, tmp_arg2;
int i;
@@ -2118,22 +2083,21 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
triggers = TRIG_TIMER;
- if (board(dev)->layout == LAYOUT_4020)
+ if (thisboard->layout == LAYOUT_4020)
triggers |= TRIG_OTHER;
else
triggers |= TRIG_FOLLOW;
err |= cfc_check_trigger_src(&cmd->scan_begin_src, triggers);
triggers = TRIG_TIMER;
- if (board(dev)->layout == LAYOUT_4020)
+ if (thisboard->layout == LAYOUT_4020)
triggers |= TRIG_NOW;
else
triggers |= TRIG_EXT;
err |= cfc_check_trigger_src(&cmd->convert_src, triggers);
-
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= cfc_check_trigger_src(&cmd->stop_src,
- TRIG_COUNT | TRIG_EXT | TRIG_NONE);
+ TRIG_COUNT | TRIG_EXT | TRIG_NONE);
if (err)
return 1;
@@ -2156,55 +2120,34 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (err)
return 2;
- /* step 3: make sure arguments are trivially compatible */
+ /* Step 3: check if arguments are trivially valid */
if (cmd->convert_src == TRIG_TIMER) {
- if (board(dev)->layout == LAYOUT_4020) {
- if (cmd->convert_arg) {
- cmd->convert_arg = 0;
- err++;
- }
+ if (thisboard->layout == LAYOUT_4020) {
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
} else {
- if (cmd->convert_arg < board(dev)->ai_speed) {
- cmd->convert_arg = board(dev)->ai_speed;
- err++;
- }
- if (cmd->scan_begin_src == TRIG_TIMER) {
- /* if scans are timed faster than conversion rate allows */
- if (cmd->convert_arg * cmd->chanlist_len >
- cmd->scan_begin_arg) {
- cmd->scan_begin_arg =
- cmd->convert_arg *
- cmd->chanlist_len;
- err++;
- }
- }
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
+ thisboard->ai_speed);
+ /* if scans are timed faster than conversion rate allows */
+ if (cmd->scan_begin_src == TRIG_TIMER)
+ err |= cfc_check_trigger_arg_min(
+ &cmd->scan_begin_arg,
+ cmd->convert_arg *
+ cmd->chanlist_len);
}
}
- if (!cmd->chanlist_len) {
- cmd->chanlist_len = 1;
- err++;
- }
- if (cmd->scan_end_arg != cmd->chanlist_len) {
- cmd->scan_end_arg = cmd->chanlist_len;
- err++;
- }
+ err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
switch (cmd->stop_src) {
case TRIG_EXT:
break;
case TRIG_COUNT:
- if (!cmd->stop_arg) {
- cmd->stop_arg = 1;
- err++;
- }
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
break;
case TRIG_NONE:
- if (cmd->stop_arg != 0) {
- cmd->stop_arg = 0;
- err++;
- }
+ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
break;
default:
break;
@@ -2240,7 +2183,7 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
}
}
/* check 4020 chanlist */
- if (board(dev)->layout == LAYOUT_4020) {
+ if (thisboard->layout == LAYOUT_4020) {
unsigned int first_channel = CR_CHAN(cmd->chanlist[0]);
for (i = 1; i < cmd->chanlist_len; i++) {
if (CR_CHAN(cmd->chanlist[i]) !=
@@ -2279,89 +2222,37 @@ static int use_hw_sample_counter(struct comedi_cmd *cmd)
static void setup_sample_counters(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
+
if (cmd->stop_src == TRIG_COUNT) {
/* set software count */
- priv(dev)->ai_count = cmd->stop_arg * cmd->chanlist_len;
+ devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len;
}
/* load hardware conversion counter */
if (use_hw_sample_counter(cmd)) {
writew(cmd->stop_arg & 0xffff,
- priv(dev)->main_iobase + ADC_COUNT_LOWER_REG);
+ devpriv->main_iobase + ADC_COUNT_LOWER_REG);
writew((cmd->stop_arg >> 16) & 0xff,
- priv(dev)->main_iobase + ADC_COUNT_UPPER_REG);
+ devpriv->main_iobase + ADC_COUNT_UPPER_REG);
} else {
- writew(1, priv(dev)->main_iobase + ADC_COUNT_LOWER_REG);
+ writew(1, devpriv->main_iobase + ADC_COUNT_LOWER_REG);
}
}
static inline unsigned int dma_transfer_size(struct comedi_device *dev)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
unsigned int num_samples;
- num_samples =
- priv(dev)->ai_fifo_segment_length *
- board(dev)->ai_fifo->sample_packing_ratio;
+ num_samples = devpriv->ai_fifo_segment_length *
+ thisboard->ai_fifo->sample_packing_ratio;
if (num_samples > DMA_BUFFER_SIZE / sizeof(uint16_t))
num_samples = DMA_BUFFER_SIZE / sizeof(uint16_t);
return num_samples;
}
-static void disable_ai_pacing(struct comedi_device *dev)
-{
- unsigned long flags;
-
- disable_ai_interrupts(dev);
-
- spin_lock_irqsave(&dev->spinlock, flags);
- priv(dev)->adc_control1_bits &= ~ADC_SW_GATE_BIT;
- writew(priv(dev)->adc_control1_bits,
- priv(dev)->main_iobase + ADC_CONTROL1_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- /* disable pacing, triggering, etc */
- writew(ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT,
- priv(dev)->main_iobase + ADC_CONTROL0_REG);
-}
-
-static void disable_ai_interrupts(struct comedi_device *dev)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->spinlock, flags);
- priv(dev)->intr_enable_bits &=
- ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT &
- ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT &
- ~EN_ADC_OVERRUN_BIT & ~ADC_INTR_SRC_MASK;
- writew(priv(dev)->intr_enable_bits,
- priv(dev)->main_iobase + INTR_ENABLE_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- DEBUG_PRINT("intr enable bits 0x%x\n", priv(dev)->intr_enable_bits);
-}
-
-static void enable_ai_interrupts(struct comedi_device *dev,
- const struct comedi_cmd *cmd)
-{
- uint32_t bits;
- unsigned long flags;
-
- bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT |
- EN_ADC_ACTIVE_INTR_BIT | EN_ADC_STOP_INTR_BIT;
- /* Use pio transfer and interrupt on end of conversion if TRIG_WAKE_EOS flag is set. */
- if (cmd->flags & TRIG_WAKE_EOS) {
- /* 4020 doesn't support pio transfers except for fifo dregs */
- if (board(dev)->layout != LAYOUT_4020)
- bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT;
- }
- spin_lock_irqsave(&dev->spinlock, flags);
- priv(dev)->intr_enable_bits |= bits;
- writew(priv(dev)->intr_enable_bits,
- priv(dev)->main_iobase + INTR_ENABLE_REG);
- DEBUG_PRINT("intr enable bits 0x%x\n", priv(dev)->intr_enable_bits);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-}
-
static uint32_t ai_convert_counter_6xxx(const struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
@@ -2373,12 +2264,13 @@ static uint32_t ai_scan_counter_6xxx(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
uint32_t count;
+
/* figure out how long we need to delay at end of scan */
switch (cmd->scan_begin_src) {
case TRIG_TIMER:
count = (cmd->scan_begin_arg -
- (cmd->convert_arg * (cmd->chanlist_len - 1)))
- / TIMER_BASE;
+ (cmd->convert_arg * (cmd->chanlist_len - 1))) /
+ TIMER_BASE;
break;
case TRIG_FOLLOW:
count = cmd->convert_arg / TIMER_BASE;
@@ -2393,6 +2285,7 @@ static uint32_t ai_scan_counter_6xxx(struct comedi_device *dev,
static uint32_t ai_convert_counter_4020(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int divisor;
switch (cmd->scan_begin_src) {
@@ -2400,7 +2293,7 @@ static uint32_t ai_convert_counter_4020(struct comedi_device *dev,
divisor = cmd->scan_begin_arg / TIMER_BASE;
break;
case TRIG_OTHER:
- divisor = priv(dev)->ext_clock.divisor;
+ divisor = devpriv->ext_clock.divisor;
break;
default: /* should never happen */
comedi_error(dev, "bug! failed to set ai pacing!");
@@ -2415,26 +2308,30 @@ static uint32_t ai_convert_counter_4020(struct comedi_device *dev,
static void select_master_clock_4020(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
+
/* select internal/external master clock */
- priv(dev)->hw_config_bits &= ~MASTER_CLOCK_4020_MASK;
+ devpriv->hw_config_bits &= ~MASTER_CLOCK_4020_MASK;
if (cmd->scan_begin_src == TRIG_OTHER) {
- int chanspec = priv(dev)->ext_clock.chanspec;
+ int chanspec = devpriv->ext_clock.chanspec;
if (CR_CHAN(chanspec))
- priv(dev)->hw_config_bits |= BNC_CLOCK_4020_BITS;
+ devpriv->hw_config_bits |= BNC_CLOCK_4020_BITS;
else
- priv(dev)->hw_config_bits |= EXT_CLOCK_4020_BITS;
+ devpriv->hw_config_bits |= EXT_CLOCK_4020_BITS;
} else {
- priv(dev)->hw_config_bits |= INTERNAL_CLOCK_4020_BITS;
+ devpriv->hw_config_bits |= INTERNAL_CLOCK_4020_BITS;
}
- writew(priv(dev)->hw_config_bits,
- priv(dev)->main_iobase + HW_CONFIG_REG);
+ writew(devpriv->hw_config_bits,
+ devpriv->main_iobase + HW_CONFIG_REG);
}
static void select_master_clock(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
- switch (board(dev)->layout) {
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+
+ switch (thisboard->layout) {
case LAYOUT_4020:
select_master_clock_4020(dev, cmd);
break;
@@ -2446,6 +2343,7 @@ static void select_master_clock(struct comedi_device *dev,
static inline void dma_start_sync(struct comedi_device *dev,
unsigned int channel)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned long flags;
/* spinlock for plx dma control/status reg */
@@ -2453,23 +2351,25 @@ static inline void dma_start_sync(struct comedi_device *dev,
if (channel)
writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT |
PLX_CLEAR_DMA_INTR_BIT,
- priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG);
+ devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
else
writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT |
PLX_CLEAR_DMA_INTR_BIT,
- priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);
+ devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
}
static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
uint32_t convert_counter = 0, scan_counter = 0;
check_adc_timing(dev, cmd);
select_master_clock(dev, cmd);
- if (board(dev)->layout == LAYOUT_4020) {
+ if (thisboard->layout == LAYOUT_4020) {
convert_counter = ai_convert_counter_4020(dev, cmd);
} else {
convert_counter = ai_convert_counter_6xxx(dev, cmd);
@@ -2478,23 +2378,24 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
/* load lower 16 bits of convert interval */
writew(convert_counter & 0xffff,
- priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG);
+ devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG);
DEBUG_PRINT("convert counter 0x%x\n", convert_counter);
/* load upper 8 bits of convert interval */
writew((convert_counter >> 16) & 0xff,
- priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
+ devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
/* load lower 16 bits of scan delay */
writew(scan_counter & 0xffff,
- priv(dev)->main_iobase + ADC_DELAY_INTERVAL_LOWER_REG);
+ devpriv->main_iobase + ADC_DELAY_INTERVAL_LOWER_REG);
/* load upper 8 bits of scan delay */
writew((scan_counter >> 16) & 0xff,
- priv(dev)->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG);
+ devpriv->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG);
DEBUG_PRINT("scan counter 0x%x\n", scan_counter);
}
static int use_internal_queue_6xxx(const struct comedi_cmd *cmd)
{
int i;
+
for (i = 0; i + 1 < cmd->chanlist_len; i++) {
if (CR_CHAN(cmd->chanlist[i + 1]) !=
CR_CHAN(cmd->chanlist[i]) + 1)
@@ -2511,14 +2412,16 @@ static int use_internal_queue_6xxx(const struct comedi_cmd *cmd)
static int setup_channel_queue(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
unsigned short bits;
int i;
- if (board(dev)->layout != LAYOUT_4020) {
+ if (thisboard->layout != LAYOUT_4020) {
if (use_internal_queue_6xxx(cmd)) {
- priv(dev)->hw_config_bits &= ~EXT_QUEUE_BIT;
- writew(priv(dev)->hw_config_bits,
- priv(dev)->main_iobase + HW_CONFIG_REG);
+ devpriv->hw_config_bits &= ~EXT_QUEUE_BIT;
+ writew(devpriv->hw_config_bits,
+ devpriv->main_iobase + HW_CONFIG_REG);
bits = 0;
/* set channel */
bits |= adc_chan_bits(CR_CHAN(cmd->chanlist[0]));
@@ -2534,30 +2437,30 @@ static int setup_channel_queue(struct comedi_device *dev,
/* set stop channel */
writew(adc_chan_bits
(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])),
- priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG);
+ devpriv->main_iobase + ADC_QUEUE_HIGH_REG);
/* set start channel, and rest of settings */
writew(bits,
- priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);
+ devpriv->main_iobase + ADC_QUEUE_LOAD_REG);
} else {
/* use external queue */
if (dev->write_subdev && dev->write_subdev->busy) {
warn_external_queue(dev);
return -EBUSY;
}
- priv(dev)->hw_config_bits |= EXT_QUEUE_BIT;
- writew(priv(dev)->hw_config_bits,
- priv(dev)->main_iobase + HW_CONFIG_REG);
+ devpriv->hw_config_bits |= EXT_QUEUE_BIT;
+ writew(devpriv->hw_config_bits,
+ devpriv->main_iobase + HW_CONFIG_REG);
/* clear DAC buffer to prevent weird interactions */
writew(0,
- priv(dev)->main_iobase + DAC_BUFFER_CLEAR_REG);
+ devpriv->main_iobase + DAC_BUFFER_CLEAR_REG);
/* clear queue pointer */
- writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG);
+ writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG);
/* load external queue */
for (i = 0; i < cmd->chanlist_len; i++) {
bits = 0;
/* set channel */
- bits |=
- adc_chan_bits(CR_CHAN(cmd->chanlist[i]));
+ bits |= adc_chan_bits(CR_CHAN(cmd->
+ chanlist[i]));
/* set gain */
bits |= ai_range_bits_6xxx(dev,
CR_RANGE(cmd->
@@ -2573,42 +2476,42 @@ static int setup_channel_queue(struct comedi_device *dev,
/* mark end of queue */
if (i == cmd->chanlist_len - 1)
bits |= QUEUE_EOSCAN_BIT |
- QUEUE_EOSEQ_BIT;
+ QUEUE_EOSEQ_BIT;
writew(bits,
- priv(dev)->main_iobase +
+ devpriv->main_iobase +
ADC_QUEUE_FIFO_REG);
- DEBUG_PRINT
- ("wrote 0x%x to external channel queue\n",
- bits);
+ DEBUG_PRINT(
+ "wrote 0x%x to external channel queue\n",
+ bits);
}
/* doing a queue clear is not specified in board docs,
* but required for reliable operation */
- writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG);
+ writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG);
/* prime queue holding register */
- writew(0, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);
+ writew(0, devpriv->main_iobase + ADC_QUEUE_LOAD_REG);
}
} else {
- unsigned short old_cal_range_bits =
- priv(dev)->i2c_cal_range_bits;
+ unsigned short old_cal_range_bits = devpriv->i2c_cal_range_bits;
- priv(dev)->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;
+ devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;
/* select BNC inputs */
- priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits(4);
+ devpriv->i2c_cal_range_bits |= adc_src_4020_bits(4);
/* select ranges */
for (i = 0; i < cmd->chanlist_len; i++) {
unsigned int channel = CR_CHAN(cmd->chanlist[i]);
unsigned int range = CR_RANGE(cmd->chanlist[i]);
if (range == 0)
- priv(dev)->i2c_cal_range_bits |=
- attenuate_bit(channel);
+ devpriv->i2c_cal_range_bits |=
+ attenuate_bit(channel);
else
- priv(dev)->i2c_cal_range_bits &=
- ~attenuate_bit(channel);
+ devpriv->i2c_cal_range_bits &=
+ ~attenuate_bit(channel);
}
- /* update calibration/range i2c register only if necessary, as it is very slow */
- if (old_cal_range_bits != priv(dev)->i2c_cal_range_bits) {
- uint8_t i2c_data = priv(dev)->i2c_cal_range_bits;
+ /* update calibration/range i2c register only if necessary,
+ * as it is very slow */
+ if (old_cal_range_bits != devpriv->i2c_cal_range_bits) {
+ uint8_t i2c_data = devpriv->i2c_cal_range_bits;
i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data,
sizeof(i2c_data));
}
@@ -2620,6 +2523,8 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev,
unsigned int dma_channel,
unsigned int descriptor_bits)
{
+ struct pcidas64_private *devpriv = dev->private;
+
/* The transfer size, pci address, and local address registers
* are supposedly unused during chained dma,
* but I have found that left over values from last operation
@@ -2627,25 +2532,27 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev,
* block. Initializing them to zero seems to fix the problem. */
if (dma_channel) {
writel(0,
- priv(dev)->plx9080_iobase + PLX_DMA1_TRANSFER_SIZE_REG);
- writel(0, priv(dev)->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG);
+ devpriv->plx9080_iobase + PLX_DMA1_TRANSFER_SIZE_REG);
+ writel(0, devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG);
writel(0,
- priv(dev)->plx9080_iobase + PLX_DMA1_LOCAL_ADDRESS_REG);
+ devpriv->plx9080_iobase + PLX_DMA1_LOCAL_ADDRESS_REG);
writel(descriptor_bits,
- priv(dev)->plx9080_iobase + PLX_DMA1_DESCRIPTOR_REG);
+ devpriv->plx9080_iobase + PLX_DMA1_DESCRIPTOR_REG);
} else {
writel(0,
- priv(dev)->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG);
- writel(0, priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG);
+ devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG);
+ writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG);
writel(0,
- priv(dev)->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG);
+ devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG);
writel(descriptor_bits,
- priv(dev)->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
+ devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
}
}
static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
uint32_t bits;
@@ -2661,7 +2568,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return retval;
/* make sure internal calibration source is turned off */
- writew(0, priv(dev)->main_iobase + CALIBRATION_REG);
+ writew(0, devpriv->main_iobase + CALIBRATION_REG);
set_ai_pacing(dev, cmd);
@@ -2671,50 +2578,51 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
spin_lock_irqsave(&dev->spinlock, flags);
/* set mode, allow conversions through software gate */
- priv(dev)->adc_control1_bits |= ADC_SW_GATE_BIT;
- priv(dev)->adc_control1_bits &= ~ADC_DITHER_BIT;
- if (board(dev)->layout != LAYOUT_4020) {
- priv(dev)->adc_control1_bits &= ~ADC_MODE_MASK;
+ devpriv->adc_control1_bits |= ADC_SW_GATE_BIT;
+ devpriv->adc_control1_bits &= ~ADC_DITHER_BIT;
+ if (thisboard->layout != LAYOUT_4020) {
+ devpriv->adc_control1_bits &= ~ADC_MODE_MASK;
if (cmd->convert_src == TRIG_EXT)
- priv(dev)->adc_control1_bits |= adc_mode_bits(13); /* good old mode 13 */
+ /* good old mode 13 */
+ devpriv->adc_control1_bits |= adc_mode_bits(13);
else
- priv(dev)->adc_control1_bits |= adc_mode_bits(8); /* mode 8. What else could you need? */
+ /* mode 8. What else could you need? */
+ devpriv->adc_control1_bits |= adc_mode_bits(8);
} else {
- priv(dev)->adc_control1_bits &= ~CHANNEL_MODE_4020_MASK;
+ devpriv->adc_control1_bits &= ~CHANNEL_MODE_4020_MASK;
if (cmd->chanlist_len == 4)
- priv(dev)->adc_control1_bits |= FOUR_CHANNEL_4020_BITS;
+ devpriv->adc_control1_bits |= FOUR_CHANNEL_4020_BITS;
else if (cmd->chanlist_len == 2)
- priv(dev)->adc_control1_bits |= TWO_CHANNEL_4020_BITS;
- priv(dev)->adc_control1_bits &= ~ADC_LO_CHANNEL_4020_MASK;
- priv(dev)->adc_control1_bits |=
- adc_lo_chan_4020_bits(CR_CHAN(cmd->chanlist[0]));
- priv(dev)->adc_control1_bits &= ~ADC_HI_CHANNEL_4020_MASK;
- priv(dev)->adc_control1_bits |=
- adc_hi_chan_4020_bits(CR_CHAN
- (cmd->
- chanlist[cmd->chanlist_len - 1]));
+ devpriv->adc_control1_bits |= TWO_CHANNEL_4020_BITS;
+ devpriv->adc_control1_bits &= ~ADC_LO_CHANNEL_4020_MASK;
+ devpriv->adc_control1_bits |=
+ adc_lo_chan_4020_bits(CR_CHAN(cmd->chanlist[0]));
+ devpriv->adc_control1_bits &= ~ADC_HI_CHANNEL_4020_MASK;
+ devpriv->adc_control1_bits |=
+ adc_hi_chan_4020_bits(CR_CHAN(cmd->chanlist
+ [cmd->chanlist_len - 1]));
}
- writew(priv(dev)->adc_control1_bits,
- priv(dev)->main_iobase + ADC_CONTROL1_REG);
- DEBUG_PRINT("control1 bits 0x%x\n", priv(dev)->adc_control1_bits);
+ writew(devpriv->adc_control1_bits,
+ devpriv->main_iobase + ADC_CONTROL1_REG);
+ DEBUG_PRINT("control1 bits 0x%x\n", devpriv->adc_control1_bits);
spin_unlock_irqrestore(&dev->spinlock, flags);
/* clear adc buffer */
- writew(0, priv(dev)->main_iobase + ADC_BUFFER_CLEAR_REG);
+ writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG);
if ((cmd->flags & TRIG_WAKE_EOS) == 0 ||
- board(dev)->layout == LAYOUT_4020) {
- priv(dev)->ai_dma_index = 0;
+ thisboard->layout == LAYOUT_4020) {
+ devpriv->ai_dma_index = 0;
/* set dma transfer size */
- for (i = 0; i < ai_dma_ring_count(board(dev)); i++)
- priv(dev)->ai_dma_desc[i].transfer_size =
- cpu_to_le32(dma_transfer_size(dev) *
- sizeof(uint16_t));
+ for (i = 0; i < ai_dma_ring_count(thisboard); i++)
+ devpriv->ai_dma_desc[i].transfer_size =
+ cpu_to_le32(dma_transfer_size(dev) *
+ sizeof(uint16_t));
/* give location of first dma descriptor */
load_first_dma_descriptor(dev, 1,
- priv(dev)->ai_dma_desc_bus_addr |
+ devpriv->ai_dma_desc_bus_addr |
PLX_DESC_IN_PCI_BIT |
PLX_INTR_TERM_COUNT |
PLX_XFER_LOCAL_TO_PCI);
@@ -2722,14 +2630,14 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
dma_start_sync(dev, 1);
}
- if (board(dev)->layout == LAYOUT_4020) {
+ if (thisboard->layout == LAYOUT_4020) {
/* set source for external triggers */
bits = 0;
if (cmd->start_src == TRIG_EXT && CR_CHAN(cmd->start_arg))
bits |= EXT_START_TRIG_BNC_BIT;
if (cmd->stop_src == TRIG_EXT && CR_CHAN(cmd->stop_arg))
bits |= EXT_STOP_TRIG_BNC_BIT;
- writew(bits, priv(dev)->main_iobase + DAQ_ATRIG_LOW_4020_REG);
+ writew(bits, devpriv->main_iobase + DAQ_ATRIG_LOW_4020_REG);
}
spin_lock_irqsave(&dev->spinlock, flags);
@@ -2747,16 +2655,16 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
bits |= ADC_START_TRIG_SOFT_BITS;
if (use_hw_sample_counter(cmd))
bits |= ADC_SAMPLE_COUNTER_EN_BIT;
- writew(bits, priv(dev)->main_iobase + ADC_CONTROL0_REG);
+ writew(bits, devpriv->main_iobase + ADC_CONTROL0_REG);
DEBUG_PRINT("control0 bits 0x%x\n", bits);
- priv(dev)->ai_cmd_running = 1;
+ devpriv->ai_cmd_running = 1;
spin_unlock_irqrestore(&dev->spinlock, flags);
/* start acquisition */
if (cmd->start_src == TRIG_NOW) {
- writew(0, priv(dev)->main_iobase + ADC_START_REG);
+ writew(0, devpriv->main_iobase + ADC_START_REG);
DEBUG_PRINT("soft trig\n");
}
@@ -2766,6 +2674,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* read num_samples from 16 bit wide ai fifo */
static void pio_drain_ai_fifo_16(struct comedi_device *dev)
{
+ struct pcidas64_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -2776,18 +2685,19 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev)
do {
/* get least significant 15 bits */
- read_index =
- readw(priv(dev)->main_iobase + ADC_READ_PNTR_REG) & 0x7fff;
- write_index =
- readw(priv(dev)->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff;
- /* Get most significant bits (grey code). Different boards use different code
- * so use a scheme that doesn't depend on encoding. This read must
+ read_index = readw(devpriv->main_iobase + ADC_READ_PNTR_REG) &
+ 0x7fff;
+ write_index = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) &
+ 0x7fff;
+ /* Get most significant bits (grey code).
+ * Different boards use different code so use a scheme
+ * that doesn't depend on encoding. This read must
* occur after reading least significant 15 bits to avoid race
* with fifo switching to next segment. */
- prepost_bits = readw(priv(dev)->main_iobase + PREPOST_REG);
+ prepost_bits = readw(devpriv->main_iobase + PREPOST_REG);
- /* if read and write pointers are not on the same fifo segment, read to the
- * end of the read segment */
+ /* if read and write pointers are not on the same fifo segment,
+ * read to the end of the read segment */
read_segment = adc_upper_read_ptr_code(prepost_bits);
write_segment = adc_upper_write_ptr_code(prepost_bits);
@@ -2797,17 +2707,17 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev)
if (read_segment != write_segment)
num_samples =
- priv(dev)->ai_fifo_segment_length - read_index;
+ devpriv->ai_fifo_segment_length - read_index;
else
num_samples = write_index - read_index;
if (cmd->stop_src == TRIG_COUNT) {
- if (priv(dev)->ai_count == 0)
+ if (devpriv->ai_count == 0)
break;
- if (num_samples > priv(dev)->ai_count)
- num_samples = priv(dev)->ai_count;
+ if (num_samples > devpriv->ai_count)
+ num_samples = devpriv->ai_count;
- priv(dev)->ai_count -= num_samples;
+ devpriv->ai_count -= num_samples;
}
if (num_samples < 0) {
@@ -2820,20 +2730,21 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev)
for (i = 0; i < num_samples; i++) {
cfc_write_to_buffer(s,
- readw(priv(dev)->main_iobase +
+ readw(devpriv->main_iobase +
ADC_FIFO_REG));
}
} while (read_segment != write_segment);
}
-/* Read from 32 bit wide ai fifo of 4020 - deal with insane grey coding of pointers.
- * The pci-4020 hardware only supports
- * dma transfers (it only supports the use of pio for draining the last remaining
- * points from the fifo when a data acquisition operation has completed).
+/* Read from 32 bit wide ai fifo of 4020 - deal with insane grey coding of
+ * pointers. The pci-4020 hardware only supports dma transfers (it only
+ * supports the use of pio for draining the last remaining points from the
+ * fifo when a data acquisition operation has completed).
*/
static void pio_drain_ai_fifo_32(struct comedi_device *dev)
{
+ struct pcidas64_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -2841,33 +2752,35 @@ static void pio_drain_ai_fifo_32(struct comedi_device *dev)
unsigned int max_transfer = 100000;
uint32_t fifo_data;
int write_code =
- readw(priv(dev)->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff;
+ readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff;
int read_code =
- readw(priv(dev)->main_iobase + ADC_READ_PNTR_REG) & 0x7fff;
+ readw(devpriv->main_iobase + ADC_READ_PNTR_REG) & 0x7fff;
if (cmd->stop_src == TRIG_COUNT) {
- if (max_transfer > priv(dev)->ai_count)
- max_transfer = priv(dev)->ai_count;
+ if (max_transfer > devpriv->ai_count)
+ max_transfer = devpriv->ai_count;
}
for (i = 0; read_code != write_code && i < max_transfer;) {
- fifo_data = readl(priv(dev)->dio_counter_iobase + ADC_FIFO_REG);
+ fifo_data = readl(devpriv->dio_counter_iobase + ADC_FIFO_REG);
cfc_write_to_buffer(s, fifo_data & 0xffff);
i++;
if (i < max_transfer) {
cfc_write_to_buffer(s, (fifo_data >> 16) & 0xffff);
i++;
}
- read_code =
- readw(priv(dev)->main_iobase + ADC_READ_PNTR_REG) & 0x7fff;
+ read_code = readw(devpriv->main_iobase + ADC_READ_PNTR_REG) &
+ 0x7fff;
}
- priv(dev)->ai_count -= i;
+ devpriv->ai_count -= i;
}
/* empty fifo */
static void pio_drain_ai_fifo(struct comedi_device *dev)
{
- if (board(dev)->layout == LAYOUT_4020)
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+
+ if (thisboard->layout == LAYOUT_4020)
pio_drain_ai_fifo_32(dev);
else
pio_drain_ai_fifo_16(dev);
@@ -2875,6 +2788,8 @@ static void pio_drain_ai_fifo(struct comedi_device *dev)
static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
struct comedi_async *async = dev->read_subdev->async;
uint32_t next_transfer_addr;
int j;
@@ -2883,46 +2798,47 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
if (channel)
pci_addr_reg =
- priv(dev)->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG;
+ devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG;
else
pci_addr_reg =
- priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG;
+ devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG;
/* loop until we have read all the full buffers */
for (j = 0, next_transfer_addr = readl(pci_addr_reg);
(next_transfer_addr <
- priv(dev)->ai_buffer_bus_addr[priv(dev)->ai_dma_index]
- || next_transfer_addr >=
- priv(dev)->ai_buffer_bus_addr[priv(dev)->ai_dma_index] +
- DMA_BUFFER_SIZE) && j < ai_dma_ring_count(board(dev)); j++) {
+ devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] ||
+ next_transfer_addr >=
+ devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] +
+ DMA_BUFFER_SIZE) && j < ai_dma_ring_count(thisboard); j++) {
/* transfer data from dma buffer to comedi buffer */
num_samples = dma_transfer_size(dev);
if (async->cmd.stop_src == TRIG_COUNT) {
- if (num_samples > priv(dev)->ai_count)
- num_samples = priv(dev)->ai_count;
- priv(dev)->ai_count -= num_samples;
+ if (num_samples > devpriv->ai_count)
+ num_samples = devpriv->ai_count;
+ devpriv->ai_count -= num_samples;
}
cfc_write_array_to_buffer(dev->read_subdev,
- priv(dev)->ai_buffer[priv(dev)->
- ai_dma_index],
+ devpriv->ai_buffer[devpriv->
+ ai_dma_index],
num_samples * sizeof(uint16_t));
- priv(dev)->ai_dma_index =
- (priv(dev)->ai_dma_index +
- 1) % ai_dma_ring_count(board(dev));
+ devpriv->ai_dma_index = (devpriv->ai_dma_index + 1) %
+ ai_dma_ring_count(thisboard);
DEBUG_PRINT("next buffer addr 0x%lx\n",
- (unsigned long)priv(dev)->
- ai_buffer_bus_addr[priv(dev)->ai_dma_index]);
+ (unsigned long)devpriv->
+ ai_buffer_bus_addr[devpriv->ai_dma_index]);
DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr);
}
- /* XXX check for dma ring buffer overrun (use end-of-chain bit to mark last
- * unused buffer) */
+ /* XXX check for dma ring buffer overrun
+ * (use end-of-chain bit to mark last unused buffer) */
}
static void handle_ai_interrupt(struct comedi_device *dev,
unsigned short status,
unsigned int plx_status)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -2936,10 +2852,10 @@ static void handle_ai_interrupt(struct comedi_device *dev,
}
/* spin lock makes sure no one else changes plx dma control reg */
spin_lock_irqsave(&dev->spinlock, flags);
- dma1_status = readb(priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG);
+ dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
if (plx_status & ICS_DMA1_A) { /* dma chan 1 interrupt */
writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
- priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG);
+ devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
DEBUG_PRINT("dma1 status 0x%x\n", dma1_status);
if (dma1_status & PLX_DMA_EN_BIT)
@@ -2956,17 +2872,17 @@ static void handle_ai_interrupt(struct comedi_device *dev,
if ((status & ADC_DONE_BIT) ||
((cmd->flags & TRIG_WAKE_EOS) &&
(status & ADC_INTR_PENDING_BIT) &&
- (board(dev)->layout != LAYOUT_4020))) {
+ (thisboard->layout != LAYOUT_4020))) {
DEBUG_PRINT("pio fifo drain\n");
spin_lock_irqsave(&dev->spinlock, flags);
- if (priv(dev)->ai_cmd_running) {
+ if (devpriv->ai_cmd_running) {
spin_unlock_irqrestore(&dev->spinlock, flags);
pio_drain_ai_fifo(dev);
} else
spin_unlock_irqrestore(&dev->spinlock, flags);
}
/* if we are have all the data, then quit */
- if ((cmd->stop_src == TRIG_COUNT && (int)priv(dev)->ai_count <= 0) ||
+ if ((cmd->stop_src == TRIG_COUNT && (int)devpriv->ai_count <= 0) ||
(cmd->stop_src == TRIG_EXT && (status & ADC_STOP_BIT))) {
async->events |= COMEDI_CB_EOA;
}
@@ -2976,29 +2892,31 @@ static void handle_ai_interrupt(struct comedi_device *dev,
static inline unsigned int prev_ao_dma_index(struct comedi_device *dev)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int buffer_index;
- if (priv(dev)->ao_dma_index == 0)
+ if (devpriv->ao_dma_index == 0)
buffer_index = AO_DMA_RING_COUNT - 1;
else
- buffer_index = priv(dev)->ao_dma_index - 1;
+ buffer_index = devpriv->ao_dma_index - 1;
return buffer_index;
}
static int last_ao_dma_load_completed(struct comedi_device *dev)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int buffer_index;
unsigned int transfer_address;
unsigned short dma_status;
buffer_index = prev_ao_dma_index(dev);
- dma_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);
+ dma_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
if ((dma_status & PLX_DMA_DONE_BIT) == 0)
return 0;
transfer_address =
- readl(priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG);
- if (transfer_address != priv(dev)->ao_buffer_bus_addr[buffer_index])
+ readl(devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG);
+ if (transfer_address != devpriv->ao_buffer_bus_addr[buffer_index])
return 0;
return 1;
@@ -3007,10 +2925,12 @@ static int last_ao_dma_load_completed(struct comedi_device *dev)
static int ao_stopped_by_error(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
+
if (cmd->stop_src == TRIG_NONE)
return 1;
if (cmd->stop_src == TRIG_COUNT) {
- if (priv(dev)->ao_count)
+ if (devpriv->ao_count)
return 1;
if (last_ao_dma_load_completed(dev) == 0)
return 1;
@@ -3032,10 +2952,11 @@ static inline int ao_dma_needs_restart(struct comedi_device *dev,
static void restart_ao_dma(struct comedi_device *dev)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int dma_desc_bits;
dma_desc_bits =
- readl(priv(dev)->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
+ readl(devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
dma_desc_bits &= ~PLX_END_OF_CHAIN_BIT;
DEBUG_PRINT("restarting ao dma, descriptor reg 0x%x\n", dma_desc_bits);
load_first_dma_descriptor(dev, 0, dma_desc_bits);
@@ -3043,9 +2964,81 @@ static void restart_ao_dma(struct comedi_device *dev)
dma_start_sync(dev, 0);
}
+static unsigned int load_ao_dma_buffer(struct comedi_device *dev,
+ const struct comedi_cmd *cmd)
+{
+ struct pcidas64_private *devpriv = dev->private;
+ unsigned int num_bytes, buffer_index, prev_buffer_index;
+ unsigned int next_bits;
+
+ buffer_index = devpriv->ao_dma_index;
+ prev_buffer_index = prev_ao_dma_index(dev);
+
+ DEBUG_PRINT("attempting to load ao buffer %i (0x%llx)\n", buffer_index,
+ (unsigned long long)devpriv->ao_buffer_bus_addr[
+ buffer_index]);
+
+ num_bytes = comedi_buf_read_n_available(dev->write_subdev->async);
+ if (num_bytes > DMA_BUFFER_SIZE)
+ num_bytes = DMA_BUFFER_SIZE;
+ if (cmd->stop_src == TRIG_COUNT && num_bytes > devpriv->ao_count)
+ num_bytes = devpriv->ao_count;
+ num_bytes -= num_bytes % bytes_in_sample;
+
+ if (num_bytes == 0)
+ return 0;
+
+ DEBUG_PRINT("loading %i bytes\n", num_bytes);
+
+ num_bytes = cfc_read_array_from_buffer(dev->write_subdev,
+ devpriv->
+ ao_buffer[buffer_index],
+ num_bytes);
+ devpriv->ao_dma_desc[buffer_index].transfer_size =
+ cpu_to_le32(num_bytes);
+ /* set end of chain bit so we catch underruns */
+ next_bits = le32_to_cpu(devpriv->ao_dma_desc[buffer_index].next);
+ next_bits |= PLX_END_OF_CHAIN_BIT;
+ devpriv->ao_dma_desc[buffer_index].next = cpu_to_le32(next_bits);
+ /* clear end of chain bit on previous buffer now that we have set it
+ * for the last buffer */
+ next_bits = le32_to_cpu(devpriv->ao_dma_desc[prev_buffer_index].next);
+ next_bits &= ~PLX_END_OF_CHAIN_BIT;
+ devpriv->ao_dma_desc[prev_buffer_index].next = cpu_to_le32(next_bits);
+
+ devpriv->ao_dma_index = (buffer_index + 1) % AO_DMA_RING_COUNT;
+ devpriv->ao_count -= num_bytes;
+
+ return num_bytes;
+}
+
+static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
+{
+ struct pcidas64_private *devpriv = dev->private;
+ unsigned int num_bytes;
+ unsigned int next_transfer_addr;
+ void __iomem *pci_addr_reg =
+ devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG;
+ unsigned int buffer_index;
+
+ do {
+ buffer_index = devpriv->ao_dma_index;
+ /* don't overwrite data that hasn't been transferred yet */
+ next_transfer_addr = readl(pci_addr_reg);
+ if (next_transfer_addr >=
+ devpriv->ao_buffer_bus_addr[buffer_index] &&
+ next_transfer_addr <
+ devpriv->ao_buffer_bus_addr[buffer_index] +
+ DMA_BUFFER_SIZE)
+ return;
+ num_bytes = load_ao_dma_buffer(dev, cmd);
+ } while (num_bytes >= DMA_BUFFER_SIZE);
+}
+
static void handle_ao_interrupt(struct comedi_device *dev,
unsigned short status, unsigned int plx_status)
{
+ struct pcidas64_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->write_subdev;
struct comedi_async *async;
struct comedi_cmd *cmd;
@@ -3060,15 +3053,15 @@ static void handle_ao_interrupt(struct comedi_device *dev,
/* spin lock makes sure no one else changes plx dma control reg */
spin_lock_irqsave(&dev->spinlock, flags);
- dma0_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);
+ dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */
- if ((dma0_status & PLX_DMA_EN_BIT)
- && !(dma0_status & PLX_DMA_DONE_BIT))
+ if ((dma0_status & PLX_DMA_EN_BIT) &&
+ !(dma0_status & PLX_DMA_DONE_BIT))
writeb(PLX_DMA_EN_BIT | PLX_CLEAR_DMA_INTR_BIT,
- priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);
+ devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
else
writeb(PLX_CLEAR_DMA_INTR_BIT,
- priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);
+ devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
DEBUG_PRINT("dma0 status 0x%x\n", dma0_status);
if (dma0_status & PLX_DMA_EN_BIT) {
@@ -3078,18 +3071,19 @@ static void handle_ao_interrupt(struct comedi_device *dev,
restart_ao_dma(dev);
}
DEBUG_PRINT(" cleared dma ch0 interrupt\n");
- } else
+ } else {
spin_unlock_irqrestore(&dev->spinlock, flags);
+ }
if ((status & DAC_DONE_BIT)) {
async->events |= COMEDI_CB_EOA;
if (ao_stopped_by_error(dev, cmd))
async->events |= COMEDI_CB_ERROR;
DEBUG_PRINT("plx dma0 desc reg 0x%x\n",
- readl(priv(dev)->plx9080_iobase +
+ readl(devpriv->plx9080_iobase +
PLX_DMA0_DESCRIPTOR_REG));
DEBUG_PRINT("plx dma0 address reg 0x%x\n",
- readl(priv(dev)->plx9080_iobase +
+ readl(devpriv->plx9080_iobase +
PLX_DMA0_PCI_ADDRESS_REG));
}
cfc_handle_events(dev, s);
@@ -3098,22 +3092,21 @@ static void handle_ao_interrupt(struct comedi_device *dev,
static irqreturn_t handle_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
+ struct pcidas64_private *devpriv = dev->private;
unsigned short status;
uint32_t plx_status;
uint32_t plx_bits;
- plx_status = readl(priv(dev)->plx9080_iobase + PLX_INTRCS_REG);
- status = readw(priv(dev)->main_iobase + HW_STATUS_REG);
+ plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG);
+ status = readw(devpriv->main_iobase + HW_STATUS_REG);
- DEBUG_PRINT("cb_pcidas64: hw status 0x%x ", status);
- DEBUG_PRINT("plx status 0x%x\n", plx_status);
+ DEBUG_PRINT("hw status 0x%x, plx status 0x%x\n", status, plx_status);
/* an interrupt before all the postconfig stuff gets done could
* cause a NULL dereference if we continue through the
* interrupt handler */
if (dev->attached == 0) {
- DEBUG_PRINT("cb_pcidas64: premature interrupt, ignoring",
- status);
+ DEBUG_PRINT("premature interrupt, ignoring\n");
return IRQ_HANDLED;
}
handle_ai_interrupt(dev, status, plx_status);
@@ -3121,8 +3114,8 @@ static irqreturn_t handle_interrupt(int irq, void *d)
/* clear possible plx9080 interrupt sources */
if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */
- plx_bits = readl(priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG);
- writel(plx_bits, priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG);
+ plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
+ writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits);
}
@@ -3131,28 +3124,17 @@ static irqreturn_t handle_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
-static void abort_dma(struct comedi_device *dev, unsigned int channel)
-{
- unsigned long flags;
-
- /* spinlock for plx dma control/status reg */
- spin_lock_irqsave(&dev->spinlock, flags);
-
- plx9080_abort_dma(priv(dev)->plx9080_iobase, channel);
-
- spin_unlock_irqrestore(&dev->spinlock, flags);
-}
-
static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned long flags;
spin_lock_irqsave(&dev->spinlock, flags);
- if (priv(dev)->ai_cmd_running == 0) {
+ if (devpriv->ai_cmd_running == 0) {
spin_unlock_irqrestore(&dev->spinlock, flags);
return 0;
}
- priv(dev)->ai_cmd_running = 0;
+ devpriv->ai_cmd_running = 0;
spin_unlock_irqrestore(&dev->spinlock, flags);
disable_ai_pacing(dev);
@@ -3166,29 +3148,31 @@ static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
int range = CR_RANGE(insn->chanspec);
/* do some initializing */
- writew(0, priv(dev)->main_iobase + DAC_CONTROL0_REG);
+ writew(0, devpriv->main_iobase + DAC_CONTROL0_REG);
/* set range */
- set_dac_range_bits(dev, &priv(dev)->dac_control1_bits, chan, range);
- writew(priv(dev)->dac_control1_bits,
- priv(dev)->main_iobase + DAC_CONTROL1_REG);
+ set_dac_range_bits(dev, &devpriv->dac_control1_bits, chan, range);
+ writew(devpriv->dac_control1_bits,
+ devpriv->main_iobase + DAC_CONTROL1_REG);
/* write to channel */
- if (board(dev)->layout == LAYOUT_4020) {
+ if (thisboard->layout == LAYOUT_4020) {
writew(data[0] & 0xff,
- priv(dev)->main_iobase + dac_lsb_4020_reg(chan));
+ devpriv->main_iobase + dac_lsb_4020_reg(chan));
writew((data[0] >> 8) & 0xf,
- priv(dev)->main_iobase + dac_msb_4020_reg(chan));
+ devpriv->main_iobase + dac_msb_4020_reg(chan));
} else {
- writew(data[0], priv(dev)->main_iobase + dac_convert_reg(chan));
+ writew(data[0], devpriv->main_iobase + dac_convert_reg(chan));
}
/* remember output value */
- priv(dev)->ao_value[chan] = data[0];
+ devpriv->ao_value[chan] = data[0];
return 1;
}
@@ -3197,7 +3181,9 @@ static int ao_readback_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- data[0] = priv(dev)->ao_value[CR_CHAN(insn->chanspec)];
+ struct pcidas64_private *devpriv = dev->private;
+
+ data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
return 1;
}
@@ -3205,8 +3191,9 @@ static int ao_readback_insn(struct comedi_device *dev,
static void set_dac_control0_reg(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int bits = DAC_ENABLE_BIT | WAVEFORM_GATE_LEVEL_BIT |
- WAVEFORM_GATE_ENABLE_BIT | WAVEFORM_GATE_SELECT_BIT;
+ WAVEFORM_GATE_ENABLE_BIT | WAVEFORM_GATE_SELECT_BIT;
if (cmd->start_src == TRIG_EXT) {
bits |= WAVEFORM_TRIG_EXT_BITS;
@@ -3220,12 +3207,13 @@ static void set_dac_control0_reg(struct comedi_device *dev,
if (cmd->scan_begin_arg & CR_INVERT)
bits |= DAC_EXT_UPDATE_FALLING_BIT;
}
- writew(bits, priv(dev)->main_iobase + DAC_CONTROL0_REG);
+ writew(bits, devpriv->main_iobase + DAC_CONTROL0_REG);
}
static void set_dac_control1_reg(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
int i;
for (i = 0; i < cmd->chanlist_len; i++) {
@@ -3233,17 +3221,18 @@ static void set_dac_control1_reg(struct comedi_device *dev,
channel = CR_CHAN(cmd->chanlist[i]);
range = CR_RANGE(cmd->chanlist[i]);
- set_dac_range_bits(dev, &priv(dev)->dac_control1_bits, channel,
+ set_dac_range_bits(dev, &devpriv->dac_control1_bits, channel,
range);
}
- priv(dev)->dac_control1_bits |= DAC_SW_GATE_BIT;
- writew(priv(dev)->dac_control1_bits,
- priv(dev)->main_iobase + DAC_CONTROL1_REG);
+ devpriv->dac_control1_bits |= DAC_SW_GATE_BIT;
+ writew(devpriv->dac_control1_bits,
+ devpriv->main_iobase + DAC_CONTROL1_REG);
}
static void set_dac_select_reg(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
uint16_t bits;
unsigned int first_channel, last_channel;
@@ -3254,12 +3243,18 @@ static void set_dac_select_reg(struct comedi_device *dev,
bits = (first_channel & 0x7) | (last_channel & 0x7) << 3;
- writew(bits, priv(dev)->main_iobase + DAC_SELECT_REG);
+ writew(bits, devpriv->main_iobase + DAC_SELECT_REG);
+}
+
+static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags)
+{
+ return get_divisor(ns, flags) - 2;
}
static void set_dac_interval_regs(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int divisor;
if (cmd->scan_begin_src != TRIG_TIMER)
@@ -3271,102 +3266,35 @@ static void set_dac_interval_regs(struct comedi_device *dev,
divisor = max_counter_value;
}
writew(divisor & 0xffff,
- priv(dev)->main_iobase + DAC_SAMPLE_INTERVAL_LOWER_REG);
+ devpriv->main_iobase + DAC_SAMPLE_INTERVAL_LOWER_REG);
writew((divisor >> 16) & 0xff,
- priv(dev)->main_iobase + DAC_SAMPLE_INTERVAL_UPPER_REG);
-}
-
-static unsigned int load_ao_dma_buffer(struct comedi_device *dev,
- const struct comedi_cmd *cmd)
-{
- unsigned int num_bytes, buffer_index, prev_buffer_index;
- unsigned int next_bits;
-
- buffer_index = priv(dev)->ao_dma_index;
- prev_buffer_index = prev_ao_dma_index(dev);
-
- DEBUG_PRINT("attempting to load ao buffer %i (0x%x)\n", buffer_index,
- priv(dev)->ao_buffer_bus_addr[buffer_index]);
-
- num_bytes = comedi_buf_read_n_available(dev->write_subdev->async);
- if (num_bytes > DMA_BUFFER_SIZE)
- num_bytes = DMA_BUFFER_SIZE;
- if (cmd->stop_src == TRIG_COUNT && num_bytes > priv(dev)->ao_count)
- num_bytes = priv(dev)->ao_count;
- num_bytes -= num_bytes % bytes_in_sample;
-
- if (num_bytes == 0)
- return 0;
-
- DEBUG_PRINT("loading %i bytes\n", num_bytes);
-
- num_bytes = cfc_read_array_from_buffer(dev->write_subdev,
- priv(dev)->
- ao_buffer[buffer_index],
- num_bytes);
- priv(dev)->ao_dma_desc[buffer_index].transfer_size =
- cpu_to_le32(num_bytes);
- /* set end of chain bit so we catch underruns */
- next_bits = le32_to_cpu(priv(dev)->ao_dma_desc[buffer_index].next);
- next_bits |= PLX_END_OF_CHAIN_BIT;
- priv(dev)->ao_dma_desc[buffer_index].next = cpu_to_le32(next_bits);
- /* clear end of chain bit on previous buffer now that we have set it
- * for the last buffer */
- next_bits = le32_to_cpu(priv(dev)->ao_dma_desc[prev_buffer_index].next);
- next_bits &= ~PLX_END_OF_CHAIN_BIT;
- priv(dev)->ao_dma_desc[prev_buffer_index].next = cpu_to_le32(next_bits);
-
- priv(dev)->ao_dma_index = (buffer_index + 1) % AO_DMA_RING_COUNT;
- priv(dev)->ao_count -= num_bytes;
-
- return num_bytes;
-}
-
-static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
-{
- unsigned int num_bytes;
- unsigned int next_transfer_addr;
- void __iomem *pci_addr_reg =
- priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG;
- unsigned int buffer_index;
-
- do {
- buffer_index = priv(dev)->ao_dma_index;
- /* don't overwrite data that hasn't been transferred yet */
- next_transfer_addr = readl(pci_addr_reg);
- if (next_transfer_addr >=
- priv(dev)->ao_buffer_bus_addr[buffer_index]
- && next_transfer_addr <
- priv(dev)->ao_buffer_bus_addr[buffer_index] +
- DMA_BUFFER_SIZE)
- return;
- num_bytes = load_ao_dma_buffer(dev, cmd);
- } while (num_bytes >= DMA_BUFFER_SIZE);
+ devpriv->main_iobase + DAC_SAMPLE_INTERVAL_UPPER_REG);
}
static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int num_bytes;
int i;
/* clear queue pointer too, since external queue has
* weird interactions with ao fifo */
- writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG);
- writew(0, priv(dev)->main_iobase + DAC_BUFFER_CLEAR_REG);
+ writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG);
+ writew(0, devpriv->main_iobase + DAC_BUFFER_CLEAR_REG);
num_bytes = (DAC_FIFO_SIZE / 2) * bytes_in_sample;
if (cmd->stop_src == TRIG_COUNT &&
- num_bytes / bytes_in_sample > priv(dev)->ao_count)
- num_bytes = priv(dev)->ao_count * bytes_in_sample;
+ num_bytes / bytes_in_sample > devpriv->ao_count)
+ num_bytes = devpriv->ao_count * bytes_in_sample;
num_bytes = cfc_read_array_from_buffer(dev->write_subdev,
- priv(dev)->ao_bounce_buffer,
+ devpriv->ao_bounce_buffer,
num_bytes);
for (i = 0; i < num_bytes / bytes_in_sample; i++) {
- writew(priv(dev)->ao_bounce_buffer[i],
- priv(dev)->main_iobase + DAC_FIFO_REG);
+ writew(devpriv->ao_bounce_buffer[i],
+ devpriv->main_iobase + DAC_FIFO_REG);
}
- priv(dev)->ao_count -= num_bytes / bytes_in_sample;
- if (cmd->stop_src == TRIG_COUNT && priv(dev)->ao_count == 0)
+ devpriv->ao_count -= num_bytes / bytes_in_sample;
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count == 0)
return 0;
num_bytes = load_ao_dma_buffer(dev, cmd);
if (num_bytes == 0)
@@ -3381,43 +3309,21 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
static inline int external_ai_queue_in_use(struct comedi_device *dev)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+
if (dev->read_subdev->busy)
return 0;
- if (board(dev)->layout == LAYOUT_4020)
+ if (thisboard->layout == LAYOUT_4020)
return 0;
else if (use_internal_queue_6xxx(&dev->read_subdev->async->cmd))
return 0;
return 1;
}
-static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- struct comedi_cmd *cmd = &s->async->cmd;
-
- if (external_ai_queue_in_use(dev)) {
- warn_external_queue(dev);
- return -EBUSY;
- }
- /* disable analog output system during setup */
- writew(0x0, priv(dev)->main_iobase + DAC_CONTROL0_REG);
-
- priv(dev)->ao_dma_index = 0;
- priv(dev)->ao_count = cmd->stop_arg * cmd->chanlist_len;
-
- set_dac_select_reg(dev, cmd);
- set_dac_interval_regs(dev, cmd);
- load_first_dma_descriptor(dev, 0, priv(dev)->ao_dma_desc_bus_addr |
- PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT);
-
- set_dac_control1_reg(dev, cmd);
- s->async->inttrig = ao_inttrig;
-
- return 0;
-}
-
static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int trig_num)
{
+ struct pcidas64_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int retval;
@@ -3431,16 +3337,43 @@ static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
set_dac_control0_reg(dev, cmd);
if (cmd->start_src == TRIG_INT)
- writew(0, priv(dev)->main_iobase + DAC_START_REG);
+ writew(0, devpriv->main_iobase + DAC_START_REG);
s->async->inttrig = NULL;
return 0;
}
+static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ struct pcidas64_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ if (external_ai_queue_in_use(dev)) {
+ warn_external_queue(dev);
+ return -EBUSY;
+ }
+ /* disable analog output system during setup */
+ writew(0x0, devpriv->main_iobase + DAC_CONTROL0_REG);
+
+ devpriv->ao_dma_index = 0;
+ devpriv->ao_count = cmd->stop_arg * cmd->chanlist_len;
+
+ set_dac_select_reg(dev, cmd);
+ set_dac_interval_regs(dev, cmd);
+ load_first_dma_descriptor(dev, 0, devpriv->ao_dma_desc_bus_addr |
+ PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT);
+
+ set_dac_control1_reg(dev, cmd);
+ s->async->inttrig = ao_inttrig;
+
+ return 0;
+}
+
static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
int err = 0;
unsigned int tmp_arg;
int i;
@@ -3449,7 +3382,7 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->scan_begin_src,
- TRIG_TIMER | TRIG_EXT);
+ TRIG_TIMER | TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
@@ -3473,29 +3406,21 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (err)
return 2;
- /* step 3: make sure arguments are trivially compatible */
+ /* Step 3: check if arguments are trivially valid */
if (cmd->scan_begin_src == TRIG_TIMER) {
- if (cmd->scan_begin_arg < board(dev)->ao_scan_speed) {
- cmd->scan_begin_arg = board(dev)->ao_scan_speed;
- err++;
- }
- if (get_ao_divisor(cmd->scan_begin_arg,
- cmd->flags) > max_counter_value) {
- cmd->scan_begin_arg =
- (max_counter_value + 2) * TIMER_BASE;
- err++;
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ thisboard->ao_scan_speed);
+ if (get_ao_divisor(cmd->scan_begin_arg, cmd->flags) >
+ max_counter_value) {
+ cmd->scan_begin_arg = (max_counter_value + 2) *
+ TIMER_BASE;
+ err |= -EINVAL;
}
}
- if (!cmd->chanlist_len) {
- cmd->chanlist_len = 1;
- err++;
- }
- if (cmd->scan_end_arg != cmd->chanlist_len) {
- cmd->scan_end_arg = cmd->chanlist_len;
- err++;
- }
+ err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
if (err)
return 3;
@@ -3504,8 +3429,8 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (cmd->scan_begin_src == TRIG_TIMER) {
tmp_arg = cmd->scan_begin_arg;
- cmd->scan_begin_arg =
- get_divisor(cmd->scan_begin_arg, cmd->flags) * TIMER_BASE;
+ cmd->scan_begin_arg = get_divisor(cmd->scan_begin_arg,
+ cmd->flags) * TIMER_BASE;
if (tmp_arg != cmd->scan_begin_arg)
err++;
}
@@ -3533,7 +3458,9 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
- writew(0x0, priv(dev)->main_iobase + DAC_CONTROL0_REG);
+ struct pcidas64_private *devpriv = dev->private;
+
+ writew(0x0, devpriv->main_iobase + DAC_CONTROL0_REG);
abort_dma(dev, 0);
return 0;
}
@@ -3564,9 +3491,10 @@ static int dio_callback_4020(int dir, int port, int data, unsigned long arg)
static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int bits;
- bits = readb(priv(dev)->dio_counter_iobase + DI_REG);
+ bits = readb(devpriv->dio_counter_iobase + DI_REG);
bits &= 0xf;
data[1] = bits;
data[0] = 0;
@@ -3577,13 +3505,15 @@ static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
+
data[0] &= 0xf;
/* zero bits we are going to change */
s->state &= ~data[0];
/* set new bits */
s->state |= data[0] & data[1];
- writeb(s->state, priv(dev)->dio_counter_iobase + DO_REG);
+ writeb(s->state, devpriv->dio_counter_iobase + DO_REG);
data[1] = s->state;
@@ -3594,6 +3524,7 @@ static int dio_60xx_config_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int mask;
mask = 1 << CR_CHAN(insn->chanspec);
@@ -3613,7 +3544,7 @@ static int dio_60xx_config_insn(struct comedi_device *dev,
}
writeb(s->io_bits,
- priv(dev)->dio_counter_iobase + DIO_DIRECTION_60XX_REG);
+ devpriv->dio_counter_iobase + DIO_DIRECTION_60XX_REG);
return 1;
}
@@ -3621,24 +3552,143 @@ static int dio_60xx_config_insn(struct comedi_device *dev,
static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
+
if (data[0]) {
s->state &= ~data[0];
s->state |= (data[0] & data[1]);
writeb(s->state,
- priv(dev)->dio_counter_iobase + DIO_DATA_60XX_REG);
+ devpriv->dio_counter_iobase + DIO_DATA_60XX_REG);
}
- data[1] = readb(priv(dev)->dio_counter_iobase + DIO_DATA_60XX_REG);
+ data[1] = readb(devpriv->dio_counter_iobase + DIO_DATA_60XX_REG);
return insn->n;
}
+/* pci-6025 8800 caldac:
+ * address 0 == dac channel 0 offset
+ * address 1 == dac channel 0 gain
+ * address 2 == dac channel 1 offset
+ * address 3 == dac channel 1 gain
+ * address 4 == fine adc offset
+ * address 5 == coarse adc offset
+ * address 6 == coarse adc gain
+ * address 7 == fine adc gain
+ */
+/* pci-6402/16 uses all 8 channels for dac:
+ * address 0 == dac channel 0 fine gain
+ * address 1 == dac channel 0 coarse gain
+ * address 2 == dac channel 0 coarse offset
+ * address 3 == dac channel 1 coarse offset
+ * address 4 == dac channel 1 fine gain
+ * address 5 == dac channel 1 coarse gain
+ * address 6 == dac channel 0 fine offset
+ * address 7 == dac channel 1 fine offset
+*/
+
+static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
+ uint8_t value)
+{
+ struct pcidas64_private *devpriv = dev->private;
+ static const int num_caldac_channels = 8;
+ static const int bitstream_length = 11;
+ unsigned int bitstream = ((address & 0x7) << 8) | value;
+ unsigned int bit, register_bits;
+ static const int caldac_8800_udelay = 1;
+
+ if (address >= num_caldac_channels) {
+ comedi_error(dev, "illegal caldac channel");
+ return -1;
+ }
+ for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
+ register_bits = 0;
+ if (bitstream & bit)
+ register_bits |= SERIAL_DATA_IN_BIT;
+ udelay(caldac_8800_udelay);
+ writew(register_bits, devpriv->main_iobase + CALIBRATION_REG);
+ register_bits |= SERIAL_CLOCK_BIT;
+ udelay(caldac_8800_udelay);
+ writew(register_bits, devpriv->main_iobase + CALIBRATION_REG);
+ }
+ udelay(caldac_8800_udelay);
+ writew(SELECT_8800_BIT, devpriv->main_iobase + CALIBRATION_REG);
+ udelay(caldac_8800_udelay);
+ writew(0, devpriv->main_iobase + CALIBRATION_REG);
+ udelay(caldac_8800_udelay);
+ return 0;
+}
+
+/* 4020 caldacs */
+static int caldac_i2c_write(struct comedi_device *dev,
+ unsigned int caldac_channel, unsigned int value)
+{
+ uint8_t serial_bytes[3];
+ uint8_t i2c_addr;
+ enum pointer_bits {
+ /* manual has gain and offset bits switched */
+ OFFSET_0_2 = 0x1,
+ GAIN_0_2 = 0x2,
+ OFFSET_1_3 = 0x4,
+ GAIN_1_3 = 0x8,
+ };
+ enum data_bits {
+ NOT_CLEAR_REGISTERS = 0x20,
+ };
+
+ switch (caldac_channel) {
+ case 0: /* chan 0 offset */
+ i2c_addr = CALDAC0_I2C_ADDR;
+ serial_bytes[0] = OFFSET_0_2;
+ break;
+ case 1: /* chan 1 offset */
+ i2c_addr = CALDAC0_I2C_ADDR;
+ serial_bytes[0] = OFFSET_1_3;
+ break;
+ case 2: /* chan 2 offset */
+ i2c_addr = CALDAC1_I2C_ADDR;
+ serial_bytes[0] = OFFSET_0_2;
+ break;
+ case 3: /* chan 3 offset */
+ i2c_addr = CALDAC1_I2C_ADDR;
+ serial_bytes[0] = OFFSET_1_3;
+ break;
+ case 4: /* chan 0 gain */
+ i2c_addr = CALDAC0_I2C_ADDR;
+ serial_bytes[0] = GAIN_0_2;
+ break;
+ case 5: /* chan 1 gain */
+ i2c_addr = CALDAC0_I2C_ADDR;
+ serial_bytes[0] = GAIN_1_3;
+ break;
+ case 6: /* chan 2 gain */
+ i2c_addr = CALDAC1_I2C_ADDR;
+ serial_bytes[0] = GAIN_0_2;
+ break;
+ case 7: /* chan 3 gain */
+ i2c_addr = CALDAC1_I2C_ADDR;
+ serial_bytes[0] = GAIN_1_3;
+ break;
+ default:
+ comedi_error(dev, "invalid caldac channel\n");
+ return -1;
+ break;
+ }
+ serial_bytes[1] = NOT_CLEAR_REGISTERS | ((value >> 8) & 0xf);
+ serial_bytes[2] = value & 0xff;
+ i2c_write(dev, i2c_addr, serial_bytes, 3);
+ return 0;
+}
+
static void caldac_write(struct comedi_device *dev, unsigned int channel,
unsigned int value)
{
- priv(dev)->caldac_state[channel] = value;
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
+
+ devpriv->caldac_state[channel] = value;
- switch (board(dev)->layout) {
+ switch (thisboard->layout) {
case LAYOUT_60XX:
case LAYOUT_64XX:
caldac_8800_write(dev, channel, value);
@@ -3655,11 +3705,12 @@ static int calib_write_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
int channel = CR_CHAN(insn->chanspec);
/* return immediately if setting hasn't changed, since
* programming these things is slow */
- if (priv(dev)->caldac_state[channel] == data[0])
+ if (devpriv->caldac_state[channel] == data[0])
return 1;
caldac_write(dev, channel, data[0]);
@@ -3671,9 +3722,10 @@ static int calib_read_insn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int channel = CR_CHAN(insn->chanspec);
- data[0] = priv(dev)->caldac_state[channel];
+ data[0] = devpriv->caldac_state[channel];
return 1;
}
@@ -3681,16 +3733,17 @@ static int calib_read_insn(struct comedi_device *dev,
static void ad8402_write(struct comedi_device *dev, unsigned int channel,
unsigned int value)
{
+ struct pcidas64_private *devpriv = dev->private;
static const int bitstream_length = 10;
unsigned int bit, register_bits;
unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff);
static const int ad8402_udelay = 1;
- priv(dev)->ad8402_state[channel] = value;
+ devpriv->ad8402_state[channel] = value;
register_bits = SELECT_8402_64XX_BIT;
udelay(ad8402_udelay);
- writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG);
+ writew(register_bits, devpriv->main_iobase + CALIBRATION_REG);
for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
if (bitstream & bit)
@@ -3698,14 +3751,14 @@ static void ad8402_write(struct comedi_device *dev, unsigned int channel,
else
register_bits &= ~SERIAL_DATA_IN_BIT;
udelay(ad8402_udelay);
- writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG);
+ writew(register_bits, devpriv->main_iobase + CALIBRATION_REG);
udelay(ad8402_udelay);
writew(register_bits | SERIAL_CLOCK_BIT,
- priv(dev)->main_iobase + CALIBRATION_REG);
+ devpriv->main_iobase + CALIBRATION_REG);
}
udelay(ad8402_udelay);
- writew(0, priv(dev)->main_iobase + CALIBRATION_REG);
+ writew(0, devpriv->main_iobase + CALIBRATION_REG);
}
/* for pci-das6402/16, channel 0 is analog input gain and channel 1 is offset */
@@ -3713,14 +3766,15 @@ static int ad8402_write_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
int channel = CR_CHAN(insn->chanspec);
/* return immediately if setting hasn't changed, since
* programming these things is slow */
- if (priv(dev)->ad8402_state[channel] == data[0])
+ if (devpriv->ad8402_state[channel] == data[0])
return 1;
- priv(dev)->ad8402_state[channel] = data[0];
+ devpriv->ad8402_state[channel] = data[0];
ad8402_write(dev, channel, data[0]);
@@ -3731,62 +3785,64 @@ static int ad8402_read_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct pcidas64_private *devpriv = dev->private;
unsigned int channel = CR_CHAN(insn->chanspec);
- data[0] = priv(dev)->ad8402_state[channel];
+ data[0] = devpriv->ad8402_state[channel];
return 1;
}
static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address)
{
+ struct pcidas64_private *devpriv = dev->private;
static const int bitstream_length = 11;
static const int read_command = 0x6;
unsigned int bitstream = (read_command << 8) | address;
unsigned int bit;
void __iomem * const plx_control_addr =
- priv(dev)->plx9080_iobase + PLX_CONTROL_REG;
+ devpriv->plx9080_iobase + PLX_CONTROL_REG;
uint16_t value;
static const int value_length = 16;
static const int eeprom_udelay = 1;
udelay(eeprom_udelay);
- priv(dev)->plx_control_bits &= ~CTL_EE_CLK & ~CTL_EE_CS;
+ devpriv->plx_control_bits &= ~CTL_EE_CLK & ~CTL_EE_CS;
/* make sure we don't send anything to the i2c bus on 4020 */
- priv(dev)->plx_control_bits |= CTL_USERO;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
+ devpriv->plx_control_bits |= CTL_USERO;
+ writel(devpriv->plx_control_bits, plx_control_addr);
/* activate serial eeprom */
udelay(eeprom_udelay);
- priv(dev)->plx_control_bits |= CTL_EE_CS;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
+ devpriv->plx_control_bits |= CTL_EE_CS;
+ writel(devpriv->plx_control_bits, plx_control_addr);
/* write read command and desired memory address */
for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
/* set bit to be written */
udelay(eeprom_udelay);
if (bitstream & bit)
- priv(dev)->plx_control_bits |= CTL_EE_W;
+ devpriv->plx_control_bits |= CTL_EE_W;
else
- priv(dev)->plx_control_bits &= ~CTL_EE_W;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
+ devpriv->plx_control_bits &= ~CTL_EE_W;
+ writel(devpriv->plx_control_bits, plx_control_addr);
/* clock in bit */
udelay(eeprom_udelay);
- priv(dev)->plx_control_bits |= CTL_EE_CLK;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
+ devpriv->plx_control_bits |= CTL_EE_CLK;
+ writel(devpriv->plx_control_bits, plx_control_addr);
udelay(eeprom_udelay);
- priv(dev)->plx_control_bits &= ~CTL_EE_CLK;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
+ devpriv->plx_control_bits &= ~CTL_EE_CLK;
+ writel(devpriv->plx_control_bits, plx_control_addr);
}
/* read back value from eeprom memory location */
value = 0;
for (bit = 1 << (value_length - 1); bit; bit >>= 1) {
/* clock out bit */
udelay(eeprom_udelay);
- priv(dev)->plx_control_bits |= CTL_EE_CLK;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
+ devpriv->plx_control_bits |= CTL_EE_CLK;
+ writel(devpriv->plx_control_bits, plx_control_addr);
udelay(eeprom_udelay);
- priv(dev)->plx_control_bits &= ~CTL_EE_CLK;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
+ devpriv->plx_control_bits &= ~CTL_EE_CLK;
+ writel(devpriv->plx_control_bits, plx_control_addr);
udelay(eeprom_udelay);
if (readl(plx_control_addr) & CTL_EE_R)
value |= bit;
@@ -3794,8 +3850,8 @@ static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address)
/* deactivate eeprom serial input */
udelay(eeprom_udelay);
- priv(dev)->plx_control_bits &= ~CTL_EE_CS;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
+ devpriv->plx_control_bits &= ~CTL_EE_CS;
+ writel(devpriv->plx_control_bits, plx_control_addr);
return value;
}
@@ -3809,419 +3865,386 @@ static int eeprom_read_insn(struct comedi_device *dev,
return 1;
}
-/* utility function that rounds desired timing to an achievable time, and
- * sets cmd members appropriately.
- * adc paces conversions from master clock by dividing by (x + 3) where x is 24 bit number
+/* Allocate and initialize the subdevice structures.
*/
-static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
+static int setup_subdevices(struct comedi_device *dev)
{
- unsigned int convert_divisor = 0, scan_divisor;
- static const int min_convert_divisor = 3;
- static const int max_convert_divisor =
- max_counter_value + min_convert_divisor;
- static const int min_scan_divisor_4020 = 2;
- unsigned long long max_scan_divisor, min_scan_divisor;
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
+ struct comedi_subdevice *s;
+ void __iomem *dio_8255_iobase;
+ int i;
+ int ret;
- if (cmd->convert_src == TRIG_TIMER) {
- if (board(dev)->layout == LAYOUT_4020) {
- cmd->convert_arg = 0;
- } else {
- convert_divisor =
- get_divisor(cmd->convert_arg, cmd->flags);
- if (convert_divisor > max_convert_divisor)
- convert_divisor = max_convert_divisor;
- if (convert_divisor < min_convert_divisor)
- convert_divisor = min_convert_divisor;
- cmd->convert_arg = convert_divisor * TIMER_BASE;
- }
- } else if (cmd->convert_src == TRIG_NOW)
- cmd->convert_arg = 0;
+ ret = comedi_alloc_subdevices(dev, 10);
+ if (ret)
+ return ret;
- if (cmd->scan_begin_src == TRIG_TIMER) {
- scan_divisor = get_divisor(cmd->scan_begin_arg, cmd->flags);
- if (cmd->convert_src == TRIG_TIMER) {
- /* XXX check for integer overflows */
- min_scan_divisor = convert_divisor * cmd->chanlist_len;
- max_scan_divisor =
- (convert_divisor * cmd->chanlist_len - 1) +
- max_counter_value;
- } else {
- min_scan_divisor = min_scan_divisor_4020;
- max_scan_divisor = max_counter_value + min_scan_divisor;
- }
- if (scan_divisor > max_scan_divisor)
- scan_divisor = max_scan_divisor;
- if (scan_divisor < min_scan_divisor)
- scan_divisor = min_scan_divisor;
- cmd->scan_begin_arg = scan_divisor * TIMER_BASE;
+ s = &dev->subdevices[0];
+ /* analog input subdevice */
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DITHER | SDF_CMD_READ;
+ if (thisboard->layout == LAYOUT_60XX)
+ s->subdev_flags |= SDF_COMMON | SDF_DIFF;
+ else if (thisboard->layout == LAYOUT_64XX)
+ s->subdev_flags |= SDF_DIFF;
+ /* XXX Number of inputs in differential mode is ignored */
+ s->n_chan = thisboard->ai_se_chans;
+ s->len_chanlist = 0x2000;
+ s->maxdata = (1 << thisboard->ai_bits) - 1;
+ s->range_table = thisboard->ai_range_table;
+ s->insn_read = ai_rinsn;
+ s->insn_config = ai_config_insn;
+ s->do_cmd = ai_cmd;
+ s->do_cmdtest = ai_cmdtest;
+ s->cancel = ai_cancel;
+ if (thisboard->layout == LAYOUT_4020) {
+ uint8_t data;
+ /* set adc to read from inputs
+ * (not internal calibration sources) */
+ devpriv->i2c_cal_range_bits = adc_src_4020_bits(4);
+ /* set channels to +-5 volt input ranges */
+ for (i = 0; i < s->n_chan; i++)
+ devpriv->i2c_cal_range_bits |= attenuate_bit(i);
+ data = devpriv->i2c_cal_range_bits;
+ i2c_write(dev, RANGE_CAL_I2C_ADDR, &data, sizeof(data));
}
- return;
-}
-
-/* Gets nearest achievable timing given master clock speed, does not
- * take into account possible minimum/maximum divisor values. Used
- * by other timing checking functions. */
-static unsigned int get_divisor(unsigned int ns, unsigned int flags)
-{
- unsigned int divisor;
-
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_UP:
- divisor = (ns + TIMER_BASE - 1) / TIMER_BASE;
- break;
- case TRIG_ROUND_DOWN:
- divisor = ns / TIMER_BASE;
- break;
- case TRIG_ROUND_NEAREST:
- default:
- divisor = (ns + TIMER_BASE / 2) / TIMER_BASE;
- break;
+ /* analog output subdevice */
+ s = &dev->subdevices[1];
+ if (thisboard->ao_nchan) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE |
+ SDF_GROUND | SDF_CMD_WRITE;
+ s->n_chan = thisboard->ao_nchan;
+ s->maxdata = (1 << thisboard->ao_bits) - 1;
+ s->range_table = thisboard->ao_range_table;
+ s->insn_read = ao_readback_insn;
+ s->insn_write = ao_winsn;
+ if (ao_cmd_is_supported(thisboard)) {
+ dev->write_subdev = s;
+ s->do_cmdtest = ao_cmdtest;
+ s->do_cmd = ao_cmd;
+ s->len_chanlist = thisboard->ao_nchan;
+ s->cancel = ao_cancel;
+ }
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
}
- return divisor;
-}
-static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags)
-{
- return get_divisor(ns, flags) - 2;
-}
+ /* digital input */
+ s = &dev->subdevices[2];
+ if (thisboard->layout == LAYOUT_64XX) {
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = di_rbits;
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
-/* adjusts the size of hardware fifo (which determines block size for dma xfers) */
-static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples)
-{
- unsigned int num_fifo_entries;
- int retval;
- const struct hw_fifo_info *const fifo = board(dev)->ai_fifo;
+ /* digital output */
+ if (thisboard->layout == LAYOUT_64XX) {
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = do_wbits;
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
- num_fifo_entries = num_samples / fifo->sample_packing_ratio;
+ /* 8255 */
+ s = &dev->subdevices[4];
+ if (thisboard->has_8255) {
+ if (thisboard->layout == LAYOUT_4020) {
+ dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG;
+ subdev_8255_init(dev, s, dio_callback_4020,
+ (unsigned long)dio_8255_iobase);
+ } else {
+ dio_8255_iobase =
+ devpriv->dio_counter_iobase + DIO_8255_OFFSET;
+ subdev_8255_init(dev, s, dio_callback,
+ (unsigned long)dio_8255_iobase);
+ }
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
- retval = set_ai_fifo_segment_length(dev,
- num_fifo_entries /
- fifo->num_segments);
- if (retval < 0)
- return retval;
+ /* 8 channel dio for 60xx */
+ s = &dev->subdevices[5];
+ if (thisboard->layout == LAYOUT_60XX) {
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_config = dio_60xx_config_insn;
+ s->insn_bits = dio_60xx_wbits;
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
- num_samples = retval * fifo->num_segments * fifo->sample_packing_ratio;
+ /* caldac */
+ s = &dev->subdevices[6];
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 8;
+ if (thisboard->layout == LAYOUT_4020)
+ s->maxdata = 0xfff;
+ else
+ s->maxdata = 0xff;
+ s->insn_read = calib_read_insn;
+ s->insn_write = calib_write_insn;
+ for (i = 0; i < s->n_chan; i++)
+ caldac_write(dev, i, s->maxdata / 2);
- DEBUG_PRINT("set hardware fifo size to %i\n", num_samples);
+ /* 2 channel ad8402 potentiometer */
+ s = &dev->subdevices[7];
+ if (thisboard->layout == LAYOUT_64XX) {
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 2;
+ s->insn_read = ad8402_read_insn;
+ s->insn_write = ad8402_write_insn;
+ s->maxdata = 0xff;
+ for (i = 0; i < s->n_chan; i++)
+ ad8402_write(dev, i, s->maxdata / 2);
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
- return num_samples;
-}
+ /* serial EEPROM, if present */
+ s = &dev->subdevices[8];
+ if (readl(devpriv->plx9080_iobase + PLX_CONTROL_REG) & CTL_EECHK) {
+ s->type = COMEDI_SUBD_MEMORY;
+ s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
+ s->n_chan = 128;
+ s->maxdata = 0xffff;
+ s->insn_read = eeprom_read_insn;
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
-/* query length of fifo */
-static unsigned int ai_fifo_size(struct comedi_device *dev)
-{
- return priv(dev)->ai_fifo_segment_length *
- board(dev)->ai_fifo->num_segments *
- board(dev)->ai_fifo->sample_packing_ratio;
+ /* user counter subd XXX */
+ s = &dev->subdevices[9];
+ s->type = COMEDI_SUBD_UNUSED;
+
+ return 0;
}
-static int set_ai_fifo_segment_length(struct comedi_device *dev,
- unsigned int num_entries)
+static const struct pcidas64_board
+*cb_pcidas64_find_pci_board(struct pci_dev *pcidev)
{
- static const int increment_size = 0x100;
- const struct hw_fifo_info *const fifo = board(dev)->ai_fifo;
- unsigned int num_increments;
- uint16_t bits;
-
- if (num_entries < increment_size)
- num_entries = increment_size;
- if (num_entries > fifo->max_segment_length)
- num_entries = fifo->max_segment_length;
-
- /* 1 == 256 entries, 2 == 512 entries, etc */
- num_increments = (num_entries + increment_size / 2) / increment_size;
-
- bits = (~(num_increments - 1)) & fifo->fifo_size_reg_mask;
- priv(dev)->fifo_size_bits &= ~fifo->fifo_size_reg_mask;
- priv(dev)->fifo_size_bits |= bits;
- writew(priv(dev)->fifo_size_bits,
- priv(dev)->main_iobase + FIFO_SIZE_REG);
-
- priv(dev)->ai_fifo_segment_length = num_increments * increment_size;
-
- DEBUG_PRINT("set hardware fifo segment length to %i\n",
- priv(dev)->ai_fifo_segment_length);
+ unsigned int i;
- return priv(dev)->ai_fifo_segment_length;
+ for (i = 0; i < ARRAY_SIZE(pcidas64_boards); i++)
+ if (pcidev->device == pcidas64_boards[i].device_id)
+ return &pcidas64_boards[i];
+ return NULL;
}
-/* pci-6025 8800 caldac:
- * address 0 == dac channel 0 offset
- * address 1 == dac channel 0 gain
- * address 2 == dac channel 1 offset
- * address 3 == dac channel 1 gain
- * address 4 == fine adc offset
- * address 5 == coarse adc offset
- * address 6 == coarse adc gain
- * address 7 == fine adc gain
- */
-/* pci-6402/16 uses all 8 channels for dac:
- * address 0 == dac channel 0 fine gain
- * address 1 == dac channel 0 coarse gain
- * address 2 == dac channel 0 coarse offset
- * address 3 == dac channel 1 coarse offset
- * address 4 == dac channel 1 fine gain
- * address 5 == dac channel 1 coarse gain
- * address 6 == dac channel 0 fine offset
- * address 7 == dac channel 1 fine offset
-*/
-
-static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
- uint8_t value)
+static int auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
{
- static const int num_caldac_channels = 8;
- static const int bitstream_length = 11;
- unsigned int bitstream = ((address & 0x7) << 8) | value;
- unsigned int bit, register_bits;
- static const int caldac_8800_udelay = 1;
+ const struct pcidas64_board *thisboard;
+ struct pcidas64_private *devpriv;
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ uint32_t local_range, local_decode;
+ int retval;
- if (address >= num_caldac_channels) {
- comedi_error(dev, "illegal caldac channel");
- return -1;
- }
- for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
- register_bits = 0;
- if (bitstream & bit)
- register_bits |= SERIAL_DATA_IN_BIT;
- udelay(caldac_8800_udelay);
- writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG);
- register_bits |= SERIAL_CLOCK_BIT;
- udelay(caldac_8800_udelay);
- writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG);
+ dev->board_ptr = cb_pcidas64_find_pci_board(pcidev);
+ if (!dev->board_ptr) {
+ dev_err(dev->class_dev,
+ "cb_pcidas64: does not support pci %s\n",
+ pci_name(pcidev));
+ return -EINVAL;
}
- udelay(caldac_8800_udelay);
- writew(SELECT_8800_BIT, priv(dev)->main_iobase + CALIBRATION_REG);
- udelay(caldac_8800_udelay);
- writew(0, priv(dev)->main_iobase + CALIBRATION_REG);
- udelay(caldac_8800_udelay);
- return 0;
-}
+ thisboard = comedi_board(dev);
-/* 4020 caldacs */
-static int caldac_i2c_write(struct comedi_device *dev,
- unsigned int caldac_channel, unsigned int value)
-{
- uint8_t serial_bytes[3];
- uint8_t i2c_addr;
- enum pointer_bits {
- /* manual has gain and offset bits switched */
- OFFSET_0_2 = 0x1,
- GAIN_0_2 = 0x2,
- OFFSET_1_3 = 0x4,
- GAIN_1_3 = 0x8,
- };
- enum data_bits {
- NOT_CLEAR_REGISTERS = 0x20,
- };
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
- switch (caldac_channel) {
- case 0: /* chan 0 offset */
- i2c_addr = CALDAC0_I2C_ADDR;
- serial_bytes[0] = OFFSET_0_2;
- break;
- case 1: /* chan 1 offset */
- i2c_addr = CALDAC0_I2C_ADDR;
- serial_bytes[0] = OFFSET_1_3;
- break;
- case 2: /* chan 2 offset */
- i2c_addr = CALDAC1_I2C_ADDR;
- serial_bytes[0] = OFFSET_0_2;
- break;
- case 3: /* chan 3 offset */
- i2c_addr = CALDAC1_I2C_ADDR;
- serial_bytes[0] = OFFSET_1_3;
- break;
- case 4: /* chan 0 gain */
- i2c_addr = CALDAC0_I2C_ADDR;
- serial_bytes[0] = GAIN_0_2;
- break;
- case 5: /* chan 1 gain */
- i2c_addr = CALDAC0_I2C_ADDR;
- serial_bytes[0] = GAIN_1_3;
- break;
- case 6: /* chan 2 gain */
- i2c_addr = CALDAC1_I2C_ADDR;
- serial_bytes[0] = GAIN_0_2;
- break;
- case 7: /* chan 3 gain */
- i2c_addr = CALDAC1_I2C_ADDR;
- serial_bytes[0] = GAIN_1_3;
- break;
- default:
- comedi_error(dev, "invalid caldac channel\n");
- return -1;
- break;
+ if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
+ dev_warn(dev->class_dev,
+ "failed to enable PCI device and request regions\n");
+ return -EIO;
}
- serial_bytes[1] = NOT_CLEAR_REGISTERS | ((value >> 8) & 0xf);
- serial_bytes[2] = value & 0xff;
- i2c_write(dev, i2c_addr, serial_bytes, 3);
- return 0;
-}
+ pci_set_master(pcidev);
-/* Their i2c requires a huge delay on setting clock or data high for some reason */
-static const int i2c_high_udelay = 1000;
-static const int i2c_low_udelay = 10;
+ /* Initialize dev->board_name */
+ dev->board_name = thisboard->name;
-/* set i2c data line high or low */
-static void i2c_set_sda(struct comedi_device *dev, int state)
-{
- static const int data_bit = CTL_EE_W;
- void __iomem *plx_control_addr = priv(dev)->plx9080_iobase +
- PLX_CONTROL_REG;
+ dev->iobase = pci_resource_start(pcidev, MAIN_BADDRINDEX);
- if (state) {
- /* set data line high */
- priv(dev)->plx_control_bits &= ~data_bit;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
- udelay(i2c_high_udelay);
- } else { /* set data line low */
+ devpriv->plx9080_phys_iobase =
+ pci_resource_start(pcidev, PLX9080_BADDRINDEX);
+ devpriv->main_phys_iobase = dev->iobase;
+ devpriv->dio_counter_phys_iobase =
+ pci_resource_start(pcidev, DIO_COUNTER_BADDRINDEX);
- priv(dev)->plx_control_bits |= data_bit;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
- udelay(i2c_low_udelay);
+ /* remap, won't work with 2.0 kernels but who cares */
+ devpriv->plx9080_iobase =
+ ioremap(devpriv->plx9080_phys_iobase,
+ pci_resource_len(pcidev, PLX9080_BADDRINDEX));
+ devpriv->main_iobase =
+ ioremap(devpriv->main_phys_iobase,
+ pci_resource_len(pcidev, MAIN_BADDRINDEX));
+ devpriv->dio_counter_iobase =
+ ioremap(devpriv->dio_counter_phys_iobase,
+ pci_resource_len(pcidev, DIO_COUNTER_BADDRINDEX));
+
+ if (!devpriv->plx9080_iobase || !devpriv->main_iobase
+ || !devpriv->dio_counter_iobase) {
+ dev_warn(dev->class_dev, "failed to remap io memory\n");
+ return -ENOMEM;
}
-}
-/* set i2c clock line high or low */
-static void i2c_set_scl(struct comedi_device *dev, int state)
-{
- static const int clock_bit = CTL_USERO;
- void __iomem *plx_control_addr = priv(dev)->plx9080_iobase +
- PLX_CONTROL_REG;
-
- if (state) {
- /* set clock line high */
- priv(dev)->plx_control_bits &= ~clock_bit;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
- udelay(i2c_high_udelay);
- } else { /* set clock line low */
-
- priv(dev)->plx_control_bits |= clock_bit;
- writel(priv(dev)->plx_control_bits, plx_control_addr);
- udelay(i2c_low_udelay);
- }
-}
+ DEBUG_PRINT(" plx9080 remapped to 0x%p\n", devpriv->plx9080_iobase);
+ DEBUG_PRINT(" main remapped to 0x%p\n", devpriv->main_iobase);
+ DEBUG_PRINT(" diocounter remapped to 0x%p\n",
+ devpriv->dio_counter_iobase);
-static void i2c_write_byte(struct comedi_device *dev, uint8_t byte)
-{
- uint8_t bit;
- unsigned int num_bits = 8;
+ /* figure out what local addresses are */
+ local_range = readl(devpriv->plx9080_iobase + PLX_LAS0RNG_REG) &
+ LRNG_MEM_MASK;
+ local_decode = readl(devpriv->plx9080_iobase + PLX_LAS0MAP_REG) &
+ local_range & LMAP_MEM_MASK;
+ devpriv->local0_iobase = ((uint32_t)devpriv->main_phys_iobase &
+ ~local_range) | local_decode;
+ local_range = readl(devpriv->plx9080_iobase + PLX_LAS1RNG_REG) &
+ LRNG_MEM_MASK;
+ local_decode = readl(devpriv->plx9080_iobase + PLX_LAS1MAP_REG) &
+ local_range & LMAP_MEM_MASK;
+ devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase &
+ ~local_range) | local_decode;
+
+ DEBUG_PRINT(" local 0 io addr 0x%x\n", devpriv->local0_iobase);
+ DEBUG_PRINT(" local 1 io addr 0x%x\n", devpriv->local1_iobase);
- DEBUG_PRINT("writing to i2c byte 0x%x\n", byte);
+ retval = alloc_and_init_dma_members(dev);
+ if (retval < 0)
+ return retval;
- for (bit = 1 << (num_bits - 1); bit; bit >>= 1) {
- i2c_set_scl(dev, 0);
- if ((byte & bit))
- i2c_set_sda(dev, 1);
- else
- i2c_set_sda(dev, 0);
- i2c_set_scl(dev, 1);
+ devpriv->hw_revision =
+ hw_revision(dev, readw(devpriv->main_iobase + HW_STATUS_REG));
+ dev_dbg(dev->class_dev, "stc hardware revision %i\n",
+ devpriv->hw_revision);
+ init_plx9080(dev);
+ init_stc_registers(dev);
+ /* get irq */
+ if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
+ "cb_pcidas64", dev)) {
+ dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
+ pcidev->irq);
+ return -EINVAL;
}
-}
-
-/* we can't really read the lines, so fake it */
-static int i2c_read_ack(struct comedi_device *dev)
-{
- i2c_set_scl(dev, 0);
- i2c_set_sda(dev, 1);
- i2c_set_scl(dev, 1);
-
- return 0; /* return fake acknowledge bit */
-}
+ dev->irq = pcidev->irq;
+ dev_dbg(dev->class_dev, "irq %u\n", dev->irq);
-/* send start bit */
-static void i2c_start(struct comedi_device *dev)
-{
- i2c_set_scl(dev, 1);
- i2c_set_sda(dev, 1);
- i2c_set_sda(dev, 0);
-}
+ retval = setup_subdevices(dev);
+ if (retval < 0)
+ return retval;
-/* send stop bit */
-static void i2c_stop(struct comedi_device *dev)
-{
- i2c_set_scl(dev, 0);
- i2c_set_sda(dev, 0);
- i2c_set_scl(dev, 1);
- i2c_set_sda(dev, 1);
+ return 0;
}
-static void i2c_write(struct comedi_device *dev, unsigned int address,
- const uint8_t *data, unsigned int length)
+static void detach(struct comedi_device *dev)
{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct pcidas64_private *devpriv = dev->private;
unsigned int i;
- uint8_t bitstream;
- static const int read_bit = 0x1;
-
-/* XXX need mutex to prevent simultaneous attempts to access eeprom and i2c bus */
- /* make sure we dont send anything to eeprom */
- priv(dev)->plx_control_bits &= ~CTL_EE_CS;
-
- i2c_stop(dev);
- i2c_start(dev);
-
- /* send address and write bit */
- bitstream = (address << 1) & ~read_bit;
- i2c_write_byte(dev, bitstream);
-
- /* get acknowledge */
- if (i2c_read_ack(dev) != 0) {
- comedi_error(dev, "i2c write failed: no acknowledge");
- i2c_stop(dev);
- return;
- }
- /* write data bytes */
- for (i = 0; i < length; i++) {
- i2c_write_byte(dev, data[i]);
- if (i2c_read_ack(dev) != 0) {
- comedi_error(dev, "i2c write failed: no acknowledge");
- i2c_stop(dev);
- return;
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (devpriv) {
+ if (pcidev) {
+ if (devpriv->plx9080_iobase) {
+ disable_plx_interrupts(dev);
+ iounmap(devpriv->plx9080_iobase);
+ }
+ if (devpriv->main_iobase)
+ iounmap(devpriv->main_iobase);
+ if (devpriv->dio_counter_iobase)
+ iounmap(devpriv->dio_counter_iobase);
+ /* free pci dma buffers */
+ for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
+ if (devpriv->ai_buffer[i])
+ pci_free_consistent(pcidev,
+ DMA_BUFFER_SIZE,
+ devpriv->ai_buffer[i],
+ devpriv->ai_buffer_bus_addr[i]);
+ }
+ for (i = 0; i < AO_DMA_RING_COUNT; i++) {
+ if (devpriv->ao_buffer[i])
+ pci_free_consistent(pcidev,
+ DMA_BUFFER_SIZE,
+ devpriv->ao_buffer[i],
+ devpriv->ao_buffer_bus_addr[i]);
+ }
+ /* free dma descriptors */
+ if (devpriv->ai_dma_desc)
+ pci_free_consistent(pcidev,
+ sizeof(struct plx_dma_desc) *
+ ai_dma_ring_count(thisboard),
+ devpriv->ai_dma_desc,
+ devpriv->ai_dma_desc_bus_addr);
+ if (devpriv->ao_dma_desc)
+ pci_free_consistent(pcidev,
+ sizeof(struct plx_dma_desc) *
+ AO_DMA_RING_COUNT,
+ devpriv->ao_dma_desc,
+ devpriv->ao_dma_desc_bus_addr);
}
}
- i2c_stop(dev);
+ if (dev->subdevices)
+ subdev_8255_cleanup(dev, &dev->subdevices[4]);
+ if (pcidev) {
+ if (dev->iobase)
+ comedi_pci_disable(pcidev);
+ }
}
static struct comedi_driver cb_pcidas64_driver = {
.driver_name = "cb_pcidas64",
.module = THIS_MODULE,
- .attach = attach,
+ .auto_attach = auto_attach,
.detach = detach,
};
-static int __devinit cb_pcidas64_pci_probe(struct pci_dev *dev,
+static int cb_pcidas64_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
return comedi_pci_auto_config(dev, &cb_pcidas64_driver);
}
-static void __devexit cb_pcidas64_pci_remove(struct pci_dev *dev)
+static void cb_pcidas64_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001e) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0035) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0036) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0037) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0052) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x005d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x005e) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x005f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0061) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0062) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0063) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0064) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0066) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0067) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0068) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x006f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0078) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0079) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, cb_pcidas64_pci_table);
@@ -4230,7 +4253,7 @@ static struct pci_driver cb_pcidas64_pci_driver = {
.name = "cb_pcidas64",
.id_table = cb_pcidas64_pci_table,
.probe = cb_pcidas64_pci_probe,
- .remove = __devexit_p(cb_pcidas64_pci_remove),
+ .remove = cb_pcidas64_pci_remove,
};
module_comedi_pci_driver(cb_pcidas64_driver, cb_pcidas64_pci_driver);