Newer
Older
UbixOS / sys / pci / pci.c
/*-
 * 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);
}