int labpc_common_attach()

in drivers/ni_labpc_common.c [1186:1337]


int labpc_common_attach(struct comedi_device *dev,
			unsigned int irq, unsigned long isr_flags)
{
	const struct labpc_boardinfo *board = dev->board_ptr;
	struct labpc_private *devpriv;
	struct comedi_subdevice *s;
	int ret;
	int i;

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

	if (dev->mmio) {
		devpriv->read_byte = labpc_readb;
		devpriv->write_byte = labpc_writeb;
	} else {
		devpriv->read_byte = labpc_inb;
		devpriv->write_byte = labpc_outb;
	}

	/* initialize board's command registers */
	devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG);
	devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
	devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG);
	devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG);
	if (board->is_labpc1200) {
		devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
		devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG);
	}

	if (irq) {
		ret = request_irq(irq, labpc_interrupt, isr_flags,
				  dev->board_name, dev);
		if (ret == 0)
			dev->irq = irq;
	}

	if (dev->mmio) {
		dev->pacer = comedi_8254_mm_init(dev->mmio + COUNTER_B_BASE_REG,
						 I8254_OSC_BASE_2MHZ,
						 I8254_IO8, 0);
		devpriv->counter = comedi_8254_mm_init(dev->mmio +
						       COUNTER_A_BASE_REG,
						       I8254_OSC_BASE_2MHZ,
						       I8254_IO8, 0);
	} else {
		dev->pacer = comedi_8254_init(dev->iobase + COUNTER_B_BASE_REG,
					      I8254_OSC_BASE_2MHZ,
					      I8254_IO8, 0);
		devpriv->counter = comedi_8254_init(dev->iobase +
						    COUNTER_A_BASE_REG,
						    I8254_OSC_BASE_2MHZ,
						    I8254_IO8, 0);
	}
	if (!dev->pacer || !devpriv->counter)
		return -ENOMEM;

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

	/* analog input subdevice */
	s = &dev->subdevices[0];
	s->type		= COMEDI_SUBD_AI;
	s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;
	s->n_chan	= 8;
	s->len_chanlist	= 8;
	s->maxdata	= 0x0fff;
	s->range_table	= board->is_labpc1200 ?
			  &range_labpc_1200_ai : &range_labpc_plus_ai;
	s->insn_read	= labpc_ai_insn_read;
	if (dev->irq) {
		dev->read_subdev = s;
		s->subdev_flags	|= SDF_CMD_READ;
		s->do_cmd	= labpc_ai_cmd;
		s->do_cmdtest	= labpc_ai_cmdtest;
		s->cancel	= labpc_cancel;
	}

	/* analog output */
	s = &dev->subdevices[1];
	if (board->has_ao) {
		s->type		= COMEDI_SUBD_AO;
		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
		s->n_chan	= 2;
		s->maxdata	= 0x0fff;
		s->range_table	= &range_labpc_ao;
		s->insn_write	= labpc_ao_insn_write;

		ret = comedi_alloc_subdev_readback(s);
		if (ret)
			return ret;

		/* initialize analog outputs to a known value */
		for (i = 0; i < s->n_chan; i++)
			labpc_ao_write(dev, s, i, s->maxdata / 2);
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	/* 8255 dio */
	s = &dev->subdevices[2];
	if (dev->mmio)
		ret = subdev_8255_mm_init(dev, s, NULL, DIO_BASE_REG);
	else
		ret = subdev_8255_init(dev, s, NULL, DIO_BASE_REG);
	if (ret)
		return ret;

	/*  calibration subdevices for boards that have one */
	s = &dev->subdevices[3];
	if (board->is_labpc1200) {
		s->type		= COMEDI_SUBD_CALIB;
		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
		s->n_chan	= 16;
		s->maxdata	= 0xff;
		s->insn_write	= labpc_calib_insn_write;

		ret = comedi_alloc_subdev_readback(s);
		if (ret)
			return ret;

		for (i = 0; i < s->n_chan; i++) {
			write_caldac(dev, i, s->maxdata / 2);
			s->readback[i] = s->maxdata / 2;
		}
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	/* EEPROM (256 bytes) */
	s = &dev->subdevices[4];
	if (board->is_labpc1200) {
		s->type		= COMEDI_SUBD_MEMORY;
		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
		s->n_chan	= 256;
		s->maxdata	= 0xff;
		s->insn_write	= labpc_eeprom_insn_write;

		ret = comedi_alloc_subdev_readback(s);
		if (ret)
			return ret;

		for (i = 0; i < s->n_chan; i++)
			s->readback[i] = labpc_eeprom_read(dev, i);
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	return 0;
}