static int apci1564_auto_attach()

in drivers/addi_apci_1564.c [658:782]


static int apci1564_auto_attach(struct comedi_device *dev,
				unsigned long context_unused)
{
	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
	struct apci1564_private *devpriv;
	struct comedi_subdevice *s;
	unsigned int val;
	int ret;

	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
	if (!devpriv)
		return -ENOMEM;

	ret = comedi_pci_enable(dev);
	if (ret)
		return ret;

	/* read the EEPROM register and check the I/O map revision */
	devpriv->eeprom = pci_resource_start(pcidev, 0);
	val = inl(devpriv->eeprom + APCI1564_EEPROM_REG);
	if (APCI1564_EEPROM_TO_REV(val) == 0) {
		/* PLD Revision 1.0 I/O Mapping */
		dev->iobase = pci_resource_start(pcidev, 1) +
			      APCI1564_REV1_MAIN_IOBASE;
		devpriv->timer = devpriv->eeprom + APCI1564_REV1_TIMER_IOBASE;
	} else {
		/* PLD Revision 2.x I/O Mapping */
		dev->iobase = devpriv->eeprom + APCI1564_REV2_MAIN_IOBASE;
		devpriv->timer = devpriv->eeprom + APCI1564_REV2_TIMER_IOBASE;
		devpriv->counters = pci_resource_start(pcidev, 1);
	}

	apci1564_reset(dev);

	if (pcidev->irq > 0) {
		ret = request_irq(pcidev->irq, apci1564_interrupt, IRQF_SHARED,
				  dev->board_name, dev);
		if (ret == 0)
			dev->irq = pcidev->irq;
	}

	ret = comedi_alloc_subdevices(dev, 7);
	if (ret)
		return ret;

	/*  Allocate and Initialise DI Subdevice Structures */
	s = &dev->subdevices[0];
	s->type		= COMEDI_SUBD_DI;
	s->subdev_flags	= SDF_READABLE;
	s->n_chan	= 32;
	s->maxdata	= 1;
	s->range_table	= &range_digital;
	s->insn_bits	= apci1564_di_insn_bits;

	/*  Allocate and Initialise DO Subdevice Structures */
	s = &dev->subdevices[1];
	s->type		= COMEDI_SUBD_DO;
	s->subdev_flags	= SDF_WRITABLE;
	s->n_chan	= 32;
	s->maxdata	= 1;
	s->range_table	= &range_digital;
	s->insn_bits	= apci1564_do_insn_bits;

	/* Change-Of-State (COS) interrupt subdevice */
	s = &dev->subdevices[2];
	if (dev->irq) {
		dev->read_subdev = s;
		s->type		= COMEDI_SUBD_DI;
		s->subdev_flags	= SDF_READABLE | SDF_CMD_READ | SDF_LSAMPL;
		s->n_chan	= 1;
		s->maxdata	= 1;
		s->range_table	= &range_digital;
		s->len_chanlist	= 1;
		s->insn_config	= apci1564_cos_insn_config;
		s->insn_bits	= apci1564_cos_insn_bits;
		s->do_cmdtest	= apci1564_cos_cmdtest;
		s->do_cmd	= apci1564_cos_cmd;
		s->cancel	= apci1564_cos_cancel;
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	/* Timer subdevice */
	s = &dev->subdevices[3];
	s->type		= COMEDI_SUBD_TIMER;
	s->subdev_flags	= SDF_WRITABLE | SDF_READABLE;
	s->n_chan	= 1;
	s->maxdata	= 0x0fff;
	s->range_table	= &range_digital;
	s->insn_config	= apci1564_timer_insn_config;
	s->insn_write	= apci1564_timer_insn_write;
	s->insn_read	= apci1564_timer_insn_read;

	/* Counter subdevice */
	s = &dev->subdevices[4];
	if (devpriv->counters) {
		s->type		= COMEDI_SUBD_COUNTER;
		s->subdev_flags	= SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL;
		s->n_chan	= 3;
		s->maxdata	= 0xffffffff;
		s->range_table	= &range_digital;
		s->insn_config	= apci1564_counter_insn_config;
		s->insn_write	= apci1564_counter_insn_write;
		s->insn_read	= apci1564_counter_insn_read;
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	/* Initialize the watchdog subdevice */
	s = &dev->subdevices[5];
	ret = addi_watchdog_init(s, dev->iobase + APCI1564_WDOG_IOBASE);
	if (ret)
		return ret;

	/* Initialize the diagnostic status subdevice */
	s = &dev->subdevices[6];
	s->type		= COMEDI_SUBD_DI;
	s->subdev_flags	= SDF_READABLE;
	s->n_chan	= 2;
	s->maxdata	= 1;
	s->range_table	= &range_digital;
	s->insn_bits	= apci1564_diag_insn_bits;

	return 0;
}