static int apci1500_timer_insn_config()

in drivers/addi_apci_1500.c [586:715]


static int apci1500_timer_insn_config(struct comedi_device *dev,
				      struct comedi_subdevice *s,
				      struct comedi_insn *insn,
				      unsigned int *data)
{
	struct apci1500_private *devpriv = dev->private;
	unsigned int chan = CR_CHAN(insn->chanspec);
	unsigned int val;

	switch (data[0]) {
	case INSN_CONFIG_ARM:
		val = data[1] & s->maxdata;
		z8536_write(dev, val & 0xff, Z8536_CT_RELOAD_LSB_REG(chan));
		z8536_write(dev, (val >> 8) & 0xff,
			    Z8536_CT_RELOAD_MSB_REG(chan));

		apci1500_timer_enable(dev, chan, true);
		z8536_write(dev, Z8536_CT_CMDSTAT_GCB,
			    Z8536_CT_CMDSTAT_REG(chan));
		break;
	case INSN_CONFIG_DISARM:
		apci1500_timer_enable(dev, chan, false);
		break;

	case INSN_CONFIG_GET_COUNTER_STATUS:
		data[1] = 0;
		val = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
		if (val & Z8536_CT_STAT_CIP)
			data[1] |= COMEDI_COUNTER_COUNTING;
		if (val & Z8536_CT_CMDSTAT_GCB)
			data[1] |= COMEDI_COUNTER_ARMED;
		if (val & Z8536_STAT_IP) {
			data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
			apci1500_ack_irq(dev, Z8536_CT_CMDSTAT_REG(chan));
		}
		data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
			  COMEDI_COUNTER_TERMINAL_COUNT;
		break;

	case INSN_CONFIG_SET_COUNTER_MODE:
		/* Simulate the 8254 timer modes */
		switch (data[1]) {
		case I8254_MODE0:
			/* Interrupt on Terminal Count */
			val = Z8536_CT_MODE_ECE |
			      Z8536_CT_MODE_DCS_ONESHOT;
			break;
		case I8254_MODE1:
			/* Hardware Retriggerable One-Shot */
			val = Z8536_CT_MODE_ETE |
			      Z8536_CT_MODE_DCS_ONESHOT;
			break;
		case I8254_MODE2:
			/* Rate Generator */
			val = Z8536_CT_MODE_CSC |
			      Z8536_CT_MODE_DCS_PULSE;
			break;
		case I8254_MODE3:
			/* Square Wave Mode */
			val = Z8536_CT_MODE_CSC |
			      Z8536_CT_MODE_DCS_SQRWAVE;
			break;
		case I8254_MODE4:
			/* Software Triggered Strobe */
			val = Z8536_CT_MODE_REB |
			      Z8536_CT_MODE_DCS_PULSE;
			break;
		case I8254_MODE5:
			/* Hardware Triggered Strobe (watchdog) */
			val = Z8536_CT_MODE_EOE |
			      Z8536_CT_MODE_ETE |
			      Z8536_CT_MODE_REB |
			      Z8536_CT_MODE_DCS_PULSE;
			break;
		default:
			return -EINVAL;
		}
		apci1500_timer_enable(dev, chan, false);
		z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
		break;

	case INSN_CONFIG_SET_CLOCK_SRC:
		if (data[1] > 2)
			return -EINVAL;
		devpriv->clk_src = data[1];
		if (devpriv->clk_src == 2)
			devpriv->clk_src = 3;
		outw(devpriv->clk_src, devpriv->addon + APCI1500_CLK_SEL_REG);
		break;
	case INSN_CONFIG_GET_CLOCK_SRC:
		switch (devpriv->clk_src) {
		case 0:
			data[1] = 0;		/* 111.86 kHz / 2 */
			data[2] = 17879;	/* 17879 ns (approx) */
			break;
		case 1:
			data[1] = 1;		/* 3.49 kHz / 2 */
			data[2] = 573066;	/* 573066 ns (approx) */
			break;
		case 3:
			data[1] = 2;		/* 1.747 kHz / 2 */
			data[2] = 1164822;	/* 1164822 ns (approx) */
			break;
		default:
			return -EINVAL;
		}
		break;

	case INSN_CONFIG_SET_GATE_SRC:
		if (chan == 0)
			return -EINVAL;

		val = z8536_read(dev, Z8536_CT_MODE_REG(chan));
		val &= Z8536_CT_MODE_EGE;
		if (data[1] == 1)
			val |= Z8536_CT_MODE_EGE;
		else if (data[1] > 1)
			return -EINVAL;
		z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
		break;
	case INSN_CONFIG_GET_GATE_SRC:
		if (chan == 0)
			return -EINVAL;
		break;

	default:
		return -EINVAL;
	}
	return insn->n;
}