COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
- Copyright (C) 2002, 2003 Frank Mori Hess <fmhess@users.sourceforge.net
+ Copyright (C) 2002-2006 Frank Mori Hess <fmhess@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#endif
/* A timeout count */
-
#define NI_TIMEOUT 1000
+static const unsigned old_RTSI_clock_channel = 7;
/* Note: this table must match the ai_gain_* definitions */
static short ni_gainlkup[][16]={
comedi_insn *insn,lsampl_t *data);
static int ni_pfi_insn_config(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data);
+static unsigned ni_old_get_pfi_routing(comedi_device *dev, unsigned chan);
static void ni_rtsi_init(comedi_device *dev);
static int ni_rtsi_insn_bits(comedi_device *dev,comedi_subdevice *s,
static int ni_8255_callback(int dir,int port,int data,unsigned long arg);
-static int ni_ns_to_timer(int *nanosec,int round_mode);
-
-
-/*GPCT function def's*/
-static int GPCT_G_Watch(comedi_device *dev, int chan);
-
-static void GPCT_Reset(comedi_device *dev, int chan);
-static void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length);
-static void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length);
-static void GPCT_Period_Meas(comedi_device *dev, int chan);
-static void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan);
-static void GPCT_Event_Counting(comedi_device *dev,int chan);
-static int GPCT_Set_Direction(comedi_device *dev,int chan,int direction);
-static int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate);
-static int GPCT_Set_Source(comedi_device *dev,int chan ,int source);
-
static int ni_gpct_insn_write(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data);
static int ni_gpct_insn_read(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data);
static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data);
+static int ni_gpct_cmd(comedi_device *dev,comedi_subdevice *s);
+static int ni_gpct_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd);
+static int ni_gpct_cancel(comedi_device *dev,comedi_subdevice *s);
static int init_cs5529(comedi_device *dev);
static int cs5529_do_conversion(comedi_device *dev, unsigned short *data);
static int ni_6143_pwm_config(comedi_device *dev, comedi_subdevice *s,
comedi_insn *insn, lsampl_t *data);
+static int ni_set_master_clock(comedi_device *dev, unsigned source, unsigned period_ns);
+
enum aimodes
{
AIMODE_NONE = 0,
static const int num_adc_stages_611x = 3;
-static void handle_a_interrupt(comedi_device *dev,unsigned short status,
- unsigned int m_status);
-static void handle_b_interrupt(comedi_device *dev,unsigned short status,
- unsigned int m_status);
+static void handle_a_interrupt(comedi_device *dev, unsigned short status,
+ unsigned ai_mite_status, unsigned gpct0_mite_status);
+static void handle_b_interrupt(comedi_device *dev, unsigned short status,
+ unsigned ao_mite_status, unsigned gpct1_mite_status);
static void get_last_sample_611x( comedi_device *dev );
static void get_last_sample_6143( comedi_device *dev );
#ifdef PCIDMA
//static void mite_handle_interrupt(comedi_device *dev,unsigned int status);
static int ni_ai_drain_dma(comedi_device *dev );
-#endif
-static void ni_flush_ai_fifo(comedi_device *dev){
+/* DMA channel setup */
+
+// negative channel means no channel
+static inline void ni_set_ai_dma_channel(comedi_device *dev, int channel)
+{
+ unsigned long flags;
+
+ comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+ devpriv->ai_ao_select_reg &= ~AI_DMA_Select_Mask;
+ if(channel >= 0)
+ {
+ devpriv->ai_ao_select_reg |= (ni_stc_dma_channel_select_bitfield(channel) << AI_DMA_Select_Shift) & AI_DMA_Select_Mask;
+ }
+ ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
+ mmiowb();
+ comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+}
+
+// negative channel means no channel
+static inline void ni_set_ao_dma_channel(comedi_device *dev, int channel)
+{
+ unsigned long flags;
+
+ comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+ devpriv->ai_ao_select_reg &= ~AO_DMA_Select_Mask;
+ if(channel >= 0)
+ {
+ devpriv->ai_ao_select_reg |= (ni_stc_dma_channel_select_bitfield(channel) << AO_DMA_Select_Shift) & AO_DMA_Select_Mask;
+ }
+ ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
+ mmiowb();
+ comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+}
+
+// negative mite_channel means no channel
+static inline void ni_set_gpct_dma_channel(comedi_device *dev, unsigned gpct_index, int mite_channel)
+{
+ unsigned long flags;
+
+ comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
+ devpriv->g0_g1_select_reg &= ~GPCT_DMA_Select_Mask(gpct_index);
+ if(mite_channel >= 0)
+ {
+ devpriv->g0_g1_select_reg |= GPCT_DMA_Select_Bits(gpct_index, mite_channel);
+ }
+ ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select);
+ mmiowb();
+ comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
+}
+
+static int ni_request_ai_mite_channel(comedi_device *dev)
+{
+ unsigned long flags;
+
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+ BUG_ON(devpriv->ai_mite_chan);
+ devpriv->ai_mite_chan = mite_request_channel(devpriv->mite, devpriv->ai_mite_ring);
+ if(devpriv->ai_mite_chan == NULL)
+ {
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+ comedi_error(dev, "failed to reserve mite dma channel for analog input.");
+ return -EBUSY;
+ }
+ ni_set_ai_dma_channel(dev, devpriv->ai_mite_chan->channel);
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+ return 0;
+}
+
+static int ni_request_ao_mite_channel(comedi_device *dev)
+{
+ unsigned long flags;
+
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+ BUG_ON(devpriv->ao_mite_chan);
+ devpriv->ao_mite_chan = mite_request_channel(devpriv->mite, devpriv->ao_mite_ring);
+ if(devpriv->ao_mite_chan == NULL)
+ {
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+ comedi_error(dev, "failed to reserve mite dma channel for analog outut.");
+ return -EBUSY;
+ }
+ ni_set_ao_dma_channel(dev, devpriv->ao_mite_chan->channel);
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+ return 0;
+}
+
+static int ni_request_gpct_mite_channel(comedi_device *dev, unsigned gpct_index)
+{
+ unsigned long flags;
+
+ BUG_ON(gpct_index >= NUM_GPCT);
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+ BUG_ON(devpriv->gpct_mite_chan[gpct_index]);
+ devpriv->gpct_mite_chan[gpct_index] = mite_request_channel(devpriv->mite, devpriv->gpct_mite_ring[gpct_index]);
+ if(devpriv->gpct_mite_chan[gpct_index] == NULL)
+ {
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+ comedi_error(dev, "failed to reserve mite dma channel for counter.");
+ return -EBUSY;
+ }
+ ni_set_gpct_dma_channel(dev, gpct_index, devpriv->gpct_mite_chan[gpct_index]->channel);
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+ return 0;
+}
+
+#endif // PCIDMA
+
+static void ni_release_ai_mite_channel(comedi_device *dev)
+{
+#ifdef PCIDMA
+ unsigned long flags;
+
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+ if(devpriv->ai_mite_chan)
+ {
+ ni_set_ai_dma_channel(dev, -1);
+ mite_dma_disarm(devpriv->ai_mite_chan);
+ mite_dma_reset(devpriv->ai_mite_chan);
+ mite_release_channel(devpriv->ai_mite_chan);
+ devpriv->ai_mite_chan = NULL;
+ }
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+#endif // PCIDMA
+}
+
+static void ni_release_ao_mite_channel(comedi_device *dev)
+{
+#ifdef PCIDMA
+ unsigned long flags;
+
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+ if(devpriv->ao_mite_chan)
+ {
+ ni_set_ao_dma_channel(dev, -1);
+ mite_dma_disarm(devpriv->ao_mite_chan);
+ mite_dma_reset(devpriv->ao_mite_chan);
+ mite_release_channel(devpriv->ao_mite_chan);
+ devpriv->ao_mite_chan = NULL;
+ }
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+#endif // PCIDMA
+}
+
+void ni_release_gpct_mite_channel(comedi_device *dev, unsigned gpct_index)
+{
+#ifdef PCIDMA
+ unsigned long flags;
+
+ BUG_ON(gpct_index >= NUM_GPCT);
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+ if(devpriv->gpct_mite_chan[gpct_index])
+ {
+ ni_set_gpct_dma_channel(dev, gpct_index, -1);
+ mite_dma_disarm(devpriv->gpct_mite_chan[gpct_index]);
+ mite_dma_reset(devpriv->gpct_mite_chan[gpct_index]);
+ mite_release_channel(devpriv->gpct_mite_chan[gpct_index]);
+ devpriv->gpct_mite_chan[gpct_index] = NULL;
+ }
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
+#endif // PCIDMA
+}
+
+static void ni_clear_ai_fifo(comedi_device *dev){
if(boardtype.reg_type == ni_reg_6143){
// Flush the 6143 data FIFO
ni_writel(0x10, AIFIFO_Control_6143); // Flush fifo
ni_writel(0x00, AIFIFO_Control_6143); // Flush fifo
while(ni_readl(AIFIFO_Status_6143) & 0x10); // Wait for complete
- }
- else {
+ }else {
devpriv->stc_writew(dev, 1,ADC_FIFO_Clear);
+ if(boardtype.reg_type == ni_reg_625x)
+ {
+ ni_writeb(0, M_Offset_Static_AI_Control(0));
+ ni_writeb(1, M_Offset_Static_AI_Control(0));
+#if 0
+ /* the NI example code does 3 convert pulses for 625x boards,
+ but that appears to be wrong in practice. */
+ devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+ devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+ devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
+#endif
+ }
}
}
devpriv->stc_writew(dev, data & 0xffff, reg + 1);
}
+static uint32_t win_in2(comedi_device *dev, int reg)
+{
+ uint32_t bits;
+ bits = devpriv->stc_readw(dev, reg) << 16;
+ bits |= devpriv->stc_readw(dev, reg + 1);
+ return bits;
+}
+
#define ao_win_out(data,addr) ni_ao_win_outw(dev,data,addr)
static inline void ni_ao_win_outw( comedi_device *dev, uint16_t data, int addr )
{
{
unsigned long flags;
- comedi_spin_lock_irqsave( &devpriv->window_lock, flags );
+ comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
switch (reg){
case Interrupt_A_Enable_Register:
if(value)
devpriv->int_a_enable_reg |= bits;
else
devpriv->int_a_enable_reg &= ~bits;
- comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags );
devpriv->stc_writew(dev, devpriv->int_a_enable_reg,Interrupt_A_Enable_Register);
break;
case Interrupt_B_Enable_Register:
devpriv->int_b_enable_reg |= bits;
else
devpriv->int_b_enable_reg &= ~bits;
- comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags );
devpriv->stc_writew(dev, devpriv->int_b_enable_reg,Interrupt_B_Enable_Register);
break;
case IO_Bidirection_Pin_Register:
devpriv->io_bidirection_pin_reg |= bits;
else
devpriv->io_bidirection_pin_reg &= ~bits;
- comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags );
devpriv->stc_writew(dev, devpriv->io_bidirection_pin_reg,IO_Bidirection_Pin_Register);
break;
default:
rt_printk("Warning ni_set_bits() called with invalid arguments\n");
rt_printk("reg is %d\n",reg);
- comedi_spin_unlock_irqrestore( &devpriv->window_lock, flags );
break;
}
+ comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags );
}
-static irqreturn_t ni_E_interrupt(int irq,void *d,struct pt_regs * regs)
+static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG)
{
comedi_device *dev=d;
unsigned short a_status;
unsigned short b_status;
- unsigned int m0_status;
- unsigned int m1_status;
+ unsigned int ai_mite_status = 0;
+ unsigned int ao_mite_status = 0;
+ unsigned gpct0_mite_status = 0;
+ unsigned gpct1_mite_status = 0;
unsigned long flags;
-#ifdef PCIDMA
struct mite_struct *mite = devpriv->mite;
-#endif
if(dev->attached == 0) return IRQ_NONE;
+ smp_mb(); // make sure dev->attached is checked before handler does anything else.
+
// lock to avoid race with comedi_poll
comedi_spin_lock_irqsave(&dev->spinlock, flags);
- a_status=devpriv->stc_readw(dev, AI_Status_1_Register);
- b_status=devpriv->stc_readw(dev, AO_Status_1_Register);
-#ifdef PCIDMA
- m0_status=readl(mite->mite_io_addr + MITE_CHSR(AI_DMA_CHAN));
- m1_status=readl(mite->mite_io_addr + MITE_CHSR(AO_DMA_CHAN));
-#else
- m0_status = 0;
- m1_status = 0;
-#endif
-
- if(a_status&Interrupt_A_St || m0_status & CHSR_INT )
- handle_a_interrupt(dev, a_status, m0_status);
- if(b_status&Interrupt_B_St || m1_status & CHSR_INT )
- handle_b_interrupt(dev, b_status, m1_status);
+ a_status = devpriv->stc_readw(dev, AI_Status_1_Register);
+ b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
+ if(mite)
+ {
+ unsigned long flags_too;
+
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags_too);
+ if(devpriv->ai_mite_chan)
+ ai_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->ai_mite_chan->channel));
+ if(devpriv->ao_mite_chan)
+ ao_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->ao_mite_chan->channel));
+ if(devpriv->gpct_mite_chan[0])
+ gpct0_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->gpct_mite_chan[0]->channel));
+ if(devpriv->gpct_mite_chan[1])
+ gpct1_mite_status = readl(mite->mite_io_addr + MITE_CHSR(devpriv->gpct_mite_chan[1]->channel));
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags_too);
+ }
+ if((a_status & Interrupt_A_St) || ((ai_mite_status | gpct0_mite_status) & CHSR_INT))
+ handle_a_interrupt(dev, a_status, ai_mite_status, gpct0_mite_status);
+ if((b_status & Interrupt_B_St) || ((ao_mite_status | gpct1_mite_status) & CHSR_INT))
+ handle_b_interrupt(dev, b_status, ao_mite_status, gpct1_mite_status);
comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
return IRQ_HANDLED;
}
#ifdef PCIDMA
-static void ni_sync_ai_dma(struct mite_struct *mite, comedi_device *dev)
+static void ni_sync_ai_dma(comedi_device *dev)
{
- int count;
comedi_subdevice *s = dev->subdevices + 0;
- comedi_async *async = s->async;
- unsigned int nbytes, old_alloc_count;
- unsigned int bytes_per_scan = bytes_per_sample(s) * async->cmd.chanlist_len;
-
- old_alloc_count = async->buf_write_alloc_count;
- // write alloc as much as we can
- comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
-
- nbytes = mite_bytes_written_to_memory_lb(mite, AI_DMA_CHAN);
- rmb();
- if( (int)(mite_bytes_written_to_memory_ub(mite, AI_DMA_CHAN) - old_alloc_count) > 0 ){
- rt_printk("ni_mio_common: DMA overwrite of free area\n");
- ni_ai_reset(dev,s);
- async->events |= COMEDI_CB_OVERFLOW;
- return;
- }
-
- count = nbytes - async->buf_write_count;
- if( count <= 0 ){
- /* it's possible count will be negative due to
- * conservative value returned by mite_bytes_transferred */
- return;
- }
- comedi_buf_write_free(async, count);
+ unsigned long flags;
- async->scan_progress += count;
- if( async->scan_progress >= bytes_per_scan )
- {
- async->scan_progress %= bytes_per_scan;
- async->events |= COMEDI_CB_EOS;
- }
- async->events |= COMEDI_CB_BLOCK;
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+ if(devpriv->ai_mite_chan)
+ mite_sync_input_dma(devpriv->ai_mite_chan, s->async);
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
}
static void mite_handle_b_linkc(struct mite_struct *mite, comedi_device *dev)
{
- int count;
comedi_subdevice *s = dev->subdevices + 1;
- comedi_async *async = s->async;
- u32 nbytes_ub, nbytes_lb;
- unsigned int new_write_count;
- u32 stop_count = async->cmd.stop_arg * sizeof(sampl_t);
-
- writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(AO_DMA_CHAN));
-
- new_write_count = async->buf_write_count;
- mb();
- nbytes_lb = mite_bytes_read_from_memory_lb(mite, AO_DMA_CHAN);
- if(async->cmd.stop_src == TRIG_COUNT &&
- (int) (nbytes_lb - stop_count) > 0)
- nbytes_lb = stop_count;
- mb();
- nbytes_ub = mite_bytes_read_from_memory_ub(mite, AO_DMA_CHAN);
- if(async->cmd.stop_src == TRIG_COUNT &&
- (int) (nbytes_ub - stop_count) > 0)
- nbytes_ub = stop_count;
- if((int)(nbytes_ub - devpriv->last_buf_write_count) > 0){
- rt_printk("ni_mio_common: DMA underrun\n");
- ni_ao_reset(dev,s);
- async->events |= COMEDI_CB_OVERFLOW;
- return;
- }
- mb();
- devpriv->last_buf_write_count = new_write_count;
- count = nbytes_lb - async->buf_read_count;
- if(count < 0){
+ if(devpriv->ao_mite_chan == NULL) return;
+ writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(devpriv->ao_mite_chan->channel));
+
+ if(mite_sync_output_dma(devpriv->ao_mite_chan, s->async) < 0)
+ {
+ s->async->events |= COMEDI_CB_ERROR;
return;
}
- comedi_buf_read_free(async, count);
-
- async->events |= COMEDI_CB_BLOCK;
}
+// #define DEBUG_DMA_TIMING
static int ni_ao_wait_for_dma_load( comedi_device *dev )
{
static const int timeout = 10000;
int i;
-
+#ifdef DEBUG_DMA_TIMING
+ struct timeval start;
+ do_gettimeofday(&start);
+#endif
for(i = 0; i < timeout; i++)
{
unsigned short b_status;
- b_status = devpriv->stc_readw(dev, AO_Status_1_Register );
+ b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
if( b_status & AO_FIFO_Half_Full_St )
break;
/* if we poll too often, the pci bus activity seems
to slow the dma transfer down */
comedi_udelay(10);
}
+#ifdef DEBUG_DMA_TIMING
+ rt_printk("looped %i times waiting for ao fifo load.\n", i);
+ struct timeval now;
+ do_gettimeofday(&now);
+ unsigned elapsed_usec = 1000000 * (now.tv_sec - start.tv_sec) + now.tv_usec - start.tv_usec;
+ rt_printk("total elapsed usec=%i\n", elapsed_usec);
+ do_gettimeofday(&start);
+ unsigned b_status;
+ for(i = 0; i < 100; ++i)
+ {
+// devpriv->stc_writew(dev, devpriv->ao_mode3, AO_Mode_3_Register);
+ b_status = devpriv->stc_readw(dev, AO_Status_1_Register);
+ }
+ do_gettimeofday(&now);
+ elapsed_usec = 1000000 * (now.tv_sec - start.tv_sec) + now.tv_usec - start.tv_usec;
+ rt_printk("usec to do 100 word xfers=%i\n", elapsed_usec);
+#endif
if( i == timeout )
{
comedi_error(dev, "timed out waiting for dma load");
for(i = 0; i < timeout; i++)
{
- ni_sync_ai_dma(devpriv->mite, dev);
+ ni_sync_ai_dma(dev);
if((s->async->events & COMEDI_CB_EOS)) break;
comedi_udelay(1);
}
/* handle special case of single scan using AI_End_On_End_Of_Scan */
if((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)){
shutdown_ai_command( dev );
- ni_ai_reset(dev, s);
}
}
#ifdef PCIDMA
ni_ai_drain_dma( dev );
- mite_dma_disarm(devpriv->mite, AI_DMA_CHAN);
#endif
ni_handle_fifo_dregs(dev);
get_last_sample_611x(dev);
get_last_sample_6143(dev);
- ni_set_bits(dev, Interrupt_A_Enable_Register,
- AI_SC_TC_Interrupt_Enable | AI_START1_Interrupt_Enable|
- AI_START2_Interrupt_Enable| AI_START_Interrupt_Enable|
- AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable|
- AI_FIFO_Interrupt_Enable,0);
-
s->async->events |= COMEDI_CB_EOA;
}
-static void handle_a_interrupt(comedi_device *dev,unsigned short status,
- unsigned int m_status)
+static void handle_gpct_interrupt(comedi_device *dev, struct mite_channel *mite_chan, unsigned short is_terminal_count)
+{
+ unsigned gpct_mite_status;
+
+ gpct_mite_status = readl(mite_chan->mite->mite_io_addr + MITE_CHSR(mite_chan->channel));
+ if(gpct_mite_status & CHSR_INT)
+ {}
+}
+
+static void ni_event(comedi_device *dev, comedi_subdevice *s, unsigned events)
+{
+ if(events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | COMEDI_CB_EOA))
+ {
+ switch(s->type)
+ {
+ case COMEDI_SUBD_AI:
+ ni_ai_reset(dev, s);
+ break;
+ case COMEDI_SUBD_AO:
+ ni_ao_reset(dev, s);
+ break;
+ default:
+ break;
+ }
+ }
+ comedi_event(dev, s, events);
+}
+
+static void ack_a_interrupt(comedi_device *dev, unsigned short a_status)
+{
+ unsigned short ack = 0;
+
+ /* test for all uncommon interrupt events at the same time */
+ if(a_status & AI_SC_TC_St)
+ {
+ ack |= AI_SC_TC_Interrupt_Ack;
+ }
+ if(a_status & AI_START1_St)
+ {
+ ack |= AI_START1_Interrupt_Ack;
+ }
+ if(a_status & AI_START_St)
+ {
+ ack |= AI_START_Interrupt_Ack;
+ }
+ if(a_status & AI_STOP_St)
+ {
+ /* not sure why we used to ack the START here also, instead of doing it independently. Frank Hess 2007-07-06 */
+ ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack*/;
+ }
+ if(a_status & G0_TC_St)
+ {
+ ack |= G0_TC_Interrupt_Ack;
+ }
+ if(a_status & G0_Gate_Interrupt_St)
+ {
+ ack |= G0_Gate_Interrupt_Ack;
+ }
+ if(ack) devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register);
+}
+
+static void handle_a_interrupt(comedi_device *dev, unsigned short status,
+ unsigned ai_mite_status, unsigned gpct0_mite_status)
{
comedi_subdevice *s=dev->subdevices+0;
- unsigned short ack=0;
s->async->events = 0;
#ifdef DEBUG_INTERRUPT
- rt_printk("ni_mio_common: interrupt: a_status=%04x m0_status=%08x\n",
- status, m_status);
+ rt_printk("ni_mio_common: interrupt: a_status=%04x ai_mite_status=%08x\n",
+ status, ai_mite_status);
ni_mio_print_status_a(status);
#endif
-
-
+ ack_a_interrupt(dev, status);
#ifdef PCIDMA
/* Currently, mite.c requires us to handle LINKC and DONE */
- if(m_status & CHSR_LINKC){
- writel(CHOR_CLRLC, devpriv->mite->mite_io_addr + MITE_CHOR(AI_DMA_CHAN));
- ni_sync_ai_dma(devpriv->mite, dev);
+ if(ai_mite_status & CHSR_LINKC){
+ writel(CHOR_CLRLC, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ai_mite_chan->channel));
+ ni_sync_ai_dma(dev);
}
- if(m_status & CHSR_DONE){
- writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(AI_DMA_CHAN));
+ if(ai_mite_status & CHSR_DONE){
+ writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ai_mite_chan->channel));
}
- if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){
- rt_printk("unknown mite interrupt, ack! (m_status=%08x)\n", m_status);
- //mite_print_chsr(m_status);
- mite_dma_disarm(devpriv->mite, AI_DMA_CHAN );
- writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR(AI_DMA_CHAN));
+ if(ai_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){
+ rt_printk("unknown mite interrupt, ack! (ai_mite_status=%08x)\n", ai_mite_status);
+ //mite_print_chsr(ai_mite_status);
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
//disable_irq(dev->irq);
}
#endif
* so it's a good idea to be careful. */
if(s->subdev_flags&SDF_RUNNING){
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- //comedi_event(dev,s,s->async->events);
+ ni_event(dev, s, s->async->events);
}
return;
}
status);
ni_mio_print_status_a(status);
- ni_ai_reset(dev,dev->subdevices);
-
-
shutdown_ai_command( dev );
s->async->events |= COMEDI_CB_ERROR;
if(status & (AI_Overrun_St | AI_Overflow_St))
s->async->events |= COMEDI_CB_OVERFLOW;
- comedi_event(dev,s,s->async->events);
+ ni_event(dev, s, s->async->events);
return;
}
rt_printk("ni_mio_common: SC_TC interrupt\n");
#endif
if(!devpriv->ai_continuous){
- shutdown_ai_command( dev );
+ shutdown_ai_command(dev);
}
- ack|=AI_SC_TC_Interrupt_Ack;
- }
- if(status&AI_START1_St){
- ack|=AI_START1_Interrupt_Ack;
}
}
#ifndef PCIDMA
if( (status & AI_STOP_St) ){
ni_handle_eos(dev, s);
- /* we need to ack the START, also */
- ack |= AI_STOP_Interrupt_Ack|AI_START_Interrupt_Ack;
}
-#if 0
- if(devpriv->aimode==AIMODE_SAMPLE){
- ni_handle_fifo_dregs(dev);
- //s->async->events |= COMEDI_CB_SAMPLE;
+ if(status & (G0_TC_St | G0_Gate_Interrupt_St))
+ {
+ unsigned long flags;
+
+ comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
+ if(devpriv->gpct_mite_chan)
+ handle_gpct_interrupt(dev, devpriv->gpct_mite_chan[0], (status & G0_TC_St));
+ comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
}
-#endif
- if(ack) devpriv->stc_writew(dev, ack,Interrupt_A_Ack_Register);
- comedi_event(dev,s,s->async->events);
+ ni_event(dev,s,s->async->events);
#ifdef DEBUG_INTERRUPT
status=devpriv->stc_readw(dev, AI_Status_1_Register);
#endif
}
-static void handle_b_interrupt(comedi_device *dev,unsigned short b_status, unsigned int m_status)
+static void ack_b_interrupt(comedi_device *dev, unsigned short b_status)
+{
+ unsigned short ack = 0;
+ if(b_status & AO_BC_TC_St)
+ {
+ ack |= AO_BC_TC_Interrupt_Ack;
+ }
+ if(b_status & AO_Overrun_St)
+ {
+ ack |= AO_Error_Interrupt_Ack;
+ }
+ if(b_status & AO_START_St)
+ {
+ ack |= AO_START_Interrupt_Ack;
+ }
+ if(b_status & AO_START1_St)
+ {
+ ack |= AO_START1_Interrupt_Ack;
+ }
+ if(b_status & AO_UC_TC_St)
+ {
+ ack |= AO_UC_TC_Interrupt_Ack;
+ }
+ if(b_status & AO_UI2_TC_St)
+ {
+ ack |= AO_UI2_TC_Interrupt_Ack;
+ }
+ if(b_status & AO_UPDATE_St)
+ {
+ ack |= AO_UPDATE_Interrupt_Ack;
+ }
+ if(b_status & G1_Gate_Interrupt_St)
+ {
+ ack |= G1_Gate_Interrupt_Ack;
+ }
+ if(b_status & G1_TC_St)
+ {
+ ack |= G1_TC_Interrupt_Ack;
+ }
+ if(ack) devpriv->stc_writew(dev, ack, Interrupt_B_Ack_Register);
+}
+
+static void handle_b_interrupt(comedi_device *dev, unsigned short b_status,
+ unsigned ao_mite_status, unsigned gpct1_mite_status)
{
comedi_subdevice *s=dev->subdevices+1;
//unsigned short ack=0;
#ifdef DEBUG_INTERRUPT
rt_printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n",
- b_status,m_status);
+ b_status,ao_mite_status);
ni_mio_print_status_b(b_status);
#endif
-
+ ack_b_interrupt(dev, b_status);
#ifdef PCIDMA
/* Currently, mite.c requires us to handle LINKC and DONE */
- if(m_status & CHSR_LINKC){
+ if(ao_mite_status & CHSR_LINKC){
mite_handle_b_linkc(devpriv->mite, dev);
}
- if(m_status & CHSR_DONE){
- writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(AO_DMA_CHAN));
+ if(ao_mite_status & CHSR_DONE){
+ writel(CHOR_CLRDONE, devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->ao_mite_chan->channel));
}
- if(m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){
- rt_printk("unknown mite interrupt, ack! (m_status=%08x)\n", m_status);
- //mite_print_chsr(m_status);
- mite_dma_disarm(devpriv->mite, AO_DMA_CHAN );
- writel(CHOR_DMARESET, devpriv->mite->mite_io_addr + MITE_CHOR(AO_DMA_CHAN));
- }
+ if(ao_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)){
+ rt_printk("unknown mite interrupt, ack! (ao_mite_status=%08x)\n", ao_mite_status);
+ //mite_print_chsr(ao_mite_status);
+ s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ }
#endif
if(b_status==0xffff)return;
if(b_status&AO_Overrun_St){
rt_printk("ni_mio_common: AO FIFO underrun status=0x%04x status2=0x%04x\n",b_status,devpriv->stc_readw(dev, AO_Status_2_Register));
- ni_ao_reset(dev,s);
s->async->events |= COMEDI_CB_OVERFLOW;
}
if(b_status&AO_BC_TC_St){
MDPRINTK("ni_mio_common: AO BC_TC status=0x%04x status2=0x%04x\n",b_status,devpriv->stc_readw(dev, AO_Status_2_Register));
- ni_ao_reset(dev,s);
s->async->events |= COMEDI_CB_EOA;
}
}
#endif
- b_status=devpriv->stc_readw(dev, AO_Status_1_Register);
- 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);
- ni_set_bits(dev,Interrupt_B_Enable_Register,~0,0);
- ni_ao_reset(dev,s);
- s->async->events |= COMEDI_CB_OVERFLOW;
- }
-
- comedi_event(dev,s,s->async->events);
+ ni_event(dev,s,s->async->events);
}
#ifdef DEBUG_STATUS_A
{
int n;
- n = comedi_buf_read_n_available(s);
+ n = comedi_buf_read_n_available(s->async);
if(n==0){
s->async->events |= COMEDI_CB_OVERFLOW;
return 0;
ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
/* load some data */
- n = comedi_buf_read_n_available(s);
+ n = comedi_buf_read_n_available(s->async);
if(n==0)return 0;
n /= sizeof(sampl_t);
#ifdef PCIDMA
static int ni_ai_drain_dma(comedi_device *dev )
{
- struct mite_struct *mite = devpriv->mite;
int i;
static const int timeout = 10000;
+ if(devpriv->ai_mite_chan == NULL) return 0;
for( i = 0; i < timeout; i++ )
{
if((devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Empty_St) &&
- mite_bytes_in_transit(mite, AI_DMA_CHAN) == 0)
+ mite_bytes_in_transit(devpriv->ai_mite_chan) == 0)
break;
comedi_udelay(2);
}
{
rt_printk("ni_mio_common: wait for dma drain timed out\n");
rt_printk("mite_bytes_in_transit=%i, AI_Status1_Register=0x%x\n",
- mite_bytes_in_transit(mite, AI_DMA_CHAN), devpriv->stc_readw(dev, AI_Status_1_Register));
+ mite_bytes_in_transit(devpriv->ai_mite_chan), devpriv->stc_readw(dev, AI_Status_1_Register));
return -1;
}
- ni_sync_ai_dma( mite, dev );
+ ni_sync_ai_dma(dev);
return 0;
}
#ifdef PCIDMA
-static void ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd)
+static int ni_ai_setup_MITE_dma(comedi_device *dev)
{
- struct mite_struct *mite = devpriv->mite;
- struct mite_channel *mite_chan = &mite->channels[ AI_DMA_CHAN ];
comedi_subdevice *s = dev->subdevices + 0;
+ int retval;
+
+ retval = ni_request_ai_mite_channel(dev);
+ if(retval) return retval;
+// rt_printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel);
/* write alloc the entire buffer */
comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
- mite_chan->current_link = 0;
- mite_chan->dir = COMEDI_INPUT;
+ devpriv->ai_mite_chan->dir = COMEDI_INPUT;
switch(boardtype.reg_type)
{
case ni_reg_611x:
case ni_reg_6143:
- mite_prep_dma(mite, AI_DMA_CHAN, 32, 16);
+ mite_prep_dma(devpriv->ai_mite_chan, 32, 16);
break;
- case ni_reg_m_series:
- if(boardtype.adbits > 16)
- mite_prep_dma(mite, AI_DMA_CHAN, 32, 32);
- else
- mite_prep_dma(mite, AI_DMA_CHAN, 16, 16); //guess
+ case ni_reg_628x:
+ mite_prep_dma(devpriv->ai_mite_chan, 32, 32);
break;
default:
- mite_prep_dma(mite, AI_DMA_CHAN, 16, 16);
+ mite_prep_dma(devpriv->ai_mite_chan, 16, 16);
break;
};
/*start the MITE*/
- mite_dma_arm(mite, AI_DMA_CHAN);
+ mite_dma_arm(devpriv->ai_mite_chan);
+ return 0;
}
-static void ni_ao_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd)
+static int ni_ao_setup_MITE_dma(comedi_device *dev)
{
- struct mite_struct *mite = devpriv->mite;
- struct mite_channel *mite_chan = &mite->channels[ AO_DMA_CHAN ];
comedi_subdevice *s = dev->subdevices + 1;
+ int retval;
- devpriv->last_buf_write_count = s->async->buf_write_count;
+ retval = ni_request_ao_mite_channel(dev);
+ if(retval) return retval;
+ //rt_printk("comedi_debug: using mite channel %i for ao.\n", devpriv->ao_mite_chan->channel);
- mite_chan->current_link = 0;
- mite_chan->dir = COMEDI_OUTPUT;
- if(boardtype.reg_type & (ni_reg_611x | ni_reg_6713))
- mite_prep_dma(mite, AO_DMA_CHAN, 32, 32);
- else
- mite_prep_dma(mite, AO_DMA_CHAN, 16, 16);
+ /* read alloc the entire buffer */
+ comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz);
+ devpriv->ao_mite_chan->dir = COMEDI_OUTPUT;
+ if(boardtype.reg_type & (ni_reg_611x | ni_reg_6713))
+ {
+ mite_prep_dma(devpriv->ao_mite_chan, 32, 32);
+ }else
+ {
+ /* doing 32 instead of 16 bit wide transfers from memory
+ makes the mite do 32 bit pci transfers, doubling pci bandwidth. */
+ mite_prep_dma(devpriv->ao_mite_chan, 16, 32);
+ }
/*start the MITE*/
- mite_dma_arm(mite, AO_DMA_CHAN);
+ mite_dma_arm(devpriv->ao_mite_chan);
+ return 0;
}
#endif // PCIDMA
static int ni_ai_reset(comedi_device *dev,comedi_subdevice *s)
{
-#ifdef PCIDMA
- mite_dma_disarm(devpriv->mite, AI_DMA_CHAN);
-#endif
+ ni_release_ai_mite_channel(dev);
/* ai configuration */
devpriv->stc_writew(dev, AI_Configuration_Start | AI_Reset, Joint_Reset_Register);
AI_STOP_Interrupt_Enable| AI_Error_Interrupt_Enable|
AI_FIFO_Interrupt_Enable,0);
- ni_flush_ai_fifo(dev);
+ ni_clear_ai_fifo(dev);
if(boardtype.reg_type != ni_reg_6143)
ni_writeb(0, Misc_Command);
AI_EXTMUX_CLK_Output_Select(0) |
AI_LOCALMUX_CLK_Output_Select(2) |
AI_SC_TC_Output_Select(3) |
- AI_CONVERT_Output_Select(3),AI_Output_Control_Register);
+ AI_CONVERT_Output_Select(AI_CONVERT_Output_Enable_High), AI_Output_Control_Register);
}else if(boardtype.reg_type == ni_reg_6143){
devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
AI_SOC_Polarity |
AI_EXTMUX_CLK_Output_Select(0) |
AI_LOCALMUX_CLK_Output_Select(2) |
AI_SC_TC_Output_Select(3) |
- AI_CONVERT_Output_Select(2),AI_Output_Control_Register);
+ AI_CONVERT_Output_Select(AI_CONVERT_Output_Enable_Low),AI_Output_Control_Register);
}else{
+ unsigned ai_output_control_bits;
devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
AI_SOC_Polarity |
AI_CONVERT_Pulse_Width |
AI_LOCALMUX_CLK_Pulse_Width, AI_Personal_Register);
- devpriv->stc_writew(dev, AI_SCAN_IN_PROG_Output_Select(3) |
+ ai_output_control_bits = AI_SCAN_IN_PROG_Output_Select(3) |
AI_EXTMUX_CLK_Output_Select(0) |
AI_LOCALMUX_CLK_Output_Select(2) |
- AI_SC_TC_Output_Select(3) |
- AI_CONVERT_Output_Select(2),AI_Output_Control_Register);
+ AI_SC_TC_Output_Select(3);
+ if(boardtype.reg_type == ni_reg_622x)
+ ai_output_control_bits |= AI_CONVERT_Output_Select(AI_CONVERT_Output_Enable_High);
+ else
+ ai_output_control_bits |= AI_CONVERT_Output_Select(AI_CONVERT_Output_Enable_Low);
+ devpriv->stc_writew(dev, ai_output_control_bits, AI_Output_Control_Register);
}
/* the following registers should not be changed, because there
* are no backup registers in devpriv. If you want to change
#ifndef PCIDMA
ni_handle_fifo_dregs(dev);
#else
- ni_sync_ai_dma(devpriv->mite, dev);
+ ni_sync_ai_dma(dev);
#endif
count = s->async->buf_write_count - s->async->buf_read_count;
if(in_interrupt() == 0)
ni_load_channelgain_list(dev,1,&insn->chanspec);
- ni_flush_ai_fifo(dev);
+ ni_clear_ai_fifo(dev);
signbits=devpriv->ai_offset[0];
if(boardtype.reg_type == ni_reg_611x){
data[n] = (((dl >> 16) & 0xFFFF) + signbits) & 0xFFFF;
}
}else{
- for(n=0;n<insn->n;n++){
+ for(n = 0; n < insn->n; n++){
devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register);
- for(i=0;i<NI_TIMEOUT;i++){
+ for(i = 0; i < NI_TIMEOUT; i++){
if(!(devpriv->stc_readw(dev, AI_Status_1_Register)&AI_FIFO_Empty_St))
break;
}
- if(i==NI_TIMEOUT){
+ if(i == NI_TIMEOUT){
rt_printk("ni_mio_common: timeout in ni_ai_insn_read\n");
return -ETIME;
}
- if(boardtype.reg_type == ni_reg_m_series)
+ if(boardtype.reg_type & ni_reg_m_series_mask)
{
data[n] = ni_readl(M_Offset_AI_FIFO_Data) & mask;
}else
{
unsigned int chan, range, aref;
unsigned int i;
- unsigned config_bits = 0;
unsigned offset;
unsigned int dither;
unsigned range_code;
// offset = 1 << (boardtype.adbits - 1);
if((list[0] & CR_ALT_SOURCE))
{
+ unsigned bypass_bits;
chan = CR_CHAN(list[0]);
range = CR_RANGE(list[0]);
range_code = ni_gainlkup[boardtype.gainlkup][range];
dither = ((list[0] & CR_ALT_FILTER) != 0);
- unsigned bypass_bits = MSeries_AI_Bypass_Config_FIFO_Bit;
+ bypass_bits = MSeries_AI_Bypass_Config_FIFO_Bit;
bypass_bits |= chan;
bypass_bits |= (devpriv->ai_calib_source) & (MSeries_AI_Bypass_Cal_Sel_Pos_Mask |
MSeries_AI_Bypass_Cal_Sel_Neg_Mask | MSeries_AI_Bypass_Mode_Mux_Mask |
offset = 0;
for(i = 0; i < n_chan; i++)
{
+ unsigned config_bits = 0;
chan = CR_CHAN(list[i]);
aref = CR_AREF(list[i]);
range = CR_RANGE(list[i]);
range_code = ni_gainlkup[boardtype.gainlkup][range];
devpriv->ai_offset[i] = offset;
-
switch( aref )
{
case AREF_DIFF:
unsigned offset;
unsigned int dither;
- if(boardtype.reg_type == ni_reg_m_series)
+ if(boardtype.reg_type & ni_reg_m_series_mask)
{
ni_m_series_load_channelgain_list(dev, n_chan, list);
return;
}
}
-#define TIMER_BASE 50 /* 20 Mhz base */
-
-static int ni_ns_to_timer(int *nanosec,int round_mode)
+static int ni_ns_to_timer(const comedi_device *dev, unsigned nanosec, int round_mode)
{
- int divider,base;
-
- base=TIMER_BASE;
-
- switch(round_mode){
+ int divider;
+ switch(round_mode)
+ {
case TRIG_ROUND_NEAREST:
default:
- divider=(*nanosec+base/2)/base;
+ divider = (nanosec + devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
case TRIG_ROUND_DOWN:
- divider=(*nanosec)/base;
+ divider = (nanosec) / devpriv->clock_ns;
break;
case TRIG_ROUND_UP:
- divider=(*nanosec+base-1)/base;
+ divider=(nanosec + devpriv->clock_ns - 1) / devpriv->clock_ns;
break;
}
+ return divider - 1;
+}
- *nanosec=base*divider;
- return divider-1;
+static unsigned ni_timer_to_ns(const comedi_device *dev, int timer)
+{
+ return devpriv->clock_ns * (timer + 1);
+}
+
+static unsigned ni_min_ai_scan_period_ns(comedi_device *dev, unsigned num_channels)
+{
+ switch(boardtype.reg_type)
+ {
+ case ni_reg_611x:
+ case ni_reg_6143:
+ // simultaneously-sampled inputs
+ return boardtype.ai_speed;
+ break;
+ default:
+ // multiplexed inputs
+ break;
+ };
+ return boardtype.ai_speed * num_channels;
}
static int ni_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
}
}
if(cmd->scan_begin_src==TRIG_TIMER){
- if(cmd->scan_begin_arg<boardtype.ai_speed){
- cmd->scan_begin_arg=boardtype.ai_speed;
+ if(cmd->scan_begin_arg < ni_min_ai_scan_period_ns(dev, cmd->chanlist_len))
+ {
+ cmd->scan_begin_arg = ni_min_ai_scan_period_ns(dev, cmd->chanlist_len);
err++;
}
- if(cmd->scan_begin_arg>TIMER_BASE*0xffffff){
- cmd->scan_begin_arg=TIMER_BASE*0xffffff;
+ if(cmd->scan_begin_arg > devpriv->clock_ns * 0xffffff){
+ cmd->scan_begin_arg = devpriv->clock_ns * 0xffffff;
err++;
}
}else if(cmd->scan_begin_src==TRIG_EXT){
cmd->convert_arg=boardtype.ai_speed;
err++;
}
- if(cmd->convert_arg>TIMER_BASE*0xffff){
- cmd->convert_arg=TIMER_BASE*0xffff;
+ if(cmd->convert_arg>devpriv->clock_ns*0xffff){
+ cmd->convert_arg=devpriv->clock_ns*0xffff;
err++;
}
}
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);
+ cmd->scan_begin_arg = ni_timer_to_ns(dev, ni_ns_to_timer(dev, cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK));
if(tmp!=cmd->scan_begin_arg)err++;
}
if(cmd->convert_src==TRIG_TIMER){
if((boardtype.reg_type != ni_reg_611x) && (boardtype.reg_type != ni_reg_6143)){
tmp=cmd->convert_arg;
- ni_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
+ cmd->convert_arg = ni_timer_to_ns(dev, ni_ns_to_timer(dev, 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)
+ {
cmd->scan_begin_arg=cmd->convert_arg*cmd->scan_end_arg;
err++;
}
static int ni_ai_cmd(comedi_device *dev,comedi_subdevice *s)
{
- comedi_cmd *cmd=&s->async->cmd;
+ const comedi_cmd *cmd=&s->async->cmd;
int timer;
int mode1=0; /* mode1 is needed for both stop and convert */
int mode2=0;
comedi_error(dev, "cannot run command without an irq");
return -EIO;
}
- ni_flush_ai_fifo(dev);
+ ni_clear_ai_fifo(dev);
ni_load_channelgain_list(dev,cmd->chanlist_len,cmd->chanlist);
devpriv->stc_writew(dev, mode2, AI_Mode_2_Register);
/* load SI */
- timer=ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
+ timer = ni_ns_to_timer(dev, cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
devpriv->stc_writel(dev, timer,AI_SI_Load_A_Registers);
devpriv->stc_writew(dev, AI_SI_Load,AI_Command_1_Register);
break;
if( cmd->convert_arg == 0 || cmd->convert_src == TRIG_NOW )
timer = 1;
else
- timer=ni_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
+ timer = ni_ns_to_timer(dev, cmd->convert_arg, TRIG_ROUND_NEAREST);
devpriv->stc_writew(dev, 1,AI_SI2_Load_A_Register); /* 0,0 does not work. */
devpriv->stc_writew(dev, timer,AI_SI2_Load_B_Register);
}
#ifdef PCIDMA
- ni_ai_setup_MITE_dma(dev,cmd);
+ {
+ int retval = ni_ai_setup_MITE_dma(dev);
+ if(retval) return retval;
+ }
//mite_dump_regs(devpriv->mite);
#endif
case INSN_CONFIG_ANALOG_TRIG:
return ni_ai_config_analog_trig(dev,s,insn,data);
case INSN_CONFIG_ALT_SOURCE:
- if(boardtype.reg_type == ni_reg_m_series)
+ if(boardtype.reg_type & ni_reg_m_series_mask)
{
if(data[1] & ~(MSeries_AI_Bypass_Cal_Sel_Pos_Mask |
MSeries_AI_Bypass_Cal_Sel_Neg_Mask | MSeries_AI_Bypass_Mode_Mux_Mask |
* data[3] is set level
* data[4] is reset level */
if(!boardtype.has_analog_trig)return -EINVAL;
- if(insn->n!=5)return -EINVAL;
if((data[1]&0xffff0000) != COMEDI_EV_SCAN_BEGIN){
- data[1]&=~(COMEDI_EV_SCAN_BEGIN&0xffff);
+ data[1]&= (COMEDI_EV_SCAN_BEGIN | 0xffff);
err++;
}
if(data[2]>=boardtype.n_adchan){
}
}
-static int ni_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
- unsigned int chanspec[], unsigned int n_chans)
+static int ni_m_series_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
+ unsigned int chanspec[], unsigned int n_chans, int timed)
{
unsigned int range;
unsigned int chan;
int i;
int invert = 0;
- for(i=0;i<n_chans;i++){
+ for(i = 0; i < boardtype.n_aochan; ++i)
+ {
+ ni_writeb(0xf, M_Offset_AO_Waveform_Order(i));
+ }
+ for(i=0;i<n_chans;i++)
+ {
+ comedi_krange *krange;
chan = CR_CHAN(chanspec[i]);
range = CR_RANGE(chanspec[i]);
- if(boardtype.reg_type == ni_reg_m_series)
+ krange = s->range_table->range + range;
+ invert = 0;
+ conf = 0;
+ switch(krange->max - krange->min)
{
- comedi_krange *krange = s->range_table->range + range;
- invert = 0;
- conf = 0;
- switch(krange->max - krange->min)
- {
- case 20000000:
- conf |= MSeries_AO_DAC_Reference_10V_Internal_Bits;
- ni_writeb(0, M_Offset_AO_Reference_Attenuation(chan));
- break;
- case 10000000:
- conf |= MSeries_AO_DAC_Reference_5V_Internal_Bits;
- ni_writeb(0, M_Offset_AO_Reference_Attenuation(chan));
- break;
- case 4000000:
- conf |= MSeries_AO_DAC_Reference_10V_Internal_Bits;
- ni_writeb(MSeries_Attenuate_x5_Bit, M_Offset_AO_Reference_Attenuation(chan));
- break;
- case 2000000:
- conf |= MSeries_AO_DAC_Reference_5V_Internal_Bits;
- ni_writeb(MSeries_Attenuate_x5_Bit, M_Offset_AO_Reference_Attenuation(chan));
- break;
- default:
- rt_printk("%s: bug! unhandled ao reference voltage\n", __FUNCTION__);
- break;
- }
- switch(krange->max + krange->min)
- {
- case 0:
- conf |= MSeries_AO_DAC_Offset_0V_Bits;
- break;
- case 10000000:
- conf |= MSeries_AO_DAC_Offset_5V_Bits;
- break;
- default:
- rt_printk("%s: bug! unhandled ao offset voltage\n", __FUNCTION__);
- break;
- }
- ni_writeb(conf, M_Offset_AO_Config_Bank(chan));
- }else
+ case 20000000:
+ conf |= MSeries_AO_DAC_Reference_10V_Internal_Bits;
+ ni_writeb(0, M_Offset_AO_Reference_Attenuation(chan));
+ break;
+ case 10000000:
+ conf |= MSeries_AO_DAC_Reference_5V_Internal_Bits;
+ ni_writeb(0, M_Offset_AO_Reference_Attenuation(chan));
+ break;
+ case 4000000:
+ conf |= MSeries_AO_DAC_Reference_10V_Internal_Bits;
+ ni_writeb(MSeries_Attenuate_x5_Bit, M_Offset_AO_Reference_Attenuation(chan));
+ break;
+ case 2000000:
+ conf |= MSeries_AO_DAC_Reference_5V_Internal_Bits;
+ ni_writeb(MSeries_Attenuate_x5_Bit, M_Offset_AO_Reference_Attenuation(chan));
+ break;
+ default:
+ rt_printk("%s: bug! unhandled ao reference voltage\n", __FUNCTION__);
+ break;
+ }
+ switch(krange->max + krange->min)
{
- conf = AO_Channel(chan);
-
- if(boardtype.ao_unipolar){
- if((range&1) == 0){
- conf |= AO_Bipolar;
- invert = (1<<(boardtype.aobits-1));
- }else{
- invert = 0;
- }
- if(range&2)
- conf |= AO_Ext_Ref;
- }else{
+ case 0:
+ conf |= MSeries_AO_DAC_Offset_0V_Bits;
+ break;
+ case 10000000:
+ conf |= MSeries_AO_DAC_Offset_5V_Bits;
+ break;
+ default:
+ rt_printk("%s: bug! unhandled ao offset voltage\n", __FUNCTION__);
+ break;
+ }
+ if(timed) conf |= MSeries_AO_Update_Timed_Bit;
+ ni_writeb(conf, M_Offset_AO_Config_Bank(chan));
+ devpriv->ao_conf[chan] = conf;
+ ni_writeb(i, M_Offset_AO_Waveform_Order(chan));
+ }
+ return invert;
+}
+
+static int ni_old_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
+ unsigned int chanspec[], unsigned int n_chans)
+{
+ unsigned int range;
+ unsigned int chan;
+ unsigned int conf;
+ int i;
+ int invert = 0;
+
+ for(i=0;i<n_chans;i++)
+ {
+ chan = CR_CHAN(chanspec[i]);
+ range = CR_RANGE(chanspec[i]);
+ conf = AO_Channel(chan);
+
+ if(boardtype.ao_unipolar){
+ if((range&1) == 0){
conf |= AO_Bipolar;
invert = (1<<(boardtype.aobits-1));
+ }else{
+ invert = 0;
}
+ if(range&2)
+ conf |= AO_Ext_Ref;
+ }else{
+ conf |= AO_Bipolar;
+ invert = (1<<(boardtype.aobits-1));
+ }
- /* not all boards can deglitch, but this shouldn't hurt */
- if(chanspec[i] & CR_DEGLITCH)
- conf |= AO_Deglitch;
+ /* not all boards can deglitch, but this shouldn't hurt */
+ if(chanspec[i] & CR_DEGLITCH)
+ conf |= AO_Deglitch;
- /* analog reference */
- /* AREF_OTHER connects AO ground to AI ground, i think */
- conf |= (CR_AREF(chanspec[i])==AREF_OTHER)? AO_Ground_Ref : 0;
+ /* analog reference */
+ /* AREF_OTHER connects AO ground to AI ground, i think */
+ conf |= (CR_AREF(chanspec[i])==AREF_OTHER)? AO_Ground_Ref : 0;
- ni_writew(conf,AO_Configuration);
- }
+ ni_writew(conf,AO_Configuration);
devpriv->ao_conf[chan] = conf;
}
return invert;
}
+static int ni_ao_config_chanlist(comedi_device *dev, comedi_subdevice *s,
+ unsigned int chanspec[], unsigned int n_chans, int timed)
+{
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ return ni_m_series_ao_config_chanlist(dev, s, chanspec, n_chans, timed);
+ else
+ return ni_old_ao_config_chanlist(dev, s, chanspec, n_chans);
+}
static int ni_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int invert;
- invert = ni_ao_config_chanlist(dev,s,&insn->chanspec,1);
+ invert = ni_ao_config_chanlist(dev,s,&insn->chanspec, 1, 0);
devpriv->ao[chan] = data[0];
- if(boardtype.reg_type == ni_reg_m_series)
+ if(boardtype.reg_type & ni_reg_m_series_mask)
{
ni_writew(data[0], M_Offset_DAC_Direct_Data(chan));
}
ao_win_out(1 << chan, AO_Immediate_671x);
invert = 1 << (boardtype.aobits - 1);
- ni_ao_config_chanlist(dev,s,&insn->chanspec,1);
+ ni_ao_config_chanlist(dev,s,&insn->chanspec, 1, 0);
devpriv->ao[chan] = data[0];
ao_win_out(data[0] ^ invert, DACx_Direct_Data_671x(chan));
int i;
static const int timeout = 1000;
- if(trignum!=0)return -EINVAL;
+ if(trignum!=0) return -EINVAL;
ni_set_bits(dev, Interrupt_B_Enable_Register, AO_FIFO_Interrupt_Enable | AO_Error_Interrupt_Enable, 0);
interrupt_b_bits = AO_Error_Interrupt_Enable;
devpriv->stc_writew(dev, 1, DAC_FIFO_Clear);
if(boardtype.reg_type & ni_reg_6xxx_mask)
ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
- ni_ao_setup_MITE_dma(dev, &s->async->cmd);
+ ret = ni_ao_setup_MITE_dma(dev);
+ if(ret) return ret;
ret = ni_ao_wait_for_dma_load(dev);
if(ret < 0) return ret;
/* wait for DACs to be loaded */
for(i = 0; i < timeout; i++)
{
- comedi_udelay(10);
+ comedi_udelay(1);
if((devpriv->stc_readw(dev, Joint_Status_2_Register) & AO_TMRDACWRs_In_Progress_St) == 0)
break;
}
static int ni_ao_cmd(comedi_device *dev,comedi_subdevice *s)
{
- comedi_cmd *cmd = &s->async->cmd;
+ const comedi_cmd *cmd = &s->async->cmd;
int trigvar;
int bits;
int i;
comedi_error(dev, "cannot run command without an irq");
return -EIO;
}
- trigvar = ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
+ trigvar = ni_ns_to_timer(dev, cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
devpriv->stc_writew(dev, AO_Configuration_Start,Joint_Reset_Register);
ao_win_out(bits, AO_Timed_611x);
}
- ni_ao_config_chanlist(dev,s,cmd->chanlist,cmd->chanlist_len);
+ ni_ao_config_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len, 1);
if(cmd->stop_src==TRIG_NONE){
devpriv->ao_mode1|=AO_Continuous;
if(cmd->scan_end_arg>1){
devpriv->ao_mode1|=AO_Multiple_Channels;
devpriv->stc_writew(dev, AO_Number_Of_Channels(cmd->scan_end_arg-1)|
- AO_UPDATE_Output_Select(1),
+ AO_UPDATE_Output_Select(AO_Update_Output_High_Z),
AO_Output_Control_Register);
}else{
+ unsigned bits;
devpriv->ao_mode1&=~AO_Multiple_Channels;
- devpriv->stc_writew(dev, AO_Number_Of_Channels(CR_CHAN(cmd->chanlist[0]))|
- AO_UPDATE_Output_Select(1),
- AO_Output_Control_Register);
+ bits = AO_UPDATE_Output_Select(AO_Update_Output_High_Z);
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ {
+ bits |= AO_Number_Of_Channels(0);
+ }else
+ {
+ bits |= AO_Number_Of_Channels(CR_CHAN(cmd->chanlist[0]));
+ }
+ devpriv->stc_writew(dev, bits, AO_Output_Control_Register);
}
devpriv->stc_writew(dev, devpriv->ao_mode1,AO_Mode_1_Register);
}
devpriv->ao_mode3|=AO_Stop_On_Overrun_Error;
devpriv->stc_writew(dev, devpriv->ao_mode3,AO_Mode_3_Register);
- devpriv->ao_mode2 &= AO_FIFO_Mode_Mask;
+ devpriv->ao_mode2 &= ~AO_FIFO_Mode_Mask;
#ifdef PCIDMA
devpriv->ao_mode2 |= AO_FIFO_Mode_HF_to_F;
#else
bits |= AO_FIFO_Enable;
else
bits |= AO_DMA_PIO_Control;
+#if 0
+ /* F Hess: windows driver does not set AO_Number_Of_DAC_Packages bit for 6281,
+ verified with bus analyzer. */
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ bits |= AO_Number_Of_DAC_Packages;
+#endif
devpriv->stc_writew(dev, bits, AO_Personal_Register);
// enable sending of ao dma requests
devpriv->stc_writew(dev, AO_AOFREQ_Enable, AO_Start_Select_Register);
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;
+ 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;
+ if(cmd->scan_begin_arg > devpriv->clock_ns * 0xffffff){ /* XXX check */
+ cmd->scan_begin_arg = devpriv->clock_ns * 0xffffff;
err++;
}
if(cmd->convert_arg!=0){
/* step 4: fix up any arguments */
tmp = cmd->scan_begin_arg;
- ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
+ cmd->scan_begin_arg = ni_timer_to_ns(dev, ni_ns_to_timer(dev, cmd->scan_begin_arg, cmd->flags&TRIG_ROUND_MASK));
if(tmp!=cmd->scan_begin_arg)err++;
if(err)return 4;
//devpriv->ao1p=AO_Channel(1);
//ni_writew(devpriv->ao1p,AO_Configuration);
-#ifdef PCIDMA
- mite_dma_disarm(devpriv->mite, AO_DMA_CHAN);
- writel(CHOR_DMARESET | CHOR_FRESET, devpriv->mite->mite_io_addr + MITE_CHOR(AO_DMA_CHAN));
-#endif
+ ni_release_ao_mite_channel(dev);
devpriv->stc_writew(dev, AO_Configuration_Start,Joint_Reset_Register);
devpriv->stc_writew(dev, AO_Disarm,AO_Command_1_Register);
devpriv->ao_cmd1=0;
devpriv->stc_writew(dev, devpriv->ao_cmd1,AO_Command_1_Register);
devpriv->ao_cmd2=0;
+ devpriv->stc_writew(dev, devpriv->ao_cmd2, AO_Command_2_Register);
devpriv->ao_mode1=0;
+ devpriv->stc_writew(dev, devpriv->ao_mode1, AO_Mode_1_Register);
devpriv->ao_mode2=0;
- if(boardtype.reg_type == ni_reg_m_series)
+ devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register);
+ if(boardtype.reg_type & ni_reg_m_series_mask)
devpriv->ao_mode3 = AO_Last_Gate_Disable;
else
devpriv->ao_mode3 = 0;
devpriv->stc_writew(dev, devpriv->ao_mode3, AO_Mode_3_Register);
- devpriv->ao_trigger_select=0;
+ devpriv->ao_trigger_select = 0;
+ devpriv->stc_writew(dev, devpriv->ao_trigger_select,AO_Trigger_Select_Register);
if(boardtype.reg_type & ni_reg_6xxx_mask){
ao_win_out(0x3, AO_Immediate_671x);
ao_win_out(CLEAR_WG, AO_Misc_611x);
ni_ao_win_outw(dev, AO_Channel(i) | 0x0, AO_Configuration_2_67xx);
}
+static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg)
+{
+ unsigned stc_register;
+ switch(reg)
+ {
+ case NITIO_G0_Autoincrement_Reg:
+ stc_register = G_Autoincrement_Register(0);
+ break;
+ case NITIO_G1_Autoincrement_Reg:
+ stc_register = G_Autoincrement_Register(1);
+ break;
+ case NITIO_G0_Command_Reg:
+ stc_register = G_Command_Register(0);
+ break;
+ case NITIO_G1_Command_Reg:
+ stc_register = G_Command_Register(1);
+ break;
+ case NITIO_G0_HW_Save_Reg:
+ stc_register = G_HW_Save_Register(0);
+ break;
+ case NITIO_G1_HW_Save_Reg:
+ stc_register = G_HW_Save_Register(1);
+ break;
+ case NITIO_G0_SW_Save_Reg:
+ stc_register = G_Save_Register(0);
+ break;
+ case NITIO_G1_SW_Save_Reg:
+ stc_register = G_Save_Register(1);
+ break;
+ case NITIO_G0_Mode_Reg:
+ stc_register = G_Mode_Register(0);
+ break;
+ case NITIO_G1_Mode_Reg:
+ stc_register = G_Mode_Register(1);
+ break;
+ case NITIO_G0_LoadA_Reg:
+ stc_register = G_Load_A_Register(0);
+ break;
+ case NITIO_G1_LoadA_Reg:
+ stc_register = G_Load_A_Register(1);
+ break;
+ case NITIO_G0_LoadB_Reg:
+ stc_register = G_Load_B_Register(0);
+ break;
+ case NITIO_G1_LoadB_Reg:
+ stc_register = G_Load_B_Register(1);
+ break;
+ case NITIO_G0_Input_Select_Reg:
+ stc_register = G_Input_Select_Register(0);
+ break;
+ case NITIO_G1_Input_Select_Reg:
+ stc_register = G_Input_Select_Register(1);
+ break;
+ case NITIO_G01_Status_Reg:
+ stc_register = G_Status_Register;
+ break;
+ case NITIO_G01_Joint_Reset_Reg:
+ stc_register = Joint_Reset_Register;
+ break;
+ case NITIO_G01_Joint_Status1_Reg:
+ stc_register = Joint_Status_1_Register;
+ break;
+ case NITIO_G01_Joint_Status2_Reg:
+ stc_register = Joint_Status_2_Register;
+ break;
+ default:
+ rt_printk("%s: unhandled register 0x%x in switch.\n", __FUNCTION__, reg);
+ BUG();
+ return 0;
+ break;
+ }
+ return stc_register;
+}
+
+static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg)
+{
+ comedi_device *dev = counter->dev;
+ unsigned stc_register;
+ /* bits in the join reset register which are relevant to counters */
+ static const unsigned gpct_joint_reset_mask = G0_Reset | G1_Reset;
+ switch(reg)
+ {
+ /* m-series-only registers */
+ case NITIO_G0_Counting_Mode_Reg:
+ ni_writew(bits, M_Offset_G0_Counting_Mode);
+ break;
+ case NITIO_G1_Counting_Mode_Reg:
+ ni_writew(bits, M_Offset_G1_Counting_Mode);
+ break;
+ case NITIO_G0_Second_Gate_Reg:
+ ni_writew(bits, M_Offset_G0_Second_Gate);
+ break;
+ case NITIO_G1_Second_Gate_Reg:
+ ni_writew(bits, M_Offset_G1_Second_Gate);
+ break;
+ case NITIO_G0_ABZ_Reg:
+ ni_writew(bits, M_Offset_G0_MSeries_ABZ);
+ break;
+ case NITIO_G1_ABZ_Reg:
+ ni_writew(bits, M_Offset_G1_MSeries_ABZ);
+ break;
+
+ /* 32 bit registers */
+ case NITIO_G0_LoadA_Reg:
+ case NITIO_G1_LoadA_Reg:
+ case NITIO_G0_LoadB_Reg:
+ case NITIO_G1_LoadB_Reg:
+ stc_register = ni_gpct_to_stc_register(reg);
+ devpriv->stc_writel(dev, bits, stc_register);
+ break;
+ /* 16 bit registers */
+ case NITIO_G01_Joint_Reset_Reg:
+ BUG_ON(bits & ~gpct_joint_reset_mask);
+ /* fall-through */
+ default:
+ stc_register = ni_gpct_to_stc_register(reg);
+ devpriv->stc_writew(dev, bits, stc_register);
+ }
+}
+
+static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg)
+{
+ comedi_device *dev = counter->dev;
+ unsigned stc_register;
+ switch(reg)
+ {
+ /* 32 bit registers */
+ case NITIO_G0_HW_Save_Reg:
+ case NITIO_G1_HW_Save_Reg:
+ case NITIO_G0_SW_Save_Reg:
+ case NITIO_G1_SW_Save_Reg:
+ stc_register = ni_gpct_to_stc_register(reg);
+ return devpriv->stc_readl(dev, stc_register);
+ break;
+ /* 16 bit registers */
+ default:
+ stc_register = ni_gpct_to_stc_register(reg);
+ return devpriv->stc_readw(dev, stc_register);
+ break;
+ }
+ return 0;
+}
+
static int ni_alloc_private(comedi_device *dev)
{
int ret;
if(ret < 0) return ret;
spin_lock_init(&devpriv->window_lock);
+ spin_lock_init(&devpriv->soft_reg_copy_lock);
+ spin_lock_init(&devpriv->mite_channel_lock);
return 0;
};
static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
{
comedi_subdevice *s;
- int bits;
+ unsigned j;
if(boardtype.n_aochan > MAX_N_AO_CHAN)
{
return -EINVAL;
}
- if(alloc_subdevices(dev, 11) < 0)
+ if(alloc_subdevices(dev, 11 + NUM_GPCT) < 0)
return -ENOMEM;
/* analog input subdevice */
dev->read_subdev=s;
if(boardtype.n_adchan){
s->type=COMEDI_SUBD_AI;
- s->subdev_flags=SDF_READABLE | SDF_DIFF | SDF_DITHER;
+ s->subdev_flags=SDF_READABLE | SDF_DIFF | SDF_DITHER | SDF_CMD_READ;
if(boardtype.reg_type != ni_reg_611x)
s->subdev_flags |= SDF_GROUND | SDF_COMMON | SDF_OTHER;
if(boardtype.adbits > 16)
s->subdev_flags |= SDF_LSAMPL;
- if(boardtype.reg_type == ni_reg_m_series)
+ if(boardtype.reg_type & ni_reg_m_series_mask)
s->subdev_flags |= SDF_SOFT_CALIBRATED;
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->insn_config=ni_ai_insn_config;
- s->do_cmdtest=ni_ai_cmdtest;
- s->do_cmd=ni_ai_cmd;
- s->cancel=ni_ai_reset;
- s->poll=ni_ai_poll;
- s->munge=ni_ai_munge;
+ s->insn_read = &ni_ai_insn_read;
+ s->insn_config = &ni_ai_insn_config;
+ s->do_cmdtest = &ni_ai_cmdtest;
+ s->do_cmd = &ni_ai_cmd;
+ s->cancel = &ni_ai_reset;
+ s->poll = &ni_ai_poll;
+ s->munge = &ni_ai_munge;
+#ifdef PCIDMA
+ s->async_dma_dir = DMA_FROM_DEVICE;
+#endif
}else{
s->type=COMEDI_SUBD_UNUSED;
}
/* analog output subdevice */
- s=dev->subdevices+1;
+ s = dev->subdevices + 1;
if(boardtype.n_aochan){
- dev->write_subdev=s;
- s->type=COMEDI_SUBD_AO;
- s->subdev_flags=SDF_WRITABLE|SDF_DEGLITCH|SDF_GROUND;
- if(boardtype.reg_type == ni_reg_m_series)
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_DEGLITCH | SDF_GROUND;
+ if(boardtype.reg_type & ni_reg_m_series_mask)
s->subdev_flags |= SDF_SOFT_CALIBRATED;
- s->n_chan=boardtype.n_aochan;
- s->maxdata=(1<<boardtype.aobits)-1;
+ s->n_chan = boardtype.n_aochan;
+ s->maxdata = (1 << boardtype.aobits) - 1;
s->range_table = boardtype.ao_range_table;
- s->insn_read=ni_ao_insn_read;
+ s->insn_read = &ni_ao_insn_read;
if(boardtype.reg_type & ni_reg_6xxx_mask){
- s->insn_write=ni_ao_insn_write_671x;
+ s->insn_write = &ni_ao_insn_write_671x;
}else{
- s->insn_write=ni_ao_insn_write;
+ s->insn_write = &ni_ao_insn_write;
}
#ifdef PCIDMA
if(boardtype.n_aochan){
+ s->async_dma_dir = DMA_TO_DEVICE;
#else
if(boardtype.ao_fifo_depth){
#endif
- s->do_cmd=ni_ao_cmd;
- s->do_cmdtest=ni_ao_cmdtest;
+ dev->write_subdev=s;
+ s->subdev_flags |= SDF_CMD_WRITE;
+ s->do_cmd = &ni_ao_cmd;
+ s->do_cmdtest = &ni_ao_cmdtest;
s->len_chanlist = boardtype.n_aochan;
- if(boardtype.reg_type != ni_reg_m_series)
+ if((boardtype.reg_type & ni_reg_m_series_mask) == 0)
s->munge=ni_ao_munge;
}
- s->cancel=ni_ao_reset;
+ s->cancel = &ni_ao_reset;
}else{
- s->type=COMEDI_SUBD_UNUSED;
+ s->type = COMEDI_SUBD_UNUSED;
}
if((boardtype.reg_type & ni_reg_67xx_mask))
init_ao_67xx(dev, s);
s->maxdata=1;
s->io_bits=0; /* all bits input */
s->range_table=&range_digital;
- if(boardtype.reg_type == ni_reg_m_series)
+ s->n_chan = boardtype.num_p0_dio_channels;
+ if(boardtype.reg_type & ni_reg_m_series_mask)
{
- s->n_chan = 32;
s->insn_bits = ni_m_series_dio_insn_bits;
s->insn_config=ni_m_series_dio_insn_config;
ni_writel(s->io_bits, M_Offset_DIO_Direction);
}else
{
- s->n_chan=8;
s->insn_bits=ni_dio_insn_bits;
s->insn_config=ni_dio_insn_config;
devpriv->dio_control = DIO_Pins_Dir(s->io_bits);
s->type=COMEDI_SUBD_UNUSED;
}
- /* general purpose counter/timer device */
+ /* formerly general purpose counter/timer device, but no longer used */
s=dev->subdevices+4;
- s->type=COMEDI_SUBD_COUNTER;
- s->subdev_flags=SDF_READABLE|SDF_WRITABLE;
- 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);
+ s->type = COMEDI_SUBD_UNUSED;
/* calibration subdevice -- ai and ao */
s=dev->subdevices+5;
s->type=COMEDI_SUBD_CALIB;
- if(boardtype.reg_type == ni_reg_m_series)
+ if(boardtype.reg_type & ni_reg_m_series_mask)
{
// internal PWM analog output used for AI nonlinearity calibration
s->subdev_flags = SDF_INTERNAL;
s->type=COMEDI_SUBD_MEMORY;
s->subdev_flags=SDF_READABLE|SDF_INTERNAL;
s->maxdata=0xff;
- if(boardtype.reg_type == ni_reg_m_series)
+ if(boardtype.reg_type & ni_reg_m_series_mask)
{
s->n_chan = M_SERIES_EEPROM_SIZE;
s->insn_read = &ni_m_series_eeprom_insn_read;
s->insn_read = &ni_eeprom_insn_read;
}
/* PFI */
- s=dev->subdevices+7;
- s->type=COMEDI_SUBD_DIO;
- s->subdev_flags=SDF_READABLE|SDF_WRITABLE|SDF_INTERNAL;
- s->n_chan=10;
- s->maxdata=1;
+ s=dev->subdevices + 7;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ {
+ unsigned i;
+ s->n_chan = 16;
+ ni_writew(s->state, M_Offset_PFI_DO);
+ for(i = 0; i < NUM_PFI_OUTPUT_SELECT_REGS; ++i)
+ {
+ ni_writew(devpriv->pfi_output_select_reg[i], M_Offset_PFI_Output_Select(i + 1));
+ }
+ }else
+ {
+ s->n_chan = 10;
+ }
+ s->maxdata = 1;
s->insn_bits = ni_pfi_insn_bits;
s->insn_config = ni_pfi_insn_config;
ni_set_bits(dev, IO_Bidirection_Pin_Register, ~0, 0);
devpriv->serial_hw_mode = 0;
/* RTSI */
- s=dev->subdevices+10;
- s->type=COMEDI_SUBD_DIO;
- s->subdev_flags=SDF_READABLE|SDF_WRITABLE|SDF_INTERNAL;
- s->n_chan=7;
- s->maxdata=1;
+ s=dev->subdevices + 10;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 8;
+ s->maxdata = 1;
s->insn_bits = ni_rtsi_insn_bits;
s->insn_config = ni_rtsi_insn_config;
ni_rtsi_init(dev);
+ /* General purpose counters */
+ for(j = 0; j < NUM_GPCT; ++j)
+ {
+ s = dev->subdevices + 11 + j;
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 3;
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ s->maxdata = 0xffffffff;
+ else
+ s->maxdata = 0xffffff;
+ s->insn_read = ni_gpct_insn_read;
+ s->insn_write = ni_gpct_insn_write;
+ s->insn_config = ni_gpct_insn_config;
+ s->do_cmd = ni_gpct_cmd;
+ s->do_cmdtest = ni_gpct_cmdtest;
+ s->cancel = ni_gpct_cancel;
+ s->async_dma_dir = DMA_BIDIRECTIONAL;
+ s->private = &devpriv->counters[j];
+
+ devpriv->counters[j].dev = dev;
+ devpriv->counters[j].chip_index = 0;
+ devpriv->counters[j].counter_index = j;
+ devpriv->counters[j].write_register = ni_gpct_write_register;
+ devpriv->counters[j].read_register = ni_gpct_read_register;
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ {
+ devpriv->counters[j].variant = ni_gpct_variant_m_series;
+ }else
+ {
+ devpriv->counters[j].variant = ni_gpct_variant_e_series;
+ }
+ devpriv->counters[j].clock_period_ps = 0;
+ devpriv->counters[j].mite_chan = NULL;
+ ni_tio_init_counter(&devpriv->counters[j]);
+ }
+
/* ai configuration */
ni_ai_reset(dev,dev->subdevices+0);
if((boardtype.reg_type & ni_reg_6xxx_mask) == 0){
}
/* DMA setup */
- /* tell the STC which dma channels to use for AI and AO */
- bits = 1 << ( AI_DMA_CHAN );
- bits |= 1 << ( AO_DMA_CHAN + 4 );
- ni_writeb( bits, AI_AO_Select);
- /* tell the STC which dma channels to use for
- * General purpose counters 0 and 1 */
- bits = 1 << ( GPC0_DMA_CHAN );
- bits |= 1 << ( GPC1_DMA_CHAN + 4 );
- ni_writeb( bits, G0_G1_Select);
+ ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
+ ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select);
if(boardtype.reg_type & ni_reg_6xxx_mask)
{
ni_writeb( 0, Magic_611x );
- }else if(boardtype.reg_type == ni_reg_m_series)
+ }else if(boardtype.reg_type & ni_reg_m_series_mask)
{
int channel;
for(channel = 0; channel < boardtype.n_aochan; ++channel)
}
printk("\n");
-
return 0;
}
static int ni_get_pwm_config(comedi_device *dev, lsampl_t *data)
{
- data[1] = devpriv->pwm_up_count * TIMER_BASE;
- data[2] = devpriv->pwm_down_count * TIMER_BASE;
+ data[1] = devpriv->pwm_up_count * devpriv->clock_ns;
+ data[2] = devpriv->pwm_down_count * devpriv->clock_ns;
return 3;
}
switch(data[1])
{
case TRIG_ROUND_NEAREST:
- up_count = (data[2] + TIMER_BASE / 2) / TIMER_BASE;
+ up_count = (data[2] + devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
case TRIG_ROUND_DOWN:
- up_count = data[2] / TIMER_BASE;
+ up_count = data[2] / devpriv->clock_ns;
break;
case TRIG_ROUND_UP:
- up_count = (data[2] + TIMER_BASE - 1) / TIMER_BASE;
+ up_count = (data[2] + devpriv->clock_ns - 1) / devpriv->clock_ns;
break;
default:
return -EINVAL;
switch(data[3])
{
case TRIG_ROUND_NEAREST:
- down_count = (data[4] + TIMER_BASE / 2) / TIMER_BASE;
+ down_count = (data[4] + devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
case TRIG_ROUND_DOWN:
- down_count = data[4] / TIMER_BASE;
+ down_count = data[4] / devpriv->clock_ns;
break;
case TRIG_ROUND_UP:
- down_count = (data[4] + TIMER_BASE - 1) / TIMER_BASE;
+ down_count = (data[4] + devpriv->clock_ns - 1) / devpriv->clock_ns;
break;
default:
return -EINVAL;
break;
}
- if(up_count * TIMER_BASE != data[2] ||
- down_count * TIMER_BASE != data[4])
+ if(up_count * devpriv->clock_ns != data[2] ||
+ down_count * devpriv->clock_ns != data[4])
{
- data[2] = up_count * TIMER_BASE;
- data[4] = down_count * TIMER_BASE;
+ data[2] = up_count * devpriv->clock_ns;
+ data[4] = down_count * devpriv->clock_ns;
return -EAGAIN;
}
ni_writel(MSeries_Cal_PWM_High_Time_Bits(up_count) | MSeries_Cal_PWM_Low_Time_Bits(down_count), M_Offset_Cal_PWM);
switch(data[1])
{
case TRIG_ROUND_NEAREST:
- up_count = (data[2] + TIMER_BASE / 2) / TIMER_BASE;
+ up_count = (data[2] + devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
case TRIG_ROUND_DOWN:
- up_count = data[2] / TIMER_BASE;
+ up_count = data[2] / devpriv->clock_ns;
break;
case TRIG_ROUND_UP:
- up_count = (data[2] + TIMER_BASE - 1) / TIMER_BASE;
+ up_count = (data[2] + devpriv->clock_ns - 1) / devpriv->clock_ns;
break;
default:
return -EINVAL;
switch(data[3])
{
case TRIG_ROUND_NEAREST:
- down_count = (data[4] + TIMER_BASE / 2) / TIMER_BASE;
+ down_count = (data[4] + devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
case TRIG_ROUND_DOWN:
- down_count = data[4] / TIMER_BASE;
+ down_count = data[4] / devpriv->clock_ns;
break;
case TRIG_ROUND_UP:
- down_count = (data[4] + TIMER_BASE - 1) / TIMER_BASE;
+ down_count = (data[4] + devpriv->clock_ns - 1) / devpriv->clock_ns;
break;
default:
return -EINVAL;
break;
}
- if(up_count * TIMER_BASE != data[2] ||
- down_count * TIMER_BASE != data[4])
+ if(up_count * devpriv->clock_ns != data[2] ||
+ down_count * devpriv->clock_ns != data[4])
{
- data[2] = up_count * TIMER_BASE;
- data[4] = down_count * TIMER_BASE;
+ data[2] = up_count * devpriv->clock_ns;
+ data[4] = down_count * devpriv->clock_ns;
return -EAGAIN;
}
ni_writel(up_count, Calibration_HighTime_6143);
}
-
-
-
-/*
- *
- * 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.
- *
- * These are inlined _only_ because they are used once in subsequent
- * code. Otherwise they should not be inlined.
- */
-static inline void GPCT_Load_A(comedi_device *dev, int chan, unsigned int value)
-{
- devpriv->stc_writel(dev, value & 0x00ffffff, G_Load_A_Register(chan));
-}
-
-static inline void GPCT_Load_B(comedi_device *dev, int chan, unsigned int value)
-{
- devpriv->stc_writel(dev, value & 0x00ffffff, G_Load_B_Register(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, unsigned int value)
-{
- devpriv->gpct_mode[chan] &= (~G_Load_Source_Select);
- devpriv->stc_writew(dev, devpriv->gpct_mode[chan],G_Mode_Register(chan));
- GPCT_Load_A(dev,chan,value);
- devpriv->stc_writew(dev, devpriv->gpct_command[chan]|G_Load,G_Command_Register(chan));
-}
-
+#if 0
/*
* Read the GPCTs current value.
*/
return (hi1<<16)|lo;
}
-
-static int GPCT_Disarm(comedi_device *dev, int chan)
+static void GPCT_Reset(comedi_device *dev, int chan)
{
- devpriv->stc_writew(dev, devpriv->gpct_command[chan] | G_Disarm,G_Command_Register(chan));
- return 0;
-}
+ int temp_ack_reg=0;
+ //printk("GPCT_Reset...");
+ devpriv->gpct_cur_operation[chan] = GPCT_RESET;
-static int GPCT_Arm(comedi_device *dev, int chan)
-{
- devpriv->stc_writew(dev, 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;
+ switch (chan) {
+ case 0:
+ devpriv->stc_writew(dev, G0_Reset,Joint_Reset_Register);
+ 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);
+ 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;
+ devpriv->stc_writew(dev, temp_ack_reg,Interrupt_A_Ack_Register);
+
+ //problem...this interferes with the other ctr...
+ devpriv->an_trig_etc_reg |= GPFO_0_Output_Enable;
+ devpriv->stc_writew(dev, devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
+ break;
+ case 1:
+ devpriv->stc_writew(dev, G1_Reset,Joint_Reset_Register);
+ 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);
+ 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;
+ devpriv->stc_writew(dev, temp_ack_reg,Interrupt_B_Ack_Register);
- g_status=devpriv->stc_readw(dev, G_Status_Register);
+ devpriv->an_trig_etc_reg |= GPFO_1_Output_Enable;
+ devpriv->stc_writew(dev, devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
+ break;
+ };
- 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;
+ devpriv->gpct_mode[chan] = 0;
+ devpriv->gpct_input_select[chan] = 0;
+ devpriv->gpct_command[chan] = 0;
+
+ devpriv->gpct_command[chan] |= G_Synchronized_Gate;
+
+ devpriv->stc_writew(dev, devpriv->gpct_mode[chan],G_Mode_Register(chan));
+ devpriv->stc_writew(dev, devpriv->gpct_input_select[chan],G_Input_Select_Register(chan));
+ devpriv->stc_writew(dev, 0,G_Autoincrement_Register(chan));
+
+ //printk("exit GPCT_Reset\n");
}
-static int GPCT_Set_Source(comedi_device *dev,int chan ,int source)
+#endif
+
+static int ni_gpct_insn_config(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
{
- //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;
- }
- devpriv->stc_writew(dev, devpriv->gpct_input_select[chan], G_Input_Select_Register(chan));
- //printk("exit GPCT_Set_Source\n");
- return 0;
+ struct ni_gpct *counter = s->private;
+ return ni_tio_insn_config(counter, insn, data);
}
-static int GPCT_Set_Gate(comedi_device *dev,int chan ,int gate)
+static int ni_gpct_insn_read(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn,lsampl_t *data)
{
- //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;
- }
- devpriv->stc_writew(dev, devpriv->gpct_input_select[chan], G_Input_Select_Register(chan));
- devpriv->stc_writew(dev, devpriv->gpct_mode[chan], G_Mode_Register(chan));
- //printk("exit GPCT_Set_Gate\n");
- return 0;
+ struct ni_gpct *counter = s->private;
+ return ni_tio_rinsn(counter, insn, data);
}
-static int GPCT_Set_Direction(comedi_device *dev,int chan,int direction)
+static int ni_gpct_insn_write(comedi_device *dev, comedi_subdevice *s,
+ comedi_insn *insn, lsampl_t *data)
{
- //printk("GPCT_Set_Direction...");
+ struct ni_gpct *counter = s->private;
+ return ni_tio_winsn(counter, insn, data);
+}
- 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:
- rt_printk("Error direction=0x%08x..",direction);
- return -EINVAL;
+static int ni_gpct_cmd(comedi_device *dev, comedi_subdevice *s)
+{
+// XXX set M_Offset_GX_DMA_Config for m-series
+#ifdef PCIDMA
+ struct ni_gpct *counter = s->private;
+ const comedi_cmd *cmd = &s->async->cmd;
+ int retval = ni_request_gpct_mite_channel(dev, counter->counter_index);
+ if(retval)
+ {
+ comedi_error(dev, "no dma channel available for use by counter");
+ return retval;
}
- devpriv->stc_writew(dev, devpriv->gpct_command[chan], G_Command_Register(chan));
- //TIM 4/23/01 devpriv->stc_writew(dev, devpriv->gpct_mode[chan], G_Mode_Register(chan));
- //printk("exit GPCT_Set_Direction\n");
- return 0;
+ return ni_tio_cmd(counter, s->async);
+#else
+ return -ENOTSUPP;
+#endif
}
-static void GPCT_Event_Counting(comedi_device *dev,int chan)
+static int ni_gpct_cmdtest(comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd)
{
+ struct ni_gpct *counter = s->private;
+ //XXX check chanlist_len == 1
+ return ni_tio_cmdtest(counter);
+}
- //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);
+static int ni_gpct_cancel(comedi_device *dev, comedi_subdevice *s)
+{
+ struct ni_gpct *counter = s->private;
+ int retval = ni_tio_cancel(counter);
+ ni_release_gpct_mite_channel(dev, counter->counter_index);
+ return retval;
+}
- // 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);
-
- devpriv->stc_writew(dev, devpriv->gpct_mode[chan],G_Mode_Register(chan));
- //printk("exit GPCT_Event_Counting\n");
-}
-
-static 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);
-
- devpriv->stc_writew(dev, devpriv->gpct_mode[chan],G_Mode_Register(chan));
- devpriv->stc_writew(dev, devpriv->gpct_command[chan],G_Command_Register(chan));
- //printk("exit GPCT_Period_Meas\n");
-}
+/*
+ *
+ * Programmable Function Inputs
+ *
+ */
-static void GPCT_Pulse_Width_Meas(comedi_device *dev, int chan)
+static int ni_m_series_set_pfi_routing(comedi_device *dev, unsigned chan, unsigned source)
{
- //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);
-
- devpriv->stc_writew(dev, devpriv->gpct_mode[chan],G_Mode_Register(chan));
- devpriv->stc_writew(dev, devpriv->gpct_command[chan],G_Command_Register(chan));
-
- //printk("exit GPCT_Pulse_Width_Meas\n");
+ unsigned pfi_reg_index;
+ unsigned array_offset;
+ if((source & 0x1f) != source) return -EINVAL;
+ pfi_reg_index = 1 + chan / 3;
+ array_offset = pfi_reg_index - 1;
+ devpriv->pfi_output_select_reg[array_offset] &= ~MSeries_PFI_Output_Select_Mask(chan);
+ devpriv->pfi_output_select_reg[array_offset] |= MSeries_PFI_Output_Select_Bits(chan, source);
+ ni_writew(devpriv->pfi_output_select_reg[array_offset], M_Offset_PFI_Output_Select(pfi_reg_index));
+ return 2;
}
-/* 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.*/
-static void GPCT_Gen_Single_Pulse(comedi_device *dev, int chan, unsigned int length)
+static int ni_old_set_pfi_routing(comedi_device *dev, unsigned chan, unsigned source)
{
- //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
-
- devpriv->stc_writew(dev, devpriv->gpct_mode[chan],G_Mode_Register(chan));
- devpriv->stc_writew(dev, devpriv->gpct_command[chan],G_Command_Register(chan));
-
- //printk("exit GPCT_Gen_Cont\n");
+ // pre-m-series boards have fixed signals on pfi pins
+ if(source != ni_old_get_pfi_routing(dev, chan)) return -EINVAL;
+ return 2;
}
-static void GPCT_Gen_Cont_Pulse(comedi_device *dev, int chan, unsigned int length)
+static int ni_set_pfi_routing(comedi_device *dev, unsigned chan, unsigned source)
{
- //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;
-
-
- devpriv->stc_writew(dev, devpriv->gpct_mode[chan],G_Mode_Register(chan));
- devpriv->stc_writew(dev, devpriv->gpct_command[chan],G_Command_Register(chan));
-
- //printk("exit GPCT_Gen_Cont\n");
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ return ni_m_series_set_pfi_routing(dev, chan, source);
+ else
+ return ni_old_set_pfi_routing(dev, chan, source);
}
-static void GPCT_Reset(comedi_device *dev, int chan)
+static unsigned ni_m_series_get_pfi_routing(comedi_device *dev, unsigned chan)
{
- int temp_ack_reg=0;
-
- //printk("GPCT_Reset...");
- devpriv->gpct_cur_operation[chan] = GPCT_RESET;
-
- switch (chan) {
- case 0:
- devpriv->stc_writew(dev, G0_Reset,Joint_Reset_Register);
- 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);
- 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;
- devpriv->stc_writew(dev, temp_ack_reg,Interrupt_A_Ack_Register);
-
- //problem...this interferes with the other ctr...
- devpriv->an_trig_etc_reg |= GPFO_0_Output_Enable;
- devpriv->stc_writew(dev, devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register);
- break;
- case 1:
- devpriv->stc_writew(dev, G1_Reset,Joint_Reset_Register);
- 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);
- 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;
- devpriv->stc_writew(dev, temp_ack_reg,Interrupt_B_Ack_Register);
-
- devpriv->an_trig_etc_reg |= GPFO_1_Output_Enable;
- devpriv->stc_writew(dev, 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;
-
- devpriv->stc_writew(dev, devpriv->gpct_mode[chan],G_Mode_Register(chan));
- devpriv->stc_writew(dev, devpriv->gpct_input_select[chan],G_Input_Select_Register(chan));
- devpriv->stc_writew(dev, 0,G_Autoincrement_Register(chan));
-
- //printk("exit GPCT_Reset\n");
+ const unsigned array_offset = chan / 3;
+ return MSeries_PFI_Output_Select_Source(chan, devpriv->pfi_output_select_reg[array_offset]);
}
-static int ni_gpct_insn_config(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
+static unsigned ni_old_get_pfi_routing(comedi_device *dev, unsigned chan)
{
- 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);
+ // pre-m-series boards have fixed signals on pfi pins
+ switch(chan)
+ {
+ case 0:
+ return NI_PFI_OUTPUT_AI_START1;
break;
- case GPCT_SET_SOURCE:
- if(insn->n!=2)return -EINVAL;
- retval=GPCT_Set_Source(dev,insn->chanspec,data[1]);
+ case 1:
+ return NI_PFI_OUTPUT_AI_START2;
break;
- case GPCT_SET_GATE:
- if(insn->n!=2)return -EINVAL;
- retval=GPCT_Set_Gate(dev,insn->chanspec,data[1]);
+ case 2:
+ return NI_PFI_OUTPUT_AI_CONVERT;
break;
- case GPCT_SET_DIRECTION:
- if(insn->n!=2) return -EINVAL;
- retval=GPCT_Set_Direction(dev,insn->chanspec,data[1]);
+ case 3:
+ return NI_PFI_OUTPUT_G_SRC1;
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
+ case 4:
+ return NI_PFI_OUTPUT_G_GATE1;
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:
- rt_printk("unsupported GPCT operation!\n");
- return -EINVAL;
- }
+ case 5:
+ return NI_PFI_OUTPUT_AO_UPDATE_N;
break;
- case GPCT_ARM:
- if(insn->n!=1)return -EINVAL;
- retval=GPCT_Arm(dev,insn->chanspec);
+ case 6:
+ return NI_PFI_OUTPUT_AO_START1;
break;
- case GPCT_DISARM:
- if(insn->n!=1)return -EINVAL;
- retval=GPCT_Disarm(dev,insn->chanspec);
+ case 7:
+ return NI_PFI_OUTPUT_AI_START_PULSE;
+ break;
+ case 8:
+ return NI_PFI_OUTPUT_G_SRC0;
+ break;
+ case 9:
+ return NI_PFI_OUTPUT_G_GATE0;
break;
default:
- return -EINVAL;
- }
-
- //catch any errors from return values
- if(retval==0){
- return insn->n;
- }else{
- if(data[0]!=GPCT_ARM){
- rt_printk("error: retval was %d\n",retval);
- rt_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(devpriv->stc_readw(dev, G_Status_Register) & (chan?G1_Counting_St:G0_Counting_St))
- data[0]=0;
+ rt_printk("%s: bug, unhandled case in switch.\n", __FUNCTION__);
+ break;
}
- return 1;
+ return 0;
}
-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 unsigned ni_get_pfi_routing(comedi_device *dev, unsigned chan)
+{
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ return ni_m_series_get_pfi_routing(dev, chan);
+ else
+ return ni_old_get_pfi_routing(dev, chan);
}
-
-/*
- *
- * Programmable Function Inputs
- *
- */
-
static int ni_pfi_insn_bits(comedi_device *dev,comedi_subdevice *s,
comedi_insn *insn,lsampl_t *data)
{
- if(insn->n!=2)return -EINVAL;
-
- data[1] = 0;
-
+ if((boardtype.reg_type & ni_reg_m_series_mask) == 0)
+ {
+ data[1] = 0;
+ return 2;
+ }
+ if(data[0])
+ {
+ s->state &= ~data[0];
+ s->state |= (data[0] & data[1]);
+ ni_writew(s->state, M_Offset_PFI_DO);
+ }
+ data[1] = ni_readw(M_Offset_PFI_DI);
return 2;
}
if(insn->n < 1)return -EINVAL;
chan = CR_CHAN(insn->chanspec);
- if(chan>10)return -EINVAL;
switch(data[0]){
case COMEDI_OUTPUT:
data[1] = (devpriv->io_bidirection_pin_reg & (1<<chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
return insn->n;
break;
+ case INSN_CONFIG_SET_ROUTING:
+ return ni_set_pfi_routing(dev, chan, data[1]);
+ break;
+ case INSN_CONFIG_GET_ROUTING:
+ data[1] = ni_get_pfi_routing(dev, chan);
+ return 2;
+ break;
default:
return -EINVAL;
}
// Initialises the RTSI bus signal switch to a default state
// Set clock mode to internal
- devpriv->stc_writew(dev, COMEDI_RTSI_CLOCK_MODE_INTERNAL, RTSI_Trig_Direction_Register);
-
- // Standard internal lines are routed to standard RTSI bus lines
- devpriv->stc_writew(dev, 0x3210, RTSI_Trig_A_Output_Register);
- devpriv->stc_writew(dev, 0x0654, RTSI_Trig_B_Output_Register);
+ devpriv->clock_and_fout2 = MSeries_RTSI_10MHz_Bit;
+ if(ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0)
+ {
+ rt_printk("ni_set_master_clock failed, bug?");
+ }
+ // default internal lines routing to RTSI bus lines
+ devpriv->rtsi_trig_a_output_reg = RTSI_Trig_Output_Bits(0, NI_RTSI_OUTPUT_ADR_START1) |
+ RTSI_Trig_Output_Bits(1, NI_RTSI_OUTPUT_ADR_START2) |
+ RTSI_Trig_Output_Bits(2, NI_RTSI_OUTPUT_SCLKG) |
+ RTSI_Trig_Output_Bits(3, NI_RTSI_OUTPUT_DACUPDN);
+ devpriv->stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
+ RTSI_Trig_A_Output_Register);
+ devpriv->rtsi_trig_b_output_reg = RTSI_Trig_Output_Bits(4, NI_RTSI_OUTPUT_DA_START1) |
+ RTSI_Trig_Output_Bits(5, NI_RTSI_OUTPUT_G_SRC0) |
+ RTSI_Trig_Output_Bits(6, NI_RTSI_OUTPUT_G_GATE0);
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ devpriv->rtsi_trig_b_output_reg |= RTSI_Trig_Output_Bits(7, NI_RTSI_OUTPUT_RTSI_OSC);
+ devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
+ RTSI_Trig_B_Output_Register);
// Sets the source and direction of the 4 on board lines
// devpriv->stc_writew(dev, 0x0000, RTSI_Board_Register);
return 2;
}
-static int ni_rtsi_insn_config(comedi_device *dev,comedi_subdevice *s,
- comedi_insn *insn,lsampl_t *data)
+/* Find best multiplier/divider to try and get the PLL running at 80 MHz
+ * given an arbitrary frequency input clock */
+static int ni_mseries_get_pll_parameters(unsigned reference_period_ns,
+ unsigned *freq_divider, unsigned *freq_multiplier, unsigned *actual_period_ns)
{
- unsigned int chan;
- unsigned int bit;
+ unsigned div;
+ unsigned best_div = 1;
+ static const unsigned max_div = 0x10;
+ unsigned mult;
+ unsigned best_mult = 1;
+ static const unsigned max_mult = 0x100;
+ static const unsigned pico_per_nano = 1000;
+
+ const unsigned reference_picosec = reference_period_ns * pico_per_nano;
+ /* m-series wants the phased-locked loop to output 80MHz, which is divided by 4 to
+ * 20 MHz for most timing clocks */
+ static const unsigned target_picosec = 12500;
+ static const unsigned fudge_factor_80_to_20Mhz = 4;
+ int best_period_picosec = 0;
+ for(div = 1; div <= max_div; ++div)
+ {
+ for(mult = 1; mult <= max_mult; ++mult)
+ {
+ unsigned new_period_ps = (reference_picosec * div) / mult;
+ if(abs(new_period_ps - target_picosec) < abs(best_period_picosec - target_picosec))
+ {
+ best_period_picosec = new_period_ps;
+ best_div = div;
+ best_mult = mult;
+ }
+ }
+ }
+ if(best_period_picosec == 0)
+ {
+ rt_printk("%s: bug, failed to find pll parameters\n", __FUNCTION__);
+ return -EIO;
+ }
+ *freq_divider = best_div;
+ *freq_multiplier = best_mult;
+ *actual_period_ns = (best_period_picosec * fudge_factor_80_to_20Mhz + (pico_per_nano / 2)) / pico_per_nano;
+ return 0;
+}
- if(insn->n < 1) return -EINVAL;
+static inline unsigned num_configurable_rtsi_channels(comedi_device *dev)
+{
+ if(boardtype.reg_type & ni_reg_m_series_mask) return 8;
+ else return 7;
+}
- if(data[0] == INSN_CONFIG_SET_RTSI_CLOCK_MODE){
- if(data[1] > 3)
- return -EINVAL;
+static int ni_mseries_set_pll_master_clock(comedi_device *dev, unsigned source, unsigned period_ns)
+{
+ static const unsigned min_period_ns = 50;
+ static const unsigned max_period_ns = 1000;
+ static const unsigned timeout = 1000;
+ unsigned pll_control_bits;
+ unsigned freq_divider;
+ unsigned freq_multiplier;
+ unsigned i;
+ int retval;
+ if(source == NI_MIO_PLL_PXI10_CLOCK) period_ns = 100;
+ // these limits are somewhat arbitrary, but NI advertises 1 to 20MHz range so we'll use that
+ if(period_ns < min_period_ns || period_ns > max_period_ns)
+ {
+ rt_printk("%s: you must specify an input clock frequency between %i and %i nanosec "
+ "for the phased-lock loop.\n", __FUNCTION__, min_period_ns, max_period_ns);
+ return -EINVAL;
+ }
+ devpriv->rtsi_trig_direction_reg &= ~Use_RTSI_Clock_Bit;
+ devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+ pll_control_bits = MSeries_PLL_Enable_Bit | MSeries_PLL_VCO_Mode_75_150MHz_Bits;
+ devpriv->clock_and_fout2 |= MSeries_Timebase1_Select_Bit | MSeries_Timebase3_Select_Bit;
+ devpriv->clock_and_fout2 &= ~MSeries_PLL_In_Source_Select_Mask;
+ switch(source)
+ {
+ case NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK:
+ devpriv->clock_and_fout2 |= MSeries_PLL_In_Source_Select_Star_Trigger_Bits;
+ retval = ni_mseries_get_pll_parameters(period_ns, &freq_divider,
+ &freq_multiplier, &devpriv->clock_ns);
+ if(retval < 0) return retval;
+ break;
+ case NI_MIO_PLL_PXI10_CLOCK:
+ /* pxi clock is 10MHz */
+ devpriv->clock_and_fout2 |= MSeries_PLL_In_Source_Select_PXI_Clock10;
+ retval = ni_mseries_get_pll_parameters(period_ns, &freq_divider,
+ &freq_multiplier, &devpriv->clock_ns);
+ if(retval < 0) return retval;
+ break;
+ default:
+ {
+ unsigned rtsi_channel;
+ static const unsigned max_rtsi_channel = 7;
+ for(rtsi_channel = 0; rtsi_channel <= max_rtsi_channel; ++rtsi_channel)
+ {
+ if(source == NI_MIO_PLL_RTSI_CLOCK(rtsi_channel))
+ {
+ devpriv->clock_and_fout2 |= MSeries_PLL_In_Source_Select_RTSI_Bits(rtsi_channel);
+ break;
+ }
+ }
+ if(rtsi_channel > max_rtsi_channel) return -EINVAL;
+ retval = ni_mseries_get_pll_parameters(period_ns, &freq_divider,
+ &freq_multiplier, &devpriv->clock_ns);
+ if(retval < 0) return retval;
+ }
+ break;
+ }
+ ni_writew(devpriv->clock_and_fout2, M_Offset_Clock_and_Fout2);
+ pll_control_bits |= MSeries_PLL_Divisor_Bits(freq_divider) | MSeries_PLL_Multiplier_Bits(freq_multiplier);
+// rt_printk("using divider=%i, multiplier=%i for PLL. pll_control_bits = 0x%x\n", freq_divider, freq_multiplier, pll_control_bits);
+// rt_printk("clock_ns=%d\n", devpriv->clock_ns);
+ ni_writew(pll_control_bits, M_Offset_PLL_Control);
+ devpriv->clock_source = source;
+ /* it seems to typically take a few hundred microseconds for PLL to lock */
+ for(i = 0; i < timeout; ++i)
+ {
+ if(ni_readw(M_Offset_PLL_Status) & MSeries_PLL_Locked_Bit)
+ {
+ break;
+ }
+ udelay(1);
+ }
+ if(i == timeout)
+ {
+ rt_printk("%s: timed out waiting for PLL to lock to reference clock source %i with period %i ns.\n",
+ __FUNCTION__, source, period_ns);
+ return -ETIMEDOUT;
+ }
+ return 3;
+}
- devpriv->rtsi_trig_direction_reg &= ~0x03;
- devpriv->rtsi_trig_direction_reg |= data[1];
+static int ni_set_master_clock(comedi_device *dev, unsigned source, unsigned period_ns)
+{
+ if(source == NI_MIO_INTERNAL_CLOCK)
+ {
+ devpriv->rtsi_trig_direction_reg &= ~Use_RTSI_Clock_Bit;
devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+ devpriv->clock_ns = 50;
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ {
+ devpriv->clock_and_fout2 &= ~(MSeries_Timebase1_Select_Bit | MSeries_Timebase3_Select_Bit);
+ ni_writew(devpriv->clock_and_fout2, M_Offset_Clock_and_Fout2);
+ ni_writew(0, M_Offset_PLL_Control);
+ }
+ devpriv->clock_source = source;
+ }else
+ {
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ {
+ return ni_mseries_set_pll_master_clock(dev, source, period_ns);
+ }else
+ {
+ if(source == NI_MIO_RTSI_CLOCK)
+ {
+ devpriv->rtsi_trig_direction_reg |= Use_RTSI_Clock_Bit;
+ devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+ if(devpriv->clock_ns == 0)
+ {
+ rt_printk("%s: we don't handle an unspecified clock period correctly yet, returning error.\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }else
+ {
+ devpriv->clock_ns = period_ns;
+ }
+ devpriv->clock_source = source;
+ }else
+ return -EINVAL;
+ }
}
- else {
- chan = CR_CHAN(insn->chanspec);
- if(chan > 6) return -EINVAL;
-
- bit = 9 + chan;
+ return 3;
+}
- switch(data[0]){
- case INSN_CONFIG_DIO_OUTPUT:
- devpriv->rtsi_trig_direction_reg |= (1 << bit);
- devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
- break;
- case INSN_CONFIG_DIO_INPUT:
- devpriv->rtsi_trig_direction_reg &= ~(1 << bit);
- devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (devpriv->rtsi_trig_direction_reg & (1<<bit)) ? INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
- return 2;
- break;
- default:
- return -EINVAL;
+static int ni_valid_rtsi_output_source(comedi_device *dev, unsigned chan, unsigned source)
+{
+ if(chan >= num_configurable_rtsi_channels(dev))
+ {
+ if(chan == old_RTSI_clock_channel)
+ {
+ if(source == NI_RTSI_OUTPUT_RTSI_OSC) return 1;
+ else
+ {
+ rt_printk("%s: invalid source for channel=%i, channel %i is always the RTSI clock for pre-m-series boards.\n",
+ __FUNCTION__, chan, old_RTSI_clock_channel);
+ return 0;
+ }
}
+ return 0;
+ }
+ switch(source)
+ {
+ case NI_RTSI_OUTPUT_ADR_START1:
+ case NI_RTSI_OUTPUT_ADR_START2:
+ case NI_RTSI_OUTPUT_SCLKG:
+ case NI_RTSI_OUTPUT_DACUPDN:
+ case NI_RTSI_OUTPUT_DA_START1:
+ case NI_RTSI_OUTPUT_G_SRC0:
+ case NI_RTSI_OUTPUT_G_GATE0:
+ case NI_RTSI_OUTPUT_RGOUT0:
+ case NI_RTSI_OUTPUT_RTSI_BRD_0:
+ return 1;
+ break;
+ case NI_RTSI_OUTPUT_RTSI_OSC:
+ if(boardtype.reg_type & ni_reg_m_series_mask)
+ return 1;
+ else return 0;
+ break;
+ default:
+ return 0;
+ break;
}
+}
+
+static int ni_set_rtsi_routing(comedi_device *dev, unsigned chan, unsigned source)
+{
+ if(ni_valid_rtsi_output_source(dev, chan, source) == 0) return -EINVAL;
+ if(chan < 4)
+ {
+ devpriv->rtsi_trig_a_output_reg &= ~RTSI_Trig_Output_Mask(chan);
+ devpriv->rtsi_trig_a_output_reg |= RTSI_Trig_Output_Bits(chan, source);
+ devpriv->stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
+ RTSI_Trig_A_Output_Register);
+ }else if(chan < 8)
+ {
+ devpriv->rtsi_trig_b_output_reg &= ~RTSI_Trig_Output_Mask(chan);
+ devpriv->rtsi_trig_b_output_reg |= RTSI_Trig_Output_Bits(chan, source);
+ devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
+ RTSI_Trig_B_Output_Register);
+ }
+ return 2;
+}
+static unsigned ni_get_rtsi_routing(comedi_device *dev, unsigned chan)
+{
+ if(chan < 4)
+ {
+ return RTSI_Trig_Output_Source(chan, devpriv->rtsi_trig_a_output_reg);
+ }else if(chan < num_configurable_rtsi_channels(dev))
+ {
+ return RTSI_Trig_Output_Source(chan, devpriv->rtsi_trig_b_output_reg);
+ }else
+ {
+ if(chan == old_RTSI_clock_channel)
+ return NI_RTSI_OUTPUT_RTSI_OSC;
+ rt_printk("%s: bug! should never get here?\n", __FUNCTION__);
+ return 0;
+ }
+}
+
+static int ni_rtsi_insn_config(comedi_device *dev,comedi_subdevice *s,
+ comedi_insn *insn,lsampl_t *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ switch(data[0]){
+ case INSN_CONFIG_DIO_OUTPUT:
+ if(chan < num_configurable_rtsi_channels(dev))
+ {
+ devpriv->rtsi_trig_direction_reg |= RTSI_Output_Bit(chan, (boardtype.reg_type & ni_reg_m_series_mask) != 0);
+ }else if(chan == old_RTSI_clock_channel)
+ {
+ devpriv->rtsi_trig_direction_reg |= Drive_RTSI_Clock_Bit;
+ }
+ devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+ break;
+ case INSN_CONFIG_DIO_INPUT:
+ if(chan < num_configurable_rtsi_channels(dev))
+ {
+ devpriv->rtsi_trig_direction_reg &= ~RTSI_Output_Bit(chan, (boardtype.reg_type & ni_reg_m_series_mask) != 0);
+ }else if(chan == old_RTSI_clock_channel)
+ {
+ devpriv->rtsi_trig_direction_reg &= ~Drive_RTSI_Clock_Bit;
+ }
+ devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+ break;
+ case INSN_CONFIG_DIO_QUERY:
+ if(chan < num_configurable_rtsi_channels(dev))
+ {
+ data[1] = (devpriv->rtsi_trig_direction_reg & RTSI_Output_Bit(chan, (boardtype.reg_type & ni_reg_m_series_mask) != 0)) ?
+ INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
+ }else if(chan == old_RTSI_clock_channel)
+ {
+ data[1] = (devpriv->rtsi_trig_direction_reg & Drive_RTSI_Clock_Bit) ? INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
+ }
+ return 2;
+ break;
+ case INSN_CONFIG_SET_CLOCK_SRC:
+ return ni_set_master_clock(dev, data[1], data[2]);
+ break;
+ case INSN_CONFIG_GET_CLOCK_SRC:
+ data[1] = devpriv->clock_source;
+ data[2] = devpriv->clock_ns;
+ return 3;
+ break;
+ case INSN_CONFIG_SET_ROUTING:
+ return ni_set_rtsi_routing(dev, chan, data[1]);
+ break;
+ case INSN_CONFIG_GET_ROUTING:
+ data[1] = ni_get_rtsi_routing(dev, chan);
+ return 2;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
return 1;
}