2 * comedi/drivers/ni_labpc_isadma.c
3 * ISA DMA support for National Instruments Lab-PC series boards and
6 * Extracted from ni_labpc.c:
7 * Copyright (C) 2001-2003 Frank Mori Hess <fmhess@users.sourceforge.net>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
20 #include <linux/module.h>
21 #include <linux/slab.h>
22 #include "../comedidev.h"
26 #include "comedi_fc.h"
28 #include "ni_labpc_regs.h"
29 #include "ni_labpc_isadma.h"
31 /* size in bytes of dma buffer */
32 static const int dma_buffer_size = 0xff00;
33 /* 2 bytes per sample */
34 static const int sample_size = 2;
36 /* utility function that suggests a dma transfer size in bytes */
37 static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
42 if (cmd->convert_src == TRIG_TIMER)
43 freq = 1000000000 / cmd->convert_arg;
45 /* return some default value */
48 /* make buffer fill in no more than 1/3 second */
49 size = (freq / 3) * sample_size;
51 /* set a minimum and maximum size allowed */
52 if (size > dma_buffer_size)
53 size = dma_buffer_size - dma_buffer_size % sample_size;
54 else if (size < sample_size)
60 void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s)
62 struct labpc_private *devpriv = dev->private;
63 struct comedi_cmd *cmd = &s->async->cmd;
64 unsigned long irq_flags;
66 irq_flags = claim_dma_lock();
67 disable_dma(devpriv->dma_chan);
68 /* clear flip-flop to make sure 2-byte registers for
69 * count and address get set correctly */
70 clear_dma_ff(devpriv->dma_chan);
71 set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
72 /* set appropriate size of transfer */
73 devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
74 if (cmd->stop_src == TRIG_COUNT &&
75 devpriv->count * sample_size < devpriv->dma_transfer_size)
76 devpriv->dma_transfer_size = devpriv->count * sample_size;
77 set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
78 enable_dma(devpriv->dma_chan);
79 release_dma_lock(irq_flags);
80 /* set CMD3 bits for caller to enable DMA and interrupt */
81 devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
83 EXPORT_SYMBOL_GPL(labpc_setup_dma);
85 void labpc_drain_dma(struct comedi_device *dev)
87 struct labpc_private *devpriv = dev->private;
88 struct comedi_subdevice *s = dev->read_subdev;
89 struct comedi_async *async = s->async;
90 struct comedi_cmd *cmd = &async->cmd;
93 unsigned int max_points, num_points, residue, leftover;
96 status = devpriv->stat1;
98 flags = claim_dma_lock();
99 disable_dma(devpriv->dma_chan);
100 /* clear flip-flop to make sure 2-byte registers for
101 * count and address get set correctly */
102 clear_dma_ff(devpriv->dma_chan);
104 /* figure out how many points to read */
105 max_points = devpriv->dma_transfer_size / sample_size;
106 /* residue is the number of points left to be done on the dma
107 * transfer. It should always be zero at this point unless
108 * the stop_src is set to external triggering.
110 residue = get_dma_residue(devpriv->dma_chan) / sample_size;
111 num_points = max_points - residue;
112 if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_points)
113 num_points = devpriv->count;
115 /* figure out how many points will be stored next time */
117 if (cmd->stop_src != TRIG_COUNT) {
118 leftover = devpriv->dma_transfer_size / sample_size;
119 } else if (devpriv->count > num_points) {
120 leftover = devpriv->count - num_points;
121 if (leftover > max_points)
122 leftover = max_points;
125 /* write data to comedi buffer */
126 for (i = 0; i < num_points; i++)
127 cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
129 if (cmd->stop_src == TRIG_COUNT)
130 devpriv->count -= num_points;
132 /* set address and count for next transfer */
133 set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
134 set_dma_count(devpriv->dma_chan, leftover * sample_size);
135 release_dma_lock(flags);
137 async->events |= COMEDI_CB_BLOCK;
139 EXPORT_SYMBOL_GPL(labpc_drain_dma);
141 static void handle_isa_dma(struct comedi_device *dev)
143 struct labpc_private *devpriv = dev->private;
145 labpc_drain_dma(dev);
147 enable_dma(devpriv->dma_chan);
149 /* clear dma tc interrupt */
150 devpriv->write_byte(dev, 0x1, DMATC_CLEAR_REG);
153 void labpc_handle_dma_status(struct comedi_device *dev)
155 const struct labpc_boardinfo *board = dev->board_ptr;
156 struct labpc_private *devpriv = dev->private;
159 * if a dma terminal count of external stop trigger
162 if (devpriv->stat1 & STAT1_GATA0 ||
163 (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1))
166 EXPORT_SYMBOL_GPL(labpc_handle_dma_status);
168 int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan)
170 struct labpc_private *devpriv = dev->private;
172 unsigned long dma_flags;
175 if (dma_chan != 1 && dma_chan != 3)
178 dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
182 ret = request_dma(dma_chan, dev->board_name);
188 devpriv->dma_buffer = dma_buffer;
189 devpriv->dma_chan = dma_chan;
190 devpriv->dma_addr = virt_to_bus(devpriv->dma_buffer);
192 dma_flags = claim_dma_lock();
193 disable_dma(devpriv->dma_chan);
194 set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
195 release_dma_lock(dma_flags);
199 EXPORT_SYMBOL_GPL(labpc_init_dma_chan);
201 void labpc_free_dma_chan(struct comedi_device *dev)
203 struct labpc_private *devpriv = dev->private;
205 kfree(devpriv->dma_buffer);
206 devpriv->dma_buffer = NULL;
207 if (devpriv->dma_chan) {
208 free_dma(devpriv->dma_chan);
209 devpriv->dma_chan = 0;
212 EXPORT_SYMBOL_GPL(labpc_free_dma_chan);
214 static int __init ni_labpc_isadma_init_module(void)
218 module_init(ni_labpc_isadma_init_module);
220 static void __exit ni_labpc_isadma_cleanup_module(void)
223 module_exit(ni_labpc_isadma_cleanup_module);
225 MODULE_AUTHOR("Comedi http://www.comedi.org");
226 MODULE_DESCRIPTION("Comedi NI Lab-PC ISA DMA support");
227 MODULE_LICENSE("GPL");