/* 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 #include #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 ") 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") */