static int ni_E_init()

in drivers/ni_mio_common.c [5970:6333]


static int ni_E_init(struct comedi_device *dev,
		     unsigned int interrupt_pin, unsigned int irq_polarity)
{
	const struct ni_board_struct *board = dev->board_ptr;
	struct ni_private *devpriv = dev->private;
	struct comedi_subdevice *s;
	int ret;
	int i;
	const char *dev_family = devpriv->is_m_series ? "ni_mseries"
						      : "ni_eseries";

	/* prepare the device for globally-named routes. */
	if (ni_assign_device_routes(dev_family, board->name,
				    board->alt_route_name,
				    &devpriv->routing_tables) < 0) {
		dev_warn(dev->class_dev, "%s: %s device has no signal routing table.\n",
			 __func__, board->name);
		dev_warn(dev->class_dev, "%s: High level NI signal names will not be available for this %s board.\n",
			 __func__, board->name);
	} else {
		/*
		 * only(?) assign insn_device_config if we have global names for
		 * this device.
		 */
		dev->insn_device_config = ni_global_insn_config;
		dev->get_valid_routes = _ni_get_valid_routes;
	}

	if (board->n_aochan > MAX_N_AO_CHAN) {
		dev_err(dev->class_dev, "bug! n_aochan > MAX_N_AO_CHAN\n");
		return -EINVAL;
	}

	/* initialize clock dividers */
	devpriv->clock_and_fout = NISTC_CLK_FOUT_SLOW_DIV2 |
				  NISTC_CLK_FOUT_SLOW_TIMEBASE |
				  NISTC_CLK_FOUT_TO_BOARD_DIV2 |
				  NISTC_CLK_FOUT_TO_BOARD;
	if (!devpriv->is_6xxx) {
		/* BEAM is this needed for PCI-6143 ?? */
		devpriv->clock_and_fout |= (NISTC_CLK_FOUT_AI_OUT_DIV2 |
					    NISTC_CLK_FOUT_AO_OUT_DIV2);
	}
	ni_stc_writew(dev, devpriv->clock_and_fout, NISTC_CLK_FOUT_REG);

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

	/* Analog Input subdevice */
	s = &dev->subdevices[NI_AI_SUBDEV];
	if (board->n_adchan) {
		s->type		= COMEDI_SUBD_AI;
		s->subdev_flags	= SDF_READABLE | SDF_DIFF | SDF_DITHER;
		if (!devpriv->is_611x)
			s->subdev_flags	|= SDF_GROUND | SDF_COMMON | SDF_OTHER;
		if (board->ai_maxdata > 0xffff)
			s->subdev_flags	|= SDF_LSAMPL;
		if (devpriv->is_m_series)
			s->subdev_flags	|= SDF_SOFT_CALIBRATED;
		s->n_chan	= board->n_adchan;
		s->maxdata	= board->ai_maxdata;
		s->range_table	= ni_range_lkup[board->gainlkup];
		s->insn_read	= ni_ai_insn_read;
		s->insn_config	= ni_ai_insn_config;
		if (dev->irq) {
			dev->read_subdev = s;
			s->subdev_flags	|= SDF_CMD_READ;
			s->len_chanlist	= 512;
			s->do_cmdtest	= ni_ai_cmdtest;
			s->do_cmd	= ni_ai_cmd;
			s->cancel	= ni_ai_reset;
			s->poll		= ni_ai_poll;
			s->munge	= ni_ai_munge;

			if (devpriv->mite)
				s->async_dma_dir = DMA_FROM_DEVICE;
		}

		/* reset the analog input configuration */
		ni_ai_reset(dev, s);
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	/* Analog Output subdevice */
	s = &dev->subdevices[NI_AO_SUBDEV];
	if (board->n_aochan) {
		s->type		= COMEDI_SUBD_AO;
		s->subdev_flags	= SDF_WRITABLE | SDF_DEGLITCH | SDF_GROUND;
		if (devpriv->is_m_series)
			s->subdev_flags	|= SDF_SOFT_CALIBRATED;
		s->n_chan	= board->n_aochan;
		s->maxdata	= board->ao_maxdata;
		s->range_table	= board->ao_range_table;
		s->insn_config	= ni_ao_insn_config;
		s->insn_write	= ni_ao_insn_write;

		ret = comedi_alloc_subdev_readback(s);
		if (ret)
			return ret;

		/*
		 * Along with the IRQ we need either a FIFO or DMA for
		 * async command support.
		 */
		if (dev->irq && (board->ao_fifo_depth || devpriv->mite)) {
			dev->write_subdev = s;
			s->subdev_flags	|= SDF_CMD_WRITE;
			s->len_chanlist	= s->n_chan;
			s->do_cmdtest	= ni_ao_cmdtest;
			s->do_cmd	= ni_ao_cmd;
			s->cancel	= ni_ao_reset;
			if (!devpriv->is_m_series)
				s->munge	= ni_ao_munge;

			if (devpriv->mite)
				s->async_dma_dir = DMA_TO_DEVICE;
		}

		if (devpriv->is_67xx)
			init_ao_67xx(dev, s);

		/* reset the analog output configuration */
		ni_ao_reset(dev, s);
	} else {
		s->type		= COMEDI_SUBD_UNUSED;
	}

	/* Digital I/O subdevice */
	s = &dev->subdevices[NI_DIO_SUBDEV];
	s->type		= COMEDI_SUBD_DIO;
	s->subdev_flags	= SDF_WRITABLE | SDF_READABLE;
	s->n_chan	= board->has_32dio_chan ? 32 : 8;
	s->maxdata	= 1;
	s->range_table	= &range_digital;
	if (devpriv->is_m_series) {
#ifdef PCIDMA
		s->subdev_flags	|= SDF_LSAMPL;
		s->insn_bits	= ni_m_series_dio_insn_bits;
		s->insn_config	= ni_m_series_dio_insn_config;
		if (dev->irq) {
			s->subdev_flags	|= SDF_CMD_WRITE /* | SDF_CMD_READ */;
			s->len_chanlist	= s->n_chan;
			s->do_cmdtest	= ni_cdio_cmdtest;
			s->do_cmd	= ni_cdio_cmd;
			s->cancel	= ni_cdio_cancel;

			/* M-series boards use DMA */
			s->async_dma_dir = DMA_BIDIRECTIONAL;
		}

		/* reset DIO and set all channels to inputs */
		ni_writel(dev, NI_M_CDO_CMD_RESET |
			       NI_M_CDI_CMD_RESET,
			  NI_M_CDIO_CMD_REG);
		ni_writel(dev, s->io_bits, NI_M_DIO_DIR_REG);
#endif /* PCIDMA */
	} else {
		s->insn_bits	= ni_dio_insn_bits;
		s->insn_config	= ni_dio_insn_config;

		/* set all channels to inputs */
		devpriv->dio_control = NISTC_DIO_CTRL_DIR(s->io_bits);
		ni_writew(dev, devpriv->dio_control, NISTC_DIO_CTRL_REG);
	}

	/* 8255 device */
	s = &dev->subdevices[NI_8255_DIO_SUBDEV];
	if (board->has_8255) {
		ret = subdev_8255_init(dev, s, ni_8255_callback,
				       NI_E_8255_BASE);
		if (ret)
			return ret;
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}

	/* formerly general purpose counter/timer device, but no longer used */
	s = &dev->subdevices[NI_UNUSED_SUBDEV];
	s->type = COMEDI_SUBD_UNUSED;

	/* Calibration subdevice */
	s = &dev->subdevices[NI_CALIBRATION_SUBDEV];
	s->type		= COMEDI_SUBD_CALIB;
	s->subdev_flags	= SDF_INTERNAL;
	s->n_chan	= 1;
	s->maxdata	= 0;
	if (devpriv->is_m_series) {
		/* internal PWM output used for AI nonlinearity calibration */
		s->insn_config	= ni_m_series_pwm_config;

		ni_writel(dev, 0x0, NI_M_CAL_PWM_REG);
	} else if (devpriv->is_6143) {
		/* internal PWM output used for AI nonlinearity calibration */
		s->insn_config	= ni_6143_pwm_config;
	} else {
		s->subdev_flags	|= SDF_WRITABLE;
		s->insn_read	= ni_calib_insn_read;
		s->insn_write	= ni_calib_insn_write;

		/* setup the caldacs and find the real n_chan and maxdata */
		caldac_setup(dev, s);
	}

	/* EEPROM subdevice */
	s = &dev->subdevices[NI_EEPROM_SUBDEV];
	s->type		= COMEDI_SUBD_MEMORY;
	s->subdev_flags	= SDF_READABLE | SDF_INTERNAL;
	s->maxdata	= 0xff;
	if (devpriv->is_m_series) {
		s->n_chan	= M_SERIES_EEPROM_SIZE;
		s->insn_read	= ni_m_series_eeprom_insn_read;
	} else {
		s->n_chan	= 512;
		s->insn_read	= ni_eeprom_insn_read;
	}

	/* Digital I/O (PFI) subdevice */
	s = &dev->subdevices[NI_PFI_DIO_SUBDEV];
	s->type		= COMEDI_SUBD_DIO;
	s->maxdata	= 1;
	if (devpriv->is_m_series) {
		s->n_chan	= 16;
		s->insn_bits	= ni_pfi_insn_bits;
		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;

		ni_writew(dev, s->state, NI_M_PFI_DO_REG);
		for (i = 0; i < NUM_PFI_OUTPUT_SELECT_REGS; ++i) {
			ni_writew(dev, devpriv->pfi_output_select_reg[i],
				  NI_M_PFI_OUT_SEL_REG(i));
		}
	} else {
		s->n_chan	= 10;
		s->subdev_flags	= SDF_INTERNAL;
	}
	s->insn_config	= ni_pfi_insn_config;

	ni_set_bits(dev, NISTC_IO_BIDIR_PIN_REG, ~0, 0);

	/* cs5529 calibration adc */
	s = &dev->subdevices[NI_CS5529_CALIBRATION_SUBDEV];
	if (devpriv->is_67xx) {
		s->type = COMEDI_SUBD_AI;
		s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL;
		/*  one channel for each analog output channel */
		s->n_chan = board->n_aochan;
		s->maxdata = BIT(16) - 1;
		s->range_table = &range_unknown;	/* XXX */
		s->insn_read = cs5529_ai_insn_read;
		s->insn_config = NULL;
		init_cs5529(dev);
	} else {
		s->type = COMEDI_SUBD_UNUSED;
	}

	/* Serial */
	s = &dev->subdevices[NI_SERIAL_SUBDEV];
	s->type = COMEDI_SUBD_SERIAL;
	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
	s->n_chan = 1;
	s->maxdata = 0xff;
	s->insn_config = ni_serial_insn_config;
	devpriv->serial_interval_ns = 0;
	devpriv->serial_hw_mode = 0;

	/* RTSI */
	s = &dev->subdevices[NI_RTSI_SUBDEV];
	s->type = COMEDI_SUBD_DIO;
	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
	s->n_chan = 8;
	s->maxdata = 1;
	s->insn_bits = ni_rtsi_insn_bits;
	s->insn_config = ni_rtsi_insn_config;
	ni_rtsi_init(dev);

	/* allocate and initialize the gpct counter device */
	devpriv->counter_dev = ni_gpct_device_construct(dev,
					ni_gpct_write_register,
					ni_gpct_read_register,
					(devpriv->is_m_series)
						? ni_gpct_variant_m_series
						: ni_gpct_variant_e_series,
					NUM_GPCT,
					NUM_GPCT,
					&devpriv->routing_tables);
	if (!devpriv->counter_dev)
		return -ENOMEM;

	/* Counter (gpct) subdevices */
	for (i = 0; i < NUM_GPCT; ++i) {
		struct ni_gpct *gpct = &devpriv->counter_dev->counters[i];

		/* setup and initialize the counter */
		ni_tio_init_counter(gpct);

		s = &dev->subdevices[NI_GPCT_SUBDEV(i)];
		s->type		= COMEDI_SUBD_COUNTER;
		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
		s->n_chan	= 3;
		s->maxdata	= (devpriv->is_m_series) ? 0xffffffff
							 : 0x00ffffff;
		s->insn_read	= ni_tio_insn_read;
		s->insn_write	= ni_tio_insn_write;
		s->insn_config	= ni_tio_insn_config;
#ifdef PCIDMA
		if (dev->irq && devpriv->mite) {
			s->subdev_flags	|= SDF_CMD_READ /* | SDF_CMD_WRITE */;
			s->len_chanlist	= 1;
			s->do_cmdtest	= ni_tio_cmdtest;
			s->do_cmd	= ni_gpct_cmd;
			s->cancel	= ni_gpct_cancel;

			s->async_dma_dir = DMA_BIDIRECTIONAL;
		}
#endif
		s->private	= gpct;
	}

	/* Initialize GPFO_{0,1} to produce output of counters */
	ni_set_gout_routing(0, 0, dev); /* output of counter 0; DAQ STC, p338 */
	ni_set_gout_routing(0, 1, dev); /* output of counter 1; DAQ STC, p338 */

	/* Frequency output subdevice */
	s = &dev->subdevices[NI_FREQ_OUT_SUBDEV];
	s->type		= COMEDI_SUBD_COUNTER;
	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
	s->n_chan	= 1;
	s->maxdata	= 0xf;
	s->insn_read	= ni_freq_out_insn_read;
	s->insn_write	= ni_freq_out_insn_write;
	s->insn_config	= ni_freq_out_insn_config;

	if (dev->irq) {
		ni_stc_writew(dev,
			      (irq_polarity ? NISTC_INT_CTRL_INT_POL : 0) |
			      (NISTC_INT_CTRL_3PIN_INT & 0) |
			      NISTC_INT_CTRL_INTA_ENA |
			      NISTC_INT_CTRL_INTB_ENA |
			      NISTC_INT_CTRL_INTA_SEL(interrupt_pin) |
			      NISTC_INT_CTRL_INTB_SEL(interrupt_pin),
			      NISTC_INT_CTRL_REG);
	}

	/* DMA setup */
	ni_writeb(dev, devpriv->ai_ao_select_reg, NI_E_DMA_AI_AO_SEL_REG);
	ni_writeb(dev, devpriv->g0_g1_select_reg, NI_E_DMA_G0_G1_SEL_REG);

	if (devpriv->is_6xxx) {
		ni_writeb(dev, 0, NI611X_MAGIC_REG);
	} else if (devpriv->is_m_series) {
		int channel;

		for (channel = 0; channel < board->n_aochan; ++channel) {
			ni_writeb(dev, 0xf,
				  NI_M_AO_WAVEFORM_ORDER_REG(channel));
			ni_writeb(dev, 0x0,
				  NI_M_AO_REF_ATTENUATION_REG(channel));
		}
		ni_writeb(dev, 0x0, NI_M_AO_CALIB_REG);
	}

	return 0;
}