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