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