From: H Hartley Sweeten Date: Wed, 25 Sep 2013 22:41:40 +0000 (-0700) Subject: staging: comedi: pcl726: add support for the external interrupt signal X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=afee35c7a4bb4fb7f60ae27d4d248a2bb956f430;p=deliverable%2Flinux.git 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 Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index b7b14aaea4b0..6df6e097b301 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; }