staging: comedi: adl_pci9111: use cfc_check_trigger_is_unique
[linux-2.6-block.git] / drivers / staging / comedi / drivers / adl_pci9111.c
CommitLineData
8cb9b9fb
EP
1/*
2
842ec6ba 3comedi/drivers/adl_pci9111.c
8cb9b9fb 4
842ec6ba 5Hardware driver for PCI9111 ADLink cards:
8cb9b9fb 6
842ec6ba 7PCI-9111HR
8cb9b9fb 8
842ec6ba 9Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
8cb9b9fb 10
842ec6ba
MD
11This program is free software; you can redistribute it and/or modify
12it under the terms of the GNU General Public License as published by
13the Free Software Foundation; either version 2 of the License, or
14(at your option) any later version.
8cb9b9fb 15
842ec6ba
MD
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19GNU General Public License for more details.
8cb9b9fb 20
842ec6ba
MD
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
8cb9b9fb
EP
24*/
25
26/*
27Driver: adl_pci9111
28Description: Adlink PCI-9111HR
29Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
30Devices: [ADLink] PCI-9111HR (adl_pci9111)
31Status: experimental
32
33Supports:
34
842ec6ba
MD
35 - ai_insn read
36 - ao_insn read/write
37 - di_insn read
38 - do_insn read/write
39 - ai_do_cmd mode with the following sources:
8cb9b9fb 40
842ec6ba
MD
41 - start_src TRIG_NOW
42 - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT
43 - convert_src TRIG_TIMER TRIG_EXT
44 - scan_end_src TRIG_COUNT
45 - stop_src TRIG_COUNT TRIG_NONE
8cb9b9fb 46
842ec6ba
MD
47The scanned channels must be consecutive and start from 0. They must
48all have the same range and aref.
8cb9b9fb 49
3e5a0ba0 50Configuration options: not applicable, uses PCI auto config
8cb9b9fb
EP
51*/
52
53/*
54CHANGELOG:
55
842ec6ba
MD
562005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be
57a multiple of chanlist_len*convert_arg.
582002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data.
592002/02/18 Added external trigger support for analog input.
8cb9b9fb
EP
60
61TODO:
62
842ec6ba
MD
63 - Really test implemented functionality.
64 - Add support for the PCI-9111DG with a probe routine to identify
65 the card type (perhaps with the help of the channel number readback
66 of the A/D Data register).
67 - Add external multiplexer support.
8cb9b9fb
EP
68
69*/
70
71#include "../comedidev.h"
72
73#include <linux/delay.h>
70265d24 74#include <linux/interrupt.h>
8cb9b9fb
EP
75
76#include "8253.h"
8cb9b9fb
EP
77#include "comedi_fc.h"
78
2f6df34c
MR
79#define PCI9111_DRIVER_NAME "adl_pci9111"
80#define PCI9111_HR_DEVICE_ID 0x9111
8cb9b9fb 81
8cb9b9fb
EP
82#define PCI9111_FIFO_HALF_SIZE 512
83
8cb9b9fb 84#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000
8cb9b9fb
EP
85
86#define PCI9111_RANGE_SETTING_DELAY 10
87#define PCI9111_AI_INSTANT_READ_UDELAY_US 2
88#define PCI9111_AI_INSTANT_READ_TIMEOUT 100
89
90#define PCI9111_8254_CLOCK_PERIOD_NS 500
91
8c7524e6
HS
92/*
93 * IO address map and bit defines
94 */
95#define PCI9111_AI_FIFO_REG 0x00
96#define PCI9111_AO_REG 0x00
97#define PCI9111_DIO_REG 0x02
98#define PCI9111_EDIO_REG 0x04
99#define PCI9111_AI_CHANNEL_REG 0x06
100#define PCI9111_AI_RANGE_STAT_REG 0x08
101#define PCI9111_AI_STAT_AD_BUSY (1 << 7)
102#define PCI9111_AI_STAT_FF_FF (1 << 6)
103#define PCI9111_AI_STAT_FF_HF (1 << 5)
104#define PCI9111_AI_STAT_FF_EF (1 << 4)
105#define PCI9111_AI_RANGE_MASK (7 << 0)
106#define PCI9111_AI_TRIG_CTRL_REG 0x0a
107#define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5)
108#define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4)
109#define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3)
110#define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2)
111#define PCI9111_AI_TRIG_CTRL_TPST (1 << 1)
112#define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0)
113#define PCI9111_INT_CTRL_REG 0x0c
114#define PCI9111_INT_CTRL_ISC2 (1 << 3)
115#define PCI9111_INT_CTRL_FFEN (1 << 2)
116#define PCI9111_INT_CTRL_ISC1 (1 << 1)
117#define PCI9111_INT_CTRL_ISC0 (1 << 0)
118#define PCI9111_SOFT_TRIG_REG 0x0e
119#define PCI9111_8254_BASE_REG 0x40
120#define PCI9111_INT_CLR_REG 0x48
8cb9b9fb 121
afa6ac4a 122static const struct comedi_lrange pci9111_ai_range = {
8cb9b9fb
EP
123 5,
124 {
afa6ac4a
HS
125 BIP_RANGE(10),
126 BIP_RANGE(5),
127 BIP_RANGE(2.5),
128 BIP_RANGE(1.25),
129 BIP_RANGE(0.625)
130 }
8cb9b9fb
EP
131};
132
52f8ac98 133/* Private data structure */
8cb9b9fb 134
c350fa19 135struct pci9111_private_data {
7ecac4c3
M
136 unsigned long lcr_io_base; /* Local configuration register base
137 * address */
8cb9b9fb
EP
138
139 int stop_counter;
140 int stop_is_none;
141
142 unsigned int scan_delay;
143 unsigned int chanlist_len;
144 unsigned int chunk_counter;
145 unsigned int chunk_num_samples;
146
52f8ac98 147 int ao_readback; /* Last written analog output data */
8cb9b9fb 148
eba16272
HS
149 unsigned int div1;
150 unsigned int div2;
8cb9b9fb 151
790c5541 152 short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
c350fa19 153};
8cb9b9fb 154
52f8ac98
BP
155/* ------------------------------------------------------------------ */
156/* PLX9050 SECTION */
157/* ------------------------------------------------------------------ */
8cb9b9fb
EP
158
159#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
160
161#define PLX9050_LINTI1_ENABLE (1 << 0)
162#define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)
163#define PLX9050_LINTI1_STATUS (1 << 2)
164#define PLX9050_LINTI2_ENABLE (1 << 3)
165#define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)
166#define PLX9050_LINTI2_STATUS (1 << 5)
167#define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)
168#define PLX9050_SOFTWARE_INTERRUPT (1 << 7)
169
170static void plx9050_interrupt_control(unsigned long io_base,
0a85b6f0
MT
171 bool LINTi1_enable,
172 bool LINTi1_active_high,
173 bool LINTi2_enable,
174 bool LINTi2_active_high,
175 bool interrupt_enable)
8cb9b9fb
EP
176{
177 int flags = 0;
178
179 if (LINTi1_enable)
180 flags |= PLX9050_LINTI1_ENABLE;
181 if (LINTi1_active_high)
182 flags |= PLX9050_LINTI1_ACTIVE_HIGH;
183 if (LINTi2_enable)
184 flags |= PLX9050_LINTI2_ENABLE;
185 if (LINTi2_active_high)
186 flags |= PLX9050_LINTI2_ACTIVE_HIGH;
187
188 if (interrupt_enable)
189 flags |= PLX9050_PCI_INTERRUPT_ENABLE;
190
191 outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
192}
193
52f8ac98
BP
194/* ------------------------------------------------------------------ */
195/* MISCELLANEOUS SECTION */
196/* ------------------------------------------------------------------ */
8cb9b9fb 197
52f8ac98 198/* 8254 timer */
8cb9b9fb 199
da91b269 200static void pci9111_timer_set(struct comedi_device *dev)
8cb9b9fb 201{
98943079 202 struct pci9111_private_data *dev_private = dev->private;
9d093151 203 unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG;
98943079 204
9d093151
HS
205 i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY);
206 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
207 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
8cb9b9fb 208
5f74ea14 209 udelay(1);
8cb9b9fb 210
eba16272
HS
211 i8254_write(timer_base, 1, 2, dev_private->div2);
212 i8254_write(timer_base, 1, 1, dev_private->div1);
8cb9b9fb
EP
213}
214
655f78f6 215enum pci9111_trigger_sources {
8cb9b9fb
EP
216 software,
217 timer_pacer,
218 external
655f78f6 219};
8cb9b9fb 220
da91b269 221static void pci9111_trigger_source_set(struct comedi_device *dev,
0a85b6f0 222 enum pci9111_trigger_sources source)
8cb9b9fb
EP
223{
224 int flags;
225
20614d96 226 /* Read the current trigger mode control bits */
8c7524e6 227 flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
20614d96
HS
228 /* Mask off the EITS and TPST bits */
229 flags &= 0x9;
8cb9b9fb
EP
230
231 switch (source) {
232 case software:
8cb9b9fb
EP
233 break;
234
235 case timer_pacer:
8c7524e6 236 flags |= PCI9111_AI_TRIG_CTRL_TPST;
8cb9b9fb
EP
237 break;
238
239 case external:
8c7524e6 240 flags |= PCI9111_AI_TRIG_CTRL_ETIS;
8cb9b9fb
EP
241 break;
242 }
243
8c7524e6 244 outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
8cb9b9fb
EP
245}
246
da91b269 247static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
8cb9b9fb
EP
248{
249 int flags;
250
20614d96 251 /* Read the current trigger mode control bits */
8c7524e6 252 flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
20614d96
HS
253 /* Mask off the PTRG bit */
254 flags &= 0x7;
8cb9b9fb
EP
255
256 if (pretrigger)
8c7524e6 257 flags |= PCI9111_AI_TRIG_CTRL_PTRG;
8cb9b9fb 258
8c7524e6 259 outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
8cb9b9fb
EP
260}
261
da91b269 262static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
8cb9b9fb
EP
263{
264 int flags;
265
20614d96 266 /* Read the current trigger mode control bits */
8c7524e6 267 flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
20614d96
HS
268 /* Mask off the ASCAN bit */
269 flags &= 0xe;
8cb9b9fb
EP
270
271 if (autoscan)
8c7524e6 272 flags |= PCI9111_AI_TRIG_CTRL_ASCAN;
8cb9b9fb 273
8c7524e6 274 outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
8cb9b9fb
EP
275}
276
3ba97b3c 277enum pci9111_ISC0_sources {
8cb9b9fb
EP
278 irq_on_eoc,
279 irq_on_fifo_half_full
3ba97b3c 280};
8cb9b9fb 281
52f8ac98 282enum pci9111_ISC1_sources {
8cb9b9fb
EP
283 irq_on_timer_tick,
284 irq_on_external_trigger
52f8ac98 285};
8cb9b9fb 286
da91b269 287static void pci9111_interrupt_source_set(struct comedi_device *dev,
0a85b6f0
MT
288 enum pci9111_ISC0_sources irq_0_source,
289 enum pci9111_ISC1_sources irq_1_source)
8cb9b9fb
EP
290{
291 int flags;
292
2959bc21 293 /* Read the current interrupt control bits */
8c7524e6 294 flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
2959bc21
HS
295 /* Shift the bits so they are compatible with the write register */
296 flags >>= 4;
297 /* Mask off the ISCx bits */
298 flags &= 0xc0;
8cb9b9fb 299
2959bc21 300 /* Now set the new ISCx bits */
8cb9b9fb 301 if (irq_0_source == irq_on_fifo_half_full)
8c7524e6 302 flags |= PCI9111_INT_CTRL_ISC0;
8cb9b9fb
EP
303
304 if (irq_1_source == irq_on_external_trigger)
8c7524e6 305 flags |= PCI9111_INT_CTRL_ISC1;
8cb9b9fb 306
2959bc21 307 outb(flags, dev->iobase + PCI9111_INT_CTRL_REG);
8cb9b9fb
EP
308}
309
6b228d8a
HS
310static void pci9111_fifo_reset(struct comedi_device *dev)
311{
312 unsigned long int_ctrl_reg = dev->iobase + PCI9111_INT_CTRL_REG;
313
314 /* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */
8c7524e6
HS
315 outb(0, int_ctrl_reg);
316 outb(PCI9111_INT_CTRL_FFEN, int_ctrl_reg);
317 outb(0, int_ctrl_reg);
6b228d8a
HS
318}
319
52f8ac98
BP
320/* ------------------------------------------------------------------ */
321/* HARDWARE TRIGGERED ANALOG INPUT SECTION */
322/* ------------------------------------------------------------------ */
8cb9b9fb 323
52f8ac98 324/* Cancel analog input autoscan */
8cb9b9fb 325
0a85b6f0
MT
326static int pci9111_ai_cancel(struct comedi_device *dev,
327 struct comedi_subdevice *s)
8cb9b9fb 328{
98943079
HS
329 struct pci9111_private_data *dev_private = dev->private;
330
52f8ac98 331 /* Disable interrupts */
8cb9b9fb
EP
332
333 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
0a85b6f0 334 true, false);
8cb9b9fb
EP
335
336 pci9111_trigger_source_set(dev, software);
337
338 pci9111_autoscan_set(dev, false);
339
6b228d8a 340 pci9111_fifo_reset(dev);
8cb9b9fb 341
8cb9b9fb
EP
342 return 0;
343}
344
97e01bb1
HS
345static int pci9111_ai_do_cmd_test(struct comedi_device *dev,
346 struct comedi_subdevice *s,
347 struct comedi_cmd *cmd)
8cb9b9fb 348{
98943079 349 struct pci9111_private_data *dev_private = dev->private;
8cb9b9fb
EP
350 int tmp;
351 int error = 0;
352 int range, reference;
353 int i;
8cb9b9fb 354
97e01bb1 355 /* Step 1 : check if trigger are trivialy valid */
8cb9b9fb 356
97e01bb1
HS
357 error |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
358 error |= cfc_check_trigger_src(&cmd->scan_begin_src,
359 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
360 error |= cfc_check_trigger_src(&cmd->convert_src,
361 TRIG_TIMER | TRIG_EXT);
362 error |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
363 error |= cfc_check_trigger_src(&cmd->stop_src,
364 TRIG_COUNT | TRIG_NONE);
8cb9b9fb
EP
365
366 if (error)
367 return 1;
368
e990333d 369 /* Step 2a : make sure trigger sources are unique */
8cb9b9fb 370
e990333d
HS
371 error |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
372 error |= cfc_check_trigger_is_unique(cmd->convert_src);
373 error |= cfc_check_trigger_is_unique(cmd->stop_src);
374
375 /* Step 2b : and mutually compatible */
8cb9b9fb 376
8cb9b9fb 377 if ((cmd->convert_src == TRIG_TIMER) &&
0a85b6f0 378 !((cmd->scan_begin_src == TRIG_TIMER) ||
2306d9b1 379 (cmd->scan_begin_src == TRIG_FOLLOW)))
e990333d 380 error |= -EINVAL;
8cb9b9fb 381 if ((cmd->convert_src == TRIG_EXT) &&
0a85b6f0 382 !((cmd->scan_begin_src == TRIG_EXT) ||
2306d9b1 383 (cmd->scan_begin_src == TRIG_FOLLOW)))
e990333d 384 error |= -EINVAL;
8cb9b9fb
EP
385
386 if (error)
387 return 2;
388
52f8ac98 389 /* Step 3 : make sure arguments are trivialy compatible */
8cb9b9fb 390
8cb9b9fb
EP
391 if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
392 cmd->start_arg = 0;
393 error++;
394 }
395
396 if ((cmd->convert_src == TRIG_TIMER) &&
02baee8c
HS
397 (cmd->convert_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) {
398 cmd->convert_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS;
8cb9b9fb
EP
399 error++;
400 }
401 if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
402 cmd->convert_arg = 0;
403 error++;
404 }
405
406 if ((cmd->scan_begin_src == TRIG_TIMER) &&
02baee8c
HS
407 (cmd->scan_begin_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) {
408 cmd->scan_begin_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS;
8cb9b9fb
EP
409 error++;
410 }
7ecac4c3
M
411 if ((cmd->scan_begin_src == TRIG_FOLLOW)
412 && (cmd->scan_begin_arg != 0)) {
8cb9b9fb
EP
413 cmd->scan_begin_arg = 0;
414 error++;
415 }
416 if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
417 cmd->scan_begin_arg = 0;
418 error++;
419 }
420
421 if ((cmd->scan_end_src == TRIG_COUNT) &&
0a85b6f0 422 (cmd->scan_end_arg != cmd->chanlist_len)) {
8cb9b9fb
EP
423 cmd->scan_end_arg = cmd->chanlist_len;
424 error++;
425 }
426
427 if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
428 cmd->stop_arg = 1;
429 error++;
430 }
431 if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
432 cmd->stop_arg = 0;
433 error++;
434 }
435
436 if (error)
437 return 3;
438
52f8ac98 439 /* Step 4 : fix up any arguments */
8cb9b9fb
EP
440
441 if (cmd->convert_src == TRIG_TIMER) {
442 tmp = cmd->convert_arg;
443 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
eba16272
HS
444 &dev_private->div1,
445 &dev_private->div2,
0a85b6f0
MT
446 &(cmd->convert_arg),
447 cmd->flags & TRIG_ROUND_MASK);
8cb9b9fb
EP
448 if (tmp != cmd->convert_arg)
449 error++;
450 }
52f8ac98
BP
451 /* There's only one timer on this card, so the scan_begin timer must */
452 /* be a multiple of chanlist_len*convert_arg */
8cb9b9fb
EP
453
454 if (cmd->scan_begin_src == TRIG_TIMER) {
455
456 unsigned int scan_begin_min;
457 unsigned int scan_begin_arg;
458 unsigned int scan_factor;
459
460 scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
461
462 if (cmd->scan_begin_arg != scan_begin_min) {
463 if (scan_begin_min < cmd->scan_begin_arg) {
464 scan_factor =
0a85b6f0 465 cmd->scan_begin_arg / scan_begin_min;
8cb9b9fb
EP
466 scan_begin_arg = scan_factor * scan_begin_min;
467 if (cmd->scan_begin_arg != scan_begin_arg) {
468 cmd->scan_begin_arg = scan_begin_arg;
469 error++;
470 }
471 } else {
472 cmd->scan_begin_arg = scan_begin_min;
473 error++;
474 }
475 }
476 }
477
478 if (error)
479 return 4;
480
52f8ac98 481 /* Step 5 : check channel list */
8cb9b9fb
EP
482
483 if (cmd->chanlist) {
484
485 range = CR_RANGE(cmd->chanlist[0]);
486 reference = CR_AREF(cmd->chanlist[0]);
487
488 if (cmd->chanlist_len > 1) {
489 for (i = 0; i < cmd->chanlist_len; i++) {
490 if (CR_CHAN(cmd->chanlist[i]) != i) {
491 comedi_error(dev,
0a85b6f0
MT
492 "entries in chanlist must be consecutive "
493 "channels,counting upwards from 0\n");
8cb9b9fb
EP
494 error++;
495 }
496 if (CR_RANGE(cmd->chanlist[i]) != range) {
497 comedi_error(dev,
0a85b6f0 498 "entries in chanlist must all have the same gain\n");
8cb9b9fb
EP
499 error++;
500 }
501 if (CR_AREF(cmd->chanlist[i]) != reference) {
502 comedi_error(dev,
0a85b6f0 503 "entries in chanlist must all have the same reference\n");
8cb9b9fb
EP
504 error++;
505 }
506 }
8cb9b9fb
EP
507 }
508 }
509
510 if (error)
511 return 5;
512
513 return 0;
514
515}
516
52f8ac98 517/* Analog input command */
8cb9b9fb 518
0a85b6f0 519static int pci9111_ai_do_cmd(struct comedi_device *dev,
d1d7b20d 520 struct comedi_subdevice *s)
8cb9b9fb 521{
98943079 522 struct pci9111_private_data *dev_private = dev->private;
d1d7b20d 523 struct comedi_cmd *async_cmd = &s->async->cmd;
8cb9b9fb
EP
524
525 if (!dev->irq) {
526 comedi_error(dev,
0a85b6f0 527 "no irq assigned for PCI9111, cannot do hardware conversion");
8cb9b9fb
EP
528 return -1;
529 }
52f8ac98
BP
530 /* Set channel scan limit */
531 /* PCI9111 allows only scanning from channel 0 to channel n */
532 /* TODO: handle the case of an external multiplexer */
8cb9b9fb
EP
533
534 if (async_cmd->chanlist_len > 1) {
0f0bde92
HS
535 outb(async_cmd->chanlist_len - 1,
536 dev->iobase + PCI9111_AI_CHANNEL_REG);
8cb9b9fb
EP
537 pci9111_autoscan_set(dev, true);
538 } else {
0f0bde92
HS
539 outb(CR_CHAN(async_cmd->chanlist[0]),
540 dev->iobase + PCI9111_AI_CHANNEL_REG);
8cb9b9fb
EP
541 pci9111_autoscan_set(dev, false);
542 }
543
52f8ac98
BP
544 /* Set gain */
545 /* This is the same gain on every channel */
8cb9b9fb 546
8c7524e6
HS
547 outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK,
548 dev->iobase + PCI9111_AI_RANGE_STAT_REG);
8cb9b9fb
EP
549
550 /* Set counter */
551
552 switch (async_cmd->stop_src) {
553 case TRIG_COUNT:
554 dev_private->stop_counter =
0a85b6f0 555 async_cmd->stop_arg * async_cmd->chanlist_len;
8cb9b9fb
EP
556 dev_private->stop_is_none = 0;
557 break;
558
559 case TRIG_NONE:
560 dev_private->stop_counter = 0;
561 dev_private->stop_is_none = 1;
562 break;
563
564 default:
565 comedi_error(dev, "Invalid stop trigger");
566 return -1;
567 }
568
52f8ac98 569 /* Set timer pacer */
8cb9b9fb
EP
570
571 dev_private->scan_delay = 0;
572 switch (async_cmd->convert_src) {
573 case TRIG_TIMER:
574 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
eba16272
HS
575 &dev_private->div1,
576 &dev_private->div2,
0a85b6f0
MT
577 &(async_cmd->convert_arg),
578 async_cmd->
579 flags & TRIG_ROUND_MASK);
8cb9b9fb
EP
580
581 pci9111_trigger_source_set(dev, software);
582 pci9111_timer_set(dev);
6b228d8a 583 pci9111_fifo_reset(dev);
8cb9b9fb 584 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
0a85b6f0 585 irq_on_timer_tick);
8cb9b9fb
EP
586 pci9111_trigger_source_set(dev, timer_pacer);
587 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
0a85b6f0 588 false, true, true);
8cb9b9fb 589
6c2fd308
IA
590 if (async_cmd->scan_begin_src == TRIG_TIMER) {
591 dev_private->scan_delay =
592 (async_cmd->scan_begin_arg /
593 (async_cmd->convert_arg *
594 async_cmd->chanlist_len)) - 1;
595 }
8cb9b9fb
EP
596
597 break;
598
599 case TRIG_EXT:
600
601 pci9111_trigger_source_set(dev, external);
6b228d8a 602 pci9111_fifo_reset(dev);
8cb9b9fb 603 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
0a85b6f0 604 irq_on_timer_tick);
8cb9b9fb 605 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
0a85b6f0 606 false, true, true);
8cb9b9fb
EP
607
608 break;
609
610 default:
611 comedi_error(dev, "Invalid convert trigger");
612 return -1;
613 }
614
615 dev_private->stop_counter *= (1 + dev_private->scan_delay);
616 dev_private->chanlist_len = async_cmd->chanlist_len;
617 dev_private->chunk_counter = 0;
618 dev_private->chunk_num_samples =
0a85b6f0 619 dev_private->chanlist_len * (1 + dev_private->scan_delay);
8cb9b9fb 620
8cb9b9fb
EP
621 return 0;
622}
623
0a85b6f0
MT
624static void pci9111_ai_munge(struct comedi_device *dev,
625 struct comedi_subdevice *s, void *data,
626 unsigned int num_bytes,
627 unsigned int start_chan_index)
8cb9b9fb 628{
790c5541 629 short *array = data;
af031edf
HS
630 unsigned int maxdata = s->maxdata;
631 unsigned int invert = (maxdata + 1) >> 1;
632 unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
633 unsigned int num_samples = num_bytes / sizeof(short);
634 unsigned int i;
635
636 for (i = 0; i < num_samples; i++)
637 array[i] = ((array[i] >> shift) & maxdata) ^ invert;
8cb9b9fb
EP
638}
639
52f8ac98
BP
640/* ------------------------------------------------------------------ */
641/* INTERRUPT SECTION */
642/* ------------------------------------------------------------------ */
8cb9b9fb 643
70265d24 644static irqreturn_t pci9111_interrupt(int irq, void *p_device)
8cb9b9fb 645{
71b5f4f1 646 struct comedi_device *dev = p_device;
98943079 647 struct pci9111_private_data *dev_private = dev->private;
d1d7b20d 648 struct comedi_subdevice *s = dev->read_subdev;
d163679c 649 struct comedi_async *async;
96764373 650 unsigned int status;
8cb9b9fb
EP
651 unsigned long irq_flags;
652 unsigned char intcsr;
653
654 if (!dev->attached) {
52f8ac98
BP
655 /* Ignore interrupt before device fully attached. */
656 /* Might not even have allocated subdevices yet! */
8cb9b9fb
EP
657 return IRQ_NONE;
658 }
659
d1d7b20d 660 async = s->async;
8cb9b9fb 661
5f74ea14 662 spin_lock_irqsave(&dev->spinlock, irq_flags);
8cb9b9fb 663
52f8ac98 664 /* Check if we are source of interrupt */
8cb9b9fb 665 intcsr = inb(dev_private->lcr_io_base +
0a85b6f0 666 PLX9050_REGISTER_INTERRUPT_CONTROL);
8cb9b9fb 667 if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
0a85b6f0
MT
668 && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
669 == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
670 || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
671 == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
52f8ac98
BP
672 /* Not the source of the interrupt. */
673 /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
5f74ea14 674 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
8cb9b9fb
EP
675 return IRQ_NONE;
676 }
677
678 if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
0a85b6f0 679 (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
52f8ac98 680 /* Interrupt comes from fifo_half-full signal */
8cb9b9fb 681
8c7524e6 682 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
96764373
HS
683
684 /* '0' means FIFO is full, data may have been lost */
8c7524e6 685 if (!(status & PCI9111_AI_STAT_FF_FF)) {
0a85b6f0 686 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
8cb9b9fb 687 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
f123f287 688 outb(0, dev->iobase + PCI9111_INT_CLR_REG);
d1d7b20d 689 pci9111_ai_cancel(dev, s);
8cb9b9fb 690 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
d1d7b20d 691 comedi_event(dev, s);
8cb9b9fb
EP
692
693 return IRQ_HANDLED;
694 }
695
96764373 696 /* '0' means FIFO is half-full */
8c7524e6 697 if (!(status & PCI9111_AI_STAT_FF_HF)) {
8cb9b9fb
EP
698 unsigned int num_samples;
699 unsigned int bytes_written = 0;
700
8cb9b9fb 701 num_samples =
0a85b6f0
MT
702 PCI9111_FIFO_HALF_SIZE >
703 dev_private->stop_counter
704 && !dev_private->
705 stop_is_none ? dev_private->stop_counter :
706 PCI9111_FIFO_HALF_SIZE;
b5d8d119 707 insw(dev->iobase + PCI9111_AI_FIFO_REG,
0a85b6f0 708 dev_private->ai_bounce_buffer, num_samples);
8cb9b9fb
EP
709
710 if (dev_private->scan_delay < 1) {
711 bytes_written =
d1d7b20d 712 cfc_write_array_to_buffer(s,
0a85b6f0
MT
713 dev_private->
714 ai_bounce_buffer,
715 num_samples *
716 sizeof(short));
8cb9b9fb
EP
717 } else {
718 int position = 0;
719 int to_read;
720
721 while (position < num_samples) {
722 if (dev_private->chunk_counter <
0a85b6f0 723 dev_private->chanlist_len) {
8cb9b9fb 724 to_read =
0a85b6f0
MT
725 dev_private->chanlist_len -
726 dev_private->chunk_counter;
8cb9b9fb
EP
727
728 if (to_read >
0a85b6f0 729 num_samples - position)
8cb9b9fb 730 to_read =
0a85b6f0
MT
731 num_samples -
732 position;
8cb9b9fb
EP
733
734 bytes_written +=
0a85b6f0 735 cfc_write_array_to_buffer
d1d7b20d 736 (s,
0a85b6f0
MT
737 dev_private->ai_bounce_buffer
738 + position,
739 to_read * sizeof(short));
8cb9b9fb
EP
740 } else {
741 to_read =
0a85b6f0
MT
742 dev_private->chunk_num_samples
743 -
744 dev_private->chunk_counter;
8cb9b9fb 745 if (to_read >
0a85b6f0 746 num_samples - position)
8cb9b9fb 747 to_read =
0a85b6f0
MT
748 num_samples -
749 position;
8cb9b9fb
EP
750
751 bytes_written +=
0a85b6f0 752 sizeof(short) * to_read;
8cb9b9fb
EP
753 }
754
755 position += to_read;
756 dev_private->chunk_counter += to_read;
757
758 if (dev_private->chunk_counter >=
0a85b6f0 759 dev_private->chunk_num_samples)
8cb9b9fb
EP
760 dev_private->chunk_counter = 0;
761 }
762 }
763
764 dev_private->stop_counter -=
0a85b6f0 765 bytes_written / sizeof(short);
8cb9b9fb
EP
766 }
767 }
768
769 if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
770 async->events |= COMEDI_CB_EOA;
d1d7b20d 771 pci9111_ai_cancel(dev, s);
8cb9b9fb
EP
772 }
773
f123f287 774 outb(0, dev->iobase + PCI9111_INT_CLR_REG);
8cb9b9fb 775
5f74ea14 776 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
8cb9b9fb 777
d1d7b20d 778 comedi_event(dev, s);
8cb9b9fb
EP
779
780 return IRQ_HANDLED;
781}
782
52f8ac98
BP
783/* ------------------------------------------------------------------ */
784/* INSTANT ANALOG INPUT OUTPUT SECTION */
785/* ------------------------------------------------------------------ */
8cb9b9fb 786
52f8ac98 787/* analog instant input */
8cb9b9fb 788
da91b269 789static int pci9111_ai_insn_read(struct comedi_device *dev,
d1d7b20d 790 struct comedi_subdevice *s,
0a85b6f0 791 struct comedi_insn *insn, unsigned int *data)
8cb9b9fb 792{
ae479ee5
HS
793 unsigned int chan = CR_CHAN(insn->chanspec);
794 unsigned int range = CR_RANGE(insn->chanspec);
2f002cc9
HS
795 unsigned int maxdata = s->maxdata;
796 unsigned int invert = (maxdata + 1) >> 1;
797 unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
96764373 798 unsigned int status;
2f002cc9
HS
799 int timeout;
800 int i;
8cb9b9fb 801
0f0bde92 802 outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG);
8cb9b9fb 803
8c7524e6
HS
804 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
805 if ((status & PCI9111_AI_RANGE_MASK) != range) {
806 outb(range & PCI9111_AI_RANGE_MASK,
807 dev->iobase + PCI9111_AI_RANGE_STAT_REG);
c514bab7 808 }
8cb9b9fb 809
6b228d8a 810 pci9111_fifo_reset(dev);
8cb9b9fb
EP
811
812 for (i = 0; i < insn->n; i++) {
3eb60d73 813 /* Generate a software trigger */
8c7524e6 814 outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG);
8cb9b9fb
EP
815
816 timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
817
818 while (timeout--) {
8c7524e6 819 status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
96764373 820 /* '1' means FIFO is not empty */
8c7524e6 821 if (status & PCI9111_AI_STAT_FF_EF)
8cb9b9fb
EP
822 goto conversion_done;
823 }
824
825 comedi_error(dev, "A/D read timeout");
826 data[i] = 0;
6b228d8a 827 pci9111_fifo_reset(dev);
8cb9b9fb
EP
828 return -ETIME;
829
0a85b6f0 830conversion_done:
8cb9b9fb 831
2f002cc9
HS
832 data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG);
833 data[i] = ((data[i] >> shift) & maxdata) ^ invert;
8cb9b9fb
EP
834 }
835
8cb9b9fb
EP
836 return i;
837}
838
2084fd19
HS
839static int pci9111_ao_insn_write(struct comedi_device *dev,
840 struct comedi_subdevice *s,
841 struct comedi_insn *insn,
842 unsigned int *data)
8cb9b9fb 843{
98943079 844 struct pci9111_private_data *dev_private = dev->private;
2084fd19 845 unsigned int val = 0;
8cb9b9fb
EP
846 int i;
847
848 for (i = 0; i < insn->n; i++) {
2084fd19
HS
849 val = data[i];
850 outw(val, dev->iobase + PCI9111_AO_REG);
8cb9b9fb 851 }
2084fd19 852 dev_private->ao_readback = val;
8cb9b9fb 853
2084fd19 854 return insn->n;
8cb9b9fb
EP
855}
856
da91b269 857static int pci9111_ao_insn_read(struct comedi_device *dev,
0a85b6f0 858 struct comedi_subdevice *s,
b3450faf
HS
859 struct comedi_insn *insn,
860 unsigned int *data)
8cb9b9fb 861{
98943079 862 struct pci9111_private_data *dev_private = dev->private;
8cb9b9fb
EP
863 int i;
864
2306d9b1 865 for (i = 0; i < insn->n; i++)
b3450faf 866 data[i] = dev_private->ao_readback;
8cb9b9fb 867
b3450faf 868 return insn->n;
8cb9b9fb
EP
869}
870
da91b269 871static int pci9111_di_insn_bits(struct comedi_device *dev,
d1d7b20d 872 struct comedi_subdevice *s,
bfa6d3b8
HS
873 struct comedi_insn *insn,
874 unsigned int *data)
8cb9b9fb 875{
bfa6d3b8 876 data[1] = inw(dev->iobase + PCI9111_DIO_REG);
8cb9b9fb 877
a2714e3e 878 return insn->n;
8cb9b9fb
EP
879}
880
da91b269 881static int pci9111_do_insn_bits(struct comedi_device *dev,
d1d7b20d 882 struct comedi_subdevice *s,
83dcfee0
HS
883 struct comedi_insn *insn,
884 unsigned int *data)
8cb9b9fb 885{
83dcfee0
HS
886 unsigned int mask = data[0];
887 unsigned int bits = data[1];
8cb9b9fb 888
83dcfee0
HS
889 if (mask) {
890 s->state &= ~mask;
891 s->state |= (bits & mask);
8cb9b9fb 892
83dcfee0
HS
893 outw(s->state, dev->iobase + PCI9111_DIO_REG);
894 }
8cb9b9fb 895
83dcfee0 896 data[1] = s->state;
8cb9b9fb 897
a2714e3e 898 return insn->n;
8cb9b9fb
EP
899}
900
52f8ac98
BP
901/* ------------------------------------------------------------------ */
902/* INITIALISATION SECTION */
903/* ------------------------------------------------------------------ */
8cb9b9fb 904
52f8ac98 905/* Reset device */
8cb9b9fb 906
da91b269 907static int pci9111_reset(struct comedi_device *dev)
8cb9b9fb 908{
98943079
HS
909 struct pci9111_private_data *dev_private = dev->private;
910
52f8ac98 911 /* Set trigger source to software */
8cb9b9fb
EP
912
913 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
0a85b6f0 914 true, false);
8cb9b9fb
EP
915
916 pci9111_trigger_source_set(dev, software);
917 pci9111_pretrigger_set(dev, false);
918 pci9111_autoscan_set(dev, false);
919
eba16272
HS
920 /* Reset 8254 chip */
921 dev_private->div1 = 0;
922 dev_private->div2 = 0;
8cb9b9fb
EP
923 pci9111_timer_set(dev);
924
925 return 0;
926}
927
3e5a0ba0
HS
928static int pci9111_attach_pci(struct comedi_device *dev,
929 struct pci_dev *pcidev)
8cb9b9fb 930{
98943079 931 struct pci9111_private_data *dev_private;
d1d7b20d 932 struct comedi_subdevice *s;
98943079 933 int ret;
3e5a0ba0
HS
934
935 comedi_set_hw_dev(dev, &pcidev->dev);
936 dev->board_name = dev->driver->driver_name;
8cb9b9fb 937
98943079
HS
938 ret = alloc_private(dev, sizeof(*dev_private));
939 if (ret)
940 return ret;
941 dev_private = dev->private;
942
3e5a0ba0
HS
943 ret = comedi_pci_enable(pcidev, dev->board_name);
944 if (ret)
945 return ret;
946 dev_private->lcr_io_base = pci_resource_start(pcidev, 1);
947 dev->iobase = pci_resource_start(pcidev, 2);
8cb9b9fb
EP
948
949 pci9111_reset(dev);
950
6a7b1b0c 951 if (pcidev->irq > 0) {
3e5a0ba0
HS
952 ret = request_irq(dev->irq, pci9111_interrupt,
953 IRQF_SHARED, dev->board_name, dev);
954 if (ret)
955 return ret;
6a7b1b0c 956 dev->irq = pcidev->irq;
8cb9b9fb 957 }
8cb9b9fb 958
98943079
HS
959 ret = comedi_alloc_subdevices(dev, 4);
960 if (ret)
961 return ret;
8cb9b9fb 962
573e31af 963 s = &dev->subdevices[0];
d1d7b20d 964 dev->read_subdev = s;
02baee8c
HS
965 s->type = COMEDI_SUBD_AI;
966 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
967 s->n_chan = 16;
968 s->maxdata = 0xffff;
969 s->len_chanlist = 16;
afa6ac4a 970 s->range_table = &pci9111_ai_range;
02baee8c
HS
971 s->cancel = pci9111_ai_cancel;
972 s->insn_read = pci9111_ai_insn_read;
973 s->do_cmdtest = pci9111_ai_do_cmd_test;
974 s->do_cmd = pci9111_ai_do_cmd;
975 s->munge = pci9111_ai_munge;
d1d7b20d 976
573e31af 977 s = &dev->subdevices[1];
05841b36
HS
978 s->type = COMEDI_SUBD_AO;
979 s->subdev_flags = SDF_WRITABLE | SDF_COMMON;
980 s->n_chan = 1;
981 s->maxdata = 0x0fff;
982 s->len_chanlist = 1;
983 s->range_table = &range_bipolar10;
984 s->insn_write = pci9111_ao_insn_write;
985 s->insn_read = pci9111_ao_insn_read;
d1d7b20d 986
573e31af 987 s = &dev->subdevices[2];
3acf3176
HS
988 s->type = COMEDI_SUBD_DI;
989 s->subdev_flags = SDF_READABLE;
990 s->n_chan = 16;
991 s->maxdata = 1;
992 s->range_table = &range_digital;
993 s->insn_bits = pci9111_di_insn_bits;
d1d7b20d 994
573e31af 995 s = &dev->subdevices[3];
3acf3176
HS
996 s->type = COMEDI_SUBD_DO;
997 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
998 s->n_chan = 16;
999 s->maxdata = 1;
1000 s->range_table = &range_digital;
1001 s->insn_bits = pci9111_do_insn_bits;
8cb9b9fb 1002
034f8734
HS
1003 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
1004
8cb9b9fb
EP
1005 return 0;
1006}
1007
484ecc95 1008static void pci9111_detach(struct comedi_device *dev)
8cb9b9fb 1009{
6a7b1b0c
HS
1010 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1011
893be483
HS
1012 if (dev->iobase)
1013 pci9111_reset(dev);
2306d9b1 1014 if (dev->irq != 0)
5f74ea14 1015 free_irq(dev->irq, dev);
6a7b1b0c 1016 if (pcidev) {
2306d9b1 1017 if (dev->iobase)
6a7b1b0c
HS
1018 comedi_pci_disable(pcidev);
1019 pci_dev_put(pcidev);
8cb9b9fb 1020 }
8cb9b9fb 1021}
90f703d3 1022
75e6301b
HS
1023static struct comedi_driver adl_pci9111_driver = {
1024 .driver_name = "adl_pci9111",
e68a83fe 1025 .module = THIS_MODULE,
3e5a0ba0 1026 .attach_pci = pci9111_attach_pci,
e68a83fe
HS
1027 .detach = pci9111_detach,
1028};
1029
75e6301b
HS
1030static int __devinit pci9111_pci_probe(struct pci_dev *dev,
1031 const struct pci_device_id *ent)
e68a83fe 1032{
75e6301b 1033 return comedi_pci_auto_config(dev, &adl_pci9111_driver);
e68a83fe
HS
1034}
1035
75e6301b 1036static void __devexit pci9111_pci_remove(struct pci_dev *dev)
e68a83fe
HS
1037{
1038 comedi_pci_auto_unconfig(dev);
1039}
1040
1041static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
1042 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
1043 /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
1044 { 0 }
1045};
1046MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
1047
75e6301b
HS
1048static struct pci_driver adl_pci9111_pci_driver = {
1049 .name = "adl_pci9111",
e68a83fe 1050 .id_table = pci9111_pci_table,
75e6301b
HS
1051 .probe = pci9111_pci_probe,
1052 .remove = __devexit_p(pci9111_pci_remove),
e68a83fe 1053};
75e6301b 1054module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
e68a83fe 1055
90f703d3
AT
1056MODULE_AUTHOR("Comedi http://www.comedi.org");
1057MODULE_DESCRIPTION("Comedi low-level driver");
1058MODULE_LICENSE("GPL");