[PATCH 001/107] staging: comedi: ni_mio_common: refactor m-series stc register handling

H Hartley Sweeten hsweeten at visionengravers.com
Fri May 1 21:58:26 UTC 2015


For M-Series boards (devpriv->is_m_series), the STC registers need to be
remapped. This is currently handled with some big switch statements to
convert the STC register offset to the M-Series offset. Some of the
registers also need special handling due to differences in the register
size on the M-Series boards.

Create some lookup tables to handle the remapping of the read and write
registers. These are easier to maintain and can contain the register size
so that a common function can be used instead of the separate helpers.

Signed-off-by: H Hartley Sweeten <hsweeten at visionengravers.com>
Cc: Ian Abbott <abbotti at mev.co.uk>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
---
 drivers/staging/comedi/drivers/ni_mio_common.c | 352 ++++++++-----------------
 1 file changed, 115 insertions(+), 237 deletions(-)

diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 69d71f3..ecfd097 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -308,262 +308,140 @@ static uint8_t ni_readb(struct comedi_device *dev, int reg)
  * windowed STC registers to the m series register offsets.
  */
 
-static void m_series_stc_writel(struct comedi_device *dev,
-				uint32_t data, int reg)
+struct mio_regmap {
+	unsigned int mio_reg;
+	int size;
+};
+
+static const struct mio_regmap m_series_stc_write_regmap[] = {
+	[Interrupt_A_Ack_Register]	= { M_Offset_Interrupt_A_Ack, 2 },
+	[Interrupt_B_Ack_Register]	= { M_Offset_Interrupt_B_Ack, 2 },
+	[AI_Command_2_Register]		= { M_Offset_AI_Command_2, 2 },
+	[AO_Command_2_Register]		= { M_Offset_AO_Command_2, 2 },
+	[G_Command_Register(0)]		= { M_Offset_G0_Command, 2 },
+	[G_Command_Register(1)]		= { M_Offset_G1_Command, 2 },
+	[AI_Command_1_Register]		= { M_Offset_AI_Command_1, 2 },
+	[AO_Command_1_Register]		= { M_Offset_AO_Command_1, 2 },
+	[DIO_Output_Register]		= { 0, 0 }, /* DOES NOT MAP CLEANLY */
+					/*
+					 * DIO_Output_Register maps to:
+					 * { M_Offset_Static_Digital_Output, 4 }
+					 * { M_Offset_SCXI_Serial_Data_Out, 1 }
+					 */
+	[DIO_Control_Register]		= { 0, 0 }, /* DOES NOT MAP CLEANLY */
+	[AI_Mode_1_Register]		= { M_Offset_AI_Mode_1, 2 },
+	[AI_Mode_2_Register]		= { M_Offset_AI_Mode_2, 2 },
+	[AI_SI_Load_A_Registers]	= { M_Offset_AI_SI_Load_A, 4 },
+	[AI_SC_Load_A_Registers]	= { M_Offset_AI_SC_Load_A, 4 },
+	[AI_SI2_Load_A_Register]	= { M_Offset_AI_SI2_Load_A, 4 },
+	[AI_SI2_Load_B_Register]	= { M_Offset_AI_SI2_Load_B, 4 },
+	[G_Mode_Register(0)]		= { M_Offset_G0_Mode, 2 },
+	[G_Mode_Register(1)]		= { M_Offset_G1_Mode, 2 },
+	[G_Load_A_Register(0)]		= { M_Offset_G0_Load_A, 4 },
+	[G_Load_B_Register(0)]		= { M_Offset_G0_Load_B, 4 },
+	[G_Load_A_Register(1)]		= { M_Offset_G1_Load_A, 4 },
+	[G_Load_B_Register(1)]		= { M_Offset_G1_Load_B, 4 },
+	[G_Input_Select_Register(0)]	= { M_Offset_G0_Input_Select, 2 },
+	[G_Input_Select_Register(1)]	= { M_Offset_G1_Input_Select, 2 },
+	[AO_Mode_1_Register]		= { M_Offset_AO_Mode_1, 2 },
+	[AO_Mode_2_Register]		= { M_Offset_AO_Mode_2, 2 },
+	[AO_UI_Load_A_Register]		= { M_Offset_AO_UI_Load_A, 4 },
+	[AO_BC_Load_A_Register]		= { M_Offset_AO_BC_Load_A, 4 },
+	[AO_UC_Load_A_Register]		= { M_Offset_AO_UC_Load_A, 4 },
+	[Clock_and_FOUT_Register]	= { M_Offset_Clock_and_FOUT, 2 },
+	[IO_Bidirection_Pin_Register]	= { M_Offset_IO_Bidirection_Pin, 2 },
+	[RTSI_Trig_Direction_Register]	= { M_Offset_RTSI_Trig_Direction, 2 },
+	[Interrupt_Control_Register]	= { M_Offset_Interrupt_Control, 2 },
+	[AI_Output_Control_Register]	= { M_Offset_AI_Output_Control, 2 },
+	[Analog_Trigger_Etc_Register]	= { M_Offset_Analog_Trigger_Etc, 2 },
+	[AI_START_STOP_Select_Register]	= { M_Offset_AI_START_STOP_Select, 2 },
+	[AI_Trigger_Select_Register]	= { M_Offset_AI_Trigger_Select, 2 },
+	[AO_Start_Select_Register]	= { M_Offset_AO_Start_Select, 2 },
+	[AO_Trigger_Select_Register]	= { M_Offset_AO_Trigger_Select, 2 },
+	[G_Autoincrement_Register(0)]	= { M_Offset_G0_Autoincrement, 2 },
+	[G_Autoincrement_Register(1)]	= { M_Offset_G1_Autoincrement, 2 },
+	[AO_Mode_3_Register]		= { M_Offset_AO_Mode_3, 2 },
+	[Joint_Reset_Register]		= { M_Offset_Joint_Reset, 2 },
+	[Interrupt_A_Enable_Register]	= { M_Offset_Interrupt_A_Enable, 2 },
+	[Interrupt_B_Enable_Register]	= { M_Offset_Interrupt_B_Enable, 2 },
+	[AI_Personal_Register]		= { M_Offset_AI_Personal, 2 },
+	[AO_Personal_Register]		= { M_Offset_AO_Personal, 2 },
+	[RTSI_Trig_A_Output_Register]	= { M_Offset_RTSI_Trig_A_Output, 2 },
+	[RTSI_Trig_B_Output_Register]	= { M_Offset_RTSI_Trig_B_Output, 2 },
+	[Configuration_Memory_Clear]	= { M_Offset_Configuration_Memory_Clear,
+					    2 },
+	[ADC_FIFO_Clear]		= { M_Offset_AI_FIFO_Clear, 2 },
+	[DAC_FIFO_Clear]		= { M_Offset_AO_FIFO_Clear, 2 },
+	[AO_Output_Control_Register]	= { M_Offset_AO_Output_Control, 2 },
+	[AI_Mode_3_Register]		= { M_Offset_AI_Mode_3, 2 },
+};
+
+static void m_series_stc_write(struct comedi_device *dev,
+			       unsigned int data, unsigned int reg)
 {
-	unsigned offset;
+	const struct mio_regmap *regmap;
 
-	switch (reg) {
-	case AI_SC_Load_A_Registers:
-		offset = M_Offset_AI_SC_Load_A;
-		break;
-	case AI_SI_Load_A_Registers:
-		offset = M_Offset_AI_SI_Load_A;
-		break;
-	case AO_BC_Load_A_Register:
-		offset = M_Offset_AO_BC_Load_A;
-		break;
-	case AO_UC_Load_A_Register:
-		offset = M_Offset_AO_UC_Load_A;
-		break;
-	case AO_UI_Load_A_Register:
-		offset = M_Offset_AO_UI_Load_A;
-		break;
-	case G_Load_A_Register(0):
-		offset = M_Offset_G0_Load_A;
-		break;
-	case G_Load_A_Register(1):
-		offset = M_Offset_G1_Load_A;
-		break;
-	case G_Load_B_Register(0):
-		offset = M_Offset_G0_Load_B;
-		break;
-	case G_Load_B_Register(1):
-		offset = M_Offset_G1_Load_B;
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			 "%s: bug! unhandled register=0x%x in switch\n",
+	if (reg < ARRAY_SIZE(m_series_stc_write_regmap)) {
+		regmap = &m_series_stc_write_regmap[reg];
+	} else {
+		dev_warn(dev->class_dev, "%s: unhandled register=0x%x\n",
 			 __func__, reg);
 		return;
 	}
-	ni_writel(dev, data, offset);
-}
-
-static void m_series_stc_writew(struct comedi_device *dev,
-				uint16_t data, int reg)
-{
-	unsigned offset;
 
-	switch (reg) {
-	case ADC_FIFO_Clear:
-		offset = M_Offset_AI_FIFO_Clear;
-		break;
-	case AI_Command_1_Register:
-		offset = M_Offset_AI_Command_1;
-		break;
-	case AI_Command_2_Register:
-		offset = M_Offset_AI_Command_2;
-		break;
-	case AI_Mode_1_Register:
-		offset = M_Offset_AI_Mode_1;
-		break;
-	case AI_Mode_2_Register:
-		offset = M_Offset_AI_Mode_2;
-		break;
-	case AI_Mode_3_Register:
-		offset = M_Offset_AI_Mode_3;
-		break;
-	case AI_Output_Control_Register:
-		offset = M_Offset_AI_Output_Control;
-		break;
-	case AI_Personal_Register:
-		offset = M_Offset_AI_Personal;
-		break;
-	case AI_SI2_Load_A_Register:
-		/* this is a 32 bit register on m series boards */
-		ni_writel(dev, data, M_Offset_AI_SI2_Load_A);
-		return;
-	case AI_SI2_Load_B_Register:
-		/* this is a 32 bit register on m series boards */
-		ni_writel(dev, data, M_Offset_AI_SI2_Load_B);
-		return;
-	case AI_START_STOP_Select_Register:
-		offset = M_Offset_AI_START_STOP_Select;
-		break;
-	case AI_Trigger_Select_Register:
-		offset = M_Offset_AI_Trigger_Select;
-		break;
-	case Analog_Trigger_Etc_Register:
-		offset = M_Offset_Analog_Trigger_Etc;
-		break;
-	case AO_Command_1_Register:
-		offset = M_Offset_AO_Command_1;
-		break;
-	case AO_Command_2_Register:
-		offset = M_Offset_AO_Command_2;
-		break;
-	case AO_Mode_1_Register:
-		offset = M_Offset_AO_Mode_1;
-		break;
-	case AO_Mode_2_Register:
-		offset = M_Offset_AO_Mode_2;
-		break;
-	case AO_Mode_3_Register:
-		offset = M_Offset_AO_Mode_3;
-		break;
-	case AO_Output_Control_Register:
-		offset = M_Offset_AO_Output_Control;
-		break;
-	case AO_Personal_Register:
-		offset = M_Offset_AO_Personal;
-		break;
-	case AO_Start_Select_Register:
-		offset = M_Offset_AO_Start_Select;
-		break;
-	case AO_Trigger_Select_Register:
-		offset = M_Offset_AO_Trigger_Select;
-		break;
-	case Clock_and_FOUT_Register:
-		offset = M_Offset_Clock_and_FOUT;
-		break;
-	case Configuration_Memory_Clear:
-		offset = M_Offset_Configuration_Memory_Clear;
-		break;
-	case DAC_FIFO_Clear:
-		offset = M_Offset_AO_FIFO_Clear;
-		break;
-	case DIO_Control_Register:
-		dev_dbg(dev->class_dev,
-			"%s: FIXME: register 0x%x does not map cleanly on to m-series boards\n",
-			__func__, reg);
-		return;
-	case G_Autoincrement_Register(0):
-		offset = M_Offset_G0_Autoincrement;
-		break;
-	case G_Autoincrement_Register(1):
-		offset = M_Offset_G1_Autoincrement;
-		break;
-	case G_Command_Register(0):
-		offset = M_Offset_G0_Command;
-		break;
-	case G_Command_Register(1):
-		offset = M_Offset_G1_Command;
-		break;
-	case G_Input_Select_Register(0):
-		offset = M_Offset_G0_Input_Select;
-		break;
-	case G_Input_Select_Register(1):
-		offset = M_Offset_G1_Input_Select;
-		break;
-	case G_Mode_Register(0):
-		offset = M_Offset_G0_Mode;
-		break;
-	case G_Mode_Register(1):
-		offset = M_Offset_G1_Mode;
-		break;
-	case Interrupt_A_Ack_Register:
-		offset = M_Offset_Interrupt_A_Ack;
-		break;
-	case Interrupt_A_Enable_Register:
-		offset = M_Offset_Interrupt_A_Enable;
-		break;
-	case Interrupt_B_Ack_Register:
-		offset = M_Offset_Interrupt_B_Ack;
-		break;
-	case Interrupt_B_Enable_Register:
-		offset = M_Offset_Interrupt_B_Enable;
-		break;
-	case Interrupt_Control_Register:
-		offset = M_Offset_Interrupt_Control;
-		break;
-	case IO_Bidirection_Pin_Register:
-		offset = M_Offset_IO_Bidirection_Pin;
-		break;
-	case Joint_Reset_Register:
-		offset = M_Offset_Joint_Reset;
-		break;
-	case RTSI_Trig_A_Output_Register:
-		offset = M_Offset_RTSI_Trig_A_Output;
-		break;
-	case RTSI_Trig_B_Output_Register:
-		offset = M_Offset_RTSI_Trig_B_Output;
+	switch (regmap->size) {
+	case 4:
+		ni_writel(dev, data, regmap->mio_reg);
 		break;
-	case RTSI_Trig_Direction_Register:
-		offset = M_Offset_RTSI_Trig_Direction;
+	case 2:
+		ni_writew(dev, data, regmap->mio_reg);
 		break;
-	/*
-	 * FIXME: DIO_Output_Register (16 bit reg) is replaced by
-	 * M_Offset_Static_Digital_Output (32 bit) and
-	 * M_Offset_SCXI_Serial_Data_Out (8 bit)
-	 */
 	default:
-		dev_warn(dev->class_dev,
-			 "%s: bug! unhandled register=0x%x in switch\n",
+		dev_warn(dev->class_dev, "%s: unmapped register=0x%x\n",
 			 __func__, reg);
-		return;
+		break;
 	}
-	ni_writew(dev, data, offset);
 }
 
-static uint32_t m_series_stc_readl(struct comedi_device *dev, int reg)
+static const struct mio_regmap m_series_stc_read_regmap[] = {
+	[AI_Status_1_Register]		= { M_Offset_AI_Status_1, 2 },
+	[AO_Status_1_Register]		= { M_Offset_AO_Status_1, 2 },
+	[G_Status_Register]		= { M_Offset_G01_Status, 2 },
+	[AO_Status_2_Register]		= { M_Offset_AO_Status_2, 2 },
+	[G_HW_Save_Register(0)]		= { M_Offset_G0_HW_Save, 4 },
+	[G_HW_Save_Register(1)]		= { M_Offset_G1_HW_Save, 4 },
+	[G_Save_Register(0)]		= { M_Offset_G0_Save, 4 },
+	[G_Save_Register(1)]		= { M_Offset_G1_Save, 4 },
+	[Joint_Status_1_Register]	= { M_Offset_Joint_Status_1, 2 },
+	[DIO_Serial_Input_Register]	= { M_Offset_SCXI_Serial_Data_In, 1 },
+	[Joint_Status_2_Register]	= { M_Offset_Joint_Status_2, 2 },
+};
+
+static unsigned int m_series_stc_read(struct comedi_device *dev,
+				      unsigned int reg)
 {
-	unsigned offset;
+	const struct mio_regmap *regmap;
 
-	switch (reg) {
-	case G_HW_Save_Register(0):
-		offset = M_Offset_G0_HW_Save;
-		break;
-	case G_HW_Save_Register(1):
-		offset = M_Offset_G1_HW_Save;
-		break;
-	case G_Save_Register(0):
-		offset = M_Offset_G0_Save;
-		break;
-	case G_Save_Register(1):
-		offset = M_Offset_G1_Save;
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			 "%s: bug! unhandled register=0x%x in switch\n",
+	if (reg < ARRAY_SIZE(m_series_stc_read_regmap)) {
+		regmap = &m_series_stc_read_regmap[reg];
+	} else {
+		dev_warn(dev->class_dev, "%s: unhandled register=0x%x\n",
 			 __func__, reg);
 		return 0;
 	}
-	return ni_readl(dev, offset);
-}
 
-static uint16_t m_series_stc_readw(struct comedi_device *dev, int reg)
-{
-	unsigned offset;
-
-	switch (reg) {
-	case AI_Status_1_Register:
-		offset = M_Offset_AI_Status_1;
-		break;
-	case AO_Status_1_Register:
-		offset = M_Offset_AO_Status_1;
-		break;
-	case AO_Status_2_Register:
-		offset = M_Offset_AO_Status_2;
-		break;
-	case DIO_Serial_Input_Register:
-		return ni_readb(dev, M_Offset_SCXI_Serial_Data_In);
-	case Joint_Status_1_Register:
-		offset = M_Offset_Joint_Status_1;
-		break;
-	case Joint_Status_2_Register:
-		offset = M_Offset_Joint_Status_2;
-		break;
-	case G_Status_Register:
-		offset = M_Offset_G01_Status;
-		break;
+	switch (regmap->size) {
+	case 4:
+		return ni_readl(dev, regmap->mio_reg);
+	case 2:
+		return ni_readw(dev, regmap->mio_reg);
+	case 1:
+		return ni_readb(dev, regmap->mio_reg);
 	default:
-		dev_warn(dev->class_dev,
-			 "%s: bug! unhandled register=0x%x in switch\n",
+		dev_warn(dev->class_dev, "%s: unmapped register=0x%x\n",
 			 __func__, reg);
 		return 0;
 	}
-	return ni_readw(dev, offset);
 }
 
 static void ni_stc_writew(struct comedi_device *dev, uint16_t data, int reg)
@@ -572,7 +450,7 @@ static void ni_stc_writew(struct comedi_device *dev, uint16_t data, int reg)
 	unsigned long flags;
 
 	if (devpriv->is_m_series) {
-		m_series_stc_writew(dev, data, reg);
+		m_series_stc_write(dev, data, reg);
 	} else {
 		spin_lock_irqsave(&devpriv->window_lock, flags);
 		if (!devpriv->mite && reg < 8) {
@@ -590,7 +468,7 @@ static void ni_stc_writel(struct comedi_device *dev, uint32_t data, int reg)
 	struct ni_private *devpriv = dev->private;
 
 	if (devpriv->is_m_series) {
-		m_series_stc_writel(dev, data, reg);
+		m_series_stc_write(dev, data, reg);
 	} else {
 		ni_stc_writew(dev, data >> 16, reg);
 		ni_stc_writew(dev, data & 0xffff, reg + 1);
@@ -604,7 +482,7 @@ static uint16_t ni_stc_readw(struct comedi_device *dev, int reg)
 	uint16_t val;
 
 	if (devpriv->is_m_series) {
-		val = m_series_stc_readw(dev, reg);
+		val = m_series_stc_read(dev, reg);
 	} else {
 		spin_lock_irqsave(&devpriv->window_lock, flags);
 		if (!devpriv->mite && reg < 8) {
@@ -624,7 +502,7 @@ static uint32_t ni_stc_readl(struct comedi_device *dev, int reg)
 	uint32_t val;
 
 	if (devpriv->is_m_series) {
-		val = m_series_stc_readl(dev, reg);
+		val = m_series_stc_read(dev, reg);
 	} else {
 		val = ni_stc_readw(dev, reg) << 16;
 		val |= ni_stc_readw(dev, reg + 1);
-- 
2.3.0



More information about the devel mailing list