New driver by Dan Block via anders.blomdell@control.lth.se (Anders Blomdell).
authorFrank Mori Hess <fmhess@speakeasy.net>
Mon, 21 Nov 2005 02:05:28 +0000 (02:05 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Mon, 21 Nov 2005 02:05:28 +0000 (02:05 +0000)
comedi/drivers/Makefile.am
comedi/drivers/c6xdigio.c [new file with mode: 0644]

index 0670e7f42b210b81b3a43a82393bca72846ffbdf..5c1dd3accf9148079251bd7744d5ad6b77ec3db9 100644 (file)
@@ -99,6 +99,7 @@ module_PROGRAMS = \
  amplc_pc236.ko \
  amplc_pc263.ko \
  amplc_dio200.ko \
+ c6xdigio.ko \
  cb_pcidas.ko \
  cb_pcidas64.ko \
  cb_pcidda.ko \
diff --git a/comedi/drivers/c6xdigio.c b/comedi/drivers/c6xdigio.c
new file mode 100644 (file)
index 0000000..8b2162a
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+   module/c6xdigio.c
+   hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card.
+   (http://robot0.ge.uiuc.edu/~spong/mecha/)
+
+   COMEDI - Linux Control and Measurement Device Interface
+   Copyright (C) 1999 Dan Block
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <linux/comedidev.h>
+#include <linux/pnp.h>
+
+static u8 ReadByteFromHwPort(int addr)
+{
+  u8 result = inb(addr);
+  return result;
+}
+
+static void WriteByteToHwPort(int addr, u8 val)
+{
+  outb_p(val, addr);
+}
+#define C6XDIGIO_SIZE 3
+
+/*
+ * port offsets
+ */
+#define C6XDIGIO_PARALLEL_DATA 0
+#define C6XDIGIO_PARALLEL_STATUS 1
+#define C6XDIGIO_PARALLEL_CONTROL 2
+struct pwmbitstype {
+         unsigned sb0: 2;
+         unsigned sb1: 2;
+         unsigned sb2: 2;
+         unsigned sb3: 2;
+         unsigned sb4: 2;
+};
+union pwmcmdtype {
+       unsigned cmd;  // assuming here that int is 32bit
+       struct pwmbitstype bits;
+};
+struct encbitstype {
+       unsigned sb0: 3;
+       unsigned sb1: 3;
+       unsigned sb2: 3;
+       unsigned sb3: 3;
+       unsigned sb4: 3;
+       unsigned sb5: 3;
+       unsigned sb6: 3;
+       unsigned sb7: 3;
+};
+union encvaluetype {
+  unsigned value;
+  struct encbitstype bits;
+};
+
+#define C6XDIGIO_TIME_OUT 20
+
+static int c6xdigio_attach(comedi_device *dev,comedi_devconfig *it);
+static int c6xdigio_detach(comedi_device *dev);
+comedi_driver driver_c6xdigio={
+       driver_name:    "c6xdigio",
+       module:         THIS_MODULE,
+       attach:         c6xdigio_attach,
+       detach:         c6xdigio_detach,
+};
+
+static void  C6X_pwmInit( unsigned baseAddr ) {
+       int timeout=0;
+
+//printk("Inside C6X_pwmInit\n");
+
+       WriteByteToHwPort(baseAddr,0x70);
+       while ( ((ReadByteFromHwPort(baseAddr+1) & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               timeout++;
+       }
+
+       WriteByteToHwPort(baseAddr,0x74);
+       timeout=0;
+       while ( ((ReadByteFromHwPort(baseAddr+1) & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               timeout++;
+       }
+       
+       WriteByteToHwPort(baseAddr,0x70);
+       timeout=0;
+       while ( ((ReadByteFromHwPort(baseAddr+1) & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               timeout++;
+       }
+       
+       WriteByteToHwPort(baseAddr,0x0);
+       timeout=0;
+       while ( ((ReadByteFromHwPort(baseAddr+1) & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               timeout++;
+       }
+       
+}
+
+static void  C6X_pwmOutput( unsigned baseAddr, unsigned channel, int value )
+{
+       unsigned ppcmd;
+       union pwmcmdtype pwm;
+       int timeout=0;
+       unsigned tmp;     
+
+
+       //printk("Inside C6X_pwmOutput\n");
+
+       pwm.cmd = value;
+       if (pwm.cmd > 498)
+       pwm.cmd = 498;
+       if (pwm.cmd < 2)
+       pwm.cmd = 2;
+
+       if (channel == 0) {
+               ppcmd = 0x28;
+       } else {   // if channel == 1
+               ppcmd = 0x30;
+       } /* endif */
+
+       WriteByteToHwPort(baseAddr,ppcmd+pwm.bits.sb0);
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       
+       WriteByteToHwPort(baseAddr,ppcmd+pwm.bits.sb1+0x4);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       
+       WriteByteToHwPort(baseAddr,ppcmd+pwm.bits.sb2);
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       
+       WriteByteToHwPort(baseAddr,ppcmd+pwm.bits.sb3+0x4);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       
+       WriteByteToHwPort(baseAddr,ppcmd+pwm.bits.sb4);
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       
+       WriteByteToHwPort(baseAddr,0x0);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       
+}
+
+static int C6X_encInput( unsigned baseAddr, unsigned channel)
+{
+       unsigned ppcmd;
+       union encvaluetype enc;
+       int timeout=0;
+       int tmp;
+
+
+       //printk("Inside C6X_encInput\n");
+
+       enc.value = 0;
+       if (channel == 0) {
+               ppcmd = 0x48;
+       } else {
+               ppcmd = 0x50;
+       }
+       WriteByteToHwPort(baseAddr,ppcmd);
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+
+       enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr+1) >> 3) & 0x7);
+       WriteByteToHwPort(baseAddr,ppcmd+0x4);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr+1) >> 3) & 0x7);
+       WriteByteToHwPort(baseAddr,ppcmd);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr+1) >> 3) & 0x7);
+       WriteByteToHwPort(baseAddr,ppcmd+0x4);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr+1) >> 3) & 0x7);
+       WriteByteToHwPort(baseAddr,ppcmd);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr+1) >> 3) & 0x7);
+       WriteByteToHwPort(baseAddr,ppcmd+0x4);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr+1) >> 3) & 0x7);
+       WriteByteToHwPort(baseAddr,ppcmd);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr+1) >> 3) & 0x7);
+       WriteByteToHwPort(baseAddr,ppcmd+0x4);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+       enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr+1) >> 3) & 0x7);
+       WriteByteToHwPort(baseAddr,ppcmd);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+
+       WriteByteToHwPort(baseAddr,0x0);
+       timeout=0;
+       tmp = ReadByteFromHwPort(baseAddr+1);
+       while ( ((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               tmp = ReadByteFromHwPort(baseAddr+1);
+               timeout++;
+       }
+
+       return(enc.value ^ 0x800000);
+}
+
+static void C6X_encResetAll( unsigned baseAddr )
+{
+    unsigned timeout=0;
+
+//printk("Inside C6X_encResetAll\n");
+
+       WriteByteToHwPort(baseAddr,0x68);
+       while ( ((ReadByteFromHwPort(baseAddr+1) & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               timeout++;
+       }
+       WriteByteToHwPort(baseAddr,0x6C);
+       timeout=0;
+       while ( ((ReadByteFromHwPort(baseAddr+1) & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               timeout++;
+       }
+       WriteByteToHwPort(baseAddr,0x68);
+       timeout=0;
+       while ( ((ReadByteFromHwPort(baseAddr+1) & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               timeout++;
+       }
+       WriteByteToHwPort(baseAddr,0x0);
+       timeout=0;
+       while ( ((ReadByteFromHwPort(baseAddr+1) & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT) ) {
+               timeout++;
+       }
+}
+
+
+static int c6xdigio_pwmo_insn_read(comedi_device *dev, 
+                                  comedi_subdevice *s,
+                                  comedi_insn *insn, 
+                                  lsampl_t *data)
+{
+  printk("c6xdigio_pwmo_insn_read %x\n", insn->n);
+  return insn->n;
+}
+
+static int c6xdigio_pwmo_insn_write(comedi_device *dev, 
+                                  comedi_subdevice *s,
+                                  comedi_insn *insn, 
+                                  lsampl_t *data)
+{
+  int i;
+  int chan = CR_CHAN(insn->chanspec);
+
+  //  printk("c6xdigio_pwmo_insn_write %x\n", insn->n);
+  for(i=0;i<insn->n;i++){
+    C6X_pwmOutput(dev->iobase, chan, data[i]);
+    /*    devpriv->ao_readback[chan] = data[i];*/
+  }
+  return i;
+}
+
+
+//static int c6xdigio_ei_init_insn_read(comedi_device *dev, 
+//                                comedi_subdevice *s,
+//                                comedi_insn *insn, 
+//                                lsampl_t *data)
+//{
+//  printk("c6xdigio_ei_init_insn_read %x\n", insn->n);
+//  return insn->n;
+//}
+
+//static int c6xdigio_ei_init_insn_write(comedi_device *dev, 
+//                                comedi_subdevice *s,
+//                                comedi_insn *insn, 
+//                                lsampl_t *data)
+//{
+//  int i;
+//  int chan = CR_CHAN(insn->chanspec);
+//
+//  C6X_encResetAll( dev->iobase );
+//  
+//  return insn->n;
+//}
+
+static int c6xdigio_ei_insn_read(comedi_device *dev, 
+                                  comedi_subdevice *s,
+                                  comedi_insn *insn, 
+                                  lsampl_t *data)
+{
+  //  printk("c6xdigio_ei__insn_read %x\n", insn->n);
+  int n;
+  int chan = CR_CHAN(insn->chanspec);
+
+  for(n=0;n<insn->n;n++){
+       data[n] = (C6X_encInput(dev->iobase,chan) & 0xffffff);
+  }
+
+  return n;
+}
+
+
+static void board_init(comedi_device *dev) {
+
+  //printk("Inside board_init\n");
+
+  C6X_pwmInit(dev->iobase);
+  C6X_encResetAll(dev->iobase);
+  
+}
+
+//static void board_halt(comedi_device *dev) {
+//  C6X_pwmInit(dev->iobase);
+//}
+
+/*
+   options[0] - I/O port
+   options[1] - irq
+   options[2] - number of encoder chips installed
+ */
+
+static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
+        /* Standard LPT Printer Port */
+        {.id = "PNP0400", .driver_data = 0},
+        /* ECP Printer Port */
+        {.id = "PNP0401", .driver_data = 0},
+        { }
+};
+
+static struct pnp_driver c6xdigio_pnp_driver = {
+        .name           = "c6xdigio",
+        .id_table       = c6xdigio_pnp_tbl,
+};
+
+static int c6xdigio_attach(comedi_device * dev, comedi_devconfig * it)
+{
+  int result = 0;
+  int iobase;
+  int irq;
+  comedi_subdevice *s;
+
+    iobase = it->options[0];
+    printk("comedi%d: c6xdigio: 0x%04x\n", dev->minor, iobase);
+    if (!request_region(iobase, C6XDIGIO_SIZE, "c6xdigio")) {
+      printk("comedi%d: I/O port conflict\n", dev->minor);
+      return -EIO;
+    }
+    dev->iobase = iobase;
+    dev->board_name = "c6xdigio";
+    
+    result = alloc_subdevices(dev, 2); // 3 with encoder_init write
+    if(result<0)return result;
+    
+    // Make sure that PnP ports gets activated
+    pnp_register_driver (&c6xdigio_pnp_driver);
+
+
+      irq = it->options[1];
+      if (irq > 0) {
+       printk("comedi%d: irq = %d ignored\n", dev->minor, irq);
+      } else if(irq == 0) {
+       printk("comedi%d: no irq\n", dev->minor);
+      }
+
+      s = dev->subdevices + 0;
+      /* pwm output subdevice */
+      s->type = COMEDI_SUBD_AO;  // Not sure what to put here
+      s->subdev_flags = SDF_WRITEABLE;
+      s->n_chan = 2;
+      /*      s->trig[0] = c6xdigio_pwmo;*/
+      s->insn_read = c6xdigio_pwmo_insn_read;
+      s->insn_write = c6xdigio_pwmo_insn_write;
+      s->maxdata = 500;
+      s->range_table = &range_bipolar10; // A suitable lie
+
+      s = dev->subdevices + 1;
+      /* encoder (counter) subdevice */
+      s->type = COMEDI_SUBD_COUNTER;
+      s->subdev_flags = SDF_READABLE | SDF_LSAMPL; 
+      s->n_chan = 2;
+      /* s->trig[0] = c6xdigio_ei;*/
+      s->insn_read = c6xdigio_ei_insn_read;
+      s->maxdata = 0xffffff;
+      s->range_table = &range_unknown;
+
+      //         s = dev->subdevices + 2;
+      //      /* pwm output subdevice */
+      //      s->type = COMEDI_SUBD_COUNTER;  // Not sure what to put here
+      //      s->subdev_flags = SDF_WRITEABLE;
+      //      s->n_chan = 1;
+      //      /* s->trig[0] = c6xdigio_ei_init; */
+      //      s->insn_read = c6xdigio_ei_init_insn_read;
+      //      s->insn_write = c6xdigio_ei_init_insn_write;
+      //      s->maxdata = 0xFFFF;  // Really just a don't care
+      //      s->range_table = &range_unknown; // Not sure what to put here
+
+         // I will call this init anyway but more than likely the DSP board will not be connect
+         // when device driver is loaded.
+      board_init(dev);
+
+
+  return 0;
+}
+
+
+static int c6xdigio_detach(comedi_device * dev)
+{
+//  board_halt(dev);  // may not need this
+
+  printk("comedi%d: c6xdigio: remove\n", dev->minor);
+
+  if (dev->iobase) { release_region(dev->iobase, C6XDIGIO_SIZE); }
+  if (dev->irq) { free_irq(dev->irq,dev); }  // Not using IRQ so I am not sure if I need this
+  pnp_unregister_driver (&c6xdigio_pnp_driver);
+
+  return 0;
+}
+
+
+#ifdef MODULE
+int init_module(void)
+{
+       comedi_driver_register(&driver_c6xdigio);
+       
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       comedi_driver_unregister(&driver_c6xdigio);
+}
+#endif
+
+
+