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