]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From c0f005888c6663898a040cd922947dd8caa55160 Mon Sep 17 00:00:00 2001 |
2 | From: Greg Kroah-Hartman <gregkh@suse.de> | |
3 | Date: Fri, 21 Mar 2008 14:12:51 -0700 | |
4 | Subject: [PATCH 09/23] Staging: add me4000 pci data collection driver | |
5 | Patch-mainline: 2.6.28 | |
6 | ||
7 | Originally written by Guenter Gebhardt <g.gebhardt@meilhaus.de> | |
8 | ||
9 | TODO: | |
10 | - checkpatch.pl cleanups | |
11 | - sparse cleanups | |
12 | - possible /proc interaction cleanups | |
13 | - more info needed for Kconfig entry | |
14 | - real device id? | |
15 | - module parameter cleanup | |
16 | ||
17 | Cc: Wolfgang Beiter <w.beiter@aon.at> | |
18 | Cc: Guenter Gebhardt <g.gebhardt@meilhaus.de> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
20 | --- | |
21 | drivers/staging/Kconfig | 2 + | |
22 | drivers/staging/Makefile | 1 + | |
23 | drivers/staging/me4000/Kconfig | 10 + | |
24 | drivers/staging/me4000/Makefile | 1 + | |
25 | drivers/staging/me4000/README | 13 + | |
26 | drivers/staging/me4000/me4000.c | 6133 +++++++++++++++++++++++++++++++++++++++ | |
27 | drivers/staging/me4000/me4000.h | 954 ++++++ | |
28 | 7 files changed, 7114 insertions(+), 0 deletions(-) | |
29 | create mode 100644 drivers/staging/me4000/Kconfig | |
30 | create mode 100644 drivers/staging/me4000/Makefile | |
31 | create mode 100644 drivers/staging/me4000/README | |
32 | create mode 100644 drivers/staging/me4000/me4000.c | |
33 | create mode 100644 drivers/staging/me4000/me4000.h | |
34 | ||
35 | diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig | |
36 | index 6da7662..56c73bc 100644 | |
37 | --- a/drivers/staging/Kconfig | |
38 | +++ b/drivers/staging/Kconfig | |
39 | @@ -29,4 +29,6 @@ source "drivers/staging/slicoss/Kconfig" | |
40 | ||
41 | source "drivers/staging/sxg/Kconfig" | |
42 | ||
43 | +source "drivers/staging/me4000/Kconfig" | |
44 | + | |
45 | endif # STAGING | |
46 | diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile | |
47 | index cd6d6a5..97df19b 100644 | |
48 | --- a/drivers/staging/Makefile | |
49 | +++ b/drivers/staging/Makefile | |
50 | @@ -3,3 +3,4 @@ | |
51 | obj-$(CONFIG_ET131X) += et131x/ | |
52 | obj-$(CONFIG_SLICOSS) += slicoss/ | |
53 | obj-$(CONFIG_SXG) += sxg/ | |
54 | +obj-$(CONFIG_ME4000) += me4000/ | |
55 | diff --git a/drivers/staging/me4000/Kconfig b/drivers/staging/me4000/Kconfig | |
56 | new file mode 100644 | |
57 | index 0000000..5e6c9de | |
58 | --- /dev/null | |
59 | +++ b/drivers/staging/me4000/Kconfig | |
60 | @@ -0,0 +1,10 @@ | |
61 | +config ME4000 | |
62 | + tristate "Meilhaus ME-4000 support" | |
63 | + default n | |
64 | + depends on PCI | |
65 | + help | |
66 | + This driver supports the Meilhaus ME-4000 family of boards | |
67 | + that do data collection and multipurpose I/O. | |
68 | + | |
69 | + To compile this driver as a module, choose M here: the module | |
70 | + will be called me4000. | |
71 | diff --git a/drivers/staging/me4000/Makefile b/drivers/staging/me4000/Makefile | |
72 | new file mode 100644 | |
73 | index 0000000..74487cd | |
74 | --- /dev/null | |
75 | +++ b/drivers/staging/me4000/Makefile | |
76 | @@ -0,0 +1 @@ | |
77 | +obj-$(CONFIG_ME4000) += me4000.o | |
78 | diff --git a/drivers/staging/me4000/README b/drivers/staging/me4000/README | |
79 | new file mode 100644 | |
80 | index 0000000..bbb8386 | |
81 | --- /dev/null | |
82 | +++ b/drivers/staging/me4000/README | |
83 | @@ -0,0 +1,13 @@ | |
84 | + | |
85 | +TODO: | |
86 | + - checkpatch.pl cleanups | |
87 | + - sparse cleanups | |
88 | + - possible /proc interaction cleanups | |
89 | + - more info needed for Kconfig entry | |
90 | + - real device id? | |
91 | + - module parameter cleanup | |
92 | + | |
93 | +Please send patches to Greg Kroah-Hartman <gregkh@suse.de> | |
94 | +and Cc: Wolfgang Beiter <w.beiter@aon.at> and | |
95 | +Guenter Gebhardt <g.gebhardt@meilhaus.de> | |
96 | + | |
97 | diff --git a/drivers/staging/me4000/me4000.c b/drivers/staging/me4000/me4000.c | |
98 | new file mode 100644 | |
99 | index 0000000..862dd7f | |
100 | --- /dev/null | |
101 | +++ b/drivers/staging/me4000/me4000.c | |
102 | @@ -0,0 +1,6133 @@ | |
103 | +/* Device driver for Meilhaus ME-4000 board family. | |
104 | + * ================================================ | |
105 | + * | |
106 | + * Copyright (C) 2003 Meilhaus Electronic GmbH (support@meilhaus.de) | |
107 | + * | |
108 | + * This file is free software; you can redistribute it and/or modify | |
109 | + * it under the terms of the GNU General Public License as published by | |
110 | + * the Free Software Foundation; either version 2 of the License, or | |
111 | + * (at your option) any later version. | |
112 | + * | |
113 | + * This program is distributed in the hope that it will be useful, | |
114 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
115 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
116 | + * GNU General Public License for more details. | |
117 | + * | |
118 | + * You should have received a copy of the GNU General Public License | |
119 | + * along with this program; if not, write to the Free Software | |
120 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
121 | + * | |
122 | + * Author: Guenter Gebhardt <g.gebhardt@meilhaus.de> | |
123 | + */ | |
124 | + | |
125 | +#include <linux/module.h> | |
126 | +#include <linux/fs.h> | |
127 | +#include <linux/sched.h> | |
128 | +#include <linux/interrupt.h> | |
129 | +#include <linux/pci.h> | |
130 | +#include <asm/io.h> | |
131 | +#include <asm/system.h> | |
132 | +#include <asm/uaccess.h> | |
133 | +#include <linux/errno.h> | |
134 | +#include <linux/delay.h> | |
135 | +#include <linux/fs.h> | |
136 | +#include <linux/mm.h> | |
137 | +#include <linux/unistd.h> | |
138 | +#include <linux/list.h> | |
139 | +#include <linux/proc_fs.h> | |
140 | + | |
141 | +#include <linux/poll.h> | |
142 | +#include <linux/vmalloc.h> | |
143 | +#include <asm/pgtable.h> | |
144 | +#include <asm/uaccess.h> | |
145 | +#include <linux/types.h> | |
146 | + | |
147 | +#include <linux/slab.h> | |
148 | + | |
149 | +/* Include-File for the Meilhaus ME-4000 I/O board */ | |
150 | +#include "me4000.h" | |
151 | +#include "me4000_firmware.h" | |
152 | +#include "me4610_firmware.h" | |
153 | + | |
154 | +/* Administrative stuff for modinfo */ | |
155 | +MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>"); | |
156 | +MODULE_DESCRIPTION | |
157 | + ("Device Driver Module for Meilhaus ME-4000 boards version 1.0.5"); | |
158 | +MODULE_SUPPORTED_DEVICE("Meilhaus ME-4000 Multi I/O boards"); | |
159 | +MODULE_LICENSE("GPL"); | |
160 | + | |
161 | +/* Board specific data are kept in a global list */ | |
162 | +LIST_HEAD(me4000_board_info_list); | |
163 | + | |
164 | +/* Major Device Numbers. 0 means to get it automatically from the System */ | |
165 | +static int me4000_ao_major_driver_no = 0; | |
166 | +static int me4000_ai_major_driver_no = 0; | |
167 | +static int me4000_dio_major_driver_no = 0; | |
168 | +static int me4000_cnt_major_driver_no = 0; | |
169 | +static int me4000_ext_int_major_driver_no = 0; | |
170 | + | |
171 | +/* Let the user specify a custom major driver number */ | |
172 | +module_param(me4000_ao_major_driver_no, int, 0); | |
173 | +MODULE_PARM_DESC(me4000_ao_major_driver_no, | |
174 | + "Major driver number for analog output (default 0)"); | |
175 | + | |
176 | +module_param(me4000_ai_major_driver_no, int, 0); | |
177 | +MODULE_PARM_DESC(me4000_ai_major_driver_no, | |
178 | + "Major driver number for analog input (default 0)"); | |
179 | + | |
180 | +module_param(me4000_dio_major_driver_no, int, 0); | |
181 | +MODULE_PARM_DESC(me4000_dio_major_driver_no, | |
182 | + "Major driver number digital I/O (default 0)"); | |
183 | + | |
184 | +module_param(me4000_cnt_major_driver_no, int, 0); | |
185 | +MODULE_PARM_DESC(me4000_cnt_major_driver_no, | |
186 | + "Major driver number for counter (default 0)"); | |
187 | + | |
188 | +module_param(me4000_ext_int_major_driver_no, int, 0); | |
189 | +MODULE_PARM_DESC(me4000_ext_int_major_driver_no, | |
190 | + "Major driver number for external interrupt (default 0)"); | |
191 | + | |
192 | +/*----------------------------------------------------------------------------- | |
193 | + Module stuff | |
194 | + ---------------------------------------------------------------------------*/ | |
195 | +int init_module(void); | |
196 | +void cleanup_module(void); | |
197 | + | |
198 | +/*----------------------------------------------------------------------------- | |
199 | + Board detection and initialization | |
200 | + ---------------------------------------------------------------------------*/ | |
201 | +static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id); | |
202 | +static int me4000_xilinx_download(me4000_info_t *); | |
203 | +static int me4000_reset_board(me4000_info_t *); | |
204 | + | |
205 | +static void clear_board_info_list(void); | |
206 | +static int get_registers(struct pci_dev *dev, me4000_info_t * info); | |
207 | +static int init_board_info(struct pci_dev *dev, me4000_info_t * board_info); | |
208 | +static int alloc_ao_contexts(me4000_info_t * info); | |
209 | +static void release_ao_contexts(me4000_info_t * board_info); | |
210 | +static int alloc_ai_context(me4000_info_t * info); | |
211 | +static int alloc_dio_context(me4000_info_t * info); | |
212 | +static int alloc_cnt_context(me4000_info_t * info); | |
213 | +static int alloc_ext_int_context(me4000_info_t * info); | |
214 | + | |
215 | +/*----------------------------------------------------------------------------- | |
216 | + Stuff used by all device parts | |
217 | + ---------------------------------------------------------------------------*/ | |
218 | +static int me4000_open(struct inode *, struct file *); | |
219 | +static int me4000_release(struct inode *, struct file *); | |
220 | + | |
221 | +static int me4000_get_user_info(me4000_user_info_t *, | |
222 | + me4000_info_t * board_info); | |
223 | +static int me4000_read_procmem(char *, char **, off_t, int, int *, void *); | |
224 | + | |
225 | +/*----------------------------------------------------------------------------- | |
226 | + Analog output stuff | |
227 | + ---------------------------------------------------------------------------*/ | |
228 | +static ssize_t me4000_ao_write_sing(struct file *, const char *, size_t, | |
229 | + loff_t *); | |
230 | +static ssize_t me4000_ao_write_wrap(struct file *, const char *, size_t, | |
231 | + loff_t *); | |
232 | +static ssize_t me4000_ao_write_cont(struct file *, const char *, size_t, | |
233 | + loff_t *); | |
234 | + | |
235 | +static int me4000_ao_ioctl_sing(struct inode *, struct file *, unsigned int, | |
236 | + unsigned long); | |
237 | +static int me4000_ao_ioctl_wrap(struct inode *, struct file *, unsigned int, | |
238 | + unsigned long); | |
239 | +static int me4000_ao_ioctl_cont(struct inode *, struct file *, unsigned int, | |
240 | + unsigned long); | |
241 | + | |
242 | +static unsigned int me4000_ao_poll_cont(struct file *, poll_table *); | |
243 | +static int me4000_ao_fsync_cont(struct file *, struct dentry *, int); | |
244 | + | |
245 | +static int me4000_ao_start(unsigned long *, me4000_ao_context_t *); | |
246 | +static int me4000_ao_stop(me4000_ao_context_t *); | |
247 | +static int me4000_ao_immediate_stop(me4000_ao_context_t *); | |
248 | +static int me4000_ao_timer_set_divisor(u32 *, me4000_ao_context_t *); | |
249 | +static int me4000_ao_preload(me4000_ao_context_t *); | |
250 | +static int me4000_ao_preload_update(me4000_ao_context_t *); | |
251 | +static int me4000_ao_ex_trig_set_edge(int *, me4000_ao_context_t *); | |
252 | +static int me4000_ao_ex_trig_enable(me4000_ao_context_t *); | |
253 | +static int me4000_ao_ex_trig_disable(me4000_ao_context_t *); | |
254 | +static int me4000_ao_prepare(me4000_ao_context_t * ao_info); | |
255 | +static int me4000_ao_reset(me4000_ao_context_t * ao_info); | |
256 | +static int me4000_ao_enable_do(me4000_ao_context_t *); | |
257 | +static int me4000_ao_disable_do(me4000_ao_context_t *); | |
258 | +static int me4000_ao_fsm_state(int *, me4000_ao_context_t *); | |
259 | + | |
260 | +static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context); | |
261 | +static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context); | |
262 | +static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context); | |
263 | +static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * channels, | |
264 | + me4000_ao_context_t * ao_context); | |
265 | + | |
266 | +static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context); | |
267 | +static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context); | |
268 | +static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context); | |
269 | + | |
270 | +static int me4000_ao_ex_trig_timeout(unsigned long *arg, | |
271 | + me4000_ao_context_t * ao_context); | |
272 | +static int me4000_ao_get_free_buffer(unsigned long *arg, | |
273 | + me4000_ao_context_t * ao_context); | |
274 | + | |
275 | +/*----------------------------------------------------------------------------- | |
276 | + Analog input stuff | |
277 | + ---------------------------------------------------------------------------*/ | |
278 | +static int me4000_ai_single(me4000_ai_single_t *, me4000_ai_context_t *); | |
279 | +static int me4000_ai_ioctl_sing(struct inode *, struct file *, unsigned int, | |
280 | + unsigned long); | |
281 | + | |
282 | +static ssize_t me4000_ai_read(struct file *, char *, size_t, loff_t *); | |
283 | +static int me4000_ai_ioctl_sw(struct inode *, struct file *, unsigned int, | |
284 | + unsigned long); | |
285 | +static unsigned int me4000_ai_poll(struct file *, poll_table *); | |
286 | +static int me4000_ai_fasync(int fd, struct file *file_p, int mode); | |
287 | + | |
288 | +static int me4000_ai_ioctl_ext(struct inode *, struct file *, unsigned int, | |
289 | + unsigned long); | |
290 | + | |
291 | +static int me4000_ai_prepare(me4000_ai_context_t * ai_context); | |
292 | +static int me4000_ai_reset(me4000_ai_context_t * ai_context); | |
293 | +static int me4000_ai_config(me4000_ai_config_t *, me4000_ai_context_t *); | |
294 | +static int me4000_ai_start(me4000_ai_context_t *); | |
295 | +static int me4000_ai_start_ex(unsigned long *, me4000_ai_context_t *); | |
296 | +static int me4000_ai_stop(me4000_ai_context_t *); | |
297 | +static int me4000_ai_immediate_stop(me4000_ai_context_t *); | |
298 | +static int me4000_ai_ex_trig_enable(me4000_ai_context_t *); | |
299 | +static int me4000_ai_ex_trig_disable(me4000_ai_context_t *); | |
300 | +static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t *, | |
301 | + me4000_ai_context_t *); | |
302 | +static int me4000_ai_sc_setup(me4000_ai_sc_t * arg, | |
303 | + me4000_ai_context_t * ai_context); | |
304 | +static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context); | |
305 | +static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context); | |
306 | +static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context); | |
307 | +static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context); | |
308 | +static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context); | |
309 | +static int me4000_ai_get_count_buffer(unsigned long *arg, | |
310 | + me4000_ai_context_t * ai_context); | |
311 | + | |
312 | +/*----------------------------------------------------------------------------- | |
313 | + EEPROM stuff | |
314 | + ---------------------------------------------------------------------------*/ | |
315 | +static int me4000_eeprom_read(me4000_eeprom_t * arg, | |
316 | + me4000_ai_context_t * ai_context); | |
317 | +static int me4000_eeprom_write(me4000_eeprom_t * arg, | |
318 | + me4000_ai_context_t * ai_context); | |
319 | +static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context, | |
320 | + unsigned long cmd, int length); | |
321 | +static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd, | |
322 | + int length); | |
323 | + | |
324 | +/*----------------------------------------------------------------------------- | |
325 | + Digital I/O stuff | |
326 | + ---------------------------------------------------------------------------*/ | |
327 | +static int me4000_dio_ioctl(struct inode *, struct file *, unsigned int, | |
328 | + unsigned long); | |
329 | +static int me4000_dio_config(me4000_dio_config_t *, me4000_dio_context_t *); | |
330 | +static int me4000_dio_get_byte(me4000_dio_byte_t *, me4000_dio_context_t *); | |
331 | +static int me4000_dio_set_byte(me4000_dio_byte_t *, me4000_dio_context_t *); | |
332 | +static int me4000_dio_reset(me4000_dio_context_t *); | |
333 | + | |
334 | +/*----------------------------------------------------------------------------- | |
335 | + Counter stuff | |
336 | + ---------------------------------------------------------------------------*/ | |
337 | +static int me4000_cnt_ioctl(struct inode *, struct file *, unsigned int, | |
338 | + unsigned long); | |
339 | +static int me4000_cnt_config(me4000_cnt_config_t *, me4000_cnt_context_t *); | |
340 | +static int me4000_cnt_read(me4000_cnt_t *, me4000_cnt_context_t *); | |
341 | +static int me4000_cnt_write(me4000_cnt_t *, me4000_cnt_context_t *); | |
342 | +static int me4000_cnt_reset(me4000_cnt_context_t *); | |
343 | + | |
344 | +/*----------------------------------------------------------------------------- | |
345 | + External interrupt routines | |
346 | + ---------------------------------------------------------------------------*/ | |
347 | +static int me4000_ext_int_ioctl(struct inode *, struct file *, unsigned int, | |
348 | + unsigned long); | |
349 | +static int me4000_ext_int_enable(me4000_ext_int_context_t *); | |
350 | +static int me4000_ext_int_disable(me4000_ext_int_context_t *); | |
351 | +static int me4000_ext_int_count(unsigned long *arg, | |
352 | + me4000_ext_int_context_t * ext_int_context); | |
353 | +static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode); | |
354 | + | |
355 | +/*----------------------------------------------------------------------------- | |
356 | + The interrupt service routines | |
357 | + ---------------------------------------------------------------------------*/ | |
358 | +static irqreturn_t me4000_ao_isr(int, void *); | |
359 | +static irqreturn_t me4000_ai_isr(int, void *); | |
360 | +static irqreturn_t me4000_ext_int_isr(int, void *); | |
361 | + | |
362 | +/*----------------------------------------------------------------------------- | |
363 | + Inline functions | |
364 | + ---------------------------------------------------------------------------*/ | |
365 | +static int inline me4000_buf_count(me4000_circ_buf_t, int); | |
366 | +static int inline me4000_buf_space(me4000_circ_buf_t, int); | |
367 | +static int inline me4000_space_to_end(me4000_circ_buf_t, int); | |
368 | +static int inline me4000_values_to_end(me4000_circ_buf_t, int); | |
369 | + | |
370 | +static void inline me4000_outb(unsigned char value, unsigned long port); | |
371 | +static void inline me4000_outl(unsigned long value, unsigned long port); | |
372 | +static unsigned long inline me4000_inl(unsigned long port); | |
373 | +static unsigned char inline me4000_inb(unsigned long port); | |
374 | + | |
375 | +static int me4000_buf_count(me4000_circ_buf_t buf, int size) | |
376 | +{ | |
377 | + return ((buf.head - buf.tail) & (size - 1)); | |
378 | +} | |
379 | + | |
380 | +static int me4000_buf_space(me4000_circ_buf_t buf, int size) | |
381 | +{ | |
382 | + return ((buf.tail - (buf.head + 1)) & (size - 1)); | |
383 | +} | |
384 | + | |
385 | +static int me4000_values_to_end(me4000_circ_buf_t buf, int size) | |
386 | +{ | |
387 | + int end; | |
388 | + int n; | |
389 | + end = size - buf.tail; | |
390 | + n = (buf.head + end) & (size - 1); | |
391 | + return (n < end) ? n : end; | |
392 | +} | |
393 | + | |
394 | +static int me4000_space_to_end(me4000_circ_buf_t buf, int size) | |
395 | +{ | |
396 | + int end; | |
397 | + int n; | |
398 | + | |
399 | + end = size - 1 - buf.head; | |
400 | + n = (end + buf.tail) & (size - 1); | |
401 | + return (n <= end) ? n : (end + 1); | |
402 | +} | |
403 | + | |
404 | +static void me4000_outb(unsigned char value, unsigned long port) | |
405 | +{ | |
406 | + PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port); | |
407 | + outb(value, port); | |
408 | +} | |
409 | + | |
410 | +static void me4000_outl(unsigned long value, unsigned long port) | |
411 | +{ | |
412 | + PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port); | |
413 | + outl(value, port); | |
414 | +} | |
415 | + | |
416 | +static unsigned long me4000_inl(unsigned long port) | |
417 | +{ | |
418 | + unsigned long value; | |
419 | + value = inl(port); | |
420 | + PORT_PDEBUG("<-- 0x%08lX port 0x%04lX\n", value, port); | |
421 | + return value; | |
422 | +} | |
423 | + | |
424 | +static unsigned char me4000_inb(unsigned long port) | |
425 | +{ | |
426 | + unsigned char value; | |
427 | + value = inb(port); | |
428 | + PORT_PDEBUG("<-- 0x%08X port 0x%04lX\n", value, port); | |
429 | + return value; | |
430 | +} | |
431 | + | |
432 | +struct pci_driver me4000_driver = { | |
433 | + .name = ME4000_NAME, | |
434 | + .id_table = me4000_pci_table, | |
435 | + .probe = me4000_probe | |
436 | +}; | |
437 | + | |
438 | +static struct file_operations me4000_ao_fops_sing = { | |
439 | + owner:THIS_MODULE, | |
440 | + write:me4000_ao_write_sing, | |
441 | + ioctl:me4000_ao_ioctl_sing, | |
442 | + open:me4000_open, | |
443 | + release:me4000_release, | |
444 | +}; | |
445 | + | |
446 | +static struct file_operations me4000_ao_fops_wrap = { | |
447 | + owner:THIS_MODULE, | |
448 | + write:me4000_ao_write_wrap, | |
449 | + ioctl:me4000_ao_ioctl_wrap, | |
450 | + open:me4000_open, | |
451 | + release:me4000_release, | |
452 | +}; | |
453 | + | |
454 | +static struct file_operations me4000_ao_fops_cont = { | |
455 | + owner:THIS_MODULE, | |
456 | + write:me4000_ao_write_cont, | |
457 | + poll:me4000_ao_poll_cont, | |
458 | + ioctl:me4000_ao_ioctl_cont, | |
459 | + open:me4000_open, | |
460 | + release:me4000_release, | |
461 | + fsync:me4000_ao_fsync_cont, | |
462 | +}; | |
463 | + | |
464 | +static struct file_operations me4000_ai_fops_sing = { | |
465 | + owner:THIS_MODULE, | |
466 | + ioctl:me4000_ai_ioctl_sing, | |
467 | + open:me4000_open, | |
468 | + release:me4000_release, | |
469 | +}; | |
470 | + | |
471 | +static struct file_operations me4000_ai_fops_cont_sw = { | |
472 | + owner:THIS_MODULE, | |
473 | + read:me4000_ai_read, | |
474 | + poll:me4000_ai_poll, | |
475 | + ioctl:me4000_ai_ioctl_sw, | |
476 | + open:me4000_open, | |
477 | + release:me4000_release, | |
478 | + fasync:me4000_ai_fasync, | |
479 | +}; | |
480 | + | |
481 | +static struct file_operations me4000_ai_fops_cont_et = { | |
482 | + owner:THIS_MODULE, | |
483 | + read:me4000_ai_read, | |
484 | + poll:me4000_ai_poll, | |
485 | + ioctl:me4000_ai_ioctl_ext, | |
486 | + open:me4000_open, | |
487 | + release:me4000_release, | |
488 | +}; | |
489 | + | |
490 | +static struct file_operations me4000_ai_fops_cont_et_value = { | |
491 | + owner:THIS_MODULE, | |
492 | + read:me4000_ai_read, | |
493 | + poll:me4000_ai_poll, | |
494 | + ioctl:me4000_ai_ioctl_ext, | |
495 | + open:me4000_open, | |
496 | + release:me4000_release, | |
497 | +}; | |
498 | + | |
499 | +static struct file_operations me4000_ai_fops_cont_et_chanlist = { | |
500 | + owner:THIS_MODULE, | |
501 | + read:me4000_ai_read, | |
502 | + poll:me4000_ai_poll, | |
503 | + ioctl:me4000_ai_ioctl_ext, | |
504 | + open:me4000_open, | |
505 | + release:me4000_release, | |
506 | +}; | |
507 | + | |
508 | +static struct file_operations me4000_dio_fops = { | |
509 | + owner:THIS_MODULE, | |
510 | + ioctl:me4000_dio_ioctl, | |
511 | + open:me4000_open, | |
512 | + release:me4000_release, | |
513 | +}; | |
514 | + | |
515 | +static struct file_operations me4000_cnt_fops = { | |
516 | + owner:THIS_MODULE, | |
517 | + ioctl:me4000_cnt_ioctl, | |
518 | + open:me4000_open, | |
519 | + release:me4000_release, | |
520 | +}; | |
521 | + | |
522 | +static struct file_operations me4000_ext_int_fops = { | |
523 | + owner:THIS_MODULE, | |
524 | + ioctl:me4000_ext_int_ioctl, | |
525 | + open:me4000_open, | |
526 | + release:me4000_release, | |
527 | + fasync:me4000_ext_int_fasync, | |
528 | +}; | |
529 | + | |
530 | +static struct file_operations *me4000_ao_fops_array[] = { | |
531 | + &me4000_ao_fops_sing, // single operations | |
532 | + &me4000_ao_fops_wrap, // wraparound operations | |
533 | + &me4000_ao_fops_cont, // continous operations | |
534 | +}; | |
535 | + | |
536 | +static struct file_operations *me4000_ai_fops_array[] = { | |
537 | + &me4000_ai_fops_sing, // single operations | |
538 | + &me4000_ai_fops_cont_sw, // continuous operations with software start | |
539 | + &me4000_ai_fops_cont_et, // continous operations with external trigger | |
540 | + &me4000_ai_fops_cont_et_value, // sample values by external trigger | |
541 | + &me4000_ai_fops_cont_et_chanlist, // work through one channel list by external trigger | |
542 | +}; | |
543 | + | |
544 | +int __init me4000_init_module(void) | |
545 | +{ | |
546 | + int result = 0; | |
547 | + | |
548 | + CALL_PDEBUG("init_module() is executed\n"); | |
549 | + | |
550 | + /* Register driver capabilities */ | |
551 | + result = pci_register_driver(&me4000_driver); | |
552 | + PDEBUG("init_module():%d devices detected\n", result); | |
553 | + if (result < 0) { | |
554 | + printk(KERN_ERR "ME4000:init_module():Can't register driver\n"); | |
555 | + goto INIT_ERROR_1; | |
556 | + } | |
557 | + | |
558 | + /* Allocate major number for analog output */ | |
559 | + result = | |
560 | + register_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME, | |
561 | + &me4000_ao_fops_sing); | |
562 | + if (result < 0) { | |
563 | + printk(KERN_ERR "ME4000:init_module():Can't get AO major no\n"); | |
564 | + goto INIT_ERROR_2; | |
565 | + } else { | |
566 | + me4000_ao_major_driver_no = result; | |
567 | + } | |
568 | + PDEBUG("init_module():Major driver number for AO = %ld\n", | |
569 | + me4000_ao_major_driver_no); | |
570 | + | |
571 | + /* Allocate major number for analog input */ | |
572 | + result = | |
573 | + register_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME, | |
574 | + &me4000_ai_fops_sing); | |
575 | + if (result < 0) { | |
576 | + printk(KERN_ERR "ME4000:init_module():Can't get AI major no\n"); | |
577 | + goto INIT_ERROR_3; | |
578 | + } else { | |
579 | + me4000_ai_major_driver_no = result; | |
580 | + } | |
581 | + PDEBUG("init_module():Major driver number for AI = %ld\n", | |
582 | + me4000_ai_major_driver_no); | |
583 | + | |
584 | + /* Allocate major number for digital I/O */ | |
585 | + result = | |
586 | + register_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME, | |
587 | + &me4000_dio_fops); | |
588 | + if (result < 0) { | |
589 | + printk(KERN_ERR | |
590 | + "ME4000:init_module():Can't get DIO major no\n"); | |
591 | + goto INIT_ERROR_4; | |
592 | + } else { | |
593 | + me4000_dio_major_driver_no = result; | |
594 | + } | |
595 | + PDEBUG("init_module():Major driver number for DIO = %ld\n", | |
596 | + me4000_dio_major_driver_no); | |
597 | + | |
598 | + /* Allocate major number for counter */ | |
599 | + result = | |
600 | + register_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME, | |
601 | + &me4000_cnt_fops); | |
602 | + if (result < 0) { | |
603 | + printk(KERN_ERR | |
604 | + "ME4000:init_module():Can't get CNT major no\n"); | |
605 | + goto INIT_ERROR_5; | |
606 | + } else { | |
607 | + me4000_cnt_major_driver_no = result; | |
608 | + } | |
609 | + PDEBUG("init_module():Major driver number for CNT = %ld\n", | |
610 | + me4000_cnt_major_driver_no); | |
611 | + | |
612 | + /* Allocate major number for external interrupt */ | |
613 | + result = | |
614 | + register_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME, | |
615 | + &me4000_ext_int_fops); | |
616 | + if (result < 0) { | |
617 | + printk(KERN_ERR | |
618 | + "ME4000:init_module():Can't get major no for external interrupt\n"); | |
619 | + goto INIT_ERROR_6; | |
620 | + } else { | |
621 | + me4000_ext_int_major_driver_no = result; | |
622 | + } | |
623 | + PDEBUG | |
624 | + ("init_module():Major driver number for external interrupt = %ld\n", | |
625 | + me4000_ext_int_major_driver_no); | |
626 | + | |
627 | + /* Create the /proc/me4000 entry */ | |
628 | + if (!create_proc_read_entry | |
629 | + ("me4000", 0, NULL, me4000_read_procmem, NULL)) { | |
630 | + result = -ENODEV; | |
631 | + printk(KERN_ERR | |
632 | + "ME4000:init_module():Can't create proc entry\n"); | |
633 | + goto INIT_ERROR_7; | |
634 | + } | |
635 | + | |
636 | + return 0; | |
637 | + | |
638 | + INIT_ERROR_7: | |
639 | + unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME); | |
640 | + | |
641 | + INIT_ERROR_6: | |
642 | + unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME); | |
643 | + | |
644 | + INIT_ERROR_5: | |
645 | + unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME); | |
646 | + | |
647 | + INIT_ERROR_4: | |
648 | + unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME); | |
649 | + | |
650 | + INIT_ERROR_3: | |
651 | + unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME); | |
652 | + | |
653 | + INIT_ERROR_2: | |
654 | + pci_unregister_driver(&me4000_driver); | |
655 | + clear_board_info_list(); | |
656 | + | |
657 | + INIT_ERROR_1: | |
658 | + return result; | |
659 | +} | |
660 | + | |
661 | +module_init(me4000_init_module); | |
662 | + | |
663 | +static void clear_board_info_list(void) | |
664 | +{ | |
665 | + struct list_head *board_p; | |
666 | + struct list_head *dac_p; | |
667 | + me4000_info_t *board_info; | |
668 | + me4000_ao_context_t *ao_context; | |
669 | + | |
670 | + /* Clear context lists */ | |
671 | + for (board_p = me4000_board_info_list.next; | |
672 | + board_p != &me4000_board_info_list; board_p = board_p->next) { | |
673 | + board_info = list_entry(board_p, me4000_info_t, list); | |
674 | + /* Clear analog output context list */ | |
675 | + while (!list_empty(&board_info->ao_context_list)) { | |
676 | + dac_p = board_info->ao_context_list.next; | |
677 | + ao_context = | |
678 | + list_entry(dac_p, me4000_ao_context_t, list); | |
679 | + me4000_ao_reset(ao_context); | |
680 | + free_irq(ao_context->irq, ao_context); | |
681 | + if (ao_context->circ_buf.buf) | |
682 | + kfree(ao_context->circ_buf.buf); | |
683 | + list_del(dac_p); | |
684 | + kfree(ao_context); | |
685 | + } | |
686 | + | |
687 | + /* Clear analog input context */ | |
688 | + if (board_info->ai_context->circ_buf.buf) | |
689 | + kfree(board_info->ai_context->circ_buf.buf); | |
690 | + kfree(board_info->ai_context); | |
691 | + | |
692 | + /* Clear digital I/O context */ | |
693 | + kfree(board_info->dio_context); | |
694 | + | |
695 | + /* Clear counter context */ | |
696 | + kfree(board_info->cnt_context); | |
697 | + | |
698 | + /* Clear external interrupt context */ | |
699 | + kfree(board_info->ext_int_context); | |
700 | + } | |
701 | + | |
702 | + /* Clear the board info list */ | |
703 | + while (!list_empty(&me4000_board_info_list)) { | |
704 | + board_p = me4000_board_info_list.next; | |
705 | + board_info = list_entry(board_p, me4000_info_t, list); | |
706 | + pci_release_regions(board_info->pci_dev_p); | |
707 | + list_del(board_p); | |
708 | + kfree(board_info); | |
709 | + } | |
710 | +} | |
711 | + | |
712 | +static int get_registers(struct pci_dev *dev, me4000_info_t * board_info) | |
713 | +{ | |
714 | + | |
715 | + /*--------------------------- plx regbase ---------------------------------*/ | |
716 | + | |
717 | + board_info->plx_regbase = pci_resource_start(dev, 1); | |
718 | + if (board_info->plx_regbase == 0) { | |
719 | + printk(KERN_ERR | |
720 | + "ME4000:get_registers():PCI base address 1 is not available\n"); | |
721 | + return -ENODEV; | |
722 | + } | |
723 | + board_info->plx_regbase_size = pci_resource_len(dev, 1); | |
724 | + | |
725 | + PDEBUG | |
726 | + ("get_registers():PLX configuration registers at address 0x%4lX [0x%4lX]\n", | |
727 | + board_info->plx_regbase, board_info->plx_regbase_size); | |
728 | + | |
729 | + /*--------------------------- me4000 regbase ------------------------------*/ | |
730 | + | |
731 | + board_info->me4000_regbase = pci_resource_start(dev, 2); | |
732 | + if (board_info->me4000_regbase == 0) { | |
733 | + printk(KERN_ERR | |
734 | + "ME4000:get_registers():PCI base address 2 is not available\n"); | |
735 | + return -ENODEV; | |
736 | + } | |
737 | + board_info->me4000_regbase_size = pci_resource_len(dev, 2); | |
738 | + | |
739 | + PDEBUG("get_registers():ME4000 registers at address 0x%4lX [0x%4lX]\n", | |
740 | + board_info->me4000_regbase, board_info->me4000_regbase_size); | |
741 | + | |
742 | + /*--------------------------- timer regbase ------------------------------*/ | |
743 | + | |
744 | + board_info->timer_regbase = pci_resource_start(dev, 3); | |
745 | + if (board_info->timer_regbase == 0) { | |
746 | + printk(KERN_ERR | |
747 | + "ME4000:get_registers():PCI base address 3 is not available\n"); | |
748 | + return -ENODEV; | |
749 | + } | |
750 | + board_info->timer_regbase_size = pci_resource_len(dev, 3); | |
751 | + | |
752 | + PDEBUG("get_registers():Timer registers at address 0x%4lX [0x%4lX]\n", | |
753 | + board_info->timer_regbase, board_info->timer_regbase_size); | |
754 | + | |
755 | + /*--------------------------- program regbase ------------------------------*/ | |
756 | + | |
757 | + board_info->program_regbase = pci_resource_start(dev, 5); | |
758 | + if (board_info->program_regbase == 0) { | |
759 | + printk(KERN_ERR | |
760 | + "get_registers():ME4000:PCI base address 5 is not available\n"); | |
761 | + return -ENODEV; | |
762 | + } | |
763 | + board_info->program_regbase_size = pci_resource_len(dev, 5); | |
764 | + | |
765 | + PDEBUG("get_registers():Program registers at address 0x%4lX [0x%4lX]\n", | |
766 | + board_info->program_regbase, board_info->program_regbase_size); | |
767 | + | |
768 | + return 0; | |
769 | +} | |
770 | + | |
771 | +static int init_board_info(struct pci_dev *pci_dev_p, | |
772 | + me4000_info_t * board_info) | |
773 | +{ | |
774 | + int i; | |
775 | + int result; | |
776 | + struct list_head *board_p; | |
777 | + board_info->pci_dev_p = pci_dev_p; | |
778 | + | |
779 | + for (i = 0; i < ME4000_BOARD_VERSIONS; i++) { | |
780 | + if (me4000_boards[i].device_id == pci_dev_p->device) { | |
781 | + board_info->board_p = &me4000_boards[i]; | |
782 | + break; | |
783 | + } | |
784 | + } | |
785 | + if (i == ME4000_BOARD_VERSIONS) { | |
786 | + printk(KERN_ERR | |
787 | + "ME4000:init_board_info():Device ID not valid\n"); | |
788 | + return -ENODEV; | |
789 | + } | |
790 | + | |
791 | + /* Get the index of the board in the global list */ | |
792 | + for (board_p = me4000_board_info_list.next, i = 0; | |
793 | + board_p != &me4000_board_info_list; board_p = board_p->next, i++) { | |
794 | + if (board_p == &board_info->list) { | |
795 | + board_info->board_count = i; | |
796 | + break; | |
797 | + } | |
798 | + } | |
799 | + if (board_p == &me4000_board_info_list) { | |
800 | + printk(KERN_ERR | |
801 | + "ME4000:init_board_info():Cannot get index of baord\n"); | |
802 | + return -ENODEV; | |
803 | + } | |
804 | + | |
805 | + /* Init list head for analog output contexts */ | |
806 | + INIT_LIST_HEAD(&board_info->ao_context_list); | |
807 | + | |
808 | + /* Init spin locks */ | |
809 | + spin_lock_init(&board_info->preload_lock); | |
810 | + spin_lock_init(&board_info->ai_ctrl_lock); | |
811 | + | |
812 | + /* Get the serial number */ | |
813 | + result = pci_read_config_dword(pci_dev_p, 0x2C, &board_info->serial_no); | |
814 | + if (result != PCIBIOS_SUCCESSFUL) { | |
815 | + printk(KERN_WARNING | |
816 | + "ME4000:init_board_info: Can't get serial_no\n"); | |
817 | + return result; | |
818 | + } | |
819 | + PDEBUG("init_board_info():serial_no = 0x%x\n", board_info->serial_no); | |
820 | + | |
821 | + /* Get the hardware revision */ | |
822 | + result = | |
823 | + pci_read_config_byte(pci_dev_p, 0x08, &board_info->hw_revision); | |
824 | + if (result != PCIBIOS_SUCCESSFUL) { | |
825 | + printk(KERN_WARNING | |
826 | + "ME4000:init_board_info():Can't get hw_revision\n"); | |
827 | + return result; | |
828 | + } | |
829 | + PDEBUG("init_board_info():hw_revision = 0x%x\n", | |
830 | + board_info->hw_revision); | |
831 | + | |
832 | + /* Get the vendor id */ | |
833 | + board_info->vendor_id = pci_dev_p->vendor; | |
834 | + PDEBUG("init_board_info():vendor_id = 0x%x\n", board_info->vendor_id); | |
835 | + | |
836 | + /* Get the device id */ | |
837 | + board_info->device_id = pci_dev_p->device; | |
838 | + PDEBUG("init_board_info():device_id = 0x%x\n", board_info->device_id); | |
839 | + | |
840 | + /* Get the pci device number */ | |
841 | + board_info->pci_dev_no = PCI_FUNC(pci_dev_p->devfn); | |
842 | + PDEBUG("init_board_info():pci_func_no = 0x%x\n", | |
843 | + board_info->pci_func_no); | |
844 | + | |
845 | + /* Get the pci slot number */ | |
846 | + board_info->pci_dev_no = PCI_SLOT(pci_dev_p->devfn); | |
847 | + PDEBUG("init_board_info():pci_dev_no = 0x%x\n", board_info->pci_dev_no); | |
848 | + | |
849 | + /* Get the pci bus number */ | |
850 | + board_info->pci_bus_no = pci_dev_p->bus->number; | |
851 | + PDEBUG("init_board_info():pci_bus_no = 0x%x\n", board_info->pci_bus_no); | |
852 | + | |
853 | + /* Get the irq assigned to the board */ | |
854 | + board_info->irq = pci_dev_p->irq; | |
855 | + PDEBUG("init_board_info():irq = %d\n", board_info->irq); | |
856 | + | |
857 | + return 0; | |
858 | +} | |
859 | + | |
860 | +static int alloc_ao_contexts(me4000_info_t * info) | |
861 | +{ | |
862 | + int i; | |
863 | + int err; | |
864 | + me4000_ao_context_t *ao_context; | |
865 | + | |
866 | + for (i = 0; i < info->board_p->ao.count; i++) { | |
867 | + ao_context = kmalloc(sizeof(me4000_ao_context_t), GFP_KERNEL); | |
868 | + if (!ao_context) { | |
869 | + printk(KERN_ERR | |
870 | + "alloc_ao_contexts():Can't get memory for ao context\n"); | |
871 | + release_ao_contexts(info); | |
872 | + return -ENOMEM; | |
873 | + } | |
874 | + memset(ao_context, 0, sizeof(me4000_ao_context_t)); | |
875 | + | |
876 | + spin_lock_init(&ao_context->use_lock); | |
877 | + spin_lock_init(&ao_context->int_lock); | |
878 | + ao_context->irq = info->irq; | |
879 | + init_waitqueue_head(&ao_context->wait_queue); | |
880 | + ao_context->board_info = info; | |
881 | + | |
882 | + if (info->board_p->ao.fifo_count) { | |
883 | + /* Allocate circular buffer */ | |
884 | + ao_context->circ_buf.buf = | |
885 | + kmalloc(ME4000_AO_BUFFER_SIZE, GFP_KERNEL); | |
886 | + if (!ao_context->circ_buf.buf) { | |
887 | + printk(KERN_ERR | |
888 | + "alloc_ao_contexts():Can't get circular buffer\n"); | |
889 | + release_ao_contexts(info); | |
890 | + return -ENOMEM; | |
891 | + } | |
892 | + memset(ao_context->circ_buf.buf, 0, | |
893 | + ME4000_AO_BUFFER_SIZE); | |
894 | + | |
895 | + /* Clear the circular buffer */ | |
896 | + ao_context->circ_buf.head = 0; | |
897 | + ao_context->circ_buf.tail = 0; | |
898 | + } | |
899 | + | |
900 | + switch (i) { | |
901 | + case 0: | |
902 | + ao_context->ctrl_reg = | |
903 | + info->me4000_regbase + ME4000_AO_00_CTRL_REG; | |
904 | + ao_context->status_reg = | |
905 | + info->me4000_regbase + ME4000_AO_00_STATUS_REG; | |
906 | + ao_context->fifo_reg = | |
907 | + info->me4000_regbase + ME4000_AO_00_FIFO_REG; | |
908 | + ao_context->single_reg = | |
909 | + info->me4000_regbase + ME4000_AO_00_SINGLE_REG; | |
910 | + ao_context->timer_reg = | |
911 | + info->me4000_regbase + ME4000_AO_00_TIMER_REG; | |
912 | + ao_context->irq_status_reg = | |
913 | + info->me4000_regbase + ME4000_IRQ_STATUS_REG; | |
914 | + ao_context->preload_reg = | |
915 | + info->me4000_regbase + ME4000_AO_LOADSETREG_XX; | |
916 | + break; | |
917 | + case 1: | |
918 | + ao_context->ctrl_reg = | |
919 | + info->me4000_regbase + ME4000_AO_01_CTRL_REG; | |
920 | + ao_context->status_reg = | |
921 | + info->me4000_regbase + ME4000_AO_01_STATUS_REG; | |
922 | + ao_context->fifo_reg = | |
923 | + info->me4000_regbase + ME4000_AO_01_FIFO_REG; | |
924 | + ao_context->single_reg = | |
925 | + info->me4000_regbase + ME4000_AO_01_SINGLE_REG; | |
926 | + ao_context->timer_reg = | |
927 | + info->me4000_regbase + ME4000_AO_01_TIMER_REG; | |
928 | + ao_context->irq_status_reg = | |
929 | + info->me4000_regbase + ME4000_IRQ_STATUS_REG; | |
930 | + ao_context->preload_reg = | |
931 | + info->me4000_regbase + ME4000_AO_LOADSETREG_XX; | |
932 | + break; | |
933 | + case 2: | |
934 | + ao_context->ctrl_reg = | |
935 | + info->me4000_regbase + ME4000_AO_02_CTRL_REG; | |
936 | + ao_context->status_reg = | |
937 | + info->me4000_regbase + ME4000_AO_02_STATUS_REG; | |
938 | + ao_context->fifo_reg = | |
939 | + info->me4000_regbase + ME4000_AO_02_FIFO_REG; | |
940 | + ao_context->single_reg = | |
941 | + info->me4000_regbase + ME4000_AO_02_SINGLE_REG; | |
942 | + ao_context->timer_reg = | |
943 | + info->me4000_regbase + ME4000_AO_02_TIMER_REG; | |
944 | + ao_context->irq_status_reg = | |
945 | + info->me4000_regbase + ME4000_IRQ_STATUS_REG; | |
946 | + ao_context->preload_reg = | |
947 | + info->me4000_regbase + ME4000_AO_LOADSETREG_XX; | |
948 | + break; | |
949 | + case 3: | |
950 | + ao_context->ctrl_reg = | |
951 | + info->me4000_regbase + ME4000_AO_03_CTRL_REG; | |
952 | + ao_context->status_reg = | |
953 | + info->me4000_regbase + ME4000_AO_03_STATUS_REG; | |
954 | + ao_context->fifo_reg = | |
955 | + info->me4000_regbase + ME4000_AO_03_FIFO_REG; | |
956 | + ao_context->single_reg = | |
957 | + info->me4000_regbase + ME4000_AO_03_SINGLE_REG; | |
958 | + ao_context->timer_reg = | |
959 | + info->me4000_regbase + ME4000_AO_03_TIMER_REG; | |
960 | + ao_context->irq_status_reg = | |
961 | + info->me4000_regbase + ME4000_IRQ_STATUS_REG; | |
962 | + ao_context->preload_reg = | |
963 | + info->me4000_regbase + ME4000_AO_LOADSETREG_XX; | |
964 | + break; | |
965 | + default: | |
966 | + break; | |
967 | + } | |
968 | + | |
969 | + if (info->board_p->ao.fifo_count) { | |
970 | + /* Request the interrupt line */ | |
971 | + err = | |
972 | + request_irq(ao_context->irq, me4000_ao_isr, | |
973 | + IRQF_DISABLED | IRQF_SHARED, | |
974 | + ME4000_NAME, ao_context); | |
975 | + if (err) { | |
976 | + printk(KERN_ERR | |
977 | + "alloc_ao_contexts():Can't get interrupt line"); | |
978 | + if (ao_context->circ_buf.buf) | |
979 | + kfree(ao_context->circ_buf.buf); | |
980 | + kfree(ao_context); | |
981 | + release_ao_contexts(info); | |
982 | + return -ENODEV; | |
983 | + } | |
984 | + } | |
985 | + | |
986 | + list_add_tail(&ao_context->list, &info->ao_context_list); | |
987 | + ao_context->index = i; | |
988 | + } | |
989 | + | |
990 | + return 0; | |
991 | +} | |
992 | + | |
993 | +static void release_ao_contexts(me4000_info_t * board_info) | |
994 | +{ | |
995 | + struct list_head *dac_p; | |
996 | + me4000_ao_context_t *ao_context; | |
997 | + | |
998 | + /* Clear analog output context list */ | |
999 | + while (!list_empty(&board_info->ao_context_list)) { | |
1000 | + dac_p = board_info->ao_context_list.next; | |
1001 | + ao_context = list_entry(dac_p, me4000_ao_context_t, list); | |
1002 | + free_irq(ao_context->irq, ao_context); | |
1003 | + if (ao_context->circ_buf.buf) | |
1004 | + kfree(ao_context->circ_buf.buf); | |
1005 | + list_del(dac_p); | |
1006 | + kfree(ao_context); | |
1007 | + } | |
1008 | +} | |
1009 | + | |
1010 | +static int alloc_ai_context(me4000_info_t * info) | |
1011 | +{ | |
1012 | + me4000_ai_context_t *ai_context; | |
1013 | + | |
1014 | + if (info->board_p->ai.count) { | |
1015 | + ai_context = kmalloc(sizeof(me4000_ai_context_t), GFP_KERNEL); | |
1016 | + if (!ai_context) { | |
1017 | + printk(KERN_ERR | |
1018 | + "ME4000:alloc_ai_context():Can't get memory for ai context\n"); | |
1019 | + return -ENOMEM; | |
1020 | + } | |
1021 | + memset(ai_context, 0, sizeof(me4000_ai_context_t)); | |
1022 | + | |
1023 | + info->ai_context = ai_context; | |
1024 | + | |
1025 | + spin_lock_init(&ai_context->use_lock); | |
1026 | + spin_lock_init(&ai_context->int_lock); | |
1027 | + ai_context->number = 0; | |
1028 | + ai_context->irq = info->irq; | |
1029 | + init_waitqueue_head(&ai_context->wait_queue); | |
1030 | + ai_context->board_info = info; | |
1031 | + | |
1032 | + ai_context->ctrl_reg = | |
1033 | + info->me4000_regbase + ME4000_AI_CTRL_REG; | |
1034 | + ai_context->status_reg = | |
1035 | + info->me4000_regbase + ME4000_AI_STATUS_REG; | |
1036 | + ai_context->channel_list_reg = | |
1037 | + info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG; | |
1038 | + ai_context->data_reg = | |
1039 | + info->me4000_regbase + ME4000_AI_DATA_REG; | |
1040 | + ai_context->chan_timer_reg = | |
1041 | + info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG; | |
1042 | + ai_context->chan_pre_timer_reg = | |
1043 | + info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG; | |
1044 | + ai_context->scan_timer_low_reg = | |
1045 | + info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG; | |
1046 | + ai_context->scan_timer_high_reg = | |
1047 | + info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG; | |
1048 | + ai_context->scan_pre_timer_low_reg = | |
1049 | + info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG; | |
1050 | + ai_context->scan_pre_timer_high_reg = | |
1051 | + info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG; | |
1052 | + ai_context->start_reg = | |
1053 | + info->me4000_regbase + ME4000_AI_START_REG; | |
1054 | + ai_context->irq_status_reg = | |
1055 | + info->me4000_regbase + ME4000_IRQ_STATUS_REG; | |
1056 | + ai_context->sample_counter_reg = | |
1057 | + info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG; | |
1058 | + } | |
1059 | + | |
1060 | + return 0; | |
1061 | +} | |
1062 | + | |
1063 | +static int alloc_dio_context(me4000_info_t * info) | |
1064 | +{ | |
1065 | + me4000_dio_context_t *dio_context; | |
1066 | + | |
1067 | + if (info->board_p->dio.count) { | |
1068 | + dio_context = kmalloc(sizeof(me4000_dio_context_t), GFP_KERNEL); | |
1069 | + if (!dio_context) { | |
1070 | + printk(KERN_ERR | |
1071 | + "ME4000:alloc_dio_context():Can't get memory for dio context\n"); | |
1072 | + return -ENOMEM; | |
1073 | + } | |
1074 | + memset(dio_context, 0, sizeof(me4000_dio_context_t)); | |
1075 | + | |
1076 | + info->dio_context = dio_context; | |
1077 | + | |
1078 | + spin_lock_init(&dio_context->use_lock); | |
1079 | + dio_context->board_info = info; | |
1080 | + | |
1081 | + dio_context->dio_count = info->board_p->dio.count; | |
1082 | + | |
1083 | + dio_context->dir_reg = | |
1084 | + info->me4000_regbase + ME4000_DIO_DIR_REG; | |
1085 | + dio_context->ctrl_reg = | |
1086 | + info->me4000_regbase + ME4000_DIO_CTRL_REG; | |
1087 | + dio_context->port_0_reg = | |
1088 | + info->me4000_regbase + ME4000_DIO_PORT_0_REG; | |
1089 | + dio_context->port_1_reg = | |
1090 | + info->me4000_regbase + ME4000_DIO_PORT_1_REG; | |
1091 | + dio_context->port_2_reg = | |
1092 | + info->me4000_regbase + ME4000_DIO_PORT_2_REG; | |
1093 | + dio_context->port_3_reg = | |
1094 | + info->me4000_regbase + ME4000_DIO_PORT_3_REG; | |
1095 | + } | |
1096 | + | |
1097 | + return 0; | |
1098 | +} | |
1099 | + | |
1100 | +static int alloc_cnt_context(me4000_info_t * info) | |
1101 | +{ | |
1102 | + me4000_cnt_context_t *cnt_context; | |
1103 | + | |
1104 | + if (info->board_p->cnt.count) { | |
1105 | + cnt_context = kmalloc(sizeof(me4000_cnt_context_t), GFP_KERNEL); | |
1106 | + if (!cnt_context) { | |
1107 | + printk(KERN_ERR | |
1108 | + "ME4000:alloc_cnt_context():Can't get memory for cnt context\n"); | |
1109 | + return -ENOMEM; | |
1110 | + } | |
1111 | + memset(cnt_context, 0, sizeof(me4000_cnt_context_t)); | |
1112 | + | |
1113 | + info->cnt_context = cnt_context; | |
1114 | + | |
1115 | + spin_lock_init(&cnt_context->use_lock); | |
1116 | + cnt_context->board_info = info; | |
1117 | + | |
1118 | + cnt_context->ctrl_reg = | |
1119 | + info->timer_regbase + ME4000_CNT_CTRL_REG; | |
1120 | + cnt_context->counter_0_reg = | |
1121 | + info->timer_regbase + ME4000_CNT_COUNTER_0_REG; | |
1122 | + cnt_context->counter_1_reg = | |
1123 | + info->timer_regbase + ME4000_CNT_COUNTER_1_REG; | |
1124 | + cnt_context->counter_2_reg = | |
1125 | + info->timer_regbase + ME4000_CNT_COUNTER_2_REG; | |
1126 | + } | |
1127 | + | |
1128 | + return 0; | |
1129 | +} | |
1130 | + | |
1131 | +static int alloc_ext_int_context(me4000_info_t * info) | |
1132 | +{ | |
1133 | + me4000_ext_int_context_t *ext_int_context; | |
1134 | + | |
1135 | + if (info->board_p->cnt.count) { | |
1136 | + ext_int_context = | |
1137 | + kmalloc(sizeof(me4000_ext_int_context_t), GFP_KERNEL); | |
1138 | + if (!ext_int_context) { | |
1139 | + printk(KERN_ERR | |
1140 | + "ME4000:alloc_ext_int_context():Can't get memory for cnt context\n"); | |
1141 | + return -ENOMEM; | |
1142 | + } | |
1143 | + memset(ext_int_context, 0, sizeof(me4000_ext_int_context_t)); | |
1144 | + | |
1145 | + info->ext_int_context = ext_int_context; | |
1146 | + | |
1147 | + spin_lock_init(&ext_int_context->use_lock); | |
1148 | + ext_int_context->board_info = info; | |
1149 | + | |
1150 | + ext_int_context->fasync_ptr = NULL; | |
1151 | + ext_int_context->irq = info->irq; | |
1152 | + | |
1153 | + ext_int_context->ctrl_reg = | |
1154 | + info->me4000_regbase + ME4000_AI_CTRL_REG; | |
1155 | + ext_int_context->irq_status_reg = | |
1156 | + info->me4000_regbase + ME4000_IRQ_STATUS_REG; | |
1157 | + } | |
1158 | + | |
1159 | + return 0; | |
1160 | +} | |
1161 | + | |
1162 | +static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id) | |
1163 | +{ | |
1164 | + int result = 0; | |
1165 | + me4000_info_t *board_info; | |
1166 | + | |
1167 | + CALL_PDEBUG("me4000_probe() is executed\n"); | |
1168 | + | |
1169 | + /* Allocate structure for board context */ | |
1170 | + board_info = kmalloc(sizeof(me4000_info_t), GFP_KERNEL); | |
1171 | + if (!board_info) { | |
1172 | + printk(KERN_ERR | |
1173 | + "ME4000:Can't get memory for board info structure\n"); | |
1174 | + result = -ENOMEM; | |
1175 | + goto PROBE_ERROR_1; | |
1176 | + } | |
1177 | + memset(board_info, 0, sizeof(me4000_info_t)); | |
1178 | + | |
1179 | + /* Add to global linked list */ | |
1180 | + list_add_tail(&board_info->list, &me4000_board_info_list); | |
1181 | + | |
1182 | + /* Get the PCI base registers */ | |
1183 | + result = get_registers(dev, board_info); | |
1184 | + if (result) { | |
1185 | + printk(KERN_ERR "me4000_probe():Cannot get registers\n"); | |
1186 | + goto PROBE_ERROR_2; | |
1187 | + } | |
1188 | + | |
1189 | + /* Enable the device */ | |
1190 | + result = pci_enable_device(dev); | |
1191 | + if (result < 0) { | |
1192 | + printk(KERN_ERR "me4000_probe():Cannot enable PCI device\n"); | |
1193 | + goto PROBE_ERROR_2; | |
1194 | + } | |
1195 | + | |
1196 | + /* Request the PCI register regions */ | |
1197 | + result = pci_request_regions(dev, ME4000_NAME); | |
1198 | + if (result < 0) { | |
1199 | + printk(KERN_ERR "me4000_probe():Cannot request I/O regions\n"); | |
1200 | + goto PROBE_ERROR_2; | |
1201 | + } | |
1202 | + | |
1203 | + /* Initialize board info */ | |
1204 | + result = init_board_info(dev, board_info); | |
1205 | + if (result) { | |
1206 | + printk(KERN_ERR "me4000_probe():Cannot init baord info\n"); | |
1207 | + goto PROBE_ERROR_3; | |
1208 | + } | |
1209 | + | |
1210 | + /* Download the xilinx firmware */ | |
1211 | + result = me4000_xilinx_download(board_info); | |
1212 | + if (result) { | |
1213 | + printk(KERN_ERR "me4000_probe:Can't download firmware\n"); | |
1214 | + goto PROBE_ERROR_3; | |
1215 | + } | |
1216 | + | |
1217 | + /* Make a hardware reset */ | |
1218 | + result = me4000_reset_board(board_info); | |
1219 | + if (result) { | |
1220 | + printk(KERN_ERR "me4000_probe:Can't reset board\n"); | |
1221 | + goto PROBE_ERROR_3; | |
1222 | + } | |
1223 | + | |
1224 | + /* Allocate analog output context structures */ | |
1225 | + result = alloc_ao_contexts(board_info); | |
1226 | + if (result) { | |
1227 | + printk(KERN_ERR "me4000_probe():Cannot allocate ao contexts\n"); | |
1228 | + goto PROBE_ERROR_3; | |
1229 | + } | |
1230 | + | |
1231 | + /* Allocate analog input context */ | |
1232 | + result = alloc_ai_context(board_info); | |
1233 | + if (result) { | |
1234 | + printk(KERN_ERR "me4000_probe():Cannot allocate ai context\n"); | |
1235 | + goto PROBE_ERROR_4; | |
1236 | + } | |
1237 | + | |
1238 | + /* Allocate digital I/O context */ | |
1239 | + result = alloc_dio_context(board_info); | |
1240 | + if (result) { | |
1241 | + printk(KERN_ERR "me4000_probe():Cannot allocate dio context\n"); | |
1242 | + goto PROBE_ERROR_5; | |
1243 | + } | |
1244 | + | |
1245 | + /* Allocate counter context */ | |
1246 | + result = alloc_cnt_context(board_info); | |
1247 | + if (result) { | |
1248 | + printk(KERN_ERR "me4000_probe():Cannot allocate cnt context\n"); | |
1249 | + goto PROBE_ERROR_6; | |
1250 | + } | |
1251 | + | |
1252 | + /* Allocate external interrupt context */ | |
1253 | + result = alloc_ext_int_context(board_info); | |
1254 | + if (result) { | |
1255 | + printk(KERN_ERR | |
1256 | + "me4000_probe():Cannot allocate ext_int context\n"); | |
1257 | + goto PROBE_ERROR_7; | |
1258 | + } | |
1259 | + | |
1260 | + return 0; | |
1261 | + | |
1262 | + PROBE_ERROR_7: | |
1263 | + kfree(board_info->cnt_context); | |
1264 | + | |
1265 | + PROBE_ERROR_6: | |
1266 | + kfree(board_info->dio_context); | |
1267 | + | |
1268 | + PROBE_ERROR_5: | |
1269 | + kfree(board_info->ai_context); | |
1270 | + | |
1271 | + PROBE_ERROR_4: | |
1272 | + release_ao_contexts(board_info); | |
1273 | + | |
1274 | + PROBE_ERROR_3: | |
1275 | + pci_release_regions(dev); | |
1276 | + | |
1277 | + PROBE_ERROR_2: | |
1278 | + list_del(&board_info->list); | |
1279 | + kfree(board_info); | |
1280 | + | |
1281 | + PROBE_ERROR_1: | |
1282 | + return result; | |
1283 | +} | |
1284 | + | |
1285 | +static int me4000_xilinx_download(me4000_info_t * info) | |
1286 | +{ | |
1287 | + int size = 0; | |
1288 | + u32 value = 0; | |
1289 | + int idx = 0; | |
1290 | + unsigned char *firm; | |
1291 | + wait_queue_head_t queue; | |
1292 | + | |
1293 | + CALL_PDEBUG("me4000_xilinx_download() is executed\n"); | |
1294 | + | |
1295 | + init_waitqueue_head(&queue); | |
1296 | + | |
1297 | + firm = (info->device_id == 0x4610) ? xilinx_firm_4610 : xilinx_firm; | |
1298 | + | |
1299 | + /* | |
1300 | + * Set PLX local interrupt 2 polarity to high. | |
1301 | + * Interrupt is thrown by init pin of xilinx. | |
1302 | + */ | |
1303 | + outl(0x10, info->plx_regbase + PLX_INTCSR); | |
1304 | + | |
1305 | + /* Set /CS and /WRITE of the Xilinx */ | |
1306 | + value = inl(info->plx_regbase + PLX_ICR); | |
1307 | + value |= 0x100; | |
1308 | + outl(value, info->plx_regbase + PLX_ICR); | |
1309 | + | |
1310 | + /* Init Xilinx with CS1 */ | |
1311 | + inb(info->program_regbase + 0xC8); | |
1312 | + | |
1313 | + /* Wait until /INIT pin is set */ | |
1314 | + udelay(20); | |
1315 | + if (!inl(info->plx_regbase + PLX_INTCSR) & 0x20) { | |
1316 | + printk(KERN_ERR "me4000_xilinx_download():Can't init Xilinx\n"); | |
1317 | + return -EIO; | |
1318 | + } | |
1319 | + | |
1320 | + /* Reset /CS and /WRITE of the Xilinx */ | |
1321 | + value = inl(info->plx_regbase + PLX_ICR); | |
1322 | + value &= ~0x100; | |
1323 | + outl(value, info->plx_regbase + PLX_ICR); | |
1324 | + | |
1325 | + /* Download Xilinx firmware */ | |
1326 | + size = (firm[0] << 24) + (firm[1] << 16) + (firm[2] << 8) + firm[3]; | |
1327 | + udelay(10); | |
1328 | + | |
1329 | + for (idx = 0; idx < size; idx++) { | |
1330 | + outb(firm[16 + idx], info->program_regbase); | |
1331 | + | |
1332 | + udelay(10); | |
1333 | + | |
1334 | + /* Check if BUSY flag is low */ | |
1335 | + if (inl(info->plx_regbase + PLX_ICR) & 0x20) { | |
1336 | + printk(KERN_ERR | |
1337 | + "me4000_xilinx_download():Xilinx is still busy (idx = %d)\n", | |
1338 | + idx); | |
1339 | + return -EIO; | |
1340 | + } | |
1341 | + } | |
1342 | + | |
1343 | + PDEBUG("me4000_xilinx_download():%d bytes written\n", idx); | |
1344 | + | |
1345 | + /* If done flag is high download was successful */ | |
1346 | + if (inl(info->plx_regbase + PLX_ICR) & 0x4) { | |
1347 | + PDEBUG("me4000_xilinx_download():Done flag is set\n"); | |
1348 | + PDEBUG("me4000_xilinx_download():Download was successful\n"); | |
1349 | + } else { | |
1350 | + printk(KERN_ERR | |
1351 | + "ME4000:me4000_xilinx_download():DONE flag is not set\n"); | |
1352 | + printk(KERN_ERR | |
1353 | + "ME4000:me4000_xilinx_download():Download not succesful\n"); | |
1354 | + return -EIO; | |
1355 | + } | |
1356 | + | |
1357 | + /* Set /CS and /WRITE */ | |
1358 | + value = inl(info->plx_regbase + PLX_ICR); | |
1359 | + value |= 0x100; | |
1360 | + outl(value, info->plx_regbase + PLX_ICR); | |
1361 | + | |
1362 | + return 0; | |
1363 | +} | |
1364 | + | |
1365 | +static int me4000_reset_board(me4000_info_t * info) | |
1366 | +{ | |
1367 | + unsigned long icr; | |
1368 | + | |
1369 | + CALL_PDEBUG("me4000_reset_board() is executed\n"); | |
1370 | + | |
1371 | + /* Make a hardware reset */ | |
1372 | + icr = me4000_inl(info->plx_regbase + PLX_ICR); | |
1373 | + icr |= 0x40000000; | |
1374 | + me4000_outl(icr, info->plx_regbase + PLX_ICR); | |
1375 | + icr &= ~0x40000000; | |
1376 | + me4000_outl(icr, info->plx_regbase + PLX_ICR); | |
1377 | + | |
1378 | + /* Set both stop bits in the analog input control register */ | |
1379 | + me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, | |
1380 | + info->me4000_regbase + ME4000_AI_CTRL_REG); | |
1381 | + | |
1382 | + /* Set both stop bits in the analog output control register */ | |
1383 | + me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, | |
1384 | + info->me4000_regbase + ME4000_AO_00_CTRL_REG); | |
1385 | + me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, | |
1386 | + info->me4000_regbase + ME4000_AO_01_CTRL_REG); | |
1387 | + me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, | |
1388 | + info->me4000_regbase + ME4000_AO_02_CTRL_REG); | |
1389 | + me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, | |
1390 | + info->me4000_regbase + ME4000_AO_03_CTRL_REG); | |
1391 | + | |
1392 | + /* 0x8000 to the DACs means an output voltage of 0V */ | |
1393 | + me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG); | |
1394 | + me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG); | |
1395 | + me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG); | |
1396 | + me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG); | |
1397 | + | |
1398 | + /* Enable interrupts on the PLX */ | |
1399 | + me4000_outl(0x43, info->plx_regbase + PLX_INTCSR); | |
1400 | + | |
1401 | + /* Set the adustment register for AO demux */ | |
1402 | + me4000_outl(ME4000_AO_DEMUX_ADJUST_VALUE, | |
1403 | + info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG); | |
1404 | + | |
1405 | + /* Set digital I/O direction for port 0 to output on isolated versions */ | |
1406 | + if (!(me4000_inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) { | |
1407 | + me4000_outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG); | |
1408 | + } | |
1409 | + | |
1410 | + return 0; | |
1411 | +} | |
1412 | + | |
1413 | +static int me4000_open(struct inode *inode_p, struct file *file_p) | |
1414 | +{ | |
1415 | + int board, dev, mode; | |
1416 | + int err = 0; | |
1417 | + int i; | |
1418 | + struct list_head *ptr; | |
1419 | + me4000_info_t *board_info = NULL; | |
1420 | + me4000_ao_context_t *ao_context = NULL; | |
1421 | + me4000_ai_context_t *ai_context = NULL; | |
1422 | + me4000_dio_context_t *dio_context = NULL; | |
1423 | + me4000_cnt_context_t *cnt_context = NULL; | |
1424 | + me4000_ext_int_context_t *ext_int_context = NULL; | |
1425 | + | |
1426 | + CALL_PDEBUG("me4000_open() is executed\n"); | |
1427 | + | |
1428 | + /* Analog output */ | |
1429 | + if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) { | |
1430 | + board = AO_BOARD(inode_p->i_rdev); | |
1431 | + dev = AO_PORT(inode_p->i_rdev); | |
1432 | + mode = AO_MODE(inode_p->i_rdev); | |
1433 | + | |
1434 | + PDEBUG("me4000_open():board = %d ao = %d mode = %d\n", board, | |
1435 | + dev, mode); | |
1436 | + | |
1437 | + /* Search for the board context */ | |
1438 | + for (ptr = me4000_board_info_list.next, i = 0; | |
1439 | + ptr != &me4000_board_info_list; ptr = ptr->next, i++) { | |
1440 | + board_info = list_entry(ptr, me4000_info_t, list); | |
1441 | + if (i == board) | |
1442 | + break; | |
1443 | + } | |
1444 | + | |
1445 | + if (ptr == &me4000_board_info_list) { | |
1446 | + printk(KERN_ERR | |
1447 | + "ME4000:me4000_open():Board %d not in device list\n", | |
1448 | + board); | |
1449 | + return -ENODEV; | |
1450 | + } | |
1451 | + | |
1452 | + /* Search for the dac context */ | |
1453 | + for (ptr = board_info->ao_context_list.next, i = 0; | |
1454 | + ptr != &board_info->ao_context_list; | |
1455 | + ptr = ptr->next, i++) { | |
1456 | + ao_context = list_entry(ptr, me4000_ao_context_t, list); | |
1457 | + if (i == dev) | |
1458 | + break; | |
1459 | + } | |
1460 | + | |
1461 | + if (ptr == &board_info->ao_context_list) { | |
1462 | + printk(KERN_ERR | |
1463 | + "ME4000:me4000_open():Device %d not in device list\n", | |
1464 | + dev); | |
1465 | + return -ENODEV; | |
1466 | + } | |
1467 | + | |
1468 | + /* Check if mode is valid */ | |
1469 | + if (mode > 2) { | |
1470 | + printk(KERN_ERR | |
1471 | + "ME4000:me4000_open():Mode is not valid\n"); | |
1472 | + return -ENODEV; | |
1473 | + } | |
1474 | + | |
1475 | + /* Check if mode is valid for this AO */ | |
1476 | + if ((mode != ME4000_AO_CONV_MODE_SINGLE) | |
1477 | + && (dev >= board_info->board_p->ao.fifo_count)) { | |
1478 | + printk(KERN_ERR | |
1479 | + "ME4000:me4000_open():AO %d only in single mode available\n", | |
1480 | + dev); | |
1481 | + return -ENODEV; | |
1482 | + } | |
1483 | + | |
1484 | + /* Check if already opened */ | |
1485 | + spin_lock(&ao_context->use_lock); | |
1486 | + if (ao_context->dac_in_use) { | |
1487 | + printk(KERN_ERR | |
1488 | + "ME4000:me4000_open():AO %d already in use\n", | |
1489 | + dev); | |
1490 | + spin_unlock(&ao_context->use_lock); | |
1491 | + return -EBUSY; | |
1492 | + } | |
1493 | + ao_context->dac_in_use = 1; | |
1494 | + spin_unlock(&ao_context->use_lock); | |
1495 | + | |
1496 | + ao_context->mode = mode; | |
1497 | + | |
1498 | + /* Hold the context in private data */ | |
1499 | + file_p->private_data = ao_context; | |
1500 | + | |
1501 | + /* Set file operations pointer */ | |
1502 | + file_p->f_op = me4000_ao_fops_array[mode]; | |
1503 | + | |
1504 | + err = me4000_ao_prepare(ao_context); | |
1505 | + if (err) { | |
1506 | + ao_context->dac_in_use = 0; | |
1507 | + return 1; | |
1508 | + } | |
1509 | + } | |
1510 | + /* Analog input */ | |
1511 | + else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) { | |
1512 | + board = AI_BOARD(inode_p->i_rdev); | |
1513 | + mode = AI_MODE(inode_p->i_rdev); | |
1514 | + | |
1515 | + PDEBUG("me4000_open():ai board = %d mode = %d\n", board, mode); | |
1516 | + | |
1517 | + /* Search for the board context */ | |
1518 | + for (ptr = me4000_board_info_list.next, i = 0; | |
1519 | + ptr != &me4000_board_info_list; ptr = ptr->next, i++) { | |
1520 | + board_info = list_entry(ptr, me4000_info_t, list); | |
1521 | + if (i == board) | |
1522 | + break; | |
1523 | + } | |
1524 | + | |
1525 | + if (ptr == &me4000_board_info_list) { | |
1526 | + printk(KERN_ERR | |
1527 | + "ME4000:me4000_open():Board %d not in device list\n", | |
1528 | + board); | |
1529 | + return -ENODEV; | |
1530 | + } | |
1531 | + | |
1532 | + ai_context = board_info->ai_context; | |
1533 | + | |
1534 | + /* Check if mode is valid */ | |
1535 | + if (mode > 5) { | |
1536 | + printk(KERN_ERR | |
1537 | + "ME4000:me4000_open():Mode is not valid\n"); | |
1538 | + return -EINVAL; | |
1539 | + } | |
1540 | + | |
1541 | + /* Check if already opened */ | |
1542 | + spin_lock(&ai_context->use_lock); | |
1543 | + if (ai_context->in_use) { | |
1544 | + printk(KERN_ERR | |
1545 | + "ME4000:me4000_open():AI already in use\n"); | |
1546 | + spin_unlock(&ai_context->use_lock); | |
1547 | + return -EBUSY; | |
1548 | + } | |
1549 | + ai_context->in_use = 1; | |
1550 | + spin_unlock(&ai_context->use_lock); | |
1551 | + | |
1552 | + ai_context->mode = mode; | |
1553 | + | |
1554 | + /* Hold the context in private data */ | |
1555 | + file_p->private_data = ai_context; | |
1556 | + | |
1557 | + /* Set file operations pointer */ | |
1558 | + file_p->f_op = me4000_ai_fops_array[mode]; | |
1559 | + | |
1560 | + /* Prepare analog input */ | |
1561 | + me4000_ai_prepare(ai_context); | |
1562 | + } | |
1563 | + /* Digital I/O */ | |
1564 | + else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) { | |
1565 | + board = DIO_BOARD(inode_p->i_rdev); | |
1566 | + dev = 0; | |
1567 | + mode = 0; | |
1568 | + | |
1569 | + PDEBUG("me4000_open():board = %d\n", board); | |
1570 | + | |
1571 | + /* Search for the board context */ | |
1572 | + for (ptr = me4000_board_info_list.next; | |
1573 | + ptr != &me4000_board_info_list; ptr = ptr->next) { | |
1574 | + board_info = list_entry(ptr, me4000_info_t, list); | |
1575 | + if (board_info->board_count == board) | |
1576 | + break; | |
1577 | + } | |
1578 | + | |
1579 | + if (ptr == &me4000_board_info_list) { | |
1580 | + printk(KERN_ERR | |
1581 | + "ME4000:me4000_open():Board %d not in device list\n", | |
1582 | + board); | |
1583 | + return -ENODEV; | |
1584 | + } | |
1585 | + | |
1586 | + /* Search for the dio context */ | |
1587 | + dio_context = board_info->dio_context; | |
1588 | + | |
1589 | + /* Check if already opened */ | |
1590 | + spin_lock(&dio_context->use_lock); | |
1591 | + if (dio_context->in_use) { | |
1592 | + printk(KERN_ERR | |
1593 | + "ME4000:me4000_open():DIO already in use\n"); | |
1594 | + spin_unlock(&dio_context->use_lock); | |
1595 | + return -EBUSY; | |
1596 | + } | |
1597 | + dio_context->in_use = 1; | |
1598 | + spin_unlock(&dio_context->use_lock); | |
1599 | + | |
1600 | + /* Hold the context in private data */ | |
1601 | + file_p->private_data = dio_context; | |
1602 | + | |
1603 | + /* Set file operations pointer to single functions */ | |
1604 | + file_p->f_op = &me4000_dio_fops; | |
1605 | + | |
1606 | + //me4000_dio_reset(dio_context); | |
1607 | + } | |
1608 | + /* Counters */ | |
1609 | + else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) { | |
1610 | + board = CNT_BOARD(inode_p->i_rdev); | |
1611 | + dev = 0; | |
1612 | + mode = 0; | |
1613 | + | |
1614 | + PDEBUG("me4000_open():board = %d\n", board); | |
1615 | + | |
1616 | + /* Search for the board context */ | |
1617 | + for (ptr = me4000_board_info_list.next; | |
1618 | + ptr != &me4000_board_info_list; ptr = ptr->next) { | |
1619 | + board_info = list_entry(ptr, me4000_info_t, list); | |
1620 | + if (board_info->board_count == board) | |
1621 | + break; | |
1622 | + } | |
1623 | + | |
1624 | + if (ptr == &me4000_board_info_list) { | |
1625 | + printk(KERN_ERR | |
1626 | + "ME4000:me4000_open():Board %d not in device list\n", | |
1627 | + board); | |
1628 | + return -ENODEV; | |
1629 | + } | |
1630 | + | |
1631 | + /* Get the cnt context */ | |
1632 | + cnt_context = board_info->cnt_context; | |
1633 | + | |
1634 | + /* Check if already opened */ | |
1635 | + spin_lock(&cnt_context->use_lock); | |
1636 | + if (cnt_context->in_use) { | |
1637 | + printk(KERN_ERR | |
1638 | + "ME4000:me4000_open():CNT already in use\n"); | |
1639 | + spin_unlock(&cnt_context->use_lock); | |
1640 | + return -EBUSY; | |
1641 | + } | |
1642 | + cnt_context->in_use = 1; | |
1643 | + spin_unlock(&cnt_context->use_lock); | |
1644 | + | |
1645 | + /* Hold the context in private data */ | |
1646 | + file_p->private_data = cnt_context; | |
1647 | + | |
1648 | + /* Set file operations pointer to single functions */ | |
1649 | + file_p->f_op = &me4000_cnt_fops; | |
1650 | + } | |
1651 | + /* External Interrupt */ | |
1652 | + else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) { | |
1653 | + board = EXT_INT_BOARD(inode_p->i_rdev); | |
1654 | + dev = 0; | |
1655 | + mode = 0; | |
1656 | + | |
1657 | + PDEBUG("me4000_open():board = %d\n", board); | |
1658 | + | |
1659 | + /* Search for the board context */ | |
1660 | + for (ptr = me4000_board_info_list.next; | |
1661 | + ptr != &me4000_board_info_list; ptr = ptr->next) { | |
1662 | + board_info = list_entry(ptr, me4000_info_t, list); | |
1663 | + if (board_info->board_count == board) | |
1664 | + break; | |
1665 | + } | |
1666 | + | |
1667 | + if (ptr == &me4000_board_info_list) { | |
1668 | + printk(KERN_ERR | |
1669 | + "ME4000:me4000_open():Board %d not in device list\n", | |
1670 | + board); | |
1671 | + return -ENODEV; | |
1672 | + } | |
1673 | + | |
1674 | + /* Get the external interrupt context */ | |
1675 | + ext_int_context = board_info->ext_int_context; | |
1676 | + | |
1677 | + /* Check if already opened */ | |
1678 | + spin_lock(&cnt_context->use_lock); | |
1679 | + if (ext_int_context->in_use) { | |
1680 | + printk(KERN_ERR | |
1681 | + "ME4000:me4000_open():External interrupt already in use\n"); | |
1682 | + spin_unlock(&ext_int_context->use_lock); | |
1683 | + return -EBUSY; | |
1684 | + } | |
1685 | + ext_int_context->in_use = 1; | |
1686 | + spin_unlock(&ext_int_context->use_lock); | |
1687 | + | |
1688 | + /* Hold the context in private data */ | |
1689 | + file_p->private_data = ext_int_context; | |
1690 | + | |
1691 | + /* Set file operations pointer to single functions */ | |
1692 | + file_p->f_op = &me4000_ext_int_fops; | |
1693 | + | |
1694 | + /* Request the interrupt line */ | |
1695 | + err = | |
1696 | + request_irq(ext_int_context->irq, me4000_ext_int_isr, | |
1697 | + IRQF_DISABLED | IRQF_SHARED, ME4000_NAME, | |
1698 | + ext_int_context); | |
1699 | + if (err) { | |
1700 | + printk(KERN_ERR | |
1701 | + "ME4000:me4000_open():Can't get interrupt line"); | |
1702 | + ext_int_context->in_use = 0; | |
1703 | + return -ENODEV; | |
1704 | + } | |
1705 | + | |
1706 | + /* Reset the counter */ | |
1707 | + me4000_ext_int_disable(ext_int_context); | |
1708 | + } else { | |
1709 | + printk(KERN_ERR "ME4000:me4000_open():Major number unknown\n"); | |
1710 | + return -EINVAL; | |
1711 | + } | |
1712 | + | |
1713 | + return 0; | |
1714 | +} | |
1715 | + | |
1716 | +static int me4000_release(struct inode *inode_p, struct file *file_p) | |
1717 | +{ | |
1718 | + me4000_ao_context_t *ao_context; | |
1719 | + me4000_ai_context_t *ai_context; | |
1720 | + me4000_dio_context_t *dio_context; | |
1721 | + me4000_cnt_context_t *cnt_context; | |
1722 | + me4000_ext_int_context_t *ext_int_context; | |
1723 | + | |
1724 | + CALL_PDEBUG("me4000_release() is executed\n"); | |
1725 | + | |
1726 | + if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) { | |
1727 | + ao_context = file_p->private_data; | |
1728 | + | |
1729 | + /* Mark DAC as unused */ | |
1730 | + ao_context->dac_in_use = 0; | |
1731 | + } else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) { | |
1732 | + ai_context = file_p->private_data; | |
1733 | + | |
1734 | + /* Reset the analog input */ | |
1735 | + me4000_ai_reset(ai_context); | |
1736 | + | |
1737 | + /* Free the interrupt and the circular buffer */ | |
1738 | + if (ai_context->mode) { | |
1739 | + free_irq(ai_context->irq, ai_context); | |
1740 | + kfree(ai_context->circ_buf.buf); | |
1741 | + ai_context->circ_buf.buf = NULL; | |
1742 | + ai_context->circ_buf.head = 0; | |
1743 | + ai_context->circ_buf.tail = 0; | |
1744 | + } | |
1745 | + | |
1746 | + /* Mark AI as unused */ | |
1747 | + ai_context->in_use = 0; | |
1748 | + } else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) { | |
1749 | + dio_context = file_p->private_data; | |
1750 | + | |
1751 | + /* Mark digital I/O as unused */ | |
1752 | + dio_context->in_use = 0; | |
1753 | + } else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) { | |
1754 | + cnt_context = file_p->private_data; | |
1755 | + | |
1756 | + /* Mark counters as unused */ | |
1757 | + cnt_context->in_use = 0; | |
1758 | + } else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) { | |
1759 | + ext_int_context = file_p->private_data; | |
1760 | + | |
1761 | + /* Disable the externel interrupt */ | |
1762 | + me4000_ext_int_disable(ext_int_context); | |
1763 | + | |
1764 | + free_irq(ext_int_context->irq, ext_int_context); | |
1765 | + | |
1766 | + /* Delete the fasync structure and free memory */ | |
1767 | + me4000_ext_int_fasync(0, file_p, 0); | |
1768 | + | |
1769 | + /* Mark as unused */ | |
1770 | + ext_int_context->in_use = 0; | |
1771 | + } else { | |
1772 | + printk(KERN_ERR | |
1773 | + "ME4000:me4000_release():Major number unknown\n"); | |
1774 | + return -EINVAL; | |
1775 | + } | |
1776 | + | |
1777 | + return 0; | |
1778 | +} | |
1779 | + | |
1780 | +/*------------------------------- Analog output stuff --------------------------------------*/ | |
1781 | + | |
1782 | +static int me4000_ao_prepare(me4000_ao_context_t * ao_context) | |
1783 | +{ | |
1784 | + unsigned long flags; | |
1785 | + | |
1786 | + CALL_PDEBUG("me4000_ao_prepare() is executed\n"); | |
1787 | + | |
1788 | + if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) { | |
1789 | + /* Only do anything if not already in the correct mode */ | |
1790 | + unsigned long mode = me4000_inl(ao_context->ctrl_reg); | |
1791 | + if ((mode & ME4000_AO_CONV_MODE_CONTINUOUS) | |
1792 | + && (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) { | |
1793 | + return 0; | |
1794 | + } | |
1795 | + | |
1796 | + /* Stop any conversion */ | |
1797 | + me4000_ao_immediate_stop(ao_context); | |
1798 | + | |
1799 | + /* Set the control register to default state */ | |
1800 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
1801 | + me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS | | |
1802 | + ME4000_AO_CTRL_BIT_ENABLE_FIFO | | |
1803 | + ME4000_AO_CTRL_BIT_STOP | | |
1804 | + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP, | |
1805 | + ao_context->ctrl_reg); | |
1806 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
1807 | + | |
1808 | + /* Set to fastest sample rate */ | |
1809 | + me4000_outl(65, ao_context->timer_reg); | |
1810 | + } else if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) { | |
1811 | + /* Only do anything if not already in the correct mode */ | |
1812 | + unsigned long mode = me4000_inl(ao_context->ctrl_reg); | |
1813 | + if ((mode & ME4000_AO_CONV_MODE_WRAPAROUND) | |
1814 | + && (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) { | |
1815 | + return 0; | |
1816 | + } | |
1817 | + | |
1818 | + /* Stop any conversion */ | |
1819 | + me4000_ao_immediate_stop(ao_context); | |
1820 | + | |
1821 | + /* Set the control register to default state */ | |
1822 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
1823 | + me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND | | |
1824 | + ME4000_AO_CTRL_BIT_ENABLE_FIFO | | |
1825 | + ME4000_AO_CTRL_BIT_STOP | | |
1826 | + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP, | |
1827 | + ao_context->ctrl_reg); | |
1828 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
1829 | + | |
1830 | + /* Set to fastest sample rate */ | |
1831 | + me4000_outl(65, ao_context->timer_reg); | |
1832 | + } else if (ao_context->mode == ME4000_AO_CONV_MODE_SINGLE) { | |
1833 | + /* Only do anything if not already in the correct mode */ | |
1834 | + unsigned long mode = me4000_inl(ao_context->ctrl_reg); | |
1835 | + if (! | |
1836 | + (mode & | |
1837 | + (ME4000_AO_CONV_MODE_WRAPAROUND | | |
1838 | + ME4000_AO_CONV_MODE_CONTINUOUS))) { | |
1839 | + return 0; | |
1840 | + } | |
1841 | + | |
1842 | + /* Stop any conversion */ | |
1843 | + me4000_ao_immediate_stop(ao_context); | |
1844 | + | |
1845 | + /* Clear the control register */ | |
1846 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
1847 | + me4000_outl(0x0, ao_context->ctrl_reg); | |
1848 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
1849 | + | |
1850 | + /* Set voltage to 0V */ | |
1851 | + me4000_outl(0x8000, ao_context->single_reg); | |
1852 | + } else { | |
1853 | + printk(KERN_ERR | |
1854 | + "ME4000:me4000_ao_prepare():Invalid mode specified\n"); | |
1855 | + return -EINVAL; | |
1856 | + } | |
1857 | + | |
1858 | + return 0; | |
1859 | +} | |
1860 | + | |
1861 | +static int me4000_ao_reset(me4000_ao_context_t * ao_context) | |
1862 | +{ | |
1863 | + u32 tmp; | |
1864 | + wait_queue_head_t queue; | |
1865 | + unsigned long flags; | |
1866 | + | |
1867 | + CALL_PDEBUG("me4000_ao_reset() is executed\n"); | |
1868 | + | |
1869 | + init_waitqueue_head(&queue); | |
1870 | + | |
1871 | + if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) { | |
1872 | + /* | |
1873 | + * First stop conversion of the DAC before reconfigure. | |
1874 | + * This is essantial, cause of the state machine. | |
1875 | + * If not stopped before configuring mode, it could | |
1876 | + * walk in a undefined state. | |
1877 | + */ | |
1878 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
1879 | + tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; | |
1880 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
1881 | + | |
1882 | + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { | |
1883 | + sleep_on_timeout(&queue, 1); | |
1884 | + } | |
1885 | + | |
1886 | + /* Set to transparent mode */ | |
1887 | + me4000_ao_simultaneous_disable(ao_context); | |
1888 | + | |
1889 | + /* Set to single mode in order to set default voltage */ | |
1890 | + me4000_outl(0x0, ao_context->ctrl_reg); | |
1891 | + | |
1892 | + /* Set voltage to 0V */ | |
1893 | + me4000_outl(0x8000, ao_context->single_reg); | |
1894 | + | |
1895 | + /* Set to fastest sample rate */ | |
1896 | + me4000_outl(65, ao_context->timer_reg); | |
1897 | + | |
1898 | + /* Set the original mode and enable FIFO */ | |
1899 | + me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND | | |
1900 | + ME4000_AO_CTRL_BIT_ENABLE_FIFO | | |
1901 | + ME4000_AO_CTRL_BIT_STOP | | |
1902 | + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP, | |
1903 | + ao_context->ctrl_reg); | |
1904 | + } else if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) { | |
1905 | + /* | |
1906 | + * First stop conversion of the DAC before reconfigure. | |
1907 | + * This is essantial, cause of the state machine. | |
1908 | + * If not stopped before configuring mode, it could | |
1909 | + * walk in a undefined state. | |
1910 | + */ | |
1911 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
1912 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
1913 | + tmp |= ME4000_AO_CTRL_BIT_STOP; | |
1914 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
1915 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
1916 | + | |
1917 | + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { | |
1918 | + sleep_on_timeout(&queue, 1); | |
1919 | + } | |
1920 | + | |
1921 | + /* Clear the circular buffer */ | |
1922 | + ao_context->circ_buf.head = 0; | |
1923 | + ao_context->circ_buf.tail = 0; | |
1924 | + | |
1925 | + /* Set to transparent mode */ | |
1926 | + me4000_ao_simultaneous_disable(ao_context); | |
1927 | + | |
1928 | + /* Set to single mode in order to set default voltage */ | |
1929 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
1930 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
1931 | + me4000_outl(0x0, ao_context->ctrl_reg); | |
1932 | + | |
1933 | + /* Set voltage to 0V */ | |
1934 | + me4000_outl(0x8000, ao_context->single_reg); | |
1935 | + | |
1936 | + /* Set to fastest sample rate */ | |
1937 | + me4000_outl(65, ao_context->timer_reg); | |
1938 | + | |
1939 | + /* Set the original mode and enable FIFO */ | |
1940 | + me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS | | |
1941 | + ME4000_AO_CTRL_BIT_ENABLE_FIFO | | |
1942 | + ME4000_AO_CTRL_BIT_STOP | | |
1943 | + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP, | |
1944 | + ao_context->ctrl_reg); | |
1945 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
1946 | + } else { | |
1947 | + /* Set to transparent mode */ | |
1948 | + me4000_ao_simultaneous_disable(ao_context); | |
1949 | + | |
1950 | + /* Set voltage to 0V */ | |
1951 | + me4000_outl(0x8000, ao_context->single_reg); | |
1952 | + } | |
1953 | + | |
1954 | + return 0; | |
1955 | +} | |
1956 | + | |
1957 | +static ssize_t me4000_ao_write_sing(struct file *filep, const char *buff, | |
1958 | + size_t cnt, loff_t * offp) | |
1959 | +{ | |
1960 | + me4000_ao_context_t *ao_context = filep->private_data; | |
1961 | + u32 value; | |
1962 | + const u16 *buffer = (const u16 *)buff; | |
1963 | + | |
1964 | + CALL_PDEBUG("me4000_ao_write_sing() is executed\n"); | |
1965 | + | |
1966 | + if (cnt != 2) { | |
1967 | + printk(KERN_ERR | |
1968 | + "me4000_ao_write_sing():Write count is not 2\n"); | |
1969 | + return -EINVAL; | |
1970 | + } | |
1971 | + | |
1972 | + if (get_user(value, buffer)) { | |
1973 | + printk(KERN_ERR | |
1974 | + "me4000_ao_write_sing():Cannot copy data from user\n"); | |
1975 | + return -EFAULT; | |
1976 | + } | |
1977 | + | |
1978 | + me4000_outl(value, ao_context->single_reg); | |
1979 | + | |
1980 | + return 2; | |
1981 | +} | |
1982 | + | |
1983 | +static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff, | |
1984 | + size_t cnt, loff_t * offp) | |
1985 | +{ | |
1986 | + me4000_ao_context_t *ao_context = filep->private_data; | |
1987 | + size_t i; | |
1988 | + u32 value; | |
1989 | + u32 tmp; | |
1990 | + const u16 *buffer = (const u16 *)buff; | |
1991 | + size_t count = cnt / 2; | |
1992 | + | |
1993 | + CALL_PDEBUG("me4000_ao_write_wrap() is executed\n"); | |
1994 | + | |
1995 | + /* Check if a conversion is already running */ | |
1996 | + if (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { | |
1997 | + printk(KERN_ERR | |
1998 | + "ME4000:me4000_ao_write_wrap():There is already a conversion running\n"); | |
1999 | + return -EBUSY; | |
2000 | + } | |
2001 | + | |
2002 | + if (count > ME4000_AO_FIFO_COUNT) { | |
2003 | + printk(KERN_ERR | |
2004 | + "me4000_ao_write_wrap():Can't load more than %d values\n", | |
2005 | + ME4000_AO_FIFO_COUNT); | |
2006 | + return -ENOSPC; | |
2007 | + } | |
2008 | + | |
2009 | + /* Reset the FIFO */ | |
2010 | + tmp = inl(ao_context->ctrl_reg); | |
2011 | + tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_FIFO; | |
2012 | + outl(tmp, ao_context->ctrl_reg); | |
2013 | + tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO; | |
2014 | + outl(tmp, ao_context->ctrl_reg); | |
2015 | + | |
2016 | + for (i = 0; i < count; i++) { | |
2017 | + if (get_user(value, buffer + i)) { | |
2018 | + printk(KERN_ERR | |
2019 | + "me4000_ao_write_single():Cannot copy data from user\n"); | |
2020 | + return -EFAULT; | |
2021 | + } | |
2022 | + if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG) | |
2023 | + || ((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG)) | |
2024 | + value = value << 16; | |
2025 | + outl(value, ao_context->fifo_reg); | |
2026 | + } | |
2027 | + CALL_PDEBUG("me4000_ao_write_wrap() is leaved with %d\n", i * 2); | |
2028 | + | |
2029 | + return i * 2; | |
2030 | +} | |
2031 | + | |
2032 | +static ssize_t me4000_ao_write_cont(struct file *filep, const char *buff, | |
2033 | + size_t cnt, loff_t * offp) | |
2034 | +{ | |
2035 | + me4000_ao_context_t *ao_context = filep->private_data; | |
2036 | + const u16 *buffer = (const u16 *)buff; | |
2037 | + size_t count = cnt / 2; | |
2038 | + unsigned long flags; | |
2039 | + u32 tmp; | |
2040 | + int c = 0; | |
2041 | + int k = 0; | |
2042 | + int ret = 0; | |
2043 | + u16 svalue; | |
2044 | + u32 lvalue; | |
2045 | + int i; | |
2046 | + wait_queue_head_t queue; | |
2047 | + | |
2048 | + CALL_PDEBUG("me4000_ao_write_cont() is executed\n"); | |
2049 | + | |
2050 | + init_waitqueue_head(&queue); | |
2051 | + | |
2052 | + /* Check count */ | |
2053 | + if (count <= 0) { | |
2054 | + PDEBUG("me4000_ao_write_cont():Count is 0\n"); | |
2055 | + return 0; | |
2056 | + } | |
2057 | + | |
2058 | + if (filep->f_flags & O_APPEND) { | |
2059 | + PDEBUG("me4000_ao_write_cont():Append data to data stream\n"); | |
2060 | + while (count > 0) { | |
2061 | + if (filep->f_flags & O_NONBLOCK) { | |
2062 | + if (ao_context->pipe_flag) { | |
2063 | + printk(KERN_ERR | |
2064 | + "ME4000:me4000_ao_write_cont():Broken pipe in nonblocking write\n"); | |
2065 | + return -EPIPE; | |
2066 | + } | |
2067 | + c = me4000_space_to_end(ao_context->circ_buf, | |
2068 | + ME4000_AO_BUFFER_COUNT); | |
2069 | + if (!c) { | |
2070 | + PDEBUG | |
2071 | + ("me4000_ao_write_cont():Returning from nonblocking write\n"); | |
2072 | + break; | |
2073 | + } | |
2074 | + } else { | |
2075 | + wait_event_interruptible(ao_context->wait_queue, | |
2076 | + (c = | |
2077 | + me4000_space_to_end | |
2078 | + (ao_context->circ_buf, | |
2079 | + ME4000_AO_BUFFER_COUNT))); | |
2080 | + if (ao_context->pipe_flag) { | |
2081 | + printk(KERN_ERR | |
2082 | + "me4000_ao_write_cont():Broken pipe in blocking write\n"); | |
2083 | + return -EPIPE; | |
2084 | + } | |
2085 | + if (signal_pending(current)) { | |
2086 | + printk(KERN_ERR | |
2087 | + "me4000_ao_write_cont():Wait for free buffer interrupted from signal\n"); | |
2088 | + return -EINTR; | |
2089 | + } | |
2090 | + } | |
2091 | + | |
2092 | + PDEBUG("me4000_ao_write_cont():Space to end = %d\n", c); | |
2093 | + | |
2094 | + /* Only able to write size of free buffer or size of count */ | |
2095 | + if (count < c) | |
2096 | + c = count; | |
2097 | + | |
2098 | + k = 2 * c; | |
2099 | + k -= copy_from_user(ao_context->circ_buf.buf + | |
2100 | + ao_context->circ_buf.head, buffer, | |
2101 | + k); | |
2102 | + c = k / 2; | |
2103 | + PDEBUG | |
2104 | + ("me4000_ao_write_cont():Copy %d values from user space\n", | |
2105 | + c); | |
2106 | + | |
2107 | + if (!c) | |
2108 | + return -EFAULT; | |
2109 | + | |
2110 | + ao_context->circ_buf.head = | |
2111 | + (ao_context->circ_buf.head + | |
2112 | + c) & (ME4000_AO_BUFFER_COUNT - 1); | |
2113 | + buffer += c; | |
2114 | + count -= c; | |
2115 | + ret += c; | |
2116 | + | |
2117 | + /* Values are now available so enable interrupts */ | |
2118 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2119 | + if (me4000_buf_count | |
2120 | + (ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) { | |
2121 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2122 | + tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ; | |
2123 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2124 | + } | |
2125 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2126 | + } | |
2127 | + | |
2128 | + /* Wait until the state machine is stopped if O_SYNC is set */ | |
2129 | + if (filep->f_flags & O_SYNC) { | |
2130 | + while (inl(ao_context->status_reg) & | |
2131 | + ME4000_AO_STATUS_BIT_FSM) { | |
2132 | + interruptible_sleep_on_timeout(&queue, 1); | |
2133 | + if (ao_context->pipe_flag) { | |
2134 | + PDEBUG | |
2135 | + ("me4000_ao_write_cont():Broken pipe detected after sync\n"); | |
2136 | + return -EPIPE; | |
2137 | + } | |
2138 | + if (signal_pending(current)) { | |
2139 | + printk(KERN_ERR | |
2140 | + "me4000_ao_write_cont():Wait on state machine after sync interrupted\n"); | |
2141 | + return -EINTR; | |
2142 | + } | |
2143 | + } | |
2144 | + } | |
2145 | + } else { | |
2146 | + PDEBUG("me4000_ao_write_cont():Preload DAC FIFO\n"); | |
2147 | + if ((me4000_inl(ao_context->status_reg) & | |
2148 | + ME4000_AO_STATUS_BIT_FSM)) { | |
2149 | + printk(KERN_ERR | |
2150 | + "me4000_ao_write_cont():Can't Preload DAC FIFO while conversion is running\n"); | |
2151 | + return -EBUSY; | |
2152 | + } | |
2153 | + | |
2154 | + /* Clear the FIFO */ | |
2155 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2156 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2157 | + tmp &= | |
2158 | + ~(ME4000_AO_CTRL_BIT_ENABLE_FIFO | | |
2159 | + ME4000_AO_CTRL_BIT_ENABLE_IRQ); | |
2160 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2161 | + tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO; | |
2162 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2163 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2164 | + | |
2165 | + /* Clear the circular buffer */ | |
2166 | + ao_context->circ_buf.head = 0; | |
2167 | + ao_context->circ_buf.tail = 0; | |
2168 | + | |
2169 | + /* Reset the broken pipe flag */ | |
2170 | + ao_context->pipe_flag = 0; | |
2171 | + | |
2172 | + /* Only able to write size of fifo or count */ | |
2173 | + c = ME4000_AO_FIFO_COUNT; | |
2174 | + if (count < c) | |
2175 | + c = count; | |
2176 | + | |
2177 | + PDEBUG | |
2178 | + ("me4000_ao_write_cont():Write %d values to DAC on 0x%lX\n", | |
2179 | + c, ao_context->fifo_reg); | |
2180 | + | |
2181 | + /* Write values to the fifo */ | |
2182 | + for (i = 0; i < c; i++) { | |
2183 | + if (get_user(svalue, buffer)) | |
2184 | + return -EFAULT; | |
2185 | + | |
2186 | + if (((ao_context->fifo_reg & 0xFF) == | |
2187 | + ME4000_AO_01_FIFO_REG) | |
2188 | + || ((ao_context->fifo_reg & 0xFF) == | |
2189 | + ME4000_AO_03_FIFO_REG)) { | |
2190 | + lvalue = ((u32) svalue) << 16; | |
2191 | + } else | |
2192 | + lvalue = (u32) svalue; | |
2193 | + | |
2194 | + outl(lvalue, ao_context->fifo_reg); | |
2195 | + buffer++; | |
2196 | + } | |
2197 | + count -= c; | |
2198 | + ret += c; | |
2199 | + | |
2200 | + while (1) { | |
2201 | + /* Get free buffer */ | |
2202 | + c = me4000_space_to_end(ao_context->circ_buf, | |
2203 | + ME4000_AO_BUFFER_COUNT); | |
2204 | + | |
2205 | + if (c == 0) | |
2206 | + return (2 * ret); | |
2207 | + | |
2208 | + /* Only able to write size of free buffer or size of count */ | |
2209 | + if (count < c) | |
2210 | + c = count; | |
2211 | + | |
2212 | + /* If count = 0 return to user */ | |
2213 | + if (c <= 0) { | |
2214 | + PDEBUG | |
2215 | + ("me4000_ao_write_cont():Count reached 0\n"); | |
2216 | + break; | |
2217 | + } | |
2218 | + | |
2219 | + k = 2 * c; | |
2220 | + k -= copy_from_user(ao_context->circ_buf.buf + | |
2221 | + ao_context->circ_buf.head, buffer, | |
2222 | + k); | |
2223 | + c = k / 2; | |
2224 | + PDEBUG | |
2225 | + ("me4000_ao_write_cont():Wrote %d values to buffer\n", | |
2226 | + c); | |
2227 | + | |
2228 | + if (!c) | |
2229 | + return -EFAULT; | |
2230 | + | |
2231 | + ao_context->circ_buf.head = | |
2232 | + (ao_context->circ_buf.head + | |
2233 | + c) & (ME4000_AO_BUFFER_COUNT - 1); | |
2234 | + buffer += c; | |
2235 | + count -= c; | |
2236 | + ret += c; | |
2237 | + | |
2238 | + /* If values in the buffer are available so enable interrupts */ | |
2239 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2240 | + if (me4000_buf_count | |
2241 | + (ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) { | |
2242 | + PDEBUG | |
2243 | + ("me4000_ao_write_cont():Enable Interrupts\n"); | |
2244 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2245 | + tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ; | |
2246 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2247 | + } | |
2248 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2249 | + } | |
2250 | + } | |
2251 | + | |
2252 | + if (filep->f_flags & O_NONBLOCK) { | |
2253 | + return (ret == 0) ? -EAGAIN : 2 * ret; | |
2254 | + } | |
2255 | + | |
2256 | + return 2 * ret; | |
2257 | +} | |
2258 | + | |
2259 | +static unsigned int me4000_ao_poll_cont(struct file *file_p, poll_table * wait) | |
2260 | +{ | |
2261 | + me4000_ao_context_t *ao_context; | |
2262 | + unsigned long mask = 0; | |
2263 | + | |
2264 | + CALL_PDEBUG("me4000_ao_poll_cont() is executed\n"); | |
2265 | + | |
2266 | + ao_context = file_p->private_data; | |
2267 | + | |
2268 | + poll_wait(file_p, &ao_context->wait_queue, wait); | |
2269 | + | |
2270 | + /* Get free buffer */ | |
2271 | + if (me4000_space_to_end(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) | |
2272 | + mask |= POLLOUT | POLLWRNORM; | |
2273 | + | |
2274 | + CALL_PDEBUG("me4000_ao_poll_cont():Return mask %lX\n", mask); | |
2275 | + | |
2276 | + return mask; | |
2277 | +} | |
2278 | + | |
2279 | +static int me4000_ao_fsync_cont(struct file *file_p, struct dentry *dentry_p, | |
2280 | + int datasync) | |
2281 | +{ | |
2282 | + me4000_ao_context_t *ao_context; | |
2283 | + wait_queue_head_t queue; | |
2284 | + | |
2285 | + CALL_PDEBUG("me4000_ao_fsync_cont() is executed\n"); | |
2286 | + | |
2287 | + ao_context = file_p->private_data; | |
2288 | + init_waitqueue_head(&queue); | |
2289 | + | |
2290 | + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { | |
2291 | + interruptible_sleep_on_timeout(&queue, 1); | |
2292 | + if (ao_context->pipe_flag) { | |
2293 | + printk(KERN_ERR | |
2294 | + "me4000_ao_fsync_cont():Broken pipe detected\n"); | |
2295 | + return -EPIPE; | |
2296 | + } | |
2297 | + | |
2298 | + if (signal_pending(current)) { | |
2299 | + printk(KERN_ERR | |
2300 | + "me4000_ao_fsync_cont():Wait on state machine interrupted\n"); | |
2301 | + return -EINTR; | |
2302 | + } | |
2303 | + } | |
2304 | + | |
2305 | + return 0; | |
2306 | +} | |
2307 | + | |
2308 | +static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p, | |
2309 | + unsigned int service, unsigned long arg) | |
2310 | +{ | |
2311 | + me4000_ao_context_t *ao_context; | |
2312 | + | |
2313 | + CALL_PDEBUG("me4000_ao_ioctl_sing() is executed\n"); | |
2314 | + | |
2315 | + ao_context = file_p->private_data; | |
2316 | + | |
2317 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
2318 | + return -ENOTTY; | |
2319 | + PDEBUG("me4000_ao_ioctl_sing():Wrong magic number\n"); | |
2320 | + } | |
2321 | + | |
2322 | + switch (service) { | |
2323 | + case ME4000_AO_EX_TRIG_SETUP: | |
2324 | + return me4000_ao_ex_trig_set_edge((int *)arg, ao_context); | |
2325 | + case ME4000_AO_EX_TRIG_ENABLE: | |
2326 | + return me4000_ao_ex_trig_enable(ao_context); | |
2327 | + case ME4000_AO_EX_TRIG_DISABLE: | |
2328 | + return me4000_ao_ex_trig_disable(ao_context); | |
2329 | + case ME4000_AO_PRELOAD: | |
2330 | + return me4000_ao_preload(ao_context); | |
2331 | + case ME4000_AO_PRELOAD_UPDATE: | |
2332 | + return me4000_ao_preload_update(ao_context); | |
2333 | + case ME4000_GET_USER_INFO: | |
2334 | + return me4000_get_user_info((me4000_user_info_t *) arg, | |
2335 | + ao_context->board_info); | |
2336 | + case ME4000_AO_SIMULTANEOUS_EX_TRIG: | |
2337 | + return me4000_ao_simultaneous_ex_trig(ao_context); | |
2338 | + case ME4000_AO_SIMULTANEOUS_SW: | |
2339 | + return me4000_ao_simultaneous_sw(ao_context); | |
2340 | + case ME4000_AO_SIMULTANEOUS_DISABLE: | |
2341 | + return me4000_ao_simultaneous_disable(ao_context); | |
2342 | + case ME4000_AO_SIMULTANEOUS_UPDATE: | |
2343 | + return | |
2344 | + me4000_ao_simultaneous_update((me4000_ao_channel_list_t *) | |
2345 | + arg, ao_context); | |
2346 | + case ME4000_AO_EX_TRIG_TIMEOUT: | |
2347 | + return me4000_ao_ex_trig_timeout((unsigned long *)arg, | |
2348 | + ao_context); | |
2349 | + case ME4000_AO_DISABLE_DO: | |
2350 | + return me4000_ao_disable_do(ao_context); | |
2351 | + default: | |
2352 | + printk(KERN_ERR | |
2353 | + "me4000_ao_ioctl_sing():Service number invalid\n"); | |
2354 | + return -ENOTTY; | |
2355 | + } | |
2356 | + | |
2357 | + return 0; | |
2358 | +} | |
2359 | + | |
2360 | +static int me4000_ao_ioctl_wrap(struct inode *inode_p, struct file *file_p, | |
2361 | + unsigned int service, unsigned long arg) | |
2362 | +{ | |
2363 | + me4000_ao_context_t *ao_context; | |
2364 | + | |
2365 | + CALL_PDEBUG("me4000_ao_ioctl_wrap() is executed\n"); | |
2366 | + | |
2367 | + ao_context = file_p->private_data; | |
2368 | + | |
2369 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
2370 | + return -ENOTTY; | |
2371 | + PDEBUG("me4000_ao_ioctl_wrap():Wrong magic number\n"); | |
2372 | + } | |
2373 | + | |
2374 | + switch (service) { | |
2375 | + case ME4000_AO_START: | |
2376 | + return me4000_ao_start((unsigned long *)arg, ao_context); | |
2377 | + case ME4000_AO_STOP: | |
2378 | + return me4000_ao_stop(ao_context); | |
2379 | + case ME4000_AO_IMMEDIATE_STOP: | |
2380 | + return me4000_ao_immediate_stop(ao_context); | |
2381 | + case ME4000_AO_RESET: | |
2382 | + return me4000_ao_reset(ao_context); | |
2383 | + case ME4000_AO_TIMER_SET_DIVISOR: | |
2384 | + return me4000_ao_timer_set_divisor((u32 *) arg, ao_context); | |
2385 | + case ME4000_AO_EX_TRIG_SETUP: | |
2386 | + return me4000_ao_ex_trig_set_edge((int *)arg, ao_context); | |
2387 | + case ME4000_AO_EX_TRIG_ENABLE: | |
2388 | + return me4000_ao_ex_trig_enable(ao_context); | |
2389 | + case ME4000_AO_EX_TRIG_DISABLE: | |
2390 | + return me4000_ao_ex_trig_disable(ao_context); | |
2391 | + case ME4000_GET_USER_INFO: | |
2392 | + return me4000_get_user_info((me4000_user_info_t *) arg, | |
2393 | + ao_context->board_info); | |
2394 | + case ME4000_AO_FSM_STATE: | |
2395 | + return me4000_ao_fsm_state((int *)arg, ao_context); | |
2396 | + case ME4000_AO_ENABLE_DO: | |
2397 | + return me4000_ao_enable_do(ao_context); | |
2398 | + case ME4000_AO_DISABLE_DO: | |
2399 | + return me4000_ao_disable_do(ao_context); | |
2400 | + case ME4000_AO_SYNCHRONOUS_EX_TRIG: | |
2401 | + return me4000_ao_synchronous_ex_trig(ao_context); | |
2402 | + case ME4000_AO_SYNCHRONOUS_SW: | |
2403 | + return me4000_ao_synchronous_sw(ao_context); | |
2404 | + case ME4000_AO_SYNCHRONOUS_DISABLE: | |
2405 | + return me4000_ao_synchronous_disable(ao_context); | |
2406 | + default: | |
2407 | + return -ENOTTY; | |
2408 | + } | |
2409 | + return 0; | |
2410 | +} | |
2411 | + | |
2412 | +static int me4000_ao_ioctl_cont(struct inode *inode_p, struct file *file_p, | |
2413 | + unsigned int service, unsigned long arg) | |
2414 | +{ | |
2415 | + me4000_ao_context_t *ao_context; | |
2416 | + | |
2417 | + CALL_PDEBUG("me4000_ao_ioctl_cont() is executed\n"); | |
2418 | + | |
2419 | + ao_context = file_p->private_data; | |
2420 | + | |
2421 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
2422 | + return -ENOTTY; | |
2423 | + PDEBUG("me4000_ao_ioctl_cont():Wrong magic number\n"); | |
2424 | + } | |
2425 | + | |
2426 | + switch (service) { | |
2427 | + case ME4000_AO_START: | |
2428 | + return me4000_ao_start((unsigned long *)arg, ao_context); | |
2429 | + case ME4000_AO_STOP: | |
2430 | + return me4000_ao_stop(ao_context); | |
2431 | + case ME4000_AO_IMMEDIATE_STOP: | |
2432 | + return me4000_ao_immediate_stop(ao_context); | |
2433 | + case ME4000_AO_RESET: | |
2434 | + return me4000_ao_reset(ao_context); | |
2435 | + case ME4000_AO_TIMER_SET_DIVISOR: | |
2436 | + return me4000_ao_timer_set_divisor((u32 *) arg, ao_context); | |
2437 | + case ME4000_AO_EX_TRIG_SETUP: | |
2438 | + return me4000_ao_ex_trig_set_edge((int *)arg, ao_context); | |
2439 | + case ME4000_AO_EX_TRIG_ENABLE: | |
2440 | + return me4000_ao_ex_trig_enable(ao_context); | |
2441 | + case ME4000_AO_EX_TRIG_DISABLE: | |
2442 | + return me4000_ao_ex_trig_disable(ao_context); | |
2443 | + case ME4000_AO_ENABLE_DO: | |
2444 | + return me4000_ao_enable_do(ao_context); | |
2445 | + case ME4000_AO_DISABLE_DO: | |
2446 | + return me4000_ao_disable_do(ao_context); | |
2447 | + case ME4000_AO_FSM_STATE: | |
2448 | + return me4000_ao_fsm_state((int *)arg, ao_context); | |
2449 | + case ME4000_GET_USER_INFO: | |
2450 | + return me4000_get_user_info((me4000_user_info_t *) arg, | |
2451 | + ao_context->board_info); | |
2452 | + case ME4000_AO_SYNCHRONOUS_EX_TRIG: | |
2453 | + return me4000_ao_synchronous_ex_trig(ao_context); | |
2454 | + case ME4000_AO_SYNCHRONOUS_SW: | |
2455 | + return me4000_ao_synchronous_sw(ao_context); | |
2456 | + case ME4000_AO_SYNCHRONOUS_DISABLE: | |
2457 | + return me4000_ao_synchronous_disable(ao_context); | |
2458 | + case ME4000_AO_GET_FREE_BUFFER: | |
2459 | + return me4000_ao_get_free_buffer((unsigned long *)arg, | |
2460 | + ao_context); | |
2461 | + default: | |
2462 | + return -ENOTTY; | |
2463 | + } | |
2464 | + return 0; | |
2465 | +} | |
2466 | + | |
2467 | +static int me4000_ao_start(unsigned long *arg, me4000_ao_context_t * ao_context) | |
2468 | +{ | |
2469 | + u32 tmp; | |
2470 | + wait_queue_head_t queue; | |
2471 | + unsigned long ref; | |
2472 | + unsigned long timeout; | |
2473 | + unsigned long flags; | |
2474 | + | |
2475 | + CALL_PDEBUG("me4000_ao_start() is executed\n"); | |
2476 | + | |
2477 | + if (get_user(timeout, arg)) { | |
2478 | + printk(KERN_ERR | |
2479 | + "me4000_ao_start():Cannot copy data from user\n"); | |
2480 | + return -EFAULT; | |
2481 | + } | |
2482 | + | |
2483 | + init_waitqueue_head(&queue); | |
2484 | + | |
2485 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2486 | + tmp = inl(ao_context->ctrl_reg); | |
2487 | + tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP); | |
2488 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2489 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2490 | + | |
2491 | + if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) { | |
2492 | + if (timeout) { | |
2493 | + ref = jiffies; | |
2494 | + while (! | |
2495 | + (inl(ao_context->status_reg) & | |
2496 | + ME4000_AO_STATUS_BIT_FSM)) { | |
2497 | + interruptible_sleep_on_timeout(&queue, 1); | |
2498 | + if (signal_pending(current)) { | |
2499 | + printk(KERN_ERR | |
2500 | + "ME4000:me4000_ao_start():Wait on start of state machine interrupted\n"); | |
2501 | + return -EINTR; | |
2502 | + } | |
2503 | + if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space | |
2504 | + printk(KERN_ERR | |
2505 | + "ME4000:me4000_ao_start():Timeout reached\n"); | |
2506 | + return -EIO; | |
2507 | + } | |
2508 | + } | |
2509 | + } | |
2510 | + } else { | |
2511 | + me4000_outl(0x8000, ao_context->single_reg); | |
2512 | + } | |
2513 | + | |
2514 | + return 0; | |
2515 | +} | |
2516 | + | |
2517 | +static int me4000_ao_stop(me4000_ao_context_t * ao_context) | |
2518 | +{ | |
2519 | + u32 tmp; | |
2520 | + wait_queue_head_t queue; | |
2521 | + unsigned long flags; | |
2522 | + | |
2523 | + init_waitqueue_head(&queue); | |
2524 | + | |
2525 | + CALL_PDEBUG("me4000_ao_stop() is executed\n"); | |
2526 | + | |
2527 | + /* Set the stop bit */ | |
2528 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2529 | + tmp = inl(ao_context->ctrl_reg); | |
2530 | + tmp |= ME4000_AO_CTRL_BIT_STOP; | |
2531 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2532 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2533 | + | |
2534 | + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { | |
2535 | + interruptible_sleep_on_timeout(&queue, 1); | |
2536 | + if (signal_pending(current)) { | |
2537 | + printk(KERN_ERR | |
2538 | + "me4000_ao_stop():Wait on state machine after stop interrupted\n"); | |
2539 | + return -EINTR; | |
2540 | + } | |
2541 | + } | |
2542 | + | |
2543 | + /* Clear the stop bit */ | |
2544 | + //tmp &= ~ME4000_AO_CTRL_BIT_STOP; | |
2545 | + //me4000_outl(tmp, ao_context->ctrl_reg); | |
2546 | + | |
2547 | + return 0; | |
2548 | +} | |
2549 | + | |
2550 | +static int me4000_ao_immediate_stop(me4000_ao_context_t * ao_context) | |
2551 | +{ | |
2552 | + u32 tmp; | |
2553 | + wait_queue_head_t queue; | |
2554 | + unsigned long flags; | |
2555 | + | |
2556 | + init_waitqueue_head(&queue); | |
2557 | + | |
2558 | + CALL_PDEBUG("me4000_ao_immediate_stop() is executed\n"); | |
2559 | + | |
2560 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2561 | + tmp = inl(ao_context->ctrl_reg); | |
2562 | + tmp |= ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; | |
2563 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2564 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2565 | + | |
2566 | + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { | |
2567 | + interruptible_sleep_on_timeout(&queue, 1); | |
2568 | + if (signal_pending(current)) { | |
2569 | + printk(KERN_ERR | |
2570 | + "me4000_ao_immediate_stop():Wait on state machine after stop interrupted\n"); | |
2571 | + return -EINTR; | |
2572 | + } | |
2573 | + } | |
2574 | + | |
2575 | + /* Clear the stop bits */ | |
2576 | + //tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP); | |
2577 | + //me4000_outl(tmp, ao_context->ctrl_reg); | |
2578 | + | |
2579 | + return 0; | |
2580 | +} | |
2581 | + | |
2582 | +static int me4000_ao_timer_set_divisor(u32 * arg, | |
2583 | + me4000_ao_context_t * ao_context) | |
2584 | +{ | |
2585 | + u32 divisor; | |
2586 | + u32 tmp; | |
2587 | + | |
2588 | + CALL_PDEBUG("me4000_ao_timer set_divisor() is executed\n"); | |
2589 | + | |
2590 | + if (get_user(divisor, arg)) | |
2591 | + return -EFAULT; | |
2592 | + | |
2593 | + /* Check if the state machine is stopped */ | |
2594 | + tmp = me4000_inl(ao_context->status_reg); | |
2595 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
2596 | + printk(KERN_ERR | |
2597 | + "me4000_ao_timer_set_divisor():Can't set timer while DAC is running\n"); | |
2598 | + return -EBUSY; | |
2599 | + } | |
2600 | + | |
2601 | + PDEBUG("me4000_ao_timer set_divisor():Divisor from user = %d\n", | |
2602 | + divisor); | |
2603 | + | |
2604 | + /* Check if the divisor is right. ME4000_AO_MIN_TICKS is the lowest */ | |
2605 | + if (divisor < ME4000_AO_MIN_TICKS) { | |
2606 | + printk(KERN_ERR | |
2607 | + "ME4000:me4000_ao_timer set_divisor():Divisor to low\n"); | |
2608 | + return -EINVAL; | |
2609 | + } | |
2610 | + | |
2611 | + /* Fix bug in Firmware */ | |
2612 | + divisor -= 2; | |
2613 | + | |
2614 | + PDEBUG("me4000_ao_timer set_divisor():Divisor to HW = %d\n", divisor); | |
2615 | + | |
2616 | + /* Write the divisor */ | |
2617 | + me4000_outl(divisor, ao_context->timer_reg); | |
2618 | + | |
2619 | + return 0; | |
2620 | +} | |
2621 | + | |
2622 | +static int me4000_ao_ex_trig_set_edge(int *arg, | |
2623 | + me4000_ao_context_t * ao_context) | |
2624 | +{ | |
2625 | + int mode; | |
2626 | + u32 tmp; | |
2627 | + unsigned long flags; | |
2628 | + | |
2629 | + CALL_PDEBUG("me4000_ao_ex_trig_set_edge() is executed\n"); | |
2630 | + | |
2631 | + if (get_user(mode, arg)) | |
2632 | + return -EFAULT; | |
2633 | + | |
2634 | + /* Check if the state machine is stopped */ | |
2635 | + tmp = me4000_inl(ao_context->status_reg); | |
2636 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
2637 | + printk(KERN_ERR | |
2638 | + "me4000_ao_ex_trig_set_edge():Can't set trigger while DAC is running\n"); | |
2639 | + return -EBUSY; | |
2640 | + } | |
2641 | + | |
2642 | + if (mode == ME4000_AO_TRIGGER_EXT_EDGE_RISING) { | |
2643 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2644 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2645 | + tmp &= | |
2646 | + ~(ME4000_AO_CTRL_BIT_EX_TRIG_EDGE | | |
2647 | + ME4000_AO_CTRL_BIT_EX_TRIG_BOTH); | |
2648 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2649 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2650 | + } else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_FALLING) { | |
2651 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2652 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2653 | + tmp &= ~ME4000_AO_CTRL_BIT_EX_TRIG_BOTH; | |
2654 | + tmp |= ME4000_AO_CTRL_BIT_EX_TRIG_EDGE; | |
2655 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2656 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2657 | + } else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_BOTH) { | |
2658 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2659 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2660 | + tmp |= | |
2661 | + ME4000_AO_CTRL_BIT_EX_TRIG_EDGE | | |
2662 | + ME4000_AO_CTRL_BIT_EX_TRIG_BOTH; | |
2663 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2664 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2665 | + } else { | |
2666 | + printk(KERN_ERR | |
2667 | + "me4000_ao_ex_trig_set_edge():Invalid trigger mode\n"); | |
2668 | + return -EINVAL; | |
2669 | + } | |
2670 | + | |
2671 | + return 0; | |
2672 | +} | |
2673 | + | |
2674 | +static int me4000_ao_ex_trig_enable(me4000_ao_context_t * ao_context) | |
2675 | +{ | |
2676 | + u32 tmp; | |
2677 | + unsigned long flags; | |
2678 | + | |
2679 | + CALL_PDEBUG("me4000_ao_ex_trig_enable() is executed\n"); | |
2680 | + | |
2681 | + /* Check if the state machine is stopped */ | |
2682 | + tmp = me4000_inl(ao_context->status_reg); | |
2683 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
2684 | + printk(KERN_ERR | |
2685 | + "me4000_ao_ex_trig_enable():Can't enable trigger while DAC is running\n"); | |
2686 | + return -EBUSY; | |
2687 | + } | |
2688 | + | |
2689 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2690 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2691 | + tmp |= ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG; | |
2692 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2693 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2694 | + | |
2695 | + return 0; | |
2696 | +} | |
2697 | + | |
2698 | +static int me4000_ao_ex_trig_disable(me4000_ao_context_t * ao_context) | |
2699 | +{ | |
2700 | + u32 tmp; | |
2701 | + unsigned long flags; | |
2702 | + | |
2703 | + CALL_PDEBUG("me4000_ao_ex_trig_disable() is executed\n"); | |
2704 | + | |
2705 | + /* Check if the state machine is stopped */ | |
2706 | + tmp = me4000_inl(ao_context->status_reg); | |
2707 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
2708 | + printk(KERN_ERR | |
2709 | + "me4000_ao_ex_trig_disable():Can't disable trigger while DAC is running\n"); | |
2710 | + return -EBUSY; | |
2711 | + } | |
2712 | + | |
2713 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2714 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2715 | + tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG; | |
2716 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2717 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2718 | + | |
2719 | + return 0; | |
2720 | +} | |
2721 | + | |
2722 | +static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context) | |
2723 | +{ | |
2724 | + u32 tmp; | |
2725 | + | |
2726 | + CALL_PDEBUG("me4000_ao_simultaneous_disable() is executed\n"); | |
2727 | + | |
2728 | + /* Check if the state machine is stopped */ | |
2729 | + /* Be careful here because this function is called from | |
2730 | + me4000_ao_synchronous disable */ | |
2731 | + tmp = me4000_inl(ao_context->status_reg); | |
2732 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
2733 | + printk(KERN_ERR | |
2734 | + "me4000_ao_simultaneous_disable():Can't disable while DAC is running\n"); | |
2735 | + return -EBUSY; | |
2736 | + } | |
2737 | + | |
2738 | + spin_lock(&ao_context->board_info->preload_lock); | |
2739 | + tmp = me4000_inl(ao_context->preload_reg); | |
2740 | + tmp &= ~(0x1 << ao_context->index); // Disable preload bit | |
2741 | + tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit | |
2742 | + me4000_outl(tmp, ao_context->preload_reg); | |
2743 | + spin_unlock(&ao_context->board_info->preload_lock); | |
2744 | + | |
2745 | + return 0; | |
2746 | +} | |
2747 | + | |
2748 | +static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context) | |
2749 | +{ | |
2750 | + u32 tmp; | |
2751 | + | |
2752 | + CALL_PDEBUG("me4000_ao_simultaneous_ex_trig() is executed\n"); | |
2753 | + | |
2754 | + spin_lock(&ao_context->board_info->preload_lock); | |
2755 | + tmp = me4000_inl(ao_context->preload_reg); | |
2756 | + tmp |= (0x1 << ao_context->index); // Enable preload bit | |
2757 | + tmp |= (0x1 << (ao_context->index + 16)); // Enable hw simultaneous bit | |
2758 | + me4000_outl(tmp, ao_context->preload_reg); | |
2759 | + spin_unlock(&ao_context->board_info->preload_lock); | |
2760 | + | |
2761 | + return 0; | |
2762 | +} | |
2763 | + | |
2764 | +static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context) | |
2765 | +{ | |
2766 | + u32 tmp; | |
2767 | + | |
2768 | + CALL_PDEBUG("me4000_ao_simultaneous_sw() is executed\n"); | |
2769 | + | |
2770 | + spin_lock(&ao_context->board_info->preload_lock); | |
2771 | + tmp = me4000_inl(ao_context->preload_reg); | |
2772 | + tmp |= (0x1 << ao_context->index); // Enable preload bit | |
2773 | + tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit | |
2774 | + me4000_outl(tmp, ao_context->preload_reg); | |
2775 | + spin_unlock(&ao_context->board_info->preload_lock); | |
2776 | + | |
2777 | + return 0; | |
2778 | +} | |
2779 | + | |
2780 | +static int me4000_ao_preload(me4000_ao_context_t * ao_context) | |
2781 | +{ | |
2782 | + CALL_PDEBUG("me4000_ao_preload() is executed\n"); | |
2783 | + return me4000_ao_simultaneous_sw(ao_context); | |
2784 | +} | |
2785 | + | |
2786 | +static int me4000_ao_preload_update(me4000_ao_context_t * ao_context) | |
2787 | +{ | |
2788 | + u32 tmp; | |
2789 | + u32 ctrl; | |
2790 | + struct list_head *entry; | |
2791 | + | |
2792 | + CALL_PDEBUG("me4000_ao_preload_update() is executed\n"); | |
2793 | + | |
2794 | + spin_lock(&ao_context->board_info->preload_lock); | |
2795 | + tmp = me4000_inl(ao_context->preload_reg); | |
2796 | + list_for_each(entry, &ao_context->board_info->ao_context_list) { | |
2797 | + /* The channels we update must be in the following state : | |
2798 | + - Mode A | |
2799 | + - Hardware trigger is disabled | |
2800 | + - Corresponding simultaneous bit is reset | |
2801 | + */ | |
2802 | + ctrl = me4000_inl(ao_context->ctrl_reg); | |
2803 | + if (! | |
2804 | + (ctrl & | |
2805 | + (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1 | | |
2806 | + ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG))) { | |
2807 | + if (! | |
2808 | + (tmp & | |
2809 | + (0x1 << | |
2810 | + (((me4000_ao_context_t *) entry)->index + 16)))) { | |
2811 | + tmp &= | |
2812 | + ~(0x1 << | |
2813 | + (((me4000_ao_context_t *) entry)->index)); | |
2814 | + } | |
2815 | + } | |
2816 | + } | |
2817 | + me4000_outl(tmp, ao_context->preload_reg); | |
2818 | + spin_unlock(&ao_context->board_info->preload_lock); | |
2819 | + | |
2820 | + return 0; | |
2821 | +} | |
2822 | + | |
2823 | +static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * arg, | |
2824 | + me4000_ao_context_t * ao_context) | |
2825 | +{ | |
2826 | + int err; | |
2827 | + int i; | |
2828 | + u32 tmp; | |
2829 | + me4000_ao_channel_list_t channels; | |
2830 | + | |
2831 | + CALL_PDEBUG("me4000_ao_simultaneous_update() is executed\n"); | |
2832 | + | |
2833 | + /* Copy data from user */ | |
2834 | + err = copy_from_user(&channels, arg, sizeof(me4000_ao_channel_list_t)); | |
2835 | + if (err) { | |
2836 | + printk(KERN_ERR | |
2837 | + "ME4000:me4000_ao_simultaneous_update():Can't copy command\n"); | |
2838 | + return -EFAULT; | |
2839 | + } | |
2840 | + | |
2841 | + channels.list = | |
2842 | + kmalloc(sizeof(unsigned long) * channels.count, GFP_KERNEL); | |
2843 | + if (!channels.list) { | |
2844 | + printk(KERN_ERR | |
2845 | + "ME4000:me4000_ao_simultaneous_update():Can't get buffer\n"); | |
2846 | + return -ENOMEM; | |
2847 | + } | |
2848 | + memset(channels.list, 0, sizeof(unsigned long) * channels.count); | |
2849 | + | |
2850 | + /* Copy channel list from user */ | |
2851 | + err = | |
2852 | + copy_from_user(channels.list, arg->list, | |
2853 | + sizeof(unsigned long) * channels.count); | |
2854 | + if (err) { | |
2855 | + printk(KERN_ERR | |
2856 | + "ME4000:me4000_ao_simultaneous_update():Can't copy list\n"); | |
2857 | + kfree(channels.list); | |
2858 | + return -EFAULT; | |
2859 | + } | |
2860 | + | |
2861 | + spin_lock(&ao_context->board_info->preload_lock); | |
2862 | + tmp = me4000_inl(ao_context->preload_reg); | |
2863 | + for (i = 0; i < channels.count; i++) { | |
2864 | + if (channels.list[i] > | |
2865 | + ao_context->board_info->board_p->ao.count) { | |
2866 | + spin_unlock(&ao_context->board_info->preload_lock); | |
2867 | + kfree(channels.list); | |
2868 | + printk(KERN_ERR | |
2869 | + "ME4000:me4000_ao_simultaneous_update():Invalid board number specified\n"); | |
2870 | + return -EFAULT; | |
2871 | + } | |
2872 | + tmp &= ~(0x1 << channels.list[i]); // Clear the preload bit | |
2873 | + tmp &= ~(0x1 << (channels.list[i] + 16)); // Clear the hw simultaneous bit | |
2874 | + } | |
2875 | + me4000_outl(tmp, ao_context->preload_reg); | |
2876 | + spin_unlock(&ao_context->board_info->preload_lock); | |
2877 | + kfree(channels.list); | |
2878 | + | |
2879 | + return 0; | |
2880 | +} | |
2881 | + | |
2882 | +static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context) | |
2883 | +{ | |
2884 | + u32 tmp; | |
2885 | + unsigned long flags; | |
2886 | + | |
2887 | + CALL_PDEBUG("me4000_ao_synchronous_ex_trig() is executed\n"); | |
2888 | + | |
2889 | + /* Check if the state machine is stopped */ | |
2890 | + tmp = me4000_inl(ao_context->status_reg); | |
2891 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
2892 | + printk(KERN_ERR | |
2893 | + "me4000_ao_synchronous_ex_trig(): DAC is running\n"); | |
2894 | + return -EBUSY; | |
2895 | + } | |
2896 | + | |
2897 | + spin_lock(&ao_context->board_info->preload_lock); | |
2898 | + tmp = me4000_inl(ao_context->preload_reg); | |
2899 | + tmp &= ~(0x1 << ao_context->index); // Disable synchronous sw bit | |
2900 | + tmp |= 0x1 << (ao_context->index + 16); // Enable synchronous hw bit | |
2901 | + me4000_outl(tmp, ao_context->preload_reg); | |
2902 | + spin_unlock(&ao_context->board_info->preload_lock); | |
2903 | + | |
2904 | + /* Make runnable */ | |
2905 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2906 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2907 | + if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) { | |
2908 | + tmp &= | |
2909 | + ~(ME4000_AO_CTRL_BIT_STOP | | |
2910 | + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP); | |
2911 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2912 | + } | |
2913 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2914 | + | |
2915 | + return 0; | |
2916 | +} | |
2917 | + | |
2918 | +static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context) | |
2919 | +{ | |
2920 | + u32 tmp; | |
2921 | + unsigned long flags; | |
2922 | + | |
2923 | + CALL_PDEBUG("me4000_ao_synchronous_sw() is executed\n"); | |
2924 | + | |
2925 | + /* Check if the state machine is stopped */ | |
2926 | + tmp = me4000_inl(ao_context->status_reg); | |
2927 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
2928 | + printk(KERN_ERR "me4000_ao_synchronous_sw(): DAC is running\n"); | |
2929 | + return -EBUSY; | |
2930 | + } | |
2931 | + | |
2932 | + spin_lock(&ao_context->board_info->preload_lock); | |
2933 | + tmp = me4000_inl(ao_context->preload_reg); | |
2934 | + tmp |= 0x1 << ao_context->index; // Enable synchronous sw bit | |
2935 | + tmp &= ~(0x1 << (ao_context->index + 16)); // Disable synchronous hw bit | |
2936 | + me4000_outl(tmp, ao_context->preload_reg); | |
2937 | + spin_unlock(&ao_context->board_info->preload_lock); | |
2938 | + | |
2939 | + /* Make runnable */ | |
2940 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
2941 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
2942 | + if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) { | |
2943 | + tmp &= | |
2944 | + ~(ME4000_AO_CTRL_BIT_STOP | | |
2945 | + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP); | |
2946 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
2947 | + } | |
2948 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
2949 | + | |
2950 | + return 0; | |
2951 | +} | |
2952 | + | |
2953 | +static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context) | |
2954 | +{ | |
2955 | + return me4000_ao_simultaneous_disable(ao_context); | |
2956 | +} | |
2957 | + | |
2958 | +static int me4000_ao_get_free_buffer(unsigned long *arg, | |
2959 | + me4000_ao_context_t * ao_context) | |
2960 | +{ | |
2961 | + unsigned long c; | |
2962 | + int err; | |
2963 | + | |
2964 | + c = me4000_buf_space(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT); | |
2965 | + | |
2966 | + err = copy_to_user(arg, &c, sizeof(unsigned long)); | |
2967 | + if (err) { | |
2968 | + printk(KERN_ERR | |
2969 | + "ME4000:me4000_ao_get_free_buffer():Can't copy to user space\n"); | |
2970 | + return -EFAULT; | |
2971 | + } | |
2972 | + | |
2973 | + return 0; | |
2974 | +} | |
2975 | + | |
2976 | +static int me4000_ao_ex_trig_timeout(unsigned long *arg, | |
2977 | + me4000_ao_context_t * ao_context) | |
2978 | +{ | |
2979 | + u32 tmp; | |
2980 | + wait_queue_head_t queue; | |
2981 | + unsigned long ref; | |
2982 | + unsigned long timeout; | |
2983 | + | |
2984 | + CALL_PDEBUG("me4000_ao_ex_trig_timeout() is executed\n"); | |
2985 | + | |
2986 | + if (get_user(timeout, arg)) { | |
2987 | + printk(KERN_ERR | |
2988 | + "me4000_ao_ex_trig_timeout():Cannot copy data from user\n"); | |
2989 | + return -EFAULT; | |
2990 | + } | |
2991 | + | |
2992 | + init_waitqueue_head(&queue); | |
2993 | + | |
2994 | + tmp = inl(ao_context->ctrl_reg); | |
2995 | + | |
2996 | + if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) { | |
2997 | + if (timeout) { | |
2998 | + ref = jiffies; | |
2999 | + while ((inl(ao_context->status_reg) & | |
3000 | + ME4000_AO_STATUS_BIT_FSM)) { | |
3001 | + interruptible_sleep_on_timeout(&queue, 1); | |
3002 | + if (signal_pending(current)) { | |
3003 | + printk(KERN_ERR | |
3004 | + "ME4000:me4000_ao_ex_trig_timeout():Wait on start of state machine interrupted\n"); | |
3005 | + return -EINTR; | |
3006 | + } | |
3007 | + if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space | |
3008 | + printk(KERN_ERR | |
3009 | + "ME4000:me4000_ao_ex_trig_timeout():Timeout reached\n"); | |
3010 | + return -EIO; | |
3011 | + } | |
3012 | + } | |
3013 | + } else { | |
3014 | + while ((inl(ao_context->status_reg) & | |
3015 | + ME4000_AO_STATUS_BIT_FSM)) { | |
3016 | + interruptible_sleep_on_timeout(&queue, 1); | |
3017 | + if (signal_pending(current)) { | |
3018 | + printk(KERN_ERR | |
3019 | + "ME4000:me4000_ao_ex_trig_timeout():Wait on start of state machine interrupted\n"); | |
3020 | + return -EINTR; | |
3021 | + } | |
3022 | + } | |
3023 | + } | |
3024 | + } else { | |
3025 | + printk(KERN_ERR | |
3026 | + "ME4000:me4000_ao_ex_trig_timeout():External Trigger is not enabled\n"); | |
3027 | + return -EINVAL; | |
3028 | + } | |
3029 | + | |
3030 | + return 0; | |
3031 | +} | |
3032 | + | |
3033 | +static int me4000_ao_enable_do(me4000_ao_context_t * ao_context) | |
3034 | +{ | |
3035 | + u32 tmp; | |
3036 | + unsigned long flags; | |
3037 | + | |
3038 | + CALL_PDEBUG("me4000_ao_enable_do() is executed\n"); | |
3039 | + | |
3040 | + /* Only available for analog output 3 */ | |
3041 | + if (ao_context->index != 3) { | |
3042 | + printk(KERN_ERR | |
3043 | + "me4000_ao_enable_do():Only available for analog output 3\n"); | |
3044 | + return -ENOTTY; | |
3045 | + } | |
3046 | + | |
3047 | + /* Check if the state machine is stopped */ | |
3048 | + tmp = me4000_inl(ao_context->status_reg); | |
3049 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
3050 | + printk(KERN_ERR "me4000_ao_enable_do(): DAC is running\n"); | |
3051 | + return -EBUSY; | |
3052 | + } | |
3053 | + | |
3054 | + /* Set the stop bit */ | |
3055 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
3056 | + tmp = inl(ao_context->ctrl_reg); | |
3057 | + tmp |= ME4000_AO_CTRL_BIT_ENABLE_DO; | |
3058 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
3059 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
3060 | + | |
3061 | + return 0; | |
3062 | +} | |
3063 | + | |
3064 | +static int me4000_ao_disable_do(me4000_ao_context_t * ao_context) | |
3065 | +{ | |
3066 | + u32 tmp; | |
3067 | + unsigned long flags; | |
3068 | + | |
3069 | + CALL_PDEBUG("me4000_ao_disable_do() is executed\n"); | |
3070 | + | |
3071 | + /* Only available for analog output 3 */ | |
3072 | + if (ao_context->index != 3) { | |
3073 | + printk(KERN_ERR | |
3074 | + "me4000_ao_disable():Only available for analog output 3\n"); | |
3075 | + return -ENOTTY; | |
3076 | + } | |
3077 | + | |
3078 | + /* Check if the state machine is stopped */ | |
3079 | + tmp = me4000_inl(ao_context->status_reg); | |
3080 | + if (tmp & ME4000_AO_STATUS_BIT_FSM) { | |
3081 | + printk(KERN_ERR "me4000_ao_disable_do(): DAC is running\n"); | |
3082 | + return -EBUSY; | |
3083 | + } | |
3084 | + | |
3085 | + spin_lock_irqsave(&ao_context->int_lock, flags); | |
3086 | + tmp = inl(ao_context->ctrl_reg); | |
3087 | + tmp &= ~(ME4000_AO_CTRL_BIT_ENABLE_DO); | |
3088 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
3089 | + spin_unlock_irqrestore(&ao_context->int_lock, flags); | |
3090 | + | |
3091 | + return 0; | |
3092 | +} | |
3093 | + | |
3094 | +static int me4000_ao_fsm_state(int *arg, me4000_ao_context_t * ao_context) | |
3095 | +{ | |
3096 | + unsigned long tmp; | |
3097 | + | |
3098 | + CALL_PDEBUG("me4000_ao_fsm_state() is executed\n"); | |
3099 | + | |
3100 | + tmp = | |
3101 | + (me4000_inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) ? 1 | |
3102 | + : 0; | |
3103 | + | |
3104 | + if (ao_context->pipe_flag) { | |
3105 | + printk(KERN_ERR "me4000_ao_fsm_state():Broken pipe detected\n"); | |
3106 | + return -EPIPE; | |
3107 | + } | |
3108 | + | |
3109 | + if (put_user(tmp, arg)) { | |
3110 | + printk(KERN_ERR "me4000_ao_fsm_state():Cannot copy to user\n"); | |
3111 | + return -EFAULT; | |
3112 | + } | |
3113 | + | |
3114 | + return 0; | |
3115 | +} | |
3116 | + | |
3117 | +/*------------------------------- Analog input stuff --------------------------------------*/ | |
3118 | + | |
3119 | +static int me4000_ai_prepare(me4000_ai_context_t * ai_context) | |
3120 | +{ | |
3121 | + wait_queue_head_t queue; | |
3122 | + int err; | |
3123 | + | |
3124 | + CALL_PDEBUG("me4000_ai_prepare() is executed\n"); | |
3125 | + | |
3126 | + init_waitqueue_head(&queue); | |
3127 | + | |
3128 | + /* Set the new mode and stop bits */ | |
3129 | + me4000_outl(ai_context-> | |
3130 | + mode | ME4000_AI_CTRL_BIT_STOP | | |
3131 | + ME4000_AI_CTRL_BIT_IMMEDIATE_STOP, ai_context->ctrl_reg); | |
3132 | + | |
3133 | + /* Set the timer registers */ | |
3134 | + ai_context->chan_timer = 66; | |
3135 | + ai_context->chan_pre_timer = 66; | |
3136 | + ai_context->scan_timer_low = 0; | |
3137 | + ai_context->scan_timer_high = 0; | |
3138 | + | |
3139 | + me4000_outl(65, ai_context->chan_timer_reg); | |
3140 | + me4000_outl(65, ai_context->chan_pre_timer_reg); | |
3141 | + me4000_outl(0, ai_context->scan_timer_low_reg); | |
3142 | + me4000_outl(0, ai_context->scan_timer_high_reg); | |
3143 | + me4000_outl(0, ai_context->scan_pre_timer_low_reg); | |
3144 | + me4000_outl(0, ai_context->scan_pre_timer_high_reg); | |
3145 | + | |
3146 | + ai_context->channel_list_count = 0; | |
3147 | + | |
3148 | + if (ai_context->mode) { | |
3149 | + /* Request the interrupt line */ | |
3150 | + err = | |
3151 | + request_irq(ai_context->irq, me4000_ai_isr, | |
3152 | + IRQF_DISABLED | IRQF_SHARED, ME4000_NAME, | |
3153 | + ai_context); | |
3154 | + if (err) { | |
3155 | + printk(KERN_ERR | |
3156 | + "ME4000:me4000_ai_prepare():Can't get interrupt line"); | |
3157 | + return -ENODEV; | |
3158 | + } | |
3159 | + | |
3160 | + /* Allocate circular buffer */ | |
3161 | + ai_context->circ_buf.buf = | |
3162 | + kmalloc(ME4000_AI_BUFFER_SIZE, GFP_KERNEL); | |
3163 | + if (!ai_context->circ_buf.buf) { | |
3164 | + printk(KERN_ERR | |
3165 | + "ME4000:me4000_ai_prepare():Can't get circular buffer\n"); | |
3166 | + free_irq(ai_context->irq, ai_context); | |
3167 | + return -ENOMEM; | |
3168 | + } | |
3169 | + memset(ai_context->circ_buf.buf, 0, ME4000_AI_BUFFER_SIZE); | |
3170 | + | |
3171 | + /* Clear the circular buffer */ | |
3172 | + ai_context->circ_buf.head = 0; | |
3173 | + ai_context->circ_buf.tail = 0; | |
3174 | + } | |
3175 | + | |
3176 | + return 0; | |
3177 | +} | |
3178 | + | |
3179 | +static int me4000_ai_reset(me4000_ai_context_t * ai_context) | |
3180 | +{ | |
3181 | + wait_queue_head_t queue; | |
3182 | + u32 tmp; | |
3183 | + unsigned long flags; | |
3184 | + | |
3185 | + CALL_PDEBUG("me4000_ai_reset() is executed\n"); | |
3186 | + | |
3187 | + init_waitqueue_head(&queue); | |
3188 | + | |
3189 | + /* | |
3190 | + * First stop conversion of the state machine before reconfigure. | |
3191 | + * If not stopped before configuring mode, it could | |
3192 | + * walk in a undefined state. | |
3193 | + */ | |
3194 | + spin_lock_irqsave(&ai_context->int_lock, flags); | |
3195 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
3196 | + tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | |
3197 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3198 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
3199 | + | |
3200 | + while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) { | |
3201 | + interruptible_sleep_on_timeout(&queue, 1); | |
3202 | + if (signal_pending(current)) { | |
3203 | + printk(KERN_ERR | |
3204 | + "me4000_ai_reset():Wait on state machine after stop interrupted\n"); | |
3205 | + return -EINTR; | |
3206 | + } | |
3207 | + } | |
3208 | + | |
3209 | + /* Clear the control register and set the stop bits */ | |
3210 | + spin_lock_irqsave(&ai_context->int_lock, flags); | |
3211 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
3212 | + me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, | |
3213 | + ai_context->ctrl_reg); | |
3214 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
3215 | + | |
3216 | + /* Reset timer registers */ | |
3217 | + ai_context->chan_timer = 66; | |
3218 | + ai_context->chan_pre_timer = 66; | |
3219 | + ai_context->scan_timer_low = 0; | |
3220 | + ai_context->scan_timer_high = 0; | |
3221 | + ai_context->sample_counter = 0; | |
3222 | + ai_context->sample_counter_reload = 0; | |
3223 | + | |
3224 | + me4000_outl(65, ai_context->chan_timer_reg); | |
3225 | + me4000_outl(65, ai_context->chan_pre_timer_reg); | |
3226 | + me4000_outl(0, ai_context->scan_timer_low_reg); | |
3227 | + me4000_outl(0, ai_context->scan_timer_high_reg); | |
3228 | + me4000_outl(0, ai_context->scan_pre_timer_low_reg); | |
3229 | + me4000_outl(0, ai_context->scan_pre_timer_high_reg); | |
3230 | + me4000_outl(0, ai_context->sample_counter_reg); | |
3231 | + | |
3232 | + ai_context->channel_list_count = 0; | |
3233 | + | |
3234 | + /* Clear the circular buffer */ | |
3235 | + ai_context->circ_buf.head = 0; | |
3236 | + ai_context->circ_buf.tail = 0; | |
3237 | + | |
3238 | + return 0; | |
3239 | +} | |
3240 | + | |
3241 | +static int me4000_ai_ioctl_sing(struct inode *inode_p, struct file *file_p, | |
3242 | + unsigned int service, unsigned long arg) | |
3243 | +{ | |
3244 | + me4000_ai_context_t *ai_context; | |
3245 | + | |
3246 | + CALL_PDEBUG("me4000_ai_ioctl_sing() is executed\n"); | |
3247 | + | |
3248 | + ai_context = file_p->private_data; | |
3249 | + | |
3250 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
3251 | + printk(KERN_ERR "me4000_ai_ioctl_sing():Wrong magic number\n"); | |
3252 | + return -ENOTTY; | |
3253 | + } | |
3254 | + if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { | |
3255 | + printk(KERN_ERR | |
3256 | + "me4000_ai_ioctl_sing():Service number to high\n"); | |
3257 | + return -ENOTTY; | |
3258 | + } | |
3259 | + | |
3260 | + switch (service) { | |
3261 | + case ME4000_AI_SINGLE: | |
3262 | + return me4000_ai_single((me4000_ai_single_t *) arg, ai_context); | |
3263 | + case ME4000_AI_EX_TRIG_ENABLE: | |
3264 | + return me4000_ai_ex_trig_enable(ai_context); | |
3265 | + case ME4000_AI_EX_TRIG_DISABLE: | |
3266 | + return me4000_ai_ex_trig_disable(ai_context); | |
3267 | + case ME4000_AI_EX_TRIG_SETUP: | |
3268 | + return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg, | |
3269 | + ai_context); | |
3270 | + case ME4000_GET_USER_INFO: | |
3271 | + return me4000_get_user_info((me4000_user_info_t *) arg, | |
3272 | + ai_context->board_info); | |
3273 | + case ME4000_AI_OFFSET_ENABLE: | |
3274 | + return me4000_ai_offset_enable(ai_context); | |
3275 | + case ME4000_AI_OFFSET_DISABLE: | |
3276 | + return me4000_ai_offset_disable(ai_context); | |
3277 | + case ME4000_AI_FULLSCALE_ENABLE: | |
3278 | + return me4000_ai_fullscale_enable(ai_context); | |
3279 | + case ME4000_AI_FULLSCALE_DISABLE: | |
3280 | + return me4000_ai_fullscale_disable(ai_context); | |
3281 | + case ME4000_AI_EEPROM_READ: | |
3282 | + return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context); | |
3283 | + case ME4000_AI_EEPROM_WRITE: | |
3284 | + return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context); | |
3285 | + default: | |
3286 | + printk(KERN_ERR | |
3287 | + "me4000_ai_ioctl_sing():Invalid service number\n"); | |
3288 | + return -ENOTTY; | |
3289 | + } | |
3290 | + return 0; | |
3291 | +} | |
3292 | + | |
3293 | +static int me4000_ai_single(me4000_ai_single_t * arg, | |
3294 | + me4000_ai_context_t * ai_context) | |
3295 | +{ | |
3296 | + me4000_ai_single_t cmd; | |
3297 | + int err; | |
3298 | + u32 tmp; | |
3299 | + wait_queue_head_t queue; | |
3300 | + unsigned long jiffy; | |
3301 | + | |
3302 | + CALL_PDEBUG("me4000_ai_single() is executed\n"); | |
3303 | + | |
3304 | + init_waitqueue_head(&queue); | |
3305 | + | |
3306 | + /* Copy data from user */ | |
3307 | + err = copy_from_user(&cmd, arg, sizeof(me4000_ai_single_t)); | |
3308 | + if (err) { | |
3309 | + printk(KERN_ERR | |
3310 | + "ME4000:me4000_ai_single():Can't copy from user space\n"); | |
3311 | + return -EFAULT; | |
3312 | + } | |
3313 | + | |
3314 | + /* Check range parameter */ | |
3315 | + switch (cmd.range) { | |
3316 | + case ME4000_AI_LIST_RANGE_BIPOLAR_10: | |
3317 | + case ME4000_AI_LIST_RANGE_BIPOLAR_2_5: | |
3318 | + case ME4000_AI_LIST_RANGE_UNIPOLAR_10: | |
3319 | + case ME4000_AI_LIST_RANGE_UNIPOLAR_2_5: | |
3320 | + break; | |
3321 | + default: | |
3322 | + printk(KERN_ERR | |
3323 | + "ME4000:me4000_ai_single():Invalid range specified\n"); | |
3324 | + return -EINVAL; | |
3325 | + } | |
3326 | + | |
3327 | + /* Check mode and channel number */ | |
3328 | + switch (cmd.mode) { | |
3329 | + case ME4000_AI_LIST_INPUT_SINGLE_ENDED: | |
3330 | + if (cmd.channel >= ai_context->board_info->board_p->ai.count) { | |
3331 | + printk(KERN_ERR | |
3332 | + "ME4000:me4000_ai_single():Analog input is not available\n"); | |
3333 | + return -EINVAL; | |
3334 | + } | |
3335 | + break; | |
3336 | + case ME4000_AI_LIST_INPUT_DIFFERENTIAL: | |
3337 | + if (cmd.channel >= | |
3338 | + ai_context->board_info->board_p->ai.diff_count) { | |
3339 | + printk(KERN_ERR | |
3340 | + "ME4000:me4000_ai_single():Analog input is not available in differential mode\n"); | |
3341 | + return -EINVAL; | |
3342 | + } | |
3343 | + break; | |
3344 | + default: | |
3345 | + printk(KERN_ERR | |
3346 | + "ME4000:me4000_ai_single():Invalid mode specified\n"); | |
3347 | + return -EINVAL; | |
3348 | + } | |
3349 | + | |
3350 | + /* Clear channel list, data fifo and both stop bits */ | |
3351 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
3352 | + tmp &= | |
3353 | + ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO | | |
3354 | + ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); | |
3355 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3356 | + | |
3357 | + /* Enable channel list and data fifo */ | |
3358 | + tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO; | |
3359 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3360 | + | |
3361 | + /* Generate channel list entry */ | |
3362 | + me4000_outl(cmd.channel | cmd.range | cmd. | |
3363 | + mode | ME4000_AI_LIST_LAST_ENTRY, | |
3364 | + ai_context->channel_list_reg); | |
3365 | + | |
3366 | + /* Set the timer to maximum */ | |
3367 | + me4000_outl(66, ai_context->chan_timer_reg); | |
3368 | + me4000_outl(66, ai_context->chan_pre_timer_reg); | |
3369 | + | |
3370 | + if (tmp & ME4000_AI_CTRL_BIT_EX_TRIG) { | |
3371 | + jiffy = jiffies; | |
3372 | + while (! | |
3373 | + (me4000_inl(ai_context->status_reg) & | |
3374 | + ME4000_AI_STATUS_BIT_EF_DATA)) { | |
3375 | + interruptible_sleep_on_timeout(&queue, 1); | |
3376 | + if (signal_pending(current)) { | |
3377 | + printk(KERN_ERR | |
3378 | + "ME4000:me4000_ai_single():Wait on start of state machine interrupted\n"); | |
3379 | + return -EINTR; | |
3380 | + } | |
3381 | + if (((jiffies - jiffy) > (cmd.timeout * HZ / USER_HZ)) && cmd.timeout) { // 2.6 has diffrent definitions for HZ in user and kernel space | |
3382 | + printk(KERN_ERR | |
3383 | + "ME4000:me4000_ai_single():Timeout reached\n"); | |
3384 | + return -EIO; | |
3385 | + } | |
3386 | + } | |
3387 | + } else { | |
3388 | + /* Start conversion */ | |
3389 | + me4000_inl(ai_context->start_reg); | |
3390 | + | |
3391 | + /* Wait until ready */ | |
3392 | + udelay(10); | |
3393 | + if (! | |
3394 | + (me4000_inl(ai_context->status_reg) & | |
3395 | + ME4000_AI_STATUS_BIT_EF_DATA)) { | |
3396 | + printk(KERN_ERR | |
3397 | + "ME4000:me4000_ai_single():Value not available after wait\n"); | |
3398 | + return -EIO; | |
3399 | + } | |
3400 | + } | |
3401 | + | |
3402 | + /* Read value from data fifo */ | |
3403 | + cmd.value = me4000_inl(ai_context->data_reg) & 0xFFFF; | |
3404 | + | |
3405 | + /* Copy result back to user */ | |
3406 | + err = copy_to_user(arg, &cmd, sizeof(me4000_ai_single_t)); | |
3407 | + if (err) { | |
3408 | + printk(KERN_ERR | |
3409 | + "ME4000:me4000_ai_single():Can't copy to user space\n"); | |
3410 | + return -EFAULT; | |
3411 | + } | |
3412 | + | |
3413 | + return 0; | |
3414 | +} | |
3415 | + | |
3416 | +static int me4000_ai_ioctl_sw(struct inode *inode_p, struct file *file_p, | |
3417 | + unsigned int service, unsigned long arg) | |
3418 | +{ | |
3419 | + me4000_ai_context_t *ai_context; | |
3420 | + | |
3421 | + CALL_PDEBUG("me4000_ai_ioctl_sw() is executed\n"); | |
3422 | + | |
3423 | + ai_context = file_p->private_data; | |
3424 | + | |
3425 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
3426 | + printk(KERN_ERR "me4000_ai_ioctl_sw():Wrong magic number\n"); | |
3427 | + return -ENOTTY; | |
3428 | + } | |
3429 | + if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { | |
3430 | + printk(KERN_ERR | |
3431 | + "me4000_ai_ioctl_sw():Service number to high\n"); | |
3432 | + return -ENOTTY; | |
3433 | + } | |
3434 | + | |
3435 | + switch (service) { | |
3436 | + case ME4000_AI_SC_SETUP: | |
3437 | + return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context); | |
3438 | + case ME4000_AI_CONFIG: | |
3439 | + return me4000_ai_config((me4000_ai_config_t *) arg, ai_context); | |
3440 | + case ME4000_AI_START: | |
3441 | + return me4000_ai_start(ai_context); | |
3442 | + case ME4000_AI_STOP: | |
3443 | + return me4000_ai_stop(ai_context); | |
3444 | + case ME4000_AI_IMMEDIATE_STOP: | |
3445 | + return me4000_ai_immediate_stop(ai_context); | |
3446 | + case ME4000_AI_FSM_STATE: | |
3447 | + return me4000_ai_fsm_state((int *)arg, ai_context); | |
3448 | + case ME4000_GET_USER_INFO: | |
3449 | + return me4000_get_user_info((me4000_user_info_t *) arg, | |
3450 | + ai_context->board_info); | |
3451 | + case ME4000_AI_EEPROM_READ: | |
3452 | + return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context); | |
3453 | + case ME4000_AI_EEPROM_WRITE: | |
3454 | + return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context); | |
3455 | + case ME4000_AI_GET_COUNT_BUFFER: | |
3456 | + return me4000_ai_get_count_buffer((unsigned long *)arg, | |
3457 | + ai_context); | |
3458 | + default: | |
3459 | + printk(KERN_ERR | |
3460 | + "ME4000:me4000_ai_ioctl_sw():Invalid service number %d\n", | |
3461 | + service); | |
3462 | + return -ENOTTY; | |
3463 | + } | |
3464 | + return 0; | |
3465 | +} | |
3466 | + | |
3467 | +static int me4000_ai_ioctl_ext(struct inode *inode_p, struct file *file_p, | |
3468 | + unsigned int service, unsigned long arg) | |
3469 | +{ | |
3470 | + me4000_ai_context_t *ai_context; | |
3471 | + | |
3472 | + CALL_PDEBUG("me4000_ai_ioctl_ext() is executed\n"); | |
3473 | + | |
3474 | + ai_context = file_p->private_data; | |
3475 | + | |
3476 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
3477 | + printk(KERN_ERR "me4000_ai_ioctl_ext():Wrong magic number\n"); | |
3478 | + return -ENOTTY; | |
3479 | + } | |
3480 | + if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { | |
3481 | + printk(KERN_ERR | |
3482 | + "me4000_ai_ioctl_ext():Service number to high\n"); | |
3483 | + return -ENOTTY; | |
3484 | + } | |
3485 | + | |
3486 | + switch (service) { | |
3487 | + case ME4000_AI_SC_SETUP: | |
3488 | + return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context); | |
3489 | + case ME4000_AI_CONFIG: | |
3490 | + return me4000_ai_config((me4000_ai_config_t *) arg, ai_context); | |
3491 | + case ME4000_AI_START: | |
3492 | + return me4000_ai_start_ex((unsigned long *)arg, ai_context); | |
3493 | + case ME4000_AI_STOP: | |
3494 | + return me4000_ai_stop(ai_context); | |
3495 | + case ME4000_AI_IMMEDIATE_STOP: | |
3496 | + return me4000_ai_immediate_stop(ai_context); | |
3497 | + case ME4000_AI_EX_TRIG_ENABLE: | |
3498 | + return me4000_ai_ex_trig_enable(ai_context); | |
3499 | + case ME4000_AI_EX_TRIG_DISABLE: | |
3500 | + return me4000_ai_ex_trig_disable(ai_context); | |
3501 | + case ME4000_AI_EX_TRIG_SETUP: | |
3502 | + return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg, | |
3503 | + ai_context); | |
3504 | + case ME4000_AI_FSM_STATE: | |
3505 | + return me4000_ai_fsm_state((int *)arg, ai_context); | |
3506 | + case ME4000_GET_USER_INFO: | |
3507 | + return me4000_get_user_info((me4000_user_info_t *) arg, | |
3508 | + ai_context->board_info); | |
3509 | + case ME4000_AI_GET_COUNT_BUFFER: | |
3510 | + return me4000_ai_get_count_buffer((unsigned long *)arg, | |
3511 | + ai_context); | |
3512 | + default: | |
3513 | + printk(KERN_ERR | |
3514 | + "ME4000:me4000_ai_ioctl_ext():Invalid service number %d\n", | |
3515 | + service); | |
3516 | + return -ENOTTY; | |
3517 | + } | |
3518 | + return 0; | |
3519 | +} | |
3520 | + | |
3521 | +static int me4000_ai_fasync(int fd, struct file *file_p, int mode) | |
3522 | +{ | |
3523 | + me4000_ai_context_t *ai_context; | |
3524 | + | |
3525 | + CALL_PDEBUG("me4000_ao_fasync_cont() is executed\n"); | |
3526 | + | |
3527 | + ai_context = file_p->private_data; | |
3528 | + return fasync_helper(fd, file_p, mode, &ai_context->fasync_p); | |
3529 | +} | |
3530 | + | |
3531 | +static int me4000_ai_config(me4000_ai_config_t * arg, | |
3532 | + me4000_ai_context_t * ai_context) | |
3533 | +{ | |
3534 | + me4000_ai_config_t cmd; | |
3535 | + u32 *list = NULL; | |
3536 | + u32 mode; | |
3537 | + int i; | |
3538 | + int err; | |
3539 | + wait_queue_head_t queue; | |
3540 | + u64 scan; | |
3541 | + u32 tmp; | |
3542 | + | |
3543 | + CALL_PDEBUG("me4000_ai_config() is executed\n"); | |
3544 | + | |
3545 | + init_waitqueue_head(&queue); | |
3546 | + | |
3547 | + /* Check if conversion is stopped */ | |
3548 | + if (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_FSM) { | |
3549 | + printk(KERN_ERR | |
3550 | + "ME4000:me4000_ai_config():Conversion is not stopped\n"); | |
3551 | + err = -EBUSY; | |
3552 | + goto AI_CONFIG_ERR; | |
3553 | + } | |
3554 | + | |
3555 | + /* Copy data from user */ | |
3556 | + err = copy_from_user(&cmd, arg, sizeof(me4000_ai_config_t)); | |
3557 | + if (err) { | |
3558 | + printk(KERN_ERR | |
3559 | + "ME4000:me4000_ai_config():Can't copy from user space\n"); | |
3560 | + err = -EFAULT; | |
3561 | + goto AI_CONFIG_ERR; | |
3562 | + } | |
3563 | + | |
3564 | + PDEBUG | |
3565 | + ("me4000_ai_config():chan = %ld, pre_chan = %ld, scan_low = %ld, scan_high = %ld, count = %ld\n", | |
3566 | + cmd.timer.chan, cmd.timer.pre_chan, cmd.timer.scan_low, | |
3567 | + cmd.timer.scan_high, cmd.channel_list.count); | |
3568 | + | |
3569 | + /* Check whether sample and hold is available for this board */ | |
3570 | + if (cmd.sh) { | |
3571 | + if (!ai_context->board_info->board_p->ai.sh_count) { | |
3572 | + printk(KERN_ERR | |
3573 | + "ME4000:me4000_ai_config():Sample and Hold is not available for this board\n"); | |
3574 | + err = -ENODEV; | |
3575 | + goto AI_CONFIG_ERR; | |
3576 | + } | |
3577 | + } | |
3578 | + | |
3579 | + /* Check the channel list size */ | |
3580 | + if (cmd.channel_list.count > ME4000_AI_CHANNEL_LIST_COUNT) { | |
3581 | + printk(KERN_ERR | |
3582 | + "me4000_ai_config():Channel list is to large\n"); | |
3583 | + err = -EINVAL; | |
3584 | + goto AI_CONFIG_ERR; | |
3585 | + } | |
3586 | + | |
3587 | + /* Copy channel list from user */ | |
3588 | + list = kmalloc(sizeof(u32) * cmd.channel_list.count, GFP_KERNEL); | |
3589 | + if (!list) { | |
3590 | + printk(KERN_ERR | |
3591 | + "ME4000:me4000_ai_config():Can't get memory for channel list\n"); | |
3592 | + err = -ENOMEM; | |
3593 | + goto AI_CONFIG_ERR; | |
3594 | + } | |
3595 | + err = | |
3596 | + copy_from_user(list, cmd.channel_list.list, | |
3597 | + sizeof(u32) * cmd.channel_list.count); | |
3598 | + if (err) { | |
3599 | + printk(KERN_ERR | |
3600 | + "ME4000:me4000_ai_config():Can't copy from user space\n"); | |
3601 | + err = -EFAULT; | |
3602 | + goto AI_CONFIG_ERR; | |
3603 | + } | |
3604 | + | |
3605 | + /* Check if last entry bit is set */ | |
3606 | + if (!(list[cmd.channel_list.count - 1] & ME4000_AI_LIST_LAST_ENTRY)) { | |
3607 | + printk(KERN_WARNING | |
3608 | + "me4000_ai_config():Last entry bit is not set\n"); | |
3609 | + list[cmd.channel_list.count - 1] |= ME4000_AI_LIST_LAST_ENTRY; | |
3610 | + } | |
3611 | + | |
3612 | + /* Check whether mode is equal for all entries */ | |
3613 | + mode = list[0] & 0x20; | |
3614 | + for (i = 0; i < cmd.channel_list.count; i++) { | |
3615 | + if ((list[i] & 0x20) != mode) { | |
3616 | + printk(KERN_ERR | |
3617 | + "ME4000:me4000_ai_config():Mode is not equal for all entries\n"); | |
3618 | + err = -EINVAL; | |
3619 | + goto AI_CONFIG_ERR; | |
3620 | + } | |
3621 | + } | |
3622 | + | |
3623 | + /* Check whether channels are available for this mode */ | |
3624 | + if (mode == ME4000_AI_LIST_INPUT_SINGLE_ENDED) { | |
3625 | + for (i = 0; i < cmd.channel_list.count; i++) { | |
3626 | + if ((list[i] & 0x1F) >= | |
3627 | + ai_context->board_info->board_p->ai.count) { | |
3628 | + printk(KERN_ERR | |
3629 | + "ME4000:me4000_ai_config():Channel is not available for single ended\n"); | |
3630 | + err = -EINVAL; | |
3631 | + goto AI_CONFIG_ERR; | |
3632 | + } | |
3633 | + } | |
3634 | + } else if (mode == ME4000_AI_LIST_INPUT_DIFFERENTIAL) { | |
3635 | + for (i = 0; i < cmd.channel_list.count; i++) { | |
3636 | + if ((list[i] & 0x1F) >= | |
3637 | + ai_context->board_info->board_p->ai.diff_count) { | |
3638 | + printk(KERN_ERR | |
3639 | + "ME4000:me4000_ai_config():Channel is not available for differential\n"); | |
3640 | + err = -EINVAL; | |
3641 | + goto AI_CONFIG_ERR; | |
3642 | + } | |
3643 | + } | |
3644 | + } | |
3645 | + | |
3646 | + /* Check if bipolar is set for all entries when in differential mode */ | |
3647 | + if (mode == ME4000_AI_LIST_INPUT_DIFFERENTIAL) { | |
3648 | + for (i = 0; i < cmd.channel_list.count; i++) { | |
3649 | + if ((list[i] & 0xC0) != ME4000_AI_LIST_RANGE_BIPOLAR_10 | |
3650 | + && (list[i] & 0xC0) != | |
3651 | + ME4000_AI_LIST_RANGE_BIPOLAR_2_5) { | |
3652 | + printk(KERN_ERR | |
3653 | + "ME4000:me4000_ai_config():Bipolar is not selected in differential mode\n"); | |
3654 | + err = -EINVAL; | |
3655 | + goto AI_CONFIG_ERR; | |
3656 | + } | |
3657 | + } | |
3658 | + } | |
3659 | + | |
3660 | + if (ai_context->mode != ME4000_AI_ACQ_MODE_EXT_SINGLE_VALUE) { | |
3661 | + /* Check for minimum channel divisor */ | |
3662 | + if (cmd.timer.chan < ME4000_AI_MIN_TICKS) { | |
3663 | + printk(KERN_ERR | |
3664 | + "ME4000:me4000_ai_config():Channel timer divisor is to low\n"); | |
3665 | + err = -EINVAL; | |
3666 | + goto AI_CONFIG_ERR; | |
3667 | + } | |
3668 | + | |
3669 | + /* Check if minimum channel divisor is adjusted when sample and hold is activated */ | |
3670 | + if ((cmd.sh) && (cmd.timer.chan != ME4000_AI_MIN_TICKS)) { | |
3671 | + printk(KERN_ERR | |
3672 | + "ME4000:me4000_ai_config():Channel timer divisor must be at minimum when sample and hold is activated\n"); | |
3673 | + err = -EINVAL; | |
3674 | + goto AI_CONFIG_ERR; | |
3675 | + } | |
3676 | + | |
3677 | + /* Check for minimum channel pre divisor */ | |
3678 | + if (cmd.timer.pre_chan < ME4000_AI_MIN_TICKS) { | |
3679 | + printk(KERN_ERR | |
3680 | + "ME4000:me4000_ai_config():Channel pre timer divisor is to low\n"); | |
3681 | + err = -EINVAL; | |
3682 | + goto AI_CONFIG_ERR; | |
3683 | + } | |
3684 | + | |
3685 | + /* Write the channel timers */ | |
3686 | + me4000_outl(cmd.timer.chan - 1, ai_context->chan_timer_reg); | |
3687 | + me4000_outl(cmd.timer.pre_chan - 1, | |
3688 | + ai_context->chan_pre_timer_reg); | |
3689 | + | |
3690 | + /* Save the timer values in the board context */ | |
3691 | + ai_context->chan_timer = cmd.timer.chan; | |
3692 | + ai_context->chan_pre_timer = cmd.timer.pre_chan; | |
3693 | + | |
3694 | + if (ai_context->mode != ME4000_AI_ACQ_MODE_EXT_SINGLE_CHANLIST) { | |
3695 | + /* Check for scan timer divisor */ | |
3696 | + scan = | |
3697 | + (u64) cmd.timer.scan_low | ((u64) cmd.timer. | |
3698 | + scan_high << 32); | |
3699 | + if (scan != 0) { | |
3700 | + if (scan < | |
3701 | + cmd.channel_list.count * cmd.timer.chan + | |
3702 | + 1) { | |
3703 | + printk(KERN_ERR | |
3704 | + "ME4000:me4000_ai_config():Scan timer divisor is to low\n"); | |
3705 | + err = -EINVAL; | |
3706 | + goto AI_CONFIG_ERR; | |
3707 | + } | |
3708 | + } | |
3709 | + | |
3710 | + /* Write the scan timers */ | |
3711 | + if (scan != 0) { | |
3712 | + scan--; | |
3713 | + tmp = (u32) (scan & 0xFFFFFFFF); | |
3714 | + me4000_outl(tmp, | |
3715 | + ai_context->scan_timer_low_reg); | |
3716 | + tmp = (u32) ((scan >> 32) & 0xFFFFFFFF); | |
3717 | + me4000_outl(tmp, | |
3718 | + ai_context->scan_timer_high_reg); | |
3719 | + | |
3720 | + scan = | |
3721 | + scan - (cmd.timer.chan - 1) + | |
3722 | + (cmd.timer.pre_chan - 1); | |
3723 | + tmp = (u32) (scan & 0xFFFFFFFF); | |
3724 | + me4000_outl(tmp, | |
3725 | + ai_context->scan_pre_timer_low_reg); | |
3726 | + tmp = (u32) ((scan >> 32) & 0xFFFFFFFF); | |
3727 | + me4000_outl(tmp, | |
3728 | + ai_context-> | |
3729 | + scan_pre_timer_high_reg); | |
3730 | + } else { | |
3731 | + me4000_outl(0x0, | |
3732 | + ai_context->scan_timer_low_reg); | |
3733 | + me4000_outl(0x0, | |
3734 | + ai_context->scan_timer_high_reg); | |
3735 | + | |
3736 | + me4000_outl(0x0, | |
3737 | + ai_context->scan_pre_timer_low_reg); | |
3738 | + me4000_outl(0x0, | |
3739 | + ai_context-> | |
3740 | + scan_pre_timer_high_reg); | |
3741 | + } | |
3742 | + | |
3743 | + ai_context->scan_timer_low = cmd.timer.scan_low; | |
3744 | + ai_context->scan_timer_high = cmd.timer.scan_high; | |
3745 | + } | |
3746 | + } | |
3747 | + | |
3748 | + /* Clear the channel list */ | |
3749 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
3750 | + tmp &= ~ME4000_AI_CTRL_BIT_CHANNEL_FIFO; | |
3751 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3752 | + tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO; | |
3753 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3754 | + | |
3755 | + /* Write the channel list */ | |
3756 | + for (i = 0; i < cmd.channel_list.count; i++) { | |
3757 | + me4000_outl(list[i], ai_context->channel_list_reg); | |
3758 | + } | |
3759 | + | |
3760 | + /* Setup sample and hold */ | |
3761 | + if (cmd.sh) { | |
3762 | + tmp |= ME4000_AI_CTRL_BIT_SAMPLE_HOLD; | |
3763 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3764 | + } else { | |
3765 | + tmp &= ~ME4000_AI_CTRL_BIT_SAMPLE_HOLD; | |
3766 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3767 | + } | |
3768 | + | |
3769 | + /* Save the channel list size in the board context */ | |
3770 | + ai_context->channel_list_count = cmd.channel_list.count; | |
3771 | + | |
3772 | + kfree(list); | |
3773 | + | |
3774 | + return 0; | |
3775 | + | |
3776 | + AI_CONFIG_ERR: | |
3777 | + | |
3778 | + /* Reset the timers */ | |
3779 | + ai_context->chan_timer = 66; | |
3780 | + ai_context->chan_pre_timer = 66; | |
3781 | + ai_context->scan_timer_low = 0; | |
3782 | + ai_context->scan_timer_high = 0; | |
3783 | + | |
3784 | + me4000_outl(65, ai_context->chan_timer_reg); | |
3785 | + me4000_outl(65, ai_context->chan_pre_timer_reg); | |
3786 | + me4000_outl(0, ai_context->scan_timer_high_reg); | |
3787 | + me4000_outl(0, ai_context->scan_timer_low_reg); | |
3788 | + me4000_outl(0, ai_context->scan_pre_timer_high_reg); | |
3789 | + me4000_outl(0, ai_context->scan_pre_timer_low_reg); | |
3790 | + | |
3791 | + ai_context->channel_list_count = 0; | |
3792 | + | |
3793 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
3794 | + tmp &= | |
3795 | + ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_SAMPLE_HOLD); | |
3796 | + | |
3797 | + if (list) | |
3798 | + kfree(list); | |
3799 | + | |
3800 | + return err; | |
3801 | + | |
3802 | +} | |
3803 | + | |
3804 | +static int ai_common_start(me4000_ai_context_t * ai_context) | |
3805 | +{ | |
3806 | + u32 tmp; | |
3807 | + CALL_PDEBUG("ai_common_start() is executed\n"); | |
3808 | + | |
3809 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
3810 | + | |
3811 | + /* Check if conversion is stopped */ | |
3812 | + if (tmp & ME4000_AI_STATUS_BIT_FSM) { | |
3813 | + printk(KERN_ERR | |
3814 | + "ME4000:ai_common_start():Conversion is not stopped\n"); | |
3815 | + return -EBUSY; | |
3816 | + } | |
3817 | + | |
3818 | + /* Clear data fifo, disable all interrupts, clear sample counter reload */ | |
3819 | + tmp &= ~(ME4000_AI_CTRL_BIT_DATA_FIFO | ME4000_AI_CTRL_BIT_LE_IRQ | | |
3820 | + ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ | | |
3821 | + ME4000_AI_CTRL_BIT_SC_RELOAD); | |
3822 | + | |
3823 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3824 | + | |
3825 | + /* Clear circular buffer */ | |
3826 | + ai_context->circ_buf.head = 0; | |
3827 | + ai_context->circ_buf.tail = 0; | |
3828 | + | |
3829 | + /* Enable data fifo */ | |
3830 | + tmp |= ME4000_AI_CTRL_BIT_DATA_FIFO; | |
3831 | + | |
3832 | + /* Determine interrupt setup */ | |
3833 | + if (ai_context->sample_counter && !ai_context->sample_counter_reload) { | |
3834 | + /* Enable Half Full Interrupt and Sample Counter Interrupt */ | |
3835 | + tmp |= ME4000_AI_CTRL_BIT_SC_IRQ | ME4000_AI_CTRL_BIT_HF_IRQ; | |
3836 | + } else if (ai_context->sample_counter | |
3837 | + && ai_context->sample_counter_reload) { | |
3838 | + if (ai_context->sample_counter <= ME4000_AI_FIFO_COUNT / 2) { | |
3839 | + /* Enable only Sample Counter Interrupt */ | |
3840 | + tmp |= | |
3841 | + ME4000_AI_CTRL_BIT_SC_IRQ | | |
3842 | + ME4000_AI_CTRL_BIT_SC_RELOAD; | |
3843 | + } else { | |
3844 | + /* Enable Half Full Interrupt and Sample Counter Interrupt */ | |
3845 | + tmp |= | |
3846 | + ME4000_AI_CTRL_BIT_SC_IRQ | | |
3847 | + ME4000_AI_CTRL_BIT_HF_IRQ | | |
3848 | + ME4000_AI_CTRL_BIT_SC_RELOAD; | |
3849 | + } | |
3850 | + } else { | |
3851 | + /* Enable only Half Full Interrupt */ | |
3852 | + tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; | |
3853 | + } | |
3854 | + | |
3855 | + /* Clear the stop bits */ | |
3856 | + tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); | |
3857 | + | |
3858 | + /* Write setup to hardware */ | |
3859 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3860 | + | |
3861 | + /* Write sample counter */ | |
3862 | + me4000_outl(ai_context->sample_counter, ai_context->sample_counter_reg); | |
3863 | + | |
3864 | + return 0; | |
3865 | +} | |
3866 | + | |
3867 | +static int me4000_ai_start(me4000_ai_context_t * ai_context) | |
3868 | +{ | |
3869 | + int err; | |
3870 | + CALL_PDEBUG("me4000_ai_start() is executed\n"); | |
3871 | + | |
3872 | + /* Prepare Hardware */ | |
3873 | + err = ai_common_start(ai_context); | |
3874 | + if (err) | |
3875 | + return err; | |
3876 | + | |
3877 | + /* Start conversion by dummy read */ | |
3878 | + me4000_inl(ai_context->start_reg); | |
3879 | + | |
3880 | + return 0; | |
3881 | +} | |
3882 | + | |
3883 | +static int me4000_ai_start_ex(unsigned long *arg, | |
3884 | + me4000_ai_context_t * ai_context) | |
3885 | +{ | |
3886 | + int err; | |
3887 | + wait_queue_head_t queue; | |
3888 | + unsigned long ref; | |
3889 | + unsigned long timeout; | |
3890 | + | |
3891 | + CALL_PDEBUG("me4000_ai_start_ex() is executed\n"); | |
3892 | + | |
3893 | + if (get_user(timeout, arg)) { | |
3894 | + printk(KERN_ERR | |
3895 | + "me4000_ai_start_ex():Cannot copy data from user\n"); | |
3896 | + return -EFAULT; | |
3897 | + } | |
3898 | + | |
3899 | + init_waitqueue_head(&queue); | |
3900 | + | |
3901 | + /* Prepare Hardware */ | |
3902 | + err = ai_common_start(ai_context); | |
3903 | + if (err) | |
3904 | + return err; | |
3905 | + | |
3906 | + if (timeout) { | |
3907 | + ref = jiffies; | |
3908 | + while (! | |
3909 | + (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM)) | |
3910 | + { | |
3911 | + interruptible_sleep_on_timeout(&queue, 1); | |
3912 | + if (signal_pending(current)) { | |
3913 | + printk(KERN_ERR | |
3914 | + "ME4000:me4000_ai_start_ex():Wait on start of state machine interrupted\n"); | |
3915 | + return -EINTR; | |
3916 | + } | |
3917 | + if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space | |
3918 | + printk(KERN_ERR | |
3919 | + "ME4000:me4000_ai_start_ex():Timeout reached\n"); | |
3920 | + return -EIO; | |
3921 | + } | |
3922 | + } | |
3923 | + } else { | |
3924 | + while (! | |
3925 | + (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM)) | |
3926 | + { | |
3927 | + interruptible_sleep_on_timeout(&queue, 1); | |
3928 | + if (signal_pending(current)) { | |
3929 | + printk(KERN_ERR | |
3930 | + "ME4000:me4000_ai_start_ex():Wait on start of state machine interrupted\n"); | |
3931 | + return -EINTR; | |
3932 | + } | |
3933 | + } | |
3934 | + } | |
3935 | + | |
3936 | + return 0; | |
3937 | +} | |
3938 | + | |
3939 | +static int me4000_ai_stop(me4000_ai_context_t * ai_context) | |
3940 | +{ | |
3941 | + wait_queue_head_t queue; | |
3942 | + u32 tmp; | |
3943 | + unsigned long flags; | |
3944 | + | |
3945 | + CALL_PDEBUG("me4000_ai_stop() is executed\n"); | |
3946 | + | |
3947 | + init_waitqueue_head(&queue); | |
3948 | + | |
3949 | + /* Disable irqs and clear data fifo */ | |
3950 | + spin_lock_irqsave(&ai_context->int_lock, flags); | |
3951 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
3952 | + tmp &= | |
3953 | + ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ | | |
3954 | + ME4000_AI_CTRL_BIT_DATA_FIFO); | |
3955 | + /* Stop conversion of the state machine */ | |
3956 | + tmp |= ME4000_AI_CTRL_BIT_STOP; | |
3957 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3958 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
3959 | + | |
3960 | + /* Clear circular buffer */ | |
3961 | + ai_context->circ_buf.head = 0; | |
3962 | + ai_context->circ_buf.tail = 0; | |
3963 | + | |
3964 | + while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) { | |
3965 | + interruptible_sleep_on_timeout(&queue, 1); | |
3966 | + if (signal_pending(current)) { | |
3967 | + printk(KERN_ERR | |
3968 | + "ME4000:me4000_ai_stop():Wait on state machine after stop interrupted\n"); | |
3969 | + return -EINTR; | |
3970 | + } | |
3971 | + } | |
3972 | + | |
3973 | + return 0; | |
3974 | +} | |
3975 | + | |
3976 | +static int me4000_ai_immediate_stop(me4000_ai_context_t * ai_context) | |
3977 | +{ | |
3978 | + wait_queue_head_t queue; | |
3979 | + u32 tmp; | |
3980 | + unsigned long flags; | |
3981 | + | |
3982 | + CALL_PDEBUG("me4000_ai_stop() is executed\n"); | |
3983 | + | |
3984 | + init_waitqueue_head(&queue); | |
3985 | + | |
3986 | + /* Disable irqs and clear data fifo */ | |
3987 | + spin_lock_irqsave(&ai_context->int_lock, flags); | |
3988 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
3989 | + tmp &= | |
3990 | + ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ | | |
3991 | + ME4000_AI_CTRL_BIT_DATA_FIFO); | |
3992 | + /* Stop conversion of the state machine */ | |
3993 | + tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | |
3994 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
3995 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
3996 | + | |
3997 | + /* Clear circular buffer */ | |
3998 | + ai_context->circ_buf.head = 0; | |
3999 | + ai_context->circ_buf.tail = 0; | |
4000 | + | |
4001 | + while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) { | |
4002 | + interruptible_sleep_on_timeout(&queue, 1); | |
4003 | + if (signal_pending(current)) { | |
4004 | + printk(KERN_ERR | |
4005 | + "ME4000:me4000_ai_stop():Wait on state machine after stop interrupted\n"); | |
4006 | + return -EINTR; | |
4007 | + } | |
4008 | + } | |
4009 | + | |
4010 | + return 0; | |
4011 | +} | |
4012 | + | |
4013 | +static int me4000_ai_ex_trig_enable(me4000_ai_context_t * ai_context) | |
4014 | +{ | |
4015 | + u32 tmp; | |
4016 | + unsigned long flags; | |
4017 | + | |
4018 | + CALL_PDEBUG("me4000_ai_ex_trig_enable() is executed\n"); | |
4019 | + | |
4020 | + spin_lock_irqsave(&ai_context->int_lock, flags); | |
4021 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
4022 | + tmp |= ME4000_AI_CTRL_BIT_EX_TRIG; | |
4023 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
4024 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
4025 | + | |
4026 | + return 0; | |
4027 | +} | |
4028 | + | |
4029 | +static int me4000_ai_ex_trig_disable(me4000_ai_context_t * ai_context) | |
4030 | +{ | |
4031 | + u32 tmp; | |
4032 | + unsigned long flags; | |
4033 | + | |
4034 | + CALL_PDEBUG("me4000_ai_ex_trig_disable() is executed\n"); | |
4035 | + | |
4036 | + spin_lock_irqsave(&ai_context->int_lock, flags); | |
4037 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
4038 | + tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG; | |
4039 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
4040 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
4041 | + | |
4042 | + return 0; | |
4043 | +} | |
4044 | + | |
4045 | +static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t * arg, | |
4046 | + me4000_ai_context_t * ai_context) | |
4047 | +{ | |
4048 | + me4000_ai_trigger_t cmd; | |
4049 | + int err; | |
4050 | + u32 tmp; | |
4051 | + unsigned long flags; | |
4052 | + | |
4053 | + CALL_PDEBUG("me4000_ai_ex_trig_setup() is executed\n"); | |
4054 | + | |
4055 | + /* Copy data from user */ | |
4056 | + err = copy_from_user(&cmd, arg, sizeof(me4000_ai_trigger_t)); | |
4057 | + if (err) { | |
4058 | + printk(KERN_ERR | |
4059 | + "ME4000:me4000_ai_ex_trig_setup():Can't copy from user space\n"); | |
4060 | + return -EFAULT; | |
4061 | + } | |
4062 | + | |
4063 | + spin_lock_irqsave(&ai_context->int_lock, flags); | |
4064 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
4065 | + | |
4066 | + if (cmd.mode == ME4000_AI_TRIGGER_EXT_DIGITAL) { | |
4067 | + tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG; | |
4068 | + } else if (cmd.mode == ME4000_AI_TRIGGER_EXT_ANALOG) { | |
4069 | + if (!ai_context->board_info->board_p->ai.ex_trig_analog) { | |
4070 | + printk(KERN_ERR | |
4071 | + "ME4000:me4000_ai_ex_trig_setup():No analog trigger available\n"); | |
4072 | + return -EINVAL; | |
4073 | + } | |
4074 | + tmp |= ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG; | |
4075 | + } else { | |
4076 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
4077 | + printk(KERN_ERR | |
4078 | + "ME4000:me4000_ai_ex_trig_setup():Invalid trigger mode specified\n"); | |
4079 | + return -EINVAL; | |
4080 | + } | |
4081 | + | |
4082 | + if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_RISING) { | |
4083 | + tmp &= | |
4084 | + ~(ME4000_AI_CTRL_BIT_EX_TRIG_BOTH | | |
4085 | + ME4000_AI_CTRL_BIT_EX_TRIG_FALLING); | |
4086 | + } else if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_FALLING) { | |
4087 | + tmp |= ME4000_AI_CTRL_BIT_EX_TRIG_FALLING; | |
4088 | + tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG_BOTH; | |
4089 | + } else if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_BOTH) { | |
4090 | + tmp |= | |
4091 | + ME4000_AI_CTRL_BIT_EX_TRIG_BOTH | | |
4092 | + ME4000_AI_CTRL_BIT_EX_TRIG_FALLING; | |
4093 | + } else { | |
4094 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
4095 | + printk(KERN_ERR | |
4096 | + "ME4000:me4000_ai_ex_trig_setup():Invalid trigger edge specified\n"); | |
4097 | + return -EINVAL; | |
4098 | + } | |
4099 | + | |
4100 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
4101 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
4102 | + return 0; | |
4103 | +} | |
4104 | + | |
4105 | +static int me4000_ai_sc_setup(me4000_ai_sc_t * arg, | |
4106 | + me4000_ai_context_t * ai_context) | |
4107 | +{ | |
4108 | + me4000_ai_sc_t cmd; | |
4109 | + int err; | |
4110 | + | |
4111 | + CALL_PDEBUG("me4000_ai_sc_setup() is executed\n"); | |
4112 | + | |
4113 | + /* Copy data from user */ | |
4114 | + err = copy_from_user(&cmd, arg, sizeof(me4000_ai_sc_t)); | |
4115 | + if (err) { | |
4116 | + printk(KERN_ERR | |
4117 | + "ME4000:me4000_ai_sc_setup():Can't copy from user space\n"); | |
4118 | + return -EFAULT; | |
4119 | + } | |
4120 | + | |
4121 | + ai_context->sample_counter = cmd.value; | |
4122 | + ai_context->sample_counter_reload = cmd.reload; | |
4123 | + | |
4124 | + return 0; | |
4125 | +} | |
4126 | + | |
4127 | +static ssize_t me4000_ai_read(struct file *filep, char *buff, size_t cnt, | |
4128 | + loff_t * offp) | |
4129 | +{ | |
4130 | + me4000_ai_context_t *ai_context = filep->private_data; | |
4131 | + s16 *buffer = (s16 *) buff; | |
4132 | + size_t count = cnt / 2; | |
4133 | + unsigned long flags; | |
4134 | + int tmp; | |
4135 | + int c = 0; | |
4136 | + int k = 0; | |
4137 | + int ret = 0; | |
4138 | + wait_queue_t wait; | |
4139 | + | |
4140 | + CALL_PDEBUG("me4000_ai_read() is executed\n"); | |
4141 | + | |
4142 | + init_waitqueue_entry(&wait, current); | |
4143 | + | |
4144 | + /* Check count */ | |
4145 | + if (count <= 0) { | |
4146 | + PDEBUG("me4000_ai_read():Count is 0\n"); | |
4147 | + return 0; | |
4148 | + } | |
4149 | + | |
4150 | + while (count > 0) { | |
4151 | + if (filep->f_flags & O_NONBLOCK) { | |
4152 | + c = me4000_values_to_end(ai_context->circ_buf, | |
4153 | + ME4000_AI_BUFFER_COUNT); | |
4154 | + if (!c) { | |
4155 | + PDEBUG | |
4156 | + ("me4000_ai_read():Returning from nonblocking read\n"); | |
4157 | + break; | |
4158 | + } | |
4159 | + } else { | |
4160 | + /* Check if conversion is still running */ | |
4161 | + if (! | |
4162 | + (me4000_inl(ai_context->status_reg) & | |
4163 | + ME4000_AI_STATUS_BIT_FSM)) { | |
4164 | + printk(KERN_ERR | |
4165 | + "ME4000:me4000_ai_read():Conversion interrupted\n"); | |
4166 | + return -EPIPE; | |
4167 | + } | |
4168 | + | |
4169 | + wait_event_interruptible(ai_context->wait_queue, | |
4170 | + (me4000_values_to_end | |
4171 | + (ai_context->circ_buf, | |
4172 | + ME4000_AI_BUFFER_COUNT))); | |
4173 | + if (signal_pending(current)) { | |
4174 | + printk(KERN_ERR | |
4175 | + "ME4000:me4000_ai_read():Wait on values interrupted from signal\n"); | |
4176 | + return -EINTR; | |
4177 | + } | |
4178 | + } | |
4179 | + | |
4180 | + /* Only read count values or as much as available */ | |
4181 | + c = me4000_values_to_end(ai_context->circ_buf, | |
4182 | + ME4000_AI_BUFFER_COUNT); | |
4183 | + PDEBUG("me4000_ai_read():%d values to end\n", c); | |
4184 | + if (count < c) | |
4185 | + c = count; | |
4186 | + | |
4187 | + PDEBUG("me4000_ai_read():Copy %d values to user space\n", c); | |
4188 | + k = 2 * c; | |
4189 | + k -= copy_to_user(buffer, | |
4190 | + ai_context->circ_buf.buf + | |
4191 | + ai_context->circ_buf.tail, k); | |
4192 | + c = k / 2; | |
4193 | + if (!c) { | |
4194 | + printk(KERN_ERR | |
4195 | + "ME4000:me4000_ai_read():Cannot copy new values to user\n"); | |
4196 | + return -EFAULT; | |
4197 | + } | |
4198 | + | |
4199 | + ai_context->circ_buf.tail = | |
4200 | + (ai_context->circ_buf.tail + c) & (ME4000_AI_BUFFER_COUNT - | |
4201 | + 1); | |
4202 | + buffer += c; | |
4203 | + count -= c; | |
4204 | + ret += c; | |
4205 | + | |
4206 | + spin_lock_irqsave(&ai_context->int_lock, flags); | |
4207 | + if (me4000_buf_space | |
4208 | + (ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) { | |
4209 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
4210 | + | |
4211 | + /* Determine interrupt setup */ | |
4212 | + if (ai_context->sample_counter | |
4213 | + && !ai_context->sample_counter_reload) { | |
4214 | + /* Enable Half Full Interrupt and Sample Counter Interrupt */ | |
4215 | + tmp |= | |
4216 | + ME4000_AI_CTRL_BIT_SC_IRQ | | |
4217 | + ME4000_AI_CTRL_BIT_HF_IRQ; | |
4218 | + } else if (ai_context->sample_counter | |
4219 | + && ai_context->sample_counter_reload) { | |
4220 | + if (ai_context->sample_counter < | |
4221 | + ME4000_AI_FIFO_COUNT / 2) { | |
4222 | + /* Enable only Sample Counter Interrupt */ | |
4223 | + tmp |= ME4000_AI_CTRL_BIT_SC_IRQ; | |
4224 | + } else { | |
4225 | + /* Enable Half Full Interrupt and Sample Counter Interrupt */ | |
4226 | + tmp |= | |
4227 | + ME4000_AI_CTRL_BIT_SC_IRQ | | |
4228 | + ME4000_AI_CTRL_BIT_HF_IRQ; | |
4229 | + } | |
4230 | + } else { | |
4231 | + /* Enable only Half Full Interrupt */ | |
4232 | + tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; | |
4233 | + } | |
4234 | + | |
4235 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
4236 | + } | |
4237 | + spin_unlock_irqrestore(&ai_context->int_lock, flags); | |
4238 | + } | |
4239 | + | |
4240 | + /* Check if conversion is still running */ | |
4241 | + if (!(me4000_inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM)) { | |
4242 | + printk(KERN_ERR | |
4243 | + "ME4000:me4000_ai_read():Conversion not running after complete read\n"); | |
4244 | + return -EPIPE; | |
4245 | + } | |
4246 | + | |
4247 | + if (filep->f_flags & O_NONBLOCK) { | |
4248 | + return (k == 0) ? -EAGAIN : 2 * ret; | |
4249 | + } | |
4250 | + | |
4251 | + CALL_PDEBUG("me4000_ai_read() is leaved\n"); | |
4252 | + return ret * 2; | |
4253 | +} | |
4254 | + | |
4255 | +static unsigned int me4000_ai_poll(struct file *file_p, poll_table * wait) | |
4256 | +{ | |
4257 | + me4000_ai_context_t *ai_context; | |
4258 | + unsigned long mask = 0; | |
4259 | + | |
4260 | + CALL_PDEBUG("me4000_ai_poll() is executed\n"); | |
4261 | + | |
4262 | + ai_context = file_p->private_data; | |
4263 | + | |
4264 | + /* Register wait queue */ | |
4265 | + poll_wait(file_p, &ai_context->wait_queue, wait); | |
4266 | + | |
4267 | + /* Get available values */ | |
4268 | + if (me4000_values_to_end(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) | |
4269 | + mask |= POLLIN | POLLRDNORM; | |
4270 | + | |
4271 | + PDEBUG("me4000_ai_poll():Return mask %lX\n", mask); | |
4272 | + | |
4273 | + return mask; | |
4274 | +} | |
4275 | + | |
4276 | +static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context) | |
4277 | +{ | |
4278 | + unsigned long tmp; | |
4279 | + | |
4280 | + CALL_PDEBUG("me4000_ai_offset_enable() is executed\n"); | |
4281 | + | |
4282 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
4283 | + tmp |= ME4000_AI_CTRL_BIT_OFFSET; | |
4284 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
4285 | + | |
4286 | + return 0; | |
4287 | +} | |
4288 | + | |
4289 | +static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context) | |
4290 | +{ | |
4291 | + unsigned long tmp; | |
4292 | + | |
4293 | + CALL_PDEBUG("me4000_ai_offset_disable() is executed\n"); | |
4294 | + | |
4295 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
4296 | + tmp &= ~ME4000_AI_CTRL_BIT_OFFSET; | |
4297 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
4298 | + | |
4299 | + return 0; | |
4300 | +} | |
4301 | + | |
4302 | +static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context) | |
4303 | +{ | |
4304 | + unsigned long tmp; | |
4305 | + | |
4306 | + CALL_PDEBUG("me4000_ai_fullscale_enable() is executed\n"); | |
4307 | + | |
4308 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
4309 | + tmp |= ME4000_AI_CTRL_BIT_FULLSCALE; | |
4310 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
4311 | + | |
4312 | + return 0; | |
4313 | +} | |
4314 | + | |
4315 | +static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context) | |
4316 | +{ | |
4317 | + unsigned long tmp; | |
4318 | + | |
4319 | + CALL_PDEBUG("me4000_ai_fullscale_disable() is executed\n"); | |
4320 | + | |
4321 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
4322 | + tmp &= ~ME4000_AI_CTRL_BIT_FULLSCALE; | |
4323 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
4324 | + | |
4325 | + return 0; | |
4326 | +} | |
4327 | + | |
4328 | +static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context) | |
4329 | +{ | |
4330 | + unsigned long tmp; | |
4331 | + | |
4332 | + CALL_PDEBUG("me4000_ai_fsm_state() is executed\n"); | |
4333 | + | |
4334 | + tmp = | |
4335 | + (me4000_inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) ? 1 | |
4336 | + : 0; | |
4337 | + | |
4338 | + if (put_user(tmp, arg)) { | |
4339 | + printk(KERN_ERR "me4000_ai_fsm_state():Cannot copy to user\n"); | |
4340 | + return -EFAULT; | |
4341 | + } | |
4342 | + | |
4343 | + return 0; | |
4344 | +} | |
4345 | + | |
4346 | +static int me4000_ai_get_count_buffer(unsigned long *arg, | |
4347 | + me4000_ai_context_t * ai_context) | |
4348 | +{ | |
4349 | + unsigned long c; | |
4350 | + int err; | |
4351 | + | |
4352 | + c = me4000_buf_count(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT); | |
4353 | + | |
4354 | + err = copy_to_user(arg, &c, sizeof(unsigned long)); | |
4355 | + if (err) { | |
4356 | + printk(KERN_ERR | |
4357 | + "ME4000:me4000_ai_get_count_buffer():Can't copy to user space\n"); | |
4358 | + return -EFAULT; | |
4359 | + } | |
4360 | + | |
4361 | + return 0; | |
4362 | +} | |
4363 | + | |
4364 | +/*---------------------------------- EEPROM stuff ---------------------------*/ | |
4365 | + | |
4366 | +static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd, | |
4367 | + int length) | |
4368 | +{ | |
4369 | + int i; | |
4370 | + unsigned long value; | |
4371 | + | |
4372 | + CALL_PDEBUG("eeprom_write_cmd() is executed\n"); | |
4373 | + | |
4374 | + PDEBUG("eeprom_write_cmd():Write command 0x%08lX with length = %d\n", | |
4375 | + cmd, length); | |
4376 | + | |
4377 | + /* Get the ICR register and clear the related bits */ | |
4378 | + value = me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR); | |
4379 | + value &= ~(PLX_ICR_MASK_EEPROM); | |
4380 | + me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); | |
4381 | + | |
4382 | + /* Raise the chip select */ | |
4383 | + value |= PLX_ICR_BIT_EEPROM_CHIP_SELECT; | |
4384 | + me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); | |
4385 | + udelay(EEPROM_DELAY); | |
4386 | + | |
4387 | + for (i = 0; i < length; i++) { | |
4388 | + if (cmd & ((0x1 << (length - 1)) >> i)) { | |
4389 | + value |= PLX_ICR_BIT_EEPROM_WRITE; | |
4390 | + } else { | |
4391 | + value &= ~PLX_ICR_BIT_EEPROM_WRITE; | |
4392 | + } | |
4393 | + | |
4394 | + /* Write to EEPROM */ | |
4395 | + me4000_outl(value, | |
4396 | + ai_context->board_info->plx_regbase + PLX_ICR); | |
4397 | + udelay(EEPROM_DELAY); | |
4398 | + | |
4399 | + /* Raising edge of the clock */ | |
4400 | + value |= PLX_ICR_BIT_EEPROM_CLOCK_SET; | |
4401 | + me4000_outl(value, | |
4402 | + ai_context->board_info->plx_regbase + PLX_ICR); | |
4403 | + udelay(EEPROM_DELAY); | |
4404 | + | |
4405 | + /* Falling edge of the clock */ | |
4406 | + value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET; | |
4407 | + me4000_outl(value, | |
4408 | + ai_context->board_info->plx_regbase + PLX_ICR); | |
4409 | + udelay(EEPROM_DELAY); | |
4410 | + } | |
4411 | + | |
4412 | + /* Clear the chip select */ | |
4413 | + value &= ~PLX_ICR_BIT_EEPROM_CHIP_SELECT; | |
4414 | + me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); | |
4415 | + udelay(EEPROM_DELAY); | |
4416 | + | |
4417 | + /* Wait until hardware is ready for sure */ | |
4418 | + mdelay(10); | |
4419 | + | |
4420 | + return 0; | |
4421 | +} | |
4422 | + | |
4423 | +static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context, | |
4424 | + unsigned long cmd, int length) | |
4425 | +{ | |
4426 | + int i; | |
4427 | + unsigned long value; | |
4428 | + unsigned short id = 0; | |
4429 | + | |
4430 | + CALL_PDEBUG("eeprom_read_cmd() is executed\n"); | |
4431 | + | |
4432 | + PDEBUG("eeprom_read_cmd():Read command 0x%08lX with length = %d\n", cmd, | |
4433 | + length); | |
4434 | + | |
4435 | + /* Get the ICR register and clear the related bits */ | |
4436 | + value = me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR); | |
4437 | + value &= ~(PLX_ICR_MASK_EEPROM); | |
4438 | + | |
4439 | + me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); | |
4440 | + | |
4441 | + /* Raise the chip select */ | |
4442 | + value |= PLX_ICR_BIT_EEPROM_CHIP_SELECT; | |
4443 | + me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); | |
4444 | + udelay(EEPROM_DELAY); | |
4445 | + | |
4446 | + /* Write the read command to the eeprom */ | |
4447 | + for (i = 0; i < length; i++) { | |
4448 | + if (cmd & ((0x1 << (length - 1)) >> i)) { | |
4449 | + value |= PLX_ICR_BIT_EEPROM_WRITE; | |
4450 | + } else { | |
4451 | + value &= ~PLX_ICR_BIT_EEPROM_WRITE; | |
4452 | + } | |
4453 | + me4000_outl(value, | |
4454 | + ai_context->board_info->plx_regbase + PLX_ICR); | |
4455 | + udelay(EEPROM_DELAY); | |
4456 | + | |
4457 | + /* Raising edge of the clock */ | |
4458 | + value |= PLX_ICR_BIT_EEPROM_CLOCK_SET; | |
4459 | + me4000_outl(value, | |
4460 | + ai_context->board_info->plx_regbase + PLX_ICR); | |
4461 | + udelay(EEPROM_DELAY); | |
4462 | + | |
4463 | + /* Falling edge of the clock */ | |
4464 | + value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET; | |
4465 | + me4000_outl(value, | |
4466 | + ai_context->board_info->plx_regbase + PLX_ICR); | |
4467 | + udelay(EEPROM_DELAY); | |
4468 | + } | |
4469 | + | |
4470 | + /* Read the value from the eeprom */ | |
4471 | + for (i = 0; i < 16; i++) { | |
4472 | + /* Raising edge of the clock */ | |
4473 | + value |= PLX_ICR_BIT_EEPROM_CLOCK_SET; | |
4474 | + me4000_outl(value, | |
4475 | + ai_context->board_info->plx_regbase + PLX_ICR); | |
4476 | + udelay(EEPROM_DELAY); | |
4477 | + | |
4478 | + if (me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR) & | |
4479 | + PLX_ICR_BIT_EEPROM_READ) { | |
4480 | + id |= (0x8000 >> i); | |
4481 | + PDEBUG("eeprom_read_cmd():OR with 0x%04X\n", | |
4482 | + (0x8000 >> i)); | |
4483 | + } else { | |
4484 | + PDEBUG("eeprom_read_cmd():Dont't OR\n"); | |
4485 | + } | |
4486 | + | |
4487 | + /* Falling edge of the clock */ | |
4488 | + value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET; | |
4489 | + me4000_outl(value, | |
4490 | + ai_context->board_info->plx_regbase + PLX_ICR); | |
4491 | + udelay(EEPROM_DELAY); | |
4492 | + } | |
4493 | + | |
4494 | + /* Clear the chip select */ | |
4495 | + value &= ~PLX_ICR_BIT_EEPROM_CHIP_SELECT; | |
4496 | + me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); | |
4497 | + udelay(EEPROM_DELAY); | |
4498 | + | |
4499 | + return id; | |
4500 | +} | |
4501 | + | |
4502 | +static int me4000_eeprom_write(me4000_eeprom_t * arg, | |
4503 | + me4000_ai_context_t * ai_context) | |
4504 | +{ | |
4505 | + int err; | |
4506 | + me4000_eeprom_t setup; | |
4507 | + unsigned long cmd; | |
4508 | + unsigned long date_high; | |
4509 | + unsigned long date_low; | |
4510 | + | |
4511 | + CALL_PDEBUG("me4000_eeprom_write() is executed\n"); | |
4512 | + | |
4513 | + err = copy_from_user(&setup, arg, sizeof(setup)); | |
4514 | + if (err) { | |
4515 | + printk(KERN_ERR | |
4516 | + "ME4000:me4000_eeprom_write():Cannot copy from user\n"); | |
4517 | + return err; | |
4518 | + } | |
4519 | + | |
4520 | + /* Enable writing */ | |
4521 | + eeprom_write_cmd(ai_context, ME4000_EEPROM_CMD_WRITE_ENABLE, | |
4522 | + ME4000_EEPROM_CMD_LENGTH_WRITE_ENABLE); | |
4523 | + | |
4524 | + /* Command for date */ | |
4525 | + date_high = (setup.date & 0xFFFF0000) >> 16; | |
4526 | + date_low = (setup.date & 0x0000FFFF); | |
4527 | + | |
4528 | + cmd = | |
4529 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_DATE_HIGH << | |
4530 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4531 | + (unsigned | |
4532 | + long) | |
4533 | + date_high); | |
4534 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4535 | + if (err) | |
4536 | + return err; | |
4537 | + | |
4538 | + cmd = | |
4539 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_DATE_LOW << | |
4540 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4541 | + (unsigned | |
4542 | + long) | |
4543 | + date_low); | |
4544 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4545 | + if (err) | |
4546 | + return err; | |
4547 | + | |
4548 | + /* Command for unipolar 10V offset */ | |
4549 | + cmd = | |
4550 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET << | |
4551 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4552 | + (unsigned | |
4553 | + long) | |
4554 | + setup. | |
4555 | + uni_10_offset); | |
4556 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4557 | + if (err) | |
4558 | + return err; | |
4559 | + | |
4560 | + /* Command for unipolar 10V fullscale */ | |
4561 | + cmd = | |
4562 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE << | |
4563 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4564 | + (unsigned | |
4565 | + long) | |
4566 | + setup. | |
4567 | + uni_10_fullscale); | |
4568 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4569 | + if (err) | |
4570 | + return err; | |
4571 | + | |
4572 | + /* Command for unipolar 2,5V offset */ | |
4573 | + cmd = | |
4574 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET << | |
4575 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4576 | + (unsigned | |
4577 | + long) | |
4578 | + setup. | |
4579 | + uni_2_5_offset); | |
4580 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4581 | + if (err) | |
4582 | + return err; | |
4583 | + | |
4584 | + /* Command for unipolar 2,5V fullscale */ | |
4585 | + cmd = | |
4586 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE << | |
4587 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4588 | + (unsigned | |
4589 | + long) | |
4590 | + setup. | |
4591 | + uni_2_5_fullscale); | |
4592 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4593 | + if (err) | |
4594 | + return err; | |
4595 | + | |
4596 | + /* Command for bipolar 10V offset */ | |
4597 | + cmd = | |
4598 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET << | |
4599 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4600 | + (unsigned | |
4601 | + long) | |
4602 | + setup. | |
4603 | + bi_10_offset); | |
4604 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4605 | + if (err) | |
4606 | + return err; | |
4607 | + | |
4608 | + /* Command for bipolar 10V fullscale */ | |
4609 | + cmd = | |
4610 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE << | |
4611 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4612 | + (unsigned | |
4613 | + long) | |
4614 | + setup. | |
4615 | + bi_10_fullscale); | |
4616 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4617 | + if (err) | |
4618 | + return err; | |
4619 | + | |
4620 | + /* Command for bipolar 2,5V offset */ | |
4621 | + cmd = | |
4622 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET << | |
4623 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4624 | + (unsigned | |
4625 | + long) | |
4626 | + setup. | |
4627 | + bi_2_5_offset); | |
4628 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4629 | + if (err) | |
4630 | + return err; | |
4631 | + | |
4632 | + /* Command for bipolar 2,5V fullscale */ | |
4633 | + cmd = | |
4634 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE << | |
4635 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4636 | + (unsigned | |
4637 | + long) | |
4638 | + setup. | |
4639 | + bi_2_5_fullscale); | |
4640 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4641 | + if (err) | |
4642 | + return err; | |
4643 | + | |
4644 | + /* Command for differential 10V offset */ | |
4645 | + cmd = | |
4646 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET << | |
4647 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4648 | + (unsigned | |
4649 | + long) | |
4650 | + setup. | |
4651 | + diff_10_offset); | |
4652 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4653 | + if (err) | |
4654 | + return err; | |
4655 | + | |
4656 | + /* Command for differential 10V fullscale */ | |
4657 | + cmd = | |
4658 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE | |
4659 | + << ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4660 | + (unsigned | |
4661 | + long) | |
4662 | + setup. | |
4663 | + diff_10_fullscale); | |
4664 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4665 | + if (err) | |
4666 | + return err; | |
4667 | + | |
4668 | + /* Command for differential 2,5V offset */ | |
4669 | + cmd = | |
4670 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET << | |
4671 | + ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4672 | + (unsigned | |
4673 | + long) | |
4674 | + setup. | |
4675 | + diff_2_5_offset); | |
4676 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4677 | + if (err) | |
4678 | + return err; | |
4679 | + | |
4680 | + /* Command for differential 2,5V fullscale */ | |
4681 | + cmd = | |
4682 | + ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE | |
4683 | + << ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & | |
4684 | + (unsigned | |
4685 | + long) | |
4686 | + setup. | |
4687 | + diff_2_5_fullscale); | |
4688 | + err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); | |
4689 | + if (err) | |
4690 | + return err; | |
4691 | + | |
4692 | + /* Disable writing */ | |
4693 | + eeprom_write_cmd(ai_context, ME4000_EEPROM_CMD_WRITE_DISABLE, | |
4694 | + ME4000_EEPROM_CMD_LENGTH_WRITE_DISABLE); | |
4695 | + | |
4696 | + return 0; | |
4697 | +} | |
4698 | + | |
4699 | +static int me4000_eeprom_read(me4000_eeprom_t * arg, | |
4700 | + me4000_ai_context_t * ai_context) | |
4701 | +{ | |
4702 | + int err; | |
4703 | + unsigned long cmd; | |
4704 | + me4000_eeprom_t setup; | |
4705 | + | |
4706 | + CALL_PDEBUG("me4000_eeprom_read() is executed\n"); | |
4707 | + | |
4708 | + /* Command for date */ | |
4709 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_DATE_HIGH; | |
4710 | + setup.date = | |
4711 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4712 | + setup.date <<= 16; | |
4713 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_DATE_LOW; | |
4714 | + setup.date |= | |
4715 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4716 | + | |
4717 | + /* Command for unipolar 10V offset */ | |
4718 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET; | |
4719 | + setup.uni_10_offset = | |
4720 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4721 | + | |
4722 | + /* Command for unipolar 10V fullscale */ | |
4723 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE; | |
4724 | + setup.uni_10_fullscale = | |
4725 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4726 | + | |
4727 | + /* Command for unipolar 2,5V offset */ | |
4728 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET; | |
4729 | + setup.uni_2_5_offset = | |
4730 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4731 | + | |
4732 | + /* Command for unipolar 2,5V fullscale */ | |
4733 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE; | |
4734 | + setup.uni_2_5_fullscale = | |
4735 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4736 | + | |
4737 | + /* Command for bipolar 10V offset */ | |
4738 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET; | |
4739 | + setup.bi_10_offset = | |
4740 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4741 | + | |
4742 | + /* Command for bipolar 10V fullscale */ | |
4743 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE; | |
4744 | + setup.bi_10_fullscale = | |
4745 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4746 | + | |
4747 | + /* Command for bipolar 2,5V offset */ | |
4748 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET; | |
4749 | + setup.bi_2_5_offset = | |
4750 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4751 | + | |
4752 | + /* Command for bipolar 2,5V fullscale */ | |
4753 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE; | |
4754 | + setup.bi_2_5_fullscale = | |
4755 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4756 | + | |
4757 | + /* Command for differntial 10V offset */ | |
4758 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET; | |
4759 | + setup.diff_10_offset = | |
4760 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4761 | + | |
4762 | + /* Command for differential 10V fullscale */ | |
4763 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE; | |
4764 | + setup.diff_10_fullscale = | |
4765 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4766 | + | |
4767 | + /* Command for differntial 2,5V offset */ | |
4768 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET; | |
4769 | + setup.diff_2_5_offset = | |
4770 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4771 | + | |
4772 | + /* Command for differential 2,5V fullscale */ | |
4773 | + cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE; | |
4774 | + setup.diff_2_5_fullscale = | |
4775 | + eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); | |
4776 | + | |
4777 | + err = copy_to_user(arg, &setup, sizeof(setup)); | |
4778 | + if (err) { | |
4779 | + printk(KERN_ERR | |
4780 | + "ME4000:me4000_eeprom_read():Cannot copy to user\n"); | |
4781 | + return err; | |
4782 | + } | |
4783 | + | |
4784 | + return 0; | |
4785 | +} | |
4786 | + | |
4787 | +/*------------------------------------ DIO stuff ----------------------------------------------*/ | |
4788 | + | |
4789 | +static int me4000_dio_ioctl(struct inode *inode_p, struct file *file_p, | |
4790 | + unsigned int service, unsigned long arg) | |
4791 | +{ | |
4792 | + me4000_dio_context_t *dio_context; | |
4793 | + | |
4794 | + CALL_PDEBUG("me4000_dio_ioctl() is executed\n"); | |
4795 | + | |
4796 | + dio_context = file_p->private_data; | |
4797 | + | |
4798 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
4799 | + printk(KERN_ERR "me4000_dio_ioctl():Wrong magic number\n"); | |
4800 | + return -ENOTTY; | |
4801 | + } | |
4802 | + if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { | |
4803 | + printk(KERN_ERR "me4000_dio_ioctl():Service number to high\n"); | |
4804 | + return -ENOTTY; | |
4805 | + } | |
4806 | + | |
4807 | + switch (service) { | |
4808 | + case ME4000_DIO_CONFIG: | |
4809 | + return me4000_dio_config((me4000_dio_config_t *) arg, | |
4810 | + dio_context); | |
4811 | + case ME4000_DIO_SET_BYTE: | |
4812 | + return me4000_dio_set_byte((me4000_dio_byte_t *) arg, | |
4813 | + dio_context); | |
4814 | + case ME4000_DIO_GET_BYTE: | |
4815 | + return me4000_dio_get_byte((me4000_dio_byte_t *) arg, | |
4816 | + dio_context); | |
4817 | + case ME4000_DIO_RESET: | |
4818 | + return me4000_dio_reset(dio_context); | |
4819 | + default: | |
4820 | + printk(KERN_ERR | |
4821 | + "ME4000:me4000_dio_ioctl():Invalid service number %d\n", | |
4822 | + service); | |
4823 | + return -ENOTTY; | |
4824 | + } | |
4825 | + return 0; | |
4826 | +} | |
4827 | + | |
4828 | +static int me4000_dio_config(me4000_dio_config_t * arg, | |
4829 | + me4000_dio_context_t * dio_context) | |
4830 | +{ | |
4831 | + me4000_dio_config_t cmd; | |
4832 | + u32 tmp; | |
4833 | + int err; | |
4834 | + | |
4835 | + CALL_PDEBUG("me4000_dio_config() is executed\n"); | |
4836 | + | |
4837 | + /* Copy data from user */ | |
4838 | + err = copy_from_user(&cmd, arg, sizeof(me4000_dio_config_t)); | |
4839 | + if (err) { | |
4840 | + printk(KERN_ERR | |
4841 | + "ME4000:me4000_dio_config():Can't copy from user space\n"); | |
4842 | + return -EFAULT; | |
4843 | + } | |
4844 | + | |
4845 | + /* Check port parameter */ | |
4846 | + if (cmd.port >= dio_context->dio_count) { | |
4847 | + printk(KERN_ERR | |
4848 | + "ME4000:me4000_dio_config():Port %d is not available\n", | |
4849 | + cmd.port); | |
4850 | + return -EINVAL; | |
4851 | + } | |
4852 | + | |
4853 | + PDEBUG("me4000_dio_config(): port %d, mode %d, function %d\n", cmd.port, | |
4854 | + cmd.mode, cmd.function); | |
4855 | + | |
4856 | + if (cmd.port == ME4000_DIO_PORT_A) { | |
4857 | + if (cmd.mode == ME4000_DIO_PORT_INPUT) { | |
4858 | + /* Check if opto isolated version */ | |
4859 | + if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { | |
4860 | + printk(KERN_ERR | |
4861 | + "ME4000:me4000_dio_config():Cannot set to input on opto isolated versions\n"); | |
4862 | + return -EIO; | |
4863 | + } | |
4864 | + | |
4865 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4866 | + tmp &= | |
4867 | + ~(ME4000_DIO_CTRL_BIT_MODE_0 | | |
4868 | + ME4000_DIO_CTRL_BIT_MODE_1); | |
4869 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4870 | + } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) { | |
4871 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4872 | + tmp &= | |
4873 | + ~(ME4000_DIO_CTRL_BIT_MODE_0 | | |
4874 | + ME4000_DIO_CTRL_BIT_MODE_1); | |
4875 | + tmp |= ME4000_DIO_CTRL_BIT_MODE_0; | |
4876 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4877 | + } else if (cmd.mode == ME4000_DIO_FIFO_LOW) { | |
4878 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4879 | + tmp &= | |
4880 | + ~(ME4000_DIO_CTRL_BIT_MODE_0 | | |
4881 | + ME4000_DIO_CTRL_BIT_MODE_1 | | |
4882 | + ME4000_DIO_CTRL_BIT_FIFO_HIGH_0); | |
4883 | + tmp |= | |
4884 | + ME4000_DIO_CTRL_BIT_MODE_0 | | |
4885 | + ME4000_DIO_CTRL_BIT_MODE_1; | |
4886 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4887 | + } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) { | |
4888 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4889 | + tmp |= | |
4890 | + ME4000_DIO_CTRL_BIT_MODE_0 | | |
4891 | + ME4000_DIO_CTRL_BIT_MODE_1 | | |
4892 | + ME4000_DIO_CTRL_BIT_FIFO_HIGH_0; | |
4893 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4894 | + } else { | |
4895 | + printk(KERN_ERR | |
4896 | + "ME4000:me4000_dio_config():Mode %d is not available\n", | |
4897 | + cmd.mode); | |
4898 | + return -EINVAL; | |
4899 | + } | |
4900 | + } else if (cmd.port == ME4000_DIO_PORT_B) { | |
4901 | + if (cmd.mode == ME4000_DIO_PORT_INPUT) { | |
4902 | + /* Only do anything when TTL version is installed */ | |
4903 | + if ((me4000_inl(dio_context->dir_reg) & 0x1)) { | |
4904 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4905 | + tmp &= | |
4906 | + ~(ME4000_DIO_CTRL_BIT_MODE_2 | | |
4907 | + ME4000_DIO_CTRL_BIT_MODE_3); | |
4908 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4909 | + } | |
4910 | + } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) { | |
4911 | + /* Check if opto isolated version */ | |
4912 | + if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { | |
4913 | + printk(KERN_ERR | |
4914 | + "ME4000:me4000_dio_config():Cannot set to output on opto isolated versions\n"); | |
4915 | + return -EIO; | |
4916 | + } | |
4917 | + | |
4918 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4919 | + tmp &= | |
4920 | + ~(ME4000_DIO_CTRL_BIT_MODE_2 | | |
4921 | + ME4000_DIO_CTRL_BIT_MODE_3); | |
4922 | + tmp |= ME4000_DIO_CTRL_BIT_MODE_2; | |
4923 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4924 | + } else if (cmd.mode == ME4000_DIO_FIFO_LOW) { | |
4925 | + /* Check if opto isolated version */ | |
4926 | + if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { | |
4927 | + printk(KERN_ERR | |
4928 | + "ME4000:me4000_dio_config():Cannot set to FIFO low output on opto isolated versions\n"); | |
4929 | + return -EIO; | |
4930 | + } | |
4931 | + | |
4932 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4933 | + tmp &= | |
4934 | + ~(ME4000_DIO_CTRL_BIT_MODE_2 | | |
4935 | + ME4000_DIO_CTRL_BIT_MODE_3 | | |
4936 | + ME4000_DIO_CTRL_BIT_FIFO_HIGH_1); | |
4937 | + tmp |= | |
4938 | + ME4000_DIO_CTRL_BIT_MODE_2 | | |
4939 | + ME4000_DIO_CTRL_BIT_MODE_3; | |
4940 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4941 | + } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) { | |
4942 | + /* Check if opto isolated version */ | |
4943 | + if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { | |
4944 | + printk(KERN_ERR | |
4945 | + "ME4000:me4000_dio_config():Cannot set to FIFO high output on opto isolated versions\n"); | |
4946 | + return -EIO; | |
4947 | + } | |
4948 | + | |
4949 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4950 | + tmp |= | |
4951 | + ME4000_DIO_CTRL_BIT_MODE_2 | | |
4952 | + ME4000_DIO_CTRL_BIT_MODE_3 | | |
4953 | + ME4000_DIO_CTRL_BIT_FIFO_HIGH_1; | |
4954 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4955 | + } else { | |
4956 | + printk(KERN_ERR | |
4957 | + "ME4000:me4000_dio_config():Mode %d is not available\n", | |
4958 | + cmd.mode); | |
4959 | + return -EINVAL; | |
4960 | + } | |
4961 | + } else if (cmd.port == ME4000_DIO_PORT_C) { | |
4962 | + if (cmd.mode == ME4000_DIO_PORT_INPUT) { | |
4963 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4964 | + tmp &= | |
4965 | + ~(ME4000_DIO_CTRL_BIT_MODE_4 | | |
4966 | + ME4000_DIO_CTRL_BIT_MODE_5); | |
4967 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4968 | + } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) { | |
4969 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4970 | + tmp &= | |
4971 | + ~(ME4000_DIO_CTRL_BIT_MODE_4 | | |
4972 | + ME4000_DIO_CTRL_BIT_MODE_5); | |
4973 | + tmp |= ME4000_DIO_CTRL_BIT_MODE_4; | |
4974 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4975 | + } else if (cmd.mode == ME4000_DIO_FIFO_LOW) { | |
4976 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4977 | + tmp &= | |
4978 | + ~(ME4000_DIO_CTRL_BIT_MODE_4 | | |
4979 | + ME4000_DIO_CTRL_BIT_MODE_5 | | |
4980 | + ME4000_DIO_CTRL_BIT_FIFO_HIGH_2); | |
4981 | + tmp |= | |
4982 | + ME4000_DIO_CTRL_BIT_MODE_4 | | |
4983 | + ME4000_DIO_CTRL_BIT_MODE_5; | |
4984 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4985 | + } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) { | |
4986 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
4987 | + tmp |= | |
4988 | + ME4000_DIO_CTRL_BIT_MODE_4 | | |
4989 | + ME4000_DIO_CTRL_BIT_MODE_5 | | |
4990 | + ME4000_DIO_CTRL_BIT_FIFO_HIGH_2; | |
4991 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
4992 | + } else { | |
4993 | + printk(KERN_ERR | |
4994 | + "ME4000:me4000_dio_config():Mode %d is not available\n", | |
4995 | + cmd.mode); | |
4996 | + return -EINVAL; | |
4997 | + } | |
4998 | + } else if (cmd.port == ME4000_DIO_PORT_D) { | |
4999 | + if (cmd.mode == ME4000_DIO_PORT_INPUT) { | |
5000 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
5001 | + tmp &= | |
5002 | + ~(ME4000_DIO_CTRL_BIT_MODE_6 | | |
5003 | + ME4000_DIO_CTRL_BIT_MODE_7); | |
5004 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
5005 | + } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) { | |
5006 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
5007 | + tmp &= | |
5008 | + ~(ME4000_DIO_CTRL_BIT_MODE_6 | | |
5009 | + ME4000_DIO_CTRL_BIT_MODE_7); | |
5010 | + tmp |= ME4000_DIO_CTRL_BIT_MODE_6; | |
5011 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
5012 | + } else if (cmd.mode == ME4000_DIO_FIFO_LOW) { | |
5013 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
5014 | + tmp &= | |
5015 | + ~(ME4000_DIO_CTRL_BIT_MODE_6 | | |
5016 | + ME4000_DIO_CTRL_BIT_MODE_7 | | |
5017 | + ME4000_DIO_CTRL_BIT_FIFO_HIGH_3); | |
5018 | + tmp |= | |
5019 | + ME4000_DIO_CTRL_BIT_MODE_6 | | |
5020 | + ME4000_DIO_CTRL_BIT_MODE_7; | |
5021 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
5022 | + } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) { | |
5023 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
5024 | + tmp |= | |
5025 | + ME4000_DIO_CTRL_BIT_MODE_6 | | |
5026 | + ME4000_DIO_CTRL_BIT_MODE_7 | | |
5027 | + ME4000_DIO_CTRL_BIT_FIFO_HIGH_3; | |
5028 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
5029 | + } else { | |
5030 | + printk(KERN_ERR | |
5031 | + "ME4000:me4000_dio_config():Mode %d is not available\n", | |
5032 | + cmd.mode); | |
5033 | + return -EINVAL; | |
5034 | + } | |
5035 | + } else { | |
5036 | + printk(KERN_ERR | |
5037 | + "ME4000:me4000_dio_config():Port %d is not available\n", | |
5038 | + cmd.port); | |
5039 | + return -EINVAL; | |
5040 | + } | |
5041 | + | |
5042 | + PDEBUG("me4000_dio_config(): port %d, mode %d, function %d\n", cmd.port, | |
5043 | + cmd.mode, cmd.function); | |
5044 | + | |
5045 | + if ((cmd.mode == ME4000_DIO_FIFO_HIGH) | |
5046 | + || (cmd.mode == ME4000_DIO_FIFO_LOW)) { | |
5047 | + tmp = me4000_inl(dio_context->ctrl_reg); | |
5048 | + tmp &= | |
5049 | + ~(ME4000_DIO_CTRL_BIT_FUNCTION_0 | | |
5050 | + ME4000_DIO_CTRL_BIT_FUNCTION_1); | |
5051 | + if (cmd.function == ME4000_DIO_FUNCTION_PATTERN) { | |
5052 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
5053 | + } else if (cmd.function == ME4000_DIO_FUNCTION_DEMUX) { | |
5054 | + tmp |= ME4000_DIO_CTRL_BIT_FUNCTION_0; | |
5055 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
5056 | + } else if (cmd.function == ME4000_DIO_FUNCTION_MUX) { | |
5057 | + tmp |= ME4000_DIO_CTRL_BIT_FUNCTION_1; | |
5058 | + me4000_outl(tmp, dio_context->ctrl_reg); | |
5059 | + } else { | |
5060 | + printk(KERN_ERR | |
5061 | + "ME4000:me4000_dio_config():Invalid port function specified\n"); | |
5062 | + return -EINVAL; | |
5063 | + } | |
5064 | + } | |
5065 | + | |
5066 | + return 0; | |
5067 | +} | |
5068 | + | |
5069 | +static int me4000_dio_set_byte(me4000_dio_byte_t * arg, | |
5070 | + me4000_dio_context_t * dio_context) | |
5071 | +{ | |
5072 | + me4000_dio_byte_t cmd; | |
5073 | + int err; | |
5074 | + | |
5075 | + CALL_PDEBUG("me4000_dio_set_byte() is executed\n"); | |
5076 | + | |
5077 | + /* Copy data from user */ | |
5078 | + err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t)); | |
5079 | + if (err) { | |
5080 | + printk(KERN_ERR | |
5081 | + "ME4000:me4000_dio_set_byte():Can't copy from user space\n"); | |
5082 | + return -EFAULT; | |
5083 | + } | |
5084 | + | |
5085 | + /* Check port parameter */ | |
5086 | + if (cmd.port >= dio_context->dio_count) { | |
5087 | + printk(KERN_ERR | |
5088 | + "ME4000:me4000_dio_set_byte():Port %d is not available\n", | |
5089 | + cmd.port); | |
5090 | + return -EINVAL; | |
5091 | + } | |
5092 | + | |
5093 | + if (cmd.port == ME4000_DIO_PORT_A) { | |
5094 | + if ((me4000_inl(dio_context->ctrl_reg) & 0x3) != 0x1) { | |
5095 | + printk(KERN_ERR | |
5096 | + "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n", | |
5097 | + cmd.port); | |
5098 | + return -EIO; | |
5099 | + } | |
5100 | + me4000_outl(cmd.byte, dio_context->port_0_reg); | |
5101 | + } else if (cmd.port == ME4000_DIO_PORT_B) { | |
5102 | + if ((me4000_inl(dio_context->ctrl_reg) & 0xC) != 0x4) { | |
5103 | + printk(KERN_ERR | |
5104 | + "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n", | |
5105 | + cmd.port); | |
5106 | + return -EIO; | |
5107 | + } | |
5108 | + me4000_outl(cmd.byte, dio_context->port_1_reg); | |
5109 | + } else if (cmd.port == ME4000_DIO_PORT_C) { | |
5110 | + if ((me4000_inl(dio_context->ctrl_reg) & 0x30) != 0x10) { | |
5111 | + printk(KERN_ERR | |
5112 | + "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n", | |
5113 | + cmd.port); | |
5114 | + return -EIO; | |
5115 | + } | |
5116 | + me4000_outl(cmd.byte, dio_context->port_2_reg); | |
5117 | + } else if (cmd.port == ME4000_DIO_PORT_D) { | |
5118 | + if ((me4000_inl(dio_context->ctrl_reg) & 0xC0) != 0x40) { | |
5119 | + printk(KERN_ERR | |
5120 | + "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n", | |
5121 | + cmd.port); | |
5122 | + return -EIO; | |
5123 | + } | |
5124 | + me4000_outl(cmd.byte, dio_context->port_3_reg); | |
5125 | + } else { | |
5126 | + printk(KERN_ERR | |
5127 | + "ME4000:me4000_dio_set_byte():Port %d is not available\n", | |
5128 | + cmd.port); | |
5129 | + return -EINVAL; | |
5130 | + } | |
5131 | + | |
5132 | + return 0; | |
5133 | +} | |
5134 | + | |
5135 | +static int me4000_dio_get_byte(me4000_dio_byte_t * arg, | |
5136 | + me4000_dio_context_t * dio_context) | |
5137 | +{ | |
5138 | + me4000_dio_byte_t cmd; | |
5139 | + int err; | |
5140 | + | |
5141 | + CALL_PDEBUG("me4000_dio_get_byte() is executed\n"); | |
5142 | + | |
5143 | + /* Copy data from user */ | |
5144 | + err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t)); | |
5145 | + if (err) { | |
5146 | + printk(KERN_ERR | |
5147 | + "ME4000:me4000_dio_get_byte():Can't copy from user space\n"); | |
5148 | + return -EFAULT; | |
5149 | + } | |
5150 | + | |
5151 | + /* Check port parameter */ | |
5152 | + if (cmd.port >= dio_context->dio_count) { | |
5153 | + printk(KERN_ERR | |
5154 | + "ME4000:me4000_dio_get_byte():Port %d is not available\n", | |
5155 | + cmd.port); | |
5156 | + return -EINVAL; | |
5157 | + } | |
5158 | + | |
5159 | + if (cmd.port == ME4000_DIO_PORT_A) { | |
5160 | + cmd.byte = me4000_inl(dio_context->port_0_reg) & 0xFF; | |
5161 | + } else if (cmd.port == ME4000_DIO_PORT_B) { | |
5162 | + cmd.byte = me4000_inl(dio_context->port_1_reg) & 0xFF; | |
5163 | + } else if (cmd.port == ME4000_DIO_PORT_C) { | |
5164 | + cmd.byte = me4000_inl(dio_context->port_2_reg) & 0xFF; | |
5165 | + } else if (cmd.port == ME4000_DIO_PORT_D) { | |
5166 | + cmd.byte = me4000_inl(dio_context->port_3_reg) & 0xFF; | |
5167 | + } else { | |
5168 | + printk(KERN_ERR | |
5169 | + "ME4000:me4000_dio_get_byte():Port %d is not available\n", | |
5170 | + cmd.port); | |
5171 | + return -EINVAL; | |
5172 | + } | |
5173 | + | |
5174 | + /* Copy result back to user */ | |
5175 | + err = copy_to_user(arg, &cmd, sizeof(me4000_dio_byte_t)); | |
5176 | + if (err) { | |
5177 | + printk(KERN_ERR | |
5178 | + "ME4000:me4000_dio_get_byte():Can't copy to user space\n"); | |
5179 | + return -EFAULT; | |
5180 | + } | |
5181 | + | |
5182 | + return 0; | |
5183 | +} | |
5184 | + | |
5185 | +static int me4000_dio_reset(me4000_dio_context_t * dio_context) | |
5186 | +{ | |
5187 | + CALL_PDEBUG("me4000_dio_reset() is executed\n"); | |
5188 | + | |
5189 | + /* Clear the control register */ | |
5190 | + me4000_outl(0, dio_context->ctrl_reg); | |
5191 | + | |
5192 | + /* Check for opto isolated version */ | |
5193 | + if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { | |
5194 | + me4000_outl(0x1, dio_context->ctrl_reg); | |
5195 | + me4000_outl(0x0, dio_context->port_0_reg); | |
5196 | + } | |
5197 | + | |
5198 | + return 0; | |
5199 | +} | |
5200 | + | |
5201 | +/*------------------------------------ COUNTER STUFF ------------------------------------*/ | |
5202 | + | |
5203 | +static int me4000_cnt_ioctl(struct inode *inode_p, struct file *file_p, | |
5204 | + unsigned int service, unsigned long arg) | |
5205 | +{ | |
5206 | + me4000_cnt_context_t *cnt_context; | |
5207 | + | |
5208 | + CALL_PDEBUG("me4000_cnt_ioctl() is executed\n"); | |
5209 | + | |
5210 | + cnt_context = file_p->private_data; | |
5211 | + | |
5212 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
5213 | + printk(KERN_ERR "me4000_dio_ioctl():Wrong magic number\n"); | |
5214 | + return -ENOTTY; | |
5215 | + } | |
5216 | + if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { | |
5217 | + printk(KERN_ERR "me4000_dio_ioctl():Service number to high\n"); | |
5218 | + return -ENOTTY; | |
5219 | + } | |
5220 | + | |
5221 | + switch (service) { | |
5222 | + case ME4000_CNT_READ: | |
5223 | + return me4000_cnt_read((me4000_cnt_t *) arg, cnt_context); | |
5224 | + case ME4000_CNT_WRITE: | |
5225 | + return me4000_cnt_write((me4000_cnt_t *) arg, cnt_context); | |
5226 | + case ME4000_CNT_CONFIG: | |
5227 | + return me4000_cnt_config((me4000_cnt_config_t *) arg, | |
5228 | + cnt_context); | |
5229 | + case ME4000_CNT_RESET: | |
5230 | + return me4000_cnt_reset(cnt_context); | |
5231 | + default: | |
5232 | + printk(KERN_ERR | |
5233 | + "ME4000:me4000_dio_ioctl():Invalid service number %d\n", | |
5234 | + service); | |
5235 | + return -ENOTTY; | |
5236 | + } | |
5237 | + return 0; | |
5238 | +} | |
5239 | + | |
5240 | +static int me4000_cnt_config(me4000_cnt_config_t * arg, | |
5241 | + me4000_cnt_context_t * cnt_context) | |
5242 | +{ | |
5243 | + me4000_cnt_config_t cmd; | |
5244 | + u8 counter; | |
5245 | + u8 mode; | |
5246 | + int err; | |
5247 | + | |
5248 | + CALL_PDEBUG("me4000_cnt_config() is executed\n"); | |
5249 | + | |
5250 | + /* Copy data from user */ | |
5251 | + err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_config_t)); | |
5252 | + if (err) { | |
5253 | + printk(KERN_ERR | |
5254 | + "ME4000:me4000_cnt_config():Can't copy from user space\n"); | |
5255 | + return -EFAULT; | |
5256 | + } | |
5257 | + | |
5258 | + /* Check counter parameter */ | |
5259 | + switch (cmd.counter) { | |
5260 | + case ME4000_CNT_COUNTER_0: | |
5261 | + counter = ME4000_CNT_CTRL_BIT_COUNTER_0; | |
5262 | + break; | |
5263 | + case ME4000_CNT_COUNTER_1: | |
5264 | + counter = ME4000_CNT_CTRL_BIT_COUNTER_1; | |
5265 | + break; | |
5266 | + case ME4000_CNT_COUNTER_2: | |
5267 | + counter = ME4000_CNT_CTRL_BIT_COUNTER_2; | |
5268 | + break; | |
5269 | + default: | |
5270 | + printk(KERN_ERR | |
5271 | + "ME4000:me4000_cnt_config():Counter %d is not available\n", | |
5272 | + cmd.counter); | |
5273 | + return -EINVAL; | |
5274 | + } | |
5275 | + | |
5276 | + /* Check mode parameter */ | |
5277 | + switch (cmd.mode) { | |
5278 | + case ME4000_CNT_MODE_0: | |
5279 | + mode = ME4000_CNT_CTRL_BIT_MODE_0; | |
5280 | + break; | |
5281 | + case ME4000_CNT_MODE_1: | |
5282 | + mode = ME4000_CNT_CTRL_BIT_MODE_1; | |
5283 | + break; | |
5284 | + case ME4000_CNT_MODE_2: | |
5285 | + mode = ME4000_CNT_CTRL_BIT_MODE_2; | |
5286 | + break; | |
5287 | + case ME4000_CNT_MODE_3: | |
5288 | + mode = ME4000_CNT_CTRL_BIT_MODE_3; | |
5289 | + break; | |
5290 | + case ME4000_CNT_MODE_4: | |
5291 | + mode = ME4000_CNT_CTRL_BIT_MODE_4; | |
5292 | + break; | |
5293 | + case ME4000_CNT_MODE_5: | |
5294 | + mode = ME4000_CNT_CTRL_BIT_MODE_5; | |
5295 | + break; | |
5296 | + default: | |
5297 | + printk(KERN_ERR | |
5298 | + "ME4000:me4000_cnt_config():Mode %d is not available\n", | |
5299 | + cmd.mode); | |
5300 | + return -EINVAL; | |
5301 | + } | |
5302 | + | |
5303 | + /* Write the control word */ | |
5304 | + me4000_outb((counter | mode | 0x30), cnt_context->ctrl_reg); | |
5305 | + | |
5306 | + return 0; | |
5307 | +} | |
5308 | + | |
5309 | +static int me4000_cnt_read(me4000_cnt_t * arg, | |
5310 | + me4000_cnt_context_t * cnt_context) | |
5311 | +{ | |
5312 | + me4000_cnt_t cmd; | |
5313 | + u8 tmp; | |
5314 | + int err; | |
5315 | + | |
5316 | + CALL_PDEBUG("me4000_cnt_read() is executed\n"); | |
5317 | + | |
5318 | + /* Copy data from user */ | |
5319 | + err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t)); | |
5320 | + if (err) { | |
5321 | + printk(KERN_ERR | |
5322 | + "ME4000:me4000_cnt_read():Can't copy from user space\n"); | |
5323 | + return -EFAULT; | |
5324 | + } | |
5325 | + | |
5326 | + /* Read counter */ | |
5327 | + switch (cmd.counter) { | |
5328 | + case ME4000_CNT_COUNTER_0: | |
5329 | + tmp = me4000_inb(cnt_context->counter_0_reg); | |
5330 | + cmd.value = tmp; | |
5331 | + tmp = me4000_inb(cnt_context->counter_0_reg); | |
5332 | + cmd.value |= ((u16) tmp) << 8; | |
5333 | + break; | |
5334 | + case ME4000_CNT_COUNTER_1: | |
5335 | + tmp = me4000_inb(cnt_context->counter_1_reg); | |
5336 | + cmd.value = tmp; | |
5337 | + tmp = me4000_inb(cnt_context->counter_1_reg); | |
5338 | + cmd.value |= ((u16) tmp) << 8; | |
5339 | + break; | |
5340 | + case ME4000_CNT_COUNTER_2: | |
5341 | + tmp = me4000_inb(cnt_context->counter_2_reg); | |
5342 | + cmd.value = tmp; | |
5343 | + tmp = me4000_inb(cnt_context->counter_2_reg); | |
5344 | + cmd.value |= ((u16) tmp) << 8; | |
5345 | + break; | |
5346 | + default: | |
5347 | + printk(KERN_ERR | |
5348 | + "ME4000:me4000_cnt_read():Counter %d is not available\n", | |
5349 | + cmd.counter); | |
5350 | + return -EINVAL; | |
5351 | + } | |
5352 | + | |
5353 | + /* Copy result back to user */ | |
5354 | + err = copy_to_user(arg, &cmd, sizeof(me4000_cnt_t)); | |
5355 | + if (err) { | |
5356 | + printk(KERN_ERR | |
5357 | + "ME4000:me4000_cnt_read():Can't copy to user space\n"); | |
5358 | + return -EFAULT; | |
5359 | + } | |
5360 | + | |
5361 | + return 0; | |
5362 | +} | |
5363 | + | |
5364 | +static int me4000_cnt_write(me4000_cnt_t * arg, | |
5365 | + me4000_cnt_context_t * cnt_context) | |
5366 | +{ | |
5367 | + me4000_cnt_t cmd; | |
5368 | + u8 tmp; | |
5369 | + int err; | |
5370 | + | |
5371 | + CALL_PDEBUG("me4000_cnt_write() is executed\n"); | |
5372 | + | |
5373 | + /* Copy data from user */ | |
5374 | + err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t)); | |
5375 | + if (err) { | |
5376 | + printk(KERN_ERR | |
5377 | + "ME4000:me4000_cnt_write():Can't copy from user space\n"); | |
5378 | + return -EFAULT; | |
5379 | + } | |
5380 | + | |
5381 | + /* Write counter */ | |
5382 | + switch (cmd.counter) { | |
5383 | + case ME4000_CNT_COUNTER_0: | |
5384 | + tmp = cmd.value & 0xFF; | |
5385 | + me4000_outb(tmp, cnt_context->counter_0_reg); | |
5386 | + tmp = (cmd.value >> 8) & 0xFF; | |
5387 | + me4000_outb(tmp, cnt_context->counter_0_reg); | |
5388 | + break; | |
5389 | + case ME4000_CNT_COUNTER_1: | |
5390 | + tmp = cmd.value & 0xFF; | |
5391 | + me4000_outb(tmp, cnt_context->counter_1_reg); | |
5392 | + tmp = (cmd.value >> 8) & 0xFF; | |
5393 | + me4000_outb(tmp, cnt_context->counter_1_reg); | |
5394 | + break; | |
5395 | + case ME4000_CNT_COUNTER_2: | |
5396 | + tmp = cmd.value & 0xFF; | |
5397 | + me4000_outb(tmp, cnt_context->counter_2_reg); | |
5398 | + tmp = (cmd.value >> 8) & 0xFF; | |
5399 | + me4000_outb(tmp, cnt_context->counter_2_reg); | |
5400 | + break; | |
5401 | + default: | |
5402 | + printk(KERN_ERR | |
5403 | + "ME4000:me4000_cnt_write():Counter %d is not available\n", | |
5404 | + cmd.counter); | |
5405 | + return -EINVAL; | |
5406 | + } | |
5407 | + | |
5408 | + return 0; | |
5409 | +} | |
5410 | + | |
5411 | +static int me4000_cnt_reset(me4000_cnt_context_t * cnt_context) | |
5412 | +{ | |
5413 | + CALL_PDEBUG("me4000_cnt_reset() is executed\n"); | |
5414 | + | |
5415 | + /* Set the mode and value for counter 0 */ | |
5416 | + me4000_outb(0x30, cnt_context->ctrl_reg); | |
5417 | + me4000_outb(0x00, cnt_context->counter_0_reg); | |
5418 | + me4000_outb(0x00, cnt_context->counter_0_reg); | |
5419 | + | |
5420 | + /* Set the mode and value for counter 1 */ | |
5421 | + me4000_outb(0x70, cnt_context->ctrl_reg); | |
5422 | + me4000_outb(0x00, cnt_context->counter_1_reg); | |
5423 | + me4000_outb(0x00, cnt_context->counter_1_reg); | |
5424 | + | |
5425 | + /* Set the mode and value for counter 2 */ | |
5426 | + me4000_outb(0xB0, cnt_context->ctrl_reg); | |
5427 | + me4000_outb(0x00, cnt_context->counter_2_reg); | |
5428 | + me4000_outb(0x00, cnt_context->counter_2_reg); | |
5429 | + | |
5430 | + return 0; | |
5431 | +} | |
5432 | + | |
5433 | +/*------------------------------------ External Interrupt stuff ------------------------------------*/ | |
5434 | + | |
5435 | +static int me4000_ext_int_ioctl(struct inode *inode_p, struct file *file_p, | |
5436 | + unsigned int service, unsigned long arg) | |
5437 | +{ | |
5438 | + me4000_ext_int_context_t *ext_int_context; | |
5439 | + | |
5440 | + CALL_PDEBUG("me4000_ext_int_ioctl() is executed\n"); | |
5441 | + | |
5442 | + ext_int_context = file_p->private_data; | |
5443 | + | |
5444 | + if (_IOC_TYPE(service) != ME4000_MAGIC) { | |
5445 | + printk(KERN_ERR "me4000_ext_int_ioctl():Wrong magic number\n"); | |
5446 | + return -ENOTTY; | |
5447 | + } | |
5448 | + if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { | |
5449 | + printk(KERN_ERR | |
5450 | + "me4000_ext_int_ioctl():Service number to high\n"); | |
5451 | + return -ENOTTY; | |
5452 | + } | |
5453 | + | |
5454 | + switch (service) { | |
5455 | + case ME4000_EXT_INT_ENABLE: | |
5456 | + return me4000_ext_int_enable(ext_int_context); | |
5457 | + case ME4000_EXT_INT_DISABLE: | |
5458 | + return me4000_ext_int_disable(ext_int_context); | |
5459 | + case ME4000_EXT_INT_COUNT: | |
5460 | + return me4000_ext_int_count((unsigned long *)arg, | |
5461 | + ext_int_context); | |
5462 | + default: | |
5463 | + printk(KERN_ERR | |
5464 | + "ME4000:me4000_ext_int_ioctl():Invalid service number %d\n", | |
5465 | + service); | |
5466 | + return -ENOTTY; | |
5467 | + } | |
5468 | + return 0; | |
5469 | +} | |
5470 | + | |
5471 | +static int me4000_ext_int_enable(me4000_ext_int_context_t * ext_int_context) | |
5472 | +{ | |
5473 | + unsigned long tmp; | |
5474 | + | |
5475 | + CALL_PDEBUG("me4000_ext_int_enable() is executed\n"); | |
5476 | + | |
5477 | + tmp = me4000_inl(ext_int_context->ctrl_reg); | |
5478 | + tmp |= ME4000_AI_CTRL_BIT_EX_IRQ; | |
5479 | + me4000_outl(tmp, ext_int_context->ctrl_reg); | |
5480 | + | |
5481 | + return 0; | |
5482 | +} | |
5483 | + | |
5484 | +static int me4000_ext_int_disable(me4000_ext_int_context_t * ext_int_context) | |
5485 | +{ | |
5486 | + unsigned long tmp; | |
5487 | + | |
5488 | + CALL_PDEBUG("me4000_ext_int_disable() is executed\n"); | |
5489 | + | |
5490 | + tmp = me4000_inl(ext_int_context->ctrl_reg); | |
5491 | + tmp &= ~ME4000_AI_CTRL_BIT_EX_IRQ; | |
5492 | + me4000_outl(tmp, ext_int_context->ctrl_reg); | |
5493 | + | |
5494 | + return 0; | |
5495 | +} | |
5496 | + | |
5497 | +static int me4000_ext_int_count(unsigned long *arg, | |
5498 | + me4000_ext_int_context_t * ext_int_context) | |
5499 | +{ | |
5500 | + | |
5501 | + CALL_PDEBUG("me4000_ext_int_count() is executed\n"); | |
5502 | + | |
5503 | + put_user(ext_int_context->int_count, arg); | |
5504 | + return 0; | |
5505 | +} | |
5506 | + | |
5507 | +/*------------------------------------ General stuff ------------------------------------*/ | |
5508 | + | |
5509 | +static int me4000_get_user_info(me4000_user_info_t * arg, | |
5510 | + me4000_info_t * board_info) | |
5511 | +{ | |
5512 | + me4000_user_info_t user_info; | |
5513 | + | |
5514 | + CALL_PDEBUG("me4000_get_user_info() is executed\n"); | |
5515 | + | |
5516 | + user_info.board_count = board_info->board_count; | |
5517 | + user_info.plx_regbase = board_info->plx_regbase; | |
5518 | + user_info.plx_regbase_size = board_info->plx_regbase_size; | |
5519 | + user_info.me4000_regbase = board_info->me4000_regbase; | |
5520 | + user_info.me4000_regbase_size = board_info->me4000_regbase_size; | |
5521 | + user_info.serial_no = board_info->serial_no; | |
5522 | + user_info.hw_revision = board_info->hw_revision; | |
5523 | + user_info.vendor_id = board_info->vendor_id; | |
5524 | + user_info.device_id = board_info->device_id; | |
5525 | + user_info.pci_bus_no = board_info->pci_bus_no; | |
5526 | + user_info.pci_dev_no = board_info->pci_dev_no; | |
5527 | + user_info.pci_func_no = board_info->pci_func_no; | |
5528 | + user_info.irq = board_info->irq; | |
5529 | + user_info.irq_count = board_info->irq_count; | |
5530 | + user_info.driver_version = ME4000_DRIVER_VERSION; | |
5531 | + user_info.ao_count = board_info->board_p->ao.count; | |
5532 | + user_info.ao_fifo_count = board_info->board_p->ao.fifo_count; | |
5533 | + | |
5534 | + user_info.ai_count = board_info->board_p->ai.count; | |
5535 | + user_info.ai_sh_count = board_info->board_p->ai.sh_count; | |
5536 | + user_info.ai_ex_trig_analog = board_info->board_p->ai.ex_trig_analog; | |
5537 | + | |
5538 | + user_info.dio_count = board_info->board_p->dio.count; | |
5539 | + | |
5540 | + user_info.cnt_count = board_info->board_p->cnt.count; | |
5541 | + | |
5542 | + if (copy_to_user(arg, &user_info, sizeof(me4000_user_info_t))) | |
5543 | + return -EFAULT; | |
5544 | + | |
5545 | + return 0; | |
5546 | +} | |
5547 | + | |
5548 | +/*------------------------------------ ISR STUFF ------------------------------------*/ | |
5549 | + | |
5550 | +static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode) | |
5551 | +{ | |
5552 | + int result = 0; | |
5553 | + me4000_ext_int_context_t *ext_int_context; | |
5554 | + | |
5555 | + CALL_PDEBUG("me4000_ext_int_fasync() is executed\n"); | |
5556 | + | |
5557 | + ext_int_context = file_ptr->private_data; | |
5558 | + | |
5559 | + result = | |
5560 | + fasync_helper(fd, file_ptr, mode, &ext_int_context->fasync_ptr); | |
5561 | + | |
5562 | + CALL_PDEBUG("me4000_ext_int_fasync() is leaved\n"); | |
5563 | + return result; | |
5564 | +} | |
5565 | + | |
5566 | +static irqreturn_t me4000_ao_isr(int irq, void *dev_id) | |
5567 | +{ | |
5568 | + u32 tmp; | |
5569 | + u32 value; | |
5570 | + me4000_ao_context_t *ao_context; | |
5571 | + int i; | |
5572 | + int c = 0; | |
5573 | + int c1 = 0; | |
5574 | + //unsigned long before; | |
5575 | + //unsigned long after; | |
5576 | + | |
5577 | + ISR_PDEBUG("me4000_ao_isr() is executed\n"); | |
5578 | + | |
5579 | + ao_context = dev_id; | |
5580 | + | |
5581 | + /* Check if irq number is right */ | |
5582 | + if (irq != ao_context->irq) { | |
5583 | + ISR_PDEBUG("me4000_ao_isr():incorrect interrupt num: %d\n", | |
5584 | + irq); | |
5585 | + return IRQ_NONE; | |
5586 | + } | |
5587 | + | |
5588 | + /* Check if this DAC rised an interrupt */ | |
5589 | + if (! | |
5590 | + ((0x1 << (ao_context->index + 3)) & | |
5591 | + me4000_inl(ao_context->irq_status_reg))) { | |
5592 | + ISR_PDEBUG("me4000_ao_isr():Not this DAC\n"); | |
5593 | + return IRQ_NONE; | |
5594 | + } | |
5595 | + | |
5596 | + /* Read status register to find out what happened */ | |
5597 | + tmp = me4000_inl(ao_context->status_reg); | |
5598 | + | |
5599 | + if (!(tmp & ME4000_AO_STATUS_BIT_EF) && (tmp & ME4000_AO_STATUS_BIT_HF) | |
5600 | + && (tmp & ME4000_AO_STATUS_BIT_HF)) { | |
5601 | + c = ME4000_AO_FIFO_COUNT; | |
5602 | + ISR_PDEBUG("me4000_ao_isr():Fifo empty\n"); | |
5603 | + } else if ((tmp & ME4000_AO_STATUS_BIT_EF) | |
5604 | + && (tmp & ME4000_AO_STATUS_BIT_HF) | |
5605 | + && (tmp & ME4000_AO_STATUS_BIT_HF)) { | |
5606 | + c = ME4000_AO_FIFO_COUNT / 2; | |
5607 | + ISR_PDEBUG("me4000_ao_isr():Fifo under half full\n"); | |
5608 | + } else { | |
5609 | + c = 0; | |
5610 | + ISR_PDEBUG("me4000_ao_isr():Fifo full\n"); | |
5611 | + } | |
5612 | + | |
5613 | + ISR_PDEBUG("me4000_ao_isr():Try to write 0x%04X values\n", c); | |
5614 | + | |
5615 | + while (1) { | |
5616 | + c1 = me4000_values_to_end(ao_context->circ_buf, | |
5617 | + ME4000_AO_BUFFER_COUNT); | |
5618 | + ISR_PDEBUG("me4000_ao_isr():Values to end = %d\n", c1); | |
5619 | + if (c1 > c) | |
5620 | + c1 = c; | |
5621 | + | |
5622 | + if (c1 <= 0) { | |
5623 | + ISR_PDEBUG | |
5624 | + ("me4000_ao_isr():Work done or buffer empty\n"); | |
5625 | + break; | |
5626 | + } | |
5627 | + //rdtscl(before); | |
5628 | + if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG) || | |
5629 | + ((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG)) { | |
5630 | + for (i = 0; i < c1; i++) { | |
5631 | + value = | |
5632 | + ((u32) | |
5633 | + (* | |
5634 | + (ao_context->circ_buf.buf + | |
5635 | + ao_context->circ_buf.tail + i))) << 16; | |
5636 | + outl(value, ao_context->fifo_reg); | |
5637 | + } | |
5638 | + } else | |
5639 | + outsw(ao_context->fifo_reg, | |
5640 | + ao_context->circ_buf.buf + | |
5641 | + ao_context->circ_buf.tail, c1); | |
5642 | + | |
5643 | + //rdtscl(after); | |
5644 | + //printk(KERN_ERR"ME4000:me4000_ao_isr():Time lapse = %lu\n", after - before); | |
5645 | + | |
5646 | + ao_context->circ_buf.tail = | |
5647 | + (ao_context->circ_buf.tail + c1) & (ME4000_AO_BUFFER_COUNT - | |
5648 | + 1); | |
5649 | + ISR_PDEBUG("me4000_ao_isr():%d values wrote to port 0x%04X\n", | |
5650 | + c1, ao_context->fifo_reg); | |
5651 | + c -= c1; | |
5652 | + } | |
5653 | + | |
5654 | + /* If there are no values left in the buffer, disable interrupts */ | |
5655 | + spin_lock(&ao_context->int_lock); | |
5656 | + if (!me4000_buf_count(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) { | |
5657 | + ISR_PDEBUG | |
5658 | + ("me4000_ao_isr():Disable Interrupt because no values left in buffer\n"); | |
5659 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
5660 | + tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_IRQ; | |
5661 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
5662 | + } | |
5663 | + spin_unlock(&ao_context->int_lock); | |
5664 | + | |
5665 | + /* Reset the interrupt */ | |
5666 | + spin_lock(&ao_context->int_lock); | |
5667 | + tmp = me4000_inl(ao_context->ctrl_reg); | |
5668 | + tmp |= ME4000_AO_CTRL_BIT_RESET_IRQ; | |
5669 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
5670 | + tmp &= ~ME4000_AO_CTRL_BIT_RESET_IRQ; | |
5671 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
5672 | + | |
5673 | + /* If state machine is stopped, flow was interrupted */ | |
5674 | + if (!(me4000_inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM)) { | |
5675 | + printk(KERN_ERR "ME4000:me4000_ao_isr():Broken pipe\n"); | |
5676 | + ao_context->pipe_flag = 1; // Set flag in order to inform write routine | |
5677 | + tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_IRQ; // Disable interrupt | |
5678 | + } | |
5679 | + me4000_outl(tmp, ao_context->ctrl_reg); | |
5680 | + spin_unlock(&ao_context->int_lock); | |
5681 | + | |
5682 | + /* Wake up waiting process */ | |
5683 | + wake_up_interruptible(&(ao_context->wait_queue)); | |
5684 | + | |
5685 | + /* Count the interrupt */ | |
5686 | + ao_context->board_info->irq_count++; | |
5687 | + | |
5688 | + return IRQ_HANDLED; | |
5689 | +} | |
5690 | + | |
5691 | +static irqreturn_t me4000_ai_isr(int irq, void *dev_id) | |
5692 | +{ | |
5693 | + u32 tmp; | |
5694 | + me4000_ai_context_t *ai_context; | |
5695 | + int i; | |
5696 | + int c = 0; | |
5697 | + int c1 = 0; | |
5698 | +#ifdef ME4000_ISR_DEBUG | |
5699 | + unsigned long before; | |
5700 | + unsigned long after; | |
5701 | +#endif | |
5702 | + | |
5703 | + ISR_PDEBUG("me4000_ai_isr() is executed\n"); | |
5704 | + | |
5705 | +#ifdef ME4000_ISR_DEBUG | |
5706 | + rdtscl(before); | |
5707 | +#endif | |
5708 | + | |
5709 | + ai_context = dev_id; | |
5710 | + | |
5711 | + /* Check if irq number is right */ | |
5712 | + if (irq != ai_context->irq) { | |
5713 | + ISR_PDEBUG("me4000_ai_isr():incorrect interrupt num: %d\n", | |
5714 | + irq); | |
5715 | + return IRQ_NONE; | |
5716 | + } | |
5717 | + | |
5718 | + if (me4000_inl(ai_context->irq_status_reg) & | |
5719 | + ME4000_IRQ_STATUS_BIT_AI_HF) { | |
5720 | + ISR_PDEBUG | |
5721 | + ("me4000_ai_isr():Fifo half full interrupt occured\n"); | |
5722 | + | |
5723 | + /* Read status register to find out what happened */ | |
5724 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
5725 | + | |
5726 | + if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && | |
5727 | + !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) | |
5728 | + && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { | |
5729 | + ISR_PDEBUG("me4000_ai_isr():Fifo full\n"); | |
5730 | + c = ME4000_AI_FIFO_COUNT; | |
5731 | + | |
5732 | + /* FIFO overflow, so stop conversion and disable all interrupts */ | |
5733 | + spin_lock(&ai_context->int_lock); | |
5734 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
5735 | + tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | |
5736 | + tmp &= | |
5737 | + ~(ME4000_AI_CTRL_BIT_HF_IRQ | | |
5738 | + ME4000_AI_CTRL_BIT_SC_IRQ); | |
5739 | + outl(tmp, ai_context->ctrl_reg); | |
5740 | + spin_unlock(&ai_context->int_lock); | |
5741 | + } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) && | |
5742 | + !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) | |
5743 | + && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { | |
5744 | + ISR_PDEBUG("me4000_ai_isr():Fifo half full\n"); | |
5745 | + c = ME4000_AI_FIFO_COUNT / 2; | |
5746 | + } else { | |
5747 | + c = 0; | |
5748 | + ISR_PDEBUG | |
5749 | + ("me4000_ai_isr():Can't determine state of fifo\n"); | |
5750 | + } | |
5751 | + | |
5752 | + ISR_PDEBUG("me4000_ai_isr():Try to read %d values\n", c); | |
5753 | + | |
5754 | + while (1) { | |
5755 | + c1 = me4000_space_to_end(ai_context->circ_buf, | |
5756 | + ME4000_AI_BUFFER_COUNT); | |
5757 | + ISR_PDEBUG("me4000_ai_isr():Space to end = %d\n", c1); | |
5758 | + if (c1 > c) | |
5759 | + c1 = c; | |
5760 | + | |
5761 | + if (c1 <= 0) { | |
5762 | + ISR_PDEBUG | |
5763 | + ("me4000_ai_isr():Work done or buffer full\n"); | |
5764 | + break; | |
5765 | + } | |
5766 | + | |
5767 | + insw(ai_context->data_reg, | |
5768 | + ai_context->circ_buf.buf + | |
5769 | + ai_context->circ_buf.head, c1); | |
5770 | + ai_context->circ_buf.head = | |
5771 | + (ai_context->circ_buf.head + | |
5772 | + c1) & (ME4000_AI_BUFFER_COUNT - 1); | |
5773 | + c -= c1; | |
5774 | + } | |
5775 | + | |
5776 | + /* Work is done, so reset the interrupt */ | |
5777 | + ISR_PDEBUG | |
5778 | + ("me4000_ai_isr():reset interrupt fifo half full interrupt\n"); | |
5779 | + spin_lock(&ai_context->int_lock); | |
5780 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
5781 | + tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET; | |
5782 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
5783 | + tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET; | |
5784 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
5785 | + spin_unlock(&ai_context->int_lock); | |
5786 | + } | |
5787 | + | |
5788 | + if (me4000_inl(ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) { | |
5789 | + ISR_PDEBUG | |
5790 | + ("me4000_ai_isr():Sample counter interrupt occured\n"); | |
5791 | + | |
5792 | + if (!ai_context->sample_counter_reload) { | |
5793 | + ISR_PDEBUG | |
5794 | + ("me4000_ai_isr():Single data block available\n"); | |
5795 | + | |
5796 | + /* Poll data until fifo empty */ | |
5797 | + for (i = 0; | |
5798 | + (i < ME4000_AI_FIFO_COUNT / 2) | |
5799 | + && (inl(ai_context->ctrl_reg) & | |
5800 | + ME4000_AI_STATUS_BIT_EF_DATA); i++) { | |
5801 | + if (me4000_space_to_end | |
5802 | + (ai_context->circ_buf, | |
5803 | + ME4000_AI_BUFFER_COUNT)) { | |
5804 | + *(ai_context->circ_buf.buf + | |
5805 | + ai_context->circ_buf.head) = | |
5806 | + inw(ai_context->data_reg); | |
5807 | + ai_context->circ_buf.head = | |
5808 | + (ai_context->circ_buf.head + | |
5809 | + 1) & (ME4000_AI_BUFFER_COUNT - 1); | |
5810 | + } else | |
5811 | + break; | |
5812 | + } | |
5813 | + ISR_PDEBUG("me4000_ai_isr():%d values read\n", i); | |
5814 | + } else { | |
5815 | + if (ai_context->sample_counter <= | |
5816 | + ME4000_AI_FIFO_COUNT / 2) { | |
5817 | + ISR_PDEBUG | |
5818 | + ("me4000_ai_isr():Interrupt from adjustable half full threshold\n"); | |
5819 | + | |
5820 | + /* Read status register to find out what happened */ | |
5821 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
5822 | + | |
5823 | + if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && | |
5824 | + !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) | |
5825 | + && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { | |
5826 | + ISR_PDEBUG | |
5827 | + ("me4000_ai_isr():Fifo full\n"); | |
5828 | + c = ME4000_AI_FIFO_COUNT; | |
5829 | + | |
5830 | + /* FIFO overflow, so stop conversion */ | |
5831 | + spin_lock(&ai_context->int_lock); | |
5832 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
5833 | + tmp |= | |
5834 | + ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | |
5835 | + outl(tmp, ai_context->ctrl_reg); | |
5836 | + spin_unlock(&ai_context->int_lock); | |
5837 | + } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) | |
5838 | + && !(tmp & | |
5839 | + ME4000_AI_STATUS_BIT_HF_DATA) | |
5840 | + && (tmp & | |
5841 | + ME4000_AI_STATUS_BIT_EF_DATA)) { | |
5842 | + ISR_PDEBUG | |
5843 | + ("me4000_ai_isr():Fifo half full\n"); | |
5844 | + c = ME4000_AI_FIFO_COUNT / 2; | |
5845 | + } else { | |
5846 | + c = ai_context->sample_counter; | |
5847 | + ISR_PDEBUG | |
5848 | + ("me4000_ai_isr():Sample count values\n"); | |
5849 | + } | |
5850 | + | |
5851 | + ISR_PDEBUG | |
5852 | + ("me4000_ai_isr():Try to read %d values\n", | |
5853 | + c); | |
5854 | + | |
5855 | + while (1) { | |
5856 | + c1 = me4000_space_to_end(ai_context-> | |
5857 | + circ_buf, | |
5858 | + ME4000_AI_BUFFER_COUNT); | |
5859 | + ISR_PDEBUG | |
5860 | + ("me4000_ai_isr():Space to end = %d\n", | |
5861 | + c1); | |
5862 | + if (c1 > c) | |
5863 | + c1 = c; | |
5864 | + | |
5865 | + if (c1 <= 0) { | |
5866 | + ISR_PDEBUG | |
5867 | + ("me4000_ai_isr():Work done or buffer full\n"); | |
5868 | + break; | |
5869 | + } | |
5870 | + | |
5871 | + insw(ai_context->data_reg, | |
5872 | + ai_context->circ_buf.buf + | |
5873 | + ai_context->circ_buf.head, c1); | |
5874 | + ai_context->circ_buf.head = | |
5875 | + (ai_context->circ_buf.head + | |
5876 | + c1) & (ME4000_AI_BUFFER_COUNT - 1); | |
5877 | + c -= c1; | |
5878 | + } | |
5879 | + } else { | |
5880 | + ISR_PDEBUG | |
5881 | + ("me4000_ai_isr():Multiple data block available\n"); | |
5882 | + | |
5883 | + /* Read status register to find out what happened */ | |
5884 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
5885 | + | |
5886 | + if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && | |
5887 | + !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) | |
5888 | + && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { | |
5889 | + ISR_PDEBUG | |
5890 | + ("me4000_ai_isr():Fifo full\n"); | |
5891 | + c = ME4000_AI_FIFO_COUNT; | |
5892 | + | |
5893 | + /* FIFO overflow, so stop conversion */ | |
5894 | + spin_lock(&ai_context->int_lock); | |
5895 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
5896 | + tmp |= | |
5897 | + ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; | |
5898 | + outl(tmp, ai_context->ctrl_reg); | |
5899 | + spin_unlock(&ai_context->int_lock); | |
5900 | + | |
5901 | + while (1) { | |
5902 | + c1 = me4000_space_to_end | |
5903 | + (ai_context->circ_buf, | |
5904 | + ME4000_AI_BUFFER_COUNT); | |
5905 | + ISR_PDEBUG | |
5906 | + ("me4000_ai_isr():Space to end = %d\n", | |
5907 | + c1); | |
5908 | + if (c1 > c) | |
5909 | + c1 = c; | |
5910 | + | |
5911 | + if (c1 <= 0) { | |
5912 | + ISR_PDEBUG | |
5913 | + ("me4000_ai_isr():Work done or buffer full\n"); | |
5914 | + break; | |
5915 | + } | |
5916 | + | |
5917 | + insw(ai_context->data_reg, | |
5918 | + ai_context->circ_buf.buf + | |
5919 | + ai_context->circ_buf.head, | |
5920 | + c1); | |
5921 | + ai_context->circ_buf.head = | |
5922 | + (ai_context->circ_buf.head + | |
5923 | + c1) & | |
5924 | + (ME4000_AI_BUFFER_COUNT - | |
5925 | + 1); | |
5926 | + c -= c1; | |
5927 | + } | |
5928 | + } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) | |
5929 | + && !(tmp & | |
5930 | + ME4000_AI_STATUS_BIT_HF_DATA) | |
5931 | + && (tmp & | |
5932 | + ME4000_AI_STATUS_BIT_EF_DATA)) { | |
5933 | + ISR_PDEBUG | |
5934 | + ("me4000_ai_isr():Fifo half full\n"); | |
5935 | + c = ME4000_AI_FIFO_COUNT / 2; | |
5936 | + | |
5937 | + while (1) { | |
5938 | + c1 = me4000_space_to_end | |
5939 | + (ai_context->circ_buf, | |
5940 | + ME4000_AI_BUFFER_COUNT); | |
5941 | + ISR_PDEBUG | |
5942 | + ("me4000_ai_isr():Space to end = %d\n", | |
5943 | + c1); | |
5944 | + if (c1 > c) | |
5945 | + c1 = c; | |
5946 | + | |
5947 | + if (c1 <= 0) { | |
5948 | + ISR_PDEBUG | |
5949 | + ("me4000_ai_isr():Work done or buffer full\n"); | |
5950 | + break; | |
5951 | + } | |
5952 | + | |
5953 | + insw(ai_context->data_reg, | |
5954 | + ai_context->circ_buf.buf + | |
5955 | + ai_context->circ_buf.head, | |
5956 | + c1); | |
5957 | + ai_context->circ_buf.head = | |
5958 | + (ai_context->circ_buf.head + | |
5959 | + c1) & | |
5960 | + (ME4000_AI_BUFFER_COUNT - | |
5961 | + 1); | |
5962 | + c -= c1; | |
5963 | + } | |
5964 | + } else { | |
5965 | + /* Poll data until fifo empty */ | |
5966 | + for (i = 0; | |
5967 | + (i < ME4000_AI_FIFO_COUNT / 2) | |
5968 | + && (inl(ai_context->ctrl_reg) & | |
5969 | + ME4000_AI_STATUS_BIT_EF_DATA); | |
5970 | + i++) { | |
5971 | + if (me4000_space_to_end | |
5972 | + (ai_context->circ_buf, | |
5973 | + ME4000_AI_BUFFER_COUNT)) { | |
5974 | + *(ai_context->circ_buf. | |
5975 | + buf + | |
5976 | + ai_context->circ_buf. | |
5977 | + head) = | |
5978 | + inw(ai_context->data_reg); | |
5979 | + ai_context->circ_buf. | |
5980 | + head = | |
5981 | + (ai_context-> | |
5982 | + circ_buf.head + | |
5983 | + 1) & | |
5984 | + (ME4000_AI_BUFFER_COUNT | |
5985 | + - 1); | |
5986 | + } else | |
5987 | + break; | |
5988 | + } | |
5989 | + ISR_PDEBUG | |
5990 | + ("me4000_ai_isr():%d values read\n", | |
5991 | + i); | |
5992 | + } | |
5993 | + } | |
5994 | + } | |
5995 | + | |
5996 | + /* Work is done, so reset the interrupt */ | |
5997 | + ISR_PDEBUG | |
5998 | + ("me4000_ai_isr():reset interrupt from sample counter\n"); | |
5999 | + spin_lock(&ai_context->int_lock); | |
6000 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
6001 | + tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET; | |
6002 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
6003 | + tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET; | |
6004 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
6005 | + spin_unlock(&ai_context->int_lock); | |
6006 | + } | |
6007 | + | |
6008 | + /* Values are now available, so wake up waiting process */ | |
6009 | + if (me4000_buf_count(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) { | |
6010 | + ISR_PDEBUG("me4000_ai_isr():Wake up waiting process\n"); | |
6011 | + wake_up_interruptible(&(ai_context->wait_queue)); | |
6012 | + } | |
6013 | + | |
6014 | + /* If there is no space left in the buffer, disable interrupts */ | |
6015 | + spin_lock(&ai_context->int_lock); | |
6016 | + if (!me4000_buf_space(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) { | |
6017 | + ISR_PDEBUG | |
6018 | + ("me4000_ai_isr():Disable Interrupt because no space left in buffer\n"); | |
6019 | + tmp = me4000_inl(ai_context->ctrl_reg); | |
6020 | + tmp &= | |
6021 | + ~(ME4000_AI_CTRL_BIT_SC_IRQ | ME4000_AI_CTRL_BIT_HF_IRQ | | |
6022 | + ME4000_AI_CTRL_BIT_LE_IRQ); | |
6023 | + me4000_outl(tmp, ai_context->ctrl_reg); | |
6024 | + } | |
6025 | + spin_unlock(&ai_context->int_lock); | |
6026 | + | |
6027 | +#ifdef ME4000_ISR_DEBUG | |
6028 | + rdtscl(after); | |
6029 | + printk(KERN_ERR "ME4000:me4000_ai_isr():Time lapse = %lu\n", | |
6030 | + after - before); | |
6031 | +#endif | |
6032 | + | |
6033 | + return IRQ_HANDLED; | |
6034 | +} | |
6035 | + | |
6036 | +static irqreturn_t me4000_ext_int_isr(int irq, void *dev_id) | |
6037 | +{ | |
6038 | + me4000_ext_int_context_t *ext_int_context; | |
6039 | + unsigned long tmp; | |
6040 | + | |
6041 | + ISR_PDEBUG("me4000_ext_int_isr() is executed\n"); | |
6042 | + | |
6043 | + ext_int_context = dev_id; | |
6044 | + | |
6045 | + /* Check if irq number is right */ | |
6046 | + if (irq != ext_int_context->irq) { | |
6047 | + ISR_PDEBUG("me4000_ext_int_isr():incorrect interrupt num: %d\n", | |
6048 | + irq); | |
6049 | + return IRQ_NONE; | |
6050 | + } | |
6051 | + | |
6052 | + if (me4000_inl(ext_int_context->irq_status_reg) & | |
6053 | + ME4000_IRQ_STATUS_BIT_EX) { | |
6054 | + ISR_PDEBUG("me4000_ext_int_isr():External interrupt occured\n"); | |
6055 | + tmp = me4000_inl(ext_int_context->ctrl_reg); | |
6056 | + tmp |= ME4000_AI_CTRL_BIT_EX_IRQ_RESET; | |
6057 | + me4000_outl(tmp, ext_int_context->ctrl_reg); | |
6058 | + tmp &= ~ME4000_AI_CTRL_BIT_EX_IRQ_RESET; | |
6059 | + me4000_outl(tmp, ext_int_context->ctrl_reg); | |
6060 | + | |
6061 | + ext_int_context->int_count++; | |
6062 | + | |
6063 | + if (ext_int_context->fasync_ptr) { | |
6064 | + ISR_PDEBUG | |
6065 | + ("me2600_ext_int_isr():Send signal to process\n"); | |
6066 | + kill_fasync(&ext_int_context->fasync_ptr, SIGIO, | |
6067 | + POLL_IN); | |
6068 | + } | |
6069 | + } | |
6070 | + | |
6071 | + return IRQ_HANDLED; | |
6072 | +} | |
6073 | + | |
6074 | +void __exit me4000_module_exit(void) | |
6075 | +{ | |
6076 | + struct list_head *board_p; | |
6077 | + me4000_info_t *board_info; | |
6078 | + | |
6079 | + CALL_PDEBUG("cleanup_module() is executed\n"); | |
6080 | + | |
6081 | + unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME); | |
6082 | + | |
6083 | + unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME); | |
6084 | + | |
6085 | + unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME); | |
6086 | + | |
6087 | + unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME); | |
6088 | + | |
6089 | + unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME); | |
6090 | + | |
6091 | + remove_proc_entry("me4000", NULL); | |
6092 | + | |
6093 | + pci_unregister_driver(&me4000_driver); | |
6094 | + | |
6095 | + /* Reset the boards */ | |
6096 | + for (board_p = me4000_board_info_list.next; | |
6097 | + board_p != &me4000_board_info_list; board_p = board_p->next) { | |
6098 | + board_info = list_entry(board_p, me4000_info_t, list); | |
6099 | + me4000_reset_board(board_info); | |
6100 | + } | |
6101 | + | |
6102 | + clear_board_info_list(); | |
6103 | +} | |
6104 | + | |
6105 | +module_exit(me4000_module_exit); | |
6106 | + | |
6107 | +static int me4000_read_procmem(char *buf, char **start, off_t offset, int count, | |
6108 | + int *eof, void *data) | |
6109 | +{ | |
6110 | + int len = 0; | |
6111 | + int limit = count - 1000; | |
6112 | + me4000_info_t *board_info; | |
6113 | + struct list_head *ptr; | |
6114 | + | |
6115 | + len += sprintf(buf + len, "\nME4000 DRIVER VERSION %X.%X.%X\n\n", | |
6116 | + (ME4000_DRIVER_VERSION & 0xFF0000) >> 16, | |
6117 | + (ME4000_DRIVER_VERSION & 0xFF00) >> 8, | |
6118 | + (ME4000_DRIVER_VERSION & 0xFF)); | |
6119 | + | |
6120 | + /* Search for the board context */ | |
6121 | + for (ptr = me4000_board_info_list.next; | |
6122 | + (ptr != &me4000_board_info_list) && (len < limit); | |
6123 | + ptr = ptr->next) { | |
6124 | + board_info = list_entry(ptr, me4000_info_t, list); | |
6125 | + | |
6126 | + len += | |
6127 | + sprintf(buf + len, "Board number %d:\n", | |
6128 | + board_info->board_count); | |
6129 | + len += sprintf(buf + len, "---------------\n"); | |
6130 | + len += | |
6131 | + sprintf(buf + len, "PLX base register = 0x%lX\n", | |
6132 | + board_info->plx_regbase); | |
6133 | + len += | |
6134 | + sprintf(buf + len, "PLX base register size = 0x%lX\n", | |
6135 | + board_info->plx_regbase_size); | |
6136 | + len += | |
6137 | + sprintf(buf + len, "ME4000 base register = 0x%lX\n", | |
6138 | + board_info->me4000_regbase); | |
6139 | + len += | |
6140 | + sprintf(buf + len, "ME4000 base register size = 0x%lX\n", | |
6141 | + board_info->me4000_regbase_size); | |
6142 | + len += | |
6143 | + sprintf(buf + len, "Serial number = 0x%X\n", | |
6144 | + board_info->serial_no); | |
6145 | + len += | |
6146 | + sprintf(buf + len, "Hardware revision = 0x%X\n", | |
6147 | + board_info->hw_revision); | |
6148 | + len += | |
6149 | + sprintf(buf + len, "Vendor id = 0x%X\n", | |
6150 | + board_info->vendor_id); | |
6151 | + len += | |
6152 | + sprintf(buf + len, "Device id = 0x%X\n", | |
6153 | + board_info->device_id); | |
6154 | + len += | |
6155 | + sprintf(buf + len, "PCI bus number = %d\n", | |
6156 | + board_info->pci_bus_no); | |
6157 | + len += | |
6158 | + sprintf(buf + len, "PCI device number = %d\n", | |
6159 | + board_info->pci_dev_no); | |
6160 | + len += | |
6161 | + sprintf(buf + len, "PCI function number = %d\n", | |
6162 | + board_info->pci_func_no); | |
6163 | + len += sprintf(buf + len, "IRQ = %u\n", board_info->irq); | |
6164 | + len += | |
6165 | + sprintf(buf + len, | |
6166 | + "Count of interrupts since module was loaded = %d\n", | |
6167 | + board_info->irq_count); | |
6168 | + | |
6169 | + len += | |
6170 | + sprintf(buf + len, "Count of analog outputs = %d\n", | |
6171 | + board_info->board_p->ao.count); | |
6172 | + len += | |
6173 | + sprintf(buf + len, "Count of analog output fifos = %d\n", | |
6174 | + board_info->board_p->ao.fifo_count); | |
6175 | + | |
6176 | + len += | |
6177 | + sprintf(buf + len, "Count of analog inputs = %d\n", | |
6178 | + board_info->board_p->ai.count); | |
6179 | + len += | |
6180 | + sprintf(buf + len, | |
6181 | + "Count of sample and hold devices for analog input = %d\n", | |
6182 | + board_info->board_p->ai.sh_count); | |
6183 | + len += | |
6184 | + sprintf(buf + len, | |
6185 | + "Analog external trigger available for analog input = %d\n", | |
6186 | + board_info->board_p->ai.ex_trig_analog); | |
6187 | + | |
6188 | + len += | |
6189 | + sprintf(buf + len, "Count of digital ports = %d\n", | |
6190 | + board_info->board_p->dio.count); | |
6191 | + | |
6192 | + len += | |
6193 | + sprintf(buf + len, "Count of counter devices = %d\n", | |
6194 | + board_info->board_p->cnt.count); | |
6195 | + len += | |
6196 | + sprintf(buf + len, "AI control register = 0x%08X\n", | |
6197 | + inl(board_info->me4000_regbase + | |
6198 | + ME4000_AI_CTRL_REG)); | |
6199 | + | |
6200 | + len += sprintf(buf + len, "AO 0 control register = 0x%08X\n", | |
6201 | + inl(board_info->me4000_regbase + | |
6202 | + ME4000_AO_00_CTRL_REG)); | |
6203 | + len += | |
6204 | + sprintf(buf + len, "AO 0 status register = 0x%08X\n", | |
6205 | + inl(board_info->me4000_regbase + | |
6206 | + ME4000_AO_00_STATUS_REG)); | |
6207 | + len += | |
6208 | + sprintf(buf + len, "AO 1 control register = 0x%08X\n", | |
6209 | + inl(board_info->me4000_regbase + | |
6210 | + ME4000_AO_01_CTRL_REG)); | |
6211 | + len += | |
6212 | + sprintf(buf + len, "AO 1 status register = 0x%08X\n", | |
6213 | + inl(board_info->me4000_regbase + | |
6214 | + ME4000_AO_01_STATUS_REG)); | |
6215 | + len += | |
6216 | + sprintf(buf + len, "AO 2 control register = 0x%08X\n", | |
6217 | + inl(board_info->me4000_regbase + | |
6218 | + ME4000_AO_02_CTRL_REG)); | |
6219 | + len += | |
6220 | + sprintf(buf + len, "AO 2 status register = 0x%08X\n", | |
6221 | + inl(board_info->me4000_regbase + | |
6222 | + ME4000_AO_02_STATUS_REG)); | |
6223 | + len += | |
6224 | + sprintf(buf + len, "AO 3 control register = 0x%08X\n", | |
6225 | + inl(board_info->me4000_regbase + | |
6226 | + ME4000_AO_03_CTRL_REG)); | |
6227 | + len += | |
6228 | + sprintf(buf + len, "AO 3 status register = 0x%08X\n", | |
6229 | + inl(board_info->me4000_regbase + | |
6230 | + ME4000_AO_03_STATUS_REG)); | |
6231 | + } | |
6232 | + | |
6233 | + *eof = 1; | |
6234 | + return len; | |
6235 | +} | |
6236 | diff --git a/drivers/staging/me4000/me4000.h b/drivers/staging/me4000/me4000.h | |
6237 | new file mode 100644 | |
6238 | index 0000000..c35e4b9 | |
6239 | --- /dev/null | |
6240 | +++ b/drivers/staging/me4000/me4000.h | |
6241 | @@ -0,0 +1,954 @@ | |
6242 | +/* | |
6243 | + * Copyright (C) 2003 Meilhaus Electronic GmbH (support@meilhaus.de) | |
6244 | + * | |
6245 | + * Source File : me4000.h | |
6246 | + * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de> | |
6247 | + */ | |
6248 | + | |
6249 | +#ifndef _ME4000_H_ | |
6250 | +#define _ME4000_H_ | |
6251 | + | |
6252 | +#ifdef __KERNEL__ | |
6253 | + | |
6254 | +/*============================================================================= | |
6255 | + The version of the driver release | |
6256 | + ===========================================================================*/ | |
6257 | + | |
6258 | +#define ME4000_DRIVER_VERSION 0x10009 // Version 1.00.09 | |
6259 | + | |
6260 | +/*============================================================================= | |
6261 | + Debug section | |
6262 | + ===========================================================================*/ | |
6263 | + | |
6264 | +#undef ME4000_CALL_DEBUG // Debug function entry and exit | |
6265 | +#undef ME4000_ISR_DEBUG // Debug the interrupt service routine | |
6266 | +#undef ME4000_PORT_DEBUG // Debug port access | |
6267 | +#undef ME4000_DEBUG // General purpose debug masseges | |
6268 | + | |
6269 | +#ifdef ME4000_CALL_DEBUG | |
6270 | +#undef CALL_PDEBUG | |
6271 | +#define CALL_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args) | |
6272 | +#else | |
6273 | +# define CALL_PDEBUG(fmt, args...) // no debugging, do nothing | |
6274 | +#endif | |
6275 | + | |
6276 | +#ifdef ME4000_ISR_DEBUG | |
6277 | +#undef ISR_PDEBUG | |
6278 | +#define ISR_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args) | |
6279 | +#else | |
6280 | +#define ISR_PDEBUG(fmt, args...) // no debugging, do nothing | |
6281 | +#endif | |
6282 | + | |
6283 | +#ifdef ME4000_PORT_DEBUG | |
6284 | +#undef PORT_PDEBUG | |
6285 | +#define PORT_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args) | |
6286 | +#else | |
6287 | +#define PORT_PDEBUG(fmt, args...) // no debugging, do nothing | |
6288 | +#endif | |
6289 | + | |
6290 | +#ifdef ME4000_DEBUG | |
6291 | +#undef PDEBUG | |
6292 | +#define PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args) | |
6293 | +#else | |
6294 | +#define PDEBUG(fmt, args...) // no debugging, do nothing | |
6295 | +#endif | |
6296 | + | |
6297 | +/*============================================================================= | |
6298 | + PCI vendor and device IDs | |
6299 | + ===========================================================================*/ | |
6300 | + | |
6301 | +#define PCI_VENDOR_ID_MEILHAUS 0x1402 | |
6302 | + | |
6303 | +#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 // Low Cost version | |
6304 | + | |
6305 | +#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 // Standard version | |
6306 | +#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 // Isolated version | |
6307 | +#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 // Standard version with Sample and Hold | |
6308 | +#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 // Isolated version with Sample and Hold | |
6309 | + | |
6310 | +#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 // Standard version | |
6311 | +#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 // Isolated version | |
6312 | +#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 // Standard version with Sample and Hold | |
6313 | +#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 // Isolated version with Sample and Hold | |
6314 | + | |
6315 | +#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 // Standard version | |
6316 | +#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 // Isolated version | |
6317 | +#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 // Standard version with Sample and Hold | |
6318 | +#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 // Isolated version with Sample and Hold | |
6319 | + | |
6320 | +/*============================================================================= | |
6321 | + Device names, for entries in /proc/.. | |
6322 | + ===========================================================================*/ | |
6323 | + | |
6324 | +#define ME4000_NAME "me4000" | |
6325 | +#define ME4000_AO_NAME "me4000_ao" | |
6326 | +#define ME4000_AI_NAME "me4000_ai" | |
6327 | +#define ME4000_DIO_NAME "me4000_dio" | |
6328 | +#define ME4000_CNT_NAME "me4000_cnt" | |
6329 | +#define ME4000_EXT_INT_NAME "me4000_ext_int" | |
6330 | + | |
6331 | +/*============================================================================= | |
6332 | + ME-4000 base register offsets | |
6333 | + ===========================================================================*/ | |
6334 | + | |
6335 | +#define ME4000_AO_00_CTRL_REG 0x00 // R/W | |
6336 | +#define ME4000_AO_00_STATUS_REG 0x04 // R/_ | |
6337 | +#define ME4000_AO_00_FIFO_REG 0x08 // _/W | |
6338 | +#define ME4000_AO_00_SINGLE_REG 0x0C // R/W | |
6339 | +#define ME4000_AO_00_TIMER_REG 0x10 // _/W | |
6340 | + | |
6341 | +#define ME4000_AO_01_CTRL_REG 0x18 // R/W | |
6342 | +#define ME4000_AO_01_STATUS_REG 0x1C // R/_ | |
6343 | +#define ME4000_AO_01_FIFO_REG 0x20 // _/W | |
6344 | +#define ME4000_AO_01_SINGLE_REG 0x24 // R/W | |
6345 | +#define ME4000_AO_01_TIMER_REG 0x28 // _/W | |
6346 | + | |
6347 | +#define ME4000_AO_02_CTRL_REG 0x30 // R/W | |
6348 | +#define ME4000_AO_02_STATUS_REG 0x34 // R/_ | |
6349 | +#define ME4000_AO_02_FIFO_REG 0x38 // _/W | |
6350 | +#define ME4000_AO_02_SINGLE_REG 0x3C // R/W | |
6351 | +#define ME4000_AO_02_TIMER_REG 0x40 // _/W | |
6352 | + | |
6353 | +#define ME4000_AO_03_CTRL_REG 0x48 // R/W | |
6354 | +#define ME4000_AO_03_STATUS_REG 0x4C // R/_ | |
6355 | +#define ME4000_AO_03_FIFO_REG 0x50 // _/W | |
6356 | +#define ME4000_AO_03_SINGLE_REG 0x54 // R/W | |
6357 | +#define ME4000_AO_03_TIMER_REG 0x58 // _/W | |
6358 | + | |
6359 | +#define ME4000_AI_CTRL_REG 0x74 // _/W | |
6360 | +#define ME4000_AI_STATUS_REG 0x74 // R/_ | |
6361 | +#define ME4000_AI_CHANNEL_LIST_REG 0x78 // _/W | |
6362 | +#define ME4000_AI_DATA_REG 0x7C // R/_ | |
6363 | +#define ME4000_AI_CHAN_TIMER_REG 0x80 // _/W | |
6364 | +#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 // _/W | |
6365 | +#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 // _/W | |
6366 | +#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8C // _/W | |
6367 | +#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 // _/W | |
6368 | +#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 // _/W | |
6369 | +#define ME4000_AI_START_REG 0x98 // R/_ | |
6370 | + | |
6371 | +#define ME4000_IRQ_STATUS_REG 0x9C // R/_ | |
6372 | + | |
6373 | +#define ME4000_DIO_PORT_0_REG 0xA0 // R/W | |
6374 | +#define ME4000_DIO_PORT_1_REG 0xA4 // R/W | |
6375 | +#define ME4000_DIO_PORT_2_REG 0xA8 // R/W | |
6376 | +#define ME4000_DIO_PORT_3_REG 0xAC // R/W | |
6377 | +#define ME4000_DIO_DIR_REG 0xB0 // R/W | |
6378 | + | |
6379 | +#define ME4000_AO_LOADSETREG_XX 0xB4 // R/W | |
6380 | + | |
6381 | +#define ME4000_DIO_CTRL_REG 0xB8 // R/W | |
6382 | + | |
6383 | +#define ME4000_AO_DEMUX_ADJUST_REG 0xBC // -/W | |
6384 | + | |
6385 | +#define ME4000_AI_SAMPLE_COUNTER_REG 0xC0 // _/W | |
6386 | + | |
6387 | +/*============================================================================= | |
6388 | + Value to adjust Demux | |
6389 | + ===========================================================================*/ | |
6390 | + | |
6391 | +#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4C | |
6392 | + | |
6393 | +/*============================================================================= | |
6394 | + Counter base register offsets | |
6395 | + ===========================================================================*/ | |
6396 | + | |
6397 | +#define ME4000_CNT_COUNTER_0_REG 0x00 | |
6398 | +#define ME4000_CNT_COUNTER_1_REG 0x01 | |
6399 | +#define ME4000_CNT_COUNTER_2_REG 0x02 | |
6400 | +#define ME4000_CNT_CTRL_REG 0x03 | |
6401 | + | |
6402 | +/*============================================================================= | |
6403 | + PLX base register offsets | |
6404 | + ===========================================================================*/ | |
6405 | + | |
6406 | +#define PLX_INTCSR 0x4C // Interrupt control and status register | |
6407 | +#define PLX_ICR 0x50 // Initialization control register | |
6408 | + | |
6409 | +/*============================================================================= | |
6410 | + Bits for the PLX_ICSR register | |
6411 | + ===========================================================================*/ | |
6412 | + | |
6413 | +#define PLX_INTCSR_LOCAL_INT1_EN 0x01 // If set, local interrupt 1 is enabled (r/w) | |
6414 | +#define PLX_INTCSR_LOCAL_INT1_POL 0x02 // If set, local interrupt 1 polarity is active high (r/w) | |
6415 | +#define PLX_INTCSR_LOCAL_INT1_STATE 0x04 // If set, local interrupt 1 is active (r/_) | |
6416 | +#define PLX_INTCSR_LOCAL_INT2_EN 0x08 // If set, local interrupt 2 is enabled (r/w) | |
6417 | +#define PLX_INTCSR_LOCAL_INT2_POL 0x10 // If set, local interrupt 2 polarity is active high (r/w) | |
6418 | +#define PLX_INTCSR_LOCAL_INT2_STATE 0x20 // If set, local interrupt 2 is active (r/_) | |
6419 | +#define PLX_INTCSR_PCI_INT_EN 0x40 // If set, PCI interrupt is enabled (r/w) | |
6420 | +#define PLX_INTCSR_SOFT_INT 0x80 // If set, a software interrupt is generated (r/w) | |
6421 | + | |
6422 | +/*============================================================================= | |
6423 | + Bits for the PLX_ICR register | |
6424 | + ===========================================================================*/ | |
6425 | + | |
6426 | +#define PLX_ICR_BIT_EEPROM_CLOCK_SET 0x01000000 | |
6427 | +#define PLX_ICR_BIT_EEPROM_CHIP_SELECT 0x02000000 | |
6428 | +#define PLX_ICR_BIT_EEPROM_WRITE 0x04000000 | |
6429 | +#define PLX_ICR_BIT_EEPROM_READ 0x08000000 | |
6430 | +#define PLX_ICR_BIT_EEPROM_VALID 0x10000000 | |
6431 | + | |
6432 | +#define PLX_ICR_MASK_EEPROM 0x1F000000 | |
6433 | + | |
6434 | +#define EEPROM_DELAY 1 | |
6435 | + | |
6436 | +/*============================================================================= | |
6437 | + Bits for the ME4000_AO_CTRL_REG register | |
6438 | + ===========================================================================*/ | |
6439 | + | |
6440 | +#define ME4000_AO_CTRL_BIT_MODE_0 0x001 | |
6441 | +#define ME4000_AO_CTRL_BIT_MODE_1 0x002 | |
6442 | +#define ME4000_AO_CTRL_MASK_MODE 0x003 | |
6443 | +#define ME4000_AO_CTRL_BIT_STOP 0x004 | |
6444 | +#define ME4000_AO_CTRL_BIT_ENABLE_FIFO 0x008 | |
6445 | +#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010 | |
6446 | +#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020 | |
6447 | +#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080 | |
6448 | +#define ME4000_AO_CTRL_BIT_ENABLE_DO 0x100 | |
6449 | +#define ME4000_AO_CTRL_BIT_ENABLE_IRQ 0x200 | |
6450 | +#define ME4000_AO_CTRL_BIT_RESET_IRQ 0x400 | |
6451 | +#define ME4000_AO_CTRL_BIT_EX_TRIG_BOTH 0x800 | |
6452 | + | |
6453 | +/*============================================================================= | |
6454 | + Bits for the ME4000_AO_STATUS_REG register | |
6455 | + ===========================================================================*/ | |
6456 | + | |
6457 | +#define ME4000_AO_STATUS_BIT_FSM 0x01 | |
6458 | +#define ME4000_AO_STATUS_BIT_FF 0x02 | |
6459 | +#define ME4000_AO_STATUS_BIT_HF 0x04 | |
6460 | +#define ME4000_AO_STATUS_BIT_EF 0x08 | |
6461 | + | |
6462 | +/*============================================================================= | |
6463 | + Bits for the ME4000_AI_CTRL_REG register | |
6464 | + ===========================================================================*/ | |
6465 | + | |
6466 | +#define ME4000_AI_CTRL_BIT_MODE_0 0x00000001 | |
6467 | +#define ME4000_AI_CTRL_BIT_MODE_1 0x00000002 | |
6468 | +#define ME4000_AI_CTRL_BIT_MODE_2 0x00000004 | |
6469 | +#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008 | |
6470 | +#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010 | |
6471 | +#define ME4000_AI_CTRL_BIT_STOP 0x00000020 | |
6472 | +#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040 | |
6473 | +#define ME4000_AI_CTRL_BIT_DATA_FIFO 0x00000080 | |
6474 | +#define ME4000_AI_CTRL_BIT_FULLSCALE 0x00000100 | |
6475 | +#define ME4000_AI_CTRL_BIT_OFFSET 0x00000200 | |
6476 | +#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400 | |
6477 | +#define ME4000_AI_CTRL_BIT_EX_TRIG 0x00000800 | |
6478 | +#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000 | |
6479 | +#define ME4000_AI_CTRL_BIT_EX_IRQ 0x00002000 | |
6480 | +#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000 | |
6481 | +#define ME4000_AI_CTRL_BIT_LE_IRQ 0x00008000 | |
6482 | +#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000 | |
6483 | +#define ME4000_AI_CTRL_BIT_HF_IRQ 0x00020000 | |
6484 | +#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000 | |
6485 | +#define ME4000_AI_CTRL_BIT_SC_IRQ 0x00080000 | |
6486 | +#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000 | |
6487 | +#define ME4000_AI_CTRL_BIT_SC_RELOAD 0x00200000 | |
6488 | +#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000 | |
6489 | + | |
6490 | +/*============================================================================= | |
6491 | + Bits for the ME4000_AI_STATUS_REG register | |
6492 | + ===========================================================================*/ | |
6493 | + | |
6494 | +#define ME4000_AI_STATUS_BIT_EF_CHANNEL 0x00400000 | |
6495 | +#define ME4000_AI_STATUS_BIT_HF_CHANNEL 0x00800000 | |
6496 | +#define ME4000_AI_STATUS_BIT_FF_CHANNEL 0x01000000 | |
6497 | +#define ME4000_AI_STATUS_BIT_EF_DATA 0x02000000 | |
6498 | +#define ME4000_AI_STATUS_BIT_HF_DATA 0x04000000 | |
6499 | +#define ME4000_AI_STATUS_BIT_FF_DATA 0x08000000 | |
6500 | +#define ME4000_AI_STATUS_BIT_LE 0x10000000 | |
6501 | +#define ME4000_AI_STATUS_BIT_FSM 0x20000000 | |
6502 | + | |
6503 | +/*============================================================================= | |
6504 | + Bits for the ME4000_IRQ_STATUS_REG register | |
6505 | + ===========================================================================*/ | |
6506 | + | |
6507 | +#define ME4000_IRQ_STATUS_BIT_EX 0x01 | |
6508 | +#define ME4000_IRQ_STATUS_BIT_LE 0x02 | |
6509 | +#define ME4000_IRQ_STATUS_BIT_AI_HF 0x04 | |
6510 | +#define ME4000_IRQ_STATUS_BIT_AO_0_HF 0x08 | |
6511 | +#define ME4000_IRQ_STATUS_BIT_AO_1_HF 0x10 | |
6512 | +#define ME4000_IRQ_STATUS_BIT_AO_2_HF 0x20 | |
6513 | +#define ME4000_IRQ_STATUS_BIT_AO_3_HF 0x40 | |
6514 | +#define ME4000_IRQ_STATUS_BIT_SC 0x80 | |
6515 | + | |
6516 | +/*============================================================================= | |
6517 | + Bits for the ME4000_DIO_CTRL_REG register | |
6518 | + ===========================================================================*/ | |
6519 | + | |
6520 | +#define ME4000_DIO_CTRL_BIT_MODE_0 0X0001 | |
6521 | +#define ME4000_DIO_CTRL_BIT_MODE_1 0X0002 | |
6522 | +#define ME4000_DIO_CTRL_BIT_MODE_2 0X0004 | |
6523 | +#define ME4000_DIO_CTRL_BIT_MODE_3 0X0008 | |
6524 | +#define ME4000_DIO_CTRL_BIT_MODE_4 0X0010 | |
6525 | +#define ME4000_DIO_CTRL_BIT_MODE_5 0X0020 | |
6526 | +#define ME4000_DIO_CTRL_BIT_MODE_6 0X0040 | |
6527 | +#define ME4000_DIO_CTRL_BIT_MODE_7 0X0080 | |
6528 | + | |
6529 | +#define ME4000_DIO_CTRL_BIT_FUNCTION_0 0X0100 | |
6530 | +#define ME4000_DIO_CTRL_BIT_FUNCTION_1 0X0200 | |
6531 | + | |
6532 | +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 0X0400 | |
6533 | +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 0X0800 | |
6534 | +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 0X1000 | |
6535 | +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 0X2000 | |
6536 | + | |
6537 | +/*============================================================================= | |
6538 | + Bits for the ME4000_CNT_CTRL_REG register | |
6539 | + ===========================================================================*/ | |
6540 | + | |
6541 | +#define ME4000_CNT_CTRL_BIT_COUNTER_0 0x00 | |
6542 | +#define ME4000_CNT_CTRL_BIT_COUNTER_1 0x40 | |
6543 | +#define ME4000_CNT_CTRL_BIT_COUNTER_2 0x80 | |
6544 | + | |
6545 | +#define ME4000_CNT_CTRL_BIT_MODE_0 0x00 // Change state if zero crossing | |
6546 | +#define ME4000_CNT_CTRL_BIT_MODE_1 0x02 // Retriggerable One-Shot | |
6547 | +#define ME4000_CNT_CTRL_BIT_MODE_2 0x04 // Asymmetrical divider | |
6548 | +#define ME4000_CNT_CTRL_BIT_MODE_3 0x06 // Symmetrical divider | |
6549 | +#define ME4000_CNT_CTRL_BIT_MODE_4 0x08 // Counter start by software trigger | |
6550 | +#define ME4000_CNT_CTRL_BIT_MODE_5 0x0A // Counter start by hardware trigger | |
6551 | + | |
6552 | +/*============================================================================= | |
6553 | + Extract information from minor device number | |
6554 | + ===========================================================================*/ | |
6555 | + | |
6556 | +#define AO_BOARD(dev) ((MINOR(dev) >> 6) & 0x3) | |
6557 | +#define AO_PORT(dev) ((MINOR(dev) >> 2) & 0xF) | |
6558 | +#define AO_MODE(dev) (MINOR(dev) & 0x3) | |
6559 | + | |
6560 | +#define AI_BOARD(dev) ((MINOR(dev) >> 3) & 0x1F) | |
6561 | +#define AI_MODE(dev) (MINOR(dev) & 0x7) | |
6562 | + | |
6563 | +#define DIO_BOARD(dev) (MINOR(dev)) | |
6564 | + | |
6565 | +#define CNT_BOARD(dev) (MINOR(dev)) | |
6566 | + | |
6567 | +#define EXT_INT_BOARD(dev) (MINOR(dev)) | |
6568 | + | |
6569 | +/*============================================================================= | |
6570 | + Circular buffer used for analog input/output reads/writes. | |
6571 | + ===========================================================================*/ | |
6572 | + | |
6573 | +typedef struct me4000_circ_buf { | |
6574 | + s16 *buf; | |
6575 | + int volatile head; | |
6576 | + int volatile tail; | |
6577 | +} me4000_circ_buf_t; | |
6578 | + | |
6579 | +/*============================================================================= | |
6580 | + Information about the hardware capabilities | |
6581 | + ===========================================================================*/ | |
6582 | + | |
6583 | +typedef struct me4000_ao_info { | |
6584 | + int count; | |
6585 | + int fifo_count; | |
6586 | +} me4000_ao_info_t; | |
6587 | + | |
6588 | +typedef struct me4000_ai_info { | |
6589 | + int count; | |
6590 | + int sh_count; | |
6591 | + int diff_count; | |
6592 | + int ex_trig_analog; | |
6593 | +} me4000_ai_info_t; | |
6594 | + | |
6595 | +typedef struct me4000_dio_info { | |
6596 | + int count; | |
6597 | +} me4000_dio_info_t; | |
6598 | + | |
6599 | +typedef struct me4000_cnt_info { | |
6600 | + int count; | |
6601 | +} me4000_cnt_info_t; | |
6602 | + | |
6603 | +typedef struct me4000_board { | |
6604 | + u16 vendor_id; | |
6605 | + u16 device_id; | |
6606 | + me4000_ao_info_t ao; | |
6607 | + me4000_ai_info_t ai; | |
6608 | + me4000_dio_info_t dio; | |
6609 | + me4000_cnt_info_t cnt; | |
6610 | +} me4000_board_t; | |
6611 | + | |
6612 | +static me4000_board_t me4000_boards[] = { | |
6613 | + {PCI_VENDOR_ID_MEILHAUS, 0x4610, {0, 0}, {16, 0, 0, 0}, {4}, {3}}, | |
6614 | + | |
6615 | + {PCI_VENDOR_ID_MEILHAUS, 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0}}, | |
6616 | + | |
6617 | + {PCI_VENDOR_ID_MEILHAUS, 0x4660, {2, 0}, {16, 0, 0, 0}, {4}, {3}}, | |
6618 | + {PCI_VENDOR_ID_MEILHAUS, 0x4661, {2, 0}, {16, 0, 0, 0}, {4}, {3}}, | |
6619 | + {PCI_VENDOR_ID_MEILHAUS, 0x4662, {2, 0}, {16, 8, 0, 0}, {4}, {3}}, | |
6620 | + {PCI_VENDOR_ID_MEILHAUS, 0x4663, {2, 0}, {16, 8, 0, 0}, {4}, {3}}, | |
6621 | + | |
6622 | + {PCI_VENDOR_ID_MEILHAUS, 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3}}, | |
6623 | + {PCI_VENDOR_ID_MEILHAUS, 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3}}, | |
6624 | + {PCI_VENDOR_ID_MEILHAUS, 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3}}, | |
6625 | + {PCI_VENDOR_ID_MEILHAUS, 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3}}, | |
6626 | + | |
6627 | + {PCI_VENDOR_ID_MEILHAUS, 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3}}, | |
6628 | + {PCI_VENDOR_ID_MEILHAUS, 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3}}, | |
6629 | + {PCI_VENDOR_ID_MEILHAUS, 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3}}, | |
6630 | + {PCI_VENDOR_ID_MEILHAUS, 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3}}, | |
6631 | + | |
6632 | + {0}, | |
6633 | +}; | |
6634 | + | |
6635 | +#define ME4000_BOARD_VERSIONS (sizeof(me4000_boards) / sizeof(me4000_board_t) - 1) | |
6636 | + | |
6637 | +/*============================================================================= | |
6638 | + PCI device table. | |
6639 | + This is used by modprobe to translate PCI IDs to drivers. | |
6640 | + ===========================================================================*/ | |
6641 | + | |
6642 | +static struct pci_device_id me4000_pci_table[] __devinitdata = { | |
6643 | + {PCI_VENDOR_ID_MEILHAUS, 0x4610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6644 | + | |
6645 | + {PCI_VENDOR_ID_MEILHAUS, 0x4650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6646 | + | |
6647 | + {PCI_VENDOR_ID_MEILHAUS, 0x4660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6648 | + {PCI_VENDOR_ID_MEILHAUS, 0x4661, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6649 | + {PCI_VENDOR_ID_MEILHAUS, 0x4662, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6650 | + {PCI_VENDOR_ID_MEILHAUS, 0x4663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6651 | + | |
6652 | + {PCI_VENDOR_ID_MEILHAUS, 0x4670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6653 | + {PCI_VENDOR_ID_MEILHAUS, 0x4671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6654 | + {PCI_VENDOR_ID_MEILHAUS, 0x4672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6655 | + {PCI_VENDOR_ID_MEILHAUS, 0x4673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6656 | + | |
6657 | + {PCI_VENDOR_ID_MEILHAUS, 0x4680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6658 | + {PCI_VENDOR_ID_MEILHAUS, 0x4681, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6659 | + {PCI_VENDOR_ID_MEILHAUS, 0x4682, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6660 | + {PCI_VENDOR_ID_MEILHAUS, 0x4683, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
6661 | + | |
6662 | + {0} | |
6663 | +}; | |
6664 | + | |
6665 | +MODULE_DEVICE_TABLE(pci, me4000_pci_table); | |
6666 | + | |
6667 | +/*============================================================================= | |
6668 | + Global board and subdevice information structures | |
6669 | + ===========================================================================*/ | |
6670 | + | |
6671 | +typedef struct me4000_info { | |
6672 | + struct list_head list; // List of all detected boards | |
6673 | + int board_count; // Index of the board after detection | |
6674 | + | |
6675 | + unsigned long plx_regbase; // PLX configuration space base address | |
6676 | + unsigned long me4000_regbase; // Base address of the ME4000 | |
6677 | + unsigned long timer_regbase; // Base address of the timer circuit | |
6678 | + unsigned long program_regbase; // Base address to set the program pin for the xilinx | |
6679 | + | |
6680 | + unsigned long plx_regbase_size; // PLX register set space | |
6681 | + unsigned long me4000_regbase_size; // ME4000 register set space | |
6682 | + unsigned long timer_regbase_size; // Timer circuit register set space | |
6683 | + unsigned long program_regbase_size; // Size of program base address of the ME4000 | |
6684 | + | |
6685 | + unsigned int serial_no; // Serial number of the board | |
6686 | + unsigned char hw_revision; // Hardware revision of the board | |
6687 | + unsigned short vendor_id; // Meilhaus vendor id (0x1402) | |
6688 | + unsigned short device_id; // Device ID | |
6689 | + | |
6690 | + int pci_bus_no; // PCI bus number | |
6691 | + int pci_dev_no; // PCI device number | |
6692 | + int pci_func_no; // PCI function number | |
6693 | + struct pci_dev *pci_dev_p; // General PCI information | |
6694 | + | |
6695 | + me4000_board_t *board_p; // Holds the board capabilities | |
6696 | + | |
6697 | + unsigned int irq; // IRQ assigned from the PCI BIOS | |
6698 | + unsigned int irq_count; // Count of external interrupts | |
6699 | + | |
6700 | + spinlock_t preload_lock; // Guards the analog output preload register | |
6701 | + spinlock_t ai_ctrl_lock; // Guards the analog input control register | |
6702 | + | |
6703 | + struct list_head ao_context_list; // List with analog output specific context | |
6704 | + struct me4000_ai_context *ai_context; // Analog input specific context | |
6705 | + struct me4000_dio_context *dio_context; // Digital I/O specific context | |
6706 | + struct me4000_cnt_context *cnt_context; // Counter specific context | |
6707 | + struct me4000_ext_int_context *ext_int_context; // External interrupt specific context | |
6708 | +} me4000_info_t; | |
6709 | + | |
6710 | +typedef struct me4000_ao_context { | |
6711 | + struct list_head list; // linked list of me4000_ao_context_t | |
6712 | + int index; // Index in the list | |
6713 | + int mode; // Indicates mode (0 = single, 1 = wraparound, 2 = continous) | |
6714 | + int dac_in_use; // Indicates if already opend | |
6715 | + spinlock_t use_lock; // Guards in_use | |
6716 | + spinlock_t int_lock; // Used when locking out interrupts | |
6717 | + me4000_circ_buf_t circ_buf; // Circular buffer | |
6718 | + wait_queue_head_t wait_queue; // Wait queue to sleep while blocking write | |
6719 | + me4000_info_t *board_info; | |
6720 | + unsigned int irq; // The irq associated with this ADC | |
6721 | + int volatile pipe_flag; // Indicates broken pipe set from me4000_ao_isr() | |
6722 | + unsigned long ctrl_reg; | |
6723 | + unsigned long status_reg; | |
6724 | + unsigned long fifo_reg; | |
6725 | + unsigned long single_reg; | |
6726 | + unsigned long timer_reg; | |
6727 | + unsigned long irq_status_reg; | |
6728 | + unsigned long preload_reg; | |
6729 | + struct fasync_struct *fasync_p; // Queue for asynchronous notification | |
6730 | +} me4000_ao_context_t; | |
6731 | + | |
6732 | +typedef struct me4000_ai_context { | |
6733 | + struct list_head list; // linked list of me4000_ai_info_t | |
6734 | + int mode; // Indicates mode | |
6735 | + int in_use; // Indicates if already opend | |
6736 | + spinlock_t use_lock; // Guards in_use | |
6737 | + spinlock_t int_lock; // Used when locking out interrupts | |
6738 | + int number; // Number of the DAC | |
6739 | + unsigned int irq; // The irq associated with this ADC | |
6740 | + me4000_circ_buf_t circ_buf; // Circular buffer | |
6741 | + wait_queue_head_t wait_queue; // Wait queue to sleep while blocking read | |
6742 | + me4000_info_t *board_info; | |
6743 | + | |
6744 | + struct fasync_struct *fasync_p; // Queue for asynchronous notification | |
6745 | + | |
6746 | + unsigned long ctrl_reg; | |
6747 | + unsigned long status_reg; | |
6748 | + unsigned long channel_list_reg; | |
6749 | + unsigned long data_reg; | |
6750 | + unsigned long chan_timer_reg; | |
6751 | + unsigned long chan_pre_timer_reg; | |
6752 | + unsigned long scan_timer_low_reg; | |
6753 | + unsigned long scan_timer_high_reg; | |
6754 | + unsigned long scan_pre_timer_low_reg; | |
6755 | + unsigned long scan_pre_timer_high_reg; | |
6756 | + unsigned long start_reg; | |
6757 | + unsigned long irq_status_reg; | |
6758 | + unsigned long sample_counter_reg; | |
6759 | + | |
6760 | + unsigned long chan_timer; | |
6761 | + unsigned long chan_pre_timer; | |
6762 | + unsigned long scan_timer_low; | |
6763 | + unsigned long scan_timer_high; | |
6764 | + unsigned long channel_list_count; | |
6765 | + unsigned long sample_counter; | |
6766 | + int sample_counter_reload; | |
6767 | +} me4000_ai_context_t; | |
6768 | + | |
6769 | +typedef struct me4000_dio_context { | |
6770 | + struct list_head list; // linked list of me4000_dio_context_t | |
6771 | + int in_use; // Indicates if already opend | |
6772 | + spinlock_t use_lock; // Guards in_use | |
6773 | + int number; | |
6774 | + int dio_count; | |
6775 | + me4000_info_t *board_info; | |
6776 | + unsigned long dir_reg; | |
6777 | + unsigned long ctrl_reg; | |
6778 | + unsigned long port_0_reg; | |
6779 | + unsigned long port_1_reg; | |
6780 | + unsigned long port_2_reg; | |
6781 | + unsigned long port_3_reg; | |
6782 | +} me4000_dio_context_t; | |
6783 | + | |
6784 | +typedef struct me4000_cnt_context { | |
6785 | + struct list_head list; // linked list of me4000_dio_context_t | |
6786 | + int in_use; // Indicates if already opend | |
6787 | + spinlock_t use_lock; // Guards in_use | |
6788 | + int number; | |
6789 | + int cnt_count; | |
6790 | + me4000_info_t *board_info; | |
6791 | + unsigned long ctrl_reg; | |
6792 | + unsigned long counter_0_reg; | |
6793 | + unsigned long counter_1_reg; | |
6794 | + unsigned long counter_2_reg; | |
6795 | +} me4000_cnt_context_t; | |
6796 | + | |
6797 | +typedef struct me4000_ext_int_context { | |
6798 | + struct list_head list; // linked list of me4000_dio_context_t | |
6799 | + int in_use; // Indicates if already opend | |
6800 | + spinlock_t use_lock; // Guards in_use | |
6801 | + int number; | |
6802 | + me4000_info_t *board_info; | |
6803 | + unsigned int irq; | |
6804 | + unsigned long int_count; | |
6805 | + struct fasync_struct *fasync_ptr; | |
6806 | + unsigned long ctrl_reg; | |
6807 | + unsigned long irq_status_reg; | |
6808 | +} me4000_ext_int_context_t; | |
6809 | + | |
6810 | +#endif | |
6811 | + | |
6812 | +/*============================================================================= | |
6813 | + Application include section starts here | |
6814 | + ===========================================================================*/ | |
6815 | + | |
6816 | +/*----------------------------------------------------------------------------- | |
6817 | + Defines for analog input | |
6818 | + ----------------------------------------------------------------------------*/ | |
6819 | + | |
6820 | +/* General stuff */ | |
6821 | +#define ME4000_AI_FIFO_COUNT 2048 | |
6822 | + | |
6823 | +#define ME4000_AI_MIN_TICKS 66 | |
6824 | +#define ME4000_AI_MAX_SCAN_TICKS 0xFFFFFFFFFFLL | |
6825 | + | |
6826 | +#define ME4000_AI_BUFFER_SIZE (32 * 1024) // Size in bytes | |
6827 | + | |
6828 | +#define ME4000_AI_BUFFER_COUNT ((ME4000_AI_BUFFER_SIZE) / 2) // Size in values | |
6829 | + | |
6830 | +/* Channel list defines and masks */ | |
6831 | +#define ME4000_AI_CHANNEL_LIST_COUNT 1024 | |
6832 | + | |
6833 | +#define ME4000_AI_LIST_INPUT_SINGLE_ENDED 0x000 | |
6834 | +#define ME4000_AI_LIST_INPUT_DIFFERENTIAL 0x020 | |
6835 | + | |
6836 | +#define ME4000_AI_LIST_RANGE_BIPOLAR_10 0x000 | |
6837 | +#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 0x040 | |
6838 | +#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 0x080 | |
6839 | +#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0 | |
6840 | + | |
6841 | +#define ME4000_AI_LIST_LAST_ENTRY 0x100 | |
6842 | + | |
6843 | +/* External trigger defines */ | |
6844 | +#define ME4000_AI_TRIGGER_SOFTWARE 0x0 // Use only with API | |
6845 | +#define ME4000_AI_TRIGGER_EXT_DIGITAL 0x1 | |
6846 | +#define ME4000_AI_TRIGGER_EXT_ANALOG 0x2 | |
6847 | + | |
6848 | +#define ME4000_AI_TRIGGER_EXT_EDGE_RISING 0x0 | |
6849 | +#define ME4000_AI_TRIGGER_EXT_EDGE_FALLING 0x1 | |
6850 | +#define ME4000_AI_TRIGGER_EXT_EDGE_BOTH 0x2 | |
6851 | + | |
6852 | +/* Sample and Hold */ | |
6853 | +#define ME4000_AI_SIMULTANEOUS_DISABLE 0x0 | |
6854 | +#define ME4000_AI_SIMULTANEOUS_ENABLE 0x1 | |
6855 | + | |
6856 | +/* Defines for the Sample Counter */ | |
6857 | +#define ME4000_AI_SC_RELOAD 0x0 | |
6858 | +#define ME4000_AI_SC_ONCE 0x1 | |
6859 | + | |
6860 | +/* Modes for analog input */ | |
6861 | +#define ME4000_AI_ACQ_MODE_SINGLE 0x00 // Catch one single value | |
6862 | +#define ME4000_AI_ACQ_MODE_SOFTWARE 0x01 // Continous sampling with software start | |
6863 | +#define ME4000_AI_ACQ_MODE_EXT 0x02 // Continous sampling with external trigger start | |
6864 | +#define ME4000_AI_ACQ_MODE_EXT_SINGLE_VALUE 0x03 // Sample one value by external trigger | |
6865 | +#define ME4000_AI_ACQ_MODE_EXT_SINGLE_CHANLIST 0x04 // Sample one channel list by external trigger | |
6866 | + | |
6867 | +/* Staus of AI FSM */ | |
6868 | +#define ME4000_AI_STATUS_IDLE 0x0 | |
6869 | +#define ME4000_AI_STATUS_BUSY 0x1 | |
6870 | + | |
6871 | +/* Voltages for calibration */ | |
6872 | +#define ME4000_AI_GAIN_1_UNI_OFFSET 10.0E-3 | |
6873 | +#define ME4000_AI_GAIN_1_UNI_FULLSCALE 9950.0E-3 | |
6874 | +#define ME4000_AI_GAIN_1_BI_OFFSET 0.0 | |
6875 | +#define ME4000_AI_GAIN_1_BI_FULLSCALE 9950.0E-3 | |
6876 | +#define ME4000_AI_GAIN_4_UNI_OFFSET 10.0E-3 | |
6877 | +#define ME4000_AI_GAIN_4_UNI_FULLSCALE 2450.0E-3 | |
6878 | +#define ME4000_AI_GAIN_4_BI_OFFSET 0.0 | |
6879 | +#define ME4000_AI_GAIN_4_BI_FULLSCALE 2450.0E-3 | |
6880 | + | |
6881 | +/* Ideal digits for calibration */ | |
6882 | +#define ME4000_AI_GAIN_1_UNI_OFFSET_DIGITS (-32702) | |
6883 | +#define ME4000_AI_GAIN_1_UNI_FULLSCALE_DIGITS 32440 | |
6884 | +#define ME4000_AI_GAIN_1_BI_OFFSET_DIGITS 0 | |
6885 | +#define ME4000_AI_GAIN_1_BI_FULLSCALE_DIGITS 32604 | |
6886 | +#define ME4000_AI_GAIN_4_UNI_OFFSET_DIGITS (-32505) | |
6887 | +#define ME4000_AI_GAIN_4_UNI_FULLSCALE_DIGITS 31457 | |
6888 | +#define ME4000_AI_GAIN_4_BI_OFFSET_DIGITS 0 | |
6889 | +#define ME4000_AI_GAIN_4_BI_FULLSCALE_DIGITS 32113 | |
6890 | + | |
6891 | +/*----------------------------------------------------------------------------- | |
6892 | + Defines for analog output | |
6893 | + ----------------------------------------------------------------------------*/ | |
6894 | + | |
6895 | +/* General stuff */ | |
6896 | +#define ME4000_AO_FIFO_COUNT (4 * 1024) | |
6897 | + | |
6898 | +#define ME4000_AO_MIN_TICKS 66 | |
6899 | + | |
6900 | +#define ME4000_AO_BUFFER_SIZE (32 * 1024) // Size in bytes | |
6901 | + | |
6902 | +#define ME4000_AO_BUFFER_COUNT ((ME4000_AO_BUFFER_SIZE) / 2) // Size in values | |
6903 | + | |
6904 | +/* Conversion modes for analog output */ | |
6905 | +#define ME4000_AO_CONV_MODE_SINGLE 0x0 | |
6906 | +#define ME4000_AO_CONV_MODE_WRAPAROUND 0x1 | |
6907 | +#define ME4000_AO_CONV_MODE_CONTINUOUS 0x2 | |
6908 | + | |
6909 | +/* Trigger setup */ | |
6910 | +#define ME4000_AO_TRIGGER_EXT_EDGE_RISING 0x0 | |
6911 | +#define ME4000_AO_TRIGGER_EXT_EDGE_FALLING 0x1 | |
6912 | +#define ME4000_AO_TRIGGER_EXT_EDGE_BOTH 0x2 | |
6913 | + | |
6914 | +/* Status of AO FSM */ | |
6915 | +#define ME4000_AO_STATUS_IDLE 0x0 | |
6916 | +#define ME4000_AO_STATUS_BUSY 0x1 | |
6917 | + | |
6918 | +/*----------------------------------------------------------------------------- | |
6919 | + Defines for eeprom | |
6920 | + ----------------------------------------------------------------------------*/ | |
6921 | + | |
6922 | +#define ME4000_EEPROM_CMD_READ 0x180 | |
6923 | +#define ME4000_EEPROM_CMD_WRITE_ENABLE 0x130 | |
6924 | +#define ME4000_EEPROM_CMD_WRITE_DISABLE 0x100 | |
6925 | +#define ME4000_EEPROM_CMD_WRITE 0x1400000 | |
6926 | + | |
6927 | +#define ME4000_EEPROM_CMD_LENGTH_READ 9 | |
6928 | +#define ME4000_EEPROM_CMD_LENGTH_WRITE_ENABLE 9 | |
6929 | +#define ME4000_EEPROM_CMD_LENGTH_WRITE_DISABLE 9 | |
6930 | +#define ME4000_EEPROM_CMD_LENGTH_WRITE 25 | |
6931 | + | |
6932 | +#define ME4000_EEPROM_ADR_DATE_HIGH 0x32 | |
6933 | +#define ME4000_EEPROM_ADR_DATE_LOW 0x33 | |
6934 | + | |
6935 | +#define ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET 0x34 | |
6936 | +#define ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE 0x35 | |
6937 | +#define ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET 0x36 | |
6938 | +#define ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE 0x37 | |
6939 | +#define ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET 0x38 | |
6940 | +#define ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE 0x39 | |
6941 | + | |
6942 | +#define ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET 0x3A | |
6943 | +#define ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE 0x3B | |
6944 | +#define ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET 0x3C | |
6945 | +#define ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE 0x3D | |
6946 | +#define ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET 0x3E | |
6947 | +#define ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE 0x3F | |
6948 | + | |
6949 | +#define ME4000_EEPROM_ADR_LENGTH 6 | |
6950 | +#define ME4000_EEPROM_DATA_LENGTH 16 | |
6951 | + | |
6952 | +/*----------------------------------------------------------------------------- | |
6953 | + Defines for digital I/O | |
6954 | + ----------------------------------------------------------------------------*/ | |
6955 | + | |
6956 | +#define ME4000_DIO_PORT_A 0x0 | |
6957 | +#define ME4000_DIO_PORT_B 0x1 | |
6958 | +#define ME4000_DIO_PORT_C 0x2 | |
6959 | +#define ME4000_DIO_PORT_D 0x3 | |
6960 | + | |
6961 | +#define ME4000_DIO_PORT_INPUT 0x0 | |
6962 | +#define ME4000_DIO_PORT_OUTPUT 0x1 | |
6963 | +#define ME4000_DIO_FIFO_LOW 0x2 | |
6964 | +#define ME4000_DIO_FIFO_HIGH 0x3 | |
6965 | + | |
6966 | +#define ME4000_DIO_FUNCTION_PATTERN 0x0 | |
6967 | +#define ME4000_DIO_FUNCTION_DEMUX 0x1 | |
6968 | +#define ME4000_DIO_FUNCTION_MUX 0x2 | |
6969 | + | |
6970 | +/*----------------------------------------------------------------------------- | |
6971 | + Defines for counters | |
6972 | + ----------------------------------------------------------------------------*/ | |
6973 | + | |
6974 | +#define ME4000_CNT_COUNTER_0 0 | |
6975 | +#define ME4000_CNT_COUNTER_1 1 | |
6976 | +#define ME4000_CNT_COUNTER_2 2 | |
6977 | + | |
6978 | +#define ME4000_CNT_MODE_0 0 // Change state if zero crossing | |
6979 | +#define ME4000_CNT_MODE_1 1 // Retriggerable One-Shot | |
6980 | +#define ME4000_CNT_MODE_2 2 // Asymmetrical divider | |
6981 | +#define ME4000_CNT_MODE_3 3 // Symmetrical divider | |
6982 | +#define ME4000_CNT_MODE_4 4 // Counter start by software trigger | |
6983 | +#define ME4000_CNT_MODE_5 5 // Counter start by hardware trigger | |
6984 | + | |
6985 | +/*----------------------------------------------------------------------------- | |
6986 | + General type definitions | |
6987 | + ----------------------------------------------------------------------------*/ | |
6988 | + | |
6989 | +typedef struct me4000_user_info { | |
6990 | + int board_count; // Index of the board after detection | |
6991 | + unsigned long plx_regbase; // PLX configuration space base address | |
6992 | + unsigned long me4000_regbase; // Base address of the ME4000 | |
6993 | + unsigned long plx_regbase_size; // PLX register set space | |
6994 | + unsigned long me4000_regbase_size; // ME4000 register set space | |
6995 | + unsigned long serial_no; // Serial number of the board | |
6996 | + unsigned char hw_revision; // Hardware revision of the board | |
6997 | + unsigned short vendor_id; // Meilhaus vendor id (0x1402) | |
6998 | + unsigned short device_id; // Device ID | |
6999 | + int pci_bus_no; // PCI bus number | |
7000 | + int pci_dev_no; // PCI device number | |
7001 | + int pci_func_no; // PCI function number | |
7002 | + char irq; // IRQ assigned from the PCI BIOS | |
7003 | + int irq_count; // Count of external interrupts | |
7004 | + | |
7005 | + int driver_version; // Version of the driver release | |
7006 | + | |
7007 | + int ao_count; // Count of analog output channels | |
7008 | + int ao_fifo_count; // Count fo analog output fifos | |
7009 | + | |
7010 | + int ai_count; // Count of analog input channels | |
7011 | + int ai_sh_count; // Count of sample and hold devices | |
7012 | + int ai_ex_trig_analog; // Flag to indicate if analogous external trigger is available | |
7013 | + | |
7014 | + int dio_count; // Count of digital I/O ports | |
7015 | + | |
7016 | + int cnt_count; // Count of counters | |
7017 | +} me4000_user_info_t; | |
7018 | + | |
7019 | +/*----------------------------------------------------------------------------- | |
7020 | + Type definitions for analog output | |
7021 | + ----------------------------------------------------------------------------*/ | |
7022 | + | |
7023 | +typedef struct me4000_ao_channel_list { | |
7024 | + unsigned long count; | |
7025 | + unsigned long *list; | |
7026 | +} me4000_ao_channel_list_t; | |
7027 | + | |
7028 | +/*----------------------------------------------------------------------------- | |
7029 | + Type definitions for analog input | |
7030 | + ----------------------------------------------------------------------------*/ | |
7031 | + | |
7032 | +typedef struct me4000_ai_channel_list { | |
7033 | + unsigned long count; | |
7034 | + unsigned long *list; | |
7035 | +} me4000_ai_channel_list_t; | |
7036 | + | |
7037 | +typedef struct me4000_ai_timer { | |
7038 | + unsigned long pre_chan; | |
7039 | + unsigned long chan; | |
7040 | + unsigned long scan_low; | |
7041 | + unsigned long scan_high; | |
7042 | +} me4000_ai_timer_t; | |
7043 | + | |
7044 | +typedef struct me4000_ai_config { | |
7045 | + me4000_ai_timer_t timer; | |
7046 | + me4000_ai_channel_list_t channel_list; | |
7047 | + int sh; | |
7048 | +} me4000_ai_config_t; | |
7049 | + | |
7050 | +typedef struct me4000_ai_single { | |
7051 | + int channel; | |
7052 | + int range; | |
7053 | + int mode; | |
7054 | + short value; | |
7055 | + unsigned long timeout; | |
7056 | +} me4000_ai_single_t; | |
7057 | + | |
7058 | +typedef struct me4000_ai_trigger { | |
7059 | + int mode; | |
7060 | + int edge; | |
7061 | +} me4000_ai_trigger_t; | |
7062 | + | |
7063 | +typedef struct me4000_ai_sc { | |
7064 | + unsigned long value; | |
7065 | + int reload; | |
7066 | +} me4000_ai_sc_t; | |
7067 | + | |
7068 | +/*----------------------------------------------------------------------------- | |
7069 | + Type definitions for eeprom | |
7070 | + ----------------------------------------------------------------------------*/ | |
7071 | + | |
7072 | +typedef struct me4000_eeprom { | |
7073 | + unsigned long date; | |
7074 | + short uni_10_offset; | |
7075 | + short uni_10_fullscale; | |
7076 | + short uni_2_5_offset; | |
7077 | + short uni_2_5_fullscale; | |
7078 | + short bi_10_offset; | |
7079 | + short bi_10_fullscale; | |
7080 | + short bi_2_5_offset; | |
7081 | + short bi_2_5_fullscale; | |
7082 | + short diff_10_offset; | |
7083 | + short diff_10_fullscale; | |
7084 | + short diff_2_5_offset; | |
7085 | + short diff_2_5_fullscale; | |
7086 | +} me4000_eeprom_t; | |
7087 | + | |
7088 | +/*----------------------------------------------------------------------------- | |
7089 | + Type definitions for digital I/O | |
7090 | + ----------------------------------------------------------------------------*/ | |
7091 | + | |
7092 | +typedef struct me4000_dio_config { | |
7093 | + int port; | |
7094 | + int mode; | |
7095 | + int function; | |
7096 | +} me4000_dio_config_t; | |
7097 | + | |
7098 | +typedef struct me4000_dio_byte { | |
7099 | + int port; | |
7100 | + unsigned char byte; | |
7101 | +} me4000_dio_byte_t; | |
7102 | + | |
7103 | +/*----------------------------------------------------------------------------- | |
7104 | + Type definitions for counters | |
7105 | + ----------------------------------------------------------------------------*/ | |
7106 | + | |
7107 | +typedef struct me4000_cnt { | |
7108 | + int counter; | |
7109 | + unsigned short value; | |
7110 | +} me4000_cnt_t; | |
7111 | + | |
7112 | +typedef struct me4000_cnt_config { | |
7113 | + int counter; | |
7114 | + int mode; | |
7115 | +} me4000_cnt_config_t; | |
7116 | + | |
7117 | +/*----------------------------------------------------------------------------- | |
7118 | + Type definitions for external interrupt | |
7119 | + ----------------------------------------------------------------------------*/ | |
7120 | + | |
7121 | +typedef struct { | |
7122 | + int int1_count; | |
7123 | + int int2_count; | |
7124 | +} me4000_int_type; | |
7125 | + | |
7126 | +/*----------------------------------------------------------------------------- | |
7127 | + The ioctls of the board | |
7128 | + ----------------------------------------------------------------------------*/ | |
7129 | + | |
7130 | +#define ME4000_IOCTL_MAXNR 50 | |
7131 | +#define ME4000_MAGIC 'y' | |
7132 | +#define ME4000_GET_USER_INFO _IOR (ME4000_MAGIC, 0, me4000_user_info_t) | |
7133 | + | |
7134 | +#define ME4000_AO_START _IOW (ME4000_MAGIC, 1, unsigned long) | |
7135 | +#define ME4000_AO_STOP _IO (ME4000_MAGIC, 2) | |
7136 | +#define ME4000_AO_IMMEDIATE_STOP _IO (ME4000_MAGIC, 3) | |
7137 | +#define ME4000_AO_RESET _IO (ME4000_MAGIC, 4) | |
7138 | +#define ME4000_AO_PRELOAD _IO (ME4000_MAGIC, 5) | |
7139 | +#define ME4000_AO_PRELOAD_UPDATE _IO (ME4000_MAGIC, 6) | |
7140 | +#define ME4000_AO_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 7) | |
7141 | +#define ME4000_AO_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 8) | |
7142 | +#define ME4000_AO_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 9, int) | |
7143 | +#define ME4000_AO_TIMER_SET_DIVISOR _IOW (ME4000_MAGIC, 10, unsigned long) | |
7144 | +#define ME4000_AO_ENABLE_DO _IO (ME4000_MAGIC, 11) | |
7145 | +#define ME4000_AO_DISABLE_DO _IO (ME4000_MAGIC, 12) | |
7146 | +#define ME4000_AO_FSM_STATE _IOR (ME4000_MAGIC, 13, int) | |
7147 | + | |
7148 | +#define ME4000_AI_SINGLE _IOR (ME4000_MAGIC, 14, me4000_ai_single_t) | |
7149 | +#define ME4000_AI_START _IOW (ME4000_MAGIC, 15, unsigned long) | |
7150 | +#define ME4000_AI_STOP _IO (ME4000_MAGIC, 16) | |
7151 | +#define ME4000_AI_IMMEDIATE_STOP _IO (ME4000_MAGIC, 17) | |
7152 | +#define ME4000_AI_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 18) | |
7153 | +#define ME4000_AI_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 19) | |
7154 | +#define ME4000_AI_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 20, me4000_ai_trigger_t) | |
7155 | +#define ME4000_AI_CONFIG _IOW (ME4000_MAGIC, 21, me4000_ai_config_t) | |
7156 | +#define ME4000_AI_SC_SETUP _IOW (ME4000_MAGIC, 22, me4000_ai_sc_t) | |
7157 | +#define ME4000_AI_FSM_STATE _IOR (ME4000_MAGIC, 23, int) | |
7158 | + | |
7159 | +#define ME4000_DIO_CONFIG _IOW (ME4000_MAGIC, 24, me4000_dio_config_t) | |
7160 | +#define ME4000_DIO_GET_BYTE _IOR (ME4000_MAGIC, 25, me4000_dio_byte_t) | |
7161 | +#define ME4000_DIO_SET_BYTE _IOW (ME4000_MAGIC, 26, me4000_dio_byte_t) | |
7162 | +#define ME4000_DIO_RESET _IO (ME4000_MAGIC, 27) | |
7163 | + | |
7164 | +#define ME4000_CNT_READ _IOR (ME4000_MAGIC, 28, me4000_cnt_t) | |
7165 | +#define ME4000_CNT_WRITE _IOW (ME4000_MAGIC, 29, me4000_cnt_t) | |
7166 | +#define ME4000_CNT_CONFIG _IOW (ME4000_MAGIC, 30, me4000_cnt_config_t) | |
7167 | +#define ME4000_CNT_RESET _IO (ME4000_MAGIC, 31) | |
7168 | + | |
7169 | +#define ME4000_EXT_INT_DISABLE _IO (ME4000_MAGIC, 32) | |
7170 | +#define ME4000_EXT_INT_ENABLE _IO (ME4000_MAGIC, 33) | |
7171 | +#define ME4000_EXT_INT_COUNT _IOR (ME4000_MAGIC, 34, int) | |
7172 | + | |
7173 | +#define ME4000_AI_OFFSET_ENABLE _IO (ME4000_MAGIC, 35) | |
7174 | +#define ME4000_AI_OFFSET_DISABLE _IO (ME4000_MAGIC, 36) | |
7175 | +#define ME4000_AI_FULLSCALE_ENABLE _IO (ME4000_MAGIC, 37) | |
7176 | +#define ME4000_AI_FULLSCALE_DISABLE _IO (ME4000_MAGIC, 38) | |
7177 | + | |
7178 | +#define ME4000_AI_EEPROM_READ _IOR (ME4000_MAGIC, 39, me4000_eeprom_t) | |
7179 | +#define ME4000_AI_EEPROM_WRITE _IOW (ME4000_MAGIC, 40, me4000_eeprom_t) | |
7180 | + | |
7181 | +#define ME4000_AO_SIMULTANEOUS_EX_TRIG _IO (ME4000_MAGIC, 41) | |
7182 | +#define ME4000_AO_SIMULTANEOUS_SW _IO (ME4000_MAGIC, 42) | |
7183 | +#define ME4000_AO_SIMULTANEOUS_DISABLE _IO (ME4000_MAGIC, 43) | |
7184 | +#define ME4000_AO_SIMULTANEOUS_UPDATE _IOW (ME4000_MAGIC, 44, me4000_ao_channel_list_t) | |
7185 | + | |
7186 | +#define ME4000_AO_SYNCHRONOUS_EX_TRIG _IO (ME4000_MAGIC, 45) | |
7187 | +#define ME4000_AO_SYNCHRONOUS_SW _IO (ME4000_MAGIC, 46) | |
7188 | +#define ME4000_AO_SYNCHRONOUS_DISABLE _IO (ME4000_MAGIC, 47) | |
7189 | + | |
7190 | +#define ME4000_AO_EX_TRIG_TIMEOUT _IOW (ME4000_MAGIC, 48, unsigned long) | |
7191 | +#define ME4000_AO_GET_FREE_BUFFER _IOR (ME4000_MAGIC, 49, unsigned long) | |
7192 | + | |
7193 | +#define ME4000_AI_GET_COUNT_BUFFER _IOR (ME4000_MAGIC, 50, unsigned long) | |
7194 | + | |
7195 | +#endif | |
7196 | -- | |
7197 | 1.6.0.2 | |
7198 |