Index: linux-3.12.33-rt47-i386/drivers/uio/Kconfig
===================================================================
--- linux-3.12.33-rt47-i386.orig/drivers/uio/Kconfig	2015-09-15 10:45:22.214318717 +0200
+++ linux-3.12.33-rt47-i386/drivers/uio/Kconfig	2015-09-15 10:45:22.306319474 +0200
@@ -28,6 +28,14 @@
 	  Driver for HDM SCU3 Board.
 	  If you don't know what to do here, say N.
 
+config UIO_HDM_SCU3_MOD
+  tristate "Driver for HDM SCU3 Board with PCIexpress"
+  depends on UIO && PCI && SERIAL_UARTLITE
+  default n
+  help
+    Driver for HDM SCU3 Board.
+    If you don't know what to do here, say N.
+
 config UIO_CIF
 	tristate "generic Hilscher CIF Card driver"
 	depends on PCI
Index: linux-3.12.33-rt47-i386/drivers/uio/Makefile
===================================================================
--- linux-3.12.33-rt47-i386.orig/drivers/uio/Makefile	2015-09-15 10:45:22.214318717 +0200
+++ linux-3.12.33-rt47-i386/drivers/uio/Makefile	2015-09-15 10:45:22.306319474 +0200
@@ -1,6 +1,7 @@
 obj-$(CONFIG_UIO)	+= uio.o
 obj-$(CONFIG_UIO_HDM_SCU2)	+= uio_scu2.o
 obj-$(CONFIG_UIO_HDM_SCU3)	+= uio_scu3.o
+obj-$(CONFIG_UIO_HDM_SCU3)	+= uio_scu3_mod.o
 obj-$(CONFIG_UIO_CIF)	+= uio_cif.o
 obj-$(CONFIG_UIO_PDRV_GENIRQ)	+= uio_pdrv_genirq.o
 obj-$(CONFIG_UIO_DMEM_GENIRQ)	+= uio_dmem_genirq.o
Index: linux-3.12.33-rt47-i386/drivers/uio/uio_scu3_mod.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-3.12.33-rt47-i386/drivers/uio/uio_scu3_mod.c	2015-09-15 11:05:12.383997604 +0200
@@ -0,0 +1,445 @@
+/*
+ * uio_scu3.c
+ *
+ * Copyright(C) 2008, Dietrich Toews <Dietrich.Toews@heidelberg.com>
+ *
+ * Userspace IO driver for HDM-Scu3 Hardwarecomponents
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#define DRV_NAME_SYS    "uio_scu3_pcie"
+#define DRV_NAME        "uio_scu3"
+#define DRV_VERSION     "2.2.0"
+#define PFX             DRV_NAME " PCIe: "
+
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+
+//static char* addrBase_7;
+static char* addrBase_c;
+static char* addrBase_d;
+#define SCU3_FPGA_ADR(range,ofs) (addrBase_##range +((ofs)&0xfffff))
+#define SCU3_FPGA_REG16(range,offset) *(unsigned short*)SCU3_FPGA_ADR(range,offset)
+#define SCU3_FPGA_REG08(range,offset) *(unsigned char*)SCU3_FPGA_ADR(range,offset)
+
+#define PCI_VENDOR_ID_SCU3   0xbad4
+#define SCU3_DEVICE_ID       0x0008
+#define SCU3_FPGA_MEM_SIZE   0x1000000
+//#define SCU3_LED_REG         SCU3_FPGA_REG08(7,0x700002)
+#define SCU3_INT_STATUS_REG  SCU3_FPGA_REG16(c,0xc00000)
+#define SCU3_INT_FRG_REG     SCU3_FPGA_REG16(c,0xc00002)
+#define SCU3_ID_REG          SCU3_FPGA_REG08(d,0xd00002)
+#define   SCU3_ID_SCU2         0x1
+#define   SCU3_ID_SCU2B        0x2
+#define   SCU3_ID_SCU2B_BB     0x4
+#define   SCU3_ID_SCU3         0x3
+
+
+#define SCU3_INT_TACHO (1<<0)
+#define SCU3_INT_SER_1 (1<<1)
+#define SCU3_INT_DPR_A (1<<2)
+#define SCU3_INT_SJA_1 (1<<3)
+#define SCU3_INT_SJA_2 (1<<4)
+#define SCU3_INT_DPR_B (1<<5)
+#define SCU3_INT_SER_2 (1<<6)
+#define SCU3_INT_SER_3 (1<<7)
+#define SCU3_INT_SER_A (1<<8)
+#define SCU3_INT_SER_B (1<<9)
+#define SCU3_INT_FINP  (1<<10)
+
+#define MY_INTS  ( 0                            \
+  | SCU3_INT_TACHO                              \
+  | SCU3_INT_DPR_A                              \
+  | SCU3_INT_SJA_1                              \
+  | SCU3_INT_SJA_2                              \
+  | SCU3_INT_DPR_B                              \
+  | SCU3_INT_SER_A                              \
+  | SCU3_INT_SER_B                              \
+  | SCU3_INT_FINP                               \
+)
+
+static unsigned         initState=0;
+static void uio_scu3_remove( struct pci_dev *dev );
+
+
+
+
+static ssize_t show_id( struct device *dev, struct device_attribute *attr, char *buf )
+{
+  const char *idstr = "UNKNOWN ID";
+  switch( SCU3_ID_REG )
+  {
+    case SCU3_ID_SCU2:
+      idstr = "SCU2\n";
+      break;
+    case SCU3_ID_SCU2B:
+      idstr = "SCU2B\n";
+      break;
+    case SCU3_ID_SCU2B_BB:
+      idstr = "SCU2B_BB\n";
+      break;
+    case SCU3_ID_SCU3:
+      idstr = "SCU3\n";
+      break;
+  }
+  return sprintf( buf, "0x%02x %s\n", SCU3_ID_REG, idstr );
+}
+static DEVICE_ATTR(scu3_id, S_IRUGO, show_id,0);
+
+static irqreturn_t uio_scu3_handler( int irq, struct uio_info *dev_info )
+{
+  u16 req = SCU3_INT_STATUS_REG & MY_INTS; //INT_MASK;
+
+  if( !req ) /* shared irq? */
+  {
+    return IRQ_NONE;
+  }
+  SCU3_INT_FRG_REG &= ~(MY_INTS); //INT_OFF_MASK;
+  return IRQ_HANDLED;
+
+/* Fast IO register
+Achtung!! see Fast_input_bit.vhd
+1. komisches interupt-Sperrverhalten.
+2. kein Intrequest Register
+
+
+1. Beim sperren der ints mit SCU3_FI_FRG_REG=0 wird die Int-erkennung halb
+ausgeschaltet. Zwischenzeitlich anfallende Ints werden bei der wiederfreigabe
+genau dann gemeldet wenn der Pegel vor der Sperre ungleich dem Pegel hinter der
+Sperre ist.
+T              1    2             3   4   5           6   7 8 9
+INPUT_REG    --______----    -----____----------   ---____--_______
+
+               |    |             |                   |
+               v    v             v                   v
+
+FRG_REG     _------------    -------______---      -----______-
+
+               |    |             | |     |           | |
+               v    v             v v     v           v v     kein int
+
+STATUS_REG   __i--__i--__    _____i-______i---__   ___i-___________
+                  ^    ^                      ^
+EOI_REG      _____-____-_    _________________-_
+
+Im Bsp. wird also zum Zeitpunkt 5 ein Int ausgeloest, zum Zeitpunkt 9
+jedoch nicht, weil der Pegel vor der Int-Sperre einmal ungleich (T=5) und beim
+zweiten Mal identisch (T=9) mit dem aktuellen Pegel ist.
+
+Dies fuehrt im schlimmsten Fall dazu, dass die Software auf dem falschen Pegel
+festklemmt. Im Bsp. erkennt die Pollingloop die Pegel bei T=6 u. T=7, aber
+T=8 kommt ausgerechnet in dem Zeitraum zwischen Pollingloop Ende und
+Int-Freigabe.
+Abhilfe: FRG_REG nicht verwenden. (Lediglich zur Komplettsperre)
+
+
+2. Das STATUS_REG ist nur dann verfuegbar wenn das FRG_REG=1 und solange noch
+kein EOI ausgeloest wurde.
+*/
+}
+
+static struct uio_info     *uinfo2 = 0;
+static dma_addr_t       dmem_baddr = 0; //bus addr
+static void            *dmem_vaddr = 0;
+
+static int dmem_init( struct pci_dev *pdev )
+{
+  int ret = -ENODEV;
+
+  uinfo2 = kzalloc( sizeof(struct uio_info), GFP_KERNEL );
+  if( !uinfo2 )
+  {
+    printk( KERN_ERR PFX "kzalloc failed\n" );
+    ret = -ENOMEM;
+    goto out_err1;
+  }
+  if( dma_set_mask( &pdev->dev, DMA_BIT_MASK( 32 ) ) )
+  {
+    printk( KERN_WARNING PFX "No suitable DMA available.\n" );
+    goto out_err2;
+  }
+#define  DMEMSIZE_K "64"
+#define  DMEMSIZE   (64*1024)
+  dmem_vaddr = dma_alloc_coherent( &pdev->dev, DMEMSIZE, &dmem_baddr, GFP_KERNEL );
+  // TODO we should free this dma memory
+  if( dmem_vaddr == 0 )
+  {
+    printk( KERN_WARNING PFX "dma_alloc_coherent failed.\n" );
+    goto out_err2;
+  }
+
+  printk(KERN_INFO PFX "allocated DMA-Memory size %x virt:%p bus:%p\n"
+         ,DMEMSIZE
+         ,dmem_vaddr
+         ,(void*)dmem_baddr
+         );
+  uinfo2->name                 = "uio_scu3_dmem";
+  uinfo2->version              = DRV_VERSION;
+  uinfo2->irq                  = UIO_IRQ_NONE;
+  uinfo2->irq_flags            = 0;
+  uinfo2->handler              = 0;
+  {
+    struct uio_mem *uioMemSlot = &uinfo2->mem[0];
+    uioMemSlot->addr           = dmem_baddr;
+    uioMemSlot->size           = DMEMSIZE;
+    uioMemSlot->memtype        = UIO_MEM_PHYS;
+    uioMemSlot->name           = "DMEM" DMEMSIZE_K;
+  }
+  if( uio_register_device( &pdev->dev, uinfo2 ) )
+  {
+    printk( KERN_ERR PFX "bad uio_register_device\n" );
+    goto out_err3;
+  }
+  return 0;
+
+ out_err3:
+  dma_free_coherent( &pdev->dev, DMEMSIZE, dmem_vaddr, dmem_baddr );
+ out_err2:
+  kfree( uinfo2 );
+ out_err1:
+  return ret;
+}
+
+static int dmem_remove( struct pci_dev *pdev )
+{
+  dma_free_coherent( &pdev->dev, DMEMSIZE, dmem_vaddr, dmem_baddr );
+  kfree( uinfo2 );
+  return 0;
+}
+
+
+static int uio_scu3_probe( struct pci_dev *pdev, const struct pci_device_id *id )
+{
+  int              ret = -ENODEV;
+  struct uio_info *info=0;
+  resource_size_t  mmio_start; //resource_size_t = phys_addr_t = u64/u32
+  //resource_size_t  mmio_end;
+  unsigned long    mmio_flags;
+  unsigned long    mmio_len;
+  int              pci_irq;
+  printk( KERN_INFO PFX "probing...\n" );
+
+  if( MAX_UIO_MAPS < 16 )
+  {
+    printk( KERN_ERR PFX "less than 16  UIO_MAPS\n" );
+    goto out_err;
+  }
+
+  info = kzalloc( sizeof(struct uio_info), GFP_KERNEL );
+  if( !info )
+  {
+    printk( KERN_ERR PFX "kzalloc failed\n" );
+    ret = -ENOMEM;
+    goto out_err;
+  }
+  pci_set_drvdata( pdev, info );
+  initState |= 1;  //drv-object memory initialized
+
+
+  if( pci_enable_device( pdev ) )
+  {
+    printk( KERN_ERR PFX "device already enabled .. aborting\n" );
+    goto out_err;
+  }
+  initState |= 2;  //enable ok
+
+  pci_irq                    = pdev->irq; //veraendert durch pci_enable_device
+  info->name                 = DRV_NAME;
+  info->version              = DRV_VERSION;
+  info->irq                  = pci_irq;
+  printk(KERN_INFO PFX "1 pdev->irq = %d\n",pdev->irq);
+  //info->irq_flags            = IRQF_DISABLED | IRQF_SHARED;
+  // see below: SCU3_INT_FRG_REG = 0;
+  info->irq_flags            = IRQF_SHARED;
+  info->handler              = uio_scu3_handler;
+
+  mmio_start = pci_resource_start( pdev, 0 ); //resource_size_t = phys_addr_t = u64/u32
+  //mmio_end   = pci_resource_end(pdev, 0);
+  mmio_flags = pci_resource_flags( pdev, 0 );
+  mmio_len = pci_resource_len( pdev, 0 );
+
+  if( !mmio_start )
+  {
+    printk( KERN_ERR PFX "mmio_start==0\n" );
+    goto out_err;
+  }
+
+  if( !(mmio_flags & IORESOURCE_MEM) )
+  {
+    printk( KERN_ERR PFX "region #0 not an MMIO resource, aborting\n" );
+    goto out_err;
+  }
+  if( mmio_len != SCU3_FPGA_MEM_SIZE )
+  {
+    printk( KERN_ERR PFX "Invalid PCI mem region size(s), aborting %lx!=%x\n", mmio_len,
+        SCU3_FPGA_MEM_SIZE );
+    goto out_err;
+  }
+  initState |= 4; //mem regions ok
+
+
+
+
+  {//dummy block
+    int k;
+    struct Tab{ unsigned ofs, size;char** pBase; const char* name;};
+    struct Tab sizes[]={
+      { 0x000000, 0x1000,           0 ,"FAST-I"},//     10 fast in
+      { 0x100000, 0x1000,           0 ,"FAST-O"},//      4 fast out
+      { 0x200000, 0x4000,           0 ,"DPR-A"},// 0x4000 dpramA
+      { 0x300000, 0x1000,           0 ,"CAN-1"},//   0x80 can1
+      { 0x400000, 0x1000,           0 ,"CAN-2"},//   0x80 can2
+      //{ 0x500000, 0x1000,           0 },//16 UART1
+      //{ 0x600000, 0x1000,           0 },//16 UART2
+      { 0x700000, 0x1000,           0 ,"PORT"},//      3 port 0,1,2
+      //{ 0x800000, 0x1000, &addrBase_8 },// 8 sioA printf serial8250_register_port
+      //{ 0x900000, 0x1000, &addrBase_9 },// 8 sioB
+      { 0xa00000,0x10000,           0 ,"NVRAM"},//0x10000 nv-ram
+      { 0xb00000, 0x1000,           0 ,"TACHO"},//   0x10 tacho
+      { 0xc00000, 0x1000, &addrBase_c ,"INT"},//      6 interupt
+      { 0xd00000, 0x1000, &addrBase_d ,"REGS"},//      6 registers
+      { 0xe00000, 0x4000,           0 ,"DPR-B"},// 0x4000 dpramB
+      //{ 0xf00000, 0x1000,           0 } //16 UART3
+    };
+
+    for( k = 0; k < sizeof(sizes) / sizeof(sizes[0]); k++ )
+    {
+      unsigned         ofs = sizes[k].ofs ;//i<<20;
+      unsigned        size = sizes[k].size;
+      resource_size_t addr = mmio_start + ofs;
+      char         **pBase = sizes[k].pBase; //(unsigned*)sizes[k*3+2];
+      struct uio_mem *uioMemSlot = &info->mem[k];
+      BUG_ON( size == 0 );
+
+      //printk(KERN_INFO PFX "region %d %08x %06x\n",k,mem->addr,mem->size);
+
+      if( !request_mem_region( addr, size, "scu3" ) )
+      {
+        printk( KERN_INFO PFX "pci_request_region %d not allowed \n", k );
+        goto out_err;
+      }
+      uioMemSlot->addr = addr;
+      uioMemSlot->size = size;
+      uioMemSlot->memtype = UIO_MEM_PHYS;
+      uioMemSlot->name = sizes[k].name;
+
+      if( pBase )
+      {
+        uioMemSlot->internal_addr = ioremap( uioMemSlot->addr, size );
+        *pBase = uioMemSlot->internal_addr;
+        if( !*pBase )
+        {
+          printk( KERN_ERR PFX "bad ioremap %d\n", k );
+          goto out_err;
+        }
+      }
+    }
+  }
+  SCU3_INT_FRG_REG = 0; //INT_OFF_MASK; //all ints off after
+  if( uio_register_device( &pdev->dev, info ) )
+  {
+    printk( KERN_ERR PFX "bad uio_register_device\n" );
+    goto out_err;
+  }
+  printk( KERN_INFO PFX "sio_init\n" );
+  initState |= 8; //device registered
+
+  if( dmem_init( pdev ) == 0 ) initState |= 0x80; //dma memory
+
+  device_create_file( &pdev->dev, &dev_attr_scu3_id );
+  initState |= 0x100;
+
+  printk(KERN_INFO PFX "successfully probed. adr=%p size=0x%lx irq=%ld =? devirq=%d\n"
+         ,(void*)info->mem[0].addr
+         ,mmio_len //info->mem[0].size
+         ,info->irq
+         ,pdev->irq
+         );
+  return 0;
+
+ out_err:
+  uio_scu3_remove( pdev ); //uio_scu3_cleanup(pdev,info);
+  printk( KERN_ERR PFX "load error\n" );
+  return ret;
+}
+
+
+static void uio_scu3_remove( struct pci_dev *pdev )
+{
+  struct uio_info *info = pci_get_drvdata( pdev );
+  if( initState & 0x100 )
+  {
+    device_remove_file( &pdev->dev, &dev_attr_scu3_id );
+  }
+  if( initState & 0x80 ) dmem_remove( pdev );
+
+  //if(initState & 0x10) serial8250_unregister_port(sioLine);
+  if( initState & 0x8 ) uio_unregister_device( info );
+  if( initState & 0x4 )
+  {
+    int k;
+    for( k = 0; k < MAX_UIO_MAPS; k++ )
+    {
+      if( info->mem[k].addr ) release_mem_region( info->mem[k].addr, info->mem[k].size );
+      if( info->mem[k].internal_addr ) iounmap( info->mem[k].internal_addr );
+    }
+  }
+  if( initState & 0x2 ) pci_disable_device( pdev );
+  if( initState & 0x1 ) pci_set_drvdata( pdev, NULL );
+  if( initState & 0x1 ) kfree( info );
+}
+
+
+static struct pci_device_id scu3_pci_tbl[] = {//
+  {
+    .vendor    = PCI_VENDOR_ID_SCU3,
+    .device    = SCU3_DEVICE_ID,
+    .subvendor = PCI_ANY_ID,
+    .subdevice = PCI_ANY_ID,
+  },
+  {0,}
+};
+//MODULE_DEVICE_TABLE (pci, scu3_pci_tbl);
+static struct pci_driver uio_scu3_driver = {
+  .name   = DRV_NAME_SYS,
+  .id_table = scu3_pci_tbl,
+  .probe  = uio_scu3_probe,
+  .remove = uio_scu3_remove,
+};
+
+
+
+/*
+ * Main initialization/remove routines
+ */
+extern void (*g_timer_int_callback)( void );
+
+static int __init uio_scu3_init_module(void)
+{
+  printk (KERN_INFO PFX "loading..\n");
+  return pci_register_driver(&uio_scu3_driver);
+}
+
+static void __exit uio_scu3_exit_module(void)
+{
+  pci_unregister_driver(&uio_scu3_driver);
+  printk(KERN_INFO PFX "successfully unloaded.\n");
+}
+
+
+module_init( uio_scu3_init_module );
+module_exit( uio_scu3_exit_module );
+
+MODULE_LICENSE( "GPL v2" );
+MODULE_AUTHOR( "Dietrich Toews" );
+MODULE_DESCRIPTION( "UIO scu3 driver PCIe" );
+
+//for entry in modules.pcimap
+MODULE_DEVICE_TABLE( pci, scu3_pci_tbl );