static int ni_8255_callback(int dir,int port,int data,unsigned long arg);
-static int ni_ns_to_timer(comedi_device *dev, int *nanosec, int round_mode);
-
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,
/* 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_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;
static int ni_request_ai_mite_channel(comedi_device *dev)
{
unsigned long flags;
- static const unsigned max_dma_channel = 5;
comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
BUG_ON(devpriv->ai_mite_chan);
- devpriv->ai_mite_chan = mite_request_channel_in_range(devpriv->mite, devpriv->ai_mite_ring, 0, max_dma_channel);
+ 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);
static int ni_request_ao_mite_channel(comedi_device *dev)
{
unsigned long flags;
- static const unsigned max_dma_channel = 5;
comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
BUG_ON(devpriv->ao_mite_chan);
- devpriv->ao_mite_chan = mite_request_channel_in_range(devpriv->mite, devpriv->ao_mite_ring, 0, max_dma_channel);
+ 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);
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)
#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
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;
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(ai_mite_status & CHSR_LINKC){
if(!devpriv->ai_continuous){
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(status & G0_TC_St)
- {
- ack |= G0_TC_Interrupt_Ack;
- }
- if(status & G0_Gate_Interrupt_St)
- {
- ack |= G0_Gate_Interrupt_Ack;
- }
if(status & (G0_TC_St | G0_Gate_Interrupt_St))
{
unsigned long flags;
comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
}
- if(ack) devpriv->stc_writew(dev, ack,Interrupt_A_Ack_Register);
ni_event(dev,s,s->async->events);
#ifdef DEBUG_INTERRUPT
#endif
}
+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)
{
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 */
}
#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);
- s->async->events |= COMEDI_CB_OVERFLOW;
- }
-
ni_event(dev,s,s->async->events);
}
#ifdef PCIDMA
-static int ni_ai_setup_MITE_dma(comedi_device *dev,comedi_cmd *cmd)
+static int ni_ai_setup_MITE_dma(comedi_device *dev)
{
comedi_subdevice *s = dev->subdevices + 0;
int retval;
return 0;
}
-static int ni_ao_setup_MITE_dma(comedi_device *dev, comedi_cmd *cmd)
+static int ni_ao_setup_MITE_dma(comedi_device *dev)
{
comedi_subdevice *s = dev->subdevices + 1;
int retval;
}
}
-static int ni_ns_to_timer(comedi_device *dev, int *nanosec, int round_mode)
+static int ni_ns_to_timer(const comedi_device *dev, unsigned nanosec, int round_mode)
{
int divider;
switch(round_mode)
{
case TRIG_ROUND_NEAREST:
default:
- divider = (*nanosec + devpriv->clock_ns / 2) / devpriv->clock_ns;
+ divider = (nanosec + devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
case TRIG_ROUND_DOWN:
- divider = (*nanosec) / devpriv->clock_ns;
+ divider = (nanosec) / devpriv->clock_ns;
break;
case TRIG_ROUND_UP:
- divider=(*nanosec + devpriv->clock_ns - 1) / devpriv->clock_ns;
+ divider=(nanosec + devpriv->clock_ns - 1) / devpriv->clock_ns;
break;
}
-
- *nanosec = devpriv->clock_ns * 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)
if(cmd->scan_begin_src==TRIG_TIMER){
tmp=cmd->scan_begin_arg;
- ni_ns_to_timer(dev, &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(dev, &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;
devpriv->stc_writew(dev, mode2, AI_Mode_2_Register);
/* load SI */
- timer = ni_ns_to_timer(dev, &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(dev, &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
{
- int retval = ni_ai_setup_MITE_dma(dev,cmd);
+ int retval = ni_ai_setup_MITE_dma(dev);
if(retval) return retval;
}
//mite_dump_regs(devpriv->mite);
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);
- ret = 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;
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(dev, &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);
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/* | AO_Multiple_DACS_Per_Package*/;
+ 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);
/* step 4: fix up any arguments */
tmp = cmd->scan_begin_arg;
- ni_ns_to_timer(dev, &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;
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:
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;
+ }
return ni_tio_cmd(counter, s->async);
#else
- return -EIO;
+ return -ENOTSUPP;
#endif
}
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);
}
static int ni_gpct_cancel(comedi_device *dev, comedi_subdevice *s)
{
struct ni_gpct *counter = s->private;
- return ni_tio_cancel(counter);
+ int retval = ni_tio_cancel(counter);
+ ni_release_gpct_mite_channel(dev, counter->counter_index);
+ return retval;
}
/*