static int setup_subdevices()

in drivers/cb_pcidas64.c [3779:3965]


static int setup_subdevices(struct comedi_device *dev)
{
	const struct pcidas64_board *board = dev->board_ptr;
	struct pcidas64_private *devpriv = dev->private;
	struct comedi_subdevice *s;
	int i;
	int ret;

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

	s = &dev->subdevices[0];
	/* analog input subdevice */
	dev->read_subdev = s;
	s->type = COMEDI_SUBD_AI;
	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DITHER | SDF_CMD_READ;
	if (board->layout == LAYOUT_60XX)
		s->subdev_flags |= SDF_COMMON | SDF_DIFF;
	else if (board->layout == LAYOUT_64XX)
		s->subdev_flags |= SDF_DIFF;
	/* XXX Number of inputs in differential mode is ignored */
	s->n_chan = board->ai_se_chans;
	s->len_chanlist = 0x2000;
	s->maxdata = (1 << board->ai_bits) - 1;
	s->range_table = board->ai_range_table;
	s->insn_read = ai_rinsn;
	s->insn_config = ai_config_insn;
	s->do_cmd = ai_cmd;
	s->do_cmdtest = ai_cmdtest;
	s->cancel = ai_cancel;
	if (board->layout == LAYOUT_4020) {
		u8 data;
		/*
		 * set adc to read from inputs
		 * (not internal calibration sources)
		 */
		devpriv->i2c_cal_range_bits = adc_src_4020_bits(4);
		/* set channels to +-5 volt input ranges */
		for (i = 0; i < s->n_chan; i++)
			devpriv->i2c_cal_range_bits |= attenuate_bit(i);
		data = devpriv->i2c_cal_range_bits;
		i2c_write(dev, RANGE_CAL_I2C_ADDR, &data, sizeof(data));
	}

	/* analog output subdevice */
	s = &dev->subdevices[1];
	if (board->ao_nchan) {
		s->type = COMEDI_SUBD_AO;
		s->subdev_flags = SDF_READABLE | SDF_WRITABLE |
				  SDF_GROUND | SDF_CMD_WRITE;
		s->n_chan = board->ao_nchan;
		s->maxdata = (1 << board->ao_bits) - 1;
		s->range_table = board->ao_range_table;
		s->insn_write = ao_winsn;

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

		if (ao_cmd_is_supported(board)) {
			dev->write_subdev = s;
			s->do_cmdtest = ao_cmdtest;
			s->do_cmd = ao_cmd;
			s->len_chanlist = board->ao_nchan;
			s->cancel = ao_cancel;
		}
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}

	/* digital input */
	s = &dev->subdevices[2];
	if (board->layout == LAYOUT_64XX) {
		s->type = COMEDI_SUBD_DI;
		s->subdev_flags = SDF_READABLE;
		s->n_chan = 4;
		s->maxdata = 1;
		s->range_table = &range_digital;
		s->insn_bits = di_rbits;
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}

	/* digital output */
	if (board->layout == LAYOUT_64XX) {
		s = &dev->subdevices[3];
		s->type = COMEDI_SUBD_DO;
		s->subdev_flags = SDF_WRITABLE;
		s->n_chan = 4;
		s->maxdata = 1;
		s->range_table = &range_digital;
		s->insn_bits = do_wbits;
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}

	/* 8255 */
	s = &dev->subdevices[4];
	if (board->has_8255) {
		if (board->layout == LAYOUT_4020) {
			ret = subdev_8255_init(dev, s, dio_callback_4020,
					       I8255_4020_REG);
		} else {
			ret = subdev_8255_mm_init(dev, s, NULL,
						  DIO_8255_OFFSET);
		}
		if (ret)
			return ret;
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}

	/* 8 channel dio for 60xx */
	s = &dev->subdevices[5];
	if (board->layout == LAYOUT_60XX) {
		s->type = COMEDI_SUBD_DIO;
		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
		s->n_chan = 8;
		s->maxdata = 1;
		s->range_table = &range_digital;
		s->insn_config = dio_60xx_config_insn;
		s->insn_bits = dio_60xx_wbits;
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}

	/* caldac */
	s = &dev->subdevices[6];
	s->type = COMEDI_SUBD_CALIB;
	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
	s->n_chan = 8;
	if (board->layout == LAYOUT_4020)
		s->maxdata = 0xfff;
	else
		s->maxdata = 0xff;
	s->insn_write = cb_pcidas64_calib_insn_write;

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

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

	/* 2 channel ad8402 potentiometer */
	s = &dev->subdevices[7];
	if (board->layout == LAYOUT_64XX) {
		s->type = COMEDI_SUBD_CALIB;
		s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
		s->n_chan = 2;
		s->maxdata = 0xff;
		s->insn_write = cb_pcidas64_ad8402_insn_write;

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

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

	/* serial EEPROM, if present */
	s = &dev->subdevices[8];
	if (readl(devpriv->plx9080_iobase + PLX_REG_CNTRL) &
	    PLX_CNTRL_EEPRESENT) {
		s->type = COMEDI_SUBD_MEMORY;
		s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
		s->n_chan = 128;
		s->maxdata = 0xffff;
		s->insn_read = eeprom_read_insn;
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}

	/* user counter subd XXX */
	s = &dev->subdevices[9];
	s->type = COMEDI_SUBD_UNUSED;

	return 0;
}