static int pcl818_attach()

in drivers/pcl818.c [979:1108]


static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
	const struct pcl818_board *board = dev->board_ptr;
	struct pcl818_private *devpriv;
	struct comedi_subdevice *s;
	unsigned int osc_base;
	int ret;

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

	ret = comedi_request_region(dev, it->options[0],
				    board->has_fifo ? 0x20 : 0x10);
	if (ret)
		return ret;

	/* 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], pcl818_interrupt, 0,
				  dev->board_name, dev);
		if (ret == 0)
			dev->irq = it->options[1];
	}

	/* should we use the FIFO? */
	if (dev->irq && board->has_fifo && it->options[2] == -1)
		devpriv->usefifo = 1;

	/* we need an IRQ to do DMA on channel 3 or 1 */
	if (dev->irq && board->has_dma)
		pcl818_alloc_dma(dev, it->options[2]);

	/* use 1MHz or 10MHz oscilator */
	if ((it->options[3] == 0) || (it->options[3] == 10))
		osc_base = I8254_OSC_BASE_10MHZ;
	else
		osc_base = I8254_OSC_BASE_1MHZ;

	dev->pacer = comedi_8254_init(dev->iobase + PCL818_TIMER_BASE,
				      osc_base, I8254_IO8, 0);
	if (!dev->pacer)
		return -ENOMEM;

	/* max sampling speed */
	devpriv->ns_min = board->ns_min;
	if (!board->is_818) {
		/* extended PCL718 to 100kHz DAC */
		if ((it->options[6] == 1) || (it->options[6] == 100))
			devpriv->ns_min = 10000;
	}

	ret = comedi_alloc_subdevices(dev, 4);
	if (ret)
		return ret;

	s = &dev->subdevices[0];
	s->type		= COMEDI_SUBD_AI;
	s->subdev_flags	= SDF_READABLE;
	if (check_single_ended(dev->iobase)) {
		s->n_chan	= 16;
		s->subdev_flags	|= SDF_COMMON | SDF_GROUND;
	} else {
		s->n_chan	= 8;
		s->subdev_flags	|= SDF_DIFF;
	}
	s->maxdata	= 0x0fff;

	pcl818_set_ai_range_table(dev, s, it);

	s->insn_read	= pcl818_ai_insn_read;
	if (dev->irq) {
		dev->read_subdev = s;
		s->subdev_flags	|= SDF_CMD_READ;
		s->len_chanlist	= s->n_chan;
		s->do_cmdtest	= ai_cmdtest;
		s->do_cmd	= pcl818_ai_cmd;
		s->cancel	= pcl818_ai_cancel;
	}

	/* Analog Output subdevice */
	s = &dev->subdevices[1];
	if (board->n_aochan) {
		s->type		= COMEDI_SUBD_AO;
		s->subdev_flags	= SDF_WRITABLE | SDF_GROUND;
		s->n_chan	= board->n_aochan;
		s->maxdata	= 0x0fff;
		s->range_table	= &range_unipolar5;
		if (board->is_818) {
			if ((it->options[4] == 1) || (it->options[4] == 10))
				s->range_table = &range_unipolar10;
			if (it->options[4] == 2)
				s->range_table = &range_unknown;
		} else {
			if ((it->options[5] == 1) || (it->options[5] == 10))
				s->range_table = &range_unipolar10;
			if (it->options[5] == 2)
				s->range_table = &range_unknown;
		}
		s->insn_write	= pcl818_ao_insn_write;

		ret = comedi_alloc_subdev_readback(s);
		if (ret)
			return ret;
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	/* Digital Input subdevice */
	s = &dev->subdevices[2];
	s->type		= COMEDI_SUBD_DI;
	s->subdev_flags	= SDF_READABLE;
	s->n_chan	= 16;
	s->maxdata	= 1;
	s->range_table	= &range_digital;
	s->insn_bits	= pcl818_di_insn_bits;

	/* Digital Output subdevice */
	s = &dev->subdevices[3];
	s->type		= COMEDI_SUBD_DO;
	s->subdev_flags	= SDF_WRITABLE;
	s->n_chan	= 16;
	s->maxdata	= 1;
	s->range_table	= &range_digital;
	s->insn_bits	= pcl818_do_insn_bits;

	pcl818_reset(dev);

	return 0;
}