staging: comedi: me4000: remove 'board' from me4000_ai_check_chanlist()
[deliverable/linux.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.
e55c95a3
GG
17 */
18/*
19Driver: me4000
20Description: Meilhaus ME-4000 series boards
21Devices: [Meilhaus] ME-4650 (me4000), ME-4670i, ME-4680, ME-4680i, ME-4680is
22Author: gg (Guenter Gebhardt <g.gebhardt@meilhaus.com>)
23Updated: Mon, 18 Mar 2002 15:34:01 -0800
24Status: broken (no support for loading firmware)
25
26Supports:
27
28 - Analog Input
29 - Analog Output
30 - Digital I/O
31 - Counter
32
5f8f8d43 33Configuration Options: not applicable, uses PCI auto config
e55c95a3
GG
34
35The firmware required by these boards is available in the
36comedi_nonfree_firmware tarball available from
37http://www.comedi.org. However, the driver's support for
38loading the firmware through comedi_config is currently
39broken.
40
41 */
42
ce157f80 43#include <linux/module.h>
e55c95a3 44#include <linux/delay.h>
33782dd5 45#include <linux/interrupt.h>
e55c95a3 46
f2e8e285 47#include "../comedi_pci.h"
33782dd5 48
d92d39d9 49#include "comedi_8254.h"
58af6b92 50#include "plx9052.h"
81dd1811 51
ac584af5 52#define ME4000_FIRMWARE "me4000_firmware.bin"
e55c95a3 53
81dd1811
HS
54/*
55 * ME4000 Register map and bit defines
56 */
57#define ME4000_AO_CHAN(x) ((x) * 0x18)
58
59#define ME4000_AO_CTRL_REG(x) (0x00 + ME4000_AO_CHAN(x))
60#define ME4000_AO_CTRL_BIT_MODE_0 (1 << 0)
61#define ME4000_AO_CTRL_BIT_MODE_1 (1 << 1)
62#define ME4000_AO_CTRL_MASK_MODE (3 << 0)
63#define ME4000_AO_CTRL_BIT_STOP (1 << 2)
64#define ME4000_AO_CTRL_BIT_ENABLE_FIFO (1 << 3)
65#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG (1 << 4)
66#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE (1 << 5)
67#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP (1 << 7)
68#define ME4000_AO_CTRL_BIT_ENABLE_DO (1 << 8)
69#define ME4000_AO_CTRL_BIT_ENABLE_IRQ (1 << 9)
70#define ME4000_AO_CTRL_BIT_RESET_IRQ (1 << 10)
71#define ME4000_AO_STATUS_REG(x) (0x04 + ME4000_AO_CHAN(x))
72#define ME4000_AO_STATUS_BIT_FSM (1 << 0)
73#define ME4000_AO_STATUS_BIT_FF (1 << 1)
74#define ME4000_AO_STATUS_BIT_HF (1 << 2)
75#define ME4000_AO_STATUS_BIT_EF (1 << 3)
76#define ME4000_AO_FIFO_REG(x) (0x08 + ME4000_AO_CHAN(x))
77#define ME4000_AO_SINGLE_REG(x) (0x0c + ME4000_AO_CHAN(x))
78#define ME4000_AO_TIMER_REG(x) (0x10 + ME4000_AO_CHAN(x))
79#define ME4000_AI_CTRL_REG 0x74
80#define ME4000_AI_STATUS_REG 0x74
81#define ME4000_AI_CTRL_BIT_MODE_0 (1 << 0)
82#define ME4000_AI_CTRL_BIT_MODE_1 (1 << 1)
83#define ME4000_AI_CTRL_BIT_MODE_2 (1 << 2)
84#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD (1 << 3)
85#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP (1 << 4)
86#define ME4000_AI_CTRL_BIT_STOP (1 << 5)
87#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO (1 << 6)
88#define ME4000_AI_CTRL_BIT_DATA_FIFO (1 << 7)
89#define ME4000_AI_CTRL_BIT_FULLSCALE (1 << 8)
90#define ME4000_AI_CTRL_BIT_OFFSET (1 << 9)
91#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG (1 << 10)
92#define ME4000_AI_CTRL_BIT_EX_TRIG (1 << 11)
93#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING (1 << 12)
94#define ME4000_AI_CTRL_BIT_EX_IRQ (1 << 13)
95#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET (1 << 14)
96#define ME4000_AI_CTRL_BIT_LE_IRQ (1 << 15)
97#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET (1 << 16)
98#define ME4000_AI_CTRL_BIT_HF_IRQ (1 << 17)
99#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET (1 << 18)
100#define ME4000_AI_CTRL_BIT_SC_IRQ (1 << 19)
101#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET (1 << 20)
102#define ME4000_AI_CTRL_BIT_SC_RELOAD (1 << 21)
103#define ME4000_AI_STATUS_BIT_EF_CHANNEL (1 << 22)
104#define ME4000_AI_STATUS_BIT_HF_CHANNEL (1 << 23)
105#define ME4000_AI_STATUS_BIT_FF_CHANNEL (1 << 24)
106#define ME4000_AI_STATUS_BIT_EF_DATA (1 << 25)
107#define ME4000_AI_STATUS_BIT_HF_DATA (1 << 26)
108#define ME4000_AI_STATUS_BIT_FF_DATA (1 << 27)
109#define ME4000_AI_STATUS_BIT_LE (1 << 28)
110#define ME4000_AI_STATUS_BIT_FSM (1 << 29)
111#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31)
112#define ME4000_AI_CHANNEL_LIST_REG 0x78
113#define ME4000_AI_LIST_INPUT_SINGLE_ENDED (0 << 5)
114#define ME4000_AI_LIST_INPUT_DIFFERENTIAL (1 << 5)
115#define ME4000_AI_LIST_RANGE_BIPOLAR_10 (0 << 6)
116#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 (1 << 6)
117#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 (2 << 6)
118#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 (3 << 6)
119#define ME4000_AI_LIST_LAST_ENTRY (1 << 8)
120#define ME4000_AI_DATA_REG 0x7c
121#define ME4000_AI_CHAN_TIMER_REG 0x80
122#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84
123#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88
124#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8c
125#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90
126#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94
127#define ME4000_AI_START_REG 0x98
128#define ME4000_IRQ_STATUS_REG 0x9c
129#define ME4000_IRQ_STATUS_BIT_EX (1 << 0)
130#define ME4000_IRQ_STATUS_BIT_LE (1 << 1)
131#define ME4000_IRQ_STATUS_BIT_AI_HF (1 << 2)
132#define ME4000_IRQ_STATUS_BIT_AO_0_HF (1 << 3)
133#define ME4000_IRQ_STATUS_BIT_AO_1_HF (1 << 4)
134#define ME4000_IRQ_STATUS_BIT_AO_2_HF (1 << 5)
135#define ME4000_IRQ_STATUS_BIT_AO_3_HF (1 << 6)
136#define ME4000_IRQ_STATUS_BIT_SC (1 << 7)
137#define ME4000_DIO_PORT_0_REG 0xa0
138#define ME4000_DIO_PORT_1_REG 0xa4
139#define ME4000_DIO_PORT_2_REG 0xa8
140#define ME4000_DIO_PORT_3_REG 0xac
141#define ME4000_DIO_DIR_REG 0xb0
142#define ME4000_AO_LOADSETREG_XX 0xb4
143#define ME4000_DIO_CTRL_REG 0xb8
144#define ME4000_DIO_CTRL_BIT_MODE_0 (1 << 0)
145#define ME4000_DIO_CTRL_BIT_MODE_1 (1 << 1)
146#define ME4000_DIO_CTRL_BIT_MODE_2 (1 << 2)
147#define ME4000_DIO_CTRL_BIT_MODE_3 (1 << 3)
148#define ME4000_DIO_CTRL_BIT_MODE_4 (1 << 4)
149#define ME4000_DIO_CTRL_BIT_MODE_5 (1 << 5)
150#define ME4000_DIO_CTRL_BIT_MODE_6 (1 << 6)
151#define ME4000_DIO_CTRL_BIT_MODE_7 (1 << 7)
152#define ME4000_DIO_CTRL_BIT_FUNCTION_0 (1 << 8)
153#define ME4000_DIO_CTRL_BIT_FUNCTION_1 (1 << 9)
154#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 (1 << 10)
155#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 (1 << 11)
156#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 (1 << 12)
157#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 (1 << 13)
158#define ME4000_AO_DEMUX_ADJUST_REG 0xbc
159#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4c
160#define ME4000_AI_SAMPLE_COUNTER_REG 0xc0
161
81dd1811
HS
162#define ME4000_AI_FIFO_COUNT 2048
163
164#define ME4000_AI_MIN_TICKS 66
165#define ME4000_AI_MIN_SAMPLE_TIME 2000
81dd1811
HS
166
167#define ME4000_AI_CHANNEL_LIST_COUNT 1024
168
cc6f3336
HS
169struct me4000_info {
170 unsigned long plx_regbase;
cc6f3336
HS
171};
172
8c355509
HS
173enum me4000_boardid {
174 BOARD_ME4650,
175 BOARD_ME4660,
176 BOARD_ME4660I,
177 BOARD_ME4660S,
178 BOARD_ME4660IS,
179 BOARD_ME4670,
180 BOARD_ME4670I,
181 BOARD_ME4670S,
182 BOARD_ME4670IS,
183 BOARD_ME4680,
184 BOARD_ME4680I,
185 BOARD_ME4680S,
186 BOARD_ME4680IS,
187};
188
06b60981
HS
189struct me4000_board {
190 const char *name;
06b60981
HS
191 int ao_nchan;
192 int ao_fifo;
193 int ai_nchan;
194 int ai_diff_nchan;
195 int ai_sh_nchan;
196 int ex_trig_analog;
06b60981
HS
197 int has_counter;
198};
199
27f4caaa 200static const struct me4000_board me4000_boards[] = {
8c355509 201 [BOARD_ME4650] = {
035d432a 202 .name = "ME-4650",
6ba8dfef 203 .ai_nchan = 16,
8c355509
HS
204 },
205 [BOARD_ME4660] = {
035d432a 206 .name = "ME-4660",
6ba8dfef
HS
207 .ai_nchan = 32,
208 .ai_diff_nchan = 16,
eedf4299 209 .has_counter = 1,
8c355509
HS
210 },
211 [BOARD_ME4660I] = {
035d432a 212 .name = "ME-4660i",
6ba8dfef
HS
213 .ai_nchan = 32,
214 .ai_diff_nchan = 16,
eedf4299 215 .has_counter = 1,
8c355509
HS
216 },
217 [BOARD_ME4660S] = {
035d432a 218 .name = "ME-4660s",
6ba8dfef
HS
219 .ai_nchan = 32,
220 .ai_diff_nchan = 16,
221 .ai_sh_nchan = 8,
eedf4299 222 .has_counter = 1,
8c355509
HS
223 },
224 [BOARD_ME4660IS] = {
035d432a 225 .name = "ME-4660is",
6ba8dfef
HS
226 .ai_nchan = 32,
227 .ai_diff_nchan = 16,
228 .ai_sh_nchan = 8,
eedf4299 229 .has_counter = 1,
8c355509
HS
230 },
231 [BOARD_ME4670] = {
035d432a 232 .name = "ME-4670",
2d504528 233 .ao_nchan = 4,
6ba8dfef
HS
234 .ai_nchan = 32,
235 .ai_diff_nchan = 16,
236 .ex_trig_analog = 1,
eedf4299 237 .has_counter = 1,
8c355509
HS
238 },
239 [BOARD_ME4670I] = {
035d432a 240 .name = "ME-4670i",
2d504528 241 .ao_nchan = 4,
6ba8dfef
HS
242 .ai_nchan = 32,
243 .ai_diff_nchan = 16,
244 .ex_trig_analog = 1,
eedf4299 245 .has_counter = 1,
8c355509
HS
246 },
247 [BOARD_ME4670S] = {
035d432a 248 .name = "ME-4670s",
2d504528 249 .ao_nchan = 4,
6ba8dfef
HS
250 .ai_nchan = 32,
251 .ai_diff_nchan = 16,
252 .ai_sh_nchan = 8,
253 .ex_trig_analog = 1,
eedf4299 254 .has_counter = 1,
8c355509
HS
255 },
256 [BOARD_ME4670IS] = {
035d432a 257 .name = "ME-4670is",
2d504528 258 .ao_nchan = 4,
6ba8dfef
HS
259 .ai_nchan = 32,
260 .ai_diff_nchan = 16,
261 .ai_sh_nchan = 8,
262 .ex_trig_analog = 1,
eedf4299 263 .has_counter = 1,
8c355509
HS
264 },
265 [BOARD_ME4680] = {
035d432a 266 .name = "ME-4680",
2d504528
HS
267 .ao_nchan = 4,
268 .ao_fifo = 4,
6ba8dfef
HS
269 .ai_nchan = 32,
270 .ai_diff_nchan = 16,
271 .ex_trig_analog = 1,
eedf4299 272 .has_counter = 1,
8c355509
HS
273 },
274 [BOARD_ME4680I] = {
035d432a 275 .name = "ME-4680i",
2d504528
HS
276 .ao_nchan = 4,
277 .ao_fifo = 4,
6ba8dfef
HS
278 .ai_nchan = 32,
279 .ai_diff_nchan = 16,
280 .ex_trig_analog = 1,
eedf4299 281 .has_counter = 1,
8c355509
HS
282 },
283 [BOARD_ME4680S] = {
035d432a 284 .name = "ME-4680s",
2d504528
HS
285 .ao_nchan = 4,
286 .ao_fifo = 4,
6ba8dfef
HS
287 .ai_nchan = 32,
288 .ai_diff_nchan = 16,
289 .ai_sh_nchan = 8,
290 .ex_trig_analog = 1,
eedf4299 291 .has_counter = 1,
8c355509
HS
292 },
293 [BOARD_ME4680IS] = {
035d432a 294 .name = "ME-4680is",
2d504528
HS
295 .ao_nchan = 4,
296 .ao_fifo = 4,
6ba8dfef
HS
297 .ai_nchan = 32,
298 .ai_diff_nchan = 16,
299 .ai_sh_nchan = 8,
300 .ex_trig_analog = 1,
eedf4299 301 .has_counter = 1,
035d432a 302 },
e55c95a3
GG
303};
304
9ced1de6 305static const struct comedi_lrange me4000_ai_range = {
93626a45
HS
306 4, {
307 UNI_RANGE(2.5),
308 UNI_RANGE(10),
309 BIP_RANGE(2.5),
310 BIP_RANGE(10)
311 }
e55c95a3
GG
312};
313
ac584af5
HS
314static int me4000_xilinx_download(struct comedi_device *dev,
315 const u8 *data, size_t size,
316 unsigned long context)
e55c95a3 317{
fe531d12 318 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
09253b39 319 struct me4000_info *info = dev->private;
fe531d12 320 unsigned long xilinx_iobase = pci_resource_start(pcidev, 5);
ac584af5
HS
321 unsigned int file_length;
322 unsigned int val;
323 unsigned int i;
e55c95a3 324
fe531d12
HS
325 if (!xilinx_iobase)
326 return -ENODEV;
327
e55c95a3
GG
328 /*
329 * Set PLX local interrupt 2 polarity to high.
330 * Interrupt is thrown by init pin of xilinx.
331 */
58af6b92 332 outl(PLX9052_INTCSR_LI2POL, info->plx_regbase + PLX9052_INTCSR);
e55c95a3
GG
333
334 /* Set /CS and /WRITE of the Xilinx */
ac584af5
HS
335 val = inl(info->plx_regbase + PLX9052_CNTRL);
336 val |= PLX9052_CNTRL_UIO2_DATA;
337 outl(val, info->plx_regbase + PLX9052_CNTRL);
e55c95a3
GG
338
339 /* Init Xilinx with CS1 */
fe531d12 340 inb(xilinx_iobase + 0xC8);
e55c95a3
GG
341
342 /* Wait until /INIT pin is set */
343 udelay(20);
ac584af5
HS
344 val = inl(info->plx_regbase + PLX9052_INTCSR);
345 if (!(val & PLX9052_INTCSR_LI2STAT)) {
5da80ee8 346 dev_err(dev->class_dev, "Can't init Xilinx\n");
e55c95a3
GG
347 return -EIO;
348 }
349
350 /* Reset /CS and /WRITE of the Xilinx */
ac584af5
HS
351 val = inl(info->plx_regbase + PLX9052_CNTRL);
352 val &= ~PLX9052_CNTRL_UIO2_DATA;
353 outl(val, info->plx_regbase + PLX9052_CNTRL);
e55c95a3 354
ac584af5
HS
355 /* Download Xilinx firmware */
356 file_length = (((unsigned int)data[0] & 0xff) << 24) +
357 (((unsigned int)data[1] & 0xff) << 16) +
358 (((unsigned int)data[2] & 0xff) << 8) +
359 ((unsigned int)data[3] & 0xff);
360 udelay(10);
e55c95a3 361
ac584af5
HS
362 for (i = 0; i < file_length; i++) {
363 outb(data[16 + i], xilinx_iobase);
364 udelay(10);
365
366 /* Check if BUSY flag is low */
367 val = inl(info->plx_regbase + PLX9052_CNTRL);
368 if (val & PLX9052_CNTRL_UIO1_DATA) {
369 dev_err(dev->class_dev,
370 "Xilinx is still busy (i = %d)\n", i);
371 return -EIO;
e55c95a3
GG
372 }
373 }
374
375 /* If done flag is high download was successful */
ac584af5
HS
376 val = inl(info->plx_regbase + PLX9052_CNTRL);
377 if (!(val & PLX9052_CNTRL_UIO0_DATA)) {
5da80ee8
HS
378 dev_err(dev->class_dev, "DONE flag is not set\n");
379 dev_err(dev->class_dev, "Download not successful\n");
e55c95a3
GG
380 return -EIO;
381 }
382
383 /* Set /CS and /WRITE */
ac584af5
HS
384 val = inl(info->plx_regbase + PLX9052_CNTRL);
385 val |= PLX9052_CNTRL_UIO2_DATA;
386 outl(val, info->plx_regbase + PLX9052_CNTRL);
e55c95a3
GG
387
388 return 0;
389}
390
2f348ecd 391static void me4000_reset(struct comedi_device *dev)
e55c95a3 392{
09253b39 393 struct me4000_info *info = dev->private;
ac2832f8 394 unsigned int val;
e1d7ccb7 395 int chan;
e55c95a3 396
e55c95a3 397 /* Make a hardware reset */
4564cfd0
HS
398 val = inl(info->plx_regbase + PLX9052_CNTRL);
399 val |= PLX9052_CNTRL_PCI_RESET;
400 outl(val, info->plx_regbase + PLX9052_CNTRL);
401 val &= ~PLX9052_CNTRL_PCI_RESET;
864b52c4 402 outl(val, info->plx_regbase + PLX9052_CNTRL);
e55c95a3
GG
403
404 /* 0x8000 to the DACs means an output voltage of 0V */
e1d7ccb7
HS
405 for (chan = 0; chan < 4; chan++)
406 outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan));
e55c95a3
GG
407
408 /* Set both stop bits in the analog input control register */
d6cbe537 409 outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
6c7d2c8b 410 dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
411
412 /* Set both stop bits in the analog output control register */
e1d7ccb7
HS
413 val = ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP;
414 for (chan = 0; chan < 4; chan++)
415 outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan));
e55c95a3
GG
416
417 /* Enable interrupts on the PLX */
58af6b92
HS
418 outl(PLX9052_INTCSR_LI1ENAB |
419 PLX9052_INTCSR_LI1POL |
420 PLX9052_INTCSR_PCIENAB, info->plx_regbase + PLX9052_INTCSR);
e55c95a3
GG
421
422 /* Set the adustment register for AO demux */
d6cbe537 423 outl(ME4000_AO_DEMUX_ADJUST_VALUE,
6c7d2c8b 424 dev->iobase + ME4000_AO_DEMUX_ADJUST_REG);
e55c95a3 425
b6241fda
GS
426 /*
427 * Set digital I/O direction for port 0
428 * to output on isolated versions
429 */
362bcbde
HS
430 if (!(inl(dev->iobase + ME4000_DIO_DIR_REG) & 0x1))
431 outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG);
e55c95a3
GG
432}
433
e55c95a3
GG
434/*=============================================================================
435 Analog input section
436 ===========================================================================*/
437
71b5f4f1 438static int me4000_ai_insn_read(struct comedi_device *dev,
1a023870
HS
439 struct comedi_subdevice *s,
440 struct comedi_insn *insn,
441 unsigned int *data)
e55c95a3 442{
e55c95a3
GG
443 int chan = CR_CHAN(insn->chanspec);
444 int rang = CR_RANGE(insn->chanspec);
445 int aref = CR_AREF(insn->chanspec);
446
ac2832f8
IA
447 unsigned int entry = 0;
448 unsigned int tmp;
449 unsigned int lval;
e55c95a3 450
e55c95a3
GG
451 if (insn->n == 0) {
452 return 0;
453 } else if (insn->n > 1) {
5da80ee8
HS
454 dev_err(dev->class_dev, "Invalid instruction length %d\n",
455 insn->n);
e55c95a3
GG
456 return -EINVAL;
457 }
458
459 switch (rang) {
460 case 0:
461 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
462 break;
463 case 1:
464 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
465 break;
466 case 2:
467 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
468 break;
469 case 3:
470 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
471 break;
472 default:
5da80ee8 473 dev_err(dev->class_dev, "Invalid range specified\n");
e55c95a3
GG
474 return -EINVAL;
475 }
476
477 switch (aref) {
478 case AREF_GROUND:
479 case AREF_COMMON:
e55c95a3
GG
480 entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan;
481 break;
482
483 case AREF_DIFF:
1a023870
HS
484 if (!(s->subdev_flags && SDF_DIFF)) {
485 dev_err(dev->class_dev,
486 "Differential inputs are not available\n");
487 return -EINVAL;
488 }
489
e55c95a3 490 if (rang == 0 || rang == 1) {
5da80ee8
HS
491 dev_err(dev->class_dev,
492 "Range must be bipolar when aref = diff\n");
e55c95a3
GG
493 return -EINVAL;
494 }
495
1a023870 496 if (chan >= (s->n_chan / 2)) {
5da80ee8
HS
497 dev_err(dev->class_dev,
498 "Analog input is not available\n");
e55c95a3
GG
499 return -EINVAL;
500 }
501 entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan;
502 break;
503 default:
5da80ee8 504 dev_err(dev->class_dev, "Invalid aref specified\n");
e55c95a3
GG
505 return -EINVAL;
506 }
507
508 entry |= ME4000_AI_LIST_LAST_ENTRY;
509
510 /* Clear channel list, data fifo and both stop bits */
b08bfa38 511 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 512 tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
0a85b6f0
MT
513 ME4000_AI_CTRL_BIT_DATA_FIFO |
514 ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
b08bfa38 515 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
516
517 /* Set the acquisition mode to single */
518 tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 |
0a85b6f0 519 ME4000_AI_CTRL_BIT_MODE_2);
b08bfa38 520 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
521
522 /* Enable channel list and data fifo */
523 tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO;
b08bfa38 524 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
525
526 /* Generate channel list entry */
b08bfa38 527 outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
e55c95a3
GG
528
529 /* Set the timer to maximum sample rate */
b08bfa38
HS
530 outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
531 outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
e55c95a3
GG
532
533 /* Start conversion by dummy read */
b08bfa38 534 inl(dev->iobase + ME4000_AI_START_REG);
e55c95a3
GG
535
536 /* Wait until ready */
537 udelay(10);
b08bfa38 538 if (!(inl(dev->iobase + ME4000_AI_STATUS_REG) &
0a85b6f0 539 ME4000_AI_STATUS_BIT_EF_DATA)) {
5da80ee8 540 dev_err(dev->class_dev, "Value not available after wait\n");
e55c95a3
GG
541 return -EIO;
542 }
543
544 /* Read value from data fifo */
b08bfa38 545 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
e55c95a3
GG
546 data[0] = lval ^ 0x8000;
547
548 return 1;
549}
550
0a85b6f0
MT
551static int me4000_ai_cancel(struct comedi_device *dev,
552 struct comedi_subdevice *s)
e55c95a3 553{
ac2832f8 554 unsigned int tmp;
e55c95a3 555
e55c95a3 556 /* Stop any running conversion */
b08bfa38 557 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 558 tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
b08bfa38 559 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
560
561 /* Clear the control register */
b08bfa38 562 outl(0x0, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
563
564 return 0;
565}
566
926e5073
HS
567static int me4000_ai_check_chanlist(struct comedi_device *dev,
568 struct comedi_subdevice *s,
569 struct comedi_cmd *cmd)
e55c95a3 570{
926e5073 571 unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
e55c95a3
GG
572 int i;
573
e55c95a3 574 for (i = 0; i < cmd->chanlist_len; i++) {
926e5073
HS
575 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
576 unsigned int range = CR_RANGE(cmd->chanlist[i]);
577 unsigned int aref = CR_AREF(cmd->chanlist[i]);
578
579 if (aref != aref0) {
580 dev_dbg(dev->class_dev,
5da80ee8 581 "Mode is not equal for all entries\n");
e55c95a3
GG
582 return -EINVAL;
583 }
e55c95a3 584
a7dab198 585 if (aref == AREF_DIFF) {
4ec85dad
HS
586 if (!(s->subdev_flags && SDF_DIFF)) {
587 dev_err(dev->class_dev,
588 "Differential inputs are not available\n");
589 return -EINVAL;
590 }
591
592 if (chan >= (s->n_chan / 2)) {
926e5073 593 dev_dbg(dev->class_dev,
5da80ee8 594 "Channel number to high\n");
e55c95a3
GG
595 return -EINVAL;
596 }
e55c95a3 597
926e5073
HS
598 if (!comedi_range_is_bipolar(s, range)) {
599 dev_dbg(dev->class_dev,
6c7d2c8b 600 "Bipolar is not selected in differential mode\n");
e55c95a3
GG
601 return -EINVAL;
602 }
603 }
604 }
605
606 return 0;
607}
608
71b5f4f1 609static int ai_round_cmd_args(struct comedi_device *dev,
0a85b6f0
MT
610 struct comedi_subdevice *s,
611 struct comedi_cmd *cmd,
612 unsigned int *init_ticks,
613 unsigned int *scan_ticks, unsigned int *chan_ticks)
e55c95a3 614{
e55c95a3
GG
615 int rest;
616
e55c95a3
GG
617 *init_ticks = 0;
618 *scan_ticks = 0;
619 *chan_ticks = 0;
620
e55c95a3
GG
621 if (cmd->start_arg) {
622 *init_ticks = (cmd->start_arg * 33) / 1000;
623 rest = (cmd->start_arg * 33) % 1000;
624
1e00dedc 625 if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
82675f35 626 if (rest > 33)
e55c95a3 627 (*init_ticks)++;
1e00dedc 628 } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
e55c95a3
GG
629 if (rest)
630 (*init_ticks)++;
631 }
632 }
633
634 if (cmd->scan_begin_arg) {
635 *scan_ticks = (cmd->scan_begin_arg * 33) / 1000;
636 rest = (cmd->scan_begin_arg * 33) % 1000;
637
1e00dedc 638 if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
82675f35 639 if (rest > 33)
e55c95a3 640 (*scan_ticks)++;
1e00dedc 641 } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
e55c95a3
GG
642 if (rest)
643 (*scan_ticks)++;
644 }
645 }
646
647 if (cmd->convert_arg) {
648 *chan_ticks = (cmd->convert_arg * 33) / 1000;
649 rest = (cmd->convert_arg * 33) % 1000;
650
1e00dedc 651 if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
82675f35 652 if (rest > 33)
e55c95a3 653 (*chan_ticks)++;
1e00dedc 654 } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
e55c95a3
GG
655 if (rest)
656 (*chan_ticks)++;
657 }
658 }
659
e55c95a3
GG
660 return 0;
661}
662
71b5f4f1 663static void ai_write_timer(struct comedi_device *dev,
0a85b6f0
MT
664 unsigned int init_ticks,
665 unsigned int scan_ticks, unsigned int chan_ticks)
e55c95a3 666{
b08bfa38
HS
667 outl(init_ticks - 1, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG);
668 outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG);
e55c95a3
GG
669
670 if (scan_ticks) {
b08bfa38
HS
671 outl(scan_ticks - 1, dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG);
672 outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG);
e55c95a3
GG
673 }
674
b08bfa38
HS
675 outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
676 outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
e55c95a3
GG
677}
678
4b2f15f1
HS
679static int ai_write_chanlist(struct comedi_device *dev,
680 struct comedi_subdevice *s, struct comedi_cmd *cmd)
681{
682 unsigned int entry;
683 unsigned int chan;
684 unsigned int rang;
685 unsigned int aref;
686 int i;
687
688 for (i = 0; i < cmd->chanlist_len; i++) {
689 chan = CR_CHAN(cmd->chanlist[i]);
690 rang = CR_RANGE(cmd->chanlist[i]);
691 aref = CR_AREF(cmd->chanlist[i]);
692
693 entry = chan;
694
695 if (rang == 0)
696 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
697 else if (rang == 1)
698 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
699 else if (rang == 2)
700 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
701 else
702 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
703
8d44945d 704 if (aref == AREF_DIFF)
4b2f15f1
HS
705 entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
706 else
707 entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED;
708
709 outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
710 }
711
712 return 0;
713}
714
71b5f4f1 715static int ai_prepare(struct comedi_device *dev,
0a85b6f0
MT
716 struct comedi_subdevice *s,
717 struct comedi_cmd *cmd,
718 unsigned int init_ticks,
719 unsigned int scan_ticks, unsigned int chan_ticks)
e55c95a3 720{
ac2832f8 721 unsigned int tmp = 0;
e55c95a3 722
e55c95a3
GG
723 /* Write timer arguments */
724 ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks);
725
726 /* Reset control register */
b08bfa38 727 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
728
729 /* Start sources */
730 if ((cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
731 cmd->scan_begin_src == TRIG_TIMER &&
732 cmd->convert_src == TRIG_TIMER) ||
733 (cmd->start_src == TRIG_EXT &&
734 cmd->scan_begin_src == TRIG_FOLLOW &&
735 cmd->convert_src == TRIG_TIMER)) {
e55c95a3 736 tmp = ME4000_AI_CTRL_BIT_MODE_1 |
0a85b6f0
MT
737 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
738 ME4000_AI_CTRL_BIT_DATA_FIFO;
e55c95a3 739 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
740 cmd->scan_begin_src == TRIG_EXT &&
741 cmd->convert_src == TRIG_TIMER) {
e55c95a3 742 tmp = ME4000_AI_CTRL_BIT_MODE_2 |
0a85b6f0
MT
743 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
744 ME4000_AI_CTRL_BIT_DATA_FIFO;
e55c95a3 745 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
746 cmd->scan_begin_src == TRIG_EXT &&
747 cmd->convert_src == TRIG_EXT) {
e55c95a3 748 tmp = ME4000_AI_CTRL_BIT_MODE_0 |
0a85b6f0
MT
749 ME4000_AI_CTRL_BIT_MODE_1 |
750 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
751 ME4000_AI_CTRL_BIT_DATA_FIFO;
e55c95a3
GG
752 } else {
753 tmp = ME4000_AI_CTRL_BIT_MODE_0 |
0a85b6f0
MT
754 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
755 ME4000_AI_CTRL_BIT_DATA_FIFO;
e55c95a3
GG
756 }
757
758 /* Stop triggers */
759 if (cmd->stop_src == TRIG_COUNT) {
d6cbe537 760 outl(cmd->chanlist_len * cmd->stop_arg,
6c7d2c8b 761 dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
e55c95a3
GG
762 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
763 } else if (cmd->stop_src == TRIG_NONE &&
0a85b6f0 764 cmd->scan_end_src == TRIG_COUNT) {
d6cbe537 765 outl(cmd->scan_end_arg,
6c7d2c8b 766 dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
e55c95a3
GG
767 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
768 } else {
769 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ;
770 }
771
772 /* Write the setup to the control register */
b08bfa38 773 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
774
775 /* Write the channel list */
776 ai_write_chanlist(dev, s, cmd);
777
778 return 0;
779}
780
0a85b6f0
MT
781static int me4000_ai_do_cmd(struct comedi_device *dev,
782 struct comedi_subdevice *s)
e55c95a3
GG
783{
784 int err;
785 unsigned int init_ticks = 0;
786 unsigned int scan_ticks = 0;
787 unsigned int chan_ticks = 0;
ea6d0d4c 788 struct comedi_cmd *cmd = &s->async->cmd;
e55c95a3 789
e55c95a3
GG
790 /* Reset the analog input */
791 err = me4000_ai_cancel(dev, s);
792 if (err)
793 return err;
794
795 /* Round the timer arguments */
796 err = ai_round_cmd_args(dev,
0a85b6f0 797 s, cmd, &init_ticks, &scan_ticks, &chan_ticks);
e55c95a3
GG
798 if (err)
799 return err;
800
801 /* Prepare the AI for acquisition */
802 err = ai_prepare(dev, s, cmd, init_ticks, scan_ticks, chan_ticks);
803 if (err)
804 return err;
805
806 /* Start acquistion by dummy read */
b08bfa38 807 inl(dev->iobase + ME4000_AI_START_REG);
e55c95a3
GG
808
809 return 0;
810}
811
71b5f4f1 812static int me4000_ai_do_cmd_test(struct comedi_device *dev,
0a85b6f0
MT
813 struct comedi_subdevice *s,
814 struct comedi_cmd *cmd)
e55c95a3 815{
e55c95a3
GG
816 unsigned int init_ticks;
817 unsigned int chan_ticks;
818 unsigned int scan_ticks;
819 int err = 0;
820
e55c95a3
GG
821 /* Round the timer arguments */
822 ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks);
823
27020ffe
HS
824 /* Step 1 : check if triggers are trivially valid */
825
51ec1db9
IA
826 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
827 err |= comedi_check_trigger_src(&cmd->scan_begin_src,
27020ffe 828 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
51ec1db9
IA
829 err |= comedi_check_trigger_src(&cmd->convert_src,
830 TRIG_TIMER | TRIG_EXT);
831 err |= comedi_check_trigger_src(&cmd->scan_end_src,
27020ffe 832 TRIG_NONE | TRIG_COUNT);
51ec1db9 833 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE | TRIG_COUNT);
27020ffe 834
82675f35 835 if (err)
e55c95a3 836 return 1;
e55c95a3 837
27020ffe
HS
838 /* Step 2a : make sure trigger sources are unique */
839
51ec1db9
IA
840 err |= comedi_check_trigger_is_unique(cmd->start_src);
841 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
842 err |= comedi_check_trigger_is_unique(cmd->convert_src);
843 err |= comedi_check_trigger_is_unique(cmd->scan_end_src);
844 err |= comedi_check_trigger_is_unique(cmd->stop_src);
27020ffe
HS
845
846 /* Step 2b : and mutually compatible */
847
e55c95a3 848 if (cmd->start_src == TRIG_NOW &&
0a85b6f0
MT
849 cmd->scan_begin_src == TRIG_TIMER &&
850 cmd->convert_src == TRIG_TIMER) {
e55c95a3 851 } else if (cmd->start_src == TRIG_NOW &&
0a85b6f0
MT
852 cmd->scan_begin_src == TRIG_FOLLOW &&
853 cmd->convert_src == TRIG_TIMER) {
e55c95a3 854 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
855 cmd->scan_begin_src == TRIG_TIMER &&
856 cmd->convert_src == TRIG_TIMER) {
e55c95a3 857 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
858 cmd->scan_begin_src == TRIG_FOLLOW &&
859 cmd->convert_src == TRIG_TIMER) {
e55c95a3 860 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
861 cmd->scan_begin_src == TRIG_EXT &&
862 cmd->convert_src == TRIG_TIMER) {
e55c95a3 863 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
864 cmd->scan_begin_src == TRIG_EXT &&
865 cmd->convert_src == TRIG_EXT) {
e55c95a3 866 } else {
27020ffe 867 err |= -EINVAL;
e55c95a3
GG
868 }
869
82675f35 870 if (err)
e55c95a3 871 return 2;
e55c95a3 872
8c6c5a69
HS
873 /* Step 3: check if arguments are trivially valid */
874
51ec1db9 875 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
025b9187 876
e55c95a3 877 if (cmd->chanlist_len < 1) {
e55c95a3 878 cmd->chanlist_len = 1;
8c6c5a69 879 err |= -EINVAL;
e55c95a3
GG
880 }
881 if (init_ticks < 66) {
e55c95a3 882 cmd->start_arg = 2000;
8c6c5a69 883 err |= -EINVAL;
e55c95a3
GG
884 }
885 if (scan_ticks && scan_ticks < 67) {
e55c95a3 886 cmd->scan_begin_arg = 2031;
8c6c5a69 887 err |= -EINVAL;
e55c95a3
GG
888 }
889 if (chan_ticks < 66) {
e55c95a3 890 cmd->convert_arg = 2000;
8c6c5a69 891 err |= -EINVAL;
e55c95a3 892 }
82675f35 893
76af50dd 894 if (cmd->stop_src == TRIG_COUNT)
51ec1db9 895 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
76af50dd 896 else /* TRIG_NONE */
51ec1db9 897 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
76af50dd 898
82675f35 899 if (err)
e55c95a3 900 return 3;
e55c95a3
GG
901
902 /*
903 * Stage 4. Check for argument conflicts.
904 */
905 if (cmd->start_src == TRIG_NOW &&
0a85b6f0
MT
906 cmd->scan_begin_src == TRIG_TIMER &&
907 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
908 /* Check timer arguments */
909 if (init_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 910 dev_err(dev->class_dev, "Invalid start arg\n");
b6c77757 911 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
912 err++;
913 }
914 if (chan_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 915 dev_err(dev->class_dev, "Invalid convert arg\n");
b6c77757 916 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
917 err++;
918 }
919 if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
5da80ee8 920 dev_err(dev->class_dev, "Invalid scan end arg\n");
b6241fda
GS
921
922 /* At least one tick more */
923 cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
e55c95a3
GG
924 err++;
925 }
926 } else if (cmd->start_src == TRIG_NOW &&
0a85b6f0
MT
927 cmd->scan_begin_src == TRIG_FOLLOW &&
928 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
929 /* Check timer arguments */
930 if (init_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 931 dev_err(dev->class_dev, "Invalid start arg\n");
b6c77757 932 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
933 err++;
934 }
935 if (chan_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 936 dev_err(dev->class_dev, "Invalid convert arg\n");
b6c77757 937 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
938 err++;
939 }
940 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
941 cmd->scan_begin_src == TRIG_TIMER &&
942 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
943 /* Check timer arguments */
944 if (init_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 945 dev_err(dev->class_dev, "Invalid start arg\n");
b6c77757 946 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
947 err++;
948 }
949 if (chan_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 950 dev_err(dev->class_dev, "Invalid convert arg\n");
b6c77757 951 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
952 err++;
953 }
954 if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
5da80ee8 955 dev_err(dev->class_dev, "Invalid scan end arg\n");
b6241fda
GS
956
957 /* At least one tick more */
958 cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
e55c95a3
GG
959 err++;
960 }
961 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
962 cmd->scan_begin_src == TRIG_FOLLOW &&
963 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
964 /* Check timer arguments */
965 if (init_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 966 dev_err(dev->class_dev, "Invalid start arg\n");
b6c77757 967 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
968 err++;
969 }
970 if (chan_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 971 dev_err(dev->class_dev, "Invalid convert arg\n");
b6c77757 972 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
973 err++;
974 }
975 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
976 cmd->scan_begin_src == TRIG_EXT &&
977 cmd->convert_src == TRIG_TIMER) {
e55c95a3
GG
978 /* Check timer arguments */
979 if (init_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 980 dev_err(dev->class_dev, "Invalid start arg\n");
b6c77757 981 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
982 err++;
983 }
984 if (chan_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 985 dev_err(dev->class_dev, "Invalid convert arg\n");
b6c77757 986 cmd->convert_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
987 err++;
988 }
989 } else if (cmd->start_src == TRIG_EXT &&
0a85b6f0
MT
990 cmd->scan_begin_src == TRIG_EXT &&
991 cmd->convert_src == TRIG_EXT) {
e55c95a3
GG
992 /* Check timer arguments */
993 if (init_ticks < ME4000_AI_MIN_TICKS) {
5da80ee8 994 dev_err(dev->class_dev, "Invalid start arg\n");
b6c77757 995 cmd->start_arg = 2000; /* 66 ticks at least */
e55c95a3
GG
996 err++;
997 }
998 }
e55c95a3
GG
999 if (cmd->scan_end_src == TRIG_COUNT) {
1000 if (cmd->scan_end_arg == 0) {
5da80ee8 1001 dev_err(dev->class_dev, "Invalid scan end arg\n");
e55c95a3
GG
1002 cmd->scan_end_arg = 1;
1003 err++;
1004 }
1005 }
82675f35
BP
1006
1007 if (err)
e55c95a3 1008 return 4;
e55c95a3 1009
926e5073
HS
1010 /* Step 5: check channel list if it exists */
1011 if (cmd->chanlist && cmd->chanlist_len > 0)
1012 err |= me4000_ai_check_chanlist(dev, s, cmd);
1013
1014 if (err)
e55c95a3
GG
1015 return 5;
1016
1017 return 0;
1018}
1019
70265d24 1020static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
e55c95a3
GG
1021{
1022 unsigned int tmp;
71b5f4f1 1023 struct comedi_device *dev = dev_id;
b3403f2e 1024 struct comedi_subdevice *s = dev->read_subdev;
e55c95a3
GG
1025 int i;
1026 int c = 0;
ac2832f8 1027 unsigned int lval;
e55c95a3 1028
ef5bbfcb 1029 if (!dev->attached)
e55c95a3 1030 return IRQ_NONE;
e55c95a3 1031
b08bfa38 1032 if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
0a85b6f0 1033 ME4000_IRQ_STATUS_BIT_AI_HF) {
e55c95a3 1034 /* Read status register to find out what happened */
b08bfa38 1035 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1036
1037 if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
0a85b6f0
MT
1038 !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) &&
1039 (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
e55c95a3
GG
1040 c = ME4000_AI_FIFO_COUNT;
1041
b6241fda
GS
1042 /*
1043 * FIFO overflow, so stop conversion
1044 * and disable all interrupts
1045 */
e55c95a3
GG
1046 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1047 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
0a85b6f0 1048 ME4000_AI_CTRL_BIT_SC_IRQ);
b08bfa38 1049 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 1050
3e6cb74f 1051 s->async->events |= COMEDI_CB_ERROR;
e55c95a3 1052
5da80ee8 1053 dev_err(dev->class_dev, "FIFO overflow\n");
e55c95a3 1054 } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
0a85b6f0
MT
1055 && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
1056 && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
e55c95a3
GG
1057 c = ME4000_AI_FIFO_COUNT / 2;
1058 } else {
5da80ee8
HS
1059 dev_err(dev->class_dev,
1060 "Can't determine state of fifo\n");
e55c95a3
GG
1061 c = 0;
1062
b6241fda
GS
1063 /*
1064 * Undefined state, so stop conversion
1065 * and disable all interrupts
1066 */
e55c95a3
GG
1067 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1068 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
0a85b6f0 1069 ME4000_AI_CTRL_BIT_SC_IRQ);
b08bfa38 1070 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 1071
3e6cb74f 1072 s->async->events |= COMEDI_CB_ERROR;
e55c95a3 1073
5da80ee8 1074 dev_err(dev->class_dev, "Undefined FIFO state\n");
e55c95a3
GG
1075 }
1076
e55c95a3
GG
1077 for (i = 0; i < c; i++) {
1078 /* Read value from data fifo */
b08bfa38 1079 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
e55c95a3
GG
1080 lval ^= 0x8000;
1081
de88924f 1082 if (!comedi_buf_write_samples(s, &lval, 1)) {
b6241fda
GS
1083 /*
1084 * Buffer overflow, so stop conversion
1085 * and disable all interrupts
1086 */
e55c95a3
GG
1087 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1088 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
0a85b6f0 1089 ME4000_AI_CTRL_BIT_SC_IRQ);
b08bfa38 1090 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1091 break;
1092 }
1093 }
1094
1095 /* Work is done, so reset the interrupt */
e55c95a3 1096 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
b08bfa38 1097 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 1098 tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
b08bfa38 1099 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1100 }
1101
b08bfa38
HS
1102 if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
1103 ME4000_IRQ_STATUS_BIT_SC) {
de88924f 1104 s->async->events |= COMEDI_CB_EOA;
e55c95a3 1105
b6241fda
GS
1106 /*
1107 * Acquisition is complete, so stop
1108 * conversion and disable all interrupts
1109 */
b08bfa38 1110 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1111 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1112 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ);
b08bfa38 1113 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1114
1115 /* Poll data until fifo empty */
b08bfa38
HS
1116 while (inl(dev->iobase + ME4000_AI_CTRL_REG) &
1117 ME4000_AI_STATUS_BIT_EF_DATA) {
e55c95a3 1118 /* Read value from data fifo */
b08bfa38 1119 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
e55c95a3
GG
1120 lval ^= 0x8000;
1121
de88924f 1122 if (!comedi_buf_write_samples(s, &lval, 1))
e55c95a3 1123 break;
e55c95a3
GG
1124 }
1125
1126 /* Work is done, so reset the interrupt */
e55c95a3 1127 tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
b08bfa38 1128 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3 1129 tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
b08bfa38 1130 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
e55c95a3
GG
1131 }
1132
3fa1eb64 1133 comedi_handle_events(dev, s);
e55c95a3
GG
1134
1135 return IRQ_HANDLED;
1136}
1137
71b5f4f1 1138static int me4000_ao_insn_write(struct comedi_device *dev,
0a85b6f0 1139 struct comedi_subdevice *s,
97e658d1
HS
1140 struct comedi_insn *insn,
1141 unsigned int *data)
e55c95a3 1142{
e55c95a3 1143 int chan = CR_CHAN(insn->chanspec);
ac2832f8 1144 unsigned int tmp;
e55c95a3 1145
e55c95a3 1146 /* Stop any running conversion */
e1d7ccb7 1147 tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan));
e55c95a3 1148 tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
e1d7ccb7 1149 outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan));
e55c95a3
GG
1150
1151 /* Clear control register and set to single mode */
e1d7ccb7 1152 outl(0x0, dev->iobase + ME4000_AO_CTRL_REG(chan));
e55c95a3
GG
1153
1154 /* Write data value */
e1d7ccb7 1155 outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan));
e55c95a3
GG
1156
1157 /* Store in the mirror */
081b6ee6 1158 s->readback[chan] = data[0];
e55c95a3
GG
1159
1160 return 1;
1161}
1162
71b5f4f1 1163static int me4000_dio_insn_bits(struct comedi_device *dev,
0a85b6f0 1164 struct comedi_subdevice *s,
b523c2b2
HS
1165 struct comedi_insn *insn,
1166 unsigned int *data)
e55c95a3 1167{
b523c2b2 1168 if (comedi_dio_update_state(s, data)) {
d6cbe537 1169 outl((s->state >> 0) & 0xFF,
6c7d2c8b 1170 dev->iobase + ME4000_DIO_PORT_0_REG);
d6cbe537 1171 outl((s->state >> 8) & 0xFF,
6c7d2c8b 1172 dev->iobase + ME4000_DIO_PORT_1_REG);
d6cbe537 1173 outl((s->state >> 16) & 0xFF,
6c7d2c8b 1174 dev->iobase + ME4000_DIO_PORT_2_REG);
d6cbe537 1175 outl((s->state >> 24) & 0xFF,
6c7d2c8b 1176 dev->iobase + ME4000_DIO_PORT_3_REG);
e55c95a3
GG
1177 }
1178
da755d15
HS
1179 data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) |
1180 ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) |
1181 ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) |
1182 ((inl(dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24);
e55c95a3 1183
a2714e3e 1184 return insn->n;
e55c95a3
GG
1185}
1186
71b5f4f1 1187static int me4000_dio_insn_config(struct comedi_device *dev,
0a85b6f0 1188 struct comedi_subdevice *s,
5dacadcc
HS
1189 struct comedi_insn *insn,
1190 unsigned int *data)
e55c95a3 1191{
5dacadcc
HS
1192 unsigned int chan = CR_CHAN(insn->chanspec);
1193 unsigned int mask;
1194 unsigned int tmp;
1195 int ret;
e55c95a3 1196
5dacadcc
HS
1197 if (chan < 8)
1198 mask = 0x000000ff;
1199 else if (chan < 16)
1200 mask = 0x0000ff00;
1201 else if (chan < 24)
1202 mask = 0x00ff0000;
1203 else
1204 mask = 0xff000000;
e55c95a3 1205
5dacadcc
HS
1206 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
1207 if (ret)
1208 return ret;
e55c95a3 1209
da755d15 1210 tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG);
5dacadcc
HS
1211 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | ME4000_DIO_CTRL_BIT_MODE_1 |
1212 ME4000_DIO_CTRL_BIT_MODE_2 | ME4000_DIO_CTRL_BIT_MODE_3 |
1213 ME4000_DIO_CTRL_BIT_MODE_4 | ME4000_DIO_CTRL_BIT_MODE_5 |
1214 ME4000_DIO_CTRL_BIT_MODE_6 | ME4000_DIO_CTRL_BIT_MODE_7);
1215 if (s->io_bits & 0x000000ff)
1216 tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
1217 if (s->io_bits & 0x0000ff00)
1218 tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
1219 if (s->io_bits & 0x00ff0000)
1220 tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
1221 if (s->io_bits & 0xff000000)
1222 tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
e55c95a3 1223
5dacadcc
HS
1224 /*
1225 * Check for optoisolated ME-4000 version.
1226 * If one the first port is a fixed output
1227 * port and the second is a fixed input port.
1228 */
1229 if (inl(dev->iobase + ME4000_DIO_DIR_REG)) {
1230 s->io_bits |= 0x000000ff;
1231 s->io_bits &= ~0x0000ff00;
1232 tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
1233 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
1234 ME4000_DIO_CTRL_BIT_MODE_3);
e55c95a3
GG
1235 }
1236
da755d15 1237 outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG);
e55c95a3 1238
5dacadcc 1239 return insn->n;
e55c95a3
GG
1240}
1241
a690b7e5 1242static int me4000_auto_attach(struct comedi_device *dev,
8c355509 1243 unsigned long context)
ba5cb4ba 1244{
750af5e5 1245 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
49ef9c85 1246 const struct me4000_board *board = NULL;
ba5cb4ba 1247 struct me4000_info *info;
ba5cb4ba
HS
1248 struct comedi_subdevice *s;
1249 int result;
4b2f15f1 1250
8c355509 1251 if (context < ARRAY_SIZE(me4000_boards))
49ef9c85
HS
1252 board = &me4000_boards[context];
1253 if (!board)
5f8f8d43 1254 return -ENODEV;
49ef9c85
HS
1255 dev->board_ptr = board;
1256 dev->board_name = board->name;
4b2f15f1 1257
0bdab509 1258 info = comedi_alloc_devpriv(dev, sizeof(*info));
c34fa261
HS
1259 if (!info)
1260 return -ENOMEM;
4b2f15f1 1261
818f569f 1262 result = comedi_pci_enable(dev);
ba5cb4ba
HS
1263 if (result)
1264 return result;
1265
1266 info->plx_regbase = pci_resource_start(pcidev, 1);
ba5cb4ba 1267 dev->iobase = pci_resource_start(pcidev, 2);
d92d39d9 1268 if (!info->plx_regbase || !dev->iobase)
4b2f15f1
HS
1269 return -ENODEV;
1270
ac584af5
HS
1271 result = comedi_load_firmware(dev, &pcidev->dev, ME4000_FIRMWARE,
1272 me4000_xilinx_download, 0);
1273 if (result < 0)
4b2f15f1
HS
1274 return result;
1275
2f348ecd 1276 me4000_reset(dev);
4b2f15f1 1277
a9b7ff93
HS
1278 if (pcidev->irq > 0) {
1279 result = request_irq(pcidev->irq, me4000_ai_isr, IRQF_SHARED,
6c7d2c8b 1280 dev->board_name, dev);
a9b7ff93
HS
1281 if (result == 0)
1282 dev->irq = pcidev->irq;
1283 }
1284
8b6c5694
HS
1285 result = comedi_alloc_subdevices(dev, 4);
1286 if (result)
1287 return result;
3af09830 1288
14aa4789 1289 /* Analog Input subdevice */
8aaf2717 1290 s = &dev->subdevices[0];
14aa4789 1291 s->type = COMEDI_SUBD_AI;
31bebc03
HS
1292 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1293 if (board->ai_diff_nchan)
1294 s->subdev_flags |= SDF_DIFF;
14aa4789
HS
1295 s->n_chan = board->ai_nchan;
1296 s->maxdata = 0xffff;
1297 s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
1298 s->range_table = &me4000_ai_range;
1299 s->insn_read = me4000_ai_insn_read;
1300
1301 if (dev->irq) {
1302 dev->read_subdev = s;
1303 s->subdev_flags |= SDF_CMD_READ;
1304 s->cancel = me4000_ai_cancel;
1305 s->do_cmdtest = me4000_ai_do_cmd_test;
1306 s->do_cmd = me4000_ai_do_cmd;
3af09830
HS
1307 }
1308
1309 /*=========================================================================
1310 Analog output subdevice
1311 ========================================================================*/
1312
8aaf2717 1313 s = &dev->subdevices[1];
3af09830 1314
49ef9c85 1315 if (board->ao_nchan) {
3af09830 1316 s->type = COMEDI_SUBD_AO;
ef49d832 1317 s->subdev_flags = SDF_WRITABLE | SDF_COMMON | SDF_GROUND;
49ef9c85 1318 s->n_chan = board->ao_nchan;
3af09830 1319 s->maxdata = 0xFFFF; /* 16 bit DAC */
4683f9f8 1320 s->range_table = &range_bipolar10;
3af09830 1321 s->insn_write = me4000_ao_insn_write;
081b6ee6
HS
1322
1323 result = comedi_alloc_subdev_readback(s);
1324 if (result)
1325 return result;
3af09830
HS
1326 } else {
1327 s->type = COMEDI_SUBD_UNUSED;
1328 }
1329
d8553701 1330 /* Digital I/O subdevice */
8aaf2717 1331 s = &dev->subdevices[2];
d8553701
HS
1332 s->type = COMEDI_SUBD_DIO;
1333 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1334 s->n_chan = 32;
1335 s->maxdata = 1;
1336 s->range_table = &range_digital;
1337 s->insn_bits = me4000_dio_insn_bits;
1338 s->insn_config = me4000_dio_insn_config;
3af09830
HS
1339
1340 /*
1341 * Check for optoisolated ME-4000 version. If one the first
1342 * port is a fixed output port and the second is a fixed input port.
1343 */
da755d15 1344 if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) {
3af09830 1345 s->io_bits |= 0xFF;
da755d15 1346 outl(ME4000_DIO_CTRL_BIT_MODE_0,
6c7d2c8b 1347 dev->iobase + ME4000_DIO_DIR_REG);
3af09830
HS
1348 }
1349
d92d39d9 1350 /* Counter subdevice (8254) */
8aaf2717 1351 s = &dev->subdevices[3];
49ef9c85 1352 if (board->has_counter) {
d92d39d9
HS
1353 unsigned long timer_base = pci_resource_start(pcidev, 3);
1354
1355 if (!timer_base)
1356 return -ENODEV;
1357
1358 dev->pacer = comedi_8254_init(timer_base, 0, I8254_IO8, 0);
1359 if (!dev->pacer)
1360 return -ENOMEM;
1361
1362 comedi_8254_subdevice_init(s, dev->pacer);
3af09830
HS
1363 } else {
1364 s->type = COMEDI_SUBD_UNUSED;
1365 }
1366
1367 return 0;
1368}
1369
484ecc95 1370static void me4000_detach(struct comedi_device *dev)
3af09830 1371{
7f072f54
HS
1372 if (dev->iobase)
1373 me4000_reset(dev);
aac307f9 1374 comedi_pci_detach(dev);
3af09830
HS
1375}
1376
75e6301b 1377static struct comedi_driver me4000_driver = {
3af09830
HS
1378 .driver_name = "me4000",
1379 .module = THIS_MODULE,
750af5e5 1380 .auto_attach = me4000_auto_attach,
3af09830
HS
1381 .detach = me4000_detach,
1382};
1383
a690b7e5 1384static int me4000_pci_probe(struct pci_dev *dev,
b8f4ac23 1385 const struct pci_device_id *id)
727b286b 1386{
b8f4ac23 1387 return comedi_pci_auto_config(dev, &me4000_driver, id->driver_data);
727b286b
AT
1388}
1389
41e043fc 1390static const struct pci_device_id me4000_pci_table[] = {
8c355509
HS
1391 { PCI_VDEVICE(MEILHAUS, 0x4650), BOARD_ME4650 },
1392 { PCI_VDEVICE(MEILHAUS, 0x4660), BOARD_ME4660 },
1393 { PCI_VDEVICE(MEILHAUS, 0x4661), BOARD_ME4660I },
1394 { PCI_VDEVICE(MEILHAUS, 0x4662), BOARD_ME4660S },
1395 { PCI_VDEVICE(MEILHAUS, 0x4663), BOARD_ME4660IS },
1396 { PCI_VDEVICE(MEILHAUS, 0x4670), BOARD_ME4670 },
1397 { PCI_VDEVICE(MEILHAUS, 0x4671), BOARD_ME4670I },
1398 { PCI_VDEVICE(MEILHAUS, 0x4672), BOARD_ME4670S },
1399 { PCI_VDEVICE(MEILHAUS, 0x4673), BOARD_ME4670IS },
1400 { PCI_VDEVICE(MEILHAUS, 0x4680), BOARD_ME4680 },
1401 { PCI_VDEVICE(MEILHAUS, 0x4681), BOARD_ME4680I },
1402 { PCI_VDEVICE(MEILHAUS, 0x4682), BOARD_ME4680S },
1403 { PCI_VDEVICE(MEILHAUS, 0x4683), BOARD_ME4680IS },
1404 { 0 }
3af09830
HS
1405};
1406MODULE_DEVICE_TABLE(pci, me4000_pci_table);
1407
75e6301b
HS
1408static struct pci_driver me4000_pci_driver = {
1409 .name = "me4000",
3af09830 1410 .id_table = me4000_pci_table,
75e6301b 1411 .probe = me4000_pci_probe,
9901a4d7 1412 .remove = comedi_pci_auto_unconfig,
727b286b 1413};
75e6301b 1414module_comedi_pci_driver(me4000_driver, me4000_pci_driver);
90f703d3
AT
1415
1416MODULE_AUTHOR("Comedi http://www.comedi.org");
1417MODULE_DESCRIPTION("Comedi low-level driver");
1418MODULE_LICENSE("GPL");
ac584af5 1419MODULE_FIRMWARE(ME4000_FIRMWARE);
This page took 0.996776 seconds and 5 git commands to generate.