/*-
* Copyright (c) 2002-2018 The UbixOS Project.
* All rights reserved.
*
* This was developed by Christopher W. Olsen for the UbixOS Project.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice, this list of
* conditions, the following disclaimer and the list of authors.
* 2) Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions, the following disclaimer and the list of authors in the documentation and/or
* other materials provided with the distribution.
* 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <pci/pci.h>
#include <sys/io.h>
#include <lib/kprintf.h>
const struct {
uInt8 baseClass;
uInt8 subClass;
uInt8 interface;
const char* name;
} pciClasses[] = { { 0x00, 0x00, 0x00, "Undefined" }, { 0x00, 0x01, 0x00, "VGA" },
{ 0x01, 0x00, 0x00, "SCSI" }, { 0x01, 0x01, 0x00, "IDE" }, { 0x01, 0x01, 0x8A, "IDE" }, { 0x01, 0x02, 0x00, "Floppy" }, { 0x01, 0x03, 0x00, "IPI" }, { 0x01, 0x04, 0x00, "RAID" }, { 0x01, 0x80, 0x00, "Other" },
{ 0x02, 0x00, 0x00, "Ethernet" }, { 0x02, 0x01, 0x00, "Token Ring" }, { 0x02, 0x02, 0x00, "FDDI" }, { 0x02, 0x03, 0x00, "ATM" }, { 0x02, 0x04, 0x00, "ISDN" }, { 0x02, 0x80, 0x00, "Other" },
{ 0x03, 0x00, 0x00, "VGA" }, { 0x03, 0x00, 0x01, "VGA+8514" }, { 0x03, 0x01, 0x00, "XGA" }, { 0x03, 0x02, 0x00, "3D" }, { 0x03, 0x80, 0x00, "VGA Other" },
{ 0x04, 0x00, 0x00, "Video" }, { 0x04, 0x01, 0x00, "Audio" }, { 0x04, 0x02, 0x00, "Telephony" }, { 0x04, 0x80, 0x00, "Other" },
{ 0x05, 0x00, 0x00, "RAM" }, { 0x05, 0x01, 0x00, "Flash" }, { 0x05, 0x80, 0x00, "Other" },
{ 0x06, 0x00, 0x00, "PCI to HOST" }, { 0x06, 0x01, 0x00, "PCI to ISA" }, { 0x06, 0x02, 0x00, "PCI to EISA" }, { 0x06, 0x03, 0x00, "PCI to MCA" }, { 0x06, 0x04, 0x00, "PCI to PCI" }, { 0x06, 0x04, 0x01, "PCI to PCI (Subtractive Decode)" }, { 0x06, 0x05, 0x00, "PCI to PCMCIA" }, { 0x06, 0x06, 0x00, "PCI to NuBUS" }, { 0x06, 0x07, 0x00, "PCI to Cardbus" }, { 0x06, 0x08, 0x00, "PCI to RACEway" }, { 0x06, 0x09, 0x00, "PCI to PCI" }, { 0x06, 0x0A, 0x00, "PCI to InfiBand" }, { 0x06, 0x80, 0x00, "PCI to Other" },
{ 0x07, 0x00, 0x00, "Serial" }, { 0x07, 0x00, 0x01, "Serial - 16450" }, { 0x07, 0x00, 0x02, "Serial - 16550" }, { 0x07, 0x00, 0x03, "Serial - 16650" }, { 0x07, 0x00, 0x04, "Serial - 16750" }, { 0x07, 0x00, 0x05, "Serial - 16850" }, { 0x07, 0x00, 0x06, "Serial - 16950" }, { 0x07, 0x01, 0x00, "Parallel" }, { 0x07, 0x01, 0x01, "Parallel - BiDir" }, { 0x07, 0x01, 0x02, "Parallel - ECP" }, { 0x07, 0x01, 0x03, "Parallel - IEEE1284" }, { 0x07, 0x01, 0xFE, "Parallel - IEEE1284 Target" }, { 0x07, 0x02, 0x00, "Multiport Serial" }, { 0x07, 0x03, 0x00, "Hayes Compatible Modem" }, { 0x07, 0x03, 0x01, "Hayes Compatible Modem, 16450" }, { 0x07, 0x03, 0x02, "Hayes Compatible Modem, 16550" }, { 0x07, 0x03, 0x03, "Hayes Compatible Modem, 16650" }, { 0x07, 0x03, 0x04, "Hayes Compatible Modem, 16750" }, { 0x07, 0x80, 0x00, "Other" },
{ 0x08, 0x00, 0x00, "PIC" }, { 0x08, 0x00, 0x01, "ISA PIC" }, { 0x08, 0x00, 0x02, "EISA PIC" }, { 0x08, 0x00, 0x10, "I/O APIC" }, { 0x08, 0x00, 0x20, "I/O(x) APIC" }, { 0x08, 0x01, 0x00, "DMA" }, { 0x08, 0x01, 0x01, "ISA DMA" }, { 0x08, 0x01, 0x02, "EISA DMA" }, { 0x08, 0x02, 0x00, "Timer" }, { 0x08, 0x02, 0x01, "ISA Timer" }, { 0x08, 0x02, 0x02, "EISA Timer" }, { 0x08, 0x03, 0x00, "RTC" }, { 0x08, 0x03, 0x00, "ISA RTC" }, { 0x08, 0x03, 0x00, "Hot-Plug" }, { 0x08, 0x80, 0x00, "Other" },
{ 0x09, 0x00, 0x00, "Keyboard" }, { 0x09, 0x01, 0x00, "Pen" }, { 0x09, 0x02, 0x00, "Mouse" }, { 0x09, 0x03, 0x00, "Scanner" }, { 0x09, 0x04, 0x00, "Game Port" }, { 0x09, 0x80, 0x00, "Other" },
{ 0x0a, 0x00, 0x00, "Generic" }, { 0x0a, 0x80, 0x00, "Other" },
{ 0x0b, 0x00, 0x00, "386" }, { 0x0b, 0x01, 0x00, "486" }, { 0x0b, 0x02, 0x00, "Pentium" }, { 0x0b, 0x03, 0x00, "PentiumPro" }, { 0x0b, 0x10, 0x00, "DEC Alpha" }, { 0x0b, 0x20, 0x00, "PowerPC" }, { 0x0b, 0x30, 0x00, "MIPS" }, { 0x0b, 0x40, 0x00, "Coprocessor" }, { 0x0b, 0x80, 0x00, "Other" },
{ 0x0c, 0x00, 0x00, "FireWire" }, { 0x0c, 0x00, 0x10, "OHCI FireWire" }, { 0x0c, 0x01, 0x00, "Access.bus" }, { 0x0c, 0x02, 0x00, "SSA" }, { 0x0c, 0x03, 0x00, "USB (UHCI)" }, { 0x0c, 0x03, 0x10, "USB (OHCI)" }, { 0x0c, 0x03, 0x80, "USB" }, { 0x0c, 0x03, 0xFE, "USB Device" }, { 0x0c, 0x04, 0x00, "Fiber" }, { 0x0c, 0x05, 0x00, "SMBus Controller" }, { 0x0c, 0x06, 0x00, "InfiniBand" }, { 0x0c, 0x80, 0x00, "Other" },
{ 0x0d, 0x00, 0x00, "iRDA" }, { 0x0d, 0x01, 0x00, "Consumer IR" }, { 0x0d, 0x10, 0x00, "RF" }, { 0x0d, 0x80, 0x00, "Other" },
{ 0x0e, 0x00, 0x00, "I2O" }, { 0x0e, 0x80, 0x00, "Other" },
{ 0x0f, 0x01, 0x00, "TV" }, { 0x0f, 0x02, 0x00, "Audio" }, { 0x0f, 0x03, 0x00, "Voice" }, { 0x0f, 0x04, 0x00, "Data" }, { 0x0f, 0x80, 0x00, "Other" },
{ 0x10, 0x00, 0x00, "Network" }, { 0x10, 0x10, 0x00, "Entertainment" }, { 0x10, 0x80, 0x00, "Other" },
{ 0x11, 0x00, 0x00, "DPIO Modules" }, { 0x11, 0x01, 0x00, "Performance Counters" }, { 0x11, 0x10, 0x00, "Comm Sync, Time+Frequency Measurement" }, { 0x11, 0x80, 0x00, "Other" },
};
uInt32 pciRead(int bus, int dev, int func, int reg, int bytes) {
uInt16 base;
union {
struct confadd c;
uInt32 n;
} u;
u.n = 0;
u.c.enable = 1;
u.c.rsvd = 0;
u.c.bus = bus;
u.c.dev = dev;
u.c.func = func;
u.c.reg = reg & 0xFC;
outportDWord(0xCF8, u.n);
base = 0xCFC + (reg & 0x03);
switch (bytes) {
case 1:
return (inportByte(base));
case 2:
return (inportWord(base));
case 4:
return (inportDWord(base));
default:
return 0;
}
}
void pciWrite(int bus, int dev, int func, int reg, uInt32 v, int bytes) {
uInt16 base;
union {
struct confadd c;
uInt32 n;
} u;
u.n = 0;
u.c.enable = 1;
u.c.rsvd = 0;
u.c.bus = bus;
u.c.dev = dev;
u.c.func = func;
u.c.reg = reg & 0xFC;
base = 0xCFC + (reg & 0x03);
outportDWord(0xCF8, u.n);
switch (bytes) {
case 1:
outportByte(base, (uInt8) v);
break;
case 2:
outportWord(base, (uInt16) v);
break;
case 4:
outportDWord(base, v);
break;
}
}
uint32_t pciProbe(int bus, int dev, int func) {
struct pciConfig *cfg = 0x0;
uint32_t v;
int i;
cfg = kmalloc(sizeof(struct pciConfig));
memset(cfg, 0x0, sizeof(struct pciConfig));
uint32_t *word = (uint32_t *) cfg;
for (i = 0; i < 4; i++) {
word[i] = pciRead(bus, dev, func, 4 * i, 4);
/* This is TEMPORARY */
if (cfg->vendorID == 0x1022 && i == 1) {
kprintf("got it: 0x%X", word[i]);
word[i] &= 0xffff0000;
word[i] |= 0x5; //0x1 //0x5;
pciWrite(bus, dev, func, 4 * i, word[i], 4);
kprintf("set it: 0x%X\n", word[i]);
}
}
if (cfg->vendorID == 0xffff) {
kfree(cfg);
return 0x0;
}
if (cfg->vendorID == 0x0) {
kfree(cfg);
return 0x0;
}
cfg->bus = bus;
cfg->dev = dev;
cfg->func = func;
/*
if (cfg->vendorID == 0x1022)
pciWrite(bus, dev, func, 0x3C, 0x5,1);
*/
switch (cfg->headerType & 0x7F) {
case 0x0: /* normal device */
for (i = 4; i <= 16; i++) {
word[i] = pciRead(bus, dev, func, 4 * i, 4);
}
if (cfg->vendorID == 0x1022) {
kprintf("Device Info: /bus/pci/%d/%d/%d\n", bus, dev, func);
kprintf(" * Vendor: %X Device: %X Class/SubClass/Interface %X/%X/%X\n", cfg->vendorID, cfg->deviceID, cfg->classCode, cfg->subClass, cfg->progIf);
kprintf(" * Status: %X Command: %X BIST/Type/Lat/CLS: %X/%X/%X/%X\n", cfg->status, cfg->command, cfg->bist, cfg->headerType, cfg->latencyTimer, cfg->cacheLineSize);
kprintf(" * IRQ: 0x%X.0x%X, BAR[0]: 0x%X\n", cfg->intLine, cfg->intPin, cfg->bar[0]);
}
break;
case 0x1:
kprintf(" * PCI <-> PCI Bridge\n");
break;
case 0x2:
kprintf(" * PCI <-> CardBus Bridge\n");
break;
default:
kprintf(" * Unknown Header Type\n");
break;
}
/*
switch (cfg->headerType & 0x7F) {
case 0: // normal device
for (i = 0; i < 6; i++) {
v = pciRead(bus, dev, func, i * 4 + 0x10, 4);
if (v) {
int v2;
pciWrite(bus, dev, func, i * 4 + 0x10, 0xffffffff, 4);
v2 = pciRead(bus, dev, func, i * 4 + 0x10, 4) & 0xfffffff0;
pciWrite(bus, dev, func, i * 4 + 0x10, v, 4);
v2 = 1 + ~v2;
if (v & 1) {
cfg->base[i] = v & 0xffff;
cfg->size[i] = v2 & 0xffff;
}
else {
cfg->base[i] = v;
cfg->size[i] = v2;
}
}
else {
cfg->base[i] = 0;
cfg->size[i] = 0;
}
}
v = pciRead(bus, dev, func, 0x3c, 1);
cfg->irq = (v == 0xff ? 0 : v);
v = pciRead(bus, dev, func, 0x40, 1);
cfg->irqLine = (v == 0xff ? 0 : v);
break;
case 1:
}
*/
return ((uint32_t) cfg);
}
int pci_init() {
uint16_t bus, dev, func;
int i = 0x0;
struct pciConfig *pcfg;
for (bus = 0x0; bus < 0x2; bus++) {
for (dev = 0; dev < 32; dev++) {
for (func = 0; func < 8; func++) {
pcfg = (struct pciConfig *) pciProbe(bus, dev, func);
if (pcfg != 0x0) {
for (i = 0x0; i < countof(pciClasses); i++) {
if (pcfg->classCode == pciClasses[i].baseClass && pcfg->subClass == pciClasses[i].subClass && pcfg->progIf == pciClasses[i].interface) {
if (pcfg->vendorID == 0x1022) {
kprintf("PCI Device: %s @ IRQ: 0x%X.0x%X\n", pciClasses[i].name, pcfg->intPin, pcfg->intLine);
}
break;
}
}
}
}
}
}
return (0x0);
}