Commit 7cbb0ef9 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

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: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2447a27c
...@@ -676,6 +676,50 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, ...@@ -676,6 +676,50 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return n; 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 */ /* probes board type, returns offset */
static int a2150_probe(struct comedi_device *dev) static int a2150_probe(struct comedi_device *dev)
{ {
...@@ -689,8 +733,6 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) ...@@ -689,8 +733,6 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
const struct a2150_board *thisboard; const struct a2150_board *thisboard;
struct a2150_private *devpriv; struct a2150_private *devpriv;
struct comedi_subdevice *s; struct comedi_subdevice *s;
unsigned int irq = it->options[1];
unsigned int dma = it->options[2];
static const int timeout = 2000; static const int timeout = 2000;
int i; int i;
int ret; int ret;
...@@ -711,31 +753,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) ...@@ -711,31 +753,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
thisboard = dev->board_ptr; thisboard = dev->board_ptr;
dev->board_name = thisboard->name; dev->board_name = thisboard->name;
if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) || a2150_alloc_irq_dma(dev, it);
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);
}
}
ret = comedi_alloc_subdevices(dev, 1); ret = comedi_alloc_subdevices(dev, 1);
if (ret) if (ret)
...@@ -749,7 +767,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) ...@@ -749,7 +767,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = 0xffff; s->maxdata = 0xffff;
s->range_table = &range_a2150; s->range_table = &range_a2150;
s->insn_read = a2150_ai_rinsn; s->insn_read = a2150_ai_rinsn;
if (dev->irq && devpriv->dma) { if (dev->irq) {
dev->read_subdev = s; dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ; s->subdev_flags |= SDF_CMD_READ;
s->len_chanlist = s->n_chan; s->len_chanlist = s->n_chan;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment