Staging: comedi: add National Instruments infrastructure
These drivers are used to support National Instruments general purpose counters and commands. From: Frank Mori Hess <fmhess@users.sourceforge.net> Cc: David Schleef <ds@schleef.org> Cc: Ian Abbott <abbotti@mev.co.uk> Cc: J.P. Mellor <jpmellor@rose-hulman.edu> Cc: Herman Bruyninckx <Herman.Bruyninckx@mech.kuleuven.ac.be> Cc: Wim Meeussen <Wim.Meeussen@mech.kuleuven.ac.be> Cc: Klass Gadeyne <Klaas.Gadeyne@mech.kuleuven.ac.be> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
f4bd8abb37
commit
cb7859a90a
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
drivers/ni_tio.h
|
||||
Header file for NI general purpose counter support code (ni_tio.c)
|
||||
|
||||
COMEDI - Linux Control and Measurement Device Interface
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _COMEDI_NI_TIO_H
|
||||
#define _COMEDI_NI_TIO_H
|
||||
|
||||
#include "../comedidev.h"
|
||||
|
||||
// forward declarations
|
||||
struct mite_struct;
|
||||
struct ni_gpct_device;
|
||||
|
||||
enum ni_gpct_register {
|
||||
NITIO_G0_Autoincrement_Reg,
|
||||
NITIO_G1_Autoincrement_Reg,
|
||||
NITIO_G2_Autoincrement_Reg,
|
||||
NITIO_G3_Autoincrement_Reg,
|
||||
NITIO_G0_Command_Reg,
|
||||
NITIO_G1_Command_Reg,
|
||||
NITIO_G2_Command_Reg,
|
||||
NITIO_G3_Command_Reg,
|
||||
NITIO_G0_HW_Save_Reg,
|
||||
NITIO_G1_HW_Save_Reg,
|
||||
NITIO_G2_HW_Save_Reg,
|
||||
NITIO_G3_HW_Save_Reg,
|
||||
NITIO_G0_SW_Save_Reg,
|
||||
NITIO_G1_SW_Save_Reg,
|
||||
NITIO_G2_SW_Save_Reg,
|
||||
NITIO_G3_SW_Save_Reg,
|
||||
NITIO_G0_Mode_Reg,
|
||||
NITIO_G1_Mode_Reg,
|
||||
NITIO_G2_Mode_Reg,
|
||||
NITIO_G3_Mode_Reg,
|
||||
NITIO_G0_LoadA_Reg,
|
||||
NITIO_G1_LoadA_Reg,
|
||||
NITIO_G2_LoadA_Reg,
|
||||
NITIO_G3_LoadA_Reg,
|
||||
NITIO_G0_LoadB_Reg,
|
||||
NITIO_G1_LoadB_Reg,
|
||||
NITIO_G2_LoadB_Reg,
|
||||
NITIO_G3_LoadB_Reg,
|
||||
NITIO_G0_Input_Select_Reg,
|
||||
NITIO_G1_Input_Select_Reg,
|
||||
NITIO_G2_Input_Select_Reg,
|
||||
NITIO_G3_Input_Select_Reg,
|
||||
NITIO_G0_Counting_Mode_Reg,
|
||||
NITIO_G1_Counting_Mode_Reg,
|
||||
NITIO_G2_Counting_Mode_Reg,
|
||||
NITIO_G3_Counting_Mode_Reg,
|
||||
NITIO_G0_Second_Gate_Reg,
|
||||
NITIO_G1_Second_Gate_Reg,
|
||||
NITIO_G2_Second_Gate_Reg,
|
||||
NITIO_G3_Second_Gate_Reg,
|
||||
NITIO_G01_Status_Reg,
|
||||
NITIO_G23_Status_Reg,
|
||||
NITIO_G01_Joint_Reset_Reg,
|
||||
NITIO_G23_Joint_Reset_Reg,
|
||||
NITIO_G01_Joint_Status1_Reg,
|
||||
NITIO_G23_Joint_Status1_Reg,
|
||||
NITIO_G01_Joint_Status2_Reg,
|
||||
NITIO_G23_Joint_Status2_Reg,
|
||||
NITIO_G0_DMA_Config_Reg,
|
||||
NITIO_G1_DMA_Config_Reg,
|
||||
NITIO_G2_DMA_Config_Reg,
|
||||
NITIO_G3_DMA_Config_Reg,
|
||||
NITIO_G0_DMA_Status_Reg,
|
||||
NITIO_G1_DMA_Status_Reg,
|
||||
NITIO_G2_DMA_Status_Reg,
|
||||
NITIO_G3_DMA_Status_Reg,
|
||||
NITIO_G0_ABZ_Reg,
|
||||
NITIO_G1_ABZ_Reg,
|
||||
NITIO_G0_Interrupt_Acknowledge_Reg,
|
||||
NITIO_G1_Interrupt_Acknowledge_Reg,
|
||||
NITIO_G2_Interrupt_Acknowledge_Reg,
|
||||
NITIO_G3_Interrupt_Acknowledge_Reg,
|
||||
NITIO_G0_Status_Reg,
|
||||
NITIO_G1_Status_Reg,
|
||||
NITIO_G2_Status_Reg,
|
||||
NITIO_G3_Status_Reg,
|
||||
NITIO_G0_Interrupt_Enable_Reg,
|
||||
NITIO_G1_Interrupt_Enable_Reg,
|
||||
NITIO_G2_Interrupt_Enable_Reg,
|
||||
NITIO_G3_Interrupt_Enable_Reg,
|
||||
NITIO_Num_Registers,
|
||||
};
|
||||
|
||||
enum ni_gpct_variant {
|
||||
ni_gpct_variant_e_series,
|
||||
ni_gpct_variant_m_series,
|
||||
ni_gpct_variant_660x
|
||||
};
|
||||
|
||||
struct ni_gpct {
|
||||
struct ni_gpct_device *counter_dev;
|
||||
unsigned counter_index;
|
||||
unsigned chip_index;
|
||||
uint64_t clock_period_ps; /* clock period in picoseconds */
|
||||
struct mite_channel *mite_chan;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct ni_gpct_device {
|
||||
comedi_device *dev;
|
||||
void (*write_register) (struct ni_gpct * counter, unsigned bits,
|
||||
enum ni_gpct_register reg);
|
||||
unsigned (*read_register) (struct ni_gpct * counter,
|
||||
enum ni_gpct_register reg);
|
||||
enum ni_gpct_variant variant;
|
||||
struct ni_gpct *counters;
|
||||
unsigned num_counters;
|
||||
unsigned regs[NITIO_Num_Registers];
|
||||
spinlock_t regs_lock;
|
||||
};
|
||||
|
||||
extern struct ni_gpct_device *ni_gpct_device_construct(comedi_device * dev,
|
||||
void (*write_register) (struct ni_gpct * counter, unsigned bits,
|
||||
enum ni_gpct_register reg),
|
||||
unsigned (*read_register) (struct ni_gpct * counter,
|
||||
enum ni_gpct_register reg), enum ni_gpct_variant variant,
|
||||
unsigned num_counters);
|
||||
extern void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev);
|
||||
extern void ni_tio_init_counter(struct ni_gpct *counter);
|
||||
extern int ni_tio_rinsn(struct ni_gpct *counter,
|
||||
comedi_insn * insn, lsampl_t * data);
|
||||
extern int ni_tio_insn_config(struct ni_gpct *counter,
|
||||
comedi_insn * insn, lsampl_t * data);
|
||||
extern int ni_tio_winsn(struct ni_gpct *counter,
|
||||
comedi_insn * insn, lsampl_t * data);
|
||||
extern int ni_tio_cmd(struct ni_gpct *counter, comedi_async * async);
|
||||
extern int ni_tio_cmdtest(struct ni_gpct *counter, comedi_cmd * cmd);
|
||||
extern int ni_tio_cancel(struct ni_gpct *counter);
|
||||
extern void ni_tio_handle_interrupt(struct ni_gpct *counter,
|
||||
comedi_subdevice * s);
|
||||
extern void ni_tio_set_mite_channel(struct ni_gpct *counter,
|
||||
struct mite_channel *mite_chan);
|
||||
extern void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter,
|
||||
int *gate_error, int *tc_error, int *perm_stale_data, int *stale_data);
|
||||
|
||||
static inline struct ni_gpct *subdev_to_counter(comedi_subdevice * s)
|
||||
{
|
||||
return s->private;
|
||||
}
|
||||
|
||||
#endif /* _COMEDI_NI_TIO_H */
|
|
@ -0,0 +1,774 @@
|
|||
/*
|
||||
drivers/ni_tio_internal.h
|
||||
Header file for NI general purpose counter support code (ni_tio.c and
|
||||
ni_tiocmd.c)
|
||||
|
||||
COMEDI - Linux Control and Measurement Device Interface
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _COMEDI_NI_TIO_INTERNAL_H
|
||||
#define _COMEDI_NI_TIO_INTERNAL_H
|
||||
|
||||
#include "ni_tio.h"
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Autoincrement_Reg(unsigned
|
||||
counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Autoincrement_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Autoincrement_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Autoincrement_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Autoincrement_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Command_Reg(unsigned counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Command_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Command_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Command_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Command_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Counting_Mode_Reg(unsigned
|
||||
counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Counting_Mode_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Counting_Mode_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Counting_Mode_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Counting_Mode_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Input_Select_Reg(unsigned
|
||||
counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Input_Select_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Input_Select_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Input_Select_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Input_Select_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gxx_Joint_Reset_Reg(unsigned
|
||||
counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
case 1:
|
||||
return NITIO_G01_Joint_Reset_Reg;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
return NITIO_G23_Joint_Reset_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gxx_Joint_Status1_Reg(unsigned
|
||||
counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
case 1:
|
||||
return NITIO_G01_Joint_Status1_Reg;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
return NITIO_G23_Joint_Status1_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gxx_Joint_Status2_Reg(unsigned
|
||||
counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
case 1:
|
||||
return NITIO_G01_Joint_Status2_Reg;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
return NITIO_G23_Joint_Status2_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gxx_Status_Reg(unsigned counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
case 1:
|
||||
return NITIO_G01_Status_Reg;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
return NITIO_G23_Status_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_LoadA_Reg(unsigned counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_LoadA_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_LoadA_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_LoadA_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_LoadA_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_LoadB_Reg(unsigned counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_LoadB_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_LoadB_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_LoadB_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_LoadB_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Mode_Reg(unsigned counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Mode_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Mode_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Mode_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Mode_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_SW_Save_Reg(int counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_SW_Save_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_SW_Save_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_SW_Save_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_SW_Save_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Second_Gate_Reg(int counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Second_Gate_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Second_Gate_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Second_Gate_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Second_Gate_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_DMA_Config_Reg(int counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_DMA_Config_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_DMA_Config_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_DMA_Config_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_DMA_Config_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_DMA_Status_Reg(int counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_DMA_Status_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_DMA_Status_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_DMA_Status_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_DMA_Status_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_ABZ_Reg(int counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_ABZ_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_ABZ_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(int
|
||||
counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Interrupt_Acknowledge_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Interrupt_Acknowledge_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Interrupt_Acknowledge_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Interrupt_Acknowledge_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Status_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Status_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Status_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Status_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(int
|
||||
counter_index)
|
||||
{
|
||||
switch (counter_index) {
|
||||
case 0:
|
||||
return NITIO_G0_Interrupt_Enable_Reg;
|
||||
break;
|
||||
case 1:
|
||||
return NITIO_G1_Interrupt_Enable_Reg;
|
||||
break;
|
||||
case 2:
|
||||
return NITIO_G2_Interrupt_Enable_Reg;
|
||||
break;
|
||||
case 3:
|
||||
return NITIO_G3_Interrupt_Enable_Reg;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum Gi_Auto_Increment_Reg_Bits {
|
||||
Gi_Auto_Increment_Mask = 0xff
|
||||
};
|
||||
|
||||
#define Gi_Up_Down_Shift 5
|
||||
enum Gi_Command_Reg_Bits {
|
||||
Gi_Arm_Bit = 0x1,
|
||||
Gi_Save_Trace_Bit = 0x2,
|
||||
Gi_Load_Bit = 0x4,
|
||||
Gi_Disarm_Bit = 0x10,
|
||||
Gi_Up_Down_Mask = 0x3 << Gi_Up_Down_Shift,
|
||||
Gi_Always_Down_Bits = 0x0 << Gi_Up_Down_Shift,
|
||||
Gi_Always_Up_Bits = 0x1 << Gi_Up_Down_Shift,
|
||||
Gi_Up_Down_Hardware_IO_Bits = 0x2 << Gi_Up_Down_Shift,
|
||||
Gi_Up_Down_Hardware_Gate_Bits = 0x3 << Gi_Up_Down_Shift,
|
||||
Gi_Write_Switch_Bit = 0x80,
|
||||
Gi_Synchronize_Gate_Bit = 0x100,
|
||||
Gi_Little_Big_Endian_Bit = 0x200,
|
||||
Gi_Bank_Switch_Start_Bit = 0x400,
|
||||
Gi_Bank_Switch_Mode_Bit = 0x800,
|
||||
Gi_Bank_Switch_Enable_Bit = 0x1000,
|
||||
Gi_Arm_Copy_Bit = 0x2000,
|
||||
Gi_Save_Trace_Copy_Bit = 0x4000,
|
||||
Gi_Disarm_Copy_Bit = 0x8000
|
||||
};
|
||||
|
||||
#define Gi_Index_Phase_Bitshift 5
|
||||
#define Gi_HW_Arm_Select_Shift 8
|
||||
enum Gi_Counting_Mode_Reg_Bits {
|
||||
Gi_Counting_Mode_Mask = 0x7,
|
||||
Gi_Counting_Mode_Normal_Bits = 0x0,
|
||||
Gi_Counting_Mode_QuadratureX1_Bits = 0x1,
|
||||
Gi_Counting_Mode_QuadratureX2_Bits = 0x2,
|
||||
Gi_Counting_Mode_QuadratureX4_Bits = 0x3,
|
||||
Gi_Counting_Mode_Two_Pulse_Bits = 0x4,
|
||||
Gi_Counting_Mode_Sync_Source_Bits = 0x6,
|
||||
Gi_Index_Mode_Bit = 0x10,
|
||||
Gi_Index_Phase_Mask = 0x3 << Gi_Index_Phase_Bitshift,
|
||||
Gi_Index_Phase_LowA_LowB = 0x0 << Gi_Index_Phase_Bitshift,
|
||||
Gi_Index_Phase_LowA_HighB = 0x1 << Gi_Index_Phase_Bitshift,
|
||||
Gi_Index_Phase_HighA_LowB = 0x2 << Gi_Index_Phase_Bitshift,
|
||||
Gi_Index_Phase_HighA_HighB = 0x3 << Gi_Index_Phase_Bitshift,
|
||||
Gi_HW_Arm_Enable_Bit = 0x80, /* from m-series example code, not documented in 660x register level manual */
|
||||
Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift, /* from m-series example code, not documented in 660x register level manual */
|
||||
Gi_660x_Prescale_X8_Bit = 0x1000,
|
||||
Gi_M_Series_Prescale_X8_Bit = 0x2000,
|
||||
Gi_M_Series_HW_Arm_Select_Mask = 0x1f << Gi_HW_Arm_Select_Shift,
|
||||
/* must be set for clocks over 40MHz, which includes synchronous counting and quadrature modes */
|
||||
Gi_660x_Alternate_Sync_Bit = 0x2000,
|
||||
Gi_M_Series_Alternate_Sync_Bit = 0x4000,
|
||||
Gi_660x_Prescale_X2_Bit = 0x4000, /* from m-series example code, not documented in 660x register level manual */
|
||||
Gi_M_Series_Prescale_X2_Bit = 0x8000,
|
||||
};
|
||||
|
||||
#define Gi_Source_Select_Shift 2
|
||||
#define Gi_Gate_Select_Shift 7
|
||||
enum Gi_Input_Select_Bits {
|
||||
Gi_Read_Acknowledges_Irq = 0x1, // not present on 660x
|
||||
Gi_Write_Acknowledges_Irq = 0x2, // not present on 660x
|
||||
Gi_Source_Select_Mask = 0x7c,
|
||||
Gi_Gate_Select_Mask = 0x1f << Gi_Gate_Select_Shift,
|
||||
Gi_Gate_Select_Load_Source_Bit = 0x1000,
|
||||
Gi_Or_Gate_Bit = 0x2000,
|
||||
Gi_Output_Polarity_Bit = 0x4000, /* set to invert */
|
||||
Gi_Source_Polarity_Bit = 0x8000 /* set to invert */
|
||||
};
|
||||
|
||||
enum Gi_Mode_Bits {
|
||||
Gi_Gating_Mode_Mask = 0x3,
|
||||
Gi_Gating_Disabled_Bits = 0x0,
|
||||
Gi_Level_Gating_Bits = 0x1,
|
||||
Gi_Rising_Edge_Gating_Bits = 0x2,
|
||||
Gi_Falling_Edge_Gating_Bits = 0x3,
|
||||
Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with rising edge gating mode */
|
||||
Gi_Trigger_Mode_for_Edge_Gate_Mask = 0x18,
|
||||
Gi_Edge_Gate_Starts_Stops_Bits = 0x0,
|
||||
Gi_Edge_Gate_Stops_Starts_Bits = 0x8,
|
||||
Gi_Edge_Gate_Starts_Bits = 0x10,
|
||||
Gi_Edge_Gate_No_Starts_or_Stops_Bits = 0x18,
|
||||
Gi_Stop_Mode_Mask = 0x60,
|
||||
Gi_Stop_on_Gate_Bits = 0x00,
|
||||
Gi_Stop_on_Gate_or_TC_Bits = 0x20,
|
||||
Gi_Stop_on_Gate_or_Second_TC_Bits = 0x40,
|
||||
Gi_Load_Source_Select_Bit = 0x80,
|
||||
Gi_Output_Mode_Mask = 0x300,
|
||||
Gi_Output_TC_Pulse_Bits = 0x100,
|
||||
Gi_Output_TC_Toggle_Bits = 0x200,
|
||||
Gi_Output_TC_or_Gate_Toggle_Bits = 0x300,
|
||||
Gi_Counting_Once_Mask = 0xc00,
|
||||
Gi_No_Hardware_Disarm_Bits = 0x000,
|
||||
Gi_Disarm_at_TC_Bits = 0x400,
|
||||
Gi_Disarm_at_Gate_Bits = 0x800,
|
||||
Gi_Disarm_at_TC_or_Gate_Bits = 0xc00,
|
||||
Gi_Loading_On_TC_Bit = 0x1000,
|
||||
Gi_Gate_Polarity_Bit = 0x2000,
|
||||
Gi_Loading_On_Gate_Bit = 0x4000,
|
||||
Gi_Reload_Source_Switching_Bit = 0x8000
|
||||
};
|
||||
|
||||
#define Gi_Second_Gate_Select_Shift 7
|
||||
/*FIXME: m-series has a second gate subselect bit */
|
||||
/*FIXME: m-series second gate sources are undocumented (by NI)*/
|
||||
enum Gi_Second_Gate_Bits {
|
||||
Gi_Second_Gate_Mode_Bit = 0x1,
|
||||
Gi_Second_Gate_Select_Mask = 0x1f << Gi_Second_Gate_Select_Shift,
|
||||
Gi_Second_Gate_Polarity_Bit = 0x2000,
|
||||
Gi_Second_Gate_Subselect_Bit = 0x4000, /* m-series only */
|
||||
Gi_Source_Subselect_Bit = 0x8000 /* m-series only */
|
||||
};
|
||||
static inline unsigned Gi_Second_Gate_Select_Bits(unsigned second_gate_select)
|
||||
{
|
||||
return (second_gate_select << Gi_Second_Gate_Select_Shift) &
|
||||
Gi_Second_Gate_Select_Mask;
|
||||
}
|
||||
|
||||
enum Gxx_Status_Bits {
|
||||
G0_Save_Bit = 0x1,
|
||||
G1_Save_Bit = 0x2,
|
||||
G0_Counting_Bit = 0x4,
|
||||
G1_Counting_Bit = 0x8,
|
||||
G0_Next_Load_Source_Bit = 0x10,
|
||||
G1_Next_Load_Source_Bit = 0x20,
|
||||
G0_Stale_Data_Bit = 0x40,
|
||||
G1_Stale_Data_Bit = 0x80,
|
||||
G0_Armed_Bit = 0x100,
|
||||
G1_Armed_Bit = 0x200,
|
||||
G0_No_Load_Between_Gates_Bit = 0x400,
|
||||
G1_No_Load_Between_Gates_Bit = 0x800,
|
||||
G0_TC_Error_Bit = 0x1000,
|
||||
G1_TC_Error_Bit = 0x2000,
|
||||
G0_Gate_Error_Bit = 0x4000,
|
||||
G1_Gate_Error_Bit = 0x8000
|
||||
};
|
||||
static inline enum Gxx_Status_Bits Gi_Counting_Bit(unsigned counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_Counting_Bit;
|
||||
return G0_Counting_Bit;
|
||||
}
|
||||
static inline enum Gxx_Status_Bits Gi_Armed_Bit(unsigned counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_Armed_Bit;
|
||||
return G0_Armed_Bit;
|
||||
}
|
||||
static inline enum Gxx_Status_Bits Gi_Next_Load_Source_Bit(unsigned
|
||||
counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_Next_Load_Source_Bit;
|
||||
return G0_Next_Load_Source_Bit;
|
||||
}
|
||||
static inline enum Gxx_Status_Bits Gi_Stale_Data_Bit(unsigned counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_Stale_Data_Bit;
|
||||
return G0_Stale_Data_Bit;
|
||||
}
|
||||
static inline enum Gxx_Status_Bits Gi_TC_Error_Bit(unsigned counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_TC_Error_Bit;
|
||||
return G0_TC_Error_Bit;
|
||||
}
|
||||
static inline enum Gxx_Status_Bits Gi_Gate_Error_Bit(unsigned counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_Gate_Error_Bit;
|
||||
return G0_Gate_Error_Bit;
|
||||
}
|
||||
|
||||
/* joint reset register bits */
|
||||
static inline unsigned Gi_Reset_Bit(unsigned counter_index)
|
||||
{
|
||||
return 0x1 << (2 + (counter_index % 2));
|
||||
}
|
||||
|
||||
enum Gxx_Joint_Status2_Bits {
|
||||
G0_Output_Bit = 0x1,
|
||||
G1_Output_Bit = 0x2,
|
||||
G0_HW_Save_Bit = 0x1000,
|
||||
G1_HW_Save_Bit = 0x2000,
|
||||
G0_Permanent_Stale_Bit = 0x4000,
|
||||
G1_Permanent_Stale_Bit = 0x8000
|
||||
};
|
||||
static inline enum Gxx_Joint_Status2_Bits Gi_Permanent_Stale_Bit(unsigned
|
||||
counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_Permanent_Stale_Bit;
|
||||
return G0_Permanent_Stale_Bit;
|
||||
}
|
||||
|
||||
enum Gi_DMA_Config_Reg_Bits {
|
||||
Gi_DMA_Enable_Bit = 0x1,
|
||||
Gi_DMA_Write_Bit = 0x2,
|
||||
Gi_DMA_Int_Bit = 0x4
|
||||
};
|
||||
|
||||
enum Gi_DMA_Status_Reg_Bits {
|
||||
Gi_DMA_Readbank_Bit = 0x2000,
|
||||
Gi_DRQ_Error_Bit = 0x4000,
|
||||
Gi_DRQ_Status_Bit = 0x8000
|
||||
};
|
||||
|
||||
enum G02_Interrupt_Acknowledge_Bits {
|
||||
G0_Gate_Error_Confirm_Bit = 0x20,
|
||||
G0_TC_Error_Confirm_Bit = 0x40
|
||||
};
|
||||
enum G13_Interrupt_Acknowledge_Bits {
|
||||
G1_Gate_Error_Confirm_Bit = 0x2,
|
||||
G1_TC_Error_Confirm_Bit = 0x4
|
||||
};
|
||||
static inline unsigned Gi_Gate_Error_Confirm_Bit(unsigned counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_Gate_Error_Confirm_Bit;
|
||||
return G0_Gate_Error_Confirm_Bit;
|
||||
}
|
||||
static inline unsigned Gi_TC_Error_Confirm_Bit(unsigned counter_index)
|
||||
{
|
||||
if (counter_index % 2)
|
||||
return G1_TC_Error_Confirm_Bit;
|
||||
return G0_TC_Error_Confirm_Bit;
|
||||
}
|
||||
|
||||
// bits that are the same in G0/G2 and G1/G3 interrupt acknowledge registers
|
||||
enum Gxx_Interrupt_Acknowledge_Bits {
|
||||
Gi_TC_Interrupt_Ack_Bit = 0x4000,
|
||||
Gi_Gate_Interrupt_Ack_Bit = 0x8000
|
||||
};
|
||||
|
||||
enum Gi_Status_Bits {
|
||||
Gi_Gate_Interrupt_Bit = 0x4,
|
||||
Gi_TC_Bit = 0x8,
|
||||
Gi_Interrupt_Bit = 0x8000
|
||||
};
|
||||
|
||||
enum G02_Interrupt_Enable_Bits {
|
||||
G0_TC_Interrupt_Enable_Bit = 0x40,
|
||||
G0_Gate_Interrupt_Enable_Bit = 0x100
|
||||
};
|
||||
enum G13_Interrupt_Enable_Bits {
|
||||
G1_TC_Interrupt_Enable_Bit = 0x200,
|
||||
G1_Gate_Interrupt_Enable_Bit = 0x400
|
||||
};
|
||||
static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index)
|
||||
{
|
||||
unsigned bit;
|
||||
|
||||
if (counter_index % 2) {
|
||||
bit = G1_Gate_Interrupt_Enable_Bit;
|
||||
} else {
|
||||
bit = G0_Gate_Interrupt_Enable_Bit;
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
|
||||
static inline void write_register(struct ni_gpct *counter, unsigned bits,
|
||||
enum ni_gpct_register reg)
|
||||
{
|
||||
BUG_ON(reg >= NITIO_Num_Registers);
|
||||
counter->counter_dev->write_register(counter, bits, reg);
|
||||
}
|
||||
|
||||
static inline unsigned read_register(struct ni_gpct *counter,
|
||||
enum ni_gpct_register reg)
|
||||
{
|
||||
BUG_ON(reg >= NITIO_Num_Registers);
|
||||
return counter->counter_dev->read_register(counter, reg);
|
||||
}
|
||||
|
||||
static inline int ni_tio_counting_mode_registers_present(
|
||||
const struct ni_gpct_device *counter_dev)
|
||||
{
|
||||
switch (counter_dev->variant) {
|
||||
case ni_gpct_variant_e_series:
|
||||
return 0;
|
||||
break;
|
||||
case ni_gpct_variant_m_series:
|
||||
case ni_gpct_variant_660x:
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ni_tio_set_bits_transient(struct ni_gpct *counter,
|
||||
enum ni_gpct_register register_index, unsigned bit_mask,
|
||||
unsigned bit_values, unsigned transient_bit_values)
|
||||
{
|
||||
struct ni_gpct_device *counter_dev = counter->counter_dev;
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(register_index >= NITIO_Num_Registers);
|
||||
comedi_spin_lock_irqsave(&counter_dev->regs_lock, flags);
|
||||
counter_dev->regs[register_index] &= ~bit_mask;
|
||||
counter_dev->regs[register_index] |= (bit_values & bit_mask);
|
||||
write_register(counter,
|
||||
counter_dev->regs[register_index] | transient_bit_values,
|
||||
register_index);
|
||||
mmiowb();
|
||||
comedi_spin_unlock_irqrestore(&counter_dev->regs_lock, flags);
|
||||
}
|
||||
|
||||
/* ni_tio_set_bits( ) is for safely writing to registers whose bits may be
|
||||
twiddled in interrupt context, or whose software copy may be read in interrupt context.
|
||||
*/
|
||||
static inline void ni_tio_set_bits(struct ni_gpct *counter,
|
||||
enum ni_gpct_register register_index, unsigned bit_mask,
|
||||
unsigned bit_values)
|
||||
{
|
||||
ni_tio_set_bits_transient(counter, register_index, bit_mask, bit_values,
|
||||
0x0);
|
||||
}
|
||||
|
||||
/* ni_tio_get_soft_copy( ) is for safely reading the software copy of a register
|
||||
whose bits might be modified in interrupt context, or whose software copy
|
||||
might need to be read in interrupt context.
|
||||
*/
|
||||
static inline unsigned ni_tio_get_soft_copy(const struct ni_gpct *counter,
|
||||
enum ni_gpct_register register_index)
|
||||
{
|
||||
struct ni_gpct_device *counter_dev = counter->counter_dev;
|
||||
unsigned long flags;
|
||||
unsigned value;
|
||||
|
||||
BUG_ON(register_index >= NITIO_Num_Registers);
|
||||
comedi_spin_lock_irqsave(&counter_dev->regs_lock, flags);
|
||||
value = counter_dev->regs[register_index];
|
||||
comedi_spin_unlock_irqrestore(&counter_dev->regs_lock, flags);
|
||||
return value;
|
||||
}
|
||||
|
||||
int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger);
|
||||
int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index,
|
||||
lsampl_t gate_source);
|
||||
|
||||
#endif /* _COMEDI_NI_TIO_INTERNAL_H */
|
|
@ -0,0 +1,523 @@
|
|||
/*
|
||||
comedi/drivers/ni_tiocmd.c
|
||||
Command support for NI general purpose counters
|
||||
|
||||
Copyright (C) 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
Driver: ni_tiocmd
|
||||
Description: National Instruments general purpose counters command support
|
||||
Devices:
|
||||
Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
|
||||
Herman.Bruyninckx@mech.kuleuven.ac.be,
|
||||
Wim.Meeussen@mech.kuleuven.ac.be,
|
||||
Klaas.Gadeyne@mech.kuleuven.ac.be,
|
||||
Frank Mori Hess <fmhess@users.sourceforge.net>
|
||||
Updated: Fri, 11 Apr 2008 12:32:35 +0100
|
||||
Status: works
|
||||
|
||||
This module is not used directly by end-users. Rather, it
|
||||
is used by other drivers (for example ni_660x and ni_pcimio)
|
||||
to provide command support for NI's general purpose counters.
|
||||
It was originally split out of ni_tio.c to stop the 'ni_tio'
|
||||
module depending on the 'mite' module.
|
||||
|
||||
References:
|
||||
DAQ 660x Register-Level Programmer Manual (NI 370505A-01)
|
||||
DAQ 6601/6602 User Manual (NI 322137B-01)
|
||||
340934b.pdf DAQ-STC reference manual
|
||||
|
||||
*/
|
||||
/*
|
||||
TODO:
|
||||
Support use of both banks X and Y
|
||||
*/
|
||||
|
||||
#include "ni_tio_internal.h"
|
||||
#include "mite.h"
|
||||
|
||||
MODULE_AUTHOR("Comedi <comedi@comedi.org>");
|
||||
MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static void ni_tio_configure_dma(struct ni_gpct *counter, short enable,
|
||||
short read_not_write)
|
||||
{
|
||||
struct ni_gpct_device *counter_dev = counter->counter_dev;
|
||||
unsigned input_select_bits = 0;
|
||||
|
||||
if (enable) {
|
||||
if (read_not_write) {
|
||||
input_select_bits |= Gi_Read_Acknowledges_Irq;
|
||||
} else {
|
||||
input_select_bits |= Gi_Write_Acknowledges_Irq;
|
||||
}
|
||||
}
|
||||
ni_tio_set_bits(counter,
|
||||
NITIO_Gi_Input_Select_Reg(counter->counter_index),
|
||||
Gi_Read_Acknowledges_Irq | Gi_Write_Acknowledges_Irq,
|
||||
input_select_bits);
|
||||
switch (counter_dev->variant) {
|
||||
case ni_gpct_variant_e_series:
|
||||
break;
|
||||
case ni_gpct_variant_m_series:
|
||||
case ni_gpct_variant_660x:
|
||||
{
|
||||
unsigned gi_dma_config_bits = 0;
|
||||
|
||||
if (enable) {
|
||||
gi_dma_config_bits |= Gi_DMA_Enable_Bit;
|
||||
gi_dma_config_bits |= Gi_DMA_Int_Bit;
|
||||
}
|
||||
if (read_not_write == 0) {
|
||||
gi_dma_config_bits |= Gi_DMA_Write_Bit;
|
||||
}
|
||||
ni_tio_set_bits(counter,
|
||||
NITIO_Gi_DMA_Config_Reg(counter->counter_index),
|
||||
Gi_DMA_Enable_Bit | Gi_DMA_Int_Bit |
|
||||
Gi_DMA_Write_Bit, gi_dma_config_bits);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ni_tio_input_inttrig(comedi_device * dev, comedi_subdevice * s,
|
||||
unsigned int trignum)
|
||||
{
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
struct ni_gpct *counter = s->private;
|
||||
|
||||
BUG_ON(counter == NULL);
|
||||
if (trignum != 0)
|
||||
return -EINVAL;
|
||||
|
||||
comedi_spin_lock_irqsave(&counter->lock, flags);
|
||||
if (counter->mite_chan)
|
||||
mite_dma_arm(counter->mite_chan);
|
||||
else
|
||||
retval = -EIO;
|
||||
comedi_spin_unlock_irqrestore(&counter->lock, flags);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
retval = ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
|
||||
s->async->inttrig = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ni_tio_input_cmd(struct ni_gpct *counter, comedi_async * async)
|
||||
{
|
||||
struct ni_gpct_device *counter_dev = counter->counter_dev;
|
||||
comedi_cmd *cmd = &async->cmd;
|
||||
int retval = 0;
|
||||
|
||||
/* write alloc the entire buffer */
|
||||
comedi_buf_write_alloc(async, async->prealloc_bufsz);
|
||||
counter->mite_chan->dir = COMEDI_INPUT;
|
||||
switch (counter_dev->variant) {
|
||||
case ni_gpct_variant_m_series:
|
||||
case ni_gpct_variant_660x:
|
||||
mite_prep_dma(counter->mite_chan, 32, 32);
|
||||
break;
|
||||
case ni_gpct_variant_e_series:
|
||||
mite_prep_dma(counter->mite_chan, 16, 32);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index),
|
||||
Gi_Save_Trace_Bit, 0);
|
||||
ni_tio_configure_dma(counter, 1, 1);
|
||||
switch (cmd->start_src) {
|
||||
case TRIG_NOW:
|
||||
async->inttrig = NULL;
|
||||
mite_dma_arm(counter->mite_chan);
|
||||
retval = ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
|
||||
break;
|
||||
case TRIG_INT:
|
||||
async->inttrig = &ni_tio_input_inttrig;
|
||||
break;
|
||||
case TRIG_EXT:
|
||||
async->inttrig = NULL;
|
||||
mite_dma_arm(counter->mite_chan);
|
||||
retval = ni_tio_arm(counter, 1, cmd->start_arg);
|
||||
case TRIG_OTHER:
|
||||
async->inttrig = NULL;
|
||||
mite_dma_arm(counter->mite_chan);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ni_tio_output_cmd(struct ni_gpct *counter, comedi_async * async)
|
||||
{
|
||||
rt_printk("ni_tio: output commands not yet implemented.\n");
|
||||
return -ENOTSUPP;
|
||||
|
||||
counter->mite_chan->dir = COMEDI_OUTPUT;
|
||||
mite_prep_dma(counter->mite_chan, 32, 32);
|
||||
ni_tio_configure_dma(counter, 1, 0);
|
||||
mite_dma_arm(counter->mite_chan);
|
||||
return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
|
||||
}
|
||||
|
||||
static int ni_tio_cmd_setup(struct ni_gpct *counter, comedi_async * async)
|
||||
{
|
||||
comedi_cmd *cmd = &async->cmd;
|
||||
int set_gate_source = 0;
|
||||
unsigned gate_source;
|
||||
int retval = 0;
|
||||
|
||||
if (cmd->scan_begin_src == TRIG_EXT) {
|
||||
set_gate_source = 1;
|
||||
gate_source = cmd->scan_begin_arg;
|
||||
} else if (cmd->convert_src == TRIG_EXT) {
|
||||
set_gate_source = 1;
|
||||
gate_source = cmd->convert_arg;
|
||||
}
|
||||
if (set_gate_source) {
|
||||
retval = ni_tio_set_gate_src(counter, 0, gate_source);
|
||||
}
|
||||
if (cmd->flags & TRIG_WAKE_EOS) {
|
||||
ni_tio_set_bits(counter,
|
||||
NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index),
|
||||
Gi_Gate_Interrupt_Enable_Bit(counter->counter_index),
|
||||
Gi_Gate_Interrupt_Enable_Bit(counter->counter_index));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ni_tio_cmd(struct ni_gpct *counter, comedi_async * async)
|
||||
{
|
||||
comedi_cmd *cmd = &async->cmd;
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
|
||||
comedi_spin_lock_irqsave(&counter->lock, flags);
|
||||
if (counter->mite_chan == NULL) {
|
||||
rt_printk
|
||||
("ni_tio: commands only supported with DMA. Interrupt-driven commands not yet implemented.\n");
|
||||
retval = -EIO;
|
||||
} else {
|
||||
retval = ni_tio_cmd_setup(counter, async);
|
||||
if (retval == 0) {
|
||||
if (cmd->flags & CMDF_WRITE) {
|
||||
retval = ni_tio_output_cmd(counter, async);
|
||||
} else {
|
||||
retval = ni_tio_input_cmd(counter, async);
|
||||
}
|
||||
}
|
||||
}
|
||||
comedi_spin_unlock_irqrestore(&counter->lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ni_tio_cmdtest(struct ni_gpct *counter, comedi_cmd * cmd)
|
||||
{
|
||||
int err = 0;
|
||||
int tmp;
|
||||
int sources;
|
||||
|
||||
/* step 1: make sure trigger sources are trivially valid */
|
||||
|
||||
tmp = cmd->start_src;
|
||||
sources = TRIG_NOW | TRIG_INT | TRIG_OTHER;
|
||||
if (ni_tio_counting_mode_registers_present(counter->counter_dev))
|
||||
sources |= TRIG_EXT;
|
||||
cmd->start_src &= sources;
|
||||
if (!cmd->start_src || tmp != cmd->start_src)
|
||||
err++;
|
||||
|
||||
tmp = cmd->scan_begin_src;
|
||||
cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER;
|
||||
if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
|
||||
err++;
|
||||
|
||||
tmp = cmd->convert_src;
|
||||
sources = TRIG_NOW | TRIG_EXT | TRIG_OTHER;
|
||||
cmd->convert_src &= sources;
|
||||
if (!cmd->convert_src || tmp != cmd->convert_src)
|
||||
err++;
|
||||
|
||||
tmp = cmd->scan_end_src;
|
||||
cmd->scan_end_src &= TRIG_COUNT;
|
||||
if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
|
||||
err++;
|
||||
|
||||
tmp = cmd->stop_src;
|
||||
cmd->stop_src &= TRIG_NONE;
|
||||
if (!cmd->stop_src || tmp != cmd->stop_src)
|
||||
err++;
|
||||
|
||||
if (err)
|
||||
return 1;
|
||||
|
||||
/* step 2: make sure trigger sources are unique... */
|
||||
|
||||
if (cmd->start_src != TRIG_NOW &&
|
||||
cmd->start_src != TRIG_INT &&
|
||||
cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_OTHER)
|
||||
err++;
|
||||
if (cmd->scan_begin_src != TRIG_FOLLOW &&
|
||||
cmd->scan_begin_src != TRIG_EXT &&
|
||||
cmd->scan_begin_src != TRIG_OTHER)
|
||||
err++;
|
||||
if (cmd->convert_src != TRIG_OTHER &&
|
||||
cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW)
|
||||
err++;
|
||||
if (cmd->stop_src != TRIG_NONE)
|
||||
err++;
|
||||
/* ... and mutually compatible */
|
||||
if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW)
|
||||
err++;
|
||||
|
||||
if (err)
|
||||
return 2;
|
||||
|
||||
/* step 3: make sure arguments are trivially compatible */
|
||||
if (cmd->start_src != TRIG_EXT) {
|
||||
if (cmd->start_arg != 0) {
|
||||
cmd->start_arg = 0;
|
||||
err++;
|
||||
}
|
||||
}
|
||||
if (cmd->scan_begin_src != TRIG_EXT) {
|
||||
if (cmd->scan_begin_arg) {
|
||||
cmd->scan_begin_arg = 0;
|
||||
err++;
|
||||
}
|
||||
}
|
||||
if (cmd->convert_src != TRIG_EXT) {
|
||||
if (cmd->convert_arg) {
|
||||
cmd->convert_arg = 0;
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->scan_end_arg != cmd->chanlist_len) {
|
||||
cmd->scan_end_arg = cmd->chanlist_len;
|
||||
err++;
|
||||
}
|
||||
|
||||
if (cmd->stop_src == TRIG_NONE) {
|
||||
if (cmd->stop_arg != 0) {
|
||||
cmd->stop_arg = 0;
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
return 3;
|
||||
|
||||
/* step 4: fix up any arguments */
|
||||
|
||||
if (err)
|
||||
return 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ni_tio_cancel(struct ni_gpct *counter)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
ni_tio_arm(counter, 0, 0);
|
||||
comedi_spin_lock_irqsave(&counter->lock, flags);
|
||||
if (counter->mite_chan) {
|
||||
mite_dma_disarm(counter->mite_chan);
|
||||
}
|
||||
comedi_spin_unlock_irqrestore(&counter->lock, flags);
|
||||
ni_tio_configure_dma(counter, 0, 0);
|
||||
|
||||
ni_tio_set_bits(counter,
|
||||
NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index),
|
||||
Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), 0x0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* During buffered input counter operation for e-series, the gate interrupt is acked
|
||||
automatically by the dma controller, due to the Gi_Read/Write_Acknowledges_IRQ bits
|
||||
in the input select register. */
|
||||
static int should_ack_gate(struct ni_gpct *counter)
|
||||
{
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
|
||||
switch (counter->counter_dev->variant) {
|
||||
case ni_gpct_variant_m_series:
|
||||
case ni_gpct_variant_660x: // not sure if 660x really supports gate interrupts (the bits are not listed in register-level manual)
|
||||
return 1;
|
||||
break;
|
||||
case ni_gpct_variant_e_series:
|
||||
comedi_spin_lock_irqsave(&counter->lock, flags);
|
||||
{
|
||||
if (counter->mite_chan == NULL ||
|
||||
counter->mite_chan->dir != COMEDI_INPUT ||
|
||||
(mite_done(counter->mite_chan))) {
|
||||
retval = 1;
|
||||
}
|
||||
}
|
||||
comedi_spin_unlock_irqrestore(&counter->lock, flags);
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error,
|
||||
int *tc_error, int *perm_stale_data, int *stale_data)
|
||||
{
|
||||
const unsigned short gxx_status = read_register(counter,
|
||||
NITIO_Gxx_Status_Reg(counter->counter_index));
|
||||
const unsigned short gi_status = read_register(counter,
|
||||
NITIO_Gi_Status_Reg(counter->counter_index));
|
||||
unsigned ack = 0;
|
||||
|
||||
if (gate_error)
|
||||
*gate_error = 0;
|
||||
if (tc_error)
|
||||
*tc_error = 0;
|
||||
if (perm_stale_data)
|
||||
*perm_stale_data = 0;
|
||||
if (stale_data)
|
||||
*stale_data = 0;
|
||||
|
||||
if (gxx_status & Gi_Gate_Error_Bit(counter->counter_index)) {
|
||||
ack |= Gi_Gate_Error_Confirm_Bit(counter->counter_index);
|
||||
if (gate_error) {
|
||||
/*660x don't support automatic acknowledgement of gate interrupt via dma read/write
|
||||
and report bogus gate errors */
|
||||
if (counter->counter_dev->variant !=
|
||||
ni_gpct_variant_660x) {
|
||||
*gate_error = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gxx_status & Gi_TC_Error_Bit(counter->counter_index)) {
|
||||
ack |= Gi_TC_Error_Confirm_Bit(counter->counter_index);
|
||||
if (tc_error)
|
||||
*tc_error = 1;
|
||||
}
|
||||
if (gi_status & Gi_TC_Bit) {
|
||||
ack |= Gi_TC_Interrupt_Ack_Bit;
|
||||
}
|
||||
if (gi_status & Gi_Gate_Interrupt_Bit) {
|
||||
if (should_ack_gate(counter))
|
||||
ack |= Gi_Gate_Interrupt_Ack_Bit;
|
||||
}
|
||||
if (ack)
|
||||
write_register(counter, ack,
|
||||
NITIO_Gi_Interrupt_Acknowledge_Reg(counter->
|
||||
counter_index));
|
||||
if (ni_tio_get_soft_copy(counter,
|
||||
NITIO_Gi_Mode_Reg(counter->
|
||||
counter_index)) & Gi_Loading_On_Gate_Bit) {
|
||||
if (gxx_status & Gi_Stale_Data_Bit(counter->counter_index)) {
|
||||
if (stale_data)
|
||||
*stale_data = 1;
|
||||
}
|
||||
if (read_register(counter,
|
||||
NITIO_Gxx_Joint_Status2_Reg(counter->
|
||||
counter_index)) &
|
||||
Gi_Permanent_Stale_Bit(counter->counter_index)) {
|
||||
rt_printk("%s: Gi_Permanent_Stale_Data detected.\n",
|
||||
__FUNCTION__);
|
||||
if (perm_stale_data)
|
||||
*perm_stale_data = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ni_tio_handle_interrupt(struct ni_gpct *counter, comedi_subdevice * s)
|
||||
{
|
||||
unsigned gpct_mite_status;
|
||||
unsigned long flags;
|
||||
int gate_error;
|
||||
int tc_error;
|
||||
int perm_stale_data;
|
||||
|
||||
ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error,
|
||||
&perm_stale_data, NULL);
|
||||
if (gate_error) {
|
||||
rt_printk("%s: Gi_Gate_Error detected.\n", __FUNCTION__);
|
||||
s->async->events |= COMEDI_CB_OVERFLOW;
|
||||
}
|
||||
if (perm_stale_data) {
|
||||
s->async->events |= COMEDI_CB_ERROR;
|
||||
}
|
||||
switch (counter->counter_dev->variant) {
|
||||
case ni_gpct_variant_m_series:
|
||||
case ni_gpct_variant_660x:
|
||||
if (read_register(counter,
|
||||
NITIO_Gi_DMA_Status_Reg(counter->
|
||||
counter_index)) & Gi_DRQ_Error_Bit) {
|
||||
rt_printk("%s: Gi_DRQ_Error detected.\n", __FUNCTION__);
|
||||
s->async->events |= COMEDI_CB_OVERFLOW;
|
||||
}
|
||||
break;
|
||||
case ni_gpct_variant_e_series:
|
||||
break;
|
||||
}
|
||||
comedi_spin_lock_irqsave(&counter->lock, flags);
|
||||
if (counter->mite_chan == NULL) {
|
||||
comedi_spin_unlock_irqrestore(&counter->lock, flags);
|
||||
return;
|
||||
}
|
||||
gpct_mite_status = mite_get_status(counter->mite_chan);
|
||||
if (gpct_mite_status & CHSR_LINKC) {
|
||||
writel(CHOR_CLRLC,
|
||||
counter->mite_chan->mite->mite_io_addr +
|
||||
MITE_CHOR(counter->mite_chan->channel));
|
||||
}
|
||||
mite_sync_input_dma(counter->mite_chan, s->async);
|
||||
comedi_spin_unlock_irqrestore(&counter->lock, flags);
|
||||
}
|
||||
|
||||
void ni_tio_set_mite_channel(struct ni_gpct *counter,
|
||||
struct mite_channel *mite_chan)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
comedi_spin_lock_irqsave(&counter->lock, flags);
|
||||
counter->mite_chan = mite_chan;
|
||||
comedi_spin_unlock_irqrestore(&counter->lock, flags);
|
||||
}
|
||||
|
||||
static int __init ni_tiocmd_init_module(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(ni_tiocmd_init_module);
|
||||
|
||||
static void __exit ni_tiocmd_cleanup_module(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_exit(ni_tiocmd_cleanup_module);
|
||||
|
||||
EXPORT_SYMBOL_GPL(ni_tio_cmd);
|
||||
EXPORT_SYMBOL_GPL(ni_tio_cmdtest);
|
||||
EXPORT_SYMBOL_GPL(ni_tio_cancel);
|
||||
EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt);
|
||||
EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel);
|
||||
EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm);
|
Loading…
Reference in New Issue