2 comedi/drivers/me4000.c
3 Source code for the Meilhaus ME-4000 board family.
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: Meilhaus ME-4000 series boards
26 Devices: [Meilhaus] ME-4650 (me4000), ME-4670i, ME-4680, ME-4680i, ME-4680is
27 Author: gg (Guenter Gebhardt <g.gebhardt@meilhaus.com>)
28 Updated: Mon, 18 Mar 2002 15:34:01 -0800
29 Status: broken (no support for loading firmware)
38 Configuration Options:
40 [0] - PCI bus number (optional)
41 [1] - PCI slot number (optional)
43 If bus/slot is not specified, the first available PCI
46 The firmware required by these boards is available in the
47 comedi_nonfree_firmware tarball available from
48 http://www.comedi.org. However, the driver's support for
49 loading the firmware through comedi_config is currently
54 #include <linux/interrupt.h>
55 #include "../comedidev.h"
57 #include <linux/delay.h>
58 #include <linux/list.h>
59 #include <linux/spinlock.h>
63 /* file removed due to GPL incompatibility */
64 #include "me4000_fw.h"
67 #define PCI_VENDOR_ID_MEILHAUS 0x1402
69 #define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650
70 #define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660
71 #define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661
72 #define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662
73 #define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663
74 #define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670
75 #define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671
76 #define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672
77 #define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673
78 #define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680
79 #define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681
80 #define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682
81 #define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683
85 unsigned short device_id;
96 static const struct me4000_board me4000_boards[] = {
99 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4650,
104 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660,
111 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660I,
118 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660S,
126 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660IS,
134 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670,
143 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670I,
152 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670S,
162 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670IS,
172 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680,
182 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680I,
192 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680S,
203 .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680IS,
215 /*-----------------------------------------------------------------------------
216 Meilhaus function prototypes
217 ---------------------------------------------------------------------------*/
218 static int xilinx_download(struct comedi_device *dev);
219 static int reset_board(struct comedi_device *dev);
221 static int ai_write_chanlist(struct comedi_device *dev,
222 struct comedi_subdevice *s,
223 struct comedi_cmd *cmd);
225 static const struct comedi_lrange me4000_ai_range = {
235 static const struct comedi_lrange me4000_ao_range = {
242 static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
244 struct me4000_info *info;
245 struct pci_dev *pci_device = NULL;
247 const struct me4000_board *board;
249 /* Allocate private memory */
250 result = alloc_private(dev, sizeof(*info));
256 * Probe the device to determine what device in the series it is.
258 for_each_pci_dev(pci_device) {
259 if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) {
260 for (i = 0; i < ARRAY_SIZE(me4000_boards); i++) {
261 if (me4000_boards[i].device_id ==
262 pci_device->device) {
265 * bus/slot requested?
267 if ((it->options[0] != 0)
268 || (it->options[1] != 0)) {
270 * Are we on the wrong
273 if (pci_device->bus->number !=
276 PCI_SLOT(pci_device->devfn)
281 dev->board_ptr = me4000_boards + i;
282 board = comedi_board(dev);
283 info->pci_dev_p = pci_device;
292 dev->board_name = board->name;
294 result = comedi_pci_enable(pci_device, dev->board_name);
298 info->plx_regbase = pci_resource_start(pci_device, 1);
299 if (!info->plx_regbase)
302 dev->iobase = pci_resource_start(pci_device, 2);
306 info->timer_regbase = pci_resource_start(pci_device, 3);
307 if (!info->timer_regbase)
310 info->program_regbase = pci_resource_start(pci_device, 5);
311 if (!info->program_regbase)
314 dev->irq = pci_device->irq;
316 result = xilinx_download(dev);
320 result = reset_board(dev);
327 #define FIRMWARE_NOT_AVAILABLE 1
328 #if FIRMWARE_NOT_AVAILABLE
329 extern unsigned char *xilinx_firm;
332 static int xilinx_download(struct comedi_device *dev)
334 struct me4000_info *info = dev->private;
336 wait_queue_head_t queue;
340 init_waitqueue_head(&queue);
343 * Set PLX local interrupt 2 polarity to high.
344 * Interrupt is thrown by init pin of xilinx.
346 outl(0x10, info->plx_regbase + PLX_INTCSR);
348 /* Set /CS and /WRITE of the Xilinx */
349 value = inl(info->plx_regbase + PLX_ICR);
351 outl(value, info->plx_regbase + PLX_ICR);
353 /* Init Xilinx with CS1 */
354 inb(info->program_regbase + 0xC8);
356 /* Wait until /INIT pin is set */
358 if (!(inl(info->plx_regbase + PLX_INTCSR) & 0x20)) {
360 "comedi%d: me4000: xilinx_download(): "
361 "Can't init Xilinx\n", dev->minor);
365 /* Reset /CS and /WRITE of the Xilinx */
366 value = inl(info->plx_regbase + PLX_ICR);
368 outl(value, info->plx_regbase + PLX_ICR);
369 if (FIRMWARE_NOT_AVAILABLE) {
370 comedi_error(dev, "xilinx firmware unavailable "
371 "due to licensing, aborting");
374 /* Download Xilinx firmware */
375 size = (xilinx_firm[0] << 24) + (xilinx_firm[1] << 16) +
376 (xilinx_firm[2] << 8) + xilinx_firm[3];
379 for (idx = 0; idx < size; idx++) {
380 outb(xilinx_firm[16 + idx], info->program_regbase);
383 /* Check if BUSY flag is low */
384 if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
386 "comedi%d: me4000: xilinx_download(): "
387 "Xilinx is still busy (idx = %d)\n",
394 /* If done flag is high download was successful */
395 if (inl(info->plx_regbase + PLX_ICR) & 0x4) {
398 "comedi%d: me4000: xilinx_download(): "
399 "DONE flag is not set\n", dev->minor);
401 "comedi%d: me4000: xilinx_download(): "
402 "Download not successful\n", dev->minor);
406 /* Set /CS and /WRITE */
407 value = inl(info->plx_regbase + PLX_ICR);
409 outl(value, info->plx_regbase + PLX_ICR);
414 static int reset_board(struct comedi_device *dev)
416 struct me4000_info *info = dev->private;
420 /* Make a hardware reset */
421 val = inl(info->plx_regbase + PLX_ICR);
423 outl(val, info->plx_regbase + PLX_ICR);
425 outl(val , info->plx_regbase + PLX_ICR);
427 /* 0x8000 to the DACs means an output voltage of 0V */
428 for (chan = 0; chan < 4; chan++)
429 outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan));
431 /* Set both stop bits in the analog input control register */
432 outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
433 dev->iobase + ME4000_AI_CTRL_REG);
435 /* Set both stop bits in the analog output control register */
436 val = ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP;
437 for (chan = 0; chan < 4; chan++)
438 outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan));
440 /* Enable interrupts on the PLX */
441 outl(0x43, info->plx_regbase + PLX_INTCSR);
443 /* Set the adustment register for AO demux */
444 outl(ME4000_AO_DEMUX_ADJUST_VALUE,
445 dev->iobase + ME4000_AO_DEMUX_ADJUST_REG);
448 * Set digital I/O direction for port 0
449 * to output on isolated versions
451 if (!(inl(dev->iobase + ME4000_DIO_DIR_REG) & 0x1))
452 outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG);
457 /*=============================================================================
459 ===========================================================================*/
461 static int me4000_ai_insn_read(struct comedi_device *dev,
462 struct comedi_subdevice *subdevice,
463 struct comedi_insn *insn, unsigned int *data)
465 const struct me4000_board *thisboard = comedi_board(dev);
466 int chan = CR_CHAN(insn->chanspec);
467 int rang = CR_RANGE(insn->chanspec);
468 int aref = CR_AREF(insn->chanspec);
470 unsigned long entry = 0;
476 } else if (insn->n > 1) {
478 "comedi%d: me4000: me4000_ai_insn_read(): "
479 "Invalid instruction length %d\n", dev->minor, insn->n);
485 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
488 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
491 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
494 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
498 "comedi%d: me4000: me4000_ai_insn_read(): "
499 "Invalid range specified\n", dev->minor);
506 if (chan >= thisboard->ai_nchan) {
508 "comedi%d: me4000: me4000_ai_insn_read(): "
509 "Analog input is not available\n", dev->minor);
512 entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan;
516 if (rang == 0 || rang == 1) {
518 "comedi%d: me4000: me4000_ai_insn_read(): "
519 "Range must be bipolar when aref = diff\n",
524 if (chan >= thisboard->ai_diff_nchan) {
526 "comedi%d: me4000: me4000_ai_insn_read(): "
527 "Analog input is not available\n", dev->minor);
530 entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan;
534 "comedi%d: me4000: me4000_ai_insn_read(): "
535 "Invalid aref specified\n", dev->minor);
539 entry |= ME4000_AI_LIST_LAST_ENTRY;
541 /* Clear channel list, data fifo and both stop bits */
542 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
543 tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
544 ME4000_AI_CTRL_BIT_DATA_FIFO |
545 ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
546 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
548 /* Set the acquisition mode to single */
549 tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 |
550 ME4000_AI_CTRL_BIT_MODE_2);
551 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
553 /* Enable channel list and data fifo */
554 tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO;
555 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
557 /* Generate channel list entry */
558 outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
560 /* Set the timer to maximum sample rate */
561 outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
562 outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
564 /* Start conversion by dummy read */
565 inl(dev->iobase + ME4000_AI_START_REG);
567 /* Wait until ready */
569 if (!(inl(dev->iobase + ME4000_AI_STATUS_REG) &
570 ME4000_AI_STATUS_BIT_EF_DATA)) {
572 "comedi%d: me4000: me4000_ai_insn_read(): "
573 "Value not available after wait\n", dev->minor);
577 /* Read value from data fifo */
578 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
579 data[0] = lval ^ 0x8000;
584 static int me4000_ai_cancel(struct comedi_device *dev,
585 struct comedi_subdevice *s)
589 /* Stop any running conversion */
590 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
591 tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
592 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
594 /* Clear the control register */
595 outl(0x0, dev->iobase + ME4000_AI_CTRL_REG);
600 static int ai_check_chanlist(struct comedi_device *dev,
601 struct comedi_subdevice *s, struct comedi_cmd *cmd)
603 const struct me4000_board *thisboard = comedi_board(dev);
607 /* Check whether a channel list is available */
608 if (!cmd->chanlist_len) {
610 "comedi%d: me4000: ai_check_chanlist(): "
611 "No channel list available\n", dev->minor);
615 /* Check the channel list size */
616 if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) {
618 "comedi%d: me4000: ai_check_chanlist(): "
619 "Channel list is to large\n", dev->minor);
623 /* Check the pointer */
624 if (!cmd->chanlist) {
626 "comedi%d: me4000: ai_check_chanlist(): "
627 "NULL pointer to channel list\n", dev->minor);
631 /* Check whether aref is equal for all entries */
632 aref = CR_AREF(cmd->chanlist[0]);
633 for (i = 0; i < cmd->chanlist_len; i++) {
634 if (CR_AREF(cmd->chanlist[i]) != aref) {
636 "comedi%d: me4000: ai_check_chanlist(): "
637 "Mode is not equal for all entries\n",
643 /* Check whether channels are available for this ending */
644 if (aref == SDF_DIFF) {
645 for (i = 0; i < cmd->chanlist_len; i++) {
646 if (CR_CHAN(cmd->chanlist[i]) >=
647 thisboard->ai_diff_nchan) {
649 "comedi%d: me4000: ai_check_chanlist():"
650 " Channel number to high\n", dev->minor);
655 for (i = 0; i < cmd->chanlist_len; i++) {
656 if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai_nchan) {
658 "comedi%d: me4000: ai_check_chanlist(): "
659 "Channel number to high\n", dev->minor);
665 /* Check if bipolar is set for all entries when in differential mode */
666 if (aref == SDF_DIFF) {
667 for (i = 0; i < cmd->chanlist_len; i++) {
668 if (CR_RANGE(cmd->chanlist[i]) != 1 &&
669 CR_RANGE(cmd->chanlist[i]) != 2) {
671 "comedi%d: me4000: ai_check_chanlist(): "
672 "Bipolar is not selected in "
673 "differential mode\n",
683 static int ai_round_cmd_args(struct comedi_device *dev,
684 struct comedi_subdevice *s,
685 struct comedi_cmd *cmd,
686 unsigned int *init_ticks,
687 unsigned int *scan_ticks, unsigned int *chan_ticks)
696 if (cmd->start_arg) {
697 *init_ticks = (cmd->start_arg * 33) / 1000;
698 rest = (cmd->start_arg * 33) % 1000;
700 if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
703 } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
709 if (cmd->scan_begin_arg) {
710 *scan_ticks = (cmd->scan_begin_arg * 33) / 1000;
711 rest = (cmd->scan_begin_arg * 33) % 1000;
713 if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
716 } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
722 if (cmd->convert_arg) {
723 *chan_ticks = (cmd->convert_arg * 33) / 1000;
724 rest = (cmd->convert_arg * 33) % 1000;
726 if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
729 } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
738 static void ai_write_timer(struct comedi_device *dev,
739 unsigned int init_ticks,
740 unsigned int scan_ticks, unsigned int chan_ticks)
742 outl(init_ticks - 1, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG);
743 outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG);
746 outl(scan_ticks - 1, dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG);
747 outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG);
750 outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
751 outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG);
754 static int ai_prepare(struct comedi_device *dev,
755 struct comedi_subdevice *s,
756 struct comedi_cmd *cmd,
757 unsigned int init_ticks,
758 unsigned int scan_ticks, unsigned int chan_ticks)
761 unsigned long tmp = 0;
763 /* Write timer arguments */
764 ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks);
766 /* Reset control register */
767 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
770 if ((cmd->start_src == TRIG_EXT &&
771 cmd->scan_begin_src == TRIG_TIMER &&
772 cmd->convert_src == TRIG_TIMER) ||
773 (cmd->start_src == TRIG_EXT &&
774 cmd->scan_begin_src == TRIG_FOLLOW &&
775 cmd->convert_src == TRIG_TIMER)) {
776 tmp = ME4000_AI_CTRL_BIT_MODE_1 |
777 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
778 ME4000_AI_CTRL_BIT_DATA_FIFO;
779 } else if (cmd->start_src == TRIG_EXT &&
780 cmd->scan_begin_src == TRIG_EXT &&
781 cmd->convert_src == TRIG_TIMER) {
782 tmp = ME4000_AI_CTRL_BIT_MODE_2 |
783 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
784 ME4000_AI_CTRL_BIT_DATA_FIFO;
785 } else if (cmd->start_src == TRIG_EXT &&
786 cmd->scan_begin_src == TRIG_EXT &&
787 cmd->convert_src == TRIG_EXT) {
788 tmp = ME4000_AI_CTRL_BIT_MODE_0 |
789 ME4000_AI_CTRL_BIT_MODE_1 |
790 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
791 ME4000_AI_CTRL_BIT_DATA_FIFO;
793 tmp = ME4000_AI_CTRL_BIT_MODE_0 |
794 ME4000_AI_CTRL_BIT_CHANNEL_FIFO |
795 ME4000_AI_CTRL_BIT_DATA_FIFO;
799 if (cmd->stop_src == TRIG_COUNT) {
800 outl(cmd->chanlist_len * cmd->stop_arg,
801 dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
802 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
803 } else if (cmd->stop_src == TRIG_NONE &&
804 cmd->scan_end_src == TRIG_COUNT) {
805 outl(cmd->scan_end_arg,
806 dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
807 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ;
809 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ;
812 /* Write the setup to the control register */
813 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
815 /* Write the channel list */
816 ai_write_chanlist(dev, s, cmd);
821 static int ai_write_chanlist(struct comedi_device *dev,
822 struct comedi_subdevice *s, struct comedi_cmd *cmd)
830 for (i = 0; i < cmd->chanlist_len; i++) {
831 chan = CR_CHAN(cmd->chanlist[i]);
832 rang = CR_RANGE(cmd->chanlist[i]);
833 aref = CR_AREF(cmd->chanlist[i]);
838 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
840 entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
842 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
844 entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
846 if (aref == SDF_DIFF)
847 entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
849 entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED;
851 outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
857 static int me4000_ai_do_cmd(struct comedi_device *dev,
858 struct comedi_subdevice *s)
861 unsigned int init_ticks = 0;
862 unsigned int scan_ticks = 0;
863 unsigned int chan_ticks = 0;
864 struct comedi_cmd *cmd = &s->async->cmd;
866 /* Reset the analog input */
867 err = me4000_ai_cancel(dev, s);
871 /* Round the timer arguments */
872 err = ai_round_cmd_args(dev,
873 s, cmd, &init_ticks, &scan_ticks, &chan_ticks);
877 /* Prepare the AI for acquisition */
878 err = ai_prepare(dev, s, cmd, init_ticks, scan_ticks, chan_ticks);
882 /* Start acquistion by dummy read */
883 inl(dev->iobase + ME4000_AI_START_REG);
889 * me4000_ai_do_cmd_test():
891 * The demo cmd.c in ./comedilib/demo specifies 6 return values:
896 * - argument conflict
898 * So I tried to adopt this scheme.
900 static int me4000_ai_do_cmd_test(struct comedi_device *dev,
901 struct comedi_subdevice *s,
902 struct comedi_cmd *cmd)
905 unsigned int init_ticks;
906 unsigned int chan_ticks;
907 unsigned int scan_ticks;
910 /* Only rounding flags are implemented */
911 cmd->flags &= TRIG_ROUND_NEAREST | TRIG_ROUND_UP | TRIG_ROUND_DOWN;
913 /* Round the timer arguments */
914 ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks);
917 * Stage 1. Check if the trigger sources are generally valid.
919 switch (cmd->start_src) {
924 cmd->start_src &= TRIG_NOW | TRIG_EXT;
929 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
930 "Invalid start source\n", dev->minor);
931 cmd->start_src = TRIG_NOW;
934 switch (cmd->scan_begin_src) {
940 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT;
945 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
946 "Invalid scan begin source\n", dev->minor);
947 cmd->scan_begin_src = TRIG_FOLLOW;
950 switch (cmd->convert_src) {
955 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
960 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
961 "Invalid convert source\n", dev->minor);
962 cmd->convert_src = TRIG_TIMER;
965 switch (cmd->scan_end_src) {
970 cmd->scan_end_src &= TRIG_NONE | TRIG_COUNT;
975 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
976 "Invalid scan end source\n", dev->minor);
977 cmd->scan_end_src = TRIG_NONE;
980 switch (cmd->stop_src) {
985 cmd->stop_src &= TRIG_NONE | TRIG_COUNT;
990 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
991 "Invalid stop source\n", dev->minor);
992 cmd->stop_src = TRIG_NONE;
999 * Stage 2. Check for trigger source conflicts.
1001 if (cmd->start_src == TRIG_NOW &&
1002 cmd->scan_begin_src == TRIG_TIMER &&
1003 cmd->convert_src == TRIG_TIMER) {
1004 } else if (cmd->start_src == TRIG_NOW &&
1005 cmd->scan_begin_src == TRIG_FOLLOW &&
1006 cmd->convert_src == TRIG_TIMER) {
1007 } else if (cmd->start_src == TRIG_EXT &&
1008 cmd->scan_begin_src == TRIG_TIMER &&
1009 cmd->convert_src == TRIG_TIMER) {
1010 } else if (cmd->start_src == TRIG_EXT &&
1011 cmd->scan_begin_src == TRIG_FOLLOW &&
1012 cmd->convert_src == TRIG_TIMER) {
1013 } else if (cmd->start_src == TRIG_EXT &&
1014 cmd->scan_begin_src == TRIG_EXT &&
1015 cmd->convert_src == TRIG_TIMER) {
1016 } else if (cmd->start_src == TRIG_EXT &&
1017 cmd->scan_begin_src == TRIG_EXT &&
1018 cmd->convert_src == TRIG_EXT) {
1021 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1022 "Invalid start trigger combination\n", dev->minor);
1023 cmd->start_src = TRIG_NOW;
1024 cmd->scan_begin_src = TRIG_FOLLOW;
1025 cmd->convert_src = TRIG_TIMER;
1029 if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) {
1030 } else if (cmd->stop_src == TRIG_COUNT &&
1031 cmd->scan_end_src == TRIG_NONE) {
1032 } else if (cmd->stop_src == TRIG_NONE &&
1033 cmd->scan_end_src == TRIG_COUNT) {
1034 } else if (cmd->stop_src == TRIG_COUNT &&
1035 cmd->scan_end_src == TRIG_COUNT) {
1038 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1039 "Invalid stop trigger combination\n", dev->minor);
1040 cmd->stop_src = TRIG_NONE;
1041 cmd->scan_end_src = TRIG_NONE;
1048 * Stage 3. Check if arguments are generally valid.
1050 if (cmd->chanlist_len < 1) {
1052 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1053 "No channel list\n", dev->minor);
1054 cmd->chanlist_len = 1;
1057 if (init_ticks < 66) {
1059 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1060 "Start arg to low\n", dev->minor);
1061 cmd->start_arg = 2000;
1064 if (scan_ticks && scan_ticks < 67) {
1066 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1067 "Scan begin arg to low\n", dev->minor);
1068 cmd->scan_begin_arg = 2031;
1071 if (chan_ticks < 66) {
1073 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1074 "Convert arg to low\n", dev->minor);
1075 cmd->convert_arg = 2000;
1083 * Stage 4. Check for argument conflicts.
1085 if (cmd->start_src == TRIG_NOW &&
1086 cmd->scan_begin_src == TRIG_TIMER &&
1087 cmd->convert_src == TRIG_TIMER) {
1089 /* Check timer arguments */
1090 if (init_ticks < ME4000_AI_MIN_TICKS) {
1092 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1093 "Invalid start arg\n", dev->minor);
1094 cmd->start_arg = 2000; /* 66 ticks at least */
1097 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1099 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1100 "Invalid convert arg\n", dev->minor);
1101 cmd->convert_arg = 2000; /* 66 ticks at least */
1104 if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
1106 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1107 "Invalid scan end arg\n", dev->minor);
1109 /* At least one tick more */
1110 cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
1113 } else if (cmd->start_src == TRIG_NOW &&
1114 cmd->scan_begin_src == TRIG_FOLLOW &&
1115 cmd->convert_src == TRIG_TIMER) {
1117 /* Check timer arguments */
1118 if (init_ticks < ME4000_AI_MIN_TICKS) {
1120 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1121 "Invalid start arg\n", dev->minor);
1122 cmd->start_arg = 2000; /* 66 ticks at least */
1125 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1127 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1128 "Invalid convert arg\n", dev->minor);
1129 cmd->convert_arg = 2000; /* 66 ticks at least */
1132 } else if (cmd->start_src == TRIG_EXT &&
1133 cmd->scan_begin_src == TRIG_TIMER &&
1134 cmd->convert_src == TRIG_TIMER) {
1136 /* Check timer arguments */
1137 if (init_ticks < ME4000_AI_MIN_TICKS) {
1139 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1140 "Invalid start arg\n", dev->minor);
1141 cmd->start_arg = 2000; /* 66 ticks at least */
1144 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1146 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1147 "Invalid convert arg\n", dev->minor);
1148 cmd->convert_arg = 2000; /* 66 ticks at least */
1151 if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
1153 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1154 "Invalid scan end arg\n", dev->minor);
1156 /* At least one tick more */
1157 cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
1160 } else if (cmd->start_src == TRIG_EXT &&
1161 cmd->scan_begin_src == TRIG_FOLLOW &&
1162 cmd->convert_src == TRIG_TIMER) {
1164 /* Check timer arguments */
1165 if (init_ticks < ME4000_AI_MIN_TICKS) {
1167 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1168 "Invalid start arg\n", dev->minor);
1169 cmd->start_arg = 2000; /* 66 ticks at least */
1172 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1174 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1175 "Invalid convert arg\n", dev->minor);
1176 cmd->convert_arg = 2000; /* 66 ticks at least */
1179 } else if (cmd->start_src == TRIG_EXT &&
1180 cmd->scan_begin_src == TRIG_EXT &&
1181 cmd->convert_src == TRIG_TIMER) {
1183 /* Check timer arguments */
1184 if (init_ticks < ME4000_AI_MIN_TICKS) {
1186 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1187 "Invalid start arg\n", dev->minor);
1188 cmd->start_arg = 2000; /* 66 ticks at least */
1191 if (chan_ticks < ME4000_AI_MIN_TICKS) {
1193 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1194 "Invalid convert arg\n", dev->minor);
1195 cmd->convert_arg = 2000; /* 66 ticks at least */
1198 } else if (cmd->start_src == TRIG_EXT &&
1199 cmd->scan_begin_src == TRIG_EXT &&
1200 cmd->convert_src == TRIG_EXT) {
1202 /* Check timer arguments */
1203 if (init_ticks < ME4000_AI_MIN_TICKS) {
1205 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1206 "Invalid start arg\n", dev->minor);
1207 cmd->start_arg = 2000; /* 66 ticks at least */
1211 if (cmd->stop_src == TRIG_COUNT) {
1212 if (cmd->stop_arg == 0) {
1214 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1215 "Invalid stop arg\n", dev->minor);
1220 if (cmd->scan_end_src == TRIG_COUNT) {
1221 if (cmd->scan_end_arg == 0) {
1223 "comedi%d: me4000: me4000_ai_do_cmd_test(): "
1224 "Invalid scan end arg\n", dev->minor);
1225 cmd->scan_end_arg = 1;
1234 * Stage 5. Check the channel list.
1236 if (ai_check_chanlist(dev, s, cmd))
1242 static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
1245 struct comedi_device *dev = dev_id;
1246 struct comedi_subdevice *s = &dev->subdevices[0];
1254 /* Reset all events */
1255 s->async->events = 0;
1257 /* Check if irq number is right */
1258 if (irq != dev->irq) {
1260 "comedi%d: me4000: me4000_ai_isr(): "
1261 "Incorrect interrupt num: %d\n", dev->minor, irq);
1265 if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
1266 ME4000_IRQ_STATUS_BIT_AI_HF) {
1267 /* Read status register to find out what happened */
1268 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
1270 if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
1271 !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) &&
1272 (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
1273 c = ME4000_AI_FIFO_COUNT;
1276 * FIFO overflow, so stop conversion
1277 * and disable all interrupts
1279 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1280 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
1281 ME4000_AI_CTRL_BIT_SC_IRQ);
1282 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
1284 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
1287 "comedi%d: me4000: me4000_ai_isr(): "
1288 "FIFO overflow\n", dev->minor);
1289 } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
1290 && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
1291 && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
1292 s->async->events |= COMEDI_CB_BLOCK;
1294 c = ME4000_AI_FIFO_COUNT / 2;
1297 "comedi%d: me4000: me4000_ai_isr(): "
1298 "Can't determine state of fifo\n", dev->minor);
1302 * Undefined state, so stop conversion
1303 * and disable all interrupts
1305 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1306 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
1307 ME4000_AI_CTRL_BIT_SC_IRQ);
1308 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
1310 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
1313 "comedi%d: me4000: me4000_ai_isr(): "
1314 "Undefined FIFO state\n", dev->minor);
1317 for (i = 0; i < c; i++) {
1318 /* Read value from data fifo */
1319 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
1322 if (!comedi_buf_put(s->async, lval)) {
1324 * Buffer overflow, so stop conversion
1325 * and disable all interrupts
1327 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1328 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
1329 ME4000_AI_CTRL_BIT_SC_IRQ);
1330 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
1332 s->async->events |= COMEDI_CB_OVERFLOW;
1335 "comedi%d: me4000: me4000_ai_isr(): "
1336 "Buffer overflow\n", dev->minor);
1342 /* Work is done, so reset the interrupt */
1343 tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
1344 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
1345 tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
1346 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
1349 if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
1350 ME4000_IRQ_STATUS_BIT_SC) {
1351 s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA;
1354 * Acquisition is complete, so stop
1355 * conversion and disable all interrupts
1357 tmp = inl(dev->iobase + ME4000_AI_CTRL_REG);
1358 tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
1359 tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ);
1360 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
1362 /* Poll data until fifo empty */
1363 while (inl(dev->iobase + ME4000_AI_CTRL_REG) &
1364 ME4000_AI_STATUS_BIT_EF_DATA) {
1365 /* Read value from data fifo */
1366 lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
1369 if (!comedi_buf_put(s->async, lval)) {
1371 "comedi%d: me4000: me4000_ai_isr(): "
1372 "Buffer overflow\n", dev->minor);
1373 s->async->events |= COMEDI_CB_OVERFLOW;
1378 /* Work is done, so reset the interrupt */
1379 tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
1380 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
1381 tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
1382 outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
1385 if (s->async->events)
1386 comedi_event(dev, s);
1391 /*=============================================================================
1392 Analog output section
1393 ===========================================================================*/
1395 static int me4000_ao_insn_write(struct comedi_device *dev,
1396 struct comedi_subdevice *s,
1397 struct comedi_insn *insn, unsigned int *data)
1399 const struct me4000_board *thisboard = comedi_board(dev);
1400 struct me4000_info *info = dev->private;
1401 int chan = CR_CHAN(insn->chanspec);
1402 int rang = CR_RANGE(insn->chanspec);
1403 int aref = CR_AREF(insn->chanspec);
1408 } else if (insn->n > 1) {
1410 "comedi%d: me4000: me4000_ao_insn_write(): "
1411 "Invalid instruction length %d\n", dev->minor, insn->n);
1415 if (chan >= thisboard->ao_nchan) {
1417 "comedi%d: me4000: me4000_ao_insn_write(): "
1418 "Invalid channel %d\n", dev->minor, insn->n);
1424 "comedi%d: me4000: me4000_ao_insn_write(): "
1425 "Invalid range %d\n", dev->minor, insn->n);
1429 if (aref != AREF_GROUND && aref != AREF_COMMON) {
1431 "comedi%d: me4000: me4000_ao_insn_write(): "
1432 "Invalid aref %d\n", dev->minor, insn->n);
1436 /* Stop any running conversion */
1437 tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan));
1438 tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
1439 outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan));
1441 /* Clear control register and set to single mode */
1442 outl(0x0, dev->iobase + ME4000_AO_CTRL_REG(chan));
1444 /* Write data value */
1445 outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan));
1447 /* Store in the mirror */
1448 info->ao_readback[chan] = data[0];
1453 static int me4000_ao_insn_read(struct comedi_device *dev,
1454 struct comedi_subdevice *s,
1455 struct comedi_insn *insn, unsigned int *data)
1457 struct me4000_info *info = dev->private;
1458 int chan = CR_CHAN(insn->chanspec);
1462 } else if (insn->n > 1) {
1464 ("comedi%d: me4000: me4000_ao_insn_read(): "
1465 "Invalid instruction length\n", dev->minor);
1469 data[0] = info->ao_readback[chan];
1474 /*=============================================================================
1476 ===========================================================================*/
1478 static int me4000_dio_insn_bits(struct comedi_device *dev,
1479 struct comedi_subdevice *s,
1480 struct comedi_insn *insn, unsigned int *data)
1483 * The insn data consists of a mask in data[0] and the new data
1484 * in data[1]. The mask defines which bits we are concerning about.
1485 * The new data must be anded with the mask.
1486 * Each channel corresponds to a bit.
1489 /* Check if requested ports are configured for output */
1490 if ((s->io_bits & data[0]) != data[0])
1493 s->state &= ~data[0];
1494 s->state |= data[0] & data[1];
1496 /* Write out the new digital output lines */
1497 outl((s->state >> 0) & 0xFF,
1498 dev->iobase + ME4000_DIO_PORT_0_REG);
1499 outl((s->state >> 8) & 0xFF,
1500 dev->iobase + ME4000_DIO_PORT_1_REG);
1501 outl((s->state >> 16) & 0xFF,
1502 dev->iobase + ME4000_DIO_PORT_2_REG);
1503 outl((s->state >> 24) & 0xFF,
1504 dev->iobase + ME4000_DIO_PORT_3_REG);
1507 /* On return, data[1] contains the value of
1508 the digital input and output lines. */
1509 data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) |
1510 ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) |
1511 ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) |
1512 ((inl(dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24);
1517 static int me4000_dio_insn_config(struct comedi_device *dev,
1518 struct comedi_subdevice *s,
1519 struct comedi_insn *insn, unsigned int *data)
1522 int chan = CR_CHAN(insn->chanspec);
1527 case INSN_CONFIG_DIO_QUERY:
1529 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
1531 case INSN_CONFIG_DIO_INPUT:
1532 case INSN_CONFIG_DIO_OUTPUT:
1537 * The input or output configuration of each digital line is
1538 * configured by a special insn_config instruction. chanspec
1539 * contains the channel to be changed, and data[0] contains the
1540 * value INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_OUTPUT.
1541 * On the ME-4000 it is only possible to switch port wise (8 bit)
1544 tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG);
1546 if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
1549 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
1550 ME4000_DIO_CTRL_BIT_MODE_1);
1551 tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
1552 } else if (chan < 16) {
1554 * Chech for optoisolated ME-4000 version.
1555 * If one the first port is a fixed output
1556 * port and the second is a fixed input port.
1558 if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
1561 s->io_bits |= 0xFF00;
1562 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
1563 ME4000_DIO_CTRL_BIT_MODE_3);
1564 tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
1565 } else if (chan < 24) {
1566 s->io_bits |= 0xFF0000;
1567 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
1568 ME4000_DIO_CTRL_BIT_MODE_5);
1569 tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
1570 } else if (chan < 32) {
1571 s->io_bits |= 0xFF000000;
1572 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
1573 ME4000_DIO_CTRL_BIT_MODE_7);
1574 tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
1581 * Chech for optoisolated ME-4000 version.
1582 * If one the first port is a fixed output
1583 * port and the second is a fixed input port.
1585 if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
1588 s->io_bits &= ~0xFF;
1589 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
1590 ME4000_DIO_CTRL_BIT_MODE_1);
1591 } else if (chan < 16) {
1592 s->io_bits &= ~0xFF00;
1593 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
1594 ME4000_DIO_CTRL_BIT_MODE_3);
1595 } else if (chan < 24) {
1596 s->io_bits &= ~0xFF0000;
1597 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
1598 ME4000_DIO_CTRL_BIT_MODE_5);
1599 } else if (chan < 32) {
1600 s->io_bits &= ~0xFF000000;
1601 tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
1602 ME4000_DIO_CTRL_BIT_MODE_7);
1608 outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG);
1613 /*=============================================================================
1615 ===========================================================================*/
1617 static int cnt_reset(struct comedi_device *dev, unsigned int channel)
1619 struct me4000_info *info = dev->private;
1623 outb(0x30, info->timer_regbase + ME4000_CNT_CTRL_REG);
1624 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
1625 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
1628 outb(0x70, info->timer_regbase + ME4000_CNT_CTRL_REG);
1629 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
1630 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
1633 outb(0xB0, info->timer_regbase + ME4000_CNT_CTRL_REG);
1634 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
1635 outb(0x00, info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
1639 "comedi%d: me4000: cnt_reset(): Invalid channel\n",
1647 static int cnt_config(struct comedi_device *dev, unsigned int channel,
1650 struct me4000_info *info = dev->private;
1655 tmp |= ME4000_CNT_COUNTER_0;
1658 tmp |= ME4000_CNT_COUNTER_1;
1661 tmp |= ME4000_CNT_COUNTER_2;
1665 "comedi%d: me4000: cnt_config(): Invalid channel\n",
1672 tmp |= ME4000_CNT_MODE_0;
1675 tmp |= ME4000_CNT_MODE_1;
1678 tmp |= ME4000_CNT_MODE_2;
1681 tmp |= ME4000_CNT_MODE_3;
1684 tmp |= ME4000_CNT_MODE_4;
1687 tmp |= ME4000_CNT_MODE_5;
1691 "comedi%d: me4000: cnt_config(): Invalid counter mode\n",
1696 /* Write the control word */
1698 outb(tmp, info->timer_regbase + ME4000_CNT_CTRL_REG);
1703 static int me4000_cnt_insn_config(struct comedi_device *dev,
1704 struct comedi_subdevice *s,
1705 struct comedi_insn *insn, unsigned int *data)
1714 "comedi%d: me4000: me4000_cnt_insn_config(): "
1715 "Invalid instruction length%d\n",
1716 dev->minor, insn->n);
1720 err = cnt_reset(dev, insn->chanspec);
1724 case GPCT_SET_OPERATION:
1727 "comedi%d: me4000: me4000_cnt_insn_config(): "
1728 "Invalid instruction length%d\n",
1729 dev->minor, insn->n);
1733 err = cnt_config(dev, insn->chanspec, data[1]);
1739 "comedi%d: me4000: me4000_cnt_insn_config(): "
1740 "Invalid instruction\n", dev->minor);
1747 static int me4000_cnt_insn_read(struct comedi_device *dev,
1748 struct comedi_subdevice *s,
1749 struct comedi_insn *insn, unsigned int *data)
1751 struct me4000_info *info = dev->private;
1759 "comedi%d: me4000: me4000_cnt_insn_read(): "
1760 "Invalid instruction length %d\n",
1761 dev->minor, insn->n);
1765 switch (insn->chanspec) {
1767 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
1769 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
1770 data[0] |= tmp << 8;
1773 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
1775 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
1776 data[0] |= tmp << 8;
1779 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
1781 tmp = inb(info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
1782 data[0] |= tmp << 8;
1786 "comedi%d: me4000: me4000_cnt_insn_read(): "
1787 "Invalid channel %d\n",
1788 dev->minor, insn->chanspec);
1795 static int me4000_cnt_insn_write(struct comedi_device *dev,
1796 struct comedi_subdevice *s,
1797 struct comedi_insn *insn, unsigned int *data)
1799 struct me4000_info *info = dev->private;
1804 } else if (insn->n > 1) {
1806 "comedi%d: me4000: me4000_cnt_insn_write(): "
1807 "Invalid instruction length %d\n",
1808 dev->minor, insn->n);
1812 switch (insn->chanspec) {
1814 tmp = data[0] & 0xFF;
1815 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
1816 tmp = (data[0] >> 8) & 0xFF;
1817 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_0_REG);
1820 tmp = data[0] & 0xFF;
1821 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
1822 tmp = (data[0] >> 8) & 0xFF;
1823 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_1_REG);
1826 tmp = data[0] & 0xFF;
1827 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
1828 tmp = (data[0] >> 8) & 0xFF;
1829 outb(tmp, info->timer_regbase + ME4000_CNT_COUNTER_2_REG);
1833 "comedi%d: me4000: me4000_cnt_insn_write(): "
1834 "Invalid channel %d\n",
1835 dev->minor, insn->chanspec);
1842 static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1844 const struct me4000_board *thisboard;
1845 struct comedi_subdevice *s;
1848 result = me4000_probe(dev, it);
1851 thisboard = comedi_board(dev);
1853 result = comedi_alloc_subdevices(dev, 4);
1857 /*=========================================================================
1858 Analog input subdevice
1859 ========================================================================*/
1861 s = &dev->subdevices[0];
1863 if (thisboard->ai_nchan) {
1864 s->type = COMEDI_SUBD_AI;
1866 SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
1867 s->n_chan = thisboard->ai_nchan;
1868 s->maxdata = 0xFFFF; /* 16 bit ADC */
1869 s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
1870 s->range_table = &me4000_ai_range;
1871 s->insn_read = me4000_ai_insn_read;
1874 if (request_irq(dev->irq, me4000_ai_isr,
1875 IRQF_SHARED, "ME-4000", dev)) {
1877 ("comedi%d: me4000: me4000_attach(): "
1878 "Unable to allocate irq\n", dev->minor);
1880 dev->read_subdev = s;
1881 s->subdev_flags |= SDF_CMD_READ;
1882 s->cancel = me4000_ai_cancel;
1883 s->do_cmdtest = me4000_ai_do_cmd_test;
1884 s->do_cmd = me4000_ai_do_cmd;
1888 "comedi%d: me4000: me4000_attach(): "
1889 "No interrupt available\n", dev->minor);
1892 s->type = COMEDI_SUBD_UNUSED;
1895 /*=========================================================================
1896 Analog output subdevice
1897 ========================================================================*/
1899 s = &dev->subdevices[1];
1901 if (thisboard->ao_nchan) {
1902 s->type = COMEDI_SUBD_AO;
1903 s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
1904 s->n_chan = thisboard->ao_nchan;
1905 s->maxdata = 0xFFFF; /* 16 bit DAC */
1906 s->range_table = &me4000_ao_range;
1907 s->insn_write = me4000_ao_insn_write;
1908 s->insn_read = me4000_ao_insn_read;
1910 s->type = COMEDI_SUBD_UNUSED;
1913 /*=========================================================================
1914 Digital I/O subdevice
1915 ========================================================================*/
1917 s = &dev->subdevices[2];
1919 if (thisboard->dio_nchan) {
1920 s->type = COMEDI_SUBD_DIO;
1921 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1922 s->n_chan = thisboard->dio_nchan;
1924 s->range_table = &range_digital;
1925 s->insn_bits = me4000_dio_insn_bits;
1926 s->insn_config = me4000_dio_insn_config;
1928 s->type = COMEDI_SUBD_UNUSED;
1932 * Check for optoisolated ME-4000 version. If one the first
1933 * port is a fixed output port and the second is a fixed input port.
1935 if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) {
1937 outl(ME4000_DIO_CTRL_BIT_MODE_0,
1938 dev->iobase + ME4000_DIO_DIR_REG);
1941 /*=========================================================================
1943 ========================================================================*/
1945 s = &dev->subdevices[3];
1947 if (thisboard->has_counter) {
1948 s->type = COMEDI_SUBD_COUNTER;
1949 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1951 s->maxdata = 0xFFFF; /* 16 bit counters */
1952 s->insn_read = me4000_cnt_insn_read;
1953 s->insn_write = me4000_cnt_insn_write;
1954 s->insn_config = me4000_cnt_insn_config;
1956 s->type = COMEDI_SUBD_UNUSED;
1962 static void me4000_detach(struct comedi_device *dev)
1964 struct me4000_info *info = dev->private;
1967 if (info->pci_dev_p) {
1969 if (info->plx_regbase)
1970 comedi_pci_disable(info->pci_dev_p);
1971 pci_dev_put(info->pci_dev_p);
1976 static struct comedi_driver me4000_driver = {
1977 .driver_name = "me4000",
1978 .module = THIS_MODULE,
1979 .attach = me4000_attach,
1980 .detach = me4000_detach,
1983 static int __devinit me4000_pci_probe(struct pci_dev *dev,
1984 const struct pci_device_id *ent)
1986 return comedi_pci_auto_config(dev, &me4000_driver);
1989 static void __devexit me4000_pci_remove(struct pci_dev *dev)
1991 comedi_pci_auto_unconfig(dev);
1994 static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
1995 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650)},
1996 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660)},
1997 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I)},
1998 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660S)},
1999 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660IS)},
2000 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670)},
2001 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I)},
2002 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S)},
2003 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS)},
2004 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680)},
2005 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I)},
2006 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S)},
2007 {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS)},
2010 MODULE_DEVICE_TABLE(pci, me4000_pci_table);
2012 static struct pci_driver me4000_pci_driver = {
2014 .id_table = me4000_pci_table,
2015 .probe = me4000_pci_probe,
2016 .remove = __devexit_p(me4000_pci_remove),
2018 module_comedi_pci_driver(me4000_driver, me4000_pci_driver);
2020 MODULE_AUTHOR("Comedi http://www.comedi.org");
2021 MODULE_DESCRIPTION("Comedi low-level driver");
2022 MODULE_LICENSE("GPL");