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#include <linux/interrupt.h>
77#include "../comedidev.h"
78#include "pcm_common.h"
79#include <linux/pci.h>
80
81
82#define CHANS_PER_PORT 8
83#define PORTS_PER_ASIC 6
84#define INTR_PORTS_PER_ASIC 3
85#define MAX_CHANS_PER_SUBDEV 24
86#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
87#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
88#define INTR_CHANS_PER_ASIC 24
89#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
90#define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT)
91#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
92#define SDEV_NO ((int)(s - dev->subdevices))
93#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) )
94
95#define ASIC_IOSIZE (0x0B)
96#define PCMMIO48_IOSIZE ASIC_IOSIZE
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111#define REG_PORT0 0x0
112#define REG_PORT1 0x1
113#define REG_PORT2 0x2
114#define REG_PORT3 0x3
115#define REG_PORT4 0x4
116#define REG_PORT5 0x5
117#define REG_INT_PENDING 0x6
118#define REG_PAGELOCK 0x7
119
120
121#define REG_POL0 0x8
122#define REG_POL1 0x9
123#define REG_POL2 0xA
124#define REG_ENAB0 0x8
125#define REG_ENAB1 0x9
126#define REG_ENAB2 0xA
127#define REG_INT_ID0 0x8
128#define REG_INT_ID1 0x9
129#define REG_INT_ID2 0xA
130
131#define NUM_PAGED_REGS 3
132#define NUM_PAGES 4
133#define FIRST_PAGED_REG 0x8
134#define REG_PAGE_BITOFFSET 6
135#define REG_LOCK_BITOFFSET 0
136#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
137#define REG_LOCK_MASK ~(REG_PAGE_MASK)
138#define PAGE_POL 1
139#define PAGE_ENAB 2
140#define PAGE_INT_ID 3
141
142typedef int (*comedi_insn_fn_t) (struct comedi_device *,
143 struct comedi_subdevice *,
144 struct comedi_insn *, unsigned int *);
145
146static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
147 struct comedi_insn *, unsigned int *);
148static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
149 struct comedi_insn *, unsigned int *);
150static int ao_winsn(struct comedi_device *, struct comedi_subdevice *,
151 struct comedi_insn *, unsigned int *);
152
153
154
155
156
157
158struct pcmmio_board {
159 const char *name;
160 const int dio_num_asics;
161 const int dio_num_ports;
162 const int total_iosize;
163 const int ai_bits;
164 const int ao_bits;
165 const int n_ai_chans;
166 const int n_ao_chans;
167 const struct comedi_lrange *ai_range_table, *ao_range_table;
168 comedi_insn_fn_t ai_rinsn, ao_rinsn, ao_winsn;
169};
170
171static const struct comedi_lrange ranges_ai =
172 { 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0.,
173 10.)}
174};
175
176static const struct comedi_lrange ranges_ao =
177 { 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
178 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
179};
180
181static const struct pcmmio_board pcmmio_boards[] = {
182 {
183 .name = "pcmmio",
184 .dio_num_asics = 1,
185 .dio_num_ports = 6,
186 .total_iosize = 32,
187 .ai_bits = 16,
188 .ao_bits = 16,
189 .n_ai_chans = 16,
190 .n_ao_chans = 8,
191 .ai_range_table = &ranges_ai,
192 .ao_range_table = &ranges_ao,
193 .ai_rinsn = ai_rinsn,
194 .ao_rinsn = ao_rinsn,
195 .ao_winsn = ao_winsn},
196};
197
198
199
200
201#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
202
203
204struct pcmmio_subdev_private {
205
206 union {
207
208 unsigned long iobases[PORTS_PER_SUBDEV];
209
210
211 unsigned long iobase;
212 };
213 union {
214 struct {
215
216
217 struct {
218 int asic;
219 int first_chan;
220
221 int num_asic_chans;
222
223 int asic_chan;
224
225 int enabled_mask;
226
227 int active;
228 int stop_count;
229 int continuous;
230 spinlock_t spinlock;
231 } intr;
232 } dio;
233 struct {
234 unsigned int shadow_samples[8];
235 } ao;
236 };
237};
238
239
240
241
242struct pcmmio_private {
243
244 struct {
245 unsigned char pagelock;
246 unsigned char pol[NUM_PAGED_REGS];
247 unsigned char enab[NUM_PAGED_REGS];
248 int num;
249 unsigned long iobase;
250 unsigned int irq;
251 spinlock_t spinlock;
252 } asics[MAX_ASICS];
253 struct pcmmio_subdev_private *sprivs;
254};
255
256
257
258
259
260#define devpriv ((struct pcmmio_private *)dev->private)
261#define subpriv ((struct pcmmio_subdev_private *)s->private)
262
263
264
265
266
267
268static int pcmmio_attach(struct comedi_device *dev,
269 struct comedi_devconfig *it);
270static int pcmmio_detach(struct comedi_device *dev);
271
272static struct comedi_driver driver = {
273 .driver_name = "pcmmio",
274 .module = THIS_MODULE,
275 .attach = pcmmio_attach,
276 .detach = pcmmio_detach,
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295 .board_name = &pcmmio_boards[0].name,
296 .offset = sizeof(struct pcmmio_board),
297 .num_names = ARRAY_SIZE(pcmmio_boards),
298};
299
300static int pcmmio_dio_insn_bits(struct comedi_device *dev,
301 struct comedi_subdevice *s,
302 struct comedi_insn *insn, unsigned int *data);
303static int pcmmio_dio_insn_config(struct comedi_device *dev,
304 struct comedi_subdevice *s,
305 struct comedi_insn *insn, unsigned int *data);
306
307static irqreturn_t interrupt_pcmmio(int irq, void *d);
308static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
309static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
310static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
311static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
312 struct comedi_cmd *cmd);
313
314
315static void init_asics(struct comedi_device *dev);
316static void switch_page(struct comedi_device *dev, int asic, int page);
317#ifdef notused
318static void lock_port(struct comedi_device *dev, int asic, int port);
319static void unlock_port(struct comedi_device *dev, int asic, int port);
320#endif
321
322
323
324
325
326
327
328static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
329{
330 struct comedi_subdevice *s;
331 int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
332 thisasic_chanct = 0;
333 unsigned long iobase;
334 unsigned int irq[MAX_ASICS];
335
336 iobase = it->options[0];
337 irq[0] = it->options[1];
338
339 printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
340 iobase);
341
342 dev->iobase = iobase;
343
344 if (!iobase || !request_region(iobase,
345 thisboard->total_iosize,
346 driver.driver_name)) {
347 printk("I/O port conflict\n");
348 return -EIO;
349 }
350
351
352
353
354
355 dev->board_name = thisboard->name;
356
357
358
359
360
361 if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
362 printk("cannot allocate private data structure\n");
363 return -ENOMEM;
364 }
365
366 for (asic = 0; asic < MAX_ASICS; ++asic) {
367 devpriv->asics[asic].num = asic;
368 devpriv->asics[asic].iobase =
369 dev->iobase + 16 + asic * ASIC_IOSIZE;
370 devpriv->asics[asic].irq = 0;
371
372
373 spin_lock_init(&devpriv->asics[asic].spinlock);
374 }
375
376 chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
377 n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
378 n_subdevs = n_dio_subdevs + 2;
379 devpriv->sprivs =
380 kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
381 GFP_KERNEL);
382 if (!devpriv->sprivs) {
383 printk("cannot allocate subdevice private data structures\n");
384 return -ENOMEM;
385 }
386
387
388
389
390
391
392 if (alloc_subdevices(dev, n_subdevs) < 0) {
393 printk("cannot allocate subdevice data structures\n");
394 return -ENOMEM;
395 }
396
397
398 sdev_no = 0;
399 s = dev->subdevices + sdev_no;
400 s->private = devpriv->sprivs + sdev_no;
401 s->maxdata = (1 << thisboard->ai_bits) - 1;
402 s->range_table = thisboard->ai_range_table;
403 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
404 s->type = COMEDI_SUBD_AI;
405 s->n_chan = thisboard->n_ai_chans;
406 s->len_chanlist = s->n_chan;
407 s->insn_read = thisboard->ai_rinsn;
408 subpriv->iobase = dev->iobase + 0;
409
410 outb(0, subpriv->iobase + 3);
411 outb(0, subpriv->iobase + 4 + 3);
412
413
414 ++sdev_no;
415 s = dev->subdevices + sdev_no;
416 s->private = devpriv->sprivs + sdev_no;
417 s->maxdata = (1 << thisboard->ao_bits) - 1;
418 s->range_table = thisboard->ao_range_table;
419 s->subdev_flags = SDF_READABLE;
420 s->type = COMEDI_SUBD_AO;
421 s->n_chan = thisboard->n_ao_chans;
422 s->len_chanlist = s->n_chan;
423 s->insn_read = thisboard->ao_rinsn;
424 s->insn_write = thisboard->ao_winsn;
425 subpriv->iobase = dev->iobase + 8;
426
427 outb(0, subpriv->iobase + 3);
428 outb(0, subpriv->iobase + 4 + 3);
429
430 ++sdev_no;
431 port = 0;
432 asic = 0;
433 for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
434 int byte_no;
435
436 s = dev->subdevices + sdev_no;
437 s->private = devpriv->sprivs + sdev_no;
438 s->maxdata = 1;
439 s->range_table = &range_digital;
440 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
441 s->type = COMEDI_SUBD_DIO;
442 s->insn_bits = pcmmio_dio_insn_bits;
443 s->insn_config = pcmmio_dio_insn_config;
444 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
445 subpriv->dio.intr.asic = -1;
446 subpriv->dio.intr.first_chan = -1;
447 subpriv->dio.intr.asic_chan = -1;
448 subpriv->dio.intr.num_asic_chans = -1;
449 subpriv->dio.intr.active = 0;
450 s->len_chanlist = 1;
451
452
453
454 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
455 if (port >= PORTS_PER_ASIC) {
456 port = 0;
457 ++asic;
458 thisasic_chanct = 0;
459 }
460 subpriv->iobases[byte_no] =
461 devpriv->asics[asic].iobase + port;
462
463 if (thisasic_chanct <
464 CHANS_PER_PORT * INTR_PORTS_PER_ASIC
465 && subpriv->dio.intr.asic < 0) {
466
467 subpriv->dio.intr.asic = asic;
468 subpriv->dio.intr.active = 0;
469 subpriv->dio.intr.stop_count = 0;
470 subpriv->dio.intr.first_chan = byte_no * 8;
471 subpriv->dio.intr.asic_chan = thisasic_chanct;
472 subpriv->dio.intr.num_asic_chans =
473 s->n_chan - subpriv->dio.intr.first_chan;
474 s->cancel = pcmmio_cancel;
475 s->do_cmd = pcmmio_cmd;
476 s->do_cmdtest = pcmmio_cmdtest;
477 s->len_chanlist =
478 subpriv->dio.intr.num_asic_chans;
479 }
480 thisasic_chanct += CHANS_PER_PORT;
481 }
482 spin_lock_init(&subpriv->dio.intr.spinlock);
483
484 chans_left -= s->n_chan;
485
486 if (!chans_left) {
487 asic = 0;
488 port = 0;
489 }
490
491 }
492
493 init_asics(dev);
494
495 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
496 if (irq[asic]
497 && request_irq(irq[asic], interrupt_pcmmio,
498 IRQF_SHARED, thisboard->name, dev)) {
499 int i;
500
501 for (i = asic - 1; i >= 0; --i) {
502 free_irq(irq[i], dev);
503 devpriv->asics[i].irq = irq[i] = 0;
504 }
505 irq[asic] = 0;
506 }
507 devpriv->asics[asic].irq = irq[asic];
508 }
509
510 dev->irq = irq[0];
511
512
513 if (irq[0]) {
514 printk("irq: %u ", irq[0]);
515 if (irq[1] && thisboard->dio_num_asics == 2)
516 printk("second ASIC irq: %u ", irq[1]);
517 } else {
518 printk("(IRQ mode disabled) ");
519 }
520
521 printk("attached\n");
522
523 return 1;
524}
525
526
527
528
529
530
531
532
533
534static int pcmmio_detach(struct comedi_device *dev)
535{
536 int i;
537
538 printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
539 if (dev->iobase)
540 release_region(dev->iobase, thisboard->total_iosize);
541
542 for (i = 0; i < MAX_ASICS; ++i) {
543 if (devpriv && devpriv->asics[i].irq)
544 free_irq(devpriv->asics[i].irq, dev);
545 }
546
547 if (devpriv && devpriv->sprivs)
548 kfree(devpriv->sprivs);
549
550 return 0;
551}
552
553
554
555
556
557
558static int pcmmio_dio_insn_bits(struct comedi_device *dev,
559 struct comedi_subdevice *s,
560 struct comedi_insn *insn, unsigned int *data)
561{
562 int byte_no;
563 if (insn->n != 2)
564 return -EINVAL;
565
566
567
568
569
570
571
572
573
574
575
576
577#ifdef DAMMIT_ITS_BROKEN
578
579 printk("write mask: %08x data: %08x\n", data[0], data[1]);
580#endif
581
582 s->state = 0;
583
584 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
585
586 unsigned long ioaddr = subpriv->iobases[byte_no],
587
588 offset = byte_no * 8;
589
590 unsigned char byte = 0,
591
592 write_mask_byte = (data[0] >> offset) & 0xff,
593
594 data_byte = (data[1] >> offset) & 0xff;
595
596 byte = inb(ioaddr);
597
598#ifdef DAMMIT_ITS_BROKEN
599
600 printk
601 ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
602 byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
603 offset, ioaddr, (unsigned)byte);
604#endif
605
606 if (write_mask_byte) {
607
608 byte &= ~write_mask_byte;
609 byte |= ~data_byte & write_mask_byte;
610
611 outb(byte, ioaddr);
612 }
613#ifdef DAMMIT_ITS_BROKEN
614
615 printk("data_out_byte %02x\n", (unsigned)byte);
616#endif
617
618 s->state |= ((unsigned int)byte) << offset;
619 }
620
621
622 data[1] = ~s->state;
623
624#ifdef DAMMIT_ITS_BROKEN
625
626 printk("s->state %08x data_out %08x\n", s->state, data[1]);
627#endif
628
629 return 2;
630}
631
632
633
634
635
636static int pcmmio_dio_insn_config(struct comedi_device *dev,
637 struct comedi_subdevice *s,
638 struct comedi_insn *insn, unsigned int *data)
639{
640 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
641 chan % 8;
642 unsigned long ioaddr;
643 unsigned char byte;
644
645
646 ioaddr = subpriv->iobases[byte_no];
647
648
649
650
651
652
653
654
655
656
657
658
659
660 switch (data[0]) {
661 case INSN_CONFIG_DIO_OUTPUT:
662
663
664 s->io_bits |= 1 << chan;
665 break;
666 case INSN_CONFIG_DIO_INPUT:
667
668
669 byte = inb(ioaddr);
670 byte &= ~(1 << bit_no);
671
672
673
674
675
676 outb(byte, ioaddr);
677
678
679 s->io_bits &= ~(1 << chan);
680 break;
681
682 case INSN_CONFIG_DIO_QUERY:
683
684 data[1] =
685 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
686 return insn->n;
687 break;
688
689 default:
690 return -EINVAL;
691 break;
692 }
693
694 return insn->n;
695}
696
697static void init_asics(struct comedi_device *dev)
698{
699
700 int asic;
701
702 for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
703 int port, page;
704 unsigned long baseaddr = devpriv->asics[asic].iobase;
705
706 switch_page(dev, asic, 0);
707
708
709 for (port = 0; port < PORTS_PER_ASIC; ++port)
710 outb(0, baseaddr + REG_PORT0 + port);
711
712
713 for (page = 1; page < NUM_PAGES; ++page) {
714 int reg;
715
716 switch_page(dev, asic, page);
717 for (reg = FIRST_PAGED_REG;
718 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
719 outb(0, baseaddr + reg);
720 }
721
722
723
724
725
726
727
728
729 switch_page(dev, asic, 0);
730
731 }
732}
733
734static void switch_page(struct comedi_device *dev, int asic, int page)
735{
736 if (asic < 0 || asic >= thisboard->dio_num_asics)
737 return;
738 if (page < 0 || page >= NUM_PAGES)
739 return;
740
741 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
742 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
743
744
745 outb(devpriv->asics[asic].pagelock,
746 devpriv->asics[asic].iobase + REG_PAGELOCK);
747}
748
749#ifdef notused
750static void lock_port(struct comedi_device *dev, int asic, int port)
751{
752 if (asic < 0 || asic >= thisboard->dio_num_asics)
753 return;
754 if (port < 0 || port >= PORTS_PER_ASIC)
755 return;
756
757 devpriv->asics[asic].pagelock |= 0x1 << port;
758
759 outb(devpriv->asics[asic].pagelock,
760 devpriv->asics[asic].iobase + REG_PAGELOCK);
761 return;
762}
763
764static void unlock_port(struct comedi_device *dev, int asic, int port)
765{
766 if (asic < 0 || asic >= thisboard->dio_num_asics)
767 return;
768 if (port < 0 || port >= PORTS_PER_ASIC)
769 return;
770 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
771
772 outb(devpriv->asics[asic].pagelock,
773 devpriv->asics[asic].iobase + REG_PAGELOCK);
774}
775#endif
776
777static irqreturn_t interrupt_pcmmio(int irq, void *d)
778{
779 int asic, got1 = 0;
780 struct comedi_device *dev = (struct comedi_device *)d;
781
782 for (asic = 0; asic < MAX_ASICS; ++asic) {
783 if (irq == devpriv->asics[asic].irq) {
784 unsigned long flags;
785 unsigned triggered = 0;
786 unsigned long iobase = devpriv->asics[asic].iobase;
787
788 unsigned char int_pend;
789
790 spin_lock_irqsave(&devpriv->asics[asic].spinlock,
791 flags);
792
793 int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
794
795 if (int_pend) {
796 int port;
797 for (port = 0; port < INTR_PORTS_PER_ASIC;
798 ++port) {
799 if (int_pend & (0x1 << port)) {
800 unsigned char
801 io_lines_with_edges = 0;
802 switch_page(dev, asic,
803 PAGE_INT_ID);
804 io_lines_with_edges =
805 inb(iobase +
806 REG_INT_ID0 + port);
807
808 if (io_lines_with_edges)
809
810 outb(0, iobase +
811 REG_INT_ID0 +
812 port);
813
814 triggered |=
815 io_lines_with_edges <<
816 port * 8;
817 }
818 }
819
820 ++got1;
821 }
822
823 spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
824 flags);
825
826 if (triggered) {
827 struct comedi_subdevice *s;
828
829 printk
830 ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
831 irq, asic, triggered);
832 for (s = dev->subdevices + 2;
833 s < dev->subdevices + dev->n_subdevices;
834 ++s) {
835 if (subpriv->dio.intr.asic == asic) {
836 unsigned long flags;
837 unsigned oldevents;
838
839 spin_lock_irqsave(&subpriv->dio.
840 intr.spinlock,
841 flags);
842
843 oldevents = s->async->events;
844
845 if (subpriv->dio.intr.active) {
846 unsigned mytrig =
847 ((triggered >>
848 subpriv->dio.intr.asic_chan)
849 &
850 ((0x1 << subpriv->
851 dio.intr.
852 num_asic_chans) -
853 1)) << subpriv->
854 dio.intr.first_chan;
855 if (mytrig &
856 subpriv->dio.
857 intr.enabled_mask) {
858 unsigned int val
859 = 0;
860 unsigned int n,
861 ch, len;
862
863 len =
864 s->
865 async->cmd.chanlist_len;
866 for (n = 0;
867 n < len;
868 n++) {
869 ch = CR_CHAN(s->async->cmd.chanlist[n]);
870 if (mytrig & (1U << ch)) {
871 val |= (1U << n);
872 }
873 }
874
875 if (comedi_buf_put(s->async, ((short *)&val)[0])
876 &&
877 comedi_buf_put
878 (s->async,
879 ((short *)
880 &val)[1]))
881 {
882 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
883 } else {
884
885
886 pcmmio_stop_intr
887 (dev,
888 s);
889 }
890
891
892 if (!subpriv->dio.intr.continuous) {
893
894 if (subpriv->dio.intr.stop_count > 0) {
895 subpriv->dio.intr.stop_count--;
896 if (subpriv->dio.intr.stop_count == 0) {
897 s->async->events |= COMEDI_CB_EOA;
898
899 pcmmio_stop_intr
900 (dev,
901 s);
902 }
903 }
904 }
905 }
906 }
907
908 spin_unlock_irqrestore
909 (&subpriv->dio.intr.
910 spinlock, flags);
911
912 if (oldevents !=
913 s->async->events) {
914 comedi_event(dev, s);
915 }
916
917 }
918
919 }
920 }
921
922 }
923 }
924 if (!got1)
925 return IRQ_NONE;
926 return IRQ_HANDLED;
927}
928
929static void pcmmio_stop_intr(struct comedi_device *dev,
930 struct comedi_subdevice *s)
931{
932 int nports, firstport, asic, port;
933
934 asic = subpriv->dio.intr.asic;
935 if (asic < 0)
936 return;
937
938 subpriv->dio.intr.enabled_mask = 0;
939 subpriv->dio.intr.active = 0;
940 s->async->inttrig = 0;
941 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
942 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
943 switch_page(dev, asic, PAGE_ENAB);
944 for (port = firstport; port < firstport + nports; ++port) {
945
946 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
947 }
948}
949
950static int pcmmio_start_intr(struct comedi_device *dev,
951 struct comedi_subdevice *s)
952{
953 if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
954
955 s->async->events |= COMEDI_CB_EOA;
956 subpriv->dio.intr.active = 0;
957 return 1;
958 } else {
959 unsigned bits = 0, pol_bits = 0, n;
960 int nports, firstport, asic, port;
961 struct comedi_cmd *cmd = &s->async->cmd;
962
963 asic = subpriv->dio.intr.asic;
964 if (asic < 0)
965 return 1;
966
967 subpriv->dio.intr.enabled_mask = 0;
968 subpriv->dio.intr.active = 1;
969 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
970 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
971 if (cmd->chanlist) {
972 for (n = 0; n < cmd->chanlist_len; n++) {
973 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
974 pol_bits |= (CR_AREF(cmd->chanlist[n])
975 || CR_RANGE(cmd->
976 chanlist[n]) ? 1U : 0U)
977 << CR_CHAN(cmd->chanlist[n]);
978 }
979 }
980 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
981 1) << subpriv->dio.intr.first_chan;
982 subpriv->dio.intr.enabled_mask = bits;
983
984 {
985 unsigned char b;
986
987 outb(1 << 4, dev->iobase + 3);
988
989 b = dev->irq & ((1 << 4) - 1);
990 outb(b, dev->iobase + 2);
991
992 }
993
994 switch_page(dev, asic, PAGE_ENAB);
995 for (port = firstport; port < firstport + nports; ++port) {
996 unsigned enab =
997 bits >> (subpriv->dio.intr.first_chan + (port -
998 firstport)
999 * 8) & 0xff, pol =
1000 pol_bits >> (subpriv->dio.intr.first_chan +
1001 (port - firstport) * 8) & 0xff;
1002
1003 outb(enab,
1004 devpriv->asics[asic].iobase + REG_ENAB0 + port);
1005 switch_page(dev, asic, PAGE_POL);
1006 outb(pol,
1007 devpriv->asics[asic].iobase + REG_ENAB0 + port);
1008 }
1009 }
1010 return 0;
1011}
1012
1013static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1014{
1015 unsigned long flags;
1016
1017 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1018 if (subpriv->dio.intr.active)
1019 pcmmio_stop_intr(dev, s);
1020 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1021
1022 return 0;
1023}
1024
1025
1026
1027
1028static int
1029pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
1030 unsigned int trignum)
1031{
1032 unsigned long flags;
1033 int event = 0;
1034
1035 if (trignum != 0)
1036 return -EINVAL;
1037
1038 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1039 s->async->inttrig = 0;
1040 if (subpriv->dio.intr.active) {
1041 event = pcmmio_start_intr(dev, s);
1042 }
1043 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1044
1045 if (event) {
1046 comedi_event(dev, s);
1047 }
1048
1049 return 1;
1050}
1051
1052
1053
1054
1055static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1056{
1057 struct comedi_cmd *cmd = &s->async->cmd;
1058 unsigned long flags;
1059 int event = 0;
1060
1061 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1062 subpriv->dio.intr.active = 1;
1063
1064
1065 switch (cmd->stop_src) {
1066 case TRIG_COUNT:
1067 subpriv->dio.intr.continuous = 0;
1068 subpriv->dio.intr.stop_count = cmd->stop_arg;
1069 break;
1070 default:
1071
1072 subpriv->dio.intr.continuous = 1;
1073 subpriv->dio.intr.stop_count = 0;
1074 break;
1075 }
1076
1077
1078 switch (cmd->start_src) {
1079 case TRIG_INT:
1080 s->async->inttrig = pcmmio_inttrig_start_intr;
1081 break;
1082 default:
1083
1084 event = pcmmio_start_intr(dev, s);
1085 break;
1086 }
1087 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1088
1089 if (event) {
1090 comedi_event(dev, s);
1091 }
1092
1093 return 0;
1094}
1095
1096static int
1097pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1098 struct comedi_cmd *cmd)
1099{
1100 return comedi_pcm_cmdtest(dev, s, cmd);
1101}
1102
1103static int adc_wait_ready(unsigned long iobase)
1104{
1105 unsigned long retry = 100000;
1106 while (retry--)
1107 if (inb(iobase + 3) & 0x80)
1108 return 0;
1109 return 1;
1110}
1111
1112
1113static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1114 struct comedi_insn *insn, unsigned int *data)
1115{
1116 int n;
1117 unsigned long iobase = subpriv->iobase;
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131 for (n = 0; n < insn->n; n++) {
1132 unsigned chan = CR_CHAN(insn->chanspec), range =
1133 CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
1134 unsigned char command_byte = 0;
1135 unsigned iooffset = 0;
1136 short sample, adc_adjust = 0;
1137
1138 if (chan > 7)
1139 chan -= 8, iooffset = 4;
1140
1141 if (aref != AREF_DIFF) {
1142 aref = AREF_GROUND;
1143 command_byte |= 1 << 7;
1144 }
1145 if (range < 2)
1146 adc_adjust = 0x8000;
1147
1148 if (chan % 2) {
1149 command_byte |= 1 << 6;
1150 }
1151
1152
1153 command_byte |= ((chan / 2) & 0x3) << 4;
1154
1155
1156 command_byte |= (range & 0x3) << 2;
1157
1158
1159 outb(command_byte, iobase + iooffset + 2);
1160
1161 adc_wait_ready(iobase + iooffset);
1162
1163 outb(command_byte, iobase + iooffset + 2);
1164
1165 adc_wait_ready(iobase + iooffset);
1166
1167 sample = inb(iobase + iooffset + 0);
1168 sample |= inb(iobase + iooffset + 1) << 8;
1169 sample += adc_adjust;
1170 data[n] = sample;
1171 }
1172
1173 return n;
1174}
1175
1176static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1177 struct comedi_insn *insn, unsigned int *data)
1178{
1179 int n;
1180 for (n = 0; n < insn->n; n++) {
1181 unsigned chan = CR_CHAN(insn->chanspec);
1182 if (chan < s->n_chan)
1183 data[n] = subpriv->ao.shadow_samples[chan];
1184 }
1185 return n;
1186}
1187
1188static int wait_dac_ready(unsigned long iobase)
1189{
1190 unsigned long retry = 100000L;
1191
1192
1193
1194
1195
1196
1197
1198 while (retry--) {
1199 if (inb(iobase + 3) & 0x80)
1200 return 0;
1201
1202 }
1203 return 1;
1204}
1205
1206static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1207 struct comedi_insn *insn, unsigned int *data)
1208{
1209 int n;
1210 unsigned iobase = subpriv->iobase, iooffset = 0;
1211
1212 for (n = 0; n < insn->n; n++) {
1213 unsigned chan = CR_CHAN(insn->chanspec), range =
1214 CR_RANGE(insn->chanspec);
1215 if (chan < s->n_chan) {
1216 unsigned char command_byte = 0, range_byte =
1217 range & ((1 << 4) - 1);
1218 if (chan >= 4)
1219 chan -= 4, iooffset += 4;
1220
1221 outb(range_byte, iobase + iooffset + 0);
1222 outb(0, iobase + iooffset + 1);
1223
1224
1225 command_byte = (chan << 1) | 0x60;
1226 outb(command_byte, iobase + iooffset + 2);
1227
1228 wait_dac_ready(iobase + iooffset);
1229
1230 outb(data[n] & 0xff, iobase + iooffset + 0);
1231 outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
1232 command_byte = 0x70 | (chan << 1);
1233
1234 outb(command_byte, iobase + iooffset + 2);
1235
1236 wait_dac_ready(iobase + iooffset);
1237
1238 subpriv->ao.shadow_samples[chan] = data[n];
1239 }
1240 }
1241 return n;
1242}
1243
1244
1245
1246
1247
1248COMEDI_INITCLEANUP(driver);
1249