mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-01 16:57:18 +09:00
staging: comedi: pcl726: add support for the external interrupt signal
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@visionengravers.com> Reviewed-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
fc93af5837
commit
afee35c7a4
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user