Working on ethernet.

Includes a prototype E1000 driver.
This commit is contained in:
Curle 2021-03-19 02:18:39 +00:00
parent 98f3786e8b
commit 2c95714d2f
Signed by: TheCurle
GPG Key ID: 5942F13718443F79
8 changed files with 698 additions and 135 deletions

View File

@ -20,6 +20,8 @@
#include <kernel/system/pci.h> #include <kernel/system/pci.h>
#include <kernel/system/stack.h> #include <kernel/system/stack.h>
#include <lainlib/ethernet/e1000/e1000.h>
//Removed cause "wacky copyrighted stuff" //Removed cause "wacky copyrighted stuff"
//#include <kernel/system/screen.h> //#include <kernel/system/screen.h>
@ -32,6 +34,8 @@ extern volatile size_t* _kernel_text_start;
extern address_space_t KernelAddressSpace; extern address_space_t KernelAddressSpace;
extern e1000_device_t* E1000NIC;
typedef struct { typedef struct {
uint32_t magic; uint32_t magic;
uint32_t version; uint32_t version;

View File

@ -31,6 +31,8 @@ typedef void (*IRQHandler)(INTERRUPT_FRAME* Frame);
extern IRQHandler IRQ_Handlers[16]; extern IRQHandler IRQ_Handlers[16];
void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame));
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt); void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
void ISR_Common(INTERRUPT_FRAME* Frame, size_t Interrupt); void ISR_Common(INTERRUPT_FRAME* Frame, size_t Interrupt);
void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception); void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception);

View File

@ -17,100 +17,100 @@
#define PCI_CONFIG_DATA 0xCFC #define PCI_CONFIG_DATA 0xCFC
const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_t progif); const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface);
const char* PCIGetClassName(uint8_t devclass); const char* PCIGetClassName(uint8_t DeviceClass);
void PCIEnumerate(); void PCIEnumerate();
uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset); uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset);
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t io_space : 1; // Device can respond to I/O access uint8_t IOMapped : 1; // Device can respond to I/O access
uint8_t memory_space : 1; // Device can respond to memory access (device is MMIO mapped) uint8_t MMIOMapped : 1; // Device can respond to memory access (device is MMIO mapped)
uint8_t bus_master : 1; // Device is Bus Master; can generate PCI addresses uint8_t IsBusMaster : 1; // Device is Bus Master; can generate PCI addresses
uint8_t special_cycle : 1; // Device can monitor Special Cycle uint8_t MonitorSpecialCycle : 1; // Device can monitor Special Cycle
uint8_t memory_write_and_invalidate : 1; // Device can generate Memory Write And Invalidate commands; else Memory Write must be used uint8_t AllowMemWriteInvalidate : 1; // Device can generate Memory Write And Invalidate commands; else Memory Write must be used
uint8_t vga_palette : 1; // Device snoops the VGA palette on write; else is treated like a normal access uint8_t SnoopVGA : 1; // Device snoops the VGA palette on write; else is treated like a normal access
uint8_t parity_error_response : 1; // Device responds to Parity Errors by setting PERR#; else will set pci_status#parity_error and continue. uint8_t RespondsParityError : 1; // Device responds to Parity Errors by setting PERR#; else will set pci_status#ParityError and continue.
uint8_t _reserved : 1; // Hardwired to 0 uint8_t _reserved : 1; // Hardwired to 0
uint8_t serr : 1; // Enable SERR# driver; System ERRor uint8_t SystemErr : 1; // Enable SERR# driver; System ERRor
uint8_t fast_back_back : 1; // Device is allowed to generate fast back-to-back transactions to other agents. uint8_t FastBack2Back : 1; // Device is allowed to generate fast back-to-back transactions to other agents.
uint8_t disable_interrupt : 1; // Disable assertion of INTx# signal; else enable. uint8_t DisableInterrupt : 1; // Disable assertion of INTx# signal; else enable.
} pci_command_t; } pci_command_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t _reserved : 3; // 3 bits hardwired to 0 uint8_t _reserved : 3; // 3 bits hardwired to 0
uint8_t interrupt : 1; // State of device's INTx# signal. If pci_command#disable_interrupt is 0 and this is 1, the signal will be asserted. uint8_t InterruptActive : 1; // State of device's INTx# signal. If pci_command#DisableInterrupt is 0 and this is 1, the signal will be asserted.
uint8_t capability_list : 1; // If set, device will implement New Capabilities list at 0x34 offset. uint8_t Capabilities : 1; // If set, device will implement New Capabilities list at 0x34 offset.
uint8_t freq_66_capable : 1; // Device can run at 66MHz. Else, device will run at 33MHz. uint8_t Mhz66Capable : 1; // Device can run at 66MHz. Else, device will run at 33MHz.
uint8_t _reserved1 : 1; // Reserved as of 3.0, Used in 2.1 as "Supports User Definable Features" uint8_t _reserved1 : 1; // Reserved as of 3.0, Used in 2.1 as "Supports User Definable Features"
uint8_t fast_back_back : 1; // Device is allowed to accept fast back-to-back transactions from other agents. uint8_t FastBack2Back : 1; // Device is allowed to accept fast back-to-back transactions from other agents.
uint8_t master_parity_error : 1; // Only set when PERR# is asserted by the Bus Master while pci_command#parity_error_response is set. uint8_t MasterParityError : 1; // Only set when PERR# is asserted by the Bus Master while pci_command#RespondsParityError is set.
uint8_t devsel_timing : 2; // Read-Only; represents the slowest time a device will assert DEVSEL#. 00 = fast, 01 = medium, 11 = slow. uint8_t DEVSELTiming : 2; // Read-Only; represents the slowest time a device will assert DEVSEL#. 00 = fast, 01 = medium, 11 = slow.
uint8_t target_signalled_abort : 1; // Target device terminated transaction via Target-Abort uint8_t TargetAborted : 1; // Target device terminated transaction via Target-Abort
uint8_t received_target_abort : 1; // Master's connection was terminated by Target-Abort uint8_t ReceivedTargetAbort : 1; // Master's connection was terminated by Target-Abort
uint8_t received_master_abort : 1; // Master's connection was terminated by Master-Abort uint8_t ReceivedMasterAbort : 1; // Master's connection was terminated by Master-Abort
uint8_t system_error_asserted : 1; // Device asserted SERR# uint8_t SystemAssertedError : 1; // Device asserted SERR#
uint8_t parity_error : 1; // Device detected parity error. Parity error may not be handled. uint8_t ParityError : 1; // Device detected parity error. Parity error may not be handled.
} pci_status_t; } pci_status_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint16_t vendor_id; // 16 bit Vendor ID allocated by PCI-SIG. 0xFFFF is invalid. uint16_t VendorID; // 16 bit Vendor ID allocated by PCI-SIG. 0xFFFF is invalid.
uint16_t device_id; // 16 bit Device ID allocated by the vendor. uint16_t DeviceID; // 16 bit Device ID allocated by the vendor.
pci_command_t command; // 16 bit PCI_COMMAND register. pci_command_t Command; // 16 bit PCI_COMMAND register.
pci_status_t status; // 16 bit PCI_STATUS register. pci_status_t Status; // 16 bit PCI_STATUS register.
uint8_t revision_id; // 8 bit register, revision identifier specified by vendor. uint8_t RevisionID; // 8 bit register, revision identifier specified by vendor.
uint8_t progIF; // 8 bit register, identifies any programming interface the device may have. uint8_t ProgrammingInterface; // 8 bit register, identifies any programming interface the device may have.
uint8_t subclass; // 8 bit Subclass code; identifies the specific function of the device uint8_t Subclass; // 8 bit Subclass code; identifies the specific function of the device
uint8_t class_code; // 8 bit Class Code; identifies the function of the device uint8_t ClassCode; // 8 bit Class Code; identifies the function of the device
uint8_t cache_line_size; // 8 bit; specifies system cache line size in 32-bit blocks. Devices can limit this. Unsupported values are treated as 0. uint8_t CacheLine; // 8 bit; specifies system cache line size in 32-bit blocks. Devices can limit this. Unsupported values are treated as 0.
uint8_t latency_timer; // 8 bit; specifies latency timer in (bus clock) units. uint8_t LatencyTimer; // 8 bit; specifies latency timer in (bus clock) units.
uint8_t header_type; // 8 bit; identifies the layout of the header and the type of device; 00 = device, 01 = pci-pci bridge, 11 = CardBus bridge. Multi-function defined by bit 7. uint8_t HeaderType; // 8 bit; identifies the layout of the header and the type of device; 00 = device, 01 = pci-pci bridge, 11 = CardBus bridge. Multi-function defined by bit 7.
uint8_t bist; // 8 bit; status and control of a device's built-in self-test (BIST) uint8_t BuiltInSelfTest; // 8 bit; status and control of a device's built-in self-test (BIST)
} pci_header_common_t; } pci_header_common_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
// pci_header_common_t first, then.. // pci_header_common_t first, then..
uint32_t bar[6]; // 6 x 32 bit Base Address Registers (BARs) uint32_t BARs[6]; // 6 x 32 bit Base Address Registers (BARs)
uint32_t cis_pointer; // Points to Card Information Structure for PCI devices that share silicon with CardBus uint32_t CISPtr; // Points to Card Information Structure for PCI devices that share silicon with CardBus
uint16_t subsystem_vendor_id; uint16_t SubsysVendor;
uint16_t subsystem_id; uint16_t SubsysID;
uint32_t expansion_bar; // Points to the base of an Expansion ROM. uint32_t ExpansionBAR; // Points to the base of an Expansion ROM.
uint8_t capabilities; // The pointer generated by pci_status#capabilities_list uint8_t Capabilities; // The pointer generated by pci_status#capabilities_list
uint8_t _reserved[3]; // 24 bit reserved at top end of register. uint8_t _reserved[3]; // 24 bit reserved at top end of register.
uint32_t _reserved2; uint32_t _reserved2;
uint8_t interrupt_line; // Specifies the PIC pin that INTx# is connected to. Can be 0-15 because x86 PICs have 16 IRQs. 0xFF is no connection. uint8_t InterruptPin; // Specifies the PIC pin that INTx# is connected to. Can be 0-15 because x86 PICs have 16 IRQs. 0xFF is no connection.
uint8_t interrupt; // Specifies the interrupt pin the device uses. 0x1 is INTA#, 0x2 is INTB#, 0x3 is INTC#, 0x4 is INTD#, 0x0 is no interrupt. uint8_t InterruptActive; // Specifies the interrupt pin the device uses. 0x1 is INTA#, 0x2 is INTB#, 0x3 is INTC#, 0x4 is INTD#, 0x0 is no interrupt.
uint8_t min_grant; // Specifies the length of the burst period, in quarter-microsecond units uint8_t MinimumTimeshare; // Specifies the length of the burst period, in quarter-microsecond units
uint8_t max_latency; // Specifies how often the device accesses the PCI bus - in quarter-microseconds uint8_t MaxmimumTimeshare; // Specifies how often the device accesses the PCI bus - in quarter-microseconds
} pci_header_device_t; } pci_header_device_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
// pci_header_common_t first // pci_header_common_t first
uint32_t bar[2]; uint32_t BARs[2];
uint8_t pri_bus; // Primary Bus Number. uint8_t PrimaryBus; // Primary Bus Number.
uint8_t sec_bus; // Secondary Bus Number. uint8_t SecondaryBus; // Secondary Bus Number.
uint8_t sub_bus; // Subordinate Bus Number. uint8_t SubordinateBus; // Subordinate Bus Number.
uint8_t sec_latency_timer; // Secondary Latency Timer. uint8_t LatencyTimer; // Secondary Latency Timer.
uint8_t io_base; // IO Base is 24 bits. This is lower 8. uint8_t IOBaseLow; // IO Base is 24 bits. This is lower 8.
uint8_t io_limit; // IO Limit is 24 bits. This is lower 8. uint8_t IOLimitLow; // IO Limit is 24 bits. This is lower 8.
pci_status_t sec_status; // Secondary Status. pci_status_t SecondaryStatus; // Secondary Status.
uint16_t mem_base; uint16_t MemoryBase;
uint16_t mem_limit; uint16_t MemoryLimit;
uint16_t mem_base_prefetch; // Prefetchable Memory Base is 48 bits. This is lower 16. uint16_t PrefetchBaseLow; // Prefetchable Memory Base is 48 bits. This is lower 16.
uint16_t mem_limit_prefetch; // Prefetchable Memory Limit is 48 bits. This is lower 16. uint16_t PrefetchLimitLow; // Prefetchable Memory Limit is 48 bits. This is lower 16.
uint32_t mem_base_prefetch_upper; // Prefetchable Memory Base is 48 bits. This is upper 32. uint32_t PrefetchBaseHigh; // Prefetchable Memory Base is 48 bits. This is upper 32.
uint32_t mem_limit_prefetch_upper; // Prefetchable Memory Limit is 48 bits. This is upper 32. uint32_t PrefetchLimitHigh; // Prefetchable Memory Limit is 48 bits. This is upper 32.
uint16_t io_base_upper; // IO Base is 24 bits. This is upper 16. uint16_t IOBaseHigh; // IO Base is 24 bits. This is upper 16.
uint16_t io_limit_upper; // IO Limit is 24 bits. This is upper 16. uint16_t IOLimitHigh; // IO Limit is 24 bits. This is upper 16.
uint8_t capabilities; // Pointer generated by pci_status#capabilities_list uint8_t Capabilities; // Pointer generated by pci_status#capabilities_list
uint8_t _reserved[3]; // 24 reserved bits. uint8_t _reserved[3]; // 24 reserved bits.
uint32_t expansion_bar; // Base of Expansion ROM. uint32_t ExpansionBAR; // Base of Expansion ROM.
uint8_t interrupt_line; // Specifies the PIC pin that INTx# is connected to. Can be 0-15 because x86 PICs have 16 IRQs. 0xFF is no connection. uint8_t InterruptPin; // Specifies the PIC pin that INTx# is connected to. Can be 0-15 because x86 PICs have 16 IRQs. 0xFF is no connection.
uint8_t interrupt; // Specifies the interrupt pin the device uses. 0x1 is INTA#, 0x2 is INTB#, 0x3 is INTC#, 0x4 is INTD#, 0x0 is no interrupt. uint8_t InterruptActive; // Specifies the interrupt pin the device uses. 0x1 is INTA#, 0x2 is INTB#, 0x3 is INTC#, 0x4 is INTD#, 0x0 is no interrupt.
uint16_t bridge_control; uint16_t BridgeControl;
} pci_header_bridge_t; } pci_header_bridge_t;
@ -122,52 +122,53 @@ typedef struct {
} pci_address_t; } pci_address_t;
typedef struct { typedef struct {
uint8_t present : 1; uint8_t Present : 1;
uint8_t mmio : 1; uint8_t MMIO : 1;
union { union {
size_t addr; size_t Address;
uint16_t port; uint16_t Port;
}; };
size_t length;
size_t Length;
} pci_bar_t; } pci_bar_t;
typedef struct pci_dev{ typedef struct pci_device {
struct pci_dev* parent; // Parent of the device (for PCI hubs / splitters) struct pci_dev* Parent; // Parent of the device (for PCI hubs / splitters)
uint16_t device_id; uint16_t DeviceID;
uint16_t vendor_id; uint16_t VendorID;
uint8_t devclass; uint8_t DeviceClass;
uint8_t subclass; uint8_t Subclass;
uint8_t progif; uint8_t ProgrammableInterface;
pci_address_t address; pci_address_t address;
pci_bar_t bars[6]; pci_bar_t BARs[6];
int irq; // The IRQ of the device if already handled int IRQ; // The IRQ of the device if already handled
// The headers! // The headers!
volatile pci_header_common_t* header; volatile pci_header_common_t* Header;
union { // The device can only be one of these at a time, but they both form part of the config space. union { // The device can only be one of these at a time, but they both form part of the config space.
volatile pci_header_bridge_t* bridge; volatile pci_header_bridge_t* bridge;
volatile pci_header_device_t* device; volatile pci_header_device_t* device;
}; };
struct pci_dev** children; // If this device is a hub, it has children... struct pci_dev** Children; // If this device is a hub, it has children...
// acpi_node_t acpi; // acpi_node_t acpi;
} pci_dev_t; } pci_device_t;
typedef struct { typedef struct {
pci_address_t key; pci_address_t key;
pci_dev_t* value; pci_device_t* value;
} pci_entry_t; } pci_entry_t;
extern pci_dev_t** pci_root_devices; extern pci_device_t** pci_root_devices;
extern pci_entry_t* pci_map; extern pci_entry_t* pci_map;

View File

@ -0,0 +1,181 @@
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
#include <stdint.h>
#include <stdbool.h>
#include <kernel/system/pci.h>
#include <kernel/system/interrupts.h>
#include <kernel/system/io.h>
#define INTEL_VEND 0x8086 // Vendor ID for Intel
#define E1000_DEV 0x100E // Device ID for the e1000 Qemu, Bochs, and VirtualBox emmulated NICs
#define E1000_I217 0x153A // Device ID for Intel I217
#define E1000_82577LM 0x10EA // Device ID for Intel 82577LM
#define REG_CTRL 0x0000
#define REG_STATUS 0x0008
#define REG_EEPROM 0x0014
#define REG_CTRL_EXT 0x0018
#define REG_IMASK 0x00D0
#define REG_RCTRL 0x0100
#define REG_RXDESCLO 0x2800
#define REG_RXDESCHI 0x2804
#define REG_RXDESCLEN 0x2808
#define REG_RXDESCHEAD 0x2810
#define REG_RXDESCTAIL 0x2818
#define REG_TCTRL 0x0400
#define REG_TXDESCLO 0x3800
#define REG_TXDESCHI 0x3804
#define REG_TXDESCLEN 0x3808
#define REG_TXDESCHEAD 0x3810
#define REG_TXDESCTAIL 0x3818
#define REG_RDTR 0x2820 // RX Delay Timer Register
#define REG_RXDCTL 0x3828 // RX Descriptor Control
#define REG_RADV 0x282C // RX Int. Absolute Delay Timer
#define REG_RSRPD 0x2C00 // RX Small Packet Detect Interrupt
#define REG_MAC 0x5400 // MAC address base
#define REG_TIPG 0x0410 // Transmit Inter Packet Gap
#define ECTRL_SLU 0x40 // set-link-up
#define RCTL_EN (1 << 1) // Receiver Enable
#define RCTL_SBP (1 << 2) // Store Bad Packets
#define RCTL_UPE (1 << 3) // Unicast Promiscuous Enabled
#define RCTL_MPE (1 << 4) // Multicast Promiscuous Enabled
#define RCTL_LPE (1 << 5) // Long Packet Reception Enable
#define RCTL_LBM_NONE (0 << 6) // No Loopback
#define RCTL_LBM_PHY (3 << 6) // PHY or external SerDesc loopback
#define RCTL_RDMTS_HALF (0 << 8) // Free Buffer Threshold is 1/2 of RDLEN
#define RCTL_RDMTS_QUARTER (1 << 8) // Free Buffer Threshold is 1/4 of RDLEN
#define RCTL_RDMTS_EIGHTH (2 << 8) // Free Buffer Threshold is 1/8 of RDLEN
#define RCTL_MO_36 (0 << 12) // Multicast Offset - bits 47:36
#define RCTL_MO_35 (1 << 12) // Multicast Offset - bits 46:35
#define RCTL_MO_34 (2 << 12) // Multicast Offset - bits 45:34
#define RCTL_MO_32 (3 << 12) // Multicast Offset - bits 43:32
#define RCTL_BAM (1 << 15) // Broadcast Accept Mode
#define RCTL_VFE (1 << 18) // VLAN Filter Enable
#define RCTL_CFIEN (1 << 19) // Canonical Form Indicator Enable
#define RCTL_CFI (1 << 20) // Canonical Form Indicator Bit Value
#define RCTL_DPF (1 << 22) // Discard Pause Frames
#define RCTL_PMCF (1 << 23) // Pass MAC Control Frames
#define RCTL_SECRC (1 << 26) // Strip Ethernet CRC
// Buffer Sizes
#define RCTL_BSIZE_256 (3 << 16)
#define RCTL_BSIZE_512 (2 << 16)
#define RCTL_BSIZE_1024 (1 << 16)
#define RCTL_BSIZE_2048 (0 << 16)
#define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25))
#define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25))
#define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25))
// Transmit Command
#define CMD_EOP (1 << 0) // End of Packet
#define CMD_IFCS (1 << 1) // Insert FCS
#define CMD_IC (1 << 2) // Insert Checksum
#define CMD_RS (1 << 3) // Report Status
#define CMD_RPS (1 << 4) // Report Packet Sent
#define CMD_VLE (1 << 6) // VLAN Packet Enable
#define CMD_IDE (1 << 7) // Interrupt Delay Enable
// TCTL Register
#define TCTL_EN (1 << 1) // Transmit Enable
#define TCTL_PSP (1 << 3) // Pad Short Packets
#define TCTL_CT_SHIFT 4 // Collision Threshold
#define TCTL_COLD_SHIFT 12 // Collision Distance
#define TCTL_RRTHRES_SHIFT 29 // Read Request Threshold
#define TCTL_SWXOFF (1 << 22) // Software XOFF Transmission
#define TCTL_RTLC (1 << 24) // Re-transmit on Late Collision
#define TSTA_DD (1 << 0) // Descriptor Done
#define TSTA_EC (1 << 1) // Excess Collisions
#define TSTA_LC (1 << 2) // Late Collision
#define LSTA_TU (1 << 3) // Transmit Underrun
#define E1000_NUM_RX_DESC 32
#define E1000_NUM_TX_DESC 8
struct e1000_receive_packet {
volatile uint64_t Address;
volatile uint16_t Length;
volatile uint16_t checksum;
volatile uint8_t Status;
volatile uint8_t errors;
volatile uint16_t Special;
} __attribute__((packed));
struct e1000_transmit_packet {
volatile uint64_t Address;
volatile uint16_t Length;
volatile uint8_t CSO;
volatile uint8_t Command;
volatile uint8_t Status;
volatile uint8_t CSS;
volatile uint16_t Special;
} __attribute__((packed));
typedef struct e1000_device {
// BAR0's type
uint8_t BARType;
// The base IO address
uint16_t IOBase;
// The base MMIO address
uint64_t MemoryBase; // MMIO Base Address
// Does this card use an EEPROM?
bool HasEEPROM;
// The MAC address
uint8_t MAC[6];
// Receive circular buffer.
struct e1000_receive_packet* ReceivePackets[E1000_NUM_RX_DESC];
// Transmit circular buffer.
struct e1000_transmit_packet* TransmitPackets[E1000_NUM_TX_DESC];
// Current receive packet index
uint16_t CurrentReceivePacket;
// Current transmit packet index
uint16_t CurrentTransmitPacket;
} e1000_device_t;
// Write a command to the E1000's registers
void E1000WriteCommandRegister(e1000_device_t* Device, uint16_t Address, uint32_t Data);
// Read the E1000's command registers
uint32_t E1000ReadCommandRegister(e1000_device_t* Device, uint16_t Address);
// Does this card use an EEPROM?
bool E1000DetectEEPROM(e1000_device_t* Device);
// Read 4 bytes from an EEPROM address
uint32_t E1000ReadEEPROM(e1000_device_t* Device, uint8_t Address);
// Read this NIC's MAC address
bool E1000ReadMAC(e1000_device_t* Device);
// Connect to a network, if there is one
void E1000Uplink(e1000_device_t* Device);
// Prepare for receiving packets
void E1000InitRX(e1000_device_t* Device);
// Prepare for sending packets
void E1000InitTX(e1000_device_t* Device);
// Prepare for receiving interrupts
void E1000InitInt(e1000_device_t* Device);
// Handle a received packet
void E1000Receive(e1000_device_t* Device);
// Handle constructing meta information about this device.
void E1000Init(e1000_device_t* Device, pci_device_t* PCIHeader);
// Initialise and start the driver
void E1000Startup(e1000_device_t* Device);
// Handle an interrupt received from the card
void E1000InterruptFired(INTERRUPT_FRAME* InterruptContext);
// Get the E1000's MAC address
uint8_t* E1000GetMAC(e1000_device_t* Device);
// Send a packet
int E1000Send(e1000_device_t* Device, const void* Data, uint16_t Length);

View File

@ -0,0 +1,352 @@
/*************************
*** Team Kitty, 2021 ***
*** Lainlib ***
************************/
#include <lainlib/ethernet/e1000/e1000.h>
#include <kernel/chroma.h>
#include <kernel/system/memory.h>
#include <kernel/system/interrupts.h>
/**
* This file handles all the logic for interfacing with the E1000 networking device.
* This card is labelled either the Intel I217, or Intel Gigabit 82577LM.
* These cards are identical, and this driver will work identically for both of them.
*
* To use this driver, allocate an e1000_device struct and pass it to the E1000Init() function,
* along with its' PCI device header.
*
* TODO: usage information
*/
/**
* Write data to the device's command registers.
* If we use BAR type 0, we use MMIO, otherwise ports.
*
* @param Device The device to which we write the data.
* @param Address The address to write the data at. For MMIO, the offset from base.
* @param Data The data to write into the register.
*/
void E1000WriteCommandRegister(e1000_device_t* Device, uint16_t Address, uint32_t Data) {
if(Device->BARType == 0)
WriteMMIO(Device->MemoryBase + Address, Data, 4);
else {
WritePort(Device->IOBase, Address, 4);
WritePort(Device->IOBase + 4, Data, 4);
}
}
/**
* Read data from the device's command registers.
* If we use BAR type 0, we read from MMIO. Otherwise, ports.
*
* @param Device The device to read the data from
* @param Address The address we expect the data to be at. For MMIO, the offset from base.
* @return uint32_t The data contained in the register.
*/
uint32_t E1000ReadCommandRegister(e1000_device_t* Device, uint16_t Address) {
if(Device->BARType == 0)
return ReadMMIO(Device->MemoryBase + Address, 4);
else {
WritePort(Device->IOBase, Address, 4);
return ReadPort(Device->IOBase + 4, 4);
}
}
/**
* Attempt to detect the presence of an EEPROM in the E1000.
* It sometimes doesn't like revealing its secrets, so we try it around 1000 times.
*
* @param Device The device to attempt to detect an EEPROM inside.
* @return true The given device has an EEPROM
* @return false The given device does not have an EEPROM
*/
bool E1000DetectEEPROM(e1000_device_t* Device) {
uint32_t Res = 0;
E1000WriteCommandRegister(Device, REG_EEPROM, 0x1);
Device->HasEEPROM = false;
for(size_t i = 0; i < 1000 && !Device->HasEEPROM; i++) {
Res = E1000ReadCommandRegister(Device, REG_EEPROM);
if(Res & 0x10)
Device->HasEEPROM = true;
}
return Res;
}
/**
* Read data from the E1000's EEPROM, if it has one.
* TODO: Unify
* @param Device The device to read
* @param Address The address we expect the data to be at
* @return uint32_t 32 bits of data in the given address of the EEPROM. 0 if not.
*/
uint32_t E1000ReadEEPROM(e1000_device_t* Device, uint8_t Address) {
uint32_t Temp = 0;
if(Device->HasEEPROM) {
// Tell the device we want the data at given address.
E1000WriteCommandRegister(Device, REG_EEPROM, (((uint32_t) Address) << 8) | 1);
// Spinlock until we get the result we expect
// TODO: Timeout?
while(!((Temp = E1000ReadCommandRegister(Device, REG_EEPROM)) & (1 << 4)));
} else {
// The E1000, if it does not have an EEPROM, instead stores it in internal ROM.
// So the same thing applies, but with different bits.
E1000WriteCommandRegister(Device, REG_EEPROM, (((uint32_t) Address) << 2) | 1);
while(!((Temp = E1000ReadCommandRegister(Device, REG_EEPROM)) & (1 << 1)));
}
return (uint16_t)((Temp >> 16) & 0xFFFF);
}
/**
* Read the E1000's MAC address into the internal buffer.
*
* @param Device The device to read from.
* @return true The read finished successfully
* @return false The MMIO base address is non-zero - this is invalid.
*/
bool E1000ReadMAC(e1000_device_t* Device) {
if(Device->HasEEPROM) {
uint32_t Temp;
Temp = E1000ReadEEPROM(Device, 0);
Device->MAC[0] = Temp & 0xff;
Device->MAC[1] = Temp >> 8;
Temp = E1000ReadEEPROM(Device, 1);
Device->MAC[2] = Temp & 0xff;
Device->MAC[3] = Temp >> 8;
Temp = E1000ReadEEPROM(Device, 2);
Device->MAC[4] = Temp & 0xff;
Device->MAC[5] = Temp >> 8;
} else {
uint8_t* MACBaseChar = (uint8_t*) (Device->MemoryBase + REG_MAC);
uint32_t* MACBaseLong = (uint32_t*) (Device->MemoryBase + REG_MAC);
if(MACBaseLong[0] != 0)
for(size_t i = 0; i < 6; i++)
Device->MAC[i] = MACBaseChar[i];
else
return false;
return true;
}
}
/**
* Prepare the receive buffers, tell the device how to handle incoming packets.
*
* @param Device The device to prepare
*/
void E1000InitRX(e1000_device_t* Device) {
uint8_t* Ptr;
struct e1000_receive_packet* Packets;
Ptr = (uint8_t*) (kmalloc(sizeof(struct e1000_receive_packet) * E1000_NUM_RX_DESC + 16));
Packets = (struct e1000_receive_packet*) Ptr;
for(size_t i = 0; i < E1000_NUM_RX_DESC; i++) {
Device->ReceivePackets[i] = (struct e1000_receive_packet*) ((uint8_t*)Packets + i*16);
Device->ReceivePackets[i]->address = (size_t) ((uint8_t*) kmalloc((PAGE_SIZE * 2) + 16));
Device->ReceivePackets[i]->Status = 0;
}
E1000WriteCommandRegister(Device, REG_TXDESCLO, (uint32_t) ((size_t)Ptr >> 32));
E1000WriteCommandRegister(Device, REG_TXDESCHI, (uint32_t) ((size_t)Ptr & 0xFFFFFFFF));
E1000WriteCommandRegister(Device, REG_RXDESCLO, (size_t) Ptr);
E1000WriteCommandRegister(Device, REG_RXDESCHI, 0);
E1000WriteCommandRegister(Device, REG_RXDESCLEN, E1000_NUM_RX_DESC * 16);
E1000WriteCommandRegister(Device, REG_RXDESCHEAD, 0);
E1000WriteCommandRegister(Device, REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1);
Device->CurrentReceivePacket = 0;
E1000WriteCommandRegister(Device, REG_RCTRL,
RCTL_EN | // ENable
RCTL_SBP | // Store Bad Packets
RCTL_UPE | // Unicast Promiscuous Enable
RCTL_MPE | // Multicast Promiscuous Enable
RCTL_LBM_NONE | // LoopBack Mode
RCTL_RDMTS_HALF | // Receive Descriptor Minimum Threshold Size - throw interrupts when the buffer gets half filled
RCTL_BAM | // Broadcast Accept Mode
RCTL_SECRC | // Strip Ethernet CRC
RCTL_BSIZE_8192 // 8192 byte long buffer.
);
}
/**
* Prepare the transmit buffers, tell the device how to handle outgoing packets.
*
* @param Device The device to prepare
*/
void E1000InitTX(e1000_device_t* Device) {
uint8_t* Ptr;
struct e1000_transmit_packet* Packets;
Ptr = (uint8_t*) (kmalloc(sizeof(struct e1000_transmit_packet) * E1000_NUM_TX_DESC + 16));
Packets = (struct e1000_transmit_packet*) Ptr;
for(int i = 0; i < E1000_NUM_TX_DESC; i++) {
Device->TransmitPackets[i] = (struct e1000_transmit_packet*) ((uint8_t*) Packets + (i * 16));
Device->TransmitPackets[i]->Address = 0;
Device->TransmitPackets[i]->Command = 0;
Device->TransmitPackets[i]->Status = TSTA_DD;
}
E1000WriteCommandRegister(Device, REG_TXDESCHI, (uint32_t) ((size_t)Ptr >> 32));
E1000WriteCommandRegister(Device, REG_TXDESCLO, (uint32_t) ((size_t)Ptr & 0xFFFFFFFF));
E1000WriteCommandRegister(Device, REG_TXDESCLEN, E1000_NUM_TX_DESC * 16);
E1000WriteCommandRegister(Device, REG_TXDESCHEAD, 0);
E1000WriteCommandRegister(Device, REG_TXDESCTAIL, 0);
Device->CurrentTransmitPacket = 0;
E1000WriteCommandRegister(Device, REG_TCTRL,
TCTL_EN | // ENable
TCTL_PSP | // Pad Short Packets
(15 << TCTL_CT_SHIFT) | // Collision Threshold - Attempt to re-send the packet 15 times.
(0x3F << TCTL_COLD_SHIFT) | // Collision Distance
(0x3 << TCTL_RRTHRES_SHIFT) // Read Request Threshold - infinity.
);
E1000WriteCommandRegister(Device, REG_TIPG,
0x0060200A);
}
/**
* Tell the device that it may send interrupts to inform us of what's going on
*
* @param Device The device to notify
*/
void E1000InitInt(e1000_device_t* Device) {
E1000WriteCommandRegister(Device, REG_IMASK, 0x1F6DC);
E1000WriteCommandRegister(Device, REG_IMASK, 0xFF & ~4);
E1000ReadCommandRegister(Device, 0xC0);
}
/**
* Handle interrupts fired by the E1000.
* It will either:
* - Help initialise the device
* - Handle an incoming packet
*
* @param InterruptContext The interrupt metadata.
*/
void E1000InterruptFired(INTERRUPT_FRAME* InterruptContext) {
e1000_device_t* NIC = E1000NIC; // TODO: Find device from interrupt frame?
E1000WriteCommandRegister(NIC, REG_IMASK, 1);
uint32_t NICStatus = E1000ReadCommandRegister(NIC, 0xC0);
if(NICStatus & 0x4)
E1000Uplink(NIC);
else if(NICStatus & 0x80)
E1000Receive(NIC);
}
/**
* Initialise the state of the device, prepare it for further initialization steps.
*
* @param Device The device to initialise
* @param PCIHeader The device's PCI headers.
*/
void E1000Init(e1000_device_t* Device, pci_device_t* PCIHeader) {
pci_bar_t BAR = PCIHeader->BARs[0];
InstallIRQ(11, E1000InterruptFired);
if(BAR.MMIO) {
Device->BARType = 0;
Device->MemoryBase = DecodeVirtualAddress(&KernelAddressSpace, BAR.Address);
SerialPrintf("[E1000] Device is memory mapped - 0x%p x 0x%d\r\n", Device->MemoryBase, BAR.Length);
// UpdatePaging
} else {
Device->BARType = 1;
Device->IOBase = BAR.Port;
SerialPrintf("[E1000] Device is port mapped - 0x%p\r\n", Device->IOBase);
}
if(E1000DetectEEPROM(Device))
SerialPrintf("[E1000] Device has EEPROM\r\n");
E1000ReadMAC(Device);
SerialPrintf("[E1000] Device's MAC is %d:%d:%d:%d:%d:%d\r\n", Device->MAC[0], Device->MAC[1], Device->MAC[2], Device->MAC[3], Device->MAC[4], Device->MAC[5]);
// Setup multicast
for(size_t i = 0; i < 0x80; i++)
WritePort(0x5200 + i * 4, 0, 4);
E1000InitRX(Device);
E1000InitTX(Device);
E1000InitInt(Device);
SerialPrintf("[E1000] Device ready.\r\n");
}
/**
* Tell the device that it may connect itself to any networks it finds itself on.
*
* @param Device The device to notify
*/
void E1000Uplink(e1000_device_t* Device) {
uint32_t Flags = E1000ReadCommandRegister(Device, 0);
E1000WriteCommandRegister(Device, 0, Flags | 0x40);
}
/**
* Handle a received packet, placing it in the buffer for other apps to consume.
*
* @param Device The device which received this packet.
*/
void E1000Receive(e1000_device_t* Device) {
uint16_t Temp;
while(Device->ReceivePackets[Device->CurrentReceivePacket]->Status & 0x1) {
Device->ReceivePackets[Device->CurrentReceivePacket]->Status = 0;
Temp = Device->CurrentReceivePacket;
Device->CurrentReceivePacket = (Device->CurrentReceivePacket + 1) % E1000_NUM_RX_DESC;
E1000WriteCommandRegister(Device, REG_RXDESCTAIL, Temp);
}
}
/**
* Retrieve the E1000's MAC address.
* Only valid after E1000ReadMAC is called.
*
* @param Device The device to read
* @return uint8_t* A pointer to the MAC data.
*/
uint8_t* E1000GetMAC(e1000_device_t* Device) {
return (uint8_t*) Device->MAC;
}
/**
* Send a packet of specified length, via the given Device.
*
* @param Device The NIC to send the packet from
* @param Data The data to send
* @param Length The length of the data
* @return int 0 if successful. No other returns.
*/
int E1000Send(e1000_device_t* Device, const void* Data, uint16_t Length) {
struct e1000_transmit_packet* Target = Device->TransmitPackets[Device->CurrentTransmitPacket];
Target->Address = (size_t) Data;
Target->Length = Length;
Target->Command = CMD_EOP | CMD_IFCS | CMD_RS;
Target->Status = 0;
uint8_t temp = Device->CurrentTransmitPacket;
Device->CurrentTransmitPacket = (Device->CurrentTransmitPacket + 1) % E1000_NUM_TX_DESC;
E1000WriteCommandRegister(Device, REG_TXDESCTAIL, Device->CurrentTransmitPacket);
while(!(Device->TransmitPackets[temp]->Status & 0xFF));
return 0;
}

View File

@ -0,0 +1,23 @@
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
#include <stdint.h>
struct mac_address {
uint8_t MAC[6];
} __attribute__((packed));
enum packet_types {
ET_ARP = 0x0806,
ET_IP4 = 0x0800,
ET_IP6 = 0x86DD,
};
struct ethernet_packet {
mac_address Dest;
mac_address Source;
uint16_t Type;
uint8_t Payload[];
};

View File

@ -178,7 +178,7 @@ void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame)) {
/* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */ /* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */
void UninstallIRQHandler(int IRQ) { void UninstallIRQHandler(int IRQ) {
IRQ_Handlers[IRQ] = NULL; // 0 is used in the common check to make sure that the function is callable. IRQ_Handlers[IRQ] = NULL; // 0 is used in the common check to make sure that the function is callable.
// This removes this irq from that check, ergo the function will no longer be called. // This removes this IRQ from that check, ergo the function will no longer be called.
} }
void EmptyIRQ(INTERRUPT_FRAME* frame) { void EmptyIRQ(INTERRUPT_FRAME* frame) {

View File

@ -12,14 +12,14 @@
* *
*/ */
pci_dev_t** pci_root_devices = NULL; pci_device_t** pci_root_devices = NULL;
pci_entry_t* pci_map = NULL; pci_entry_t* pci_map = NULL;
//static uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset); //static uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset);
//static const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_t progif); //static const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface);
//static const char* PCIGetClassName(uint8_t devclass); //static const char* PCIGetClassName(uint8_t DeviceClass);
void PCIEnumerate() { void PCIEnumerate() {
@ -27,9 +27,9 @@ void PCIEnumerate() {
uint32_t registerData; uint32_t registerData;
uint16_t device_id, vendor_id; uint16_t DeviceID, VendorID;
uint8_t class_code, subclass_code; uint8_t ClassCode, subclass_code;
SerialPrintf("[ PCI] Started PCI Enumeration."); SerialPrintf("[ PCI] Started PCI Enumeration.");
@ -42,11 +42,11 @@ void PCIEnumerate() {
uint8_t multifunction_bit = header & 0x80; // The multifunction bit is the highest bit of the header uint8_t multifunction_bit = header & 0x80; // The multifunction bit is the highest bit of the header
registerData = PCIReadConfig(bus, device, function, 0); // Read the Vendor/Device ID register registerData = PCIReadConfig(bus, device, function, 0); // Read the Vendor/Device ID register
vendor_id = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word VendorID = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word
device_id = (uint16_t) (registerData >> 16); // Device ID is top word DeviceID = (uint16_t) (registerData >> 16); // Device ID is top word
registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register
class_code = (uint16_t)( registerData >> 24); // Device class is top byte, so shift them down ClassCode = (uint16_t)( registerData >> 24); // Device class is top byte, so shift them down
subclass_code = (uint16_t) ((registerData >> 16) & 0x00FF); // Device subclass is same as header - lower byte of higher word. Shift down and mask just like before. subclass_code = (uint16_t) ((registerData >> 16) & 0x00FF); // Device subclass is same as header - lower byte of higher word. Shift down and mask just like before.
uint8_t device_progif = (uint16_t) ((registerData & 0x0000FF00) >> 8); // Device Programming Interface is higher byte of lower word, so mask and shift uint8_t device_progif = (uint16_t) ((registerData & 0x0000FF00) >> 8); // Device Programming Interface is higher byte of lower word, so mask and shift
uint8_t device_revision = (uint16_t) (registerData & 0x000000FF); // Device revision is lower byte of whole double word. Just mask it. uint8_t device_revision = (uint16_t) (registerData & 0x000000FF); // Device revision is lower byte of whole double word. Just mask it.
@ -55,9 +55,9 @@ void PCIEnumerate() {
/* 0xFFFF is not a valid Vendor ID. This serves as a sanity check. /* 0xFFFF is not a valid Vendor ID. This serves as a sanity check.
* If this check is true, then nothing is logged and we continue for the next loop. * If this check is true, then nothing is logged and we continue for the next loop.
*/ */
if(vendor_id != 0xFFFF) { if(VendorID != 0xFFFF) {
SerialPrintf("[ PCI]\n[ PCI]\t%x:%x:\n[ PCI]\t\tVendor: %x\n[ PCI]\t\tDevice: %x", bus, device, vendor_id, device_id); SerialPrintf("[ PCI]\n[ PCI]\t%x:%x:\n[ PCI]\t\tVendor: %x\n[ PCI]\t\tDevice: %x", bus, device, VendorID, DeviceID);
SerialPrintf("\n[ PCI]\t\tClass: %s\n[ PCI]\t\tDevice Type: %s\n[ PCI]\t\tRevision: %d\n", PCIGetClassName(class_code), PCIGetDeviceName_Subclass(class_code, subclass_code, device_progif), device_revision); SerialPrintf("\n[ PCI]\t\tClass: %s\n[ PCI]\t\tDevice Type: %s\n[ PCI]\t\tRevision: %d\n", PCIGetClassName(ClassCode), PCIGetDeviceName_Subclass(ClassCode, subclass_code, device_progif), device_revision);
} }
/* If the PCI Device header tells us that this is not a multifunction device, /* If the PCI Device header tells us that this is not a multifunction device,
@ -102,11 +102,11 @@ uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offs
return ReadPort(0xCFC, 4); return ReadPort(0xCFC, 4);
} }
const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_t progif) { const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface) {
switch(devclass) { switch(DeviceClass) {
case 0x00: { case 0x00: {
switch(subclass) { switch(Subclass) {
case 0x00: return "Non-VGA-Compatible device"; case 0x00: return "Non-VGA-Compatible device";
case 0x01: return "VGA-Compatible device"; case 0x01: return "VGA-Compatible device";
default: return "Unknown Unclassified"; default: return "Unknown Unclassified";
@ -114,10 +114,10 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x01: { case 0x01: {
switch(subclass) { switch(Subclass) {
case 0x00: return "SCSI Bus Controller"; case 0x00: return "SCSI Bus Controller";
case 0x01: { case 0x01: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "ISA Compatibility Mode-only IDE Controller"; case 0x00: return "ISA Compatibility Mode-only IDE Controller";
case 0x05: return "PCI Native Mode-only IDE Controller"; case 0x05: return "PCI Native Mode-only IDE Controller";
case 0x0A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode)"; case 0x0A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode)";
@ -133,7 +133,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
case 0x03: return "IPI Bus Controller"; case 0x03: return "IPI Bus Controller";
case 0x04: return "RAID Controller"; case 0x04: return "RAID Controller";
case 0x05: { case 0x05: {
switch(progif) { switch(ProgrammableInterface) {
case 0x20: return "Single-DMA ATA Controller"; case 0x20: return "Single-DMA ATA Controller";
case 0x30: return "Chained-DMA ATA Controller"; case 0x30: return "Chained-DMA ATA Controller";
default: return "ATA Controller"; default: return "ATA Controller";
@ -142,7 +142,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
case 0x06: { case 0x06: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Vendor-Specific Interface SATA Controller"; case 0x00: return "Vendor-Specific Interface SATA Controller";
case 0x01: return "AHCI 1.0 SATA Controller"; case 0x01: return "AHCI 1.0 SATA Controller";
case 0x02: return "Serial Storage Bus SATA Controller"; case 0x02: return "Serial Storage Bus SATA Controller";
@ -152,7 +152,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
case 0x07: return "Serial Attached SCSI (SAS)"; case 0x07: return "Serial Attached SCSI (SAS)";
case 0x08:{ case 0x08:{
switch(progif) { switch(ProgrammableInterface) {
case 0x01: return "NVMHCI Memory Controller"; case 0x01: return "NVMHCI Memory Controller";
case 0x02: return "NVMe Memory Controller"; case 0x02: return "NVMe Memory Controller";
default: return "Non-Volatile Memory Controller"; default: return "Non-Volatile Memory Controller";
@ -166,7 +166,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x02: { case 0x02: {
switch(subclass) { switch(Subclass) {
case 0x00: return "Ethernet Controller"; case 0x00: return "Ethernet Controller";
case 0x01: return "Token Ring Controller"; case 0x01: return "Token Ring Controller";
case 0x02: return "FDDI Controller"; case 0x02: return "FDDI Controller";
@ -182,9 +182,9 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x03: { case 0x03: {
switch(subclass) { switch(Subclass) {
case 0x00: { case 0x00: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "VGA Controller"; case 0x00: return "VGA Controller";
case 0x01: return "8514 VGA Controller"; case 0x01: return "8514 VGA Controller";
default: return "VGA Compatible Controller"; default: return "VGA Compatible Controller";
@ -199,7 +199,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x04: { case 0x04: {
switch(subclass) { switch(Subclass) {
case 0x00: return "Multimedia Video Controller"; case 0x00: return "Multimedia Video Controller";
case 0x01: return "Multimedia Audio Controller"; case 0x01: return "Multimedia Audio Controller";
case 0x02: return "Computer Telephony Device"; case 0x02: return "Computer Telephony Device";
@ -210,7 +210,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x05: { case 0x05: {
switch(subclass) { switch(Subclass) {
case 0x00: return "RAM Controller"; case 0x00: return "RAM Controller";
case 0x01: return "Flash Controller"; case 0x01: return "Flash Controller";
case 0x80: return "Other"; case 0x80: return "Other";
@ -219,7 +219,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x06: { case 0x06: {
switch(subclass) { switch(Subclass) {
case 0x00: return "Host Bridge"; case 0x00: return "Host Bridge";
case 0x01: return "ISA Bridge"; case 0x01: return "ISA Bridge";
case 0x02: return "EISA Bridge"; case 0x02: return "EISA Bridge";
@ -238,10 +238,10 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x07: { case 0x07: {
switch(subclass) { switch(Subclass) {
case 0x00: { case 0x00: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Serial Controller <8250>"; case 0x00: return "Serial Controller <8250>";
case 0x01: return "Serial controller <16450>"; case 0x01: return "Serial controller <16450>";
case 0x02: return "Serial controller <16550>"; case 0x02: return "Serial controller <16550>";
@ -255,7 +255,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x01: { case 0x01: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Standard Parallel Port"; case 0x00: return "Standard Parallel Port";
case 0x01: return "Bi-Directional Parallel Port"; case 0x01: return "Bi-Directional Parallel Port";
case 0x02: return "ECP 1.X Compliant Parallel Port"; case 0x02: return "ECP 1.X Compliant Parallel Port";
@ -267,7 +267,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
case 0x02: return "Multiport Serial Controller"; case 0x02: return "Multiport Serial Controller";
case 0x03: { case 0x03: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Generic Modem"; case 0x00: return "Generic Modem";
case 0x01: return "Hayes 16450 Compatible Modem"; case 0x01: return "Hayes 16450 Compatible Modem";
case 0x02: return "Hayes 16550 Compatible Modem"; case 0x02: return "Hayes 16550 Compatible Modem";
@ -285,9 +285,9 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x08: { case 0x08: {
switch(subclass) { switch(Subclass) {
case 0x00: { case 0x00: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Generic 8259-Compatible PIC"; case 0x00: return "Generic 8259-Compatible PIC";
case 0x01: return "ISA-Compatible PIC"; case 0x01: return "ISA-Compatible PIC";
case 0x02: return "EISA-Compatible PIC"; case 0x02: return "EISA-Compatible PIC";
@ -298,7 +298,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x01: { case 0x01: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Generic 8237-Compatible DMA Controller"; case 0x00: return "Generic 8237-Compatible DMA Controller";
case 0x01: return "ISA-Compatible DMA Controller"; case 0x01: return "ISA-Compatible DMA Controller";
case 0x02: return "EISA-Compatible DMA Controller"; case 0x02: return "EISA-Compatible DMA Controller";
@ -307,7 +307,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x02: { case 0x02: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Generic 8254-Compatible Timer"; case 0x00: return "Generic 8254-Compatible Timer";
case 0x01: return "ISA-Compatible Timer"; case 0x01: return "ISA-Compatible Timer";
case 0x02: return "EISA-Compatible Timer"; case 0x02: return "EISA-Compatible Timer";
@ -317,7 +317,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x03: { case 0x03: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Generic RTC Controller"; case 0x00: return "Generic RTC Controller";
case 0x01: return "ISA-Compatible RTC Controller"; case 0x01: return "ISA-Compatible RTC Controller";
default: return "RTC Controller"; default: return "RTC Controller";
@ -334,14 +334,14 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x09: { case 0x09: {
switch(subclass) { switch(Subclass) {
case 0x00: return "Keyboard Controller"; case 0x00: return "Keyboard Controller";
case 0x01: return "Digitiser Pen"; case 0x01: return "Digitiser Pen";
case 0x02: return "Mouse Controller"; case 0x02: return "Mouse Controller";
case 0x03: return "Scanner Controller"; case 0x03: return "Scanner Controller";
case 0x04: { case 0x04: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Generic Gameport Controller"; case 0x00: return "Generic Gameport Controller";
case 0x10: return "Extended Gameport Controller"; case 0x10: return "Extended Gameport Controller";
default: return "Gameport Controller"; default: return "Gameport Controller";
@ -355,7 +355,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x0A: { case 0x0A: {
switch(subclass) { switch(Subclass) {
case 0x00: return "Generic Docking Station"; case 0x00: return "Generic Docking Station";
case 0x80: return "Other"; case 0x80: return "Other";
default: return "Unknown Docking Station"; default: return "Unknown Docking Station";
@ -363,7 +363,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x0B: { case 0x0B: {
switch(subclass) { switch(Subclass) {
case 0x00: return "386 Processor"; case 0x00: return "386 Processor";
case 0x01: return "486 Processor"; case 0x01: return "486 Processor";
case 0x02: return "Pentium Processor"; case 0x02: return "Pentium Processor";
@ -378,9 +378,9 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x0C: { case 0x0C: {
switch(subclass) { switch(Subclass) {
case 0x00: { case 0x00: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "Generic Firewire Controller"; case 0x00: return "Generic Firewire Controller";
case 0x10: return "OHCI Firewire Controller"; case 0x10: return "OHCI Firewire Controller";
default: return "FireWire (IEEE 1394) Controller"; default: return "FireWire (IEEE 1394) Controller";
@ -391,7 +391,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
case 0x02: return "SSA"; case 0x02: return "SSA";
case 0x03: { case 0x03: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "UHCI USB Controller"; case 0x00: return "UHCI USB Controller";
case 0x10: return "OHCI USB Controller"; case 0x10: return "OHCI USB Controller";
case 0x20: return "EHCI USB (2.0) Controller"; case 0x20: return "EHCI USB (2.0) Controller";
@ -407,7 +407,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
case 0x06: return "InfiniBand"; case 0x06: return "InfiniBand";
case 0x07: { case 0x07: {
switch(progif) { switch(ProgrammableInterface) {
case 0x00: return "SMIC IPMI Interface"; case 0x00: return "SMIC IPMI Interface";
case 0x01: return "Keyboard Controller-Style IPMI Interface"; case 0x01: return "Keyboard Controller-Style IPMI Interface";
case 0x02: return "Block Transfer IPMI Interface"; case 0x02: return "Block Transfer IPMI Interface";
@ -423,7 +423,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x0D: { case 0x0D: {
switch(subclass) { switch(Subclass) {
case 0x00: return "IRDA Compatible Controller"; case 0x00: return "IRDA Compatible Controller";
case 0x01: return "Consumer IR Controller"; case 0x01: return "Consumer IR Controller";
case 0x10: return "RF Controller"; case 0x10: return "RF Controller";
@ -437,14 +437,14 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x0E: { case 0x0E: {
switch(subclass) { switch(Subclass) {
case 0x00: return "I20"; case 0x00: return "I20";
default: return "Unknown Intelligent Controller"; default: return "Unknown Intelligent Controller";
} }
} }
case 0x0F: { case 0x0F: {
switch(subclass) { switch(Subclass) {
case 0x01: return "Satellite TV Controller"; case 0x01: return "Satellite TV Controller";
case 0x02: return "Satellite Audio Controller"; case 0x02: return "Satellite Audio Controller";
case 0x03: return "Satellite Voice Controller"; case 0x03: return "Satellite Voice Controller";
@ -454,7 +454,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x10: { case 0x10: {
switch(subclass) { switch(Subclass) {
case 0x00: return "Network & Computing Codec"; case 0x00: return "Network & Computing Codec";
case 0x10: return "Entertainment Codec"; case 0x10: return "Entertainment Codec";
case 0x80: return "Other Codec"; case 0x80: return "Other Codec";
@ -463,7 +463,7 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
} }
case 0x11: { case 0x11: {
switch(subclass) { switch(Subclass) {
case 0x00: return "DPIO Modules"; case 0x00: return "DPIO Modules";
case 0x01: return "Performance Counters"; case 0x01: return "Performance Counters";
case 0x10: return "Communication Synchronizer"; case 0x10: return "Communication Synchronizer";
@ -489,9 +489,9 @@ const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_
return "Invalid Device!"; return "Invalid Device!";
} }
const char* PCIGetClassName(uint8_t devclass) { const char* PCIGetClassName(uint8_t DeviceClass) {
switch(devclass) { switch(DeviceClass) {
case 0x00: return "Unclassified"; case 0x00: return "Unclassified";
case 0x01: return "Mass Storage Controller"; case 0x01: return "Mass Storage Controller";
case 0x02: return "Network Controller"; case 0x02: return "Network Controller";