diff options
author | H Hartley Sweeten <hartleys@visionengravers.com> | 2015-01-12 10:55:48 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-01-17 14:25:19 -0800 |
commit | 7cbb0ef93a63f7c0574d852607af71f348ccc751 (patch) | |
tree | f857f06ade0f4e0692cd29e70b45b42eb02f890e | |
parent | 2447a27c877a1a4995a85eb4bc456551c0c5a5f9 (diff) |
staging: comedi: ni_at_a2150: introduce a2150_alloc_irq_dma()
This driver requires an IRQ and DMA in order to support async commands.
For aesthetics, introduce a helper function to request the IRQ and DMA
channels and allocate the DMA buffer. Since the async command support
is optional, make the helper function handle any request/allocation
errors and allow the driver to still attach without async command support.
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/drivers/ni_at_a2150.c | 74 |
1 files changed, 46 insertions, 28 deletions
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 7380dac9215c..11b168156a6a 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -676,6 +676,50 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return n; } +static void a2150_alloc_irq_dma(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct a2150_private *devpriv = dev->private; + unsigned int irq_num = it->options[1]; + unsigned int dma_chan = it->options[2]; + + /* + * Only IRQs 15, 14, 12-9, and 7-3 are valid. + * Only DMA channels 7-5 and 3-0 are valid. + * + * Both must be valid for async command support. + */ + if (irq_num > 15 || dma_chan > 7 || + !((1 << irq_num) & 0xdef8) || !((1 << dma_chan) & 0xef)) + return; + + /* + * Request the IRQ and DMA channels and allocate the DMA buffer. + * If the requests or allocation fail async command supprt will + * not be available. + */ + if (request_irq(irq_num, a2150_interrupt, 0, dev->board_name, dev)) + return; + if (request_dma(dma_chan, dev->board_name)) { + free_irq(irq_num, dev); + return; + } + devpriv->dma_buffer = kmalloc(A2150_DMA_BUFFER_SIZE, + GFP_KERNEL | GFP_DMA); + if (!devpriv->dma_buffer) { + free_dma(dma_chan); + free_irq(irq_num, dev); + return; + } + + dev->irq = irq_num; + devpriv->dma = dma_chan; + devpriv->irq_dma_bits = IRQ_LVL_BITS(irq_num) | DMA_CHAN_BITS(dma_chan); + + disable_dma(dma_chan); + set_dma_mode(dma_chan, DMA_MODE_READ); +} + /* probes board type, returns offset */ static int a2150_probe(struct comedi_device *dev) { @@ -689,8 +733,6 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) const struct a2150_board *thisboard; struct a2150_private *devpriv; struct comedi_subdevice *s; - unsigned int irq = it->options[1]; - unsigned int dma = it->options[2]; static const int timeout = 2000; int i; int ret; @@ -711,31 +753,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) thisboard = dev->board_ptr; dev->board_name = thisboard->name; - if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) || - irq == 14 || irq == 15) { - ret = request_irq(irq, a2150_interrupt, 0, - dev->board_name, dev); - if (ret == 0) { - devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); - dev->irq = irq; - } - } - - if (dev->irq && dma <= 7 && dma != 4) { - ret = request_dma(dma, dev->board_name); - if (ret == 0) { - devpriv->dma = dma; - devpriv->dma_buffer = kmalloc(A2150_DMA_BUFFER_SIZE, - GFP_KERNEL | GFP_DMA); - if (!devpriv->dma_buffer) - return -ENOMEM; - - disable_dma(dma); - set_dma_mode(dma, DMA_MODE_READ); - - devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma); - } - } + a2150_alloc_irq_dma(dev, it); ret = comedi_alloc_subdevices(dev, 1); if (ret) @@ -749,7 +767,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0xffff; s->range_table = &range_a2150; s->insn_read = a2150_ai_rinsn; - if (dev->irq && devpriv->dma) { + if (dev->irq) { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; s->len_chanlist = s->n_chan; |