in drivers/adl_pci7x3x.c [341:497]
static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct adl_pci7x3x_boardinfo *board = NULL;
struct comedi_subdevice *s;
struct adl_pci7x3x_dev_private_data *dev_private;
int subdev;
int nchan;
int ret;
int ic;
if (context < ARRAY_SIZE(adl_pci7x3x_boards))
board = &adl_pci7x3x_boards[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;
dev->iobase = pci_resource_start(pcidev, 2);
dev_private->lcr_io_base = pci_resource_start(pcidev, 1);
adl_pci7x3x_reset(dev);
if (board->irq_nchan) {
/* discard all evtl. old IRQs */
outb(0x00, dev->iobase + ADL_PT_CLRIRQ);
if (pcidev->irq) {
ret = request_irq(pcidev->irq, adl_pci7x3x_interrupt,
IRQF_SHARED, dev->board_name, dev);
if (ret == 0) {
dev->irq = pcidev->irq;
/* 0x52 PCI + IDI Ch 1 Ch 0 IRQ Off ActHigh */
dev_private->int_ctrl = EN_PCI_LINT2H_LINT1H;
outl(dev_private->int_ctrl,
dev_private->lcr_io_base + PLX9052_INTCSR);
}
}
}
ret = comedi_alloc_subdevices(dev, board->nsubdevs);
if (ret)
return ret;
subdev = 0;
if (board->di_nchan) {
nchan = min(board->di_nchan, 32);
s = &dev->subdevices[subdev];
/* Isolated digital inputs 0 to 15/31 */
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE;
s->n_chan = nchan;
s->maxdata = 1;
s->insn_bits = adl_pci7x3x_di_insn_bits;
s->range_table = &range_digital;
s->private = (void *)PCI7X3X_DIO_REG;
subdev++;
nchan = board->di_nchan - nchan;
if (nchan) {
s = &dev->subdevices[subdev];
/* Isolated digital inputs 32 to 63 */
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE;
s->n_chan = nchan;
s->maxdata = 1;
s->insn_bits = adl_pci7x3x_di_insn_bits;
s->range_table = &range_digital;
s->private = (void *)PCI743X_DIO_REG;
subdev++;
}
}
if (board->do_nchan) {
nchan = min(board->do_nchan, 32);
s = &dev->subdevices[subdev];
/* Isolated digital outputs 0 to 15/31 */
s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = nchan;
s->maxdata = 1;
s->insn_bits = adl_pci7x3x_do_insn_bits;
s->range_table = &range_digital;
s->private = (void *)PCI7X3X_DIO_REG;
subdev++;
nchan = board->do_nchan - nchan;
if (nchan) {
s = &dev->subdevices[subdev];
/* Isolated digital outputs 32 to 63 */
s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = nchan;
s->maxdata = 1;
s->insn_bits = adl_pci7x3x_do_insn_bits;
s->range_table = &range_digital;
s->private = (void *)PCI743X_DIO_REG;
subdev++;
}
}
for (ic = 0; ic < board->irq_nchan; ++ic) {
struct adl_pci7x3x_sd_private_data *sd_priv;
nchan = 1;
s = &dev->subdevices[subdev];
/* Isolated digital inputs 0 or 1 */
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE;
s->n_chan = nchan;
s->maxdata = 1;
s->insn_bits = adl_pci7x3x_dirq_insn_bits;
s->range_table = &range_digital;
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 = PCI7X3X_DIO_REG;
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 = adl_pci7x3x_asy_cmdtest;
s->do_cmd = adl_pci7x3x_asy_cmd;
s->cancel = adl_pci7x3x_asy_cancel;
}
subdev++;
}
return 0;
}