summaryrefslogtreecommitdiff
path: root/util/extensions/legacybios/kernel/pcibios.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/extensions/legacybios/kernel/pcibios.c')
-rw-r--r--util/extensions/legacybios/kernel/pcibios.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/util/extensions/legacybios/kernel/pcibios.c b/util/extensions/legacybios/kernel/pcibios.c
new file mode 100644
index 0000000000..75024d3ddc
--- /dev/null
+++ b/util/extensions/legacybios/kernel/pcibios.c
@@ -0,0 +1,155 @@
+/*
+ * pcibios code from linuxbios
+ */
+
+#include <pci.h>
+#undef __KERNEL__
+#include <io.h>
+
+void printk(const char *fmt, ...);
+
+#define printk_debug printk
+#define printk_err printk
+
+enum {
+ CHECK = 0xb001,
+ FINDDEV = 0xb102,
+ READCONFBYTE = 0xb108,
+ READCONFWORD = 0xb109,
+ READCONFDWORD = 0xb10a,
+ WRITECONFBYTE = 0xb10b,
+ WRITECONFWORD = 0xb10c,
+ WRITECONFDWORD = 0xb10d
+};
+
+// errors go in AH. Just set these up so that word assigns
+// will work. KISS.
+enum {
+ PCIBIOS_NODEV = 0x8600,
+ PCIBIOS_BADREG = 0x8700
+};
+
+int
+pcibios(
+ unsigned long *pedi,
+ unsigned long *pesi,
+ unsigned long *pebp,
+ unsigned long *pesp,
+ unsigned long *pebx,
+ unsigned long *pedx,
+ unsigned long *pecx,
+ unsigned long *peax,
+ unsigned long *pflags
+ ) {
+ unsigned long edi = *pedi;
+ unsigned long esi = *pesi;
+ unsigned long ebp = *pebp;
+ unsigned long esp = *pesp;
+ unsigned long ebx = *pebx;
+ unsigned long edx = *pedx;
+ unsigned long ecx = *pecx;
+ unsigned long eax = *peax;
+ unsigned long flags = *pflags;
+ unsigned short func = (unsigned short) eax;
+ int retval = -1;
+ unsigned short devid, vendorid, devfn;
+ short devindex; /* Use short to get rid of gabage in upper half of 32-bit register */
+ unsigned char bus;
+ struct pci_dev *dev;
+
+ switch(func) {
+ case CHECK:
+ *pedx = 0x4350;
+ *pecx = 0x2049;
+ retval = 0;
+ break;
+ case FINDDEV:
+ {
+ devid = *pecx;
+ vendorid = *pedx;
+ devindex = *pesi;
+ dev = 0;
+ while ((dev = pci_find_device(vendorid, devid, dev))) {
+ if (devindex <= 0)
+ break;
+ devindex--;
+ }
+ if (dev) {
+ unsigned short busdevfn;
+ *peax = 0;
+ // busnum is an unsigned char;
+ // devfn is an int, so we mask it off.
+ busdevfn = (dev->bus << 8)
+ | (dev->devfn & 0xff);
+ printk_debug("0x%x: return 0x%x\n", func, busdevfn);
+ *pebx = busdevfn;
+ retval = 0;
+ } else {
+ *peax = PCIBIOS_NODEV;
+ retval = -1;
+ }
+ }
+ break;
+ case READCONFDWORD:
+ case READCONFWORD:
+ case READCONFBYTE:
+ case WRITECONFDWORD:
+ case WRITECONFWORD:
+ case WRITECONFBYTE:
+ {
+ unsigned int dword;
+ unsigned short word;
+ unsigned char byte;
+ unsigned char reg;
+
+ devfn = *pebx & 0xff;
+ bus = *pebx >> 8;
+ reg = *pedi;
+ dev = pci_find_slot(bus, devfn);
+ if (! dev) {
+ printk_debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
+ // idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
+ *peax = PCIBIOS_BADREG;
+ retval = -1;
+ }
+ switch(func) {
+ case READCONFBYTE:
+ retval = pci_read_config_byte(dev, reg, &byte);
+ *pecx = byte;
+ break;
+ case READCONFWORD:
+ retval = pci_read_config_word(dev, reg, &word);
+ *pecx = word;
+ break;
+ case READCONFDWORD:
+ retval = pci_read_config_dword(dev, reg, &dword);
+ *pecx = dword;
+ break;
+ case WRITECONFBYTE:
+ byte = *pecx;
+ retval = pci_write_config_byte(dev, reg, byte);
+ break;
+ case WRITECONFWORD:
+ word = *pecx;
+ retval = pci_write_config_word(dev, reg, word);
+ break;
+ case WRITECONFDWORD:
+ word = *pecx;
+ retval = pci_write_config_dword(dev, reg, dword);
+ break;
+ }
+
+ if (retval)
+ retval = PCIBIOS_BADREG;
+ printk_debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n", func, bus, devfn, reg, *pecx);
+ *peax = 0;
+ retval = 0;
+ }
+ break;
+ default:
+ printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
+ break;
+ }
+
+ return retval;
+}