From 1d28a6fae4a26538f33a1849fea9678545d81537 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 3 Dec 2012 18:15:45 +0000 Subject: [PATCH] --- yaml --- r: 353919 b: refs/heads/master c: 5c2d4cba9586ddc3505f51bddf935ddc65a0e0bb h: refs/heads/master i: 353917: b4c8437b4e409af90e3cae884b554cb41eec18c1 353915: c7c5e316a14ae4e8d7f7bafb7cc552a36a7b4171 353911: a23fe5510a42d2d9020ff743f49b0df4f49cad10 353903: 3a30d7b060706a3f101f4b996fe48b0c993541bb 353887: a8b8fd5698e971a05a8a64e69ea5d5878c5f1c2a 353855: e866539bdbfb5ffc0884d75657abe8c1927b6b6a 353791: f60c668283ba8d8ee2d85f265b72009731d86325 v: v3 --- [refs] | 2 +- .../staging/comedi/drivers/addi_apci_2032.c | 99 +++++++++++++++---- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/[refs] b/[refs] index e11f36e9b505..c39efe150805 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: ef6543dbad12c1086f3bc3565d8266352521d8a3 +refs/heads/master: 5c2d4cba9586ddc3505f51bddf935ddc65a0e0bb diff --git a/trunk/drivers/staging/comedi/drivers/addi_apci_2032.c b/trunk/drivers/staging/comedi/drivers/addi_apci_2032.c index 98691fdfbd48..dd81ddc3d986 100644 --- a/trunk/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/trunk/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -58,6 +58,12 @@ struct apci2032_private { unsigned int wdog_ctrl; }; +struct apci2032_int_private { + spinlock_t spinlock; + bool active; + unsigned char enabled_isns; +}; + static int apci2032_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -163,6 +169,16 @@ static int apci2032_int_insn_bits(struct comedi_device *dev, return insn->n; } +static void apci2032_int_stop(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci2032_int_private *subpriv = s->private; + + subpriv->active = false; + subpriv->enabled_isns = 0; + outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG); +} + static int apci2032_int_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -172,8 +188,8 @@ static int apci2032_int_cmdtest(struct comedi_device *dev, /* 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_OTHER); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); @@ -189,17 +205,9 @@ static int apci2032_int_cmdtest(struct comedi_device *dev, /* Step 3: check if arguments are trivially valid */ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - - /* - * 0 == no trigger - * 1 == trigger on VCC interrupt - * 2 == trigger on CC interrupt - * 3 == trigger on either VCC or CC interrupt - */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 3); - + 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->scan_end_arg, cmd->chanlist_len); err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) @@ -217,8 +225,20 @@ static int apci2032_int_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; + struct apci2032_int_private *subpriv = s->private; + unsigned char enabled_isns; + unsigned int n; + unsigned long flags; + + enabled_isns = 0; + for (n = 0; n < cmd->chanlist_len; n++) + enabled_isns |= 1 << CR_CHAN(cmd->chanlist[n]); - outl(cmd->scan_begin_arg, dev->iobase + APCI2032_INT_CTRL_REG); + spin_lock_irqsave(&subpriv->spinlock, flags); + subpriv->enabled_isns = enabled_isns; + subpriv->active = true; + outl(subpriv->enabled_isns, dev->iobase + APCI2032_INT_CTRL_REG); + spin_unlock_irqrestore(&subpriv->spinlock, flags); return 0; } @@ -226,7 +246,13 @@ static int apci2032_int_cmd(struct comedi_device *dev, static int apci2032_int_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG); + struct apci2032_int_private *subpriv = s->private; + unsigned long flags; + + spin_lock_irqsave(&subpriv->spinlock, flags); + if (subpriv->active) + apci2032_int_stop(dev, s); + spin_unlock_irqrestore(&subpriv->spinlock, flags); return 0; } @@ -235,7 +261,9 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; + struct apci2032_int_private *subpriv; unsigned int val; + bool do_event = false; if (!dev->attached) return IRQ_NONE; @@ -245,6 +273,9 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) if (!val) return IRQ_NONE; + subpriv = s->private; + spin_lock(&subpriv->spinlock); + val = inl(dev->iobase + APCI2032_INT_STATUS_REG) & 3; /* Disable triggered interrupt sources. */ outl(~val & 3, dev->iobase + APCI2032_INT_CTRL_REG); @@ -254,11 +285,31 @@ static irqreturn_t apci2032_interrupt(int irq, void *d) * they'd keep triggering interrupts repeatedly. */ - if (comedi_buf_put(s->async, val)) - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - else - s->async->events |= COMEDI_CB_OVERFLOW; - comedi_event(dev, s); + if (subpriv->active && (val & subpriv->enabled_isns) != 0) { + unsigned short bits; + unsigned int n, len; + unsigned int *chanlist; + + /* Bits in scan data correspond to indices in channel list. */ + bits = 0; + len = s->async->cmd.chanlist_len; + chanlist = &s->async->cmd.chanlist[0]; + for (n = 0; n < len; n++) + if ((val & (1U << CR_CHAN(chanlist[n]))) != 0) + bits |= 1U << n; + + if (comedi_buf_put(s->async, bits)) { + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + } else { + apci2032_int_stop(dev, s); + s->async->events |= COMEDI_CB_OVERFLOW; + } + do_event = true; + } + + spin_unlock(&subpriv->spinlock); + if (do_event) + comedi_event(dev, s); return IRQ_HANDLED; } @@ -327,10 +378,18 @@ static int apci2032_auto_attach(struct comedi_device *dev, /* Initialize the interrupt subdevice */ s = &dev->subdevices[2]; if (dev->irq) { + struct apci2032_int_private *subpriv; + dev->read_subdev = s; + subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); + if (!subpriv) + return -ENOMEM; + spin_lock_init(&subpriv->spinlock); + s->private = subpriv; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_CMD_READ; s->n_chan = 2; + s->len_chanlist = 2; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = apci2032_int_insn_bits; @@ -352,6 +411,8 @@ static void apci2032_detach(struct comedi_device *dev) apci2032_reset(dev); if (dev->irq) free_irq(dev->irq, dev); + if (dev->read_subdev) + kfree(dev->read_subdev->private); if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev);