// SPDX-License-Identifier: GPL-2.0+ /* * Command support for NI general purpose counters * * Copyright (C) 2006 Frank Mori Hess <fmhess@users.sourceforge.net>
*/
/* * Module: ni_tiocmd * Description: National Instruments general purpose counters command support * Author: J.P. Mellor <jpmellor@rose-hulman.edu>, * Herman.Bruyninckx@mech.kuleuven.ac.be, * Wim.Meeussen@mech.kuleuven.ac.be, * Klaas.Gadeyne@mech.kuleuven.ac.be, * Frank Mori Hess <fmhess@users.sourceforge.net> * Updated: Fri, 11 Apr 2008 12:32:35 +0100 * Status: works * * This module is not used directly by end-users. Rather, it * is used by other drivers (for example ni_660x and ni_pcimio) * to provide command support for NI's general purpose counters. * It was originally split out of ni_tio.c to stop the 'ni_tio' * module depending on the 'mite' module. * * References: * DAQ 660x Register-Level Programmer Manual (NI 370505A-01) * DAQ 6601/6602 User Manual (NI 322137B-01) * 340934b.pdf DAQ-STC reference manual * * TODO: Support use of both banks X and Y
*/
if (cmd->start_src == TRIG_NOW)
ret = ni_tio_arm(counter, true, NI_GPCT_ARM_IMMEDIATE); elseif (cmd->start_src == TRIG_EXT) { int reg = CR_CHAN(cmd->start_arg);
if (reg >= NI_NAMES_BASE) { /* using a device-global name. lookup reg */
reg = ni_get_reg_value(reg,
NI_CtrArmStartTrigger(cidx),
routing_tables); /* mark this as a raw register value */
reg |= NI_GPCT_HW_ARM;
}
ret = ni_tio_arm(counter, true, reg);
}
} return ret;
}
if (cmd->scan_begin_src == TRIG_EXT) {
set_gate_source = 1;
gate_source = cmd->scan_begin_arg;
} elseif (cmd->convert_src == TRIG_EXT) {
set_gate_source = 1;
gate_source = cmd->convert_arg;
} if (set_gate_source) { if (CR_CHAN(gate_source) >= NI_NAMES_BASE) { /* Lookup and use the real register values */ int reg = ni_get_reg_value(CR_CHAN(gate_source),
NI_CtrGate(cidx),
routing_tables); if (reg < 0) return -EINVAL;
retval = ni_tio_set_gate_src_raw(counter, 0, reg);
} else { /* * This function must be used separately since it does * not expect real register values and attempts to * convert these to real register values.
*/
retval = ni_tio_set_gate_src(counter, 0, gate_source);
}
} if (cmd->flags & CMDF_WAKE_EOS) {
ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
GI_GATE_INTERRUPT_ENABLE(cidx),
GI_GATE_INTERRUPT_ENABLE(cidx));
} return retval;
}
/* Step 3: check if arguments are trivially valid */
switch (cmd->start_src) { case TRIG_NOW: case TRIG_INT: case TRIG_OTHER:
err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); break; case TRIG_EXT: /* start_arg is the start_trigger passed to ni_tio_arm() */ /* * This should be done, but we don't yet know the actual * register values. These should be tested and then documented * in the ni_route_values/ni_*.csv files, with indication of * who/when/which/how these were tested. * When at least a e/m/660x series have been tested, this code * should be uncommented: * * err |= ni_check_trigger_arg(CR_CHAN(cmd->start_arg), * NI_CtrArmStartTrigger(cidx), * routing_tables);
*/ break;
}
/* * It seems that convention is to allow either scan_begin_arg or * convert_arg to specify the Gate source, with scan_begin_arg taking * precedence.
*/ if (cmd->scan_begin_src != TRIG_EXT)
err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); else
err |= ni_check_trigger_arg(CR_CHAN(cmd->scan_begin_arg),
NI_CtrGate(cidx), routing_tables);
switch (counter->counter_dev->variant) { case ni_gpct_variant_m_series: case ni_gpct_variant_660x: /* * not sure if 660x really supports gate interrupts * (the bits are not listed in register-level manual)
*/ return 1; case ni_gpct_variant_e_series: /* * During buffered input counter operation for e-series, * the gate interrupt is acked automatically by the dma * controller, due to the Gi_Read/Write_Acknowledges_IRQ * bits in the input select register.
*/
spin_lock_irqsave(&counter->lock, flags);
{ if (!counter->mite_chan ||
counter->mite_chan->dir != COMEDI_INPUT ||
(mite_done(counter->mite_chan))) {
retval = 1;
}
}
spin_unlock_irqrestore(&counter->lock, flags); break;
} return retval;
}
staticvoid ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error, int *perm_stale_data)
{ unsignedint cidx = counter->counter_index; constunsignedshort gxx_status = ni_tio_read(counter,
NITIO_SHARED_STATUS_REG(cidx)); constunsignedshort gi_status = ni_tio_read(counter,
NITIO_STATUS_REG(cidx)); unsignedint ack = 0;
if (gate_error)
*gate_error = 0; if (tc_error)
*tc_error = 0; if (perm_stale_data)
*perm_stale_data = 0;
if (gxx_status & GI_GATE_ERROR(cidx)) {
ack |= GI_GATE_ERROR_CONFIRM(cidx); if (gate_error) { /* * 660x don't support automatic acknowledgment * of gate interrupt via dma read/write * and report bogus gate errors
*/ if (counter->counter_dev->variant !=
ni_gpct_variant_660x)
*gate_error = 1;
}
} if (gxx_status & GI_TC_ERROR(cidx)) {
ack |= GI_TC_ERROR_CONFIRM(cidx); if (tc_error)
*tc_error = 1;
} if (gi_status & GI_TC)
ack |= GI_TC_INTERRUPT_ACK; if (gi_status & GI_GATE_INTERRUPT) { if (should_ack_gate(counter))
ack |= GI_GATE_INTERRUPT_ACK;
} if (ack)
ni_tio_write(counter, ack, NITIO_INT_ACK_REG(cidx)); if (ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx)) &
GI_LOADING_ON_GATE) { if (ni_tio_read(counter, NITIO_STATUS2_REG(cidx)) &
GI_PERMANENT_STALE(cidx)) {
dev_info(counter->counter_dev->dev->class_dev, "%s: Gi_Permanent_Stale_Data detected.\n",
__func__); if (perm_stale_data)
*perm_stale_data = 1;
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.