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
571 /* old configuration for backwards compatibility */
572 cmReg.reg.coutSource = 0; // out RCAP
573 cmReg.reg.coutPolarity = 0; // Polarity inverted
574 cmReg.reg.autoLoadResetRcap = 0; // Auto load disabled
575 cmReg.reg.hwCtEnableSource = 2; // NOT RCAP
576 cmReg.reg.ctEnableCtrl = 1; // 1: Software, >1 : Hardware
577 cmReg.reg.clockSource = 3; // x4
578 cmReg.reg.countDir = 0; // up
579 cmReg.reg.countDirCtrl = 0; // quadrature
580 cmReg.reg.outputRegLatchCtrl = 0; // latch on read
581 cmReg.reg.preloadRegSel = 0; // PR0
582 cmReg.reg.reserved = 0;
584 cmReg.value = data[1] & 0xFFFF;
587 // printk("s526: Counter Mode register=%x\n", cmReg.value);
588 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
590 // Reset the counter if it is software preload
591 if (cmReg.reg.autoLoadResetRcap == 0) {
592 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter
593 // outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0
596 cmReg.reg.countDirCtrl = 0; // 0 quadrature, 1 software control
598 // data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4
599 if (data[1] == GPCT_X2) {
600 cmReg.reg.clockSource = 1;
601 } else if (data[1] == GPCT_X4) {
602 cmReg.reg.clockSource = 2;
604 cmReg.reg.clockSource = 0;
607 // When to take into account the indexpulse:
608 if (data[2] == GPCT_IndexPhaseLowLow) {
609 } else if (data[2] == GPCT_IndexPhaseLowHigh) {
610 } else if (data[2] == GPCT_IndexPhaseHighLow) {
611 } else if (data[2] == GPCT_IndexPhaseHighHigh) {
613 // Take into account the index pulse?
614 if (data[3] == GPCT_RESET_COUNTER_ON_INDEX)
615 cmReg.reg.autoLoadResetRcap = 4; // Auto load with INDEX^
617 // Set Counter Mode Register
618 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
619 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
621 // Load the pre-laod register high word
622 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
623 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
625 // Load the pre-laod register low word
626 value = (sampl_t) (data[2] & 0xFFFF);
627 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
629 // Write the Counter Control Register
631 value = (sampl_t) (data[3] & 0xFFFF);
632 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
634 // Reset the counter if it is software preload
635 if (cmReg.reg.autoLoadResetRcap == 0) {
636 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter
637 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0
642 case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
644 data[0]: Application Type
645 data[1]: Counter Mode Register Value
646 data[2]: Pre-load Register 0 Value
647 data[3]: Pre-load Register 1 Value
648 data[4]: Conter Control Register
650 printk("s526: GPCT_INSN_CONFIG: Configuring SPG\n");
652 printk("s526: Error: SPG data too short\n");
655 devpriv->s526_gpct_config[subdev_channel].app =
656 SinglePulseGeneration;
658 // Set Counter Mode Register
659 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
660 cmReg.reg.preloadRegSel = 0; // PR0
661 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
663 // Load the pre-laod register 0 high word
664 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
665 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
667 // Load the pre-laod register 0 low word
668 value = (sampl_t) (data[2] & 0xFFFF);
669 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
671 // Set Counter Mode Register
672 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
673 cmReg.reg.preloadRegSel = 1; // PR1
674 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
676 // Load the pre-laod register 1 high word
677 value = (sampl_t) ((data[3] >> 16) & 0xFFFF);
678 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
680 // Load the pre-laod register 1 low word
681 value = (sampl_t) (data[3] & 0xFFFF);
682 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
684 // Write the Counter Control Register
686 value = (sampl_t) (data[4] & 0xFFFF);
687 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
691 case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
693 data[0]: Application Type
694 data[1]: Counter Mode Register Value
695 data[2]: Pre-load Register 0 Value
696 data[3]: Pre-load Register 1 Value
697 data[4]: Conter Control Register
699 printk("s526: GPCT_INSN_CONFIG: Configuring PTG\n");
701 printk("s526: Error: PTG data too short\n");
704 devpriv->s526_gpct_config[subdev_channel].app =
705 PulseTrainGeneration;
707 // Set Counter Mode Register
708 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
709 cmReg.reg.preloadRegSel = 0; // PR0
710 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
712 // Load the pre-laod register 0 high word
713 value = (sampl_t) ((data[2] >> 16) & 0xFFFF);
714 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
716 // Load the pre-laod register 0 low word
717 value = (sampl_t) (data[2] & 0xFFFF);
718 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
720 // Set Counter Mode Register
721 cmReg.value = (sampl_t) (data[1] & 0xFFFF);
722 cmReg.reg.preloadRegSel = 1; // PR1
723 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
725 // Load the pre-laod register 1 high word
726 value = (sampl_t) ((data[3] >> 16) & 0xFFFF);
727 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
729 // Load the pre-laod register 1 low word
730 value = (sampl_t) (data[3] & 0xFFFF);
731 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
733 // Write the Counter Control Register
735 value = (sampl_t) (data[4] & 0xFFFF);
736 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
741 printk("s526: unsupported GPCT_insn_config\n");
749 static int s526_gpct_winsn(comedi_device * dev, comedi_subdevice * s,
750 comedi_insn * insn, lsampl_t * data)
752 int subdev_channel = CR_CHAN(insn->chanspec); // Unpack chanspec
756 printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel);
757 cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
758 printk("s526: Counter Mode Register: %x\n", cmReg.value);
760 printk("S525: INSN_WRITE: Can't handle data length %u\n",
764 // Check what Application of Counter this channel is configured for
765 switch (devpriv->s526_gpct_config[subdev_channel].app) {
766 case PositionMeasurement:
767 printk("S526: INSN_WRITE: PM\n");
768 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
770 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
773 case SinglePulseGeneration:
774 printk("S526: INSN_WRITE: SPG\n");
775 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
777 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
780 case PulseTrainGeneration:
781 /* data[0] contains the PULSE_WIDTH
782 data[1] contains the PULSE_PERIOD
783 @pre PULSE_PERIOD > PULSE_WIDTH > 0
784 The above periods must be expressed as a multiple of the
785 pulse frequency on the selected source
787 printk("S526: INSN_WRITE: PTG\n");
789 printk("s526: INSN_WRITE: PTG: Problem with data length -> %u\n",
792 } else if ((data[1] <= data[0]) || (data[0] == 0)) {
793 printk("s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
798 value = (sampl_t) ((*data >> 16) & 0xFFFF);
799 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
800 value = (sampl_t) (*data & 0xFFFF);
801 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
803 default: // Impossible
804 printk("s526: INSN_WRITE: Functionality %d not implemented yet\n", devpriv->s526_gpct_config[subdev_channel].app);
808 // return the number of samples written
812 #define ISR_ADC_DONE 0x4
813 static int s526_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
814 comedi_insn * insn, lsampl_t * data)
816 int result = -EINVAL;
823 /* data[0] : channels was set in relevant bits.
826 /* COMMENT: abbotti 2008-07-24: I don't know why you'd want to
827 * enable channels here. The channel should be enabled in the
828 * INSN_READ handler. */
830 // Enable ADC interrupt
831 outw(ISR_ADC_DONE, ADDR_REG(REG_IER));
832 // printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC)));
833 devpriv->s526_ai_config = (data[0] & 0x3FF) << 5;
835 devpriv->s526_ai_config |= 0x8000; //set the delay
837 devpriv->s526_ai_config |= 0x0001; // ADC start bit.
843 * "instructions" read/write data in "one-shot" or "software-triggered"
846 static int s526_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
847 comedi_insn * insn, lsampl_t * data)
850 int chan = CR_CHAN(insn->chanspec);
851 unsigned short value;
855 /* Set configured delay, enable channel for this channel only,
856 * select "ADC read" channel, set "ADC start" bit. */
857 value = (devpriv->s526_ai_config & 0x8000) |
858 ((1 << 5) << chan) | (chan << 1) | 0x0001;
860 /* convert n samples */
861 for (n = 0; n < insn->n; n++) {
862 /* trigger conversion */
863 outw(value, ADDR_REG(REG_ADC));
864 // printk("s526: Wrote 0x%04x to ADC\n", value);
865 // printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC)));
868 /* wait for conversion to end */
869 for (i = 0; i < TIMEOUT; i++) {
870 status = inw(ADDR_REG(REG_ISR));
871 if (status & ISR_ADC_DONE) {
872 outw(ISR_ADC_DONE, ADDR_REG(REG_ISR));
877 /* rt_printk() should be used instead of printk()
878 * whenever the code can be called from real-time. */
879 rt_printk("s526: ADC(0x%04x) timeout\n",
880 inw(ADDR_REG(REG_ISR)));
885 d = inw(ADDR_REG(REG_ADD));
886 // printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF));
889 data[n] = d ^ 0x8000;
892 /* return the number of samples read/written */
896 static int s526_ao_winsn(comedi_device * dev, comedi_subdevice * s,
897 comedi_insn * insn, lsampl_t * data)
900 int chan = CR_CHAN(insn->chanspec);
903 // printk("s526_ao_winsn\n");
905 // outw(val, dev->iobase + REG_DAC);
906 outw(val, ADDR_REG(REG_DAC));
908 /* Writing a list of values to an AO channel is probably not
909 * very useful, but that's how the interface is defined. */
910 for (i = 0; i < insn->n; i++) {
911 /* a typical programming sequence */
912 // outw(data[i], dev->iobase + REG_ADD); // write the data to preload register
913 outw(data[i], ADDR_REG(REG_ADD)); // write the data to preload register
914 devpriv->ao_readback[chan] = data[i];
915 // outw(val + 1, dev->iobase + REG_DAC); // starts the D/A conversion.
916 outw(val + 1, ADDR_REG(REG_DAC)); // starts the D/A conversion.
919 /* return the number of samples read/written */
923 /* AO subdevices should have a read insn as well as a write insn.
924 * Usually this means copying a value stored in devpriv. */
925 static int s526_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
926 comedi_insn * insn, lsampl_t * data)
929 int chan = CR_CHAN(insn->chanspec);
931 for (i = 0; i < insn->n; i++)
932 data[i] = devpriv->ao_readback[chan];
937 /* DIO devices are slightly special. Although it is possible to
938 * implement the insn_read/insn_write interface, it is much more
939 * useful to applications if you implement the insn_bits interface.
940 * This allows packed reading/writing of the DIO channels. The
941 * comedi core can convert between insn_bits and insn_read/write */
942 static int s526_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
943 comedi_insn * insn, lsampl_t * data)
948 /* The insn data is a mask in data[0] and the new data
949 * in data[1], each channel cooresponding to a bit. */
951 s->state &= ~data[0];
952 s->state |= data[0] & data[1];
953 /* Write out the new digital output lines */
954 outw(s->state, ADDR_REG(REG_DIO));
957 /* on return, data[1] contains the value of the digital
958 * input and output lines. */
959 data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; // low 8 bits are the data
960 /* or we could just return the software copy of the output values if
961 * it was a purely digital output subdevice */
962 //data[1]=s->state & 0xFF;
967 static int s526_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
968 comedi_insn * insn, lsampl_t * data)
970 int chan = CR_CHAN(insn->chanspec);
973 printk("S526 DIO insn_config\n");
975 /* The input or output configuration of each digital line is
976 * configured by a special insn_config instruction. chanspec
977 * contains the channel to be changed, and data[0] contains the
978 * value COMEDI_INPUT or COMEDI_OUTPUT. */
981 mask = 0xF << (group << 2);
983 case INSN_CONFIG_DIO_OUTPUT:
984 s->state |= 1 << (group + 10); // bit 10/11 set the group 1/2's mode
987 case INSN_CONFIG_DIO_INPUT:
988 s->state &= ~(1 << (group + 10));// 1 is output, 0 is input.
991 case INSN_CONFIG_DIO_QUERY:
992 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
997 outw(s->state, ADDR_REG(REG_DIO));
1003 * A convenient macro that defines init_module() and cleanup_module(),
1006 COMEDI_INITCLEANUP(driver_s526);