1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77#include "../comedidev.h"
78
79#include <linux/delay.h>
80#include <linux/interrupt.h>
81
82#include "8253.h"
83#include "comedi_pci.h"
84#include "comedi_fc.h"
85
86#define PCI9111_DRIVER_NAME "adl_pci9111"
87#define PCI9111_HR_DEVICE_ID 0x9111
88
89
90
91#define PCI9111_IO_RANGE 0x0100
92
93#define PCI9111_FIFO_HALF_SIZE 512
94
95#define PCI9111_AI_CHANNEL_NBR 16
96
97#define PCI9111_AI_RESOLUTION 12
98#define PCI9111_AI_RESOLUTION_MASK 0x0FFF
99#define PCI9111_AI_RESOLUTION_2_CMP_BIT 0x0800
100
101#define PCI9111_HR_AI_RESOLUTION 16
102#define PCI9111_HR_AI_RESOLUTION_MASK 0xFFFF
103#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT 0x8000
104
105#define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000
106#define PCI9111_AO_CHANNEL_NBR 1
107#define PCI9111_AO_RESOLUTION 12
108#define PCI9111_AO_RESOLUTION_MASK 0x0FFF
109#define PCI9111_DI_CHANNEL_NBR 16
110#define PCI9111_DO_CHANNEL_NBR 16
111#define PCI9111_DO_MASK 0xFFFF
112
113#define PCI9111_RANGE_SETTING_DELAY 10
114#define PCI9111_AI_INSTANT_READ_UDELAY_US 2
115#define PCI9111_AI_INSTANT_READ_TIMEOUT 100
116
117#define PCI9111_8254_CLOCK_PERIOD_NS 500
118
119#define PCI9111_8254_COUNTER_0 0x00
120#define PCI9111_8254_COUNTER_1 0x40
121#define PCI9111_8254_COUNTER_2 0x80
122#define PCI9111_8254_COUNTER_LATCH 0x00
123#define PCI9111_8254_READ_LOAD_LSB_ONLY 0x10
124#define PCI9111_8254_READ_LOAD_MSB_ONLY 0x20
125#define PCI9111_8254_READ_LOAD_LSB_MSB 0x30
126#define PCI9111_8254_MODE_0 0x00
127#define PCI9111_8254_MODE_1 0x02
128#define PCI9111_8254_MODE_2 0x04
129#define PCI9111_8254_MODE_3 0x06
130#define PCI9111_8254_MODE_4 0x08
131#define PCI9111_8254_MODE_5 0x0A
132#define PCI9111_8254_BINARY_COUNTER 0x00
133#define PCI9111_8254_BCD_COUNTER 0x01
134
135
136
137#define PCI9111_REGISTER_AD_FIFO_VALUE 0x00
138#define PCI9111_REGISTER_DA_OUTPUT 0x00
139#define PCI9111_REGISTER_DIGITAL_IO 0x02
140#define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04
141#define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06
142#define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06
143#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08
144#define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08
145#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A
146#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A
147#define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E
148#define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C
149#define PCI9111_REGISTER_8254_COUNTER_0 0x40
150#define PCI9111_REGISTER_8254_COUNTER_1 0x42
151#define PCI9111_REGISTER_8254_COUNTER_2 0X44
152#define PCI9111_REGISTER_8254_CONTROL 0x46
153#define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48
154
155#define PCI9111_TRIGGER_MASK 0x0F
156#define PCI9111_PTRG_OFF (0 << 3)
157#define PCI9111_PTRG_ON (1 << 3)
158#define PCI9111_EITS_EXTERNAL (1 << 2)
159#define PCI9111_EITS_INTERNAL (0 << 2)
160#define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1)
161#define PCI9111_TPST_TIMER_PACER (1 << 1)
162#define PCI9111_ASCAN_ON (1 << 0)
163#define PCI9111_ASCAN_OFF (0 << 0)
164
165#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
166#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0)
167#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1)
168#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1)
169#define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2)
170#define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2)
171
172#define PCI9111_CHANNEL_MASK 0x0F
173
174#define PCI9111_RANGE_MASK 0x07
175#define PCI9111_FIFO_EMPTY_MASK 0x10
176#define PCI9111_FIFO_HALF_FULL_MASK 0x20
177#define PCI9111_FIFO_FULL_MASK 0x40
178#define PCI9111_AD_BUSY_MASK 0x80
179
180#define PCI9111_IO_BASE dev->iobase
181
182
183
184
185
186#define pci9111_trigger_and_autoscan_get() \
187 (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F)
188
189#define pci9111_trigger_and_autoscan_set(flags) \
190 outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
191
192#define pci9111_interrupt_and_fifo_get() \
193 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) >> 4) &0x03)
194
195#define pci9111_interrupt_and_fifo_set(flags) \
196 outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
197
198#define pci9111_interrupt_clear() \
199 outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR)
200
201#define pci9111_software_trigger() \
202 outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER)
203
204#define pci9111_fifo_reset() \
205 outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
206 outb(PCI9111_FFEN_SET_FIFO_DISABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
207 outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
208
209#define pci9111_is_fifo_full() \
210 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
211 PCI9111_FIFO_FULL_MASK)==0)
212
213#define pci9111_is_fifo_half_full() \
214 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
215 PCI9111_FIFO_HALF_FULL_MASK)==0)
216
217#define pci9111_is_fifo_empty() \
218 ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
219 PCI9111_FIFO_EMPTY_MASK)==0)
220
221#define pci9111_ai_channel_set(channel) \
222 outb((channel)&PCI9111_CHANNEL_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL)
223
224#define pci9111_ai_channel_get() \
225 inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK)&PCI9111_CHANNEL_MASK
226
227#define pci9111_ai_range_set(range) \
228 outb((range)&PCI9111_RANGE_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
229
230#define pci9111_ai_range_get() \
231 inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)&PCI9111_RANGE_MASK
232
233#define pci9111_ai_get_data() \
234 ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4)&PCI9111_AI_RESOLUTION_MASK) \
235 ^ PCI9111_AI_RESOLUTION_2_CMP_BIT
236
237#define pci9111_hr_ai_get_data() \
238 (inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) & PCI9111_HR_AI_RESOLUTION_MASK) \
239 ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT
240
241#define pci9111_ao_set_data(data) \
242 outw(data&PCI9111_AO_RESOLUTION_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT)
243
244#define pci9111_di_get_bits() \
245 inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
246
247#define pci9111_do_set_bits(bits) \
248 outw(bits, PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
249
250#define pci9111_8254_control_set(flags) \
251 outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL)
252
253#define pci9111_8254_counter_0_set(data) \
254 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \
255 outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0)
256
257#define pci9111_8254_counter_1_set(data) \
258 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \
259 outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1)
260
261#define pci9111_8254_counter_2_set(data) \
262 outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
263 outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2)
264
265
266
267static int pci9111_attach(struct comedi_device *dev,
268 struct comedi_devconfig *it);
269static int pci9111_detach(struct comedi_device *dev);
270static void pci9111_ai_munge(struct comedi_device *dev,
271 struct comedi_subdevice *s, void *data,
272 unsigned int num_bytes,
273 unsigned int start_chan_index);
274
275static const struct comedi_lrange pci9111_hr_ai_range = {
276 5,
277 {
278 BIP_RANGE(10),
279 BIP_RANGE(5),
280 BIP_RANGE(2.5),
281 BIP_RANGE(1.25),
282 BIP_RANGE(0.625)
283 }
284};
285
286static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
287 {
288 PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID,
289 PCI_ANY_ID, 0, 0, 0},
290
291 {
292 0}
293};
294
295MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
296
297
298
299
300
301struct pci9111_board {
302 const char *name;
303 int device_id;
304 int ai_channel_nbr;
305 int ao_channel_nbr;
306 int ai_resolution;
307 int ai_resolution_mask;
308 int ao_resolution;
309 int ao_resolution_mask;
310 const struct comedi_lrange *ai_range_list;
311 const struct comedi_lrange *ao_range_list;
312 unsigned int ai_acquisition_period_min_ns;
313};
314
315static const struct pci9111_board pci9111_boards[] = {
316 {
317 .name = "pci9111_hr",
318 .device_id = PCI9111_HR_DEVICE_ID,
319 .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR,
320 .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR,
321 .ai_resolution = PCI9111_HR_AI_RESOLUTION,
322 .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK,
323 .ao_resolution = PCI9111_AO_RESOLUTION,
324 .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK,
325 .ai_range_list = &pci9111_hr_ai_range,
326 .ao_range_list = &range_bipolar10,
327 .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS}
328};
329
330#define pci9111_board_nbr \
331 (sizeof(pci9111_boards)/sizeof(struct pci9111_board))
332
333static struct comedi_driver pci9111_driver = {
334 .driver_name = PCI9111_DRIVER_NAME,
335 .module = THIS_MODULE,
336 .attach = pci9111_attach,
337 .detach = pci9111_detach,
338};
339
340COMEDI_PCI_INITCLEANUP(pci9111_driver, pci9111_pci_table);
341
342
343
344struct pci9111_private_data {
345 struct pci_dev *pci_device;
346 unsigned long io_range;
347
348 unsigned long lcr_io_base;
349 unsigned long lcr_io_range;
350
351 int stop_counter;
352 int stop_is_none;
353
354 unsigned int scan_delay;
355 unsigned int chanlist_len;
356 unsigned int chunk_counter;
357 unsigned int chunk_num_samples;
358
359 int ao_readback;
360
361 int timer_divisor_1;
362 int timer_divisor_2;
363
364 int is_valid;
365
366 short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
367};
368
369#define dev_private ((struct pci9111_private_data *)dev->private)
370
371
372
373
374
375#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
376
377#define PLX9050_LINTI1_ENABLE (1 << 0)
378#define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)
379#define PLX9050_LINTI1_STATUS (1 << 2)
380#define PLX9050_LINTI2_ENABLE (1 << 3)
381#define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)
382#define PLX9050_LINTI2_STATUS (1 << 5)
383#define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)
384#define PLX9050_SOFTWARE_INTERRUPT (1 << 7)
385
386static void plx9050_interrupt_control(unsigned long io_base,
387 bool LINTi1_enable,
388 bool LINTi1_active_high,
389 bool LINTi2_enable,
390 bool LINTi2_active_high,
391 bool interrupt_enable)
392{
393 int flags = 0;
394
395 if (LINTi1_enable)
396 flags |= PLX9050_LINTI1_ENABLE;
397 if (LINTi1_active_high)
398 flags |= PLX9050_LINTI1_ACTIVE_HIGH;
399 if (LINTi2_enable)
400 flags |= PLX9050_LINTI2_ENABLE;
401 if (LINTi2_active_high)
402 flags |= PLX9050_LINTI2_ACTIVE_HIGH;
403
404 if (interrupt_enable)
405 flags |= PLX9050_PCI_INTERRUPT_ENABLE;
406
407 outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
408}
409
410
411
412
413
414
415
416static void pci9111_timer_set(struct comedi_device *dev)
417{
418 pci9111_8254_control_set(PCI9111_8254_COUNTER_0 |
419 PCI9111_8254_READ_LOAD_LSB_MSB |
420 PCI9111_8254_MODE_0 |
421 PCI9111_8254_BINARY_COUNTER);
422
423 pci9111_8254_control_set(PCI9111_8254_COUNTER_1 |
424 PCI9111_8254_READ_LOAD_LSB_MSB |
425 PCI9111_8254_MODE_2 |
426 PCI9111_8254_BINARY_COUNTER);
427
428 pci9111_8254_control_set(PCI9111_8254_COUNTER_2 |
429 PCI9111_8254_READ_LOAD_LSB_MSB |
430 PCI9111_8254_MODE_2 |
431 PCI9111_8254_BINARY_COUNTER);
432
433 udelay(1);
434
435 pci9111_8254_counter_2_set(dev_private->timer_divisor_2);
436 pci9111_8254_counter_1_set(dev_private->timer_divisor_1);
437}
438
439enum pci9111_trigger_sources {
440 software,
441 timer_pacer,
442 external
443};
444
445static void pci9111_trigger_source_set(struct comedi_device *dev,
446 enum pci9111_trigger_sources source)
447{
448 int flags;
449
450 flags = pci9111_trigger_and_autoscan_get() & 0x09;
451
452 switch (source) {
453 case software:
454 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER;
455 break;
456
457 case timer_pacer:
458 flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER;
459 break;
460
461 case external:
462 flags |= PCI9111_EITS_EXTERNAL;
463 break;
464 }
465
466 pci9111_trigger_and_autoscan_set(flags);
467}
468
469static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger)
470{
471 int flags;
472
473 flags = pci9111_trigger_and_autoscan_get() & 0x07;
474
475 if (pretrigger)
476 flags |= PCI9111_PTRG_ON;
477
478 pci9111_trigger_and_autoscan_set(flags);
479}
480
481static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan)
482{
483 int flags;
484
485 flags = pci9111_trigger_and_autoscan_get() & 0x0e;
486
487 if (autoscan)
488 flags |= PCI9111_ASCAN_ON;
489
490 pci9111_trigger_and_autoscan_set(flags);
491}
492
493enum pci9111_ISC0_sources {
494 irq_on_eoc,
495 irq_on_fifo_half_full
496};
497
498enum pci9111_ISC1_sources {
499 irq_on_timer_tick,
500 irq_on_external_trigger
501};
502
503static void pci9111_interrupt_source_set(struct comedi_device *dev,
504 enum pci9111_ISC0_sources irq_0_source,
505 enum pci9111_ISC1_sources irq_1_source)
506{
507 int flags;
508
509 flags = pci9111_interrupt_and_fifo_get() & 0x04;
510
511 if (irq_0_source == irq_on_fifo_half_full)
512 flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL;
513
514 if (irq_1_source == irq_on_external_trigger)
515 flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG;
516
517 pci9111_interrupt_and_fifo_set(flags);
518}
519
520
521
522
523
524
525
526#undef AI_DO_CMD_DEBUG
527
528static int pci9111_ai_cancel(struct comedi_device *dev,
529 struct comedi_subdevice *s)
530{
531
532
533 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
534 true, false);
535
536 pci9111_trigger_source_set(dev, software);
537
538 pci9111_autoscan_set(dev, false);
539
540 pci9111_fifo_reset();
541
542#ifdef AI_DO_CMD_DEBUG
543 printk(PCI9111_DRIVER_NAME ": ai_cancel\n");
544#endif
545
546 return 0;
547}
548
549
550
551#define pci9111_check_trigger_src(src, flags) \
552 tmp = src; \
553 src &= flags; \
554 if (!src || tmp != src) error++
555
556static int
557pci9111_ai_do_cmd_test(struct comedi_device *dev,
558 struct comedi_subdevice *s, struct comedi_cmd *cmd)
559{
560 int tmp;
561 int error = 0;
562 int range, reference;
563 int i;
564 struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr;
565
566
567
568 pci9111_check_trigger_src(cmd->start_src, TRIG_NOW);
569 pci9111_check_trigger_src(cmd->scan_begin_src,
570 TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
571 pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT);
572 pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT);
573 pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE);
574
575 if (error)
576 return 1;
577
578
579
580 if (cmd->start_src != TRIG_NOW)
581 error++;
582
583 if ((cmd->scan_begin_src != TRIG_TIMER) &&
584 (cmd->scan_begin_src != TRIG_FOLLOW) &&
585 (cmd->scan_begin_src != TRIG_EXT))
586 error++;
587
588 if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT)) {
589 error++;
590 }
591 if ((cmd->convert_src == TRIG_TIMER) &&
592 !((cmd->scan_begin_src == TRIG_TIMER) ||
593 (cmd->scan_begin_src == TRIG_FOLLOW))) {
594 error++;
595 }
596 if ((cmd->convert_src == TRIG_EXT) &&
597 !((cmd->scan_begin_src == TRIG_EXT) ||
598 (cmd->scan_begin_src == TRIG_FOLLOW))) {
599 error++;
600 }
601
602 if (cmd->scan_end_src != TRIG_COUNT)
603 error++;
604 if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE))
605 error++;
606
607 if (error)
608 return 2;
609
610
611
612 if (cmd->chanlist_len < 1) {
613 cmd->chanlist_len = 1;
614 error++;
615 }
616
617 if (cmd->chanlist_len > board->ai_channel_nbr) {
618 cmd->chanlist_len = board->ai_channel_nbr;
619 error++;
620 }
621
622 if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) {
623 cmd->start_arg = 0;
624 error++;
625 }
626
627 if ((cmd->convert_src == TRIG_TIMER) &&
628 (cmd->convert_arg < board->ai_acquisition_period_min_ns)) {
629 cmd->convert_arg = board->ai_acquisition_period_min_ns;
630 error++;
631 }
632 if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) {
633 cmd->convert_arg = 0;
634 error++;
635 }
636
637 if ((cmd->scan_begin_src == TRIG_TIMER) &&
638 (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) {
639 cmd->scan_begin_arg = board->ai_acquisition_period_min_ns;
640 error++;
641 }
642 if ((cmd->scan_begin_src == TRIG_FOLLOW) && (cmd->scan_begin_arg != 0)) {
643 cmd->scan_begin_arg = 0;
644 error++;
645 }
646 if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) {
647 cmd->scan_begin_arg = 0;
648 error++;
649 }
650
651 if ((cmd->scan_end_src == TRIG_COUNT) &&
652 (cmd->scan_end_arg != cmd->chanlist_len)) {
653 cmd->scan_end_arg = cmd->chanlist_len;
654 error++;
655 }
656
657 if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) {
658 cmd->stop_arg = 1;
659 error++;
660 }
661 if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) {
662 cmd->stop_arg = 0;
663 error++;
664 }
665
666 if (error)
667 return 3;
668
669
670
671 if (cmd->convert_src == TRIG_TIMER) {
672 tmp = cmd->convert_arg;
673 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
674 &(dev_private->timer_divisor_1),
675 &(dev_private->timer_divisor_2),
676 &(cmd->convert_arg),
677 cmd->flags & TRIG_ROUND_MASK);
678 if (tmp != cmd->convert_arg)
679 error++;
680 }
681
682
683
684 if (cmd->scan_begin_src == TRIG_TIMER) {
685
686 unsigned int scan_begin_min;
687 unsigned int scan_begin_arg;
688 unsigned int scan_factor;
689
690 scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
691
692 if (cmd->scan_begin_arg != scan_begin_min) {
693 if (scan_begin_min < cmd->scan_begin_arg) {
694 scan_factor =
695 cmd->scan_begin_arg / scan_begin_min;
696 scan_begin_arg = scan_factor * scan_begin_min;
697 if (cmd->scan_begin_arg != scan_begin_arg) {
698 cmd->scan_begin_arg = scan_begin_arg;
699 error++;
700 }
701 } else {
702 cmd->scan_begin_arg = scan_begin_min;
703 error++;
704 }
705 }
706 }
707
708 if (error)
709 return 4;
710
711
712
713 if (cmd->chanlist) {
714
715 range = CR_RANGE(cmd->chanlist[0]);
716 reference = CR_AREF(cmd->chanlist[0]);
717
718 if (cmd->chanlist_len > 1) {
719 for (i = 0; i < cmd->chanlist_len; i++) {
720 if (CR_CHAN(cmd->chanlist[i]) != i) {
721 comedi_error(dev,
722 "entries in chanlist must be consecutive "
723 "channels,counting upwards from 0\n");
724 error++;
725 }
726 if (CR_RANGE(cmd->chanlist[i]) != range) {
727 comedi_error(dev,
728 "entries in chanlist must all have the same gain\n");
729 error++;
730 }
731 if (CR_AREF(cmd->chanlist[i]) != reference) {
732 comedi_error(dev,
733 "entries in chanlist must all have the same reference\n");
734 error++;
735 }
736 }
737 } else {
738 if ((CR_CHAN(cmd->chanlist[0]) >
739 (board->ai_channel_nbr - 1))
740 || (CR_CHAN(cmd->chanlist[0]) < 0)) {
741 comedi_error(dev,
742 "channel number is out of limits\n");
743 error++;
744 }
745 }
746 }
747
748 if (error)
749 return 5;
750
751 return 0;
752
753}
754
755
756
757static int pci9111_ai_do_cmd(struct comedi_device *dev,
758 struct comedi_subdevice *subdevice)
759{
760 struct comedi_cmd *async_cmd = &subdevice->async->cmd;
761
762 if (!dev->irq) {
763 comedi_error(dev,
764 "no irq assigned for PCI9111, cannot do hardware conversion");
765 return -1;
766 }
767
768
769
770
771 if (async_cmd->chanlist_len > 1) {
772 pci9111_ai_channel_set((async_cmd->chanlist_len) - 1);
773 pci9111_autoscan_set(dev, true);
774 } else {
775 pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0]));
776 pci9111_autoscan_set(dev, false);
777 }
778
779
780
781
782 pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0]));
783
784
785
786 switch (async_cmd->stop_src) {
787 case TRIG_COUNT:
788 dev_private->stop_counter =
789 async_cmd->stop_arg * async_cmd->chanlist_len;
790 dev_private->stop_is_none = 0;
791 break;
792
793 case TRIG_NONE:
794 dev_private->stop_counter = 0;
795 dev_private->stop_is_none = 1;
796 break;
797
798 default:
799 comedi_error(dev, "Invalid stop trigger");
800 return -1;
801 }
802
803
804
805 dev_private->scan_delay = 0;
806 switch (async_cmd->convert_src) {
807 case TRIG_TIMER:
808 i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS,
809 &(dev_private->timer_divisor_1),
810 &(dev_private->timer_divisor_2),
811 &(async_cmd->convert_arg),
812 async_cmd->
813 flags & TRIG_ROUND_MASK);
814#ifdef AI_DO_CMD_DEBUG
815 printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n",
816 dev_private->timer_divisor_1,
817 dev_private->timer_divisor_2);
818#endif
819
820 pci9111_trigger_source_set(dev, software);
821 pci9111_timer_set(dev);
822 pci9111_fifo_reset();
823 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
824 irq_on_timer_tick);
825 pci9111_trigger_source_set(dev, timer_pacer);
826 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
827 false, true, true);
828
829 dev_private->scan_delay =
830 (async_cmd->scan_begin_arg / (async_cmd->convert_arg *
831 async_cmd->chanlist_len)) - 1;
832
833 break;
834
835 case TRIG_EXT:
836
837 pci9111_trigger_source_set(dev, external);
838 pci9111_fifo_reset();
839 pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
840 irq_on_timer_tick);
841 plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
842 false, true, true);
843
844 break;
845
846 default:
847 comedi_error(dev, "Invalid convert trigger");
848 return -1;
849 }
850
851 dev_private->stop_counter *= (1 + dev_private->scan_delay);
852 dev_private->chanlist_len = async_cmd->chanlist_len;
853 dev_private->chunk_counter = 0;
854 dev_private->chunk_num_samples =
855 dev_private->chanlist_len * (1 + dev_private->scan_delay);
856
857#ifdef AI_DO_CMD_DEBUG
858 printk(PCI9111_DRIVER_NAME ": start interruptions!\n");
859 printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n",
860 pci9111_trigger_and_autoscan_get());
861 printk(PCI9111_DRIVER_NAME ": irq source = %2x\n",
862 pci9111_interrupt_and_fifo_get());
863 printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n");
864 printk(PCI9111_DRIVER_NAME ": stop counter = %d\n",
865 dev_private->stop_counter);
866 printk(PCI9111_DRIVER_NAME ": scan delay = %d\n",
867 dev_private->scan_delay);
868 printk(PCI9111_DRIVER_NAME ": chanlist_len = %d\n",
869 dev_private->chanlist_len);
870 printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n",
871 dev_private->chunk_num_samples);
872#endif
873
874 return 0;
875}
876
877static void pci9111_ai_munge(struct comedi_device *dev,
878 struct comedi_subdevice *s, void *data,
879 unsigned int num_bytes,
880 unsigned int start_chan_index)
881{
882 unsigned int i, num_samples = num_bytes / sizeof(short);
883 short *array = data;
884 int resolution =
885 ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
886
887 for (i = 0; i < num_samples; i++) {
888 if (resolution == PCI9111_HR_AI_RESOLUTION)
889 array[i] =
890 (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^
891 PCI9111_HR_AI_RESOLUTION_2_CMP_BIT;
892 else
893 array[i] =
894 ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^
895 PCI9111_AI_RESOLUTION_2_CMP_BIT;
896 }
897}
898
899
900
901
902
903#undef INTERRUPT_DEBUG
904
905static irqreturn_t pci9111_interrupt(int irq, void *p_device)
906{
907 struct comedi_device *dev = p_device;
908 struct comedi_subdevice *subdevice = dev->read_subdev;
909 struct comedi_async *async;
910 unsigned long irq_flags;
911 unsigned char intcsr;
912
913 if (!dev->attached) {
914
915
916 return IRQ_NONE;
917 }
918
919 async = subdevice->async;
920
921 spin_lock_irqsave(&dev->spinlock, irq_flags);
922
923
924 intcsr = inb(dev_private->lcr_io_base +
925 PLX9050_REGISTER_INTERRUPT_CONTROL);
926 if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
927 && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
928 == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
929 || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
930 == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
931
932
933 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
934 return IRQ_NONE;
935 }
936
937 if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
938 (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
939
940
941 if (pci9111_is_fifo_full()) {
942 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
943 comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
944 pci9111_interrupt_clear();
945 pci9111_ai_cancel(dev, subdevice);
946 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
947 comedi_event(dev, subdevice);
948
949 return IRQ_HANDLED;
950 }
951
952 if (pci9111_is_fifo_half_full()) {
953 unsigned int num_samples;
954 unsigned int bytes_written = 0;
955
956#ifdef INTERRUPT_DEBUG
957 printk(PCI9111_DRIVER_NAME ": fifo is half full\n");
958#endif
959
960 num_samples =
961 PCI9111_FIFO_HALF_SIZE >
962 dev_private->stop_counter
963 && !dev_private->
964 stop_is_none ? dev_private->stop_counter :
965 PCI9111_FIFO_HALF_SIZE;
966 insw(PCI9111_IO_BASE + PCI9111_REGISTER_AD_FIFO_VALUE,
967 dev_private->ai_bounce_buffer, num_samples);
968
969 if (dev_private->scan_delay < 1) {
970 bytes_written =
971 cfc_write_array_to_buffer(subdevice,
972 dev_private->
973 ai_bounce_buffer,
974 num_samples *
975 sizeof(short));
976 } else {
977 int position = 0;
978 int to_read;
979
980 while (position < num_samples) {
981 if (dev_private->chunk_counter <
982 dev_private->chanlist_len) {
983 to_read =
984 dev_private->chanlist_len -
985 dev_private->chunk_counter;
986
987 if (to_read >
988 num_samples - position)
989 to_read =
990 num_samples -
991 position;
992
993 bytes_written +=
994 cfc_write_array_to_buffer
995 (subdevice,
996 dev_private->ai_bounce_buffer
997 + position,
998 to_read * sizeof(short));
999 } else {
1000 to_read =
1001 dev_private->chunk_num_samples
1002 -
1003 dev_private->chunk_counter;
1004 if (to_read >
1005 num_samples - position)
1006 to_read =
1007 num_samples -
1008 position;
1009
1010 bytes_written +=
1011 sizeof(short) * to_read;
1012 }
1013
1014 position += to_read;
1015 dev_private->chunk_counter += to_read;
1016
1017 if (dev_private->chunk_counter >=
1018 dev_private->chunk_num_samples)
1019 dev_private->chunk_counter = 0;
1020 }
1021 }
1022
1023 dev_private->stop_counter -=
1024 bytes_written / sizeof(short);
1025 }
1026 }
1027
1028 if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
1029 async->events |= COMEDI_CB_EOA;
1030 pci9111_ai_cancel(dev, subdevice);
1031 }
1032
1033
1034
1035
1036 pci9111_interrupt_clear();
1037
1038 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
1039
1040 comedi_event(dev, subdevice);
1041
1042 return IRQ_HANDLED;
1043}
1044
1045
1046
1047
1048
1049
1050
1051#undef AI_INSN_DEBUG
1052
1053static int pci9111_ai_insn_read(struct comedi_device *dev,
1054 struct comedi_subdevice *subdevice,
1055 struct comedi_insn *insn, unsigned int *data)
1056{
1057 int resolution =
1058 ((struct pci9111_board *)dev->board_ptr)->ai_resolution;
1059
1060 int timeout, i;
1061
1062#ifdef AI_INSN_DEBUG
1063 printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n",
1064 CR_CHAN((&insn->chanspec)[0]),
1065 CR_RANGE((&insn->chanspec)[0]), insn->n);
1066#endif
1067
1068 pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0]));
1069
1070 if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0])) {
1071 pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0]));
1072 }
1073
1074 pci9111_fifo_reset();
1075
1076 for (i = 0; i < insn->n; i++) {
1077 pci9111_software_trigger();
1078
1079 timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
1080
1081 while (timeout--) {
1082 if (!pci9111_is_fifo_empty())
1083 goto conversion_done;
1084 }
1085
1086 comedi_error(dev, "A/D read timeout");
1087 data[i] = 0;
1088 pci9111_fifo_reset();
1089 return -ETIME;
1090
1091conversion_done:
1092
1093 if (resolution == PCI9111_HR_AI_RESOLUTION) {
1094 data[i] = pci9111_hr_ai_get_data();
1095 } else {
1096 data[i] = pci9111_ai_get_data();
1097 }
1098 }
1099
1100#ifdef AI_INSN_DEBUG
1101 printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n",
1102 pci9111_ai_channel_get(),
1103 pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get());
1104#endif
1105
1106 return i;
1107}
1108
1109
1110
1111static int
1112pci9111_ao_insn_write(struct comedi_device *dev,
1113 struct comedi_subdevice *s, struct comedi_insn *insn,
1114 unsigned int *data)
1115{
1116 int i;
1117
1118 for (i = 0; i < insn->n; i++) {
1119 pci9111_ao_set_data(data[i]);
1120 dev_private->ao_readback = data[i];
1121 }
1122
1123 return i;
1124}
1125
1126
1127
1128static int pci9111_ao_insn_read(struct comedi_device *dev,
1129 struct comedi_subdevice *s,
1130 struct comedi_insn *insn, unsigned int *data)
1131{
1132 int i;
1133
1134 for (i = 0; i < insn->n; i++) {
1135 data[i] = dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK;
1136 }
1137
1138 return i;
1139}
1140
1141
1142
1143
1144
1145
1146
1147static int pci9111_di_insn_bits(struct comedi_device *dev,
1148 struct comedi_subdevice *subdevice,
1149 struct comedi_insn *insn, unsigned int *data)
1150{
1151 unsigned int bits;
1152
1153 bits = pci9111_di_get_bits();
1154 data[1] = bits;
1155
1156 return 2;
1157}
1158
1159
1160
1161static int pci9111_do_insn_bits(struct comedi_device *dev,
1162 struct comedi_subdevice *subdevice,
1163 struct comedi_insn *insn, unsigned int *data)
1164{
1165 unsigned int bits;
1166
1167
1168
1169
1170
1171 data[0] &= PCI9111_DO_MASK;
1172
1173 bits = subdevice->state;
1174 bits &= ~data[0];
1175 bits |= data[0] & data[1];
1176 subdevice->state = bits;
1177
1178 pci9111_do_set_bits(bits);
1179
1180 data[1] = bits;
1181
1182 return 2;
1183}
1184
1185
1186
1187
1188
1189
1190
1191static int pci9111_reset(struct comedi_device *dev)
1192{
1193
1194
1195 plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true,
1196 true, false);
1197
1198 pci9111_trigger_source_set(dev, software);
1199 pci9111_pretrigger_set(dev, false);
1200 pci9111_autoscan_set(dev, false);
1201
1202
1203
1204 dev_private->timer_divisor_1 = 0;
1205 dev_private->timer_divisor_2 = 0;
1206
1207 pci9111_timer_set(dev);
1208
1209 return 0;
1210}
1211
1212
1213
1214
1215
1216static int pci9111_attach(struct comedi_device *dev,
1217 struct comedi_devconfig *it)
1218{
1219 struct comedi_subdevice *subdevice;
1220 unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
1221 struct pci_dev *pci_device;
1222 int error, i;
1223 const struct pci9111_board *board;
1224
1225 if (alloc_private(dev, sizeof(struct pci9111_private_data)) < 0) {
1226 return -ENOMEM;
1227 }
1228
1229
1230 printk("comedi%d: " PCI9111_DRIVER_NAME " driver\n", dev->minor);
1231
1232 for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
1233 pci_device != NULL;
1234 pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
1235 if (pci_device->vendor == PCI_VENDOR_ID_ADLINK) {
1236 for (i = 0; i < pci9111_board_nbr; i++) {
1237 if (pci9111_boards[i].device_id ==
1238 pci_device->device) {
1239
1240 if ((it->options[0] != 0)
1241 || (it->options[1] != 0)) {
1242
1243 if (pci_device->bus->number !=
1244 it->options[0]
1245 ||
1246 PCI_SLOT(pci_device->devfn)
1247 != it->options[1]) {
1248 continue;
1249 }
1250 }
1251
1252 dev->board_ptr = pci9111_boards + i;
1253 board =
1254 (struct pci9111_board *)
1255 dev->board_ptr;
1256 dev_private->pci_device = pci_device;
1257 goto found;
1258 }
1259 }
1260 }
1261 }
1262
1263 printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
1264 dev->minor, it->options[0], it->options[1]);
1265 return -EIO;
1266
1267found:
1268
1269 printk("comedi%d: found %s (b:s:f=%d:%d:%d) , irq=%d\n",
1270 dev->minor,
1271 pci9111_boards[i].name,
1272 pci_device->bus->number,
1273 PCI_SLOT(pci_device->devfn),
1274 PCI_FUNC(pci_device->devfn), pci_device->irq);
1275
1276
1277
1278 switch (board->device_id) {
1279 };
1280
1281
1282
1283 lcr_io_base = pci_resource_start(pci_device, 1);
1284 lcr_io_range = pci_resource_len(pci_device, 1);
1285
1286 printk
1287 ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n",
1288 dev->minor, lcr_io_base, lcr_io_range);
1289
1290
1291 if (comedi_pci_enable(pci_device, PCI9111_DRIVER_NAME) < 0) {
1292 printk
1293 ("comedi%d: Failed to enable PCI device and request regions\n",
1294 dev->minor);
1295 return -EIO;
1296 }
1297
1298
1299 io_base = pci_resource_start(pci_device, 2);
1300 io_range = pci_resource_len(pci_device, 2);
1301
1302 printk("comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n",
1303 dev->minor, io_base, io_range);
1304
1305 dev->iobase = io_base;
1306 dev->board_name = board->name;
1307 dev_private->io_range = io_range;
1308 dev_private->is_valid = 0;
1309 dev_private->lcr_io_base = lcr_io_base;
1310 dev_private->lcr_io_range = lcr_io_range;
1311
1312 pci9111_reset(dev);
1313
1314
1315
1316 dev->irq = 0;
1317 if (pci_device->irq > 0) {
1318 if (request_irq(pci_device->irq, pci9111_interrupt,
1319 IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) {
1320 printk("comedi%d: unable to allocate irq %u\n",
1321 dev->minor, pci_device->irq);
1322 return -EINVAL;
1323 }
1324 }
1325 dev->irq = pci_device->irq;
1326
1327
1328
1329 error = alloc_subdevices(dev, 4);
1330 if (error < 0)
1331 return error;
1332
1333 subdevice = dev->subdevices + 0;
1334 dev->read_subdev = subdevice;
1335
1336 subdevice->type = COMEDI_SUBD_AI;
1337 subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
1338
1339
1340
1341
1342
1343 subdevice->n_chan = board->ai_channel_nbr;
1344 subdevice->maxdata = board->ai_resolution_mask;
1345 subdevice->len_chanlist = board->ai_channel_nbr;
1346 subdevice->range_table = board->ai_range_list;
1347 subdevice->cancel = pci9111_ai_cancel;
1348 subdevice->insn_read = pci9111_ai_insn_read;
1349 subdevice->do_cmdtest = pci9111_ai_do_cmd_test;
1350 subdevice->do_cmd = pci9111_ai_do_cmd;
1351 subdevice->munge = pci9111_ai_munge;
1352
1353 subdevice = dev->subdevices + 1;
1354 subdevice->type = COMEDI_SUBD_AO;
1355 subdevice->subdev_flags = SDF_WRITABLE | SDF_COMMON;
1356 subdevice->n_chan = board->ao_channel_nbr;
1357 subdevice->maxdata = board->ao_resolution_mask;
1358 subdevice->len_chanlist = board->ao_channel_nbr;
1359 subdevice->range_table = board->ao_range_list;
1360 subdevice->insn_write = pci9111_ao_insn_write;
1361 subdevice->insn_read = pci9111_ao_insn_read;
1362
1363 subdevice = dev->subdevices + 2;
1364 subdevice->type = COMEDI_SUBD_DI;
1365 subdevice->subdev_flags = SDF_READABLE;
1366 subdevice->n_chan = PCI9111_DI_CHANNEL_NBR;
1367 subdevice->maxdata = 1;
1368 subdevice->range_table = &range_digital;
1369 subdevice->insn_bits = pci9111_di_insn_bits;
1370
1371 subdevice = dev->subdevices + 3;
1372 subdevice->type = COMEDI_SUBD_DO;
1373 subdevice->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1374 subdevice->n_chan = PCI9111_DO_CHANNEL_NBR;
1375 subdevice->maxdata = 1;
1376 subdevice->range_table = &range_digital;
1377 subdevice->insn_bits = pci9111_do_insn_bits;
1378
1379 dev_private->is_valid = 1;
1380
1381 return 0;
1382}
1383
1384
1385
1386static int pci9111_detach(struct comedi_device *dev)
1387{
1388
1389
1390 if (dev->private != 0) {
1391 if (dev_private->is_valid)
1392 pci9111_reset(dev);
1393
1394 }
1395
1396
1397 if (dev->irq != 0) {
1398 free_irq(dev->irq, dev);
1399 }
1400
1401 if (dev_private != 0 && dev_private->pci_device != 0) {
1402 if (dev->iobase) {
1403 comedi_pci_disable(dev_private->pci_device);
1404 }
1405 pci_dev_put(dev_private->pci_device);
1406 }
1407
1408 return 0;
1409}
1410