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