mirror of
https://github.com/phire/kvmbox.git
synced 2024-05-12 18:25:12 -04:00
287 lines
6.6 KiB
C
287 lines
6.6 KiB
C
// Copyright (c) 2011 Scott Mansell <phiren@gmail.com>
|
|
// Licensed under the MIT license
|
|
// Refer to the included LICENCE file.
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
int bus;
|
|
int device;
|
|
int function;
|
|
int reg;
|
|
|
|
struct pci_config {
|
|
uint16_t DeviceID;
|
|
uint16_t VenderID;
|
|
uint16_t Status;
|
|
uint16_t Command;
|
|
uint8_t ClassCode;
|
|
uint8_t Subclass;
|
|
uint8_t ProgIF;
|
|
uint8_t RevID;
|
|
uint8_t BIST;
|
|
uint8_t HeaderType;
|
|
uint8_t LatTimer;
|
|
uint8_t CacheLine;
|
|
uint32_t bar1;
|
|
uint32_t bar2;
|
|
uint32_t bar3;
|
|
uint32_t bar4;
|
|
uint32_t bar5;
|
|
uint32_t bar6;
|
|
uint32_t CardbusCIS;
|
|
uint16_t SubID;
|
|
uint16_t SubVID;
|
|
uint32_t ExpansionROM;
|
|
uint8_t _reserved[3];
|
|
uint8_t CapPointer;
|
|
uint32_t __reserved;
|
|
uint8_t MaxLat;
|
|
uint8_t MinGnt;
|
|
uint8_t InterruptPin;
|
|
uint8_t InterruptLine;
|
|
uint8_t extra[0xc0];
|
|
} __attribute__((packed));
|
|
|
|
struct pci_config ideController = {
|
|
.DeviceID = 0x10de,
|
|
.VenderID = 0x01bc,
|
|
.Status = 0x00b0,
|
|
.ClassCode = 0x1,
|
|
.Subclass = 0x1,
|
|
.ProgIF = 0x8a,
|
|
.RevID = 0xd4,
|
|
.bar5 = 0x00000001,
|
|
.CapPointer = 0x44,
|
|
.MaxLat = 1,
|
|
.MinGnt = 0,
|
|
.extra = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
|
|
0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xff, 0x20,
|
|
},
|
|
};
|
|
struct pci_config forcedeth = {
|
|
.DeviceID = 0x10de,
|
|
.VenderID = 0x01c3,
|
|
.Status = 0x00b0,
|
|
.ClassCode = 0x02,
|
|
.Subclass = 0x00,
|
|
.ProgIF = 0x00,
|
|
.RevID = 0xd2,
|
|
.bar2 = 1,
|
|
.CapPointer = 0x44,
|
|
.MaxLat = 0x14,
|
|
.MinGnt = 1,
|
|
.InterruptPin = 1,
|
|
.InterruptLine = 0,
|
|
.extra = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0xfe,
|
|
0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
|
},
|
|
};
|
|
|
|
struct pci_config usb1 = {
|
|
.DeviceID = 0x10de,
|
|
.VenderID = 0x01c2,
|
|
.Status = 0x00b0,
|
|
.ClassCode = 0x0c,
|
|
.Subclass = 0x03,
|
|
.ProgIF = 0x10,
|
|
.RevID = 0xd4,
|
|
.CapPointer = 0x44,
|
|
.MaxLat = 1,
|
|
.MinGnt = 1,
|
|
.InterruptPin = 1,
|
|
.InterruptLine = 0,
|
|
.extra = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0xfe,
|
|
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
0x0f,
|
|
},
|
|
};
|
|
|
|
struct pci_config usb2 = {
|
|
.DeviceID = 0x10de,
|
|
.VenderID = 0x01c2,
|
|
.Status = 0x00b0,
|
|
.ClassCode = 0x0c,
|
|
.Subclass = 0x03,
|
|
.ProgIF = 0x10,
|
|
.RevID = 0xd4,
|
|
.CapPointer = 0x44,
|
|
.MaxLat = 1,
|
|
.MinGnt = 1,
|
|
.InterruptPin = 1,
|
|
.InterruptLine = 0,
|
|
.extra = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0xfe,
|
|
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
0x0f,
|
|
},
|
|
};
|
|
|
|
struct pci_config audio = {
|
|
.DeviceID = 0x10de,
|
|
.VenderID = 0x01b1,
|
|
.Status = 0x00b0,
|
|
.ClassCode = 0x04,
|
|
.Subclass = 0x01,
|
|
.ProgIF = 0x00,
|
|
.RevID = 0xd2,
|
|
.bar1 = 1,
|
|
.bar2 = 1,
|
|
.CapPointer = 0x44,
|
|
.MaxLat = 5,
|
|
.MinGnt = 2,
|
|
.InterruptPin = 1,
|
|
.InterruptLine = 0,
|
|
.extra = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x06,
|
|
0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00,
|
|
},
|
|
};
|
|
|
|
struct pci_config audio2 = {
|
|
.DeviceID = 0x10de,
|
|
.VenderID = 0x01b0,
|
|
.Status = 0x00b0,
|
|
.ClassCode = 0x04,
|
|
.Subclass = 0x01,
|
|
.ProgIF = 0x00,
|
|
.RevID = 0xd2,
|
|
.CapPointer = 0x44,
|
|
.MaxLat = 0xc,
|
|
.MinGnt = 1,
|
|
.InterruptPin = 1,
|
|
.InterruptLine = 0,
|
|
.extra = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x06,
|
|
0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
0x01, 0x00, 0x02, 0x06, 0x01, 0x00, 0x02, 0x06,
|
|
},
|
|
};
|
|
|
|
struct pci_config vga = {
|
|
.DeviceID = 0x10de,
|
|
.VenderID = 0x02a0,
|
|
.Status = 0x00b0,
|
|
.ClassCode = 0x03,
|
|
.Subclass = 0x00,
|
|
.ProgIF = 0x00,
|
|
.RevID = 0xa1,
|
|
.CapPointer = 0x60,
|
|
.MaxLat = 1,
|
|
.MinGnt = 5,
|
|
.InterruptPin = 1,
|
|
.InterruptLine = 0,
|
|
.extra = {0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
|
|
0x07, 0x00, 0x00, 0x1f, 0x14, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
0xce, 0xd6, 0x23, 0x00, 0x0f, 0x00, 0x00, 0x00,
|
|
0x01, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x65, 0xd0, 0x16, 0x2b, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
},
|
|
};
|
|
|
|
struct pci_config *getConfig() {
|
|
switch(bus << 16 | device << 11 | function << 8) {
|
|
case 9 << 11:
|
|
return &ideController;
|
|
case 4 << 11:
|
|
return &forcedeth;
|
|
case 2 << 11:
|
|
return &usb1;
|
|
case 3 << 11:
|
|
return &usb2;
|
|
case 6 << 11:
|
|
return &audio;
|
|
case 5 << 11:
|
|
return &audio2;
|
|
case 1 << 16:
|
|
return &vga;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint32_t readConfig(reg) {
|
|
struct pci_config *config = getConfig();
|
|
if (!config) {
|
|
debugf("Unimplemented PCI device read %i:%i:%i[0x%02x]\n", bus, device, function, reg);
|
|
return 0;
|
|
}
|
|
return ((uint32_t *)config)[reg];
|
|
}
|
|
|
|
void writeConfig(reg, value) {
|
|
struct pci_config *config = getConfig();
|
|
if (!config) {
|
|
debugf("Unimplemented PCI device write %i:%i:%i[0x%02x] = %08x\n", bus, device, function, reg, value);
|
|
return;
|
|
}
|
|
((uint32_t *)config)[reg] = value;
|
|
}
|
|
|
|
|
|
|
|
void pciConfigIO(uint16_t port, uint8_t direction, uint8_t size, uint8_t *p) {
|
|
if(port == 0xcf8) {
|
|
uint32_t addr = *(uint32_t *)p;
|
|
bus = (addr >> 16) & 0xff;
|
|
device = (addr >> 11) & 0x1f;
|
|
function = (addr >> 8) & 0x7;
|
|
reg = (addr >> 2) & 0x3f;
|
|
}
|
|
if(port == 0xcfc) {
|
|
if(direction) {
|
|
switch(size) {
|
|
case 1:
|
|
writeConfig(reg, *p);
|
|
break;
|
|
case 2:
|
|
writeConfig(reg, *(uint16_t *)p);
|
|
break;
|
|
case 4:
|
|
writeConfig(reg, *(uint32_t *)p);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
switch(size) {
|
|
case 1:
|
|
*p = readConfig(reg);
|
|
break;
|
|
case 2:
|
|
*(uint16_t *)p = readConfig(reg);
|
|
break;
|
|
case 4:
|
|
*(uint32_t *)p = readConfig(reg);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|