[PATCH 16/19] staging: comedi: pcl726: add support for the external interrupt signal

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The ACL-6126 board supports an external interrupt signal on pin 17 of
its I/O connector (CN3). Add a new subdevice to this driver to support
asynchronous commands with this input.

Signed-off-by: H Hartley Sweeten <hsweeten@xxxxxxxxxxxxxxxxxxx>
Cc: Ian Abbott <abbotti@xxxxxxxxx>
Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
 drivers/staging/comedi/drivers/pcl726.c | 115 ++++++++++++++++++++++++++++++--
 1 file changed, 111 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index b7b14aa..6df6e09 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -67,6 +67,8 @@ Interrupts are not supported.
 
 #include "../comedidev.h"
 
+#include "comedi_fc.h"
+
 #define PCL726_AO_MSB_REG(x)	(0x00 + ((x) * 2))
 #define PCL726_AO_LSB_REG(x)	(0x01 + ((x) * 2))
 #define PCL726_DO_MSB_REG	0x0c
@@ -157,10 +159,94 @@ static const struct pcl726_board boardtypes[] = {
 struct pcl726_private {
 	const struct comedi_lrange *rangelist[12];
 	unsigned int ao_readback[12];
+	unsigned int cmd_running:1;
 };
 
+static int pcl818_intr_insn_bits(struct comedi_device *dev,
+				 struct comedi_subdevice *s,
+				 struct comedi_insn *insn,
+				 unsigned int *data)
+{
+	data[1] = 0;
+	return insn->n;
+}
+
+static int pcl818_intr_cmdtest(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_cmd *cmd)
+{
+	int err = 0;
+
+	/* Step 1 : check if triggers are trivially valid */
+
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
+
+	if (err)
+		return 1;
+
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
+
+	if (err)
+		return 2;
+
+	/* Step 3: check if arguments are trivially valid */
+
+	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
+	err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+	if (err)
+		return 3;
+
+	/* step 4: ignored */
+
+	if (err)
+		return 4;
+
+	return 0;
+}
+
+static int pcl818_intr_cmd(struct comedi_device *dev,
+			   struct comedi_subdevice *s)
+{
+	struct pcl726_private *devpriv = dev->private;
+
+	devpriv->cmd_running = 1;
+
+	return 0;
+}
+
+static int pcl818_intr_cancel(struct comedi_device *dev,
+			      struct comedi_subdevice *s)
+{
+	struct pcl726_private *devpriv = dev->private;
+
+	devpriv->cmd_running = 0;
+
+	return 0;
+}
+
 static irqreturn_t pcl818_interrupt(int irq, void *d)
 {
+	struct comedi_device *dev = d;
+	struct comedi_subdevice *s = dev->read_subdev;
+	struct pcl726_private *devpriv = dev->private;
+
+	if (devpriv->cmd_running) {
+		pcl818_intr_cancel(dev, s);
+
+		comedi_buf_put(s->async, 0);
+		s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
+		comedi_event(dev, s);
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -262,6 +348,7 @@ static int pcl726_attach(struct comedi_device *dev,
 	const struct pcl726_board *board = comedi_board(dev);
 	struct pcl726_private *devpriv;
 	struct comedi_subdevice *s;
+	int subdev;
 	int ret;
 	int i;
 
@@ -296,12 +383,17 @@ static int pcl726_attach(struct comedi_device *dev,
 			devpriv->rangelist[i] = &range_unknown;
 	}
 
-	ret = comedi_alloc_subdevices(dev, board->have_dio ? 3 : 1);
+	subdev = board->have_dio ? 3 : 1;
+	if (dev->irq)
+		subdev++;
+	ret = comedi_alloc_subdevices(dev, subdev);
 	if (ret)
 		return ret;
 
+	subdev = 0;
+
 	/* Analog Output subdevice */
-	s = &dev->subdevices[0];
+	s = &dev->subdevices[subdev++];
 	s->type		= COMEDI_SUBD_AO;
 	s->subdev_flags	= SDF_WRITABLE | SDF_GROUND;
 	s->n_chan	= board->ao_nchan;
@@ -312,7 +404,7 @@ static int pcl726_attach(struct comedi_device *dev,
 
 	if (board->have_dio) {
 		/* Digital Input subdevice */
-		s = &dev->subdevices[1];
+		s = &dev->subdevices[subdev++];
 		s->type		= COMEDI_SUBD_DI;
 		s->subdev_flags	= SDF_READABLE;
 		s->n_chan	= 16;
@@ -321,7 +413,7 @@ static int pcl726_attach(struct comedi_device *dev,
 		s->range_table	= &range_digital;
 
 		/* Digital Output subdevice */
-		s = &dev->subdevices[2];
+		s = &dev->subdevices[subdev++];
 		s->type		= COMEDI_SUBD_DO;
 		s->subdev_flags	= SDF_WRITABLE;
 		s->n_chan	= 16;
@@ -330,6 +422,21 @@ static int pcl726_attach(struct comedi_device *dev,
 		s->range_table	= &range_digital;
 	}
 
+	if (dev->irq) {
+		/* Digial Input subdevice - Interrupt support */
+		s = &dev->subdevices[subdev++];
+		dev->read_subdev = s;
+		s->type		= COMEDI_SUBD_DI;
+		s->subdev_flags	= SDF_READABLE | SDF_CMD_READ;
+		s->n_chan	= 1;
+		s->maxdata	= 1;
+		s->range_table	= &range_digital;
+		s->insn_bits	= pcl818_intr_insn_bits;
+		s->do_cmdtest	= pcl818_intr_cmdtest;
+		s->do_cmd	= pcl818_intr_cmd;
+		s->cancel	= pcl818_intr_cancel;
+	}
+
 	return 0;
 }
 
-- 
1.8.3.2

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel




[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux