staging: comedi: dt2814: Fix asynchronous command interrupt handling
The support for asynchronous commands in this driver is currently broken. If interrupts are enabled, the interrupt handler is called at the end of every A/D conversion. A/D conversions could be due to software-triggered conversions resulting from Comedi `INSN_READ` instruction handling, or due to timer-trigger conversions enabled when a Comedi asynchronous command is set up. We only want the interrupt handler to read a sample from the A/D Data register for timer-triggered conversions, but currently it always reads the A/D Data register. Since the A/D Data register is read twice (to read a 12-bit value from an 8-bit register), that probably interferes with the reading for software-triggered conversions. The interrupt handler does not currently do anything with the data, it just ignores it. It should be written to the Comedi buffer if handling an asynchronous command. Other problems are that the driver has no Comedi `cancel` handler to call when the asynchronous command is being stopped manually, and it does not handle "infinite" acquisitions (when the command's `stop_src == TRIG_NONE`) properly. Change the interrupt handler to check the timer enable (ENB) bit to check the asynchronous command is active and return early if not enabled. Also check the error (ERR) and "conversion complete" (FINISH) bits, and return early if neither is set. Then the sample can be read from the A/D Data register to clear the ERR and FINISH bits. If the ERR bit was set, terminate the acquisition with an error, otherwise write the data to the Comedi buffer and check for end of acquisition. Replace the current check for end of acquisition, using the count of completed scans in `scans_done` (updated by calls to `comedi_buf_write_samples()`) when `stop_src == TRIG_COUNT`) and allowing "infinite" acquisitions when `stop_src == TRIG_NONE`. Add a `cancel` handler function `dt2814_ai_cancel()` that will be called when the end of acquisition event is processed and when the acquisition is stopped manually. It turns off the timer enable (ENB) bit in the Control register, leaving the current channel selected. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Link: https://lore.kernel.org/r/20210301165757.243065-5-abbotti@mev.co.ukSigned-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing
Please register or sign in to comment