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