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