Index: linux-3.12.33-rt47-i386/drivers/uio/uio_scu2.c
===================================================================
@ linux-3.12.33-rt47-i386/drivers/uio/uio_scu2.c:4 @
+/*
+ * uio_scu2.c
+ *
+ * Copyright(C) 2008, Thomas Husterer <Thomas.Husterer@heidelberg.com>
+ *
+ * Userspace IO driver for HDM-Scu2 Hardwarecomponents
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#define DRV_NAME        "uio_scu2"
+#define DRV_VERSION	"1.0.0"
+#define PFX             DRV_NAME ": "
+
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+//#include "scu2Adr.h"
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+
+//unsigned addrBase[16];
+static char* addrBase_0;
+static char* addrBase_7;
+static char* addrBase_c;
+static char* addrBase_d;
+#define SCU2_FPGA_ADR(range,ofs) (addrBase_##range +((ofs)&0xfffff))
+#define SCU2_FPGA_REG16(range,offset) *(unsigned short*)SCU2_FPGA_ADR(range,offset)
+#define SCU2_FPGA_REG08(range,offset) *SCU2_FPGA_ADR(range,offset)
+
+//#define SCU2_SIO1_OFS          0x800000
+#define SCU2_VENDOR_ID       0x10ee
+#define SCU2_DEVICE_ID       0x0300
+#define SCU2_FPGA_MEM_SIZE   0x1000000
+#define SCU2_FI_STATUS_REG   SCU2_FPGA_REG16(0,0x000000)
+#define SCU2_FI_EOI_REG      SCU2_FPGA_REG16(0,0x000004)
+#define SCU2_LED_REG         SCU2_FPGA_REG08(7,0x700002)
+#define SCU2_INT_STATUS_REG  SCU2_FPGA_REG16(c,0xc00000)
+#define SCU2_INT_FRG_REG     SCU2_FPGA_REG16(c,0xc00002)
+#define SCU2_ID_REG          SCU2_FPGA_REG08(d,0xd00002)
+#define   SCU2_ID_SCU2         0x1
+#define   SCU2_ID_SCU2B        0x2
+#define   SCU2_ID_SCU2B_BB     0x4
+
+//#define SCU2_FPGA_ADR(range,ofs) (addrBase[ofs>>20] +((ofs)&0xfffff))
+#ifndef CONFIG_HDM_SCU2_SIO_8250_PCI
+int              sioLine;
+#endif
+unsigned         initState=0;
+static void uio_scu2_remove(struct pci_dev *dev);
+
+
+#define LED_ACCESS(num)                                                 \
+static ssize_t show_led##num(struct device *dev,                        \
+                            struct device_attribute *attr,              \
+                            char *buf)                                  \
+{                                                                       \
+  int    msk            = 1<<(num-1);                                   \
+  return sprintf(buf, "%c\n", SCU2_LED_REG & msk ? '1' : '0' );         \
+}                                                                       \
+                                                                        \
+static ssize_t store_led##num(struct device *dev,                       \
+                             struct device_attribute *attr,             \
+                             const char *buf, size_t count)             \
+{                                                                       \
+  int msk=  1<<(num-1);                                                 \
+  unsigned char kbuf    = buf[0]&0xf;                                   \
+  if(count<1)                                                           \
+    return -EFAULT;                                                     \
+  if(kbuf){                                                             \
+    SCU2_LED_REG |=  msk;                                               \
+  }else {                                                               \
+    SCU2_LED_REG &= ~msk;                                               \
+  }                                                                     \
+  return count;                                                         \
+}                                                                       \
+static DEVICE_ATTR(scu2_led##num, S_IRUGO | S_IWUGO, show_led##num, store_led##num);
+LED_ACCESS(1)
+LED_ACCESS(2)
+LED_ACCESS(3)
+LED_ACCESS(4)
+
+static ssize_t show_leds(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+  return sprintf(buf, "0x%02x\n", SCU2_LED_REG );
+}
+
+static ssize_t store_leds(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+  if(count<1)
+    return -EFAULT;
+  SCU2_LED_REG  = simple_strtoul(buf,0,16);
+  return count;
+}
+static DEVICE_ATTR(scu2_leds, S_IRUGO | S_IWUGO, show_leds, store_leds);
+
+
+
+//extern int nmi_watchdog_counter;
+//static ssize_t show_wdg(struct device *dev,
+//                            struct device_attribute *attr,
+//                            char *buf)
+//{
+//  return sprintf(buf, "%d\n", nmi_watchdog_counter );
+//}
+//
+//static ssize_t store_wdg(struct device *dev,
+//                          struct device_attribute *attr,
+//                          const char *buf, size_t count)
+//{
+//  if(count<1)
+//    return -EFAULT;
+//  nmi_watchdog_counter  = simple_strtoul(buf,0,10);
+//  return count;
+//}
+//static DEVICE_ATTR(scu2_wdg, S_IRUGO | S_IWUGO, show_wdg, store_wdg);
+
+
+
+
+static ssize_t show_id(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+  const char *idstr="UNKNOWN ID";
+  switch(SCU2_ID_REG)
+  {
+    case SCU2_ID_SCU2:     idstr="SCU2\n"; break;
+    case SCU2_ID_SCU2B:    idstr="SCU2B\n"; break;
+    case SCU2_ID_SCU2B_BB: idstr="SCU2B_BB\n"; break;
+  }
+  return sprintf(buf, "0x%02x %s\n", SCU2_ID_REG, idstr);
+}
+static DEVICE_ATTR(scu2_id, S_IRUGO, show_id,0);
+
+static irqreturn_t uio_scu2_handler(int irq, struct uio_info *dev_info)
+{
+  //char* scu2BaseAdr = dev_info->mem[0].internal_addr;
+  u16 req=((SCU2_INT_STATUS_REG & 0xff) << 8) | (SCU2_FI_STATUS_REG & 0xff);
+
+  if(!req)   /* shared irq? */
+  {
+    return IRQ_NONE;
+  }
+  //SCU2_FI_FRG_REG  = 0; nicht sperren damit weiterhin alle flanken sichtbar
+  SCU2_FI_EOI_REG  = 0xff; //Fast Input Ints mit EOI beseitigen
+  SCU2_INT_FRG_REG = 0; //Hier gehts nicht mit EOI weil die Quellen noch anstehen
+  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 SCU2_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   3   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 int uio_scu2_probe(struct pci_dev *dev, 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
+  //unsigned long    mmio_end;
+  unsigned long    mmio_flags;
+  unsigned long    mmio_len;
+#ifndef CONFIG_HDM_SCU2_SIO_8250_PCI
+  struct uart_8250_port serial_port;
+#endif
+  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(dev, info);
+  initState|=1;
+
+  if (pci_enable_device(dev))
+  {
+    printk(KERN_ERR PFX "device already enabled .. ignoring\n");
+#ifndef CONFIG_HDM_SCU2_SIO_8250_PCI
+    goto out_err;
+#endif
+  }else{
+    initState|=2;
+  }
+
+  info->name                 = DRV_NAME;
+  info->version              = DRV_VERSION;
+  info->irq                  = dev->irq; //veraendert durch pci_enable_device
+  //  info->irq_flags            = IRQF_DISABLED | IRQF_SHARED;
+  info->irq_flags            = IRQF_SHARED;
+  info->handler              = uio_scu2_handler;
+
+
+
+  mmio_start = pci_resource_start(dev, 0);
+  //mmio_end   = pci_resource_end(dev, 0);
+  mmio_flags = pci_resource_flags(dev, 0);
+  mmio_len   = pci_resource_len(dev, 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 != SCU2_FPGA_MEM_SIZE) {
+    printk(KERN_ERR PFX "Invalid PCI mem region size(s), aborting %lx!=%x\n",mmio_len,SCU2_FPGA_MEM_SIZE);
+    goto out_err;
+  }
+
+  initState|=4;
+
+  {//dummy block
+    int k;
+    struct Tab{unsigned ofs,size;char**pBase;};
+    struct Tab sizes[]={
+      { 0x000000, 0x1000, &addrBase_0 },//     10
+      { 0x100000, 0x1000,           0 },//      4
+      { 0x200000, 0x4000,           0 },// 0x4000
+      { 0x300000, 0x1000,           0 },//   0x80
+      { 0x400000, 0x1000,           0 },//   0x80
+      //0x500000,      0,           0,
+      //0x600000,      0,           0,
+      { 0x700000, 0x1000, &addrBase_7 },//      4
+      //0x800000,      0,            0,//sioA printf serial8250_register_port
+      { 0x900000, 0x1000,           0 },//      8
+      { 0xa00000,0x10000,           0 },//0x10000
+      { 0xb00000, 0x1000,           0 },//   0x1e
+      { 0xc00000, 0x1000, &addrBase_c },//      6
+      { 0xd00000, 0x1000, &addrBase_d },//     ,6
+      { 0xe00000, 0x4000,           0 } // 0x4000
+      //0xf00000,      0,           0
+    };
+
+    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  *mem = &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,"scu2"))
+      {
+        printk(KERN_INFO PFX "pci_request_region %d not allowed \n",k);
+        goto out_err;
+      }
+      mem->addr           = addr;
+      mem->size           = size;
+      mem->memtype        = UIO_MEM_PHYS;
+
+      if(pBase){
+        mem->internal_addr = ioremap(mem->addr,size);
+        *pBase             = mem->internal_addr;
+        if (!*pBase)
+        {
+          printk(KERN_ERR PFX "bad ioremap %d\n",k);
+          goto out_err;
+        }
+      }
+    }
+  }
+  if (uio_register_device(&dev->dev, info)) {
+    printk(KERN_ERR PFX "bad uio_register_device\n");
+    goto out_err;
+  }
+  initState|=8;
+
+
+#ifndef CONFIG_HDM_SCU2_SIO_8250_PCI
+  //see drivers/serial/8250_pci.c:1651
+  memset(&serial_port, 0, sizeof(struct uart_8250_port));
+  serial_port.port.flags   = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF |
+                        UPF_SHARE_IRQ | UPF_IOREMAP;
+  serial_port.port.uartclk = 230400*16;//board->base_baud * 16;
+  serial_port.port.irq     = 0;//get_pci_irq(dev, board);
+  serial_port.port.dev     = &dev->dev;
+
+  //see drivers/serial/8250_pci.c:94 (setup_port)
+  serial_port.port.iotype   = UPIO_MEM;
+  serial_port.port.iobase   = 0;
+  serial_port.port.mapbase  = mmio_start+0x800000;//base + offset;
+  serial_port.port.regshift = 0;
+  //serial_port.membase = scu2BaseAdr+0x800000;// serial8250_request_std_resource macht das selbst UPF_IOREMAP
+
+  sioLine=serial8250_register_8250_port(&serial_port);
+  if (sioLine < 0) {
+    printk(KERN_WARNING PFX "Couldn't register serial port %s: %d\n", pci_name(dev), sioLine);
+    goto out_err;
+  }
+  initState|=0x10;
+#endif
+
+
+
+  ///home/husteret/build/SfcLeanOs-RT/trunk/Src/kernel/linux-2.6.22.1-rt9-lttng/include/linux/pci.h
+    //  class_create_file(&dev->bus->class_dev, &dev_attr_led1);
+  device_create_file(&dev->dev, &dev_attr_scu2_led1);
+  device_create_file(&dev->dev, &dev_attr_scu2_led2);
+  device_create_file(&dev->dev, &dev_attr_scu2_led3);
+  device_create_file(&dev->dev, &dev_attr_scu2_led4);
+  device_create_file(&dev->dev, &dev_attr_scu2_leds);
+  //device_create_file(&dev->dev, &dev_attr_scu2_wdg);
+  device_create_file(&dev->dev, &dev_attr_scu2_id);
+  initState|=0x20;
+
+  printk(KERN_INFO PFX "successfully probed. adr=%p size=0x%lx irq=%ld\n"
+         ,(void*)info->mem[0].addr
+         ,info->mem[0].size
+         ,info->irq
+         );
+  return 0;
+
+ out_err:
+  uio_scu2_remove(dev);//uio_scu2_cleanup(dev,info);
+  printk(KERN_ERR PFX "load error\n");
+  return ret;
+}
+static void uio_scu2_remove(struct pci_dev *dev)
+{
+  struct uio_info *info = pci_get_drvdata(dev);
+  if(initState & 0x20)
+  {
+    device_remove_file(&dev->dev, &dev_attr_scu2_led1);
+    device_remove_file(&dev->dev, &dev_attr_scu2_led2);
+    device_remove_file(&dev->dev, &dev_attr_scu2_led3);
+    device_remove_file(&dev->dev, &dev_attr_scu2_led4);
+    device_remove_file(&dev->dev, &dev_attr_scu2_leds);
+    //device_remove_file(&dev->dev, &dev_attr_scu2_wdg);
+    device_remove_file(&dev->dev, &dev_attr_scu2_id);
+  }
+
+#ifndef CONFIG_HDM_SCU2_SIO_8250_PCI
+  if(initState & 0x10) serial8250_unregister_port(sioLine);
+#endif
+  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(dev);
+  if(initState & 0x1) pci_set_drvdata(dev, NULL);
+  if(initState & 0x1) kfree(info);
+}
+
+// static void uio_scu2_remove(struct pci_dev *dev)
+// {
+//   struct uio_info *info = pci_get_drvdata(dev);
+//   uio_scu2_cleanup(dev,info);
+//
+// }
+
+static struct pci_device_id scu2_pci_tbl[] = {//
+  {
+    .vendor    = SCU2_VENDOR_ID,
+    .device    = SCU2_DEVICE_ID,
+    .subvendor = PCI_ANY_ID,
+    .subdevice = PCI_ANY_ID,
+  },
+  {0,}
+};
+//MODULE_DEVICE_TABLE (pci, scu2_pci_tbl);
+#ifndef CONFIG_HDM_SCU2_SIO_8250_PCI
+static struct pci_driver uio_scu2_driver = {
+  .name		= DRV_NAME,
+  .id_table	= scu2_pci_tbl,
+  .probe	= uio_scu2_probe,
+  .remove	= uio_scu2_remove,
+};
+#endif
+
+
+
+/*
+ * Main initialization/remove routines
+ */
+extern void (*g_timer_int_callback)(void);
+
+struct pci_dev *pciDev = NULL;
+static int __init uio_scu2_init_module(void)
+{
+  printk (KERN_INFO PFX "loading..\n");
+#ifndef CONFIG_HDM_SCU2_SIO_8250_PCI
+  return pci_register_driver(&uio_scu2_driver);
+#else
+  {
+    if((pciDev = pci_get_device(SCU2_VENDOR_ID, SCU2_DEVICE_ID, 0)))
+    {
+      printk (KERN_INFO PFX "found scu2 hardware..\n");
+      return uio_scu2_probe(pciDev,&scu2_pci_tbl[0]);
+    }
+  }
+  return -ENODEV;
+#endif
+
+}
+
+static void __exit uio_scu2_exit_module(void)
+{
+#ifndef CONFIG_HDM_SCU2_SIO_8250_PCI
+  pci_unregister_driver(&uio_scu2_driver);
+#else
+  if(pciDev)
+  {
+    printk (KERN_INFO PFX "release pci-device..\n");
+    uio_scu2_remove(pciDev);
+    pci_dev_put(pciDev);
+  }
+#endif
+  printk(KERN_INFO PFX "successfully unloaded.\n");
+}
+
+module_init(uio_scu2_init_module);
+module_exit(uio_scu2_exit_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Husterer");
+MODULE_DESCRIPTION("UIO scu2 driver");
Index: linux-3.12.33-rt47-i386/drivers/uio/uio_scu3.c
===================================================================
--- /dev/null
+++ linux-3.12.33-rt47-i386/drivers/uio/uio_scu3.c
@ linux-3.12.33-rt47-i386/drivers/uio/uio_scu2.c:4 @
+/*
+ * uio_scu3.c
+ *
+ * Copyright(C) 2008, Thomas Husterer <Thomas.Husterer@heidelberg.com>
+ *
+ * Userspace IO driver for HDM-Scu3 Hardwarecomponents
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#define DRV_NAME        "uio_scu3"
+#define DRV_VERSION	"2.1.0"
+#define PFX             DRV_NAME ": "
+
+
+#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   0x163d
+#define SCU3_DEVICE_ID       0x1961
+#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);
+
+
+#define LED_ACCESS(num)                                                 \
+static ssize_t show_led##num(struct device *dev,                        \
+                            struct device_attribute *attr,              \
+                            char *buf)                                  \
+{                                                                       \
+  int    msk            = 1<<(num-1);                                   \
+  return sprintf(buf, "%c\n", SCU3_LED_REG & msk ? '1' : '0' );         \
+}                                                                       \
+                                                                        \
+static ssize_t store_led##num(struct device *dev,                       \
+                             struct device_attribute *attr,             \
+                             const char *buf, size_t count)             \
+{                                                                       \
+  int msk=  1<<(num-1);                                                 \
+  unsigned char kbuf    = buf[0]&0xf;                                   \
+  if(count<1)                                                           \
+    return -EFAULT;                                                     \
+  if(kbuf){                                                             \
+    SCU3_LED_REG |=  msk;                                               \
+  }else {                                                               \
+    SCU3_LED_REG &= ~msk;                                               \
+  }                                                                     \
+  return count;                                                         \
+}                                                                       \
+static DEVICE_ATTR(scu3_led##num, S_IRUGO | S_IWUGO, show_led##num, store_led##num);
+LED_ACCESS(1)
+LED_ACCESS(2)
+LED_ACCESS(3)
+LED_ACCESS(4)
+
+static ssize_t show_leds(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+  return sprintf(buf, "0x%02x\n", SCU3_LED_REG );
+}
+
+static ssize_t store_leds(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+  if(count<1)
+    return -EFAULT;
+  SCU3_LED_REG  = simple_strtoul(buf,0,16);
+  return count;
+}
+static DEVICE_ATTR(scu3_leds, S_IRUGO | S_IWUGO, show_leds, store_leds);
+
+
+
+//extern int nmi_watchdog_counter;
+//static ssize_t show_wdg(struct device *dev,
+//                            struct device_attribute *attr,
+//                            char *buf)
+//{
+//  return sprintf(buf, "%d\n", nmi_watchdog_counter );
+//}
+//
+//static ssize_t store_wdg(struct device *dev,
+//                          struct device_attribute *attr,
+//                          const char *buf, size_t count)
+//{
+//  if(count<1)
+//    return -EFAULT;
+//  nmi_watchdog_counter  = simple_strtoul(buf,0,10);
+//  return count;
+//}
+//static DEVICE_ATTR(scu3_wdg, S_IRUGO | S_IWUGO, show_wdg, store_wdg);
+
+
+
+
+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;
+
+// old
+// static irqreturn_t uio_scu3_handler(int irq, struct uio_info *dev_info)
+// {
+//   u16 req=((SCU3_INT_STATUS_REG & 0xff) << 8) | (SCU3_FI_STATUS_REG & 0xff);
+//
+//   if(!req)   /* shared irq? */
+//   {
+//     return IRQ_NONE;
+//   }
+//   //SCU3_FI_FRG_REG  = 0; nicht sperren damit weiterhin alle flanken sichtbar
+//   SCU3_FI_EOI_REG  = 0xff; //Fast Input Ints mit EOI beseitigen
+//   SCU3_INT_FRG_REG = 0; //Hier gehts nicht mit EOI weil die Quellen noch anstehen
+//   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;
+}
+
+
+//#define NUM_RESOURCES 2
+#define NUM_UARTLITES 3
+//static struct resource             uart_res[NUM_UARTLITES][NUM_RESOURCES];
+static struct platform_device *uart_devices[NUM_UARTLITES];
+
+
+static int sio_init(unsigned int num, resource_size_t base, int irq, int intmsk)
+{
+  int ret;
+  //  struct resource        *pres = uart_res[num];
+  struct resource  uart_res[] = {
+    {.flags = IORESOURCE_MEM,    .start = base,    .end   = base + 16,},
+    {.flags = IORESOURCE_IRQ,    .start = irq,     .end   = irq,      }
+  };
+  //struct resource        *pres = uart_res;
+  struct platform_device *pdev;
+  if(num > NUM_UARTLITES)
+  {
+    printk(KERN_ERR PFX "sio_init() index out of range %d\n",num);
+    return -ENOENT;
+  }
+
+  printk(KERN_INFO PFX "sio_init %d: pres %p\n",
+           num,&uart_res);
+
+//   pres[0].flags = IORESOURCE_MEM;
+//   pres[0].start = base;
+//   pres[0].end   = base + 16;
+//   pres[1].flags = IORESOURCE_IRQ;
+//   pres[1].start = irq;
+//   pres[1].end   = irq;
+
+  SCU3_INT_FRG_REG  |= intmsk; //sio_int_masks[num];
+
+//   pdev = platform_device_register_simple("uartlite", num, pres, 2);
+  pdev = platform_device_register_simple("uartlite", num,
+                                         uart_res, sizeof(uart_res)/sizeof(uart_res[0]));
+  uart_devices[num]=pdev;
+
+  ret =  PTR_ERR(pdev);
+  if (IS_ERR(pdev))
+  {
+    printk(KERN_ERR PFX "Unable to register platform device '%s'#%d: err=%d\n",
+           "uartlite", num, ret);
+    SCU3_INT_FRG_REG  &= ~intmsk;//sio_int_masks[num];
+  }
+  else
+  {
+    printk(KERN_INFO PFX "Registered platform device '%s'#%d\n",
+           pdev->name,pdev->id);
+  }
+  return ret;
+}
+
+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;
+  }else{
+    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, &addrBase_7 ,"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(sio_init(0, mmio_start+0x500000, pci_irq,SCU3_INT_SER_1)==0)
+    initState|=0x10; //sio0 initialized
+  if(sio_init(1, mmio_start+0x600000, pci_irq,SCU3_INT_SER_2)==0)
+    initState|=0x20; //sio1 initialized
+  if(sio_init(2, mmio_start+0xf00000, pci_irq,SCU3_INT_SER_3)==0)
+    initState|=0x40; //sio2 initialized
+
+  if(dmem_init(pdev)==0)
+    initState|=0x80; //dma memory
+
+  ///home/husteret/build/SfcLeanOs-RT/trunk/Src/kernel/linux-2.6.22.1-rt9-lttng/include/linux/pci.h
+    //  class_create_file(&pdev->bus->class_dev, &dev_attr_led1);
+  device_create_file(&pdev->dev, &dev_attr_scu3_led1);
+  device_create_file(&pdev->dev, &dev_attr_scu3_led2);
+  device_create_file(&pdev->dev, &dev_attr_scu3_led3);
+  device_create_file(&pdev->dev, &dev_attr_scu3_led4);
+  device_create_file(&pdev->dev, &dev_attr_scu3_leds);
+  //device_create_file(&dev->dev, &dev_attr_scu3_wdg);
+  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_led1);
+    device_remove_file(&pdev->dev, &dev_attr_scu3_led2);
+    device_remove_file(&pdev->dev, &dev_attr_scu3_led3);
+    device_remove_file(&pdev->dev, &dev_attr_scu3_led4);
+    device_remove_file(&pdev->dev, &dev_attr_scu3_leds);
+    //device_remove_file(&pdev->dev, &dev_attr_scu3_wdg);
+    device_remove_file(&pdev->dev, &dev_attr_scu3_id);
+  }
+  if(initState & 0x80)  dmem_remove(pdev);
+  if(initState & 0x40)  platform_device_unregister(uart_devices[2]);
+  if(initState & 0x20)  platform_device_unregister(uart_devices[1]);
+  if(initState & 0x10)  platform_device_unregister(uart_devices[0]);
+
+  //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,
+  .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");
+MODULE_AUTHOR("Thomas Husterer");
+MODULE_DESCRIPTION("UIO scu3 driver");
+
+//for entry in modules.pcimap
+MODULE_DEVICE_TABLE(pci, scu3_pci_tbl);