/drivers/staging/comedi/drivers/ni_mio_common.c
https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t · C · 6005 lines · 4968 code · 604 blank · 433 comment · 869 complexity · c44039260f42b06fffd172846b247bbb MD5 · raw file
Large files are truncated click here to view the full file
- /*
- comedi/drivers/ni_mio_common.c
- Hardware driver for DAQ-STC based boards
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
- Copyright (C) 2002-2006 Frank Mori Hess <fmhess@users.sourceforge.net>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- /*
- This file is meant to be included by another file, e.g.,
- ni_atmio.c or ni_pcimio.c.
- Interrupt support originally added by Truxton Fulton
- <trux@truxton.com>
- References (from ftp://ftp.natinst.com/support/manuals):
- 340747b.pdf AT-MIO E series Register Level Programmer Manual
- 341079b.pdf PCI E Series RLPM
- 340934b.pdf DAQ-STC reference manual
- 67xx and 611x registers (from ftp://ftp.ni.com/support/daq/mhddk/documentation/)
- release_ni611x.pdf
- release_ni67xx.pdf
- Other possibly relevant info:
- 320517c.pdf User manual (obsolete)
- 320517f.pdf User manual (new)
- 320889a.pdf delete
- 320906c.pdf maximum signal ratings
- 321066a.pdf about 16x
- 321791a.pdf discontinuation of at-mio-16e-10 rev. c
- 321808a.pdf about at-mio-16e-10 rev P
- 321837a.pdf discontinuation of at-mio-16de-10 rev d
- 321838a.pdf about at-mio-16de-10 rev N
- ISSUES:
- - the interrupt routine needs to be cleaned up
- 2006-02-07: S-Series PCI-6143: Support has been added but is not
- fully tested as yet. Terry Barnaby, BEAM Ltd.
- */
- /* #define DEBUG_INTERRUPT */
- /* #define DEBUG_STATUS_A */
- /* #define DEBUG_STATUS_B */
- #include <linux/interrupt.h>
- #include <linux/sched.h>
- #include "8255.h"
- #include "mite.h"
- #include "comedi_fc.h"
- #ifndef MDPRINTK
- #define MDPRINTK(format, args...)
- #endif
- /* A timeout count */
- #define NI_TIMEOUT 1000
- static const unsigned old_RTSI_clock_channel = 7;
- /* Note: this table must match the ai_gain_* definitions */
- static const short ni_gainlkup[][16] = {
- [ai_gain_16] = {0, 1, 2, 3, 4, 5, 6, 7,
- 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107},
- [ai_gain_8] = {1, 2, 4, 7, 0x101, 0x102, 0x104, 0x107},
- [ai_gain_14] = {1, 2, 3, 4, 5, 6, 7,
- 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107},
- [ai_gain_4] = {0, 1, 4, 7},
- [ai_gain_611x] = {0x00a, 0x00b, 0x001, 0x002,
- 0x003, 0x004, 0x005, 0x006},
- [ai_gain_622x] = {0, 1, 4, 5},
- [ai_gain_628x] = {1, 2, 3, 4, 5, 6, 7},
- [ai_gain_6143] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- };
- static const struct comedi_lrange range_ni_E_ai = { 16, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2.5, 2.5),
- RANGE(-1, 1),
- RANGE(-0.5, 0.5),
- RANGE(-0.25, 0.25),
- RANGE(-0.1, 0.1),
- RANGE(-0.05, 0.05),
- RANGE(0, 20),
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 2),
- RANGE(0, 1),
- RANGE(0, 0.5),
- RANGE(0, 0.2),
- RANGE(0, 0.1),
- }
- };
- static const struct comedi_lrange range_ni_E_ai_limited = { 8, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-1, 1),
- RANGE(-0.1,
- 0.1),
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 1),
- RANGE(0, 0.1),
- }
- };
- static const struct comedi_lrange range_ni_E_ai_limited14 = { 14, {
- RANGE(-10,
- 10),
- RANGE(-5, 5),
- RANGE(-2, 2),
- RANGE(-1, 1),
- RANGE(-0.5,
- 0.5),
- RANGE(-0.2,
- 0.2),
- RANGE(-0.1,
- 0.1),
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 2),
- RANGE(0, 1),
- RANGE(0,
- 0.5),
- RANGE(0,
- 0.2),
- RANGE(0,
- 0.1),
- }
- };
- static const struct comedi_lrange range_ni_E_ai_bipolar4 = { 4, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-0.5,
- 0.5),
- RANGE(-0.05,
- 0.05),
- }
- };
- static const struct comedi_lrange range_ni_E_ai_611x = { 8, {
- RANGE(-50, 50),
- RANGE(-20, 20),
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2, 2),
- RANGE(-1, 1),
- RANGE(-0.5, 0.5),
- RANGE(-0.2, 0.2),
- }
- };
- static const struct comedi_lrange range_ni_M_ai_622x = { 4, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-1, 1),
- RANGE(-0.2, 0.2),
- }
- };
- static const struct comedi_lrange range_ni_M_ai_628x = { 7, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2, 2),
- RANGE(-1, 1),
- RANGE(-0.5, 0.5),
- RANGE(-0.2, 0.2),
- RANGE(-0.1, 0.1),
- }
- };
- static const struct comedi_lrange range_ni_S_ai_6143 = { 1, {
- RANGE(-5, +5),
- }
- };
- static const struct comedi_lrange range_ni_E_ao_ext = { 4, {
- RANGE(-10, 10),
- RANGE(0, 10),
- RANGE_ext(-1, 1),
- RANGE_ext(0, 1),
- }
- };
- static const struct comedi_lrange *const ni_range_lkup[] = {
- [ai_gain_16] = &range_ni_E_ai,
- [ai_gain_8] = &range_ni_E_ai_limited,
- [ai_gain_14] = &range_ni_E_ai_limited14,
- [ai_gain_4] = &range_ni_E_ai_bipolar4,
- [ai_gain_611x] = &range_ni_E_ai_611x,
- [ai_gain_622x] = &range_ni_M_ai_622x,
- [ai_gain_628x] = &range_ni_M_ai_628x,
- [ai_gain_6143] = &range_ni_S_ai_6143
- };
- static int ni_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_cdio_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
- static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
- static int ni_cdio_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
- static void handle_cdio_interrupt(struct comedi_device *dev);
- static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum);
- static int ni_serial_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_serial_hw_readwrite8(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned char data_out,
- unsigned char *data_in);
- static int ni_serial_sw_readwrite8(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned char data_out,
- unsigned char *data_in);
- static int ni_calib_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_calib_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_eeprom_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_m_series_eeprom_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- static int ni_pfi_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_pfi_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static unsigned ni_old_get_pfi_routing(struct comedi_device *dev,
- unsigned chan);
- static void ni_rtsi_init(struct comedi_device *dev);
- static int ni_rtsi_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_rtsi_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s);
- static int ni_read_eeprom(struct comedi_device *dev, int addr);
- #ifdef DEBUG_STATUS_A
- static void ni_mio_print_status_a(int status);
- #else
- #define ni_mio_print_status_a(a)
- #endif
- #ifdef DEBUG_STATUS_B
- static void ni_mio_print_status_b(int status);
- #else
- #define ni_mio_print_status_b(a)
- #endif
- static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s);
- #ifndef PCIDMA
- static void ni_handle_fifo_half_full(struct comedi_device *dev);
- static int ni_ao_fifo_half_empty(struct comedi_device *dev,
- struct comedi_subdevice *s);
- #endif
- static void ni_handle_fifo_dregs(struct comedi_device *dev);
- static int ni_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum);
- static void ni_load_channelgain_list(struct comedi_device *dev,
- unsigned int n_chan, unsigned int *list);
- static void shutdown_ai_command(struct comedi_device *dev);
- static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum);
- static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s);
- static int ni_8255_callback(int dir, int port, int data, unsigned long arg);
- static int ni_gpct_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_gpct_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_gpct_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
- static int ni_gpct_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
- static int ni_gpct_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
- static void handle_gpct_interrupt(struct comedi_device *dev,
- unsigned short counter_index);
- static int init_cs5529(struct comedi_device *dev);
- static int cs5529_do_conversion(struct comedi_device *dev,
- unsigned short *data);
- static int cs5529_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- #ifdef NI_CS5529_DEBUG
- static unsigned int cs5529_config_read(struct comedi_device *dev,
- unsigned int reg_select_bits);
- #endif
- static void cs5529_config_write(struct comedi_device *dev, unsigned int value,
- unsigned int reg_select_bits);
- static int ni_m_series_pwm_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_6143_pwm_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- static int ni_set_master_clock(struct comedi_device *dev, unsigned source,
- unsigned period_ns);
- static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status);
- static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status);
- enum aimodes {
- AIMODE_NONE = 0,
- AIMODE_HALF_FULL = 1,
- AIMODE_SCAN = 2,
- AIMODE_SAMPLE = 3,
- };
- enum ni_common_subdevices {
- NI_AI_SUBDEV,
- NI_AO_SUBDEV,
- NI_DIO_SUBDEV,
- NI_8255_DIO_SUBDEV,
- NI_UNUSED_SUBDEV,
- NI_CALIBRATION_SUBDEV,
- NI_EEPROM_SUBDEV,
- NI_PFI_DIO_SUBDEV,
- NI_CS5529_CALIBRATION_SUBDEV,
- NI_SERIAL_SUBDEV,
- NI_RTSI_SUBDEV,
- NI_GPCT0_SUBDEV,
- NI_GPCT1_SUBDEV,
- NI_FREQ_OUT_SUBDEV,
- NI_NUM_SUBDEVICES
- };
- static inline unsigned NI_GPCT_SUBDEV(unsigned counter_index)
- {
- switch (counter_index) {
- case 0:
- return NI_GPCT0_SUBDEV;
- break;
- case 1:
- return NI_GPCT1_SUBDEV;
- break;
- default:
- break;
- }
- BUG();
- return NI_GPCT0_SUBDEV;
- }
- enum timebase_nanoseconds {
- TIMEBASE_1_NS = 50,
- TIMEBASE_2_NS = 10000
- };
- #define SERIAL_DISABLED 0
- #define SERIAL_600NS 600
- #define SERIAL_1_2US 1200
- #define SERIAL_10US 10000
- static const int num_adc_stages_611x = 3;
- static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
- unsigned ai_mite_status);
- static void handle_b_interrupt(struct comedi_device *dev, unsigned short status,
- unsigned ao_mite_status);
- static void get_last_sample_611x(struct comedi_device *dev);
- static void get_last_sample_6143(struct comedi_device *dev);
- static inline void ni_set_bitfield(struct comedi_device *dev, int reg,
- unsigned bit_mask, unsigned bit_values)
- {
- unsigned long flags;
- spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
- switch (reg) {
- case Interrupt_A_Enable_Register:
- devpriv->int_a_enable_reg &= ~bit_mask;
- devpriv->int_a_enable_reg |= bit_values & bit_mask;
- devpriv->stc_writew(dev, devpriv->int_a_enable_reg,
- Interrupt_A_Enable_Register);
- break;
- case Interrupt_B_Enable_Register:
- devpriv->int_b_enable_reg &= ~bit_mask;
- devpriv->int_b_enable_reg |= bit_values & bit_mask;
- devpriv->stc_writew(dev, devpriv->int_b_enable_reg,
- Interrupt_B_Enable_Register);
- break;
- case IO_Bidirection_Pin_Register:
- devpriv->io_bidirection_pin_reg &= ~bit_mask;
- devpriv->io_bidirection_pin_reg |= bit_values & bit_mask;
- devpriv->stc_writew(dev, devpriv->io_bidirection_pin_reg,
- IO_Bidirection_Pin_Register);
- break;
- case AI_AO_Select:
- devpriv->ai_ao_select_reg &= ~bit_mask;
- devpriv->ai_ao_select_reg |= bit_values & bit_mask;
- ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
- break;
- case G0_G1_Select:
- devpriv->g0_g1_select_reg &= ~bit_mask;
- devpriv->g0_g1_select_reg |= bit_values & bit_mask;
- ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select);
- break;
- default:
- printk("Warning %s() called with invalid register\n", __func__);
- printk("reg is %d\n", reg);
- break;
- }
- mmiowb();
- spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
- }
- #ifdef PCIDMA
- static int ni_ai_drain_dma(struct comedi_device *dev);
- /* DMA channel setup */
- /* negative channel means no channel */
- static inline void ni_set_ai_dma_channel(struct comedi_device *dev, int channel)
- {
- unsigned bitfield;
- if (channel >= 0) {
- bitfield =
- (ni_stc_dma_channel_select_bitfield(channel) <<
- AI_DMA_Select_Shift) & AI_DMA_Select_Mask;
- } else {
- bitfield = 0;
- }
- ni_set_bitfield(dev, AI_AO_Select, AI_DMA_Select_Mask, bitfield);
- }
- /* negative channel means no channel */
- static inline void ni_set_ao_dma_channel(struct comedi_device *dev, int channel)
- {
- unsigned bitfield;
- if (channel >= 0) {
- bitfield =
- (ni_stc_dma_channel_select_bitfield(channel) <<
- AO_DMA_Select_Shift) & AO_DMA_Select_Mask;
- } else {
- bitfield = 0;
- }
- ni_set_bitfield(dev, AI_AO_Select, AO_DMA_Select_Mask, bitfield);
- }
- /* negative mite_channel means no channel */
- static inline void ni_set_gpct_dma_channel(struct comedi_device *dev,
- unsigned gpct_index,
- int mite_channel)
- {
- unsigned bitfield;
- if (mite_channel >= 0) {
- bitfield = GPCT_DMA_Select_Bits(gpct_index, mite_channel);
- } else {
- bitfield = 0;
- }
- ni_set_bitfield(dev, G0_G1_Select, GPCT_DMA_Select_Mask(gpct_index),
- bitfield);
- }
- /* negative mite_channel means no channel */
- static inline void ni_set_cdo_dma_channel(struct comedi_device *dev,
- int mite_channel)
- {
- unsigned long flags;
- spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
- devpriv->cdio_dma_select_reg &= ~CDO_DMA_Select_Mask;
- if (mite_channel >= 0) {
- /*XXX just guessing ni_stc_dma_channel_select_bitfield() returns the right bits,
- under the assumption the cdio dma selection works just like ai/ao/gpct.
- Definitely works for dma channels 0 and 1. */
- devpriv->cdio_dma_select_reg |=
- (ni_stc_dma_channel_select_bitfield(mite_channel) <<
- CDO_DMA_Select_Shift) & CDO_DMA_Select_Mask;
- }
- ni_writeb(devpriv->cdio_dma_select_reg, M_Offset_CDIO_DMA_Select);
- mmiowb();
- spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
- }
- static int ni_request_ai_mite_channel(struct comedi_device *dev)
- {
- unsigned long flags;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- BUG_ON(devpriv->ai_mite_chan);
- devpriv->ai_mite_chan =
- mite_request_channel(devpriv->mite, devpriv->ai_mite_ring);
- if (devpriv->ai_mite_chan == NULL) {
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- comedi_error(dev,
- "failed to reserve mite dma channel for analog input.");
- return -EBUSY;
- }
- devpriv->ai_mite_chan->dir = COMEDI_INPUT;
- ni_set_ai_dma_channel(dev, devpriv->ai_mite_chan->channel);
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- return 0;
- }
- static int ni_request_ao_mite_channel(struct comedi_device *dev)
- {
- unsigned long flags;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- BUG_ON(devpriv->ao_mite_chan);
- devpriv->ao_mite_chan =
- mite_request_channel(devpriv->mite, devpriv->ao_mite_ring);
- if (devpriv->ao_mite_chan == NULL) {
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- comedi_error(dev,
- "failed to reserve mite dma channel for analog outut.");
- return -EBUSY;
- }
- devpriv->ao_mite_chan->dir = COMEDI_OUTPUT;
- ni_set_ao_dma_channel(dev, devpriv->ao_mite_chan->channel);
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- return 0;
- }
- static int ni_request_gpct_mite_channel(struct comedi_device *dev,
- unsigned gpct_index,
- enum comedi_io_direction direction)
- {
- unsigned long flags;
- struct mite_channel *mite_chan;
- BUG_ON(gpct_index >= NUM_GPCT);
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- BUG_ON(devpriv->counter_dev->counters[gpct_index].mite_chan);
- mite_chan =
- mite_request_channel(devpriv->mite,
- devpriv->gpct_mite_ring[gpct_index]);
- if (mite_chan == NULL) {
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- comedi_error(dev,
- "failed to reserve mite dma channel for counter.");
- return -EBUSY;
- }
- mite_chan->dir = direction;
- ni_tio_set_mite_channel(&devpriv->counter_dev->counters[gpct_index],
- mite_chan);
- ni_set_gpct_dma_channel(dev, gpct_index, mite_chan->channel);
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- return 0;
- }
- #endif /* PCIDMA */
- static int ni_request_cdo_mite_channel(struct comedi_device *dev)
- {
- #ifdef PCIDMA
- unsigned long flags;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- BUG_ON(devpriv->cdo_mite_chan);
- devpriv->cdo_mite_chan =
- mite_request_channel(devpriv->mite, devpriv->cdo_mite_ring);
- if (devpriv->cdo_mite_chan == NULL) {
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- comedi_error(dev,
- "failed to reserve mite dma channel for correlated digital outut.");
- return -EBUSY;
- }
- devpriv->cdo_mite_chan->dir = COMEDI_OUTPUT;
- ni_set_cdo_dma_channel(dev, devpriv->cdo_mite_chan->channel);
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- #endif /* PCIDMA */
- return 0;
- }
- static void ni_release_ai_mite_channel(struct comedi_device *dev)
- {
- #ifdef PCIDMA
- unsigned long flags;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->ai_mite_chan) {
- ni_set_ai_dma_channel(dev, -1);
- mite_release_channel(devpriv->ai_mite_chan);
- devpriv->ai_mite_chan = NULL;
- }
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- #endif /* PCIDMA */
- }
- static void ni_release_ao_mite_channel(struct comedi_device *dev)
- {
- #ifdef PCIDMA
- unsigned long flags;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->ao_mite_chan) {
- ni_set_ao_dma_channel(dev, -1);
- mite_release_channel(devpriv->ao_mite_chan);
- devpriv->ao_mite_chan = NULL;
- }
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- #endif /* PCIDMA */
- }
- void ni_release_gpct_mite_channel(struct comedi_device *dev,
- unsigned gpct_index)
- {
- #ifdef PCIDMA
- unsigned long flags;
- BUG_ON(gpct_index >= NUM_GPCT);
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->counter_dev->counters[gpct_index].mite_chan) {
- struct mite_channel *mite_chan =
- devpriv->counter_dev->counters[gpct_index].mite_chan;
- ni_set_gpct_dma_channel(dev, gpct_index, -1);
- ni_tio_set_mite_channel(&devpriv->
- counter_dev->counters[gpct_index],
- NULL);
- mite_release_channel(mite_chan);
- }
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- #endif /* PCIDMA */
- }
- static void ni_release_cdo_mite_channel(struct comedi_device *dev)
- {
- #ifdef PCIDMA
- unsigned long flags;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->cdo_mite_chan) {
- ni_set_cdo_dma_channel(dev, -1);
- mite_release_channel(devpriv->cdo_mite_chan);
- devpriv->cdo_mite_chan = NULL;
- }
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- #endif /* PCIDMA */
- }
- /* e-series boards use the second irq signals to generate dma requests for their counters */
- #ifdef PCIDMA
- static void ni_e_series_enable_second_irq(struct comedi_device *dev,
- unsigned gpct_index, short enable)
- {
- if (boardtype.reg_type & ni_reg_m_series_mask)
- return;
- switch (gpct_index) {
- case 0:
- if (enable) {
- devpriv->stc_writew(dev, G0_Gate_Second_Irq_Enable,
- Second_IRQ_A_Enable_Register);
- } else {
- devpriv->stc_writew(dev, 0,
- Second_IRQ_A_Enable_Register);
- }
- break;
- case 1:
- if (enable) {
- devpriv->stc_writew(dev, G1_Gate_Second_Irq_Enable,
- Second_IRQ_B_Enable_Register);
- } else {
- devpriv->stc_writew(dev, 0,
- Second_IRQ_B_Enable_Register);
- }
- break;
- default:
- BUG();
- break;
- }
- }
- #endif /* PCIDMA */
- static void ni_clear_ai_fifo(struct comedi_device *dev)
- {
- if (boardtype.reg_type == ni_reg_6143) {
- /* Flush the 6143 data FIFO */
- ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */
- ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */
- while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */
- } else {
- devpriv->stc_writew(dev, 1, ADC_FIFO_Clear);
- if (boardtype.reg_type == ni_reg_625x) {
- ni_writeb(0, M_Offset_Static_AI_Control(0));
- ni_writeb(1, M_Offset_Static_AI_Control(0));
- #if 0
- /* the NI example code does 3 convert pulses for 625x boards,
- but that appears to be wrong in practice. */
- devpriv->stc_writew(dev, AI_CONVERT_Pulse,
- AI_Command_1_Register);
- devpriv->stc_writew(dev, AI_CONVERT_Pulse,
- AI_Command_1_Register);
- devpriv->stc_writew(dev, AI_CONVERT_Pulse,
- AI_Command_1_Register);
- #endif
- }
- }
- }
- static void win_out2(struct comedi_device *dev, uint32_t data, int reg)
- {
- devpriv->stc_writew(dev, data >> 16, reg);
- devpriv->stc_writew(dev, data & 0xffff, reg + 1);
- }
- static uint32_t win_in2(struct comedi_device *dev, int reg)
- {
- uint32_t bits;
- bits = devpriv->stc_readw(dev, reg) << 16;
- bits |= devpriv->stc_readw(dev, reg + 1);
- return bits;
- }
- #define ao_win_out(data, addr) ni_ao_win_outw(dev, data, addr)
- static inline void ni_ao_win_outw(struct comedi_device *dev, uint16_t data,
- int addr)
- {
- unsigned long flags;
- spin_lock_irqsave(&devpriv->window_lock, flags);
- ni_writew(addr, AO_Window_Address_611x);
- ni_writew(data, AO_Window_Data_611x);
- spin_unlock_irqrestore(&devpriv->window_lock, flags);
- }
- static inline void ni_ao_win_outl(struct comedi_device *dev, uint32_t data,
- int addr)
- {
- unsigned long flags;
- spin_lock_irqsave(&devpriv->window_lock, flags);
- ni_writew(addr, AO_Window_Address_611x);
- ni_writel(data, AO_Window_Data_611x);
- spin_unlock_irqrestore(&devpriv->window_lock, flags);
- }
- static inline unsigned short ni_ao_win_inw(struct comedi_device *dev, int addr)
- {
- unsigned long flags;
- unsigned short data;
- spin_lock_irqsave(&devpriv->window_lock, flags);
- ni_writew(addr, AO_Window_Address_611x);
- data = ni_readw(AO_Window_Data_611x);
- spin_unlock_irqrestore(&devpriv->window_lock, flags);
- return data;
- }
- /* ni_set_bits( ) allows different parts of the ni_mio_common driver to
- * share registers (such as Interrupt_A_Register) without interfering with
- * each other.
- *
- * NOTE: the switch/case statements are optimized out for a constant argument
- * so this is actually quite fast--- If you must wrap another function around this
- * make it inline to avoid a large speed penalty.
- *
- * value should only be 1 or 0.
- */
- static inline void ni_set_bits(struct comedi_device *dev, int reg,
- unsigned bits, unsigned value)
- {
- unsigned bit_values;
- if (value)
- bit_values = bits;
- else
- bit_values = 0;
- ni_set_bitfield(dev, reg, bits, bit_values);
- }
- static irqreturn_t ni_E_interrupt(int irq, void *d)
- {
- struct comedi_device *dev = d;
- unsigned short a_status;
- unsigned short b_status;
- unsigned int ai_mite_status = 0;
- unsigned int ao_mite_status = 0;
- unsigned long flags;
- #ifdef PCIDMA
- struct mite_struct *mite = devpriv->mite;
- #endif
- if (dev->attached == 0)
- return IRQ_NONE;
- smp_mb(); /* make sure dev->attached is checked before handler does anything else. */
- /* lock to avoid race with comedi_poll */
- spin_lock_irqsave(&dev->spinlock, flags);
- a_status = devpriv->stc_readw(dev, AI_Status_1_Register);
- b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
- #ifdef PCIDMA
- if (mite) {
- unsigned long flags_too;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags_too);
- if (devpriv->ai_mite_chan) {
- ai_mite_status = mite_get_status(devpriv->ai_mite_chan);
- if (ai_mite_status & CHSR_LINKC)
- writel(CHOR_CLRLC,
- devpriv->mite->mite_io_addr +
- MITE_CHOR(devpriv->
- ai_mite_chan->channel));
- }
- if (devpriv->ao_mite_chan) {
- ao_mite_status = mite_get_status(devpriv->ao_mite_chan);
- if (ao_mite_status & CHSR_LINKC)
- writel(CHOR_CLRLC,
- mite->mite_io_addr +
- MITE_CHOR(devpriv->
- ao_mite_chan->channel));
- }
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags_too);
- }
- #endif
- ack_a_interrupt(dev, a_status);
- ack_b_interrupt(dev, b_status);
- if ((a_status & Interrupt_A_St) || (ai_mite_status & CHSR_INT))
- handle_a_interrupt(dev, a_status, ai_mite_status);
- if ((b_status & Interrupt_B_St) || (ao_mite_status & CHSR_INT))
- handle_b_interrupt(dev, b_status, ao_mite_status);
- handle_gpct_interrupt(dev, 0);
- handle_gpct_interrupt(dev, 1);
- handle_cdio_interrupt(dev);
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return IRQ_HANDLED;
- }
- #ifdef PCIDMA
- static void ni_sync_ai_dma(struct comedi_device *dev)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
- unsigned long flags;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->ai_mite_chan)
- mite_sync_input_dma(devpriv->ai_mite_chan, s->async);
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- }
- static void mite_handle_b_linkc(struct mite_struct *mite,
- struct comedi_device *dev)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV;
- unsigned long flags;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->ao_mite_chan) {
- mite_sync_output_dma(devpriv->ao_mite_chan, s->async);
- }
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- }
- static int ni_ao_wait_for_dma_load(struct comedi_device *dev)
- {
- static const int timeout = 10000;
- int i;
- for (i = 0; i < timeout; i++) {
- unsigned short b_status;
- b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
- if (b_status & AO_FIFO_Half_Full_St)
- break;
- /* if we poll too often, the pci bus activity seems
- to slow the dma transfer down */
- udelay(10);
- }
- if (i == timeout) {
- comedi_error(dev, "timed out waiting for dma load");
- return -EPIPE;
- }
- return 0;
- }
- #endif /* PCIDMA */
- static void ni_handle_eos(struct comedi_device *dev, struct comedi_subdevice *s)
- {
- if (devpriv->aimode == AIMODE_SCAN) {
- #ifdef PCIDMA
- static const int timeout = 10;
- int i;
- for (i = 0; i < timeout; i++) {
- ni_sync_ai_dma(dev);
- if ((s->async->events & COMEDI_CB_EOS))
- break;
- udelay(1);
- }
- #else
- ni_handle_fifo_dregs(dev);
- s->async->events |= COMEDI_CB_EOS;
- #endif
- }
- /* handle special case of single scan using AI_End_On_End_Of_Scan */
- if ((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)) {
- shutdown_ai_command(dev);
- }
- }
- static void shutdown_ai_command(struct comedi_device *dev)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
- #ifdef PCIDMA
- ni_ai_drain_dma(dev);
- #endif
- ni_handle_fifo_dregs(dev);
- get_last_sample_611x(dev);
- get_last_sample_6143(dev);
- s->async->events |= COMEDI_CB_EOA;
- }
- static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s)
- {
- if (s->
- async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW |
- COMEDI_CB_EOA)) {
- switch (s - dev->subdevices) {
- case NI_AI_SUBDEV:
- ni_ai_reset(dev, s);
- break;
- case NI_AO_SUBDEV:
- ni_ao_reset(dev, s);
- break;
- case NI_GPCT0_SUBDEV:
- case NI_GPCT1_SUBDEV:
- ni_gpct_cancel(dev, s);
- break;
- case NI_DIO_SUBDEV:
- ni_cdio_cancel(dev, s);
- break;
- default:
- break;
- }
- }
- comedi_event(dev, s);
- }
- static void handle_gpct_interrupt(struct comedi_device *dev,
- unsigned short counter_index)
- {
- #ifdef PCIDMA
- struct comedi_subdevice *s =
- dev->subdevices + NI_GPCT_SUBDEV(counter_index);
- ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index],
- s);
- if (s->async->events)
- ni_event(dev, s);
- #endif
- }
- static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status)
- {
- unsigned short ack = 0;
- if (a_status & AI_SC_TC_St) {
- ack |= AI_SC_TC_Interrupt_Ack;
- }
- if (a_status & AI_START1_St) {
- ack |= AI_START1_Interrupt_Ack;
- }
- if (a_status & AI_START_St) {
- ack |= AI_START_Interrupt_Ack;
- }
- if (a_status & AI_STOP_St) {
- /* not sure why we used to ack the START here also, instead of doing it independently. Frank Hess 2007-07-06 */
- ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack */ ;
- }
- if (ack)
- devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register);
- }
- static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
- unsigned ai_mite_status)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
- /* 67xx boards don't have ai subdevice, but their gpct0 might generate an a interrupt */
- if (s->type == COMEDI_SUBD_UNUSED)
- return;
- #ifdef DEBUG_INTERRUPT
- printk
- ("ni_mio_common: interrupt: a_status=%04x ai_mite_status=%08x\n",
- status, ai_mite_status);
- ni_mio_print_status_a(status);
- #endif
- #ifdef PCIDMA
- if (ai_mite_status & CHSR_LINKC) {
- ni_sync_ai_dma(dev);
- }
- if (ai_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY |
- CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR |
- CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)) {
- printk
- ("unknown mite interrupt, ack! (ai_mite_status=%08x)\n",
- ai_mite_status);
- /* mite_print_chsr(ai_mite_status); */
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- /* disable_irq(dev->irq); */
- }
- #endif
- /* test for all uncommon interrupt events at the same time */
- if (status & (AI_Overrun_St | AI_Overflow_St | AI_SC_TC_Error_St |
- AI_SC_TC_St | AI_START1_St)) {
- if (status == 0xffff) {
- printk
- ("ni_mio_common: a_status=0xffff. Card removed?\n");
- /* we probably aren't even running a command now,
- * so it's a good idea to be careful. */
- if (comedi_get_subdevice_runflags(s) & SRF_RUNNING) {
- s->async->events |=
- COMEDI_CB_ERROR | COMEDI_CB_EOA;
- ni_event(dev, s);
- }
- return;
- }
- if (status & (AI_Overrun_St | AI_Overflow_St |
- AI_SC_TC_Error_St)) {
- printk("ni_mio_common: ai error a_status=%04x\n",
- status);
- ni_mio_print_status_a(status);
- shutdown_ai_command(dev);
- s->async->events |= COMEDI_CB_ERROR;
- if (status & (AI_Overrun_St | AI_Overflow_St))
- s->async->events |= COMEDI_CB_OVERFLOW;
- ni_event(dev, s);
- return;
- }
- if (status & AI_SC_TC_St) {
- #ifdef DEBUG_INTERRUPT
- printk("ni_mio_common: SC_TC interrupt\n");
- #endif
- if (!devpriv->ai_continuous) {
- shutdown_ai_command(dev);
- }
- }
- }
- #ifndef PCIDMA
- if (status & AI_FIFO_Half_Full_St) {
- int i;
- static const int timeout = 10;
- /* pcmcia cards (at least 6036) seem to stop producing interrupts if we
- *fail to get the fifo less than half full, so loop to be sure.*/
- for (i = 0; i < timeout; ++i) {
- ni_handle_fifo_half_full(dev);
- if ((devpriv->stc_readw(dev,
- AI_Status_1_Register) &
- AI_FIFO_Half_Full_St) == 0)
- break;
- }
- }
- #endif /* !PCIDMA */
- if ((status & AI_STOP_St)) {
- ni_handle_eos(dev, s);
- }
- ni_event(dev, s);
- #ifdef DEBUG_INTERRUPT
- status = devpriv->stc_readw(dev, AI_Status_1_Register);
- if (status & Interrupt_A_St) {
- printk
- ("handle_a_interrupt: didn't clear interrupt? status=0x%x\n",
- status);
- }
- #endif
- }
- static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status)
- {
- unsigned short ack = 0;
- if (b_status & AO_BC_TC_St) {
- ack |= AO_BC_TC_Interrupt_Ack;
- }
- if (b_status & AO_Overrun_St) {
- ack |= AO_Error_Interrupt_Ack;
- }
- if (b_status & AO_START_St) {
- ack |= AO_START_Interrupt_Ack;
- }
- if (b_status & AO_START1_St) {
- ack |= AO_START1_Interrupt_Ack;
- }
- if (b_status & AO_UC_TC_St) {
- ack |= AO_UC_TC_Interrupt_Ack;
- }
- if (b_status & AO_UI2_TC_St) {
- ack |= AO_UI2_TC_Interrupt_Ack;
- }
- if (b_status & AO_UPDATE_St) {
- ack |= AO_UPDATE_Interrupt_Ack;
- }
- if (ack)
- devpriv->stc_writew(dev, ack, Interrupt_B_Ack_Register);
- }
- static void handle_b_interrupt(struct comedi_device *dev,
- unsigned short b_status, unsigned ao_mite_status)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV;
- /* unsigned short ack=0; */
- #ifdef DEBUG_INTERRUPT
- printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n",
- b_status, ao_mite_status);
- ni_mio_print_status_b(b_status);
- #endif
- #ifdef PCIDMA
- /* Currently, mite.c requires us to handle LINKC */
- if (ao_mite_status & CHSR_LINKC) {
- mite_handle_b_linkc(devpriv->mite, dev);
- }
- if (ao_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY |
- CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR |
- CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)) {
- printk
- ("unknown mite interrupt, ack! (ao_mite_status=%08x)\n",
- ao_mite_status);
- /* mite_print_chsr(ao_mite_status); */
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- }
- #endif
- if (b_status == 0xffff)
- return;
- if (b_status & AO_Overrun_St) {
- printk
- ("ni_mio_common: AO FIFO underrun status=0x%04x status2=0x%04x\n",
- b_status, devpriv->stc_readw(dev, AO_Status_2_Register));
- s->async->events |= COMEDI_CB_OVERFLOW;
- }
- if (b_status & AO_BC_TC_St) {
- MDPRINTK
- ("ni_mio_common: AO BC_TC status=0x%04x status2=0x%04x\n",
- b_status, devpriv->stc_readw(dev, AO_Status_2_Register));
- s->async->events |= COMEDI_CB_EOA;
- }
- #ifndef PCIDMA
- if (b_status & AO_FIFO_Request_St) {
- int ret;
- ret = ni_ao_fifo_half_empty(dev, s);
- if (!ret) {
- printk("ni_mio_common: AO buffer underrun\n");
- ni_set_bits(dev, Interrupt_B_Enable_Register,
- AO_FIFO_Interrupt_Enable |
- AO_Error_Interrupt_Enable, 0);
- s->async->events |= COMEDI_CB_OVERFLOW;
- }
- }
- #endif
- ni_event(dev, s);
- }
- #ifdef DEBUG_STATUS_A
- static const char *const status_a_strings[] = {
- "passthru0", "fifo", "G0_gate", "G0_TC",
- "stop", "start", "sc_tc", "start1",
- "start2", "sc_tc_error", "overflow", "overrun",
- "fifo_empty", "fifo_half_full", "fifo_full", "interrupt_a"
- };
- static void ni_mio_print_status_a(int status)
- {
- int i;
- printk("A status:");
- for (i = 15; i >= 0; i--) {
- if (status & (1 << i)) {
- printk(" %s", status_a_strings[i]);
- }
- }
- printk("\n");
- }
- #endif
- #ifdef DEBUG_STATUS_B
- static const char *const status_b_strings[] = {
- "passthru1", "fifo", "G1_gate", "G1_TC",
- "UI2_TC", "UPDATE", "UC_TC", "BC_TC",
- "start1", "overrun", "start", "bc_tc_error",
- "fifo_empty", "fifo_half_full", "fifo_full", "interrupt_b"
- };
- static void ni_mio_print_status_b(int status)
- {
- int i;
- printk("B status:");
- for (i = 15; i >= 0; i--) {
- if (status & (1 << i)) {
- printk(" %s", status_b_strings[i]);
- }
- }
- printk("\n");
- }
- #endif
- #ifndef PCIDMA
- static void ni_ao_fifo_load(struct comedi_device *dev,
- struct comedi_subdevice *s, int n)
- {
- struct comedi_async *async = s->async;
- struct comedi_cmd *cmd = &async->cmd;
- int chan;
- int i;
- short d;
- u32 packed_data;
- int range;
- int err = 1;
- chan = async->cur_chan;
- for (i = 0; i < n; i++) {
- err &= comedi_buf_get(async, &d);
- if (err == 0)
- break;
- range = CR_RANGE(cmd->chanlist[chan]);
- if (boardtype.reg_type & ni_reg_6xxx_mask) {
- packed_data = d & 0xffff;
- /* 6711 only has 16 bit wide ao fifo */
- if (boardtype.reg_type != ni_reg_6711) {
- err &= comedi_buf_get(async, &d);
- if (err == 0)
- break;
- chan++;
- i++;
- packed_data |= (d << 16) & 0xffff0000;
- }
- ni_writel(packed_data, DAC_FIFO_Data_611x);
- } else {
- ni_writew(d, DAC_FIFO_Data);
- }
- chan++;
- chan %= cmd->chanlist_len;
- }
- async->cur_chan = chan;
- if (err == 0) {
- async->events |= COMEDI_CB_OVERFLOW;
- }
- }
- /*
- * There's a small problem if the FIFO gets really low and we
- * don't have the data to fill it. Basically, if after we fill
- * the FIFO with all the data available, the FIFO is _still_
- * less than half full, we never clear the interrupt. If the
- * IRQ is in edge mode, we never get another interrupt, because
- * this one wasn't cleared. If in level mode, we get flooded
- * with interrupts that we can't fulfill, because nothing ever
- * gets put into the buffer.
- *
- * This kind of situation is recoverable, but it is easier to
- * just pretend we had a FIFO underrun, since there is a good
- * chance it will happen anyway. This is _not_ the case for
- * RT code, as RT code might purposely be running close to the
- * metal. Needs to be fixed eventually.
- */
- static int ni_ao_fifo_half_empty(struct comedi_device *dev,
- struct comedi_subdevice *s)
- {
- int n;
- n = comedi_buf_read_n_available(s->async);
- if (n == 0) {
- s->async->events |= COMEDI_CB_OVERFLOW;
- return 0;
- }
- n /= sizeof(short);
- if (n > boardtype.ao_fifo_depth / 2)
- n = boardtype.ao_fifo_depth / 2;
- ni_ao_fifo_load(dev, s, n);
- s->async->events |= COMEDI_CB_BLOCK;
- return 1;
- }
- static int ni_ao_prep_fifo(struct comedi_device *dev,
- struct comedi_subdevice *s)
- {
- int n;
- /* reset fifo */
- devpriv->stc_writew(dev, 1, DAC_FIFO_Clear);
- if (boardtype.reg_type & ni_reg_6xxx_mask)
- ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
- /* load some data */
- n = comedi_buf_read_n_available(s->async);
- if (n == 0)
- return 0;
- n /= sizeof(short);
- if (n > boardtype.ao_fifo_depth)
- n = boardtype.ao_fifo_depth;
- ni_ao_fifo_load(dev, s, n);
- return n;
- }
- static void ni_ai_fifo_read(struct comedi_device *dev,
- struct comedi_subdevice *s, int n)
- {
- struct comedi_async *async = s->async;
- int i;
- if (boardtype.reg_type == ni_reg_611x) {
- short data[2];
- u32 dl;
- for (i = 0; i < n / 2; i++) {
- dl = ni_readl(ADC_FIFO_Data_611x);
- /* This may get the hi/lo data in the wrong order */
- data[0] = (dl >> 16) & 0xffff;
- data[1] = dl & 0xffff;
- cfc_write_array_to_buffer(s, data, sizeof(data));
- }
- /* Check if there's a single sample stuck in the FIFO */
- if (n % 2) {
- dl = ni_readl(ADC_FIFO_Data_611x);
- data[0] = dl & 0xffff;
- cfc_write_to_buffer(s, data[0]);
- }
- } else if (boardtype.reg_type == ni_reg_6143) {
- short data[2];
- u32 dl;
- /* This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed */
- for (i = 0; i < n / 2; i++) {
- dl = ni_readl(AIFIFO_Data_6143);
- data[0] = (dl >> 16) & 0xffff;
- data[1] = dl & 0xffff;
- cfc_write_array_to_buffer(s, data, sizeof(data));
- }
- if (n % 2) {
- /* Assume there is a single sample stuck in the FIFO */
- ni_writel(0x01, AIFIFO_Control_6143); /* Get stranded sample into FIFO */
- dl = ni_readl(AIFIFO_Data_6143);
- data[0] = (dl >> 16) & 0xffff;
- cfc_write_to_buffer(s, data[0]);
- }
- } else {
- if (n > sizeof(devpriv->ai_fifo_buffer) /
- sizeof(devpriv->ai_fifo_buffer[0])) {
- comedi_error(dev, "bug! ai_fifo_buffer too small");
- async->events |= COMEDI_CB_ERROR;
- return;
- }
- for (i = 0; i < n; i++) {
- devpriv->ai_fifo_buffer[i] =
- ni_readw(ADC_FIFO_Data_Register);
- }
- cfc_write_array_to_buffer(s, devpriv->ai_fifo_buffer,
- n *
- sizeof(devpriv->ai_fifo_buffer[0]));
- }
- }
- static void ni_handle_fifo_half_full(struct comedi_device *dev)
- {
- int n;
- struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
- n = boardtype.ai_fifo_depth / 2;
- ni_ai_fifo_read(dev, s, n);
- }
- #endif
- #ifdef PCIDMA
- static int ni_ai_drain_dma(struct comedi_device *dev)
- {
- int i;
- static const int timeout = 10000;
- unsigned long flags;
- int retval = 0;
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->ai_mite_chan) {
- for (i = 0; i < timeout; i++) {
- if ((devpriv->stc_readw(dev,
- AI_Status_1_Register) &
- AI_FIFO_Empty_St)
- && mite_bytes_in_transit(devpriv->ai_mite_chan) ==
- 0)
- break;
- udelay(5);
- }
- if (i == timeout) {
- printk("ni_mio_common: wait for dma drain timed out\n");
- printk
- ("mite_bytes_in_transit=%i, AI_Status1_Register=0x%x\n",
- mite_bytes_in_transit(devpriv->ai_mite_chan),
- devpriv->stc_readw(dev, AI_Status_1_Register));
- retval = -1;
- }
- }
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- ni_sync_ai_dma(dev);
- return retval;
- }
- #endif
- /*
- Empties the AI fifo
- */
- static void ni_handle_fifo_dregs(struct comedi_device *dev)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
- short data[2];
- u32 dl;
- short fifo_empty;
- int i;
- if (boardtype.reg_type == ni_reg_611x) {
- while ((devpriv->stc_readw(dev,
- AI_Status_1_Register) &
- AI_FIFO_Empty_St) == 0) {
- dl = ni_readl(ADC_FIFO_Data_611x);
- /* This may get the hi/lo data in the wrong order */
- data[0] = (dl >> 16);
- data[1] = (dl & 0xffff);
- cfc_write_array_to_buffer(s, data, sizeof(data));
- }
- } else if (boardtype.reg_type == ni_reg_6143) {
- i = 0;
- while (ni_readl(AIFIFO_Status_6143) & 0x04) {
- dl = ni_readl(AIFIFO_Data_6143);
- /* This may get the hi/lo data in the wrong order */
- data[0] = (dl >> 16);
- data[1] = (dl & 0xffff);
- cfc_write_array_to_buffer(s, data, sizeof(data));
- i += 2;
- }
- /* Check if stranded sample is present */
- if (ni_readl(AIFIFO_Status_6143) & 0x01) {
- ni_writel(0x01, AIFIFO_Control_6143); /* Get stranded sample into FIFO */
- dl = ni_readl(AIFIFO_Data_6143);
- data[0] = (dl >> 16) & 0xffff;
- cfc_write_to_buffer(s, data[0]);
- }
- } else {
- fifo_empty =
- devpriv->stc_readw(dev,
- AI_Status_1_Register) & AI_FIFO_Empty_St;
- while (fifo_empty == 0) {
- for (i = 0;
- i <
- sizeof(devpriv->ai_fifo_buffer) /
- sizeof(devpriv->ai_fifo_buffer[0]); i++) {
- fifo_empty =
- devpriv->stc_readw(dev,
- AI_Status_1_Register) &
- AI_FIFO_Empty_St;
- if (fifo_empty)
- break;
- devpriv->ai_fifo_buffer[i] =
- ni_readw(ADC_FIFO_Data_Register);
- }
- cfc_write_array_to_buffer(s, devpriv->ai_fifo_buffer,
- i *
- sizeof(devpriv->
- ai_fifo_buffer[0]));
- }
- }
- }
- static void get_last_sample_611x(struct comedi_device *dev)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
- short data;
- u32 dl;
- if (boardtype.reg_type != ni_reg_611x)
- return;
- /* Check if there's a single sample stuck in the FIFO */
- if (ni_readb(XXX_Status) & 0x80) {
- dl = ni_readl(ADC_FIFO_Data_611x);
- data = (dl & 0xffff);
- cfc_write_to_buffer(s, data);
- }
- }
- static void get_last_sample_6143(struct comedi_device *dev)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
- short data;
- u32 dl;
- if (boardtype.reg_type != ni_reg_6143)
- return;
- /* Check if there's a single sample stuck in the FIFO */
- if (ni_readl(AIFIFO_Status_6143) & 0x01) {
- ni_writel(0x01, AIFIFO_Control_6143); /* Get stranded sample into FIFO */
- dl = ni_readl(AIFIFO_Data_6143);
- /* This may get the hi/lo data in the wrong order */
- data = (dl >> 16) & 0xffff;
- cfc_write_to_buffer(s, data);
- }
- }
- static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s,
- void *data, unsigned int num_bytes,
- unsigned int chan_index)
- {
- struct comedi_async *async = s->async;
- unsigned int i;
- unsigned int length = num_bytes / bytes_per_sample(s);
- short *array = data;
- unsigned int *larray = data;
- for (i = 0; i < length; i++) {
- #ifdef PCIDMA
- if (s->subdev_flags & SDF_LSAMPL)
- larray[i] = le32_to_cpu(larray[i]);
- else
- array[i] = le16_to_cpu(array[i]);
- #endif
- if (s->subdev_flags & SDF_LSAMPL)
- larray[i] += devpriv->ai_offset[chan_index];
- else
- array[i] += devpriv->ai_offset[chan_index];
- chan_index++;
- chan_index %= async->cmd.chanlist_len;
- }
- }
- #ifdef PCIDMA
- static int ni_ai_setup_MITE_dma(struct comedi_device *dev)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV;
- int retval;
- unsigned long flags;
- retval = ni_request_ai_mite_channel(dev);
- if (retval)
- return retval;
- /* printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel); */
- /* write alloc the entire buffer */
- comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->ai_mite_chan == NULL) {
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- return -EIO;
- }
- switch (boardtype.reg_type) {
- case ni_reg_611x:
- case ni_reg_6143:
- mite_prep_dma(devpriv->ai_mite_chan, 32, 16);
- break;
- case ni_reg_628x:
- mite_prep_dma(devpriv->ai_mite_chan, 32, 32);
- break;
- default:
- mite_prep_dma(devpriv->ai_mite_chan, 16, 16);
- break;
- }
- /*start the MITE */
- mite_dma_arm(devpriv->ai_mite_chan);
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- return 0;
- }
- static int ni_ao_setup_MITE_dma(struct comedi_device *dev)
- {
- struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV;
- int retval;
- unsigned long flags;
- retval = ni_request_ao_mite_channel(dev);
- if (retval)
- return retval;
- /* read alloc the entire buffer */
- comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz);
- spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->ao_mite_chan) {
- if (boardtype.reg_type & (ni_reg_611x | ni_reg_6713)) {
- mite_prep_dma(devpriv->ao_mite_chan, 32, 32);
- } else {
- /* doing 32 instead of 16 bit wide transfers from memory
- makes the mite do 32 bit pci transfers, doubling pci bandwidth. */
- mite_prep_dma(devpriv->ao_mite_chan, 16, 32);
- }
- mite_dma_arm(devpriv->ao_mite_chan);
- } else
- retval = -EIO;
- spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
- return retval;
- }
- #endif /* PCIDMA */
- /*
- used for both cancel ioctl and board initialization
- this is pretty harsh for a cancel, but it works...
- */
- static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s)
- {
- ni_release_ai_mite_channel(dev);
- /* ai configuration */
- devpriv->stc_writew(dev, AI_Configuration_Start | AI_Reset,
- Joint_Reset_Register);
- ni_set_bits(dev, Interrupt_A_Enable_Register,
- AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable |
- AI_START2_Interrupt_Enable | AI_START_Interrupt_Enable |
- AI_STOP_Interrupt_Enable | AI_Error_Interrupt_Enable |
- AI_FIFO_Interrupt_Enable, 0);
- ni_clear_ai_fifo(dev);
- if (boardtype.reg_type != ni_reg_6143)
- ni_writeb(0, Misc_Command);
- devpriv->stc_writew(dev, AI_Disarm, AI_Command_1_Register); /* reset pulses */
- devpriv->stc_writew(dev,
- AI_Start_Stop | AI_Mode_1_Reserved
- /*| AI_Trigger_Once */ ,
- AI_Mode_1_Register);
- devpriv->stc_writew(dev, 0x0000, AI_Mode_2_Register);
- /* generate FIFO interrupts on non-empty */
- devpriv->stc_writew(dev, (0 << 6) | 0x0000, AI_Mode_3_Register);
- if (boardtype.reg_type == ni_reg_611x) {
- devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
- AI_SOC_Polarity |
- AI_LOCALMUX_CLK_Pulse_Width,
- AI_Personal_Register);
- devpriv->stc_writew(dev,
- AI_SCAN_IN_PROG_Output_Select(3) |
- AI_EXTMUX_CLK_Output_Select(0) |
- AI_LOCALMUX_CLK_Output_Select(2) |
- AI_SC_TC_Output_Select(3) |
- AI_CONVERT_Output_Select
- (AI_CONVERT_Output_Enable_High),
- AI_Output_Control_Register);
- } else if (boardtype.reg_type == ni_reg_6143) {
- devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
- AI_SOC_Polarity |
- AI_LOCALMUX_CLK_Pulse_Width,
- AI_Personal_Register);
- devpriv->stc_writew(dev,
- AI_SCAN_IN_PROG_Output_Select(3) |
- AI_EXTMUX_CLK_Output_Select(0) |
- AI_LOCALMUX_CLK_Output_Select(2) |
- AI_SC_TC_Output_Select(3) |
- AI_CONVERT_Output_Select
- (AI_CONVERT_Output_Enable_Low),
- AI_Output_Control_Register);
- } else {
- unsigned ai_output_control_bits;
- devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
- AI_SOC_Polarity |
- AI_CONVERT_Pulse_Width |
- AI_LOCALMUX_CLK_Pulse_Width,
- AI_Personal_Register);
- ai_output_control_bits =
- AI_SCAN_IN_PROG_Output_Select(3) |
- AI_EXTMUX_CLK_Output_Select(0) |
- AI_LOCALMUX_CLK_Output_Select(2) |
- AI_SC_TC_Output_Select(3);
- if (boardtype.reg_type == ni_reg_622x)
- ai_output_control_bits |=
- AI_CONVERT_Output_Select
- (AI_CONVERT_Output_Enable_High);
- else
- ai_output_control_bits |=
- AI_CONVERT_Output_Select
- (AI_CONVERT_Output_Enable_Low);
- devpriv->stc_writew(dev, ai_output_control_bits,
- AI_Output_Control_Register);
- }
- /* the following registers should not be changed, because there
- * are no backup registers in devpriv. If you want to chang…