Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1fa51639 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman
Browse files

staging: comedi: pcl816: introduce pcl816_alloc_dma()



The IRA and DMA are optional with this driver but both are required to
support async commands. Introduce a helper function to request the IRQ
and DMA channel and allocate the buffers. Don't fail the driver attach
if the user passed an invalid IRQ or DMA channel or they cannot be
requested.

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 1c53093a
Loading
Loading
Loading
Loading
+56 −35
Original line number Diff line number Diff line
@@ -657,40 +657,36 @@ static void pcl816_reset(struct comedi_device *dev)
	outb(0, dev->iobase + PCL816_DO_DI_MSB_REG);
}

static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static int pcl816_alloc_dma(struct comedi_device *dev,
			    unsigned int irq_num, unsigned int dma_chan)
{
	const struct pcl816_board *board = dev->board_ptr;
	struct pcl816_private *devpriv;
	struct comedi_subdevice *s;
	int ret;
	struct pcl816_private *devpriv = dev->private;
	int i;

	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
	if (!devpriv)
		return -ENOMEM;

	ret = comedi_request_region(dev, it->options[0], 0x10);
	if (ret)
		return ret;
	/*
	 * Only IRQs 2-7 are valid.
	 * Only DMA channels 3 and 1 are valid.
	 *
	 * Both must be valid for async command support.
	 */
	if (!(irq_num >= 2 && irq_num <= 7) ||
	    !(dma_chan == 3 || dma_chan == 1))
		return 0;

	/* we can use IRQ 2-7 for async command support */
	if (it->options[1] >= 2 && it->options[1] <= 7) {
		ret = request_irq(it->options[1], pcl816_interrupt, 0,
				  dev->board_name, dev);
		if (ret == 0)
			dev->irq = it->options[1];
	}

	/* we need an IRQ to do DMA on channel 3 or 1 */
	if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) {
		ret = request_dma(it->options[2], dev->board_name);
		if (ret) {
			dev_err(dev->class_dev,
				"unable to request DMA channel %d\n",
				it->options[2]);
			return -EBUSY;
	/*
	 * 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;
	}
		devpriv->dma = it->options[2];

	dev->irq = irq_num;
	devpriv->dma = dma_chan;

	devpriv->dmapages = 2;	/* we need 16KB */
	devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
@@ -705,8 +701,33 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
		devpriv->dmabuf[i] = dmabuf;
		devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
	}
	return 0;
}

static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
	const struct pcl816_board *board = dev->board_ptr;
	struct pcl816_private *devpriv;
	struct comedi_subdevice *s;
	int ret;

	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
	if (!devpriv)
		return -ENOMEM;

	ret = comedi_request_region(dev, it->options[0], 0x10);
	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;

	ret = comedi_alloc_subdevices(dev, 4);
	if (ret)
		return ret;
@@ -718,7 +739,7 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
	s->maxdata	= board->ai_maxdata;
	s->range_table	= &range_pcl816;
	s->insn_read	= pcl816_ai_insn_read;
	if (devpriv->dma) {
	if (dev->irq) {
		dev->read_subdev = s;
		s->subdev_flags	|= SDF_CMD_READ;
		s->len_chanlist	= board->ai_chanlist;