static int ni_ai_cmd()

in drivers/ni_mio_common.c [2162:2462]


static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
	struct ni_private *devpriv = dev->private;
	const struct comedi_cmd *cmd = &s->async->cmd;
	int timer;
	int mode1 = 0;		/* mode1 is needed for both stop and convert */
	int mode2 = 0;
	int start_stop_select = 0;
	unsigned int stop_count;
	int interrupt_a_enable = 0;
	unsigned int ai_trig;

	if (dev->irq == 0) {
		dev_err(dev->class_dev, "cannot run command without an irq\n");
		return -EIO;
	}
	ni_clear_ai_fifo(dev);

	ni_load_channelgain_list(dev, s, cmd->chanlist_len, cmd->chanlist);

	/* start configuration */
	ni_stc_writew(dev, NISTC_RESET_AI_CFG_START, NISTC_RESET_REG);

	/*
	 * Disable analog triggering for now, since it interferes
	 * with the use of pfi0.
	 */
	devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_ENA;
	ni_stc_writew(dev, devpriv->an_trig_etc_reg, NISTC_ATRIG_ETC_REG);

	ai_trig = NISTC_AI_TRIG_START2_SEL(0) | NISTC_AI_TRIG_START1_SYNC;
	switch (cmd->start_src) {
	case TRIG_INT:
	case TRIG_NOW:
		ai_trig |= NISTC_AI_TRIG_START1_EDGE |
			   NISTC_AI_TRIG_START1_SEL(0);
		break;
	case TRIG_EXT:
		ai_trig |= NISTC_AI_TRIG_START1_SEL(
				ni_get_reg_value_roffs(
					CR_CHAN(cmd->start_arg),
					NI_AI_StartTrigger,
					&devpriv->routing_tables, 1));

		if (cmd->start_arg & CR_INVERT)
			ai_trig |= NISTC_AI_TRIG_START1_POLARITY;
		if (cmd->start_arg & CR_EDGE)
			ai_trig |= NISTC_AI_TRIG_START1_EDGE;
		break;
	}
	ni_stc_writew(dev, ai_trig, NISTC_AI_TRIG_SEL_REG);

	mode2 &= ~NISTC_AI_MODE2_PRE_TRIGGER;
	mode2 &= ~NISTC_AI_MODE2_SC_INIT_LOAD_SRC;
	mode2 &= ~NISTC_AI_MODE2_SC_RELOAD_MODE;
	ni_stc_writew(dev, mode2, NISTC_AI_MODE2_REG);

	if (cmd->chanlist_len == 1 || devpriv->is_611x || devpriv->is_6143) {
		/* logic low */
		start_stop_select |= NISTC_AI_STOP_POLARITY |
				     NISTC_AI_STOP_SEL(31) |
				     NISTC_AI_STOP_SYNC;
	} else {
		/*  ai configuration memory */
		start_stop_select |= NISTC_AI_STOP_SEL(19);
	}
	ni_stc_writew(dev, start_stop_select, NISTC_AI_START_STOP_REG);

	devpriv->ai_cmd2 = 0;
	switch (cmd->stop_src) {
	case TRIG_COUNT:
		stop_count = cmd->stop_arg - 1;

		if (devpriv->is_611x) {
			/*  have to take 3 stage adc pipeline into account */
			stop_count += num_adc_stages_611x;
		}
		/* stage number of scans */
		ni_stc_writel(dev, stop_count, NISTC_AI_SC_LOADA_REG);

		mode1 |= NISTC_AI_MODE1_START_STOP |
			 NISTC_AI_MODE1_RSVD |
			 NISTC_AI_MODE1_TRIGGER_ONCE;
		ni_stc_writew(dev, mode1, NISTC_AI_MODE1_REG);
		/* load SC (Scan Count) */
		ni_stc_writew(dev, NISTC_AI_CMD1_SC_LOAD, NISTC_AI_CMD1_REG);

		if (stop_count == 0) {
			devpriv->ai_cmd2 |= NISTC_AI_CMD2_END_ON_EOS;
			interrupt_a_enable |= NISTC_INTA_ENA_AI_STOP;
			/*
			 * This is required to get the last sample for
			 * chanlist_len > 1, not sure why.
			 */
			if (cmd->chanlist_len > 1)
				start_stop_select |= NISTC_AI_STOP_POLARITY |
						     NISTC_AI_STOP_EDGE;
		}
		break;
	case TRIG_NONE:
		/* stage number of scans */
		ni_stc_writel(dev, 0, NISTC_AI_SC_LOADA_REG);

		mode1 |= NISTC_AI_MODE1_START_STOP |
			 NISTC_AI_MODE1_RSVD |
			 NISTC_AI_MODE1_CONTINUOUS;
		ni_stc_writew(dev, mode1, NISTC_AI_MODE1_REG);

		/* load SC (Scan Count) */
		ni_stc_writew(dev, NISTC_AI_CMD1_SC_LOAD, NISTC_AI_CMD1_REG);
		break;
	}

	switch (cmd->scan_begin_src) {
	case TRIG_TIMER:
		/*
		 * stop bits for non 611x boards
		 * NISTC_AI_MODE3_SI_TRIG_DELAY=0
		 * NISTC_AI_MODE2_PRE_TRIGGER=0
		 * NISTC_AI_START_STOP_REG:
		 * NISTC_AI_START_POLARITY=0	(?) rising edge
		 * NISTC_AI_START_EDGE=1	edge triggered
		 * NISTC_AI_START_SYNC=1	(?)
		 * NISTC_AI_START_SEL=0		SI_TC
		 * NISTC_AI_STOP_POLARITY=0	rising edge
		 * NISTC_AI_STOP_EDGE=0		level
		 * NISTC_AI_STOP_SYNC=1
		 * NISTC_AI_STOP_SEL=19		external pin (configuration mem)
		 */
		start_stop_select |= NISTC_AI_START_EDGE | NISTC_AI_START_SYNC;
		ni_stc_writew(dev, start_stop_select, NISTC_AI_START_STOP_REG);

		mode2 &= ~NISTC_AI_MODE2_SI_INIT_LOAD_SRC;	/* A */
		mode2 |= NISTC_AI_MODE2_SI_RELOAD_MODE(0);
		/* mode2 |= NISTC_AI_MODE2_SC_RELOAD_MODE; */
		ni_stc_writew(dev, mode2, NISTC_AI_MODE2_REG);

		/* load SI */
		timer = ni_ns_to_timer(dev, cmd->scan_begin_arg,
				       CMDF_ROUND_NEAREST);
		ni_stc_writel(dev, timer, NISTC_AI_SI_LOADA_REG);
		ni_stc_writew(dev, NISTC_AI_CMD1_SI_LOAD, NISTC_AI_CMD1_REG);
		break;
	case TRIG_EXT:
		if (cmd->scan_begin_arg & CR_EDGE)
			start_stop_select |= NISTC_AI_START_EDGE;
		if (cmd->scan_begin_arg & CR_INVERT)	/* falling edge */
			start_stop_select |= NISTC_AI_START_POLARITY;
		if (cmd->scan_begin_src != cmd->convert_src ||
		    (cmd->scan_begin_arg & ~CR_EDGE) !=
		    (cmd->convert_arg & ~CR_EDGE))
			start_stop_select |= NISTC_AI_START_SYNC;

		start_stop_select |= NISTC_AI_START_SEL(
					ni_get_reg_value_roffs(
						CR_CHAN(cmd->scan_begin_arg),
						NI_AI_SampleClock,
						&devpriv->routing_tables, 1));
		ni_stc_writew(dev, start_stop_select, NISTC_AI_START_STOP_REG);
		break;
	}

	switch (cmd->convert_src) {
	case TRIG_TIMER:
	case TRIG_NOW:
		if (cmd->convert_arg == 0 || cmd->convert_src == TRIG_NOW)
			timer = 1;
		else
			timer = ni_ns_to_timer(dev, cmd->convert_arg,
					       CMDF_ROUND_NEAREST);
		/* 0,0 does not work */
		ni_stc_writew(dev, 1, NISTC_AI_SI2_LOADA_REG);
		ni_stc_writew(dev, timer, NISTC_AI_SI2_LOADB_REG);

		mode2 &= ~NISTC_AI_MODE2_SI2_INIT_LOAD_SRC;	/* A */
		mode2 |= NISTC_AI_MODE2_SI2_RELOAD_MODE;	/* alternate */
		ni_stc_writew(dev, mode2, NISTC_AI_MODE2_REG);

		ni_stc_writew(dev, NISTC_AI_CMD1_SI2_LOAD, NISTC_AI_CMD1_REG);

		mode2 |= NISTC_AI_MODE2_SI2_INIT_LOAD_SRC;	/* B */
		mode2 |= NISTC_AI_MODE2_SI2_RELOAD_MODE;	/* alternate */
		ni_stc_writew(dev, mode2, NISTC_AI_MODE2_REG);
		break;
	case TRIG_EXT:
		mode1 |= NISTC_AI_MODE1_CONVERT_SRC(
				ni_get_reg_value_roffs(
						CR_CHAN(cmd->convert_arg),
						NI_AI_ConvertClock,
						&devpriv->routing_tables, 1));
		if ((cmd->convert_arg & CR_INVERT) == 0)
			mode1 |= NISTC_AI_MODE1_CONVERT_POLARITY;
		ni_stc_writew(dev, mode1, NISTC_AI_MODE1_REG);

		mode2 |= NISTC_AI_MODE2_SC_GATE_ENA |
			 NISTC_AI_MODE2_START_STOP_GATE_ENA;
		ni_stc_writew(dev, mode2, NISTC_AI_MODE2_REG);

		break;
	}

	if (dev->irq) {
		/* interrupt on FIFO, errors, SC_TC */
		interrupt_a_enable |= NISTC_INTA_ENA_AI_ERR |
				      NISTC_INTA_ENA_AI_SC_TC;

#ifndef PCIDMA
		interrupt_a_enable |= NISTC_INTA_ENA_AI_FIFO;
#endif

		if ((cmd->flags & CMDF_WAKE_EOS) ||
		    (devpriv->ai_cmd2 & NISTC_AI_CMD2_END_ON_EOS)) {
			/* wake on end-of-scan */
			devpriv->aimode = AIMODE_SCAN;
		} else {
			devpriv->aimode = AIMODE_HALF_FULL;
		}

		switch (devpriv->aimode) {
		case AIMODE_HALF_FULL:
			/* FIFO interrupts and DMA requests on half-full */
#ifdef PCIDMA
			ni_stc_writew(dev, NISTC_AI_MODE3_FIFO_MODE_HF_E,
				      NISTC_AI_MODE3_REG);
#else
			ni_stc_writew(dev, NISTC_AI_MODE3_FIFO_MODE_HF,
				      NISTC_AI_MODE3_REG);
#endif
			break;
		case AIMODE_SAMPLE:
			/* generate FIFO interrupts on non-empty */
			ni_stc_writew(dev, NISTC_AI_MODE3_FIFO_MODE_NE,
				      NISTC_AI_MODE3_REG);
			break;
		case AIMODE_SCAN:
#ifdef PCIDMA
			ni_stc_writew(dev, NISTC_AI_MODE3_FIFO_MODE_NE,
				      NISTC_AI_MODE3_REG);
#else
			ni_stc_writew(dev, NISTC_AI_MODE3_FIFO_MODE_HF,
				      NISTC_AI_MODE3_REG);
#endif
			interrupt_a_enable |= NISTC_INTA_ENA_AI_STOP;
			break;
		default:
			break;
		}

		/* clear interrupts */
		ni_stc_writew(dev, NISTC_INTA_ACK_AI_ALL, NISTC_INTA_ACK_REG);

		ni_set_bits(dev, NISTC_INTA_ENA_REG, interrupt_a_enable, 1);
	} else {
		/* interrupt on nothing */
		ni_set_bits(dev, NISTC_INTA_ENA_REG, ~0, 0);

		/* XXX start polling if necessary */
	}

	/* end configuration */
	ni_stc_writew(dev, NISTC_RESET_AI_CFG_END, NISTC_RESET_REG);

	switch (cmd->scan_begin_src) {
	case TRIG_TIMER:
		ni_stc_writew(dev, NISTC_AI_CMD1_SI2_ARM |
				   NISTC_AI_CMD1_SI_ARM |
				   NISTC_AI_CMD1_DIV_ARM |
				   NISTC_AI_CMD1_SC_ARM,
			      NISTC_AI_CMD1_REG);
		break;
	case TRIG_EXT:
		ni_stc_writew(dev, NISTC_AI_CMD1_SI2_ARM |
				   NISTC_AI_CMD1_SI_ARM |	/* XXX ? */
				   NISTC_AI_CMD1_DIV_ARM |
				   NISTC_AI_CMD1_SC_ARM,
			      NISTC_AI_CMD1_REG);
		break;
	}

#ifdef PCIDMA
	{
		int retval = ni_ai_setup_MITE_dma(dev);

		if (retval)
			return retval;
	}
#endif

	if (cmd->start_src == TRIG_NOW) {
		ni_stc_writew(dev, NISTC_AI_CMD2_START1_PULSE |
				   devpriv->ai_cmd2,
			      NISTC_AI_CMD2_REG);
		s->async->inttrig = NULL;
	} else if (cmd->start_src == TRIG_EXT) {
		s->async->inttrig = NULL;
	} else {	/* TRIG_INT */
		s->async->inttrig = ni_ai_inttrig;
	}

	return 0;
}