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