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;
}