in drivers/adv_pci_dio.c [547:710]
static int pci_dio_auto_attach(struct comedi_device *dev,
unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct dio_boardtype *board = NULL;
struct comedi_subdevice *s;
struct pci_dio_dev_private_data *dev_private;
int ret, subdev, i, j;
if (context < ARRAY_SIZE(boardtypes))
board = &boardtypes[context];
if (!board)
return -ENODEV;
dev->board_ptr = board;
dev->board_name = board->name;
dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private));
if (!dev_private)
return -ENOMEM;
ret = comedi_pci_enable(dev);
if (ret)
return ret;
if (context == TYPE_PCI1736)
dev->iobase = pci_resource_start(pcidev, 0);
else
dev->iobase = pci_resource_start(pcidev, 2);
dev_private->boardtype = context;
pci_dio_reset(dev, context);
/* request IRQ if device has irq subdevices */
if (board->sdirq[0].int_en && pcidev->irq) {
ret = request_irq(pcidev->irq, pci_dio_interrupt, IRQF_SHARED,
dev->board_name, dev);
if (ret == 0)
dev->irq = pcidev->irq;
}
ret = comedi_alloc_subdevices(dev, board->nsubdevs);
if (ret)
return ret;
subdev = 0;
for (i = 0; i < PCI_DIO_MAX_DI_SUBDEVS; i++) {
const struct diosubd_data *d = &board->sdi[i];
if (d->chans) {
s = &dev->subdevices[subdev++];
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE;
s->n_chan = d->chans;
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = board->is_16bit
? pci_dio_insn_bits_di_w
: pci_dio_insn_bits_di_b;
s->private = (void *)d->addr;
}
}
for (i = 0; i < PCI_DIO_MAX_DO_SUBDEVS; i++) {
const struct diosubd_data *d = &board->sdo[i];
if (d->chans) {
s = &dev->subdevices[subdev++];
s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = d->chans;
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = board->is_16bit
? pci_dio_insn_bits_do_w
: pci_dio_insn_bits_do_b;
s->private = (void *)d->addr;
/* reset all outputs to 0 */
if (board->is_16bit) {
outw(0, dev->iobase + d->addr);
if (s->n_chan > 16)
outw(0, dev->iobase + d->addr + 2);
} else {
outb(0, dev->iobase + d->addr);
if (s->n_chan > 8)
outb(0, dev->iobase + d->addr + 1);
if (s->n_chan > 16)
outb(0, dev->iobase + d->addr + 2);
if (s->n_chan > 24)
outb(0, dev->iobase + d->addr + 3);
}
}
}
for (i = 0; i < PCI_DIO_MAX_DIO_SUBDEVG; i++) {
const struct diosubd_data *d = &board->sdio[i];
for (j = 0; j < d->chans; j++) {
s = &dev->subdevices[subdev++];
ret = subdev_8255_init(dev, s, NULL,
d->addr + j * I8255_SIZE);
if (ret)
return ret;
}
}
if (board->id_reg) {
s = &dev->subdevices[subdev++];
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
s->n_chan = 4;
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = board->is_16bit ? pci_dio_insn_bits_di_w
: pci_dio_insn_bits_di_b;
s->private = (void *)board->id_reg;
}
if (board->timer_regbase) {
s = &dev->subdevices[subdev++];
dev->pacer = comedi_8254_init(dev->iobase +
board->timer_regbase,
0, I8254_IO8, 0);
if (!dev->pacer)
return -ENOMEM;
comedi_8254_subdevice_init(s, dev->pacer);
}
dev_private->irq_subd = subdev; /* first interrupt subdevice index */
for (i = 0; i < PCI_DIO_MAX_IRQ_SUBDEVS; ++i) {
struct pci_dio_sd_private_data *sd_priv = NULL;
const struct dio_irq_subd_data *d = &board->sdirq[i];
if (d->int_en) {
s = &dev->subdevices[subdev++];
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE;
s->n_chan = 1;
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = pci_dio_insn_bits_dirq_b;
sd_priv = comedi_alloc_spriv(s, sizeof(*sd_priv));
if (!sd_priv)
return -ENOMEM;
spin_lock_init(&sd_priv->subd_slock);
sd_priv->port_offset = d->addr;
sd_priv->cmd_running = 0;
if (dev->irq) {
dev->read_subdev = s;
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
s->len_chanlist = 1;
s->do_cmdtest = pci_dio_asy_cmdtest;
s->do_cmd = pci_dio_asy_cmd;
s->cancel = pci_dio_asy_cancel;
}
}
}
return 0;
}