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