diff options
author | Guenter Gebhardt <g.gebhardt@meilhaus.com> | 2008-11-19 12:38:19 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 16:52:23 -0500 |
commit | e55c95a3be5e202f0fc30126aff172c706b304f8 (patch) | |
tree | 3575b1b1c48a3055bc2f5f7c7180224303370e23 | |
parent | 96341f71538c48dcec873873cabc11477cf26ae9 (diff) |
Staging: comedi: add me4000 driver
This adds the me4000 driver to the comedi staging tree
From: Guenter Gebhardt <g.gebhardt@meilhaus.com>
Cc: David Schleef <ds@schleef.org>
Cc: Frank Mori Hess <fmhess@users.sourceforge.net>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/staging/comedi/drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/comedi/drivers/me4000.c | 2362 | ||||
-rw-r--r-- | drivers/staging/comedi/drivers/me4000.h | 446 |
3 files changed, 2809 insertions, 0 deletions
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 4d16634c934..bcc9ce816d0 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_COMEDI) += comedi_parport.o | |||
10 | # Comedi PCI drivers | 10 | # Comedi PCI drivers |
11 | obj-$(CONFIG_COMEDI_PCI_DRIVERS) += mite.o | 11 | obj-$(CONFIG_COMEDI_PCI_DRIVERS) += mite.o |
12 | obj-$(CONFIG_COMEDI_PCI_DRIVERS) += icp_multi.o | 12 | obj-$(CONFIG_COMEDI_PCI_DRIVERS) += icp_multi.o |
13 | obj-$(CONFIG_COMEDI_PCI_DRIVERS) += me4000.o | ||
13 | 14 | ||
14 | # Comedi USB drivers | 15 | # Comedi USB drivers |
15 | obj-$(CONFIG_COMEDI_USB_DRIVERS) += usbdux.o | 16 | obj-$(CONFIG_COMEDI_USB_DRIVERS) += usbdux.o |
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c new file mode 100644 index 00000000000..b432aa7d764 --- /dev/null +++ b/drivers/staging/comedi/drivers/me4000.c | |||
@@ -0,0 +1,2362 @@ | |||
1 | /* | ||
2 | comedi/drivers/me4000.c | ||
3 | Source code for the Meilhaus ME-4000 board family. | ||
4 | |||
5 | COMEDI - Linux Control and Measurement Device Interface | ||
6 | Copyright (C) 2000 David A. Schleef <ds@schleef.org> | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | */ | ||
23 | /* | ||
24 | Driver: me4000 | ||
25 | Description: Meilhaus ME-4000 series boards | ||
26 | Devices: [Meilhaus] ME-4650 (me4000), ME-4670i, ME-4680, ME-4680i, ME-4680is | ||
27 | Author: gg (Guenter Gebhardt <g.gebhardt@meilhaus.com>) | ||
28 | Updated: Mon, 18 Mar 2002 15:34:01 -0800 | ||
29 | Status: broken (no support for loading firmware) | ||
30 | |||
31 | Supports: | ||
32 | |||
33 | - Analog Input | ||
34 | - Analog Output | ||
35 | - Digital I/O | ||
36 | - Counter | ||
37 | |||
38 | Configuration Options: | ||
39 | |||
40 | [0] - PCI bus number (optional) | ||
41 | [1] - PCI slot number (optional) | ||
42 | |||
43 | If bus/slot is not specified, the first available PCI | ||
44 | device will be used. | ||
45 | |||
46 | The firmware required by these boards is available in the | ||
47 | comedi_nonfree_firmware tarball available from | ||
48 | http://www.comedi.org. However, the driver's support for | ||
49 | loading the firmware through comedi_config is currently | ||
50 | broken. | ||
51 | |||
52 | */ | ||
53 | |||
54 | #include "../comedidev.h" | ||
55 | |||
56 | #include <linux/delay.h> | ||
57 | #include <linux/list.h> | ||
58 | #include <linux/spinlock.h> | ||
59 | |||
60 | #include "comedi_pci.h" | ||
61 | #include "me4000.h" | ||
62 | #if 0 | ||
63 | /* file removed due to GPL incompatibility */ | ||
64 | #include "me4000_fw.h" | ||
65 | #endif | ||
66 | |||
67 | /*============================================================================= | ||
68 | PCI device table. | ||
69 | This is used by modprobe to translate PCI IDs to drivers. | ||
70 | ===========================================================================*/ | ||
71 | |||
72 | static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = { | ||
73 | {PCI_VENDOR_ID_MEILHAUS, 0x4650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
74 | |||
75 | {PCI_VENDOR_ID_MEILHAUS, 0x4660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
76 | {PCI_VENDOR_ID_MEILHAUS, 0x4661, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
77 | {PCI_VENDOR_ID_MEILHAUS, 0x4662, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
78 | {PCI_VENDOR_ID_MEILHAUS, 0x4663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
79 | |||
80 | {PCI_VENDOR_ID_MEILHAUS, 0x4670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
81 | {PCI_VENDOR_ID_MEILHAUS, 0x4671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
82 | {PCI_VENDOR_ID_MEILHAUS, 0x4672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
83 | {PCI_VENDOR_ID_MEILHAUS, 0x4673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
84 | |||
85 | {PCI_VENDOR_ID_MEILHAUS, 0x4680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
86 | {PCI_VENDOR_ID_MEILHAUS, 0x4681, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
87 | {PCI_VENDOR_ID_MEILHAUS, 0x4682, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
88 | {PCI_VENDOR_ID_MEILHAUS, 0x4683, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
89 | |||
90 | {0} | ||
91 | }; | ||
92 | |||
93 | MODULE_DEVICE_TABLE(pci, me4000_pci_table); | ||
94 | |||
95 | static const me4000_board_t me4000_boards[] = { | ||
96 | {"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0}}, | ||
97 | |||
98 | {"ME-4660", 0x4660, {0, 0}, {32, 0, 16, 0}, {4}, {3}}, | ||
99 | {"ME-4660i", 0x4661, {0, 0}, {32, 0, 16, 0}, {4}, {3}}, | ||
100 | {"ME-4660s", 0x4662, {0, 0}, {32, 8, 16, 0}, {4}, {3}}, | ||
101 | {"ME-4660is", 0x4663, {0, 0}, {32, 8, 16, 0}, {4}, {3}}, | ||
102 | |||
103 | {"ME-4670", 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3}}, | ||
104 | {"ME-4670i", 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3}}, | ||
105 | {"ME-4670s", 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3}}, | ||
106 | {"ME-4670is", 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3}}, | ||
107 | |||
108 | {"ME-4680", 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3}}, | ||
109 | {"ME-4680i", 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3}}, | ||
110 | {"ME-4680s", 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3}}, | ||
111 | {"ME-4680is", 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3}}, | ||
112 | |||
113 | {0}, | ||
114 | }; | ||
115 | |||
116 | #define ME4000_BOARD_VERSIONS (sizeof(me4000_boards) / sizeof(me4000_board_t) - 1) | ||
117 | |||
118 | /*----------------------------------------------------------------------------- | ||
119 | Comedi function prototypes | ||
120 | ---------------------------------------------------------------------------*/ | ||
121 | static int me4000_attach(comedi_device * dev, comedi_devconfig * it); | ||
122 | static int me4000_detach(comedi_device * dev); | ||
123 | static comedi_driver driver_me4000 = { | ||
124 | driver_name:"me4000", | ||
125 | module:THIS_MODULE, | ||
126 | attach:me4000_attach, | ||
127 | detach:me4000_detach, | ||
128 | }; | ||
129 | |||
130 | /*----------------------------------------------------------------------------- | ||
131 | Meilhaus function prototypes | ||
132 | ---------------------------------------------------------------------------*/ | ||
133 | static int me4000_probe(comedi_device * dev, comedi_devconfig * it); | ||
134 | static int get_registers(comedi_device * dev, struct pci_dev *pci_dev_p); | ||
135 | static int init_board_info(comedi_device * dev, struct pci_dev *pci_dev_p); | ||
136 | static int init_ao_context(comedi_device * dev); | ||
137 | static int init_ai_context(comedi_device * dev); | ||
138 | static int init_dio_context(comedi_device * dev); | ||
139 | static int init_cnt_context(comedi_device * dev); | ||
140 | static int xilinx_download(comedi_device * dev); | ||
141 | static int reset_board(comedi_device * dev); | ||
142 | |||
143 | static int me4000_dio_insn_bits(comedi_device * dev, | ||
144 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); | ||
145 | |||
146 | static int me4000_dio_insn_config(comedi_device * dev, | ||
147 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); | ||
148 | |||
149 | static int cnt_reset(comedi_device * dev, unsigned int channel); | ||
150 | |||
151 | static int cnt_config(comedi_device * dev, | ||
152 | unsigned int channel, unsigned int mode); | ||
153 | |||
154 | static int me4000_cnt_insn_config(comedi_device * dev, | ||
155 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); | ||
156 | |||
157 | static int me4000_cnt_insn_write(comedi_device * dev, | ||
158 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); | ||
159 | |||
160 | static int me4000_cnt_insn_read(comedi_device * dev, | ||
161 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); | ||
162 | |||
163 | static int me4000_ai_insn_read(comedi_device * dev, | ||
164 | comedi_subdevice * subdevice, comedi_insn * insn, lsampl_t * data); | ||
165 | |||
166 | static int me4000_ai_cancel(comedi_device * dev, comedi_subdevice * s); | ||
167 | |||
168 | static int ai_check_chanlist(comedi_device * dev, | ||
169 | comedi_subdevice * s, comedi_cmd * cmd); | ||
170 | |||
171 | static int ai_round_cmd_args(comedi_device * dev, | ||
172 | comedi_subdevice * s, | ||
173 | comedi_cmd * cmd, | ||
174 | unsigned int *init_ticks, | ||
175 | unsigned int *scan_ticks, unsigned int *chan_ticks); | ||
176 | |||
177 | static int ai_prepare(comedi_device * dev, | ||
178 | comedi_subdevice * s, | ||
179 | comedi_cmd * cmd, | ||
180 | unsigned int init_ticks, | ||
181 | unsigned int scan_ticks, unsigned int chan_ticks); | ||
182 | |||
183 | static int ai_write_chanlist(comedi_device * dev, | ||
184 | comedi_subdevice * s, comedi_cmd * cmd); | ||
185 | |||
186 | static irqreturn_t me4000_ai_isr(int irq, void *dev_id PT_REGS_ARG); | ||
187 | |||
188 | static int me4000_ai_do_cmd_test(comedi_device * dev, | ||
189 | comedi_subdevice * s, comedi_cmd * cmd); | ||
190 | |||
191 | static int me4000_ai_do_cmd(comedi_device * dev, comedi_subdevice * s); | ||
192 | |||
193 | static int me4000_ao_insn_write(comedi_device * dev, | ||
194 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); | ||
195 | |||
196 | static int me4000_ao_insn_read(comedi_device * dev, | ||
197 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data); | ||
198 | |||
199 | /*----------------------------------------------------------------------------- | ||
200 | Meilhaus inline functions | ||
201 | ---------------------------------------------------------------------------*/ | ||
202 | |||
203 | static inline void me4000_outb(comedi_device * dev, unsigned char value, | ||
204 | unsigned long port) | ||
205 | { | ||
206 | PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port); | ||
207 | outb(value, port); | ||
208 | } | ||
209 | |||
210 | static inline void me4000_outl(comedi_device * dev, unsigned long value, | ||
211 | unsigned long port) | ||
212 | { | ||
213 | PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port); | ||
214 | outl(value, port); | ||
215 | } | ||
216 | |||
217 | static inline unsigned long me4000_inl(comedi_device * dev, unsigned long port) | ||
218 | { | ||
219 | unsigned long value; | ||
220 | value = inl(port); | ||
221 | PORT_PDEBUG("<-- 0x%08lX port 0x%04lX\n", value, port); | ||
222 | return value; | ||
223 | } | ||
224 | |||
225 | static inline unsigned char me4000_inb(comedi_device * dev, unsigned long port) | ||
226 | { | ||
227 | unsigned char value; | ||
228 | value = inb(port); | ||
229 | PORT_PDEBUG("<-- 0x%08X port 0x%04lX\n", value, port); | ||
230 | return value; | ||
231 | } | ||
232 | |||
233 | static const comedi_lrange me4000_ai_range = { | ||
234 | 4, | ||
235 | { | ||
236 | UNI_RANGE(2.5), | ||
237 | UNI_RANGE(10), | ||
238 | BIP_RANGE(2.5), | ||
239 | BIP_RANGE(10), | ||
240 | } | ||
241 | }; | ||
242 | |||
243 | static const comedi_lrange me4000_ao_range = { | ||
244 | 1, | ||
245 | { | ||
246 | BIP_RANGE(10), | ||
247 | } | ||
248 | }; | ||
249 | |||
250 | static int me4000_attach(comedi_device * dev, comedi_devconfig * it) | ||
251 | { | ||
252 | comedi_subdevice *s; | ||
253 | int result; | ||
254 | |||
255 | CALL_PDEBUG("In me4000_attach()\n"); | ||
256 | |||
257 | result = me4000_probe(dev, it); | ||
258 | if (result) | ||
259 | return result; | ||
260 | |||
261 | /* | ||
262 | * Allocate the subdevice structures. alloc_subdevice() is a | ||
263 | * convenient macro defined in comedidev.h. It relies on | ||
264 | * n_subdevices being set correctly. | ||
265 | */ | ||
266 | if (alloc_subdevices(dev, 4) < 0) | ||
267 | return -ENOMEM; | ||
268 | |||
269 | /*========================================================================= | ||
270 | Analog input subdevice | ||
271 | ========================================================================*/ | ||
272 | |||
273 | s = dev->subdevices + 0; | ||
274 | |||
275 | if (thisboard->ai.count) { | ||
276 | s->type = COMEDI_SUBD_AI; | ||
277 | s->subdev_flags = | ||
278 | SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; | ||
279 | s->n_chan = thisboard->ai.count; | ||
280 | s->maxdata = 0xFFFF; // 16 bit ADC | ||
281 | s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; | ||
282 | s->range_table = &me4000_ai_range; | ||
283 | s->insn_read = me4000_ai_insn_read; | ||
284 | |||
285 | if (info->irq > 0) { | ||
286 | if (comedi_request_irq(info->irq, me4000_ai_isr, | ||
287 | IRQF_SHARED, "ME-4000", dev)) { | ||
288 | printk("comedi%d: me4000: me4000_attach(): Unable to allocate irq\n", dev->minor); | ||
289 | } else { | ||
290 | dev->read_subdev = s; | ||
291 | s->subdev_flags |= SDF_CMD_READ; | ||
292 | s->cancel = me4000_ai_cancel; | ||
293 | s->do_cmdtest = me4000_ai_do_cmd_test; | ||
294 | s->do_cmd = me4000_ai_do_cmd; | ||
295 | } | ||
296 | } else { | ||
297 | printk(KERN_WARNING | ||
298 | "comedi%d: me4000: me4000_attach(): No interrupt available\n", | ||
299 | dev->minor); | ||
300 | } | ||
301 | } else { | ||
302 | s->type = COMEDI_SUBD_UNUSED; | ||
303 | } | ||
304 | |||
305 | /*========================================================================= | ||
306 | Analog output subdevice | ||
307 | ========================================================================*/ | ||
308 | |||
309 | s = dev->subdevices + 1; | ||
310 | |||
311 | if (thisboard->ao.count) { | ||
312 | s->type = COMEDI_SUBD_AO; | ||
313 | s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND; | ||
314 | s->n_chan = thisboard->ao.count; | ||
315 | s->maxdata = 0xFFFF; // 16 bit DAC | ||
316 | s->range_table = &me4000_ao_range; | ||
317 | s->insn_write = me4000_ao_insn_write; | ||
318 | s->insn_read = me4000_ao_insn_read; | ||
319 | } else { | ||
320 | s->type = COMEDI_SUBD_UNUSED; | ||
321 | } | ||
322 | |||
323 | /*========================================================================= | ||
324 | Digital I/O subdevice | ||
325 | ========================================================================*/ | ||
326 | |||
327 | s = dev->subdevices + 2; | ||
328 | |||
329 | if (thisboard->dio.count) { | ||
330 | s->type = COMEDI_SUBD_DIO; | ||
331 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE; | ||
332 | s->n_chan = thisboard->dio.count * 8; | ||
333 | s->maxdata = 1; | ||
334 | s->range_table = &range_digital; | ||
335 | s->insn_bits = me4000_dio_insn_bits; | ||
336 | s->insn_config = me4000_dio_insn_config; | ||
337 | } else { | ||
338 | s->type = COMEDI_SUBD_UNUSED; | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * Check for optoisolated ME-4000 version. If one the first | ||
343 | * port is a fixed output port and the second is a fixed input port. | ||
344 | */ | ||
345 | if (!me4000_inl(dev, info->dio_context.dir_reg)) { | ||
346 | s->io_bits |= 0xFF; | ||
347 | me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0, | ||
348 | info->dio_context.dir_reg); | ||
349 | } | ||
350 | |||
351 | /*========================================================================= | ||
352 | Counter subdevice | ||
353 | ========================================================================*/ | ||
354 | |||
355 | s = dev->subdevices + 3; | ||
356 | |||
357 | if (thisboard->cnt.count) { | ||
358 | s->type = COMEDI_SUBD_COUNTER; | ||
359 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE; | ||
360 | s->n_chan = thisboard->cnt.count; | ||
361 | s->maxdata = 0xFFFF; // 16 bit counters | ||
362 | s->insn_read = me4000_cnt_insn_read; | ||
363 | s->insn_write = me4000_cnt_insn_write; | ||
364 | s->insn_config = me4000_cnt_insn_config; | ||
365 | } else { | ||
366 | s->type = COMEDI_SUBD_UNUSED; | ||
367 | } | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int me4000_probe(comedi_device * dev, comedi_devconfig * it) | ||
373 | { | ||
374 | struct pci_dev *pci_device; | ||
375 | int result, i; | ||
376 | me4000_board_t *board; | ||
377 | |||
378 | CALL_PDEBUG("In me4000_probe()\n"); | ||
379 | |||
380 | /* Allocate private memory */ | ||
381 | if (alloc_private(dev, sizeof(me4000_info_t)) < 0) { | ||
382 | return -ENOMEM; | ||
383 | } | ||
384 | /* | ||
385 | * Probe the device to determine what device in the series it is. | ||
386 | */ | ||
387 | for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); | ||
388 | pci_device != NULL; | ||
389 | pci_device = | ||
390 | pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) { | ||
391 | if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) { | ||
392 | for (i = 0; i < ME4000_BOARD_VERSIONS; i++) { | ||
393 | if (me4000_boards[i].device_id == | ||
394 | pci_device->device) { | ||
395 | /* Was a particular bus/slot requested? */ | ||
396 | if ((it->options[0] != 0) | ||
397 | || (it->options[1] != 0)) { | ||
398 | /* Are we on the wrong bus/slot? */ | ||
399 | if (pci_device->bus->number != | ||
400 | it->options[0] | ||
401 | || PCI_SLOT(pci_device-> | ||
402 | devfn) != | ||
403 | it->options[1]) { | ||
404 | continue; | ||
405 | } | ||
406 | } | ||
407 | dev->board_ptr = me4000_boards + i; | ||
408 | board = (me4000_board_t *) dev-> | ||
409 | board_ptr; | ||
410 | info->pci_dev_p = pci_device; | ||
411 | goto found; | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | |||
417 | printk(KERN_ERR | ||
418 | "comedi%d: me4000: me4000_probe(): No supported board found (req. bus/slot : %d/%d)\n", | ||
419 | dev->minor, it->options[0], it->options[1]); | ||
420 | return -ENODEV; | ||
421 | |||
422 | found: | ||
423 | |||
424 | printk(KERN_INFO | ||
425 | "comedi%d: me4000: me4000_probe(): Found %s at PCI bus %d, slot %d\n", | ||
426 | dev->minor, me4000_boards[i].name, pci_device->bus->number, | ||
427 | PCI_SLOT(pci_device->devfn)); | ||
428 | |||
429 | /* Set data in device structure */ | ||
430 | dev->board_name = board->name; | ||
431 | |||
432 | /* Enable PCI device and request regions */ | ||
433 | result = comedi_pci_enable(pci_device, dev->board_name); | ||
434 | if (result) { | ||
435 | printk(KERN_ERR | ||
436 | "comedi%d: me4000: me4000_probe(): Cannot enable PCI device and request I/O regions\n", | ||
437 | dev->minor); | ||
438 | return result; | ||
439 | } | ||
440 | |||
441 | /* Get the PCI base registers */ | ||
442 | result = get_registers(dev, pci_device); | ||
443 | if (result) { | ||
444 | printk(KERN_ERR | ||
445 | "comedi%d: me4000: me4000_probe(): Cannot get registers\n", | ||
446 | dev->minor); | ||
447 | return result; | ||
448 | } | ||
449 | /* Initialize board info */ | ||
450 | result = init_board_info(dev, pci_device); | ||
451 | if (result) { | ||
452 | printk(KERN_ERR | ||
453 | "comedi%d: me4000: me4000_probe(): Cannot init baord info\n", | ||
454 | dev->minor); | ||
455 | return result; | ||
456 | } | ||
457 | |||
458 | /* Init analog output context */ | ||
459 | result = init_ao_context(dev); | ||
460 | if (result) { | ||
461 | printk(KERN_ERR | ||
462 | "comedi%d: me4000: me4000_probe(): Cannot init ao context\n", | ||
463 | dev->minor); | ||
464 | return result; | ||
465 | } | ||
466 | |||
467 | /* Init analog input context */ | ||
468 | result = init_ai_context(dev); | ||
469 | if (result) { | ||
470 | printk(KERN_ERR | ||
471 | "comedi%d: me4000: me4000_probe(): Cannot init ai context\n", | ||
472 | dev->minor); | ||
473 | return result; | ||
474 | } | ||
475 | |||
476 | /* Init digital I/O context */ | ||
477 | result = init_dio_context(dev); | ||
478 | if (result) { | ||
479 | printk(KERN_ERR | ||
480 | "comedi%d: me4000: me4000_probe(): Cannot init dio context\n", | ||
481 | dev->minor); | ||
482 | return result; | ||
483 | } | ||
484 | |||
485 | /* Init counter context */ | ||
486 | result = init_cnt_context(dev); | ||
487 | if (result) { | ||
488 | printk(KERN_ERR | ||
489 | "comedi%d: me4000: me4000_probe(): Cannot init cnt context\n", | ||
490 | dev->minor); | ||
491 | return result; | ||
492 | } | ||
493 | |||
494 | /* Download the xilinx firmware */ | ||
495 | result = xilinx_download(dev); | ||
496 | if (result) { | ||
497 | printk(KERN_ERR | ||
498 | "comedi%d: me4000: me4000_probe(): Can't download firmware\n", | ||
499 | dev->minor); | ||
500 | return result; | ||
501 | } | ||
502 | |||
503 | /* Make a hardware reset */ | ||
504 | result = reset_board(dev); | ||
505 | if (result) { | ||
506 | printk(KERN_ERR | ||
507 | "comedi%d: me4000: me4000_probe(): Can't reset board\n", | ||
508 | dev->minor); | ||
509 | return result; | ||
510 | } | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static int get_registers(comedi_device * dev, struct pci_dev *pci_dev_p) | ||
516 | { | ||
517 | |||
518 | CALL_PDEBUG("In get_registers()\n"); | ||
519 | |||
520 | /*--------------------------- plx regbase ---------------------------------*/ | ||
521 | |||
522 | info->plx_regbase = pci_resource_start(pci_dev_p, 1); | ||
523 | if (info->plx_regbase == 0) { | ||
524 | printk(KERN_ERR | ||
525 | "comedi%d: me4000: get_registers(): PCI base address 1 is not available\n", | ||
526 | dev->minor); | ||
527 | return -ENODEV; | ||
528 | } | ||
529 | info->plx_regbase_size = pci_resource_len(pci_dev_p, 1); | ||
530 | |||
531 | /*--------------------------- me4000 regbase ------------------------------*/ | ||
532 | |||
533 | info->me4000_regbase = pci_resource_start(pci_dev_p, 2); | ||
534 | if (info->me4000_regbase == 0) { | ||
535 | printk(KERN_ERR | ||
536 | "comedi%d: me4000: get_registers(): PCI base address 2 is not available\n", | ||
537 | dev->minor); | ||
538 | return -ENODEV; | ||
539 | } | ||
540 | info->me4000_regbase_size = pci_resource_len(pci_dev_p, 2); | ||
541 | |||
542 | /*--------------------------- timer regbase ------------------------------*/ | ||
543 | |||
544 | info->timer_regbase = pci_resource_start(pci_dev_p, 3); | ||
545 | if (info->timer_regbase == 0) { | ||
546 | printk(KERN_ERR | ||
547 | "comedi%d: me4000: get_registers(): PCI base address 3 is not available\n", | ||
548 | dev->minor); | ||
549 | return -ENODEV; | ||
550 | } | ||
551 | info->timer_regbase_size = pci_resource_len(pci_dev_p, 3); | ||
552 | |||
553 | /*--------------------------- program regbase ------------------------------*/ | ||
554 | |||
555 | info->program_regbase = pci_resource_start(pci_dev_p, 5); | ||
556 | if (info->program_regbase == 0) { | ||
557 | printk(KERN_ERR | ||
558 | "comedi%d: me4000: get_registers(): PCI base address 5 is not available\n", | ||
559 | dev->minor); | ||
560 | return -ENODEV; | ||
561 | } | ||
562 | info->program_regbase_size = pci_resource_len(pci_dev_p, 5); | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static int init_board_info(comedi_device * dev, struct pci_dev *pci_dev_p) | ||
568 | { | ||
569 | int result; | ||
570 | |||
571 | CALL_PDEBUG("In init_board_info()\n"); | ||
572 | |||
573 | /* Init spin locks */ | ||
574 | //spin_lock_init(&info->preload_lock); | ||
575 | //spin_lock_init(&info->ai_ctrl_lock); | ||
576 | |||
577 | /* Get the serial number */ | ||
578 | result = pci_read_config_dword(pci_dev_p, 0x2C, &info->serial_no); | ||
579 | if (result != PCIBIOS_SUCCESSFUL) { | ||
580 | return result; | ||
581 | } | ||
582 | |||
583 | /* Get the hardware revision */ | ||
584 | result = pci_read_config_byte(pci_dev_p, 0x08, &info->hw_revision); | ||
585 | if (result != PCIBIOS_SUCCESSFUL) { | ||
586 | return result; | ||
587 | } | ||
588 | |||
589 | /* Get the vendor id */ | ||
590 | info->vendor_id = pci_dev_p->vendor; | ||
591 | |||
592 | /* Get the device id */ | ||
593 | info->device_id = pci_dev_p->device; | ||
594 | |||
595 | /* Get the irq assigned to the board */ | ||
596 | info->irq = pci_dev_p->irq; | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | static int init_ao_context(comedi_device * dev) | ||
602 | { | ||
603 | int i; | ||
604 | |||
605 | CALL_PDEBUG("In init_ao_context()\n"); | ||
606 | |||
607 | for (i = 0; i < thisboard->ao.count; i++) { | ||
608 | //spin_lock_init(&info->ao_context[i].use_lock); | ||
609 | info->ao_context[i].irq = info->irq; | ||
610 | |||
611 | switch (i) { | ||
612 | case 0: | ||
613 | info->ao_context[i].ctrl_reg = | ||
614 | info->me4000_regbase + ME4000_AO_00_CTRL_REG; | ||
615 | info->ao_context[i].status_reg = | ||
616 | info->me4000_regbase + ME4000_AO_00_STATUS_REG; | ||
617 | info->ao_context[i].fifo_reg = | ||
618 | info->me4000_regbase + ME4000_AO_00_FIFO_REG; | ||
619 | info->ao_context[i].single_reg = | ||
620 | info->me4000_regbase + ME4000_AO_00_SINGLE_REG; | ||
621 | info->ao_context[i].timer_reg = | ||
622 | info->me4000_regbase + ME4000_AO_00_TIMER_REG; | ||
623 | info->ao_context[i].irq_status_reg = | ||
624 | info->me4000_regbase + ME4000_IRQ_STATUS_REG; | ||
625 | info->ao_context[i].preload_reg = | ||
626 | info->me4000_regbase + ME4000_AO_LOADSETREG_XX; | ||
627 | break; | ||
628 | case 1: | ||
629 | info->ao_context[i].ctrl_reg = | ||
630 | info->me4000_regbase + ME4000_AO_01_CTRL_REG; | ||
631 | info->ao_context[i].status_reg = | ||
632 | info->me4000_regbase + ME4000_AO_01_STATUS_REG; | ||
633 | info->ao_context[i].fifo_reg = | ||
634 | info->me4000_regbase + ME4000_AO_01_FIFO_REG; | ||
635 | info->ao_context[i].single_reg = | ||
636 | info->me4000_regbase + ME4000_AO_01_SINGLE_REG; | ||
637 | info->ao_context[i].timer_reg = | ||
638 | info->me4000_regbase + ME4000_AO_01_TIMER_REG; | ||
639 | info->ao_context[i].irq_status_reg = | ||
640 | info->me4000_regbase + ME4000_IRQ_STATUS_REG; | ||
641 | info->ao_context[i].preload_reg = | ||
642 | info->me4000_regbase + ME4000_AO_LOADSETREG_XX; | ||
643 | break; | ||
644 | case 2: | ||
645 | info->ao_context[i].ctrl_reg = | ||
646 | info->me4000_regbase + ME4000_AO_02_CTRL_REG; | ||
647 | info->ao_context[i].status_reg = | ||
648 | info->me4000_regbase + ME4000_AO_02_STATUS_REG; | ||
649 | info->ao_context[i].fifo_reg = | ||
650 | info->me4000_regbase + ME4000_AO_02_FIFO_REG; | ||
651 | info->ao_context[i].single_reg = | ||
652 | info->me4000_regbase + ME4000_AO_02_SINGLE_REG; | ||
653 | info->ao_context[i].timer_reg = | ||
654 | info->me4000_regbase + ME4000_AO_02_TIMER_REG; | ||
655 | info->ao_context[i].irq_status_reg = | ||
656 | info->me4000_regbase + ME4000_IRQ_STATUS_REG; | ||
657 | info->ao_context[i].preload_reg = | ||
658 | info->me4000_regbase + ME4000_AO_LOADSETREG_XX; | ||
659 | break; | ||
660 | case 3: | ||
661 | info->ao_context[i].ctrl_reg = | ||
662 | info->me4000_regbase + ME4000_AO_03_CTRL_REG; | ||
663 | info->ao_context[i].status_reg = | ||
664 | info->me4000_regbase + ME4000_AO_03_STATUS_REG; | ||
665 | info->ao_context[i].fifo_reg = | ||
666 | info->me4000_regbase + ME4000_AO_03_FIFO_REG; | ||
667 | info->ao_context[i].single_reg = | ||
668 | info->me4000_regbase + ME4000_AO_03_SINGLE_REG; | ||
669 | info->ao_context[i].timer_reg = | ||
670 | info->me4000_regbase + ME4000_AO_03_TIMER_REG; | ||
671 | info->ao_context[i].irq_status_reg = | ||
672 | info->me4000_regbase + ME4000_IRQ_STATUS_REG; | ||
673 | info->ao_context[i].preload_reg = | ||
674 | info->me4000_regbase + ME4000_AO_LOADSETREG_XX; | ||
675 | break; | ||
676 | default: | ||
677 | break; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | static int init_ai_context(comedi_device * dev) | ||
685 | { | ||
686 | |||
687 | CALL_PDEBUG("In init_ai_context()\n"); | ||
688 | |||
689 | info->ai_context.irq = info->irq; | ||
690 | |||
691 | info->ai_context.ctrl_reg = info->me4000_regbase + ME4000_AI_CTRL_REG; | ||
692 | info->ai_context.status_reg = | ||
693 | info->me4000_regbase + ME4000_AI_STATUS_REG; | ||
694 | info->ai_context.channel_list_reg = | ||
695 | info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG; | ||
696 | info->ai_context.data_reg = info->me4000_regbase + ME4000_AI_DATA_REG; | ||
697 | info->ai_context.chan_timer_reg = | ||
698 | info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG; | ||
699 | info->ai_context.chan_pre_timer_reg = | ||
700 | info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG; | ||
701 | info->ai_context.scan_timer_low_reg = | ||
702 | info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG; | ||
703 | info->ai_context.scan_timer_high_reg = | ||
704 | info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG; | ||
705 | info->ai_context.scan_pre_timer_low_reg = | ||
706 | info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG; | ||
707 | info->ai_context.scan_pre_timer_high_reg = | ||
708 | info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG; | ||
709 | info->ai_context.start_reg = info->me4000_regbase + ME4000_AI_START_REG; | ||
710 | info->ai_context.irq_status_reg = | ||
711 | info->me4000_regbase + ME4000_IRQ_STATUS_REG; | ||
712 | info->ai_context.sample_counter_reg = | ||
713 | info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG; | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | static int init_dio_context(comedi_device * dev) | ||
719 | { | ||
720 | |||
721 | CALL_PDEBUG("In init_dio_context()\n"); | ||
722 | |||
723 | info->dio_context.dir_reg = info->me4000_regbase + ME4000_DIO_DIR_REG; | ||
724 | info->dio_context.ctrl_reg = info->me4000_regbase + ME4000_DIO_CTRL_REG; | ||
725 | info->dio_context.port_0_reg = | ||
726 | info->me4000_regbase + ME4000_DIO_PORT_0_REG; | ||
727 | info->dio_context.port_1_reg = | ||
728 | info->me4000_regbase + ME4000_DIO_PORT_1_REG; | ||
729 | info->dio_context.port_2_reg = | ||
730 | info->me4000_regbase + ME4000_DIO_PORT_2_REG; | ||
731 | info->dio_context.port_3_reg = | ||
732 | info->me4000_regbase + ME4000_DIO_PORT_3_REG; | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static int init_cnt_context(comedi_device * dev) | ||
738 | { | ||
739 | |||
740 | CALL_PDEBUG("In init_cnt_context()\n"); | ||
741 | |||
742 | info->cnt_context.ctrl_reg = info->timer_regbase + ME4000_CNT_CTRL_REG; | ||
743 | info->cnt_context.counter_0_reg = | ||
744 | info->timer_regbase + ME4000_CNT_COUNTER_0_REG; | ||
745 | info->cnt_context.counter_1_reg = | ||
746 | info->timer_regbase + ME4000_CNT_COUNTER_1_REG; | ||
747 | info->cnt_context.counter_2_reg = | ||
748 | info->timer_regbase + ME4000_CNT_COUNTER_2_REG; | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | #define FIRMWARE_NOT_AVAILABLE 1 | ||
754 | #if FIRMWARE_NOT_AVAILABLE | ||
755 | extern unsigned char *xilinx_firm; | ||
756 | #endif | ||
757 | |||
758 | static int xilinx_download(comedi_device * dev) | ||
759 | { | ||
760 | u32 value = 0; | ||
761 | wait_queue_head_t queue; | ||
762 | int idx = 0; | ||
763 | int size = 0; | ||
764 | |||
765 | CALL_PDEBUG("In xilinx_download()\n"); | ||
766 | |||
767 | init_waitqueue_head(&queue); | ||
768 | |||
769 | /* | ||
770 | * Set PLX local interrupt 2 polarity to high. | ||
771 | * Interrupt is thrown by init pin of xilinx. | ||
772 | */ | ||
773 | outl(0x10, info->plx_regbase + PLX_INTCSR); | ||
774 | |||
775 | /* Set /CS and /WRITE of the Xilinx */ | ||
776 | value = inl(info->plx_regbase + PLX_ICR); | ||
777 | value |= 0x100; | ||
778 | outl(value, info->plx_regbase + PLX_ICR); | ||
779 | |||
780 | /* Init Xilinx with CS1 */ | ||
781 | inb(info->program_regbase + 0xC8); | ||
782 | |||
783 | /* Wait until /INIT pin is set */ | ||
784 | udelay(20); | ||
785 | if (!inl(info->plx_regbase + PLX_INTCSR) & 0x20) { | ||
786 | printk(KERN_ERR | ||
787 | "comedi%d: me4000: xilinx_download(): Can't init Xilinx\n", | ||
788 | dev->minor); | ||
789 | return -EIO; | ||
790 | } | ||
791 | |||
792 | /* Reset /CS and /WRITE of the Xilinx */ | ||
793 | value = inl(info->plx_regbase + PLX_ICR); | ||
794 | value &= ~0x100; | ||
795 | outl(value, info->plx_regbase + PLX_ICR); | ||
796 | if (FIRMWARE_NOT_AVAILABLE) { | ||
797 | comedi_error(dev, | ||
798 | "xilinx firmware unavailable due to licensing, aborting"); | ||
799 | return -EIO; | ||
800 | } else { | ||
801 | /* Download Xilinx firmware */ | ||
802 | size = (xilinx_firm[0] << 24) + (xilinx_firm[1] << 16) + | ||
803 | (xilinx_firm[2] << 8) + xilinx_firm[3]; | ||
804 | udelay(10); | ||
805 | |||
806 | for (idx = 0; idx < size; idx++) { | ||
807 | outb(xilinx_firm[16 + idx], info->program_regbase); | ||
808 | udelay(10); | ||
809 | |||
810 | /* Check if BUSY flag is low */ | ||
811 | if (inl(info->plx_regbase + PLX_ICR) & 0x20) { | ||
812 | printk(KERN_ERR | ||
813 | "comedi%d: me4000: xilinx_download(): Xilinx is still busy (idx = %d)\n", | ||
814 | dev->minor, idx); | ||
815 | return -EIO; | ||
816 | } | ||
817 | } | ||
818 | } | ||
819 | |||
820 | /* If done flag is high download was successful */ | ||
821 | if (inl(info->plx_regbase + PLX_ICR) & 0x4) { | ||
822 | } else { | ||
823 | printk(KERN_ERR | ||
824 | "comedi%d: me4000: xilinx_download(): DONE flag is not set\n", | ||
825 | dev->minor); | ||
826 | printk(KERN_ERR | ||
827 | "comedi%d: me4000: xilinx_download(): Download not succesful\n", | ||
828 | dev->minor); | ||
829 | return -EIO; | ||
830 | } | ||
831 | |||
832 | /* Set /CS and /WRITE */ | ||
833 | value = inl(info->plx_regbase + PLX_ICR); | ||
834 | value |= 0x100; | ||
835 | outl(value, info->plx_regbase + PLX_ICR); | ||
836 | |||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | static int reset_board(comedi_device * dev) | ||
841 | { | ||
842 | unsigned long icr; | ||
843 | |||
844 | CALL_PDEBUG("In reset_board()\n"); | ||
845 | |||
846 | /* Make a hardware reset */ | ||
847 | icr = me4000_inl(dev, info->plx_regbase + PLX_ICR); | ||
848 | icr |= 0x40000000; | ||
849 | me4000_outl(dev, icr, info->plx_regbase + PLX_ICR); | ||
850 | icr &= ~0x40000000; | ||
851 | me4000_outl(dev, icr, info->plx_regbase + PLX_ICR); | ||
852 | |||
853 | /* 0x8000 to the DACs means an output voltage of 0V */ | ||
854 | me4000_outl(dev, 0x8000, | ||
855 | info->me4000_regbase + ME4000_AO_00_SINGLE_REG); | ||
856 | me4000_outl(dev, 0x8000, | ||
857 | info->me4000_regbase + ME4000_AO_01_SINGLE_REG); | ||
858 | me4000_outl(dev, 0x8000, | ||
859 | info->me4000_regbase + ME4000_AO_02_SINGLE_REG); | ||
860 | me4000_outl(dev, 0x8000, | ||
861 | info->me4000_regbase + ME4000_AO_03_SINGLE_REG); | ||
862 | |||
863 | /* Set both stop bits in the analog input control register */ | ||
864 | me4000_outl(dev, | ||
865 | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, | ||
866 | info->me4000_regbase + ME4000_AI_CTRL_REG); | ||
867 | |||
868 | /* Set both stop bits in the analog output control register */ | ||
869 | me4000_outl(dev, | ||
870 | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, | ||
871 | info->me4000_regbase + ME4000_AO_00_CTRL_REG); | ||
872 | me4000_outl(dev, | ||
873 | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, | ||
874 | info->me4000_regbase + ME4000_AO_01_CTRL_REG); | ||
875 | me4000_outl(dev, | ||
876 | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, | ||
877 | info->me4000_regbase + ME4000_AO_02_CTRL_REG); | ||
878 | me4000_outl(dev, | ||
879 | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, | ||
880 | info->me4000_regbase + ME4000_AO_03_CTRL_REG); | ||
881 | |||
882 | /* Enable interrupts on the PLX */ | ||
883 | me4000_outl(dev, 0x43, info->plx_regbase + PLX_INTCSR); | ||
884 | |||
885 | /* Set the adustment register for AO demux */ | ||
886 | me4000_outl(dev, ME4000_AO_DEMUX_ADJUST_VALUE, | ||
887 | info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG); | ||
888 | |||
889 | /* Set digital I/O direction for port 0 to output on isolated versions */ | ||
890 | if (!(me4000_inl(dev, info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) { | ||
891 | me4000_outl(dev, 0x1, | ||
892 | info->me4000_regbase + ME4000_DIO_CTRL_REG); | ||
893 | } | ||
894 | |||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | static int me4000_detach(comedi_device * dev) | ||
899 | { | ||
900 | CALL_PDEBUG("In me4000_detach()\n"); | ||
901 | |||
902 | if (info) { | ||
903 | if (info->pci_dev_p) { | ||
904 | reset_board(dev); | ||
905 | if (info->plx_regbase) { | ||
906 | comedi_pci_disable(info->pci_dev_p); | ||
907 | } | ||
908 | pci_dev_put(info->pci_dev_p); | ||
909 | } | ||
910 | } | ||
911 | |||
912 | return 0; | ||
913 | } | ||
914 | |||
915 | /*============================================================================= | ||
916 | Analog input section | ||
917 | ===========================================================================*/ | ||
918 | |||
919 | static int me4000_ai_insn_read(comedi_device * dev, | ||
920 | comedi_subdevice * subdevice, comedi_insn * insn, lsampl_t * data) | ||
921 | { | ||
922 | |||
923 | int chan = CR_CHAN(insn->chanspec); | ||
924 | int rang = CR_RANGE(insn->chanspec); | ||
925 | int aref = CR_AREF(insn->chanspec); | ||
926 | |||
927 | unsigned long entry = 0; | ||
928 | unsigned long tmp; | ||
929 | long lval; | ||
930 | |||
931 | CALL_PDEBUG("In me4000_ai_insn_read()\n"); | ||
932 | |||
933 | if (insn->n == 0) { | ||
934 | return 0; | ||
935 | } else if (insn->n > 1) { | ||
936 | printk(KERN_ERR | ||
937 | "comedi%d: me4000: me4000_ai_insn_read(): Invalid instruction length %d\n", | ||
938 | dev->minor, insn->n); | ||
939 | return -EINVAL; | ||
940 | } | ||
941 | |||
942 | switch (rang) { | ||
943 | case 0: | ||
944 | entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; | ||
945 | break; | ||
946 | case 1: | ||
947 | entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; | ||
948 | break; | ||
949 | case 2: | ||
950 | entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; | ||
951 | break; | ||
952 | case 3: | ||
953 | entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; | ||
954 | break; | ||
955 | default: | ||
956 | printk(KERN_ERR | ||
957 | "comedi%d: me4000: me4000_ai_insn_read(): Invalid range specified\n", | ||
958 | dev->minor); | ||
959 | return -EINVAL; | ||
960 | } | ||
961 | |||
962 | switch (aref) { | ||
963 | case AREF_GROUND: | ||
964 | case AREF_COMMON: | ||
965 | if (chan >= thisboard->ai.count) { | ||
966 | printk(KERN_ERR | ||
967 | "comedi%d: me4000: me4000_ai_insn_read(): Analog input is not available\n", | ||
968 | dev->minor); | ||
969 | return -EINVAL; | ||
970 | } | ||
971 | entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan; | ||
972 | break; | ||
973 | |||
974 | case AREF_DIFF: | ||
975 | if (rang == 0 || rang == 1) { | ||
976 | printk(KERN_ERR | ||
977 | "comedi%d: me4000: me4000_ai_insn_read(): Range must be bipolar when aref = diff\n", | ||
978 | dev->minor); | ||
979 | return -EINVAL; | ||
980 | } | ||
981 | |||
982 | if (chan >= thisboard->ai.diff_count) { | ||
983 | printk(KERN_ERR | ||
984 | "comedi%d: me4000: me4000_ai_insn_read(): Analog input is not available\n", | ||
985 | dev->minor); | ||
986 | return -EINVAL; | ||
987 | } | ||
988 | entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan; | ||
989 | break; | ||
990 | default: | ||
991 | printk(KERN_ERR | ||
992 | "comedi%d: me4000: me4000_ai_insn_read(): Invalid aref specified\n", | ||
993 | dev->minor); | ||
994 | return -EINVAL; | ||
995 | } | ||
996 | |||
997 | entry |= ME4000_AI_LIST_LAST_ENTRY; | ||
998 | |||
999 | /* Clear channel list, data fifo and both stop bits */ | ||
1000 | tmp = me4000_inl(dev, info->ai_context.ctrl_reg); | ||
1001 | tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | | ||
1002 | ME4000_AI_CTRL_BIT_DATA_FIFO | | ||
1003 | ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); | ||
1004 | me4000_outl(dev, tmp, info->ai_context.ctrl_reg); | ||
1005 | |||
1006 | /* Set the acquisition mode to single */ | ||
1007 | tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 | | ||
1008 | ME4000_AI_CTRL_BIT_MODE_2); | ||
1009 | me4000_outl(dev, tmp, info->ai_context.ctrl_reg); | ||
1010 | |||
1011 | /* Enable channel list and data fifo */ | ||
1012 | tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO; | ||
1013 | me4000_outl(dev, tmp, info->ai_context.ctrl_reg); | ||
1014 | |||
1015 | /* Generate channel list entry */ | ||
1016 | me4000_outl(dev, entry, info->ai_context.channel_list_reg); | ||
1017 | |||
1018 | /* Set the timer to maximum sample rate */ | ||
1019 | me4000_outl(dev, ME4000_AI_MIN_TICKS, info->ai_context.chan_timer_reg); | ||
1020 | me4000_outl(dev, ME4000_AI_MIN_TICKS, | ||
1021 | info->ai_context.chan_pre_timer_reg); | ||
1022 | |||
1023 | /* Start conversion by dummy read */ | ||
1024 | me4000_inl(dev, info->ai_context.start_reg); | ||
1025 | |||
1026 | /* Wait until ready */ | ||
1027 | udelay(10); | ||
1028 | if (!(me4000_inl(dev, info->ai_context. | ||
1029 | status_reg) & ME4000_AI_STATUS_BIT_EF_DATA)) { | ||
1030 | printk(KERN_ERR | ||
1031 | "comedi%d: me4000: me4000_ai_insn_read(): Value not available after wait\n", | ||
1032 | dev->minor); | ||
1033 | return -EIO; | ||
1034 | } | ||
1035 | |||
1036 | /* Read value from data fifo */ | ||
1037 | lval = me4000_inl(dev, info->ai_context.data_reg) & 0xFFFF; | ||
1038 | data[0] = lval ^ 0x8000; | ||
1039 | |||
1040 | return 1; | ||
1041 | } | ||
1042 | |||
1043 | static int me4000_ai_cancel(comedi_device * dev, comedi_subdevice * s) | ||
1044 | { | ||
1045 | unsigned long tmp; | ||
1046 | |||
1047 | CALL_PDEBUG("In me4000_ai_cancel()\n"); | ||
1048 | |||
1049 | /* Stop any running conversion */ | ||
1050 | tmp = me4000_inl(dev, info->ai_context.ctrl_reg); | ||
1051 | tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); | ||
1052 | me4000_outl(dev, tmp, info->ai_context.ctrl_reg); | ||
1053 | |||
1054 | /* Clear the control register */ | ||
1055 | me4000_outl(dev, 0x0, info->ai_context.ctrl_reg); | ||
1056 | |||
1057 | return 0; | ||
1058 | } | ||
1059 | |||
1060 | static int ai_check_chanlist(comedi_device * dev, | ||
1061 | comedi_subdevice * s, comedi_cmd * cmd) | ||
1062 | { | ||
1063 | int aref; | ||
1064 | int i; | ||
1065 | |||
1066 | CALL_PDEBUG("In ai_check_chanlist()\n"); | ||
1067 | |||
1068 | /* Check whether a channel list is available */ | ||
1069 | if (!cmd->chanlist_len) { | ||
1070 | printk(KERN_ERR | ||
1071 | "comedi%d: me4000: ai_check_chanlist(): No channel list available\n", | ||
1072 | dev->minor); | ||
1073 | return -EINVAL; | ||
1074 | } | ||
1075 | |||
1076 | /* Check the channel list size */ | ||
1077 | if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) { | ||
1078 | printk(KERN_ERR | ||
1079 | "comedi%d: me4000: ai_check_chanlist(): Channel list is to large\n", | ||
1080 | dev->minor); | ||
1081 | return -EINVAL; | ||
1082 | } | ||
1083 | |||
1084 | /* Check the pointer */ | ||
1085 | if (!cmd->chanlist) { | ||
1086 | printk(KERN_ERR | ||
1087 | "comedi%d: me4000: ai_check_chanlist(): NULL pointer to channel list\n", | ||
1088 | dev->minor); | ||
1089 | return -EFAULT; | ||
1090 | } | ||
1091 | |||
1092 | /* Check whether aref is equal for all entries */ | ||
1093 | aref = CR_AREF(cmd->chanlist[0]); | ||
1094 | for (i = 0; i < cmd->chanlist_len; i++) { | ||
1095 | if (CR_AREF(cmd->chanlist[i]) != aref) { | ||
1096 | printk(KERN_ERR | ||
1097 | "comedi%d: me4000: ai_check_chanlist(): Mode is not equal for all entries\n", | ||
1098 | dev->minor); | ||
1099 | return -EINVAL; | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | /* Check whether channels are available for this ending */ | ||
1104 | if (aref == SDF_DIFF) { | ||
1105 | for (i = 0; i < cmd->chanlist_len; i++) { | ||
1106 | if (CR_CHAN(cmd->chanlist[i]) >= | ||
1107 | thisboard->ai.diff_count) { | ||
1108 | printk(KERN_ERR | ||
1109 | "comedi%d: me4000: ai_check_chanlist(): Channel number to high\n", | ||
1110 | dev->minor); | ||
1111 | return -EINVAL; | ||
1112 | } | ||
1113 | } | ||
1114 | } else { | ||
1115 | for (i = 0; i < cmd->chanlist_len; i++) { | ||
1116 | if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai.count) { | ||
1117 | printk(KERN_ERR | ||
1118 | "comedi%d: me4000: ai_check_chanlist(): Channel number to high\n", | ||
1119 | dev->minor); | ||
1120 | return -EINVAL; | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1124 | |||
1125 | /* Check if bipolar is set for all entries when in differential mode */ | ||
1126 | if (aref == SDF_DIFF) { | ||
1127 | for (i = 0; i < cmd->chanlist_len; i++) { | ||
1128 | if (CR_RANGE(cmd->chanlist[i]) != 1 && | ||
1129 | CR_RANGE(cmd->chanlist[i]) != 2) { | ||
1130 | printk(KERN_ERR | ||
1131 | "comedi%d: me4000: ai_check_chanlist(): Bipolar is not selected in differential mode\n", | ||
1132 | dev->minor); | ||
1133 | return -EINVAL; | ||
1134 | } | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1141 | static int ai_round_cmd_args(comedi_device * dev, | ||
1142 | comedi_subdevice * s, | ||
1143 | comedi_cmd * cmd, | ||
1144 | unsigned int *init_ticks, | ||
1145 | unsigned int *scan_ticks, unsigned int *chan_ticks) | ||
1146 | { | ||
1147 | |||
1148 | int rest; | ||
1149 | |||
1150 | CALL_PDEBUG("In ai_round_cmd_args()\n"); | ||
1151 | |||
1152 | *init_ticks = 0; | ||
1153 | *scan_ticks = 0; | ||
1154 | *chan_ticks = 0; | ||
1155 | |||
1156 | PDEBUG("ai_round_cmd_arg(): start_arg = %d\n", cmd->start_arg); | ||
1157 | PDEBUG("ai_round_cmd_arg(): scan_begin_arg = %d\n", | ||
1158 | cmd->scan_begin_arg); | ||
1159 | PDEBUG("ai_round_cmd_arg(): convert_arg = %d\n", cmd->convert_arg); | ||
1160 | |||
1161 | if (cmd->start_arg) { | ||
1162 | *init_ticks = (cmd->start_arg * 33) / 1000; | ||
1163 | rest = (cmd->start_arg * 33) % 1000; | ||
1164 | |||
1165 | if (cmd->flags & TRIG_ROUND_NEAREST) { | ||
1166 | if (rest > 33) { | ||
1167 | (*init_ticks)++; | ||
1168 | } | ||
1169 | } else if (cmd->flags & TRIG_ROUND_UP) { | ||
1170 | if (rest) | ||
1171 | (*init_ticks)++; | ||
1172 | } | ||
1173 | } | ||
1174 | |||
1175 | if (cmd->scan_begin_arg) { | ||
1176 | *scan_ticks = (cmd->scan_begin_arg * 33) / 1000; | ||
1177 | rest = (cmd->scan_begin_arg * 33) % 1000; | ||
1178 | |||
1179 | if (cmd->flags & TRIG_ROUND_NEAREST) { | ||
1180 | if (rest > 33) { | ||
1181 | (*scan_ticks)++; | ||
1182 | } | ||
1183 | } else if (cmd->flags & TRIG_ROUND_UP) { | ||
1184 | if (rest) | ||
1185 | (*scan_ticks)++; | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | if (cmd->convert_arg) { | ||
1190 | *chan_ticks = (cmd->convert_arg * 33) / 1000; | ||
1191 | rest = (cmd->convert_arg * 33) % 1000; | ||
1192 | |||
1193 | if (cmd->flags & TRIG_ROUND_NEAREST) { | ||
1194 | if (rest > 33) { | ||
1195 | (*chan_ticks)++; | ||
1196 | } | ||
1197 | } else if (cmd->flags & TRIG_ROUND_UP) { | ||
1198 | if (rest) | ||
1199 | (*chan_ticks)++; | ||
1200 | } | ||
1201 | } | ||
1202 | |||
1203 | PDEBUG("ai_round_cmd_args(): init_ticks = %d\n", *init_ticks); | ||
1204 | PDEBUG("ai_round_cmd_args(): scan_ticks = %d\n", *scan_ticks); | ||
1205 | PDEBUG("ai_round_cmd_args(): chan_ticks = %d\n", *chan_ticks); | ||
1206 | |||
1207 | return 0; | ||
1208 | } | ||
1209 | |||
1210 | static void ai_write_timer(comedi_device * dev, | ||
1211 | unsigned int init_ticks, | ||
1212 | unsigned int scan_ticks, unsigned int chan_ticks) | ||
1213 | { | ||
1214 | |||
1215 | CALL_PDEBUG("In ai_write_timer()\n"); | ||
1216 | |||
1217 | me4000_outl(dev, init_ticks - 1, | ||
1218 | info->ai_context.scan_pre_timer_low_reg); | ||
1219 | me4000_outl(dev, 0x0, info->ai_context.scan_pre_timer_high_reg); | ||
1220 | |||
1221 | if (scan_ticks) { | ||
1222 | me4000_outl(dev, scan_ticks - 1, | ||
1223 | info->ai_context.scan_timer_low_reg); | ||
1224 | me4000_outl(dev, 0x0, info->ai_context.scan_timer_high_reg); | ||
1225 | } | ||
1226 | |||
1227 | me4000_outl(dev, chan_ticks - 1, info->ai_context.chan_pre_timer_reg); | ||
1228 | me4000_outl(dev, chan_ticks - 1, info->ai_context.chan_timer_reg); | ||
1229 | } | ||
1230 | |||
1231 | static int ai_prepare(comedi_device * dev, | ||
1232 | comedi_subdevice * s, | ||
1233 | comedi_cmd * cmd, | ||
1234 | unsigned int init_ticks, | ||
1235 | unsigned int scan_ticks, unsigned int chan_ticks) | ||
1236 | { | ||
1237 | |||
1238 | unsigned long tmp = 0; | ||
1239 | |||
1240 | CALL_PDEBUG("In ai_prepare()\n"); | ||
1241 | |||
1242 | /* Write timer arguments */ | ||
1243 | ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks); | ||
1244 | |||
1245 | /* Reset control register */ | ||
1246 | me4000_outl(dev, tmp, info->ai_context.ctrl_reg); | ||
1247 | |||
1248 | /* Start sources */ | ||
1249 | if ((cmd->start_src == TRIG_EXT && | ||
1250 | cmd->scan_begin_src == TRIG_TIMER && | ||
1251 | cmd->convert_src == TRIG_TIMER) || | ||
1252 | (cmd->start_src == TRIG_EXT && | ||
1253 | cmd->scan_begin_src == TRIG_FOLLOW && | ||
1254 | cmd->convert_src == TRIG_TIMER)) { | ||
1255 | tmp = ME4000_AI_CTRL_BIT_MODE_1 | | ||
1256 | ME4000_AI_CTRL_BIT_CHANNEL_FIFO | | ||
1257 | ME4000_AI_CTRL_BIT_DATA_FIFO; | ||
1258 | } else if (cmd->start_src == TRIG_EXT && | ||
1259 | cmd->scan_begin_src == TRIG_EXT && | ||
1260 | cmd->convert_src == TRIG_TIMER) { | ||
1261 | tmp = ME4000_AI_CTRL_BIT_MODE_2 | | ||
1262 | ME4000_AI_CTRL_BIT_CHANNEL_FIFO | | ||
1263 | ME4000_AI_CTRL_BIT_DATA_FIFO; | ||
1264 | } else if (cmd->start_src == TRIG_EXT && | ||
1265 | cmd->scan_begin_src == TRIG_EXT && | ||
1266 | cmd->convert_src == TRIG_EXT) { | ||
1267 | tmp = ME4000_AI_CTRL_BIT_MODE_0 | | ||
1268 | ME4000_AI_CTRL_BIT_MODE_1 | | ||
1269 | ME4000_AI_CTRL_BIT_CHANNEL_FIFO | | ||
1270 | ME4000_AI_CTRL_BIT_DATA_FIFO; | ||
1271 | } else { | ||
1272 | tmp = ME4000_AI_CTRL_BIT_MODE_0 | | ||
1273 | ME4000_AI_CTRL_BIT_CHANNEL_FIFO | | ||
1274 | ME4000_AI_CTRL_BIT_DATA_FIFO; | ||
1275 | } | ||
1276 | |||
1277 | /* Stop triggers */ | ||
1278 | if (cmd->stop_src == TRIG_COUNT) { | ||
1279 | me4000_outl(dev, cmd->chanlist_len * cmd->stop_arg, | ||
1280 | info->ai_context.sample_counter_reg); | ||
1281 | tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; | ||
1282 | } else if (cmd->stop_src == TRIG_NONE && | ||
1283 | cmd->scan_end_src == TRIG_COUNT) { | ||
1284 | me4000_outl(dev, cmd->scan_end_arg, | ||
1285 | info->ai_context.sample_counter_reg); | ||
1286 | tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; | ||
1287 | } else { | ||
1288 | tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; | ||
1289 | } | ||
1290 | |||
1291 | /* Write the setup to the control register */ | ||
1292 | me4000_outl(dev, tmp, info->ai_context.ctrl_reg); | ||
1293 | |||
1294 | /* Write the channel list */ | ||
1295 | ai_write_chanlist(dev, s, cmd); | ||
1296 | |||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | static int ai_write_chanlist(comedi_device * dev, | ||
1301 | comedi_subdevice * s, comedi_cmd * cmd) | ||
1302 | { | ||
1303 | unsigned int entry; | ||
1304 | unsigned int chan; | ||
1305 | unsigned int rang; | ||
1306 | unsigned int aref; | ||
1307 | int i; | ||
1308 | |||
1309 | CALL_PDEBUG("In ai_write_chanlist()\n"); | ||
1310 | |||
1311 | for (i = 0; i < cmd->chanlist_len; i++) { | ||
1312 | chan = CR_CHAN(cmd->chanlist[i]); | ||
1313 | rang = CR_RANGE(cmd->chanlist[i]); | ||
1314 | aref = CR_AREF(cmd->chanlist[i]); | ||
1315 | |||
1316 | entry = chan; | ||
1317 | |||
1318 | if (rang == 0) { | ||
1319 | entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; | ||
1320 | } else if (rang == 1) { | ||
1321 | entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; | ||
1322 | } else if (rang == 2) { | ||
1323 | entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; | ||
1324 | } else { | ||
1325 | entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; | ||
1326 | } | ||
1327 | |||
1328 | if (aref == SDF_DIFF) { | ||
1329 | entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; | ||
1330 | } else { | ||
1331 | entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; | ||
1332 | } | ||
1333 | |||
1334 | me4000_outl(dev, entry, info->ai_context.channel_list_reg); | ||
1335 | } | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | static int me4000_ai_do_cmd(comedi_device * dev, comedi_subdevice * s) | ||
1341 | { | ||
1342 | int err; | ||
1343 | unsigned int init_ticks = 0; | ||
1344 | unsigned int scan_ticks = 0; | ||
1345 | unsigned int chan_ticks = 0; | ||
1346 | comedi_cmd *cmd = &s->async->cmd; | ||
1347 | |||
1348 | CALL_PDEBUG("In me4000_ai_do_cmd()\n"); | ||
1349 | |||
1350 | /* Reset the analog input */ | ||
1351 | err = me4000_ai_cancel(dev, s); | ||
1352 | if (err) | ||
1353 | return err; | ||
1354 | |||
1355 | /* Round the timer arguments */ | ||
1356 | err = ai_round_cmd_args(dev, | ||
1357 | s, cmd, &init_ticks, &scan_ticks, &chan_ticks); | ||
1358 | if (err) | ||
1359 | return err; | ||
1360 | |||
1361 | /* Prepare the AI for acquisition */ | ||
1362 | err = ai_prepare(dev, s, cmd, init_ticks, scan_ticks, chan_ticks); | ||
1363 | if (err) | ||
1364 | return err; | ||
1365 | |||
1366 | /* Start acquistion by dummy read */ | ||
1367 | me4000_inl(dev, info->ai_context.start_reg); | ||
1368 | |||
1369 | return 0; | ||
1370 | } | ||
1371 | |||
1372 | /* | ||
1373 | * me4000_ai_do_cmd_test(): | ||
1374 | * | ||
1375 | * The demo cmd.c in ./comedilib/demo specifies 6 return values: | ||
1376 | * - success | ||
1377 | * - invalid source | ||
1378 | * - source conflict | ||
1379 | * - invalid argument | ||
1380 | * - argument conflict | ||
1381 | * - invalid chanlist | ||
1382 | * So I tried to adopt this scheme. | ||
1383 | */ | ||
1384 | static int me4000_ai_do_cmd_test(comedi_device * dev, | ||
1385 | comedi_subdevice * s, comedi_cmd * cmd) | ||
1386 | { | ||
1387 | |||
1388 | unsigned int init_ticks; | ||
1389 | unsigned int chan_ticks; | ||
1390 | unsigned int scan_ticks; | ||
1391 | int err = 0; | ||
1392 | |||
1393 | CALL_PDEBUG("In me4000_ai_do_cmd_test()\n"); | ||
1394 | |||
1395 | PDEBUG("me4000_ai_do_cmd_test(): subdev = %d\n", cmd->subdev); | ||
1396 | PDEBUG("me4000_ai_do_cmd_test(): flags = %08X\n", cmd->flags); | ||
1397 | PDEBUG("me4000_ai_do_cmd_test(): start_src = %08X\n", | ||
1398 | cmd->start_src); | ||
1399 | PDEBUG("me4000_ai_do_cmd_test(): start_arg = %d\n", | ||
1400 | cmd->start_arg); | ||
1401 | PDEBUG("me4000_ai_do_cmd_test(): scan_begin_src = %08X\n", | ||
1402 | cmd->scan_begin_src); | ||
1403 | PDEBUG("me4000_ai_do_cmd_test(): scan_begin_arg = %d\n", | ||
1404 | cmd->scan_begin_arg); | ||
1405 | PDEBUG("me4000_ai_do_cmd_test(): convert_src = %08X\n", | ||
1406 | cmd->convert_src); | ||
1407 | PDEBUG("me4000_ai_do_cmd_test(): convert_arg = %d\n", | ||
1408 | cmd->convert_arg); | ||
1409 | PDEBUG("me4000_ai_do_cmd_test(): scan_end_src = %08X\n", | ||
1410 | cmd->scan_end_src); | ||
1411 | PDEBUG("me4000_ai_do_cmd_test(): scan_end_arg = %d\n", | ||
1412 | cmd->scan_end_arg); | ||
1413 | PDEBUG("me4000_ai_do_cmd_test(): stop_src = %08X\n", | ||
1414 | cmd->stop_src); | ||
1415 | PDEBUG("me4000_ai_do_cmd_test(): stop_arg = %d\n", cmd->stop_arg); | ||
1416 | PDEBUG("me4000_ai_do_cmd_test(): chanlist = %d\n", | ||
1417 | (unsigned int)cmd->chanlist); | ||
1418 | PDEBUG("me4000_ai_do_cmd_test(): chanlist_len = %d\n", | ||
1419 | cmd->chanlist_len); | ||
1420 | |||
1421 | /* Only rounding flags are implemented */ | ||
1422 | cmd->flags &= TRIG_ROUND_NEAREST | TRIG_ROUND_UP | TRIG_ROUND_DOWN; | ||
1423 | |||
1424 | /* Round the timer arguments */ | ||
1425 | ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks); | ||
1426 | |||
1427 | /* | ||
1428 | * Stage 1. Check if the trigger sources are generally valid. | ||
1429 | */ | ||
1430 | switch (cmd->start_src) { | ||
1431 | case TRIG_NOW: | ||
1432 | case TRIG_EXT: | ||
1433 | break; | ||
1434 | case TRIG_ANY: | ||
1435 | cmd->start_src &= TRIG_NOW | TRIG_EXT; | ||
1436 | err++; | ||
1437 | break; | ||
1438 | default: | ||
1439 | printk(KERN_ERR | ||
1440 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start source\n", | ||
1441 | dev->minor); | ||
1442 | cmd->start_src = TRIG_NOW; | ||
1443 | err++; | ||
1444 | } | ||
1445 | switch (cmd->scan_begin_src) { | ||
1446 | case TRIG_FOLLOW: | ||
1447 | case TRIG_TIMER: | ||
1448 | case TRIG_EXT: | ||
1449 | break; | ||
1450 | case TRIG_ANY: | ||
1451 | cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT; | ||
1452 | err++; | ||
1453 | break; | ||
1454 | default: | ||
1455 | printk(KERN_ERR | ||
1456 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan begin source\n", | ||
1457 | dev->minor); | ||
1458 | cmd->scan_begin_src = TRIG_FOLLOW; | ||
1459 | err++; | ||
1460 | } | ||
1461 | switch (cmd->convert_src) { | ||
1462 | case TRIG_TIMER: | ||
1463 | case TRIG_EXT: | ||
1464 | break; | ||
1465 | case TRIG_ANY: | ||
1466 | cmd->convert_src &= TRIG_TIMER | TRIG_EXT; | ||
1467 | err++; | ||
1468 | break; | ||
1469 | default: | ||
1470 | printk(KERN_ERR | ||
1471 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert source\n", | ||
1472 | dev->minor); | ||
1473 | cmd->convert_src = TRIG_TIMER; | ||
1474 | err++; | ||
1475 | } | ||
1476 | switch (cmd->scan_end_src) { | ||
1477 | case TRIG_NONE: | ||
1478 | case TRIG_COUNT: | ||
1479 | break; | ||
1480 | case TRIG_ANY: | ||
1481 | cmd->scan_end_src &= TRIG_NONE | TRIG_COUNT; | ||
1482 | err++; | ||
1483 | break; | ||
1484 | default: | ||
1485 | printk(KERN_ERR | ||
1486 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan end source\n", | ||
1487 | dev->minor); | ||
1488 | cmd->scan_end_src = TRIG_NONE; | ||
1489 | err++; | ||
1490 | } | ||
1491 | switch (cmd->stop_src) { | ||
1492 | case TRIG_NONE: | ||
1493 | case TRIG_COUNT: | ||
1494 | break; | ||
1495 | case TRIG_ANY: | ||
1496 | cmd->stop_src &= TRIG_NONE | TRIG_COUNT; | ||
1497 | err++; | ||
1498 | break; | ||
1499 | default: | ||
1500 | printk(KERN_ERR | ||
1501 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid stop source\n", | ||
1502 | dev->minor); | ||
1503 | cmd->stop_src = TRIG_NONE; | ||
1504 | err++; | ||
1505 | } | ||
1506 | if (err) { | ||
1507 | return 1; | ||
1508 | } | ||
1509 | |||
1510 | /* | ||
1511 | * Stage 2. Check for trigger source conflicts. | ||
1512 | */ | ||
1513 | if (cmd->start_src == TRIG_NOW && | ||
1514 | cmd->scan_begin_src == TRIG_TIMER && | ||
1515 | cmd->convert_src == TRIG_TIMER) { | ||
1516 | } else if (cmd->start_src == TRIG_NOW && | ||
1517 | cmd->scan_begin_src == TRIG_FOLLOW && | ||
1518 | cmd->convert_src == TRIG_TIMER) { | ||
1519 | } else if (cmd->start_src == TRIG_EXT && | ||
1520 | cmd->scan_begin_src == TRIG_TIMER && | ||
1521 | cmd->convert_src == TRIG_TIMER) { | ||
1522 | } else if (cmd->start_src == TRIG_EXT && | ||
1523 | cmd->scan_begin_src == TRIG_FOLLOW && | ||
1524 | cmd->convert_src == TRIG_TIMER) { | ||
1525 | } else if (cmd->start_src == TRIG_EXT && | ||
1526 | cmd->scan_begin_src == TRIG_EXT && | ||
1527 | cmd->convert_src == TRIG_TIMER) { | ||
1528 | } else if (cmd->start_src == TRIG_EXT && | ||
1529 | cmd->scan_begin_src == TRIG_EXT && | ||
1530 | cmd->convert_src == TRIG_EXT) { | ||
1531 | } else { | ||
1532 | printk(KERN_ERR | ||
1533 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start trigger combination\n", | ||
1534 | dev->minor); | ||
1535 | cmd->start_src = TRIG_NOW; | ||
1536 | cmd->scan_begin_src = TRIG_FOLLOW; | ||
1537 | cmd->convert_src = TRIG_TIMER; | ||
1538 | err++; | ||
1539 | } | ||
1540 | |||
1541 | if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) { | ||
1542 | } else if (cmd->stop_src == TRIG_COUNT && | ||
1543 | cmd->scan_end_src == TRIG_NONE) { | ||
1544 | } else if (cmd->stop_src == TRIG_NONE && | ||
1545 | cmd->scan_end_src == TRIG_COUNT) { | ||
1546 | } else if (cmd->stop_src == TRIG_COUNT && | ||
1547 | cmd->scan_end_src == TRIG_COUNT) { | ||
1548 | } else { | ||
1549 | printk(KERN_ERR | ||
1550 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid stop trigger combination\n", | ||
1551 | dev->minor); | ||
1552 | cmd->stop_src = TRIG_NONE; | ||
1553 | cmd->scan_end_src = TRIG_NONE; | ||
1554 | err++; | ||
1555 | } | ||
1556 | if (err) { | ||
1557 | return 2; | ||
1558 | } | ||
1559 | |||
1560 | /* | ||
1561 | * Stage 3. Check if arguments are generally valid. | ||
1562 | */ | ||
1563 | if (cmd->chanlist_len < 1) { | ||
1564 | printk(KERN_ERR | ||
1565 | "comedi%d: me4000: me4000_ai_do_cmd_test(): No channel list\n", | ||
1566 | dev->minor); | ||
1567 | cmd->chanlist_len = 1; | ||
1568 | err++; | ||
1569 | } | ||
1570 | if (init_ticks < 66) { | ||
1571 | printk(KERN_ERR | ||
1572 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Start arg to low\n", | ||
1573 | dev->minor); | ||
1574 | cmd->start_arg = 2000; | ||
1575 | err++; | ||
1576 | } | ||
1577 | if (scan_ticks && scan_ticks < 67) { | ||
1578 | printk(KERN_ERR | ||
1579 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Scan begin arg to low\n", | ||
1580 | dev->minor); | ||
1581 | cmd->scan_begin_arg = 2031; | ||
1582 | err++; | ||
1583 | } | ||
1584 | if (chan_ticks < 66) { | ||
1585 | printk(KERN_ERR | ||
1586 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Convert arg to low\n", | ||
1587 | dev->minor); | ||
1588 | cmd->convert_arg = 2000; | ||
1589 | err++; | ||
1590 | } | ||
1591 | if (err) { | ||
1592 | return 3; | ||
1593 | } | ||
1594 | |||
1595 | /* | ||
1596 | * Stage 4. Check for argument conflicts. | ||
1597 | */ | ||
1598 | if (cmd->start_src == TRIG_NOW && | ||
1599 | cmd->scan_begin_src == TRIG_TIMER && | ||
1600 | cmd->convert_src == TRIG_TIMER) { | ||
1601 | |||
1602 | /* Check timer arguments */ | ||
1603 | if (init_ticks < ME4000_AI_MIN_TICKS) { | ||
1604 | printk(KERN_ERR | ||
1605 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n", | ||
1606 | dev->minor); | ||
1607 | cmd->start_arg = 2000; // 66 ticks at least | ||
1608 | err++; | ||
1609 | } | ||
1610 | if (chan_ticks < ME4000_AI_MIN_TICKS) { | ||
1611 | printk(KERN_ERR | ||
1612 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n", | ||
1613 | dev->minor); | ||
1614 | cmd->convert_arg = 2000; // 66 ticks at least | ||
1615 | err++; | ||
1616 | } | ||
1617 | if (scan_ticks <= cmd->chanlist_len * chan_ticks) { | ||
1618 | printk(KERN_ERR | ||
1619 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan end arg\n", | ||
1620 | dev->minor); | ||
1621 | cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; // At least one tick more | ||
1622 | err++; | ||
1623 | } | ||
1624 | } else if (cmd->start_src == TRIG_NOW && | ||
1625 | cmd->scan_begin_src == TRIG_FOLLOW && | ||
1626 | cmd->convert_src == TRIG_TIMER) { | ||
1627 | |||
1628 | /* Check timer arguments */ | ||
1629 | if (init_ticks < ME4000_AI_MIN_TICKS) { | ||
1630 | printk(KERN_ERR | ||
1631 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n", | ||
1632 | dev->minor); | ||
1633 | cmd->start_arg = 2000; // 66 ticks at least | ||
1634 | err++; | ||
1635 | } | ||
1636 | if (chan_ticks < ME4000_AI_MIN_TICKS) { | ||
1637 | printk(KERN_ERR | ||
1638 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n", | ||
1639 | dev->minor); | ||
1640 | cmd->convert_arg = 2000; // 66 ticks at least | ||
1641 | err++; | ||
1642 | } | ||
1643 | } else if (cmd->start_src == TRIG_EXT && | ||
1644 | cmd->scan_begin_src == TRIG_TIMER && | ||
1645 | cmd->convert_src == TRIG_TIMER) { | ||
1646 | |||
1647 | /* Check timer arguments */ | ||
1648 | if (init_ticks < ME4000_AI_MIN_TICKS) { | ||
1649 | printk(KERN_ERR | ||
1650 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n", | ||
1651 | dev->minor); | ||
1652 | cmd->start_arg = 2000; // 66 ticks at least | ||
1653 | err++; | ||
1654 | } | ||
1655 | if (chan_ticks < ME4000_AI_MIN_TICKS) { | ||
1656 | printk(KERN_ERR | ||
1657 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n", | ||
1658 | dev->minor); | ||
1659 | cmd->convert_arg = 2000; // 66 ticks at least | ||
1660 | err++; | ||
1661 | } | ||
1662 | if (scan_ticks <= cmd->chanlist_len * chan_ticks) { | ||
1663 | printk(KERN_ERR | ||
1664 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan end arg\n", | ||
1665 | dev->minor); | ||
1666 | cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; // At least one tick more | ||
1667 | err++; | ||
1668 | } | ||
1669 | } else if (cmd->start_src == TRIG_EXT && | ||
1670 | cmd->scan_begin_src == TRIG_FOLLOW && | ||
1671 | cmd->convert_src == TRIG_TIMER) { | ||
1672 | |||
1673 | /* Check timer arguments */ | ||
1674 | if (init_ticks < ME4000_AI_MIN_TICKS) { | ||
1675 | printk(KERN_ERR | ||
1676 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n", | ||
1677 | dev->minor); | ||
1678 | cmd->start_arg = 2000; // 66 ticks at least | ||
1679 | err++; | ||
1680 | } | ||
1681 | if (chan_ticks < ME4000_AI_MIN_TICKS) { | ||
1682 | printk(KERN_ERR | ||
1683 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n", | ||
1684 | dev->minor); | ||
1685 | cmd->convert_arg = 2000; // 66 ticks at least | ||
1686 | err++; | ||
1687 | } | ||
1688 | } else if (cmd->start_src == TRIG_EXT && | ||
1689 | cmd->scan_begin_src == TRIG_EXT && | ||
1690 | cmd->convert_src == TRIG_TIMER) { | ||
1691 | |||
1692 | /* Check timer arguments */ | ||
1693 | if (init_ticks < ME4000_AI_MIN_TICKS) { | ||
1694 | printk(KERN_ERR | ||
1695 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n", | ||
1696 | dev->minor); | ||
1697 | cmd->start_arg = 2000; // 66 ticks at least | ||
1698 | err++; | ||
1699 | } | ||
1700 | if (chan_ticks < ME4000_AI_MIN_TICKS) { | ||
1701 | printk(KERN_ERR | ||
1702 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n", | ||
1703 | dev->minor); | ||
1704 | cmd->convert_arg = 2000; // 66 ticks at least | ||
1705 | err++; | ||
1706 | } | ||
1707 | } else if (cmd->start_src == TRIG_EXT && | ||
1708 | cmd->scan_begin_src == TRIG_EXT && | ||
1709 | cmd->convert_src == TRIG_EXT) { | ||
1710 | |||
1711 | /* Check timer arguments */ | ||
1712 | if (init_ticks < ME4000_AI_MIN_TICKS) { | ||
1713 | printk(KERN_ERR | ||
1714 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n", | ||
1715 | dev->minor); | ||
1716 | cmd->start_arg = 2000; // 66 ticks at least | ||
1717 | err++; | ||
1718 | } | ||
1719 | } | ||
1720 | if (cmd->stop_src == TRIG_COUNT) { | ||
1721 | if (cmd->stop_arg == 0) { | ||
1722 | printk(KERN_ERR | ||
1723 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid stop arg\n", | ||
1724 | dev->minor); | ||
1725 | cmd->stop_arg = 1; | ||
1726 | err++; | ||
1727 | } | ||
1728 | } | ||
1729 | if (cmd->scan_end_src == TRIG_COUNT) { | ||
1730 | if (cmd->scan_end_arg == 0) { | ||
1731 | printk(KERN_ERR | ||
1732 | "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan end arg\n", | ||
1733 | dev->minor); | ||
1734 | cmd->scan_end_arg = 1; | ||
1735 | err++; | ||
1736 | } | ||
1737 | } | ||
1738 | if (err) { | ||
1739 | return 4; | ||
1740 | } | ||
1741 | |||
1742 | /* | ||
1743 | * Stage 5. Check the channel list. | ||
1744 | */ | ||
1745 | if (ai_check_chanlist(dev, s, cmd)) | ||
1746 | return 5; | ||
1747 | |||
1748 | return 0; | ||
1749 | } | ||
1750 | |||
1751 | static irqreturn_t me4000_ai_isr(int irq, void *dev_id PT_REGS_ARG) | ||
1752 | { | ||
1753 | unsigned int tmp; | ||
1754 | comedi_device *dev = dev_id; | ||
1755 | comedi_subdevice *s = dev->subdevices; | ||
1756 | me4000_ai_context_t *ai_context = &info->ai_context; | ||
1757 | int i; | ||
1758 | int c = 0; | ||
1759 | long lval; | ||
1760 | |||
1761 | ISR_PDEBUG("me4000_ai_isr() is executed\n"); | ||
1762 | |||
1763 | if (!dev->attached) { | ||
1764 | ISR_PDEBUG("me4000_ai_isr() premature interrupt\n"); | ||
1765 | return IRQ_NONE; | ||
1766 | } | ||
1767 | |||
1768 | /* Reset all events */ | ||
1769 | s->async->events = 0; | ||
1770 | |||
1771 | /* Check if irq number is right */ | ||
1772 | if (irq != ai_context->irq) { | ||
1773 | printk(KERN_ERR | ||
1774 | "comedi%d: me4000: me4000_ai_isr(): Incorrect interrupt num: %d\n", | ||
1775 | dev->minor, irq); | ||
1776 | return IRQ_HANDLED; | ||
1777 | } | ||
1778 | |||
1779 | if (me4000_inl(dev, | ||
1780 | ai_context-> | ||
1781 | irq_status_reg) & ME4000_IRQ_STATUS_BIT_AI_HF) { | ||
1782 | ISR_PDEBUG | ||
1783 | ("me4000_ai_isr(): Fifo half full interrupt occured\n"); | ||
1784 | |||
1785 | /* Read status register to find out what happened */ | ||
1786 | tmp = me4000_inl(dev, ai_context->ctrl_reg); | ||
1787 | |||
1788 | if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && | ||
1789 | !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && | ||
1790 | (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { | ||
1791 | ISR_PDEBUG("me4000_ai_isr(): Fifo full\n"); | ||
1792 | c = ME4000_AI_FIFO_COUNT; | ||
1793 | |||
1794 | /* FIFO overflow, so stop conversion and disable all interrupts */ | ||
1795 | tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | ||
1796 | tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | | ||
1797 | ME4000_AI_CTRL_BIT_SC_IRQ); | ||
1798 | me4000_outl(dev, tmp, ai_context->ctrl_reg); | ||
1799 | |||
1800 | s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; | ||
1801 | |||
1802 | printk(KERN_ERR | ||
1803 | "comedi%d: me4000: me4000_ai_isr(): FIFO overflow\n", | ||
1804 | dev->minor); | ||
1805 | } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) | ||
1806 | && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) | ||
1807 | && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { | ||
1808 | ISR_PDEBUG("me4000_ai_isr(): Fifo half full\n"); | ||
1809 | |||
1810 | s->async->events |= COMEDI_CB_BLOCK; | ||
1811 | |||
1812 | c = ME4000_AI_FIFO_COUNT / 2; | ||
1813 | } else { | ||
1814 | printk(KERN_ERR | ||
1815 | "comedi%d: me4000: me4000_ai_isr(): Can't determine state of fifo\n", | ||
1816 | dev->minor); | ||
1817 | c = 0; | ||
1818 | |||
1819 | /* Undefined state, so stop conversion and disable all interrupts */ | ||
1820 | tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | ||
1821 | tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | | ||
1822 | ME4000_AI_CTRL_BIT_SC_IRQ); | ||
1823 | me4000_outl(dev, tmp, ai_context->ctrl_reg); | ||
1824 | |||
1825 | s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; | ||
1826 | |||
1827 | printk(KERN_ERR | ||
1828 | "comedi%d: me4000: me4000_ai_isr(): Undefined FIFO state\n", | ||
1829 | dev->minor); | ||
1830 | } | ||
1831 | |||
1832 | ISR_PDEBUG("me4000_ai_isr(): Try to read %d values\n", c); | ||
1833 | |||
1834 | for (i = 0; i < c; i++) { | ||
1835 | /* Read value from data fifo */ | ||
1836 | lval = inl(ai_context->data_reg) & 0xFFFF; | ||
1837 | lval ^= 0x8000; | ||
1838 | |||
1839 | if (!comedi_buf_put(s->async, lval)) { | ||
1840 | /* Buffer overflow, so stop conversion and disable all interrupts */ | ||
1841 | tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | ||
1842 | tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | | ||
1843 | ME4000_AI_CTRL_BIT_SC_IRQ); | ||
1844 | me4000_outl(dev, tmp, ai_context->ctrl_reg); | ||
1845 | |||
1846 | s->async->events |= COMEDI_CB_OVERFLOW; | ||
1847 | |||
1848 | printk(KERN_ERR | ||
1849 | "comedi%d: me4000: me4000_ai_isr(): Buffer overflow\n", | ||
1850 | dev->minor); | ||
1851 | |||
1852 | break; | ||
1853 | } | ||
1854 | } | ||
1855 | |||
1856 | /* Work is done, so reset the interrupt */ | ||
1857 | ISR_PDEBUG("me4000_ai_isr(): Reset fifo half full interrupt\n"); | ||
1858 | tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET; | ||
1859 | me4000_outl(dev, tmp, ai_context->ctrl_reg); | ||
1860 | tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET; | ||
1861 | me4000_outl(dev, tmp, ai_context->ctrl_reg); | ||
1862 | } | ||
1863 | |||
1864 | if (me4000_inl(dev, | ||
1865 | ai_context-> | ||
1866 | irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) { | ||
1867 | ISR_PDEBUG | ||
1868 | ("me4000_ai_isr(): Sample counter interrupt occured\n"); | ||
1869 | |||
1870 | s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA; | ||
1871 | |||
1872 | /* Acquisition is complete, so stop conversion and disable all interrupts */ | ||
1873 | tmp = me4000_inl(dev, ai_context->ctrl_reg); | ||
1874 | tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | ||
1875 | tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); | ||
1876 | me4000_outl(dev, tmp, ai_context->ctrl_reg); | ||
1877 | |||
1878 | /* Poll data until fifo empty */ | ||
1879 | while (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_EF_DATA) { | ||
1880 | /* Read value from data fifo */ | ||
1881 | lval = inl(ai_context->data_reg) & 0xFFFF; | ||
1882 | lval ^= 0x8000; | ||
1883 | |||
1884 | if (!comedi_buf_put(s->async, lval)) { | ||
1885 | printk(KERN_ERR | ||
1886 | "comedi%d: me4000: me4000_ai_isr(): Buffer overflow\n", | ||
1887 | dev->minor); | ||
1888 | s->async->events |= COMEDI_CB_OVERFLOW; | ||
1889 | break; | ||
1890 | } | ||
1891 | } | ||
1892 | |||
1893 | /* Work is done, so reset the interrupt */ | ||
1894 | ISR_PDEBUG | ||
1895 | ("me4000_ai_isr(): Reset interrupt from sample counter\n"); | ||
1896 | tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET; | ||
1897 | me4000_outl(dev, tmp, ai_context->ctrl_reg); | ||
1898 | tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET; | ||
1899 | me4000_outl(dev, tmp, ai_context->ctrl_reg); | ||
1900 | } | ||
1901 | |||
1902 | ISR_PDEBUG("me4000_ai_isr(): Events = 0x%X\n", s->async->events); | ||
1903 | |||
1904 | if (s->async->events) | ||
1905 | comedi_event(dev, s); | ||
1906 | |||
1907 | return IRQ_HANDLED; | ||
1908 | } | ||
1909 | |||
1910 | /*============================================================================= | ||
1911 | Analog output section | ||
1912 | ===========================================================================*/ | ||
1913 | |||
1914 | static int me4000_ao_insn_write(comedi_device * dev, | ||
1915 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
1916 | { | ||
1917 | |||
1918 | int chan = CR_CHAN(insn->chanspec); | ||
1919 | int rang = CR_RANGE(insn->chanspec); | ||
1920 | int aref = CR_AREF(insn->chanspec); | ||
1921 | unsigned long tmp; | ||
1922 | |||
1923 | CALL_PDEBUG("In me4000_ao_insn_write()\n"); | ||
1924 | |||
1925 | if (insn->n == 0) { | ||
1926 | return 0; | ||
1927 | } else if (insn->n > 1) { | ||
1928 | printk(KERN_ERR | ||
1929 | "comedi%d: me4000: me4000_ao_insn_write(): Invalid instruction length %d\n", | ||
1930 | dev->minor, insn->n); | ||
1931 | return -EINVAL; | ||
1932 | } | ||
1933 | |||
1934 | if (chan >= thisboard->ao.count) { | ||
1935 | printk(KERN_ERR | ||
1936 | "comedi%d: me4000: me4000_ao_insn_write(): Invalid channel %d\n", | ||
1937 | dev->minor, insn->n); | ||
1938 | return -EINVAL; | ||
1939 | } | ||
1940 | |||
1941 | if (rang != 0) { | ||
1942 | printk(KERN_ERR | ||
1943 | "comedi%d: me4000: me4000_ao_insn_write(): Invalid range %d\n", | ||
1944 | dev->minor, insn->n); | ||
1945 | return -EINVAL; | ||
1946 | } | ||
1947 | |||
1948 | if (aref != AREF_GROUND && aref != AREF_COMMON) { | ||
1949 | printk(KERN_ERR | ||
1950 | "comedi%d: me4000: me4000_ao_insn_write(): Invalid aref %d\n", | ||
1951 | dev->minor, insn->n); | ||
1952 | return -EINVAL; | ||
1953 | } | ||
1954 | |||
1955 | /* Stop any running conversion */ | ||
1956 | tmp = me4000_inl(dev, info->ao_context[chan].ctrl_reg); | ||
1957 | tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; | ||
1958 | me4000_outl(dev, tmp, info->ao_context[chan].ctrl_reg); | ||
1959 | |||
1960 | /* Clear control register and set to single mode */ | ||
1961 | me4000_outl(dev, 0x0, info->ao_context[chan].ctrl_reg); | ||
1962 | |||
1963 | /* Write data value */ | ||
1964 | me4000_outl(dev, data[0], info->ao_context[chan].single_reg); | ||
1965 | |||
1966 | /* Store in the mirror */ | ||
1967 | info->ao_context[chan].mirror = data[0]; | ||
1968 | |||
1969 | return 1; | ||
1970 | } | ||
1971 | |||
1972 | static int me4000_ao_insn_read(comedi_device * dev, | ||
1973 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
1974 | { | ||
1975 | int chan = CR_CHAN(insn->chanspec); | ||
1976 | |||
1977 | if (insn->n == 0) { | ||
1978 | return 0; | ||
1979 | } else if (insn->n > 1) { | ||
1980 | printk("comedi%d: me4000: me4000_ao_insn_read(): Invalid instruction length\n", dev->minor); | ||
1981 | return -EINVAL; | ||
1982 | } | ||
1983 | |||
1984 | data[0] = info->ao_context[chan].mirror; | ||
1985 | |||
1986 | return 1; | ||
1987 | } | ||
1988 | |||
1989 | /*============================================================================= | ||
1990 | Digital I/O section | ||
1991 | ===========================================================================*/ | ||
1992 | |||
1993 | static int me4000_dio_insn_bits(comedi_device * dev, | ||
1994 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
1995 | { | ||
1996 | |||
1997 | CALL_PDEBUG("In me4000_dio_insn_bits()\n"); | ||
1998 | |||
1999 | /* Length of data must be 2 (mask and new data, see below) */ | ||
2000 | if (insn->n == 0) { | ||
2001 | return 0; | ||
2002 | } | ||
2003 | if (insn->n != 2) { | ||
2004 | printk("comedi%d: me4000: me4000_dio_insn_bits(): Invalid instruction length\n", dev->minor); | ||
2005 | return -EINVAL; | ||
2006 | } | ||
2007 | |||
2008 | /* | ||
2009 | * The insn data consists of a mask in data[0] and the new data | ||
2010 | * in data[1]. The mask defines which bits we are concerning about. | ||
2011 | * The new data must be anded with the mask. | ||
2012 | * Each channel corresponds to a bit. | ||
2013 | */ | ||
2014 | if (data[0]) { | ||
2015 | /* Check if requested ports are configured for output */ | ||
2016 | if ((s->io_bits & data[0]) != data[0]) | ||
2017 | return -EIO; | ||
2018 | |||
2019 | s->state &= ~data[0]; | ||
2020 | s->state |= data[0] & data[1]; | ||
2021 | |||
2022 | /* Write out the new digital output lines */ | ||
2023 | me4000_outl(dev, (s->state >> 0) & 0xFF, | ||
2024 | info->dio_context.port_0_reg); | ||
2025 | me4000_outl(dev, (s->state >> 8) & 0xFF, | ||
2026 | info->dio_context.port_1_reg); | ||
2027 | me4000_outl(dev, (s->state >> 16) & 0xFF, | ||
2028 | info->dio_context.port_2_reg); | ||
2029 | me4000_outl(dev, (s->state >> 24) & 0xFF, | ||
2030 | info->dio_context.port_3_reg); | ||
2031 | } | ||
2032 | |||
2033 | /* On return, data[1] contains the value of | ||
2034 | the digital input and output lines. */ | ||
2035 | data[1] = | ||
2036 | ((me4000_inl(dev, info->dio_context.port_0_reg) & 0xFF) << 0) | | ||
2037 | ((me4000_inl(dev, info->dio_context.port_1_reg) & 0xFF) << 8) | | ||
2038 | ((me4000_inl(dev, info->dio_context.port_2_reg) & 0xFF) << 16) | | ||
2039 | ((me4000_inl(dev, info->dio_context.port_3_reg) & 0xFF) << 24); | ||
2040 | |||
2041 | return 2; | ||
2042 | } | ||
2043 | |||
2044 | static int me4000_dio_insn_config(comedi_device * dev, | ||
2045 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
2046 | { | ||
2047 | unsigned long tmp; | ||
2048 | int chan = CR_CHAN(insn->chanspec); | ||
2049 | |||
2050 | CALL_PDEBUG("In me4000_dio_insn_config()\n"); | ||
2051 | |||
2052 | if (data[0] == INSN_CONFIG_DIO_QUERY) { | ||
2053 | data[1] = | ||
2054 | (s-> | ||
2055 | io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; | ||
2056 | return insn->n; | ||
2057 | } | ||
2058 | |||
2059 | /* | ||
2060 | * The input or output configuration of each digital line is | ||
2061 | * configured by a special insn_config instruction. chanspec | ||
2062 | * contains the channel to be changed, and data[0] contains the | ||
2063 | * value COMEDI_INPUT or COMEDI_OUTPUT. | ||
2064 | * On the ME-4000 it is only possible to switch port wise (8 bit) | ||
2065 | */ | ||
2066 | |||
2067 | tmp = me4000_inl(dev, info->dio_context.ctrl_reg); | ||
2068 | |||
2069 | if (data[0] == COMEDI_OUTPUT) { | ||
2070 | if (chan < 8) { | ||
2071 | s->io_bits |= 0xFF; | ||
2072 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | | ||
2073 | ME4000_DIO_CTRL_BIT_MODE_1); | ||
2074 | tmp |= ME4000_DIO_CTRL_BIT_MODE_0; | ||
2075 | } else if (chan < 16) { | ||
2076 | /* | ||
2077 | * Chech for optoisolated ME-4000 version. If one the first | ||
2078 | * port is a fixed output port and the second is a fixed input port. | ||
2079 | */ | ||
2080 | if (!me4000_inl(dev, info->dio_context.dir_reg)) | ||
2081 | return -ENODEV; | ||
2082 | |||
2083 | s->io_bits |= 0xFF00; | ||
2084 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | | ||
2085 | ME4000_DIO_CTRL_BIT_MODE_3); | ||
2086 | tmp |= ME4000_DIO_CTRL_BIT_MODE_2; | ||
2087 | } else if (chan < 24) { | ||
2088 | s->io_bits |= 0xFF0000; | ||
2089 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 | | ||
2090 | ME4000_DIO_CTRL_BIT_MODE_5); | ||
2091 | tmp |= ME4000_DIO_CTRL_BIT_MODE_4; | ||
2092 | } else if (chan < 32) { | ||
2093 | s->io_bits |= 0xFF000000; | ||
2094 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 | | ||
2095 | ME4000_DIO_CTRL_BIT_MODE_7); | ||
2096 | tmp |= ME4000_DIO_CTRL_BIT_MODE_6; | ||
2097 | } else { | ||
2098 | return -EINVAL; | ||
2099 | } | ||
2100 | } else { | ||
2101 | if (chan < 8) { | ||
2102 | /* | ||
2103 | * Chech for optoisolated ME-4000 version. If one the first | ||
2104 | * port is a fixed output port and the second is a fixed input port. | ||
2105 | */ | ||
2106 | if (!me4000_inl(dev, info->dio_context.dir_reg)) | ||
2107 | return -ENODEV; | ||
2108 | |||
2109 | s->io_bits &= ~0xFF; | ||
2110 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | | ||
2111 | ME4000_DIO_CTRL_BIT_MODE_1); | ||
2112 | } else if (chan < 16) { | ||
2113 | s->io_bits &= ~0xFF00; | ||
2114 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | | ||
2115 | ME4000_DIO_CTRL_BIT_MODE_3); | ||
2116 | } else if (chan < 24) { | ||
2117 | s->io_bits &= ~0xFF0000; | ||
2118 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 | | ||
2119 | ME4000_DIO_CTRL_BIT_MODE_5); | ||
2120 | } else if (chan < 32) { | ||
2121 | s->io_bits &= ~0xFF000000; | ||
2122 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 | | ||
2123 | ME4000_DIO_CTRL_BIT_MODE_7); | ||
2124 | } else { | ||
2125 | return -EINVAL; | ||
2126 | } | ||
2127 | } | ||
2128 | |||
2129 | me4000_outl(dev, tmp, info->dio_context.ctrl_reg); | ||
2130 | |||
2131 | return 1; | ||
2132 | } | ||
2133 | |||
2134 | /*============================================================================= | ||
2135 | Counter section | ||
2136 | ===========================================================================*/ | ||
2137 | |||
2138 | static int cnt_reset(comedi_device * dev, unsigned int channel) | ||
2139 | { | ||
2140 | |||
2141 | CALL_PDEBUG("In cnt_reset()\n"); | ||
2142 | |||
2143 | switch (channel) { | ||
2144 | case 0: | ||
2145 | me4000_outb(dev, 0x30, info->cnt_context.ctrl_reg); | ||
2146 | me4000_outb(dev, 0x00, info->cnt_context.counter_0_reg); | ||
2147 | me4000_outb(dev, 0x00, info->cnt_context.counter_0_reg); | ||
2148 | break; | ||
2149 | case 1: | ||
2150 | me4000_outb(dev, 0x70, info->cnt_context.ctrl_reg); | ||
2151 | me4000_outb(dev, 0x00, info->cnt_context.counter_1_reg); | ||
2152 | me4000_outb(dev, 0x00, info->cnt_context.counter_1_reg); | ||
2153 | break; | ||
2154 | case 2: | ||
2155 | me4000_outb(dev, 0xB0, info->cnt_context.ctrl_reg); | ||
2156 | me4000_outb(dev, 0x00, info->cnt_context.counter_2_reg); | ||
2157 | me4000_outb(dev, 0x00, info->cnt_context.counter_2_reg); | ||
2158 | break; | ||
2159 | default: | ||
2160 | printk(KERN_ERR | ||
2161 | "comedi%d: me4000: cnt_reset(): Invalid channel\n", | ||
2162 | dev->minor); | ||
2163 | return -EINVAL; | ||
2164 | } | ||
2165 | |||
2166 | return 0; | ||
2167 | } | ||
2168 | |||
2169 | static int cnt_config(comedi_device * dev, unsigned int channel, | ||
2170 | unsigned int mode) | ||
2171 | { | ||
2172 | int tmp = 0; | ||
2173 | |||
2174 | CALL_PDEBUG("In cnt_config()\n"); | ||
2175 | |||
2176 | switch (channel) { | ||
2177 | case 0: | ||
2178 | tmp |= ME4000_CNT_COUNTER_0; | ||
2179 | break; | ||
2180 | case 1: | ||
2181 | tmp |= ME4000_CNT_COUNTER_1; | ||
2182 | break; | ||
2183 | case 2: | ||
2184 | tmp |= ME4000_CNT_COUNTER_2; | ||
2185 | break; | ||
2186 | default: | ||
2187 | printk(KERN_ERR | ||
2188 | "comedi%d: me4000: cnt_config(): Invalid channel\n", | ||
2189 | dev->minor); | ||
2190 | return -EINVAL; | ||
2191 | } | ||
2192 | |||
2193 | switch (mode) { | ||
2194 | case 0: | ||
2195 | tmp |= ME4000_CNT_MODE_0; | ||
2196 | break; | ||
2197 | case 1: | ||
2198 | tmp |= ME4000_CNT_MODE_1; | ||
2199 | break; | ||
2200 | case 2: | ||
2201 | tmp |= ME4000_CNT_MODE_2; | ||
2202 | break; | ||
2203 | case 3: | ||
2204 | tmp |= ME4000_CNT_MODE_3; | ||
2205 | break; | ||
2206 | case 4: | ||
2207 | tmp |= ME4000_CNT_MODE_4; | ||
2208 | break; | ||
2209 | case 5: | ||
2210 | tmp |= ME4000_CNT_MODE_5; | ||
2211 | break; | ||
2212 | default: | ||
2213 | printk(KERN_ERR | ||
2214 | "comedi%d: me4000: cnt_config(): Invalid counter mode\n", | ||
2215 | dev->minor); | ||
2216 | return -EINVAL; | ||
2217 | } | ||
2218 | |||
2219 | /* Write the control word */ | ||
2220 | tmp |= 0x30; | ||
2221 | me4000_outb(dev, tmp, info->cnt_context.ctrl_reg); | ||
2222 | |||
2223 | return 0; | ||
2224 | } | ||
2225 | |||
2226 | static int me4000_cnt_insn_config(comedi_device * dev, | ||
2227 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
2228 | { | ||
2229 | |||
2230 | int err; | ||
2231 | |||
2232 | CALL_PDEBUG("In me4000_cnt_insn_config()\n"); | ||
2233 | |||
2234 | switch (data[0]) { | ||
2235 | case GPCT_RESET: | ||
2236 | if (insn->n != 1) { | ||
2237 | printk(KERN_ERR | ||
2238 | "comedi%d: me4000: me4000_cnt_insn_config(): Invalid instruction length%d\n", | ||
2239 | dev->minor, insn->n); | ||
2240 | return -EINVAL; | ||
2241 | } | ||
2242 | |||
2243 | err = cnt_reset(dev, insn->chanspec); | ||
2244 | if (err) | ||
2245 | return err; | ||
2246 | break; | ||
2247 | case GPCT_SET_OPERATION: | ||
2248 | if (insn->n != 2) { | ||
2249 | printk(KERN_ERR | ||
2250 | "comedi%d: me4000: me4000_cnt_insn_config(): Invalid instruction length%d\n", | ||
2251 | dev->minor, insn->n); | ||
2252 | return -EINVAL; | ||
2253 | } | ||
2254 | |||
2255 | err = cnt_config(dev, insn->chanspec, data[1]); | ||
2256 | if (err) | ||
2257 | return err; | ||
2258 | break; | ||
2259 | default: | ||
2260 | printk(KERN_ERR | ||
2261 | "comedi%d: me4000: me4000_cnt_insn_config(): Invalid instruction\n", | ||
2262 | dev->minor); | ||
2263 | return -EINVAL; | ||
2264 | } | ||
2265 | |||
2266 | return 2; | ||
2267 | } | ||
2268 | |||
2269 | static int me4000_cnt_insn_read(comedi_device * dev, | ||
2270 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
2271 | { | ||
2272 | |||
2273 | unsigned short tmp; | ||
2274 | |||
2275 | CALL_PDEBUG("In me4000_cnt_insn_read()\n"); | ||
2276 | |||
2277 | if (insn->n == 0) { | ||
2278 | return 0; | ||
2279 | } | ||
2280 | if (insn->n > 1) { | ||
2281 | printk(KERN_ERR | ||
2282 | "comedi%d: me4000: me4000_cnt_insn_read(): Invalid instruction length %d\n", | ||
2283 | dev->minor, insn->n); | ||
2284 | return -EINVAL; | ||
2285 | } | ||
2286 | |||
2287 | switch (insn->chanspec) { | ||
2288 | case 0: | ||
2289 | tmp = me4000_inb(dev, info->cnt_context.counter_0_reg); | ||
2290 | data[0] = tmp; | ||
2291 | tmp = me4000_inb(dev, info->cnt_context.counter_0_reg); | ||
2292 | data[0] |= tmp << 8; | ||
2293 | break; | ||
2294 | case 1: | ||
2295 | tmp = me4000_inb(dev, info->cnt_context.counter_1_reg); | ||
2296 | data[0] = tmp; | ||
2297 | tmp = me4000_inb(dev, info->cnt_context.counter_1_reg); | ||
2298 | data[0] |= tmp << 8; | ||
2299 | break; | ||
2300 | case 2: | ||
2301 | tmp = me4000_inb(dev, info->cnt_context.counter_2_reg); | ||
2302 | data[0] = tmp; | ||
2303 | tmp = me4000_inb(dev, info->cnt_context.counter_2_reg); | ||
2304 | data[0] |= tmp << 8; | ||
2305 | break; | ||
2306 | default: | ||
2307 | printk(KERN_ERR | ||
2308 | "comedi%d: me4000: me4000_cnt_insn_read(): Invalid channel %d\n", | ||
2309 | dev->minor, insn->chanspec); | ||
2310 | return -EINVAL; | ||
2311 | } | ||
2312 | |||
2313 | return 1; | ||
2314 | } | ||
2315 | |||
2316 | static int me4000_cnt_insn_write(comedi_device * dev, | ||
2317 | comedi_subdevice * s, comedi_insn * insn, lsampl_t * data) | ||
2318 | { | ||
2319 | |||
2320 | unsigned short tmp; | ||
2321 | |||
2322 | CALL_PDEBUG("In me4000_cnt_insn_write()\n"); | ||
2323 | |||
2324 | if (insn->n == 0) { | ||
2325 | return 0; | ||
2326 | } else if (insn->n > 1) { | ||
2327 | printk(KERN_ERR | ||
2328 | "comedi%d: me4000: me4000_cnt_insn_write(): Invalid instruction length %d\n", | ||
2329 | dev->minor, insn->n); | ||
2330 | return -EINVAL; | ||
2331 | } | ||
2332 | |||
2333 | switch (insn->chanspec) { | ||
2334 | case 0: | ||
2335 | tmp = data[0] & 0xFF; | ||
2336 | me4000_outb(dev, tmp, info->cnt_context.counter_0_reg); | ||
2337 | tmp = (data[0] >> 8) & 0xFF; | ||
2338 | me4000_outb(dev, tmp, info->cnt_context.counter_0_reg); | ||
2339 | break; | ||
2340 | case 1: | ||
2341 | tmp = data[0] & 0xFF; | ||
2342 | me4000_outb(dev, tmp, info->cnt_context.counter_1_reg); | ||
2343 | tmp = (data[0] >> 8) & 0xFF; | ||
2344 | me4000_outb(dev, tmp, info->cnt_context.counter_1_reg); | ||
2345 | break; | ||
2346 | case 2: | ||
2347 | tmp = data[0] & 0xFF; | ||
2348 | me4000_outb(dev, tmp, info->cnt_context.counter_2_reg); | ||
2349 | tmp = (data[0] >> 8) & 0xFF; | ||
2350 | me4000_outb(dev, tmp, info->cnt_context.counter_2_reg); | ||
2351 | break; | ||
2352 | default: | ||
2353 | printk(KERN_ERR | ||
2354 | "comedi%d: me4000: me4000_cnt_insn_write(): Invalid channel %d\n", | ||
2355 | dev->minor, insn->chanspec); | ||
2356 | return -EINVAL; | ||
2357 | } | ||
2358 | |||
2359 | return 1; | ||
2360 | } | ||
2361 | |||
2362 | COMEDI_PCI_INITCLEANUP(driver_me4000, me4000_pci_table); | ||
diff --git a/drivers/staging/comedi/drivers/me4000.h b/drivers/staging/comedi/drivers/me4000.h new file mode 100644 index 00000000000..f12b8873ec3 --- /dev/null +++ b/drivers/staging/comedi/drivers/me4000.h | |||
@@ -0,0 +1,446 @@ | |||
1 | /* | ||
2 | me4000.h | ||
3 | Register descriptions and defines for the ME-4000 board family | ||
4 | |||
5 | COMEDI - Linux Control and Measurement Device Interface | ||
6 | Copyright (C) 1998-9 David A. Schleef <ds@schleef.org> | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | */ | ||
23 | |||
24 | #ifndef _ME4000_H_ | ||
25 | #define _ME4000_H_ | ||
26 | |||
27 | /*============================================================================= | ||
28 | Debug section | ||
29 | ===========================================================================*/ | ||
30 | |||
31 | #undef ME4000_CALL_DEBUG // Debug function entry and exit | ||
32 | #undef ME4000_PORT_DEBUG // Debug port access | ||
33 | #undef ME4000_ISR_DEBUG // Debug the interrupt service routine | ||
34 | #undef ME4000_DEBUG // General purpose debug masseges | ||
35 | |||
36 | #ifdef ME4000_CALL_DEBUG | ||
37 | #undef CALL_PDEBUG | ||
38 | #define CALL_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args) | ||
39 | #else | ||
40 | # define CALL_PDEBUG(fmt, args...) // no debugging, do nothing | ||
41 | #endif | ||
42 | |||
43 | #ifdef ME4000_PORT_DEBUG | ||
44 | #undef PORT_PDEBUG | ||
45 | #define PORT_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args) | ||
46 | #else | ||
47 | #define PORT_PDEBUG(fmt, args...) // no debugging, do nothing | ||
48 | #endif | ||
49 | |||
50 | #ifdef ME4000_ISR_DEBUG | ||
51 | #undef ISR_PDEBUG | ||
52 | #define ISR_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args) | ||
53 | #else | ||
54 | #define ISR_PDEBUG(fmt, args...) // no debugging, do nothing | ||
55 | #endif | ||
56 | |||
57 | #ifdef ME4000_DEBUG | ||
58 | #undef PDEBUG | ||
59 | #define PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args) | ||
60 | #else | ||
61 | #define PDEBUG(fmt, args...) // no debugging, do nothing | ||
62 | #endif | ||
63 | |||
64 | /*============================================================================= | ||
65 | PCI vendor and device IDs | ||
66 | ===========================================================================*/ | ||
67 | |||
68 | #define PCI_VENDOR_ID_MEILHAUS 0x1402 | ||
69 | |||
70 | #define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 // Low Cost version | ||
71 | |||
72 | #define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 // Standard version | ||
73 | #define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 // Isolated version | ||
74 | #define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 // Standard version with Sample and Hold | ||
75 | #define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 // Isolated version with Sample and Hold | ||
76 | |||
77 | #define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 // Standard version | ||
78 | #define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 // Isolated version | ||
79 | #define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 // Standard version with Sample and Hold | ||
80 | #define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 // Isolated version with Sample and Hold | ||
81 | |||
82 | #define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 // Standard version | ||
83 | #define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 // Isolated version | ||
84 | #define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 // Standard version with Sample and Hold | ||
85 | #define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 // Isolated version with Sample and Hold | ||
86 | |||
87 | /*============================================================================= | ||
88 | ME-4000 base register offsets | ||
89 | ===========================================================================*/ | ||
90 | |||
91 | #define ME4000_AO_00_CTRL_REG 0x00 // R/W | ||
92 | #define ME4000_AO_00_STATUS_REG 0x04 // R/_ | ||
93 | #define ME4000_AO_00_FIFO_REG 0x08 // _/W | ||
94 | #define ME4000_AO_00_SINGLE_REG 0x0C // R/W | ||
95 | #define ME4000_AO_00_TIMER_REG 0x10 // _/W | ||
96 | |||
97 | #define ME4000_AO_01_CTRL_REG 0x18 // R/W | ||
98 | #define ME4000_AO_01_STATUS_REG 0x1C // R/_ | ||
99 | #define ME4000_AO_01_FIFO_REG 0x20 // _/W | ||
100 | #define ME4000_AO_01_SINGLE_REG 0x24 // R/W | ||
101 | #define ME4000_AO_01_TIMER_REG 0x28 // _/W | ||
102 | |||
103 | #define ME4000_AO_02_CTRL_REG 0x30 // R/W | ||
104 | #define ME4000_AO_02_STATUS_REG 0x34 // R/_ | ||
105 | #define ME4000_AO_02_FIFO_REG 0x38 // _/W | ||
106 | #define ME4000_AO_02_SINGLE_REG 0x3C // R/W | ||
107 | #define ME4000_AO_02_TIMER_REG 0x40 // _/W | ||
108 | |||
109 | #define ME4000_AO_03_CTRL_REG 0x48 // R/W | ||
110 | #define ME4000_AO_03_STATUS_REG 0x4C // R/_ | ||
111 | #define ME4000_AO_03_FIFO_REG 0x50 // _/W | ||
112 | #define ME4000_AO_03_SINGLE_REG 0x54 // R/W | ||
113 | #define ME4000_AO_03_TIMER_REG 0x58 // _/W | ||
114 | |||
115 | #define ME4000_AI_CTRL_REG 0x74 // _/W | ||
116 | #define ME4000_AI_STATUS_REG 0x74 // R/_ | ||
117 | #define ME4000_AI_CHANNEL_LIST_REG 0x78 // _/W | ||
118 | #define ME4000_AI_DATA_REG 0x7C // R/_ | ||
119 | #define ME4000_AI_CHAN_TIMER_REG 0x80 // _/W | ||
120 | #define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 // _/W | ||
121 | #define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 // _/W | ||
122 | #define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8C // _/W | ||
123 | #define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 // _/W | ||
124 | #define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 // _/W | ||
125 | #define ME4000_AI_START_REG 0x98 // R/_ | ||
126 | |||
127 | #define ME4000_IRQ_STATUS_REG 0x9C // R/_ | ||
128 | |||
129 | #define ME4000_DIO_PORT_0_REG 0xA0 // R/W | ||
130 | #define ME4000_DIO_PORT_1_REG 0xA4 // R/W | ||
131 | #define ME4000_DIO_PORT_2_REG 0xA8 // R/W | ||
132 | #define ME4000_DIO_PORT_3_REG 0xAC // R/W | ||
133 | #define ME4000_DIO_DIR_REG 0xB0 // R/W | ||
134 | |||
135 | #define ME4000_AO_LOADSETREG_XX 0xB4 // R/W | ||
136 | |||
137 | #define ME4000_DIO_CTRL_REG 0xB8 // R/W | ||
138 | |||
139 | #define ME4000_AO_DEMUX_ADJUST_REG 0xBC // -/W | ||
140 | |||
141 | #define ME4000_AI_SAMPLE_COUNTER_REG 0xC0 // _/W | ||
142 | |||
143 | /*============================================================================= | ||
144 | Value to adjust Demux | ||
145 | ===========================================================================*/ | ||
146 | |||
147 | #define ME4000_AO_DEMUX_ADJUST_VALUE 0x4C | ||
148 | |||
149 | /*============================================================================= | ||
150 | Counter base register offsets | ||
151 | ===========================================================================*/ | ||
152 | |||
153 | #define ME4000_CNT_COUNTER_0_REG 0x00 | ||
154 | #define ME4000_CNT_COUNTER_1_REG 0x01 | ||
155 | #define ME4000_CNT_COUNTER_2_REG 0x02 | ||
156 | #define ME4000_CNT_CTRL_REG 0x03 | ||
157 | |||
158 | /*============================================================================= | ||
159 | PLX base register offsets | ||
160 | ===========================================================================*/ | ||
161 | |||
162 | #define PLX_INTCSR 0x4C // Interrupt control and status register | ||
163 | #define PLX_ICR 0x50 // Initialization control register | ||
164 | |||
165 | /*============================================================================= | ||
166 | Bits for the PLX_ICSR register | ||
167 | ===========================================================================*/ | ||
168 | |||
169 | #define PLX_INTCSR_LOCAL_INT1_EN 0x01 // If set, local interrupt 1 is enabled (r/w) | ||
170 | #define PLX_INTCSR_LOCAL_INT1_POL 0x02 // If set, local interrupt 1 polarity is active high (r/w) | ||
171 | #define PLX_INTCSR_LOCAL_INT1_STATE 0x04 // If set, local interrupt 1 is active (r/_) | ||
172 | #define PLX_INTCSR_LOCAL_INT2_EN 0x08 // If set, local interrupt 2 is enabled (r/w) | ||
173 | #define PLX_INTCSR_LOCAL_INT2_POL 0x10 // If set, local interrupt 2 polarity is active high (r/w) | ||
174 | #define PLX_INTCSR_LOCAL_INT2_STATE 0x20 // If set, local interrupt 2 is active (r/_) | ||
175 | #define PLX_INTCSR_PCI_INT_EN 0x40 // If set, PCI interrupt is enabled (r/w) | ||
176 | #define PLX_INTCSR_SOFT_INT 0x80 // If set, a software interrupt is generated (r/w) | ||
177 | |||
178 | /*============================================================================= | ||
179 | Bits for the PLX_ICR register | ||
180 | ===========================================================================*/ | ||
181 | |||
182 | #define PLX_ICR_BIT_EEPROM_CLOCK_SET 0x01000000 | ||
183 | #define PLX_ICR_BIT_EEPROM_CHIP_SELECT 0x02000000 | ||
184 | #define PLX_ICR_BIT_EEPROM_WRITE 0x04000000 | ||
185 | #define PLX_ICR_BIT_EEPROM_READ 0x08000000 | ||
186 | #define PLX_ICR_BIT_EEPROM_VALID 0x10000000 | ||
187 | |||
188 | #define PLX_ICR_MASK_EEPROM 0x1F000000 | ||
189 | |||
190 | #define EEPROM_DELAY 1 | ||
191 | |||
192 | /*============================================================================= | ||
193 | Bits for the ME4000_AO_CTRL_REG register | ||
194 | ===========================================================================*/ | ||
195 | |||
196 | #define ME4000_AO_CTRL_BIT_MODE_0 0x001 | ||
197 | #define ME4000_AO_CTRL_BIT_MODE_1 0x002 | ||
198 | #define ME4000_AO_CTRL_MASK_MODE 0x003 | ||
199 | #define ME4000_AO_CTRL_BIT_STOP 0x004 | ||
200 | #define ME4000_AO_CTRL_BIT_ENABLE_FIFO 0x008 | ||
201 | #define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010 | ||
202 | #define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020 | ||
203 | #define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080 | ||
204 | #define ME4000_AO_CTRL_BIT_ENABLE_DO 0x100 | ||
205 | #define ME4000_AO_CTRL_BIT_ENABLE_IRQ 0x200 | ||
206 | #define ME4000_AO_CTRL_BIT_RESET_IRQ 0x400 | ||
207 | |||
208 | /*============================================================================= | ||
209 | Bits for the ME4000_AO_STATUS_REG register | ||
210 | ===========================================================================*/ | ||
211 | |||
212 | #define ME4000_AO_STATUS_BIT_FSM 0x01 | ||
213 | #define ME4000_AO_STATUS_BIT_FF 0x02 | ||
214 | #define ME4000_AO_STATUS_BIT_HF 0x04 | ||
215 | #define ME4000_AO_STATUS_BIT_EF 0x08 | ||
216 | |||
217 | /*============================================================================= | ||
218 | Bits for the ME4000_AI_CTRL_REG register | ||
219 | ===========================================================================*/ | ||
220 | |||
221 | #define ME4000_AI_CTRL_BIT_MODE_0 0x00000001 | ||
222 | #define ME4000_AI_CTRL_BIT_MODE_1 0x00000002 | ||
223 | #define ME4000_AI_CTRL_BIT_MODE_2 0x00000004 | ||
224 | #define ME4000_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008 | ||
225 | #define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010 | ||
226 | #define ME4000_AI_CTRL_BIT_STOP 0x00000020 | ||
227 | #define ME4000_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040 | ||
228 | #define ME4000_AI_CTRL_BIT_DATA_FIFO 0x00000080 | ||
229 | #define ME4000_AI_CTRL_BIT_FULLSCALE 0x00000100 | ||
230 | #define ME4000_AI_CTRL_BIT_OFFSET 0x00000200 | ||
231 | #define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400 | ||
232 | #define ME4000_AI_CTRL_BIT_EX_TRIG 0x00000800 | ||
233 | #define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000 | ||
234 | #define ME4000_AI_CTRL_BIT_EX_IRQ 0x00002000 | ||
235 | #define ME4000_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000 | ||
236 | #define ME4000_AI_CTRL_BIT_LE_IRQ 0x00008000 | ||
237 | #define ME4000_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000 | ||
238 | #define ME4000_AI_CTRL_BIT_HF_IRQ 0x00020000 | ||
239 | #define ME4000_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000 | ||
240 | #define ME4000_AI_CTRL_BIT_SC_IRQ 0x00080000 | ||
241 | #define ME4000_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000 | ||
242 | #define ME4000_AI_CTRL_BIT_SC_RELOAD 0x00200000 | ||
243 | #define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000 | ||
244 | |||
245 | /*============================================================================= | ||
246 | Bits for the ME4000_AI_STATUS_REG register | ||
247 | ===========================================================================*/ | ||
248 | |||
249 | #define ME4000_AI_STATUS_BIT_EF_CHANNEL 0x00400000 | ||
250 | #define ME4000_AI_STATUS_BIT_HF_CHANNEL 0x00800000 | ||
251 | #define ME4000_AI_STATUS_BIT_FF_CHANNEL 0x01000000 | ||
252 | #define ME4000_AI_STATUS_BIT_EF_DATA 0x02000000 | ||
253 | #define ME4000_AI_STATUS_BIT_HF_DATA 0x04000000 | ||
254 | #define ME4000_AI_STATUS_BIT_FF_DATA 0x08000000 | ||
255 | #define ME4000_AI_STATUS_BIT_LE 0x10000000 | ||
256 | #define ME4000_AI_STATUS_BIT_FSM 0x20000000 | ||
257 | |||
258 | /*============================================================================= | ||
259 | Bits for the ME4000_IRQ_STATUS_REG register | ||
260 | ===========================================================================*/ | ||
261 | |||
262 | #define ME4000_IRQ_STATUS_BIT_EX 0x01 | ||
263 | #define ME4000_IRQ_STATUS_BIT_LE 0x02 | ||
264 | #define ME4000_IRQ_STATUS_BIT_AI_HF 0x04 | ||
265 | #define ME4000_IRQ_STATUS_BIT_AO_0_HF 0x08 | ||
266 | #define ME4000_IRQ_STATUS_BIT_AO_1_HF 0x10 | ||
267 | #define ME4000_IRQ_STATUS_BIT_AO_2_HF 0x20 | ||
268 | #define ME4000_IRQ_STATUS_BIT_AO_3_HF 0x40 | ||
269 | #define ME4000_IRQ_STATUS_BIT_SC 0x80 | ||
270 | |||
271 | /*============================================================================= | ||
272 | Bits for the ME4000_DIO_CTRL_REG register | ||
273 | ===========================================================================*/ | ||
274 | |||
275 | #define ME4000_DIO_CTRL_BIT_MODE_0 0x0001 | ||
276 | #define ME4000_DIO_CTRL_BIT_MODE_1 0x0002 | ||
277 | #define ME4000_DIO_CTRL_BIT_MODE_2 0x0004 | ||
278 | #define ME4000_DIO_CTRL_BIT_MODE_3 0x0008 | ||
279 | #define ME4000_DIO_CTRL_BIT_MODE_4 0x0010 | ||
280 | #define ME4000_DIO_CTRL_BIT_MODE_5 0x0020 | ||
281 | #define ME4000_DIO_CTRL_BIT_MODE_6 0x0040 | ||
282 | #define ME4000_DIO_CTRL_BIT_MODE_7 0x0080 | ||
283 | |||
284 | #define ME4000_DIO_CTRL_BIT_FUNCTION_0 0x0100 | ||
285 | #define ME4000_DIO_CTRL_BIT_FUNCTION_1 0x0200 | ||
286 | |||
287 | #define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 0x0400 | ||
288 | #define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 0x0800 | ||
289 | #define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 0x1000 | ||
290 | #define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 0x2000 | ||
291 | |||
292 | /*============================================================================= | ||
293 | Information about the hardware capabilities | ||
294 | ===========================================================================*/ | ||
295 | |||
296 | typedef struct me4000_ao_info { | ||
297 | int count; | ||
298 | int fifo_count; | ||
299 | } me4000_ao_info_t; | ||
300 | |||
301 | typedef struct me4000_ai_info { | ||
302 | int count; | ||
303 | int sh_count; | ||
304 | int diff_count; | ||
305 | int ex_trig_analog; | ||
306 | } me4000_ai_info_t; | ||
307 | |||
308 | typedef struct me4000_dio_info { | ||
309 | int count; | ||
310 | } me4000_dio_info_t; | ||
311 | |||
312 | typedef struct me4000_cnt_info { | ||
313 | int count; | ||
314 | } me4000_cnt_info_t; | ||
315 | |||
316 | typedef struct me4000_board { | ||
317 | const char *name; | ||
318 | unsigned short device_id; | ||
319 | me4000_ao_info_t ao; | ||
320 | me4000_ai_info_t ai; | ||
321 | me4000_dio_info_t dio; | ||
322 | me4000_cnt_info_t cnt; | ||
323 | } me4000_board_t; | ||
324 | |||
325 | #define thisboard ((const me4000_board_t *)dev->board_ptr) | ||
326 | |||
327 | /*============================================================================= | ||
328 | Global board and subdevice information structures | ||
329 | ===========================================================================*/ | ||
330 | |||
331 | typedef struct me4000_ao_context { | ||
332 | int irq; | ||
333 | |||
334 | unsigned long mirror; // Store the last written value | ||
335 | |||
336 | unsigned long ctrl_reg; | ||
337 | unsigned long status_reg; | ||
338 | unsigned long fifo_reg; | ||
339 | unsigned long single_reg; | ||
340 | unsigned long timer_reg; | ||
341 | unsigned long irq_status_reg; | ||
342 | unsigned long preload_reg; | ||
343 | } me4000_ao_context_t; | ||
344 | |||
345 | typedef struct me4000_ai_context { | ||
346 | int irq; | ||
347 | |||
348 | unsigned long ctrl_reg; | ||
349 | unsigned long status_reg; | ||
350 | unsigned long channel_list_reg; | ||
351 | unsigned long data_reg; | ||
352 | unsigned long chan_timer_reg; | ||
353 | unsigned long chan_pre_timer_reg; | ||
354 | unsigned long scan_timer_low_reg; | ||
355 | unsigned long scan_timer_high_reg; | ||
356 | unsigned long scan_pre_timer_low_reg; | ||
357 | unsigned long scan_pre_timer_high_reg; | ||
358 | unsigned long start_reg; | ||
359 | unsigned long irq_status_reg; | ||
360 | unsigned long sample_counter_reg; | ||
361 | } me4000_ai_context_t; | ||
362 | |||
363 | typedef struct me4000_dio_context { | ||
364 | unsigned long dir_reg; | ||
365 | unsigned long ctrl_reg; | ||
366 | unsigned long port_0_reg; | ||
367 | unsigned long port_1_reg; | ||
368 | unsigned long port_2_reg; | ||
369 | unsigned long port_3_reg; | ||
370 | } me4000_dio_context_t; | ||
371 | |||
372 | typedef struct me4000_cnt_context { | ||
373 | unsigned long ctrl_reg; | ||
374 | unsigned long counter_0_reg; | ||
375 | unsigned long counter_1_reg; | ||
376 | unsigned long counter_2_reg; | ||
377 | } me4000_cnt_context_t; | ||
378 | |||
379 | typedef struct me4000_info { | ||
380 | unsigned long plx_regbase; // PLX configuration space base address | ||
381 | unsigned long me4000_regbase; // Base address of the ME4000 | ||
382 | unsigned long timer_regbase; // Base address of the timer circuit | ||
383 | unsigned long program_regbase; // Base address to set the program pin for the xilinx | ||
384 | |||
385 | unsigned long plx_regbase_size; // PLX register set space | ||
386 | unsigned long me4000_regbase_size; // ME4000 register set space | ||
387 | unsigned long timer_regbase_size; // Timer circuit register set space | ||
388 | unsigned long program_regbase_size; // Size of program base address of the ME4000 | ||
389 | |||
390 | unsigned int serial_no; // Serial number of the board | ||
391 | unsigned char hw_revision; // Hardware revision of the board | ||
392 | unsigned short vendor_id; // Meilhaus vendor id | ||
393 | unsigned short device_id; // Device id | ||
394 | |||
395 | struct pci_dev *pci_dev_p; // General PCI information | ||
396 | |||
397 | unsigned int irq; // IRQ assigned from the PCI BIOS | ||
398 | |||
399 | struct me4000_ai_context ai_context; // Analog input specific context | ||
400 | struct me4000_ao_context ao_context[4]; // Vector with analog output specific context | ||
401 | struct me4000_dio_context dio_context; // Digital I/O specific context | ||
402 | struct me4000_cnt_context cnt_context; // Counter specific context | ||
403 | } me4000_info_t; | ||
404 | |||
405 | #define info ((me4000_info_t *)dev->private) | ||
406 | |||
407 | /*----------------------------------------------------------------------------- | ||
408 | Defines for analog input | ||
409 | ----------------------------------------------------------------------------*/ | ||
410 | |||
411 | /* General stuff */ | ||
412 | #define ME4000_AI_FIFO_COUNT 2048 | ||
413 | |||
414 | #define ME4000_AI_MIN_TICKS 66 | ||
415 | #define ME4000_AI_MIN_SAMPLE_TIME 2000 // Minimum sample time [ns] | ||
416 | #define ME4000_AI_BASE_FREQUENCY (unsigned int) 33E6 | ||
417 | |||
418 | /* Channel list defines and masks */ | ||
419 | #define ME4000_AI_CHANNEL_LIST_COUNT 1024 | ||
420 | |||
421 | #define ME4000_AI_LIST_INPUT_SINGLE_ENDED 0x000 | ||
422 | #define ME4000_AI_LIST_INPUT_DIFFERENTIAL 0x020 | ||
423 | |||
424 | #define ME4000_AI_LIST_RANGE_BIPOLAR_10 0x000 | ||
425 | #define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 0x040 | ||
426 | #define ME4000_AI_LIST_RANGE_UNIPOLAR_10 0x080 | ||
427 | #define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0 | ||
428 | |||
429 | #define ME4000_AI_LIST_LAST_ENTRY 0x100 | ||
430 | |||
431 | /*----------------------------------------------------------------------------- | ||
432 | Defines for counters | ||
433 | ----------------------------------------------------------------------------*/ | ||
434 | |||
435 | #define ME4000_CNT_COUNTER_0 0x00 | ||
436 | #define ME4000_CNT_COUNTER_1 0x40 | ||
437 | #define ME4000_CNT_COUNTER_2 0x80 | ||
438 | |||
439 | #define ME4000_CNT_MODE_0 0x00 // Change state if zero crossing | ||
440 | #define ME4000_CNT_MODE_1 0x02 // Retriggerable One-Shot | ||
441 | #define ME4000_CNT_MODE_2 0x04 // Asymmetrical divider | ||
442 | #define ME4000_CNT_MODE_3 0x06 // Symmetrical divider | ||
443 | #define ME4000_CNT_MODE_4 0x08 // Counter start by software trigger | ||
444 | #define ME4000_CNT_MODE_5 0x0A // Counter start by hardware trigger | ||
445 | |||
446 | #endif | ||