s526: backwards compatible change for INSN_CONFIG_GPCT_QUADRATURE_ENCODER
[comedi.git] / comedi / drivers / s526.c
1 /*
2     comedi/drivers/s526.c
3     Sensoray s526 Comedi driver
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23 /*
24 Driver: s526
25 Description: Sensoray 526 driver
26 Devices: [Sensoray] 526 (s526)
27 Author: Richie
28         Everett Wang <everett.wang@everteq.com>
29 Updated: Thu, 14 Sep. 2006
30 Status: experimental
31
32 Encoder works
33 Analog input works
34 Analog output works
35 PWM output works
36 Commands are not supported yet.
37
38 Configuration Options:
39
40 comedi_config /dev/comedi0 s526 0x2C0,0x3
41
42 */
43
44 #include <linux/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 /* Ports */
54 #define S526_IOSIZE 0x40
55 #define S526_NUM_PORTS 27
56
57 /* registers */
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
86 static 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
116 typedef struct {
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 } counter_mode_register_t;
145
146 union cmReg {
147         counter_mode_register_t reg;
148         unsigned short value;
149 };
150
151 /* Different Application Classes for GPCT Subdevices */
152 /* The list is not exhaustive and needs discussion! */
153 typedef enum {
154         CountingAndTimeMeasurement,
155         SinglePulseGeneration,
156         PulseTrainGeneration,
157         PositionMeasurement,
158         Miscellaneous
159 } S526_GPCT_APP_CLASS;
160
161 /* Config struct for different GPCT subdevice Application Classes and
162    their options
163 */
164 typedef struct s526GPCTConfig {
165         S526_GPCT_APP_CLASS app;
166 } s526_gpct_config_t;
167
168 /*
169  * Board descriptions for two imaginary boards.  Describing the
170  * boards in this way is optional, and completely driver-dependent.
171  * Some drivers use arrays such as this, other do not.
172  */
173 typedef struct s526_board_struct {
174         const char *name;
175         int gpct_chans;
176         int gpct_bits;
177         int ad_chans;
178         int ad_bits;
179         int da_chans;
180         int da_bits;
181         int have_dio;
182 } s526_board;
183
184 static const s526_board s526_boards[] = {
185         {
186               name:     "s526",
187               gpct_chans:4,
188               gpct_bits:24,
189               ad_chans:8,
190               ad_bits:  16,
191               da_chans:4,
192               da_bits:  16,
193               have_dio:1,
194                 }
195 };
196
197 #define ADDR_REG(reg) (dev->iobase + (reg))
198 #define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8)
199
200 /*
201  * Useful for shorthand access to the particular board structure
202  */
203 #define thisboard ((const s526_board *)dev->board_ptr)
204
205 /* this structure is for data unique to this hardware driver.  If
206    several hardware drivers keep similar information in this structure,
207    feel free to suggest moving the variable to the comedi_device struct.  */
208 typedef struct {
209         int data;
210
211         /* would be useful for a PCI device */
212         struct pci_dev *pci_dev;
213
214         /* Used for AO readback */
215         lsampl_t ao_readback[2];
216
217         s526_gpct_config_t s526_gpct_config[4];
218         unsigned short s526_ai_config;
219 } s526_private;
220 /*
221  * most drivers define the following macro to make it easy to
222  * access the private structure.
223  */
224 #define devpriv ((s526_private *)dev->private)
225
226 /*
227  * The comedi_driver structure tells the Comedi core module
228  * which functions to call to configure/deconfigure (attach/detach)
229  * the board, and also about the kernel module that contains
230  * the device code.
231  */
232 static int s526_attach(comedi_device * dev, comedi_devconfig * it);
233 static int s526_detach(comedi_device * dev);
234 static comedi_driver driver_s526 = {
235       driver_name:"s526",
236       module:THIS_MODULE,
237       attach:s526_attach,
238       detach:s526_detach,
239 /* It is not necessary to implement the following members if you are
240  * writing a driver for a ISA PnP or PCI card */
241         /* Most drivers will support multiple types of boards by
242          * having an array of board structures.  These were defined
243          * in s526_boards[] above.  Note that the element 'name'
244          * was first in the structure -- Comedi uses this fact to
245          * extract the name of the board without knowing any details
246          * about the structure except for its length.
247          * When a device is attached (by comedi_config), the name
248          * of the device is given to Comedi, and Comedi tries to
249          * match it by going through the list of board names.  If
250          * there is a match, the address of the pointer is put
251          * into dev->board_ptr and driver->attach() is called.
252          *
253          * Note that these are not necessary if you can determine
254          * the type of board in software.  ISA PnP, PCI, and PCMCIA
255          * devices are such boards.
256          */
257       board_name:&s526_boards[0].name,
258       offset:sizeof(s526_board),
259       num_names:sizeof(s526_boards) / sizeof(s526_board),
260 };
261
262 static int s526_gpct_rinsn(comedi_device * dev, comedi_subdevice * s,
263         comedi_insn * insn, lsampl_t * data);
264 static int s526_gpct_insn_config(comedi_device * dev, comedi_subdevice * s,
265         comedi_insn * insn, lsampl_t * data);
266 static int s526_gpct_winsn(comedi_device * dev, comedi_subdevice * s,
267         comedi_insn * insn, lsampl_t * data);
268 static int s526_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
269         comedi_insn * insn, lsampl_t * data);
270 static int s526_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
271         comedi_insn * insn, lsampl_t * data);
272 static int s526_ao_winsn(comedi_device * dev, comedi_subdevice * s,
273         comedi_insn * insn, lsampl_t * data);
274 static int s526_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
275         comedi_insn * insn, lsampl_t * data);
276 static int s526_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
277         comedi_insn * insn, lsampl_t * data);
278 static int s526_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
279         comedi_insn * insn, lsampl_t * data);
280
281 /*
282  * Attach is called by the Comedi core to configure the driver
283  * for a particular board.  If you specified a board_name array
284  * in the driver structure, dev->board_ptr contains that
285  * address.
286  */
287 static int s526_attach(comedi_device * dev, comedi_devconfig * it)
288 {
289         comedi_subdevice *s;
290         int iobase;
291         int i, n;
292 //      sampl_t value;
293 //      int subdev_channel = 0;
294         union cmReg cmReg;
295
296         printk("comedi%d: s526: ", dev->minor);
297
298         iobase = it->options[0];
299         if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
300                 comedi_error(dev, "I/O port conflict");
301                 return -EIO;
302         }
303         dev->iobase = iobase;
304
305         printk("iobase=0x%lx\n", dev->iobase);
306
307         /*** make it a little quieter, exw, 8/29/06
308         for (i = 0; i < S526_NUM_PORTS; i++) {
309                 printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
310         }
311         ***/
312
313 /*
314  * Initialize dev->board_name.  Note that we can use the "thisboard"
315  * macro now, since we just initialized it in the last line.
316  */
317         dev->board_ptr = &s526_boards[0];
318
319         dev->board_name = thisboard->name;
320
321 /*
322  * Allocate the private structure area.  alloc_private() is a
323  * convenient macro defined in comedidev.h.
324  */
325         if (alloc_private(dev, sizeof(s526_private)) < 0)
326                 return -ENOMEM;
327
328 /*
329  * Allocate the subdevice structures.  alloc_subdevice() is a
330  * convenient macro defined in comedidev.h.
331  */
332         dev->n_subdevices = 4;
333         if (alloc_subdevices(dev, dev->n_subdevices) < 0)
334                 return -ENOMEM;
335
336         s = dev->subdevices + 0;
337         /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
338         s->type = COMEDI_SUBD_COUNTER;
339         s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
340         /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
341         s->n_chan = thisboard->gpct_chans;
342         s->maxdata = 0x00ffffff;        /* 24 bit counter */
343         s->insn_read = s526_gpct_rinsn;
344         s->insn_config = s526_gpct_insn_config;
345         s->insn_write = s526_gpct_winsn;
346
347         /* Command are not implemented yet, however they are necessary to
348            allocate the necessary memory for the comedi_async struct (used
349            to trigger the GPCT in case of pulsegenerator function */
350         //s->do_cmd = s526_gpct_cmd;
351         //s->do_cmdtest = s526_gpct_cmdtest;
352         //s->cancel = s526_gpct_cancel;
353
354         s = dev->subdevices + 1;
355         //dev->read_subdev=s;
356         /* analog input subdevice */
357         s->type = COMEDI_SUBD_AI;
358         /* we support differential */
359         s->subdev_flags = SDF_READABLE | SDF_DIFF;
360         /* channels 0 to 7 are the regular differential inputs */
361         /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
362         s->n_chan = 10;
363         s->maxdata = 0xffff;
364         s->range_table = &range_bipolar10;
365         s->len_chanlist = 16;   /* This is the maximum chanlist length that
366                                    the board can handle */
367         s->insn_read = s526_ai_rinsn;
368         s->insn_config = s526_ai_insn_config;
369
370         s = dev->subdevices + 2;
371         /* analog output subdevice */
372         s->type = COMEDI_SUBD_AO;
373         s->subdev_flags = SDF_WRITABLE;
374         s->n_chan = 4;
375         s->maxdata = 0xffff;
376         s->range_table = &range_bipolar10;
377         s->insn_write = s526_ao_winsn;
378         s->insn_read = s526_ao_rinsn;
379
380         s = dev->subdevices + 3;
381         /* digital i/o subdevice */
382         if (thisboard->have_dio) {
383                 s->type = COMEDI_SUBD_DIO;
384                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
385                 s->n_chan = 8;
386                 s->maxdata = 1;
387                 s->range_table = &range_digital;
388                 s->insn_bits = s526_dio_insn_bits;
389                 s->insn_config = s526_dio_insn_config;
390         } else {
391                 s->type = COMEDI_SUBD_UNUSED;
392         }
393
394         printk("attached\n");
395
396         return 1;
397
398 #if 0
399         // Example of Counter Application
400         //One-shot (software trigger)
401         cmReg.reg.coutSource = 0;       // out RCAP
402         cmReg.reg.coutPolarity = 1;     // Polarity inverted
403         cmReg.reg.autoLoadResetRcap = 1;        // Auto load 0:disabled, 1:enabled
404         cmReg.reg.hwCtEnableSource = 3; // NOT RCAP
405         cmReg.reg.ctEnableCtrl = 2;     // Hardware
406         cmReg.reg.clockSource = 2;      // Internal
407         cmReg.reg.countDir = 1; // Down
408         cmReg.reg.countDirCtrl = 1;     // Software
409         cmReg.reg.outputRegLatchCtrl = 0;       // latch on read
410         cmReg.reg.preloadRegSel = 0;    // PR0
411         cmReg.reg.reserved = 0;
412
413         outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
414
415         outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
416         outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
417
418         outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Reset the counter
419         outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Load the counter from PR0
420
421         outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Reset RCAP (fires one-shot)
422
423 #else
424
425         // Set Counter Mode Register
426         cmReg.reg.coutSource = 0;       // out RCAP
427         cmReg.reg.coutPolarity = 0;     // Polarity inverted
428         cmReg.reg.autoLoadResetRcap = 0;        // Auto load disabled
429         cmReg.reg.hwCtEnableSource = 2; // NOT RCAP
430         cmReg.reg.ctEnableCtrl = 1;     // 1: Software,  >1 : Hardware
431         cmReg.reg.clockSource = 3;      // x4
432         cmReg.reg.countDir = 0; // up
433         cmReg.reg.countDirCtrl = 0;     // quadrature
434         cmReg.reg.outputRegLatchCtrl = 0;       // latch on read
435         cmReg.reg.preloadRegSel = 0;    // PR0
436         cmReg.reg.reserved = 0;
437
438         n = 0;
439         printk("Mode reg=0x%04x, 0x%04lx\n", cmReg.value, ADDR_CHAN_REG(REG_C0M,
440                         n));
441         outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
442         udelay(1000);
443         printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
444
445         // Load the pre-laod register high word
446 //                      value = (sampl_t) (0x55);
447 //                      outw(value, ADDR_CHAN_REG(REG_C0H, n));
448
449         // Load the pre-laod register low word
450 //                      value = (sampl_t)(0xaa55);
451 //                      outw(value, ADDR_CHAN_REG(REG_C0L, n));
452
453         // Write the Counter Control Register
454 //                      outw(value, ADDR_CHAN_REG(REG_C0C, 0));
455
456         // Reset the counter if it is software preload
457         if (cmReg.reg.autoLoadResetRcap == 0) {
458                 outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));        // Reset the counter
459                 outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));        // Load the counter from PR0
460         }
461
462         outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
463         udelay(1000);
464         printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
465
466 #endif
467         printk("Current registres:\n");
468
469         for (i = 0; i < S526_NUM_PORTS; i++) {
470                 printk("0x%02lx: 0x%04x\n", ADDR_REG(s526_ports[i]),
471                         inw(ADDR_REG(s526_ports[i])));
472         }
473         return 1;
474 }
475
476 /*
477  * _detach is called to deconfigure a device.  It should deallocate
478  * resources.
479  * This function is also called when _attach() fails, so it should be
480  * careful not to release resources that were not necessarily
481  * allocated by _attach().  dev->private and dev->subdevices are
482  * deallocated automatically by the core.
483  */
484 static int s526_detach(comedi_device * dev)
485 {
486         printk("comedi%d: s526: remove\n", dev->minor);
487
488         if (dev->iobase > 0)
489                 release_region(dev->iobase, S526_IOSIZE);
490
491         return 0;
492 }
493
494 static int s526_gpct_rinsn(comedi_device * dev, comedi_subdevice * s,
495         comedi_insn * insn, lsampl_t * data)
496 {
497         int i;                  // counts the Data
498         int counter_channel = CR_CHAN(insn->chanspec);
499         unsigned short datalow;
500         unsigned short datahigh;
501
502         // Check if (n > 0)
503         if (insn->n <= 0) {
504                 printk("s526: INSN_READ: n should be > 0\n");
505                 return -EINVAL;
506         }
507         // Read the low word first
508         for (i = 0; i < insn->n; i++) {
509                 datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel));
510                 datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel));
511                 data[i] = (int)(datahigh & 0x00FF);
512                 data[i] = (data[i] << 16) | (datalow & 0xFFFF);
513 //              printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", counter_channel, data[i], datahigh, datalow);
514         }
515         return i;
516 }
517
518 static int s526_gpct_insn_config(comedi_device * dev, comedi_subdevice * s,
519         comedi_insn * insn, lsampl_t * data)
520 {
521         int subdev_channel = CR_CHAN(insn->chanspec);   // Unpack chanspec
522         sampl_t value;
523         union cmReg cmReg;
524
525 //        printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel);
526
527         // Check what type of Counter the user requested, data[0] contains
528         // the Application type
529         switch (data[0]) {
530         case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
531                 /*
532                    data[0]: Application Type
533                    data[1]: Counter Mode Register Value
534                    data[2]: Pre-load Register Value
535                    data[3]: Conter Control Register
536                  */
537                 printk("s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
538                 devpriv->s526_gpct_config[subdev_channel].app =
539                         PositionMeasurement;
540
541 /*
542                         // Example of Counter Application
543                         //One-shot (software trigger)
544                         cmReg.reg.coutSource            = 0; // out RCAP
545                         cmReg.reg.coutPolarity          = 1; // Polarity inverted
546                         cmReg.reg.autoLoadResetRcap     = 0; // Auto load disabled
547                         cmReg.reg.hwCtEnableSource      = 3; // NOT RCAP
548                         cmReg.reg.ctEnableCtrl          = 2; // Hardware
549                         cmReg.reg.clockSource           = 2; // Internal
550                         cmReg.reg.countDir              = 1; // Down
551                         cmReg.reg.countDirCtrl          = 1; // Software
552                         cmReg.reg.outputRegLatchCtrl    = 0; // latch on read
553                         cmReg.reg.preloadRegSel         = 0; // PR0
554                         cmReg.reg.reserved              = 0;
555
556                         outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
557
558                         outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
559                         outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
560
561                         outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Reset the counter
562                         outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Load the counter from PR0
563
564                         outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));  // Reset RCAP (fires one-shot)
565
566 */
567
568 #if 1
569                 // Set Counter Mode Register
570                 if (insn->n < 2) {
571                         /* old configuration for backwards compatibility */
572                         cmReg.reg.coutSource = 0;       // out RCAP
573                         cmReg.reg.coutPolarity = 0;     // Polarity inverted
574                         cmReg.reg.autoLoadResetRcap = 0;        // Auto load disabled
575                         cmReg.reg.hwCtEnableSource = 2; // NOT RCAP
576                         cmReg.reg.ctEnableCtrl = 1;     // 1: Software,  >1 : Hardware
577                         cmReg.reg.clockSource = 3;      // x4
578                         cmReg.reg.countDir = 0; // up
579                         cmReg.reg.countDirCtrl = 0;     // quadrature
580                         cmReg.reg.outputRegLatchCtrl = 0;       // latch on read
581                         cmReg.reg.preloadRegSel = 0;    // PR0
582                         cmReg.reg.reserved = 0;
583                 } else {
584                         cmReg.value = data[1] & 0xFFFF;
585                 }
586
587 //                      printk("s526: Counter Mode register=%x\n", cmReg.value);
588                 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
589
590                 // Reset the counter if it is software preload
591                 if (cmReg.reg.autoLoadResetRcap == 0) {
592                         outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Reset the counter
593 //                              outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Load the counter from PR0
594                 }
595 #else
596                 cmReg.reg.countDirCtrl = 0;     // 0 quadrature, 1 software control
597
598                 // data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4
599                 if (data[1] == GPCT_X2) {
600                         cmReg.reg.clockSource = 1;
601                 } else if (data[1] == GPCT_X4) {
602                         cmReg.reg.clockSource = 2;
603                 } else {
604                         cmReg.reg.clockSource = 0;
605                 }
606
607                 // When to take into account the indexpulse:
608                 if (data[2] == GPCT_IndexPhaseLowLow) {
609                 } else if (data[2] == GPCT_IndexPhaseLowHigh) {
610                 } else if (data[2] == GPCT_IndexPhaseHighLow) {
611                 } else if (data[2] == GPCT_IndexPhaseHighHigh) {
612                 }
613                 // Take into account the index pulse?
614                 if (data[3] == GPCT_RESET_COUNTER_ON_INDEX)
615                         cmReg.reg.autoLoadResetRcap = 4;        // Auto load with INDEX^
616
617                 // Set Counter Mode Register
618                 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
619                 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
620
621                 // Load the pre-laod register high word
622                 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
623                 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
624
625                 // Load the pre-laod register low word
626                 value = (sampl_t) (data[2] & 0xFFFF);
627                 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
628
629                 // Write the Counter Control Register
630                 if (data[3] != 0) {
631                         value = (sampl_t) (data[3] & 0xFFFF);
632                         outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
633                 }
634                 // Reset the counter if it is software preload
635                 if (cmReg.reg.autoLoadResetRcap == 0) {
636                         outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Reset the counter
637                         outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Load the counter from PR0
638                 }
639 #endif
640                 break;
641
642         case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
643                 /*
644                    data[0]: Application Type
645                    data[1]: Counter Mode Register Value
646                    data[2]: Pre-load Register 0 Value
647                    data[3]: Pre-load Register 1 Value
648                    data[4]: Conter Control Register
649                  */
650                 printk("s526: GPCT_INSN_CONFIG: Configuring SPG\n");
651                 if (insn->n < 5) {
652                         printk("s526: Error: SPG data too short\n");
653                         return -EINVAL;
654                 }
655                 devpriv->s526_gpct_config[subdev_channel].app =
656                         SinglePulseGeneration;
657
658                 // Set Counter Mode Register
659                 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
660                 cmReg.reg.preloadRegSel = 0;    // PR0
661                 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
662
663                 // Load the pre-laod register 0 high word
664                 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
665                 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
666
667                 // Load the pre-laod register 0 low word
668                 value = (sampl_t) (data[2] & 0xFFFF);
669                 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
670
671                 // Set Counter Mode Register
672                 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
673                 cmReg.reg.preloadRegSel = 1;    // PR1
674                 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
675
676                 // Load the pre-laod register 1 high word
677                 value = (sampl_t) ((data[3] >> 16) & 0xFFFF);
678                 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
679
680                 // Load the pre-laod register 1 low word
681                 value = (sampl_t) (data[3] & 0xFFFF);
682                 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
683
684                 // Write the Counter Control Register
685                 if (data[4] != 0) {
686                         value = (sampl_t) (data[4] & 0xFFFF);
687                         outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
688                 }
689                 break;
690
691         case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
692                 /*
693                    data[0]: Application Type
694                    data[1]: Counter Mode Register Value
695                    data[2]: Pre-load Register 0 Value
696                    data[3]: Pre-load Register 1 Value
697                    data[4]: Conter Control Register
698                  */
699                 printk("s526: GPCT_INSN_CONFIG: Configuring PTG\n");
700                 if (insn->n < 5) {
701                         printk("s526: Error: PTG data too short\n");
702                         return -EINVAL;
703                 }
704                 devpriv->s526_gpct_config[subdev_channel].app =
705                         PulseTrainGeneration;
706
707                 // Set Counter Mode Register
708                 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
709                 cmReg.reg.preloadRegSel = 0;    // PR0
710                 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
711
712                 // Load the pre-laod register 0 high word
713                 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
714                 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
715
716                 // Load the pre-laod register 0 low word
717                 value = (sampl_t) (data[2] & 0xFFFF);
718                 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
719
720                 // Set Counter Mode Register
721                 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
722                 cmReg.reg.preloadRegSel = 1;    // PR1
723                 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
724
725                 // Load the pre-laod register 1 high word
726                 value = (sampl_t) ((data[3] >> 16) & 0xFFFF);
727                 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
728
729                 // Load the pre-laod register 1 low word
730                 value = (sampl_t) (data[3] & 0xFFFF);
731                 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
732
733                 // Write the Counter Control Register
734                 if (data[4] != 0) {
735                         value = (sampl_t) (data[4] & 0xFFFF);
736                         outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
737                 }
738                 break;
739
740         default:
741                 printk("s526: unsupported GPCT_insn_config\n");
742                 return -EINVAL;
743                 break;
744         }
745
746         return insn->n;
747 }
748
749 static int s526_gpct_winsn(comedi_device * dev, comedi_subdevice * s,
750         comedi_insn * insn, lsampl_t * data)
751 {
752         int subdev_channel = CR_CHAN(insn->chanspec);   // Unpack chanspec
753         sampl_t value;
754         union cmReg cmReg;
755
756         printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel);
757         cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
758         printk("s526: Counter Mode Register: %x\n", cmReg.value);
759         if (insn->n < 1) {
760                 printk("S525: INSN_WRITE: Can't handle data length %u\n",
761                                 insn->n);
762                 return -EINVAL;
763         }
764         // Check what Application of Counter this channel is configured for
765         switch (devpriv->s526_gpct_config[subdev_channel].app) {
766         case PositionMeasurement:
767                 printk("S526: INSN_WRITE: PM\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 SinglePulseGeneration:
774                 printk("S526: INSN_WRITE: SPG\n");
775                 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
776                                 subdev_channel));
777                 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
778                 break;
779
780         case PulseTrainGeneration:
781                 /* data[0] contains the PULSE_WIDTH
782                    data[1] contains the PULSE_PERIOD
783                    @pre PULSE_PERIOD > PULSE_WIDTH > 0
784                    The above periods must be expressed as a multiple of the
785                    pulse frequency on the selected source
786                  */
787                 printk("S526: INSN_WRITE: PTG\n");
788                 if (insn->n < 2) {
789                         printk("s526: INSN_WRITE: PTG: Problem with data length -> %u\n",
790                                         insn->n);
791                         return -EINVAL;
792                 } else if ((data[1] <= data[0]) || (data[0] == 0)) {
793                         printk("s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
794                                 data[0], data[1]);
795                         return -EINVAL;
796                 }
797
798                 value = (sampl_t) ((*data >> 16) & 0xFFFF);
799                 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
800                 value = (sampl_t) (*data & 0xFFFF);
801                 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
802                 break;
803         default:                // Impossible
804                 printk("s526: INSN_WRITE: Functionality %d not implemented yet\n", devpriv->s526_gpct_config[subdev_channel].app);
805                 return -EINVAL;
806                 break;
807         }
808         // return the number of samples written
809         return insn->n;
810 }
811
812 #define ISR_ADC_DONE 0x4
813 static int s526_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
814         comedi_insn * insn, lsampl_t * data)
815 {
816         int result = -EINVAL;
817
818         if (insn->n < 1)
819                 return result;
820
821         result = insn->n;
822
823         /* data[0] : channels was set in relevant bits.
824            data[1] : delay
825          */
826         /* COMMENT: abbotti 2008-07-24: I don't know why you'd want to
827          * enable channels here.  The channel should be enabled in the
828          * INSN_READ handler. */
829
830         // Enable ADC interrupt
831         outw(ISR_ADC_DONE, ADDR_REG(REG_IER));
832 //      printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC)));
833         devpriv->s526_ai_config = (data[0] & 0x3FF) << 5;
834         if (data[1] > 0)
835                 devpriv->s526_ai_config |= 0x8000;      //set the delay
836
837         devpriv->s526_ai_config |= 0x0001;      // ADC start bit.
838
839         return result;
840 }
841
842 /*
843  * "instructions" read/write data in "one-shot" or "software-triggered"
844  * mode.
845  */
846 static int s526_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
847         comedi_insn * insn, lsampl_t * data)
848 {
849         int n, i;
850         int chan = CR_CHAN(insn->chanspec);
851         unsigned short value;
852         unsigned int d;
853         unsigned int status;
854
855         /* Set configured delay, enable channel for this channel only,
856          * select "ADC read" channel, set "ADC start" bit. */
857         value = (devpriv->s526_ai_config & 0x8000) |
858                 ((1 << 5) << chan) | (chan << 1) | 0x0001;
859
860         /* convert n samples */
861         for (n = 0; n < insn->n; n++) {
862                 /* trigger conversion */
863                 outw(value, ADDR_REG(REG_ADC));
864 //              printk("s526: Wrote 0x%04x to ADC\n", value);
865 //              printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC)));
866
867 #define TIMEOUT 100
868                 /* wait for conversion to end */
869                 for (i = 0; i < TIMEOUT; i++) {
870                         status = inw(ADDR_REG(REG_ISR));
871                         if (status & ISR_ADC_DONE) {
872                                 outw(ISR_ADC_DONE, ADDR_REG(REG_ISR));
873                                 break;
874                         }
875                 }
876                 if (i == TIMEOUT) {
877                         /* rt_printk() should be used instead of printk()
878                          * whenever the code can be called from real-time. */
879                         rt_printk("s526: ADC(0x%04x) timeout\n",
880                                 inw(ADDR_REG(REG_ISR)));
881                         return -ETIMEDOUT;
882                 }
883
884                 /* read data */
885                 d = inw(ADDR_REG(REG_ADD));
886 //              printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF));
887
888                 /* munge data */
889                 data[n] = d ^ 0x8000;
890         }
891
892         /* return the number of samples read/written */
893         return n;
894 }
895
896 static int s526_ao_winsn(comedi_device * dev, comedi_subdevice * s,
897         comedi_insn * insn, lsampl_t * data)
898 {
899         int i;
900         int chan = CR_CHAN(insn->chanspec);
901         unsigned short val;
902
903 //      printk("s526_ao_winsn\n");
904         val = chan << 1;
905 //      outw(val, dev->iobase + REG_DAC);
906         outw(val, ADDR_REG(REG_DAC));
907
908         /* Writing a list of values to an AO channel is probably not
909          * very useful, but that's how the interface is defined. */
910         for (i = 0; i < insn->n; i++) {
911                 /* a typical programming sequence */
912 //              outw(data[i], dev->iobase + REG_ADD);  // write the data to preload register
913                 outw(data[i], ADDR_REG(REG_ADD));       // write the data to preload register
914                 devpriv->ao_readback[chan] = data[i];
915 //              outw(val + 1, dev->iobase + REG_DAC); // starts the D/A conversion.
916                 outw(val + 1, ADDR_REG(REG_DAC));       // starts the D/A conversion.
917         }
918
919         /* return the number of samples read/written */
920         return i;
921 }
922
923 /* AO subdevices should have a read insn as well as a write insn.
924  * Usually this means copying a value stored in devpriv. */
925 static int s526_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
926         comedi_insn * insn, lsampl_t * data)
927 {
928         int i;
929         int chan = CR_CHAN(insn->chanspec);
930
931         for (i = 0; i < insn->n; i++)
932                 data[i] = devpriv->ao_readback[chan];
933
934         return i;
935 }
936
937 /* DIO devices are slightly special.  Although it is possible to
938  * implement the insn_read/insn_write interface, it is much more
939  * useful to applications if you implement the insn_bits interface.
940  * This allows packed reading/writing of the DIO channels.  The
941  * comedi core can convert between insn_bits and insn_read/write */
942 static int s526_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
943         comedi_insn * insn, lsampl_t * data)
944 {
945         if (insn->n != 2)
946                 return -EINVAL;
947
948         /* The insn data is a mask in data[0] and the new data
949          * in data[1], each channel cooresponding to a bit. */
950         if (data[0]) {
951                 s->state &= ~data[0];
952                 s->state |= data[0] & data[1];
953                 /* Write out the new digital output lines */
954                 outw(s->state, ADDR_REG(REG_DIO));
955         }
956
957         /* on return, data[1] contains the value of the digital
958          * input and output lines. */
959         data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF;        // low 8 bits are the data
960         /* or we could just return the software copy of the output values if
961          * it was a purely digital output subdevice */
962         //data[1]=s->state & 0xFF;
963
964         return 2;
965 }
966
967 static int s526_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
968         comedi_insn * insn, lsampl_t * data)
969 {
970         int chan = CR_CHAN(insn->chanspec);
971         int group, mask;
972
973         printk("S526 DIO insn_config\n");
974
975         /* The input or output configuration of each digital line is
976          * configured by a special insn_config instruction.  chanspec
977          * contains the channel to be changed, and data[0] contains the
978          * value COMEDI_INPUT or COMEDI_OUTPUT. */
979
980         group = chan >> 2;
981         mask = 0xF << (group << 2);
982         switch (data[0]) {
983         case INSN_CONFIG_DIO_OUTPUT:
984                 s->state |= 1 << (group + 10);  // bit 10/11 set the group 1/2's mode
985                 s->io_bits |= mask;
986                 break;
987         case INSN_CONFIG_DIO_INPUT:
988                 s->state &= ~(1 << (group + 10));// 1 is output, 0 is input.
989                 s->io_bits &= ~mask;
990                 break;
991         case INSN_CONFIG_DIO_QUERY:
992                 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
993                 return insn->n;
994         default:
995                 return -EINVAL;
996         }
997         outw(s->state, ADDR_REG(REG_DIO));
998
999         return 1;
1000 }
1001
1002 /*
1003  * A convenient macro that defines init_module() and cleanup_module(),
1004  * as necessary.
1005  */
1006 COMEDI_INITCLEANUP(driver_s526);