mkopci (MB11.xx) device (RC Module project) provides data transference through 
a serial bus bar according to MIL-STD-1553.
the driver used for operating devices, reads PCI configuration space and pass 
interrupts to user-space applications.

Please consider adding this patch to the linux-next queue.

Signed-off-by: Sergej Bauer <sergej.ba...@gmail.com>
---
 Documentation/misc-devices/mkopci.txt |   51 ++
 drivers/misc/Kconfig                  |    9 +
 drivers/misc/Makefile                 |    1 +
 drivers/misc/mkopci.c                 | 1272 +++++++++++++++++++++++++++++++++
 include/misc/mkopci.h                 |   81 +++
 5 files changed, 1414 insertions(+)
create mode 100644 Documentation/misc-devices/mkopci.txt
create mode 100644 drivers/misc/mkopci.c
create mode 100644 include/misc/mkopci.h
diff --git a/Documentation/misc-devices/mkopci.txt 
b/Documentation/misc-devices/mkopci.txt
new file mode 100644
index 0000000..0fcec6d
--- /dev/null
+++ b/Documentation/misc-devices/mkopci.txt
@@ -0,0 +1,51 @@
+    PCI-based MKO bus driver.
+
+
+For dealing with driver without using of root's account it will be helpfull
+to add group `mkopci' with appropriate users and put file, say 60-mkopci.rules 
to
+/etc/udev/rules.d in your system.
+--- cut 60-mkopci.rules ---
+# MKO devices
+KERNEL=="mkopci*", SUBSYSTEM=="mkopci", ACTION=="add", DRIVERS=="?*", 
ATTRS{idVendor}=="0x6403"
+GROUP="mkopci"
+---
+
+
+Kernel module parameters
+
+Kernel module can take parameters 'v' and 'omited'
+- 'v' is 0 to 3, and affects the amount of information
+output to the system log.
+0 - (default) comletely silent
+1 - prints only detected BARs, reports loading / unloading
+2 - + prints IRQ and memory mapping events
+3 - + prints ioctl events
+
+- 'plx9050bug_quirk' controls workaround controller PLX9050. Can
+the following values:
+0 - workaround is disabled (default)
+1 - workaround is enabled
+2 - forced bug
+
+- 'omited' tells the driver which device should not be initialized
+at load time.
+The value of this parameter to the kernel module 2.4 is a physical address
+device on the bus, such as "0x10800" without the quotes.
+In kernel versions 2.6+ can exclude multiple devices, transferring them
+values separated by commas, but not more than 4.
+
+The parameter values can be specified as follows:
+$ insmod/modprobe mkopci.[ko/o] parameter1_name=value [parameter2_name=value]
+
+Record the physical address of the device in the file /proc/mkopci/core
+also controls "visibility" for user programs. Missed return device
+You can command 'echo ADDR > /proc/mkopci/core'. ADDR can be either a simple
+number of device, but always in hexadecimal, or (for Linux-2.6+)
+the number of devices in a standard format Linux kind NM:XY.z.
+
+
+PROC filesystem
+
+/proc/mkopci/devices - read only text device table
+/proc/mkopci/core    - device table for user space applications
+
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 006242c..7db247e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -124,6 +124,15 @@ config PHANTOM
          If you choose to build module, its name will be phantom. If unsure,
          say N here.
 
+config MKOPCI 
+       tristate "Module PCI bus driver"
+       depends on PCI && PROC_FS
+       help
+         Say Y here if you want to build a driver for Module(RC) MKOPCI 
devices.
+
+         If you choose to build module, its name will be mkopci. If unsure,
+         say N here.
+
 config INTEL_MID_PTI
        tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
        depends on PCI && TTY && (X86_INTEL_MID || COMPILE_TEST)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7d5c4cd..afb92b4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE)          += genwqe/
 obj-$(CONFIG_ECHO)             += echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)  += vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)         += cxl/
+obj-$(CONFIG_MKOPCI)           += mkopci.o
diff --git a/drivers/misc/mkopci.c b/drivers/misc/mkopci.c
new file mode 100644
index 0000000..d223478
--- /dev/null
+++ b/drivers/misc/mkopci.c
@@ -0,0 +1,1272 @@
+/*
+ *  MKOPCI driver
+ *
+ *  Copyright (C) 2007-2015 Sergej Bauer <sergej.ba...@gmail.com>
+ *
+ *  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, version 2.
+*/
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "misc/mkopci.h"
+
+#define MKO_VENDOR  0x6403
+#define MKO_DEVICE1 0x0430
+#define MKO_DEVICE2 0x0431
+#define MKO_DEVICE3 0x0434
+
+#define PLX9050BUG_BAR0 0x1
+#define PLX9050BUG_BAR1 0x2
+#define PLX9050BUG_INJECT 0x4
+
+#if !defined(__user)
+#define __user
+#endif
+
+static struct pci_device_id ids[] = {
+       {MKO_VENDOR, MKO_DEVICE1, PCI_ANY_ID, PCI_ANY_ID,},
+       {MKO_VENDOR, MKO_DEVICE2, PCI_ANY_ID, PCI_ANY_ID,},
+       {MKO_VENDOR, MKO_DEVICE3, PCI_ANY_ID, PCI_ANY_ID,},
+       {0, 0,}
+};
+
+MODULE_DEVICE_TABLE(pci, ids);
+
+#ifdef __LP64__
+#define PFMT   "llx"
+#else
+#define PFMT   "x"
+#endif
+
+unsigned char drv_version = 0x11;
+#define mko_pci_addr(bus, device, func, regoffs) (\
+       ((bus  & 0xFF) << 16) | ((device & 0x1F) << 11) | \
+       ((func & 0x7)  <<  8) | (regoffs & 0xFC))
+
+static struct kmem_cache *mkopci_device_cache;
+static dev_t devp;
+static struct class *mkopci_class;
+static struct rw_semaphore devices_sem;
+static LIST_HEAD(devices);
+static atomic_t devices_nr = ATOMIC_INIT(0);
+
+/*** module parameters ***/
+static int plx9050bug_quirk = 1;
+/* verbosity level */
+static int v;
+module_param(plx9050bug_quirk, int, S_IRUGO);
+module_param(v, int, S_IRUGO);
+MODULE_PARM_DESC(plx9050bug_quirk, "PLX9050 bug quirk");
+MODULE_PARM_DESC(v, "verbosity level");
+
+/* only MAX_DEVICES_NR devices at once can be omited */
+static int omited[MAX_DEVICES_NR];
+static int omited_nr;
+module_param_array(omited, int, &omited_nr, S_IRUGO);
+MODULE_PARM_DESC(omited, "device(s) to omit");
+#ifndef VM_RESERVED
+#define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
+#endif
+#define __unused __attribute__ ((unused))
+
+/***************************** Interrupt handling 
*****************************/
+static int mkopci_wait_irq(struct mkopci_device *dev)
+{
+       volatile unsigned long *LPCI_4C =
+               (unsigned long *)(dev->core.lin_base[0] + 0x4C);
+
+       *LPCI_4C |= 0x49;
+
+       if (wait_event_interruptible(dev->wq, *LPCI_4C & 0x24))
+               return -ERESTARTSYS;
+       if (v > 1)
+               pr_info("mkopci%d: irq received\n", dev->core.n_dev);
+       *LPCI_4C &= ~0x40;
+
+       return 0;
+}
+
+static irqreturn_t mkopci_int_handler(int __unused irq, void *dev)
+{
+       struct mkopci_device *mko_dev = (struct mkopci_device *)dev;
+       volatile unsigned long *LPCI_4C =
+           (unsigned long *)((mko_dev->core.lin_base[0] + 0x4C));
+
+       if (*LPCI_4C & 0x24) {
+               *LPCI_4C &= ~0x40;
+               wake_up_interruptible(&mko_dev->wq);
+       } else
+               return IRQ_NONE;
+
+       return IRQ_HANDLED;
+}
+
+static int mkopci_request_irq(struct mkopci_device *dev)
+{
+       int ret = 0;
+
+       if (dev->core.irq_requested) {
+               pr_err("mkopci%d: irq already requested\n", dev->core.n_dev);
+               return -EBUSY;
+       }
+       ret = request_irq(dev->core.irq, &mkopci_int_handler, IRQF_SHARED,
+                       dev->core.name, dev);
+       if (ret) {
+               pr_err("mkopci%d: failed to request irq %d\n", dev->core.n_dev,
+                       dev->core.irq);
+               return ret;
+       }
+
+       dev->core.irq_requested++;
+
+       if (strcmp(current->comm, "TestSetISR") && v > 1) {
+               pr_info("mkopci%d: irq %d requested (%s)\n", dev->core.n_dev,
+                       dev->core.irq, current->comm);
+       }
+
+       return ret;
+}
+
+static void mkopci_free_irq(struct mkopci_device *dev)
+{
+       if (dev->core.irq_requested) {
+               synchronize_irq(dev->core.irq);
+               free_irq(dev->core.irq, dev);
+               dev->core.irq_requested--;
+
+               if (strcmp(current->comm, "TestSetISR") && v > 1) {
+                       pr_info("mkopci%d: irq %d released\n", dev->core.n_dev,
+                               dev->core.irq);
+               }
+       }
+}
+/************************* End of Interrupt handling 
**************************/
+
+/**************************** File operations 
*********************************/
+static int mkopci_open(struct inode *inode, struct file *filp)
+{
+       int ret = 0;
+       struct mkopci_device *dev =
+           container_of(inode->i_cdev, struct mkopci_device, cdev);
+
+       if (!try_module_get(THIS_MODULE))
+               return -EINVAL;
+
+       if (dev == NULL) {
+               module_put(THIS_MODULE);
+               return -ENODEV;
+       }
+
+       down_write(&dev->rwsem);
+       if (dev->omited) {
+               ret = -ENODEV;
+               goto err;
+       }
+       if (!(filp->f_flags & O_NONBLOCK)) {
+               if (dev->core.process) {
+                       ret = -EBUSY;
+                       goto err;
+               }
+               dev->backdoor = 0;
+               dev->core.process = current->pid;
+       } else {
+               dev->backdoor = current->pid;
+               dev->core.process = 0;
+       }
+
+       filp->private_data = dev;
+
+       if (strcmp(current->comm, "TstOpenClose") && v > 1)
+               pr_info("mkopci%d: device opened in %s mode (%s)\n",
+                       dev->core.n_dev, dev->backdoor ? "backdoor" : "regular",
+                       current->comm);
+       goto out;
+
+err:
+       module_put(THIS_MODULE);
+out:
+       up_write(&dev->rwsem);
+
+       return ret;
+}
+
+static int mkopci_release(struct inode __unused *inode, struct file *filp)
+{
+       struct mkopci_device *dev;
+
+       if (filp->private_data == NULL)
+               return 0;
+
+       dev = (struct mkopci_device *)filp->private_data;
+       down_write(&dev->rwsem);
+       dev->core.process = 0;
+       dev->backdoor = 0;
+       dev->core.c_bar = -1;
+       filp->private_data = NULL;
+       mkopci_free_irq(dev);
+
+       if (strcmp(current->comm, "TstOpenClose") && v > 1)
+               pr_info("mkopci%d: device released\n", dev->core.n_dev);
+       up_write(&dev->rwsem);
+       module_put(THIS_MODULE);
+
+       return 0;
+}
+
+static long mkopci_ioctl(struct file *filp, unsigned int cmd, unsigned long 
arg)
+{
+       int ret = 0, n = 0;
+       struct mkopci_device *dev =
+           (struct mkopci_device *)filp->private_data, *d;
+
+       if (_IOC_TYPE(cmd) != MKO_IOC_MAGIC) {
+               pr_err("mkopci%d: _IOC_TYPE(cmd) != MKO_IOC_MAGIC\n",
+                       dev->core.n_dev);
+               return -ENOTTY;
+       }
+
+       if (_IOC_NR(cmd) > MKO_IOC_MAXNR) {
+               pr_err("mkopci%d: _IOC_NR(cmd) > MKO_IOC_MAXNR\n",
+                       dev->core.n_dev);
+               return -ENOTTY;
+       }
+
+       if (_IOC_DIR(cmd) & _IOC_READ) {
+               ret =
+                   !access_ok(VERIFY_WRITE, (void __user *)arg,
+                               _IOC_SIZE(cmd));
+       } else if (_IOC_DIR(cmd) & _IOC_WRITE) {
+               ret =
+                   !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
+       }
+
+       if (ret) {
+               pr_err("mkopci%d: mkopci_ioctl: access_ok failed\n",
+                      dev->core.n_dev);
+               return -EIO;
+       }
+
+       switch (cmd) {
+       case MKOPCI_IOCTL_CWPID:
+               if (v > 2)
+                       pr_info("mkopci%d: MKOPCI_IOCTL_CWPID ioctl\n",
+                               dev->core.n_dev);
+               down_read(&dev->rwsem);
+               ret = dev->core.process;
+               up_read(&dev->rwsem);
+               break;
+       case MKOPCI_IOCTL_GET_VERSION:
+               if (v > 2)
+                       pr_info("mkopci%d: MKOPCI_IOCTL_GET_VERSION  ioctl\n",
+                               dev->core.n_dev);
+               ret = put_user(drv_version, (int __user *)arg);
+               break;
+       case MKOPCI_IOCTL_GET_BOARDS_COUNT:
+               if (v > 2)
+                       pr_info
+                           ("mkopci%d: MKOPCI_IOCTL_GET_BOARDS_COUNT ioctl\n",
+                            dev->core.n_dev);
+               down_read(&dev->rwsem);
+               ret =
+                   put_user((unsigned short)atomic_read(&devices_nr),
+                            (int __user *)arg);
+               up_read(&dev->rwsem);
+               break;
+       case MKOPCI_IOCTL_GET_DEVICE_TABLE:
+               if (v > 2)
+                       pr_info
+                           ("mkopci%d: MKOPCI_IOCTL_GET_DEVICE_TABLE ioctl\n",
+                            dev->core.n_dev);
+               down_read(&devices_sem);
+               if (put_user
+                   ((unsigned short)atomic_read(&devices_nr),
+                    (int __user *)arg)) {
+                       up_read(&devices_sem);
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               list_for_each_entry(d, &devices, list) {
+                       down_read(&d->rwsem);
+                       if (d->omited) {
+                               up_read(&d->rwsem);
+                               continue;
+                       }
+                       if (copy_to_user
+                           ((void __user *)arg + sizeof(unsigned short) +
+                            n * sizeof(struct mkopci_core), &d->core,
+                            sizeof(struct mkopci_core))) {
+                               up_read(&d->rwsem);
+                               ret = -ERESTARTSYS;
+                               break;
+                       }
+                       up_read(&d->rwsem);
+                       n++;
+               }
+               up_read(&devices_sem);
+               break;
+       case MKOPCI_IOCTL_ATTACH_IRQ:
+               if (v > 2)
+                       pr_info("mkopci%d: MKOPCI_IOCTL_ATTACH_IRQ ioctl\n",
+                               dev->core.n_dev);
+               down_write(&dev->rwsem);
+               ret = mkopci_request_irq(dev);
+               up_write(&dev->rwsem);
+               break;
+       case MKOPCI_IOCTL_DETACH_IRQ:
+               if (v > 2)
+                       pr_info("mkopci%d: MKOPCI_IOCTL_DETACH_IRQ ioctl\n",
+                               dev->core.n_dev);
+               down_write(&dev->rwsem);
+               mkopci_free_irq(dev);
+               up_write(&dev->rwsem);
+               break;
+       case MKOPCI_IOCTL_WAIT_IRQ:
+               if (v > 2)
+                       pr_info("mkopci%d: MKOPCI_IOCTL_WAIT_IRQ ioctl\n",
+                               dev->core.n_dev);
+               ret = mkopci_wait_irq(dev);
+               break;
+       case MKOPCI_IOCTL_REQUEST_BAR:
+               if (v > 2)
+                       pr_info("mkopci%d: MKOPCI_IOCTL_REQUEST_BAR ioctl\n",
+                               dev->core.n_dev);
+               down_write(&dev->rwsem);
+               ret = get_user(dev->core.c_bar, (int __user *)arg);
+               up_write(&dev->rwsem);
+               break;
+       default:
+               pr_err("mkopci%d: invalid ioctl %d\n", dev->core.n_dev,
+                      _IOC_NR(cmd));
+               ret = -EINVAL;
+               break;
+       };
+
+       return ret;
+}
+
+#ifndef pgprot_noncached
+static inline pgprot_t pgprot_noncached(pgprot_t _prot)
+{
+       unsigned long prot = pgprot_val(_prot);
+
+       if (boot_cpu_data.x86 > 3)
+               prot |= _PAGE_PCD | _PAGE_PWT;
+
+       return __pgprot(prot);
+}
+#endif
+
+static int mkopci_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct mkopci_device *dev = filp->private_data;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+       if (dev->core.c_bar == -1) {
+               pr_err("mkopci%d: invalid c_bar number\n", dev->core.n_dev);
+               return -EINVAL;
+       }
+
+       if (vma->vm_pgoff != 0) {
+               pr_err("mkopci%d: vma->vm_pgoff != 0, aborting mapping\n",
+                      dev->core.n_dev);
+               return -EINVAL;
+       }
+
+       if (PAGE_ALIGN(dev->core.mem_size[dev->core.c_bar]) !=
+           PAGE_ALIGN(vma->vm_end - vma->vm_start)) {
+               pr_err("mkopci%d: PAGE_ALIGN error\n", dev->core.n_dev);
+               return -EINVAL;
+       }
+
+       if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))
+               vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED | VM_SHARED;
+
+       if (v > 1 && strcmp("TstOpenClose", current->comm)) {
+               pr_info
+                   ("mkopci%d: .mmap BAR%d: [0x%lx - 0x%lx], vma [0x%lx - 
0x%lx]\n",
+                    dev->core.n_dev, dev->core.c_bar,
+                    dev->core.mem_base[dev->core.c_bar],
+                    dev->core.mem_base[dev->core.c_bar] +
+                    dev->core.mem_size[dev->core.c_bar], vma->vm_start,
+                    vma->vm_end);
+       }
+
+       if (remap_pfn_range
+           (vma, vma->vm_start,
+            virt_to_phys(bus_to_virt(dev->core.mem_base[dev->core.c_bar])) >>
+            PAGE_SHIFT, dev->core.mem_size[dev->core.c_bar],
+            pgprot_noncached(vma->vm_page_prot))) {
+               pr_err("mkopci%d: memory remapping failed\n", dev->core.n_dev);
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+static const struct file_operations mkopci_fops = {
+       .owner = THIS_MODULE,
+       .open = mkopci_open,
+       .release = mkopci_release,
+       .unlocked_ioctl = mkopci_ioctl,
+       .mmap = mkopci_mmap,
+};
+/************************ End of File operations 
******************************/
+
+/*************************** pci_driver functions 
*****************************/
+static int mkopci_probe_cdevhelper(struct pci_dev *dev)
+{
+       struct mkopci_device *device =
+           (struct mkopci_device *)pci_get_drvdata(dev);
+       struct device *dev_;
+       int err = 0;
+
+       cdev_init(&device->cdev, &mkopci_fops);
+       device->cdev.owner = THIS_MODULE;
+
+       err = cdev_add(&device->cdev, MKDEV(MAJOR(devp),
+                       MINOR(devp) + device->core.n_dev), 1);
+       if (err) {
+               pr_err("mkopci%d: error while cdev_add\n", device->core.n_dev);
+               return err;
+       }
+
+       dev_ =
+           device_create(mkopci_class, NULL,
+                         MKDEV(MAJOR(devp), MINOR(devp) + device->core.n_dev),
+                         NULL, device->core.name);
+       if (IS_ERR(dev_)) {
+               pr_err("mkopci%d: Unable to create device\n",
+                      device->core.n_dev);
+               err = PTR_ERR(dev_);
+               cdev_del(&device->cdev);
+       }
+
+       return err;
+}
+
+static int mkopci_plx9050workaround(struct pci_dev *dev, int plx9050bug)
+{
+       struct mkopci_device *device;
+       int err = 0;
+       phys_addr_t plxphys = ~(phys_addr_t) 0;
+       resource_size_t len;
+       struct resource *res;
+
+       device = (struct mkopci_device *)pci_get_drvdata(dev);
+       if (!device) {
+               err = -ENODEV;
+               goto out;
+       }
+
+       if (plx9050bug & PLX9050BUG_INJECT || plx9050bug & PLX9050BUG_BAR0) {
+               plxphys =
+                   (pci_resource_start(dev, 0) & ~0xff) +
+                   ((plx9050bug & PLX9050BUG_INJECT) ? 0x80 : 0x0);
+               if (plx9050bug & PLX9050BUG_INJECT) {
+                       pr_info
+                           ("mkopci%d: [PLX9050 bug injection] mem start = 0x%"
+                            PFMT "\n", device->core.n_dev, plxphys);
+                       dev->resource[0].start |= 0x80;
+                       dev->resource[0].end =
+                           dev->resource[0].start + 0x80 - 1;
+                       err = pci_request_region(dev, 0, device->core.name);
+                       if (err) {
+                               pr_err("failed to request region 0");
+                               goto out;
+                       }
+               } else {
+                       pr_info
+                           ("mkopci%d: [PLX9050 bug workaround] mem start = 
0x%"
+                            PFMT "\n", device->core.n_dev, plxphys);
+                       res = &dev->resource[0];
+                       res->start &= ~0xff;
+                       res->end = res->start + 0x80 - 1;
+                       err = pci_request_region(dev, 0, device->core.name);
+                       if (err) {
+                               err =
+                                   allocate_resource(dev->resource[0].parent,
+                                                     res, 0x80,
+                                                     res->parent->start,
+                                                     res->parent->end - 0x80,
+                                                     0x100, NULL, NULL);
+                               if (err)
+                                       err =
+                                           allocate_resource(&iomem_resource,
+                                                             res, 0x80,
+                                                             iomem_resource.
+                                                             start,
+                                                             iomem_resource.
+                                                             end - 0x80, 0x100,
+                                                             NULL, NULL);
+                               if (err) {
+                                       pr_err("failed to allocate region");
+                                       goto out;
+                               }
+                               err =
+                                   pci_request_region(dev, 0,
+                                                      device->core.name);
+                               if (err) {
+                                       pr_err("failed to allocate region");
+                                       goto out;
+                               }
+                       }
+               }
+               len = pci_resource_len(dev, 0);
+               pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+                                      dev->resource[0].start);
+
+               device->core.mem_base[0] = dev->resource[0].start;
+               device->core.mem_size[0] = len;
+               pr_info("mkopci%d: device->core.mem_size[0] = %d\n",
+                       device->core.n_dev, device->core.mem_size[0]);
+       }
+
+       if (plx9050bug & PLX9050BUG_INJECT)
+               goto out;
+
+       if (plx9050bug & PLX9050BUG_BAR1) {
+               plxphys = pci_resource_start(dev, 1);
+               len = pci_resource_len(dev, 1);
+               plxphys = plxphys & (PAGE_MASK | 0xf00);
+               pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, plxphys);
+               dev->resource[1].start = plxphys;
+               dev->resource[1].end = dev->resource[1].start + len - 1;
+
+               if (pci_request_region(dev, 1, device->core.name)) {
+                       err = -EFAULT;
+                       if (plx9050bug & PLX9050BUG_BAR0) {
+                               iounmap((void *)device->core.lin_base[0]);
+                               device->core.lin_base[0] = 0;
+                               pci_release_region(dev, 0);
+                       }
+                       goto out;
+               }
+
+               if (v > 0)
+                       pr_info
+                           ("mkopci%d: BAR%d = 0x%lx I/O region [PLX9050 bug 
workaround]\n",
+                            device->core.n_dev, 1,
+                            (unsigned long)pci_resource_start(dev, 1));
+       }
+out:
+       return err;
+}
+
+static int mkopci_probe_helper(struct pci_dev *dev)
+{
+       int reg = 0, n = 0, err = 0, plx9050bug = 0;
+       struct mkopci_device *device;
+
+       device = (struct mkopci_device *)pci_get_drvdata(dev);
+       if (!device)
+               return -ENODEV;
+
+       if (dev->device == MKO_DEVICE1 || plx9050bug_quirk == 2 ||
+           plx9050bug_quirk == 1) {
+               if (plx9050bug_quirk == 2) {
+                       err = mkopci_plx9050workaround(dev,
+                                                     plx9050bug |
+                                                     PLX9050BUG_INJECT);
+                       if (err)
+                               return err;
+               }
+
+               if (pci_resource_start(dev, 0) & 0x80)
+                       plx9050bug = PLX9050BUG_BAR0;
+               if (pci_resource_start(dev, 1) & 0x80)
+                       plx9050bug |= PLX9050BUG_BAR1;
+
+               if (plx9050bug && plx9050bug_quirk == 1) {
+                       err = mkopci_plx9050workaround(dev, plx9050bug);
+                       if (err)
+                               return err;
+               }
+       }
+
+       for (; reg < MAX_MEM_WIN + 1; reg++) {
+               if (pci_resource_flags(dev, reg) & IORESOURCE_MEM) {
+                       device->core.mem_base[n] = pci_resource_start(dev, reg);
+                       if (!device->core.mem_base[n]) {
+                               pr_err("mkopci%d: Unable to get BAR%d\n",
+                                      device->core.n_dev, n);
+                               err = -EFAULT;
+                               goto fail;
+                       }
+
+                       device->core.mem_size[n] = pci_resource_len(dev, reg);
+                       if (!device->core.mem_size[n]) {
+                               pr_err
+                                   ("mkopci%d: Unable to get size of BAR%d\n",
+                                    device->core.n_dev, n);
+                               err = -EFAULT;
+                               goto fail;
+                       }
+
+                       if ((reg != 0) || !(plx9050bug & PLX9050BUG_BAR0)) {
+                               err = pci_request_region(dev, reg, 
device->core.name);
+                               if (err) {
+                                       pr_err
+                                               ("mkopci%d: couldn't request 
region 0x%x with size 0x%x\n",
+                                                device->core.n_dev,
+                                                (unsigned 
int)device->core.mem_base[n],
+                                                (unsigned 
int)device->core.mem_size[n]);
+                                       iounmap((void 
*)device->core.lin_base[n]);
+                                       goto fail;
+                               }
+                       }
+
+                       device->core.lin_base[n] =
+                           (unsigned long)ioremap_nocache(device->core.
+                                                          mem_base[n],
+                                                          device->core.
+                                                          mem_size[n]);
+                       if (!device->core.lin_base[n]) {
+                               pr_err
+                                   ("mkopci%d: Unable to remap 
BAR%d[0x%lx:0x%lx]\n",
+                                    device->core.n_dev, n,
+                                    device->core.mem_base[n],
+                                    device->core.mem_base[n] +
+                                    device->core.mem_size[n] - 1);
+                               err = -EFAULT;
+                               goto fail;
+                       }
+                       if (v > 0)
+                               pr_info
+                                   ("mkopci%d: BAR%d = 0x%08lx, linear = 
0x%08lx, len = 0x%x\n",
+                                    device->core.n_dev, reg,
+                                    device->core.mem_base[n],
+                                    device->core.lin_base[n],
+                                    device->core.mem_size[n]);
+                       n++;
+               } else {
+                       if (v > 0)
+                               pr_info("mkopci%d: BAR%d = 0x%lx I/O region\n",
+                                       device->core.n_dev, reg,
+                                       (unsigned long)pci_resource_start(dev,
+                                                                         reg));
+                       err = pci_request_region(dev, reg, device->core.name);
+                       if (err) {
+                               pr_err("mkopci%d: couldn't request region %d\n",
+                                      device->core.n_dev, reg);
+                               goto fail;
+                       }
+               }
+       }
+       device->core.mem_windows_nr = n;
+
+       device->core.ltype =
+           (*((unsigned short *)(device->core.lin_base[4]) + 3)) & 0xFF;
+       device->core.irq = dev->irq;
+       if (v > 0)
+               pr_info("mkopci%d: irq = %d\n", device->core.n_dev,
+                       device->core.irq);
+       device->core.irq_requested = 0;
+       device->core.c_bar = -1;
+
+       err = mkopci_probe_cdevhelper(dev);
+       if (err) {
+               plx9050bug = 0;
+               goto fail2;
+       }
+       atomic_inc(&devices_nr);
+       goto out;
+
+fail:
+       reg--;
+       n--;
+fail2:
+       for (; reg >= 0; reg--) {
+               if (plx9050bug && reg < 2)
+                       break;
+               if (pci_resource_flags(dev, reg) & IORESOURCE_MEM) {
+                       iounmap((void *)device->core.lin_base[n]);
+                       device->core.lin_base[n--] = 0;
+               }
+               pci_release_region(dev, reg);
+       }
+
+out:
+       return err;
+}
+
+static int mkopci_probe(struct pci_dev *dev, const struct pci_device_id 
__unused *id)
+{
+       int n_prdev = 0, err = 0;
+       int n;
+       struct mkopci_device *device, *mdev = NULL;
+       struct list_head *it;
+
+       if (atomic_read(&devices_nr) == (1 << 8 * sizeof(unsigned char)) - 1)
+               return -EBUSY;
+
+       err = pci_enable_device(dev);
+       if (err) {
+               pr_err("mkopci: error = %d while enabling PCI device\n", err);
+               return err;
+       }
+
+       device = kmem_cache_zalloc(mkopci_device_cache, GFP_KERNEL);
+       if (!device) {
+               pr_err("mkopci: Unable to allocate memory\n");
+               pci_disable_device(dev);
+               return -ENOMEM;
+       }
+
+       down_write(&devices_sem);
+       if (!list_empty(&devices)) {
+               list_for_each(it, &devices) {
+                       mdev = list_entry(it, struct mkopci_device, list);
+                       if (n_prdev < mdev->core.n_dev) {
+                               if (n_prdev)
+                                       device->core.n_dev = n_prdev - 1;
+                               else
+                                       device->core.n_dev = n_prdev;
+                               list_add(&device->list, mdev->list.prev);
+                               break;
+                       }
+                       n_prdev++;
+               }
+               if (n_prdev >= mdev->core.n_dev) {
+                       device->core.n_dev = atomic_read(&devices_nr);
+                       list_add_tail(&device->list, &devices);
+               }
+       } else
+               list_add_tail(&device->list, &devices);
+       up_write(&devices_sem);
+
+       pci_set_drvdata(dev, device);
+       device->pci_dev = dev;
+       for (n = 0; n < omited_nr; n++) {
+               if (omited[n] ==
+                   mko_pci_addr(dev->bus->number, PCI_SLOT(dev->devfn),
+                                PCI_FUNC(dev->devfn), 0)) {
+                       pci_disable_device(dev);
+                       device->omited = 1;
+               }
+       }
+
+       device->core.vendor_id = dev->vendor;
+       device->core.device_id = dev->device;
+       device->core.subs_vendor_id = dev->subsystem_vendor;
+       device->core.subs_id = dev->subsystem_device;
+       device->core.instance =
+           mko_pci_addr(dev->bus->number, PCI_SLOT(dev->devfn),
+                        PCI_FUNC(dev->devfn), 0);
+       sprintf(device->core.name, "mkopci%d", device->core.n_dev);
+
+       init_waitqueue_head(&device->wq);
+       init_rwsem(&device->rwsem);
+
+       down_write(&device->rwsem);
+       if (device->omited)
+               goto out;
+
+       err = mkopci_probe_helper(dev);
+       if (err) {
+               pci_disable_device(dev);
+               list_del(&device->list);
+               kmem_cache_free(mkopci_device_cache, device);
+       }
+
+out:
+       up_write(&device->rwsem);
+       return err;
+}
+
+static void mkopci_remove_helper(struct pci_dev *dev)
+{
+       int reg, n = 0;
+       unsigned char rom_base_reg = dev->rom_base_reg;
+       struct mkopci_device *device =
+           (struct mkopci_device *)pci_get_drvdata(dev);
+
+       rom_base_reg = dev->rom_base_reg / 8;
+       for (reg = 0; reg < DEVICE_COUNT_RESOURCE; reg++) {
+               if (reg == rom_base_reg)
+                       continue;
+               if (pci_resource_flags(dev, reg) & IORESOURCE_MEM) {
+                       if (v > 1)
+                               pr_info("mkopci%d: unmapping BAR%d (0x%lx)\n",
+                                       device->core.n_dev, reg,
+                                       device->core.lin_base[n]);
+                       iounmap((void *)device->core.lin_base[n]);
+                       device->core.lin_base[n++] = 0;
+               }
+
+               pci_release_region(dev, reg);
+       }
+
+       mkopci_free_irq(device);
+       pci_disable_device(dev);
+       device_destroy(mkopci_class,
+                      MKDEV(MAJOR(devp), MINOR(devp) + device->core.n_dev));
+       cdev_del(&device->cdev);
+       atomic_dec(&devices_nr);
+}
+
+static void mkopci_remove(struct pci_dev *dev)
+{
+       struct mkopci_device *device =
+           (struct mkopci_device *)pci_get_drvdata(dev);
+
+       down_write(&device->rwsem);
+       if (!device->omited)
+               mkopci_remove_helper(dev);
+       list_del(&device->list);
+       up_write(&device->rwsem);
+       kmem_cache_free(mkopci_device_cache, device);
+       if (v > 0)
+               pr_info("mkopci%d: removed\n", device->core.n_dev);
+}
+
+#ifdef CONFIG_PM
+static int mkopci_suspend(struct device __unused *device)
+{
+       return -ENOSYS;
+}
+
+static int mkopci_resume(struct device __unused *device)
+{
+       return 0;
+}
+#else
+#define mkopci_suspend NULL
+#define mkopci_resume NULL
+#endif
+
+/*********************** End of pci_driver functions 
**************************/
+
+/*************************** proc entries functions 
***************************/
+static struct proc_dir_entry *mkopci_proc_file, *mkopci_proc_dir,
+       *mkopci_proc_core;
+
+static int mkopci_proc_show(struct seq_file *m, void __unused *vp)
+{
+       struct mkopci_device *mko_dev;
+
+       down_read(&devices_sem);
+       if (!atomic_read(&devices_nr))
+               seq_printf(m, "no devices detected\n");
+       else
+               seq_printf(m, "%d device(s) detected\n",
+                          atomic_read(&devices_nr));
+
+       seq_printf(m, "plx9050bug_quirk = %d\n", plx9050bug_quirk);
+       seq_printf(m, "verbosity level = %d\n", v);
+
+       list_for_each_entry(mko_dev, &devices, list) {
+               down_read(&mko_dev->rwsem);
+               seq_printf(m,
+                          "\ndevice\t\t\t/dev/%s\n" "vendor_id =\t\t0x%04x\n"
+                          "device_id =\t\t0x%04x\n"
+                          "subs_vendor_id =\t0x%04x\n" "subs_id =\t\t0x%04x\n"
+                          "ltype =\t\t\t%d\n" "instance =\t\t%02x:%02x.%x"
+                          " (0x%x)\n" "process =\t\t%d\n"
+                          "mem_base[0] =\t\t0x%08lx (linear = 0x%lx, size 
0x%x)\n"
+                          "mem_base[1] =\t\t0x%08lx (linear = 0x%lx, size 
0x%x)\n"
+                          "mem_base[2] =\t\t0x%08lx (linear = 0x%lx, size 
0x%x)\n"
+                          "mem_base[3] =\t\t0x%08lx (linear = 0x%lx, size 
0x%x)\n"
+                          "mem_base[4] =\t\t0x%08lx (linear = 0x%lx, size 
0x%x)\n"
+                          "irq_n =\t\t\t%d\n" "irq_requested =\t\t%d\n",
+                          mko_dev->omited ? "(OMITED)" : mko_dev->core.name,
+                          mko_dev->core.vendor_id, mko_dev->core.device_id,
+                          mko_dev->core.subs_vendor_id, mko_dev->core.subs_id,
+                          mko_dev->core.ltype, mko_dev->core.instance >> 16,
+                          mko_dev->core.instance >> 11 & 0x001f,
+                          (mko_dev->core.instance >> 8) & 0x7,
+                          mko_dev->core.instance, mko_dev->core.process,
+                          mko_dev->core.mem_base[0], mko_dev->core.lin_base[0],
+                          mko_dev->core.mem_size[0], mko_dev->core.mem_base[1],
+                          mko_dev->core.lin_base[1], mko_dev->core.mem_size[1],
+                          mko_dev->core.mem_base[2], mko_dev->core.lin_base[2],
+                          mko_dev->core.mem_size[2], mko_dev->core.mem_base[3],
+                          mko_dev->core.lin_base[3], mko_dev->core.mem_size[3],
+                          mko_dev->core.mem_base[4], mko_dev->core.lin_base[4],
+                          mko_dev->core.mem_size[4], mko_dev->core.irq,
+                          mko_dev->core.irq_requested);
+               up_read(&mko_dev->rwsem);
+       }
+       up_read(&devices_sem);
+
+       return 0;
+}
+
+static int proc_text_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mkopci_proc_show, inode->i_cdev);
+}
+
+static const struct file_operations mkopci_proc_fops = {
+       .owner = THIS_MODULE,
+       .open = proc_text_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static ssize_t mkopci_proc_core_read(struct file __unused *file, char __user 
*buffer,
+                                    size_t count, loff_t *offset)
+{
+       const int MAX_CORE_LEN =
+           MAX_DEVICES_NR * sizeof(struct mkopci_core) +
+           sizeof(unsigned short);
+       int n, len = 0, ret = 0;
+       struct mkopci_device *d;
+
+       down_read(&devices_sem);
+       n = atomic_read(&devices_nr) * sizeof(struct mkopci_core) +
+           sizeof(unsigned short);
+       if (*offset >= n)
+               goto out;
+
+       if (*offset == 0) {
+               if (put_user((unsigned long)atomic_read(&devices_nr), buffer)) {
+                       ret = -ERESTARTSYS;
+                       goto out;
+               }
+               len = sizeof(unsigned long);
+       }
+
+       list_for_each_entry(d, &devices, list) {
+               down_read(&d->rwsem);
+               if (d->omited) {
+                       up_read(&d->rwsem);
+                       continue;
+               }
+               if (copy_to_user
+                   (buffer + len, &d->core, sizeof(struct mkopci_core))) {
+                       up_read(&d->rwsem);
+                       ret = -ERESTARTSYS;
+                       goto out;
+               }
+               up_read(&d->rwsem);
+               len += sizeof(struct mkopci_core);
+       }
+
+       if (count > len)
+               if (len < MAX_CORE_LEN) {
+                       if (clear_user(buffer + len + 1, MAX_CORE_LEN - len)) {
+                               ret = -ERESTARTSYS;
+                               goto out;
+                       }
+               }
+
+       *offset += len;
+       ret = len;
+
+out:
+       up_read(&devices_sem);
+       return ret;
+}
+
+static int hex2int(const char s[])
+{
+       static const char hexalpha[] = "aAbBcCdDeEfF";
+       unsigned int ret = 0;
+       int i = 0, k;
+       int err = 0;
+       int hexint = 0;
+
+       if (s[i] == '0') {
+               i++;
+               if (s[i] == 'x' || s[i] == 'X')
+                       i++;
+       }
+
+       while (!err && s[i] != '\0') {
+               ret = ret << 4;
+               if (s[i] >= '0' && s[i] <= '9')
+                       ret = ret + (s[i] - '0');
+               else {
+                       for (k = 0; hexint == 0 && hexalpha[k] != '\0'; k++) {
+                               if (hexalpha[k] == s[i])
+                                       hexint = 10 + k / 2;
+                       }
+                       if (hexint == 0) {
+                               err = -EINVAL;
+                               break;
+                       }
+                       ret = ret + hexint;
+                       hexint = 0;
+               }
+               i++;
+       }
+
+       if (err)
+               ret = err;
+
+       return ret;
+}
+
+static ssize_t mkopci_proc_core_write(struct file __unused *file,
+                                     const char __user *buffer, size_t count,
+                                     loff_t __unused *offset)
+{
+       char buf[8];
+       int ret = 0, instance = 0, nodev = 1;
+       struct mkopci_device *d;
+       struct pci_dev *dev;
+
+       if (copy_from_user(buf, buffer, min(sizeof(buf), count))) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       if (count > sizeof(buf)) {
+               ret = -EINVAL;
+               goto out;
+       } else
+               buf[count - 1] = 0;
+
+       if (!strncmp(buf, "0x", 2) || !strncmp(buf, "0X", 2))
+               instance = hex2int(buf);
+       else if ((strlen(buf) == 7) && (buf[2] == ':') && (buf[5] == '.')) {
+               int a, b, c;
+
+               buf[2] = 0;
+               buf[5] = 0;
+               a = hex2int(buf);
+               b = hex2int(buf + 3);
+               c = hex2int(buf + 6);
+               buf[2] = ':';
+               buf[5] = '.';
+
+               instance = mko_pci_addr(a, b, c, 0);
+       } else
+               instance = -EINVAL;
+
+       if (instance == -EINVAL) {
+               pr_err("mkopci: inappropriate PCI address '%s'\n", buf);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       down_write(&devices_sem);
+       list_for_each_entry(d, &devices, list) {
+               down_write(&d->rwsem);
+               if (d->core.instance != instance) {
+                       up_write(&d->rwsem);
+                       continue;
+               }
+               nodev = 0;
+               if (d->core.process || d->backdoor) {
+                       if (v > 0) {
+                               if (d->core.process)
+                                       pr_info
+                                           ("mkopci%d: device is handled by 
process [%d]\n",
+                                            d->core.n_dev, d->core.process);
+                               else
+                                       pr_info
+                                           ("mkopci%d: device is handled by 
process [%d] in backdoor mode\n",
+                                            d->core.n_dev, d->backdoor);
+                       }
+                       ret = -EBUSY;
+                       goto out_up_sems;
+               }
+               dev = d->pci_dev;
+               if (d->omited) {
+                       ret = pci_enable_device(dev);
+                       if (ret) {
+                               pr_err
+                                   ("mkopci: error = %d while enabling PCI 
device\n",
+                                    ret);
+                               goto out_up_sems;
+                       }
+
+                       ret = mkopci_probe_helper(dev);
+                       if (ret) {
+                               pr_err
+                                   ("mkopci: error = %d in 
mkopci_probe_helper\n",
+                                    ret);
+                               goto out_ph_fail;
+                       }
+                       d->omited = 0;
+               } else {
+                       mkopci_remove_helper(dev);
+                       d->omited = 1;
+               }
+               up_write(&d->rwsem);
+               break;
+       }
+       up_write(&devices_sem);
+
+       if (nodev) {
+               pr_info("mkopci: no device with address %s was found\n", buf);
+               ret = -ENODEV;
+               goto out;
+       }
+       ret = min(sizeof(buf), count);
+       goto out;
+
+out_ph_fail:
+       pci_disable_device(dev);
+out_up_sems:
+       up_write(&d->rwsem);
+       up_write(&devices_sem);
+out:
+       return ret;
+}
+
+static const struct file_operations mko_core_proc_fops = {
+       .owner = THIS_MODULE,
+       .read = mkopci_proc_core_read,
+       .write = mkopci_proc_core_write,
+};
+
+static int mkopci_create_proc_entry(void)
+{
+       mkopci_proc_dir = proc_mkdir("mkopci", NULL);
+       if (mkopci_proc_dir == NULL) {
+               remove_proc_entry("mkopci", NULL);
+               pr_err("mkopci: could not initialize /proc/mkopci/\n");
+               return -ENOMEM;
+       }
+
+       mkopci_proc_file =
+           proc_create("devices", S_IFREG | S_IRUGO, mkopci_proc_dir,
+                       &mkopci_proc_fops);
+       if (mkopci_proc_file == NULL) {
+               remove_proc_entry("mkopci", NULL);
+               pr_err("mkopci: could not initialize /proc/mkopci/devices\n");
+               return -ENOMEM;
+       }
+       mkopci_proc_core =
+           proc_create("core", S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP,
+                       mkopci_proc_dir, &mko_core_proc_fops);
+       if (mkopci_proc_core == NULL) {
+               remove_proc_entry("devices", mkopci_proc_dir);
+               remove_proc_entry("mkopci", NULL);
+               pr_err("mkopci: could not initialize /proc/mkopci/core\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+/************************* End of proc entries functions 
**********************/
+
+static SIMPLE_DEV_PM_OPS(mkopci_pm_ops, mkopci_suspend, mkopci_resume);
+
+static struct pci_driver mkopci_driver = {
+       .name = "mkopci",
+       .id_table = ids,
+       .probe = mkopci_probe,
+       .remove = mkopci_remove,
+       .driver.pm = &mkopci_pm_ops,
+};
+
+static int __init mkopci_init(void)
+{
+       int ret = 0;
+       struct mkopci_device *d;
+
+       if (v < 0 || v > 3 || omited_nr > MAX_DEVICES_NR) {
+               pr_err("mkopci: inappropriate parameters\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       mkopci_device_cache =
+           kmem_cache_create("mkopci_dev_cache", sizeof(struct mkopci_device),
+                             0, 0, 0);
+
+       if (!mkopci_device_cache) {
+               pr_err("mkopci: Unable to allocate memory\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+       init_rwsem(&devices_sem);
+
+       mkopci_class = class_create(THIS_MODULE, "mkopci");
+       if ((IS_ERR(mkopci_class))) {
+               pr_err("mkopci: error creating class\n");
+               ret = PTR_ERR(mkopci_class);
+               goto destroy_cache;
+       }
+
+       ret = alloc_chrdev_region(&devp, 0, MAX_DEVICES_NR, "mkopci");
+       if (ret) {
+               pr_err("mkopci: failed to allocate chrdev region\n");
+               goto destoy_class;
+       }
+
+       if (v > 0)
+               pr_info("mkopci: major number = %d\n", MAJOR(devp));
+
+       ret = pci_register_driver(&mkopci_driver);
+       if (ret < 0) {
+               pr_err("mkopci: error (%d) while pci_register_driver\n", ret);
+               goto free_chr_reg;
+       }
+
+       ret = mkopci_create_proc_entry();
+       if (ret) {
+               pr_err("mkopci: error creating proc entries\n");
+               goto unreg_drv;
+       }
+       pr_info("mkopci: driver loaded\n");
+       goto out;
+
+unreg_drv:
+       pci_unregister_driver(&mkopci_driver);
+free_chr_reg:
+       unregister_chrdev_region(devp, MAX_DEVICES_NR);
+destoy_class:
+       class_destroy(mkopci_class);
+       while (!list_empty(&devices)) {
+               d = list_entry(devices.next, struct mkopci_device, list);
+               list_del(devices.next);
+               kmem_cache_free(mkopci_device_cache, d);
+       }
+destroy_cache:
+       kmem_cache_destroy(mkopci_device_cache);
+
+out:
+       return ret;
+}
+
+static void __exit mkopci_exit(void)
+{
+       struct mkopci_device *d;
+
+       remove_proc_entry("core", mkopci_proc_dir);
+       remove_proc_entry("devices", mkopci_proc_dir);
+       remove_proc_entry("mkopci", NULL);
+
+       pci_unregister_driver(&mkopci_driver);
+       unregister_chrdev_region(devp, MAX_DEVICES_NR);
+       class_destroy(mkopci_class);
+       while (!list_empty(&devices)) {
+               d = list_entry(devices.next, struct mkopci_device, list);
+               list_del(devices.next);
+               kmem_cache_free(mkopci_device_cache, d);
+       }
+       kmem_cache_destroy(mkopci_device_cache);
+
+       pr_info("mkopci: driver unloaded\n");
+}
+
+MODULE_DESCRIPTION("MKO PCI card driver");
+MODULE_AUTHOR("Sergej Bauer");
+MODULE_LICENSE("GPL");
+
+module_init(mkopci_init);
+module_exit(mkopci_exit);
+
diff --git a/include/misc/mkopci.h b/include/misc/mkopci.h
new file mode 100644
index 0000000..3fa3a4e
--- /dev/null
+++ b/include/misc/mkopci.h
@@ -0,0 +1,81 @@
+#ifndef MKOPCI_H
+#define MKOPCI_H
+
+#define MKO_IOC_MAGIC 'X'
+
+#define MAX_MEM_WIN     5
+#define MAX_DEVICES_NR 16
+
+#if !defined(__KERNEL__)
+#define MaxDeviceCount MAX_DEVICES_NR
+typedef struct {
+    unsigned short      VendorId;
+    unsigned short      DeviceId;
+    unsigned short      SubsystemVendorId;
+    unsigned short      SubsystemId;
+    unsigned int        InstanceId;
+    unsigned int        ProcessId;
+    unsigned int        LType;
+    unsigned short      NumMemWindows;
+    unsigned long       MemBase[MAX_MEM_WIN];
+    unsigned long       LinBase[MAX_MEM_WIN];
+    unsigned int        MemSize[MAX_MEM_WIN];
+    unsigned short      IRQ;
+    int                 handle;  // device file descriptor
+    char                name[sizeof("mkopci00") + 1];
+    unsigned char       irq_requested;
+    int                 c_bar;
+    unsigned char       n_dev;
+} mkopcilnx_device_info_t;
+
+typedef struct {
+    unsigned short          DeviceCount;
+    mkopcilnx_device_info_t DeviceInfo[MaxDeviceCount];
+} mkopcilnx_device_table_t;
+#else // defined(__KERNEL__)
+struct mkopci_core {
+    unsigned short      vendor_id;
+    unsigned short      device_id;
+    unsigned short      subs_vendor_id;
+    unsigned short      subs_id;
+    unsigned int        instance;
+    unsigned int        process;
+    unsigned int        ltype;
+    unsigned short      mem_windows_nr;
+    unsigned long       mem_base[MAX_MEM_WIN];
+    unsigned long       lin_base[MAX_MEM_WIN];
+    unsigned int        mem_size[MAX_MEM_WIN];
+    unsigned short      irq;
+    int                 handle;
+    char                name[sizeof("mkopci00") + 1];
+    unsigned char       irq_requested;
+    int                 c_bar;
+    unsigned char       n_dev;
+};
+
+// kernel's structure of the driver
+struct mkopci_device {
+    struct mkopci_core  core;
+    struct rw_semaphore rwsem;
+    wait_queue_head_t   wq;
+    struct cdev         cdev;
+    unsigned char       omited;
+    unsigned int        backdoor;
+    struct pci_dev      *pci_dev;
+    struct list_head    list;
+};
+#endif // !defined(_KERNEL__)
+
+#define MKOPCI_IOCTL_GET_VERSION            _IOR(MKO_IOC_MAGIC, 1, int)
+#define MKOPCI_IOCTL_GET_BOARDS_COUNT       _IOR(MKO_IOC_MAGIC, 2, int)
+#define MKOPCI_IOCTL_GET_DEVICE_TABLE       _IOR(MKO_IOC_MAGIC, 3, struct 
mkopci_core)
+#define MKOPCI_IOCTL_ATTACH_IRQ             _IO(MKO_IOC_MAGIC,  4)
+#define MKOPCI_IOCTL_WAIT_IRQ               _IO(MKO_IOC_MAGIC,  5)
+#define MKOPCI_IOCTL_DETACH_IRQ             _IO(MKO_IOC_MAGIC,  6)
+#define MKOPCI_IOCTL_REQUEST_BAR            _IOW(MKO_IOC_MAGIC, 7, int)
+#define MKOPCI_IOCTL_CWPID                  _IO(MKO_IOC_MAGIC,  8)
+
+#define MKO_IOC_MAXNR 8
+
+#endif
+
---
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to