sortix-mirror/sortix/pci.cpp

297 lines
14 KiB
C++

/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
pci.h
Handles basic PCI bus stuff.
******************************************************************************/
#include <sortix/kernel/platform.h>
#include "cpu.h"
#include <libmaxsi/error.h>
#include "pci.h"
#include <sortix/kernel/log.h>
#include "ata.h"
using namespace Maxsi;
namespace Sortix
{
namespace PCI
{
const uint16_t Config_Address = 0xCF8;
const uint16_t Config_Data = 0xCFC;
uint32_t SwapBytes(uint32_t I)
{
return (I >> 24) | ((I >> 8) & 0x0000FF00) | ((I << 8) & 0x00FF0000) | (I << 24);
}
const char* ToDeviceDesc(uint32_t ProductInfo, uint32_t DeviceType)
{
uint32_t Class = (DeviceType) >> 24;
uint32_t SubClass = (DeviceType >> 16) & 0xFF;
uint32_t ProgIF = (DeviceType >> 8) & 0xFF;
uint32_t RevisionID = (DeviceType) & 0xFF;
if ( Class == 0x00 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Any device except for VGA-Compatible devices"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "VGA-Compatible Device"; }
}
if ( Class == 0x01 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "SCSI Bus Controller"; }
if ( SubClass == 0x01 ) { return "IDE Controller"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "Floppy Disk Controller"; }
if ( SubClass == 0x03 && ProgIF == 0x00 ) { return "IPI Bus Controller"; }
if ( SubClass == 0x04 && ProgIF == 0x00 ) { return "RAID Controller"; }
if ( SubClass == 0x05 && ProgIF == 0x20 ) { return "ATA Controller (Single DMA)"; }
if ( SubClass == 0x05 && ProgIF == 0x30 ) { return "ATA Controller (Chained DMA)"; }
if ( SubClass == 0x06 && ProgIF == 0x00 ) { return "Serial ATA (Direct Port Access)"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Mass Storage Controller"; }
}
if ( Class == 0x02 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Ethernet Controller"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "Token Ring Controller"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "FDDI Controller"; }
if ( SubClass == 0x03 && ProgIF == 0x00 ) { return "ATM Controller"; }
if ( SubClass == 0x04 && ProgIF == 0x00 ) { return "ISDN Controller"; }
if ( SubClass == 0x05 && ProgIF == 0x00 ) { return "WorldFip Controller"; }
if ( SubClass == 0x05 && ProgIF == 0x00 ) { return "ATA Controller (Chained DMA)"; }
if ( SubClass == 0x06 ) { return "PICMG 2.14 Multi Computing"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Network Controller"; }
}
if ( Class == 0x03 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "VGA-Compatible Controller"; }
if ( SubClass == 0x00 && ProgIF == 0x01 ) { return "8512-Compatible Controller"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "XGA Controller"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "3D Controller (Not VGA-Compatible)"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Display Controller"; }
}
if ( Class == 0x04 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Video Device"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "Audio Device"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "Computer Telephony Device"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Multimedia Device"; }
}
if ( Class == 0x05 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "RAM Controller"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "Flash Controller"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Memory Controller"; }
}
if ( Class == 0x06 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Host Bridge"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "ISA Bridge"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "EISA Bridge"; }
if ( SubClass == 0x03 && ProgIF == 0x00 ) { return "MCA Bridge"; }
if ( SubClass == 0x04 && ProgIF == 0x00 ) { return "PCI-to-PCI Bridge"; }
if ( SubClass == 0x04 && ProgIF == 0x01 ) { return "PCI-to-PCI Bridge (Subtractive Decode)"; }
if ( SubClass == 0x05 && ProgIF == 0x00 ) { return "PCMCIA Bridge"; }
if ( SubClass == 0x06 && ProgIF == 0x00 ) { return "NuBus Bridge"; }
if ( SubClass == 0x07 && ProgIF == 0x00 ) { return "CardBus Bridge"; }
if ( SubClass == 0x08 ) { return "RACEway Bridge"; }
if ( SubClass == 0x09 && ProgIF == 0x40 ) { return "PCI-to-PCI Bridge (Semi-Transparent, Primary)"; }
if ( SubClass == 0x09 && ProgIF == 0x80 ) { return "PCI-to-PCI Bridge (Semi-Transparent, Secondary)"; }
if ( SubClass == 0x0A && ProgIF == 0x00 ) { return "InfiniBrand-to-PCI Host Bridge"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Bridge Device"; }
}
if ( Class == 0x07 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Generic XT-Compatible Serial Controller"; }
if ( SubClass == 0x00 && ProgIF == 0x01 ) { return "16450-Compatible Serial Controller"; }
if ( SubClass == 0x00 && ProgIF == 0x02 ) { return "16550-Compatible Serial Controller"; }
if ( SubClass == 0x00 && ProgIF == 0x03 ) { return "16650-Compatible Serial Controller"; }
if ( SubClass == 0x00 && ProgIF == 0x04 ) { return "16750-Compatible Serial Controller"; }
if ( SubClass == 0x00 && ProgIF == 0x05 ) { return "16850-Compatible Serial Controller"; }
if ( SubClass == 0x00 && ProgIF == 0x06 ) { return "16950-Compatible Serial Controller"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "Parallel Port"; }
if ( SubClass == 0x01 && ProgIF == 0x01 ) { return "Bi-Directional Parallel Port"; }
if ( SubClass == 0x01 && ProgIF == 0x02 ) { return "ECP 1.X Compliant Parallel Port"; }
if ( SubClass == 0x01 && ProgIF == 0x03 ) { return "IEEE 1284 Controller"; }
if ( SubClass == 0x01 && ProgIF == 0xFE ) { return "IEEE 1284 Target Device"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "Multiport Serial Controller"; }
if ( SubClass == 0x03 && ProgIF == 0x00 ) { return "Generic Modem"; }
if ( SubClass == 0x03 && ProgIF == 0x01 ) { return "Hayes Compatible Modem (16450-Compatible Interface)"; }
if ( SubClass == 0x03 && ProgIF == 0x02 ) { return "Hayes Compatible Modem (16550-Compatible Interface)"; }
if ( SubClass == 0x03 && ProgIF == 0x03 ) { return "Hayes Compatible Modem (16650-Compatible Interface)"; }
if ( SubClass == 0x03 && ProgIF == 0x04 ) { return "Hayes Compatible Modem (16750-Compatible Interface)"; }
if ( SubClass == 0x04 && ProgIF == 0x00 ) { return "IEEE 488.1/2 (GPIB) Controller"; }
if ( SubClass == 0x05 && ProgIF == 0x00 ) { return "Smart Card"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Communications Device"; }
}
if ( Class == 0x08 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Generic 8259 PIC"; }
if ( SubClass == 0x00 && ProgIF == 0x01 ) { return "ISA PIC"; }
if ( SubClass == 0x00 && ProgIF == 0x02 ) { return "EISA PIC"; }
if ( SubClass == 0x00 && ProgIF == 0x10 ) { return "I/O APIC Interrupt Controller"; }
if ( SubClass == 0x00 && ProgIF == 0x20 ) { return "I/O(x) APIC Interrupt Controller"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "Generic 8237 DMA Controller"; }
if ( SubClass == 0x01 && ProgIF == 0x01 ) { return "ISA DMA Controller"; }
if ( SubClass == 0x01 && ProgIF == 0x02 ) { return "EISA DMA Controller"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "Generic 8254 System Timer"; }
if ( SubClass == 0x02 && ProgIF == 0x01 ) { return "ISA System Timer"; }
if ( SubClass == 0x02 && ProgIF == 0x02 ) { return "EISA System Timer"; }
if ( SubClass == 0x03 && ProgIF == 0x00 ) { return "Generic RTC Controller"; }
if ( SubClass == 0x03 && ProgIF == 0x01 ) { return "ISA RTC Controller"; }
if ( SubClass == 0x04 && ProgIF == 0x01 ) { return "Generic PCI Hot-Plug Controller"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other System Peripheral"; }
}
if ( Class == 0x09 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Keyboard Controller"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "Digitizer"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "Mouse Controller"; }
if ( SubClass == 0x03 && ProgIF == 0x00 ) { return "Scanner Controller"; }
if ( SubClass == 0x04 && ProgIF == 0x00 ) { return "Gameport Controller (Generic)"; }
if ( SubClass == 0x04 && ProgIF == 0x10 ) { return "Gameport Controller (Legacy)"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Input Controller"; }
}
if ( Class == 0x0A )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Generic Docking Station"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Docking Station"; }
}
if ( Class == 0x0B )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "386 Processor"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "486 Processor"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "Pentium Processor"; }
if ( SubClass == 0x10 && ProgIF == 0x00 ) { return "Alpha Processor"; }
if ( SubClass == 0x20 && ProgIF == 0x00 ) { return "PowerPC Processor"; }
if ( SubClass == 0x30 && ProgIF == 0x00 ) { return "MIPS Processor"; }
if ( SubClass == 0x40 && ProgIF == 0x00 ) { return "Co-Processor"; }
}
if ( Class == 0x0C )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "IEEE 1394 Controller (FireWire)"; }
if ( SubClass == 0x00 && ProgIF == 0x10 ) { return "IEEE 1394 Controller (1394 OpenHCI Spec)"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "ACCESS.bus"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "SSA"; }
if ( SubClass == 0x03 && ProgIF == 0x00 ) { return "USB (Universal Host Controller Spec)"; }
if ( SubClass == 0x03 && ProgIF == 0x10 ) { return "USB (Open Host Controller Spec)"; }
if ( SubClass == 0x03 && ProgIF == 0x20 ) { return "USB2 Host Controller (Intel Enhanced Host Controller Interface)"; }
if ( SubClass == 0x03 && ProgIF == 0x80 ) { return "USB"; }
if ( SubClass == 0x03 && ProgIF == 0xFE ) { return "USB (Not Host Controller)"; }
if ( SubClass == 0x04 && ProgIF == 0x00 ) { return "Fibre Channel"; }
if ( SubClass == 0x05 && ProgIF == 0x00 ) { return "SMBus"; }
if ( SubClass == 0x06 && ProgIF == 0x00 ) { return "InfiniBand"; }
if ( SubClass == 0x07 && ProgIF == 0x00 ) { return "IPMI SMIC Interface"; }
if ( SubClass == 0x07 && ProgIF == 0x01 ) { return "IPMI Kybd Controller Style Interface"; }
if ( SubClass == 0x07 && ProgIF == 0x02 ) { return "IPMI Block Transfer Interface"; }
if ( SubClass == 0x08 && ProgIF == 0x02 ) { return "SERCOS Interface Standard (IEC 61491)"; }
if ( SubClass == 0x09 && ProgIF == 0x00 ) { return "CANbus"; }
}
if ( Class == 0x0E )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Message FIFO"; }
if ( SubClass == 0x00 ) { return "I20 Architecture"; }
}
if ( Class == 0x0F )
{
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "TV Controller"; }
if ( SubClass == 0x02 && ProgIF == 0x00 ) { return "Audio Controller"; }
if ( SubClass == 0x03 && ProgIF == 0x00 ) { return "Voice Controller"; }
if ( SubClass == 0x04 && ProgIF == 0x00 ) { return "Data Controller"; }
}
if ( Class == 0x10 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "Network and Computing Encryption/Decryption"; }
if ( SubClass == 0x10 && ProgIF == 0x00 ) { return "Entertainment Encryption/Decryption"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Encryption/Decryption"; }
}
if ( Class == 0x11 )
{
if ( SubClass == 0x00 && ProgIF == 0x00 ) { return "DPIO Modules"; }
if ( SubClass == 0x01 && ProgIF == 0x00 ) { return "Performance Counters"; }
if ( SubClass == 0x10 && ProgIF == 0x00 ) { return "Communications Syncrhonization Plus Time and Frequency Test/Measurment"; }
if ( SubClass == 0x20 && ProgIF == 0x00 ) { return "Management Card"; }
if ( SubClass == 0x80 && ProgIF == 0x00 ) { return "Other Data Acquisition/Signal Processing Controller"; }
}
return NULL;
}
void Init()
{
ATA::Init();
#if 0
Log::Print("PCI Devices: ");
for ( nat Bus = 0; Bus < 256; Bus++ )
{
for ( nat Slot = 0; Slot < 32; Slot++ )
{
for ( nat Function = 0; Function < 8; Function++ )
{
uint32_t ProductInfo = CheckDevice(Bus, Slot, Function);
if ( ProductInfo == 0xFFFFFFFF ) { continue; }
uint32_t DeviceType = ReadLong(Bus, Slot, Function, 0x08);
const char* DeviceDesc = ToDeviceDesc(ProductInfo, DeviceType);
if ( DeviceDesc != NULL )
{
Log::PrintF("%s, ", DeviceDesc);
}
else
{
Log::PrintF("Unknown PCI Device @ %x:%x.%x (ProductInfo=0x%x, DeviceType=0x%x), ", Bus, Slot, Function, ProductInfo, DeviceType);
}
}
}
}
Log::Print("\b\b\n");
#endif
}
uint32_t ReadLong(uint8_t Bus, uint8_t Slot, uint8_t Function, uint8_t Offset)
{
unsigned long LBus = (unsigned long) Bus;
unsigned long LSlot = (unsigned long) Slot;
unsigned long LFunc = (unsigned long) Function;
// create configuration address.
unsigned long Address = (unsigned long) ( (LBus << 16) | (LSlot << 11) | (LFunc << 8) | (Offset & 0xFC) | ((uint32_t) 0x80000000));
// Write out the address.
CPU::OutPortL(Config_Address, Address);
// Read in the data.
return CPU::InPortL(Config_Data);
}
uint32_t CheckDevice(uint8_t Bus, uint8_t Slot, uint8_t Function)
{
return ReadLong(Bus, Slot, Function, 0);
}
}
}