diff options
author | H Hartley Sweeten <hsweeten@visionengravers.com> | 2015-01-14 10:05:04 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-01-17 14:32:55 -0800 |
commit | bd7ea421e3f9750deecdf78af94c8191ef05788d (patch) | |
tree | 3ed6b114f2a5f821f6e17ac1537cc924d91d9fa2 | |
parent | dd7c0f04168a3faedf4a5a8ef9605ef90bdeb09c (diff) |
staging: comedi: pcl816: remove depends on ISA_DMA_API limitation
Use the new comedi_isadma module to provide the ISA DMA support. This removes
all the ISA_DMA_API code from this driver and allows the driver to be used on
platforms that don't support the ISA_DMA_API.
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>
-rw-r--r-- | drivers/staging/comedi/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/comedi/drivers/pcl816.c | 208 |
2 files changed, 70 insertions, 140 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 4c9e2a8a8393..1ed797b79aaa 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -179,7 +179,7 @@ config COMEDI_PCL812 config COMEDI_PCL816 tristate "Advantech PCL-814 and PCL-816 ISA card support" - depends on ISA_DMA_API + select COMEDI_ISADMA if ISA_DMA_API ---help--- Enable support for Advantech PCL-814 and PCL-816 ISA cards diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index d2ce7751df93..09fa40904daa 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -33,14 +33,14 @@ Configuration Options: */ #include <linux/module.h> -#include "../comedidev.h" - #include <linux/gfp.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/interrupt.h> -#include <asm/dma.h> +#include "../comedidev.h" + +#include "comedi_isadma.h" #include "comedi_fc.h" #include "8253.h" @@ -113,17 +113,8 @@ static const struct pcl816_board boardtypes[] = { }, }; -struct pcl816_dma_desc { - void *virt_addr; /* virtual address of DMA buffer */ - dma_addr_t hw_addr; /* hardware (bus) address of DMA buffer */ - unsigned int size; /* transfer size (in bytes) */ -}; - struct pcl816_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ - unsigned int hwdmasize; - struct pcl816_dma_desc dma_desc[2]; - int cur_dma; + struct comedi_isadma *dma; long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ @@ -133,29 +124,6 @@ struct pcl816_private { unsigned int ai_cmd_canceled:1; }; -static void pcl816_isadma_program(unsigned int dma_chan, - struct pcl816_dma_desc *dma) -{ - unsigned long flags; - - flags = claim_dma_lock(); - clear_dma_ff(dma_chan); - set_dma_mode(dma_chan, DMA_MODE_READ); - set_dma_addr(dma_chan, dma->hw_addr); - set_dma_count(dma_chan, dma->size); - enable_dma(dma_chan); - release_dma_lock(flags); -} - -static void pcl816_isadma_disable(unsigned int dma_chan) -{ - unsigned long flags; - - flags = claim_dma_lock(); - disable_dma(dma_chan); - release_dma_lock(flags); -} - static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters) { struct pcl816_private *devpriv = dev->private; @@ -179,29 +147,30 @@ static void pcl816_ai_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; - struct pcl816_dma_desc *dma = &devpriv->dma_desc[0]; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[0]; struct comedi_cmd *cmd = &s->async->cmd; if (cmd->stop_src == TRIG_COUNT) { /* how many */ - dma->size = cmd->stop_arg * comedi_bytes_per_scan(s); + desc->size = cmd->stop_arg * comedi_bytes_per_scan(s); /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = dma->size / devpriv->hwdmasize; + devpriv->dma_runs_to_end = desc->size / desc->maxsize; /* on last dma transfer must be moved */ - devpriv->last_dma_run = dma->size % devpriv->hwdmasize; + devpriv->last_dma_run = desc->size % desc->maxsize; devpriv->dma_runs_to_end--; if (devpriv->dma_runs_to_end >= 0) - dma->size = devpriv->hwdmasize; + desc->size = desc->maxsize; } else { - dma->size = devpriv->hwdmasize; + desc->size = desc->maxsize; devpriv->dma_runs_to_end = -1; } - devpriv->cur_dma = 0; + dma->cur_dma = 0; - pcl816_isadma_program(devpriv->dma, dma); + comedi_isadma_program(desc); } static void pcl816_ai_setup_next_dma(struct comedi_device *dev, @@ -209,19 +178,21 @@ static void pcl816_ai_setup_next_dma(struct comedi_device *dev, { struct pcl816_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - struct pcl816_dma_desc *dma; + struct comedi_isadma *dma = devpriv->dma; + + comedi_isadma_disable(dma->chan); + dma->cur_dma = 1 - dma->cur_dma; - pcl816_isadma_disable(devpriv->dma); + /* switch dma bufs if still running */ if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { - /* switch dma bufs */ - devpriv->cur_dma = 1 - devpriv->cur_dma; - dma = &devpriv->dma_desc[devpriv->cur_dma]; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; + if (devpriv->dma_runs_to_end) - dma->size = devpriv->hwdmasize; + desc->size = desc->maxsize; else - dma->size = devpriv->last_dma_run; + desc->size = devpriv->last_dma_run; - pcl816_isadma_program(devpriv->dma, dma); + comedi_isadma_program(desc); } devpriv->dma_runs_to_end--; @@ -337,7 +308,8 @@ static irqreturn_t pcl816_interrupt(int irq, void *d) struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; struct pcl816_private *devpriv = dev->private; - struct pcl816_dma_desc *dma = &devpriv->dma_desc[devpriv->cur_dma]; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; unsigned int nsamples; unsigned int bufptr; @@ -354,11 +326,12 @@ static irqreturn_t pcl816_interrupt(int irq, void *d) pcl816_ai_setup_next_dma(dev, s); - nsamples = comedi_bytes_to_samples(s, dma->size) - devpriv->ai_poll_ptr; + nsamples = comedi_bytes_to_samples(s, desc->size) - + devpriv->ai_poll_ptr; bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; - transfer_from_dma_buf(dev, s, dma->virt_addr, bufptr, nsamples); + transfer_from_dma_buf(dev, s, desc->virt_addr, bufptr, nsamples); pcl816_ai_clear_eoc(dev); @@ -500,6 +473,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; + struct comedi_isadma *dma = devpriv->dma; struct comedi_cmd *cmd = &s->async->cmd; unsigned int ctrl; unsigned int seglen; @@ -530,7 +504,8 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) ctrl |= PCL816_CTRL_EXT_TRIG; outb(ctrl, dev->iobase + PCL816_CTRL_REG); - outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG); + outb((dma->chan << 4) | dev->irq, + dev->iobase + PCL816_STATUS_REG); return 0; } @@ -538,41 +513,34 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; - struct pcl816_dma_desc *dma = &devpriv->dma_desc[devpriv->cur_dma]; + struct comedi_isadma *dma = devpriv->dma; + struct comedi_isadma_desc *desc; unsigned long flags; - unsigned int top1, top2, i; + unsigned int poll; + int ret; spin_lock_irqsave(&dev->spinlock, flags); - for (i = 0; i < 20; i++) { - top1 = get_dma_residue(devpriv->dma); /* where is now DMA */ - top2 = get_dma_residue(devpriv->dma); - if (top1 == top2) - break; - } - if (top1 != top2) { - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; - } - - /* where is now DMA in buffer */ - top1 = dma->size - top1; - top1 >>= 1; /* sample position */ - top2 = top1 - devpriv->ai_poll_ptr; - if (top2 < 1) { /* no new samples */ - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; - } + poll = comedi_isadma_poll(dma); + poll = comedi_bytes_to_samples(s, poll); + if (poll > devpriv->ai_poll_ptr) { + desc = &dma->desc[dma->cur_dma]; + transfer_from_dma_buf(dev, s, desc->virt_addr, + devpriv->ai_poll_ptr, + poll - devpriv->ai_poll_ptr); + /* new buffer position */ + devpriv->ai_poll_ptr = poll; - transfer_from_dma_buf(dev, s, dma->virt_addr, - devpriv->ai_poll_ptr, top2); + comedi_handle_events(dev, s); - devpriv->ai_poll_ptr = top1; /* new buffer position */ + ret = comedi_buf_n_bytes_ready(s); + } else { + /* no new samples */ + ret = 0; + } spin_unlock_irqrestore(&dev->spinlock, flags); - comedi_handle_events(dev, s); - - return comedi_buf_n_bytes_ready(s); + return ret; } static int pcl816_ai_cancel(struct comedi_device *dev, @@ -673,68 +641,36 @@ static void pcl816_reset(struct comedi_device *dev) outb(0, dev->iobase + PCL816_DO_DI_MSB_REG); } -static int pcl816_alloc_dma(struct comedi_device *dev, - unsigned int irq_num, unsigned int dma_chan) +static void pcl816_alloc_irq_and_dma(struct comedi_device *dev, + struct comedi_devconfig *it) { struct pcl816_private *devpriv = dev->private; - struct pcl816_dma_desc *dma; - int i; + unsigned int irq_num = it->options[1]; + unsigned int dma_chan = it->options[2]; - /* - * Only IRQs 2-7 are valid. - * Only DMA channels 3 and 1 are valid. - * - * Both must be valid for async command support. - */ + /* only IRQs 2-7 and DMA channels 3 and 1 are valid */ if (!(irq_num >= 2 && irq_num <= 7) || !(dma_chan == 3 || dma_chan == 1)) - return 0; + return; - /* - * Request the IRQ and DMA channels and allocate the DMA buffers. - * If the requests or allocations fail async command supprt will - * not be available. - */ if (request_irq(irq_num, pcl816_interrupt, 0, dev->board_name, dev)) - return 0; - if (request_dma(dma_chan, dev->board_name)) { - free_irq(irq_num, dev); - return 0; - } - - dev->irq = irq_num; - devpriv->dma = dma_chan; - - devpriv->hwdmasize = PAGE_SIZE * 4; /* we need 16KB */ - - for (i = 0; i < 2; i++) { - dma = &devpriv->dma_desc[i]; + return; - dma->virt_addr = dma_alloc_coherent(NULL, devpriv->hwdmasize, - &dma->hw_addr, GFP_KERNEL); - if (!dma->virt_addr) - return -ENOMEM; - } - return 0; + /* DMA uses two 16K buffers */ + devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan, + PAGE_SIZE * 4, COMEDI_ISADMA_READ); + if (!devpriv->dma) + free_irq(irq_num, dev); + else + dev->irq = irq_num; } static void pcl816_free_dma(struct comedi_device *dev) { struct pcl816_private *devpriv = dev->private; - struct pcl816_dma_desc *dma; - int i; - if (!devpriv) - return; - - if (devpriv->dma) - free_dma(devpriv->dma); - for (i = 0; i < 2; i++) { - dma = &devpriv->dma_desc[i]; - if (dma->virt_addr) - dma_free_coherent(NULL, devpriv->hwdmasize, - dma->virt_addr, dma->hw_addr); - } + if (devpriv) + comedi_isadma_free(devpriv->dma); } static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -752,14 +688,8 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - /* - * An IRQ and DMA are required to support async commands. - * pcl816_alloc_dma() will only fail if the DMA buffers - * cannot be allocated. - */ - ret = pcl816_alloc_dma(dev, it->options[1], it->options[2]); - if (ret) - return ret; + /* an IRQ and DMA are required to support async commands */ + pcl816_alloc_irq_and_dma(dev, it); ret = comedi_alloc_subdevices(dev, 4); if (ret) |