Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / unix / plugins / plugin_pci / plugin_pci.c
diff --git a/qemu/roms/openbios/arch/unix/plugins/plugin_pci/plugin_pci.c b/qemu/roms/openbios/arch/unix/plugins/plugin_pci/plugin_pci.c
new file mode 100644 (file)
index 0000000..586ea2a
--- /dev/null
@@ -0,0 +1,221 @@
+/* tag: openbios pci plugin
+ *
+ * Copyright (C) 2003 Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "unix/plugins.h"
+#include "unix/plugin_pci.h"
+
+#define DEBUG
+
+u32 pci_conf_addr = 0;
+pci_dev_t *pci_devices = NULL;
+
+static pci_dev_t *find_device(u32 conf_addr)
+{
+       pci_dev_t *devs = pci_devices;
+       unsigned bus = (conf_addr >> 16) & 0xff;
+       unsigned dev = (conf_addr >> 11) & 0x1f;
+       unsigned fn = (conf_addr >> 8) & 0x7;
+
+       // printf("Looking for device %x\n",conf_addr);
+
+       while (devs) {
+               if (devs->bus == bus && devs->dev == dev && devs->fn == fn)
+                       return devs;
+               devs = devs->next;
+       }
+       return NULL;
+}
+
+/*
+ * IO functions. These manage all the magic of providing a PCI
+ * compatible interface to OpenBIOS' unix version of the kernel.
+ */
+
+static u8 pci_inb(u32 reg)
+{
+       u32 basereg = (reg & 0xfffc);
+       u32 basepos = (reg & 0x03);
+       pci_dev_t *dev;
+
+       if (basereg == 0xcf8) {
+               return (pci_conf_addr >> (basepos << 3));
+       }
+
+       /* still here? so we're 0xCFC */
+       dev = find_device(pci_conf_addr);
+       if (!dev || !dev->config)
+               return 0xff;
+
+       return dev->config[(pci_conf_addr + basepos) & 0xff];
+}
+
+static u16 pci_inw(u32 reg)
+{
+       u32 basereg = (reg & 0xfffc);
+       u32 basepos = (reg & 0x02);
+       pci_dev_t *dev;
+
+       if (basereg == 0xcf8) {
+               return (pci_conf_addr >> (basepos << 3));
+       }
+
+       /* still here? so we're 0xCFC */
+       dev = find_device(pci_conf_addr);
+       if (!dev || !dev->config)
+               return 0xffff;
+
+       return *(u16 *) (dev->config + ((pci_conf_addr + basepos) & 0xff));
+}
+
+static u32 pci_inl(u32 reg)
+{
+       u32 basereg = (reg & 0xfffc);
+       pci_dev_t *dev;
+
+       if (basereg == 0xcf8) {
+               return pci_conf_addr;
+       }
+
+       /* still here? so we're 0xCFC */
+       dev = find_device(pci_conf_addr);
+       if (!dev || !dev->config)
+               return 0xffffffff;
+
+       return *(u32 *) (dev->config + (pci_conf_addr & 0xff));
+}
+
+static void pci_outb(u32 reg, u8 val)
+{
+       u32 basereg = (reg & 0xfffc);
+       u32 basepos = (reg & 0x03);
+       pci_dev_t *dev;
+
+       if (basereg == 0xcf8) {
+               pci_conf_addr &= (~(0xff << (basepos << 3)));
+               pci_conf_addr |= (val << (basepos << 3));
+               return;
+       }
+
+       /* still here? so we're 0xCFC */
+       dev = find_device(pci_conf_addr);
+       if (!dev || !dev->config)
+               return;
+
+       dev->config[pci_conf_addr & 0xff] = val;
+}
+
+static void pci_outw(u32 reg, u16 val)
+{
+       u32 basereg = (reg & 0xfffc);
+       u32 basepos = (reg & 0x02);
+       pci_dev_t *dev;
+
+       if (basereg == 0xcf8) {
+               pci_conf_addr &= (~(0xffff << (basepos << 3)));
+               pci_conf_addr |= (val << (basepos << 3));
+               return;
+       }
+
+       /* still here? so we're 0xCFC */
+       dev = find_device(pci_conf_addr);
+       if (!dev || !dev->config)
+               return;
+
+       *(u16 *) (dev->config + (pci_conf_addr & 0xff)) = val;
+}
+
+static void pci_outl(u32 reg, u32 val)
+{
+       u32 basereg = (reg & 0xfffc);
+       pci_dev_t *dev;
+
+       if (basereg == 0xcf8) {
+               pci_conf_addr = val;
+               return;
+       }
+
+       /* still here? so we're 0xCFC */
+       dev = find_device(pci_conf_addr);
+       if (!dev || !dev->config)
+               return;
+
+       *(u32 *) (dev->config + (pci_conf_addr & 0xff)) = val;
+}
+
+static io_ops_t pci_io_ops = {
+      inb:pci_inb,
+      inw:pci_inw,
+      inl:pci_inl,
+      outb:pci_outb,
+      outw:pci_outw,
+      outl:pci_outl
+};
+
+/*
+ * Functions visible to modules depending on this module.
+ */
+
+int pci_register_device(unsigned bus, unsigned dev, unsigned fn,
+                       u8 * config)
+{
+       pci_dev_t *newdev;
+       u32 caddr = (1 << 31) | (bus << 16) | (dev << 11) | (fn << 8);
+
+       if (find_device(caddr)) {
+               printf("Error: pci device %02x:%02x.%01x already exists\n",
+                      bus, dev, fn);
+               return -1;
+       }
+
+       newdev = malloc(sizeof(pci_dev_t));
+
+       if (!newdev) {
+               printf("Out of memory\n");
+               return -1;
+       }
+
+       newdev->bus = bus;
+       newdev->dev = dev;
+       newdev->fn = fn;
+       newdev->config = config;
+       newdev->next = pci_devices;
+
+       pci_devices = newdev;
+
+       return 0;
+}
+
+/*
+ * Initialization is really simple. We just grab the
+ * PCI conf1 io range for our emulation functions.
+ */
+extern int plugin_pci_init( void );
+
+int plugin_pci_init(void)
+{
+#ifdef DEBUG
+       printf("Plugin \"pci\" initializing... ");
+#endif
+       register_iorange("pci", &pci_io_ops, 0xcf8, 0xcff);
+#ifdef DEBUG
+       printf("done.\n");
+#endif
+       return 0;
+}
+
+/* plugin meta information available for the plugin loader */
+PLUGIN_AUTHOR       ("Stefan Reinauer <stepan@openbios.org>")
+PLUGIN_DESCRIPTION  ("Generic PCI Device Emulation")
+PLUGIN_LICENSE      ("GPL v2")
+
+/* This plugin has no dependencies. Otherwise the following
+ * macro would be uncommented:
+ * PLUGIN_DEPENDENCIES ("this", "that")
+ */