All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jerome Poncin <JPoncin@hilscher.com>
To: xenomai@xenomai.org
Subject: Re: [Xenomai] Hilscher driver for cifX boards
Date: Mon, 04 Mar 2013 10:13:51 +0100	[thread overview]
Message-ID: <513465CF.4030807@hilscher.com> (raw)
In-Reply-To: <5130B39C.70300@hilscher.com>

Hello,

I did two patch one for version head, and for 2.6 version in attached 
files.  The result is identical.

Therefore, I let you

"perform a code review and merge
the code if it is fine."

For information, I checked a complete kernel compilation with cifX driver, and it's running good on xenomai version 2.6.2.1.

Thank you very much for your help.


Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44


-------------- next part --------------
diff --git a/ksrc/drivers/cifx/Config.in b/ksrc/drivers/cifx/Config.in
new file mode 100644
index 0000000..b4e6be1
--- /dev/null
+++ b/ksrc/drivers/cifx/Config.in
@@ -0,0 +1,10 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+mainmenu_option next_comment
+comment 'Real-time Hilscher cifX driver'
+
+dep_tristate 'Hilscher cifX' CONFIG_XENO_DRIVERS_CIFX $CONFIG_XENO_SKIN_RTDM
+
+endmenu
diff --git a/ksrc/drivers/cifx/Config.in~ b/ksrc/drivers/cifx/Config.in~
new file mode 100644
index 0000000..2bbb0bb
--- /dev/null
+++ b/ksrc/drivers/cifx/Config.in~
@@ -0,0 +1,10 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+mainmenu_option next_comment
+comment 'Real-time Hilscher cifX driver'
+
+dep_tristate 'Hilscher cifX driver' CONFIG_XENO_DRIVERS_CIFX $CONFIG_XENO_SKIN_RTDM
+
+endmenu
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Kconfig~ b/ksrc/drivers/cifx/Kconfig~
new file mode 100644
index 0000000..914d6e6
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig~
@@ -0,0 +1,11 @@
+menu "Real-time IPC drivers"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..63cbc00
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,37 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-objs := cifx_pci.o
+
+opt_objs-y :=
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+xeno_cifx_pci-objs += $(opt_objs-y)
+
+export-objs := $(xeno_cifx_pci-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_cifx_pci.o: $(xeno_cifx_pci-objs)
+	$(LD) -r -o $@ $(xeno_cifx_pci-objs)
+
+endif
diff --git a/ksrc/drivers/cifx/Makefile~ b/ksrc/drivers/cifx/Makefile~
new file mode 100644
index 0000000..3c90f1a
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile~
@@ -0,0 +1,41 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_rtipc.o
+
+xeno_rtipc-y := rtipc.o
+
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_XDDP) += xddp.o
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_IDDP) += iddp.o
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_BUFP) += bufp.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_RTIPC) += xeno_rtipc.o
+
+xeno_rtipc-objs := rtipc.o
+
+opt_objs-y :=
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_XDDP) += xddp.o
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_IDDP) += iddp.o
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_BUFP) += bufp.o
+
+xeno_rtipc-objs += $(opt_objs-y)
+
+export-objs := $(xeno_rtipc-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_rtipc.o: $(xeno_rtipc-objs)
+	$(LD) -r -o $@ $(xeno_rtipc-objs)
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..677367d
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,1189 @@
+/***************************************************************************
+ *   Copyright (C) 2013                                                    *
+ *   Hilscher France (JP)                                                  *
+ *   http://www.hilscher.fr                                                *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+/*****************************************************************************/
+
+/* Includes */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <rtdm/rtdm_driver.h>
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+/*****************************************************************************/
+/*!
+ *   \addtogroup cifx_pci_Core
+ *   @{
+ */
+/*****************************************************************************/
+
+/* #define */
+
+#ifndef TRUE
+#define TRUE                            1
+#endif				/* TRUE */
+
+#ifndef FALSE
+#define FALSE                           0
+#endif				/* TRUE */
+
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER          0x15CF
+#endif				/* PCI_VENDOR_ID_HILSCHER */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
+#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA          0x3335
+#endif				/* PCI_SUBDEVICE_ID_NXPCA */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+/*****************************************************************************/
+
+/* structure */
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	uint8_t irq_enable;
+	uint8_t irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+/*****************************************************************************/
+
+/* Prototypes */
+
+#ifdef IRQ_SUPPORT
+static int cifx_handler(rtdm_irq_t *irq);
+#endif /* IRQ_SUPPORT */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/*****************************************************************************/
+
+/* Local variables */
+
+/** Number or cifx found and open */
+static int32_t cifx_num;
+
+/** RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/** Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETX,
+		.subvendor = 0,
+		.subdevice = 0,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/** RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*****************************************************************************/
+
+#ifdef IRQ_SUPPORT
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_handler
+ *
+ *   \param  [in]	irq       Resource task pointer
+ *
+ *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
+ *
+ *   \note   cifx interrupt handler
+ */
+/*****************************************************************************/
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info =
+	    (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
+	struct io_info_t *device_data = (struct io_info_t *)info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == FALSE)
+	    || (device_data->irq_enable == FALSE)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+#endif /* IRQ_SUPPORT */
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_set_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Set plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_dpm_mode
+ *
+ *	 \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get dpm mode
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_open
+ *
+ *   \param	[in]	context		context
+ *   \param	[in]	user_info	user information
+ *	 \param	[in]	oflags		flags (flag IRQ used)
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Open RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	int32_t ret;
+
+	/* Test if (oflags) IRQ are use */
+	if (oflags == TRUE) {
+		if (((struct io_info_t *)info->device_data)->irq_registered
+		    == FALSE) {
+			/* Register IRQ */
+			ret =
+			    rtdm_irq_request(&
+					     (((struct io_info_t *)info->
+					       device_data)->irq_handle),
+					     ((struct io_info_t *)info->
+					      device_data)->irq, cifx_handler,
+					     RTDM_IRQTYPE_SHARED,
+					     info->device_name, (void *)info);
+
+			if (ret != 0) {
+#ifdef DEBUG
+				switch (ret) {
+				case -EINVAL:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: an invalid parameter was passed\n");
+					break;
+				case -EBUSY:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: the specified IRQ line is already in use\n");
+					break;
+				default:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request error\n");
+					break;
+				}
+#endif /* DEBUG */
+
+				return -ENODEV;
+			} else
+				((io_info_t *) info->
+				 device_data)->irq_registered = TRUE;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_close
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *
+ *	\return 0 (OK) or Error
+ *
+ *	\note	Close RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (((struct io_info_t *)info->device_data)->irq_registered == TRUE) {
+		if (((struct io_info_t *)info->device_data)->
+							irq_enable == TRUE) {
+			/* Disable IRQ */
+			if (rtdm_irq_disable
+			    (&
+			     (((struct io_info_t *)info->device_data)->
+			      irq_handle)) != 0) {
+#ifdef DEBUG
+				rtdm_printk(
+			"cifx rtdm driver error : rtdm_irq_disable error\n");
+#endif /* DEBUG */
+
+				return -ENODEV;
+			}
+		}
+
+		/* Unregister IRQ */
+		if (rtdm_irq_free
+		    (&(((struct io_info_t *)info->device_data)->irq_handle)) !=
+		    0) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_irq_free error\n");
+#endif /* DEBUG */
+
+			return -ENODEV;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *  \brief  cifx_pci_read
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *  \return size read
+ *
+ *  \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_write
+ *
+ *  \param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *   \return size read
+ *
+ *   \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	uint8_t irq_enable;
+#endif /* IRQ_SUPPORT */
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+#ifdef IRQ_SUPPORT
+	if (nbyte == sizeof(uint8_t)) {
+		/* Copy data for Kernel */
+		if (rtdm_safe_copy_from_user
+		    (user_info, &irq_enable, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (((((struct io_info *)info->device_data)->
+			     irq_enable) != irq_enable)
+			&& (((struct io_info *)info->device_data)->
+				    irq_registered == TRUE)) {
+					if (irq_enable == TRUE) {
+						/* Enable IRQ */
+						rtdm_irq_enable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					} else {
+						/* Disable IRQ */
+						rtdm_irq_disable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					}
+
+					((struct io_info *)info->device_data)->
+					    irq_enable = irq_enable;
+				}
+			}
+		}
+	} else if (nbyte == sizeof(struct io_map_mem)) {
+#else /* IRQ_SUPPORT */
+	if (nbyte == sizeof(struct io_map_mem)) {
+#endif /* IRQ_SUPPORT */
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_probe
+ *
+ *   \param  [in]   dev
+ *   \param  [in]   id
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note  Open the device.
+ *			This function is called when the device shall be opened.
+ */
+/*****************************************************************************/
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (!pxa_info->plx)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = FALSE;
+	((struct io_info *)device_data)->irq_registered = FALSE;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_remove
+ *
+ *   \param [in] dev
+ *
+ *   \return None
+ *
+ *   \note   Close the device.
+ *   This function is called when the device shall be closed.
+ */
+/*****************************************************************************/
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_init
+ *
+ *   \return None
+ *
+ *   \note   It simply registers the RTDM device.
+ *   This function is called when the module is loaded.
+ */
+/*****************************************************************************/
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_exit
+ *
+ *   \return None
+ *
+ *   \note  It unregister the RTDM device.
+ *   This function is called when the module is unloaded.
+ */
+/*****************************************************************************/
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*! \}     cifx_pci_Core                                                     */
+/*****************************************************************************/
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */
diff --git a/ksrc/drivers/cifx/cifx_pci.c~ b/ksrc/drivers/cifx/cifx_pci.c~
new file mode 100644
index 0000000..2b3ffea
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c~
@@ -0,0 +1,1190 @@
+/***************************************************************************
+ *   Copyright (C) 2013                                                    *
+ *   Hilscher France (JP)                                                  *
+ *   http://www.hilscher.fr                                                *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+/*****************************************************************************/
+
+/* Includes */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#include <linux/mman.h>
+
+#include <rtdm/rtdm_driver.h>
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+/*****************************************************************************/
+/*!
+ *   \addtogroup cifx_pci_Core
+ *   @{
+ */
+/*****************************************************************************/
+
+/* #define */
+
+#ifndef TRUE
+#define TRUE                            1
+#endif				/* TRUE */
+
+#ifndef FALSE
+#define FALSE                           0
+#endif				/* TRUE */
+
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER          0x15CF
+#endif				/* PCI_VENDOR_ID_HILSCHER */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
+#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA          0x3335
+#endif				/* PCI_SUBDEVICE_ID_NXPCA */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+/*****************************************************************************/
+
+/* structure */
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	uint8_t irq_enable;
+	uint8_t irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+/*****************************************************************************/
+
+/* Prototypes */
+
+#ifdef IRQ_SUPPORT
+static int cifx_handler(rtdm_irq_t *irq);
+#endif /* IRQ_SUPPORT */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/*****************************************************************************/
+
+/* Local variables */
+
+/** Number or cifx found and open */
+static int32_t cifx_num;
+
+/** RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/** Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETX,
+		.subvendor = 0,
+		.subdevice = 0,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/** RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*****************************************************************************/
+
+#ifdef IRQ_SUPPORT
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_handler
+ *
+ *   \param  [in]	irq       Resource task pointer
+ *
+ *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
+ *
+ *   \note   cifx interrupt handler
+ */
+/*****************************************************************************/
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info =
+	    (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
+	struct io_info_t *device_data = (struct io_info_t *)info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == FALSE)
+	    || (device_data->irq_enable == FALSE)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+#endif /* IRQ_SUPPORT */
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_set_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Set plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_dpm_mode
+ *
+ *	 \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get dpm mode
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_open
+ *
+ *   \param	[in]	context		context
+ *   \param	[in]	user_info	user information
+ *	 \param	[in]	oflags		flags (flag IRQ used)
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Open RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	int32_t ret;
+
+	/* Test if (oflags) IRQ are use */
+	if (oflags == TRUE) {
+		if (((struct io_info_t *)info->device_data)->irq_registered
+		    == FALSE) {
+			/* Register IRQ */
+			ret =
+			    rtdm_irq_request(&
+					     (((struct io_info_t *)info->
+					       device_data)->irq_handle),
+					     ((struct io_info_t *)info->
+					      device_data)->irq, cifx_handler,
+					     RTDM_IRQTYPE_SHARED,
+					     info->device_name, (void *)info);
+
+			if (ret != 0) {
+#ifdef DEBUG
+				switch (ret) {
+				case -EINVAL:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: an invalid parameter was passed\n");
+					break;
+				case -EBUSY:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: the specified IRQ line is already in use\n");
+					break;
+				default:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request error\n");
+					break;
+				}
+#endif /* DEBUG */
+
+				return -ENODEV;
+			} else
+				((io_info_t *) info->
+				 device_data)->irq_registered = TRUE;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_close
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *
+ *	\return 0 (OK) or Error
+ *
+ *	\note	Close RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (((struct io_info_t *)info->device_data)->irq_registered == TRUE) {
+		if (((struct io_info_t *)info->device_data)->
+							irq_enable == TRUE) {
+			/* Disable IRQ */
+			if (rtdm_irq_disable
+			    (&
+			     (((struct io_info_t *)info->device_data)->
+			      irq_handle)) != 0) {
+#ifdef DEBUG
+				rtdm_printk(
+			"cifx rtdm driver error : rtdm_irq_disable error\n");
+#endif /* DEBUG */
+
+				return -ENODEV;
+			}
+		}
+
+		/* Unregister IRQ */
+		if (rtdm_irq_free
+		    (&(((struct io_info_t *)info->device_data)->irq_handle)) !=
+		    0) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_irq_free error\n");
+#endif /* DEBUG */
+
+			return -ENODEV;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *  \brief  cifx_pci_read
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *  \return size read
+ *
+ *  \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_write
+ *
+ *  \param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *   \return size read
+ *
+ *   \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	uint8_t irq_enable;
+#endif /* IRQ_SUPPORT */
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+#ifdef IRQ_SUPPORT
+	if (nbyte == sizeof(uint8_t)) {
+		/* Copy data for Kernel */
+		if (rtdm_safe_copy_from_user
+		    (user_info, &irq_enable, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (((((struct io_info *)info->device_data)->
+			     irq_enable) != irq_enable)
+			&& (((struct io_info *)info->device_data)->
+				    irq_registered == TRUE)) {
+					if (irq_enable == TRUE) {
+						/* Enable IRQ */
+						rtdm_irq_enable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					} else {
+						/* Disable IRQ */
+						rtdm_irq_disable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					}
+
+					((struct io_info *)info->device_data)->
+					    irq_enable = irq_enable;
+				}
+			}
+		}
+	} else if (nbyte == sizeof(struct io_map_mem)) {
+#else /* IRQ_SUPPORT */
+	if (nbyte == sizeof(struct io_map_mem)) {
+#endif /* IRQ_SUPPORT */
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_probe
+ *
+ *   \param  [in]   dev
+ *   \param  [in]   id
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note  Open the device.
+ *			This function is called when the device shall be opened.
+ */
+/*****************************************************************************/
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (!pxa_info->plx)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = FALSE;
+	((struct io_info *)device_data)->irq_registered = FALSE;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_remove
+ *
+ *   \param [in] dev
+ *
+ *   \return None
+ *
+ *   \note   Close the device.
+ *   This function is called when the device shall be closed.
+ */
+/*****************************************************************************/
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_init
+ *
+ *   \return None
+ *
+ *   \note   It simply registers the RTDM device.
+ *   This function is called when the module is loaded.
+ */
+/*****************************************************************************/
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_exit
+ *
+ *   \return None
+ *
+ *   \note  It unregister the RTDM device.
+ *   This function is called when the module is unloaded.
+ */
+/*****************************************************************************/
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*! \}     cifx_pci_Core                                                     */
+/*****************************************************************************/
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */
-------------- next part --------------
diff --git a/ksrc/drivers/cifx/Config.in b/ksrc/drivers/cifx/Config.in
new file mode 100644
index 0000000..b4e6be1
--- /dev/null
+++ b/ksrc/drivers/cifx/Config.in
@@ -0,0 +1,10 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+mainmenu_option next_comment
+comment 'Real-time Hilscher cifX driver'
+
+dep_tristate 'Hilscher cifX' CONFIG_XENO_DRIVERS_CIFX $CONFIG_XENO_SKIN_RTDM
+
+endmenu
diff --git a/ksrc/drivers/cifx/Config.in~ b/ksrc/drivers/cifx/Config.in~
new file mode 100644
index 0000000..2bbb0bb
--- /dev/null
+++ b/ksrc/drivers/cifx/Config.in~
@@ -0,0 +1,10 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+mainmenu_option next_comment
+comment 'Real-time Hilscher cifX driver'
+
+dep_tristate 'Hilscher cifX driver' CONFIG_XENO_DRIVERS_CIFX $CONFIG_XENO_SKIN_RTDM
+
+endmenu
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Kconfig~ b/ksrc/drivers/cifx/Kconfig~
new file mode 100644
index 0000000..914d6e6
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig~
@@ -0,0 +1,11 @@
+menu "Real-time IPC drivers"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..63cbc00
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,37 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-objs := cifx_pci.o
+
+opt_objs-y :=
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+xeno_cifx_pci-objs += $(opt_objs-y)
+
+export-objs := $(xeno_cifx_pci-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_cifx_pci.o: $(xeno_cifx_pci-objs)
+	$(LD) -r -o $@ $(xeno_cifx_pci-objs)
+
+endif
diff --git a/ksrc/drivers/cifx/Makefile~ b/ksrc/drivers/cifx/Makefile~
new file mode 100644
index 0000000..3c90f1a
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile~
@@ -0,0 +1,41 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_rtipc.o
+
+xeno_rtipc-y := rtipc.o
+
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_XDDP) += xddp.o
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_IDDP) += iddp.o
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_BUFP) += bufp.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_RTIPC) += xeno_rtipc.o
+
+xeno_rtipc-objs := rtipc.o
+
+opt_objs-y :=
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_XDDP) += xddp.o
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_IDDP) += iddp.o
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_BUFP) += bufp.o
+
+xeno_rtipc-objs += $(opt_objs-y)
+
+export-objs := $(xeno_rtipc-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_rtipc.o: $(xeno_rtipc-objs)
+	$(LD) -r -o $@ $(xeno_rtipc-objs)
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..677367d
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,1189 @@
+/***************************************************************************
+ *   Copyright (C) 2013                                                    *
+ *   Hilscher France (JP)                                                  *
+ *   http://www.hilscher.fr                                                *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+/*****************************************************************************/
+
+/* Includes */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <rtdm/rtdm_driver.h>
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+/*****************************************************************************/
+/*!
+ *   \addtogroup cifx_pci_Core
+ *   @{
+ */
+/*****************************************************************************/
+
+/* #define */
+
+#ifndef TRUE
+#define TRUE                            1
+#endif				/* TRUE */
+
+#ifndef FALSE
+#define FALSE                           0
+#endif				/* TRUE */
+
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER          0x15CF
+#endif				/* PCI_VENDOR_ID_HILSCHER */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
+#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA          0x3335
+#endif				/* PCI_SUBDEVICE_ID_NXPCA */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+/*****************************************************************************/
+
+/* structure */
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	uint8_t irq_enable;
+	uint8_t irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+/*****************************************************************************/
+
+/* Prototypes */
+
+#ifdef IRQ_SUPPORT
+static int cifx_handler(rtdm_irq_t *irq);
+#endif /* IRQ_SUPPORT */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/*****************************************************************************/
+
+/* Local variables */
+
+/** Number or cifx found and open */
+static int32_t cifx_num;
+
+/** RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/** Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETX,
+		.subvendor = 0,
+		.subdevice = 0,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/** RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*****************************************************************************/
+
+#ifdef IRQ_SUPPORT
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_handler
+ *
+ *   \param  [in]	irq       Resource task pointer
+ *
+ *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
+ *
+ *   \note   cifx interrupt handler
+ */
+/*****************************************************************************/
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info =
+	    (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
+	struct io_info_t *device_data = (struct io_info_t *)info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == FALSE)
+	    || (device_data->irq_enable == FALSE)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+#endif /* IRQ_SUPPORT */
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_set_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Set plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_dpm_mode
+ *
+ *	 \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get dpm mode
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_open
+ *
+ *   \param	[in]	context		context
+ *   \param	[in]	user_info	user information
+ *	 \param	[in]	oflags		flags (flag IRQ used)
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Open RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	int32_t ret;
+
+	/* Test if (oflags) IRQ are use */
+	if (oflags == TRUE) {
+		if (((struct io_info_t *)info->device_data)->irq_registered
+		    == FALSE) {
+			/* Register IRQ */
+			ret =
+			    rtdm_irq_request(&
+					     (((struct io_info_t *)info->
+					       device_data)->irq_handle),
+					     ((struct io_info_t *)info->
+					      device_data)->irq, cifx_handler,
+					     RTDM_IRQTYPE_SHARED,
+					     info->device_name, (void *)info);
+
+			if (ret != 0) {
+#ifdef DEBUG
+				switch (ret) {
+				case -EINVAL:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: an invalid parameter was passed\n");
+					break;
+				case -EBUSY:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: the specified IRQ line is already in use\n");
+					break;
+				default:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request error\n");
+					break;
+				}
+#endif /* DEBUG */
+
+				return -ENODEV;
+			} else
+				((io_info_t *) info->
+				 device_data)->irq_registered = TRUE;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_close
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *
+ *	\return 0 (OK) or Error
+ *
+ *	\note	Close RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (((struct io_info_t *)info->device_data)->irq_registered == TRUE) {
+		if (((struct io_info_t *)info->device_data)->
+							irq_enable == TRUE) {
+			/* Disable IRQ */
+			if (rtdm_irq_disable
+			    (&
+			     (((struct io_info_t *)info->device_data)->
+			      irq_handle)) != 0) {
+#ifdef DEBUG
+				rtdm_printk(
+			"cifx rtdm driver error : rtdm_irq_disable error\n");
+#endif /* DEBUG */
+
+				return -ENODEV;
+			}
+		}
+
+		/* Unregister IRQ */
+		if (rtdm_irq_free
+		    (&(((struct io_info_t *)info->device_data)->irq_handle)) !=
+		    0) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_irq_free error\n");
+#endif /* DEBUG */
+
+			return -ENODEV;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *  \brief  cifx_pci_read
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *  \return size read
+ *
+ *  \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_write
+ *
+ *  \param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *   \return size read
+ *
+ *   \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	uint8_t irq_enable;
+#endif /* IRQ_SUPPORT */
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+#ifdef IRQ_SUPPORT
+	if (nbyte == sizeof(uint8_t)) {
+		/* Copy data for Kernel */
+		if (rtdm_safe_copy_from_user
+		    (user_info, &irq_enable, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (((((struct io_info *)info->device_data)->
+			     irq_enable) != irq_enable)
+			&& (((struct io_info *)info->device_data)->
+				    irq_registered == TRUE)) {
+					if (irq_enable == TRUE) {
+						/* Enable IRQ */
+						rtdm_irq_enable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					} else {
+						/* Disable IRQ */
+						rtdm_irq_disable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					}
+
+					((struct io_info *)info->device_data)->
+					    irq_enable = irq_enable;
+				}
+			}
+		}
+	} else if (nbyte == sizeof(struct io_map_mem)) {
+#else /* IRQ_SUPPORT */
+	if (nbyte == sizeof(struct io_map_mem)) {
+#endif /* IRQ_SUPPORT */
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_probe
+ *
+ *   \param  [in]   dev
+ *   \param  [in]   id
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note  Open the device.
+ *			This function is called when the device shall be opened.
+ */
+/*****************************************************************************/
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (!pxa_info->plx)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = FALSE;
+	((struct io_info *)device_data)->irq_registered = FALSE;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_remove
+ *
+ *   \param [in] dev
+ *
+ *   \return None
+ *
+ *   \note   Close the device.
+ *   This function is called when the device shall be closed.
+ */
+/*****************************************************************************/
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_init
+ *
+ *   \return None
+ *
+ *   \note   It simply registers the RTDM device.
+ *   This function is called when the module is loaded.
+ */
+/*****************************************************************************/
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_exit
+ *
+ *   \return None
+ *
+ *   \note  It unregister the RTDM device.
+ *   This function is called when the module is unloaded.
+ */
+/*****************************************************************************/
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*! \}     cifx_pci_Core                                                     */
+/*****************************************************************************/
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */
diff --git a/ksrc/drivers/cifx/cifx_pci.c~ b/ksrc/drivers/cifx/cifx_pci.c~
new file mode 100644
index 0000000..2b3ffea
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c~
@@ -0,0 +1,1190 @@
+/***************************************************************************
+ *   Copyright (C) 2013                                                    *
+ *   Hilscher France (JP)                                                  *
+ *   http://www.hilscher.fr                                                *
+ *                                                                         *
+ *   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.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+/*****************************************************************************/
+
+/* Includes */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#include <linux/mman.h>
+
+#include <rtdm/rtdm_driver.h>
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+/*****************************************************************************/
+/*!
+ *   \addtogroup cifx_pci_Core
+ *   @{
+ */
+/*****************************************************************************/
+
+/* #define */
+
+#ifndef TRUE
+#define TRUE                            1
+#endif				/* TRUE */
+
+#ifndef FALSE
+#define FALSE                           0
+#endif				/* TRUE */
+
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER          0x15CF
+#endif				/* PCI_VENDOR_ID_HILSCHER */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
+#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA          0x3335
+#endif				/* PCI_SUBDEVICE_ID_NXPCA */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+/*****************************************************************************/
+
+/* structure */
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	uint8_t irq_enable;
+	uint8_t irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+/*****************************************************************************/
+
+/* Prototypes */
+
+#ifdef IRQ_SUPPORT
+static int cifx_handler(rtdm_irq_t *irq);
+#endif /* IRQ_SUPPORT */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/*****************************************************************************/
+
+/* Local variables */
+
+/** Number or cifx found and open */
+static int32_t cifx_num;
+
+/** RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/** Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETX,
+		.subvendor = 0,
+		.subdevice = 0,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/** RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*****************************************************************************/
+
+#ifdef IRQ_SUPPORT
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_handler
+ *
+ *   \param  [in]	irq       Resource task pointer
+ *
+ *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
+ *
+ *   \note   cifx interrupt handler
+ */
+/*****************************************************************************/
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info =
+	    (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
+	struct io_info_t *device_data = (struct io_info_t *)info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == FALSE)
+	    || (device_data->irq_enable == FALSE)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+#endif /* IRQ_SUPPORT */
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_set_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Set plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_dpm_mode
+ *
+ *	 \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get dpm mode
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_open
+ *
+ *   \param	[in]	context		context
+ *   \param	[in]	user_info	user information
+ *	 \param	[in]	oflags		flags (flag IRQ used)
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Open RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	int32_t ret;
+
+	/* Test if (oflags) IRQ are use */
+	if (oflags == TRUE) {
+		if (((struct io_info_t *)info->device_data)->irq_registered
+		    == FALSE) {
+			/* Register IRQ */
+			ret =
+			    rtdm_irq_request(&
+					     (((struct io_info_t *)info->
+					       device_data)->irq_handle),
+					     ((struct io_info_t *)info->
+					      device_data)->irq, cifx_handler,
+					     RTDM_IRQTYPE_SHARED,
+					     info->device_name, (void *)info);
+
+			if (ret != 0) {
+#ifdef DEBUG
+				switch (ret) {
+				case -EINVAL:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: an invalid parameter was passed\n");
+					break;
+				case -EBUSY:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: the specified IRQ line is already in use\n");
+					break;
+				default:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request error\n");
+					break;
+				}
+#endif /* DEBUG */
+
+				return -ENODEV;
+			} else
+				((io_info_t *) info->
+				 device_data)->irq_registered = TRUE;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_close
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *
+ *	\return 0 (OK) or Error
+ *
+ *	\note	Close RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (((struct io_info_t *)info->device_data)->irq_registered == TRUE) {
+		if (((struct io_info_t *)info->device_data)->
+							irq_enable == TRUE) {
+			/* Disable IRQ */
+			if (rtdm_irq_disable
+			    (&
+			     (((struct io_info_t *)info->device_data)->
+			      irq_handle)) != 0) {
+#ifdef DEBUG
+				rtdm_printk(
+			"cifx rtdm driver error : rtdm_irq_disable error\n");
+#endif /* DEBUG */
+
+				return -ENODEV;
+			}
+		}
+
+		/* Unregister IRQ */
+		if (rtdm_irq_free
+		    (&(((struct io_info_t *)info->device_data)->irq_handle)) !=
+		    0) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_irq_free error\n");
+#endif /* DEBUG */
+
+			return -ENODEV;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *  \brief  cifx_pci_read
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *  \return size read
+ *
+ *  \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_write
+ *
+ *  \param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *   \return size read
+ *
+ *   \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	uint8_t irq_enable;
+#endif /* IRQ_SUPPORT */
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+#ifdef IRQ_SUPPORT
+	if (nbyte == sizeof(uint8_t)) {
+		/* Copy data for Kernel */
+		if (rtdm_safe_copy_from_user
+		    (user_info, &irq_enable, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (((((struct io_info *)info->device_data)->
+			     irq_enable) != irq_enable)
+			&& (((struct io_info *)info->device_data)->
+				    irq_registered == TRUE)) {
+					if (irq_enable == TRUE) {
+						/* Enable IRQ */
+						rtdm_irq_enable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					} else {
+						/* Disable IRQ */
+						rtdm_irq_disable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					}
+
+					((struct io_info *)info->device_data)->
+					    irq_enable = irq_enable;
+				}
+			}
+		}
+	} else if (nbyte == sizeof(struct io_map_mem)) {
+#else /* IRQ_SUPPORT */
+	if (nbyte == sizeof(struct io_map_mem)) {
+#endif /* IRQ_SUPPORT */
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_probe
+ *
+ *   \param  [in]   dev
+ *   \param  [in]   id
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note  Open the device.
+ *			This function is called when the device shall be opened.
+ */
+/*****************************************************************************/
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (!pxa_info->plx)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = FALSE;
+	((struct io_info *)device_data)->irq_registered = FALSE;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_remove
+ *
+ *   \param [in] dev
+ *
+ *   \return None
+ *
+ *   \note   Close the device.
+ *   This function is called when the device shall be closed.
+ */
+/*****************************************************************************/
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_init
+ *
+ *   \return None
+ *
+ *   \note   It simply registers the RTDM device.
+ *   This function is called when the module is loaded.
+ */
+/*****************************************************************************/
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_exit
+ *
+ *   \return None
+ *
+ *   \note  It unregister the RTDM device.
+ *   This function is called when the module is unloaded.
+ */
+/*****************************************************************************/
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*! \}     cifx_pci_Core                                                     */
+/*****************************************************************************/
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */

  parent reply	other threads:[~2013-03-04  9:13 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-02-26  9:29 [Xenomai] Hilscher driver for cifX boards Jerome Poncin
2013-02-26 11:37 ` Jan Kiszka
2013-02-26 14:25   ` Jerome Poncin
2013-02-26 14:28     ` Jan Kiszka
2013-02-28  8:15       ` Jerome Poncin
2013-02-28 11:31         ` Jan Kiszka
2013-02-28 12:08           ` Jerome Poncin
2013-03-01 13:56             ` Jerome Poncin
2013-03-01 17:02               ` Jan Kiszka
2013-03-01 20:06               ` Gilles Chanteperdrix
2013-03-04  9:13               ` Jerome Poncin [this message]
2013-03-04 21:08                 ` Gilles Chanteperdrix
2013-03-05 10:45                   ` Jerome Poncin
2013-03-05 11:26                     ` Jan Kiszka
2013-03-05 12:21                       ` Gilles Chanteperdrix
2013-03-05 12:30                       ` Gilles Chanteperdrix
2013-03-05 15:42                       ` Jerome Poncin
2013-03-05 19:41                         ` Gilles Chanteperdrix
2013-03-06  8:10                           ` Jerome Poncin
2013-03-06  8:19                             ` Gilles Chanteperdrix
2013-03-06  8:55                               ` Jerome Poncin
2013-03-06 10:33                               ` Jerome Poncin
2013-03-06 12:04                                 ` Gilles Chanteperdrix
2013-03-06 13:58                                   ` Jerome Poncin
2013-03-06 15:28                                     ` Jan Kiszka
2013-03-06 21:05                                       ` Gilles Chanteperdrix
2013-03-07 15:33                                         ` Jerome Poncin
2013-03-08 10:17                                           ` Jerome Poncin
2013-03-08 12:22                                             ` Gilles Chanteperdrix
2013-03-12  9:10                                               ` Jerome Poncin
2013-03-12 12:21                                                 ` Gilles Chanteperdrix
2013-03-12 15:27                                                   ` Jerome Poncin
2013-03-12 19:38                                                     ` Gilles Chanteperdrix
2013-03-13 11:08                                                       ` Jerome Poncin
2013-03-15  9:09                                                         ` Jerome Poncin
2013-03-15 11:07                                                           ` Jan Kiszka
2013-03-15 13:04                                                             ` Jerome Poncin
2013-03-15 13:24                                                               ` Jan Kiszka
2013-03-18 10:02                                                                 ` Jerome Poncin
2013-03-19 13:42                                                                   ` Jerome Poncin
2013-03-06 20:42                                     ` Gilles Chanteperdrix
  -- strict thread matches above, loose matches on Subject: below --
2013-02-12 11:37 Stéphane LOS
2013-02-12 11:51 ` Jan Kiszka
2013-02-13 14:09   ` Stéphane LOS
2013-02-14 13:36     ` Stéphane LOS
2013-02-14 15:01       ` Stéphane LOS
2013-02-15 14:54         ` Jan Kiszka
2013-02-18 11:43           ` Stéphane LOS
2013-02-07 14:53 Stéphane LOS
2013-02-07 16:11 ` Gilles Chanteperdrix
2013-02-08  9:07   ` Stéphane LOS
2013-02-08  9:18     ` Gilles Chanteperdrix
2013-02-08 11:28       ` Jan Kiszka
2013-02-08 11:35         ` Gilles Chanteperdrix
2013-02-08 11:46           ` Jan Kiszka
     [not found]         ` <5114FD7B.20902@hilscher.com>
2013-02-08 13:40           ` Jan Kiszka
2013-02-08 14:33             ` Stéphane LOS

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=513465CF.4030807@hilscher.com \
    --to=jponcin@hilscher.com \
    --cc=xenomai@xenomai.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.