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