staging: comedi: me4000: store the pci_dev in the comedi_device
[linux-2.6-block.git] / drivers / staging / comedi / drivers / me4000.c
CommitLineData
e55c95a3
GG
1/*
2 comedi/drivers/me4000.c
3 Source code for the Meilhaus ME-4000 board family.
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23/*
24Driver: me4000
25Description: Meilhaus ME-4000 series boards
26Devices: [Meilhaus] ME-4650 (me4000), ME-4670i, ME-4680, ME-4680i, ME-4680is
27Author: gg (Guenter Gebhardt <g.gebhardt@meilhaus.com>)
28Updated: Mon, 18 Mar 2002 15:34:01 -0800
29Status: broken (no support for loading firmware)
30
31Supports:
32
33 - Analog Input
34 - Analog Output
35 - Digital I/O
36 - Counter
37
38Configuration Options:
39
40 [0] - PCI bus number (optional)
41 [1] - PCI slot number (optional)
42
43 If bus/slot is not specified, the first available PCI
44 device will be used.
45
46The firmware required by these boards is available in the
47comedi_nonfree_firmware tarball available from
48http://www.comedi.org. However, the driver's support for
49loading the firmware through comedi_config is currently
50broken.
51
52 */
53
25436dc9 54#include <linux/interrupt.h>
e55c95a3
GG
55#include "../comedidev.h"
56
57#include <linux/delay.h>
58#include <linux/list.h>
59#include <linux/spinlock.h>
60
e55c95a3
GG
61#include "me4000.h"
62#if 0
63/* file removed due to GPL incompatibility */
64#include "me4000_fw.h"
65#endif
66
9e072731
HS
67#define PCI_VENDOR_ID_MEILHAUS 0x1402
68
69#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650
70#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660
71#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661
72#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662
73#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663
74#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670
75#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671
76#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672
77#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673
78#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680
79#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681
80#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682
81#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683
82
06b60981
HS
83struct me4000_board {
84 const char *name;
85 unsigned short device_id;
86 int ao_nchan;
87 int ao_fifo;
88 int ai_nchan;
89 int ai_diff_nchan;
90 int ai_sh_nchan;
91 int ex_trig_analog;
92 int dio_nchan;
93 int has_counter;
94};
95
27f4caaa 96static const struct me4000_board me4000_boards[] = {
035d432a
HS
97 {
98 .name = "ME-4650",
9e072731 99 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4650,
6ba8dfef 100 .ai_nchan = 16,
898f5191 101 .dio_nchan = 32,
035d432a
HS
102 }, {
103 .name = "ME-4660",
9e072731 104 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660,
6ba8dfef
HS
105 .ai_nchan = 32,
106 .ai_diff_nchan = 16,
898f5191 107 .dio_nchan = 32,
eedf4299 108 .has_counter = 1,
035d432a
HS
109 }, {
110 .name = "ME-4660i",
9e072731 111 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660I,
6ba8dfef
HS
112 .ai_nchan = 32,
113 .ai_diff_nchan = 16,
898f5191 114 .dio_nchan = 32,
eedf4299 115 .has_counter = 1,
035d432a
HS
116 }, {
117 .name = "ME-4660s",
9e072731 118 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660S,
6ba8dfef
HS
119 .ai_nchan = 32,
120 .ai_diff_nchan = 16,
121 .ai_sh_nchan = 8,
898f5191 122 .dio_nchan = 32,
eedf4299 123 .has_counter = 1,
035d432a
HS
124 }, {
125 .name = "ME-4660is",
9e072731 126 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660IS,
6ba8dfef
HS
127 .ai_nchan = 32,
128 .ai_diff_nchan = 16,
129 .ai_sh_nchan = 8,
898f5191 130 .dio_nchan = 32,
eedf4299 131 .has_counter = 1,
035d432a
HS
132 }, {
133 .name = "ME-4670",
9e072731 134 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670,
2d504528 135 .ao_nchan = 4,
6ba8dfef
HS
136 .ai_nchan = 32,
137 .ai_diff_nchan = 16,
138 .ex_trig_analog = 1,
898f5191 139 .dio_nchan = 32,
eedf4299 140 .has_counter = 1,
035d432a
HS
141 }, {
142 .name = "ME-4670i",
9e072731 143 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670I,
2d504528 144 .ao_nchan = 4,
6ba8dfef
HS
145 .ai_nchan = 32,
146 .ai_diff_nchan = 16,
147 .ex_trig_analog = 1,
898f5191 148 .dio_nchan = 32,
eedf4299 149 .has_counter = 1,
035d432a
HS
150 }, {
151 .name = "ME-4670s",
9e072731 152 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670S,
2d504528 153 .ao_nchan = 4,
6ba8dfef
HS
154 .ai_nchan = 32,
155 .ai_diff_nchan = 16,
156 .ai_sh_nchan = 8,
157 .ex_trig_analog = 1,
898f5191 158 .dio_nchan = 32,
eedf4299 159 .has_counter = 1,
035d432a
HS
160 }, {
161 .name = "ME-4670is",
9e072731 162 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670IS,
2d504528 163 .ao_nchan = 4,
6ba8dfef
HS
164 .ai_nchan = 32,
165 .ai_diff_nchan = 16,
166 .ai_sh_nchan = 8,
167 .ex_trig_analog = 1,
898f5191 168 .dio_nchan = 32,
eedf4299 169 .has_counter = 1,
035d432a
HS
170 }, {
171 .name = "ME-4680",
9e072731 172 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680,
2d504528
HS
173 .ao_nchan = 4,
174 .ao_fifo = 4,
6ba8dfef
HS
175 .ai_nchan = 32,
176 .ai_diff_nchan = 16,
177 .ex_trig_analog = 1,
898f5191 178 .dio_nchan = 32,
eedf4299 179 .has_counter = 1,
035d432a
HS
180 }, {
181 .name = "ME-4680i",
9e072731 182 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680I,
2d504528
HS
183 .ao_nchan = 4,
184 .ao_fifo = 4,
6ba8dfef
HS
185 .ai_nchan = 32,
186 .ai_diff_nchan = 16,
187 .ex_trig_analog = 1,
898f5191 188 .dio_nchan = 32,
eedf4299 189 .has_counter = 1,
035d432a
HS
190 }, {
191 .name = "ME-4680s",
9e072731 192 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680S,
2d504528
HS
193 .ao_nchan = 4,
194 .ao_fifo = 4,
6ba8dfef
HS
195 .ai_nchan = 32,
196 .ai_diff_nchan = 16,
197 .ai_sh_nchan = 8,
198 .ex_trig_analog = 1,
898f5191 199 .dio_nchan = 32,
eedf4299 200 .has_counter = 1,
035d432a
HS
201 }, {
202 .name = "ME-4680is",
9e072731 203 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680IS,
2d504528
HS
204 .ao_nchan = 4,
205 .ao_fifo = 4,
6ba8dfef
HS
206 .ai_nchan = 32,
207 .ai_diff_nchan = 16,
208 .ai_sh_nchan = 8,
209 .ex_trig_analog = 1,
898f5191 210 .dio_nchan = 32,
eedf4299 211 .has_counter = 1,
035d432a 212 },
e55c95a3
GG
213};
214
9ced1de6 215static const struct comedi_lrange me4000_ai_range = {
e55c95a3
GG
216 4,
217 {
0a85b6f0
MT
218 UNI_RANGE(2.5),
219 UNI_RANGE(10),
220 BIP_RANGE(2.5),
221 BIP_RANGE(10),
222 }
e55c95a3
GG
223};
224
e55c95a3
GG
225#define FIRMWARE_NOT_AVAILABLE 1
226#if FIRMWARE_NOT_AVAILABLE
227extern unsigned char *xilinx_firm;
228#endif
229
71b5f4f1 230static int xilinx_download(struct comedi_device *dev)
e55c95a3 231{
09253b39 232 struct me4000_info *info = dev->private;
e55c95a3
GG
233 u32 value = 0;
234 wait_queue_head_t queue;
235 int idx = 0;
236 int size = 0;
237
e55c95a3
GG
238 init_waitqueue_head(&queue);
239
240 /*
241 * Set PLX local interrupt 2 polarity to high.
242 * Interrupt is thrown by init pin of xilinx.
243 */
244 outl(0x10, info->plx_regbase + PLX_INTCSR);
245
246 /* Set /CS and /WRITE of the Xilinx */
247 value = inl(info->plx_regbase + PLX_ICR);
248 value |= 0x100;
249 outl(value, info->plx_regbase + PLX_ICR);
250
251 /* Init Xilinx with CS1 */
252 inb(info->program_regbase + 0xC8);
253
254 /* Wait until /INIT pin is set */
255 udelay(20);
d86d3a01 256 if (!(inl(info->plx_regbase + PLX_INTCSR) & 0x20)) {
e55c95a3 257 printk(KERN_ERR
b6241fda
GS
258 "comedi%d: me4000: xilinx_download(): "
259 "Can't init Xilinx\n", dev->minor);
e55c95a3
GG
260 return -EIO;
261 }
262
263 /* Reset /CS and /WRITE of the Xilinx */
264 value = inl(info->plx_regbase + PLX_ICR);
265 value &= ~0x100;
266 outl(value, info->plx_regbase + PLX_ICR);
267 if (FIRMWARE_NOT_AVAILABLE) {
b6241fda
GS
268 comedi_error(dev, "xilinx firmware unavailable "
269 "due to licensing, aborting");
e55c95a3
GG
270 return -EIO;
271 } else {
272 /* Download Xilinx firmware */
273 size = (xilinx_firm[0] << 24) + (xilinx_firm[1] << 16) +
0a85b6f0 274 (xilinx_firm[2] << 8) + xilinx_firm[3];
e55c95a3
GG
275 udelay(10);
276
277 for (idx = 0; idx < size; idx++) {
278 outb(xilinx_firm[16 + idx], info->program_regbase);
279 udelay(10);
280
281 /* Check if BUSY flag is low */
282 if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
283 printk(KERN_ERR
b6241fda
GS
284 "comedi%d: me4000: xilinx_download(): "
285 "Xilinx is still busy (idx = %d)\n",
0a85b6f0 286 dev->minor, idx);
e55c95a3
GG
287 return -EIO;
288 }
289 }
290 }
291
292 /* If done flag is high download was successful */
293 if (inl(info->plx_regbase + PLX_ICR) & 0x4) {
294 } else {
295 printk(KERN_ERR
b6241fda
GS
296 "comedi%d: me4000: xilinx_download(): "
297 "DONE flag is not set\n", dev->minor);
e55c95a3 298 printk(KERN_ERR
b6241fda
GS
299 "comedi%d: me4000: xilinx_download(): "
300 "Download not successful\n", dev->minor);
e55c95a3
GG
301 return -EIO;
302 }
303
304 /* Set /CS and /WRITE */
305 value = inl(info->plx_regbase + PLX_ICR);
306 value |= 0x100;
307 outl(value, info->plx_regbase + PLX_ICR);
308
309 return 0;
310}
311
71b5f4f1 312static int reset_board(struct comedi_device *dev)
e55c95a3 313{
09253b39 314 struct me4000_info *info = dev->private;
e1d7ccb7
HS
315 unsigned long val;
316 int chan;
e55c95a3 317
e55c95a3 318 /* Make a hardware reset */
e1d7ccb7
HS
319 val = inl(info->plx_regbase + PLX_ICR);
320 val |= 0x40000000;
321 outl(val, info->plx_regbase + PLX_ICR);
322 val &= ~0x40000000;
323 outl(val , info->plx_regbase + PLX_ICR);
e55c95a3
GG
324
325 /* 0x8000 to the DACs means an output voltage of 0V */
e1d7ccb7
HS
326 for (chan = 0; chan < 4; chan++)
327 outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan));
e55c95a3
GG
328
329 /* Set both stop bits in the analog input control register */
d6cbe537 330 outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
362bcbde 331 dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
332
333 /* Set both stop bits in the analog output control register */
e1d7ccb7
HS
334 val = ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP;
335 for (chan = 0; chan < 4; chan++)
336 outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan));
e55c95a3
GG
337
338 /* Enable interrupts on the PLX */
d6cbe537 339 outl(0x43, info->plx_regbase + PLX_INTCSR);
e55c95a3
GG
340
341 /* Set the adustment register for AO demux */
d6cbe537 342 outl(ME4000_AO_DEMUX_ADJUST_VALUE,
362bcbde 343 dev->iobase + ME4000_AO_DEMUX_ADJUST_REG);
e55c95a3 344
b6241fda
GS
345 /*
346 * Set digital I/O direction for port 0
347 * to output on isolated versions
348 */
362bcbde
HS
349 if (!(inl(dev->iobase + ME4000_DIO_DIR_REG) & 0x1))
350 outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG);
e55c95a3
GG
351
352 return 0;
353}
354
e55c95a3
GG
355/*=============================================================================
356 Analog input section
357 ===========================================================================*/
358
71b5f4f1 359static int me4000_ai_insn_read(struct comedi_device *dev,
0a85b6f0
MT
360 struct comedi_subdevice *subdevice,
361 struct comedi_insn *insn, unsigned int *data)
e55c95a3 362{
8407593a 363 const struct me4000_board *thisboard = comedi_board(dev);
e55c95a3
GG
364 int chan = CR_CHAN(insn->chanspec);
365 int rang = CR_RANGE(insn->chanspec);
366 int aref = CR_AREF(insn->chanspec);
367
368 unsigned long entry = 0;
369 unsigned long tmp;
370 long lval;
371
e55c95a3
GG
372 if (insn->n == 0) {
373 return 0;
374 } else if (insn->n > 1) {
375 printk(KERN_ERR
b6241fda
GS
376 "comedi%d: me4000: me4000_ai_insn_read(): "
377 "Invalid instruction length %d\n", dev->minor, insn->n);
e55c95a3
GG
378 return -EINVAL;
379 }
380
381 switch (rang) {
382 case 0:
383 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
384 break;
385 case 1:
386 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
387 break;
388 case 2:
389 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
390 break;
391 case 3:
392 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
393 break;
394 default:
395 printk(KERN_ERR
b6241fda
GS
396 "comedi%d: me4000: me4000_ai_insn_read(): "
397 "Invalid range specified\n", dev->minor);
e55c95a3
GG
398 return -EINVAL;
399 }
400
401 switch (aref) {
402 case AREF_GROUND:
403 case AREF_COMMON:
6ba8dfef 404 if (chan >= thisboard->ai_nchan) {
e55c95a3 405 printk(KERN_ERR
b6241fda
GS
406 "comedi%d: me4000: me4000_ai_insn_read(): "
407 "Analog input is not available\n", dev->minor);
e55c95a3
GG
408 return -EINVAL;
409 }
410 entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan;
411 break;
412
413 case AREF_DIFF:
414 if (rang == 0 || rang == 1) {
415 printk(KERN_ERR
b6241fda
GS
416 "comedi%d: me4000: me4000_ai_insn_read(): "
417 "Range must be bipolar when aref = diff\n",
0a85b6f0 418 dev->minor);
e55c95a3
GG
419 return -EINVAL;
420 }
421
6ba8dfef 422 if (chan >= thisboard->ai_diff_nchan) {
e55c95a3 423 printk(KERN_ERR
b6241fda
GS
424 "comedi%d: me4000: me4000_ai_insn_read(): "
425 "Analog input is not available\n", dev->minor);
e55c95a3
GG
426 return -EINVAL;
427 }
428 entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan;
429 break;
430 default:
431 printk(KERN_ERR
b6241fda
GS
432 "comedi%d: me4000: me4000_ai_insn_read(): "
433 "Invalid aref specified\n", dev->minor);
e55c95a3
GG
434 return -EINVAL;
435 }
436
437 entry |= ME4000_AI_LIST_LAST_ENTRY;
438
439 /* Clear channel list, data fifo and both stop bits */
b08bfa38 440 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 441 tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
0a85b6f0
MT
442 ME4000_AI_CTRL_BIT_DATA_FIFO |
443 ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
b08bfa38 444 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
445
446 /* Set the acquisition mode to single */
447 tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 |
0a85b6f0 448 ME4000_AI_CTRL_BIT_MODE_2);
b08bfa38 449 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
450
451 /* Enable channel list and data fifo */
452 tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO;
b08bfa38 453 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
454
455 /* Generate channel list entry */
b08bfa38 456 outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
e55c95a3
GG
457
458 /* Set the timer to maximum sample rate */
b08bfa38
HS
459 outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
460 outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
e55c95a3
GG
461
462 /* Start conversion by dummy read */
b08bfa38 463 inl(dev->iobase + ME4000_AI_START_REG);
e55c95a3
GG
464
465 /* Wait until ready */
466 udelay(10);
b08bfa38 467 if (!(inl(dev->iobase + ME4000_AI_STATUS_REG) &
0a85b6f0 468 ME4000_AI_STATUS_BIT_EF_DATA)) {
e55c95a3 469 printk(KERN_ERR
b6241fda
GS
470 "comedi%d: me4000: me4000_ai_insn_read(): "
471 "Value not available after wait\n", dev->minor);
e55c95a3
GG
472 return -EIO;
473 }
474
475 /* Read value from data fifo */
b08bfa38 476 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
e55c95a3
GG
477 data[0] = lval ^ 0x8000;
478
479 return 1;
480}
481
0a85b6f0
MT
482static int me4000_ai_cancel(struct comedi_device *dev,
483 struct comedi_subdevice *s)
e55c95a3
GG
484{
485 unsigned long tmp;
486
e55c95a3 487 /* Stop any running conversion */
b08bfa38 488 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 489 tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
b08bfa38 490 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
491
492 /* Clear the control register */
b08bfa38 493 outl(0x0, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
494
495 return 0;
496}
497
71b5f4f1 498static int ai_check_chanlist(struct comedi_device *dev,
0a85b6f0 499 struct comedi_subdevice *s, struct comedi_cmd *cmd)
e55c95a3 500{
8407593a 501 const struct me4000_board *thisboard = comedi_board(dev);
e55c95a3
GG
502 int aref;
503 int i;
504
e55c95a3
GG
505 /* Check whether a channel list is available */
506 if (!cmd->chanlist_len) {
507 printk(KERN_ERR
b6241fda
GS
508 "comedi%d: me4000: ai_check_chanlist(): "
509 "No channel list available\n", dev->minor);
e55c95a3
GG
510 return -EINVAL;
511 }
512
513 /* Check the channel list size */
514 if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) {
515 printk(KERN_ERR
b6241fda
GS
516 "comedi%d: me4000: ai_check_chanlist(): "
517 "Channel list is to large\n", dev->minor);
e55c95a3
GG
518 return -EINVAL;
519 }
520
521 /* Check the pointer */
522 if (!cmd->chanlist) {
523 printk(KERN_ERR
b6241fda
GS
524 "comedi%d: me4000: ai_check_chanlist(): "
525 "NULL pointer to channel list\n", dev->minor);
e55c95a3
GG
526 return -EFAULT;
527 }
528
529 /* Check whether aref is equal for all entries */
530 aref = CR_AREF(cmd->chanlist[0]);
531 for (i = 0; i < cmd->chanlist_len; i++) {
532 if (CR_AREF(cmd->chanlist[i]) != aref) {
533 printk(KERN_ERR
b6241fda
GS
534 "comedi%d: me4000: ai_check_chanlist(): "
535 "Mode is not equal for all entries\n",
0a85b6f0 536 dev->minor);
e55c95a3
GG
537 return -EINVAL;
538 }
539 }
540
541 /* Check whether channels are available for this ending */
542 if (aref == SDF_DIFF) {
543 for (i = 0; i < cmd->chanlist_len; i++) {
544 if (CR_CHAN(cmd->chanlist[i]) >=
6ba8dfef 545 thisboard->ai_diff_nchan) {
e55c95a3 546 printk(KERN_ERR
b6241fda
GS
547 "comedi%d: me4000: ai_check_chanlist():"
548 " Channel number to high\n", dev->minor);
e55c95a3
GG
549 return -EINVAL;
550 }
551 }
552 } else {
553 for (i = 0; i < cmd->chanlist_len; i++) {
6ba8dfef 554 if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai_nchan) {
e55c95a3 555 printk(KERN_ERR
b6241fda
GS
556 "comedi%d: me4000: ai_check_chanlist(): "
557 "Channel number to high\n", dev->minor);
e55c95a3
GG
558 return -EINVAL;
559 }
560 }
561 }
562
563 /* Check if bipolar is set for all entries when in differential mode */
564 if (aref == SDF_DIFF) {
565 for (i = 0; i < cmd->chanlist_len; i++) {
566 if (CR_RANGE(cmd->chanlist[i]) != 1 &&
0a85b6f0 567 CR_RANGE(cmd->chanlist[i]) != 2) {
e55c95a3 568 printk(KERN_ERR
b6241fda
GS
569 "comedi%d: me4000: ai_check_chanlist(): "
570 "Bipolar is not selected in "
571 "differential mode\n",
0a85b6f0 572 dev->minor);
e55c95a3
GG
573 return -EINVAL;
574 }
575 }
576 }
577
578 return 0;
579}
580
71b5f4f1 581static int ai_round_cmd_args(struct comedi_device *dev,
0a85b6f0
MT
582 struct comedi_subdevice *s,
583 struct comedi_cmd *cmd,
584 unsigned int *init_ticks,
585 unsigned int *scan_ticks, unsigned int *chan_ticks)
e55c95a3
GG
586{
587
588 int rest;
589
e55c95a3
GG
590 *init_ticks = 0;
591 *scan_ticks = 0;
592 *chan_ticks = 0;
593
e55c95a3
GG
594 if (cmd->start_arg) {
595 *init_ticks = (cmd->start_arg * 33) / 1000;
596 rest = (cmd->start_arg * 33) % 1000;
597
91211dd1 598 if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
82675f35 599 if (rest > 33)
e55c95a3 600 (*init_ticks)++;
91211dd1 601 } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
e55c95a3
GG
602 if (rest)
603 (*init_ticks)++;
604 }
605 }
606
607 if (cmd->scan_begin_arg) {
608 *scan_ticks = (cmd->scan_begin_arg * 33) / 1000;
609 rest = (cmd->scan_begin_arg * 33) % 1000;
610
91211dd1 611 if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
82675f35 612 if (rest > 33)
e55c95a3 613 (*scan_ticks)++;
91211dd1 614 } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
e55c95a3
GG
615 if (rest)
616 (*scan_ticks)++;
617 }
618 }
619
620 if (cmd->convert_arg) {
621 *chan_ticks = (cmd->convert_arg * 33) / 1000;
622 rest = (cmd->convert_arg * 33) % 1000;
623
91211dd1 624 if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
82675f35 625 if (rest > 33)
e55c95a3 626 (*chan_ticks)++;
91211dd1 627 } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
e55c95a3
GG
628 if (rest)
629 (*chan_ticks)++;
630 }
631 }
632
e55c95a3
GG
633 return 0;
634}
635
71b5f4f1 636static void ai_write_timer(struct comedi_device *dev,
0a85b6f0
MT
637 unsigned int init_ticks,
638 unsigned int scan_ticks, unsigned int chan_ticks)
e55c95a3 639{
b08bfa38
HS
640 outl(init_ticks - 1, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG);
641 outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG);
e55c95a3
GG
642
643 if (scan_ticks) {
b08bfa38
HS
644 outl(scan_ticks - 1, dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG);
645 outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG);
e55c95a3
GG
646 }
647
b08bfa38
HS
648 outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
649 outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
e55c95a3
GG
650}
651
4b2f15f1
HS
652static int ai_write_chanlist(struct comedi_device *dev,
653 struct comedi_subdevice *s, struct comedi_cmd *cmd)
654{
655 unsigned int entry;
656 unsigned int chan;
657 unsigned int rang;
658 unsigned int aref;
659 int i;
660
661 for (i = 0; i < cmd->chanlist_len; i++) {
662 chan = CR_CHAN(cmd->chanlist[i]);
663 rang = CR_RANGE(cmd->chanlist[i]);
664 aref = CR_AREF(cmd->chanlist[i]);
665
666 entry = chan;
667
668 if (rang == 0)
669 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
670 else if (rang == 1)
671 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
672 else if (rang == 2)
673 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
674 else
675 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
676
677 if (aref == SDF_DIFF)
678 entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
679 else
680 entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED;
681
682 outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
683 }
684
685 return 0;
686}
687
71b5f4f1 688static int ai_prepare(struct comedi_device *dev,
0a85b6f0
MT
689 struct comedi_subdevice *s,
690 struct comedi_cmd *cmd,
691 unsigned int init_ticks,
692 unsigned int scan_ticks, unsigned int chan_ticks)
e55c95a3
GG
693{
694
695 unsigned long tmp = 0;
696
e55c95a3
GG
697 /* Write timer arguments */
698 ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks);
699
700 /* Reset control register */
b08bfa38 701 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
702
703 /* Start sources */
704 if ((cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
705 cmd->scan_begin_src == TRIG_TIMER &&
706 cmd->convert_src == TRIG_TIMER) ||
707 (cmd->start_src == TRIG_EXT &&
708 cmd->scan_begin_src == TRIG_FOLLOW &&
709 cmd->convert_src == TRIG_TIMER)) {
e55c95a3 710 tmp = ME4000_AI_CTRL_BIT_MODE_1 |
0a85b6f0
MT
711 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
712 ME4000_AI_CTRL_BIT_DATA_FIFO;
e55c95a3 713 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
714 cmd->scan_begin_src == TRIG_EXT &&
715 cmd->convert_src == TRIG_TIMER) {
e55c95a3 716 tmp = ME4000_AI_CTRL_BIT_MODE_2 |
0a85b6f0
MT
717 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
718 ME4000_AI_CTRL_BIT_DATA_FIFO;
e55c95a3 719 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
720 cmd->scan_begin_src == TRIG_EXT &&
721 cmd->convert_src == TRIG_EXT) {
e55c95a3 722 tmp = ME4000_AI_CTRL_BIT_MODE_0 |
0a85b6f0
MT
723 ME4000_AI_CTRL_BIT_MODE_1 |
724 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
725 ME4000_AI_CTRL_BIT_DATA_FIFO;
e55c95a3
GG
726 } else {
727 tmp = ME4000_AI_CTRL_BIT_MODE_0 |
0a85b6f0
MT
728 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
729 ME4000_AI_CTRL_BIT_DATA_FIFO;
e55c95a3
GG
730 }
731
732 /* Stop triggers */
733 if (cmd->stop_src == TRIG_COUNT) {
d6cbe537 734 outl(cmd->chanlist_len * cmd->stop_arg,
b08bfa38 735 dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
e55c95a3
GG
736 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
737 } else if (cmd->stop_src == TRIG_NONE &&
0a85b6f0 738 cmd->scan_end_src == TRIG_COUNT) {
d6cbe537 739 outl(cmd->scan_end_arg,
b08bfa38 740 dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
e55c95a3
GG
741 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
742 } else {
743 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ;
744 }
745
746 /* Write the setup to the control register */
b08bfa38 747 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
748
749 /* Write the channel list */
750 ai_write_chanlist(dev, s, cmd);
751
752 return 0;
753}
754
0a85b6f0
MT
755static int me4000_ai_do_cmd(struct comedi_device *dev,
756 struct comedi_subdevice *s)
e55c95a3
GG
757{
758 int err;
759 unsigned int init_ticks = 0;
760 unsigned int scan_ticks = 0;
761 unsigned int chan_ticks = 0;
ea6d0d4c 762 struct comedi_cmd *cmd = &s->async->cmd;
e55c95a3 763
e55c95a3
GG
764 /* Reset the analog input */
765 err = me4000_ai_cancel(dev, s);
766 if (err)
767 return err;
768
769 /* Round the timer arguments */
770 err = ai_round_cmd_args(dev,
0a85b6f0 771 s, cmd, &init_ticks, &scan_ticks, &chan_ticks);
e55c95a3
GG
772 if (err)
773 return err;
774
775 /* Prepare the AI for acquisition */
776 err = ai_prepare(dev, s, cmd, init_ticks, scan_ticks, chan_ticks);
777 if (err)
778 return err;
779
780 /* Start acquistion by dummy read */
b08bfa38 781 inl(dev->iobase + ME4000_AI_START_REG);
e55c95a3
GG
782
783 return 0;
784}
785
786/*
787 * me4000_ai_do_cmd_test():
788 *
789 * The demo cmd.c in ./comedilib/demo specifies 6 return values:
790 * - success
791 * - invalid source
792 * - source conflict
793 * - invalid argument
794 * - argument conflict
795 * - invalid chanlist
796 * So I tried to adopt this scheme.
797 */
71b5f4f1 798static int me4000_ai_do_cmd_test(struct comedi_device *dev,
0a85b6f0
MT
799 struct comedi_subdevice *s,
800 struct comedi_cmd *cmd)
e55c95a3
GG
801{
802
803 unsigned int init_ticks;
804 unsigned int chan_ticks;
805 unsigned int scan_ticks;
806 int err = 0;
807
e55c95a3
GG
808 /* Only rounding flags are implemented */
809 cmd->flags &= TRIG_ROUND_NEAREST | TRIG_ROUND_UP | TRIG_ROUND_DOWN;
810
811 /* Round the timer arguments */
812 ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks);
813
814 /*
815 * Stage 1. Check if the trigger sources are generally valid.
816 */
817 switch (cmd->start_src) {
818 case TRIG_NOW:
819 case TRIG_EXT:
820 break;
821 case TRIG_ANY:
822 cmd->start_src &= TRIG_NOW | TRIG_EXT;
823 err++;
824 break;
825 default:
826 printk(KERN_ERR
b6241fda
GS
827 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
828 "Invalid start source\n", dev->minor);
e55c95a3
GG
829 cmd->start_src = TRIG_NOW;
830 err++;
831 }
832 switch (cmd->scan_begin_src) {
833 case TRIG_FOLLOW:
834 case TRIG_TIMER:
835 case TRIG_EXT:
836 break;
837 case TRIG_ANY:
838 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT;
839 err++;
840 break;
841 default:
842 printk(KERN_ERR
b6241fda
GS
843 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
844 "Invalid scan begin source\n", dev->minor);
e55c95a3
GG
845 cmd->scan_begin_src = TRIG_FOLLOW;
846 err++;
847 }
848 switch (cmd->convert_src) {
849 case TRIG_TIMER:
850 case TRIG_EXT:
851 break;
852 case TRIG_ANY:
853 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
854 err++;
855 break;
856 default:
857 printk(KERN_ERR
b6241fda
GS
858 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
859 "Invalid convert source\n", dev->minor);
e55c95a3
GG
860 cmd->convert_src = TRIG_TIMER;
861 err++;
862 }
863 switch (cmd->scan_end_src) {
864 case TRIG_NONE:
865 case TRIG_COUNT:
866 break;
867 case TRIG_ANY:
868 cmd->scan_end_src &= TRIG_NONE | TRIG_COUNT;
869 err++;
870 break;
871 default:
872 printk(KERN_ERR
b6241fda
GS
873 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
874 "Invalid scan end source\n", dev->minor);
e55c95a3
GG
875 cmd->scan_end_src = TRIG_NONE;
876 err++;
877 }
878 switch (cmd->stop_src) {
879 case TRIG_NONE:
880 case TRIG_COUNT:
881 break;
882 case TRIG_ANY:
883 cmd->stop_src &= TRIG_NONE | TRIG_COUNT;
884 err++;
885 break;
886 default:
887 printk(KERN_ERR
b6241fda
GS
888 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
889 "Invalid stop source\n", dev->minor);
e55c95a3
GG
890 cmd->stop_src = TRIG_NONE;
891 err++;
892 }
82675f35 893 if (err)
e55c95a3 894 return 1;
e55c95a3
GG
895
896 /*
897 * Stage 2. Check for trigger source conflicts.
898 */
899 if (cmd->start_src == TRIG_NOW &&
0a85b6f0
MT
900 cmd->scan_begin_src == TRIG_TIMER &&
901 cmd->convert_src == TRIG_TIMER) {
e55c95a3 902 } else if (cmd->start_src == TRIG_NOW &&
0a85b6f0
MT
903 cmd->scan_begin_src == TRIG_FOLLOW &&
904 cmd->convert_src == TRIG_TIMER) {
e55c95a3 905 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
906 cmd->scan_begin_src == TRIG_TIMER &&
907 cmd->convert_src == TRIG_TIMER) {
e55c95a3 908 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
909 cmd->scan_begin_src == TRIG_FOLLOW &&
910 cmd->convert_src == TRIG_TIMER) {
e55c95a3 911 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
912 cmd->scan_begin_src == TRIG_EXT &&
913 cmd->convert_src == TRIG_TIMER) {
e55c95a3 914 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
915 cmd->scan_begin_src == TRIG_EXT &&
916 cmd->convert_src == TRIG_EXT) {
e55c95a3
GG
917 } else {
918 printk(KERN_ERR
b6241fda
GS
919 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
920 "Invalid start trigger combination\n", dev->minor);
e55c95a3
GG
921 cmd->start_src = TRIG_NOW;
922 cmd->scan_begin_src = TRIG_FOLLOW;
923 cmd->convert_src = TRIG_TIMER;
924 err++;
925 }
926
927 if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) {
928 } else if (cmd->stop_src == TRIG_COUNT &&
0a85b6f0 929 cmd->scan_end_src == TRIG_NONE) {
e55c95a3 930 } else if (cmd->stop_src == TRIG_NONE &&
0a85b6f0 931 cmd->scan_end_src == TRIG_COUNT) {
e55c95a3 932 } else if (cmd->stop_src == TRIG_COUNT &&
0a85b6f0 933 cmd->scan_end_src == TRIG_COUNT) {
e55c95a3
GG
934 } else {
935 printk(KERN_ERR
b6241fda
GS
936 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
937 "Invalid stop trigger combination\n", dev->minor);
e55c95a3
GG
938 cmd->stop_src = TRIG_NONE;
939 cmd->scan_end_src = TRIG_NONE;
940 err++;
941 }
82675f35 942 if (err)
e55c95a3 943 return 2;
e55c95a3
GG
944
945 /*
946 * Stage 3. Check if arguments are generally valid.
947 */
948 if (cmd->chanlist_len < 1) {
949 printk(KERN_ERR
b6241fda
GS
950 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
951 "No channel list\n", dev->minor);
e55c95a3
GG
952 cmd->chanlist_len = 1;
953 err++;
954 }
955 if (init_ticks < 66) {
956 printk(KERN_ERR
b6241fda
GS
957 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
958 "Start arg to low\n", dev->minor);
e55c95a3
GG
959 cmd->start_arg = 2000;
960 err++;
961 }
962 if (scan_ticks && scan_ticks < 67) {
963 printk(KERN_ERR
b6241fda
GS
964 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
965 "Scan begin arg to low\n", dev->minor);
e55c95a3
GG
966 cmd->scan_begin_arg = 2031;
967 err++;
968 }
969 if (chan_ticks < 66) {
970 printk(KERN_ERR
b6241fda
GS
971 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
972 "Convert arg to low\n", dev->minor);
e55c95a3
GG
973 cmd->convert_arg = 2000;
974 err++;
975 }
82675f35
BP
976
977 if (err)
e55c95a3 978 return 3;
e55c95a3
GG
979
980 /*
981 * Stage 4. Check for argument conflicts.
982 */
983 if (cmd->start_src == TRIG_NOW &&
0a85b6f0
MT
984 cmd->scan_begin_src == TRIG_TIMER &&
985 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
986
987 /* Check timer arguments */
988 if (init_ticks < ME4000_AI_MIN_TICKS) {
989 printk(KERN_ERR
b6241fda
GS
990 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
991 "Invalid start arg\n", dev->minor);
b6c77757 992 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
993 err++;
994 }
995 if (chan_ticks < ME4000_AI_MIN_TICKS) {
996 printk(KERN_ERR
b6241fda
GS
997 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
998 "Invalid convert arg\n", dev->minor);
b6c77757 999 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1000 err++;
1001 }
1002 if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
1003 printk(KERN_ERR
b6241fda
GS
1004 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1005 "Invalid scan end arg\n", dev->minor);
1006
1007 /* At least one tick more */
1008 cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
e55c95a3
GG
1009 err++;
1010 }
1011 } else if (cmd->start_src == TRIG_NOW &&
0a85b6f0
MT
1012 cmd->scan_begin_src == TRIG_FOLLOW &&
1013 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
1014
1015 /* Check timer arguments */
1016 if (init_ticks < ME4000_AI_MIN_TICKS) {
1017 printk(KERN_ERR
b6241fda
GS
1018 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1019 "Invalid start arg\n", dev->minor);
b6c77757 1020 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1021 err++;
1022 }
1023 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1024 printk(KERN_ERR
b6241fda
GS
1025 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1026 "Invalid convert arg\n", dev->minor);
b6c77757 1027 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1028 err++;
1029 }
1030 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
1031 cmd->scan_begin_src == TRIG_TIMER &&
1032 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
1033
1034 /* Check timer arguments */
1035 if (init_ticks < ME4000_AI_MIN_TICKS) {
1036 printk(KERN_ERR
b6241fda
GS
1037 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1038 "Invalid start arg\n", dev->minor);
b6c77757 1039 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1040 err++;
1041 }
1042 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1043 printk(KERN_ERR
b6241fda
GS
1044 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1045 "Invalid convert arg\n", dev->minor);
b6c77757 1046 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1047 err++;
1048 }
1049 if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
1050 printk(KERN_ERR
b6241fda
GS
1051 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1052 "Invalid scan end arg\n", dev->minor);
1053
1054 /* At least one tick more */
1055 cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
e55c95a3
GG
1056 err++;
1057 }
1058 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
1059 cmd->scan_begin_src == TRIG_FOLLOW &&
1060 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
1061
1062 /* Check timer arguments */
1063 if (init_ticks < ME4000_AI_MIN_TICKS) {
1064 printk(KERN_ERR
b6241fda
GS
1065 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1066 "Invalid start arg\n", dev->minor);
b6c77757 1067 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1068 err++;
1069 }
1070 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1071 printk(KERN_ERR
b6241fda
GS
1072 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1073 "Invalid convert arg\n", dev->minor);
b6c77757 1074 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1075 err++;
1076 }
1077 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
1078 cmd->scan_begin_src == TRIG_EXT &&
1079 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
1080
1081 /* Check timer arguments */
1082 if (init_ticks < ME4000_AI_MIN_TICKS) {
1083 printk(KERN_ERR
b6241fda
GS
1084 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1085 "Invalid start arg\n", dev->minor);
b6c77757 1086 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1087 err++;
1088 }
1089 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1090 printk(KERN_ERR
b6241fda
GS
1091 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1092 "Invalid convert arg\n", dev->minor);
b6c77757 1093 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1094 err++;
1095 }
1096 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
1097 cmd->scan_begin_src == TRIG_EXT &&
1098 cmd->convert_src == TRIG_EXT) {
e55c95a3
GG
1099
1100 /* Check timer arguments */
1101 if (init_ticks < ME4000_AI_MIN_TICKS) {
1102 printk(KERN_ERR
b6241fda
GS
1103 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1104 "Invalid start arg\n", dev->minor);
b6c77757 1105 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
1106 err++;
1107 }
1108 }
1109 if (cmd->stop_src == TRIG_COUNT) {
1110 if (cmd->stop_arg == 0) {
1111 printk(KERN_ERR
b6241fda
GS
1112 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1113 "Invalid stop arg\n", dev->minor);
e55c95a3
GG
1114 cmd->stop_arg = 1;
1115 err++;
1116 }
1117 }
1118 if (cmd->scan_end_src == TRIG_COUNT) {
1119 if (cmd->scan_end_arg == 0) {
1120 printk(KERN_ERR
b6241fda
GS
1121 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1122 "Invalid scan end arg\n", dev->minor);
e55c95a3
GG
1123 cmd->scan_end_arg = 1;
1124 err++;
1125 }
1126 }
82675f35
BP
1127
1128 if (err)
e55c95a3 1129 return 4;
e55c95a3
GG
1130
1131 /*
1132 * Stage 5. Check the channel list.
1133 */
1134 if (ai_check_chanlist(dev, s, cmd))
1135 return 5;
1136
1137 return 0;
1138}
1139
70265d24 1140static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
e55c95a3
GG
1141{
1142 unsigned int tmp;
71b5f4f1 1143 struct comedi_device *dev = dev_id;
8aaf2717 1144 struct comedi_subdevice *s = &dev->subdevices[0];
e55c95a3
GG
1145 int i;
1146 int c = 0;
1147 long lval;
1148
ef5bbfcb 1149 if (!dev->attached)
e55c95a3 1150 return IRQ_NONE;
e55c95a3
GG
1151
1152 /* Reset all events */
1153 s->async->events = 0;
1154
1155 /* Check if irq number is right */
109daa79 1156 if (irq != dev->irq) {
e55c95a3 1157 printk(KERN_ERR
b6241fda
GS
1158 "comedi%d: me4000: me4000_ai_isr(): "
1159 "Incorrect interrupt num: %d\n", dev->minor, irq);
e55c95a3
GG
1160 return IRQ_HANDLED;
1161 }
1162
b08bfa38 1163 if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
0a85b6f0 1164 ME4000_IRQ_STATUS_BIT_AI_HF) {
e55c95a3 1165 /* Read status register to find out what happened */
b08bfa38 1166 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1167
1168 if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
0a85b6f0
MT
1169 !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) &&
1170 (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
e55c95a3
GG
1171 c = ME4000_AI_FIFO_COUNT;
1172
b6241fda
GS
1173 /*
1174 * FIFO overflow, so stop conversion
1175 * and disable all interrupts
1176 */
e55c95a3
GG
1177 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1178 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
0a85b6f0 1179 ME4000_AI_CTRL_BIT_SC_IRQ);
b08bfa38 1180 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1181
1182 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
1183
1184 printk(KERN_ERR
b6241fda
GS
1185 "comedi%d: me4000: me4000_ai_isr(): "
1186 "FIFO overflow\n", dev->minor);
e55c95a3 1187 } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
0a85b6f0
MT
1188 && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
1189 && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
e55c95a3
GG
1190 s->async->events |= COMEDI_CB_BLOCK;
1191
1192 c = ME4000_AI_FIFO_COUNT / 2;
1193 } else {
1194 printk(KERN_ERR
b6241fda
GS
1195 "comedi%d: me4000: me4000_ai_isr(): "
1196 "Can't determine state of fifo\n", dev->minor);
e55c95a3
GG
1197 c = 0;
1198
b6241fda
GS
1199 /*
1200 * Undefined state, so stop conversion
1201 * and disable all interrupts
1202 */
e55c95a3
GG
1203 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1204 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
0a85b6f0 1205 ME4000_AI_CTRL_BIT_SC_IRQ);
b08bfa38 1206 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1207
1208 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
1209
1210 printk(KERN_ERR
b6241fda
GS
1211 "comedi%d: me4000: me4000_ai_isr(): "
1212 "Undefined FIFO state\n", dev->minor);
e55c95a3
GG
1213 }
1214
e55c95a3
GG
1215 for (i = 0; i < c; i++) {
1216 /* Read value from data fifo */
b08bfa38 1217 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
e55c95a3
GG
1218 lval ^= 0x8000;
1219
1220 if (!comedi_buf_put(s->async, lval)) {
b6241fda
GS
1221 /*
1222 * Buffer overflow, so stop conversion
1223 * and disable all interrupts
1224 */
e55c95a3
GG
1225 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1226 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
0a85b6f0 1227 ME4000_AI_CTRL_BIT_SC_IRQ);
b08bfa38 1228 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1229
1230 s->async->events |= COMEDI_CB_OVERFLOW;
1231
1232 printk(KERN_ERR
b6241fda
GS
1233 "comedi%d: me4000: me4000_ai_isr(): "
1234 "Buffer overflow\n", dev->minor);
e55c95a3
GG
1235
1236 break;
1237 }
1238 }
1239
1240 /* Work is done, so reset the interrupt */
e55c95a3 1241 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
b08bfa38 1242 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 1243 tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
b08bfa38 1244 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1245 }
1246
b08bfa38
HS
1247 if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
1248 ME4000_IRQ_STATUS_BIT_SC) {
e55c95a3
GG
1249 s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA;
1250
b6241fda
GS
1251 /*
1252 * Acquisition is complete, so stop
1253 * conversion and disable all interrupts
1254 */
b08bfa38 1255 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1256 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1257 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ);
b08bfa38 1258 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1259
1260 /* Poll data until fifo empty */
b08bfa38
HS
1261 while (inl(dev->iobase + ME4000_AI_CTRL_REG) &
1262 ME4000_AI_STATUS_BIT_EF_DATA) {
e55c95a3 1263 /* Read value from data fifo */
b08bfa38 1264 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
e55c95a3
GG
1265 lval ^= 0x8000;
1266
1267 if (!comedi_buf_put(s->async, lval)) {
1268 printk(KERN_ERR
b6241fda
GS
1269 "comedi%d: me4000: me4000_ai_isr(): "
1270 "Buffer overflow\n", dev->minor);
e55c95a3
GG
1271 s->async->events |= COMEDI_CB_OVERFLOW;
1272 break;
1273 }
1274 }
1275
1276 /* Work is done, so reset the interrupt */
e55c95a3 1277 tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
b08bfa38 1278 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 1279 tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
b08bfa38 1280 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1281 }
1282
e55c95a3
GG
1283 if (s->async->events)
1284 comedi_event(dev, s);
1285
1286 return IRQ_HANDLED;
1287}
1288
1289/*=============================================================================
1290 Analog output section
1291 ===========================================================================*/
1292
71b5f4f1 1293static int me4000_ao_insn_write(struct comedi_device *dev,
0a85b6f0
MT
1294 struct comedi_subdevice *s,
1295 struct comedi_insn *insn, unsigned int *data)
e55c95a3 1296{
8407593a 1297 const struct me4000_board *thisboard = comedi_board(dev);
09253b39 1298 struct me4000_info *info = dev->private;
e55c95a3
GG
1299 int chan = CR_CHAN(insn->chanspec);
1300 int rang = CR_RANGE(insn->chanspec);
1301 int aref = CR_AREF(insn->chanspec);
1302 unsigned long tmp;
1303
e55c95a3
GG
1304 if (insn->n == 0) {
1305 return 0;
1306 } else if (insn->n > 1) {
1307 printk(KERN_ERR
b6241fda
GS
1308 "comedi%d: me4000: me4000_ao_insn_write(): "
1309 "Invalid instruction length %d\n", dev->minor, insn->n);
e55c95a3
GG
1310 return -EINVAL;
1311 }
1312
2d504528 1313 if (chan >= thisboard->ao_nchan) {
e55c95a3 1314 printk(KERN_ERR
b6241fda
GS
1315 "comedi%d: me4000: me4000_ao_insn_write(): "
1316 "Invalid channel %d\n", dev->minor, insn->n);
e55c95a3
GG
1317 return -EINVAL;
1318 }
1319
1320 if (rang != 0) {
1321 printk(KERN_ERR
b6241fda
GS
1322 "comedi%d: me4000: me4000_ao_insn_write(): "
1323 "Invalid range %d\n", dev->minor, insn->n);
e55c95a3
GG
1324 return -EINVAL;
1325 }
1326
1327 if (aref != AREF_GROUND && aref != AREF_COMMON) {
1328 printk(KERN_ERR
b6241fda
GS
1329 "comedi%d: me4000: me4000_ao_insn_write(): "
1330 "Invalid aref %d\n", dev->minor, insn->n);
e55c95a3
GG
1331 return -EINVAL;
1332 }
1333
1334 /* Stop any running conversion */
e1d7ccb7 1335 tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan));
e55c95a3 1336 tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
e1d7ccb7 1337 outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan));
e55c95a3
GG
1338
1339 /* Clear control register and set to single mode */
e1d7ccb7 1340 outl(0x0, dev->iobase + ME4000_AO_CTRL_REG(chan));
e55c95a3
GG
1341
1342 /* Write data value */
e1d7ccb7 1343 outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan));
e55c95a3
GG
1344
1345 /* Store in the mirror */
e1d7ccb7 1346 info->ao_readback[chan] = data[0];
e55c95a3
GG
1347
1348 return 1;
1349}
1350
71b5f4f1 1351static int me4000_ao_insn_read(struct comedi_device *dev,
0a85b6f0
MT
1352 struct comedi_subdevice *s,
1353 struct comedi_insn *insn, unsigned int *data)
e55c95a3 1354{
09253b39 1355 struct me4000_info *info = dev->private;
e55c95a3
GG
1356 int chan = CR_CHAN(insn->chanspec);
1357
1358 if (insn->n == 0) {
1359 return 0;
1360 } else if (insn->n > 1) {
0a85b6f0 1361 printk
b6241fda
GS
1362 ("comedi%d: me4000: me4000_ao_insn_read(): "
1363 "Invalid instruction length\n", dev->minor);
e55c95a3
GG
1364 return -EINVAL;
1365 }
1366
e1d7ccb7 1367 data[0] = info->ao_readback[chan];
e55c95a3
GG
1368
1369 return 1;
1370}
1371
1372/*=============================================================================
1373 Digital I/O section
1374 ===========================================================================*/
1375
71b5f4f1 1376static int me4000_dio_insn_bits(struct comedi_device *dev,
0a85b6f0
MT
1377 struct comedi_subdevice *s,
1378 struct comedi_insn *insn, unsigned int *data)
e55c95a3 1379{
e55c95a3
GG
1380 /*
1381 * The insn data consists of a mask in data[0] and the new data
1382 * in data[1]. The mask defines which bits we are concerning about.
1383 * The new data must be anded with the mask.
1384 * Each channel corresponds to a bit.
1385 */
1386 if (data[0]) {
1387 /* Check if requested ports are configured for output */
1388 if ((s->io_bits & data[0]) != data[0])
1389 return -EIO;
1390
1391 s->state &= ~data[0];
1392 s->state |= data[0] & data[1];
1393
1394 /* Write out the new digital output lines */
d6cbe537 1395 outl((s->state >> 0) & 0xFF,
da755d15 1396 dev->iobase + ME4000_DIO_PORT_0_REG);
d6cbe537 1397 outl((s->state >> 8) & 0xFF,
da755d15 1398 dev->iobase + ME4000_DIO_PORT_1_REG);
d6cbe537 1399 outl((s->state >> 16) & 0xFF,
da755d15 1400 dev->iobase + ME4000_DIO_PORT_2_REG);
d6cbe537 1401 outl((s->state >> 24) & 0xFF,
da755d15 1402 dev->iobase + ME4000_DIO_PORT_3_REG);
e55c95a3
GG
1403 }
1404
1405 /* On return, data[1] contains the value of
1406 the digital input and output lines. */
da755d15
HS
1407 data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) |
1408 ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) |
1409 ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) |
1410 ((inl(dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24);
e55c95a3 1411
a2714e3e 1412 return insn->n;
e55c95a3
GG
1413}
1414
71b5f4f1 1415static int me4000_dio_insn_config(struct comedi_device *dev,
0a85b6f0
MT
1416 struct comedi_subdevice *s,
1417 struct comedi_insn *insn, unsigned int *data)
e55c95a3
GG
1418{
1419 unsigned long tmp;
1420 int chan = CR_CHAN(insn->chanspec);
1421
f3445c1e
IA
1422 switch (data[0]) {
1423 default:
1424 return -EINVAL;
1425 case INSN_CONFIG_DIO_QUERY:
e55c95a3 1426 data[1] =
0a85b6f0 1427 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
e55c95a3 1428 return insn->n;
f3445c1e
IA
1429 case INSN_CONFIG_DIO_INPUT:
1430 case INSN_CONFIG_DIO_OUTPUT:
1431 break;
e55c95a3
GG
1432 }
1433
1434 /*
1435 * The input or output configuration of each digital line is
1436 * configured by a special insn_config instruction. chanspec
1437 * contains the channel to be changed, and data[0] contains the
f3445c1e 1438 * value INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_OUTPUT.
e55c95a3
GG
1439 * On the ME-4000 it is only possible to switch port wise (8 bit)
1440 */
1441
da755d15 1442 tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG);
e55c95a3 1443
f3445c1e 1444 if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
e55c95a3
GG
1445 if (chan < 8) {
1446 s->io_bits |= 0xFF;
1447 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
0a85b6f0 1448 ME4000_DIO_CTRL_BIT_MODE_1);
e55c95a3
GG
1449 tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
1450 } else if (chan < 16) {
1451 /*
b6241fda
GS
1452 * Chech for optoisolated ME-4000 version.
1453 * If one the first port is a fixed output
1454 * port and the second is a fixed input port.
e55c95a3 1455 */
da755d15 1456 if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
e55c95a3
GG
1457 return -ENODEV;
1458
1459 s->io_bits |= 0xFF00;
1460 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
0a85b6f0 1461 ME4000_DIO_CTRL_BIT_MODE_3);
e55c95a3
GG
1462 tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
1463 } else if (chan < 24) {
1464 s->io_bits |= 0xFF0000;
1465 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
0a85b6f0 1466 ME4000_DIO_CTRL_BIT_MODE_5);
e55c95a3
GG
1467 tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
1468 } else if (chan < 32) {
1469 s->io_bits |= 0xFF000000;
1470 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
0a85b6f0 1471 ME4000_DIO_CTRL_BIT_MODE_7);
e55c95a3
GG
1472 tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
1473 } else {
1474 return -EINVAL;
1475 }
1476 } else {
1477 if (chan < 8) {
1478 /*
b6241fda
GS
1479 * Chech for optoisolated ME-4000 version.
1480 * If one the first port is a fixed output
1481 * port and the second is a fixed input port.
e55c95a3 1482 */
da755d15 1483 if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
e55c95a3
GG
1484 return -ENODEV;
1485
1486 s->io_bits &= ~0xFF;
1487 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
0a85b6f0 1488 ME4000_DIO_CTRL_BIT_MODE_1);
e55c95a3
GG
1489 } else if (chan < 16) {
1490 s->io_bits &= ~0xFF00;
1491 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
0a85b6f0 1492 ME4000_DIO_CTRL_BIT_MODE_3);
e55c95a3
GG
1493 } else if (chan < 24) {
1494 s->io_bits &= ~0xFF0000;
1495 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
0a85b6f0 1496 ME4000_DIO_CTRL_BIT_MODE_5);
e55c95a3
GG
1497 } else if (chan < 32) {
1498 s->io_bits &= ~0xFF000000;
1499 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
0a85b6f0 1500 ME4000_DIO_CTRL_BIT_MODE_7);
e55c95a3
GG
1501 } else {
1502 return -EINVAL;
1503 }
1504 }
1505
da755d15 1506 outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG);
e55c95a3
GG
1507
1508 return 1;
1509}
1510
1511/*=============================================================================
1512 Counter section
1513 ===========================================================================*/
1514
71b5f4f1 1515static int cnt_reset(struct comedi_device *dev, unsigned int channel)
e55c95a3 1516{
09253b39
HS
1517 struct me4000_info *info = dev->private;
1518
e55c95a3
GG
1519 switch (channel) {
1520 case 0:
ba98ab03
HS
1521 outb(0x30, info->timer_regbase + ME4000_CNT_CTRL_REG);
1522 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
1523 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
e55c95a3
GG
1524 break;
1525 case 1:
ba98ab03
HS
1526 outb(0x70, info->timer_regbase + ME4000_CNT_CTRL_REG);
1527 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
1528 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
e55c95a3
GG
1529 break;
1530 case 2:
ba98ab03
HS
1531 outb(0xB0, info->timer_regbase + ME4000_CNT_CTRL_REG);
1532 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
1533 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
e55c95a3
GG
1534 break;
1535 default:
1536 printk(KERN_ERR
0a85b6f0
MT
1537 "comedi%d: me4000: cnt_reset(): Invalid channel\n",
1538 dev->minor);
e55c95a3
GG
1539 return -EINVAL;
1540 }
1541
1542 return 0;
1543}
1544
71b5f4f1 1545static int cnt_config(struct comedi_device *dev, unsigned int channel,
0a85b6f0 1546 unsigned int mode)
e55c95a3 1547{
09253b39 1548 struct me4000_info *info = dev->private;
e55c95a3
GG
1549 int tmp = 0;
1550
e55c95a3
GG
1551 switch (channel) {
1552 case 0:
1553 tmp |= ME4000_CNT_COUNTER_0;
1554 break;
1555 case 1:
1556 tmp |= ME4000_CNT_COUNTER_1;
1557 break;
1558 case 2:
1559 tmp |= ME4000_CNT_COUNTER_2;
1560 break;
1561 default:
1562 printk(KERN_ERR
0a85b6f0
MT
1563 "comedi%d: me4000: cnt_config(): Invalid channel\n",
1564 dev->minor);
e55c95a3
GG
1565 return -EINVAL;
1566 }
1567
1568 switch (mode) {
1569 case 0:
1570 tmp |= ME4000_CNT_MODE_0;
1571 break;
1572 case 1:
1573 tmp |= ME4000_CNT_MODE_1;
1574 break;
1575 case 2:
1576 tmp |= ME4000_CNT_MODE_2;
1577 break;
1578 case 3:
1579 tmp |= ME4000_CNT_MODE_3;
1580 break;
1581 case 4:
1582 tmp |= ME4000_CNT_MODE_4;
1583 break;
1584 case 5:
1585 tmp |= ME4000_CNT_MODE_5;
1586 break;
1587 default:
1588 printk(KERN_ERR
0a85b6f0
MT
1589 "comedi%d: me4000: cnt_config(): Invalid counter mode\n",
1590 dev->minor);
e55c95a3
GG
1591 return -EINVAL;
1592 }
1593
1594 /* Write the control word */
1595 tmp |= 0x30;
ba98ab03 1596 outb(tmp, info->timer_regbase + ME4000_CNT_CTRL_REG);
e55c95a3
GG
1597
1598 return 0;
1599}
1600
71b5f4f1 1601static int me4000_cnt_insn_config(struct comedi_device *dev,
0a85b6f0
MT
1602 struct comedi_subdevice *s,
1603 struct comedi_insn *insn, unsigned int *data)
e55c95a3
GG
1604{
1605
1606 int err;
1607
e55c95a3
GG
1608 switch (data[0]) {
1609 case GPCT_RESET:
1610 if (insn->n != 1) {
1611 printk(KERN_ERR
b6241fda
GS
1612 "comedi%d: me4000: me4000_cnt_insn_config(): "
1613 "Invalid instruction length%d\n",
0a85b6f0 1614 dev->minor, insn->n);
e55c95a3
GG
1615 return -EINVAL;
1616 }
1617
1618 err = cnt_reset(dev, insn->chanspec);
1619 if (err)
1620 return err;
1621 break;
1622 case GPCT_SET_OPERATION:
1623 if (insn->n != 2) {
1624 printk(KERN_ERR
b6241fda
GS
1625 "comedi%d: me4000: me4000_cnt_insn_config(): "
1626 "Invalid instruction length%d\n",
0a85b6f0 1627 dev->minor, insn->n);
e55c95a3
GG
1628 return -EINVAL;
1629 }
1630
1631 err = cnt_config(dev, insn->chanspec, data[1]);
1632 if (err)
1633 return err;
1634 break;
1635 default:
1636 printk(KERN_ERR
b6241fda
GS
1637 "comedi%d: me4000: me4000_cnt_insn_config(): "
1638 "Invalid instruction\n", dev->minor);
e55c95a3
GG
1639 return -EINVAL;
1640 }
1641
1642 return 2;
1643}
1644
71b5f4f1 1645static int me4000_cnt_insn_read(struct comedi_device *dev,
0a85b6f0
MT
1646 struct comedi_subdevice *s,
1647 struct comedi_insn *insn, unsigned int *data)
e55c95a3 1648{
09253b39 1649 struct me4000_info *info = dev->private;
e55c95a3
GG
1650 unsigned short tmp;
1651
82675f35 1652 if (insn->n == 0)
e55c95a3 1653 return 0;
82675f35 1654
e55c95a3
GG
1655 if (insn->n > 1) {
1656 printk(KERN_ERR
b6241fda
GS
1657 "comedi%d: me4000: me4000_cnt_insn_read(): "
1658 "Invalid instruction length %d\n",
0a85b6f0 1659 dev->minor, insn->n);
e55c95a3
GG
1660 return -EINVAL;
1661 }
1662
1663 switch (insn->chanspec) {
1664 case 0:
ba98ab03 1665 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
e55c95a3 1666 data[0] = tmp;
ba98ab03 1667 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
e55c95a3
GG
1668 data[0] |= tmp << 8;
1669 break;
1670 case 1:
ba98ab03 1671 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
e55c95a3 1672 data[0] = tmp;
ba98ab03 1673 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
e55c95a3
GG
1674 data[0] |= tmp << 8;
1675 break;
1676 case 2:
ba98ab03 1677 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
e55c95a3 1678 data[0] = tmp;
ba98ab03 1679 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
e55c95a3
GG
1680 data[0] |= tmp << 8;
1681 break;
1682 default:
1683 printk(KERN_ERR
b6241fda
GS
1684 "comedi%d: me4000: me4000_cnt_insn_read(): "
1685 "Invalid channel %d\n",
0a85b6f0 1686 dev->minor, insn->chanspec);
e55c95a3
GG
1687 return -EINVAL;
1688 }
1689
1690 return 1;
1691}
1692
71b5f4f1 1693static int me4000_cnt_insn_write(struct comedi_device *dev,
0a85b6f0
MT
1694 struct comedi_subdevice *s,
1695 struct comedi_insn *insn, unsigned int *data)
e55c95a3 1696{
09253b39 1697 struct me4000_info *info = dev->private;
e55c95a3
GG
1698 unsigned short tmp;
1699
e55c95a3
GG
1700 if (insn->n == 0) {
1701 return 0;
1702 } else if (insn->n > 1) {
1703 printk(KERN_ERR
b6241fda
GS
1704 "comedi%d: me4000: me4000_cnt_insn_write(): "
1705 "Invalid instruction length %d\n",
0a85b6f0 1706 dev->minor, insn->n);
e55c95a3
GG
1707 return -EINVAL;
1708 }
1709
1710 switch (insn->chanspec) {
1711 case 0:
1712 tmp = data[0] & 0xFF;
ba98ab03 1713 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
e55c95a3 1714 tmp = (data[0] >> 8) & 0xFF;
ba98ab03 1715 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
e55c95a3
GG
1716 break;
1717 case 1:
1718 tmp = data[0] & 0xFF;
ba98ab03 1719 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
e55c95a3 1720 tmp = (data[0] >> 8) & 0xFF;
ba98ab03 1721 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
e55c95a3
GG
1722 break;
1723 case 2:
1724 tmp = data[0] & 0xFF;
ba98ab03 1725 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
e55c95a3 1726 tmp = (data[0] >> 8) & 0xFF;
ba98ab03 1727 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
e55c95a3
GG
1728 break;
1729 default:
1730 printk(KERN_ERR
b6241fda
GS
1731 "comedi%d: me4000: me4000_cnt_insn_write(): "
1732 "Invalid channel %d\n",
0a85b6f0 1733 dev->minor, insn->chanspec);
e55c95a3
GG
1734 return -EINVAL;
1735 }
1736
1737 return 1;
1738}
1739
4b2f15f1
HS
1740static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
1741{
1742 struct me4000_info *info;
1743 struct pci_dev *pci_device = NULL;
1744 int result, i;
1745 const struct me4000_board *board;
1746
1747 /* Allocate private memory */
1748 result = alloc_private(dev, sizeof(*info));
1749 if (result)
1750 return result;
1751 info = dev->private;
1752
1753 /*
1754 * Probe the device to determine what device in the series it is.
1755 */
1756 for_each_pci_dev(pci_device) {
1757 if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) {
1758 for (i = 0; i < ARRAY_SIZE(me4000_boards); i++) {
1759 if (me4000_boards[i].device_id ==
1760 pci_device->device) {
1761 /*
1762 * Was a particular
1763 * bus/slot requested?
1764 */
1765 if ((it->options[0] != 0)
1766 || (it->options[1] != 0)) {
1767 /*
1768 * Are we on the wrong
1769 * bus/slot?
1770 */
1771 if (pci_device->bus->number !=
1772 it->options[0]
1773 ||
1774 PCI_SLOT(pci_device->devfn)
1775 != it->options[1]) {
1776 continue;
1777 }
1778 }
1779 dev->board_ptr = me4000_boards + i;
1780 board = comedi_board(dev);
4b2f15f1
HS
1781 goto found;
1782 }
1783 }
1784 }
1785 }
1786 return -ENODEV;
1787
1788found:
f4c772f0 1789 comedi_set_hw_dev(dev, &pci_device->dev);
4b2f15f1
HS
1790 dev->board_name = board->name;
1791
1792 result = comedi_pci_enable(pci_device, dev->board_name);
1793 if (result)
1794 return result;
1795
1796 info->plx_regbase = pci_resource_start(pci_device, 1);
1797 if (!info->plx_regbase)
1798 return -ENODEV;
1799
1800 dev->iobase = pci_resource_start(pci_device, 2);
1801 if (!dev->iobase)
1802 return -ENODEV;
1803
1804 info->timer_regbase = pci_resource_start(pci_device, 3);
1805 if (!info->timer_regbase)
1806 return -ENODEV;
1807
1808 info->program_regbase = pci_resource_start(pci_device, 5);
1809 if (!info->program_regbase)
1810 return -ENODEV;
1811
1812 dev->irq = pci_device->irq;
1813
1814 result = xilinx_download(dev);
1815 if (result)
1816 return result;
1817
1818 result = reset_board(dev);
1819 if (result)
1820 return result;
1821
1822 return 0;
1823}
1824
3af09830
HS
1825static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1826{
8407593a 1827 const struct me4000_board *thisboard;
3af09830
HS
1828 struct comedi_subdevice *s;
1829 int result;
1830
3af09830
HS
1831 result = me4000_probe(dev, it);
1832 if (result)
1833 return result;
8407593a 1834 thisboard = comedi_board(dev);
3af09830 1835
8b6c5694
HS
1836 result = comedi_alloc_subdevices(dev, 4);
1837 if (result)
1838 return result;
3af09830
HS
1839
1840 /*=========================================================================
1841 Analog input subdevice
1842 ========================================================================*/
1843
8aaf2717 1844 s = &dev->subdevices[0];
3af09830 1845
6ba8dfef 1846 if (thisboard->ai_nchan) {
3af09830
HS
1847 s->type = COMEDI_SUBD_AI;
1848 s->subdev_flags =
1849 SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
6ba8dfef 1850 s->n_chan = thisboard->ai_nchan;
3af09830
HS
1851 s->maxdata = 0xFFFF; /* 16 bit ADC */
1852 s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
1853 s->range_table = &me4000_ai_range;
1854 s->insn_read = me4000_ai_insn_read;
1855
109daa79
HS
1856 if (dev->irq > 0) {
1857 if (request_irq(dev->irq, me4000_ai_isr,
3af09830
HS
1858 IRQF_SHARED, "ME-4000", dev)) {
1859 printk
1860 ("comedi%d: me4000: me4000_attach(): "
1861 "Unable to allocate irq\n", dev->minor);
1862 } else {
1863 dev->read_subdev = s;
1864 s->subdev_flags |= SDF_CMD_READ;
1865 s->cancel = me4000_ai_cancel;
1866 s->do_cmdtest = me4000_ai_do_cmd_test;
1867 s->do_cmd = me4000_ai_do_cmd;
1868 }
1869 } else {
1870 printk(KERN_WARNING
1871 "comedi%d: me4000: me4000_attach(): "
1872 "No interrupt available\n", dev->minor);
1873 }
1874 } else {
1875 s->type = COMEDI_SUBD_UNUSED;
1876 }
1877
1878 /*=========================================================================
1879 Analog output subdevice
1880 ========================================================================*/
1881
8aaf2717 1882 s = &dev->subdevices[1];
3af09830 1883
2d504528 1884 if (thisboard->ao_nchan) {
3af09830
HS
1885 s->type = COMEDI_SUBD_AO;
1886 s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
2d504528 1887 s->n_chan = thisboard->ao_nchan;
3af09830 1888 s->maxdata = 0xFFFF; /* 16 bit DAC */
4683f9f8 1889 s->range_table = &range_bipolar10;
3af09830
HS
1890 s->insn_write = me4000_ao_insn_write;
1891 s->insn_read = me4000_ao_insn_read;
1892 } else {
1893 s->type = COMEDI_SUBD_UNUSED;
1894 }
1895
1896 /*=========================================================================
1897 Digital I/O subdevice
1898 ========================================================================*/
1899
8aaf2717 1900 s = &dev->subdevices[2];
3af09830 1901
898f5191 1902 if (thisboard->dio_nchan) {
3af09830
HS
1903 s->type = COMEDI_SUBD_DIO;
1904 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
898f5191 1905 s->n_chan = thisboard->dio_nchan;
3af09830
HS
1906 s->maxdata = 1;
1907 s->range_table = &range_digital;
1908 s->insn_bits = me4000_dio_insn_bits;
1909 s->insn_config = me4000_dio_insn_config;
1910 } else {
1911 s->type = COMEDI_SUBD_UNUSED;
1912 }
1913
1914 /*
1915 * Check for optoisolated ME-4000 version. If one the first
1916 * port is a fixed output port and the second is a fixed input port.
1917 */
da755d15 1918 if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) {
3af09830 1919 s->io_bits |= 0xFF;
da755d15
HS
1920 outl(ME4000_DIO_CTRL_BIT_MODE_0,
1921 dev->iobase + ME4000_DIO_DIR_REG);
3af09830
HS
1922 }
1923
1924 /*=========================================================================
1925 Counter subdevice
1926 ========================================================================*/
1927
8aaf2717 1928 s = &dev->subdevices[3];
3af09830 1929
eedf4299 1930 if (thisboard->has_counter) {
3af09830
HS
1931 s->type = COMEDI_SUBD_COUNTER;
1932 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
eedf4299 1933 s->n_chan = 3;
3af09830
HS
1934 s->maxdata = 0xFFFF; /* 16 bit counters */
1935 s->insn_read = me4000_cnt_insn_read;
1936 s->insn_write = me4000_cnt_insn_write;
1937 s->insn_config = me4000_cnt_insn_config;
1938 } else {
1939 s->type = COMEDI_SUBD_UNUSED;
1940 }
1941
1942 return 0;
1943}
1944
484ecc95 1945static void me4000_detach(struct comedi_device *dev)
3af09830 1946{
f4c772f0 1947 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
09253b39 1948
f4c772f0
HS
1949 if (pcidev) {
1950 if (dev->iobase) {
3af09830 1951 reset_board(dev);
f4c772f0 1952 comedi_pci_disable(pcidev);
3af09830 1953 }
f4c772f0 1954 pci_dev_put(pcidev);
3af09830 1955 }
3af09830
HS
1956}
1957
75e6301b 1958static struct comedi_driver me4000_driver = {
3af09830
HS
1959 .driver_name = "me4000",
1960 .module = THIS_MODULE,
1961 .attach = me4000_attach,
1962 .detach = me4000_detach,
1963};
1964
75e6301b
HS
1965static int __devinit me4000_pci_probe(struct pci_dev *dev,
1966 const struct pci_device_id *ent)
727b286b 1967{
75e6301b 1968 return comedi_pci_auto_config(dev, &me4000_driver);
727b286b
AT
1969}
1970
75e6301b 1971static void __devexit me4000_pci_remove(struct pci_dev *dev)
727b286b
AT
1972{
1973 comedi_pci_auto_unconfig(dev);
1974}
1975
3af09830 1976static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
9e072731
HS
1977 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650)},
1978 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660)},
1979 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I)},
1980 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660S)},
1981 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660IS)},
1982 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670)},
1983 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I)},
1984 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S)},
1985 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS)},
1986 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680)},
1987 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I)},
1988 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S)},
1989 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS)},
1990 {0}
3af09830
HS
1991};
1992MODULE_DEVICE_TABLE(pci, me4000_pci_table);
1993
75e6301b
HS
1994static struct pci_driver me4000_pci_driver = {
1995 .name = "me4000",
3af09830 1996 .id_table = me4000_pci_table,
75e6301b
HS
1997 .probe = me4000_pci_probe,
1998 .remove = __devexit_p(me4000_pci_remove),
727b286b 1999};
75e6301b 2000module_comedi_pci_driver(me4000_driver, me4000_pci_driver);
90f703d3
AT
2001
2002MODULE_AUTHOR("Comedi http://www.comedi.org");
2003MODULE_DESCRIPTION("Comedi low-level driver");
2004MODULE_LICENSE("GPL");