-
-/*
- 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>
-
- 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 TRY_BLOCK
-#define DEBUG_STATUS_A
-//#define DEBUG_STATUS_B
-
-#include <8255.h>
-
-#ifndef MDPRINTK
-#define MDPRINTK(format,args...)
-#endif
-
-/* reference: ground, common, differential, other */
-static int ni_modebits1[4]={ 0x3000, 0x2000, 0x1000, 0 };
-static int ni_modebits2[4]={ 0x3f, 0x3f, 0x37, 0x37 };
-
-static int ni_gainlkup[][16]={
- { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
- { 1, 2, 4, 7, 9, 10, 12, 15, 0,0,0,0,0,0,0,0 },
- { 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 0,0 },
- { 0, 1, 4, 7, 8, 9, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 4, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-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 ),
-}};
-#if 0
-static comedi_lrange range_ni_E_ao = { 2, {
- RANGE( -10, 10 ),
- RANGE( 0, 10 ),
-}};
-#endif
-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,
-};
-
-
-
-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 void caldac_setup(comedi_device *dev,comedi_subdevice *s);
-static int ni_read_eeprom(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(comedi_device *dev,comedi_subdevice *s);
-static void ni_handle_fifo_half_full(comedi_device *dev);
-static void ni_handle_fifo_dregs(comedi_device *dev);
-#ifdef TRY_BLOCK
-static void ni_handle_block(comedi_device *dev);
-#endif
-#ifdef PCIDMA
-static void ni_handle_block_dma(comedi_device *dev);
-#endif
-static int ni_ai_inttrig(comedi_device *dev,comedi_subdevice *s,
- unsigned int trignum);
-
-static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s);
-
-static int ni_8255_callback(int dir,int port,int data,void *arg);
-
-static int ni_ns_to_timer(int *nanosec,int round_mode);
-
-//static int gpct_setup(comedi_device *dev,comedi_subdevice *s);
-static int ni_gpct_insn_config(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 void pfi_setup(comedi_device *dev);
-
-/*GPCT function def's*/
-int GPCT_G_Watch(comedi_device *dev, int chan);
-
-void GPCT_Reset(comedi_device *dev, int chan);
-void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length);
-void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length);
-void GPCT_Period_Meas(comedi_device *dev, int chan);
-void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan);
-void GPCT_Event_Counting(comedi_device *dev,int chan);
-int GPCT_Set_Direction(comedi_device *dev,int chan,int direction);
-int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate);
-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);
-
-#undef DEBUG
-
-#define AIMODE_NONE 0
-#define AIMODE_HALF_FULL 1
-#define AIMODE_SCAN 2
-#define AIMODE_SAMPLE 3
-
-static void handle_a_interrupt(comedi_device *dev,unsigned short status);
-static void handle_b_interrupt(comedi_device *dev,unsigned short status);
-#ifdef PCIDMA
-/*status must be long because the CHSR is 32 bits and the high bits
-are important to us */
-static void mite_handle_interrupt(comedi_device *dev,unsigned long status);
-void ni_munge(comedi_device *dev,comedi_subdevice *s,sampl_t *start, sampl_t *stop);
-#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. Use comedi_spin_lock_irqsave() and comedi_spin_unlock_irqrestore()
-* if you use this to modify the interrupt enable registers...which are sometimes
-* changed in ISRs
-*
-* 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.
-*/
-void inline ni_set_bits(comedi_device *dev, int reg, int bits, int value) {
-
- switch (reg){
- case Interrupt_A_Enable_Register:
- if(value)
- devpriv->int_a_enable_reg |= bits;
- else
- devpriv->int_a_enable_reg &= ~bits;
- 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;
- 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;
- 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);
- 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;
- int wsave;
-#ifdef PCIDMA
- /* m_status must be long because the CHSR is a 32 bit register and we are
- interested in several high bits */
- unsigned long m_status;
-#endif
-
- MDPRINTK("ni_E_Interrupt\n");
-/*
- If you want to use windowed registers in an interrupt, it is
- important that you restore the window address register. If
- you change certain modes, e.g., AI_Configuration_Start/End,
- you need to set up software flags for non-interrupt routines.
-*/
- wsave=win_save();
-
- a_status=ni_readw(AI_Status_1);
- b_status=ni_readw(AO_Status_1);
-#ifdef PCIDMA
- m_status=readl(devpriv->mite->mite_io_addr+MITE_CHSR+CHAN_OFFSET(0));
-#endif
-#ifdef DEBUG_INTERRUPT
- rt_printk("ni_mio_common: interrupt: a_status=%04x b_status=%04x\n",
- a_status,b_status);
- ni_mio_print_status_a(a_status);
- ni_mio_print_status_b(b_status);
-#endif
-#ifdef PCIDMA
- //rt_printk("mite status=0x%08lx\n",m_status);
- if(m_status&CHSR_INT)mite_handle_interrupt(dev,m_status);
-#endif
- if(a_status&Interrupt_A_St)handle_a_interrupt(dev,a_status);
- if(b_status&Interrupt_B_St)handle_b_interrupt(dev,b_status);
-
- win_restore(wsave);
- MDPRINTK("exit ni_E_Interrupt\n");
-}
-
-#ifdef PCIDMA
-static void mite_handle_interrupt(comedi_device *dev,unsigned long m_status)
-{
- comedi_subdevice *s=dev->subdevices+0;
-
- comedi_event(dev,s,COMEDI_CB_BLOCK);
-
- MDPRINTK("mite_handle_interrupt\n");
- writel(CHOR_CLRLC, devpriv->mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(0));
-#if 0
- //Don't munge the data, just update the user's status variables
- s->async->buf_int_count=mite_bytes_transferred(devpriv->mite, 0);
- s->async->buf_int_ptr= s->async->buf_int_count % s->async->prealloc_bufsz;
-#else
- //Munge the ADC data to change its format from twos complement to unsigned int
- //This is slow but makes it more compatible with other cards
- {
- unsigned int raw_ptr;
- s->async->buf_int_count = mite_bytes_transferred(devpriv->mite, 0);
- raw_ptr = s->async->buf_int_count % s->async->prealloc_bufsz;
- if(s->async->buf_int_ptr > raw_ptr) {
- ni_munge(dev,s,s->async->buf_int_ptr+s->async->prealloc_buf,
- s->async->prealloc_buf+s->async->prealloc_bufsz);
- s->async->buf_int_ptr = 0;
- }
- ni_munge(dev,s,s->async->buf_int_ptr+s->async->prealloc_buf,
- raw_ptr+s->async->prealloc_buf);
- s->async->buf_int_ptr = raw_ptr;
- }
-#endif
- MDPRINTK("CHSR is 0x%08lx, count is %d\n",m_status,s->async->buf_int_count);
- if(m_status&CHSR_DONE){
- writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(0));
- //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");
- return;
-}
-
-#endif //PCIDMA
-
-static void handle_a_interrupt(comedi_device *dev,unsigned short status)
-{
- comedi_subdevice *s=dev->subdevices+0;
- unsigned short ack=0;
-
- s->async->events = 0;
-
- /* uncommon interrupt events */
- if(status&(AI_Overrun_St|AI_Overflow_St|AI_SC_TC_Error_St|AI_SC_TC_St|AI_START1_St)){
- if(status==0xffff){
- rt_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(s->subdev_flags&SDF_RUNNING)comedi_done(dev,s);
- return;
- }
- if(status&(AI_Overrun_St|AI_Overflow_St|AI_SC_TC_Error_St)){
- rt_printk("ni_mio_common: ai error a_status=%04x\n",
- status);
- ni_mio_print_status_a(status);
-
- //TIM 5/11/01
- win_out(AI_Error_Interrupt_Ack, Interrupt_A_Ack_Register);
-
- #ifndef PCIDMA
- ni_handle_fifo_dregs(dev);
+\r
+/*\r
+ comedi/drivers/ni_mio_common.c\r
+ Hardware driver for DAQ-STC based boards\r
+\r
+ COMEDI - Linux Control and Measurement Device Interface\r
+ Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+/*\r
+ This file is meant to be included by another file, e.g.,\r
+ ni_atmio.c or ni_pcimio.c.\r
+\r
+ Interrupt support originally added by Truxton Fulton\r
+ <trux@truxton.com>\r
+\r
+ References (from ftp://ftp.natinst.com/support/manuals):\r
+ \r
+ 340747b.pdf AT-MIO E series Register Level Programmer Manual\r
+ 341079b.pdf PCI E Series RLPM\r
+ 340934b.pdf DAQ-STC reference manual\r
+\r
+ Other possibly relevant info:\r
+ \r
+ 320517c.pdf User manual (obsolete)\r
+ 320517f.pdf User manual (new)\r
+ 320889a.pdf delete\r
+ 320906c.pdf maximum signal ratings\r
+ 321066a.pdf about 16x\r
+ 321791a.pdf discontinuation of at-mio-16e-10 rev. c\r
+ 321808a.pdf about at-mio-16e-10 rev P\r
+ 321837a.pdf discontinuation of at-mio-16de-10 rev d\r
+ 321838a.pdf about at-mio-16de-10 rev N\r
+ \r
+ ISSUES:\r
+\r
+ - the interrupt routine needs to be cleaned up\r
+ - many printk's need to be changed to rt_printk()\r
+*/\r
+\r
+//#define DEBUG_INTERRUPT\r
+//#define TRY_BLOCK\r
+#define DEBUG_STATUS_A\r
+//#define DEBUG_STATUS_B\r
+\r
+#include "8255.h"\r
+\r
+#ifndef MDPRINTK\r
+#define MDPRINTK(format,args...)\r
+#endif\r
+\r
+/* reference: ground, common, differential, other */\r
+static int ni_modebits1[4]={ 0x3000, 0x2000, 0x1000, 0 };\r
+static int ni_modebits2[4]={ 0x3f, 0x3f, 0x37, 0x37 };\r
+\r
+static int ni_gainlkup[][16]={\r
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },\r
+ { 1, 2, 4, 7, 9, 10, 12, 15, 0,0,0,0,0,0,0,0 },\r
+ { 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 0,0 },\r
+ { 0, 1, 4, 7, 8, 9, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0 },\r
+ { 0, 1, 4, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }\r
+};\r
+\r
+static comedi_lrange range_ni_E_ai={ 16, {\r
+ RANGE( -10, 10 ),\r
+ RANGE( -5, 5 ),\r
+ RANGE( -2.5, 2.5 ),\r
+ RANGE( -1, 1 ),\r
+ RANGE( -0.5, 0.5 ),\r
+ RANGE( -0.25, 0.25 ),\r
+ RANGE( -0.1, 0.1 ),\r
+ RANGE( -0.05, 0.05 ),\r
+ RANGE( 0, 20 ),\r
+ RANGE( 0, 10 ),\r
+ RANGE( 0, 5 ),\r
+ RANGE( 0, 2 ),\r
+ RANGE( 0, 1 ),\r
+ RANGE( 0, 0.5 ),\r
+ RANGE( 0, 0.2 ),\r
+ RANGE( 0, 0.1 ),\r
+}};\r
+static comedi_lrange range_ni_E_ai_limited={ 8, {\r
+ RANGE( -10, 10 ),\r
+ RANGE( -5, 5 ),\r
+ RANGE( -1, 1 ),\r
+ RANGE( -0.1, 0.1 ),\r
+ RANGE( 0, 10 ),\r
+ RANGE( 0, 5 ),\r
+ RANGE( 0, 1 ),\r
+ RANGE( 0, 0.1 ),\r
+}};\r
+static comedi_lrange range_ni_E_ai_limited14={ 14, {\r
+ RANGE( -10, 10 ),\r
+ RANGE( -5, 5 ),\r
+ RANGE( -2, 2 ),\r
+ RANGE( -1, 1 ),\r
+ RANGE( -0.5, 0.5 ),\r
+ RANGE( -0.2, 0.2 ),\r
+ RANGE( -0.1, 0.1 ),\r
+ RANGE( 0, 10 ),\r
+ RANGE( 0, 5 ),\r
+ RANGE( 0, 2 ),\r
+ RANGE( 0, 1 ),\r
+ RANGE( 0, 0.5 ),\r
+ RANGE( 0, 0.2 ),\r
+ RANGE( 0, 0.1 ),\r
+}};\r
+static comedi_lrange range_ni_E_ai_bipolar4={ 4, {\r
+ RANGE( -10, 10 ),\r
+ RANGE( -5, 5 ),\r
+ RANGE( -0.5, 0.5 ),\r
+ RANGE( -0.05, 0.05 ),\r
+}};\r
+#if 0\r
+static comedi_lrange range_ni_E_ao = { 2, {\r
+ RANGE( -10, 10 ),\r
+ RANGE( 0, 10 ),\r
+}};\r
+#endif\r
+static comedi_lrange range_ni_E_ao_ext = { 4, {\r
+ RANGE( -10, 10 ),\r
+ RANGE( 0, 10 ),\r
+ RANGE_ext( -1, 1 ),\r
+ RANGE_ext( 0, 1 ),\r
+}};\r
+\r
+static comedi_lrange *ni_range_lkup[]={\r
+ &range_ni_E_ai,\r
+ &range_ni_E_ai_limited,\r
+ &range_ni_E_ai_limited14,\r
+ &range_ni_E_ai_bipolar4,\r
+};\r
+\r
+\r
+\r
+static int ni_dio_insn_config(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+static int ni_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+\r
+static int ni_calib_insn_read(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+static int ni_calib_insn_write(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+\r
+static int ni_eeprom_insn_read(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+\r
+static void caldac_setup(comedi_device *dev,comedi_subdevice *s);\r
+static int ni_read_eeprom(comedi_device *dev,int addr);\r
+\r
+#ifdef DEBUG_STATUS_A\r
+static void ni_mio_print_status_a(int status);\r
+#else\r
+#define ni_mio_print_status_a(a)\r
+#endif\r
+#ifdef DEBUG_STATUS_B\r
+static void ni_mio_print_status_b(int status);\r
+#else\r
+#define ni_mio_print_status_b(a)\r
+#endif\r
+\r
+static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s);\r
+static void ni_handle_fifo_half_full(comedi_device *dev);\r
+static void ni_handle_fifo_dregs(comedi_device *dev);\r
+#ifdef TRY_BLOCK\r
+static void ni_handle_block(comedi_device *dev);\r
+#endif\r
+#ifdef PCIDMA\r
+static void ni_handle_block_dma(comedi_device *dev);\r
+#endif\r
+static int ni_ai_inttrig(comedi_device *dev,comedi_subdevice *s,\r
+ unsigned int trignum);\r
+\r
+static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s);\r
+\r
+static int ni_8255_callback(int dir,int port,int data,void *arg);\r
+\r
+static int ni_ns_to_timer(int *nanosec,int round_mode);\r
+\r
+//static int gpct_setup(comedi_device *dev,comedi_subdevice *s);\r
+static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+static int ni_gpct_insn_read(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+\r
+static void pfi_setup(comedi_device *dev);\r
+\r
+/*GPCT function def's*/\r
+int GPCT_G_Watch(comedi_device *dev, int chan);\r
+\r
+void GPCT_Reset(comedi_device *dev, int chan);\r
+void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length);\r
+void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length);\r
+void GPCT_Period_Meas(comedi_device *dev, int chan);\r
+void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan);\r
+void GPCT_Event_Counting(comedi_device *dev,int chan);\r
+int GPCT_Set_Direction(comedi_device *dev,int chan,int direction);\r
+int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate);\r
+int GPCT_Set_Source(comedi_device *dev,int chan ,int source);\r
+\r
+static int ni_gpct_insn_write(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+static int ni_gpct_insn_read(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data);\r
+\r
+#undef DEBUG\r
+\r
+#define AIMODE_NONE 0\r
+#define AIMODE_HALF_FULL 1\r
+#define AIMODE_SCAN 2\r
+#define AIMODE_SAMPLE 3\r
+\r
+static void handle_a_interrupt(comedi_device *dev,unsigned short status);\r
+static void handle_b_interrupt(comedi_device *dev,unsigned short status);\r
+#ifdef PCIDMA\r
+/*status must be long because the CHSR is 32 bits and the high bits\r
+are important to us */\r
+static void mite_handle_interrupt(comedi_device *dev,unsigned long status);\r
+void ni_munge(comedi_device *dev,comedi_subdevice *s,sampl_t *start, sampl_t *stop);\r
+#endif\r
+\r
+/* ni_set_bits( ) allows different parts of the ni_mio_common driver to \r
+* share registers (such as Interrupt_A_Register) without interfering with\r
+* each other. Use comedi_spin_lock_irqsave() and comedi_spin_unlock_irqrestore()\r
+* if you use this to modify the interrupt enable registers...which are sometimes\r
+* changed in ISRs\r
+*\r
+* NOTE: the switch/case statements are optimized out for a constant argument\r
+* so this is actually quite fast--- If you must wrap another function around this\r
+* make it inline to avoid a large speed penalty.\r
+*\r
+* value should only be 1 or 0.\r
+*/\r
+void inline ni_set_bits(comedi_device *dev, int reg, int bits, int value) {\r
+ \r
+ switch (reg){\r
+ case Interrupt_A_Enable_Register:\r
+ if(value)\r
+ devpriv->int_a_enable_reg |= bits;\r
+ else\r
+ devpriv->int_a_enable_reg &= ~bits;\r
+ win_out(devpriv->int_a_enable_reg,Interrupt_A_Enable_Register);\r
+ break;\r
+ case Interrupt_B_Enable_Register:\r
+ if(value)\r
+ devpriv->int_b_enable_reg |= bits;\r
+ else\r
+ devpriv->int_b_enable_reg &= ~bits;\r
+ win_out(devpriv->int_b_enable_reg,Interrupt_B_Enable_Register);\r
+ break;\r
+ case IO_Bidirection_Pin_Register:\r
+ if(value)\r
+ devpriv->io_bidirection_pin_reg |= bits;\r
+ else\r
+ devpriv->io_bidirection_pin_reg &= ~bits;\r
+ win_out(devpriv->io_bidirection_pin_reg,IO_Bidirection_Pin_Register);\r
+ break;\r
+ default:\r
+ printk("Warning ni_set_bits() called with invalid arguments\n");\r
+ printk("reg is %d\n",reg);\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+static\r
+void ni_E_interrupt(int irq,void *d,struct pt_regs * regs)\r
+{\r
+ comedi_device *dev=d;\r
+ unsigned short a_status;\r
+ unsigned short b_status;\r
+ int wsave;\r
+#ifdef PCIDMA\r
+ /* m_status must be long because the CHSR is a 32 bit register and we are\r
+ interested in several high bits */\r
+ unsigned long m_status;\r
+#endif\r
+\r
+ MDPRINTK("ni_E_Interrupt\n");\r
+/*\r
+ If you want to use windowed registers in an interrupt, it is\r
+ important that you restore the window address register. If\r
+ you change certain modes, e.g., AI_Configuration_Start/End,\r
+ you need to set up software flags for non-interrupt routines.\r
+*/\r
+ wsave=win_save();\r
+ \r
+ a_status=ni_readw(AI_Status_1);\r
+ b_status=ni_readw(AO_Status_1);\r
+#ifdef PCIDMA\r
+ m_status=readl(devpriv->mite->mite_io_addr+MITE_CHSR+CHAN_OFFSET(0));\r
+#endif\r
+#ifdef DEBUG_INTERRUPT\r
+ rt_printk("ni_mio_common: interrupt: a_status=%04x b_status=%04x\n",\r
+ a_status,b_status);\r
+ ni_mio_print_status_a(a_status);\r
+ ni_mio_print_status_b(b_status);\r
+#endif\r
+#ifdef PCIDMA\r
+ //rt_printk("mite status=0x%08lx\n",m_status);\r
+ if(m_status&CHSR_INT)mite_handle_interrupt(dev,m_status);\r
+#endif\r
+ if(a_status&Interrupt_A_St)handle_a_interrupt(dev,a_status);\r
+ if(b_status&Interrupt_B_St)handle_b_interrupt(dev,b_status);\r
+ \r
+ win_restore(wsave);\r
+ MDPRINTK("exit ni_E_Interrupt\n");\r
+}\r
+\r
+#ifdef PCIDMA\r
+static void mite_handle_interrupt(comedi_device *dev,unsigned long m_status)\r
+{\r
+ comedi_subdevice *s=dev->subdevices+0;\r
+ \r
+ comedi_event(dev,s,COMEDI_CB_BLOCK);\r
+\r
+ MDPRINTK("mite_handle_interrupt\n");\r
+ writel(CHOR_CLRLC, devpriv->mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(0));\r
+#if 0\r
+ //Don't munge the data, just update the user's status variables\r
+ s->async->buf_int_count=mite_bytes_transferred(devpriv->mite, 0);\r
+ s->async->buf_int_ptr= s->async->buf_int_count % s->async->prealloc_bufsz; \r
+#else\r
+ //Munge the ADC data to change its format from twos complement to unsigned int\r
+ //This is slow but makes it more compatible with other cards\r
+ { \r
+ unsigned int raw_ptr;\r
+ s->async->buf_int_count = mite_bytes_transferred(devpriv->mite, 0);\r
+ raw_ptr = s->async->buf_int_count % s->async->prealloc_bufsz;\r
+ if(s->async->buf_int_ptr > raw_ptr) {\r
+ ni_munge(dev,s,s->async->buf_int_ptr+s->async->prealloc_buf, \r
+ s->async->prealloc_buf+s->async->prealloc_bufsz);\r
+ s->async->buf_int_ptr = 0;\r
+ }\r
+ ni_munge(dev,s,s->async->buf_int_ptr+s->async->prealloc_buf, \r
+ raw_ptr+s->async->prealloc_buf);\r
+ s->async->buf_int_ptr = raw_ptr;\r
+ }\r
+#endif\r
+ MDPRINTK("CHSR is 0x%08lx, count is %d\n",m_status,s->async->buf_int_count);\r
+ if(m_status&CHSR_DONE){\r
+ writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr+MITE_CHOR+CHAN_OFFSET(0));\r
+ //printk("buf_int_count is %d, buf_int_ptr is %d\n",\r
+ // s->async->buf_int_count,s->async->buf_int_ptr);\r
+ ni_handle_block_dma(dev);\r
+ } \r
+ MDPRINTK("exit mite_handle_interrupt\n");\r
+ return; \r
+} \r
+\r
+#endif //PCIDMA\r
+\r
+static void handle_a_interrupt(comedi_device *dev,unsigned short status)\r
+{\r
+ comedi_subdevice *s=dev->subdevices+0;\r
+ unsigned short ack=0;\r
+\r
+ s->async->events = 0;\r
+\r
+ /* uncommon interrupt events */\r
+ if(status&(AI_Overrun_St|AI_Overflow_St|AI_SC_TC_Error_St|AI_SC_TC_St|AI_START1_St)){\r
+ if(status==0xffff){\r
+ rt_printk("ni_mio_common: a_status=0xffff. Card removed?\n");\r
+ /* we probably aren't even running a command now,\r
+ * so it's a good idea to be careful. */\r
+ if(s->subdev_flags&SDF_RUNNING)comedi_done(dev,s);\r
+ return;\r
+ }\r
+ if(status&(AI_Overrun_St|AI_Overflow_St|AI_SC_TC_Error_St)){\r
+ rt_printk("ni_mio_common: ai error a_status=%04x\n",\r
+ status);\r
+ ni_mio_print_status_a(status);\r
+ \r
+ //TIM 5/11/01\r
+ win_out(AI_Error_Interrupt_Ack, Interrupt_A_Ack_Register);\r
+ \r
+ #ifndef PCIDMA\r
+ ni_handle_fifo_dregs(dev);\r
#endif \r
-
- //TIM 4/17/01
- //win_out(0x0000,Interrupt_A_Enable_Register);
- //turn off all AI interrupts
- 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_ai_reset(dev,dev->subdevices);//added by tim
- comedi_done(dev,s);
- return;
- }
- if(status&AI_SC_TC_St){
-#ifdef DEBUG_INTERRUPT
- rt_printk("ni_mio_common: SC_TC interrupt\n");
-#endif
-#ifdef TRY_BLOCK
- ni_handle_block(dev);
-#else
- //for MITE DMA ignore the terminal count from the STC
- //instead finish up when the MITE asserts DONE
-#ifndef PCIDMA
-
- if(!devpriv->ai_continuous){
- ni_handle_fifo_dregs(dev);
- //win_out(0x0000,Interrupt_A_Enable_Register); TIM 4/17/01
- 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);
-
- comedi_done(dev,s);
- }
-#endif //PCIDMA
-#endif //TRY_BLOCK
- ack|=AI_SC_TC_Interrupt_Ack;
- }
- if(status&AI_START1_St){
- ack|=AI_START1_Interrupt_Ack;
- }
- }
-#ifndef PCIDMA
- if(status&AI_FIFO_Half_Full_St){
- ni_handle_fifo_half_full(dev);
- }
-#endif //PCIDMA
- if(devpriv->aimode==AIMODE_SCAN && status&AI_STOP_St){
- ni_handle_fifo_dregs(dev);
-
- s->async->events |= COMEDI_CB_EOS;
-
- /* we need to ack the START, also */
- ack|=AI_STOP_Interrupt_Ack|AI_START_Interrupt_Ack;
- }
- if(devpriv->aimode==AIMODE_SAMPLE){
- ni_handle_fifo_dregs(dev);
-
- //s->async->events |= COMEDI_CB_SAMPLE;
- }
-
- if(ack) ni_writew(ack,Interrupt_A_Ack);
-
- comedi_event(dev,s,s->async->events);
-}
-
-static void handle_b_interrupt(comedi_device *dev,unsigned short b_status)
-{
- comedi_subdevice *s=dev->subdevices+1;
- //unsigned short ack=0;
-
- if(b_status==0xffff)return;
- if(b_status&AO_Overrun_St){
- rt_printk("ni-E: AO FIFO underrun status=0x%04x status2=0x%04x\n",b_status,ni_readw(AO_Status_2));
- }
-
- if(b_status&AO_BC_TC_St){
- rt_printk("ni-E: AO BC_TC status=0x%04x status2=0x%04x\n",b_status,ni_readw(AO_Status_2));
- }
-
- if(b_status&AO_FIFO_Request_St)
- ni_ao_fifo_half_empty(dev,s);
-
- b_status=ni_readw(AO_Status_1);
- if(b_status&Interrupt_B_St){
- if(b_status&AO_FIFO_Request_St){
- rt_printk("ni_mio_common: AO buffer underrun\n");
- }
- rt_printk("Ack! didn't clear AO interrupt. b_status=0x%04x\n",b_status);
- win_out(0,Interrupt_B_Enable_Register);
- }
-}
-
-#ifdef DEBUG_STATUS_A
-static char *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;
-
- rt_printk("A status:");
- for(i=15;i>=0;i--){
- if(status&(1<<i)){
- rt_printk(" %s",status_a_strings[i]);
- }
- }
- rt_printk("\n");
-}
-#endif
-
-#ifdef DEBUG_STATUS_B
-static char *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;
-
- rt_printk("B status:");
- for(i=15;i>=0;i--){
- if(status&(1<<i)){
- rt_printk(" %s",status_b_strings[i]);
- }
- }
- rt_printk("\n");
-}
-#endif
-
-static void ni_ai_fifo_read(comedi_device *dev,comedi_subdevice *s,
- sampl_t *data,int n)
-{
- comedi_async *async = s->async;
- int i,j;
- sampl_t d;
- unsigned int mask;
-
- mask=(1<<boardtype.adbits)-1;
- j=async->cur_chan;
- for(i=0;i<n;i++){
- d=ni_readw(ADC_FIFO_Data_Register);
- d^=devpriv->ai_xorlist[j];
- d&=mask;
- data[i]=d;
- j++;
- if(j>=async->cur_chanlist_len){
- j=0;
- async->events |= COMEDI_CB_EOS;
- }
- }
- async->cur_chan=j;
-}
-
-#ifdef PCIDMA
-void ni_munge(comedi_device *dev,comedi_subdevice *s,sampl_t *start, sampl_t *stop)
-{
- comedi_async *async = s->async;
- int j;
- sampl_t *i;
- unsigned int mask;
-
- mask=(1<<boardtype.adbits)-1;
- j=async->cur_chan;
- for(i=start;i<stop;i++){
- *i ^=devpriv->ai_xorlist[j];
- *i &=mask;
- j++;
- j %= async->cur_chanlist_len;
- }
- async->cur_chan=j;
-}
-
-static void ni_handle_block_dma(comedi_device *dev)
-{
- MDPRINTK("ni_handle_block_dma\n");
- //mite_dump_regs(devpriv->mite);
- mite_dma_disarm(devpriv->mite);
- //TIM 4/17/01 win_out(0x0000,Interrupt_A_Enable_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_ai_reset(dev,dev->subdevices);
- comedi_done(dev,dev->subdevices);
- MDPRINTK("exit ni_handle_block_dma\n");
-}
-#endif
-
-#ifdef TRY_BLOCK
-/* Blocked mode is used to get interrupts at convenient places
- * to do DMA. It is also useful when you want to count greater
- * than 16M scans.
- */
-static void ni_handle_block(comedi_device *dev)
-{
- int n;
-
- if(devpriv->ai_continuous){
- n = devpriv->blocksize;
- }else{
- if(devpriv->n_left==0){
- ni_handle_fifo_dregs(dev);
- printk("end\n");
- //TIM 4/17/01 win_out(0x0000,Interrupt_A_Enable_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_ai_reset(dev,dev->subdevices);
- comedi_done(dev,dev->subdevices);
- }else if(devpriv->n_left<=devpriv->blocksize){
- printk("last block %d\n",devpriv->n_left);
- n = devpriv->n_left;
- devpriv->n_left = 0;
- }else{
- printk("block %d\n",devpriv->n_left);
- n = devpriv->blocksize;
- devpriv->n_left -= devpriv->blocksize;
- }
- }
-#if 0
- {
- int size=0x10000;
-
- /* stage number of scans */
- win_out((size-1)>>16,AI_SC_Load_A_Registers);
- win_out((size-1)&0xffff,AI_SC_Load_A_Registers+1);
-
- //mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;
- mode1 |= 0xe;
- win_out(mode1,AI_Mode_1_Register);
-
- /* load SC (Scan Count) */
- win_out(AI_SC_Load,AI_Command_1_Register);
-
- }
-#endif
-}
-#endif
-
-static void ni_handle_fifo_half_full(comedi_device *dev)
-{
- int n,m;
- comedi_subdevice *s=dev->subdevices+0;
- comedi_async *async=s->async;
-
- /*
- if we got a fifo_half_full interrupt, we can transfer fifo/2
- samples without checking the empty flag. It doesn't matter if
- we transfer the rest of the samples, the performance trade-off
- is minimal (checking empty flag for a few samples vs. having
- 1% more interrupts.) At really high speeds, it's better to
- ignore them.
-
- */
-
- n=boardtype.ai_fifo_depth/2;
-
- /* this makes the assumption that the buffer length is
- greater than the half-fifo depth. */
-
- if(async->buf_int_ptr+n*sizeof(sampl_t)>=async->data_len){
- m=(async->data_len-async->buf_int_ptr)/sizeof(sampl_t);
- ni_ai_fifo_read(dev,s,async->data+async->buf_int_ptr,m);
- async->buf_int_count+=m*sizeof(sampl_t);
- n-=m;
- async->buf_int_ptr=0;
-
- async->events |= COMEDI_CB_EOBUF;
- }
- ni_ai_fifo_read(dev,s,async->data+async->buf_int_ptr,n);
- async->buf_int_count+=n*sizeof(sampl_t);
- async->buf_int_ptr+=n*sizeof(sampl_t);
-
- async->events |= COMEDI_CB_BLOCK;
-}
-
-/*
- Empties the AI fifo
-*/
-static void ni_handle_fifo_dregs(comedi_device *dev)
-{
- comedi_subdevice *s=dev->subdevices+0;
- sampl_t *data,d;
- int i,n;
- int j;
- unsigned int mask;
-
- mask=(1<<boardtype.adbits)-1;
- j=s->async->cur_chan;
- data=s->async->data+s->async->buf_int_ptr;
- while(1){
- n=(s->async->data_len-s->async->buf_int_ptr)/sizeof(sampl_t);
- for(i=0;i<n;i++){
- if(ni_readw(AI_Status_1)&AI_FIFO_Empty_St){
- s->async->cur_chan=j;
- return;
- }
- d=ni_readw(ADC_FIFO_Data_Register);
- d^=devpriv->ai_xorlist[j];
- d&=mask;
- *data=d;
- j++;
- if(j>=s->async->cur_chanlist_len){
- j=0;
- //s->events |= COMEDI_CB_EOS;
- }
- data++;
- s->async->buf_int_ptr+=sizeof(sampl_t);
- s->async->buf_int_count+=sizeof(sampl_t);
- }
- s->async->buf_int_ptr=0;
- data=s->async->data;
- s->async->events |= COMEDI_CB_EOBUF;
- }
-}
-
-#ifdef PCIDMA
-int ni_ai_setup_block_dma(comedi_device *dev,int frob,int mode1)
-{
- int n;
- int len;
- unsigned long ll_start;
- comedi_cmd *cmd=&dev->subdevices->async->cmd;
-
- MDPRINTK("ni_ai_setup_block_dma\n");
-
- /*Build MITE linked list and configure the MITE
- * ******WARNING******
- * There is no error handling here,
- * the memory buffer *Must* be mlock'ed by the user*/
-
- len = sizeof(sampl_t)*cmd->stop_arg*cmd->scan_end_arg;
-
- /*use kvmem if no user buf specified */
- ll_start = mite_ll_from_kvmem(devpriv->mite,dev->subdevices->async,
- len);
-
- mite_setregs(devpriv->mite, ll_start,0,COMEDI_INPUT);
-
- /*tell the STC to use DMA0 for AI.
- * Select the MITE DMA channel to use, 0x01=A*/
- ni_writeb(0x01,AI_AO_Select);
-
- /* stage number of scans */
- n = cmd->stop_arg;
- win_out((n-1)>>16,AI_SC_Load_A_Registers);
- win_out((n-1)&0xffff,AI_SC_Load_A_Registers+1);
- win_out((n-1)>>16,AI_SC_Load_B_Registers);
- win_out((n-1)&0xffff,AI_SC_Load_B_Registers+1);
-
- /* load SC (Scan Count) */
- win_out(AI_SC_Load,AI_Command_1_Register);
-
- mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;
- win_out(mode1,AI_Mode_1_Register);
-
- /*start the MITE*/
- mite_dma_arm(devpriv->mite);
-
- MDPRINTK("exit ni_ai_setup_block_dma\n");
-
- return mode1;
-}
-#endif
-
-#ifdef TRY_BLOCK
-int ni_ai_setup_block(comedi_device *dev,int frob,int mode1)
-{
- int n;
- int last=0;
-
-printk("n_left = %d\n",devpriv->n_left);
- if(devpriv->ai_continuous){
- n=devpriv->blocksize;
- last=0;
- }else{
- n=devpriv->n_left;
- if(n>devpriv->blocksize){
- n=devpriv->blocksize;
- last=0;
- }else{
- last=1;
- }
- devpriv->n_left -= n;
- }
-
- if(frob){
- /* stage number of scans */
- win_out((n-1)>>16,AI_SC_Load_A_Registers);
- win_out((n-1)&0xffff,AI_SC_Load_A_Registers+1);
- win_out((n-1)>>16,AI_SC_Load_B_Registers);
- win_out((n-1)&0xffff,AI_SC_Load_B_Registers+1);
-
- /* load SC (Scan Count) */
- win_out(AI_SC_Load,AI_Command_1_Register);
-#if 0
- if(!last){
- mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;
- }else{
- mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Trigger_Once;
- }
-#endif
- mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;
- win_out(mode1,AI_Mode_1_Register);
-
- }
-
- return mode1;
-}
-#endif
-
-#ifdef PCIDMA
-int ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd,int mode1)
-{
- int n,len;
- unsigned long ll_start;
- comedi_async *async_mite;
-
- len = sizeof(sampl_t)*cmd->stop_arg*cmd->scan_end_arg;
- async_mite=dev->subdevices[cmd->subdev].async;
- ll_start = mite_ll_from_kvmem(devpriv->mite, async_mite,len);
- mite_setregs(devpriv->mite, ll_start,0,COMEDI_INPUT);
-
- /*tell the STC to use DMA0 for AI.
- Select the MITE DMA channel to use, 0x01=A*/
- ni_writeb(0x01,AI_AO_Select);
-
- /* stage number of scans */
- n = cmd->stop_arg;
- win_out((n-1)>>16,AI_SC_Load_A_Registers);
- win_out((n-1)&0xffff,AI_SC_Load_A_Registers+1);
- win_out((n-1)>>16,AI_SC_Load_B_Registers);
- win_out((n-1)&0xffff,AI_SC_Load_B_Registers+1);
-
- /* load SC (Scan Count) */
- win_out(AI_SC_Load,AI_Command_1_Register);
-
- mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;
- win_out(mode1,AI_Mode_1_Register);
-
- /*start the MITE*/
- mite_dma_arm(devpriv->mite);
- return mode1;
-}
-#endif
-
-/*
- used for both cancel ioctl and board initialization
-
- this is pretty harsh for a cancel, but it works...
- */
-static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s)
-{
-#ifdef PCIDMA
- mite_dma_disarm(devpriv->mite);
-#endif
- //TIM 4/17/01 win_out(0x0000,Interrupt_A_Enable_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);
-
- win_out(AI_Reset,Joint_Reset_Register);
-
- win_out(1,ADC_FIFO_Clear);
-
- /* ai configuration */
-
- win_out(AI_Configuration_Start,Joint_Reset_Register);
-
- win_out(0x0000,AI_Command_1_Register); /* reset pulses */
- win_out(0x000d,AI_Mode_1_Register);
- win_out(0x0000,AI_Mode_2_Register);
-#if 0
- win_out((1<<6)|0x0000,AI_Mode_3_Register); /* generate FIFO interrupts on half full */
-#else
- win_out((0<<6)|0x0000,AI_Mode_3_Register); /* generate FIFO interrupts on non-empty */
-#endif
- /* TIM 5/11/01
- 0xA4A0 causes overrun errors at high speeds. 0xA420 fixes it,
- but I haven't tested to see if it breaks something else. I don't think it would*/
- #ifdef PCIDMA
- win_out(0xA420,AI_Personal_Register);
- #else
- win_out(0xa4a0,AI_Personal_Register); /* ? */
- #endif
- win_out(0x032e,AI_Output_Control_Register);
- win_out(0x0060,AI_Trigger_Select_Register); /* trigger source */
-
- /* this should be done in _ai_modeX() */
- win_out(0x29e0,AI_START_STOP_Select_Register);
-
- /* the following registers should not be changed, because there
- * are no backup registers in devpriv. If you want to change
- * any of these, add a backup register and other appropriate code:
- * Clock_and_FOUT_Register
- * AI_Mode_1_Register
- * AI_Mode_3_Register
- * AI_Personal_Register
- * AI_Output_Control_Register
- * AI_Trigger_Select_Register
- */
- win_out(0x3f80,Interrupt_A_Ack_Register); /* clear interrupts */
-
- win_out(AI_Configuration_End,Joint_Reset_Register);
-
- return 0;
-}
-
-static int ni_ai_poll(comedi_device *dev,comedi_subdevice *s)
-{
- unsigned long flags;
-
- comedi_spin_lock_irqsave(&dev->spinlock,flags);
- ni_handle_fifo_dregs(dev);
- comedi_spin_unlock_irqrestore(&dev->spinlock,flags);
-
- comedi_event(dev,s,s->async->events);
-
- return s->async->buf_int_count-s->async->buf_user_count;
-}
-
-static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,unsigned int *list,int dither);
-
-#define NI_TIMEOUT 1000
-
-
-static int ni_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
-{
- int i,n;
- int wsave;
- unsigned int mask,sign;
-
- wsave=win_save();
-
- win_out(1,ADC_FIFO_Clear);
-
- /* interrupt on errors */
- //TIM 4/17/01 win_out(0x0020,Interrupt_A_Enable_Register);
- ni_set_bits(dev, Interrupt_A_Enable_Register, AI_Error_Interrupt_Enable,1);
-
-
- //ni_load_channelgain_list(dev,1,&insn->chanspec,(insn->flags&TRIG_DITHER)==TRIG_DITHER);
- ni_load_channelgain_list(dev,1,&insn->chanspec,0);
-
-#if 0
-#define NI_TIMEOUT 1000
-#endif
- mask=(1<<boardtype.adbits)-1;
- sign=devpriv->ai_xorlist[0];
- for(n=0;n<insn->n;n++){
- win_out(1,AI_Command_1_Register);
- for(i=0;i<NI_TIMEOUT;i++){
- if(!(ni_readw(AI_Status_1)&AI_FIFO_Empty_St))
- break;
- }
- if(i==NI_TIMEOUT){
- rt_printk("ni_E: timeout 2\n");
- win_restore(wsave);
- return -ETIME;
- }
- data[n]=(ni_readw(ADC_FIFO_Data_Register)&mask)^sign;
- }
- win_restore(wsave);
- return insn->n;
-}
-
-
-static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,unsigned int *list,int dither)
-{
- unsigned int chan,range,aref;
- unsigned int i;
- unsigned int hi,lo;
- unsigned short sign;
-
- if(n_chan==1){
- if(devpriv->changain_state && devpriv->changain_spec==list[0]){
- // ready to go.
- return;
- }
- devpriv->changain_state=1;
- devpriv->changain_spec=list[0];
- }else{
- devpriv->changain_state=0;
- }
-
- win_out(1,Configuration_Memory_Clear);
-
- sign=1<<(boardtype.adbits-1);
- for(i=0;i<n_chan;i++){
- chan=CR_CHAN(list[i]);
- range=CR_RANGE(list[i]);
- aref=CR_AREF(list[i]);
-
- /* fix the external/internal range differences */
- range=ni_gainlkup[boardtype.gainlkup][range];
- devpriv->ai_xorlist[i]=(range<8)?sign:0;
-
- hi=ni_modebits1[aref]|(chan&ni_modebits2[aref]);
- ni_writew(hi,Configuration_Memory_High);
-
- lo=((i==n_chan-1)?0x8000:0) | ((range&0x8)<<5) | (range&0x7) | (dither<<9);
- ni_writew(lo,Configuration_Memory_Low);
- }
-
- /* prime the channel/gain list */
-
- win_out(1,AI_Command_1_Register);
- for(i=0;i<1000;i++){
- if(!(ni_readw(AI_Status_1)&AI_FIFO_Empty_St)){
- win_out(1,ADC_FIFO_Clear);
- return;
- }
- //udelay(25);
- }
- rt_printk("ni_E: timeout 1\n");
-}
-
-#define TIMER_BASE 50 /* 20 Mhz base */
-
-static int ni_ns_to_timer(int *nanosec,int round_mode)
-{
- int divider,base;
-
- base=TIMER_BASE;
-
- switch(round_mode){
- case TRIG_ROUND_NEAREST:
- default:
- divider=(*nanosec+base/2)/base;
- break;
- case TRIG_ROUND_DOWN:
- divider=(*nanosec)/base;
- break;
- case TRIG_ROUND_UP:
- divider=(*nanosec+base-1)/base;
- break;
- }
-
- *nanosec=base*divider;
- return divider-1;
-}
-
-static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
-{
- int err=0;
- int tmp;
-
- /* step 1: make sure trigger sources are trivially valid */
-
- tmp=cmd->start_src;
- cmd->start_src &= TRIG_NOW|TRIG_INT;
- if(!cmd->start_src || tmp!=cmd->start_src)err++;
-
- tmp=cmd->scan_begin_src;
- cmd->scan_begin_src &= TRIG_TIMER|TRIG_EXT;
- if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
-
- tmp=cmd->convert_src;
- cmd->convert_src &= TRIG_TIMER|TRIG_EXT;
- if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
-
- tmp=cmd->scan_end_src;
- cmd->scan_end_src &= TRIG_COUNT;
- if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
-
- tmp=cmd->stop_src;
- cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
- if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
-
- if(err)return 1;
-
- /* step 2: make sure trigger sources are unique and mutually compatible */
-
- /* note that mutual compatiblity is not an issue here */
- if(cmd->start_src!=TRIG_NOW &&
- cmd->start_src!=TRIG_INT)err++;
- if(cmd->scan_begin_src!=TRIG_TIMER &&
- cmd->scan_begin_src!=TRIG_EXT)err++;
- if(cmd->convert_src!=TRIG_TIMER &&
- cmd->convert_src!=TRIG_EXT)err++;
- if(cmd->stop_src!=TRIG_COUNT &&
- cmd->stop_src!=TRIG_NONE)err++;
-
- if(err)return 2;
-
- /* step 3: make sure arguments are trivially compatible */
-
- if(cmd->start_arg!=0){
- /* true for both TRIG_NOW and TRIG_INT */
- cmd->start_arg=0;
- err++;
- }
- if(cmd->scan_begin_src==TRIG_TIMER){
- if(cmd->scan_begin_arg<boardtype.ai_speed){
- cmd->scan_begin_arg=boardtype.ai_speed;
- err++;
- }
- if(cmd->scan_begin_arg>TIMER_BASE*0xffffff){
- cmd->scan_begin_arg=TIMER_BASE*0xffffff;
- err++;
- }
- }else{
- /* external trigger */
- /* should be level/edge, hi/lo specification here */
- /* should specify multiple external triggers */
-#if 0
-/* XXX This is disabled, since we want to use bits 30 and 31 to
- * refer to edge/level and hi/lo triggering. */
- if(cmd->scan_begin_arg>9){
- cmd->scan_begin_arg=9;
- err++;
- }
-#endif
- }
- if(cmd->convert_src==TRIG_TIMER){
- if(cmd->convert_arg<boardtype.ai_speed){
- cmd->convert_arg=boardtype.ai_speed;
- err++;
- }
- if(cmd->convert_arg>TIMER_BASE*0xffff){
- cmd->convert_arg=TIMER_BASE*0xffff;
- err++;
- }
- }else{
- /* external trigger */
- /* see above */
-#if 0
-/* XXX This is disabled, since we want to use bits 30 and 31 to
- * refer to edge/level and hi/lo triggering. */
- if(cmd->convert_arg>9){
- cmd->convert_arg=9;
- err++;
- }
-#endif
- }
-
- if(cmd->scan_end_arg!=cmd->chanlist_len){
- cmd->scan_end_arg=cmd->chanlist_len;
- err++;
- }
- if(cmd->stop_src==TRIG_COUNT){
- if(cmd->stop_arg>0x00ffffff){
- cmd->stop_arg=0x00ffffff;
- err++;
- }
- }else{
- /* TRIG_NONE */
- if(cmd->stop_arg!=0){
- cmd->stop_arg=0;
- err++;
- }
- }
-
- if(err)return 3;
-
- /* step 4: fix up any arguments */
-
- if(cmd->scan_begin_src==TRIG_TIMER){
- tmp=cmd->scan_begin_arg;
- ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
- if(tmp!=cmd->scan_begin_arg)err++;
- }
- if(cmd->convert_src==TRIG_TIMER){
- tmp=cmd->convert_arg;
- ni_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
- if(tmp!=cmd->convert_arg)err++;
- if(cmd->scan_begin_src==TRIG_TIMER &&
- cmd->scan_begin_arg<cmd->convert_arg*cmd->scan_end_arg){
- cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg;
- err++;
- }
- }
-
- if(err)return 4;
-
- return 0;
-}
-
-static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
-{
- int wsave;
- comedi_cmd *cmd=&s->async->cmd;
- int timer;
- int mode1=0; /* mode1 is needed for both stop and convert */
- int mode2=0;
-
- MDPRINTK("ni_ai_cmd\n");
- wsave = win_save();
-
- win_out(1,ADC_FIFO_Clear);
-
- ni_load_channelgain_list(dev,cmd->chanlist_len,cmd->chanlist,
- (cmd->flags&TRIG_DITHER)==TRIG_DITHER);
-
- /* start configuration */
- win_out(AI_Configuration_Start,Joint_Reset_Register);
-
-#ifndef TRY_BLOCK
- #ifdef PCIDMA
- ni_ai_setup_MITE_dma(dev,cmd,mode1);
- #else
- switch(cmd->stop_src){
- case TRIG_COUNT:
- /* stage number of scans */
- win_out((cmd->stop_arg-1)>>16,AI_SC_Load_A_Registers);
- win_out((cmd->stop_arg-1)&0xffff,AI_SC_Load_A_Registers+1);
-
- mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Trigger_Once;
- win_out(mode1,AI_Mode_1_Register);
-
- /* load SC (Scan Count) */
- win_out(AI_SC_Load,AI_Command_1_Register);
-
- devpriv->ai_continuous = 0;
-
- break;
- case TRIG_NONE:
- /* stage number of scans */
- win_out(0,AI_SC_Load_A_Registers);
- win_out(0,AI_SC_Load_A_Registers+1);
-
- mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;
- win_out(mode1,AI_Mode_1_Register);
-
- /* load SC (Scan Count) */
- win_out(AI_SC_Load,AI_Command_1_Register);
-
- devpriv->ai_continuous = 1;
-
- break;
- }
- #endif
-#else
- devpriv->blocksize = 0x4000;
- switch(cmd->stop_src){
- case TRIG_COUNT:
- devpriv->ai_continuous = 0;
- devpriv->n_left = cmd->stop_arg;
- break;
- case TRIG_NONE:
- devpriv->ai_continuous = 1;
- devpriv->n_left = 0;
- break;
- }
-
- mode1 = ni_ai_setup_block(dev,1,mode1);
-#endif
-
-
- switch(cmd->scan_begin_src){
- case TRIG_TIMER:
- /*
- AI_SI_Special_Trigger_Delay=0
- AI_Pre_Trigger=0
- AI_START_STOP_Select_Register:
- AI_START_Polarity=0 (?) rising edge
- AI_START_Edge=1 edge triggered
- AI_START_Sync=1 (?)
- AI_START_Select=0 SI_TC
- AI_STOP_Polarity=0 rising edge
- AI_STOP_Edge=0 level
- AI_STOP_Sync=1
- AI_STOP_Select=19 external pin (configuration mem)
- */
- win_out(AI_START_Edge|AI_START_Sync|
- AI_STOP_Select(19)|AI_STOP_Sync,
- AI_START_STOP_Select_Register);
-
- timer=ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
- win_out((timer>>16),AI_SI_Load_A_Registers);
- win_out((timer&0xffff),AI_SI_Load_A_Registers+1);
-
- /* AI_SI_Initial_Load_Source=A */
- mode2 |= AI_SI_Initial_Load_Source&0;
-//mode2 |= AI_SC_Reload_Mode;
- win_out(mode2,AI_Mode_2_Register);
-
- /* load SI */
- win_out(AI_SI_Load,AI_Command_1_Register);
-
- /* stage freq. counter into SI B */
- win_out((timer>>16),AI_SI_Load_B_Registers);
- win_out((timer&0xffff),AI_SI_Load_B_Registers+1);
-
- break;
- case TRIG_EXT:
- {
- unsigned int reg = 0;
-
-/* XXX duh, these should be moved, but I need to think about it
- * a bit first. --ds */
-#define COMEDI_TRIG_LEVEL 0
-#define COMEDI_TRIG_EDGE (1<<31)
-#define COMEDI_TRIG_FALLING 0
-#define COMEDI_TRIG_RISING (1<<30)
-
- if(cmd->scan_begin_arg&COMEDI_TRIG_EDGE)
- reg |= AI_START_Edge;
- /* AI_START_Polarity==1 is falling edge */
- if(!(cmd->scan_begin_arg&COMEDI_TRIG_RISING))
- reg |= AI_START_Polarity;
- reg |= AI_START_Sync;
- reg |= AI_START_Select(1+(cmd->scan_begin_arg&0xf));
- reg |= AI_STOP_Select(19)|AI_STOP_Sync;
-
- win_out(reg,AI_START_STOP_Select_Register);
- break;
- }
- }
-
- switch(cmd->convert_src){
- case TRIG_TIMER:
- timer=ni_ns_to_timer(&cmd->convert_arg,TRIG_ROUND_NEAREST);
- win_out(1,AI_SI2_Load_A_Register); /* 0,0 does not work. */
- win_out(timer,AI_SI2_Load_B_Register);
-
- /* AI_SI2_Reload_Mode = alternate */
- /* AI_SI2_Initial_Load_Source = A */
- win_out((AI_SI2_Initial_Load_Source&0)|
- (AI_SI2_Reload_Mode),
- AI_Mode_2_Register);
-
- /* AI_SI2_Load */
- win_out(AI_SI2_Load,AI_Command_1_Register);
-
- //mode2 |= AI_SI_Reload_Mode(0);
- /* XXX the AI_SI stuff should go to the scan_begin_src area */
- mode2 |= AI_SI_Reload_Mode(1);
- //mode2 |= 0&AI_SI_Initial_Load_Source;
- mode2 |= AI_SI_Initial_Load_Source;
- mode2 |= AI_SI2_Reload_Mode; // alternate
- mode2 |= AI_SI2_Initial_Load_Source; // B
-
- win_out(mode2,AI_Mode_2_Register);
-
- break;
- case TRIG_EXT:
- mode1 |= AI_CONVERT_Source_Select(1+cmd->convert_arg) |
- AI_CONVERT_Source_Polarity;
- win_out(mode1,AI_Mode_1_Register);
-
- win_out(mode2 | AI_SI2_Reload_Mode,AI_Mode_2_Register);
-
- mode2 |= AI_SI_Reload_Mode(0);
- mode2 |= 0&AI_SI_Initial_Load_Source;
- mode2 |= AI_SI2_Reload_Mode; // alternate
- mode2 |= AI_SI2_Initial_Load_Source; // B
-
- win_out(mode2,AI_Mode_2_Register);
-
- break;
- }
-
- if(dev->irq){
- int bits;
-
- /* interrupt on FIFO, errors, SC_TC */
- bits= AI_Error_Interrupt_Enable|
- AI_SC_TC_Interrupt_Enable;
-
-#ifndef PCIDMA
- bits|=AI_FIFO_Interrupt_Enable;
-#endif
-
- if(s->async->cb_mask&COMEDI_CB_EOS){
- /* wake on end-of-scan */
- devpriv->aimode=AIMODE_SCAN;
- }else{
- devpriv->aimode=AIMODE_HALF_FULL;
- }
-
- switch(devpriv->aimode){
- case AIMODE_HALF_FULL:
- /*generate FIFO interrupts on half-full */
- win_out(AI_FIFO_Mode_HF|0x0000,AI_Mode_3_Register);
- break;
- case AIMODE_SAMPLE:
- /*generate FIFO interrupts on non-empty */
- win_out(AI_FIFO_Mode_NE|0x0000,AI_Mode_3_Register);
- break;
- case AIMODE_SCAN:
- /*generate FIFO interrupts on half-full */
- win_out(AI_FIFO_Mode_HF|0x0000,AI_Mode_3_Register);
- bits|=AI_STOP_Interrupt_Enable;
- break;
- default:
- break;
- }
-
- win_out(0x3f80,Interrupt_A_Ack_Register); /* clear interrupts */
-
- //TIM 4/17/01 win_out(bits,Interrupt_A_Enable_Register) ;
- ni_set_bits(dev, Interrupt_A_Enable_Register, bits, 1);
-
- MDPRINTK("Interrupt_A_Enable_Register = 0x%04x\n",bits);
- }else{
- /* interrupt on nothing */
- win_out(0x0000,Interrupt_A_Enable_Register) ;
-
- /* XXX start polling if necessary */
- MDPRINTK("interrupting on nothing\n");
- }
-
- /* end configuration */
- win_out(AI_Configuration_End,Joint_Reset_Register);
-
- switch(cmd->scan_begin_src){
- case TRIG_TIMER:
- /* AI_SI2_Arm, AI_SI_Arm, AI_DIV_Arm, AI_SC_Arm */
- win_out(0x1540,AI_Command_1_Register);
- break;
- case TRIG_EXT:
- /* AI_SI2_Arm, AI_DIV_Arm, AI_SC_Arm */
- win_out(0x1540,AI_Command_1_Register);
- break;
- }
-
- if(cmd->start_src==TRIG_NOW){
- /* TRIG_NOW */
- /* AI_START1_Pulse */
- win_out(AI_START1_Pulse,AI_Command_2_Register);
- s->async->inttrig=NULL;
- }else{
- /* TRIG_INT */
- s->async->inttrig=ni_ai_inttrig;
- }
-
- win_restore(wsave);
-
- //mite_dump_regs(devpriv->mite);
- MDPRINTK("exit ni_ai_cmd\n");
-
- return 0;
-}
-
-static int ni_ai_inttrig(comedi_device *dev,comedi_subdevice *s,
- unsigned int trignum)
-{
- int wsave;
-
- if(trignum!=0)return -EINVAL;
-
- wsave = win_save();
-
- win_out(AI_START1_Pulse,AI_Command_2_Register);
- s->async->inttrig=NULL;
-
- win_restore(wsave);
-
- return 1;
-}
-
-static void ni_ao_fifo_load(comedi_device *dev,comedi_subdevice *s,
- sampl_t *data,int n)
-{
- int i;
-
- for(i=0;i<n;i++){
- ni_writew(data[i],DAC_FIFO_Data);
- }
-}
-
-
-/*
- * 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(comedi_device *dev,comedi_subdevice *s)
-{
- int n,m;
-
- n=(s->async->buf_int_count-s->async->buf_user_count)/sizeof(sampl_t);
- if(n==0)return 0;
- if(n>boardtype.ao_fifo_depth/2)
- n=boardtype.ao_fifo_depth/2;
-
- if(s->async->buf_int_ptr+n*sizeof(sampl_t)>s->async->data_len){
- m=(s->async->data_len-s->async->buf_int_ptr)/sizeof(sampl_t);
- ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,m);
- s->async->buf_int_count+=m*sizeof(sampl_t);
- s->async->buf_int_ptr=0;
- n-=m;
- }
- ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,n);
- s->async->buf_int_count+=n*sizeof(sampl_t);
- s->async->buf_int_ptr+=n*sizeof(sampl_t);
-
- comedi_bufcheck(dev,s);
-
- return 1;
-}
-
-static int ni_ao_prep_fifo(comedi_device *dev,comedi_subdevice *s)
-{
- int n;
-
- /* reset fifo */
- win_out(0,DAC_FIFO_Clear);
-
- /* load some data */
- n=(s->async->buf_int_count-s->async->buf_user_count)/sizeof(sampl_t);
- if(n==0)return 0;
- if(n>boardtype.ao_fifo_depth)
- n=boardtype.ao_fifo_depth;
-
- ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,n);
- s->async->buf_int_count+=n*sizeof(sampl_t);
- s->async->buf_int_ptr+=n*sizeof(sampl_t);
-
- return n;
-}
-
-
-static int ni_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
-{
- data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int ni_ao_insn_write(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
-{
- unsigned int conf;
- unsigned int chan;
- unsigned int range;
- unsigned int dat = data[0];
-
- chan=CR_CHAN(insn->chanspec);
-
- conf=chan<<8;
-
- /* XXX check range with current range in flaglist[chan] */
- /* should update calibration if range changes (ick) */
-
- range = CR_RANGE(insn->chanspec);
- if(boardtype.ao_unipolar){
- conf |= (range&1)^1;
- }
- conf |= (range&2)<<1;
-
-#if 0
- /* XXX oops. forgot flags in insn! */
- /* not all boards can deglitch, but this shouldn't hurt */
- if(insn->flags & TRIG_DEGLITCH)
- conf |= 2;
-#endif
-
- /* analog reference */
- /* AREF_OTHER connects AO ground to AI ground, i think */
- conf |= (CR_AREF(insn->chanspec)==AREF_OTHER)? 8 : 0;
-
- ni_writew(conf,AO_Configuration);
-
- devpriv->ao[chan] = dat;
-
- if(((range&1)==0) || !boardtype.ao_unipolar)
- dat^=(1<<(boardtype.aobits-1));
-
- ni_writew(dat,(chan)? DAC1_Direct_Data : DAC0_Direct_Data);
-
- return 1;
-}
-
-static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s)
-{
- comedi_cmd *cmd = &s->async->cmd;
- unsigned int conf;
- unsigned int chan;
- unsigned int range;
- int trigvar;
- int i;
-
- trigvar = ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
-
- win_out(AO_Disarm,AO_Command_1_Register);
-
- for(i=0;i<cmd->chanlist_len;i++){
- chan=CR_CHAN(cmd->chanlist[i]);
-
- conf=chan<<8;
-
- /* XXX check range with current range in flaglist[chan] */
- /* should update calibration if range changes (ick) */
-
- range = CR_RANGE(cmd->chanlist[i]);
- conf |= (range&1);
- conf |= (range&2)<<1;
-
- /* not all boards can deglitch, but this shouldn't hurt */
- if(cmd->flags & TRIG_DEGLITCH) /* XXX ? */
- conf |= 2;
-
- /* analog reference */
- /* AREF_OTHER connects AO ground to AI ground, i think */
- conf |= (CR_AREF(cmd->chanlist[i])==AREF_OTHER)? 8 : 0;
-
- ni_writew(conf,AO_Configuration);
- }
-
- /* user is supposed to write() to buffer before triggering */
- if(ni_ao_prep_fifo(dev,s)==0)
- return -EIO;
-
- win_out(AO_Configuration_Start,Joint_Reset_Register);
-
- devpriv->ao_mode1|=AO_Trigger_Once;
- win_out(devpriv->ao_mode1,AO_Mode_1_Register);
- devpriv->ao_trigger_select&=~(AO_START1_Polarity|AO_START1_Select(-1));
- devpriv->ao_trigger_select|=AO_START1_Edge|AO_START1_Sync;
- win_out(devpriv->ao_trigger_select,AO_Trigger_Select_Register);
- devpriv->ao_mode3&=~AO_Trigger_Length;
- win_out(devpriv->ao_mode3,AO_Mode_3_Register);
-
- if(cmd->stop_src==TRIG_NOW){
- devpriv->ao_mode1|=AO_Continuous;
- }else{
- devpriv->ao_mode1&=~AO_Continuous;
- }
- win_out(devpriv->ao_mode1,AO_Mode_1_Register);
- devpriv->ao_mode2&=~AO_BC_Initial_Load_Source;
- win_out(devpriv->ao_mode2,AO_Mode_2_Register);
- if(cmd->stop_src==TRIG_NOW){
- win_out(0xff,AO_BC_Load_A_Register_High);
- win_out(0xffff,AO_BC_Load_A_Register_Low);
- }else{
- win_out(0,AO_BC_Load_A_Register_High);
- win_out(0,AO_BC_Load_A_Register_Low);
- }
- win_out(AO_BC_Load,AO_Command_1_Register);
- devpriv->ao_mode2&=~AO_UC_Initial_Load_Source;
- win_out(devpriv->ao_mode2,AO_Mode_2_Register);
- if(cmd->stop_src==TRIG_NOW){
- win_out(0xff,AO_UC_Load_A_Register_High);
- win_out(0xffff,AO_UC_Load_A_Register_Low);
- win_out(AO_UC_Load,AO_Command_1_Register);
- win_out(0xff,AO_UC_Load_A_Register_High);
- win_out(0xffff,AO_UC_Load_A_Register_Low);
- }else{
- win_out(0,AO_UC_Load_A_Register_High);
- win_out(0,AO_UC_Load_A_Register_Low);
- win_out(AO_UC_Load,AO_Command_1_Register);
- win_out((cmd->stop_arg-1)>>16,AO_UC_Load_A_Register_High);
- win_out((cmd->stop_arg-1)&0xffff,AO_UC_Load_A_Register_Low);
- }
-
- devpriv->ao_cmd2&=~AO_BC_Gate_Enable;
- ni_writew(devpriv->ao_cmd2,AO_Command_2);
- devpriv->ao_mode1&=~(AO_UI_Source_Select(0x1f)|AO_UI_Source_Polarity);
- win_out(devpriv->ao_mode1,AO_Mode_1_Register);
- devpriv->ao_mode2&=~(AO_UI_Reload_Mode(3)|AO_UI_Initial_Load_Source);
- win_out(devpriv->ao_mode2,AO_Mode_2_Register);
- win_out(0,AO_UI_Load_A_Register_High);
- win_out(1,AO_UI_Load_A_Register_Low);
- win_out(AO_UI_Load,AO_Command_1_Register);
- win_out((trigvar>>16),AO_UI_Load_A_Register_High);
- win_out((trigvar&0xffff),AO_UI_Load_A_Register_Low);
-
- if(cmd->scan_end_arg>1){
- devpriv->ao_mode1|=AO_Multiple_Channels;
- win_out(AO_Number_Of_Channels(cmd->scan_end_arg-1)|
- AO_UPDATE_Output_Select(1),
- AO_Output_Control_Register);
- }else{
- devpriv->ao_mode1&=~AO_Multiple_Channels;
- win_out(AO_Number_Of_Channels(CR_CHAN(cmd->chanlist[0]))|
- AO_UPDATE_Output_Select(1),
- AO_Output_Control_Register);
- }
- win_out(devpriv->ao_mode1,AO_Mode_1_Register);
-
- win_out(AO_DAC0_Update_Mode|AO_DAC1_Update_Mode,AO_Command_1_Register);
-
- devpriv->ao_mode3|=AO_Stop_On_Overrun_Error;
- win_out(devpriv->ao_mode3,AO_Mode_3_Register);
-
-devpriv->ao_mode2|=AO_FIFO_Mode(1);
- devpriv->ao_mode2&=~AO_FIFO_Retransmit_Enable;
- win_out(devpriv->ao_mode2,AO_Mode_2_Register);
-
- win_out(AO_Configuration_End,Joint_Reset_Register);
-
- win_out(devpriv->ao_mode3|AO_Not_An_UPDATE,AO_Mode_3_Register);
- win_out(devpriv->ao_mode3,AO_Mode_3_Register);
-
- /* wait for DACs to be loaded */
- udelay(100);
-
- win_out(devpriv->ao_cmd1|AO_UI_Arm|AO_UC_Arm|AO_BC_Arm|AO_DAC1_Update_Mode|AO_DAC0_Update_Mode,
- AO_Command_1_Register);
-
- //TIM 4/17/01 win_out(AO_FIFO_Interrupt_Enable|AO_Error_Interrupt_Enable,Interrupt_B_Enable_Register);
- ni_set_bits(dev, Interrupt_B_Enable_Register,
- AO_FIFO_Interrupt_Enable|AO_Error_Interrupt_Enable, 1);
-
- ni_writew(devpriv->ao_cmd2|AO_START1_Pulse,AO_Command_2);
-
- return 0;
-}
-
-static int ni_ao_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
-{
- int err=0;
- int tmp;
-
- /* step 1: make sure trigger sources are trivially valid */
-
- tmp=cmd->start_src;
- cmd->start_src &= TRIG_NOW;
- if(!cmd->start_src || tmp!=cmd->start_src)err++;
-
- tmp=cmd->scan_begin_src;
- cmd->scan_begin_src &= TRIG_TIMER;
- if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
-
- tmp=cmd->convert_src;
- cmd->convert_src &= TRIG_NOW;
- if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
-
- tmp=cmd->scan_end_src;
- cmd->scan_end_src &= TRIG_COUNT;
- if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
-
- tmp=cmd->stop_src;
- cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
- if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
-
- if(err)return 1;
-
- /* step 2: make sure trigger sources are unique and mutually compatible */
-
- if(cmd->stop_src!=TRIG_COUNT &&
- cmd->stop_src!=TRIG_NONE)err++;
-
- if(err)return 2;
-
- /* step 3: make sure arguments are trivially compatible */
-
- if(cmd->start_arg!=0){
- cmd->start_arg=0;
- err++;
- }
-#if 0
- /* XXX need ao_speed */
- if(cmd->scan_begin_arg<boardtype.ao_speed){
- cmd->scan_begin_arg=boardtype.ao_speed;
- err++;
- }
-#endif
- if(cmd->scan_begin_arg>TIMER_BASE*0xffffff){ /* XXX check */
- cmd->scan_begin_arg=TIMER_BASE*0xffffff;
- err++;
- }
- if(cmd->convert_arg!=0){
- cmd->convert_arg=0;
- err++;
- }
- if(cmd->scan_end_arg!=cmd->chanlist_len){
- cmd->scan_end_arg=cmd->chanlist_len;
- err++;
- }
- if(cmd->stop_src==TRIG_COUNT){ /* XXX check */
- if(cmd->stop_arg>0x00ffffff){
- cmd->stop_arg=0x00ffffff;
- err++;
- }
- }else{
- /* TRIG_NONE */
- if(cmd->stop_arg!=0){
- cmd->stop_arg=0;
- err++;
- }
- }
-
- if(err)return 3;
-
- /* step 4: fix up any arguments */
-
- tmp = cmd->scan_begin_arg;
- ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
- if(tmp!=cmd->scan_begin_arg)err++;
-
- if(err)return 4;
-
- return 0;
-}
-
-
-static int ni_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
-{
-#ifdef DEBUG_DIO
- printk("ni_dio_insn_config() chan=%d io=%d\n",
- CR_CHAN(insn->chanspec),data[0]);
-#endif
- if(insn->n!=1)return -EINVAL;
- switch(data[0]){
- case COMEDI_OUTPUT:
- s->io_bits |= 1<<CR_CHAN(insn->chanspec);
- break;
- case COMEDI_INPUT:
- s->io_bits &= ~(1<<CR_CHAN(insn->chanspec));
- break;
- default:
- return -EINVAL;
- }
-
- devpriv->dio_control &= ~DIO_Pins_Dir_Mask;
- devpriv->dio_control |= DIO_Pins_Dir(s->io_bits);
- win_out(devpriv->dio_control,DIO_Control_Register);
-
- return 1;
-}
-
-static int ni_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
-{
-#ifdef DEBUG_DIO
- printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n",data[0],data[1]);
-#endif
- if(insn->n!=2)return -EINVAL;
- if(data[0]){
- s->state &= ~data[0];
- s->state |= (data[0]&data[1]);
- devpriv->dio_output &= ~DIO_Parallel_Data_Mask;
- devpriv->dio_output |= DIO_Parallel_Data_Out(s->state);
- win_out(devpriv->dio_output,DIO_Output_Register);
- }
- data[1] = ni_readw(DIO_Parallel_Input);
-
- return 2;
-}
-
-static void mio_common_detach(comedi_device *dev)
-{
- if(dev->subdevices && boardtype.has_8255)
- subdev_8255_cleanup(dev,dev->subdevices+3);
-}
-
-static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
-{
- comedi_subdevice *s;
-
- dev->n_subdevices=7;
-
- if(alloc_subdevices(dev)<0)
- return -ENOMEM;
-
- /* analog input subdevice */
-
- s=dev->subdevices+0;
- dev->read_subdev=s;
- s->type=COMEDI_SUBD_AI;
- s->subdev_flags=SDF_READABLE|SDF_RT|SDF_GROUND|SDF_COMMON|SDF_DIFF|SDF_OTHER;
- s->subdev_flags|=SDF_DITHER;
- s->n_chan=boardtype.n_adchan;
- s->len_chanlist=512;
- s->maxdata=(1<<boardtype.adbits)-1;
- s->range_table=ni_range_lkup[boardtype.gainlkup];
- s->insn_read=ni_ai_insn_read;
- s->do_cmdtest=ni_ai_cmdtest;
- s->do_cmd=ni_ai_cmd;
- s->cancel=ni_ai_reset;
- s->poll=ni_ai_poll;
-
- /* analog output subdevice */
-
- s=dev->subdevices+1;
- if(boardtype.n_aochan){
- dev->write_subdev=s;
- s->type=COMEDI_SUBD_AO;
- s->subdev_flags=SDF_WRITEABLE|SDF_RT|SDF_DEGLITCH|SDF_GROUND|SDF_OTHER;
- s->n_chan=boardtype.n_aochan;
- s->maxdata=(1<<boardtype.aobits)-1;
- if(boardtype.ao_unipolar){
- s->range_table=&range_ni_E_ao_ext; /* XXX wrong for some boards */
- }else{
- s->range_table=&range_bipolar10;
- }
- s->insn_read=ni_ao_insn_read;
- s->insn_write=ni_ao_insn_write;
- s->do_cmd=ni_ao_cmd;
- s->do_cmdtest=ni_ao_cmdtest;
- s->len_chanlist = 2;
- }else{
- s->type=COMEDI_SUBD_UNUSED;
- }
-
- /* digital i/o subdevice */
-
- s=dev->subdevices+2;
- s->type=COMEDI_SUBD_DIO;
- s->subdev_flags=SDF_WRITEABLE|SDF_READABLE|SDF_RT;
- s->n_chan=8;
- s->maxdata=1;
- s->range_table=&range_digital;
- s->io_bits=0; /* all bits input */
- s->insn_bits=ni_dio_insn_bits;
- s->insn_config=ni_dio_insn_config;
-
- /* dio setup */
- devpriv->dio_control = DIO_Pins_Dir(s->io_bits);
- win_out(devpriv->dio_control,DIO_Control_Register);
-
- /* 8255 device */
- s=dev->subdevices+3;
- if(boardtype.has_8255){
- subdev_8255_init(dev,s,ni_8255_callback,dev);
- }else{
- s->type=COMEDI_SUBD_UNUSED;
- }
- /* XXX */
-
- /* general purpose counter/timer device */
- s=dev->subdevices+4;
- s->type=COMEDI_SUBD_COUNTER;
- s->subdev_flags=SDF_READABLE|SDF_WRITEABLE;
- s->insn_read=ni_gpct_insn_read;
- s->insn_config=ni_gpct_insn_config;
- s->n_chan=1; /* XXX */
- s->maxdata=1;
-
- s=dev->subdevices+4;
- s->type=COMEDI_SUBD_COUNTER;
- s->subdev_flags=SDF_READABLE|SDF_WRITEABLE;
- s->insn_read= ni_gpct_insn_read;
- s->insn_write= ni_gpct_insn_write;
- s->insn_config=ni_gpct_insn_config;
- s->n_chan=2;
- s->maxdata=1;
- devpriv->an_trig_etc_reg = 0;
- GPCT_Reset(dev,0);
- GPCT_Reset(dev,1);
-
- /* calibration subdevice -- ai and ao */
- s=dev->subdevices+5;
- s->type=COMEDI_SUBD_CALIB;
- s->subdev_flags=SDF_WRITEABLE|SDF_INTERNAL;
- caldac_setup(dev,s);
- s->insn_read=ni_calib_insn_read;
- s->insn_write=ni_calib_insn_write;
-
- /* EEPROM */
- s=dev->subdevices+6;
- s->type=COMEDI_SUBD_MEMORY;
- s->subdev_flags=SDF_READABLE|SDF_INTERNAL;
- s->n_chan=512;
- s->maxdata=0xff;
- s->insn_read=ni_eeprom_insn_read;
-
- /* ai configuration */
- ni_ai_reset(dev,dev->subdevices+0);
- win_out(0x1ba0,Clock_and_FOUT_Register);
-
-
- /* analog output configuration */
-
- devpriv->ao0p=0x0000;
- ni_writew(devpriv->ao0p,AO_Configuration);
- devpriv->ao1p=0x0100;
- ni_writew(devpriv->ao1p,AO_Configuration);
- win_out(AO_Configuration_Start,Joint_Reset_Register);
- win_out(AO_Disarm,AO_Command_1_Register);
- win_out(0,Interrupt_B_Enable_Register);
- win_out(0x0010,AO_Personal_Register);
- ni_writew(0x3f98,Interrupt_B_Ack);
- win_out(0x1430,AO_Personal_Register);
- win_out(0,AO_Output_Control_Register);
- win_out(0,AO_Start_Select_Register);
- devpriv->ao_cmd1=0;
- win_out(devpriv->ao_cmd1,AO_Command_1_Register);
- devpriv->ao_cmd2=0;
- devpriv->ao_mode1=0;
- devpriv->ao_mode2=0;
- devpriv->ao_mode3=0;
- devpriv->ao_trigger_select=0;
-
- if(dev->irq){
- win_out((IRQ_POLARITY<<0) | /* polarity : active high */
- (0<<1) | /* no interrupt on 3 pins */
- (1<<11) | /* enable int A */
- (1<<15) | /* enable int B */
- (interrupt_pin(dev->irq)<<8) | /* interrupt output pin A */
- (interrupt_pin(dev->irq)<<12) , /* interrupt output pin B */
- Interrupt_Control_Register
- );
- }
-
- pfi_setup(dev);
-
- printk("\n");
-
- return 0;
-}
-
-
-
-
-/*
- presents the EEPROM as a subdevice
-*/
-
-static int ni_eeprom_insn_read(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
-{
- data[0]=ni_read_eeprom(dev,CR_CHAN(insn->chanspec));
-
- return 1;
-}
-
-/*
- reads bytes out of eeprom
-*/
-
-static int ni_read_eeprom(comedi_device *dev,int addr)
-{
- int bit;
- int bitstring;
-
- bitstring=0x0300|((addr&0x100)<<3)|(addr&0xff);
- ni_writeb_p(0x04,Serial_Command);
- for(bit=0x8000;bit;bit>>=1){
- ni_writeb_p(0x04|((bit&bitstring)?0x02:0),Serial_Command);
- ni_writeb_p(0x05|((bit&bitstring)?0x02:0),Serial_Command);
- }
- bitstring=0;
- for(bit=0x80;bit;bit>>=1){
- ni_writeb_p(0x04,Serial_Command);
- ni_writeb_p(0x05,Serial_Command);
- bitstring|=((ni_readb_p(XXX_Status)&0x01)?bit:0);
- }
- ni_writeb_p(0x00,Serial_Command);
-
- return bitstring;
-}
-
-static void ni_write_caldac(comedi_device *dev,int addr,int val);
-/*
- calibration subdevice
-*/
-static int ni_calib_insn_write(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
-{
- ni_write_caldac(dev,CR_CHAN(insn->chanspec),data[0]);
- devpriv->caldacs[CR_CHAN(insn->chanspec)] = data[0];
-
- return 1;
-}
-
-static int ni_calib_insn_read(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
-{
- data[0] = devpriv->caldacs[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int pack_mb88341(int addr,int val,int *bitstring);
-static int pack_dac8800(int addr,int val,int *bitstring);
-static int pack_dac8043(int addr,int val,int *bitstring);
-#ifdef PCIMIO
-static int pack_ad8522(int addr,int val,int *bitstring);
-#endif
-
-struct caldac_struct{
- int n_chans;
- int n_bits;
- int (*packbits)(int,int,int *);
-};
-
-static struct caldac_struct caldac_mb88341={ 12, 8, pack_mb88341 };
-static struct caldac_struct caldac_dac8800={ 8, 8, pack_dac8800 };
-static struct caldac_struct caldac_dac8043={ 1, 12, pack_dac8043 };
-#ifdef PCIMIO
-static struct caldac_struct caldac_ad8522={ 2, 12, pack_ad8522 };
-#endif
-
-
-static void caldac_setup(comedi_device *dev,comedi_subdevice *s)
-{
- int i,j;
- int n_dacs;
- int n_chans=0;
- int n_bits;
- int diffbits=0;
-
- if(!boardtype.caldac[0])return;
- n_bits=boardtype.caldac[0]->n_bits;
- for(i=0;i<3;i++){
- if(!boardtype.caldac[i])break;
- if(boardtype.caldac[i]->n_bits!=n_bits)diffbits=1;
- n_chans+=boardtype.caldac[i]->n_chans;
- }
- n_dacs=i;
- s->n_chan=n_chans;
-
- if(diffbits){
- int chan;
-
- s->maxdata_list=kmalloc(sizeof(int)*n_chans,GFP_KERNEL);
- chan=0;
- for(i=0;i<n_dacs;i++){
- for(j=0;j<boardtype.caldac[i]->n_chans;j++){
- s->maxdata_list[chan]=
- (1<<boardtype.caldac[i]->n_bits)-1;
- chan++;
- }
- }
- }else{
- s->maxdata=(1<<boardtype.caldac[0]->n_bits)-1;
- }
-}
-
-static void ni_write_caldac(comedi_device *dev,int addr,int val)
-{
- int loadbit=0,bits=0,bit,bitstring=0;
- int i;
-
- for(i=0;i<3;i++){
- if(!boardtype.caldac[i])return;
- if(addr<boardtype.caldac[i]->n_chans){
- bits=boardtype.caldac[i]->packbits(addr,val,&bitstring);
- loadbit=SerDacLd(i);
- break;
- }
- addr-=boardtype.caldac[i]->n_chans;
- }
-
- for(bit=1<<(bits-1);bit;bit>>=1){
- ni_writeb(((bit&bitstring)?0x02:0),Serial_Command);
- ni_writeb(1|((bit&bitstring)?0x02:0),Serial_Command);
- }
- ni_writeb(loadbit,Serial_Command);
- ni_writeb(0,Serial_Command);
-}
-
-
-
-static int pack_mb88341(int addr,int val,int *bitstring)
-{
- /*
- Fujitsu MB 88341
- Note that address bits are reversed. Thanks to
- Ingo Keen for noticing this.
-
- Note also that the 88341 expects address values from
- 1-12, whereas we use channel numbers 0-11. The NI
- docs use 1-12, also, so be careful here.
- */
- addr++;
- *bitstring=((addr&0x1)<<11) |
- ((addr&0x2)<<9) |
- ((addr&0x4)<<7) |
- ((addr&0x8)<<5) |
- (val&0xff);
- return 12;
-}
-
-static int pack_dac8800(int addr,int val,int *bitstring)
-{
- *bitstring=((addr&0x7)<<8)|(val&0xff);
- return 11;
-}
-
-static int pack_dac8043(int addr,int val,int *bitstring)
-{
- *bitstring=val&0xfff;
- return 12;
-}
-
-#ifdef PCIMIO
-static int pack_ad8522(int addr,int val,int *bitstring)
-{
- *bitstring=(val&0xfff)|(addr ? 0xc000:0xa000);
- return 16;
-}
-#endif
-
-
-
-/*
- *
- * Programmable Function Inputs
- *
- */
-
-
-static void pfi_setup(comedi_device *dev)
-{
- /* currently, we don't output any signals, thus, all
- the PFI's are input */
-
- //TIM 4/17/01 win_out(0,IO_Bidirection_Pin_Register);
- ni_set_bits(dev, IO_Bidirection_Pin_Register, 0x03ff, 0);
-}
-
-
-
-/*
- *
- * General Purpose Counter/Timer section
- *
- */
-
-/*
-* Low level stuff...Each STC counter has two 24 bit load registers (A&B). Just make
-* it easier to access them.
-*/
-static void GPCT_Load_A(comedi_device *dev, int chan, long value)
-{
- win_out( (value>>16) & 0x00ff, G_Load_A_Register_High(chan));
- win_out( value & 0xffff, G_Load_A_Register_Low(chan));
-}
-
-static void GPCT_Load_B(comedi_device *dev, int chan, long value)
-{
- win_out( (value>>16) & 0x00ff, G_Load_B_Register_High(chan));
- win_out( value & 0xffff, G_Load_B_Register_Low(chan));
-}
-
-/* Load a value into the counter, using register A as the intermediate step.
-* You might use GPCT_Load_Using_A to load a 0x000000 into a counter
-* reset its value.
-*/
-static void GPCT_Load_Using_A(comedi_device *dev, int chan, long value)
-{
- devpriv->gpct_mode[chan] &= (~G_Load_Source_Select);
- win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
- GPCT_Load_A(dev,chan,value);
- win_out( devpriv->gpct_command[chan]|G_Load,G_Command_Register(chan));
-}
-
-/* Don't use this by itself! The read is not atomic and quite unsafe.
-* If you think you need this function, use GPCT_G_Watch instead.
-*/
-int inline GPCT_G_Read(comedi_device *dev, int chan)
-{
- int tmp;
- tmp = win_in( G_Save_Register_High(chan)) << 16;
- tmp |= win_in(G_Save_Register_Low(chan));
- return tmp;
-}
-
-/*
-* Read the GPCTs current value.
-* This function is actually straight out of the STC RLPM.
-*/
-int GPCT_G_Watch(comedi_device *dev, int chan)
-{
- int save1,save2;
-
- devpriv->gpct_command[chan] &= ~G_Save_Trace;
- win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
-
- devpriv->gpct_command[chan] |= G_Save_Trace;
- win_out( devpriv->gpct_command[chan], G_Command_Register(chan));
-
- save1 = GPCT_G_Read(dev,chan);
- save2 = GPCT_G_Read(dev,chan);
-
- /*if the value changed during the read, try again*/
- if (save1 != save2) {
- save1 = GPCT_G_Read(dev,chan);
- }
- return save1;
-}
-
-
-int GPCT_Disarm(comedi_device *dev, int chan)
-{
- win_out( devpriv->gpct_command[chan] | G_Disarm,G_Command_Register(chan));
- return 0;
-}
-
-
-int GPCT_Arm(comedi_device *dev, int chan)
-{
- win_out( devpriv->gpct_command[chan] | G_Arm,G_Command_Register(chan));
- /* If the counter is doing pulse width measurement, then make
- sure that the counter did not start counting right away. This would
- indicate that we started acquiring the pulse after it had already
- started and our measurement would be inaccurate */
- if(devpriv->gpct_cur_operation[chan] == GPCT_SINGLE_PW){
- int g_status;
-
- g_status=win_in(G_Status_Register);
-
- if(chan == 0){
- //TIM 5/2/01 possible error with very short pulses
- if((G0_Counting_St & g_status)|| !(G0_Armed_St&g_status)) {
- //error: we missed the beginning of the pulse
- return -EINVAL; //there is probably a more accurate error code...
- }
- }else{
- if((G1_Counting_St & g_status)|| !(G1_Armed_St&g_status)) {
- //error: we missed the beginning of the pulse
- return -EINVAL;
- }
- }
- }
- return 0;
-}
-
-int GPCT_Set_Source(comedi_device *dev,int chan ,int source)
-{
- //printk("GPCT_Set_Source...");
- devpriv->gpct_input_select[chan] &= ~G_Source_Select(0x1f);//reset gate to 0
- switch(source) {
- case GPCT_INT_CLOCK:
- devpriv->gpct_input_select[chan] |= G_Source_Select(0);//INT_TIMEBASE
- break;
- case GPCT_EXT_PIN:
- if(chan==0)
- devpriv->gpct_input_select[chan] |= G_Source_Select(9);//PFI8
- else
- devpriv->gpct_input_select[chan] |= G_Source_Select(4);//PFI3
- break;
- default:
- return -EINVAL;
- }
- win_out(devpriv->gpct_input_select[chan], G_Input_Select_Register(chan));
- //printk("exit GPCT_Set_Source\n");
- return 0;
-}
-
-int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate)
-{
- //printk("GPCT_Set_Gate...");
- devpriv->gpct_input_select[chan] &= ~G_Gate_Select(0x1f);//reset gate to 0
- switch(gate) {
- case GPCT_NO_GATE:
- devpriv->gpct_input_select[chan] |= G_Gate_Select(31);//Low
- devpriv->gpct_mode[chan] |= G_Gate_Polarity;
- break;
- case GPCT_EXT_PIN:
- devpriv->gpct_mode[chan] &= ~G_Gate_Polarity;
- if(chan==0){
- devpriv->gpct_input_select[chan] |= G_Gate_Select(10);//PFI9
- }else{
- devpriv->gpct_input_select[chan] |= G_Gate_Select(5);//PFI4
- }
- break;
- default:
- return -EINVAL;
- }
- win_out(devpriv->gpct_input_select[chan], G_Input_Select_Register(chan));
- win_out(devpriv->gpct_mode[chan], G_Mode_Register(chan));
- //printk("exit GPCT_Set_Gate\n");
- return 0;
-}
-
-int GPCT_Set_Direction(comedi_device *dev,int chan,int direction)
-{
- //printk("GPCT_Set_Direction...");
-
- devpriv->gpct_command[chan] &= ~G_Up_Down(0x3);
- switch (direction) {
- case GPCT_UP:
- devpriv->gpct_command[chan] |= G_Up_Down(1);
- break;
- case GPCT_DOWN:
- devpriv->gpct_command[chan] |= G_Up_Down(0);
- break;
- case GPCT_HWUD:
- devpriv->gpct_command[chan] |= G_Up_Down(2);
- break;
- default:
- printk("Error direction=0x%08x..",direction);
- return -EINVAL;
- }
- win_out(devpriv->gpct_command[chan], G_Command_Register(chan));
- //TIM 4/23/01 win_out(devpriv->gpct_mode[chan], G_Mode_Register(chan));
- //printk("exit GPCT_Set_Direction\n");
- return 0;
-}
-
-void GPCT_Event_Counting(comedi_device *dev,int chan)
-{
-
- //NOTE: possible residual bits from multibit masks can corrupt
- //If you config for several measurements between Resets, watch out!
-
- //printk("GPCT_Event_Counting...");
-
- devpriv->gpct_cur_operation[chan] = GPCT_SIMPLE_EVENT;
-
- // Gating_Mode = 1
- devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Gating_Mode(1);
-
- // Trigger_Mode_For_Edge_Gate = 1
- devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
- devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);
-
- win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
- //printk("exit GPCT_Event_Counting\n");
-}
-
-void GPCT_Period_Meas(comedi_device *dev, int chan)
-{
- //printk("GPCT_Period_Meas...");
-
- devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PERIOD;
-
-
- //NOTE: possible residual bits from multibit masks can corrupt
- //If you config for several measurements between Resets, watch out!
- devpriv->gpct_mode[chan] &= ~G_OR_Gate;
- devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;
-
- // Output_Mode = 3
- devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Output_Mode(3);
-
-
- //Gating Mode=2
- devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Gating_Mode(2);
-
- // Trigger_Mode_For_Edge_Gate=0
- devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
- devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(0);
-
- devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;
- devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;
- devpriv->gpct_mode[chan] &= ~G_Loading_On_TC;
- devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;
-
- // Stop_Mode = 2
- devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Stop_Mode(0);
-
- // Counting_Once = 2
- devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
- devpriv->gpct_mode[chan] |= G_Counting_Once(2);
-
- // Up_Down = 1
- devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));
- devpriv->gpct_command[chan] |= G_Up_Down(1);
-
- win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
- win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
- //printk("exit GPCT_Period_Meas\n");
-}
-
-void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan)
-{
- //printk("GPCT_Pulse_Width_Meas...");
-
- devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PW;
-
- devpriv->gpct_mode[chan] &= ~G_OR_Gate;
- devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;
-
- // Output_Mode = 3
- devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Output_Mode(3);
-
- //Gating Mode=1
- devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Gating_Mode(1);//TIM 4/24/01 was 2
-
- // Trigger_Mode_For_Edge_Gate=2
- devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
- devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);//TIM 4/24/01 was 0
-
-
- devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;//TIM 4/24/01 was 1
- devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;//TIM 4/24/01 was 0
-
- devpriv->gpct_mode[chan] &= ~G_Loading_On_TC;
- devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;
-
- // Stop_Mode = 0
- devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Stop_Mode(0);
-
- // Counting_Once = 2
- devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
- devpriv->gpct_mode[chan] |= G_Counting_Once(2);
-
- // Up_Down = 1
- devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));
- devpriv->gpct_command[chan] |= G_Up_Down(1);
-
- win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
- win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
-
- //printk("exit GPCT_Pulse_Width_Meas\n");
-}
-
-/* GPCT_Gen_Single_Pulse() creates pulse of length pulsewidth which starts after the Arm
-signal is sent. The pulse is delayed by the value already in the counter. This function could
-be modified to send a pulse in response to a trigger event at its gate.*/
-void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length)
-{
- //printk("GPCT_Gen_Cont...");
-
- devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PULSE_OUT;
-
- // Set length of the pulse
- GPCT_Load_B(dev,chan, length-1);
-
- //Load next time using B, This is reset by GPCT_Load_Using_A()
- devpriv->gpct_mode[chan] |= G_Load_Source_Select;
-
- devpriv->gpct_mode[chan] &= ~G_OR_Gate;
- devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;
-
- // Output_Mode = 3
- devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Output_Mode(2); //TIM 4/26/01 was 3
-
- //Gating Mode=0 for untriggered single pulse
- devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Gating_Mode(0); //TIM 4/25/01 was 1
-
- // Trigger_Mode_For_Edge_Gate=0
- devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
- devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);
-
-
- devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;
- devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;
- devpriv->gpct_mode[chan] |= G_Loading_On_TC; //TIM 4/25/01
- devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;
-
- // Stop_Mode = 2
- devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Stop_Mode(2); //TIM 4/25/01
-
- // Counting_Once = 2
- devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
- devpriv->gpct_mode[chan] |= G_Counting_Once(1); //TIM 4/25/01
-
- // Up_Down = 1
- devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));
- devpriv->gpct_command[chan] |= G_Up_Down(0); //TIM 4/25/01 was 1
-
- win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
- win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
-
- //printk("exit GPCT_Gen_Cont\n");
-}
-
-void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length)
-{
- //printk("GPCT_Gen_Cont...");
-
- devpriv->gpct_cur_operation[chan] = GPCT_CONT_PULSE_OUT;
-
- // Set length of the pulse
- GPCT_Load_B(dev,chan, length-1);
-
- //Load next time using B, This is reset by GPCT_Load_Using_A()
- devpriv->gpct_mode[chan] |= G_Load_Source_Select;
-
- devpriv->gpct_mode[chan] &= ~G_OR_Gate;
- devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;
-
- // Output_Mode = 3
- devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Output_Mode(2); //TIM 4/26/01 was 3
-
- //Gating Mode=0 for untriggered single pulse
- devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Gating_Mode(0); //TIM 4/26/01 was 0
-
- // Trigger_Mode_For_Edge_Gate=0
- devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));
- devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);
-
-
- devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;
- devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;
- devpriv->gpct_mode[chan] |= G_Loading_On_TC;
- devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;
-
- // Stop_Mode = 2
- devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
- devpriv->gpct_mode[chan] |= G_Stop_Mode(0); //TIM 4/26/01
-
- // Counting_Once = 2
- devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
- devpriv->gpct_mode[chan] |= G_Counting_Once(0); //TIM 4/26/01
-
- // Up_Down = 1
- devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));
- devpriv->gpct_command[chan] |= G_Up_Down(0);
-
- //TIM 4/26/01
- //This seems pretty unsafe since I don't think it is cleared anywhere.
- //I don't think this is working
- //devpriv->gpct_command[chan] &= ~G_Bank_Switch_Enable;
- //devpriv->gpct_command[chan] &= ~G_Bank_Switch_Mode;
-
-
- win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
- win_out( devpriv->gpct_command[chan],G_Command_Register(chan));
-
- //printk("exit GPCT_Gen_Cont\n");
-}
-
-void GPCT_Reset(comedi_device *dev, int chan)
-{
- unsigned long irqflags;
- int temp_ack_reg=0;
-
- //printk("GPCT_Reset...");
- devpriv->gpct_cur_operation[chan] = GPCT_RESET;
-
- switch (chan) {
- case 0:
- //note: I need to share the soft copies of the Enable Register with the ISRs.
- // so I'm using comedi_spin_lock_irqsave() to guard this section of code
- win_out(G0_Reset,Joint_Reset_Register);
- comedi_spin_lock_irqsave(&dev->spinlock, irqflags);
- ni_set_bits(dev,Interrupt_A_Enable_Register,G0_TC_Interrupt_Enable, 0);
- ni_set_bits(dev,Interrupt_A_Enable_Register,G0_Gate_Interrupt_Enable,0);
- comedi_spin_unlock_irqrestore(&dev->spinlock, irqflags);
- temp_ack_reg |= G0_Gate_Error_Confirm;
- temp_ack_reg |= G0_TC_Error_Confirm;
- temp_ack_reg |= G0_TC_Interrupt_Ack;
- temp_ack_reg |= G0_Gate_Interrupt_Ack;
- win_out(temp_ack_reg,Interrupt_A_Ack_Register);
-
- //problem...this interferes with the other ctr...
- devpriv->an_trig_etc_reg |= GPFO_0_Output_Enable;
- win_out(devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
- break;
- case 1:
- win_out(G1_Reset,Joint_Reset_Register);
- comedi_spin_lock_irqsave(&dev->spinlock, irqflags);
- ni_set_bits(dev,Interrupt_B_Enable_Register,G1_TC_Interrupt_Enable, 0);
- ni_set_bits(dev,Interrupt_B_Enable_Register,G0_Gate_Interrupt_Enable,0);
- comedi_spin_unlock_irqrestore(&dev->spinlock, irqflags);
- temp_ack_reg |= G1_Gate_Error_Confirm;
- temp_ack_reg |= G1_TC_Error_Confirm;
- temp_ack_reg |= G1_TC_Interrupt_Ack;
- temp_ack_reg |= G1_Gate_Interrupt_Ack;
- win_out(temp_ack_reg,Interrupt_B_Ack_Register);
-
- devpriv->an_trig_etc_reg |= GPFO_1_Output_Enable;
- win_out(devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
- break;
- };
-
- devpriv->gpct_mode[chan] = 0;
- devpriv->gpct_input_select[chan] = 0;
- devpriv->gpct_command[chan] = 0;
-
- devpriv->gpct_command[chan] |= G_Synchronized_Gate;
-
- win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
- win_out( devpriv->gpct_input_select[chan],G_Input_Select_Register(chan));
- win_out( 0,G_Autoincrement_Register(chan));
-
- //printk("exit GPCT_Reset\n");
-}
-
-static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
-{
- int retval=0;
- //printk("data[0] is 0x%08x, data[1] is 0x%08x\n",data[0],data[1]);
- switch(data[0]){
- case GPCT_RESET:
- if(insn->n!=1)return -EINVAL;
- GPCT_Reset(dev,insn->chanspec);
- break;
- case GPCT_SET_SOURCE:
- if(insn->n!=2)return -EINVAL;
- retval=GPCT_Set_Source(dev,insn->chanspec,data[1]);
- break;
- case GPCT_SET_GATE:
- if(insn->n!=2)return -EINVAL;
- retval=GPCT_Set_Gate(dev,insn->chanspec,data[1]);
- break;
- case GPCT_SET_DIRECTION:
- if(insn->n!=2) return -EINVAL;
- retval=GPCT_Set_Direction(dev,insn->chanspec,data[1]);
- break;
- case GPCT_GET_INT_CLK_FRQ:
- if(insn->n!=2) return -EINVAL;
- //There are actually 2 internal clocks on the STC, we always
- //use the fast 20MHz one at this time. Tim Ousley 5/1/01
- //NOTE: This is not the final interface, ideally the user
- //will never need to know the int. clk. freq.
- data[1]=50;//50ns = 20MHz = internal timebase of STC
- break;
- case GPCT_SET_OPERATION:
- //TIM 5/1/01 if((insn->n<2)||(insn->n>3))return -EINVAL;
- switch(data[1]){
- case GPCT_SIMPLE_EVENT:
- GPCT_Event_Counting(dev,insn->chanspec);
- break;
- case GPCT_SINGLE_PERIOD:
- GPCT_Period_Meas(dev,insn->chanspec);
- break;
- case GPCT_SINGLE_PW:
- GPCT_Pulse_Width_Meas(dev,insn->chanspec);
- break;
- case GPCT_SINGLE_PULSE_OUT:
- GPCT_Gen_Single_Pulse(dev,insn->chanspec,data[2]);
- break;
- case GPCT_CONT_PULSE_OUT:
- GPCT_Gen_Cont_Pulse(dev,insn->chanspec,data[2]);
- break;
- default:
- printk("unsupported GPCT operation!\n");
- return -EINVAL;
- }
- break;
- case GPCT_ARM:
- if(insn->n!=1)return -EINVAL;
- retval=GPCT_Arm(dev,insn->chanspec);
- break;
- case GPCT_DISARM:
- if(insn->n!=1)return -EINVAL;
- retval=GPCT_Disarm(dev,insn->chanspec);
- break;
- default:
- return -EINVAL;
- }
-
- //catch any errors from return values
- if(retval==0){
- return insn->n;
- }else{
- if(data[0]!=GPCT_ARM){
- printk("error: retval was %d\n",retval);
- printk("data[0] is 0x%08x, data[1] is 0x%08x\n",data[0],data[1]);
- }
-
- return retval;
- }
-}
-
-static int ni_gpct_insn_read(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data) {
-
- int chan=insn->chanspec;
- int cur_op = devpriv->gpct_cur_operation[chan];
-
- //printk("in ni_gpct_insn_read, n=%d, data[0]=%d\n",insn->chanspec,data[0]);
- if(insn->n!=1)return -EINVAL;
-
- data[0] = GPCT_G_Watch(dev,insn->chanspec);
-
- /* for certain modes (period and pulse width measurment), the value
- in the counter is not valid until the counter stops. If the value is
- invalid, return a 0 */
- if((cur_op == GPCT_SINGLE_PERIOD) || (cur_op == GPCT_SINGLE_PW)){
- /* is the counter still running? */
- if(win_in(G_Status_Register) & (chan?G1_Counting_St:G0_Counting_St))
- data[0]=0;
- }
- return 1;
-}
-
-static int ni_gpct_insn_write(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data) {
-
- //printk("in ni_gpct_insn_write");
- if(insn->n!=1)return -EINVAL;
- GPCT_Load_Using_A(dev,insn->chanspec,data[0]);
- return 1;
-}
-
-
-static int ni_8255_callback(int dir,int port,int data,void *arg)
-{
- comedi_device *dev=arg;
-
- if(dir){
- ni_writeb(data,Port_A+2*port);
- return 0;
- }else{
- return ni_readb(Port_A+2*port);
- }
-}
+ \r
+ //TIM 4/17/01\r
+ //win_out(0x0000,Interrupt_A_Enable_Register);\r
+ //turn off all AI interrupts\r
+ ni_set_bits(dev, Interrupt_A_Enable_Register,\r
+ AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|\r
+ AI_START2_Interrupt_Enable| AI_START_Interrupt_Enable|\r
+ AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable|\r
+ AI_FIFO_Interrupt_Enable,0);\r
+ \r
+ ni_ai_reset(dev,dev->subdevices);//added by tim\r
+ comedi_done(dev,s);\r
+ return;\r
+ }\r
+ if(status&AI_SC_TC_St){\r
+#ifdef DEBUG_INTERRUPT\r
+ rt_printk("ni_mio_common: SC_TC interrupt\n");\r
+#endif\r
+#ifdef TRY_BLOCK\r
+ ni_handle_block(dev);\r
+#else\r
+ //for MITE DMA ignore the terminal count from the STC\r
+ //instead finish up when the MITE asserts DONE\r
+#ifndef PCIDMA\r
+ \r
+ if(!devpriv->ai_continuous){\r
+ ni_handle_fifo_dregs(dev);\r
+ //win_out(0x0000,Interrupt_A_Enable_Register); TIM 4/17/01\r
+ ni_set_bits(dev, Interrupt_A_Enable_Register,\r
+ AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|\r
+ AI_START2_Interrupt_Enable| AI_START_Interrupt_Enable|\r
+ AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable|\r
+ AI_FIFO_Interrupt_Enable,0);\r
+\r
+ comedi_done(dev,s);\r
+ }\r
+#endif //PCIDMA\r
+#endif //TRY_BLOCK\r
+ ack|=AI_SC_TC_Interrupt_Ack;\r
+ }\r
+ if(status&AI_START1_St){\r
+ ack|=AI_START1_Interrupt_Ack;\r
+ }\r
+ }\r
+#ifndef PCIDMA\r
+ if(status&AI_FIFO_Half_Full_St){\r
+ ni_handle_fifo_half_full(dev);\r
+ }\r
+#endif //PCIDMA\r
+ if(devpriv->aimode==AIMODE_SCAN && status&AI_STOP_St){\r
+ ni_handle_fifo_dregs(dev);\r
+\r
+ s->async->events |= COMEDI_CB_EOS;\r
+\r
+ /* we need to ack the START, also */\r
+ ack|=AI_STOP_Interrupt_Ack|AI_START_Interrupt_Ack;\r
+ }\r
+ if(devpriv->aimode==AIMODE_SAMPLE){\r
+ ni_handle_fifo_dregs(dev);\r
+\r
+ //s->async->events |= COMEDI_CB_SAMPLE;\r
+ }\r
+\r
+ if(ack) ni_writew(ack,Interrupt_A_Ack);\r
+\r
+ comedi_event(dev,s,s->async->events);\r
+}\r
+\r
+static void handle_b_interrupt(comedi_device *dev,unsigned short b_status)\r
+{\r
+ comedi_subdevice *s=dev->subdevices+1;\r
+ //unsigned short ack=0;\r
+\r
+ if(b_status==0xffff)return;\r
+ if(b_status&AO_Overrun_St){\r
+ rt_printk("ni-E: AO FIFO underrun status=0x%04x status2=0x%04x\n",b_status,ni_readw(AO_Status_2));\r
+ }\r
+\r
+ if(b_status&AO_BC_TC_St){\r
+ rt_printk("ni-E: AO BC_TC status=0x%04x status2=0x%04x\n",b_status,ni_readw(AO_Status_2));\r
+ }\r
+\r
+ if(b_status&AO_FIFO_Request_St)\r
+ ni_ao_fifo_half_empty(dev,s);\r
+\r
+ b_status=ni_readw(AO_Status_1);\r
+ if(b_status&Interrupt_B_St){\r
+ if(b_status&AO_FIFO_Request_St){\r
+ rt_printk("ni_mio_common: AO buffer underrun\n");\r
+ }\r
+ rt_printk("Ack! didn't clear AO interrupt. b_status=0x%04x\n",b_status);\r
+ win_out(0,Interrupt_B_Enable_Register);\r
+ }\r
+}\r
+\r
+#ifdef DEBUG_STATUS_A\r
+static char *status_a_strings[]={\r
+ "passthru0","fifo","G0_gate","G0_TC",\r
+ "stop","start","sc_tc","start1",\r
+ "start2","sc_tc_error","overflow","overrun",\r
+ "fifo_empty","fifo_half_full","fifo_full","interrupt_a"\r
+};\r
+\r
+static void ni_mio_print_status_a(int status)\r
+{\r
+ int i;\r
+\r
+ rt_printk("A status:");\r
+ for(i=15;i>=0;i--){\r
+ if(status&(1<<i)){\r
+ rt_printk(" %s",status_a_strings[i]);\r
+ }\r
+ }\r
+ rt_printk("\n");\r
+}\r
+#endif\r
+\r
+#ifdef DEBUG_STATUS_B\r
+static char *status_b_strings[]={\r
+ "passthru1","fifo","G1_gate","G1_TC",\r
+ "UI2_TC","UPDATE","UC_TC","BC_TC",\r
+ "start1","overrun","start","bc_tc_error",\r
+ "fifo_empty","fifo_half_full","fifo_full","interrupt_b"\r
+};\r
+\r
+static void ni_mio_print_status_b(int status)\r
+{\r
+ int i;\r
+\r
+ rt_printk("B status:");\r
+ for(i=15;i>=0;i--){\r
+ if(status&(1<<i)){\r
+ rt_printk(" %s",status_b_strings[i]);\r
+ }\r
+ }\r
+ rt_printk("\n");\r
+}\r
+#endif\r
+\r
+static void ni_ai_fifo_read(comedi_device *dev,comedi_subdevice *s,\r
+ sampl_t *data,int n)\r
+{\r
+ comedi_async *async = s->async;\r
+ int i,j;\r
+ sampl_t d;\r
+ unsigned int mask;\r
+\r
+ mask=(1<<boardtype.adbits)-1;\r
+ j=async->cur_chan;\r
+ for(i=0;i<n;i++){\r
+ d=ni_readw(ADC_FIFO_Data_Register);\r
+ d^=devpriv->ai_xorlist[j];\r
+ d&=mask;\r
+ data[i]=d;\r
+ j++;\r
+ if(j>=async->cur_chanlist_len){\r
+ j=0;\r
+ async->events |= COMEDI_CB_EOS;\r
+ }\r
+ }\r
+ async->cur_chan=j;\r
+}\r
+\r
+#ifdef PCIDMA\r
+void ni_munge(comedi_device *dev,comedi_subdevice *s,sampl_t *start, sampl_t *stop)\r
+{\r
+ comedi_async *async = s->async;\r
+ int j;\r
+ sampl_t *i;\r
+ unsigned int mask;\r
+\r
+ mask=(1<<boardtype.adbits)-1;\r
+ j=async->cur_chan;\r
+ for(i=start;i<stop;i++){\r
+ *i ^=devpriv->ai_xorlist[j];\r
+ *i &=mask;\r
+ j++;\r
+ j %= async->cur_chanlist_len;\r
+ }\r
+ async->cur_chan=j;\r
+}\r
+\r
+static void ni_handle_block_dma(comedi_device *dev)\r
+{\r
+ MDPRINTK("ni_handle_block_dma\n");\r
+ //mite_dump_regs(devpriv->mite); \r
+ mite_dma_disarm(devpriv->mite);\r
+ //TIM 4/17/01 win_out(0x0000,Interrupt_A_Enable_Register);\r
+ ni_set_bits(dev, Interrupt_A_Enable_Register,\r
+ AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|\r
+ AI_START2_Interrupt_Enable| AI_START_Interrupt_Enable|\r
+ AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable|\r
+ AI_FIFO_Interrupt_Enable,0);\r
+\r
+ ni_ai_reset(dev,dev->subdevices);\r
+ comedi_done(dev,dev->subdevices);\r
+ MDPRINTK("exit ni_handle_block_dma\n");\r
+}\r
+#endif\r
+\r
+#ifdef TRY_BLOCK\r
+/* Blocked mode is used to get interrupts at convenient places\r
+ * to do DMA. It is also useful when you want to count greater\r
+ * than 16M scans.\r
+ */\r
+static void ni_handle_block(comedi_device *dev)\r
+{\r
+ int n;\r
+\r
+ if(devpriv->ai_continuous){\r
+ n = devpriv->blocksize;\r
+ }else{\r
+ if(devpriv->n_left==0){\r
+ ni_handle_fifo_dregs(dev);\r
+ printk("end\n");\r
+ //TIM 4/17/01 win_out(0x0000,Interrupt_A_Enable_Register);\r
+ ni_set_bits(dev, Interrupt_A_Enable_Register,\r
+ AI_SC_TC_Interrupt_Enable | AI_Start1_Interrupt_Enable|\r
+ AI_Start2_Interrupt_Enable| AI_Start_Interrupt_Enable|\r
+ AI_Stop_Interrupt_Enable| AI_Error_Interrupt_Enable|\r
+ AI_FIFO_Interrupt_Enable,0);\r
+ ni_ai_reset(dev,dev->subdevices);\r
+ comedi_done(dev,dev->subdevices);\r
+ }else if(devpriv->n_left<=devpriv->blocksize){\r
+ printk("last block %d\n",devpriv->n_left);\r
+ n = devpriv->n_left;\r
+ devpriv->n_left = 0;\r
+ }else{\r
+ printk("block %d\n",devpriv->n_left);\r
+ n = devpriv->blocksize;\r
+ devpriv->n_left -= devpriv->blocksize;\r
+ }\r
+ }\r
+#if 0\r
+ {\r
+ int size=0x10000;\r
+\r
+ /* stage number of scans */\r
+ win_out((size-1)>>16,AI_SC_Load_A_Registers);\r
+ win_out((size-1)&0xffff,AI_SC_Load_A_Registers+1);\r
+\r
+ //mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;\r
+ mode1 |= 0xe;\r
+ win_out(mode1,AI_Mode_1_Register);\r
+\r
+ /* load SC (Scan Count) */\r
+ win_out(AI_SC_Load,AI_Command_1_Register);\r
+\r
+ }\r
+#endif\r
+}\r
+#endif\r
+\r
+static void ni_handle_fifo_half_full(comedi_device *dev)\r
+{\r
+ int n,m;\r
+ comedi_subdevice *s=dev->subdevices+0;\r
+ comedi_async *async=s->async;\r
+\r
+ /*\r
+ if we got a fifo_half_full interrupt, we can transfer fifo/2\r
+ samples without checking the empty flag. It doesn't matter if\r
+ we transfer the rest of the samples, the performance trade-off\r
+ is minimal (checking empty flag for a few samples vs. having\r
+ 1% more interrupts.) At really high speeds, it's better to\r
+ ignore them.\r
+\r
+ */\r
+\r
+ n=boardtype.ai_fifo_depth/2;\r
+\r
+ /* this makes the assumption that the buffer length is\r
+ greater than the half-fifo depth. */\r
+\r
+ if(async->buf_int_ptr+n*sizeof(sampl_t)>=async->data_len){\r
+ m=(async->data_len-async->buf_int_ptr)/sizeof(sampl_t);\r
+ ni_ai_fifo_read(dev,s,async->data+async->buf_int_ptr,m);\r
+ async->buf_int_count+=m*sizeof(sampl_t);\r
+ n-=m;\r
+ async->buf_int_ptr=0;\r
+\r
+ async->events |= COMEDI_CB_EOBUF;\r
+ }\r
+ ni_ai_fifo_read(dev,s,async->data+async->buf_int_ptr,n);\r
+ async->buf_int_count+=n*sizeof(sampl_t);\r
+ async->buf_int_ptr+=n*sizeof(sampl_t);\r
+\r
+ async->events |= COMEDI_CB_BLOCK;\r
+}\r
+\r
+/*\r
+ Empties the AI fifo\r
+*/\r
+static void ni_handle_fifo_dregs(comedi_device *dev)\r
+{\r
+ comedi_subdevice *s=dev->subdevices+0;\r
+ sampl_t *data,d;\r
+ int i,n;\r
+ int j;\r
+ unsigned int mask;\r
+\r
+ mask=(1<<boardtype.adbits)-1;\r
+ j=s->async->cur_chan;\r
+ data=s->async->data+s->async->buf_int_ptr;\r
+ while(1){\r
+ n=(s->async->data_len-s->async->buf_int_ptr)/sizeof(sampl_t);\r
+ for(i=0;i<n;i++){\r
+ if(ni_readw(AI_Status_1)&AI_FIFO_Empty_St){\r
+ s->async->cur_chan=j;\r
+ return;\r
+ }\r
+ d=ni_readw(ADC_FIFO_Data_Register);\r
+ d^=devpriv->ai_xorlist[j];\r
+ d&=mask;\r
+ *data=d;\r
+ j++;\r
+ if(j>=s->async->cur_chanlist_len){\r
+ j=0;\r
+ //s->events |= COMEDI_CB_EOS;\r
+ }\r
+ data++;\r
+ s->async->buf_int_ptr+=sizeof(sampl_t);\r
+ s->async->buf_int_count+=sizeof(sampl_t);\r
+ }\r
+ s->async->buf_int_ptr=0;\r
+ data=s->async->data;\r
+ s->async->events |= COMEDI_CB_EOBUF;\r
+ }\r
+}\r
+\r
+#ifdef PCIDMA\r
+int ni_ai_setup_block_dma(comedi_device *dev,int frob,int mode1)\r
+{\r
+ int n;\r
+ int len;\r
+ unsigned long ll_start;\r
+ comedi_cmd *cmd=&dev->subdevices->async->cmd;\r
+ \r
+ MDPRINTK("ni_ai_setup_block_dma\n");\r
+ \r
+ /*Build MITE linked list and configure the MITE\r
+ * ******WARNING******\r
+ * There is no error handling here, \r
+ * the memory buffer *Must* be mlock'ed by the user*/\r
+\r
+ len = sizeof(sampl_t)*cmd->stop_arg*cmd->scan_end_arg;\r
+\r
+ /*use kvmem if no user buf specified */\r
+ ll_start = mite_ll_from_kvmem(devpriv->mite,dev->subdevices->async,\r
+ len);\r
+\r
+ mite_setregs(devpriv->mite, ll_start,0,COMEDI_INPUT);\r
+\r
+ /*tell the STC to use DMA0 for AI. \r
+ * Select the MITE DMA channel to use, 0x01=A*/\r
+ ni_writeb(0x01,AI_AO_Select);\r
+\r
+ /* stage number of scans */\r
+ n = cmd->stop_arg;\r
+ win_out((n-1)>>16,AI_SC_Load_A_Registers);\r
+ win_out((n-1)&0xffff,AI_SC_Load_A_Registers+1);\r
+ win_out((n-1)>>16,AI_SC_Load_B_Registers);\r
+ win_out((n-1)&0xffff,AI_SC_Load_B_Registers+1);\r
+ \r
+ /* load SC (Scan Count) */\r
+ win_out(AI_SC_Load,AI_Command_1_Register);\r
+\r
+ mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;\r
+ win_out(mode1,AI_Mode_1_Register);\r
+ \r
+ /*start the MITE*/\r
+ mite_dma_arm(devpriv->mite);\r
+ \r
+ MDPRINTK("exit ni_ai_setup_block_dma\n");\r
+\r
+ return mode1;\r
+}\r
+#endif\r
+\r
+#ifdef TRY_BLOCK\r
+int ni_ai_setup_block(comedi_device *dev,int frob,int mode1)\r
+{\r
+ int n;\r
+ int last=0;\r
+\r
+printk("n_left = %d\n",devpriv->n_left);\r
+ if(devpriv->ai_continuous){\r
+ n=devpriv->blocksize;\r
+ last=0;\r
+ }else{\r
+ n=devpriv->n_left;\r
+ if(n>devpriv->blocksize){\r
+ n=devpriv->blocksize;\r
+ last=0;\r
+ }else{\r
+ last=1;\r
+ }\r
+ devpriv->n_left -= n;\r
+ }\r
+\r
+ if(frob){\r
+ /* stage number of scans */\r
+ win_out((n-1)>>16,AI_SC_Load_A_Registers);\r
+ win_out((n-1)&0xffff,AI_SC_Load_A_Registers+1);\r
+ win_out((n-1)>>16,AI_SC_Load_B_Registers);\r
+ win_out((n-1)&0xffff,AI_SC_Load_B_Registers+1);\r
+\r
+ /* load SC (Scan Count) */\r
+ win_out(AI_SC_Load,AI_Command_1_Register);\r
+#if 0\r
+ if(!last){\r
+ mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;\r
+ }else{\r
+ mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Trigger_Once;\r
+ }\r
+#endif\r
+ mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;\r
+ win_out(mode1,AI_Mode_1_Register);\r
+\r
+ }\r
+\r
+ return mode1;\r
+}\r
+#endif\r
+\r
+#ifdef PCIDMA\r
+int ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd,int mode1)\r
+{\r
+ int n,len;\r
+ unsigned long ll_start;\r
+ comedi_async *async_mite;\r
+ \r
+ len = sizeof(sampl_t)*cmd->stop_arg*cmd->scan_end_arg;\r
+ async_mite=dev->subdevices[cmd->subdev].async;\r
+ ll_start = mite_ll_from_kvmem(devpriv->mite, async_mite,len);\r
+ mite_setregs(devpriv->mite, ll_start,0,COMEDI_INPUT);\r
+\r
+ /*tell the STC to use DMA0 for AI.\r
+ Select the MITE DMA channel to use, 0x01=A*/\r
+ ni_writeb(0x01,AI_AO_Select);\r
+\r
+ /* stage number of scans */\r
+ n = cmd->stop_arg;\r
+ win_out((n-1)>>16,AI_SC_Load_A_Registers);\r
+ win_out((n-1)&0xffff,AI_SC_Load_A_Registers+1);\r
+ win_out((n-1)>>16,AI_SC_Load_B_Registers);\r
+ win_out((n-1)&0xffff,AI_SC_Load_B_Registers+1);\r
+ \r
+ /* load SC (Scan Count) */\r
+ win_out(AI_SC_Load,AI_Command_1_Register);\r
+\r
+ mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;\r
+ win_out(mode1,AI_Mode_1_Register);\r
+ \r
+ /*start the MITE*/\r
+ mite_dma_arm(devpriv->mite);\r
+ return mode1;\r
+}\r
+#endif\r
+\r
+/*\r
+ used for both cancel ioctl and board initialization\r
+\r
+ this is pretty harsh for a cancel, but it works...\r
+ */\r
+static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s)\r
+{\r
+#ifdef PCIDMA\r
+ mite_dma_disarm(devpriv->mite);\r
+#endif\r
+ //TIM 4/17/01 win_out(0x0000,Interrupt_A_Enable_Register);\r
+ ni_set_bits(dev, Interrupt_A_Enable_Register,\r
+ AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|\r
+ AI_START2_Interrupt_Enable| AI_START_Interrupt_Enable|\r
+ AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable|\r
+ AI_FIFO_Interrupt_Enable,0);\r
+\r
+ win_out(AI_Reset,Joint_Reset_Register);\r
+\r
+ win_out(1,ADC_FIFO_Clear);\r
+\r
+ /* ai configuration */\r
+\r
+ win_out(AI_Configuration_Start,Joint_Reset_Register);\r
+\r
+ win_out(0x0000,AI_Command_1_Register); /* reset pulses */\r
+ win_out(0x000d,AI_Mode_1_Register);\r
+ win_out(0x0000,AI_Mode_2_Register);\r
+#if 0\r
+ win_out((1<<6)|0x0000,AI_Mode_3_Register); /* generate FIFO interrupts on half full */\r
+#else\r
+ win_out((0<<6)|0x0000,AI_Mode_3_Register); /* generate FIFO interrupts on non-empty */\r
+#endif\r
+ /* TIM 5/11/01 \r
+ 0xA4A0 causes overrun errors at high speeds. 0xA420 fixes it,\r
+ but I haven't tested to see if it breaks something else. I don't think it would*/\r
+ #ifdef PCIDMA \r
+ win_out(0xA420,AI_Personal_Register); \r
+ #else\r
+ win_out(0xa4a0,AI_Personal_Register); /* ? */\r
+ #endif\r
+ win_out(0x032e,AI_Output_Control_Register);\r
+ win_out(0x0060,AI_Trigger_Select_Register); /* trigger source */\r
+\r
+ /* this should be done in _ai_modeX() */\r
+ win_out(0x29e0,AI_START_STOP_Select_Register);\r
+\r
+ /* the following registers should not be changed, because there\r
+ * are no backup registers in devpriv. If you want to change\r
+ * any of these, add a backup register and other appropriate code:\r
+ * Clock_and_FOUT_Register\r
+ * AI_Mode_1_Register\r
+ * AI_Mode_3_Register\r
+ * AI_Personal_Register\r
+ * AI_Output_Control_Register\r
+ * AI_Trigger_Select_Register\r
+ */\r
+ win_out(0x3f80,Interrupt_A_Ack_Register); /* clear interrupts */\r
+\r
+ win_out(AI_Configuration_End,Joint_Reset_Register);\r
+\r
+ return 0;\r
+}\r
+\r
+static int ni_ai_poll(comedi_device *dev,comedi_subdevice *s)\r
+{\r
+ unsigned long flags;\r
+\r
+ comedi_spin_lock_irqsave(&dev->spinlock,flags);\r
+ ni_handle_fifo_dregs(dev);\r
+ comedi_spin_unlock_irqrestore(&dev->spinlock,flags);\r
+\r
+ comedi_event(dev,s,s->async->events);\r
+\r
+ return s->async->buf_int_count-s->async->buf_user_count;\r
+}\r
+\r
+static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,unsigned int *list,int dither);\r
+\r
+#define NI_TIMEOUT 1000\r
+\r
+\r
+static int ni_ai_insn_read(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)\r
+{\r
+ int i,n;\r
+ int wsave;\r
+ unsigned int mask,sign;\r
+\r
+ wsave=win_save();\r
+\r
+ win_out(1,ADC_FIFO_Clear);\r
+\r
+ /* interrupt on errors */\r
+ //TIM 4/17/01 win_out(0x0020,Interrupt_A_Enable_Register);\r
+ ni_set_bits(dev, Interrupt_A_Enable_Register, AI_Error_Interrupt_Enable,1);\r
+\r
+\r
+ //ni_load_channelgain_list(dev,1,&insn->chanspec,(insn->flags&TRIG_DITHER)==TRIG_DITHER);\r
+ ni_load_channelgain_list(dev,1,&insn->chanspec,0);\r
+\r
+#if 0\r
+#define NI_TIMEOUT 1000\r
+#endif\r
+ mask=(1<<boardtype.adbits)-1;\r
+ sign=devpriv->ai_xorlist[0];\r
+ for(n=0;n<insn->n;n++){\r
+ win_out(1,AI_Command_1_Register);\r
+ for(i=0;i<NI_TIMEOUT;i++){\r
+ if(!(ni_readw(AI_Status_1)&AI_FIFO_Empty_St))\r
+ break;\r
+ }\r
+ if(i==NI_TIMEOUT){\r
+ rt_printk("ni_E: timeout 2\n");\r
+ win_restore(wsave);\r
+ return -ETIME;\r
+ }\r
+ data[n]=(ni_readw(ADC_FIFO_Data_Register)&mask)^sign;\r
+ }\r
+ win_restore(wsave);\r
+ return insn->n;\r
+}\r
+\r
+\r
+static void ni_load_channelgain_list(comedi_device *dev,unsigned int n_chan,unsigned int *list,int dither)\r
+{\r
+ unsigned int chan,range,aref;\r
+ unsigned int i;\r
+ unsigned int hi,lo;\r
+ unsigned short sign;\r
+\r
+ if(n_chan==1){\r
+ if(devpriv->changain_state && devpriv->changain_spec==list[0]){\r
+ // ready to go.\r
+ return;\r
+ }\r
+ devpriv->changain_state=1;\r
+ devpriv->changain_spec=list[0];\r
+ }else{\r
+ devpriv->changain_state=0;\r
+ }\r
+\r
+ win_out(1,Configuration_Memory_Clear);\r
+\r
+ sign=1<<(boardtype.adbits-1);\r
+ for(i=0;i<n_chan;i++){\r
+ chan=CR_CHAN(list[i]);\r
+ range=CR_RANGE(list[i]);\r
+ aref=CR_AREF(list[i]);\r
+\r
+ /* fix the external/internal range differences */\r
+ range=ni_gainlkup[boardtype.gainlkup][range];\r
+ devpriv->ai_xorlist[i]=(range<8)?sign:0;\r
+\r
+ hi=ni_modebits1[aref]|(chan&ni_modebits2[aref]);\r
+ ni_writew(hi,Configuration_Memory_High);\r
+\r
+ lo=((i==n_chan-1)?0x8000:0) | ((range&0x8)<<5) | (range&0x7) | (dither<<9);\r
+ ni_writew(lo,Configuration_Memory_Low);\r
+ }\r
+\r
+ /* prime the channel/gain list */\r
+\r
+ win_out(1,AI_Command_1_Register);\r
+ for(i=0;i<1000;i++){\r
+ if(!(ni_readw(AI_Status_1)&AI_FIFO_Empty_St)){\r
+ win_out(1,ADC_FIFO_Clear);\r
+ return;\r
+ }\r
+ //udelay(25);\r
+ }\r
+ rt_printk("ni_E: timeout 1\n");\r
+}\r
+\r
+#define TIMER_BASE 50 /* 20 Mhz base */\r
+\r
+static int ni_ns_to_timer(int *nanosec,int round_mode)\r
+{\r
+ int divider,base;\r
+\r
+ base=TIMER_BASE;\r
+\r
+ switch(round_mode){\r
+ case TRIG_ROUND_NEAREST:\r
+ default:\r
+ divider=(*nanosec+base/2)/base;\r
+ break;\r
+ case TRIG_ROUND_DOWN:\r
+ divider=(*nanosec)/base;\r
+ break;\r
+ case TRIG_ROUND_UP:\r
+ divider=(*nanosec+base-1)/base;\r
+ break;\r
+ }\r
+\r
+ *nanosec=base*divider;\r
+ return divider-1;\r
+}\r
+\r
+static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)\r
+{\r
+ int err=0;\r
+ int tmp;\r
+\r
+ /* step 1: make sure trigger sources are trivially valid */\r
+\r
+ tmp=cmd->start_src;\r
+ cmd->start_src &= TRIG_NOW|TRIG_INT;\r
+ if(!cmd->start_src || tmp!=cmd->start_src)err++;\r
+\r
+ tmp=cmd->scan_begin_src;\r
+ cmd->scan_begin_src &= TRIG_TIMER|TRIG_EXT;\r
+ if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;\r
+\r
+ tmp=cmd->convert_src;\r
+ cmd->convert_src &= TRIG_TIMER|TRIG_EXT;\r
+ if(!cmd->convert_src || tmp!=cmd->convert_src)err++;\r
+\r
+ tmp=cmd->scan_end_src;\r
+ cmd->scan_end_src &= TRIG_COUNT;\r
+ if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;\r
+\r
+ tmp=cmd->stop_src;\r
+ cmd->stop_src &= TRIG_COUNT|TRIG_NONE;\r
+ if(!cmd->stop_src || tmp!=cmd->stop_src)err++;\r
+\r
+ if(err)return 1;\r
+\r
+ /* step 2: make sure trigger sources are unique and mutually compatible */\r
+\r
+ /* note that mutual compatiblity is not an issue here */\r
+ if(cmd->start_src!=TRIG_NOW &&\r
+ cmd->start_src!=TRIG_INT)err++;\r
+ if(cmd->scan_begin_src!=TRIG_TIMER &&\r
+ cmd->scan_begin_src!=TRIG_EXT)err++;\r
+ if(cmd->convert_src!=TRIG_TIMER &&\r
+ cmd->convert_src!=TRIG_EXT)err++;\r
+ if(cmd->stop_src!=TRIG_COUNT &&\r
+ cmd->stop_src!=TRIG_NONE)err++;\r
+\r
+ if(err)return 2;\r
+\r
+ /* step 3: make sure arguments are trivially compatible */\r
+\r
+ if(cmd->start_arg!=0){\r
+ /* true for both TRIG_NOW and TRIG_INT */\r
+ cmd->start_arg=0;\r
+ err++;\r
+ }\r
+ if(cmd->scan_begin_src==TRIG_TIMER){\r
+ if(cmd->scan_begin_arg<boardtype.ai_speed){\r
+ cmd->scan_begin_arg=boardtype.ai_speed;\r
+ err++;\r
+ }\r
+ if(cmd->scan_begin_arg>TIMER_BASE*0xffffff){\r
+ cmd->scan_begin_arg=TIMER_BASE*0xffffff;\r
+ err++;\r
+ }\r
+ }else{\r
+ /* external trigger */\r
+ /* should be level/edge, hi/lo specification here */\r
+ /* should specify multiple external triggers */\r
+#if 0\r
+/* XXX This is disabled, since we want to use bits 30 and 31 to\r
+ * refer to edge/level and hi/lo triggering. */\r
+ if(cmd->scan_begin_arg>9){\r
+ cmd->scan_begin_arg=9;\r
+ err++;\r
+ }\r
+#endif\r
+ }\r
+ if(cmd->convert_src==TRIG_TIMER){\r
+ if(cmd->convert_arg<boardtype.ai_speed){\r
+ cmd->convert_arg=boardtype.ai_speed;\r
+ err++;\r
+ }\r
+ if(cmd->convert_arg>TIMER_BASE*0xffff){\r
+ cmd->convert_arg=TIMER_BASE*0xffff;\r
+ err++;\r
+ }\r
+ }else{\r
+ /* external trigger */\r
+ /* see above */\r
+#if 0\r
+/* XXX This is disabled, since we want to use bits 30 and 31 to\r
+ * refer to edge/level and hi/lo triggering. */\r
+ if(cmd->convert_arg>9){\r
+ cmd->convert_arg=9;\r
+ err++;\r
+ }\r
+#endif\r
+ }\r
+\r
+ if(cmd->scan_end_arg!=cmd->chanlist_len){\r
+ cmd->scan_end_arg=cmd->chanlist_len;\r
+ err++;\r
+ }\r
+ if(cmd->stop_src==TRIG_COUNT){\r
+ if(cmd->stop_arg>0x00ffffff){\r
+ cmd->stop_arg=0x00ffffff;\r
+ err++;\r
+ }\r
+ }else{\r
+ /* TRIG_NONE */\r
+ if(cmd->stop_arg!=0){\r
+ cmd->stop_arg=0;\r
+ err++;\r
+ }\r
+ }\r
+\r
+ if(err)return 3;\r
+\r
+ /* step 4: fix up any arguments */\r
+\r
+ if(cmd->scan_begin_src==TRIG_TIMER){\r
+ tmp=cmd->scan_begin_arg;\r
+ ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);\r
+ if(tmp!=cmd->scan_begin_arg)err++;\r
+ }\r
+ if(cmd->convert_src==TRIG_TIMER){\r
+ tmp=cmd->convert_arg;\r
+ ni_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);\r
+ if(tmp!=cmd->convert_arg)err++;\r
+ if(cmd->scan_begin_src==TRIG_TIMER &&\r
+ cmd->scan_begin_arg<cmd->convert_arg*cmd->scan_end_arg){\r
+ cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg;\r
+ err++;\r
+ }\r
+ }\r
+\r
+ if(err)return 4;\r
+\r
+ return 0;\r
+}\r
+\r
+static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)\r
+{\r
+ int wsave;\r
+ comedi_cmd *cmd=&s->async->cmd;\r
+ int timer;\r
+ int mode1=0; /* mode1 is needed for both stop and convert */\r
+ int mode2=0;\r
+\r
+ MDPRINTK("ni_ai_cmd\n");\r
+ wsave = win_save();\r
+\r
+ win_out(1,ADC_FIFO_Clear);\r
+\r
+ ni_load_channelgain_list(dev,cmd->chanlist_len,cmd->chanlist,\r
+ (cmd->flags&TRIG_DITHER)==TRIG_DITHER);\r
+\r
+ /* start configuration */\r
+ win_out(AI_Configuration_Start,Joint_Reset_Register);\r
+\r
+#ifndef TRY_BLOCK\r
+ #ifdef PCIDMA\r
+ ni_ai_setup_MITE_dma(dev,cmd,mode1); \r
+ #else\r
+ switch(cmd->stop_src){\r
+ case TRIG_COUNT:\r
+ /* stage number of scans */\r
+ win_out((cmd->stop_arg-1)>>16,AI_SC_Load_A_Registers);\r
+ win_out((cmd->stop_arg-1)&0xffff,AI_SC_Load_A_Registers+1);\r
+\r
+ mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Trigger_Once;\r
+ win_out(mode1,AI_Mode_1_Register);\r
+\r
+ /* load SC (Scan Count) */\r
+ win_out(AI_SC_Load,AI_Command_1_Register);\r
+\r
+ devpriv->ai_continuous = 0;\r
+\r
+ break;\r
+ case TRIG_NONE:\r
+ /* stage number of scans */\r
+ win_out(0,AI_SC_Load_A_Registers);\r
+ win_out(0,AI_SC_Load_A_Registers+1);\r
+\r
+ mode1 |= AI_Start_Stop | AI_Mode_1_Reserved | AI_Continuous;\r
+ win_out(mode1,AI_Mode_1_Register);\r
+\r
+ /* load SC (Scan Count) */\r
+ win_out(AI_SC_Load,AI_Command_1_Register);\r
+\r
+ devpriv->ai_continuous = 1;\r
+\r
+ break;\r
+ }\r
+ #endif\r
+#else\r
+ devpriv->blocksize = 0x4000;\r
+ switch(cmd->stop_src){\r
+ case TRIG_COUNT:\r
+ devpriv->ai_continuous = 0;\r
+ devpriv->n_left = cmd->stop_arg;\r
+ break;\r
+ case TRIG_NONE:\r
+ devpriv->ai_continuous = 1;\r
+ devpriv->n_left = 0;\r
+ break;\r
+ }\r
+\r
+ mode1 = ni_ai_setup_block(dev,1,mode1);\r
+#endif\r
+\r
+\r
+ switch(cmd->scan_begin_src){\r
+ case TRIG_TIMER:\r
+ /*\r
+ AI_SI_Special_Trigger_Delay=0\r
+ AI_Pre_Trigger=0\r
+ AI_START_STOP_Select_Register:\r
+ AI_START_Polarity=0 (?) rising edge\r
+ AI_START_Edge=1 edge triggered\r
+ AI_START_Sync=1 (?)\r
+ AI_START_Select=0 SI_TC\r
+ AI_STOP_Polarity=0 rising edge\r
+ AI_STOP_Edge=0 level\r
+ AI_STOP_Sync=1\r
+ AI_STOP_Select=19 external pin (configuration mem)\r
+ */\r
+ win_out(AI_START_Edge|AI_START_Sync|\r
+ AI_STOP_Select(19)|AI_STOP_Sync,\r
+ AI_START_STOP_Select_Register);\r
+\r
+ timer=ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);\r
+ win_out((timer>>16),AI_SI_Load_A_Registers);\r
+ win_out((timer&0xffff),AI_SI_Load_A_Registers+1);\r
+\r
+ /* AI_SI_Initial_Load_Source=A */\r
+ mode2 |= AI_SI_Initial_Load_Source&0;\r
+//mode2 |= AI_SC_Reload_Mode;\r
+ win_out(mode2,AI_Mode_2_Register);\r
+\r
+ /* load SI */\r
+ win_out(AI_SI_Load,AI_Command_1_Register);\r
+\r
+ /* stage freq. counter into SI B */\r
+ win_out((timer>>16),AI_SI_Load_B_Registers);\r
+ win_out((timer&0xffff),AI_SI_Load_B_Registers+1);\r
+\r
+ break;\r
+ case TRIG_EXT:\r
+ {\r
+ unsigned int reg = 0;\r
+\r
+/* XXX duh, these should be moved, but I need to think about it\r
+ * a bit first. --ds */\r
+#define COMEDI_TRIG_LEVEL 0\r
+#define COMEDI_TRIG_EDGE (1<<31)\r
+#define COMEDI_TRIG_FALLING 0\r
+#define COMEDI_TRIG_RISING (1<<30)\r
+\r
+ if(cmd->scan_begin_arg&COMEDI_TRIG_EDGE)\r
+ reg |= AI_START_Edge;\r
+ /* AI_START_Polarity==1 is falling edge */\r
+ if(!(cmd->scan_begin_arg&COMEDI_TRIG_RISING))\r
+ reg |= AI_START_Polarity;\r
+ reg |= AI_START_Sync;\r
+ reg |= AI_START_Select(1+(cmd->scan_begin_arg&0xf));\r
+ reg |= AI_STOP_Select(19)|AI_STOP_Sync;\r
+\r
+ win_out(reg,AI_START_STOP_Select_Register);\r
+ break;\r
+ }\r
+ }\r
+\r
+ switch(cmd->convert_src){\r
+ case TRIG_TIMER:\r
+ timer=ni_ns_to_timer(&cmd->convert_arg,TRIG_ROUND_NEAREST);\r
+ win_out(1,AI_SI2_Load_A_Register); /* 0,0 does not work. */\r
+ win_out(timer,AI_SI2_Load_B_Register);\r
+\r
+ /* AI_SI2_Reload_Mode = alternate */\r
+ /* AI_SI2_Initial_Load_Source = A */\r
+ win_out((AI_SI2_Initial_Load_Source&0)|\r
+ (AI_SI2_Reload_Mode),\r
+ AI_Mode_2_Register);\r
+\r
+ /* AI_SI2_Load */\r
+ win_out(AI_SI2_Load,AI_Command_1_Register);\r
+\r
+ //mode2 |= AI_SI_Reload_Mode(0);\r
+ /* XXX the AI_SI stuff should go to the scan_begin_src area */\r
+ mode2 |= AI_SI_Reload_Mode(1);\r
+ //mode2 |= 0&AI_SI_Initial_Load_Source;\r
+ mode2 |= AI_SI_Initial_Load_Source;\r
+ mode2 |= AI_SI2_Reload_Mode; // alternate\r
+ mode2 |= AI_SI2_Initial_Load_Source; // B\r
+\r
+ win_out(mode2,AI_Mode_2_Register);\r
+\r
+ break;\r
+ case TRIG_EXT:\r
+ mode1 |= AI_CONVERT_Source_Select(1+cmd->convert_arg) |\r
+ AI_CONVERT_Source_Polarity;\r
+ win_out(mode1,AI_Mode_1_Register);\r
+\r
+ win_out(mode2 | AI_SI2_Reload_Mode,AI_Mode_2_Register);\r
+\r
+ mode2 |= AI_SI_Reload_Mode(0);\r
+ mode2 |= 0&AI_SI_Initial_Load_Source;\r
+ mode2 |= AI_SI2_Reload_Mode; // alternate\r
+ mode2 |= AI_SI2_Initial_Load_Source; // B\r
+\r
+ win_out(mode2,AI_Mode_2_Register);\r
+\r
+ break;\r
+ }\r
+\r
+ if(dev->irq){\r
+ int bits;\r
+\r
+ /* interrupt on FIFO, errors, SC_TC */\r
+ bits= AI_Error_Interrupt_Enable|\r
+ AI_SC_TC_Interrupt_Enable;\r
+\r
+#ifndef PCIDMA\r
+ bits|=AI_FIFO_Interrupt_Enable;\r
+#endif\r
+\r
+ if(s->async->cb_mask&COMEDI_CB_EOS){\r
+ /* wake on end-of-scan */\r
+ devpriv->aimode=AIMODE_SCAN;\r
+ }else{\r
+ devpriv->aimode=AIMODE_HALF_FULL;\r
+ }\r
+\r
+ switch(devpriv->aimode){\r
+ case AIMODE_HALF_FULL:\r
+ /*generate FIFO interrupts on half-full */\r
+ win_out(AI_FIFO_Mode_HF|0x0000,AI_Mode_3_Register);\r
+ break;\r
+ case AIMODE_SAMPLE:\r
+ /*generate FIFO interrupts on non-empty */\r
+ win_out(AI_FIFO_Mode_NE|0x0000,AI_Mode_3_Register);\r
+ break;\r
+ case AIMODE_SCAN:\r
+ /*generate FIFO interrupts on half-full */\r
+ win_out(AI_FIFO_Mode_HF|0x0000,AI_Mode_3_Register);\r
+ bits|=AI_STOP_Interrupt_Enable;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ win_out(0x3f80,Interrupt_A_Ack_Register); /* clear interrupts */\r
+\r
+ //TIM 4/17/01 win_out(bits,Interrupt_A_Enable_Register) ;\r
+ ni_set_bits(dev, Interrupt_A_Enable_Register, bits, 1);\r
+ \r
+ MDPRINTK("Interrupt_A_Enable_Register = 0x%04x\n",bits);\r
+ }else{\r
+ /* interrupt on nothing */\r
+ win_out(0x0000,Interrupt_A_Enable_Register) ;\r
+\r
+ /* XXX start polling if necessary */\r
+ MDPRINTK("interrupting on nothing\n");\r
+ }\r
+\r
+ /* end configuration */\r
+ win_out(AI_Configuration_End,Joint_Reset_Register);\r
+\r
+ switch(cmd->scan_begin_src){\r
+ case TRIG_TIMER:\r
+ /* AI_SI2_Arm, AI_SI_Arm, AI_DIV_Arm, AI_SC_Arm */\r
+ win_out(0x1540,AI_Command_1_Register);\r
+ break;\r
+ case TRIG_EXT:\r
+ /* AI_SI2_Arm, AI_DIV_Arm, AI_SC_Arm */\r
+ win_out(0x1540,AI_Command_1_Register);\r
+ break;\r
+ }\r
+\r
+ if(cmd->start_src==TRIG_NOW){\r
+ /* TRIG_NOW */\r
+ /* AI_START1_Pulse */\r
+ win_out(AI_START1_Pulse,AI_Command_2_Register);\r
+ s->async->inttrig=NULL;\r
+ }else{\r
+ /* TRIG_INT */\r
+ s->async->inttrig=ni_ai_inttrig;\r
+ }\r
+\r
+ win_restore(wsave);\r
+\r
+ //mite_dump_regs(devpriv->mite);\r
+ MDPRINTK("exit ni_ai_cmd\n");\r
+ \r
+ return 0;\r
+}\r
+\r
+static int ni_ai_inttrig(comedi_device *dev,comedi_subdevice *s,\r
+ unsigned int trignum)\r
+{\r
+ int wsave;\r
+\r
+ if(trignum!=0)return -EINVAL;\r
+\r
+ wsave = win_save();\r
+\r
+ win_out(AI_START1_Pulse,AI_Command_2_Register);\r
+ s->async->inttrig=NULL;\r
+\r
+ win_restore(wsave);\r
+\r
+ return 1;\r
+}\r
+\r
+static void ni_ao_fifo_load(comedi_device *dev,comedi_subdevice *s,\r
+ sampl_t *data,int n)\r
+{\r
+ int i;\r
+\r
+ for(i=0;i<n;i++){\r
+ ni_writew(data[i],DAC_FIFO_Data);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * There's a small problem if the FIFO gets really low and we\r
+ * don't have the data to fill it. Basically, if after we fill\r
+ * the FIFO with all the data available, the FIFO is _still_\r
+ * less than half full, we never clear the interrupt. If the\r
+ * IRQ is in edge mode, we never get another interrupt, because\r
+ * this one wasn't cleared. If in level mode, we get flooded\r
+ * with interrupts that we can't fulfill, because nothing ever\r
+ * gets put into the buffer.\r
+ *\r
+ * This kind of situation is recoverable, but it is easier to\r
+ * just pretend we had a FIFO underrun, since there is a good\r
+ * chance it will happen anyway. This is _not_ the case for\r
+ * RT code, as RT code might purposely be running close to the\r
+ * metal. Needs to be fixed eventually.\r
+ */\r
+static int ni_ao_fifo_half_empty(comedi_device *dev,comedi_subdevice *s)\r
+{\r
+ int n,m;\r
+\r
+ n=(s->async->buf_int_count-s->async->buf_user_count)/sizeof(sampl_t);\r
+ if(n==0)return 0;\r
+ if(n>boardtype.ao_fifo_depth/2)\r
+ n=boardtype.ao_fifo_depth/2;\r
+\r
+ if(s->async->buf_int_ptr+n*sizeof(sampl_t)>s->async->data_len){\r
+ m=(s->async->data_len-s->async->buf_int_ptr)/sizeof(sampl_t);\r
+ ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,m);\r
+ s->async->buf_int_count+=m*sizeof(sampl_t);\r
+ s->async->buf_int_ptr=0;\r
+ n-=m;\r
+ }\r
+ ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,n);\r
+ s->async->buf_int_count+=n*sizeof(sampl_t);\r
+ s->async->buf_int_ptr+=n*sizeof(sampl_t);\r
+\r
+ comedi_bufcheck(dev,s);\r
+\r
+ return 1;\r
+}\r
+\r
+static int ni_ao_prep_fifo(comedi_device *dev,comedi_subdevice *s)\r
+{\r
+ int n;\r
+\r
+ /* reset fifo */\r
+ win_out(0,DAC_FIFO_Clear);\r
+\r
+ /* load some data */\r
+ n=(s->async->buf_int_count-s->async->buf_user_count)/sizeof(sampl_t);\r
+ if(n==0)return 0;\r
+ if(n>boardtype.ao_fifo_depth)\r
+ n=boardtype.ao_fifo_depth;\r
+\r
+ ni_ao_fifo_load(dev,s,s->async->data+s->async->buf_int_ptr,n);\r
+ s->async->buf_int_count+=n*sizeof(sampl_t);\r
+ s->async->buf_int_ptr+=n*sizeof(sampl_t);\r
+\r
+ return n;\r
+}\r
+\r
+\r
+static int ni_ao_insn_read(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data)\r
+{\r
+ data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];\r
+\r
+ return 1;\r
+}\r
+\r
+static int ni_ao_insn_write(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data)\r
+{\r
+ unsigned int conf;\r
+ unsigned int chan;\r
+ unsigned int range;\r
+ unsigned int dat = data[0];\r
+\r
+ chan=CR_CHAN(insn->chanspec);\r
+\r
+ conf=chan<<8;\r
+\r
+ /* XXX check range with current range in flaglist[chan] */\r
+ /* should update calibration if range changes (ick) */\r
+\r
+ range = CR_RANGE(insn->chanspec);\r
+ if(boardtype.ao_unipolar){\r
+ conf |= (range&1)^1;\r
+ }\r
+ conf |= (range&2)<<1;\r
+\r
+#if 0\r
+ /* XXX oops. forgot flags in insn! */\r
+ /* not all boards can deglitch, but this shouldn't hurt */\r
+ if(insn->flags & TRIG_DEGLITCH)\r
+ conf |= 2;\r
+#endif\r
+\r
+ /* analog reference */\r
+ /* AREF_OTHER connects AO ground to AI ground, i think */\r
+ conf |= (CR_AREF(insn->chanspec)==AREF_OTHER)? 8 : 0;\r
+\r
+ ni_writew(conf,AO_Configuration);\r
+\r
+ devpriv->ao[chan] = dat;\r
+\r
+ if(((range&1)==0) || !boardtype.ao_unipolar)\r
+ dat^=(1<<(boardtype.aobits-1));\r
+\r
+ ni_writew(dat,(chan)? DAC1_Direct_Data : DAC0_Direct_Data);\r
+\r
+ return 1;\r
+}\r
+\r
+static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s)\r
+{\r
+ comedi_cmd *cmd = &s->async->cmd;\r
+ unsigned int conf;\r
+ unsigned int chan;\r
+ unsigned int range;\r
+ int trigvar;\r
+ int i;\r
+ \r
+ trigvar = ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);\r
+\r
+ win_out(AO_Disarm,AO_Command_1_Register);\r
+\r
+ for(i=0;i<cmd->chanlist_len;i++){\r
+ chan=CR_CHAN(cmd->chanlist[i]);\r
+\r
+ conf=chan<<8;\r
+ \r
+ /* XXX check range with current range in flaglist[chan] */\r
+ /* should update calibration if range changes (ick) */\r
+\r
+ range = CR_RANGE(cmd->chanlist[i]);\r
+ conf |= (range&1);\r
+ conf |= (range&2)<<1;\r
+ \r
+ /* not all boards can deglitch, but this shouldn't hurt */\r
+ if(cmd->flags & TRIG_DEGLITCH) /* XXX ? */\r
+ conf |= 2;\r
+\r
+ /* analog reference */\r
+ /* AREF_OTHER connects AO ground to AI ground, i think */\r
+ conf |= (CR_AREF(cmd->chanlist[i])==AREF_OTHER)? 8 : 0;\r
+\r
+ ni_writew(conf,AO_Configuration);\r
+ }\r
+\r
+ /* user is supposed to write() to buffer before triggering */\r
+ if(ni_ao_prep_fifo(dev,s)==0)\r
+ return -EIO;\r
+\r
+ win_out(AO_Configuration_Start,Joint_Reset_Register);\r
+\r
+ devpriv->ao_mode1|=AO_Trigger_Once;\r
+ win_out(devpriv->ao_mode1,AO_Mode_1_Register);\r
+ devpriv->ao_trigger_select&=~(AO_START1_Polarity|AO_START1_Select(-1));\r
+ devpriv->ao_trigger_select|=AO_START1_Edge|AO_START1_Sync;\r
+ win_out(devpriv->ao_trigger_select,AO_Trigger_Select_Register);\r
+ devpriv->ao_mode3&=~AO_Trigger_Length;\r
+ win_out(devpriv->ao_mode3,AO_Mode_3_Register);\r
+\r
+ if(cmd->stop_src==TRIG_NOW){\r
+ devpriv->ao_mode1|=AO_Continuous;\r
+ }else{\r
+ devpriv->ao_mode1&=~AO_Continuous;\r
+ }\r
+ win_out(devpriv->ao_mode1,AO_Mode_1_Register);\r
+ devpriv->ao_mode2&=~AO_BC_Initial_Load_Source;\r
+ win_out(devpriv->ao_mode2,AO_Mode_2_Register);\r
+ if(cmd->stop_src==TRIG_NOW){\r
+ win_out(0xff,AO_BC_Load_A_Register_High);\r
+ win_out(0xffff,AO_BC_Load_A_Register_Low);\r
+ }else{\r
+ win_out(0,AO_BC_Load_A_Register_High);\r
+ win_out(0,AO_BC_Load_A_Register_Low);\r
+ }\r
+ win_out(AO_BC_Load,AO_Command_1_Register);\r
+ devpriv->ao_mode2&=~AO_UC_Initial_Load_Source;\r
+ win_out(devpriv->ao_mode2,AO_Mode_2_Register);\r
+ if(cmd->stop_src==TRIG_NOW){\r
+ win_out(0xff,AO_UC_Load_A_Register_High);\r
+ win_out(0xffff,AO_UC_Load_A_Register_Low);\r
+ win_out(AO_UC_Load,AO_Command_1_Register);\r
+ win_out(0xff,AO_UC_Load_A_Register_High);\r
+ win_out(0xffff,AO_UC_Load_A_Register_Low);\r
+ }else{\r
+ win_out(0,AO_UC_Load_A_Register_High);\r
+ win_out(0,AO_UC_Load_A_Register_Low);\r
+ win_out(AO_UC_Load,AO_Command_1_Register);\r
+ win_out((cmd->stop_arg-1)>>16,AO_UC_Load_A_Register_High);\r
+ win_out((cmd->stop_arg-1)&0xffff,AO_UC_Load_A_Register_Low);\r
+ }\r
+\r
+ devpriv->ao_cmd2&=~AO_BC_Gate_Enable;\r
+ ni_writew(devpriv->ao_cmd2,AO_Command_2);\r
+ devpriv->ao_mode1&=~(AO_UI_Source_Select(0x1f)|AO_UI_Source_Polarity);\r
+ win_out(devpriv->ao_mode1,AO_Mode_1_Register);\r
+ devpriv->ao_mode2&=~(AO_UI_Reload_Mode(3)|AO_UI_Initial_Load_Source);\r
+ win_out(devpriv->ao_mode2,AO_Mode_2_Register);\r
+ win_out(0,AO_UI_Load_A_Register_High);\r
+ win_out(1,AO_UI_Load_A_Register_Low);\r
+ win_out(AO_UI_Load,AO_Command_1_Register);\r
+ win_out((trigvar>>16),AO_UI_Load_A_Register_High);\r
+ win_out((trigvar&0xffff),AO_UI_Load_A_Register_Low);\r
+\r
+ if(cmd->scan_end_arg>1){\r
+ devpriv->ao_mode1|=AO_Multiple_Channels;\r
+ win_out(AO_Number_Of_Channels(cmd->scan_end_arg-1)|\r
+ AO_UPDATE_Output_Select(1),\r
+ AO_Output_Control_Register);\r
+ }else{\r
+ devpriv->ao_mode1&=~AO_Multiple_Channels;\r
+ win_out(AO_Number_Of_Channels(CR_CHAN(cmd->chanlist[0]))|\r
+ AO_UPDATE_Output_Select(1),\r
+ AO_Output_Control_Register);\r
+ }\r
+ win_out(devpriv->ao_mode1,AO_Mode_1_Register);\r
+\r
+ win_out(AO_DAC0_Update_Mode|AO_DAC1_Update_Mode,AO_Command_1_Register);\r
+\r
+ devpriv->ao_mode3|=AO_Stop_On_Overrun_Error;\r
+ win_out(devpriv->ao_mode3,AO_Mode_3_Register);\r
+\r
+devpriv->ao_mode2|=AO_FIFO_Mode(1);\r
+ devpriv->ao_mode2&=~AO_FIFO_Retransmit_Enable;\r
+ win_out(devpriv->ao_mode2,AO_Mode_2_Register);\r
+\r
+ win_out(AO_Configuration_End,Joint_Reset_Register);\r
+\r
+ win_out(devpriv->ao_mode3|AO_Not_An_UPDATE,AO_Mode_3_Register);\r
+ win_out(devpriv->ao_mode3,AO_Mode_3_Register);\r
+\r
+ /* wait for DACs to be loaded */\r
+ udelay(100);\r
+\r
+ win_out(devpriv->ao_cmd1|AO_UI_Arm|AO_UC_Arm|AO_BC_Arm|AO_DAC1_Update_Mode|AO_DAC0_Update_Mode,\r
+ AO_Command_1_Register);\r
+\r
+ //TIM 4/17/01 win_out(AO_FIFO_Interrupt_Enable|AO_Error_Interrupt_Enable,Interrupt_B_Enable_Register);\r
+ ni_set_bits(dev, Interrupt_B_Enable_Register,\r
+ AO_FIFO_Interrupt_Enable|AO_Error_Interrupt_Enable, 1);\r
+\r
+ ni_writew(devpriv->ao_cmd2|AO_START1_Pulse,AO_Command_2);\r
+ \r
+ return 0;\r
+}\r
+\r
+static int ni_ao_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)\r
+{\r
+ int err=0;\r
+ int tmp;\r
+\r
+ /* step 1: make sure trigger sources are trivially valid */\r
+\r
+ tmp=cmd->start_src;\r
+ cmd->start_src &= TRIG_NOW;\r
+ if(!cmd->start_src || tmp!=cmd->start_src)err++;\r
+\r
+ tmp=cmd->scan_begin_src;\r
+ cmd->scan_begin_src &= TRIG_TIMER;\r
+ if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;\r
+\r
+ tmp=cmd->convert_src;\r
+ cmd->convert_src &= TRIG_NOW;\r
+ if(!cmd->convert_src || tmp!=cmd->convert_src)err++;\r
+\r
+ tmp=cmd->scan_end_src;\r
+ cmd->scan_end_src &= TRIG_COUNT;\r
+ if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;\r
+\r
+ tmp=cmd->stop_src;\r
+ cmd->stop_src &= TRIG_COUNT|TRIG_NONE;\r
+ if(!cmd->stop_src || tmp!=cmd->stop_src)err++;\r
+\r
+ if(err)return 1;\r
+\r
+ /* step 2: make sure trigger sources are unique and mutually compatible */\r
+\r
+ if(cmd->stop_src!=TRIG_COUNT &&\r
+ cmd->stop_src!=TRIG_NONE)err++;\r
+\r
+ if(err)return 2;\r
+\r
+ /* step 3: make sure arguments are trivially compatible */\r
+\r
+ if(cmd->start_arg!=0){\r
+ cmd->start_arg=0;\r
+ err++;\r
+ }\r
+#if 0\r
+ /* XXX need ao_speed */\r
+ if(cmd->scan_begin_arg<boardtype.ao_speed){\r
+ cmd->scan_begin_arg=boardtype.ao_speed;\r
+ err++;\r
+ }\r
+#endif\r
+ if(cmd->scan_begin_arg>TIMER_BASE*0xffffff){ /* XXX check */\r
+ cmd->scan_begin_arg=TIMER_BASE*0xffffff;\r
+ err++;\r
+ }\r
+ if(cmd->convert_arg!=0){\r
+ cmd->convert_arg=0;\r
+ err++;\r
+ }\r
+ if(cmd->scan_end_arg!=cmd->chanlist_len){\r
+ cmd->scan_end_arg=cmd->chanlist_len;\r
+ err++;\r
+ }\r
+ if(cmd->stop_src==TRIG_COUNT){ /* XXX check */\r
+ if(cmd->stop_arg>0x00ffffff){\r
+ cmd->stop_arg=0x00ffffff;\r
+ err++;\r
+ }\r
+ }else{\r
+ /* TRIG_NONE */\r
+ if(cmd->stop_arg!=0){\r
+ cmd->stop_arg=0;\r
+ err++;\r
+ }\r
+ }\r
+\r
+ if(err)return 3;\r
+\r
+ /* step 4: fix up any arguments */\r
+\r
+ tmp = cmd->scan_begin_arg;\r
+ ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);\r
+ if(tmp!=cmd->scan_begin_arg)err++;\r
+ \r
+ if(err)return 4;\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static int ni_dio_insn_config(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data)\r
+{\r
+#ifdef DEBUG_DIO\r
+ printk("ni_dio_insn_config() chan=%d io=%d\n",\r
+ CR_CHAN(insn->chanspec),data[0]);\r
+#endif\r
+ if(insn->n!=1)return -EINVAL;\r
+ switch(data[0]){\r
+ case COMEDI_OUTPUT:\r
+ s->io_bits |= 1<<CR_CHAN(insn->chanspec);\r
+ break;\r
+ case COMEDI_INPUT:\r
+ s->io_bits &= ~(1<<CR_CHAN(insn->chanspec));\r
+ break;\r
+ default:\r
+ return -EINVAL;\r
+ }\r
+\r
+ devpriv->dio_control &= ~DIO_Pins_Dir_Mask;\r
+ devpriv->dio_control |= DIO_Pins_Dir(s->io_bits);\r
+ win_out(devpriv->dio_control,DIO_Control_Register);\r
+\r
+ return 1;\r
+}\r
+\r
+static int ni_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data)\r
+{\r
+#ifdef DEBUG_DIO\r
+ printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n",data[0],data[1]);\r
+#endif\r
+ if(insn->n!=2)return -EINVAL;\r
+ if(data[0]){\r
+ s->state &= ~data[0];\r
+ s->state |= (data[0]&data[1]);\r
+ devpriv->dio_output &= ~DIO_Parallel_Data_Mask;\r
+ devpriv->dio_output |= DIO_Parallel_Data_Out(s->state);\r
+ win_out(devpriv->dio_output,DIO_Output_Register);\r
+ }\r
+ data[1] = ni_readw(DIO_Parallel_Input);\r
+\r
+ return 2;\r
+}\r
+\r
+static void mio_common_detach(comedi_device *dev)\r
+{\r
+ if(dev->subdevices && boardtype.has_8255)\r
+ subdev_8255_cleanup(dev,dev->subdevices+3);\r
+}\r
+\r
+static int ni_E_init(comedi_device *dev,comedi_devconfig *it)\r
+{\r
+ comedi_subdevice *s;\r
+ \r
+ dev->n_subdevices=7;\r
+ \r
+ if(alloc_subdevices(dev)<0)\r
+ return -ENOMEM;\r
+ \r
+ /* analog input subdevice */\r
+\r
+ s=dev->subdevices+0;\r
+ dev->read_subdev=s;\r
+ s->type=COMEDI_SUBD_AI;\r
+ s->subdev_flags=SDF_READABLE|SDF_RT|SDF_GROUND|SDF_COMMON|SDF_DIFF|SDF_OTHER;\r
+ s->subdev_flags|=SDF_DITHER;\r
+ s->n_chan=boardtype.n_adchan;\r
+ s->len_chanlist=512;\r
+ s->maxdata=(1<<boardtype.adbits)-1;\r
+ s->range_table=ni_range_lkup[boardtype.gainlkup];\r
+ s->insn_read=ni_ai_insn_read;\r
+ s->do_cmdtest=ni_ai_cmdtest;\r
+ s->do_cmd=ni_ai_cmd;\r
+ s->cancel=ni_ai_reset;\r
+ s->poll=ni_ai_poll;\r
+\r
+ /* analog output subdevice */\r
+\r
+ s=dev->subdevices+1;\r
+ if(boardtype.n_aochan){\r
+ dev->write_subdev=s;\r
+ s->type=COMEDI_SUBD_AO;\r
+ s->subdev_flags=SDF_WRITEABLE|SDF_RT|SDF_DEGLITCH|SDF_GROUND|SDF_OTHER;\r
+ s->n_chan=boardtype.n_aochan;\r
+ s->maxdata=(1<<boardtype.aobits)-1;\r
+ if(boardtype.ao_unipolar){\r
+ s->range_table=&range_ni_E_ao_ext; /* XXX wrong for some boards */\r
+ }else{\r
+ s->range_table=&range_bipolar10;\r
+ }\r
+ s->insn_read=ni_ao_insn_read;\r
+ s->insn_write=ni_ao_insn_write;\r
+ s->do_cmd=ni_ao_cmd;\r
+ s->do_cmdtest=ni_ao_cmdtest;\r
+ s->len_chanlist = 2;\r
+ }else{\r
+ s->type=COMEDI_SUBD_UNUSED;\r
+ }\r
+ \r
+ /* digital i/o subdevice */\r
+ \r
+ s=dev->subdevices+2;\r
+ s->type=COMEDI_SUBD_DIO;\r
+ s->subdev_flags=SDF_WRITEABLE|SDF_READABLE|SDF_RT;\r
+ s->n_chan=8;\r
+ s->maxdata=1;\r
+ s->range_table=&range_digital;\r
+ s->io_bits=0; /* all bits input */\r
+ s->insn_bits=ni_dio_insn_bits;\r
+ s->insn_config=ni_dio_insn_config;\r
+\r
+ /* dio setup */\r
+ devpriv->dio_control = DIO_Pins_Dir(s->io_bits);\r
+ win_out(devpriv->dio_control,DIO_Control_Register);\r
+ \r
+ /* 8255 device */\r
+ s=dev->subdevices+3;\r
+ if(boardtype.has_8255){\r
+ subdev_8255_init(dev,s,ni_8255_callback,dev);\r
+ }else{\r
+ s->type=COMEDI_SUBD_UNUSED;\r
+ }\r
+ /* XXX */\r
+ \r
+ /* general purpose counter/timer device */\r
+ s=dev->subdevices+4;\r
+ s->type=COMEDI_SUBD_COUNTER;\r
+ s->subdev_flags=SDF_READABLE|SDF_WRITEABLE;\r
+ s->insn_read=ni_gpct_insn_read;\r
+ s->insn_config=ni_gpct_insn_config;\r
+ s->n_chan=1; /* XXX */\r
+ s->maxdata=1;\r
+ \r
+ s=dev->subdevices+4;\r
+ s->type=COMEDI_SUBD_COUNTER;\r
+ s->subdev_flags=SDF_READABLE|SDF_WRITEABLE;\r
+ s->insn_read= ni_gpct_insn_read;\r
+ s->insn_write= ni_gpct_insn_write;\r
+ s->insn_config=ni_gpct_insn_config;\r
+ s->n_chan=2;\r
+ s->maxdata=1;\r
+ devpriv->an_trig_etc_reg = 0;\r
+ GPCT_Reset(dev,0);\r
+ GPCT_Reset(dev,1);\r
+ \r
+ /* calibration subdevice -- ai and ao */\r
+ s=dev->subdevices+5;\r
+ s->type=COMEDI_SUBD_CALIB;\r
+ s->subdev_flags=SDF_WRITEABLE|SDF_INTERNAL;\r
+ caldac_setup(dev,s);\r
+ s->insn_read=ni_calib_insn_read;\r
+ s->insn_write=ni_calib_insn_write;\r
+ \r
+ /* EEPROM */\r
+ s=dev->subdevices+6;\r
+ s->type=COMEDI_SUBD_MEMORY;\r
+ s->subdev_flags=SDF_READABLE|SDF_INTERNAL;\r
+ s->n_chan=512;\r
+ s->maxdata=0xff;\r
+ s->insn_read=ni_eeprom_insn_read;\r
+ \r
+ /* ai configuration */\r
+ ni_ai_reset(dev,dev->subdevices+0);\r
+ win_out(0x1ba0,Clock_and_FOUT_Register);\r
+\r
+\r
+ /* analog output configuration */\r
+ \r
+ devpriv->ao0p=0x0000;\r
+ ni_writew(devpriv->ao0p,AO_Configuration);\r
+ devpriv->ao1p=0x0100;\r
+ ni_writew(devpriv->ao1p,AO_Configuration);\r
+ win_out(AO_Configuration_Start,Joint_Reset_Register);\r
+ win_out(AO_Disarm,AO_Command_1_Register);\r
+ win_out(0,Interrupt_B_Enable_Register);\r
+ win_out(0x0010,AO_Personal_Register);\r
+ ni_writew(0x3f98,Interrupt_B_Ack);\r
+ win_out(0x1430,AO_Personal_Register);\r
+ win_out(0,AO_Output_Control_Register);\r
+ win_out(0,AO_Start_Select_Register);\r
+ devpriv->ao_cmd1=0;\r
+ win_out(devpriv->ao_cmd1,AO_Command_1_Register);\r
+ devpriv->ao_cmd2=0;\r
+ devpriv->ao_mode1=0;\r
+ devpriv->ao_mode2=0;\r
+ devpriv->ao_mode3=0;\r
+ devpriv->ao_trigger_select=0;\r
+\r
+ if(dev->irq){\r
+ win_out((IRQ_POLARITY<<0) | /* polarity : active high */\r
+ (0<<1) | /* no interrupt on 3 pins */\r
+ (1<<11) | /* enable int A */\r
+ (1<<15) | /* enable int B */\r
+ (interrupt_pin(dev->irq)<<8) | /* interrupt output pin A */\r
+ (interrupt_pin(dev->irq)<<12) , /* interrupt output pin B */\r
+ Interrupt_Control_Register\r
+ );\r
+ }\r
+\r
+ pfi_setup(dev);\r
+\r
+ printk("\n");\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+ presents the EEPROM as a subdevice\r
+*/\r
+\r
+static int ni_eeprom_insn_read(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data)\r
+{\r
+ data[0]=ni_read_eeprom(dev,CR_CHAN(insn->chanspec));\r
+\r
+ return 1;\r
+}\r
+\r
+/*\r
+ reads bytes out of eeprom\r
+*/\r
+\r
+static int ni_read_eeprom(comedi_device *dev,int addr)\r
+{\r
+ int bit;\r
+ int bitstring;\r
+\r
+ bitstring=0x0300|((addr&0x100)<<3)|(addr&0xff);\r
+ ni_writeb_p(0x04,Serial_Command);\r
+ for(bit=0x8000;bit;bit>>=1){\r
+ ni_writeb_p(0x04|((bit&bitstring)?0x02:0),Serial_Command);\r
+ ni_writeb_p(0x05|((bit&bitstring)?0x02:0),Serial_Command);\r
+ }\r
+ bitstring=0;\r
+ for(bit=0x80;bit;bit>>=1){\r
+ ni_writeb_p(0x04,Serial_Command);\r
+ ni_writeb_p(0x05,Serial_Command);\r
+ bitstring|=((ni_readb_p(XXX_Status)&0x01)?bit:0);\r
+ }\r
+ ni_writeb_p(0x00,Serial_Command);\r
+ \r
+ return bitstring;\r
+}\r
+\r
+static void ni_write_caldac(comedi_device *dev,int addr,int val);\r
+/*\r
+ calibration subdevice\r
+*/\r
+static int ni_calib_insn_write(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data)\r
+{\r
+ ni_write_caldac(dev,CR_CHAN(insn->chanspec),data[0]);\r
+ devpriv->caldacs[CR_CHAN(insn->chanspec)] = data[0];\r
+\r
+ return 1;\r
+}\r
+\r
+static int ni_calib_insn_read(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data)\r
+{\r
+ data[0] = devpriv->caldacs[CR_CHAN(insn->chanspec)];\r
+\r
+ return 1;\r
+}\r
+\r
+static int pack_mb88341(int addr,int val,int *bitstring);\r
+static int pack_dac8800(int addr,int val,int *bitstring);\r
+static int pack_dac8043(int addr,int val,int *bitstring);\r
+#ifdef PCIMIO\r
+static int pack_ad8522(int addr,int val,int *bitstring);\r
+#endif\r
+\r
+struct caldac_struct{\r
+ int n_chans;\r
+ int n_bits;\r
+ int (*packbits)(int,int,int *);\r
+};\r
+\r
+static struct caldac_struct caldac_mb88341={ 12, 8, pack_mb88341 };\r
+static struct caldac_struct caldac_dac8800={ 8, 8, pack_dac8800 };\r
+static struct caldac_struct caldac_dac8043={ 1, 12, pack_dac8043 };\r
+#ifdef PCIMIO\r
+static struct caldac_struct caldac_ad8522={ 2, 12, pack_ad8522 };\r
+#endif\r
+\r
+\r
+static void caldac_setup(comedi_device *dev,comedi_subdevice *s)\r
+{\r
+ int i,j;\r
+ int n_dacs;\r
+ int n_chans=0;\r
+ int n_bits;\r
+ int diffbits=0;\r
+ \r
+ if(!boardtype.caldac[0])return;\r
+ n_bits=boardtype.caldac[0]->n_bits;\r
+ for(i=0;i<3;i++){\r
+ if(!boardtype.caldac[i])break;\r
+ if(boardtype.caldac[i]->n_bits!=n_bits)diffbits=1;\r
+ n_chans+=boardtype.caldac[i]->n_chans;\r
+ }\r
+ n_dacs=i;\r
+ s->n_chan=n_chans;\r
+\r
+ if(diffbits){\r
+ int chan;\r
+\r
+ s->maxdata_list=kmalloc(sizeof(int)*n_chans,GFP_KERNEL);\r
+ chan=0;\r
+ for(i=0;i<n_dacs;i++){\r
+ for(j=0;j<boardtype.caldac[i]->n_chans;j++){\r
+ s->maxdata_list[chan]=\r
+ (1<<boardtype.caldac[i]->n_bits)-1;\r
+ chan++;\r
+ }\r
+ }\r
+ }else{\r
+ s->maxdata=(1<<boardtype.caldac[0]->n_bits)-1;\r
+ }\r
+}\r
+\r
+static void ni_write_caldac(comedi_device *dev,int addr,int val)\r
+{\r
+ int loadbit=0,bits=0,bit,bitstring=0;\r
+ int i;\r
+ \r
+ for(i=0;i<3;i++){\r
+ if(!boardtype.caldac[i])return;\r
+ if(addr<boardtype.caldac[i]->n_chans){\r
+ bits=boardtype.caldac[i]->packbits(addr,val,&bitstring);\r
+ loadbit=SerDacLd(i);\r
+ break;\r
+ }\r
+ addr-=boardtype.caldac[i]->n_chans;\r
+ }\r
+\r
+ for(bit=1<<(bits-1);bit;bit>>=1){\r
+ ni_writeb(((bit&bitstring)?0x02:0),Serial_Command);\r
+ ni_writeb(1|((bit&bitstring)?0x02:0),Serial_Command);\r
+ }\r
+ ni_writeb(loadbit,Serial_Command);\r
+ ni_writeb(0,Serial_Command);\r
+}\r
+\r
+\r
+\r
+static int pack_mb88341(int addr,int val,int *bitstring)\r
+{\r
+ /*\r
+ Fujitsu MB 88341\r
+ Note that address bits are reversed. Thanks to\r
+ Ingo Keen for noticing this.\r
+\r
+ Note also that the 88341 expects address values from\r
+ 1-12, whereas we use channel numbers 0-11. The NI\r
+ docs use 1-12, also, so be careful here.\r
+ */\r
+ addr++;\r
+ *bitstring=((addr&0x1)<<11) |\r
+ ((addr&0x2)<<9) |\r
+ ((addr&0x4)<<7) |\r
+ ((addr&0x8)<<5) |\r
+ (val&0xff);\r
+ return 12;\r
+}\r
+\r
+static int pack_dac8800(int addr,int val,int *bitstring)\r
+{\r
+ *bitstring=((addr&0x7)<<8)|(val&0xff);\r
+ return 11;\r
+}\r
+\r
+static int pack_dac8043(int addr,int val,int *bitstring)\r
+{\r
+ *bitstring=val&0xfff;\r
+ return 12;\r
+}\r
+ \r
+#ifdef PCIMIO\r
+static int pack_ad8522(int addr,int val,int *bitstring)\r
+{\r
+ *bitstring=(val&0xfff)|(addr ? 0xc000:0xa000);\r
+ return 16;\r
+}\r
+#endif\r
+\r
+\r
+\r
+/*\r
+ *\r
+ * Programmable Function Inputs\r
+ *\r
+ */\r
+\r
+\r
+static void pfi_setup(comedi_device *dev)\r
+{\r
+ /* currently, we don't output any signals, thus, all\r
+ the PFI's are input */\r
+ \r
+ //TIM 4/17/01 win_out(0,IO_Bidirection_Pin_Register);\r
+ ni_set_bits(dev, IO_Bidirection_Pin_Register, 0x03ff, 0);\r
+}\r
+\r
+\r
+\r
+/*\r
+ *\r
+ * General Purpose Counter/Timer section\r
+ *\r
+ */\r
+\r
+/*\r
+* Low level stuff...Each STC counter has two 24 bit load registers (A&B). Just make\r
+* it easier to access them.\r
+*/\r
+static void GPCT_Load_A(comedi_device *dev, int chan, long value)\r
+{\r
+ win_out( (value>>16) & 0x00ff, G_Load_A_Register_High(chan));\r
+ win_out( value & 0xffff, G_Load_A_Register_Low(chan));\r
+}\r
+\r
+static void GPCT_Load_B(comedi_device *dev, int chan, long value)\r
+{\r
+ win_out( (value>>16) & 0x00ff, G_Load_B_Register_High(chan));\r
+ win_out( value & 0xffff, G_Load_B_Register_Low(chan));\r
+}\r
+\r
+/* Load a value into the counter, using register A as the intermediate step.\r
+* You might use GPCT_Load_Using_A to load a 0x000000 into a counter\r
+* reset its value.\r
+*/\r
+static void GPCT_Load_Using_A(comedi_device *dev, int chan, long value)\r
+{\r
+ devpriv->gpct_mode[chan] &= (~G_Load_Source_Select);\r
+ win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));\r
+ GPCT_Load_A(dev,chan,value);\r
+ win_out( devpriv->gpct_command[chan]|G_Load,G_Command_Register(chan));\r
+}\r
+\r
+/* Don't use this by itself! The read is not atomic and quite unsafe.\r
+* If you think you need this function, use GPCT_G_Watch instead.\r
+*/\r
+int inline GPCT_G_Read(comedi_device *dev, int chan)\r
+{\r
+ int tmp;\r
+ tmp = win_in( G_Save_Register_High(chan)) << 16;\r
+ tmp |= win_in(G_Save_Register_Low(chan));\r
+ return tmp;\r
+}\r
+\r
+/*\r
+* Read the GPCTs current value. \r
+* This function is actually straight out of the STC RLPM.\r
+*/\r
+int GPCT_G_Watch(comedi_device *dev, int chan)\r
+{\r
+ int save1,save2;\r
+ \r
+ devpriv->gpct_command[chan] &= ~G_Save_Trace;\r
+ win_out( devpriv->gpct_command[chan],G_Command_Register(chan));\r
+ \r
+ devpriv->gpct_command[chan] |= G_Save_Trace;\r
+ win_out( devpriv->gpct_command[chan], G_Command_Register(chan));\r
+\r
+ save1 = GPCT_G_Read(dev,chan);\r
+ save2 = GPCT_G_Read(dev,chan);\r
+ \r
+ /*if the value changed during the read, try again*/\r
+ if (save1 != save2) {\r
+ save1 = GPCT_G_Read(dev,chan);\r
+ }\r
+ return save1;\r
+}\r
+\r
+\r
+int GPCT_Disarm(comedi_device *dev, int chan)\r
+{\r
+ win_out( devpriv->gpct_command[chan] | G_Disarm,G_Command_Register(chan));\r
+ return 0;\r
+}\r
+\r
+\r
+int GPCT_Arm(comedi_device *dev, int chan)\r
+{\r
+ win_out( devpriv->gpct_command[chan] | G_Arm,G_Command_Register(chan));\r
+ /* If the counter is doing pulse width measurement, then make\r
+ sure that the counter did not start counting right away. This would\r
+ indicate that we started acquiring the pulse after it had already \r
+ started and our measurement would be inaccurate */\r
+ if(devpriv->gpct_cur_operation[chan] == GPCT_SINGLE_PW){\r
+ int g_status; \r
+\r
+ g_status=win_in(G_Status_Register);\r
+ \r
+ if(chan == 0){\r
+ //TIM 5/2/01 possible error with very short pulses\r
+ if((G0_Counting_St & g_status)|| !(G0_Armed_St&g_status)) {\r
+ //error: we missed the beginning of the pulse\r
+ return -EINVAL; //there is probably a more accurate error code...\r
+ }\r
+ }else{\r
+ if((G1_Counting_St & g_status)|| !(G1_Armed_St&g_status)) {\r
+ //error: we missed the beginning of the pulse\r
+ return -EINVAL;\r
+ }\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+int GPCT_Set_Source(comedi_device *dev,int chan ,int source)\r
+{\r
+ //printk("GPCT_Set_Source...");\r
+ devpriv->gpct_input_select[chan] &= ~G_Source_Select(0x1f);//reset gate to 0\r
+ switch(source) {\r
+ case GPCT_INT_CLOCK:\r
+ devpriv->gpct_input_select[chan] |= G_Source_Select(0);//INT_TIMEBASE\r
+ break;\r
+ case GPCT_EXT_PIN:\r
+ if(chan==0)\r
+ devpriv->gpct_input_select[chan] |= G_Source_Select(9);//PFI8\r
+ else\r
+ devpriv->gpct_input_select[chan] |= G_Source_Select(4);//PFI3\r
+ break;\r
+ default:\r
+ return -EINVAL;\r
+ }\r
+ win_out(devpriv->gpct_input_select[chan], G_Input_Select_Register(chan));\r
+ //printk("exit GPCT_Set_Source\n");\r
+ return 0;\r
+}\r
+\r
+int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate)\r
+{\r
+ //printk("GPCT_Set_Gate...");\r
+ devpriv->gpct_input_select[chan] &= ~G_Gate_Select(0x1f);//reset gate to 0\r
+ switch(gate) {\r
+ case GPCT_NO_GATE:\r
+ devpriv->gpct_input_select[chan] |= G_Gate_Select(31);//Low\r
+ devpriv->gpct_mode[chan] |= G_Gate_Polarity;\r
+ break;\r
+ case GPCT_EXT_PIN:\r
+ devpriv->gpct_mode[chan] &= ~G_Gate_Polarity;\r
+ if(chan==0){\r
+ devpriv->gpct_input_select[chan] |= G_Gate_Select(10);//PFI9\r
+ }else{\r
+ devpriv->gpct_input_select[chan] |= G_Gate_Select(5);//PFI4\r
+ }\r
+ break;\r
+ default:\r
+ return -EINVAL;\r
+ }\r
+ win_out(devpriv->gpct_input_select[chan], G_Input_Select_Register(chan));\r
+ win_out(devpriv->gpct_mode[chan], G_Mode_Register(chan));\r
+ //printk("exit GPCT_Set_Gate\n");\r
+ return 0;\r
+}\r
+\r
+int GPCT_Set_Direction(comedi_device *dev,int chan,int direction)\r
+{\r
+ //printk("GPCT_Set_Direction...");\r
+ \r
+ devpriv->gpct_command[chan] &= ~G_Up_Down(0x3);\r
+ switch (direction) {\r
+ case GPCT_UP:\r
+ devpriv->gpct_command[chan] |= G_Up_Down(1);\r
+ break;\r
+ case GPCT_DOWN:\r
+ devpriv->gpct_command[chan] |= G_Up_Down(0);\r
+ break;\r
+ case GPCT_HWUD:\r
+ devpriv->gpct_command[chan] |= G_Up_Down(2);\r
+ break;\r
+ default:\r
+ printk("Error direction=0x%08x..",direction);\r
+ return -EINVAL;\r
+ }\r
+ win_out(devpriv->gpct_command[chan], G_Command_Register(chan));\r
+ //TIM 4/23/01 win_out(devpriv->gpct_mode[chan], G_Mode_Register(chan));\r
+ //printk("exit GPCT_Set_Direction\n");\r
+ return 0;\r
+}\r
+\r
+void GPCT_Event_Counting(comedi_device *dev,int chan)\r
+{\r
+\r
+ //NOTE: possible residual bits from multibit masks can corrupt\r
+ //If you config for several measurements between Resets, watch out!\r
+ \r
+ //printk("GPCT_Event_Counting...");\r
+ \r
+ devpriv->gpct_cur_operation[chan] = GPCT_SIMPLE_EVENT;\r
+ \r
+ // Gating_Mode = 1\r
+ devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Gating_Mode(1);\r
+ \r
+ // Trigger_Mode_For_Edge_Gate = 1\r
+ devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);\r
+\r
+ win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));\r
+ //printk("exit GPCT_Event_Counting\n");\r
+}\r
+\r
+void GPCT_Period_Meas(comedi_device *dev, int chan)\r
+{\r
+ //printk("GPCT_Period_Meas...");\r
+ \r
+ devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PERIOD;\r
+\r
+ \r
+ //NOTE: possible residual bits from multibit masks can corrupt\r
+ //If you config for several measurements between Resets, watch out! \r
+ devpriv->gpct_mode[chan] &= ~G_OR_Gate;\r
+ devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;\r
+ \r
+ // Output_Mode = 3 \r
+ devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Output_Mode(3);\r
+ \r
+ \r
+ //Gating Mode=2\r
+ devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Gating_Mode(2);\r
+ \r
+ // Trigger_Mode_For_Edge_Gate=0\r
+ devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(0);\r
+\r
+ devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;\r
+ devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;\r
+ devpriv->gpct_mode[chan] &= ~G_Loading_On_TC;\r
+ devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;\r
+\r
+ // Stop_Mode = 2\r
+ devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Stop_Mode(0);\r
+ \r
+ // Counting_Once = 2 \r
+ devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Counting_Once(2);\r
+\r
+ // Up_Down = 1 \r
+ devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));\r
+ devpriv->gpct_command[chan] |= G_Up_Down(1);\r
+\r
+ win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));\r
+ win_out( devpriv->gpct_command[chan],G_Command_Register(chan));\r
+ //printk("exit GPCT_Period_Meas\n");\r
+}\r
+\r
+void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan)\r
+{\r
+ //printk("GPCT_Pulse_Width_Meas...");\r
+\r
+ devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PW;\r
+\r
+ devpriv->gpct_mode[chan] &= ~G_OR_Gate;\r
+ devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;\r
+\r
+ // Output_Mode = 3 \r
+ devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Output_Mode(3);\r
+ \r
+ //Gating Mode=1\r
+ devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Gating_Mode(1);//TIM 4/24/01 was 2\r
+ \r
+ // Trigger_Mode_For_Edge_Gate=2\r
+ devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);//TIM 4/24/01 was 0\r
+\r
+\r
+ devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;//TIM 4/24/01 was 1\r
+ devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;//TIM 4/24/01 was 0\r
+\r
+ devpriv->gpct_mode[chan] &= ~G_Loading_On_TC;\r
+ devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;\r
+\r
+ // Stop_Mode = 0\r
+ devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Stop_Mode(0);\r
+ \r
+ // Counting_Once = 2 \r
+ devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Counting_Once(2);\r
+\r
+ // Up_Down = 1 \r
+ devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));\r
+ devpriv->gpct_command[chan] |= G_Up_Down(1);\r
+\r
+ win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));\r
+ win_out( devpriv->gpct_command[chan],G_Command_Register(chan));\r
+\r
+ //printk("exit GPCT_Pulse_Width_Meas\n");\r
+}\r
+\r
+/* GPCT_Gen_Single_Pulse() creates pulse of length pulsewidth which starts after the Arm\r
+signal is sent. The pulse is delayed by the value already in the counter. This function could\r
+be modified to send a pulse in response to a trigger event at its gate.*/\r
+void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length)\r
+{\r
+ //printk("GPCT_Gen_Cont...");\r
+\r
+ devpriv->gpct_cur_operation[chan] = GPCT_SINGLE_PULSE_OUT;\r
+\r
+ // Set length of the pulse\r
+ GPCT_Load_B(dev,chan, length-1);\r
+\r
+ //Load next time using B, This is reset by GPCT_Load_Using_A()\r
+ devpriv->gpct_mode[chan] |= G_Load_Source_Select;\r
+ \r
+ devpriv->gpct_mode[chan] &= ~G_OR_Gate;\r
+ devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;\r
+\r
+ // Output_Mode = 3 \r
+ devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Output_Mode(2); //TIM 4/26/01 was 3\r
+ \r
+ //Gating Mode=0 for untriggered single pulse\r
+ devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Gating_Mode(0); //TIM 4/25/01 was 1\r
+ \r
+ // Trigger_Mode_For_Edge_Gate=0\r
+ devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);\r
+\r
+\r
+ devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;\r
+ devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;\r
+ devpriv->gpct_mode[chan] |= G_Loading_On_TC; //TIM 4/25/01\r
+ devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;\r
+\r
+ // Stop_Mode = 2\r
+ devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Stop_Mode(2); //TIM 4/25/01\r
+ \r
+ // Counting_Once = 2 \r
+ devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Counting_Once(1); //TIM 4/25/01\r
+\r
+ // Up_Down = 1 \r
+ devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));\r
+ devpriv->gpct_command[chan] |= G_Up_Down(0); //TIM 4/25/01 was 1\r
+\r
+ win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));\r
+ win_out( devpriv->gpct_command[chan],G_Command_Register(chan));\r
+\r
+ //printk("exit GPCT_Gen_Cont\n");\r
+}\r
+\r
+void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length)\r
+{\r
+ //printk("GPCT_Gen_Cont...");\r
+\r
+ devpriv->gpct_cur_operation[chan] = GPCT_CONT_PULSE_OUT;\r
+\r
+ // Set length of the pulse\r
+ GPCT_Load_B(dev,chan, length-1);\r
+\r
+ //Load next time using B, This is reset by GPCT_Load_Using_A()\r
+ devpriv->gpct_mode[chan] |= G_Load_Source_Select;\r
+ \r
+ devpriv->gpct_mode[chan] &= ~G_OR_Gate;\r
+ devpriv->gpct_mode[chan] &= ~G_Gate_Select_Load_Source;\r
+\r
+ // Output_Mode = 3 \r
+ devpriv->gpct_mode[chan] &= ~(G_Output_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Output_Mode(2); //TIM 4/26/01 was 3\r
+ \r
+ //Gating Mode=0 for untriggered single pulse\r
+ devpriv->gpct_mode[chan] &= ~(G_Gating_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Gating_Mode(0); //TIM 4/26/01 was 0\r
+ \r
+ // Trigger_Mode_For_Edge_Gate=0\r
+ devpriv->gpct_mode[chan] &= ~(G_Trigger_Mode_For_Edge_Gate(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Trigger_Mode_For_Edge_Gate(2);\r
+\r
+\r
+ devpriv->gpct_mode[chan] |= G_Reload_Source_Switching;\r
+ devpriv->gpct_mode[chan] &= ~G_Loading_On_Gate;\r
+ devpriv->gpct_mode[chan] |= G_Loading_On_TC; \r
+ devpriv->gpct_mode[chan] &= ~G_Gate_On_Both_Edges;\r
+\r
+ // Stop_Mode = 2\r
+ devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Stop_Mode(0); //TIM 4/26/01\r
+ \r
+ // Counting_Once = 2 \r
+ devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));\r
+ devpriv->gpct_mode[chan] |= G_Counting_Once(0); //TIM 4/26/01\r
+\r
+ // Up_Down = 1 \r
+ devpriv->gpct_command[chan] &= ~(G_Up_Down(0x3));\r
+ devpriv->gpct_command[chan] |= G_Up_Down(0); \r
+\r
+ //TIM 4/26/01\r
+ //This seems pretty unsafe since I don't think it is cleared anywhere.\r
+ //I don't think this is working\r
+ //devpriv->gpct_command[chan] &= ~G_Bank_Switch_Enable;\r
+ //devpriv->gpct_command[chan] &= ~G_Bank_Switch_Mode;\r
+ \r
+\r
+ win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));\r
+ win_out( devpriv->gpct_command[chan],G_Command_Register(chan));\r
+\r
+ //printk("exit GPCT_Gen_Cont\n");\r
+}\r
+\r
+void GPCT_Reset(comedi_device *dev, int chan)\r
+{\r
+ unsigned long irqflags;\r
+ int temp_ack_reg=0;\r
+ \r
+ //printk("GPCT_Reset...");\r
+ devpriv->gpct_cur_operation[chan] = GPCT_RESET;\r
+\r
+ switch (chan) {\r
+ case 0:\r
+ //note: I need to share the soft copies of the Enable Register with the ISRs.\r
+ // so I'm using comedi_spin_lock_irqsave() to guard this section of code\r
+ win_out(G0_Reset,Joint_Reset_Register);\r
+ comedi_spin_lock_irqsave(&dev->spinlock, irqflags);\r
+ ni_set_bits(dev,Interrupt_A_Enable_Register,G0_TC_Interrupt_Enable, 0);\r
+ ni_set_bits(dev,Interrupt_A_Enable_Register,G0_Gate_Interrupt_Enable,0);\r
+ comedi_spin_unlock_irqrestore(&dev->spinlock, irqflags);\r
+ temp_ack_reg |= G0_Gate_Error_Confirm;\r
+ temp_ack_reg |= G0_TC_Error_Confirm;\r
+ temp_ack_reg |= G0_TC_Interrupt_Ack;\r
+ temp_ack_reg |= G0_Gate_Interrupt_Ack;\r
+ win_out(temp_ack_reg,Interrupt_A_Ack_Register);\r
+ \r
+ //problem...this interferes with the other ctr...\r
+ devpriv->an_trig_etc_reg |= GPFO_0_Output_Enable;\r
+ win_out(devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);\r
+ break;\r
+ case 1:\r
+ win_out(G1_Reset,Joint_Reset_Register);\r
+ comedi_spin_lock_irqsave(&dev->spinlock, irqflags);\r
+ ni_set_bits(dev,Interrupt_B_Enable_Register,G1_TC_Interrupt_Enable, 0);\r
+ ni_set_bits(dev,Interrupt_B_Enable_Register,G0_Gate_Interrupt_Enable,0);\r
+ comedi_spin_unlock_irqrestore(&dev->spinlock, irqflags);\r
+ temp_ack_reg |= G1_Gate_Error_Confirm;\r
+ temp_ack_reg |= G1_TC_Error_Confirm;\r
+ temp_ack_reg |= G1_TC_Interrupt_Ack;\r
+ temp_ack_reg |= G1_Gate_Interrupt_Ack;\r
+ win_out(temp_ack_reg,Interrupt_B_Ack_Register);\r
+ \r
+ devpriv->an_trig_etc_reg |= GPFO_1_Output_Enable;\r
+ win_out(devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);\r
+ break;\r
+ };\r
+ \r
+ devpriv->gpct_mode[chan] = 0;\r
+ devpriv->gpct_input_select[chan] = 0;\r
+ devpriv->gpct_command[chan] = 0;\r
+ \r
+ devpriv->gpct_command[chan] |= G_Synchronized_Gate;\r
+ \r
+ win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));\r
+ win_out( devpriv->gpct_input_select[chan],G_Input_Select_Register(chan));\r
+ win_out( 0,G_Autoincrement_Register(chan)); \r
+ \r
+ //printk("exit GPCT_Reset\n");\r
+}\r
+\r
+static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data)\r
+{\r
+ int retval=0;\r
+ //printk("data[0] is 0x%08x, data[1] is 0x%08x\n",data[0],data[1]);\r
+ switch(data[0]){\r
+ case GPCT_RESET:\r
+ if(insn->n!=1)return -EINVAL;\r
+ GPCT_Reset(dev,insn->chanspec);\r
+ break;\r
+ case GPCT_SET_SOURCE:\r
+ if(insn->n!=2)return -EINVAL;\r
+ retval=GPCT_Set_Source(dev,insn->chanspec,data[1]);\r
+ break;\r
+ case GPCT_SET_GATE:\r
+ if(insn->n!=2)return -EINVAL;\r
+ retval=GPCT_Set_Gate(dev,insn->chanspec,data[1]);\r
+ break;\r
+ case GPCT_SET_DIRECTION:\r
+ if(insn->n!=2) return -EINVAL;\r
+ retval=GPCT_Set_Direction(dev,insn->chanspec,data[1]);\r
+ break;\r
+ case GPCT_GET_INT_CLK_FRQ:\r
+ if(insn->n!=2) return -EINVAL;\r
+ //There are actually 2 internal clocks on the STC, we always\r
+ //use the fast 20MHz one at this time. Tim Ousley 5/1/01\r
+ //NOTE: This is not the final interface, ideally the user\r
+ //will never need to know the int. clk. freq.\r
+ data[1]=50;//50ns = 20MHz = internal timebase of STC\r
+ break;\r
+ case GPCT_SET_OPERATION:\r
+ //TIM 5/1/01 if((insn->n<2)||(insn->n>3))return -EINVAL;\r
+ switch(data[1]){\r
+ case GPCT_SIMPLE_EVENT:\r
+ GPCT_Event_Counting(dev,insn->chanspec);\r
+ break;\r
+ case GPCT_SINGLE_PERIOD:\r
+ GPCT_Period_Meas(dev,insn->chanspec);\r
+ break;\r
+ case GPCT_SINGLE_PW:\r
+ GPCT_Pulse_Width_Meas(dev,insn->chanspec);\r
+ break;\r
+ case GPCT_SINGLE_PULSE_OUT:\r
+ GPCT_Gen_Single_Pulse(dev,insn->chanspec,data[2]);\r
+ break;\r
+ case GPCT_CONT_PULSE_OUT:\r
+ GPCT_Gen_Cont_Pulse(dev,insn->chanspec,data[2]);\r
+ break;\r
+ default:\r
+ printk("unsupported GPCT operation!\n");\r
+ return -EINVAL;\r
+ }\r
+ break;\r
+ case GPCT_ARM:\r
+ if(insn->n!=1)return -EINVAL;\r
+ retval=GPCT_Arm(dev,insn->chanspec);\r
+ break;\r
+ case GPCT_DISARM:\r
+ if(insn->n!=1)return -EINVAL;\r
+ retval=GPCT_Disarm(dev,insn->chanspec);\r
+ break;\r
+ default:\r
+ return -EINVAL;\r
+ }\r
+\r
+ //catch any errors from return values\r
+ if(retval==0){\r
+ return insn->n;\r
+ }else{\r
+ if(data[0]!=GPCT_ARM){ \r
+ printk("error: retval was %d\n",retval);\r
+ printk("data[0] is 0x%08x, data[1] is 0x%08x\n",data[0],data[1]);\r
+ }\r
+\r
+ return retval;\r
+ }\r
+}\r
+\r
+static int ni_gpct_insn_read(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data) {\r
+\r
+ int chan=insn->chanspec;\r
+ int cur_op = devpriv->gpct_cur_operation[chan];\r
+ \r
+ //printk("in ni_gpct_insn_read, n=%d, data[0]=%d\n",insn->chanspec,data[0]);\r
+ if(insn->n!=1)return -EINVAL;\r
+ \r
+ data[0] = GPCT_G_Watch(dev,insn->chanspec);\r
+ \r
+ /* for certain modes (period and pulse width measurment), the value\r
+ in the counter is not valid until the counter stops. If the value is \r
+ invalid, return a 0 */\r
+ if((cur_op == GPCT_SINGLE_PERIOD) || (cur_op == GPCT_SINGLE_PW)){\r
+ /* is the counter still running? */\r
+ if(win_in(G_Status_Register) & (chan?G1_Counting_St:G0_Counting_St))\r
+ data[0]=0;\r
+ }\r
+ return 1;\r
+}\r
+\r
+static int ni_gpct_insn_write(comedi_device *dev,comedi_subdevice *s,\r
+ comedi_insn *insn,lsampl_t *data) {\r
+\r
+ //printk("in ni_gpct_insn_write");\r
+ if(insn->n!=1)return -EINVAL;\r
+ GPCT_Load_Using_A(dev,insn->chanspec,data[0]);\r
+ return 1;\r
+}\r
+\r
+\r
+static int ni_8255_callback(int dir,int port,int data,void *arg)\r
+{\r
+ comedi_device *dev=arg;\r
+\r
+ if(dir){\r
+ ni_writeb(data,Port_A+2*port);\r
+ return 0;\r
+ }else{\r
+ return ni_readb(Port_A+2*port);\r
+ }\r
+}\r