diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/ni_6527.c')
-rw-r--r-- | drivers/staging/comedi/drivers/ni_6527.c | 154 |
1 files changed, 95 insertions, 59 deletions
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index c8b1fa793a37..e84dac2bf3b2 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -90,7 +90,6 @@ static const struct ni6527_board ni6527_boards[] = { }; struct ni6527_private { - void __iomem *mmio_base; unsigned int filter_interval; unsigned int filter_enable; }; @@ -99,14 +98,15 @@ static void ni6527_set_filter_interval(struct comedi_device *dev, unsigned int val) { struct ni6527_private *devpriv = dev->private; - void __iomem *mmio = devpriv->mmio_base; if (val != devpriv->filter_interval) { - writeb(val & 0xff, mmio + NI6527_FILT_INTERVAL_REG(0)); - writeb((val >> 8) & 0xff, mmio + NI6527_FILT_INTERVAL_REG(1)); - writeb((val >> 16) & 0x0f, mmio + NI6527_FILT_INTERVAL_REG(2)); + writeb(val & 0xff, dev->mmio + NI6527_FILT_INTERVAL_REG(0)); + writeb((val >> 8) & 0xff, + dev->mmio + NI6527_FILT_INTERVAL_REG(1)); + writeb((val >> 16) & 0x0f, + dev->mmio + NI6527_FILT_INTERVAL_REG(2)); - writeb(NI6527_CLR_INTERVAL, mmio + NI6527_CLR_REG); + writeb(NI6527_CLR_INTERVAL, dev->mmio + NI6527_CLR_REG); devpriv->filter_interval = val; } @@ -115,12 +115,9 @@ static void ni6527_set_filter_interval(struct comedi_device *dev, static void ni6527_set_filter_enable(struct comedi_device *dev, unsigned int val) { - struct ni6527_private *devpriv = dev->private; - void __iomem *mmio = devpriv->mmio_base; - - writeb(val & 0xff, mmio + NI6527_FILT_ENA_REG(0)); - writeb((val >> 8) & 0xff, mmio + NI6527_FILT_ENA_REG(1)); - writeb((val >> 16) & 0xff, mmio + NI6527_FILT_ENA_REG(2)); + writeb(val & 0xff, dev->mmio + NI6527_FILT_ENA_REG(0)); + writeb((val >> 8) & 0xff, dev->mmio + NI6527_FILT_ENA_REG(1)); + writeb((val >> 16) & 0xff, dev->mmio + NI6527_FILT_ENA_REG(2)); } static int ni6527_di_insn_config(struct comedi_device *dev, @@ -162,13 +159,11 @@ static int ni6527_di_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct ni6527_private *devpriv = dev->private; - void __iomem *mmio = devpriv->mmio_base; unsigned int val; - val = readb(mmio + NI6527_DI_REG(0)); - val |= (readb(mmio + NI6527_DI_REG(1)) << 8); - val |= (readb(mmio + NI6527_DI_REG(2)) << 16); + val = readb(dev->mmio + NI6527_DI_REG(0)); + val |= (readb(dev->mmio + NI6527_DI_REG(1)) << 8); + val |= (readb(dev->mmio + NI6527_DI_REG(2)) << 16); data[1] = val; @@ -180,8 +175,6 @@ static int ni6527_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct ni6527_private *devpriv = dev->private; - void __iomem *mmio = devpriv->mmio_base; unsigned int mask; mask = comedi_dio_update_state(s, data); @@ -190,11 +183,13 @@ static int ni6527_do_insn_bits(struct comedi_device *dev, unsigned int val = s->state ^ 0xffffff; if (mask & 0x0000ff) - writeb(val & 0xff, mmio + NI6527_DO_REG(0)); + writeb(val & 0xff, dev->mmio + NI6527_DO_REG(0)); if (mask & 0x00ff00) - writeb((val >> 8) & 0xff, mmio + NI6527_DO_REG(1)); + writeb((val >> 8) & 0xff, + dev->mmio + NI6527_DO_REG(1)); if (mask & 0xff0000) - writeb((val >> 16) & 0xff, mmio + NI6527_DO_REG(2)); + writeb((val >> 16) & 0xff, + dev->mmio + NI6527_DO_REG(2)); } data[1] = s->state; @@ -205,12 +200,10 @@ static int ni6527_do_insn_bits(struct comedi_device *dev, static irqreturn_t ni6527_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct ni6527_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; - void __iomem *mmio = devpriv->mmio_base; unsigned int status; - status = readb(mmio + NI6527_STATUS_REG); + status = readb(dev->mmio + NI6527_STATUS_REG); if (!(status & NI6527_STATUS_IRQ)) return IRQ_NONE; @@ -220,7 +213,7 @@ static irqreturn_t ni6527_interrupt(int irq, void *d) comedi_event(dev, s); } - writeb(NI6527_CLR_IRQS, mmio + NI6527_CLR_REG); + writeb(NI6527_CLR_IRQS, dev->mmio + NI6527_CLR_REG); return IRQ_HANDLED; } @@ -270,11 +263,8 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev, static int ni6527_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct ni6527_private *devpriv = dev->private; - void __iomem *mmio = devpriv->mmio_base; - - writeb(NI6527_CLR_IRQS, mmio + NI6527_CLR_REG); - writeb(NI6527_CTRL_ENABLE_IRQS, mmio + NI6527_CTRL_REG); + writeb(NI6527_CLR_IRQS, dev->mmio + NI6527_CLR_REG); + writeb(NI6527_CTRL_ENABLE_IRQS, dev->mmio + NI6527_CTRL_REG); return 0; } @@ -282,10 +272,7 @@ static int ni6527_intr_cmd(struct comedi_device *dev, static int ni6527_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct ni6527_private *devpriv = dev->private; - void __iomem *mmio = devpriv->mmio_base; - - writeb(NI6527_CTRL_DISABLE_IRQS, mmio + NI6527_CTRL_REG); + writeb(NI6527_CTRL_DISABLE_IRQS, dev->mmio + NI6527_CTRL_REG); return 0; } @@ -299,21 +286,37 @@ static int ni6527_intr_insn_bits(struct comedi_device *dev, } static void ni6527_set_edge_detection(struct comedi_device *dev, + unsigned int mask, unsigned int rising, unsigned int falling) { - struct ni6527_private *devpriv = dev->private; - void __iomem *mmio = devpriv->mmio_base; - - /* enable rising-edge detection channels */ - writeb(rising & 0xff, mmio + NI6527_RISING_EDGE_REG(0)); - writeb((rising >> 8) & 0xff, mmio + NI6527_RISING_EDGE_REG(1)); - writeb((rising >> 16) & 0xff, mmio + NI6527_RISING_EDGE_REG(2)); - - /* enable falling-edge detection channels */ - writeb(falling & 0xff, mmio + NI6527_FALLING_EDGE_REG(0)); - writeb((falling >> 8) & 0xff, mmio + NI6527_FALLING_EDGE_REG(1)); - writeb((falling >> 16) & 0xff, mmio + NI6527_FALLING_EDGE_REG(2)); + unsigned int i; + + rising &= mask; + falling &= mask; + for (i = 0; i < 2; i++) { + if (mask & 0xff) { + if (~mask & 0xff) { + /* preserve rising-edge detection channels */ + rising |= readb(dev->mmio + + NI6527_RISING_EDGE_REG(i)) & + (~mask & 0xff); + /* preserve falling-edge detection channels */ + falling |= readb(dev->mmio + + NI6527_FALLING_EDGE_REG(i)) & + (~mask & 0xff); + } + /* update rising-edge detection channels */ + writeb(rising & 0xff, + dev->mmio + NI6527_RISING_EDGE_REG(i)); + /* update falling-edge detection channels */ + writeb(falling & 0xff, + dev->mmio + NI6527_FALLING_EDGE_REG(i)); + } + rising >>= 8; + falling >>= 8; + mask >>= 8; + } } static int ni6527_intr_insn_config(struct comedi_device *dev, @@ -321,12 +324,45 @@ static int ni6527_intr_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { + unsigned int mask = 0xffffffff; + unsigned int rising, falling, shift; + switch (data[0]) { case INSN_CONFIG_CHANGE_NOTIFY: /* check_insn_config_length() does not check this instruction */ if (insn->n != 3) return -EINVAL; - ni6527_set_edge_detection(dev, data[1], data[2]); + rising = data[1]; + falling = data[2]; + ni6527_set_edge_detection(dev, mask, rising, falling); + break; + case INSN_CONFIG_DIGITAL_TRIG: + /* check trigger number */ + if (data[1] != 0) + return -EINVAL; + /* check digital trigger operation */ + switch (data[2]) { + case COMEDI_DIGITAL_TRIG_DISABLE: + rising = 0; + falling = 0; + break; + case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: + /* check shift amount */ + shift = data[3]; + if (shift >= s->n_chan) { + mask = 0; + rising = 0; + falling = 0; + } else { + mask <<= shift; + rising = data[4] << shift; + falling = data[5] << shift; + } + break; + default: + return -EINVAL; + } + ni6527_set_edge_detection(dev, mask, rising, falling); break; default: return -EINVAL; @@ -337,15 +373,15 @@ static int ni6527_intr_insn_config(struct comedi_device *dev, static void ni6527_reset(struct comedi_device *dev) { - struct ni6527_private *devpriv = dev->private; - void __iomem *mmio = devpriv->mmio_base; - /* disable deglitch filters on all channels */ ni6527_set_filter_enable(dev, 0); + /* disable edge detection */ + ni6527_set_edge_detection(dev, 0xffffffff, 0, 0); + writeb(NI6527_CLR_IRQS | NI6527_CLR_RESET_FILT, - mmio + NI6527_CLR_REG); - writeb(NI6527_CTRL_DISABLE_IRQS, mmio + NI6527_CTRL_REG); + dev->mmio + NI6527_CLR_REG); + writeb(NI6527_CTRL_DISABLE_IRQS, dev->mmio + NI6527_CTRL_REG); } static int ni6527_auto_attach(struct comedi_device *dev, @@ -372,12 +408,12 @@ static int ni6527_auto_attach(struct comedi_device *dev, if (ret) return ret; - devpriv->mmio_base = pci_ioremap_bar(pcidev, 1); - if (!devpriv->mmio_base) + dev->mmio = pci_ioremap_bar(pcidev, 1); + if (!dev->mmio) return -ENOMEM; /* make sure this is actually a 6527 device */ - if (readb(devpriv->mmio_base + NI6527_ID_REG) != 0x27) + if (readb(dev->mmio + NI6527_ID_REG) != 0x27) return -ENODEV; ni6527_reset(dev); @@ -434,12 +470,12 @@ static int ni6527_auto_attach(struct comedi_device *dev, static void ni6527_detach(struct comedi_device *dev) { - struct ni6527_private *devpriv = dev->private; - - if (devpriv && devpriv->mmio_base) + if (dev->mmio) ni6527_reset(dev); if (dev->irq) free_irq(dev->irq, dev); + if (dev->mmio) + iounmap(dev->mmio); comedi_pci_disable(dev); } |