I'm gunna hafta start kickin' some asses if files are checked in
authorDavid Schleef <ds@schleef.org>
Tue, 3 Jul 2001 00:04:44 +0000 (00:04 +0000)
committerDavid Schleef <ds@schleef.org>
Tue, 3 Jul 2001 00:04:44 +0000 (00:04 +0000)
with CR/LF end-of-lines.

comedi/drivers/ni_mio_common.c

index 970439a0c4add79b025860b1e08d9e15561a04aa..ef62a62e00c8a9541c20b6388f91766e4394d9d4 100644 (file)
-\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
-                                               \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
+
+/*
+    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);
+                       #endif 
+                                               
+                       //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);
+       }
+}