in drivers/pcl812.c [1128:1313]
static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl812_board *board = dev->board_ptr;
struct pcl812_private *devpriv;
struct comedi_subdevice *s;
int n_subdevices;
int subdev;
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;
if (board->irq_bits) {
dev->pacer = comedi_8254_init(dev->iobase + PCL812_TIMER_BASE,
I8254_OSC_BASE_2MHZ,
I8254_IO8, 0);
if (!dev->pacer)
return -ENOMEM;
if ((1 << it->options[1]) & board->irq_bits) {
ret = request_irq(it->options[1], pcl812_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 && board->has_dma)
pcl812_alloc_dma(dev, it->options[2]);
/* differential analog inputs? */
switch (board->board_type) {
case BOARD_A821:
if (it->options[2] == 1)
devpriv->use_diff = 1;
break;
case BOARD_ACL8112:
case BOARD_ACL8216:
if (it->options[4] == 1)
devpriv->use_diff = 1;
break;
default:
break;
}
n_subdevices = 1; /* all boardtypes have analog inputs */
if (board->n_aochan > 0)
n_subdevices++;
if (board->has_dio)
n_subdevices += 2;
ret = comedi_alloc_subdevices(dev, n_subdevices);
if (ret)
return ret;
subdev = 0;
/* Analog Input subdevice */
s = &dev->subdevices[subdev];
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE;
if (devpriv->use_diff) {
s->subdev_flags |= SDF_DIFF;
s->n_chan = board->n_aichan / 2;
} else {
s->subdev_flags |= SDF_GROUND;
s->n_chan = board->n_aichan;
}
s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff;
pcl812_set_ai_range_table(dev, s, it);
s->insn_read = pcl812_ai_insn_read;
if (dev->irq) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->len_chanlist = MAX_CHANLIST_LEN;
s->do_cmdtest = pcl812_ai_cmdtest;
s->do_cmd = pcl812_ai_cmd;
s->poll = pcl812_ai_poll;
s->cancel = pcl812_ai_cancel;
}
devpriv->use_mpc508 = board->has_mpc508_mux;
subdev++;
/* analog output */
if (board->n_aochan > 0) {
s = &dev->subdevices[subdev];
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
s->n_chan = board->n_aochan;
s->maxdata = 0xfff;
switch (board->board_type) {
case BOARD_A821:
if (it->options[3] == 1)
s->range_table = &range_unipolar10;
else
s->range_table = &range_unipolar5;
break;
case BOARD_PCL812:
case BOARD_ACL8112:
case BOARD_PCL812PG:
case BOARD_ACL8216:
switch (it->options[5]) {
case 1:
s->range_table = &range_unipolar10;
break;
case 2:
s->range_table = &range_unknown;
break;
default:
s->range_table = &range_unipolar5;
break;
}
break;
default:
s->range_table = &range_unipolar5;
break;
}
s->insn_write = pcl812_ao_insn_write;
ret = comedi_alloc_subdev_readback(s);
if (ret)
return ret;
subdev++;
}
if (board->has_dio) {
/* Digital Input subdevice */
s = &dev->subdevices[subdev];
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 = pcl812_di_insn_bits;
subdev++;
/* Digital Output subdevice */
s = &dev->subdevices[subdev];
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 = pcl812_do_insn_bits;
subdev++;
}
switch (board->board_type) {
case BOARD_ACL8216:
case BOARD_PCL812PG:
case BOARD_PCL812:
case BOARD_ACL8112:
devpriv->max_812_ai_mode0_rangewait = 1;
if (it->options[3] > 0)
/* we use external trigger */
devpriv->use_ext_trg = 1;
break;
case BOARD_A821:
devpriv->max_812_ai_mode0_rangewait = 1;
devpriv->mode_reg_int = (dev->irq << 4) & 0xf0;
break;
case BOARD_PCL813B:
case BOARD_PCL813:
case BOARD_ISO813:
case BOARD_ACL8113:
/* maybe there must by greatest timeout */
devpriv->max_812_ai_mode0_rangewait = 5;
break;
}
pcl812_reset(dev);
return 0;
}