linux/drivers/staging/comedi/drivers/ni_tiocmd.c
<<
>>
Prefs
   1/*
   2 * Command support for NI general purpose counters
   3 *
   4 * Copyright (C) 2006 Frank Mori Hess <fmhess@users.sourceforge.net>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17/*
  18 * Module: ni_tiocmd
  19 * Description: National Instruments general purpose counters command support
  20 * Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
  21 *         Herman.Bruyninckx@mech.kuleuven.ac.be,
  22 *         Wim.Meeussen@mech.kuleuven.ac.be,
  23 *         Klaas.Gadeyne@mech.kuleuven.ac.be,
  24 *         Frank Mori Hess <fmhess@users.sourceforge.net>
  25 * Updated: Fri, 11 Apr 2008 12:32:35 +0100
  26 * Status: works
  27 *
  28 * This module is not used directly by end-users.  Rather, it
  29 * is used by other drivers (for example ni_660x and ni_pcimio)
  30 * to provide command support for NI's general purpose counters.
  31 * It was originally split out of ni_tio.c to stop the 'ni_tio'
  32 * module depending on the 'mite' module.
  33 *
  34 * References:
  35 * DAQ 660x Register-Level Programmer Manual  (NI 370505A-01)
  36 * DAQ 6601/6602 User Manual (NI 322137B-01)
  37 * 340934b.pdf  DAQ-STC reference manual
  38 *
  39 * TODO: Support use of both banks X and Y
  40 */
  41
  42#include <linux/module.h>
  43#include "ni_tio_internal.h"
  44#include "mite.h"
  45
  46static void ni_tio_configure_dma(struct ni_gpct *counter,
  47                                 bool enable, bool read)
  48{
  49        struct ni_gpct_device *counter_dev = counter->counter_dev;
  50        unsigned int cidx = counter->counter_index;
  51        unsigned int mask;
  52        unsigned int bits;
  53
  54        mask = GI_READ_ACKS_IRQ | GI_WRITE_ACKS_IRQ;
  55        bits = 0;
  56
  57        if (enable) {
  58                if (read)
  59                        bits |= GI_READ_ACKS_IRQ;
  60                else
  61                        bits |= GI_WRITE_ACKS_IRQ;
  62        }
  63        ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), mask, bits);
  64
  65        switch (counter_dev->variant) {
  66        case ni_gpct_variant_e_series:
  67                break;
  68        case ni_gpct_variant_m_series:
  69        case ni_gpct_variant_660x:
  70                mask = GI_DMA_ENABLE | GI_DMA_INT_ENA | GI_DMA_WRITE;
  71                bits = 0;
  72
  73                if (enable)
  74                        bits |= GI_DMA_ENABLE | GI_DMA_INT_ENA;
  75                if (!read)
  76                        bits |= GI_DMA_WRITE;
  77                ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), mask, bits);
  78                break;
  79        }
  80}
  81
  82static int ni_tio_input_inttrig(struct comedi_device *dev,
  83                                struct comedi_subdevice *s,
  84                                unsigned int trig_num)
  85{
  86        struct ni_gpct *counter = s->private;
  87        struct comedi_cmd *cmd = &s->async->cmd;
  88        unsigned long flags;
  89        int ret = 0;
  90
  91        if (trig_num != cmd->start_arg)
  92                return -EINVAL;
  93
  94        spin_lock_irqsave(&counter->lock, flags);
  95        if (counter->mite_chan)
  96                mite_dma_arm(counter->mite_chan);
  97        else
  98                ret = -EIO;
  99        spin_unlock_irqrestore(&counter->lock, flags);
 100        if (ret < 0)
 101                return ret;
 102        ret = ni_tio_arm(counter, true, NI_GPCT_ARM_IMMEDIATE);
 103        s->async->inttrig = NULL;
 104
 105        return ret;
 106}
 107
 108static int ni_tio_input_cmd(struct comedi_subdevice *s)
 109{
 110        struct ni_gpct *counter = s->private;
 111        struct ni_gpct_device *counter_dev = counter->counter_dev;
 112        unsigned int cidx = counter->counter_index;
 113        struct comedi_async *async = s->async;
 114        struct comedi_cmd *cmd = &async->cmd;
 115        int ret = 0;
 116
 117        /* write alloc the entire buffer */
 118        comedi_buf_write_alloc(s, async->prealloc_bufsz);
 119        counter->mite_chan->dir = COMEDI_INPUT;
 120        switch (counter_dev->variant) {
 121        case ni_gpct_variant_m_series:
 122        case ni_gpct_variant_660x:
 123                mite_prep_dma(counter->mite_chan, 32, 32);
 124                break;
 125        case ni_gpct_variant_e_series:
 126                mite_prep_dma(counter->mite_chan, 16, 32);
 127                break;
 128        }
 129        ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), GI_SAVE_TRACE, 0);
 130        ni_tio_configure_dma(counter, true, true);
 131
 132        if (cmd->start_src == TRIG_INT) {
 133                async->inttrig = &ni_tio_input_inttrig;
 134        } else {        /* TRIG_NOW || TRIG_EXT || TRIG_OTHER */
 135                async->inttrig = NULL;
 136                mite_dma_arm(counter->mite_chan);
 137
 138                if (cmd->start_src == TRIG_NOW)
 139                        ret = ni_tio_arm(counter, true, NI_GPCT_ARM_IMMEDIATE);
 140                else if (cmd->start_src == TRIG_EXT)
 141                        ret = ni_tio_arm(counter, true, cmd->start_arg);
 142        }
 143        return ret;
 144}
 145
 146static int ni_tio_output_cmd(struct comedi_subdevice *s)
 147{
 148        struct ni_gpct *counter = s->private;
 149
 150        dev_err(counter->counter_dev->dev->class_dev,
 151                "output commands not yet implemented.\n");
 152        return -ENOTSUPP;
 153}
 154
 155static int ni_tio_cmd_setup(struct comedi_subdevice *s)
 156{
 157        struct comedi_cmd *cmd = &s->async->cmd;
 158        struct ni_gpct *counter = s->private;
 159        unsigned int cidx = counter->counter_index;
 160        int set_gate_source = 0;
 161        unsigned int gate_source;
 162        int retval = 0;
 163
 164        if (cmd->scan_begin_src == TRIG_EXT) {
 165                set_gate_source = 1;
 166                gate_source = cmd->scan_begin_arg;
 167        } else if (cmd->convert_src == TRIG_EXT) {
 168                set_gate_source = 1;
 169                gate_source = cmd->convert_arg;
 170        }
 171        if (set_gate_source)
 172                retval = ni_tio_set_gate_src(counter, 0, gate_source);
 173        if (cmd->flags & CMDF_WAKE_EOS) {
 174                ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
 175                                GI_GATE_INTERRUPT_ENABLE(cidx),
 176                                GI_GATE_INTERRUPT_ENABLE(cidx));
 177        }
 178        return retval;
 179}
 180
 181int ni_tio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 182{
 183        struct ni_gpct *counter = s->private;
 184        struct comedi_async *async = s->async;
 185        struct comedi_cmd *cmd = &async->cmd;
 186        int retval = 0;
 187        unsigned long flags;
 188
 189        spin_lock_irqsave(&counter->lock, flags);
 190        if (!counter->mite_chan) {
 191                dev_err(counter->counter_dev->dev->class_dev,
 192                        "commands only supported with DMA.  ");
 193                dev_err(counter->counter_dev->dev->class_dev,
 194                        "Interrupt-driven commands not yet implemented.\n");
 195                retval = -EIO;
 196        } else {
 197                retval = ni_tio_cmd_setup(s);
 198                if (retval == 0) {
 199                        if (cmd->flags & CMDF_WRITE)
 200                                retval = ni_tio_output_cmd(s);
 201                        else
 202                                retval = ni_tio_input_cmd(s);
 203                }
 204        }
 205        spin_unlock_irqrestore(&counter->lock, flags);
 206        return retval;
 207}
 208EXPORT_SYMBOL_GPL(ni_tio_cmd);
 209
 210int ni_tio_cmdtest(struct comedi_device *dev,
 211                   struct comedi_subdevice *s,
 212                   struct comedi_cmd *cmd)
 213{
 214        struct ni_gpct *counter = s->private;
 215        int err = 0;
 216        unsigned int sources;
 217
 218        /* Step 1 : check if triggers are trivially valid */
 219
 220        sources = TRIG_NOW | TRIG_INT | TRIG_OTHER;
 221        if (ni_tio_counting_mode_registers_present(counter->counter_dev))
 222                sources |= TRIG_EXT;
 223        err |= comedi_check_trigger_src(&cmd->start_src, sources);
 224
 225        err |= comedi_check_trigger_src(&cmd->scan_begin_src,
 226                                        TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER);
 227        err |= comedi_check_trigger_src(&cmd->convert_src,
 228                                        TRIG_NOW | TRIG_EXT | TRIG_OTHER);
 229        err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 230        err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 231
 232        if (err)
 233                return 1;
 234
 235        /* Step 2a : make sure trigger sources are unique */
 236
 237        err |= comedi_check_trigger_is_unique(cmd->start_src);
 238        err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
 239        err |= comedi_check_trigger_is_unique(cmd->convert_src);
 240
 241        /* Step 2b : and mutually compatible */
 242
 243        if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW)
 244                err |= -EINVAL;
 245
 246        if (err)
 247                return 2;
 248
 249        /* Step 3: check if arguments are trivially valid */
 250
 251        switch (cmd->start_src) {
 252        case TRIG_NOW:
 253        case TRIG_INT:
 254        case TRIG_OTHER:
 255                err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 256                break;
 257        case TRIG_EXT:
 258                /* start_arg is the start_trigger passed to ni_tio_arm() */
 259                break;
 260        }
 261
 262        if (cmd->scan_begin_src != TRIG_EXT)
 263                err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 264
 265        if (cmd->convert_src != TRIG_EXT)
 266                err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
 267
 268        err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 269                                           cmd->chanlist_len);
 270        err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 271
 272        if (err)
 273                return 3;
 274
 275        /* Step 4: fix up any arguments */
 276
 277        /* Step 5: check channel list if it exists */
 278
 279        return 0;
 280}
 281EXPORT_SYMBOL_GPL(ni_tio_cmdtest);
 282
 283int ni_tio_cancel(struct ni_gpct *counter)
 284{
 285        unsigned int cidx = counter->counter_index;
 286        unsigned long flags;
 287
 288        ni_tio_arm(counter, false, 0);
 289        spin_lock_irqsave(&counter->lock, flags);
 290        if (counter->mite_chan)
 291                mite_dma_disarm(counter->mite_chan);
 292        spin_unlock_irqrestore(&counter->lock, flags);
 293        ni_tio_configure_dma(counter, false, false);
 294
 295        ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
 296                        GI_GATE_INTERRUPT_ENABLE(cidx), 0x0);
 297        return 0;
 298}
 299EXPORT_SYMBOL_GPL(ni_tio_cancel);
 300
 301static int should_ack_gate(struct ni_gpct *counter)
 302{
 303        unsigned long flags;
 304        int retval = 0;
 305
 306        switch (counter->counter_dev->variant) {
 307        case ni_gpct_variant_m_series:
 308        case ni_gpct_variant_660x:
 309                /*
 310                 * not sure if 660x really supports gate interrupts
 311                 * (the bits are not listed in register-level manual)
 312                 */
 313                return 1;
 314        case ni_gpct_variant_e_series:
 315                /*
 316                 * During buffered input counter operation for e-series,
 317                 * the gate interrupt is acked automatically by the dma
 318                 * controller, due to the Gi_Read/Write_Acknowledges_IRQ
 319                 * bits in the input select register.
 320                 */
 321                spin_lock_irqsave(&counter->lock, flags);
 322                {
 323                        if (!counter->mite_chan ||
 324                            counter->mite_chan->dir != COMEDI_INPUT ||
 325                            (mite_done(counter->mite_chan))) {
 326                                retval = 1;
 327                        }
 328                }
 329                spin_unlock_irqrestore(&counter->lock, flags);
 330                break;
 331        }
 332        return retval;
 333}
 334
 335static void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter,
 336                                           int *gate_error,
 337                                           int *tc_error,
 338                                           int *perm_stale_data)
 339{
 340        unsigned int cidx = counter->counter_index;
 341        const unsigned short gxx_status = ni_tio_read(counter,
 342                                                NITIO_SHARED_STATUS_REG(cidx));
 343        const unsigned short gi_status = ni_tio_read(counter,
 344                                                NITIO_STATUS_REG(cidx));
 345        unsigned int ack = 0;
 346
 347        if (gate_error)
 348                *gate_error = 0;
 349        if (tc_error)
 350                *tc_error = 0;
 351        if (perm_stale_data)
 352                *perm_stale_data = 0;
 353
 354        if (gxx_status & GI_GATE_ERROR(cidx)) {
 355                ack |= GI_GATE_ERROR_CONFIRM(cidx);
 356                if (gate_error) {
 357                        /*
 358                         * 660x don't support automatic acknowledgment
 359                         * of gate interrupt via dma read/write
 360                         * and report bogus gate errors
 361                         */
 362                        if (counter->counter_dev->variant !=
 363                            ni_gpct_variant_660x)
 364                                *gate_error = 1;
 365                }
 366        }
 367        if (gxx_status & GI_TC_ERROR(cidx)) {
 368                ack |= GI_TC_ERROR_CONFIRM(cidx);
 369                if (tc_error)
 370                        *tc_error = 1;
 371        }
 372        if (gi_status & GI_TC)
 373                ack |= GI_TC_INTERRUPT_ACK;
 374        if (gi_status & GI_GATE_INTERRUPT) {
 375                if (should_ack_gate(counter))
 376                        ack |= GI_GATE_INTERRUPT_ACK;
 377        }
 378        if (ack)
 379                ni_tio_write(counter, ack, NITIO_INT_ACK_REG(cidx));
 380        if (ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx)) &
 381            GI_LOADING_ON_GATE) {
 382                if (ni_tio_read(counter, NITIO_STATUS2_REG(cidx)) &
 383                    GI_PERMANENT_STALE(cidx)) {
 384                        dev_info(counter->counter_dev->dev->class_dev,
 385                                 "%s: Gi_Permanent_Stale_Data detected.\n",
 386                                 __func__);
 387                        if (perm_stale_data)
 388                                *perm_stale_data = 1;
 389                }
 390        }
 391}
 392
 393void ni_tio_acknowledge(struct ni_gpct *counter)
 394{
 395        ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL);
 396}
 397EXPORT_SYMBOL_GPL(ni_tio_acknowledge);
 398
 399void ni_tio_handle_interrupt(struct ni_gpct *counter,
 400                             struct comedi_subdevice *s)
 401{
 402        unsigned int cidx = counter->counter_index;
 403        unsigned long flags;
 404        int gate_error;
 405        int tc_error;
 406        int perm_stale_data;
 407
 408        ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error,
 409                                       &perm_stale_data);
 410        if (gate_error) {
 411                dev_notice(counter->counter_dev->dev->class_dev,
 412                           "%s: Gi_Gate_Error detected.\n", __func__);
 413                s->async->events |= COMEDI_CB_OVERFLOW;
 414        }
 415        if (perm_stale_data)
 416                s->async->events |= COMEDI_CB_ERROR;
 417        switch (counter->counter_dev->variant) {
 418        case ni_gpct_variant_m_series:
 419        case ni_gpct_variant_660x:
 420                if (ni_tio_read(counter, NITIO_DMA_STATUS_REG(cidx)) &
 421                    GI_DRQ_ERROR) {
 422                        dev_notice(counter->counter_dev->dev->class_dev,
 423                                   "%s: Gi_DRQ_Error detected.\n", __func__);
 424                        s->async->events |= COMEDI_CB_OVERFLOW;
 425                }
 426                break;
 427        case ni_gpct_variant_e_series:
 428                break;
 429        }
 430        spin_lock_irqsave(&counter->lock, flags);
 431        if (counter->mite_chan)
 432                mite_ack_linkc(counter->mite_chan, s, true);
 433        spin_unlock_irqrestore(&counter->lock, flags);
 434}
 435EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt);
 436
 437void ni_tio_set_mite_channel(struct ni_gpct *counter,
 438                             struct mite_channel *mite_chan)
 439{
 440        unsigned long flags;
 441
 442        spin_lock_irqsave(&counter->lock, flags);
 443        counter->mite_chan = mite_chan;
 444        spin_unlock_irqrestore(&counter->lock, flags);
 445}
 446EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel);
 447
 448static int __init ni_tiocmd_init_module(void)
 449{
 450        return 0;
 451}
 452module_init(ni_tiocmd_init_module);
 453
 454static void __exit ni_tiocmd_cleanup_module(void)
 455{
 456}
 457module_exit(ni_tiocmd_cleanup_module);
 458
 459MODULE_AUTHOR("Comedi <comedi@comedi.org>");
 460MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters");
 461MODULE_LICENSE("GPL");
 462