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
233
234
235
236
237
238
239static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it);
240static int s526_detach(struct comedi_device *dev);
241static struct comedi_driver driver_s526 = {
242 .driver_name = "s526",
243 .module = THIS_MODULE,
244 .attach = s526_attach,
245 .detach = s526_detach,
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 .board_name = &s526_boards[0].name,
265 .offset = sizeof(struct s526_board),
266 .num_names = ARRAY_SIZE(s526_boards),
267};
268
269static int s526_gpct_rinsn(struct comedi_device *dev,
270 struct comedi_subdevice *s, struct comedi_insn *insn,
271 unsigned int *data);
272static int s526_gpct_insn_config(struct comedi_device *dev,
273 struct comedi_subdevice *s,
274 struct comedi_insn *insn, unsigned int *data);
275static int s526_gpct_winsn(struct comedi_device *dev,
276 struct comedi_subdevice *s, struct comedi_insn *insn,
277 unsigned int *data);
278static int s526_ai_insn_config(struct comedi_device *dev,
279 struct comedi_subdevice *s,
280 struct comedi_insn *insn, unsigned int *data);
281static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
282 struct comedi_insn *insn, unsigned int *data);
283static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
284 struct comedi_insn *insn, unsigned int *data);
285static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
286 struct comedi_insn *insn, unsigned int *data);
287static int s526_dio_insn_bits(struct comedi_device *dev,
288 struct comedi_subdevice *s,
289 struct comedi_insn *insn, unsigned int *data);
290static int s526_dio_insn_config(struct comedi_device *dev,
291 struct comedi_subdevice *s,
292 struct comedi_insn *insn, unsigned int *data);
293
294
295
296
297
298
299
300static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
301{
302 struct comedi_subdevice *s;
303 int iobase;
304 int i, n;
305
306
307 union cmReg cmReg;
308
309 printk(KERN_INFO "comedi%d: s526: ", dev->minor);
310
311 iobase = it->options[0];
312 if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
313 comedi_error(dev, "I/O port conflict");
314 return -EIO;
315 }
316 dev->iobase = iobase;
317
318 printk("iobase=0x%lx\n", dev->iobase);
319
320
321
322
323
324
325
326
327
328
329
330
331 dev->board_ptr = &s526_boards[0];
332
333 dev->board_name = thisboard->name;
334
335
336
337
338
339 if (alloc_private(dev, sizeof(struct s526_private)) < 0)
340 return -ENOMEM;
341
342
343
344
345
346 dev->n_subdevices = 4;
347 if (alloc_subdevices(dev, dev->n_subdevices) < 0)
348 return -ENOMEM;
349
350 s = dev->subdevices + 0;
351
352 s->type = COMEDI_SUBD_COUNTER;
353 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
354
355 s->n_chan = thisboard->gpct_chans;
356 s->maxdata = 0x00ffffff;
357 s->insn_read = s526_gpct_rinsn;
358 s->insn_config = s526_gpct_insn_config;
359 s->insn_write = s526_gpct_winsn;
360
361
362
363
364
365
366
367
368 s = dev->subdevices + 1;
369
370
371 s->type = COMEDI_SUBD_AI;
372
373 s->subdev_flags = SDF_READABLE | SDF_DIFF;
374
375
376 s->n_chan = 10;
377 s->maxdata = 0xffff;
378 s->range_table = &range_bipolar10;
379 s->len_chanlist = 16;
380
381 s->insn_read = s526_ai_rinsn;
382 s->insn_config = s526_ai_insn_config;
383
384 s = dev->subdevices + 2;
385
386 s->type = COMEDI_SUBD_AO;
387 s->subdev_flags = SDF_WRITABLE;
388 s->n_chan = 4;
389 s->maxdata = 0xffff;
390 s->range_table = &range_bipolar10;
391 s->insn_write = s526_ao_winsn;
392 s->insn_read = s526_ao_rinsn;
393
394 s = dev->subdevices + 3;
395
396 if (thisboard->have_dio) {
397 s->type = COMEDI_SUBD_DIO;
398 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
399 s->n_chan = 8;
400 s->maxdata = 1;
401 s->range_table = &range_digital;
402 s->insn_bits = s526_dio_insn_bits;
403 s->insn_config = s526_dio_insn_config;
404 } else {
405 s->type = COMEDI_SUBD_UNUSED;
406 }
407
408 printk(KERN_INFO "attached\n");
409
410 return 1;
411
412#if 0
413
414
415 cmReg.reg.coutSource = 0;
416 cmReg.reg.coutPolarity = 1;
417 cmReg.reg.autoLoadResetRcap = 1;
418 cmReg.reg.hwCtEnableSource = 3;
419 cmReg.reg.ctEnableCtrl = 2;
420 cmReg.reg.clockSource = 2;
421 cmReg.reg.countDir = 1;
422 cmReg.reg.countDirCtrl = 1;
423 cmReg.reg.outputRegLatchCtrl = 0;
424 cmReg.reg.preloadRegSel = 0;
425 cmReg.reg.reserved = 0;
426
427 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
428
429 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
430 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
431
432
433 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
434
435 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
436
437 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
438
439#else
440
441
442 cmReg.reg.coutSource = 0;
443 cmReg.reg.coutPolarity = 0;
444 cmReg.reg.autoLoadResetRcap = 0;
445 cmReg.reg.hwCtEnableSource = 2;
446 cmReg.reg.ctEnableCtrl = 1;
447 cmReg.reg.clockSource = 3;
448 cmReg.reg.countDir = 0;
449 cmReg.reg.countDirCtrl = 0;
450 cmReg.reg.outputRegLatchCtrl = 0;
451 cmReg.reg.preloadRegSel = 0;
452 cmReg.reg.reserved = 0;
453
454 n = 0;
455 printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
456 cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
457 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
458 udelay(1000);
459 printk(KERN_INFO "Read back mode reg=0x%04x\n",
460 inw(ADDR_CHAN_REG(REG_C0M, n)));
461
462
463
464
465
466
467
468
469
470
471
472
473
474 if (cmReg.reg.autoLoadResetRcap == 0) {
475
476 outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
477
478 outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
479 }
480
481 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
482 udelay(1000);
483 printk(KERN_INFO "Read back mode reg=0x%04x\n",
484 inw(ADDR_CHAN_REG(REG_C0M, n)));
485
486#endif
487 printk(KERN_INFO "Current registres:\n");
488
489 for (i = 0; i < S526_NUM_PORTS; i++) {
490 printk(KERN_INFO "0x%02lx: 0x%04x\n",
491 ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
492 }
493 return 1;
494}
495
496
497
498
499
500
501
502
503
504static int s526_detach(struct comedi_device *dev)
505{
506 printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor);
507
508 if (dev->iobase > 0)
509 release_region(dev->iobase, S526_IOSIZE);
510
511 return 0;
512}
513
514static int s526_gpct_rinsn(struct comedi_device *dev,
515 struct comedi_subdevice *s, struct comedi_insn *insn,
516 unsigned int *data)
517{
518 int i;
519 int counter_channel = CR_CHAN(insn->chanspec);
520 unsigned short datalow;
521 unsigned short datahigh;
522
523
524 if (insn->n <= 0) {
525 printk(KERN_ERR "s526: INSN_READ: n should be > 0\n");
526 return -EINVAL;
527 }
528
529 for (i = 0; i < insn->n; i++) {
530 datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel));
531 datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel));
532 data[i] = (int)(datahigh & 0x00FF);
533 data[i] = (data[i] << 16) | (datalow & 0xFFFF);
534
535
536 }
537 return i;
538}
539
540static int s526_gpct_insn_config(struct comedi_device *dev,
541 struct comedi_subdevice *s,
542 struct comedi_insn *insn, unsigned int *data)
543{
544 int subdev_channel = CR_CHAN(insn->chanspec);
545 int i;
546 short value;
547 union cmReg cmReg;
548
549
550
551
552 for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) {
553 devpriv->s526_gpct_config[subdev_channel].data[i] =
554 insn->data[i];
555
556 }
557
558
559
560 switch (insn->data[0]) {
561 case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
562
563
564
565
566
567
568 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
569 devpriv->s526_gpct_config[subdev_channel].app =
570 PositionMeasurement;
571
572#if 0
573
574
575 cmReg.reg.coutSource = 0;
576 cmReg.reg.coutPolarity = 1;
577 cmReg.reg.autoLoadResetRcap = 0;
578 cmReg.reg.hwCtEnableSource = 3;
579 cmReg.reg.ctEnableCtrl = 2;
580 cmReg.reg.clockSource = 2;
581 cmReg.reg.countDir = 1;
582 cmReg.reg.countDirCtrl = 1;
583 cmReg.reg.outputRegLatchCtrl = 0;
584 cmReg.reg.preloadRegSel = 0;
585 cmReg.reg.reserved = 0;
586
587 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
588
589 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
590 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
591
592
593 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
594
595 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
596
597
598 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
599
600#endif
601
602#if 1
603
604 cmReg.value = insn->data[1] & 0xFFFF;
605
606
607 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
608
609
610 if (cmReg.reg.autoLoadResetRcap == 0) {
611
612 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
613
614
615
616 }
617#else
618
619 cmReg.reg.countDirCtrl = 0;
620
621
622 if (insn->data[1] == GPCT_X2)
623 cmReg.reg.clockSource = 1;
624 else if (insn->data[1] == GPCT_X4)
625 cmReg.reg.clockSource = 2;
626 else
627 cmReg.reg.clockSource = 0;
628
629
630
631
632
633
634
635
636 if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX)
637
638 cmReg.reg.autoLoadResetRcap = 4;
639
640
641 cmReg.value = (short)(insn->data[1] & 0xFFFF);
642 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
643
644
645 value = (short)((insn->data[2] >> 16) & 0xFFFF);
646 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
647
648
649 value = (short)(insn->data[2] & 0xFFFF);
650 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
651
652
653 if (insn->data[3] != 0) {
654 value = (short)(insn->data[3] & 0xFFFF);
655 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
656 }
657
658 if (cmReg.reg.autoLoadResetRcap == 0) {
659
660 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
661
662 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
663 }
664#endif
665 break;
666
667 case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
668
669
670
671
672
673
674
675 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n");
676 devpriv->s526_gpct_config[subdev_channel].app =
677 SinglePulseGeneration;
678
679
680 cmReg.value = (short)(insn->data[1] & 0xFFFF);
681 cmReg.reg.preloadRegSel = 0;
682 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
683
684
685 value = (short)((insn->data[2] >> 16) & 0xFFFF);
686 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
687
688
689 value = (short)(insn->data[2] & 0xFFFF);
690 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
691
692
693 cmReg.value = (short)(insn->data[1] & 0xFFFF);
694 cmReg.reg.preloadRegSel = 1;
695 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
696
697
698 value = (short)((insn->data[3] >> 16) & 0xFFFF);
699 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
700
701
702 value = (short)(insn->data[3] & 0xFFFF);
703 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
704
705
706 if (insn->data[4] != 0) {
707 value = (short)(insn->data[4] & 0xFFFF);
708 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
709 }
710 break;
711
712 case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
713
714
715
716
717
718
719
720 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n");
721 devpriv->s526_gpct_config[subdev_channel].app =
722 PulseTrainGeneration;
723
724
725 cmReg.value = (short)(insn->data[1] & 0xFFFF);
726 cmReg.reg.preloadRegSel = 0;
727 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
728
729
730 value = (short)((insn->data[2] >> 16) & 0xFFFF);
731 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
732
733
734 value = (short)(insn->data[2] & 0xFFFF);
735 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
736
737
738 cmReg.value = (short)(insn->data[1] & 0xFFFF);
739 cmReg.reg.preloadRegSel = 1;
740 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
741
742
743 value = (short)((insn->data[3] >> 16) & 0xFFFF);
744 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
745
746
747 value = (short)(insn->data[3] & 0xFFFF);
748 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
749
750
751 if (insn->data[4] != 0) {
752 value = (short)(insn->data[4] & 0xFFFF);
753 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
754 }
755 break;
756
757 default:
758 printk(KERN_ERR "s526: unsupported GPCT_insn_config\n");
759 return -EINVAL;
760 break;
761 }
762
763 return insn->n;
764}
765
766static int s526_gpct_winsn(struct comedi_device *dev,
767 struct comedi_subdevice *s, struct comedi_insn *insn,
768 unsigned int *data)
769{
770 int subdev_channel = CR_CHAN(insn->chanspec);
771 short value;
772 union cmReg cmReg;
773
774 printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n",
775 subdev_channel);
776 cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
777 printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value);
778
779 switch (devpriv->s526_gpct_config[subdev_channel].app) {
780 case PositionMeasurement:
781 printk(KERN_INFO "S526: INSN_WRITE: PM\n");
782 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
783 subdev_channel));
784 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
785 break;
786
787 case SinglePulseGeneration:
788 printk(KERN_INFO "S526: INSN_WRITE: SPG\n");
789 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
790 subdev_channel));
791 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
792 break;
793
794 case PulseTrainGeneration:
795
796
797
798
799
800
801 printk(KERN_INFO "S526: INSN_WRITE: PTG\n");
802 if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) {
803 (devpriv->s526_gpct_config[subdev_channel]).data[0] =
804 insn->data[0];
805 (devpriv->s526_gpct_config[subdev_channel]).data[1] =
806 insn->data[1];
807 } else {
808 printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
809 insn->data[0], insn->data[1]);
810 return -EINVAL;
811 }
812
813 value = (short)((*data >> 16) & 0xFFFF);
814 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
815 value = (short)(*data & 0xFFFF);
816 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
817 break;
818 default:
819 printk
820 ("s526: INSN_WRITE: Functionality %d not implemented yet\n",
821 devpriv->s526_gpct_config[subdev_channel].app);
822 return -EINVAL;
823 break;
824 }
825
826 return insn->n;
827}
828
829#define ISR_ADC_DONE 0x4
830static int s526_ai_insn_config(struct comedi_device *dev,
831 struct comedi_subdevice *s,
832 struct comedi_insn *insn, unsigned int *data)
833{
834 int result = -EINVAL;
835
836 if (insn->n < 1)
837 return result;
838
839 result = insn->n;
840
841
842
843
844
845
846
847
848
849 outw(ISR_ADC_DONE, ADDR_REG(REG_IER));
850
851 devpriv->s526_ai_config = (data[0] & 0x3FF) << 5;
852 if (data[1] > 0)
853 devpriv->s526_ai_config |= 0x8000;
854
855 devpriv->s526_ai_config |= 0x0001;
856
857 return result;
858}
859
860
861
862
863
864static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
865 struct comedi_insn *insn, unsigned int *data)
866{
867 int n, i;
868 int chan = CR_CHAN(insn->chanspec);
869 unsigned short value;
870 unsigned int d;
871 unsigned int status;
872
873
874
875 value = (devpriv->s526_ai_config & 0x8000) |
876 ((1 << 5) << chan) | (chan << 1) | 0x0001;
877
878
879 for (n = 0; n < insn->n; n++) {
880
881 outw(value, ADDR_REG(REG_ADC));
882
883
884
885#define TIMEOUT 100
886
887 for (i = 0; i < TIMEOUT; i++) {
888 status = inw(ADDR_REG(REG_ISR));
889 if (status & ISR_ADC_DONE) {
890 outw(ISR_ADC_DONE, ADDR_REG(REG_ISR));
891 break;
892 }
893 }
894 if (i == TIMEOUT) {
895
896
897 printk(KERN_ERR "s526: ADC(0x%04x) timeout\n",
898 inw(ADDR_REG(REG_ISR)));
899 return -ETIMEDOUT;
900 }
901
902
903 d = inw(ADDR_REG(REG_ADD));
904
905
906
907 data[n] = d ^ 0x8000;
908 }
909
910
911 return n;
912}
913
914static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
915 struct comedi_insn *insn, unsigned int *data)
916{
917 int i;
918 int chan = CR_CHAN(insn->chanspec);
919 unsigned short val;
920
921
922 val = chan << 1;
923
924 outw(val, ADDR_REG(REG_DAC));
925
926
927
928 for (i = 0; i < insn->n; i++) {
929
930
931
932
933
934 outw(data[i], ADDR_REG(REG_ADD));
935 devpriv->ao_readback[chan] = data[i];
936
937 outw(val + 1, ADDR_REG(REG_DAC));
938 }
939
940
941 return i;
942}
943
944
945
946static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
947 struct comedi_insn *insn, unsigned int *data)
948{
949 int i;
950 int chan = CR_CHAN(insn->chanspec);
951
952 for (i = 0; i < insn->n; i++)
953 data[i] = devpriv->ao_readback[chan];
954
955 return i;
956}
957
958
959
960
961
962
963static int s526_dio_insn_bits(struct comedi_device *dev,
964 struct comedi_subdevice *s,
965 struct comedi_insn *insn, unsigned int *data)
966{
967 if (insn->n != 2)
968 return -EINVAL;
969
970
971
972 if (data[0]) {
973 s->state &= ~data[0];
974 s->state |= data[0] & data[1];
975
976 outw(s->state, ADDR_REG(REG_DIO));
977 }
978
979
980
981 data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF;
982
983
984
985
986 return 2;
987}
988
989static int s526_dio_insn_config(struct comedi_device *dev,
990 struct comedi_subdevice *s,
991 struct comedi_insn *insn, unsigned int *data)
992{
993 int chan = CR_CHAN(insn->chanspec);
994 int group, mask;
995
996 printk(KERN_INFO "S526 DIO insn_config\n");
997
998
999
1000
1001
1002
1003 group = chan >> 2;
1004 mask = 0xF << (group << 2);
1005 switch (data[0]) {
1006 case INSN_CONFIG_DIO_OUTPUT:
1007
1008 s->state |= 1 << (group + 10);
1009 s->io_bits |= mask;
1010 break;
1011 case INSN_CONFIG_DIO_INPUT:
1012 s->state &= ~(1 << (group + 10));
1013 s->io_bits &= ~mask;
1014 break;
1015 case INSN_CONFIG_DIO_QUERY:
1016 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
1017 return insn->n;
1018 default:
1019 return -EINVAL;
1020 }
1021 outw(s->state, ADDR_REG(REG_DIO));
1022
1023 return 1;
1024}
1025
1026
1027
1028
1029
1030static int __init driver_s526_init_module(void)
1031{
1032 return comedi_driver_register(&driver_s526);
1033}
1034
1035static void __exit driver_s526_cleanup_module(void)
1036{
1037 comedi_driver_unregister(&driver_s526);
1038}
1039
1040module_init(driver_s526_init_module);
1041module_exit(driver_s526_cleanup_module);
1042
1043MODULE_AUTHOR("Comedi http://www.comedi.org");
1044MODULE_DESCRIPTION("Comedi low-level driver");
1045MODULE_LICENSE("GPL");
1046