Module: xenomai-head
Branch: master
Commit: 350062394f8d6d5f851fb6db7e9dc16a6f95b648
URL:    
http://git.xenomai.org/?p=xenomai-head.git;a=commit;h=350062394f8d6d5f851fb6db7e9dc16a6f95b648

Author: Alexis Berlemont <alexis.berlem...@gmail.com>
Date:   Sun Nov  8 02:20:48 2009 +0100

analogy: add an analogy driver for standard parallel port

WARNING: the arguments management in some instruction functions is not
coherent with the one in the NI PCIMIO driver. This issue has to be
fixed shortly.

---

 ksrc/drivers/analogy/intel/Kconfig   |    9 +-
 ksrc/drivers/analogy/intel/Makefile  |   15 +-
 ksrc/drivers/analogy/intel/parport.c |  428 ++++++++++++++++++++++++++++++++++
 3 files changed, 447 insertions(+), 5 deletions(-)

diff --git a/ksrc/drivers/analogy/intel/Kconfig 
b/ksrc/drivers/analogy/intel/Kconfig
index 6271d19..193c9da 100644
--- a/ksrc/drivers/analogy/intel/Kconfig
+++ b/ksrc/drivers/analogy/intel/Kconfig
@@ -1,5 +1,10 @@
 
 config XENO_DRIVERS_ANALOGY_8255
-       depends on XENO_DRIVERS_ANALOGY && EXPERIMENTAL
+       depends on XENO_DRIVERS_ANALOGY
        tristate "8255 driver"
-       default n
\ No newline at end of file
+       default n
+
+config XENO_DRIVERS_ANALOGY_PARPORT
+       depends on XENO_DRIVERS_ANALOGY
+       tristate "Standard parallel port driver"
+       default n
diff --git a/ksrc/drivers/analogy/intel/Makefile 
b/ksrc/drivers/analogy/intel/Makefile
index 57ea839..e708c39 100644
--- a/ksrc/drivers/analogy/intel/Makefile
+++ b/ksrc/drivers/analogy/intel/Makefile
@@ -6,8 +6,13 @@ EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai
 
 obj-$(CONFIG_XENO_DRIVERS_ANALOGY_8255) += analogy_8255.o
 
+obj-$(CONFIG_XENO_DRIVERS_ANALOGY_PARPORT) += analogy_parport.o
+
 analogy_8255-y := 8255.o
 
+analogy_parport-y := parport.o
+
+
 else
 
 # Makefile frag for Linux v2.4
@@ -16,15 +21,19 @@ O_TARGET := built-in.o
 
 obj-$(CONFIG_XENO_DRIVERS_ANALOGY_8255) += analogy_8255.o
 
+obj-$(CONFIG_XENO_DRIVERS_ANALOGY_PARPORT) += analogy_parport.o
+
 analogy_8255-objs := 8255.o
 
-export-objs := $(analgoy_8255-objs)
+analogy_parport-objs := parport.o
+
+export-objs := $(analgoy_8255-objs) $(analgoy_parport-objs)
 
 EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai 
-I$(TOPDIR)/include/xenomai/compat
 
 include $(TOPDIR)/Rules.make
 
-analogy_8255.o: $(analogy_8255-objs)
-       $(LD) -r -o $@ $(analogy_8255-objs)
+analogy_8255.o: $(analogy_8255-objs) $(analgoy_parport-objs)
+       $(LD) -r -o $@ $(analogy_8255-objs) $(analgoy_parport-objs)
 
 endif
diff --git a/ksrc/drivers/analogy/intel/parport.c 
b/ksrc/drivers/analogy/intel/parport.c
new file mode 100644
index 0000000..6abc5b4
--- /dev/null
+++ b/ksrc/drivers/analogy/intel/parport.c
@@ -0,0 +1,428 @@
+/**
+ * @file
+ * Analogy driver for standard parallel port
+ * @note Copyright (C) 1998,2001 David A. Schleef <d...@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+
+/* 
+   A cheap and easy way to get a few more digital I/O lines.  Steal
+   additional parallel ports from old computers or your neighbors'
+   computers.
+
+   Option list:
+   0: I/O port base for the parallel port.
+   1: IRQ
+
+   Parallel Port Lines:
+
+   pin     subdev  chan    aka
+   ---     ------  ----    ---
+   1       2       0       strobe
+   2       0       0       data 0
+   3       0       1       data 1
+   4       0       2       data 2
+   5       0       3       data 3
+   6       0       4       data 4
+   7       0       5       data 5
+   8       0       6       data 6
+   9       0       7       data 7
+   10      1       3       acknowledge
+   11      1       4       busy
+   12      1       2       output
+   13      1       1       printer selected
+   14      2       1       auto LF
+   15      1       0       error
+   16      2       2       init
+   17      2       3       select printer
+   18-25   ground
+
+   Notes:
+
+   Subdevices 0 is digital I/O, subdevice 1 is digital input, and
+   subdevice 2 is digital output.  Unlike other Analogy devices,
+   subdevice 0 defaults to output.
+
+   Pins 13 and 14 are inverted once by Comedi and once by the
+   hardware, thus cancelling the effect.
+
+   Pin 1 is a strobe, thus acts like one.  There's no way in software
+   to change this, at least on a standard parallel port.
+
+   Subdevice 3 pretends to be a digital input subdevice, but it always
+   returns 0 when read.  However, if you run a command with
+   scan_begin_src=TRIG_EXT, it uses pin 10 as a external triggering
+   pin, which can be used to wake up tasks.
+
+   see http://www.beyondlogic.org/ for information.
+   or http://www.linux-magazin.de/ausgabe/1999/10/IO/io.html
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <analogy/analogy_driver.h>
+
+#define PARPORT_SIZE 3
+
+#define PARPORT_A 0
+#define PARPORT_B 1
+#define PARPORT_C 2
+
+typedef struct parport_subd_priv {
+       unsigned long io_bits;
+} parport_spriv_t;
+
+typedef struct parport_priv {
+       unsigned long io_base;
+       unsigned int a_data;
+       unsigned int c_data;
+       int enable_irq;
+} parport_priv_t;
+
+#define devpriv ((parport_priv_t *)(dev->priv))
+
+static int parport_insn_a(a4l_subd_t *subd, a4l_kinsn_t *insn)
+{
+       a4l_dev_t *dev = subd->dev;
+
+       if (insn->data[0]) {
+               devpriv->a_data &= ~insn->data[0];
+               devpriv->a_data |= (insn->data[0] & insn->data[1]);
+
+               outb(devpriv->a_data, devpriv->io_base + PARPORT_A);
+       }
+
+       insn->data[1] = inb(devpriv->io_base + PARPORT_A);
+
+       return 0;
+}
+
+static int parport_insn_config_a(a4l_subd_t *subd, a4l_kinsn_t *insn)
+{
+       a4l_dev_t *dev = subd->dev;
+       parport_spriv_t *spriv = (parport_spriv_t *)subd->priv;
+
+       if (insn->data[0]) {
+               spriv->io_bits = 0xff;
+               devpriv->c_data &= ~(1 << 5);
+       } else {
+               spriv->io_bits = 0;
+               devpriv->c_data |= (1 << 5);
+       }
+       outb(devpriv->c_data, devpriv->io_base + PARPORT_C);
+
+       return 0;
+}
+
+static int parport_insn_b(a4l_subd_t *subd, a4l_kinsn_t *insn)
+{
+       a4l_dev_t *dev = subd->dev;
+
+       if (insn->data[0]) {
+               /* should writes be ignored? */
+       }
+
+       insn->data[1] = (inb(devpriv->io_base + PARPORT_B) >> 3);
+
+       return 0;
+}
+
+static int parport_insn_c(a4l_subd_t *subd, a4l_kinsn_t *insn)
+{
+       a4l_dev_t *dev = subd->dev;
+
+       insn->data[0] &= 0x0f;
+       if (insn->data[0]) {
+               devpriv->c_data &= ~insn->data[0];
+               devpriv->c_data |= (insn->data[0] & insn->data[1]);
+
+               outb(devpriv->c_data, devpriv->io_base + PARPORT_C);
+       }
+
+       insn->data[1] = devpriv->c_data & 0xf;
+
+       return 2;
+}
+
+static int parport_intr_insn(a4l_subd_t *subd, a4l_kinsn_t *insn)
+{
+       if (insn->data_size < 1)
+               return -EINVAL;
+
+       insn->data[1] = 0;
+       return 0;
+}
+
+static a4l_cmd_t parport_intr_cmd_mask = {
+       .idx_subd = 0,
+       .start_src = TRIG_NOW,
+       .scan_begin_src = TRIG_EXT,
+       .convert_src = TRIG_FOLLOW,
+       .scan_end_src = TRIG_COUNT,
+       .stop_src = TRIG_NONE,
+};
+
+static int parport_intr_cmdtest(a4l_subd_t *subd, a4l_cmd_t * cmd)
+{
+
+       if (cmd->start_arg != 0) {
+               return -EINVAL;
+       }
+       if (cmd->scan_begin_arg != 0) {
+               return -EINVAL;
+       }
+       if (cmd->convert_arg != 0) {
+               return -EINVAL;
+       }
+       if (cmd->scan_end_arg != 1) {
+               return -EINVAL;
+       }
+       if (cmd->stop_arg != 0) {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int parport_intr_cmd(a4l_subd_t *subd, a4l_cmd_t *cmd)
+{
+       a4l_dev_t *dev = subd->dev;
+
+       devpriv->c_data |= 0x10;
+       outb(devpriv->c_data, devpriv->io_base + PARPORT_C);
+
+       devpriv->enable_irq = 1;
+
+       return 0;
+}
+
+static int parport_intr_cancel(a4l_subd_t *subd)
+{
+       a4l_dev_t *dev = subd->dev;
+
+       a4l_info(dev, "parport_intr_cancel: cancel in progress\n");
+
+       devpriv->c_data &= ~0x10;
+       outb(devpriv->c_data, devpriv->io_base + PARPORT_C);
+
+       devpriv->enable_irq = 0;
+
+       return 0;
+}
+
+static int parport_interrupt(unsigned int irq, void *d)
+{
+       a4l_dev_t *dev = d;
+       a4l_subd_t *subd = a4l_get_subd(dev, 3);
+
+       if (!devpriv->enable_irq) {
+               a4l_err(dev, "parport_interrupt: bogus irq, ignored\n");
+               return IRQ_NONE;
+       }
+
+       a4l_buf_put(subd, 0, sizeof(unsigned int));
+       a4l_buf_evt(subd, 0);
+       
+       return 0;
+}
+
+
+/* --- Channels descriptor --- */
+
+static a4l_chdesc_t parport_chan_desc_a = {
+       .mode = A4L_CHAN_GLOBAL_CHANDESC,
+       .length = 8,
+       .chans = { 
+               {A4L_CHAN_AREF_GROUND, 1},
+       },
+};
+
+static a4l_chdesc_t parport_chan_desc_b = {
+       .mode = A4L_CHAN_GLOBAL_CHANDESC,
+       .length = 5,
+       .chans = { 
+               {A4L_CHAN_AREF_GROUND, 1},
+       },
+};
+
+static a4l_chdesc_t parport_chan_desc_c = {
+       .mode = A4L_CHAN_GLOBAL_CHANDESC,
+       .length = 4,
+       .chans = { 
+               {A4L_CHAN_AREF_GROUND, 1},
+       },
+};
+
+static a4l_chdesc_t parport_chan_desc_intr = {
+       .mode = A4L_CHAN_GLOBAL_CHANDESC,
+       .length = 1,
+       .chans = { 
+               {A4L_CHAN_AREF_GROUND, 1},
+       },
+};
+
+/* --- Subdevice initialization functions --- */
+
+static void setup_subd_a(a4l_subd_t *subd)
+{
+       subd->flags = A4L_SUBD_DIO;
+       subd->chan_desc = &parport_chan_desc_a;
+       subd->rng_desc = &range_digital;
+       subd->insn_bits = parport_insn_a;
+       subd->insn_config = parport_insn_config_a;
+}
+
+static void setup_subd_b(a4l_subd_t *subd)
+{
+       subd->flags = A4L_SUBD_DI;
+       subd->chan_desc = &parport_chan_desc_b;
+       subd->rng_desc = &range_digital;
+       subd->insn_bits = parport_insn_b;
+}
+
+static void setup_subd_c(a4l_subd_t *subd)
+{
+       subd->flags = A4L_SUBD_DO;
+       subd->chan_desc = &parport_chan_desc_c;
+       subd->rng_desc = &range_digital;
+       subd->insn_bits = parport_insn_c;
+}
+
+static void setup_subd_intr(a4l_subd_t *subd)
+{
+       subd->flags = A4L_SUBD_DI;
+       subd->chan_desc = &parport_chan_desc_intr;
+       subd->rng_desc = &range_digital;
+       subd->insn_bits = parport_intr_insn;
+       subd->cmd_mask = &parport_intr_cmd_mask;
+       subd->do_cmdtest = parport_intr_cmdtest;
+       subd->do_cmd = parport_intr_cmd;
+       subd->cancel = parport_intr_cancel;
+}
+
+static void (*setup_subds[3])(a4l_subd_t *) = {
+       setup_subd_a,
+       setup_subd_b,
+       setup_subd_c
+};
+
+static int dev_parport_attach(a4l_dev_t *dev, a4l_lnkdesc_t *arg)
+{
+       int i, err = 0, irq = A4L_IRQ_UNUSED;
+       unsigned long io_base;
+
+       if(arg->opts == NULL || arg->opts_size < sizeof(unsigned long)) {
+               a4l_err(dev, 
+                       "dev_parport_attach: "
+                       "unable to detect any parallel port, "
+                       "no addresses / IRQ passed as attach arguments\n");
+               return -EINVAL;
+       }
+
+       io_base = ((unsigned long *)arg->opts)[0];
+
+       if (!request_region(io_base, PARPORT_SIZE, "analogy_parport")) {
+               a4l_err(dev, "dev_parport_attach: I/O port conflict");
+               return -EIO;
+       }
+
+       a4l_info(dev, "dev_parport_attach: address = 0x%lx\n", io_base);
+       
+       if (arg->opts_size == 2 * sizeof(unsigned long))
+               irq = (int) ((unsigned long *)arg->opts)[1];
+
+       for (i = 0; i < 3; i++) {
+               
+               a4l_subd_t *subd = a4l_alloc_subd(sizeof(parport_spriv_t), 
+                                                 setup_subds[i]);
+               if (subd == NULL)
+                       return -ENOMEM;
+               
+               err = a4l_add_subd(dev, subd);
+               if (err != i)
+                       return err;             
+       }
+
+       if (irq != A4L_IRQ_UNUSED) {
+
+               a4l_subd_t *subd;
+
+               a4l_info(dev, "dev_parport_attach: irq = 0x%d\n", irq);
+
+               err = a4l_request_irq(dev, irq, parport_interrupt, 0, dev);
+               if (err < 0) {
+                       a4l_err(dev, "dev_parport_attach: irq not available\n");
+                       return err;
+               }
+
+               subd = a4l_alloc_subd(0, setup_subd_intr);
+               if (subd == NULL)
+                       return -ENOMEM;
+               
+               err = a4l_add_subd(dev, subd);
+               if (err < 0)
+                       return err;
+       }
+
+       devpriv->io_base = io_base;
+
+       devpriv->a_data = 0;
+       outb(devpriv->a_data, devpriv->io_base + PARPORT_A);
+
+       devpriv->c_data = 0;
+       outb(devpriv->c_data, devpriv->io_base + PARPORT_C);
+
+       return 0;
+}
+
+static int dev_parport_detach(a4l_dev_t *dev)
+{
+       int err = 0;
+
+       if (devpriv->io_base != 0)
+               release_region(devpriv->io_base, PARPORT_SIZE);
+       
+       if (a4l_get_irq(dev) != A4L_IRQ_UNUSED) {
+               a4l_free_irq(dev, a4l_get_irq(dev));
+       }
+
+       
+       return err;
+}
+
+static a4l_drv_t drv_parport = {
+       .owner = THIS_MODULE,
+       .board_name = "analogy_parport",
+       .attach = dev_parport_attach,
+       .detach = dev_parport_detach,   
+       .privdata_size = sizeof(parport_priv_t),
+};
+
+static int __init drv_parport_init(void)
+{
+       return a4l_register_drv(&drv_parport);
+}
+
+static void __exit drv_parport_cleanup(void)
+{
+       a4l_unregister_drv(&drv_parport);
+}
+
+MODULE_DESCRIPTION("Analogy driver for standard parallel port");
+MODULE_LICENSE("GPL");
+
+module_init(drv_parport_init);
+module_exit(drv_parport_cleanup);


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to