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