3 Sensoray s526 Comedi driver
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
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.
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.
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.
25 Description: Sensoray 526 driver
26 Devices: [Sensoray] 526 (s526)
28 Everett Wang <everett.wang@everteq.com>
29 Updated: Thu, 14 Sep. 2006
36 Commands are not supported yet.
38 Configuration Options:
40 comedi_config /dev/comedi0 s526 0x2C0,0x3
44 #include <linux/comedidev.h>
45 #include <linux/ioport.h>
46 #include <asm/byteorder.h>
50 #define S526_START_AI_CONV 0
51 #define S526_AI_READ 0
54 #define S526_IOSIZE 0x40
55 #define S526_NUM_PORTS 27
86 static const int s526_ports[] = {
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;
142 #error Unknown bit field order
144 } counter_mode_register_t;
147 counter_mode_register_t reg;
148 unsigned short value;
151 /* Different Application Classes for GPCT Subdevices */
152 /* The list is not exhaustive and needs discussion! */
154 CountingAndTimeMeasurement,
155 SinglePulseGeneration,
156 PulseTrainGeneration,
159 } S526_GPCT_APP_CLASS;
161 /* Config struct for different GPCT subdevice Application Classes and
164 typedef struct s526GPCTConfig {
165 S526_GPCT_APP_CLASS app;
166 } s526_gpct_config_t;
169 * Board descriptions for two imaginary boards. Describing the
170 * boards in this way is optional, and completely driver-dependent.
171 * Some drivers use arrays such as this, other do not.
173 typedef struct s526_board_struct {
184 static const s526_board s526_boards[] = {
197 #define ADDR_REG(reg) (dev->iobase + (reg))
198 #define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8)
201 * Useful for shorthand access to the particular board structure
203 #define thisboard ((const s526_board *)dev->board_ptr)
205 /* this structure is for data unique to this hardware driver. If
206 several hardware drivers keep similar information in this structure,
207 feel free to suggest moving the variable to the comedi_device struct. */
211 /* would be useful for a PCI device */
212 struct pci_dev *pci_dev;
214 /* Used for AO readback */
215 lsampl_t ao_readback[2];
217 s526_gpct_config_t s526_gpct_config[4];
218 unsigned short s526_ai_config;
221 * most drivers define the following macro to make it easy to
222 * access the private structure.
224 #define devpriv ((s526_private *)dev->private)
227 * The comedi_driver structure tells the Comedi core module
228 * which functions to call to configure/deconfigure (attach/detach)
229 * the board, and also about the kernel module that contains
232 static int s526_attach(comedi_device * dev, comedi_devconfig * it);
233 static int s526_detach(comedi_device * dev);
234 static comedi_driver driver_s526 = {
239 /* It is not necessary to implement the following members if you are
240 * writing a driver for a ISA PnP or PCI card */
241 /* Most drivers will support multiple types of boards by
242 * having an array of board structures. These were defined
243 * in s526_boards[] above. Note that the element 'name'
244 * was first in the structure -- Comedi uses this fact to
245 * extract the name of the board without knowing any details
246 * about the structure except for its length.
247 * When a device is attached (by comedi_config), the name
248 * of the device is given to Comedi, and Comedi tries to
249 * match it by going through the list of board names. If
250 * there is a match, the address of the pointer is put
251 * into dev->board_ptr and driver->attach() is called.
253 * Note that these are not necessary if you can determine
254 * the type of board in software. ISA PnP, PCI, and PCMCIA
255 * devices are such boards.
257 board_name:&s526_boards[0].name,
258 offset:sizeof(s526_board),
259 num_names:sizeof(s526_boards) / sizeof(s526_board),
262 static int s526_gpct_rinsn(comedi_device * dev, comedi_subdevice * s,
263 comedi_insn * insn, lsampl_t * data);
264 static int s526_gpct_insn_config(comedi_device * dev, comedi_subdevice * s,
265 comedi_insn * insn, lsampl_t * data);
266 static int s526_gpct_winsn(comedi_device * dev, comedi_subdevice * s,
267 comedi_insn * insn, lsampl_t * data);
268 static int s526_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
269 comedi_insn * insn, lsampl_t * data);
270 static int s526_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
271 comedi_insn * insn, lsampl_t * data);
272 static int s526_ao_winsn(comedi_device * dev, comedi_subdevice * s,
273 comedi_insn * insn, lsampl_t * data);
274 static int s526_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
275 comedi_insn * insn, lsampl_t * data);
276 static int s526_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
277 comedi_insn * insn, lsampl_t * data);
278 static int s526_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
279 comedi_insn * insn, lsampl_t * data);
282 * Attach is called by the Comedi core to configure the driver
283 * for a particular board. If you specified a board_name array
284 * in the driver structure, dev->board_ptr contains that
287 static int s526_attach(comedi_device * dev, comedi_devconfig * it)
293 // int subdev_channel = 0;
296 printk("comedi%d: s526: ", dev->minor);
298 iobase = it->options[0];
299 if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
300 comedi_error(dev, "I/O port conflict");
303 dev->iobase = iobase;
305 printk("iobase=0x%lx\n", dev->iobase);
307 /*** make it a little quieter, exw, 8/29/06
308 for (i = 0; i < S526_NUM_PORTS; i++) {
309 printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
314 * Initialize dev->board_name. Note that we can use the "thisboard"
315 * macro now, since we just initialized it in the last line.
317 dev->board_ptr = &s526_boards[0];
319 dev->board_name = thisboard->name;
322 * Allocate the private structure area. alloc_private() is a
323 * convenient macro defined in comedidev.h.
325 if (alloc_private(dev, sizeof(s526_private)) < 0)
329 * Allocate the subdevice structures. alloc_subdevice() is a
330 * convenient macro defined in comedidev.h.
332 dev->n_subdevices = 4;
333 if (alloc_subdevices(dev, dev->n_subdevices) < 0)
336 s = dev->subdevices + 0;
337 /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
338 s->type = COMEDI_SUBD_COUNTER;
339 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
340 /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
341 s->n_chan = thisboard->gpct_chans;
342 s->maxdata = 0x00ffffff; /* 24 bit counter */
343 s->insn_read = s526_gpct_rinsn;
344 s->insn_config = s526_gpct_insn_config;
345 s->insn_write = s526_gpct_winsn;
347 /* Command are not implemented yet, however they are necessary to
348 allocate the necessary memory for the comedi_async struct (used
349 to trigger the GPCT in case of pulsegenerator function */
350 //s->do_cmd = s526_gpct_cmd;
351 //s->do_cmdtest = s526_gpct_cmdtest;
352 //s->cancel = s526_gpct_cancel;
354 s = dev->subdevices + 1;
355 //dev->read_subdev=s;
356 /* analog input subdevice */
357 s->type = COMEDI_SUBD_AI;
358 /* we support differential */
359 s->subdev_flags = SDF_READABLE | SDF_DIFF;
360 /* channels 0 to 7 are the regular differential inputs */
361 /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
364 s->range_table = &range_bipolar10;
365 s->len_chanlist = 16; /* This is the maximum chanlist length that
366 the board can handle */
367 s->insn_read = s526_ai_rinsn;
368 s->insn_config = s526_ai_insn_config;
370 s = dev->subdevices + 2;
371 /* analog output subdevice */
372 s->type = COMEDI_SUBD_AO;
373 s->subdev_flags = SDF_WRITABLE;
376 s->range_table = &range_bipolar10;
377 s->insn_write = s526_ao_winsn;
378 s->insn_read = s526_ao_rinsn;
380 s = dev->subdevices + 3;
381 /* digital i/o subdevice */
382 if (thisboard->have_dio) {
383 s->type = COMEDI_SUBD_DIO;
384 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
387 s->range_table = &range_digital;
388 s->insn_bits = s526_dio_insn_bits;
389 s->insn_config = s526_dio_insn_config;
391 s->type = COMEDI_SUBD_UNUSED;
394 printk("attached\n");
399 // Example of Counter Application
400 //One-shot (software trigger)
401 cmReg.reg.coutSource = 0; // out RCAP
402 cmReg.reg.coutPolarity = 1; // Polarity inverted
403 cmReg.reg.autoLoadResetRcap = 1; // Auto load 0:disabled, 1:enabled
404 cmReg.reg.hwCtEnableSource = 3; // NOT RCAP
405 cmReg.reg.ctEnableCtrl = 2; // Hardware
406 cmReg.reg.clockSource = 2; // Internal
407 cmReg.reg.countDir = 1; // Down
408 cmReg.reg.countDirCtrl = 1; // Software
409 cmReg.reg.outputRegLatchCtrl = 0; // latch on read
410 cmReg.reg.preloadRegSel = 0; // PR0
411 cmReg.reg.reserved = 0;
413 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
415 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
416 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
418 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter
419 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0
421 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset RCAP (fires one-shot)
425 // Set Counter Mode Register
426 cmReg.reg.coutSource = 0; // out RCAP
427 cmReg.reg.coutPolarity = 0; // Polarity inverted
428 cmReg.reg.autoLoadResetRcap = 0; // Auto load disabled
429 cmReg.reg.hwCtEnableSource = 2; // NOT RCAP
430 cmReg.reg.ctEnableCtrl = 1; // 1: Software, >1 : Hardware
431 cmReg.reg.clockSource = 3; // x4
432 cmReg.reg.countDir = 0; // up
433 cmReg.reg.countDirCtrl = 0; // quadrature
434 cmReg.reg.outputRegLatchCtrl = 0; // latch on read
435 cmReg.reg.preloadRegSel = 0; // PR0
436 cmReg.reg.reserved = 0;
439 printk("Mode reg=0x%04x, 0x%04lx\n", cmReg.value, ADDR_CHAN_REG(REG_C0M,
441 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
443 printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
445 // Load the pre-laod register high word
446 // value = (sampl_t) (0x55);
447 // outw(value, ADDR_CHAN_REG(REG_C0H, n));
449 // Load the pre-laod register low word
450 // value = (sampl_t)(0xaa55);
451 // outw(value, ADDR_CHAN_REG(REG_C0L, n));
453 // Write the Counter Control Register
454 // outw(value, ADDR_CHAN_REG(REG_C0C, 0));
456 // Reset the counter if it is software preload
457 if (cmReg.reg.autoLoadResetRcap == 0) {
458 outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); // Reset the counter
459 outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); // Load the counter from PR0
462 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
464 printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
467 printk("Current registres:\n");
469 for (i = 0; i < S526_NUM_PORTS; i++) {
470 printk("0x%02lx: 0x%04x\n", ADDR_REG(s526_ports[i]),
471 inw(ADDR_REG(s526_ports[i])));
477 * _detach is called to deconfigure a device. It should deallocate
479 * This function is also called when _attach() fails, so it should be
480 * careful not to release resources that were not necessarily
481 * allocated by _attach(). dev->private and dev->subdevices are
482 * deallocated automatically by the core.
484 static int s526_detach(comedi_device * dev)
486 printk("comedi%d: s526: remove\n", dev->minor);
489 release_region(dev->iobase, S526_IOSIZE);
494 static int s526_gpct_rinsn(comedi_device * dev, comedi_subdevice * s,
495 comedi_insn * insn, lsampl_t * data)
497 int i; // counts the Data
498 int counter_channel = CR_CHAN(insn->chanspec);
499 unsigned short datalow;
500 unsigned short datahigh;
504 printk("s526: INSN_READ: n should be > 0\n");
507 // Read the low word first
508 for (i = 0; i < insn->n; i++) {
509 datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel));
510 datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel));
511 data[i] = (int)(datahigh & 0x00FF);
512 data[i] = (data[i] << 16) | (datalow & 0xFFFF);
513 // printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", counter_channel, data[i], datahigh, datalow);
518 static int s526_gpct_insn_config(comedi_device * dev, comedi_subdevice * s,
519 comedi_insn * insn, lsampl_t * data)
521 int subdev_channel = CR_CHAN(insn->chanspec); // Unpack chanspec
525 // printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel);
527 // Check what type of Counter the user requested, data[0] contains
528 // the Application type
530 case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
532 data[0]: Application Type
533 data[1]: Counter Mode Register Value
534 data[2]: Pre-load Register Value
535 data[3]: Conter Control Register
537 printk("s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
538 devpriv->s526_gpct_config[subdev_channel].app =
542 // Example of Counter Application
543 //One-shot (software trigger)
544 cmReg.reg.coutSource = 0; // out RCAP
545 cmReg.reg.coutPolarity = 1; // Polarity inverted
546 cmReg.reg.autoLoadResetRcap = 0; // Auto load disabled
547 cmReg.reg.hwCtEnableSource = 3; // NOT RCAP
548 cmReg.reg.ctEnableCtrl = 2; // Hardware
549 cmReg.reg.clockSource = 2; // Internal
550 cmReg.reg.countDir = 1; // Down
551 cmReg.reg.countDirCtrl = 1; // Software
552 cmReg.reg.outputRegLatchCtrl = 0; // latch on read
553 cmReg.reg.preloadRegSel = 0; // PR0
554 cmReg.reg.reserved = 0;
556 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
558 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
559 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
561 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter
562 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0
564 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset RCAP (fires one-shot)
569 // Set Counter Mode Register
570 cmReg.value = data[1] & 0xFFFF;
572 // printk("s526: Counter Mode register=%x\n", cmReg.value);
573 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
575 // Reset the counter if it is software preload
576 if (cmReg.reg.autoLoadResetRcap == 0) {
577 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter
578 // outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0
581 cmReg.reg.countDirCtrl = 0; // 0 quadrature, 1 software control
583 // data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4
584 if (data[1] == GPCT_X2) {
585 cmReg.reg.clockSource = 1;
586 } else if (data[1] == GPCT_X4) {
587 cmReg.reg.clockSource = 2;
589 cmReg.reg.clockSource = 0;
592 // When to take into account the indexpulse:
593 if (data[2] == GPCT_IndexPhaseLowLow) {
594 } else if (data[2] == GPCT_IndexPhaseLowHigh) {
595 } else if (data[2] == GPCT_IndexPhaseHighLow) {
596 } else if (data[2] == GPCT_IndexPhaseHighHigh) {
598 // Take into account the index pulse?
599 if (data[3] == GPCT_RESET_COUNTER_ON_INDEX)
600 cmReg.reg.autoLoadResetRcap = 4; // Auto load with INDEX^
602 // Set Counter Mode Register
603 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
604 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
606 // Load the pre-laod register high word
607 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
608 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
610 // Load the pre-laod register low word
611 value = (sampl_t) (data[2] & 0xFFFF);
612 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
614 // Write the Counter Control Register
616 value = (sampl_t) (data[3] & 0xFFFF);
617 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
619 // Reset the counter if it is software preload
620 if (cmReg.reg.autoLoadResetRcap == 0) {
621 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter
622 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0
627 case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
629 data[0]: Application Type
630 data[1]: Counter Mode Register Value
631 data[2]: Pre-load Register 0 Value
632 data[3]: Pre-load Register 1 Value
633 data[4]: Conter Control Register
635 printk("s526: GPCT_INSN_CONFIG: Configuring SPG\n");
636 devpriv->s526_gpct_config[subdev_channel].app =
637 SinglePulseGeneration;
639 // Set Counter Mode Register
640 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
641 cmReg.reg.preloadRegSel = 0; // PR0
642 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
644 // Load the pre-laod register 0 high word
645 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
646 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
648 // Load the pre-laod register 0 low word
649 value = (sampl_t) (data[2] & 0xFFFF);
650 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
652 // Set Counter Mode Register
653 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
654 cmReg.reg.preloadRegSel = 1; // PR1
655 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
657 // Load the pre-laod register 1 high word
658 value = (sampl_t) ((data[3] >> 16) & 0xFFFF);
659 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
661 // Load the pre-laod register 1 low word
662 value = (sampl_t) (data[3] & 0xFFFF);
663 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
665 // Write the Counter Control Register
667 value = (sampl_t) (data[4] & 0xFFFF);
668 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
672 case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
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
680 printk("s526: GPCT_INSN_CONFIG: Configuring PTG\n");
681 devpriv->s526_gpct_config[subdev_channel].app =
682 PulseTrainGeneration;
684 // Set Counter Mode Register
685 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
686 cmReg.reg.preloadRegSel = 0; // PR0
687 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
689 // Load the pre-laod register 0 high word
690 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
691 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
693 // Load the pre-laod register 0 low word
694 value = (sampl_t) (data[2] & 0xFFFF);
695 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
697 // Set Counter Mode Register
698 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
699 cmReg.reg.preloadRegSel = 1; // PR1
700 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
702 // Load the pre-laod register 1 high word
703 value = (sampl_t) ((data[3] >> 16) & 0xFFFF);
704 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
706 // Load the pre-laod register 1 low word
707 value = (sampl_t) (data[3] & 0xFFFF);
708 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
710 // Write the Counter Control Register
712 value = (sampl_t) (data[4] & 0xFFFF);
713 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
718 printk("s526: unsupported GPCT_insn_config\n");
726 static int s526_gpct_winsn(comedi_device * dev, comedi_subdevice * s,
727 comedi_insn * insn, lsampl_t * data)
729 int subdev_channel = CR_CHAN(insn->chanspec); // Unpack chanspec
733 printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel);
734 cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
735 printk("s526: Counter Mode Register: %x\n", cmReg.value);
737 printk("S525: INSN_WRITE: Can't handle data length %u\n",
741 // Check what Application of Counter this channel is configured for
742 switch (devpriv->s526_gpct_config[subdev_channel].app) {
743 case PositionMeasurement:
744 printk("S526: INSN_WRITE: PM\n");
745 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
747 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
750 case SinglePulseGeneration:
751 printk("S526: INSN_WRITE: SPG\n");
752 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
754 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
757 case PulseTrainGeneration:
758 /* data[0] contains the PULSE_WIDTH
759 data[1] contains the PULSE_PERIOD
760 @pre PULSE_PERIOD > PULSE_WIDTH > 0
761 The above periods must be expressed as a multiple of the
762 pulse frequency on the selected source
764 printk("S526: INSN_WRITE: PTG\n");
766 printk("s526: INSN_WRITE: PTG: Problem with data length -> %u\n",
769 } else if ((data[1] <= data[0]) || (data[0] == 0)) {
770 printk("s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
775 value = (sampl_t) ((*data >> 16) & 0xFFFF);
776 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
777 value = (sampl_t) (*data & 0xFFFF);
778 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
780 default: // Impossible
781 printk("s526: INSN_WRITE: Functionality %d not implemented yet\n", devpriv->s526_gpct_config[subdev_channel].app);
785 // return the number of samples written
789 #define ISR_ADC_DONE 0x4
790 static int s526_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
791 comedi_insn * insn, lsampl_t * data)
793 int result = -EINVAL;
800 /* data[0] : channels was set in relevant bits.
803 /* COMMENT: abbotti 2008-07-24: I don't know why you'd want to
804 * enable channels here. The channel should be enabled in the
805 * INSN_READ handler. */
807 // Enable ADC interrupt
808 outw(ISR_ADC_DONE, ADDR_REG(REG_IER));
809 // printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC)));
810 devpriv->s526_ai_config = (data[0] & 0x3FF) << 5;
812 devpriv->s526_ai_config |= 0x8000; //set the delay
814 devpriv->s526_ai_config |= 0x0001; // ADC start bit.
820 * "instructions" read/write data in "one-shot" or "software-triggered"
823 static int s526_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
824 comedi_insn * insn, lsampl_t * data)
827 int chan = CR_CHAN(insn->chanspec);
828 unsigned short value;
832 /* Set configured delay, enable channel for this channel only,
833 * select "ADC read" channel, set "ADC start" bit. */
834 value = (devpriv->s526_ai_config & 0x8000) |
835 ((1 << 5) << chan) | (chan << 1) | 0x0001;
837 /* convert n samples */
838 for (n = 0; n < insn->n; n++) {
839 /* trigger conversion */
840 outw(value, ADDR_REG(REG_ADC));
841 // printk("s526: Wrote 0x%04x to ADC\n", value);
842 // printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC)));
845 /* wait for conversion to end */
846 for (i = 0; i < TIMEOUT; i++) {
847 status = inw(ADDR_REG(REG_ISR));
848 if (status & ISR_ADC_DONE) {
849 outw(ISR_ADC_DONE, ADDR_REG(REG_ISR));
854 /* rt_printk() should be used instead of printk()
855 * whenever the code can be called from real-time. */
856 rt_printk("s526: ADC(0x%04x) timeout\n",
857 inw(ADDR_REG(REG_ISR)));
862 d = inw(ADDR_REG(REG_ADD));
863 // printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF));
866 data[n] = d ^ 0x8000;
869 /* return the number of samples read/written */
873 static int s526_ao_winsn(comedi_device * dev, comedi_subdevice * s,
874 comedi_insn * insn, lsampl_t * data)
877 int chan = CR_CHAN(insn->chanspec);
880 // printk("s526_ao_winsn\n");
882 // outw(val, dev->iobase + REG_DAC);
883 outw(val, ADDR_REG(REG_DAC));
885 /* Writing a list of values to an AO channel is probably not
886 * very useful, but that's how the interface is defined. */
887 for (i = 0; i < insn->n; i++) {
888 /* a typical programming sequence */
889 // outw(data[i], dev->iobase + REG_ADD); // write the data to preload register
890 outw(data[i], ADDR_REG(REG_ADD)); // write the data to preload register
891 devpriv->ao_readback[chan] = data[i];
892 // outw(val + 1, dev->iobase + REG_DAC); // starts the D/A conversion.
893 outw(val + 1, ADDR_REG(REG_DAC)); // starts the D/A conversion.
896 /* return the number of samples read/written */
900 /* AO subdevices should have a read insn as well as a write insn.
901 * Usually this means copying a value stored in devpriv. */
902 static int s526_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
903 comedi_insn * insn, lsampl_t * data)
906 int chan = CR_CHAN(insn->chanspec);
908 for (i = 0; i < insn->n; i++)
909 data[i] = devpriv->ao_readback[chan];
914 /* DIO devices are slightly special. Although it is possible to
915 * implement the insn_read/insn_write interface, it is much more
916 * useful to applications if you implement the insn_bits interface.
917 * This allows packed reading/writing of the DIO channels. The
918 * comedi core can convert between insn_bits and insn_read/write */
919 static int s526_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
920 comedi_insn * insn, lsampl_t * data)
925 /* The insn data is a mask in data[0] and the new data
926 * in data[1], each channel cooresponding to a bit. */
928 s->state &= ~data[0];
929 s->state |= data[0] & data[1];
930 /* Write out the new digital output lines */
931 outw(s->state, ADDR_REG(REG_DIO));
934 /* on return, data[1] contains the value of the digital
935 * input and output lines. */
936 data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; // low 8 bits are the data
937 /* or we could just return the software copy of the output values if
938 * it was a purely digital output subdevice */
939 //data[1]=s->state & 0xFF;
944 static int s526_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
945 comedi_insn * insn, lsampl_t * data)
947 int chan = CR_CHAN(insn->chanspec);
950 printk("S526 DIO insn_config\n");
952 /* The input or output configuration of each digital line is
953 * configured by a special insn_config instruction. chanspec
954 * contains the channel to be changed, and data[0] contains the
955 * value COMEDI_INPUT or COMEDI_OUTPUT. */
958 mask = 0xF << (group << 2);
960 case INSN_CONFIG_DIO_OUTPUT:
961 s->state |= 1 << (group + 10); // bit 10/11 set the group 1/2's mode
964 case INSN_CONFIG_DIO_INPUT:
965 s->state &= ~(1 << (group + 10));// 1 is output, 0 is input.
968 case INSN_CONFIG_DIO_QUERY:
969 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
974 outw(s->state, ADDR_REG(REG_DIO));
980 * A convenient macro that defines init_module() and cleanup_module(),
983 COMEDI_INITCLEANUP(driver_s526);