summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH Hartley Sweeten <hartleys@visionengravers.com>2015-01-12 10:55:48 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-17 14:25:19 -0800
commit7cbb0ef93a63f7c0574d852607af71f348ccc751 (patch)
treef857f06ade0f4e0692cd29e70b45b42eb02f890e
parent2447a27c877a1a4995a85eb4bc456551c0c5a5f9 (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.c74
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;