in drivers/das16.c [1015:1165]
static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct das16_board *board = dev->board_ptr;
struct das16_private_struct *devpriv;
struct comedi_subdevice *s;
unsigned int osc_base;
unsigned int status;
int ret;
/* check that clock setting is valid */
if (it->options[3]) {
if (it->options[3] != 1 && it->options[3] != 10) {
dev_err(dev->class_dev,
"Invalid option. Master clock must be set to 1 or 10 (MHz)\n");
return -EINVAL;
}
}
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
devpriv->dev = dev;
if (board->size < 0x400) {
ret = comedi_request_region(dev, it->options[0], board->size);
if (ret)
return ret;
} else {
ret = comedi_request_region(dev, it->options[0], 0x10);
if (ret)
return ret;
/* Request an additional region for the 8255 */
ret = __comedi_request_region(dev, dev->iobase + 0x400,
board->size & 0x3ff);
if (ret)
return ret;
devpriv->extra_iobase = dev->iobase + 0x400;
devpriv->can_burst = 1;
}
/* probe id bits to make sure they are consistent */
if (das16_probe(dev, it))
return -EINVAL;
/* get master clock speed */
osc_base = I8254_OSC_BASE_1MHZ;
if (devpriv->can_burst) {
status = inb(dev->iobase + DAS1600_STATUS_REG);
if (status & DAS1600_STATUS_CLK_10MHZ)
osc_base = I8254_OSC_BASE_10MHZ;
} else {
if (it->options[3])
osc_base = I8254_OSC_BASE_1MHZ / it->options[3];
}
dev->pacer = comedi_8254_init(dev->iobase + DAS16_TIMER_BASE_REG,
osc_base, I8254_IO8, 0);
if (!dev->pacer)
return -ENOMEM;
das16_alloc_dma(dev, it->options[2]);
ret = comedi_alloc_subdevices(dev, 4 + board->has_8255);
if (ret)
return ret;
status = inb(dev->iobase + DAS16_STATUS_REG);
/* Analog Input subdevice */
s = &dev->subdevices[0];
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE;
if (status & DAS16_STATUS_MUXBIT) {
s->subdev_flags |= SDF_GROUND;
s->n_chan = 16;
} else {
s->subdev_flags |= SDF_DIFF;
s->n_chan = 8;
}
s->len_chanlist = s->n_chan;
s->maxdata = board->ai_maxdata;
s->range_table = das16_ai_range(dev, s, it, board->ai_pg, status);
s->insn_read = das16_ai_insn_read;
if (devpriv->dma) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->do_cmdtest = das16_cmd_test;
s->do_cmd = das16_cmd_exec;
s->cancel = das16_cancel;
s->munge = das16_ai_munge;
}
/* Analog Output subdevice */
s = &dev->subdevices[1];
if (board->has_ao) {
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 2;
s->maxdata = 0x0fff;
s->range_table = das16_ao_range(dev, s, it);
s->insn_write = das16_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 = 4;
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = das16_di_insn_bits;
/* Digital Output subdevice */
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 = das16_do_insn_bits;
/* initialize digital output lines */
outb(s->state, dev->iobase + DAS16_DIO_REG);
/* 8255 Digital I/O subdevice */
if (board->has_8255) {
s = &dev->subdevices[4];
ret = subdev_8255_init(dev, s, NULL, board->i8255_offset);
if (ret)
return ret;
}
das16_reset(dev);
/* set the interrupt level */
devpriv->ctrl_reg = DAS16_CTRL_IRQ(dev->irq);
outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
if (devpriv->can_burst) {
outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE_REG);
outb(0, dev->iobase + DAS1600_CONV_REG);
outb(0, dev->iobase + DAS1600_BURST_REG);
}
return 0;
}