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