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#include "../comedidev.h"
45#include <linux/ioport.h>
46#include <asm/byteorder.h>
47
48#define S526_SIZE 64
49
50#define S526_START_AI_CONV 0
51#define S526_AI_READ 0
52
53
54#define S526_IOSIZE 0x40
55#define S526_NUM_PORTS 27
56
57
58#define REG_TCR 0x00
59#define REG_WDC 0x02
60#define REG_DAC 0x04
61#define REG_ADC 0x06
62#define REG_ADD 0x08
63#define REG_DIO 0x0A
64#define REG_IER 0x0C
65#define REG_ISR 0x0E
66#define REG_MSC 0x10
67#define REG_C0L 0x12
68#define REG_C0H 0x14
69#define REG_C0M 0x16
70#define REG_C0C 0x18
71#define REG_C1L 0x1A
72#define REG_C1H 0x1C
73#define REG_C1M 0x1E
74#define REG_C1C 0x20
75#define REG_C2L 0x22
76#define REG_C2H 0x24
77#define REG_C2M 0x26
78#define REG_C2C 0x28
79#define REG_C3L 0x2A
80#define REG_C3H 0x2C
81#define REG_C3M 0x2E
82#define REG_C3C 0x30
83#define REG_EED 0x32
84#define REG_EEC 0x34
85
86static const int s526_ports[] = {
87 REG_TCR,
88 REG_WDC,
89 REG_DAC,
90 REG_ADC,
91 REG_ADD,
92 REG_DIO,
93 REG_IER,
94 REG_ISR,
95 REG_MSC,
96 REG_C0L,
97 REG_C0H,
98 REG_C0M,
99 REG_C0C,
100 REG_C1L,
101 REG_C1H,
102 REG_C1M,
103 REG_C1C,
104 REG_C2L,
105 REG_C2H,
106 REG_C2M,
107 REG_C2C,
108 REG_C3L,
109 REG_C3H,
110 REG_C3M,
111 REG_C3C,
112 REG_EED,
113 REG_EEC
114};
115
116struct counter_mode_register_t {
117#if defined(__LITTLE_ENDIAN_BITFIELD)
118 unsigned short coutSource:1;
119 unsigned short coutPolarity:1;
120 unsigned short autoLoadResetRcap:3;
121 unsigned short hwCtEnableSource:2;
122 unsigned short ctEnableCtrl:2;
123 unsigned short clockSource:2;
124 unsigned short countDir:1;
125 unsigned short countDirCtrl:1;
126 unsigned short outputRegLatchCtrl:1;
127 unsigned short preloadRegSel:1;
128 unsigned short reserved:1;
129 #elif defined(__BIG_ENDIAN_BITFIELD)
130 unsigned short reserved:1;
131 unsigned short preloadRegSel:1;
132 unsigned short outputRegLatchCtrl:1;
133 unsigned short countDirCtrl:1;
134 unsigned short countDir:1;
135 unsigned short clockSource:2;
136 unsigned short ctEnableCtrl:2;
137 unsigned short hwCtEnableSource:2;
138 unsigned short autoLoadResetRcap:3;
139 unsigned short coutPolarity:1;
140 unsigned short coutSource:1;
141#else
142#error Unknown bit field order
143#endif
144};
145
146union cmReg {
147 struct counter_mode_register_t reg;
148 unsigned short value;
149};
150
151#define MAX_GPCT_CONFIG_DATA 6
152
153
154
155enum S526_GPCT_APP_CLASS {
156 CountingAndTimeMeasurement,
157 SinglePulseGeneration,
158 PulseTrainGeneration,
159 PositionMeasurement,
160 Miscellaneous
161};
162
163
164
165
166struct s526GPCTConfig {
167 enum S526_GPCT_APP_CLASS app;
168 int data[MAX_GPCT_CONFIG_DATA];
169};
170
171
172
173
174
175
176struct s526_board {
177 const char *name;
178 int gpct_chans;
179 int gpct_bits;
180 int ad_chans;
181 int ad_bits;
182 int da_chans;
183 int da_bits;
184 int have_dio;
185};
186
187static const struct s526_board s526_boards[] = {
188 {
189 .name = "s526",
190 .gpct_chans = 4,
191 .gpct_bits = 24,
192 .ad_chans = 8,
193 .ad_bits = 16,
194 .da_chans = 4,
195 .da_bits = 16,
196 .have_dio = 1,
197 }
198};
199
200#define ADDR_REG(reg) (dev->iobase + (reg))
201#define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8)
202
203
204
205
206#define thisboard ((const struct s526_board *)dev->board_ptr)
207
208
209
210
211
212
213struct s526_private {
214
215 int data;
216
217
218 struct pci_dev *pci_dev;
219
220
221 unsigned int ao_readback[2];
222
223 struct s526GPCTConfig s526_gpct_config[4];
224 unsigned short s526_ai_config;
225};
226
227
228
229
230
231#define devpriv ((struct s526_private *)dev->private)
232
233static int s526_gpct_rinsn(struct comedi_device *dev,
234 struct comedi_subdevice *s, struct comedi_insn *insn,
235 unsigned int *data)
236{
237 int i;
238 int counter_channel = CR_CHAN(insn->chanspec);
239 unsigned short datalow;
240 unsigned short datahigh;
241
242
243 if (insn->n <= 0) {
244 printk(KERN_ERR "s526: INSN_READ: n should be > 0\n");
245 return -EINVAL;
246 }
247
248 for (i = 0; i < insn->n; i++) {
249 datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel));
250 datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel));
251 data[i] = (int)(datahigh & 0x00FF);
252 data[i] = (data[i] << 16) | (datalow & 0xFFFF);
253
254
255 }
256 return i;
257}
258
259static int s526_gpct_insn_config(struct comedi_device *dev,
260 struct comedi_subdevice *s,
261 struct comedi_insn *insn, unsigned int *data)
262{
263 int subdev_channel = CR_CHAN(insn->chanspec);
264 int i;
265 short value;
266 union cmReg cmReg;
267
268
269
270
271 for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) {
272 devpriv->s526_gpct_config[subdev_channel].data[i] =
273 insn->data[i];
274
275 }
276
277
278
279 switch (insn->data[0]) {
280 case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
281
282
283
284
285
286
287 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
288 devpriv->s526_gpct_config[subdev_channel].app =
289 PositionMeasurement;
290
291#if 0
292
293
294 cmReg.reg.coutSource = 0;
295 cmReg.reg.coutPolarity = 1;
296 cmReg.reg.autoLoadResetRcap = 0;
297 cmReg.reg.hwCtEnableSource = 3;
298 cmReg.reg.ctEnableCtrl = 2;
299 cmReg.reg.clockSource = 2;
300 cmReg.reg.countDir = 1;
301 cmReg.reg.countDirCtrl = 1;
302 cmReg.reg.outputRegLatchCtrl = 0;
303 cmReg.reg.preloadRegSel = 0;
304 cmReg.reg.reserved = 0;
305
306 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
307
308 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
309 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
310
311
312 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
313
314 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
315
316
317 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
318
319#endif
320
321#if 1
322
323 cmReg.value = insn->data[1] & 0xFFFF;
324
325
326 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
327
328
329 if (cmReg.reg.autoLoadResetRcap == 0) {
330
331 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
332
333
334
335 }
336#else
337
338 cmReg.reg.countDirCtrl = 0;
339
340
341 if (insn->data[1] == GPCT_X2)
342 cmReg.reg.clockSource = 1;
343 else if (insn->data[1] == GPCT_X4)
344 cmReg.reg.clockSource = 2;
345 else
346 cmReg.reg.clockSource = 0;
347
348
349
350
351
352
353
354
355 if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX)
356
357 cmReg.reg.autoLoadResetRcap = 4;
358
359
360 cmReg.value = (short)(insn->data[1] & 0xFFFF);
361 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
362
363
364 value = (short)((insn->data[2] >> 16) & 0xFFFF);
365 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
366
367
368 value = (short)(insn->data[2] & 0xFFFF);
369 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
370
371
372 if (insn->data[3] != 0) {
373 value = (short)(insn->data[3] & 0xFFFF);
374 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
375 }
376
377 if (cmReg.reg.autoLoadResetRcap == 0) {
378
379 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
380
381 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
382 }
383#endif
384 break;
385
386 case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
387
388
389
390
391
392
393
394 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n");
395 devpriv->s526_gpct_config[subdev_channel].app =
396 SinglePulseGeneration;
397
398
399 cmReg.value = (short)(insn->data[1] & 0xFFFF);
400 cmReg.reg.preloadRegSel = 0;
401 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
402
403
404 value = (short)((insn->data[2] >> 16) & 0xFFFF);
405 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
406
407
408 value = (short)(insn->data[2] & 0xFFFF);
409 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
410
411
412 cmReg.value = (short)(insn->data[1] & 0xFFFF);
413 cmReg.reg.preloadRegSel = 1;
414 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
415
416
417 value = (short)((insn->data[3] >> 16) & 0xFFFF);
418 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
419
420
421 value = (short)(insn->data[3] & 0xFFFF);
422 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
423
424
425 if (insn->data[4] != 0) {
426 value = (short)(insn->data[4] & 0xFFFF);
427 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
428 }
429 break;
430
431 case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
432
433
434
435
436
437
438
439 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n");
440 devpriv->s526_gpct_config[subdev_channel].app =
441 PulseTrainGeneration;
442
443
444 cmReg.value = (short)(insn->data[1] & 0xFFFF);
445 cmReg.reg.preloadRegSel = 0;
446 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
447
448
449 value = (short)((insn->data[2] >> 16) & 0xFFFF);
450 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
451
452
453 value = (short)(insn->data[2] & 0xFFFF);
454 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
455
456
457 cmReg.value = (short)(insn->data[1] & 0xFFFF);
458 cmReg.reg.preloadRegSel = 1;
459 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
460
461
462 value = (short)((insn->data[3] >> 16) & 0xFFFF);
463 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
464
465
466 value = (short)(insn->data[3] & 0xFFFF);
467 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
468
469
470 if (insn->data[4] != 0) {
471 value = (short)(insn->data[4] & 0xFFFF);
472 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
473 }
474 break;
475
476 default:
477 printk(KERN_ERR "s526: unsupported GPCT_insn_config\n");
478 return -EINVAL;
479 break;
480 }
481
482 return insn->n;
483}
484
485static int s526_gpct_winsn(struct comedi_device *dev,
486 struct comedi_subdevice *s, struct comedi_insn *insn,
487 unsigned int *data)
488{
489 int subdev_channel = CR_CHAN(insn->chanspec);
490 short value;
491 union cmReg cmReg;
492
493 printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n",
494 subdev_channel);
495 cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
496 printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value);
497
498 switch (devpriv->s526_gpct_config[subdev_channel].app) {
499 case PositionMeasurement:
500 printk(KERN_INFO "S526: INSN_WRITE: PM\n");
501 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
502 subdev_channel));
503 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
504 break;
505
506 case SinglePulseGeneration:
507 printk(KERN_INFO "S526: INSN_WRITE: SPG\n");
508 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
509 subdev_channel));
510 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
511 break;
512
513 case PulseTrainGeneration:
514
515
516
517
518
519
520 printk(KERN_INFO "S526: INSN_WRITE: PTG\n");
521 if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) {
522 (devpriv->s526_gpct_config[subdev_channel]).data[0] =
523 insn->data[0];
524 (devpriv->s526_gpct_config[subdev_channel]).data[1] =
525 insn->data[1];
526 } else {
527 printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
528 insn->data[0], insn->data[1]);
529 return -EINVAL;
530 }
531
532 value = (short)((*data >> 16) & 0xFFFF);
533 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
534 value = (short)(*data & 0xFFFF);
535 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
536 break;
537 default:
538 printk
539 ("s526: INSN_WRITE: Functionality %d not implemented yet\n",
540 devpriv->s526_gpct_config[subdev_channel].app);
541 return -EINVAL;
542 break;
543 }
544
545 return insn->n;
546}
547
548#define ISR_ADC_DONE 0x4
549static int s526_ai_insn_config(struct comedi_device *dev,
550 struct comedi_subdevice *s,
551 struct comedi_insn *insn, unsigned int *data)
552{
553 int result = -EINVAL;
554
555 if (insn->n < 1)
556 return result;
557
558 result = insn->n;
559
560
561
562
563
564
565
566
567
568 outw(ISR_ADC_DONE, ADDR_REG(REG_IER));
569
570 devpriv->s526_ai_config = (data[0] & 0x3FF) << 5;
571 if (data[1] > 0)
572 devpriv->s526_ai_config |= 0x8000;
573
574 devpriv->s526_ai_config |= 0x0001;
575
576 return result;
577}
578
579
580
581
582
583static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
584 struct comedi_insn *insn, unsigned int *data)
585{
586 int n, i;
587 int chan = CR_CHAN(insn->chanspec);
588 unsigned short value;
589 unsigned int d;
590 unsigned int status;
591
592
593
594 value = (devpriv->s526_ai_config & 0x8000) |
595 ((1 << 5) << chan) | (chan << 1) | 0x0001;
596
597
598 for (n = 0; n < insn->n; n++) {
599
600 outw(value, ADDR_REG(REG_ADC));
601
602
603
604#define TIMEOUT 100
605
606 for (i = 0; i < TIMEOUT; i++) {
607 status = inw(ADDR_REG(REG_ISR));
608 if (status & ISR_ADC_DONE) {
609 outw(ISR_ADC_DONE, ADDR_REG(REG_ISR));
610 break;
611 }
612 }
613 if (i == TIMEOUT) {
614
615
616 printk(KERN_ERR "s526: ADC(0x%04x) timeout\n",
617 inw(ADDR_REG(REG_ISR)));
618 return -ETIMEDOUT;
619 }
620
621
622 d = inw(ADDR_REG(REG_ADD));
623
624
625
626 data[n] = d ^ 0x8000;
627 }
628
629
630 return n;
631}
632
633static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
634 struct comedi_insn *insn, unsigned int *data)
635{
636 int i;
637 int chan = CR_CHAN(insn->chanspec);
638 unsigned short val;
639
640
641 val = chan << 1;
642
643 outw(val, ADDR_REG(REG_DAC));
644
645
646
647 for (i = 0; i < insn->n; i++) {
648
649
650
651
652
653 outw(data[i], ADDR_REG(REG_ADD));
654 devpriv->ao_readback[chan] = data[i];
655
656 outw(val + 1, ADDR_REG(REG_DAC));
657 }
658
659
660 return i;
661}
662
663
664
665static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
666 struct comedi_insn *insn, unsigned int *data)
667{
668 int i;
669 int chan = CR_CHAN(insn->chanspec);
670
671 for (i = 0; i < insn->n; i++)
672 data[i] = devpriv->ao_readback[chan];
673
674 return i;
675}
676
677
678
679
680
681
682static int s526_dio_insn_bits(struct comedi_device *dev,
683 struct comedi_subdevice *s,
684 struct comedi_insn *insn, unsigned int *data)
685{
686 if (insn->n != 2)
687 return -EINVAL;
688
689
690
691 if (data[0]) {
692 s->state &= ~data[0];
693 s->state |= data[0] & data[1];
694
695 outw(s->state, ADDR_REG(REG_DIO));
696 }
697
698
699
700 data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF;
701
702
703
704
705 return 2;
706}
707
708static int s526_dio_insn_config(struct comedi_device *dev,
709 struct comedi_subdevice *s,
710 struct comedi_insn *insn, unsigned int *data)
711{
712 int chan = CR_CHAN(insn->chanspec);
713 int group, mask;
714
715 printk(KERN_INFO "S526 DIO insn_config\n");
716
717
718
719
720
721
722 group = chan >> 2;
723 mask = 0xF << (group << 2);
724 switch (data[0]) {
725 case INSN_CONFIG_DIO_OUTPUT:
726
727 s->state |= 1 << (group + 10);
728 s->io_bits |= mask;
729 break;
730 case INSN_CONFIG_DIO_INPUT:
731 s->state &= ~(1 << (group + 10));
732 s->io_bits &= ~mask;
733 break;
734 case INSN_CONFIG_DIO_QUERY:
735 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
736 return insn->n;
737 default:
738 return -EINVAL;
739 }
740 outw(s->state, ADDR_REG(REG_DIO));
741
742 return 1;
743}
744
745static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
746{
747 struct comedi_subdevice *s;
748 int iobase;
749 int i, n;
750
751
752 union cmReg cmReg;
753
754 printk(KERN_INFO "comedi%d: s526: ", dev->minor);
755
756 iobase = it->options[0];
757 if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
758 comedi_error(dev, "I/O port conflict");
759 return -EIO;
760 }
761 dev->iobase = iobase;
762
763 printk("iobase=0x%lx\n", dev->iobase);
764
765
766
767
768
769
770
771
772
773
774
775
776 dev->board_ptr = &s526_boards[0];
777
778 dev->board_name = thisboard->name;
779
780
781
782
783
784 if (alloc_private(dev, sizeof(struct s526_private)) < 0)
785 return -ENOMEM;
786
787
788
789
790
791 dev->n_subdevices = 4;
792 if (alloc_subdevices(dev, dev->n_subdevices) < 0)
793 return -ENOMEM;
794
795 s = dev->subdevices + 0;
796
797 s->type = COMEDI_SUBD_COUNTER;
798 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
799
800 s->n_chan = thisboard->gpct_chans;
801 s->maxdata = 0x00ffffff;
802 s->insn_read = s526_gpct_rinsn;
803 s->insn_config = s526_gpct_insn_config;
804 s->insn_write = s526_gpct_winsn;
805
806
807
808
809
810
811
812
813 s = dev->subdevices + 1;
814
815
816 s->type = COMEDI_SUBD_AI;
817
818 s->subdev_flags = SDF_READABLE | SDF_DIFF;
819
820
821 s->n_chan = 10;
822 s->maxdata = 0xffff;
823 s->range_table = &range_bipolar10;
824 s->len_chanlist = 16;
825
826 s->insn_read = s526_ai_rinsn;
827 s->insn_config = s526_ai_insn_config;
828
829 s = dev->subdevices + 2;
830
831 s->type = COMEDI_SUBD_AO;
832 s->subdev_flags = SDF_WRITABLE;
833 s->n_chan = 4;
834 s->maxdata = 0xffff;
835 s->range_table = &range_bipolar10;
836 s->insn_write = s526_ao_winsn;
837 s->insn_read = s526_ao_rinsn;
838
839 s = dev->subdevices + 3;
840
841 if (thisboard->have_dio) {
842 s->type = COMEDI_SUBD_DIO;
843 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
844 s->n_chan = 8;
845 s->maxdata = 1;
846 s->range_table = &range_digital;
847 s->insn_bits = s526_dio_insn_bits;
848 s->insn_config = s526_dio_insn_config;
849 } else {
850 s->type = COMEDI_SUBD_UNUSED;
851 }
852
853 printk(KERN_INFO "attached\n");
854
855 return 1;
856
857#if 0
858
859
860 cmReg.reg.coutSource = 0;
861 cmReg.reg.coutPolarity = 1;
862 cmReg.reg.autoLoadResetRcap = 1;
863 cmReg.reg.hwCtEnableSource = 3;
864 cmReg.reg.ctEnableCtrl = 2;
865 cmReg.reg.clockSource = 2;
866 cmReg.reg.countDir = 1;
867 cmReg.reg.countDirCtrl = 1;
868 cmReg.reg.outputRegLatchCtrl = 0;
869 cmReg.reg.preloadRegSel = 0;
870 cmReg.reg.reserved = 0;
871
872 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
873
874 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
875 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
876
877
878 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
879
880 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
881
882 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
883
884#else
885
886
887 cmReg.reg.coutSource = 0;
888 cmReg.reg.coutPolarity = 0;
889 cmReg.reg.autoLoadResetRcap = 0;
890 cmReg.reg.hwCtEnableSource = 2;
891 cmReg.reg.ctEnableCtrl = 1;
892 cmReg.reg.clockSource = 3;
893 cmReg.reg.countDir = 0;
894 cmReg.reg.countDirCtrl = 0;
895 cmReg.reg.outputRegLatchCtrl = 0;
896 cmReg.reg.preloadRegSel = 0;
897 cmReg.reg.reserved = 0;
898
899 n = 0;
900 printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
901 cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
902 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
903 udelay(1000);
904 printk(KERN_INFO "Read back mode reg=0x%04x\n",
905 inw(ADDR_CHAN_REG(REG_C0M, n)));
906
907
908
909
910
911
912
913
914
915
916
917
918
919 if (cmReg.reg.autoLoadResetRcap == 0) {
920
921 outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
922
923 outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
924 }
925
926 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
927 udelay(1000);
928 printk(KERN_INFO "Read back mode reg=0x%04x\n",
929 inw(ADDR_CHAN_REG(REG_C0M, n)));
930
931#endif
932 printk(KERN_INFO "Current registres:\n");
933
934 for (i = 0; i < S526_NUM_PORTS; i++) {
935 printk(KERN_INFO "0x%02lx: 0x%04x\n",
936 ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
937 }
938 return 1;
939}
940
941static void s526_detach(struct comedi_device *dev)
942{
943 if (dev->iobase > 0)
944 release_region(dev->iobase, S526_IOSIZE);
945}
946
947static struct comedi_driver s526_driver = {
948 .driver_name = "s526",
949 .module = THIS_MODULE,
950 .attach = s526_attach,
951 .detach = s526_detach,
952 .board_name = &s526_boards[0].name,
953 .offset = sizeof(struct s526_board),
954 .num_names = ARRAY_SIZE(s526_boards),
955};
956module_comedi_driver(s526_driver);
957
958MODULE_AUTHOR("Comedi http://www.comedi.org");
959MODULE_DESCRIPTION("Comedi low-level driver");
960MODULE_LICENSE("GPL");
961