linux/drivers/staging/comedi/drivers/ni_labpc_isadma.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * comedi/drivers/ni_labpc_isadma.c
   4 * ISA DMA support for National Instruments Lab-PC series boards and
   5 * compatibles.
   6 *
   7 * Extracted from ni_labpc.c:
   8 * Copyright (C) 2001-2003 Frank Mori Hess <fmhess@users.sourceforge.net>
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/slab.h>
  13
  14#include "../comedidev.h"
  15
  16#include "comedi_isadma.h"
  17#include "ni_labpc.h"
  18#include "ni_labpc_regs.h"
  19#include "ni_labpc_isadma.h"
  20
  21/* size in bytes of dma buffer */
  22#define LABPC_ISADMA_BUFFER_SIZE        0xff00
  23
  24/* utility function that suggests a dma transfer size in bytes */
  25static unsigned int labpc_suggest_transfer_size(struct comedi_device *dev,
  26                                                struct comedi_subdevice *s,
  27                                                unsigned int maxbytes)
  28{
  29        struct comedi_cmd *cmd = &s->async->cmd;
  30        unsigned int sample_size = comedi_bytes_per_sample(s);
  31        unsigned int size;
  32        unsigned int freq;
  33
  34        if (cmd->convert_src == TRIG_TIMER)
  35                freq = 1000000000 / cmd->convert_arg;
  36        else
  37                /* return some default value */
  38                freq = 0xffffffff;
  39
  40        /* make buffer fill in no more than 1/3 second */
  41        size = (freq / 3) * sample_size;
  42
  43        /* set a minimum and maximum size allowed */
  44        if (size > maxbytes)
  45                size = maxbytes;
  46        else if (size < sample_size)
  47                size = sample_size;
  48
  49        return size;
  50}
  51
  52void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s)
  53{
  54        struct labpc_private *devpriv = dev->private;
  55        struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
  56        struct comedi_cmd *cmd = &s->async->cmd;
  57        unsigned int sample_size = comedi_bytes_per_sample(s);
  58
  59        /* set appropriate size of transfer */
  60        desc->size = labpc_suggest_transfer_size(dev, s, desc->maxsize);
  61        if (cmd->stop_src == TRIG_COUNT &&
  62            devpriv->count * sample_size < desc->size)
  63                desc->size = devpriv->count * sample_size;
  64
  65        comedi_isadma_program(desc);
  66
  67        /* set CMD3 bits for caller to enable DMA and interrupt */
  68        devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
  69}
  70EXPORT_SYMBOL_GPL(labpc_setup_dma);
  71
  72void labpc_drain_dma(struct comedi_device *dev)
  73{
  74        struct labpc_private *devpriv = dev->private;
  75        struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
  76        struct comedi_subdevice *s = dev->read_subdev;
  77        struct comedi_async *async = s->async;
  78        struct comedi_cmd *cmd = &async->cmd;
  79        unsigned int max_samples = comedi_bytes_to_samples(s, desc->size);
  80        unsigned int residue;
  81        unsigned int nsamples;
  82        unsigned int leftover;
  83
  84        /*
  85         * residue is the number of bytes left to be done on the dma
  86         * transfer.  It should always be zero at this point unless
  87         * the stop_src is set to external triggering.
  88         */
  89        residue = comedi_isadma_disable(desc->chan);
  90
  91        /*
  92         * Figure out how many samples to read for this transfer and
  93         * how many will be stored for next time.
  94         */
  95        nsamples = max_samples - comedi_bytes_to_samples(s, residue);
  96        if (cmd->stop_src == TRIG_COUNT) {
  97                if (devpriv->count <= nsamples) {
  98                        nsamples = devpriv->count;
  99                        leftover = 0;
 100                } else {
 101                        leftover = devpriv->count - nsamples;
 102                        if (leftover > max_samples)
 103                                leftover = max_samples;
 104                }
 105                devpriv->count -= nsamples;
 106        } else {
 107                leftover = max_samples;
 108        }
 109        desc->size = comedi_samples_to_bytes(s, leftover);
 110
 111        comedi_buf_write_samples(s, desc->virt_addr, nsamples);
 112}
 113EXPORT_SYMBOL_GPL(labpc_drain_dma);
 114
 115static void handle_isa_dma(struct comedi_device *dev)
 116{
 117        struct labpc_private *devpriv = dev->private;
 118        struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
 119
 120        labpc_drain_dma(dev);
 121
 122        if (desc->size)
 123                comedi_isadma_program(desc);
 124
 125        /* clear dma tc interrupt */
 126        devpriv->write_byte(dev, 0x1, DMATC_CLEAR_REG);
 127}
 128
 129void labpc_handle_dma_status(struct comedi_device *dev)
 130{
 131        const struct labpc_boardinfo *board = dev->board_ptr;
 132        struct labpc_private *devpriv = dev->private;
 133
 134        /*
 135         * if a dma terminal count of external stop trigger
 136         * has occurred
 137         */
 138        if (devpriv->stat1 & STAT1_GATA0 ||
 139            (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1))
 140                handle_isa_dma(dev);
 141}
 142EXPORT_SYMBOL_GPL(labpc_handle_dma_status);
 143
 144void labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan)
 145{
 146        struct labpc_private *devpriv = dev->private;
 147
 148        /* only DMA channels 3 and 1 are valid */
 149        if (dma_chan != 1 && dma_chan != 3)
 150                return;
 151
 152        /* DMA uses 1 buffer */
 153        devpriv->dma = comedi_isadma_alloc(dev, 1, dma_chan, dma_chan,
 154                                           LABPC_ISADMA_BUFFER_SIZE,
 155                                           COMEDI_ISADMA_READ);
 156}
 157EXPORT_SYMBOL_GPL(labpc_init_dma_chan);
 158
 159void labpc_free_dma_chan(struct comedi_device *dev)
 160{
 161        struct labpc_private *devpriv = dev->private;
 162
 163        if (devpriv)
 164                comedi_isadma_free(devpriv->dma);
 165}
 166EXPORT_SYMBOL_GPL(labpc_free_dma_chan);
 167
 168static int __init ni_labpc_isadma_init_module(void)
 169{
 170        return 0;
 171}
 172module_init(ni_labpc_isadma_init_module);
 173
 174static void __exit ni_labpc_isadma_cleanup_module(void)
 175{
 176}
 177module_exit(ni_labpc_isadma_cleanup_module);
 178
 179MODULE_AUTHOR("Comedi http://www.comedi.org");
 180MODULE_DESCRIPTION("Comedi NI Lab-PC ISA DMA support");
 181MODULE_LICENSE("GPL");
 182