📄 ni_mio_common.c
字号:
/* 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, 2003 Frank Mori Hess <fmhess@users.sourceforge.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//* 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 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 - many printk's need to be changed to rt_printk()*///#define DEBUG_INTERRUPT//#define DEBUG_STATUS_A//#define DEBUG_STATUS_B#include "8255.h"#include "mite.h"#ifndef MDPRINTK#define MDPRINTK(format,args...)#endif/* A timeout count */#define NI_TIMEOUT 1000/* Note: this table must match the ai_gain_* definitions */static 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 }};static 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 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 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 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 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 comedi_lrange range_ni_E_ao_ext = { 4, { RANGE( -10, 10 ), RANGE( 0, 10 ), RANGE_ext( -1, 1 ), RANGE_ext( 0, 1 ),}};static comedi_lrange *ni_range_lkup[]={ &range_ni_E_ai, &range_ni_E_ai_limited, &range_ni_E_ai_limited14, &range_ni_E_ai_bipolar4, &range_ni_E_ai_611x,};static int ni_dio_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int ni_dio_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int ni_calib_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int ni_calib_insn_write(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int ni_eeprom_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int ni_pfi_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int ni_pfi_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static void caldac_setup(comedi_device *dev,comedi_subdevice *s);static int ni_read_eeprom(comedi_device *dev,int addr);#ifdef DEBUG_STATUS_Astatic void ni_mio_print_status_a(int status);#else#define ni_mio_print_status_a(a)#endif#ifdef DEBUG_STATUS_Bstatic void ni_mio_print_status_b(int status);#else#define ni_mio_print_status_b(a)#endifstatic int ni_ai_reset(comedi_device *dev,comedi_subdevice *s);#ifndef PCIDMAstatic void ni_handle_fifo_half_full(comedi_device *dev);static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s);#endifstatic void ni_handle_fifo_dregs(comedi_device *dev);static int ni_ai_inttrig(comedi_device *dev,comedi_subdevice *s, unsigned int trignum);static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan, unsigned int *list);static int ni_ao_inttrig(comedi_device *dev,comedi_subdevice *s, unsigned int trignum);static int ni_ao_reset(comedi_device *dev,comedi_subdevice *s);static int ni_8255_callback(int dir,int port,int data,unsigned long arg);static int ni_ns_to_timer(int *nanosec,int round_mode);/*GPCT function def's*/static int GPCT_G_Watch(comedi_device *dev, int chan);static void GPCT_Reset(comedi_device *dev, int chan);static void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length);static void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length);static void GPCT_Period_Meas(comedi_device *dev, int chan);static void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan);static void GPCT_Event_Counting(comedi_device *dev,int chan);static int GPCT_Set_Direction(comedi_device *dev,int chan,int direction);static int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate);static int GPCT_Set_Source(comedi_device *dev,int chan ,int source);static int ni_gpct_insn_write(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int ni_gpct_insn_read(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);enum aimodes{ AIMODE_NONE = 0, AIMODE_HALF_FULL = 1, AIMODE_SCAN = 2, AIMODE_SAMPLE = 3,};static const int num_adc_stages_611x = 3;static void handle_a_interrupt(comedi_device *dev,unsigned short status, unsigned int m_status);static void handle_b_interrupt(comedi_device *dev,unsigned short status, unsigned int m_status);static void get_last_sample_611x( comedi_device *dev );#ifdef PCIDMA//static void mite_handle_interrupt(comedi_device *dev,unsigned int status);static int ni_ai_drain_dma(comedi_device *dev );#endif/* 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(comedi_device *dev, int reg, int bits, int value){ unsigned long flags; comedi_spin_lock_irqsave( &dev->spinlock, flags ); switch (reg){ case Interrupt_A_Enable_Register: if(value) devpriv->int_a_enable_reg |= bits; else devpriv->int_a_enable_reg &= ~bits; comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); win_out(devpriv->int_a_enable_reg,Interrupt_A_Enable_Register); break; case Interrupt_B_Enable_Register: if(value) devpriv->int_b_enable_reg |= bits; else devpriv->int_b_enable_reg &= ~bits; comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); win_out(devpriv->int_b_enable_reg,Interrupt_B_Enable_Register); break; case IO_Bidirection_Pin_Register: if(value) devpriv->io_bidirection_pin_reg |= bits; else devpriv->io_bidirection_pin_reg &= ~bits; comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); win_out(devpriv->io_bidirection_pin_reg,IO_Bidirection_Pin_Register); break; default: printk("Warning ni_set_bits() called with invalid arguments\n"); printk("reg is %d\n",reg); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); break; }}static void ni_E_interrupt(int irq,void *d,struct pt_regs * regs){ comedi_device *dev=d; unsigned short a_status; unsigned short b_status; unsigned int m0_status; unsigned int m1_status;#ifdef PCIDMA struct mite_struct *mite = devpriv->mite;#endif a_status=win_in(AI_Status_1_Register); b_status=win_in(AO_Status_1_Register);#ifdef PCIDMA m0_status=readl(mite->mite_io_addr+MITE_CHSR+CHAN_OFFSET(AI_DMA_CHAN)); m1_status=readl(mite->mite_io_addr+MITE_CHSR+CHAN_OFFSET(AO_DMA_CHAN));#else m0_status = 0; m1_status = 0;#endif if(a_status&Interrupt_A_St || m0_status & CHSR_INT ) handle_a_interrupt(dev, a_status, m0_status); if(b_status&Interrupt_B_St || m1_status & CHSR_INT ) handle_b_interrupt(dev, b_status, m1_status);}#ifdef PCIDMAstatic void ni_sync_ai_dma(struct mite_struct *mite, comedi_device *dev){ int count; comedi_subdevice *s = dev->subdevices + 0; comedi_async *async = s->async; unsigned int nbytes, old_alloc_count; unsigned int bytes_per_scan = 2 * async->cmd.chanlist_len; writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(AI_DMA_CHAN)); old_alloc_count = async->buf_write_alloc_count; // write alloc as much as we can comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); nbytes = mite_bytes_transferred(mite, AI_DMA_CHAN); if( (int)(nbytes - old_alloc_count) > 0 ){ printk("ni_mio_common: DMA overwrite of free area\n"); ni_ai_reset(dev,s); async->events |= COMEDI_CB_OVERFLOW; return; } count = nbytes - async->buf_write_count; if( count < 0 ){ rt_printk("ni_mio_common: BUG: negative ai count\n"); count = 0; } comedi_buf_munge(dev, s, count); comedi_buf_write_free(async, count); async->scan_progress += count; if( async->scan_progress >= bytes_per_scan ) { async->scan_progress %= bytes_per_scan; async->events |= COMEDI_CB_EOS; } async->events |= COMEDI_CB_BLOCK;}static void mite_handle_b_linkc(struct mite_struct *mite, comedi_device *dev){ int count; comedi_subdevice *s = dev->subdevices + 1; comedi_async *async = s->async; unsigned int nbytes, new_write_count; writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(AO_DMA_CHAN)); new_write_count = async->buf_write_count; nbytes = mite_bytes_read(mite, AO_DMA_CHAN); if( async->cmd.stop_src == TRIG_COUNT && (int) (nbytes - async->cmd.stop_arg * sizeof( sampl_t ) ) > 0 ) nbytes = async->cmd.stop_arg * sizeof( sampl_t ); if( (int)(nbytes - devpriv->last_buf_write_count) > 0 ){ rt_printk("ni_mio_common: DMA underrun\n"); ni_ao_reset(dev,s); async->events |= COMEDI_CB_OVERFLOW; return; } devpriv->last_buf_write_count = new_write_count; count = nbytes - async->buf_read_count; if( count < 0 ){ rt_printk("ni_mio_common: BUG: negative ao count\n"); count = 0; } comedi_buf_read_free(async, count); async->events |= COMEDI_CB_BLOCK;}#if 0static void mite_handle_interrupt(comedi_device *dev,unsigned int m_status){ int len; comedi_subdevice *s = dev->subdevices+0; comedi_async *async = s->async; struct mite_struct *mite = devpriv->mite; async->events |= COMEDI_CB_BLOCK; MDPRINTK("mite_handle_interrupt: m_status=%08x\n",m_status); if(m_status & CHSR_DONE){ writel(CHOR_CLRDONE, mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(0)); }#if 0 len = sizeof(sampl_t)*async->cmd.stop_arg*async->cmd.scan_end_arg; if((devpriv->mite->DMA_CheckNearEnd) && (s->async->buf_int_count > (len - s->async->prealloc_bufsz))) { long offset; int i; offset = len % async->prealloc_bufsz; if(offset < mite->ring[0].count) { mite->ring[0].count = offset; mite->ring[1].count = 0; }else{ offset -= mite->ring[0].count; i = offset >> PAGE_SHIFT; mite->ring[i].count = offset & ~PAGE_MASK; mite->ring[(i+1)%mite->n_links].count = 0; } mite->DMA_CheckNearEnd = 0; }#endif#if 0 MDPRINTK("CHSR is 0x%08x, count is %d\n",m_status,async->buf_int_count); if(m_status&CHSR_DONE){ writel(CHOR_CLRDONE, mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(mite->chan)); //printk("buf_int_count is %d, buf_int_ptr is %d\n", // s->async->buf_int_count,s->async->buf_int_ptr); ni_handle_block_dma(dev); } MDPRINTK("exit mite_handle_interrupt\n");#endif //comedi_event(dev,s,async->events);}#endifstatic int ni_ao_wait_for_dma_load( comedi_device *dev ){ static const int timeout = 10000; int i; for( i = 0; i < timeout; i++ ) { unsigned short b_status; b_status = win_in( AO_Status_1_Register ); if( b_status & AO_FIFO_Half_Full_St ) break; } if( i == timeout ) return -EPIPE; return 0;}#endif //PCIDMAstatic void shutdown_ai_command( comedi_device *dev ){ comedi_subdevice *s = dev->subdevices + 0;#ifdef PCIDMA ni_ai_drain_dma( dev ); mite_dma_disarm(devpriv->mite, AI_DMA_CHAN);#endif ni_handle_fifo_dregs(dev); get_last_sample_611x(dev); 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); s->async->events |= COMEDI_CB_EOA;}static void handle_a_interrupt(comedi_device *dev,unsigned short status, unsigned int m_status){ comedi_subdevice *s=dev->subdevices+0; //comedi_async *async = s->async; unsigned short ack=0; s->async->events = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -