static int adl_pci7x3x_auto_attach()

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