From fb5bae234cbfc4b2d511fe477f41637e1e8d1ce1 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 11 Apr 2008 15:54:27 +0000 Subject: [PATCH] Stopped the 'ni_atmio' and 'ni_mio_cs' drivers depending on the 'mite' module indirectly. The 'ni_tio' module has been split into two modules, 'ni_tio' and 'ni_tiocmd'. The 'ni_tiocmd' module has the command processing that depends on the 'mite' module. The 'ni_tio' module no longer depends on 'mite'. Also fixed some .symvers dependencies for non-Kbuild builds. --- comedi/drivers/Kbuild | 1 + comedi/drivers/Makefile.am | 40 +- comedi/drivers/ni_tio.c | 1228 +----------------------------- comedi/drivers/ni_tio_internal.h | 774 +++++++++++++++++++ comedi/drivers/ni_tiocmd.c | 510 +++++++++++++ 5 files changed, 1322 insertions(+), 1231 deletions(-) create mode 100644 comedi/drivers/ni_tio_internal.h create mode 100644 comedi/drivers/ni_tiocmd.c diff --git a/comedi/drivers/Kbuild b/comedi/drivers/Kbuild index 49030164..da209dff 100644 --- a/comedi/drivers/Kbuild +++ b/comedi/drivers/Kbuild @@ -57,6 +57,7 @@ obj-$(CONFIG_COMEDI_PCI_MODULES) += ni_660x.o obj-$(CONFIG_COMEDI_PCI_MODULES) += ni_670x.o obj-$(CONFIG_COMEDI_PCI_MODULES) += ni_pcidio.o obj-$(CONFIG_COMEDI_PCI_MODULES) += ni_pcimio.o +obj-$(CONFIG_COMEDI_PCI_MODULES) += ni_tiocmd.o obj-$(CONFIG_COMEDI_PCI_MODULES) += rtd520.o obj-$(CONFIG_COMEDI_PCI_MODULES) += s626.o diff --git a/comedi/drivers/Makefile.am b/comedi/drivers/Makefile.am index 91370823..85b7a1b0 100644 --- a/comedi/drivers/Makefile.am +++ b/comedi/drivers/Makefile.am @@ -4,25 +4,41 @@ SUBDIRS = addi-data AM_CFLAGS = $(COMEDI_CFLAGS) $(LINUX_CFLAGS) $(RTAI_CFLAGS) $(RTLINUX_CFLAGS) LINK = $(top_builddir)/modtool --link -o $@ \ -i ../.mods/comedi.o.symvers \ + -i ../kcomedilib/.mods/kcomedilib.o.symvers \ -i .mods/8255.o.symvers \ -i .mods/comedi_fc.o.symvers \ + -i .mods/ni_tio.o.symvers \ -i .mods/das08.o.symvers \ + -i .mods/ni_labpc.o.symvers +if CONFIG_COMEDI_PCI +LINK += \ -i .mods/mite.o.symvers \ - -i .mods/ni_labpc.o.symvers \ - -i .mods/ni_tio.o.symvers + -i .mods/ni_tiocmd.o.symvers +endif 8255_ko_LINK = $(top_builddir)/modtool --link -o $@ \ -i ../.mods/comedi.o.symvers comedi_fc_ko_LINK = $(top_builddir)/modtool --link -o $@ \ -i ../.mods/comedi.o.symvers das08_ko_LINK = $(top_builddir)/modtool --link -o $@ \ - -i ../.mods/comedi.o.symvers + -i ../.mods/comedi.o.symvers \ + -i .mods/8255.o.symvers mite_ko_LINK = $(top_builddir)/modtool --link -o $@ \ -i ../.mods/comedi.o.symvers ni_labpc_ko_LINK = $(top_builddir)/modtool --link -o $@ \ - -i ../.mods/comedi.o.symvers + -i ../.mods/comedi.o.symvers \ + -i .mods/8255.o.symvers \ + -i .mods/comedi_fc.o.symvers +if CONFIG_COMEDI_PCI +ni_labpc_ko_LINK += \ + -i .mods/mite.o.symvers +endif ni_tio_ko_LINK = $(top_builddir)/modtool --link -o $@ \ -i ../.mods/comedi.o.symvers +ni_tiocmd_ko_LINK = $(top_builddir)/modtool --link -o $@ \ + -i ../.mods/comedi.o.symvers \ + -i .mods/ni_tio.o.symvers \ + -i .mods/mite.o.symvers 8255_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB comedi_fc_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB @@ -30,6 +46,7 @@ das08_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB mite_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB ni_labpc_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB ni_tio_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB +ni_tiocmd_ko_CFLAGS = $(AM_CFLAGS) -DEXPORT_SYMTAB EXTRA_DIST = \ @@ -54,6 +71,7 @@ EXTRA_DIST = \ ni_mio_common.c \ ni_stc.h \ ni_tio.h \ + ni_tio_internal.h \ plx9052.h \ plx9080.h \ rtd520.h \ @@ -68,8 +86,11 @@ rt_modules = endif if CONFIG_COMEDI_PCI -pci_modules= \ +# split to build modules in correct order (for non-Kbuild builds) +pci_modules1= \ mite.ko \ + ni_tiocmd.ko +pci_modules2= \ addi_apci_035.ko \ addi_apci_1032.ko \ addi_apci_1500.ko \ @@ -119,7 +140,8 @@ pci_modules= \ rtd520.ko \ s626.ko else -pci_modules= +pci_modules1= +pci_modules2= endif @@ -152,6 +174,8 @@ module_PROGRAMS = \ 8255.ko \ comedi_fc.ko \ das08.ko \ + ni_tio.ko \ + $(pci_modules1) \ ni_labpc.ko \ acl7225b.ko \ adq12b.ko \ @@ -181,7 +205,6 @@ module_PROGRAMS = \ ni_atmio16d.ko \ ni_at_a2150.ko \ ni_at_ao.ko \ - ni_tio.ko \ pcm3724.ko \ pcm3730.ko \ pcmad.ko \ @@ -206,7 +229,7 @@ module_PROGRAMS = \ s526.ko \ comedi_test.ko \ unioxx5.ko \ - $(pci_modules) \ + $(pci_modules2) \ $(pcmcia_modules) \ $(usb_modules) \ $(rt_modules) @@ -303,6 +326,7 @@ ni_daq_700_ko_SOURCES = ni_daq_700.c ni_daq_dio24_ko_SOURCES = ni_daq_dio24.c ni_at_ao_ko_SOURCES = ni_at_ao.c ni_tio_ko_SOURCES = ni_tio.c +ni_tiocmd_ko_SOURCES = ni_tiocmd.c pcm3724_ko_SOURCES = pcm3724.c pcm3730_ko_SOURCES = pcm3730.c pcmad_ko_SOURCES = pcmad.c diff --git a/comedi/drivers/ni_tio.c b/comedi/drivers/ni_tio.c index 480147aa..f2fd095c 100644 --- a/comedi/drivers/ni_tio.c +++ b/comedi/drivers/ni_tio.c @@ -48,8 +48,7 @@ TODO: Support use of both banks X and Y */ -#include "ni_tio.h" -#include "mite.h" +#include "ni_tio_internal.h" static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter, unsigned generic_clock_source); @@ -59,463 +58,6 @@ MODULE_AUTHOR("Comedi "); MODULE_DESCRIPTION("Comedi support for NI general-purpose counters"); MODULE_LICENSE("GPL"); -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, -}; static inline enum Gi_Counting_Mode_Reg_Bits Gi_Alternate_Sync_Bit(enum ni_gpct_variant variant) { @@ -691,18 +233,6 @@ static inline unsigned NI_M_Series_PFI_Gate_Select(unsigned n) return 0xb + n; } -#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 */ -}; static inline unsigned Gi_Source_Select_Bits(unsigned source) { return (source << Gi_Source_Select_Shift) & Gi_Source_Select_Mask; @@ -712,38 +242,6 @@ static inline unsigned Gi_Gate_Select_Bits(unsigned gate_select) return (gate_select << Gi_Gate_Select_Shift) & Gi_Gate_Select_Mask; } -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 -}; - enum ni_660x_second_gate_select { NI_660x_Source_Pin_i_Second_Gate_Select = 0x0, NI_660x_Up_Down_Pin_i_Second_Gate_Select = 0x1, @@ -764,181 +262,9 @@ static inline unsigned NI_660x_RTSI_Second_Gate_Select(unsigned n) return 0xb + n; } -#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 const lsampl_t counter_status_mask = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING; -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 int __init ni_tio_init_module(void) { return 0; @@ -993,24 +319,6 @@ void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev) kfree(counter_dev); } -static 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 int ni_tio_second_gate_registers_present(const struct ni_gpct_device *counter_dev) { @@ -1029,53 +337,6 @@ static int ni_tio_second_gate_registers_present(const struct ni_gpct_device 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; -} - static void ni_tio_reset_count_and_disarm(struct ni_gpct *counter) { write_register(counter, Gi_Reset_Bit(counter->counter_index), @@ -1246,7 +507,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) return 0; } -static int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) +int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) { struct ni_gpct_device *counter_dev = counter->counter_dev; @@ -1914,7 +1175,7 @@ static int ni_m_series_set_second_gate(struct ni_gpct *counter, return 0; } -static int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, +int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, lsampl_t gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; @@ -2420,490 +1681,11 @@ int ni_tio_winsn(struct ni_gpct *counter, comedi_insn * insn, lsampl_t * data) return 0; } -#ifdef CONFIG_COMEDI_PCI -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; - } -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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; -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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; -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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); -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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; -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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; -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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; -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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; -} -#endif - - /* 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. */ -#ifdef CONFIG_COMEDI_PCI -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; -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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; - } - } -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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); -} -#endif - -#ifdef CONFIG_COMEDI_PCI -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); -} -#endif - EXPORT_SYMBOL_GPL(ni_tio_rinsn); EXPORT_SYMBOL_GPL(ni_tio_winsn); -#ifdef CONFIG_COMEDI_PCI -EXPORT_SYMBOL_GPL(ni_tio_cmd); -EXPORT_SYMBOL_GPL(ni_tio_cmdtest); -EXPORT_SYMBOL_GPL(ni_tio_cancel); -#endif EXPORT_SYMBOL_GPL(ni_tio_insn_config); EXPORT_SYMBOL_GPL(ni_tio_init_counter); +EXPORT_SYMBOL_GPL(ni_tio_arm); +EXPORT_SYMBOL_GPL(ni_tio_set_gate_src); EXPORT_SYMBOL_GPL(ni_gpct_device_construct); EXPORT_SYMBOL_GPL(ni_gpct_device_destroy); -#ifdef CONFIG_COMEDI_PCI -EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt); -EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel); -EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm); -#endif diff --git a/comedi/drivers/ni_tio_internal.h b/comedi/drivers/ni_tio_internal.h new file mode 100644 index 00000000..e5aa578f --- /dev/null +++ b/comedi/drivers/ni_tio_internal.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 */ diff --git a/comedi/drivers/ni_tiocmd.c b/comedi/drivers/ni_tiocmd.c new file mode 100644 index 00000000..408a6838 --- /dev/null +++ b/comedi/drivers/ni_tiocmd.c @@ -0,0 +1,510 @@ +/* + comedi/drivers/ni_tiocmd.c + Command support for NI general purpose counters + + Copyright (C) 2006 Frank Mori Hess + + 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 , + Herman.Bruyninckx@mech.kuleuven.ac.be, + Wim.Meeussen@mech.kuleuven.ac.be, + Klaas.Gadeyne@mech.kuleuven.ac.be, + Frank Mori Hess +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 "); +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); +} + +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); -- 2.26.2