mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-25 22:14:34 +00:00
fix(drivers): remove drivers that are now in kernel
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
This commit is contained in:
parent
95585fce5f
commit
7b85636f8f
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
@ -1,881 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <audio.h>
|
||||
#include <regs.h>
|
||||
#include <base.h>
|
||||
#include <pci.h>
|
||||
#include <io.h>
|
||||
#include <fs.h>
|
||||
|
||||
#define DescriptorListLength 0x20
|
||||
|
||||
enum AudioVolumeValues
|
||||
{
|
||||
AV_Maximum = 0x0,
|
||||
AV_Minimum = 0x3F,
|
||||
};
|
||||
|
||||
enum AudioEncodingValues
|
||||
{
|
||||
AE_PCMs8,
|
||||
AE_PCMu8,
|
||||
|
||||
AE_PCMs16le,
|
||||
AE_PCMs20le,
|
||||
AE_PCMs24le,
|
||||
AE_PCMs32le,
|
||||
|
||||
AE_PCMu16le,
|
||||
AE_PCMu20le,
|
||||
AE_PCMu24le,
|
||||
AE_PCMu32le,
|
||||
|
||||
AE_PCMs16be,
|
||||
AE_PCMs20be,
|
||||
AE_PCMs24be,
|
||||
AE_PCMs32be,
|
||||
|
||||
AE_PCMu16be,
|
||||
AE_PCMu20be,
|
||||
AE_PCMu24be,
|
||||
AE_PCMu32be,
|
||||
};
|
||||
|
||||
enum NativeAudioMixerRegisters
|
||||
{
|
||||
/**
|
||||
* @brief Reset Register
|
||||
* @note Length: word
|
||||
*/
|
||||
NAM_Reset = 0x00,
|
||||
|
||||
/**
|
||||
* @brief Master Volume Register
|
||||
* @note Length: word
|
||||
*/
|
||||
NAM_MasterVolume = 0x02,
|
||||
|
||||
/**
|
||||
* @brief Microphone Volume Register
|
||||
* @note Length: word
|
||||
*/
|
||||
NAM_MicrophoneVolume = 0x0E,
|
||||
|
||||
/**
|
||||
* @brief PCM Out Volume Register
|
||||
* @note Length: word
|
||||
*/
|
||||
NAM_PCMOutVolume = 0x18,
|
||||
|
||||
/**
|
||||
* @brief Select Record Input Register
|
||||
* @note Length: word
|
||||
*/
|
||||
NAM_SelectRecordInput = 0x1A,
|
||||
|
||||
/**
|
||||
* @brief Record Gain Register
|
||||
* @note Length: word
|
||||
*/
|
||||
NAM_RecordGain = 0x1C,
|
||||
|
||||
/**
|
||||
* @brief Record Gain Microphone Register
|
||||
* @note Length: word
|
||||
*/
|
||||
NAM_RecordGainMicrophone = 0x1E,
|
||||
};
|
||||
|
||||
enum NativeAudioBusMasterRegisters
|
||||
{
|
||||
/**
|
||||
* @brief Register box for PCM IN
|
||||
* @note Length: below
|
||||
*/
|
||||
NABM_PCMInBox = 0x00,
|
||||
|
||||
/**
|
||||
* @brief Register box for PCM OUT
|
||||
* @note Length: below
|
||||
*/
|
||||
NABM_PCMOutBox = 0x10,
|
||||
|
||||
/**
|
||||
* @brief Register box for Microphone
|
||||
* @note Length: below
|
||||
*/
|
||||
NABM_MicrophoneBox = 0x20,
|
||||
|
||||
/**
|
||||
* @brief Global Control Register
|
||||
* @note Length: dword
|
||||
*/
|
||||
NABM_GlobalControl = 0x2C, /* 0x30 */
|
||||
|
||||
/**
|
||||
* @brief Global Status Register
|
||||
* @note Length: dword
|
||||
*/
|
||||
NABM_GlobalStatus = 0x30, /* 0x34 */
|
||||
};
|
||||
|
||||
enum NativeAudioBusMasterBoxOffsets
|
||||
{
|
||||
/**
|
||||
* @brief Physical Address of Buffer Descriptor List
|
||||
* @note Length: dword
|
||||
*/
|
||||
NABMBOFF_BufferDescriptorList = 0x00,
|
||||
|
||||
/**
|
||||
* @brief Number of Actual Processed Buffer Descriptor Entry
|
||||
* @note Length: byte
|
||||
*/
|
||||
NABMBOFF_BufferDescriptorEntry = 0x04,
|
||||
|
||||
/**
|
||||
* @brief Number of all Descriptor Entries
|
||||
* @note Length: byte
|
||||
*/
|
||||
NABMBOFF_DescriptorEntries = 0x05,
|
||||
|
||||
/**
|
||||
* @brief Status of transferring Data
|
||||
* @note Length: word
|
||||
*/
|
||||
NABMBOFF_Status = 0x06,
|
||||
|
||||
/**
|
||||
* @brief Number of transferred Samples in Actual Processed Entry
|
||||
* @note Length: word
|
||||
*/
|
||||
NABMBOFF_TransferredSamples = 0x08,
|
||||
|
||||
/**
|
||||
* @brief Number of next processed Buffer Entry
|
||||
* @note Length: byte
|
||||
*/
|
||||
NABMBOFF_NextProcessedBufferEntry = 0x0A,
|
||||
|
||||
/**
|
||||
* @brief Transfer Control
|
||||
* @note Length: byte
|
||||
*/
|
||||
NABMBOFF_TransferControl = 0x0B,
|
||||
};
|
||||
|
||||
enum OutputPulseCodeModulationRegisters
|
||||
{
|
||||
/**
|
||||
* @brief Physical Address of Buffer Descriptor List
|
||||
* @note Length: dword
|
||||
*/
|
||||
PCMOUT_BufferDescriptorList = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorList,
|
||||
|
||||
/**
|
||||
* @brief Number of Actual Processed Buffer Descriptor Entry
|
||||
* @note Length: byte
|
||||
*/
|
||||
PCMOUT_BufferDescriptorEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorEntry,
|
||||
|
||||
/**
|
||||
* @brief Number of all Descriptor Entries
|
||||
* @note Length: byte
|
||||
*/
|
||||
PCMOUT_DescriptorEntries = (int)NABM_PCMOutBox + (int)NABMBOFF_DescriptorEntries,
|
||||
|
||||
/**
|
||||
* @brief Status of transferring Data
|
||||
* @note Length: word
|
||||
*/
|
||||
PCMOUT_Status = (int)NABM_PCMOutBox + (int)NABMBOFF_Status,
|
||||
|
||||
/**
|
||||
* @brief Number of transferred Samples in Actual Processed Entry
|
||||
* @note Length: word
|
||||
*/
|
||||
PCMOUT_TransferredSamples = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferredSamples,
|
||||
|
||||
/**
|
||||
* @brief Number of next processed Buffer Entry
|
||||
* @note Length: byte
|
||||
*/
|
||||
PCMOUT_NextProcessedBufferEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_NextProcessedBufferEntry,
|
||||
|
||||
/**
|
||||
* @brief Transfer Control
|
||||
* @note Length: byte
|
||||
*/
|
||||
PCMOUT_TransferControl = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferControl,
|
||||
};
|
||||
|
||||
enum TransferControlRegisters
|
||||
{
|
||||
/**
|
||||
* @brief DMA controller control
|
||||
*
|
||||
* 0 = Pause transfer
|
||||
* 1 = Transfer sound data
|
||||
*/
|
||||
TC_DMAControllerControl = 0x01,
|
||||
|
||||
/**
|
||||
* @brief Reset
|
||||
*
|
||||
* 0 = Remove reset condition
|
||||
* 1 = Reset this NABM register box, this bit is cleared by card when is reset complete
|
||||
*/
|
||||
TC_TransferReset = 0x02,
|
||||
|
||||
/**
|
||||
* @brief Last Buffer Entry Interrupt enable
|
||||
*
|
||||
* 0 = Disable interrupt
|
||||
* 1 = Enable interrupt
|
||||
*/
|
||||
TC_LastBufferEntryInterruptEnable = 0x04,
|
||||
|
||||
/**
|
||||
* @brief IOC Interrupt enable
|
||||
*
|
||||
* 0 = Disable interrupt
|
||||
* 1 = Enable interrupt
|
||||
*/
|
||||
TC_IOCInterruptEnable = 0x08,
|
||||
|
||||
/**
|
||||
* @brief Fifo ERROR Interrupt enable
|
||||
*
|
||||
* 0 = Disable interrupt
|
||||
* 1 = Enable interrupt
|
||||
*/
|
||||
TC_FifoERRORInterruptEnable = 0x10,
|
||||
};
|
||||
|
||||
enum GlobalControlRegisters
|
||||
{
|
||||
/**
|
||||
* @brief Global Interrupt Enable
|
||||
*
|
||||
* 0 = Disable Interrupts
|
||||
* 1 = Enable Interrupts
|
||||
*/
|
||||
GC_GlobalInterruptEnable = 0x01,
|
||||
|
||||
/**
|
||||
* @brief Cold reset
|
||||
*
|
||||
* 0 = Device is in reset and can not be used
|
||||
* 1 = Resume to operational state
|
||||
*/
|
||||
GC_ColdReset = 0x02,
|
||||
|
||||
/**
|
||||
* @brief Warm reset
|
||||
*/
|
||||
GC_WarmReset = 0x04,
|
||||
|
||||
/**
|
||||
* @brief Shut down
|
||||
*
|
||||
* 0 = Device is powered
|
||||
* 1 = Shut down
|
||||
*/
|
||||
GC_ShutDown = 0x08,
|
||||
|
||||
/**
|
||||
* @brief Channels for PCM Output
|
||||
*
|
||||
* 00 = 2 channels
|
||||
* 01 = 4 channels
|
||||
* 10 = 6 channels
|
||||
* 11 = Reserved
|
||||
*/
|
||||
GC_ChannelsForPCMOutput = 0x30,
|
||||
|
||||
/**
|
||||
* @brief PCM Output mode
|
||||
*
|
||||
* 00 = 16 bit samples
|
||||
* 01 = 20 bit samples
|
||||
*/
|
||||
GC_PCMOutputMode = 0xC0,
|
||||
};
|
||||
|
||||
struct BufferDescriptorList
|
||||
{
|
||||
/**
|
||||
* @brief Physical Address to sound data in memory
|
||||
* @note Length: dword
|
||||
*/
|
||||
uint32_t Address;
|
||||
|
||||
/**
|
||||
* @brief Number of samples in this buffer
|
||||
* @note Length: word
|
||||
*/
|
||||
uint16_t SampleCount;
|
||||
|
||||
/**
|
||||
* @brief Flags
|
||||
* @note Length: word
|
||||
*
|
||||
* Bit 15 = Interrupt fired when data from this entry is transferred
|
||||
* Bit 14 = Last entry of buffer, stop playing
|
||||
* Other bits = Reserved
|
||||
*/
|
||||
uint16_t Flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
uint16_t MixerVolume(uint8_t Left, uint8_t Right, bool Mute)
|
||||
{
|
||||
return ((uint16_t)((Right & 0x3F) |
|
||||
((Left & 0x3F) << 0x8) |
|
||||
(Mute & 1 << 0xF)));
|
||||
}
|
||||
|
||||
class AC97Device
|
||||
{
|
||||
private:
|
||||
PCIHeader0 *Header;
|
||||
BufferDescriptorList *DescriptorList = nullptr;
|
||||
|
||||
uint16_t MixerAddress;
|
||||
uint16_t BusMasterAddress;
|
||||
|
||||
AudioEncodingValues Encoding = AE_PCMs16le;
|
||||
char Channels = 2;
|
||||
uint8_t Volume = AV_Maximum;
|
||||
bool Mute = false;
|
||||
int SampleRate = 48000;
|
||||
char SampleSize = 2;
|
||||
|
||||
public:
|
||||
size_t write(uint8_t *Buffer, size_t Size)
|
||||
{
|
||||
if (Buffer == nullptr)
|
||||
{
|
||||
KernelLog("Invalid buffer.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((Size == 0) || (Size % (SampleSize * Channels)))
|
||||
{
|
||||
KernelLog("Invalid buffer length.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int TotalBDLToFill = (int)((Size + PAGE_SIZE - 1) >> 12);
|
||||
|
||||
while (Size > 0)
|
||||
{
|
||||
bool ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
|
||||
|
||||
if (ActiveDMA)
|
||||
{
|
||||
int RemainingBDL = 0;
|
||||
|
||||
do
|
||||
{
|
||||
int CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
|
||||
int LastBDL = inb(BusMasterAddress + PCMOUT_DescriptorEntries);
|
||||
|
||||
RemainingBDL = LastBDL - CurrentBDL;
|
||||
if (RemainingBDL < 0)
|
||||
RemainingBDL += DescriptorListLength;
|
||||
|
||||
RemainingBDL += 1;
|
||||
|
||||
if (RemainingBDL >= DescriptorListLength - 1)
|
||||
{
|
||||
long SampleCount = DescriptorList[(CurrentBDL + 1) % DescriptorListLength].SampleCount / Channels;
|
||||
if (SampleCount > 0)
|
||||
Sleep(SampleCount * 1000 / SampleRate);
|
||||
}
|
||||
|
||||
} while (RemainingBDL >= DescriptorListLength - 1 &&
|
||||
!(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl));
|
||||
}
|
||||
|
||||
uint8_t CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
|
||||
uint8_t LastBDL = inb(BusMasterAddress + PCMOUT_DescriptorEntries);
|
||||
uint8_t NextBDL = LastBDL % DescriptorListLength;
|
||||
|
||||
ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
|
||||
if (ActiveDMA)
|
||||
{
|
||||
NextBDL = (uint8_t)((LastBDL + 1) % DescriptorListLength);
|
||||
if (NextBDL == CurrentBDL)
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
size_t Wrote = (PAGE_SIZE > Size) ? size_t(Size)
|
||||
: size_t(PAGE_SIZE);
|
||||
|
||||
if (Wrote == 0)
|
||||
{
|
||||
KernelLog("Wrote 0 bytes.");
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy((void *)((uint64_t)DescriptorList[NextBDL].Address), Buffer, Wrote);
|
||||
DescriptorList[NextBDL].Flags = 0;
|
||||
|
||||
Buffer += Wrote;
|
||||
Size -= (unsigned int)Wrote;
|
||||
|
||||
DescriptorList[NextBDL].SampleCount = uint16_t(Wrote / SampleSize);
|
||||
TotalBDLToFill--;
|
||||
NextBDL = (uint8_t)((NextBDL + 1) % DescriptorListLength);
|
||||
} while (TotalBDLToFill-- && NextBDL != CurrentBDL);
|
||||
|
||||
outb(BusMasterAddress + PCMOUT_DescriptorEntries, NextBDL - 1);
|
||||
|
||||
ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
|
||||
if (!ActiveDMA)
|
||||
{
|
||||
// Start DMA
|
||||
outb(BusMasterAddress + PCMOUT_TransferControl,
|
||||
inb(BusMasterAddress + PCMOUT_TransferControl) | TC_DMAControllerControl);
|
||||
}
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
int ioctl(AudioIoctl, void *)
|
||||
{
|
||||
// if (Data->AudioCallback.Adjust._Volume)
|
||||
// {
|
||||
// Volume = (uint8_t)(0x3F - (0x3F * Data->AudioCallback.Adjust.Volume / 100));
|
||||
// outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
|
||||
// // outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute));
|
||||
// }
|
||||
// else if (Data->AudioCallback.Adjust._Encoding)
|
||||
// {
|
||||
// fixme("Encoding changing not supported yet.");
|
||||
// }
|
||||
// else if (Data->AudioCallback.Adjust._SampleRate)
|
||||
// {
|
||||
// switch (Data->AudioCallback.Adjust.SampleRate)
|
||||
// {
|
||||
// case 0:
|
||||
// {
|
||||
// SampleRate = 8000;
|
||||
// break;
|
||||
// }
|
||||
// case 1:
|
||||
// {
|
||||
// SampleRate = 11025;
|
||||
// break;
|
||||
// }
|
||||
// case 2:
|
||||
// {
|
||||
// SampleRate = 16000;
|
||||
// break;
|
||||
// }
|
||||
// case 3:
|
||||
// {
|
||||
// SampleRate = 22050;
|
||||
// break;
|
||||
// }
|
||||
// case 4:
|
||||
// {
|
||||
// SampleRate = 32000;
|
||||
// break;
|
||||
// }
|
||||
// case 5:
|
||||
// {
|
||||
// SampleRate = 44100;
|
||||
// break;
|
||||
// }
|
||||
// case 6:
|
||||
// {
|
||||
// SampleRate = 48000;
|
||||
// break;
|
||||
// }
|
||||
// case 7:
|
||||
// {
|
||||
// SampleRate = 88200;
|
||||
// break;
|
||||
// }
|
||||
// case 8:
|
||||
// {
|
||||
// SampleRate = 96000;
|
||||
// break;
|
||||
// }
|
||||
// default:
|
||||
// {
|
||||
// SampleRate = 16000;
|
||||
// error("Invalid sample rate. Defaulting to 16000.");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if (Data->AudioCallback.Adjust._Channels)
|
||||
// {
|
||||
// switch (Data->AudioCallback.Adjust.Channels)
|
||||
// {
|
||||
// case 0:
|
||||
// {
|
||||
// Channels = 1; // Mono
|
||||
// break;
|
||||
// }
|
||||
// case 1:
|
||||
// {
|
||||
// Channels = 2; // Stereo
|
||||
// break;
|
||||
// }
|
||||
// default:
|
||||
// {
|
||||
// Channels = 2;
|
||||
// error("Invalid channel count. Defaulting to 2.");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OnInterruptReceived(TrapFrame *)
|
||||
{
|
||||
uint16_t Status = inw(MixerAddress + PCMOUT_Status);
|
||||
if (Status & TC_IOCInterruptEnable)
|
||||
{
|
||||
DebugLog("IOC");
|
||||
outw(MixerAddress + PCMOUT_Status, TC_IOCInterruptEnable);
|
||||
uint16_t CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
|
||||
uint16_t LastBDL = (CurrentBDL + 2) & (DescriptorListLength - 1);
|
||||
outb(BusMasterAddress + PCMOUT_DescriptorEntries, LastBDL);
|
||||
KernelLog("FIXME: CurrentBDL: %d, LastBDL: %d", CurrentBDL, LastBDL);
|
||||
}
|
||||
else if (Status & TC_LastBufferEntryInterruptEnable)
|
||||
{
|
||||
DebugLog("Last buffer entry");
|
||||
// Stop DMA
|
||||
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
|
||||
TransferControl &= ~TC_DMAControllerControl;
|
||||
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
|
||||
|
||||
outw(MixerAddress + PCMOUT_Status, TC_LastBufferEntryInterruptEnable);
|
||||
}
|
||||
else if (Status & TC_FifoERRORInterruptEnable)
|
||||
{
|
||||
KernelLog("FIFO error");
|
||||
outw(MixerAddress + PCMOUT_Status, TC_FifoERRORInterruptEnable);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugLog("Unknown interrupt status %#x", Status);
|
||||
outw(MixerAddress + PCMOUT_Status, 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
void Panic()
|
||||
{
|
||||
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
|
||||
TransferControl &= ~(TC_LastBufferEntryInterruptEnable |
|
||||
TC_IOCInterruptEnable |
|
||||
TC_FifoERRORInterruptEnable);
|
||||
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
|
||||
|
||||
uint32_t GlobalControl = inl((uint16_t)(BusMasterAddress + NABM_GlobalControl));
|
||||
GlobalControl &= ~GC_GlobalInterruptEnable;
|
||||
GlobalControl |= GC_ShutDown;
|
||||
outl((uint16_t)(BusMasterAddress + NABM_GlobalControl), GlobalControl);
|
||||
}
|
||||
|
||||
AC97Device(PCIHeader0 *_Header)
|
||||
: Header(_Header)
|
||||
{
|
||||
/* Native Audio Mixer Base Address */
|
||||
uint32_t PCIBAR0 = Header->BAR0;
|
||||
|
||||
/* Native Audio Bus Master Base Address */
|
||||
uint32_t PCIBAR1 = Header->BAR1;
|
||||
|
||||
// uint8_t Type = PCIBAR0 & 1;
|
||||
MixerAddress = (uint16_t)(PCIBAR0 & (~3));
|
||||
BusMasterAddress = PCIBAR1 & (~15);
|
||||
|
||||
uint16_t OutputPCMTransferControl = BusMasterAddress + PCMOUT_TransferControl;
|
||||
|
||||
/* DescriptorList address MUST be physical. */
|
||||
DescriptorList = (BufferDescriptorList *)AllocateMemory(TO_PAGES(sizeof(BufferDescriptorList) * DescriptorListLength));
|
||||
memset(DescriptorList, 0, sizeof(BufferDescriptorList) * DescriptorListLength);
|
||||
|
||||
uint16_t DLSampleCount = (uint16_t)(PAGE_SIZE / SampleSize);
|
||||
for (int i = 0; i < DescriptorListLength; i++)
|
||||
{
|
||||
DescriptorList[i].Address = (uint32_t)(uintptr_t)AllocateMemory(TO_PAGES(sizeof(uint16_t *)));
|
||||
DescriptorList[i].SampleCount = DLSampleCount;
|
||||
DescriptorList[i].Flags = 0;
|
||||
DebugLog("DescriptorList[%d] = { Address: %#lx, SampleCount: %d, Flags: %#lx }",
|
||||
i,
|
||||
DescriptorList[i].Address,
|
||||
DescriptorList[i].SampleCount,
|
||||
DescriptorList[i].Flags);
|
||||
}
|
||||
|
||||
outw(MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
|
||||
outw(MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute));
|
||||
|
||||
Volume = 0x3F - (0x3F * /* VOL 50% */ 50 / 100);
|
||||
outw(MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
|
||||
|
||||
outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) | TC_TransferReset);
|
||||
while (inb(OutputPCMTransferControl) & TC_TransferReset)
|
||||
;
|
||||
|
||||
uint32_t GlobalControl = inl(BusMasterAddress + NABM_GlobalControl);
|
||||
GlobalControl = (GlobalControl & ~((0x3U) << 0x16)); /* PCM 16-bit mode */
|
||||
GlobalControl = (GlobalControl & ~((0x3U) << 20)); /* 2 channels */
|
||||
GlobalControl |= GC_GlobalInterruptEnable;
|
||||
GlobalControl &= ~GC_ShutDown;
|
||||
|
||||
outl(BusMasterAddress + PCMOUT_BufferDescriptorList,
|
||||
(uint32_t)(uint64_t)DescriptorList);
|
||||
|
||||
outl(BusMasterAddress + NABM_GlobalControl, GlobalControl);
|
||||
|
||||
uint8_t TransferControl = inb(OutputPCMTransferControl);
|
||||
TransferControl |= TC_IOCInterruptEnable |
|
||||
TC_FifoERRORInterruptEnable;
|
||||
outb(OutputPCMTransferControl, TransferControl);
|
||||
|
||||
// Stop DMA
|
||||
outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) & ~TC_DMAControllerControl);
|
||||
}
|
||||
|
||||
~AC97Device()
|
||||
{
|
||||
outw(MixerAddress + NAM_MasterVolume, MixerVolume(AV_Maximum, AV_Maximum, true));
|
||||
outw(MixerAddress + NAM_PCMOutVolume, MixerVolume(AV_Maximum, AV_Maximum, true));
|
||||
|
||||
// Stop DMA
|
||||
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl),
|
||||
inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl)) & ~TC_DMAControllerControl);
|
||||
|
||||
// Disable interrupts
|
||||
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
|
||||
|
||||
TransferControl &= ~(TC_LastBufferEntryInterruptEnable |
|
||||
TC_IOCInterruptEnable |
|
||||
TC_FifoERRORInterruptEnable);
|
||||
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
|
||||
|
||||
// Disable global control
|
||||
uint32_t GlobalControl = inl((uint16_t)(BusMasterAddress + NABM_GlobalControl));
|
||||
GlobalControl &= ~GC_GlobalInterruptEnable;
|
||||
GlobalControl |= GC_ShutDown;
|
||||
outl((uint16_t)(BusMasterAddress + NABM_GlobalControl), GlobalControl);
|
||||
}
|
||||
};
|
||||
|
||||
AC97Device *Drivers[4] = {nullptr};
|
||||
dev_t AudioID[4] = {(dev_t)-1};
|
||||
|
||||
#define OIR(x) OIR_##x
|
||||
#define CREATE_OIR(x) \
|
||||
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
|
||||
|
||||
CREATE_OIR(0);
|
||||
CREATE_OIR(1);
|
||||
CREATE_OIR(2);
|
||||
CREATE_OIR(3);
|
||||
|
||||
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
|
||||
int __fs_Close(struct Inode *) { return 0; }
|
||||
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
|
||||
|
||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
||||
{
|
||||
return Drivers[AudioID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
return Drivers[AudioID[Node->GetMinor()]]->ioctl((AudioIoctl)Request, Argp);
|
||||
}
|
||||
|
||||
const struct InodeOperations AudioOps = {
|
||||
.Lookup = nullptr,
|
||||
.Create = nullptr,
|
||||
.Remove = nullptr,
|
||||
.Rename = nullptr,
|
||||
.Read = __fs_Read,
|
||||
.Write = __fs_Write,
|
||||
.Truncate = nullptr,
|
||||
.Open = __fs_Open,
|
||||
.Close = __fs_Close,
|
||||
.Ioctl = __fs_Ioctl,
|
||||
.ReadDir = nullptr,
|
||||
.MkDir = nullptr,
|
||||
.RmDir = nullptr,
|
||||
.SymLink = nullptr,
|
||||
.ReadLink = nullptr,
|
||||
.Seek = nullptr,
|
||||
.Stat = nullptr,
|
||||
};
|
||||
|
||||
PCIArray *Devices;
|
||||
EXTERNC int cxx_Panic()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
short Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Drivers[Count] != nullptr)
|
||||
Drivers[Count]->Panic();
|
||||
Count++;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Probe()
|
||||
{
|
||||
uint16_t VendorIDs[] = {0x8086, PCI_END};
|
||||
uint16_t DeviceIDs[] = {0x2415, PCI_END};
|
||||
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
|
||||
if (Devices == nullptr)
|
||||
{
|
||||
KernelLog("No AC'97 device found.");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
PCIArray *ctx = Devices;
|
||||
bool Found = false;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count++ > sizeof(Drivers) / sizeof(AC97Device *))
|
||||
break;
|
||||
|
||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
||||
uint8_t Type = PCIBAR0 & 1;
|
||||
if (Type != 1)
|
||||
{
|
||||
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
|
||||
PCIBaseAddress->Header.VendorID,
|
||||
PCIBaseAddress->Header.DeviceID,
|
||||
PCIBaseAddress->Header.ProgIF);
|
||||
continue;
|
||||
}
|
||||
|
||||
Found = true;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
{
|
||||
KernelLog("No valid AC'97 device found.");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Initialize()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count > sizeof(Drivers) / sizeof(AC97Device *))
|
||||
break;
|
||||
|
||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
||||
uint8_t Type = PCIBAR0 & 1;
|
||||
if (Type != 1)
|
||||
{
|
||||
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
|
||||
PCIBaseAddress->Header.VendorID,
|
||||
PCIBaseAddress->Header.DeviceID,
|
||||
PCIBaseAddress->Header.ProgIF);
|
||||
continue;
|
||||
}
|
||||
|
||||
InitializePCI(ctx->Device);
|
||||
|
||||
Drivers[Count] = new AC97Device((PCIHeader0 *)ctx->Device->Header);
|
||||
/* FIXME: bad code */
|
||||
switch (Count)
|
||||
{
|
||||
case 0:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
|
||||
break;
|
||||
case 1:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
|
||||
break;
|
||||
case 2:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
|
||||
break;
|
||||
case 3:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
dev_t ret = RegisterDevice(AUDIO_TYPE_PCM, &AudioOps);
|
||||
AudioID[Count] = ret;
|
||||
Count++;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Finalize()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count++ > sizeof(Drivers) / sizeof(AC97Device *))
|
||||
break;
|
||||
|
||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
||||
uint8_t Type = PCIBAR0 & 1;
|
||||
if (Type != 1)
|
||||
{
|
||||
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
|
||||
PCIBaseAddress->Header.VendorID,
|
||||
PCIBaseAddress->Header.DeviceID,
|
||||
PCIBaseAddress->Header.ProgIF);
|
||||
continue;
|
||||
}
|
||||
|
||||
delete Drivers[Count++];
|
||||
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(AudioID) / sizeof(dev_t); i++)
|
||||
{
|
||||
if (AudioID[i] != (dev_t)-1)
|
||||
UnregisterDevice(AudioID[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
EXTERNC int cxx_Panic();
|
||||
EXTERNC int cxx_Probe();
|
||||
EXTERNC int cxx_Initialize();
|
||||
EXTERNC int cxx_Finalize();
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <base.h>
|
||||
|
||||
#include "ac97.hpp"
|
||||
|
||||
int DriverEntry() { return cxx_Initialize(); }
|
||||
int DriverFinal() { return cxx_Finalize(); }
|
||||
int DriverPanic() { return cxx_Panic(); }
|
||||
int DriverProbe() { return cxx_Probe(); }
|
||||
|
||||
DriverInfo("ac97",
|
||||
"Audio Codec '97 Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
@ -1,263 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <audio.h>
|
||||
#include <regs.h>
|
||||
#include <base.h>
|
||||
#include <pci.h>
|
||||
#include <io.h>
|
||||
#include <fs.h>
|
||||
|
||||
#include "hda.hpp"
|
||||
|
||||
class HDADevice
|
||||
{
|
||||
private:
|
||||
PCIHeader0 *Header;
|
||||
bool Initialized = false;
|
||||
|
||||
ControllerRegisters *CTL;
|
||||
|
||||
uint32_t *CORB;
|
||||
uint64_t *RIRB;
|
||||
|
||||
public:
|
||||
bool IsInitialized() { return Initialized; }
|
||||
|
||||
size_t write(uint8_t *, size_t Size)
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
int ioctl(AudioIoctl, void *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OnInterruptReceived(TrapFrame *)
|
||||
{
|
||||
}
|
||||
|
||||
void Panic()
|
||||
{
|
||||
}
|
||||
|
||||
HDADevice(PCIHeader0 *_Header)
|
||||
: Header(_Header),
|
||||
CORB((uint32_t *)(uintptr_t)AllocateMemory(1)),
|
||||
RIRB((uint64_t *)AllocateMemory(1))
|
||||
{
|
||||
CTL = (ControllerRegisters *)(uintptr_t)Header->BAR0;
|
||||
KernelLog("Unimplemented HDA driver");
|
||||
return;
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
~HDADevice()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
HDADevice *Drivers[4] = {nullptr};
|
||||
dev_t AudioID[4] = {(dev_t)-1};
|
||||
|
||||
#define OIR(x) OIR_##x
|
||||
#define CREATE_OIR(x) \
|
||||
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
|
||||
|
||||
CREATE_OIR(0);
|
||||
CREATE_OIR(1);
|
||||
CREATE_OIR(2);
|
||||
CREATE_OIR(3);
|
||||
|
||||
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
|
||||
int __fs_Close(struct Inode *) { return 0; }
|
||||
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
|
||||
|
||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
||||
{
|
||||
return Drivers[AudioID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
return Drivers[AudioID[Node->GetMinor()]]->ioctl((AudioIoctl)Request, Argp);
|
||||
}
|
||||
|
||||
const struct InodeOperations AudioOps = {
|
||||
.Lookup = nullptr,
|
||||
.Create = nullptr,
|
||||
.Remove = nullptr,
|
||||
.Rename = nullptr,
|
||||
.Read = __fs_Read,
|
||||
.Write = __fs_Write,
|
||||
.Truncate = nullptr,
|
||||
.Open = __fs_Open,
|
||||
.Close = __fs_Close,
|
||||
.Ioctl = __fs_Ioctl,
|
||||
.ReadDir = nullptr,
|
||||
.MkDir = nullptr,
|
||||
.RmDir = nullptr,
|
||||
.SymLink = nullptr,
|
||||
.ReadLink = nullptr,
|
||||
.Seek = nullptr,
|
||||
.Stat = nullptr,
|
||||
};
|
||||
|
||||
PCIArray *Devices;
|
||||
EXTERNC int cxx_Panic()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
short Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Drivers[Count] != nullptr)
|
||||
Drivers[Count]->Panic();
|
||||
Count++;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Probe()
|
||||
{
|
||||
uint16_t VendorIDs[] = {0x8086, /* Intel */
|
||||
0x15AD, /* VMware */
|
||||
PCI_END};
|
||||
uint16_t DeviceIDs[] = {0x9D71 /* Sunrise Point-LP HD Audio */,
|
||||
0x2668 /* ICH6 */,
|
||||
0x293E /* ICH9 */,
|
||||
PCI_END};
|
||||
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
|
||||
if (Devices == nullptr)
|
||||
{
|
||||
KernelLog("No HDA device found.");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
PCIArray *ctx = Devices;
|
||||
bool Found = false;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count++ > sizeof(Drivers) / sizeof(HDADevice *))
|
||||
break;
|
||||
|
||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
||||
uint8_t Type = PCIBAR0 & 1;
|
||||
if (Type == 1)
|
||||
{
|
||||
KernelLog("Device %x:%x.%d BAR0 is I/O.",
|
||||
PCIBaseAddress->Header.VendorID,
|
||||
PCIBaseAddress->Header.DeviceID,
|
||||
PCIBaseAddress->Header.ProgIF);
|
||||
continue;
|
||||
}
|
||||
|
||||
Found = true;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
{
|
||||
KernelLog("No valid HDA device found.");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Initialize()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count > sizeof(Drivers) / sizeof(HDADevice *))
|
||||
break;
|
||||
|
||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
||||
uint8_t Type = PCIBAR0 & 1;
|
||||
if (Type == 1)
|
||||
{
|
||||
KernelLog("Device %x:%x.%d BAR0 is I/O.",
|
||||
PCIBaseAddress->Header.VendorID,
|
||||
PCIBaseAddress->Header.DeviceID,
|
||||
PCIBaseAddress->Header.ProgIF);
|
||||
continue;
|
||||
}
|
||||
|
||||
InitializePCI(ctx->Device);
|
||||
|
||||
Drivers[Count] = new HDADevice((PCIHeader0 *)ctx->Device->Header);
|
||||
|
||||
if (Drivers[Count]->IsInitialized())
|
||||
{
|
||||
dev_t ret = RegisterDevice(AUDIO_TYPE_PCM, &AudioOps);
|
||||
AudioID[Count] = ret;
|
||||
Count++;
|
||||
}
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
KernelLog("No valid HDA device found.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Finalize()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count++ > sizeof(Drivers) / sizeof(HDADevice *))
|
||||
break;
|
||||
|
||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
||||
uint8_t Type = PCIBAR0 & 1;
|
||||
if (Type == 1)
|
||||
{
|
||||
KernelLog("Device %x:%x.%d BAR0 is I/O.",
|
||||
PCIBaseAddress->Header.VendorID,
|
||||
PCIBaseAddress->Header.DeviceID,
|
||||
PCIBaseAddress->Header.ProgIF);
|
||||
continue;
|
||||
}
|
||||
|
||||
delete Drivers[Count++];
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(AudioID) / sizeof(dev_t); i++)
|
||||
{
|
||||
if (AudioID[i] != (dev_t)-1)
|
||||
UnregisterDevice(AudioID[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,635 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct StreamDescriptor
|
||||
{
|
||||
/** Control */
|
||||
uint32_t CTL : 24;
|
||||
|
||||
/** Status */
|
||||
uint8_t STS;
|
||||
|
||||
/** Link Position in Current Buffer */
|
||||
uint32_t LPIB;
|
||||
|
||||
/** Cyclic Buffer Length */
|
||||
uint32_t CBL;
|
||||
|
||||
/** Last Valid Index */
|
||||
uint16_t LVI;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd0[2];
|
||||
|
||||
/** FIFO Size */
|
||||
uint16_t FIFOD;
|
||||
|
||||
/** Format */
|
||||
uint16_t FMT;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd1[4];
|
||||
|
||||
/** Buffer Descriptor List Pointer - Lower */
|
||||
uint32_t BDPL;
|
||||
|
||||
/** Buffer Descriptor List Pointer - Upper */
|
||||
uint32_t BDPU;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ControllerRegisters
|
||||
{
|
||||
uint16_t GCAP;
|
||||
uint8_t VMIN;
|
||||
uint8_t VMJ;
|
||||
uint16_t OUTPAY;
|
||||
uint16_t INPAY;
|
||||
uint32_t GCTL;
|
||||
uint16_t WAKEEN;
|
||||
uint16_t WAKESTS;
|
||||
uint16_t GSTS;
|
||||
uint8_t Rsvd0[6];
|
||||
uint16_t OUTSTRMPAY;
|
||||
uint16_t INSTRMPAY;
|
||||
uint8_t Rsvd1[4];
|
||||
uint32_t INTCTL;
|
||||
uint32_t INTSTS;
|
||||
uint8_t Rsvd2[8];
|
||||
uint32_t WALCLK;
|
||||
uint8_t Rsvd3[4];
|
||||
uint32_t SSYNC;
|
||||
uint8_t Rsvd4[4];
|
||||
uint32_t CORBLBASE;
|
||||
uint32_t CORBUBASE;
|
||||
uint16_t CORBWP;
|
||||
uint16_t CORBRP;
|
||||
uint8_t CORBCTL;
|
||||
uint8_t CORBSTS;
|
||||
uint8_t CORBSIZE;
|
||||
uint8_t Rsvd5;
|
||||
uint32_t RIRBLBASE;
|
||||
uint32_t RIRBUBASE;
|
||||
uint16_t RIRBWP;
|
||||
uint16_t RINTCNT;
|
||||
uint8_t RIRBCTL;
|
||||
uint8_t RIRBSTS;
|
||||
uint8_t RIRBSIZE;
|
||||
uint8_t Rsvd6;
|
||||
uint32_t ICOI;
|
||||
uint32_t ICII;
|
||||
uint16_t ICIS;
|
||||
uint8_t Rsvd7[6];
|
||||
uint32_t DPIBLBASE;
|
||||
uint32_t DPIBUBASE;
|
||||
uint8_t Rsvd8[8];
|
||||
StreamDescriptor SD[];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Not working as expected */
|
||||
struct __ControllerRegisters
|
||||
{
|
||||
/** Global Capabilities */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** 64 Bit Address Supported
|
||||
*
|
||||
* 0 = 32-bit addressing
|
||||
* 1 = 64-bit addressing
|
||||
*/
|
||||
uint16_t _64OK : 1;
|
||||
|
||||
/** Number of Serial Data Out Signals
|
||||
*
|
||||
* 00 = 1 SDO
|
||||
* 01 = 2 SDOs
|
||||
* 10 = 4 SDOs
|
||||
* 11 = Reserved
|
||||
*/
|
||||
uint16_t NSDO : 2;
|
||||
|
||||
/** Number of Bidirectional Streams Supported
|
||||
*
|
||||
* 00000b = No bidirectional streams supported
|
||||
* 00001b = 1 bidirectional stream supported
|
||||
* ...
|
||||
* 11110b = 30 bidirectional streams supported
|
||||
*/
|
||||
uint16_t BSS : 5;
|
||||
|
||||
/** Number of Input Streams Supported
|
||||
*
|
||||
* 0000b = No input streams supported
|
||||
* 0001b = 1 input stream supported
|
||||
* ...
|
||||
* 1111b = 15 input streams supported
|
||||
*/
|
||||
uint16_t ISS : 4;
|
||||
|
||||
/** Number of Output Streams Supported
|
||||
*
|
||||
* 0000b = No output streams supported
|
||||
* 0001b = 1 output stream supported
|
||||
* ...
|
||||
* 1111b = 15 output streams supported
|
||||
*/
|
||||
uint16_t OSS : 4;
|
||||
} __attribute__((packed));
|
||||
uint16_t Raw;
|
||||
} GCAP;
|
||||
|
||||
/** Minor Version */
|
||||
uint8_t VMIN;
|
||||
|
||||
/** Major Version */
|
||||
uint8_t VMJ;
|
||||
|
||||
/** Output Payload Capability
|
||||
*
|
||||
* 00h = 0 Words
|
||||
* 01h = 1 Word payload
|
||||
* ...
|
||||
* FFh = 255h Word payload
|
||||
*/
|
||||
uint16_t OUTPAY;
|
||||
|
||||
/** Input Payload Capability
|
||||
*
|
||||
* 00h = 0 Words
|
||||
* 01h = 1 Word payload
|
||||
* ...
|
||||
* FFh = 255h Word payload
|
||||
*/
|
||||
uint16_t INPAY;
|
||||
|
||||
/** Global Control */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Controller Reset
|
||||
*
|
||||
* 0 = Reset
|
||||
* 1 = Normal Operation
|
||||
*/
|
||||
uint32_t CRST : 1;
|
||||
|
||||
/** Flush Control
|
||||
*
|
||||
* 0 = Idle
|
||||
* 1 = Flush
|
||||
*/
|
||||
uint32_t FCNTRL : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint32_t RsvdP0 : 6;
|
||||
|
||||
/** Accept Unsolicited Response Enable
|
||||
*
|
||||
* 0 = Disabled
|
||||
* 1 = Enabled
|
||||
*/
|
||||
uint32_t UNSOL : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint32_t RsvdP1 : 23;
|
||||
} __attribute__((packed));
|
||||
uint32_t Raw;
|
||||
} GCTL;
|
||||
|
||||
/** Wake Enable */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** SDIN Wake Enable Flags */
|
||||
uint16_t SDIWEN : 15;
|
||||
|
||||
/** Reserved */
|
||||
uint16_t RsvdP0 : 1;
|
||||
} __attribute__((packed));
|
||||
uint16_t Raw;
|
||||
} WAKEEN;
|
||||
|
||||
/** Wake Status */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** SDIN State Change Status Flags */
|
||||
uint16_t SDIWAKE : 15;
|
||||
|
||||
/** Reserved */
|
||||
uint16_t RsvdZ0 : 1;
|
||||
} __attribute__((packed));
|
||||
uint16_t Raw;
|
||||
} WAKESTS;
|
||||
|
||||
/** Global Status */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t RsvdZ0 : 1;
|
||||
uint16_t FSTS : 1;
|
||||
uint16_t RsvdZ1 : 14;
|
||||
} __attribute__((packed));
|
||||
uint16_t Raw;
|
||||
} GSTS;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd0[6];
|
||||
|
||||
/** Output Stream Payload Capability */
|
||||
uint16_t OUTSTRMPAY;
|
||||
|
||||
/** Input Stream Payload Capability */
|
||||
uint16_t INSTRMPAY;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd1[4];
|
||||
|
||||
/** Interrupt Control */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Stream Interrupt Enable
|
||||
*
|
||||
* Bit 0 = Input Stream 0
|
||||
* Bit 1 = Input Stream 1
|
||||
* Bit 2 = Output Stream 0
|
||||
* Bit 3 = Output Stream 1
|
||||
* Bit 4 = Output Stream 2
|
||||
* Bit 5 = Bidirectional Stream 0
|
||||
* Bits 6-28 = Reserved
|
||||
*/
|
||||
uint32_t SIE : 30;
|
||||
|
||||
/** Controller Interrupt Enable */
|
||||
uint32_t CIE : 1;
|
||||
|
||||
/** Global Interrupt Enable */
|
||||
uint32_t GIE : 1;
|
||||
} __attribute__((packed));
|
||||
uint32_t Raw;
|
||||
} INTCTL;
|
||||
|
||||
/** Interrupt Status */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Stream Interrupt Status */
|
||||
uint32_t SIS : 30;
|
||||
|
||||
/** Controller Interrupt Status */
|
||||
uint32_t CIS : 1;
|
||||
|
||||
/** Global Interrupt Status */
|
||||
uint32_t GIS : 1;
|
||||
} __attribute__((packed));
|
||||
uint32_t Raw;
|
||||
} INTSTS;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd2[8];
|
||||
|
||||
/** Wall Clock Counter */
|
||||
uint32_t WALCLK;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd3[4];
|
||||
|
||||
/** Stream Synchronization */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Stream Synchronization Bits */
|
||||
uint32_t SSYNC : 30;
|
||||
|
||||
/** Reserved */
|
||||
uint32_t RsvdP0 : 2;
|
||||
} __attribute__((packed));
|
||||
uint32_t Raw;
|
||||
} SSYNC;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd4[4];
|
||||
|
||||
/** CORB Lower Base Address */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** CORB Lower Base Unimplemented Bits */
|
||||
uint32_t Unimplemented : 7;
|
||||
|
||||
/** CORB Lower Base Address */
|
||||
uint32_t CORBLBASE : 25;
|
||||
} __attribute__((packed));
|
||||
uint32_t Raw;
|
||||
} CORBLBASE;
|
||||
|
||||
/** CORB Upper Base Address */
|
||||
uint32_t CORBUBASE;
|
||||
|
||||
/** CORB Write Pointer */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** CORB Write Pointer */
|
||||
uint16_t CORBWP : 8;
|
||||
|
||||
/** Reserved */
|
||||
uint16_t RsvdP0 : 8;
|
||||
} __attribute__((packed));
|
||||
uint16_t Raw;
|
||||
} CORBWP;
|
||||
|
||||
/** CORB Read Pointer */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** CORB Read Pointer */
|
||||
uint16_t CORBRP : 8;
|
||||
|
||||
/** Reserved */
|
||||
uint16_t RsvdP0 : 7;
|
||||
|
||||
/** CORB Read Pointer Reset */
|
||||
uint16_t CORBRPRST : 1;
|
||||
} __attribute__((packed));
|
||||
uint16_t Raw;
|
||||
} CORBRP;
|
||||
|
||||
/** CORB Control */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** CORB Memory Error Interrupt Enable */
|
||||
uint8_t CMEIE : 1;
|
||||
|
||||
/** Enable CORB DMA Engine
|
||||
*
|
||||
* 0 = DMA Stop
|
||||
* 1 = DMA Run
|
||||
*
|
||||
* @note Must read the value back.
|
||||
*/
|
||||
uint8_t CORBRUN : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t RsvdP0 : 6;
|
||||
} __attribute__((packed));
|
||||
uint8_t Raw;
|
||||
} CORBCTL;
|
||||
|
||||
/** CORB Status */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** CORB Memory Error Indication */
|
||||
uint8_t CMEI : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t RsvdZ0 : 7;
|
||||
} __attribute__((packed));
|
||||
uint8_t Raw;
|
||||
} CORBSTS;
|
||||
|
||||
/** CORB Size */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** CORB Size
|
||||
*
|
||||
* 00b = 2 entries
|
||||
* 01b = 16 entries
|
||||
* 10b = 256 entries
|
||||
* 11b = Reserved
|
||||
*/
|
||||
uint8_t CORBSIZE : 2;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t RsvdP0 : 2;
|
||||
|
||||
/** CORB Size Capability
|
||||
*
|
||||
* 0001b = 2 entries
|
||||
* 0010b = 16 entries
|
||||
* 0100b = 256 entries
|
||||
* 1000b = Reserved
|
||||
*/
|
||||
uint8_t CORBSZCAP : 4;
|
||||
} __attribute__((packed));
|
||||
uint8_t Raw;
|
||||
} CORBSIZE;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd5;
|
||||
|
||||
/** RIRB Lower Base Address */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** RIRB Lower Base Unimplemented Bits */
|
||||
uint32_t Unimplemented : 7;
|
||||
|
||||
/** RIRB Lower Base Address */
|
||||
uint32_t RIRBLBASE : 25;
|
||||
} __attribute__((packed));
|
||||
uint32_t Raw;
|
||||
} RIRBLBASE;
|
||||
|
||||
/** RIRB Upper Base Address */
|
||||
uint32_t RIRBUBASE;
|
||||
|
||||
/** RIRB Write Pointer */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** RIRB Write Pointer */
|
||||
uint16_t RIRBWP : 8;
|
||||
|
||||
/** Reserved */
|
||||
uint16_t RsvdP0 : 7;
|
||||
|
||||
/** RIRB Write Pointer Reset */
|
||||
uint16_t RIRBWPRST : 1;
|
||||
} __attribute__((packed));
|
||||
uint16_t Raw;
|
||||
} RIRBWP;
|
||||
|
||||
/** Response Interrupt Count */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** N Response Interrupt Count
|
||||
*
|
||||
* 00000001b = 1 Response sent to RIRB
|
||||
* ...
|
||||
* 11111111b = 255 Responses sent to RIRB
|
||||
* 00000000b = 256 Response sent to RIRB
|
||||
*/
|
||||
uint16_t RINTCNT : 8;
|
||||
|
||||
/** Reserved */
|
||||
uint16_t RsvdP0 : 8;
|
||||
} __attribute__((packed));
|
||||
uint16_t Raw;
|
||||
} RINTCNT;
|
||||
|
||||
/** RIRB Control */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Response Interrupt Control
|
||||
*
|
||||
* 0 = Disable Interrupt
|
||||
* 1 = Generate an interrupt after N responses are sent to the RIRB
|
||||
*/
|
||||
uint8_t RINTCTL : 1;
|
||||
|
||||
/** RIRB DMA Enable
|
||||
*
|
||||
* 0 = DMA Stop
|
||||
* 1 = DMA Run
|
||||
*/
|
||||
uint8_t RIRBDMAEN : 1;
|
||||
|
||||
/** Response Overrun Interrupt Control */
|
||||
uint8_t RIRBOIC : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t RsvdP0 : 5;
|
||||
} __attribute__((packed));
|
||||
uint8_t Raw;
|
||||
} RIRBCTL;
|
||||
|
||||
/** RIRB Status */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Response Interrupt */
|
||||
uint8_t RINTFL : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t RsvdZ0 : 1;
|
||||
|
||||
/** Response Overrun Interrupt Status */
|
||||
uint8_t RIRBOIS : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t RsvdZ1 : 5;
|
||||
} __attribute__((packed));
|
||||
uint8_t Raw;
|
||||
} RIRBSTS;
|
||||
|
||||
/** RIRB Size */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** RIRB Size
|
||||
*
|
||||
* 00b = 2 entries
|
||||
* 01b = 16 entries
|
||||
* 10b = 256 entries
|
||||
* 11b = Reserved
|
||||
*/
|
||||
uint8_t RIRBSIZE : 2;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t RsvdP0 : 2;
|
||||
|
||||
/** RIRB Size Capability
|
||||
*
|
||||
* 0001b = 2 entries
|
||||
* 0010b = 16 entries
|
||||
* 0100b = 256 entries
|
||||
* 1000b = Reserved
|
||||
*/
|
||||
uint8_t RIRBSZCAP : 4;
|
||||
} __attribute__((packed));
|
||||
uint8_t Raw;
|
||||
} RIRBSIZE;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd6;
|
||||
|
||||
/** Immediate Command Output Interface */
|
||||
uint32_t ICOI;
|
||||
|
||||
/** Immediate Command Input Interface */
|
||||
uint32_t ICII;
|
||||
|
||||
/** Immediate Command Status */
|
||||
uint16_t ICIS;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd7[6];
|
||||
|
||||
/** DMA Position Buffer Lower Base */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** DMA Position Buffer Enable */
|
||||
uint32_t DPBEN : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint32_t RsvdZ0 : 6;
|
||||
|
||||
/** DMA Position Lower Base Address */
|
||||
uint32_t DPLBASE : 25;
|
||||
} __attribute__((packed));
|
||||
uint32_t Raw;
|
||||
} DPIBLBASE;
|
||||
|
||||
/** DMA Position Buffer Upper Base */
|
||||
uint32_t DPIBUBASE;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t Rsvd8[8];
|
||||
|
||||
StreamDescriptor SD[];
|
||||
} __attribute__((packed));
|
||||
#endif
|
||||
|
||||
EXTERNC int cxx_Panic();
|
||||
EXTERNC int cxx_Probe();
|
||||
EXTERNC int cxx_Initialize();
|
||||
EXTERNC int cxx_Finalize();
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <base.h>
|
||||
|
||||
#include "hda.hpp"
|
||||
|
||||
int DriverEntry() { return cxx_Initialize(); }
|
||||
int DriverFinal() { return cxx_Finalize(); }
|
||||
int DriverPanic() { return cxx_Panic(); }
|
||||
int DriverProbe() { return cxx_Probe(); }
|
||||
|
||||
DriverInfo("hda",
|
||||
"Intel High Definition Audio Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
@ -1,290 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_DRIVER_FAT_H__
|
||||
#define __FENNIX_DRIVER_FAT_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/* Source: https://wiki.osdev.org/FAT */
|
||||
|
||||
struct BIOSParameterBlock
|
||||
{
|
||||
/** The first three bytes EB 3C 90 disassemble to JMP SHORT 3C NOP.
|
||||
* (The 3C value may be different.) The reason for this is to jump
|
||||
* over the disk format information (the BPB and EBPB). Since the
|
||||
* first sector of the disk is loaded into ram at location
|
||||
* 0x0000:0x7c00 and executed, without this jump, the processor
|
||||
* would attempt to execute data that isn't code. Even for
|
||||
* non-bootable volumes, code matching this pattern (or using the
|
||||
* E9 jump opcode) is required to be present by both Windows and
|
||||
* OS X. To fulfil this requirement, an infinite loop can be placed
|
||||
* here with the bytes EB FE 90. */
|
||||
uint8_t JumpBoot[3];
|
||||
|
||||
/** OEM identifier. The first 8 Bytes (3 - 10) is the version of DOS
|
||||
* being used. The next eight Bytes 29 3A 63 7E 2D 49 48 and 43 read
|
||||
* out the name of the version. The official FAT Specification from
|
||||
* Microsoft says that this field is really meaningless and is ignored
|
||||
* by MS FAT Modules, however it does recommend the value "MSWIN4.1"
|
||||
* as some 3rd party drivers supposedly check it and expect it to
|
||||
* have that value. Older versions of dos also report MSDOS5.1,
|
||||
* linux-formatted floppy will likely to carry "mkdosfs" here, and
|
||||
* FreeDOS formatted disks have been observed to have "FRDOS5.1" here.
|
||||
* If the string is less than 8 bytes, it is padded with spaces. */
|
||||
uint8_t OEM[8];
|
||||
|
||||
/** The number of Bytes per sector (remember, all numbers are in the
|
||||
* little-endian format). */
|
||||
uint16_t BytesPerSector;
|
||||
|
||||
/** Number of sectors per cluster. */
|
||||
uint8_t SectorsPerCluster;
|
||||
|
||||
/** Number of reserved sectors. The boot record sectors are included
|
||||
* in this value. */
|
||||
uint16_t ReservedSectors;
|
||||
|
||||
/** Number of File Allocation Tables (FAT's) on the storage media.
|
||||
* Often this value is 2. */
|
||||
uint8_t NumberOfFATs;
|
||||
|
||||
/** Number of root directory entries (must be set so that the root
|
||||
* directory occupies entire sectors). */
|
||||
uint16_t RootDirectoryEntries;
|
||||
|
||||
/** The total sectors in the logical volume. If this value is 0, it
|
||||
* means there are more than 65535 sectors in the volume, and the
|
||||
* actual count is stored in the Large Sector Count entry at 0x20. */
|
||||
uint16_t Sectors16;
|
||||
|
||||
/** This Byte indicates the media descriptor type. */
|
||||
uint8_t Media;
|
||||
|
||||
/** Number of sectors per FAT. FAT12/FAT16 only. */
|
||||
uint16_t SectorsPerFAT;
|
||||
|
||||
/** Number of sectors per track. */
|
||||
uint16_t SectorsPerTrack;
|
||||
|
||||
/** Number of heads or sides on the storage media. */
|
||||
uint16_t NumberOfHeads;
|
||||
|
||||
/** Number of hidden sectors. (i.e. the LBA of the beginning of
|
||||
* the partition). */
|
||||
uint32_t HiddenSectors;
|
||||
|
||||
/** Large sector count. This field is set if there are more than
|
||||
* 65535 sectors in the volume, resulting in a value which does not
|
||||
* fit in the Number of Sectors entry at 0x13. */
|
||||
uint32_t Sectors32;
|
||||
} __packed;
|
||||
|
||||
struct ExtendedBootRecord_FAT12_16
|
||||
{
|
||||
/** Drive number. The value here should be identical to the value
|
||||
* returned by BIOS interrupt 0x13, or passed in the DL register;
|
||||
* i.e. 0x00 for a floppy disk and 0x80 for hard disks. This number
|
||||
* is useless because the media is likely to be moved to another
|
||||
* machine and inserted in a drive with a different drive number. */
|
||||
uint8_t DriveNumber;
|
||||
|
||||
/** Flags in Windows NT. Reserved otherwise. */
|
||||
uint8_t Flags;
|
||||
|
||||
/** Signature (must be 0x28 or 0x29). */
|
||||
uint8_t Signature;
|
||||
|
||||
/** VolumeID 'Serial' number. Used for tracking volumes between
|
||||
* computers. You can ignore this if you want. */
|
||||
uint32_t VolumeID;
|
||||
|
||||
/** Volume label string. This field is padded with spaces. */
|
||||
uint8_t VolumeLabel[11];
|
||||
|
||||
/** System identifier string. This field is a string representation
|
||||
* of the FAT file system type. It is padded with spaces. The spec
|
||||
* says never to trust the contents of this string for any use. */
|
||||
uint8_t SystemIdentifier[8];
|
||||
|
||||
/** Boot code. */
|
||||
uint8_t BootCode[448];
|
||||
|
||||
/** Bootable partition signature 0xAA55. */
|
||||
uint16_t BootSignature;
|
||||
} __packed;
|
||||
|
||||
struct ExtendedBootRecord_FAT32
|
||||
{
|
||||
/** Sectors per FAT. The size of the FAT in sectors. */
|
||||
uint32_t SectorsPerFAT;
|
||||
|
||||
/** Flags. */
|
||||
uint16_t Flags;
|
||||
|
||||
/** FAT version number. The high byte is the major version and the
|
||||
* low byte is the minor version. FAT drivers should respect this
|
||||
* field. */
|
||||
uint16_t FATVersion;
|
||||
|
||||
/** The cluster number of the root directory. Often this field is
|
||||
* set to 2. */
|
||||
uint32_t RootDirectoryCluster;
|
||||
|
||||
/** The sector number of the FSInfo structure. */
|
||||
uint16_t FSInfoSector;
|
||||
|
||||
/** The sector number of the backup boot sector. */
|
||||
uint16_t BackupBootSector;
|
||||
|
||||
/** Reserved. When the volume is formated these bytes should be zero. */
|
||||
uint8_t Reserved[12];
|
||||
|
||||
/** Drive number. The values here are identical to the values returned
|
||||
* by the BIOS interrupt 0x13. 0x00 for a floppy disk and 0x80 for
|
||||
* hard disks. */
|
||||
uint8_t DriveNumber;
|
||||
|
||||
/** Flags in Windows NT. Reserved otherwise. */
|
||||
uint8_t Flags2;
|
||||
|
||||
/** Signature (must be 0x28 or 0x29). */
|
||||
uint8_t Signature;
|
||||
|
||||
/** Volume ID 'Serial' number. Used for tracking volumes between
|
||||
* computers. You can ignore this if you want. */
|
||||
uint32_t VolumeID;
|
||||
|
||||
/** Volume label string. This field is padded with spaces. */
|
||||
uint8_t VolumeLabel[11];
|
||||
|
||||
/** System identifier string. Always "FAT32 ". The spec says never
|
||||
* to trust the contents of this string for any use. */
|
||||
uint8_t SystemIdentifier[8];
|
||||
|
||||
/** Boot code. */
|
||||
uint8_t BootCode[420];
|
||||
|
||||
/** Bootable partition signature 0xAA55. */
|
||||
uint16_t BootSignature;
|
||||
} __packed;
|
||||
|
||||
struct FSInfo
|
||||
{
|
||||
/** Lead signature (must be 0x41615252 to indicate a valid FSInfo
|
||||
* structure). */
|
||||
uint32_t LeadSignature;
|
||||
|
||||
/** Reserved, these bytes should never be used. */
|
||||
uint8_t Reserved1[480];
|
||||
|
||||
/** Another signature (must be 0x61417272). */
|
||||
uint32_t AnotherSignature;
|
||||
|
||||
/** Contains the last known free cluster count on the volume. If the
|
||||
* value is 0xFFFFFFFF, then the free count is unknown and must be
|
||||
* computed. However, this value might be incorrect and should at
|
||||
* least be range checked (<= volume cluster count). */
|
||||
uint32_t FreeClusterCount;
|
||||
|
||||
/** Indicates the cluster number at which the filesystem driver should
|
||||
* start looking for available clusters. If the value is 0xFFFFFFFF,
|
||||
* then there is no hint and the driver should start searching at 2.
|
||||
* Typically this value is set to the last allocated cluster number.
|
||||
* As the previous field, this value should be range checked. */
|
||||
uint32_t NextFreeCluster;
|
||||
|
||||
/** Reserved. */
|
||||
uint8_t Reserved2[12];
|
||||
|
||||
/** Trail signature (0xAA550000). */
|
||||
uint32_t TrailSignature;
|
||||
} __packed;
|
||||
|
||||
struct exFATBootRecord
|
||||
{
|
||||
/** The first three bytes EB 3C 90 disassemble to JMP SHORT 3C NOP.
|
||||
* (The 3C value may be different.) The reason for this is to jump
|
||||
* over the disk format information (the BPB and EBPB). Since the
|
||||
* first sector of the disk is loaded into ram at location
|
||||
* 0x0000:0x7c00 and executed, without this jump, the processor
|
||||
* would attempt to execute data that isn't code. Even for
|
||||
* non-bootable volumes, code matching this pattern (or using the
|
||||
* E9 jump opcode) is required to be present by both Windows and
|
||||
* OS X. To fulfil this requirement, an infinite loop can be placed
|
||||
* here with the bytes EB FE 90. */
|
||||
uint8_t JumpBoot[3];
|
||||
|
||||
/** OEM identifier. This contains the string "EXFAT ". Not to be
|
||||
* used for filesystem determination, but it's a nice hint. */
|
||||
uint8_t OEM[8];
|
||||
|
||||
/** Set to zero. This makes sure any FAT driver will not be able to
|
||||
* load it. */
|
||||
uint8_t Reserved1[53];
|
||||
|
||||
/** Partition offset. No idea why the partition itself would have
|
||||
* this, but it's here. Might be wrong. Probably best to just ignore. */
|
||||
uint64_t PartitionOffset;
|
||||
|
||||
/** Volume length. */
|
||||
uint64_t VolumeLength;
|
||||
|
||||
/** FAT offset (in sectors) from start of partition. */
|
||||
uint32_t FATOffset;
|
||||
|
||||
/** FAT length (in sectors). */
|
||||
uint32_t FATLength;
|
||||
|
||||
/** Cluster heap offset (in sectors). */
|
||||
uint32_t ClusterHeapOffset;
|
||||
|
||||
/** Cluster count. */
|
||||
uint32_t ClusterCount;
|
||||
|
||||
/** Root directory cluster. Typically 4 (but just read this value). */
|
||||
uint32_t RootDirectoryCluster;
|
||||
|
||||
/** Serial number of partition. */
|
||||
uint32_t SerialNumber;
|
||||
|
||||
/** Filesystem revision. */
|
||||
uint16_t FilesystemRevision;
|
||||
|
||||
/** Flags. */
|
||||
uint16_t Flags;
|
||||
|
||||
/** Sector shift. */
|
||||
uint8_t SectorShift;
|
||||
|
||||
/** Cluster shift. */
|
||||
uint8_t ClusterShift;
|
||||
|
||||
/** Number of FATs. */
|
||||
uint8_t NumberOfFATs;
|
||||
|
||||
/** Drive select. */
|
||||
uint8_t DriveSelect;
|
||||
|
||||
/** Percentage in use. */
|
||||
uint8_t PercentageInUse;
|
||||
|
||||
/** Reserved (set to 0). */
|
||||
uint8_t Reserved2[7];
|
||||
} __packed;
|
||||
|
||||
#endif // !__FENNIX_DRIVER_FAT_H__
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <base.h>
|
||||
|
||||
int DriverEntry()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverFinal()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverPanic()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverProbe()
|
||||
{
|
||||
/* Nothing to do */
|
||||
return 0;
|
||||
}
|
||||
|
||||
DriverInfo("fat",
|
||||
"File Allocation Table Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
@ -103,6 +103,7 @@ typedef union
|
||||
uint8_t Raw;
|
||||
} PS2_OUTPUT_PORT;
|
||||
|
||||
#ifndef __kernel__
|
||||
void PIC_EOI(uint8_t IRQ);
|
||||
void IRQ_MASK(uint8_t IRQ);
|
||||
void IRQ_UNMASK(uint8_t IRQ);
|
||||
@ -114,11 +115,11 @@ uint8_t PS2ReadStatus();
|
||||
uint8_t PS2ReadAfterACK();
|
||||
void PS2ClearOutputBuffer();
|
||||
int PS2ACKTimeout();
|
||||
#endif // !__kernel__
|
||||
|
||||
#define WaitOutput PS2Wait(DriverID, true)
|
||||
#define WaitInput PS2Wait(DriverID, false)
|
||||
|
||||
|
||||
#define PS2_KBD_CMD_SET_LEDS 0xED
|
||||
#define PS2_KBD_CMD_ECHO 0xEE
|
||||
#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0
|
||||
@ -189,7 +190,6 @@ typedef union
|
||||
uint8_t Raw;
|
||||
} PS2_KBD_TYPEMATIC;
|
||||
|
||||
|
||||
#define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6
|
||||
#define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7
|
||||
#define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8
|
||||
|
@ -69,7 +69,10 @@ typedef enum
|
||||
BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128,
|
||||
} DeviceType;
|
||||
|
||||
#ifndef __kernel__
|
||||
EXTERNC dev_t CreateDeviceFile(const char *name, mode_t mode, const struct InodeOperations *Operations);
|
||||
EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations);
|
||||
EXTERNC int UnregisterDevice(dev_t Device);
|
||||
#endif // !__kernel__
|
||||
|
||||
#endif // !__FENNIX_API_DEVICE_H__
|
||||
|
@ -377,7 +377,9 @@ struct FileSystemInfo
|
||||
void *PrivateData;
|
||||
} __attribute__((packed));
|
||||
|
||||
#ifndef __kernel__
|
||||
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
||||
int UnregisterFileSystem(dev_t Device);
|
||||
#endif // !__kernel__
|
||||
|
||||
#endif // !__FENNIX_API_FILESYSTEM_H__
|
||||
|
@ -239,6 +239,8 @@ typedef struct
|
||||
};
|
||||
} InputReport;
|
||||
|
||||
#ifndef __kernel__
|
||||
EXTERNC int ReportInputEvent(InputReport *Report);
|
||||
#endif // !__kernel__
|
||||
|
||||
#endif // !__FENNIX_API_INPUT_H__
|
||||
|
@ -171,11 +171,13 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef __kernel__
|
||||
PCIArray *GetPCIDevices(uint16_t Vendors[], uint16_t Devices[]);
|
||||
void InitializePCI(PCIDevice *Device);
|
||||
uint32_t GetBAR(uint8_t Index, PCIDevice *Device);
|
||||
uint8_t iLine(PCIDevice *Device);
|
||||
uint8_t iPin(PCIDevice *Device);
|
||||
#endif // !__kernel__
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_DRIVER_AIP_H__
|
||||
#define __FENNIX_DRIVER_AIP_H__
|
||||
|
||||
#include <types.h>
|
||||
#include <aip.h>
|
||||
#include <regs.h>
|
||||
|
||||
extern uint8_t Device1ID[];
|
||||
extern uint8_t Device2ID[];
|
||||
|
||||
void PS2KbdInterruptHandler(TrapFrame *);
|
||||
int InitializeKeyboard();
|
||||
int FinalizeKeyboard();
|
||||
int DetectPS2Keyboard();
|
||||
|
||||
void PS2MouseInterruptHandler(TrapFrame *);
|
||||
int InitializeMouse();
|
||||
int FinalizeMouse();
|
||||
int DetectPS2Mouse();
|
||||
int DetectUART();
|
||||
|
||||
#endif // !__FENNIX_DRIVER_AIP_H__
|
@ -1,335 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "aip.h"
|
||||
|
||||
#include <driver.h>
|
||||
#include <errno.h>
|
||||
#include <fs.h>
|
||||
#include <input.h>
|
||||
#include <base.h>
|
||||
#include <io.h>
|
||||
|
||||
uint8_t KeyboardScanCodeSet = 0;
|
||||
dev_t KeyboardDevID = -1;
|
||||
|
||||
const unsigned short ScanCodeSet1[] =
|
||||
{KEY_NULL, KEY_ESCAPE,
|
||||
KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
|
||||
KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_TAB,
|
||||
KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P,
|
||||
KEY_LEFT_BRACKET, KEY_RIGHT_BRACKET, KEY_RETURN, KEY_LEFT_CTRL,
|
||||
KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L,
|
||||
KEY_SEMICOLON, KEY_APOSTROPHE, KEY_BACK_TICK, KEY_LEFT_SHIFT, KEY_BACKSLASH,
|
||||
KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M,
|
||||
KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_RIGHT_SHIFT,
|
||||
KEYPAD_ASTERISK, KEY_LEFT_ALT, KEY_SPACE, KEY_CAPS_LOCK,
|
||||
KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,
|
||||
KEY_NUM_LOCK, KEY_SCROLL_LOCK,
|
||||
KEYPAD_7, KEYPAD_8, KEYPAD_9, KEYPAD_MINUS,
|
||||
KEYPAD_4, KEYPAD_5, KEYPAD_6, KEYPAD_PLUS,
|
||||
KEYPAD_1, KEYPAD_2, KEYPAD_3, KEYPAD_0, KEYPAD_PERIOD,
|
||||
KEY_NULL, KEY_NULL, KEY_NULL,
|
||||
KEY_F11, KEY_F12};
|
||||
|
||||
const unsigned short ScanCodeSet1mm[] = {
|
||||
[0x10] = KEY_MULTIMEDIA_PREV_TRACK,
|
||||
[0x19] = KEY_MULTIMEDIA_NEXT_TRACK,
|
||||
[0x1C] = KEYPAD_RETURN,
|
||||
[0x1D] = KEY_RIGHT_CTRL,
|
||||
[0x20] = KEY_MULTIMEDIA_MUTE,
|
||||
[0x21] = KEY_MULTIMEDIA_CALCULATOR,
|
||||
[0x22] = KEY_MULTIMEDIA_PLAY,
|
||||
[0x24] = KEY_MULTIMEDIA_STOP,
|
||||
[0x2A] = KEY_PRINT_SCREEN,
|
||||
[0x2E] = KEY_MULTIMEDIA_VOL_DOWN,
|
||||
[0x30] = KEY_MULTIMEDIA_VOL_UP,
|
||||
[0x32] = KEY_MULTIMEDIA_WWW_HOME,
|
||||
[0x35] = KEYPAD_SLASH,
|
||||
[0x37] = KEY_PRINT_SCREEN,
|
||||
[0x38] = KEY_RIGHT_ALT,
|
||||
[0x47] = KEY_HOME,
|
||||
[0x48] = KEY_UP_ARROW,
|
||||
[0x49] = KEY_PAGE_UP,
|
||||
[0x4B] = KEY_LEFT_ARROW,
|
||||
[0x4D] = KEY_RIGHT_ARROW,
|
||||
[0x4F] = KEY_END,
|
||||
[0x50] = KEY_DOWN_ARROW,
|
||||
[0x51] = KEY_PAGE_DOWN,
|
||||
[0x52] = KEY_INSERT,
|
||||
[0x53] = KEY_DELETE,
|
||||
[0x5B] = KEY_LEFT_GUI,
|
||||
[0x5C] = KEY_RIGHT_GUI,
|
||||
[0x5D] = KEY_APPS,
|
||||
[0x5E] = KEY_ACPI_POWER,
|
||||
[0x5F] = KEY_ACPI_SLEEP,
|
||||
[0x63] = KEY_ACPI_WAKE,
|
||||
[0x65] = KEY_MULTIMEDIA_WWW_SEARCH,
|
||||
[0x66] = KEY_MULTIMEDIA_WWW_FAVORITES,
|
||||
[0x67] = KEY_MULTIMEDIA_WWW_REFRESH,
|
||||
[0x68] = KEY_MULTIMEDIA_WWW_STOP,
|
||||
[0x69] = KEY_MULTIMEDIA_WWW_FORWARD,
|
||||
[0x6A] = KEY_MULTIMEDIA_WWW_BACK,
|
||||
[0x6B] = KEY_MULTIMEDIA_MY_COMPUTER,
|
||||
[0x6C] = KEY_MULTIMEDIA_EMAIL,
|
||||
[0x6D] = KEY_MULTIMEDIA_MEDIA_SELECT,
|
||||
|
||||
/* RELEASED */
|
||||
|
||||
[0x90] = KEY_MULTIMEDIA_PREV_TRACK,
|
||||
[0x99] = KEY_MULTIMEDIA_NEXT_TRACK,
|
||||
[0x9C] = KEYPAD_RETURN,
|
||||
[0x9D] = KEY_RIGHT_CTRL,
|
||||
[0xA0] = KEY_MULTIMEDIA_MUTE,
|
||||
[0xA1] = KEY_MULTIMEDIA_CALCULATOR,
|
||||
[0xA2] = KEY_MULTIMEDIA_PLAY,
|
||||
[0xA4] = KEY_MULTIMEDIA_STOP,
|
||||
[0xAA] = KEY_PRINT_SCREEN,
|
||||
[0xAE] = KEY_MULTIMEDIA_VOL_DOWN,
|
||||
[0xB0] = KEY_MULTIMEDIA_VOL_UP,
|
||||
[0xB2] = KEY_MULTIMEDIA_WWW_HOME,
|
||||
[0xB5] = KEYPAD_SLASH,
|
||||
[0xB7] = KEY_PRINT_SCREEN,
|
||||
[0xB8] = KEY_RIGHT_ALT,
|
||||
[0xC7] = KEY_HOME,
|
||||
[0xC8] = KEY_UP_ARROW,
|
||||
[0xC9] = KEY_PAGE_UP,
|
||||
[0xCB] = KEY_LEFT_ARROW,
|
||||
[0xCD] = KEY_RIGHT_ARROW,
|
||||
[0xCF] = KEY_END,
|
||||
[0xD0] = KEY_DOWN_ARROW,
|
||||
[0xD1] = KEY_PAGE_DOWN,
|
||||
[0xD2] = KEY_INSERT,
|
||||
[0xD3] = KEY_DELETE,
|
||||
[0xDB] = KEY_LEFT_GUI,
|
||||
[0xDC] = KEY_RIGHT_GUI,
|
||||
[0xDD] = KEY_APPS,
|
||||
[0xDE] = KEY_ACPI_POWER,
|
||||
[0xDF] = KEY_ACPI_SLEEP,
|
||||
[0xE3] = KEY_ACPI_WAKE,
|
||||
[0xE5] = KEY_MULTIMEDIA_WWW_SEARCH,
|
||||
[0xE6] = KEY_MULTIMEDIA_WWW_FAVORITES,
|
||||
[0xE7] = KEY_MULTIMEDIA_WWW_REFRESH,
|
||||
[0xE8] = KEY_MULTIMEDIA_WWW_STOP,
|
||||
[0xE9] = KEY_MULTIMEDIA_WWW_FORWARD,
|
||||
[0xEA] = KEY_MULTIMEDIA_WWW_BACK,
|
||||
[0xEB] = KEY_MULTIMEDIA_MY_COMPUTER,
|
||||
[0xEC] = KEY_MULTIMEDIA_EMAIL,
|
||||
[0xED] = KEY_MULTIMEDIA_MEDIA_SELECT};
|
||||
|
||||
const unsigned short ScanCodeSet3[] = {
|
||||
[0x15] = KEY_Q,
|
||||
[0x1A] = KEY_Z,
|
||||
[0x1B] = KEY_S,
|
||||
[0x1C] = KEY_A,
|
||||
[0x1D] = KEY_W,
|
||||
|
||||
[0x21] = KEY_C,
|
||||
[0x22] = KEY_X,
|
||||
[0x23] = KEY_D,
|
||||
[0x24] = KEY_E,
|
||||
[0x2A] = KEY_V,
|
||||
[0x2B] = KEY_F,
|
||||
[0x2C] = KEY_T,
|
||||
[0x2D] = KEY_R,
|
||||
|
||||
[0x31] = KEY_N,
|
||||
[0x32] = KEY_B,
|
||||
[0x33] = KEY_H,
|
||||
[0x34] = KEY_G,
|
||||
[0x35] = KEY_Y,
|
||||
[0x3A] = KEY_M,
|
||||
[0x3B] = KEY_J,
|
||||
[0x3C] = KEY_U,
|
||||
|
||||
[0x42] = KEY_K,
|
||||
[0x43] = KEY_I,
|
||||
[0x44] = KEY_O,
|
||||
[0x4B] = KEY_L,
|
||||
[0x4D] = KEY_P};
|
||||
|
||||
InputReport kir = {0};
|
||||
int ReportKeyboardEvent(dev_t Device, KeyScanCodes ScanCode, uint8_t Pressed)
|
||||
{
|
||||
kir.Type = INPUT_TYPE_KEYBOARD;
|
||||
kir.Device = Device;
|
||||
kir.Keyboard.Key = ScanCode;
|
||||
kir.Keyboard.Key |= Pressed ? KEY_PRESSED : 0;
|
||||
ReportInputEvent(&kir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IsE0 = false;
|
||||
bool IsE1 = false;
|
||||
void PS2KbdInterruptHandler(TrapFrame *)
|
||||
{
|
||||
uint8_t sc = inb(PS2_DATA);
|
||||
if (sc == PS2_KBD_RESP_ACK ||
|
||||
sc == PS2_KBD_RESP_ECHO ||
|
||||
sc == PS2_KBD_RESP_RESEND)
|
||||
return;
|
||||
|
||||
if (sc == 0xE0)
|
||||
{
|
||||
IsE0 = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc == 0xE1)
|
||||
{
|
||||
IsE1 = true;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (KeyboardScanCodeSet)
|
||||
{
|
||||
case PS2_KBD_SC_SET_1:
|
||||
case PS2_KBD_SC_SET_2:
|
||||
{
|
||||
if (IsE0)
|
||||
{
|
||||
IsE0 = false;
|
||||
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet1mm[sc], sc < 0x90);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool released = sc & 0x80;
|
||||
uint8_t scFinal = released ? sc & 0x7F : sc;
|
||||
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet1[scFinal], !released);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* FIXME: https://wiki.osdev.org/PS/2_Keyboard */
|
||||
// case PS2_KBD_SC_SET_2:
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
case PS2_KBD_SC_SET_3:
|
||||
{
|
||||
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet3[sc], true);
|
||||
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet3[sc], false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (IsE0)
|
||||
IsE0 = false;
|
||||
KernelLog("Unknown PS/2 Keyboard Scan Code Set: %#x", KeyboardScanCodeSet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __fs_kb_Ioctl(struct Inode *, unsigned long, void *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct InodeOperations KbdOps = {
|
||||
.Ioctl = __fs_kb_Ioctl,
|
||||
};
|
||||
|
||||
int InitializeKeyboard()
|
||||
{
|
||||
// PS2WriteData(PS2_KBD_CMD_RESET);
|
||||
// uint8_t test = PS2ReadData();
|
||||
// if (test != PS2_KBD_RESP_TEST_PASSED &&
|
||||
// test != PS2_KBD_RESP_ACK)
|
||||
// {
|
||||
// KernelLog("PS/2 keyboard reset failed (%#x)", test);
|
||||
// return -EFAULT;
|
||||
// }
|
||||
|
||||
PS2WriteData(PS2_KBD_CMD_DEFAULTS);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 keyboard failed to set defaults");
|
||||
|
||||
PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 keyboard failed to set scan code set");
|
||||
|
||||
/* We want Scan Code Set 1 */
|
||||
PS2WriteData(PS2_KBD_SCAN_CODE_SET_2); /* It will set to 1 but with translation? */
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 keyboard failed to set scan code set 2");
|
||||
|
||||
PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 keyboard failed to set scan code set");
|
||||
|
||||
PS2WriteData(PS2_KBD_SCAN_CODE_GET_CURRENT);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 keyboard failed to get current scan code set");
|
||||
|
||||
KeyboardScanCodeSet = PS2ReadAfterACK();
|
||||
KernelLog("PS/2 Keyboard Scan Code Set: 0x%X", KeyboardScanCodeSet);
|
||||
PS2ClearOutputBuffer();
|
||||
|
||||
PS2WriteData(PS2_KBD_CMD_ENABLE_SCANNING);
|
||||
|
||||
RegisterInterruptHandler(1, PS2KbdInterruptHandler);
|
||||
|
||||
KeyboardDevID = RegisterDevice(INPUT_TYPE_KEYBOARD, &KbdOps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FinalizeKeyboard()
|
||||
{
|
||||
PS2WriteData(PS2_KBD_CMD_DISABLE_SCANNING);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 keyboard failed to disable scanning");
|
||||
|
||||
UnregisterDevice(KeyboardDevID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DetectPS2Keyboard()
|
||||
{
|
||||
PS2WriteData(PS2_KBD_CMD_DISABLE_SCANNING);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 keyboard failed to disable scanning");
|
||||
|
||||
PS2WriteData(PS2_KBD_CMD_IDENTIFY);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 keyboard failed to identify");
|
||||
|
||||
uint8_t recByte;
|
||||
int timeout = 1000000;
|
||||
while (timeout--)
|
||||
{
|
||||
recByte = PS2ReadData();
|
||||
if (recByte != PS2_ACK)
|
||||
break;
|
||||
}
|
||||
Device1ID[0] = recByte;
|
||||
|
||||
timeout = 1000000;
|
||||
while (timeout--)
|
||||
{
|
||||
recByte = PS2ReadData();
|
||||
if (recByte != PS2_ACK)
|
||||
break;
|
||||
}
|
||||
if (timeout == 0)
|
||||
KernelLog("PS/2 keyboard second byte timed out");
|
||||
else
|
||||
Device1ID[1] = recByte;
|
||||
|
||||
KernelLog("PS2 Keyboard Device: 0x%X 0x%X", Device1ID[0], Device1ID[1]);
|
||||
return 0;
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "aip.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <base.h>
|
||||
|
||||
bool IsKeyboard(uint8_t ID)
|
||||
{
|
||||
/* Common keyboard IDs */
|
||||
return ID == 0xAB || ID == 0xAC || ID == 0x5D ||
|
||||
ID == 0x2B || ID == 0x47 || ID == 0x60;
|
||||
}
|
||||
|
||||
bool IsMouse(uint8_t ID)
|
||||
{
|
||||
/* Common mouse IDs */
|
||||
return ID == 0x00 || ID == 0x03 || ID == 0x04;
|
||||
}
|
||||
|
||||
const char *GetPS2DeviceName(uint8_t ID, uint8_t SubID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
case 0x00:
|
||||
return "Standard PS/2 Mouse";
|
||||
case 0x03:
|
||||
return "Mouse with scroll wheel";
|
||||
case 0x04:
|
||||
return "Mouse 5 buttons";
|
||||
case 0xAB:
|
||||
{
|
||||
switch (SubID)
|
||||
{
|
||||
case 0x83: /* Normal */
|
||||
case 0x41: /* Translated */
|
||||
case 0xC1: /* Normal + Translated */
|
||||
return "Standard PS/2 Keyboard";
|
||||
case 0x84:
|
||||
case 0x54:
|
||||
return "IBM Thinkpad/Spacesaver Keyboard";
|
||||
case 0x85:
|
||||
return "NCD N-97/122-Key Host Connect(ed) Keyboard";
|
||||
case 0x86:
|
||||
return "122-Key Keyboard";
|
||||
case 0x90:
|
||||
return "Japanese \"G\" Keyboard";
|
||||
case 0x91:
|
||||
return "Japanese \"P\" Keyboard";
|
||||
case 0x92:
|
||||
return "Japanese \"A\" Keyboard";
|
||||
default:
|
||||
return "Unknown PS/2 Keyboard";
|
||||
}
|
||||
}
|
||||
case 0xAC:
|
||||
{
|
||||
switch (SubID)
|
||||
{
|
||||
case 0xA1:
|
||||
return "NCD Sun Keyboard";
|
||||
default:
|
||||
return "Unknown NCD Sun Keyboard";
|
||||
}
|
||||
}
|
||||
case 0x5D:
|
||||
case 0x2B:
|
||||
return "Trust Keyboard";
|
||||
case 0x47:
|
||||
case 0x60:
|
||||
return "NMB SGI Keyboard";
|
||||
default:
|
||||
return "Unknown PS/2 Device";
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Device1ID[2] = {0x00, 0x00};
|
||||
uint8_t Device2ID[2] = {0x00, 0x00};
|
||||
bool DualChannel = false;
|
||||
|
||||
int DriverEntry()
|
||||
{
|
||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
|
||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
|
||||
PS2ClearOutputBuffer();
|
||||
|
||||
PS2WriteCommand(PS2_CMD_READ_CONFIG);
|
||||
PS2_CONFIGURATION cfg = {.Raw = PS2ReadData()};
|
||||
|
||||
DualChannel = cfg.Port2Clock;
|
||||
if (DualChannel)
|
||||
KernelLog("Dual channel PS/2 controller detected");
|
||||
cfg.Port1Interrupt = 1;
|
||||
cfg.Port2Interrupt = 1;
|
||||
cfg.Port1Translation = 1;
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
|
||||
PS2WriteData(cfg.Raw);
|
||||
|
||||
PS2WriteCommand(PS2_CMD_TEST_CONTROLLER);
|
||||
uint8_t test = PS2ReadData();
|
||||
if (test != PS2_TEST_PASSED)
|
||||
{
|
||||
KernelLog("PS/2 controller self test failed (%#x)", test);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
|
||||
PS2WriteData(cfg.Raw);
|
||||
|
||||
// bool port2avail = false;
|
||||
// if (DualChannel)
|
||||
// {
|
||||
// PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
|
||||
// PS2WriteCommand(PS2_CMD_READ_CONFIG);
|
||||
// cfg.Raw = PS2ReadData();
|
||||
// port2avail = cfg.Port2Clock;
|
||||
// PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
|
||||
// }
|
||||
|
||||
PS2WriteCommand(PS2_CMD_TEST_PORT_1);
|
||||
test = PS2ReadData();
|
||||
if (test != 0x00)
|
||||
{
|
||||
KernelLog("PS/2 Port 1 self test failed (%#x)", test);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (DualChannel)
|
||||
{
|
||||
PS2WriteCommand(PS2_CMD_TEST_PORT_2);
|
||||
test = PS2ReadData();
|
||||
if (test != 0x00)
|
||||
{
|
||||
KernelLog("PS/2 Port 2 self test failed (%#x)", test);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
|
||||
if (DualChannel)
|
||||
PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
|
||||
|
||||
int errK = InitializeKeyboard();
|
||||
|
||||
int errM = 0;
|
||||
if (DualChannel)
|
||||
errM = InitializeMouse();
|
||||
|
||||
/** A device may fail, but if the other one works,
|
||||
* we can still use it.
|
||||
*/
|
||||
if (errK != 0 && errM != 0)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverFinal()
|
||||
{
|
||||
FinalizeKeyboard();
|
||||
FinalizeMouse();
|
||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
|
||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverPanic()
|
||||
{
|
||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
|
||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __intStub() {}
|
||||
int DriverProbe()
|
||||
{
|
||||
RegisterInterruptHandler(1, __intStub);
|
||||
RegisterInterruptHandler(12, __intStub);
|
||||
|
||||
int kbd = DetectPS2Keyboard();
|
||||
int mouse = DetectPS2Mouse();
|
||||
int uart = DetectUART();
|
||||
|
||||
UnregisterAllInterruptHandlers(__intStub);
|
||||
|
||||
if (kbd != 0 && mouse != 0 && uart != 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (kbd == 0)
|
||||
{
|
||||
if (!IsKeyboard(Device1ID[0]))
|
||||
{
|
||||
KernelLog("PS/2 Port 1 is not a keyboard");
|
||||
// return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mouse == 0)
|
||||
{
|
||||
if (!IsMouse(Device2ID[0]))
|
||||
{
|
||||
KernelLog("PS/2 Port 2 is not a mouse");
|
||||
// return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
KernelPrint("PS/2 Port 1: %s (0x%X 0x%X)",
|
||||
GetPS2DeviceName(Device1ID[0], Device1ID[1]),
|
||||
Device1ID[0], Device1ID[1]);
|
||||
KernelPrint("PS/2 Port 2: %s (0x%X 0x%X)",
|
||||
GetPS2DeviceName(Device2ID[0], Device2ID[1]),
|
||||
Device2ID[0], Device2ID[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DriverInfo("aip",
|
||||
"Advanced Integrated Peripheral Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
@ -1,244 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "aip.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <base.h>
|
||||
#include <fs.h>
|
||||
#include <input.h>
|
||||
|
||||
dev_t MouseDevID = -1;
|
||||
bool PacketReady = false;
|
||||
bool FourPackets = false;
|
||||
bool MouseButton45 = false;
|
||||
uint8_t Cycle = 0;
|
||||
PS2_MOUSE_PACKET Packet = {0};
|
||||
|
||||
InputReport mir = {0};
|
||||
void PS2MouseInterruptHandler(TrapFrame *)
|
||||
{
|
||||
uint8_t data = PS2ReadData();
|
||||
if (data == PS2_MOUSE_RESP_ACK ||
|
||||
data == PS2_MOUSE_RESP_RESEND)
|
||||
return;
|
||||
|
||||
if (!PacketReady)
|
||||
{
|
||||
switch (Cycle)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if ((data & 0b00001000 /* Always 1 */) == 0)
|
||||
return;
|
||||
|
||||
Packet.Base.Raw = data;
|
||||
Cycle++;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
Packet.XMovement = data;
|
||||
Cycle++;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
Packet.YMovement = data;
|
||||
if (FourPackets)
|
||||
Cycle++;
|
||||
else
|
||||
{
|
||||
Cycle = 0;
|
||||
PacketReady = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
Packet.ZMovement.Raw = data;
|
||||
Cycle = 0;
|
||||
PacketReady = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* https://stackoverflow.com/a/3208376/9352057 */
|
||||
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
|
||||
#define BYTE_TO_BINARY(byte) \
|
||||
((byte) & 0x80 ? '1' : '0'), \
|
||||
((byte) & 0x40 ? '1' : '0'), \
|
||||
((byte) & 0x20 ? '1' : '0'), \
|
||||
((byte) & 0x10 ? '1' : '0'), \
|
||||
((byte) & 0x08 ? '1' : '0'), \
|
||||
((byte) & 0x04 ? '1' : '0'), \
|
||||
((byte) & 0x02 ? '1' : '0'), \
|
||||
((byte) & 0x01 ? '1' : '0')
|
||||
|
||||
DebugLog("PS/2 Mouse Packet: [" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN "] LB:%d RB:%d MB:%d A1:%d XS:%d YS:%d XO:%d YO:%d | X:%03d Y:%03d | Z:%d B4:%d B5:%d A0:%d A0:%d",
|
||||
BYTE_TO_BINARY(Packet.Base.Raw),
|
||||
BYTE_TO_BINARY(Packet.XMovement),
|
||||
BYTE_TO_BINARY(Packet.YMovement),
|
||||
BYTE_TO_BINARY(Packet.ZMovement.Raw),
|
||||
Packet.Base.LeftButton, Packet.Base.RightButton, Packet.Base.MiddleButton,
|
||||
Packet.Base.Always1,
|
||||
Packet.Base.XSign, Packet.Base.YSign,
|
||||
Packet.Base.XOverflow, Packet.Base.YOverflow,
|
||||
Packet.XMovement, Packet.YMovement,
|
||||
Packet.ZMovement.Z, Packet.ZMovement.Button4, Packet.ZMovement.Button5,
|
||||
Packet.ZMovement.Always0, Packet.ZMovement.Always0_2);
|
||||
|
||||
int X, Y;
|
||||
X = Packet.XMovement - (Packet.Base.XSign ? 256 : 0);
|
||||
Y = Packet.YMovement - (Packet.Base.YSign ? 256 : 0);
|
||||
|
||||
if (Packet.Base.XOverflow)
|
||||
X = 0;
|
||||
|
||||
if (Packet.Base.YOverflow)
|
||||
Y = 0;
|
||||
|
||||
mir.Type = INPUT_TYPE_MOUSE;
|
||||
mir.Device = MouseDevID;
|
||||
mir.Mouse.LeftButton = Packet.Base.LeftButton;
|
||||
mir.Mouse.RightButton = Packet.Base.RightButton;
|
||||
mir.Mouse.MiddleButton = Packet.Base.MiddleButton;
|
||||
mir.Mouse.Button4 = Packet.ZMovement.Button4;
|
||||
mir.Mouse.Button5 = Packet.ZMovement.Button5;
|
||||
mir.Mouse.X = X;
|
||||
mir.Mouse.Y = -Y;
|
||||
mir.Mouse.Z = Packet.ZMovement.Z;
|
||||
ReportInputEvent(&mir);
|
||||
PacketReady = false;
|
||||
}
|
||||
|
||||
void MouseSampleRate(uint8_t SampleRate)
|
||||
{
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_SET_SAMPLE_RATE);
|
||||
PS2ReadData();
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(SampleRate);
|
||||
PS2ReadData();
|
||||
}
|
||||
|
||||
int __fs_ms_Ioctl(struct Inode *, unsigned long, void *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct InodeOperations MouseOps = {
|
||||
.Ioctl = __fs_ms_Ioctl,
|
||||
};
|
||||
|
||||
int InitializeMouse()
|
||||
{
|
||||
PS2WriteData(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_RESET);
|
||||
uint8_t test = PS2ReadData();
|
||||
if (test != PS2_MOUSE_RESP_TEST_PASSED &&
|
||||
test != PS2_MOUSE_RESP_ACK)
|
||||
{
|
||||
KernelLog("PS/2 mouse reset failed! (%#x)", test);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
RegisterInterruptHandler(12, PS2MouseInterruptHandler);
|
||||
|
||||
MouseDevID = RegisterDevice(INPUT_TYPE_MOUSE, &MouseOps);
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
|
||||
PS2ReadData();
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
|
||||
|
||||
MouseSampleRate(200);
|
||||
MouseSampleRate(100);
|
||||
MouseSampleRate(80);
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
|
||||
uint8_t Device2ID = PS2ReadData();
|
||||
KernelLog("PS/2 Mouse ID: %#x", Device2ID);
|
||||
|
||||
MouseSampleRate(200);
|
||||
MouseSampleRate(200);
|
||||
MouseSampleRate(80);
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
|
||||
Device2ID = PS2ReadData();
|
||||
KernelLog("PS/2 Mouse ID: %#x", Device2ID);
|
||||
|
||||
if (Device2ID >= 3 && Device2ID <= 4)
|
||||
FourPackets = true;
|
||||
if (Device2ID == 4)
|
||||
MouseButton45 = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FinalizeMouse()
|
||||
{
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||
|
||||
UnregisterDevice(MouseDevID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DetectPS2Mouse()
|
||||
{
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 mouse failed to disable data reporting!");
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
|
||||
if (PS2ACKTimeout() != 0)
|
||||
KernelLog("PS/2 mouse failed to read ID!");
|
||||
|
||||
uint8_t recByte;
|
||||
int timeout = 1000000;
|
||||
while (timeout--)
|
||||
{
|
||||
recByte = PS2ReadData();
|
||||
if (recByte != PS2_ACK)
|
||||
break;
|
||||
}
|
||||
Device2ID[0] = recByte;
|
||||
|
||||
timeout = 1000000;
|
||||
while (timeout--)
|
||||
{
|
||||
recByte = PS2ReadData();
|
||||
if (recByte != PS2_ACK)
|
||||
break;
|
||||
}
|
||||
Device2ID[1] = recByte;
|
||||
|
||||
KernelLog("PS2 Mouse Device: 0x%X 0x%X", Device2ID[0], Device2ID[1]);
|
||||
return 0;
|
||||
}
|
@ -1,646 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "aip.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <base.h>
|
||||
#include <fs.h>
|
||||
#include <input.h>
|
||||
#include <io.h>
|
||||
|
||||
#define SERIAL_ENABLE_DLAB 0x80
|
||||
#define SERIAL_BUFFER_EMPTY 0x20
|
||||
|
||||
enum Ports
|
||||
{
|
||||
COM1 = 0x3F8,
|
||||
COM2 = 0x2F8,
|
||||
COM3 = 0x3E8,
|
||||
COM4 = 0x2E8,
|
||||
COM5 = 0x5F8,
|
||||
COM6 = 0x4F8,
|
||||
COM7 = 0x5E8,
|
||||
COM8 = 0x4E8,
|
||||
|
||||
LPT1 = 0x378,
|
||||
LPT2 = 0x278,
|
||||
LPT3 = 0x3BC
|
||||
};
|
||||
|
||||
enum SerialSpeed
|
||||
{
|
||||
RATE_50_HI = 0x09,
|
||||
RATE_50_LO = 0x00,
|
||||
|
||||
RATE_300_HI = 0x01,
|
||||
RATE_300_LO = 0x80,
|
||||
|
||||
RATE_600_HI = 0x00,
|
||||
RATE_600_LO = 0xC0,
|
||||
|
||||
RATE_2400_HI = 0x00,
|
||||
RATE_2400_LO = 0x30,
|
||||
|
||||
RATE_4800_HI = 0x00,
|
||||
RATE_4800_LO = 0x18,
|
||||
|
||||
RATE_9600_HI = 0x00,
|
||||
RATE_9600_LO = 0x0C,
|
||||
|
||||
RATE_19200_HI = 0x00,
|
||||
RATE_19200_LO = 0x06,
|
||||
|
||||
RATE_38400_HI = 0x00,
|
||||
RATE_38400_LO = 0x03,
|
||||
|
||||
RATE_57600_HI = 0x00,
|
||||
RATE_57600_LO = 0x02,
|
||||
|
||||
RATE_115200_HI = 0x00,
|
||||
RATE_115200_LO = 0x01
|
||||
};
|
||||
|
||||
/*
|
||||
. Table of Registers .
|
||||
/---------------------------------------------------------------------\
|
||||
| Base Address | DLAB | R/W | Abr | Register Name |
|
||||
|---------------------------------------------------------------------|
|
||||
| +0 | =0 | W | - | Transmitter Holding Buffer |
|
||||
| | =0 | R | - | Receiver Buffer |
|
||||
| | =1 | R/W | - | Divisor Latch Low Byte |
|
||||
| +1 | =0 | R/W | IER | Interrupt Enable Register |
|
||||
| | =1 | R/W | - | Divisor Latch High Byte |
|
||||
| +2 | - | R | IIR | Interrupt Identification Register |
|
||||
| | - | W | FCR | FIFO Control Register |
|
||||
| +3 | - | R/W | LCR | Line Control Register |
|
||||
| +4 | - | R/W | MCR | Modem Control Register |
|
||||
| +5 | - | R | LSR | Line Status Register |
|
||||
| +6 | - | R | MSR | Modem Status Register |
|
||||
| +7 | - | R/W | - | Scratch Register |
|
||||
\---------------------------------------------------------------------/
|
||||
|
||||
Source:
|
||||
Interfacing the Serial / RS232 Port V5.0
|
||||
Table 5 : Table of Registers
|
||||
*/
|
||||
|
||||
/** Interrupt Enable Register */
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/* Enable Received Data Available Interrupt */
|
||||
uint8_t InterruptOnReceive : 1;
|
||||
|
||||
/* Enable Transmitter Holding Register Empty Interrupt */
|
||||
uint8_t InterruptOnTransmitter : 1;
|
||||
|
||||
/* Enable Receiver Line Status Interrupt */
|
||||
uint8_t LineStatusInterrupt : 1;
|
||||
|
||||
/* Enable Modem Status Interrupt */
|
||||
uint8_t ModemStatusInterrupt : 1;
|
||||
|
||||
/* Enables Sleep Mode (16750) */
|
||||
uint8_t SleepMode : 1;
|
||||
|
||||
/* Enables Low Power Mode (16750) */
|
||||
uint8_t LowPowerMode : 1;
|
||||
|
||||
/* Reserved */
|
||||
uint8_t __reserved : 2;
|
||||
};
|
||||
uint8_t raw;
|
||||
} IER;
|
||||
|
||||
/** Interrupt Identification Register */
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/* Interrupt pending */
|
||||
uint8_t InterruptPending : 1;
|
||||
|
||||
/**
|
||||
* Interrupt Status
|
||||
*
|
||||
* 00b = Modem Status Interrupt
|
||||
* 01b = Transmitter Holding Register Empty Interrupt
|
||||
* 10b = Received Data Available Interrupt
|
||||
* 11b = Receiver Line Status Interrupt
|
||||
*/
|
||||
uint8_t InterruptStatus : 2;
|
||||
|
||||
/**
|
||||
* 16550 Time-out Interrupt Pending
|
||||
*
|
||||
* @note Reserved on 8250, 16450
|
||||
*/
|
||||
uint8_t TimeOutIP : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t __reserved : 1;
|
||||
|
||||
/** 64 Byte Fifo Enabled (16750 only) */
|
||||
uint8_t FIFO64 : 1;
|
||||
|
||||
/**
|
||||
* Enable FIFO
|
||||
*
|
||||
* 00b = No FIFO
|
||||
* 01b = FIFO Enabled but Unusable
|
||||
* 11b = FIFO Enabled
|
||||
*/
|
||||
uint8_t FIFO : 2;
|
||||
};
|
||||
uint8_t raw;
|
||||
} IIR;
|
||||
|
||||
/** First In / First Out Control Register */
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Enable FIFO's */
|
||||
uint8_t FIFO : 1;
|
||||
|
||||
/** Clear Receive FIFO */
|
||||
uint8_t ClearRX : 1;
|
||||
|
||||
/** Clear Transmit FIFO */
|
||||
uint8_t ClearTX : 1;
|
||||
|
||||
/** DMA Mode Select.
|
||||
*
|
||||
* Change status of RXRDY & TXRDY pins from mode 1 to mode 2.
|
||||
*/
|
||||
uint8_t DMAMode : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t __reserved : 1;
|
||||
|
||||
/** Enable 64 Byte FIFO (16750 only) */
|
||||
uint8_t FIFO64 : 1;
|
||||
|
||||
/** Interrupt Trigger Level
|
||||
*
|
||||
* 00b = 1 Byte
|
||||
* 01b = 4 Bytes
|
||||
* 10b = 8 Bytes
|
||||
* 11b = 14 Bytes
|
||||
*/
|
||||
uint8_t TriggerLevel : 2;
|
||||
};
|
||||
uint8_t raw;
|
||||
} FCR;
|
||||
|
||||
/** Line Control Register */
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Word Length
|
||||
*
|
||||
* 00b = 5 bits
|
||||
* 01b = 6 bits
|
||||
* 10b = 7 bits
|
||||
* 11b = 8 bits
|
||||
*/
|
||||
uint8_t WordLength : 2;
|
||||
|
||||
/** Length of Stop Bit
|
||||
*
|
||||
* 0b = One Stop Bit
|
||||
* 1b = 2 Stop bits for words of length 6,7 or 8 bits or 1.5 Stop Bits for Word lengths of 5 bits.
|
||||
*/
|
||||
uint8_t StopBit : 1;
|
||||
|
||||
/** Parity Select
|
||||
*
|
||||
* 0b = No Parity
|
||||
* 001b = Odd Parity
|
||||
* 011b = Even Parity
|
||||
* 101b = High Parity (Sticky)
|
||||
* 111b = Low Parity (Sticky)
|
||||
*/
|
||||
uint8_t Parity : 3;
|
||||
|
||||
/** Set Break Enable */
|
||||
uint8_t SetBreak : 1;
|
||||
|
||||
/**
|
||||
* Divisor Latch Access
|
||||
*
|
||||
* 0b = Access to Receiver buffer, Transmitter buffer & Interrupt Enable Register
|
||||
* 1b = Divisor Latch Access Bit
|
||||
*/
|
||||
uint8_t DLAB : 1;
|
||||
};
|
||||
uint8_t raw;
|
||||
} LCR;
|
||||
|
||||
/** Modem Control Register */
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Force Data Terminal Ready */
|
||||
uint8_t DataTerminalReady : 1;
|
||||
|
||||
/** Force Request to Send */
|
||||
uint8_t RequestToSend : 1;
|
||||
|
||||
/** Auxiliary Output 1 */
|
||||
uint8_t Out1 : 1;
|
||||
|
||||
/** Auxiliary Output 2 */
|
||||
uint8_t Out2 : 1;
|
||||
|
||||
/** Loopback Mode */
|
||||
uint8_t Loopback : 1;
|
||||
|
||||
/** Autoflow Control Enabled (16750 only) */
|
||||
uint8_t Autoflow : 1;
|
||||
|
||||
/** Reserved */
|
||||
uint8_t __reserved : 2;
|
||||
};
|
||||
uint8_t raw;
|
||||
} MCR;
|
||||
|
||||
/** Line Status Register */
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Data Ready */
|
||||
uint8_t DataReady : 1;
|
||||
|
||||
/** Overrun Error */
|
||||
uint8_t OverrunError : 1;
|
||||
|
||||
/** Parity Error */
|
||||
uint8_t ParityError : 1;
|
||||
|
||||
/** Framing Error */
|
||||
uint8_t FramingError : 1;
|
||||
|
||||
/** Break Interrupt */
|
||||
uint8_t BreakInterrupt : 1;
|
||||
|
||||
/** Empty Transmitter Holding Register */
|
||||
uint8_t EmptyTransmitterHolding : 1;
|
||||
|
||||
/** Empty Data Holding Registers */
|
||||
uint8_t EmptyDataHolding : 1;
|
||||
|
||||
/** Error in Received FIFO */
|
||||
uint8_t ErrorReceivedFIFO : 1;
|
||||
};
|
||||
uint8_t raw;
|
||||
} LSR;
|
||||
|
||||
/** Modem Status Register */
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Delta Clear to Send */
|
||||
uint8_t DeltaClearToSend : 1;
|
||||
|
||||
/** Delta Data Set Ready */
|
||||
uint8_t DeltaDataSetReady : 1;
|
||||
|
||||
/** Trailing Edge Ring Indicator */
|
||||
uint8_t TrailingEdgeRingIndicator : 1;
|
||||
|
||||
/** Delta Data Carrier Detect */
|
||||
uint8_t DeltaDataCarrierDetect : 1;
|
||||
|
||||
/** Clear To Send */
|
||||
uint8_t ClearToSend : 1;
|
||||
|
||||
/** Data Set Ready */
|
||||
uint8_t DataSetReady : 1;
|
||||
|
||||
/** Ring Indicator */
|
||||
uint8_t RingIndicator : 1;
|
||||
|
||||
/** Carrier Detect */
|
||||
uint8_t CarrierDetect : 1;
|
||||
};
|
||||
uint8_t raw;
|
||||
} MSR;
|
||||
|
||||
union UARTs
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t com1 : 1;
|
||||
uint8_t com2 : 1;
|
||||
uint8_t com3 : 1;
|
||||
uint8_t com4 : 1;
|
||||
uint8_t com5 : 1;
|
||||
uint8_t com6 : 1;
|
||||
uint8_t com7 : 1;
|
||||
uint8_t com8 : 1;
|
||||
|
||||
uint8_t lpt1 : 1;
|
||||
uint8_t lpt2 : 1;
|
||||
uint8_t lpt3 : 1;
|
||||
|
||||
uint8_t __reserved : 5;
|
||||
};
|
||||
uint16_t raw;
|
||||
} uart;
|
||||
|
||||
bool IsDataReady(uint16_t Port)
|
||||
{
|
||||
LSR lsr;
|
||||
lsr.raw = inb(Port + 5);
|
||||
return lsr.DataReady;
|
||||
}
|
||||
|
||||
bool IsTransmitEmpty(uint16_t Port)
|
||||
{
|
||||
LSR lsr;
|
||||
lsr.raw = inb(Port + 5);
|
||||
return lsr.EmptyTransmitterHolding;
|
||||
}
|
||||
|
||||
char ReadSerial(uint16_t Port)
|
||||
{
|
||||
while (!IsDataReady(Port))
|
||||
Yield();
|
||||
return inb(Port);
|
||||
}
|
||||
|
||||
void WriteSerial(uint16_t Port, char Character)
|
||||
{
|
||||
while (!IsTransmitEmpty(Port))
|
||||
Yield();
|
||||
outb(Port, Character);
|
||||
}
|
||||
|
||||
void ReportSerialReceived(uint8_t Data)
|
||||
{
|
||||
DebugLog("%c", Data);
|
||||
}
|
||||
|
||||
void UartCOM24(TrapFrame *)
|
||||
{
|
||||
LSR lsr2, lsr4;
|
||||
do
|
||||
{
|
||||
lsr2.raw = inb(COM2 + 5);
|
||||
if (lsr2.DataReady)
|
||||
ReportSerialReceived(inb(COM2));
|
||||
lsr4.raw = inb(COM4 + 5);
|
||||
if (lsr4.DataReady)
|
||||
ReportSerialReceived(inb(COM4));
|
||||
} while (lsr2.DataReady || lsr4.DataReady);
|
||||
}
|
||||
|
||||
void UartCOM13(TrapFrame *)
|
||||
{
|
||||
LSR lsr1, lsr3;
|
||||
do
|
||||
{
|
||||
lsr1.raw = inb(COM1 + 5);
|
||||
if (lsr1.DataReady)
|
||||
ReportSerialReceived(inb(COM1));
|
||||
lsr3.raw = inb(COM3 + 5);
|
||||
if (lsr3.DataReady)
|
||||
ReportSerialReceived(inb(COM3));
|
||||
} while (lsr1.DataReady || lsr3.DataReady);
|
||||
}
|
||||
|
||||
bool InitializePort(uint16_t Port)
|
||||
{
|
||||
ECS;
|
||||
LCR lcr = {0};
|
||||
IER ier = {0};
|
||||
FCR fcr = {0};
|
||||
MCR mcr = {0};
|
||||
|
||||
outb(Port + 3, lcr.raw);
|
||||
outb(Port + 1, ier.raw);
|
||||
|
||||
lcr.DLAB = 1;
|
||||
outb(Port + 3, lcr.raw);
|
||||
|
||||
outb(Port + 0, RATE_115200_LO);
|
||||
outb(Port + 1, RATE_115200_HI);
|
||||
|
||||
lcr.DLAB = 0;
|
||||
lcr.WordLength = 0b11;
|
||||
outb(Port + 3, lcr.raw);
|
||||
|
||||
fcr.FIFO = 1;
|
||||
fcr.ClearRX = 1;
|
||||
fcr.ClearTX = 1;
|
||||
fcr.TriggerLevel = 0b11;
|
||||
outb(Port + 2, fcr.raw);
|
||||
|
||||
mcr.DataTerminalReady = 1;
|
||||
mcr.RequestToSend = 1;
|
||||
mcr.Out2 = 1;
|
||||
mcr.Loopback = 1;
|
||||
outb(Port + 4, mcr.raw);
|
||||
|
||||
/* Test the serial port */
|
||||
outb(Port + 0, 0x48);
|
||||
uint8_t result = inb(Port + 0);
|
||||
if (result != 0x48)
|
||||
{
|
||||
/* FIXME: DETECT BAUD RATE
|
||||
Do multiple test to check if the output is garbage.
|
||||
If so, reduce the baud rate until it works. */
|
||||
|
||||
LCS;
|
||||
KernelPrint("Port %#X test failed!", Port);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set normal operation mode */
|
||||
mcr.DataTerminalReady = 1;
|
||||
mcr.RequestToSend = 1;
|
||||
mcr.Out1 = 1;
|
||||
mcr.Out2 = 1;
|
||||
mcr.Loopback = 0;
|
||||
outb(Port + 4, mcr.raw);
|
||||
|
||||
/* Enable interrupts on receive */
|
||||
ier.InterruptOnReceive = 1;
|
||||
outb(Port + 1, ier.raw);
|
||||
RegisterInterruptHandler(3, UartCOM24);
|
||||
RegisterInterruptHandler(4, UartCOM13);
|
||||
|
||||
LCS;
|
||||
KernelPrint("Port %#X initialized", Port);
|
||||
return true;
|
||||
}
|
||||
|
||||
int DetectUART()
|
||||
{
|
||||
uart.com1 = inb(COM1) != 0xFF ? true : false;
|
||||
uart.com2 = inb(COM2) != 0xFF ? true : false;
|
||||
uart.com3 = inb(COM3) != 0xFF ? true : false;
|
||||
uart.com4 = inb(COM4) != 0xFF ? true : false;
|
||||
uart.com5 = inb(COM5) != 0xFF ? true : false;
|
||||
uart.com6 = inb(COM6) != 0xFF ? true : false;
|
||||
uart.com7 = inb(COM7) != 0xFF ? true : false;
|
||||
uart.com8 = inb(COM8) != 0xFF ? true : false;
|
||||
|
||||
uart.lpt1 = inb(LPT1) != 0xFF ? true : false;
|
||||
uart.lpt2 = inb(LPT2) != 0xFF ? true : false;
|
||||
uart.lpt3 = inb(LPT3) != 0xFF ? true : false;
|
||||
|
||||
if (uart.com1 == true)
|
||||
if (InitializePort(COM1) == false)
|
||||
uart.com1 = false;
|
||||
|
||||
if (uart.com2 == true)
|
||||
if (InitializePort(COM2) == false)
|
||||
uart.com1 = false;
|
||||
|
||||
if (uart.com3 == true)
|
||||
if (InitializePort(COM3) == false)
|
||||
uart.com1 = false;
|
||||
|
||||
if (uart.com4 == true)
|
||||
if (InitializePort(COM4) == false)
|
||||
uart.com1 = false;
|
||||
|
||||
if (uart.com5 == true)
|
||||
if (InitializePort(COM5) == false)
|
||||
uart.com1 = false;
|
||||
|
||||
if (uart.com6 == true)
|
||||
if (InitializePort(COM6) == false)
|
||||
uart.com1 = false;
|
||||
|
||||
if (uart.com7 == true)
|
||||
if (InitializePort(COM7) == false)
|
||||
uart.com1 = false;
|
||||
|
||||
if (uart.com8 == true)
|
||||
if (InitializePort(COM8) == false)
|
||||
uart.com1 = false;
|
||||
|
||||
if (uart.lpt1 == true)
|
||||
KernelPrint("LPT1 is present");
|
||||
|
||||
if (uart.lpt2 == true)
|
||||
KernelPrint("LPT2 is present");
|
||||
|
||||
if (uart.lpt3 == true)
|
||||
KernelPrint("LPT3 is present");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static int once = 0;
|
||||
// static uint8_t com4 = 0xFF;
|
||||
// if (!once++)
|
||||
// com4 = inb(0x2E8);
|
||||
// if (com4 == 0xFF)
|
||||
// CPU::Halt(true);
|
||||
// char UserInputBuffer[256]{'\0'};
|
||||
// int BackSpaceLimit = 0;
|
||||
// while (true)
|
||||
// {
|
||||
// while ((inb(0x2E8 + 5) & 1) == 0)
|
||||
// CPU::Pause();
|
||||
// char key = inb(0x2E8);
|
||||
// // debug("key: %d", key);
|
||||
// if (key == '\x7f') /* Backspace (DEL) */
|
||||
// {
|
||||
// if (BackSpaceLimit <= 0)
|
||||
// continue;
|
||||
// char keyBuf[5] = {'\b', '\x1b', '[', 'K', '\0'};
|
||||
// ExPrint(keyBuf);
|
||||
// backspace(UserInputBuffer);
|
||||
// BackSpaceLimit--;
|
||||
// continue;
|
||||
// }
|
||||
// else if (key == '\x0d') /* Enter (CR) */
|
||||
// {
|
||||
// UserInput(UserInputBuffer);
|
||||
// BackSpaceLimit = 0;
|
||||
// UserInputBuffer[0] = '\0';
|
||||
// continue;
|
||||
// }
|
||||
// else if (key == '\x1b') /* Escape */
|
||||
// {
|
||||
// char tmp[16]{'\0'};
|
||||
// append(tmp, key);
|
||||
// while ((inb(0x2E8 + 5) & 1) == 0)
|
||||
// CPU::Pause();
|
||||
// char key = inb(0x2E8);
|
||||
// append(tmp, key);
|
||||
// if (key == '[')
|
||||
// {
|
||||
// // 27 91
|
||||
// // < 68
|
||||
// // > 67
|
||||
// // down 66
|
||||
// // up 65
|
||||
// while ((inb(0x2E8 + 5) & 1) == 0)
|
||||
// CPU::Pause();
|
||||
// key = inb(0x2E8);
|
||||
// append(tmp, key);
|
||||
// switch (key)
|
||||
// {
|
||||
// case 'A':
|
||||
// key = KEY_D_UP;
|
||||
// break;
|
||||
// case 'B':
|
||||
// key = KEY_D_DOWN;
|
||||
// break;
|
||||
// case 'C':
|
||||
// key = KEY_D_RIGHT;
|
||||
// break;
|
||||
// case 'D':
|
||||
// key = KEY_D_LEFT;
|
||||
// break;
|
||||
// default:
|
||||
// {
|
||||
// for (size_t i = 0; i < strlen(tmp); i++)
|
||||
// {
|
||||
// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
|
||||
// continue;
|
||||
// append(UserInputBuffer, tmp[i]);
|
||||
// BackSpaceLimit++;
|
||||
// char keyBuf[2] = {(char)tmp[i], '\0'};
|
||||
// ExPrint(keyBuf);
|
||||
// }
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
// ArrowInput(key);
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
|
||||
// continue;
|
||||
// append(UserInputBuffer, key);
|
||||
// BackSpaceLimit++;
|
||||
// char keyBuf[2] = {(char)key, '\0'};
|
||||
// ExPrint(keyBuf);
|
||||
// }
|
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
@ -1,897 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.h>
|
||||
#include <errno.h>
|
||||
#include <fs.h>
|
||||
#include <input.h>
|
||||
#include <regs.h>
|
||||
#include <base.h>
|
||||
#include <aip.h>
|
||||
#include <io.h>
|
||||
|
||||
enum RPCMessages
|
||||
{
|
||||
MSG_OPEN,
|
||||
MSG_SENDSIZE,
|
||||
MSG_SENDPAYLOAD,
|
||||
MSG_RECVSIZE,
|
||||
MSG_RECVPAYLOAD,
|
||||
MSG_RECVSTATUS,
|
||||
MSG_CLOSE,
|
||||
};
|
||||
|
||||
enum RPCStatus
|
||||
{
|
||||
STATUS_SUCCESS = 0x1,
|
||||
STATUS_DORECV = 0x2,
|
||||
STATUS_CPT = 0x10,
|
||||
STATUS_HB = 0x80,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t ax;
|
||||
uint32_t magic;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t bx;
|
||||
size_t size;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t cx;
|
||||
uint16_t command;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t dx;
|
||||
uint16_t port;
|
||||
};
|
||||
uint32_t si;
|
||||
uint32_t di;
|
||||
} VMwareCommand;
|
||||
|
||||
#define VMWARE_MAGIC 0x564D5868
|
||||
|
||||
#define VMWARE_PORT 0x5658
|
||||
#define VMWARE_PORTHB 0x5659
|
||||
|
||||
#define VMWARE_HYPERVISOR_HB 0x00000000
|
||||
#define VMWARE_HYPERVISOR_OUT 0x00000001
|
||||
|
||||
#define CMD_GETVERSION 0xA
|
||||
#define CMD_MESSAGE 0x1E
|
||||
#define CMD_ABSPOINTER_DATA 0x27
|
||||
#define CMD_ABSPOINTER_STATUS 0x28
|
||||
#define CMD_ABSPOINTER_COMMAND 0x29
|
||||
|
||||
#define ABSPOINTER_ENABLE 0x45414552
|
||||
#define ABSPOINTER_RELATIVE 0xF5
|
||||
#define ABSPOINTER_ABSOLUTE 0x53424152
|
||||
|
||||
#define MESSAGE_RPCI 0x49435052
|
||||
#define MESSAGE_TCLO 0x4f4c4354
|
||||
|
||||
#define FLAG_COOKIE 0x80000000
|
||||
|
||||
#define ToMsg(x) ((x) << 16 | CMD_MESSAGE)
|
||||
#define HighWord(x) ((x & 0xFFFF0000) >> 16)
|
||||
|
||||
#define MESSAGE_HB_MSG 0
|
||||
|
||||
#define MESSAGE_OPEN_CHANNEL ToMsg(MSG_OPEN)
|
||||
#define MESSAGE_CLOSE_CHANNEL ToMsg(MSG_CLOSE)
|
||||
|
||||
#define MESSAGE_SEND_SIZE ToMsg(MSG_SENDSIZE)
|
||||
#define MESSAGE_SEND_PAYLOAD ToMsg(MSG_SENDPAYLOAD)
|
||||
|
||||
#define MESSAGE_RECV_SIZE ToMsg(MSG_RECVSIZE)
|
||||
#define MESSAGE_RECV_PAYLOAD ToMsg(MSG_RECVPAYLOAD)
|
||||
#define MESSAGE_RECV_STATUS ToMsg(MSG_RECVSTATUS)
|
||||
|
||||
#if defined(__amd64__)
|
||||
|
||||
#define VM_PORT(cmd, in_ebx, isi, idi, \
|
||||
flags, magic, \
|
||||
ax, bx, cx, dx, si, di) \
|
||||
__asm__ __volatile__("movw $0x5658, %%dx\n" \
|
||||
"inl %%dx, %%eax\n" \
|
||||
: "=a"(ax), \
|
||||
"=b"(bx), \
|
||||
"=c"(cx), \
|
||||
"=d"(dx), \
|
||||
"=S"(si), \
|
||||
"=D"(di) \
|
||||
: "a"(magic), \
|
||||
"b"(in_ebx), \
|
||||
"c"(cmd), \
|
||||
"d"(flags), \
|
||||
"S"(isi), \
|
||||
"D"(idi) : "memory")
|
||||
|
||||
#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
|
||||
flags, magic, bp, \
|
||||
ax, bx, cx, dx, si, di) \
|
||||
__asm__ __volatile__("push %%rbp\n" \
|
||||
"mov %12, %%rbp\n" \
|
||||
"movw $0x5659, %%dx\n" \
|
||||
"rep outsb\n" \
|
||||
"pop %%rbp\n" \
|
||||
: "=a"(ax), \
|
||||
"=b"(bx), \
|
||||
"=c"(cx), \
|
||||
"=d"(dx), \
|
||||
"=S"(si), \
|
||||
"=D"(di) \
|
||||
: "a"(magic), \
|
||||
"b"(cmd), \
|
||||
"c"(in_ecx), \
|
||||
"d"(flags), \
|
||||
"S"(isi), \
|
||||
"D"(idi), \
|
||||
"r"(bp) : "memory", "cc")
|
||||
|
||||
#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
|
||||
flags, magic, bp, \
|
||||
ax, bx, cx, dx, si, di) \
|
||||
__asm__ __volatile__("push %%rbp\n" \
|
||||
"mov %12, %%rbp\n" \
|
||||
"movw $0x5659, %%dx\n" \
|
||||
"rep insb\n" \
|
||||
"pop %%rbp\n" \
|
||||
: "=a"(ax), \
|
||||
"=b"(bx), \
|
||||
"=c"(cx), \
|
||||
"=d"(dx), \
|
||||
"=S"(si), \
|
||||
"=D"(di) \
|
||||
: "a"(magic), \
|
||||
"b"(cmd), \
|
||||
"c"(in_ecx), \
|
||||
"d"(flags), \
|
||||
"S"(isi), \
|
||||
"D"(idi), \
|
||||
"r"(bp) : "memory", "cc")
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
#define VM_PORT(cmd, in_ebx, isi, idi, \
|
||||
flags, magic, \
|
||||
ax, bx, cx, dx, si, di)
|
||||
|
||||
#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
|
||||
flags, \
|
||||
magic, bp, ax, \
|
||||
bx, cx, dx, si, di)
|
||||
|
||||
#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
|
||||
flags, magic, bp, \
|
||||
ax, bx, cx, dx, si, di)
|
||||
|
||||
#endif
|
||||
|
||||
/* TODO:
|
||||
- use vmcall or vmmcall instead of "out" and "in" if available
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int TCLOChannel;
|
||||
uint16_t ChannelID;
|
||||
uint32_t CookieHigh;
|
||||
uint32_t CookieLow;
|
||||
} ToolboxContext;
|
||||
|
||||
dev_t MouseDevID = -1;
|
||||
|
||||
int __strcmp(const char *l, const char *r)
|
||||
{
|
||||
for (; *l == *r && *l; l++, r++)
|
||||
;
|
||||
|
||||
return *(unsigned char *)l - *(unsigned char *)r;
|
||||
}
|
||||
|
||||
void __cpuid(uint32_t Function,
|
||||
uint32_t *eax, uint32_t *ebx,
|
||||
uint32_t *ecx, uint32_t *edx)
|
||||
{
|
||||
asmv("cpuid"
|
||||
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
|
||||
: "a"(Function));
|
||||
}
|
||||
|
||||
bool __CheckHypervisorBit()
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
__cpuid(0x1, &eax, &ebx, &ecx, &edx);
|
||||
if (!(ecx & (1 << 31)))
|
||||
return false; /* Hypervisor not detected */
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __VMwareBackdoorHypervisors()
|
||||
{
|
||||
const char hv[13] = {0};
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
__cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
*(uint32_t *)hv = ebx;
|
||||
*(uint32_t *)(hv + 4) = ecx;
|
||||
*(uint32_t *)(hv + 8) = edx;
|
||||
|
||||
if (__strcmp(hv, "VMwareVMware") != 0 &&
|
||||
__strcmp(hv, "KVMKVMKVM") != 0 &&
|
||||
__strcmp(hv, "TCGTCGTCGTCG") != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsVMwareBackdoorAvailable()
|
||||
{
|
||||
if (!__CheckHypervisorBit())
|
||||
return false;
|
||||
|
||||
if (!__VMwareBackdoorHypervisors())
|
||||
return false;
|
||||
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t ax;
|
||||
uint32_t magic;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t bx;
|
||||
size_t size;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t cx;
|
||||
uint16_t command;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t dx;
|
||||
uint16_t port;
|
||||
};
|
||||
uint32_t si;
|
||||
uint32_t di;
|
||||
} cmd;
|
||||
|
||||
cmd.si = cmd.di = 0;
|
||||
cmd.bx = ~0x564D5868;
|
||||
cmd.command = 0xA;
|
||||
cmd.magic = 0x564D5868;
|
||||
cmd.port = 0x5658;
|
||||
|
||||
asmv("in %%dx, %0"
|
||||
: "+a"(cmd.ax), "+b"(cmd.bx),
|
||||
"+c"(cmd.cx), "+d"(cmd.dx),
|
||||
"+S"(cmd.si), "+D"(cmd.di));
|
||||
|
||||
if (cmd.bx != 0x564D5868 ||
|
||||
cmd.ax == 0xFFFFFFFF)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int OpenMessageChannel(ToolboxContext *ctx, uint32_t Protocol)
|
||||
{
|
||||
uintptr_t ax, bx, cx, dx, si = 0, di = 0;
|
||||
|
||||
VM_PORT(MESSAGE_OPEN_CHANNEL,
|
||||
(Protocol | FLAG_COOKIE), si, di,
|
||||
0, VMWARE_MAGIC,
|
||||
ax, bx, cx, dx, si, di);
|
||||
|
||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
||||
{
|
||||
KernelLog("Failed to open message channel %#lx", Protocol);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DebugLog("Opened message channel %d (Protocol: %#lx)",
|
||||
HighWord(dx), Protocol);
|
||||
ctx->ChannelID = (uint16_t)HighWord(dx);
|
||||
ctx->CookieHigh = si;
|
||||
ctx->CookieLow = di;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void MessageClose(ToolboxContext *ctx)
|
||||
{
|
||||
uintptr_t ax, bx, cx, dx,
|
||||
si = ctx->CookieHigh,
|
||||
di = ctx->CookieLow;
|
||||
|
||||
VM_PORT(MESSAGE_CLOSE_CHANNEL,
|
||||
0, si, di,
|
||||
ctx->ChannelID << 16,
|
||||
VMWARE_MAGIC,
|
||||
ax, bx, cx, dx, si, di);
|
||||
|
||||
DebugLog("Closed message channel %d", ctx->ChannelID);
|
||||
}
|
||||
|
||||
static uintptr_t MessageSendHB(ToolboxContext *ctx,
|
||||
const char *Message)
|
||||
{
|
||||
uintptr_t ax, bx, cx, dx,
|
||||
si = (uintptr_t)Message,
|
||||
di = ctx->CookieLow,
|
||||
bp = ctx->CookieHigh;
|
||||
|
||||
uint32_t ChannelID = ctx->ChannelID << 16;
|
||||
size_t Size = StringLength(Message);
|
||||
|
||||
VM_PORT_HB_OUT((STATUS_SUCCESS << 16) | MESSAGE_HB_MSG,
|
||||
Size, si, di,
|
||||
VMWARE_HYPERVISOR_HB | ChannelID | VMWARE_HYPERVISOR_OUT,
|
||||
VMWARE_MAGIC, bp,
|
||||
ax, bx, cx, dx, si, di);
|
||||
|
||||
return bx;
|
||||
}
|
||||
|
||||
static uintptr_t MessageSendLB(ToolboxContext *ctx,
|
||||
const char *Message)
|
||||
{
|
||||
uintptr_t ax, bx,
|
||||
cx = STATUS_SUCCESS << 16,
|
||||
dx, si, di;
|
||||
|
||||
size_t Size = StringLength(Message);
|
||||
while (Size &&
|
||||
(HighWord(cx) & STATUS_SUCCESS))
|
||||
{
|
||||
uint32_t TotalBytes = MIN((uint32_t)Size, (uint32_t)4);
|
||||
uint32_t Word = 0;
|
||||
MemoryCopy(&Word, Message, TotalBytes);
|
||||
Message += TotalBytes;
|
||||
|
||||
si = ctx->CookieHigh;
|
||||
di = ctx->CookieLow;
|
||||
|
||||
VM_PORT(MESSAGE_SEND_PAYLOAD,
|
||||
Word, si, di,
|
||||
ctx->ChannelID << 16,
|
||||
VMWARE_MAGIC,
|
||||
ax, bx, cx, dx, si, di);
|
||||
}
|
||||
|
||||
return cx;
|
||||
}
|
||||
|
||||
static uintptr_t MessageReceiveHB(ToolboxContext *ctx,
|
||||
char *Buffer,
|
||||
size_t BufferSize)
|
||||
{
|
||||
uintptr_t ax, bx, cx, dx,
|
||||
si = ctx->CookieHigh,
|
||||
di = (uintptr_t)Buffer,
|
||||
bp = ctx->CookieLow;
|
||||
|
||||
uint32_t ChannelID = ctx->ChannelID << 16;
|
||||
|
||||
VM_PORT_HB_IN((STATUS_SUCCESS << 16) | MESSAGE_HB_MSG,
|
||||
BufferSize, si, di,
|
||||
VMWARE_HYPERVISOR_HB | ChannelID | VMWARE_HYPERVISOR_OUT,
|
||||
VMWARE_MAGIC, bp,
|
||||
ax, bx, cx, dx, si, di);
|
||||
|
||||
return bx;
|
||||
}
|
||||
|
||||
static uintptr_t MessageReceiveLB(ToolboxContext *ctx,
|
||||
char *Buffer,
|
||||
size_t BufferSize)
|
||||
{
|
||||
uintptr_t ax, bx,
|
||||
cx = STATUS_SUCCESS << 16,
|
||||
dx, si, di;
|
||||
|
||||
while (BufferSize)
|
||||
{
|
||||
uint32_t TotalBytes = MIN((uint32_t)BufferSize, (uint32_t)4);
|
||||
|
||||
si = ctx->CookieHigh;
|
||||
di = ctx->CookieLow;
|
||||
|
||||
VM_PORT(MESSAGE_RECV_PAYLOAD,
|
||||
STATUS_SUCCESS, si, di,
|
||||
ctx->ChannelID << 16,
|
||||
VMWARE_MAGIC,
|
||||
ax, bx, cx, dx, si, di);
|
||||
|
||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
||||
break;
|
||||
|
||||
MemoryCopy(Buffer, &bx, TotalBytes);
|
||||
Buffer += TotalBytes;
|
||||
BufferSize -= TotalBytes;
|
||||
}
|
||||
|
||||
return cx;
|
||||
}
|
||||
|
||||
static int MessageSend(ToolboxContext *ctx,
|
||||
const char *Message)
|
||||
{
|
||||
uintptr_t ax, bx, cx, dx, si, di;
|
||||
size_t Size = StringLength(Message);
|
||||
int Retries = 0;
|
||||
|
||||
while (Retries < 2)
|
||||
{
|
||||
Retries++;
|
||||
si = ctx->CookieHigh;
|
||||
di = ctx->CookieLow;
|
||||
|
||||
VM_PORT(MESSAGE_SEND_SIZE,
|
||||
Size, si, di,
|
||||
ctx->ChannelID << 16,
|
||||
VMWARE_MAGIC,
|
||||
ax, bx, cx, dx, si, di);
|
||||
|
||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
||||
{
|
||||
KernelLog("Failed to send message size for \"%s\": %d",
|
||||
Message, cx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bool HighBand = (HighWord(cx) & STATUS_HB) != 0;
|
||||
if (HighBand)
|
||||
bx = MessageSendHB(ctx, Message);
|
||||
else
|
||||
bx = MessageSendLB(ctx, Message);
|
||||
|
||||
int status = HighWord(bx);
|
||||
|
||||
if ((status & STATUS_SUCCESS) != 0)
|
||||
{
|
||||
DebugLog("Message \"%s\" sent", Message);
|
||||
return 0;
|
||||
}
|
||||
else if ((status & STATUS_CPT) == 0)
|
||||
{
|
||||
KernelLog("Checkpoint occurred for message \"%s\"", Message);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
KernelLog("Failed to send message \"%s\": %#lx", Message, bx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int MessageReceive(ToolboxContext *ctx,
|
||||
char **Buffer,
|
||||
size_t *BufferSize)
|
||||
{
|
||||
uintptr_t ax, bx, cx, dx, si, di;
|
||||
int Retries = 0;
|
||||
|
||||
*Buffer = NULL;
|
||||
*BufferSize = 0;
|
||||
|
||||
char *ReplyBuf = NULL;
|
||||
size_t ReplyBufPages = 0;
|
||||
size_t ReplySize = 0;
|
||||
while (Retries < 2)
|
||||
{
|
||||
Retries++;
|
||||
si = ctx->CookieHigh;
|
||||
di = ctx->CookieLow;
|
||||
|
||||
VM_PORT(MESSAGE_RECV_SIZE,
|
||||
0, si, di,
|
||||
ctx->ChannelID << 16,
|
||||
VMWARE_MAGIC,
|
||||
ax, bx, cx, dx, si, di);
|
||||
|
||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
||||
{
|
||||
KernelLog("Failed to receive message size: %d", cx);
|
||||
return -EINVAL;
|
||||
}
|
||||
else if ((HighWord(cx) & STATUS_DORECV) == 0)
|
||||
{
|
||||
DebugLog("No message to receive");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
ReplySize = bx;
|
||||
|
||||
if (ReplyBuf != NULL)
|
||||
FreeMemory(ReplyBuf, ReplyBufPages);
|
||||
ReplyBufPages = ReplySize / 0x1000 + 1;
|
||||
ReplyBuf = AllocateMemory(ReplyBufPages);
|
||||
|
||||
bool HighBand = (HighWord(cx) & STATUS_HB) != 0;
|
||||
if (HighBand)
|
||||
bx = MessageReceiveHB(ctx, ReplyBuf, ReplySize);
|
||||
else
|
||||
bx = MessageReceiveLB(ctx, ReplyBuf, ReplySize);
|
||||
|
||||
if ((HighWord(bx) & STATUS_SUCCESS) == 0)
|
||||
{
|
||||
if ((HighWord(bx) & STATUS_CPT) == 0)
|
||||
{
|
||||
KernelLog("Checkpoint occurred for message payload");
|
||||
continue;
|
||||
}
|
||||
|
||||
KernelLog("Failed to receive message payload: %d", HighWord(bx));
|
||||
FreeMemory(ReplyBuf, ReplyBufPages);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ReplyBuf[ReplySize] = '\0';
|
||||
|
||||
si = ctx->CookieHigh;
|
||||
di = ctx->CookieLow;
|
||||
|
||||
VM_PORT(MESSAGE_RECV_STATUS,
|
||||
STATUS_SUCCESS, si, di,
|
||||
ctx->ChannelID << 16,
|
||||
VMWARE_MAGIC,
|
||||
ax, bx, cx, dx, si, di);
|
||||
|
||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
||||
{
|
||||
if ((HighWord(cx) & STATUS_CPT) == 0)
|
||||
{
|
||||
KernelLog("Retrying message receive");
|
||||
continue;
|
||||
}
|
||||
|
||||
KernelLog("Failed to receive message status: %d", HighWord(cx));
|
||||
FreeMemory(ReplyBuf, ReplyBufPages);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (ReplyBuf == NULL)
|
||||
{
|
||||
KernelLog("Failed to receive message");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*Buffer = ReplyBuf;
|
||||
*BufferSize = ReplySize;
|
||||
DebugLog("Received message \"%s\"", ReplyBuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SendRPCI(ToolboxContext *, const char *Request)
|
||||
{
|
||||
ToolboxContext rpci_ctx = {0};
|
||||
int status = OpenMessageChannel(&rpci_ctx, MESSAGE_RPCI);
|
||||
if (status < 0)
|
||||
{
|
||||
KernelLog("Failed to open RPCI channel: %d", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = MessageSend(&rpci_ctx, Request);
|
||||
if (status < 0)
|
||||
{
|
||||
KernelLog("Failed to send RPCI request: %d", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
MessageClose(&rpci_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MsgEqual(const char *haystack, const char *needle)
|
||||
{
|
||||
return strstr(haystack, needle) == haystack;
|
||||
}
|
||||
|
||||
static int DisplayGetSize(ToolboxContext *ctx)
|
||||
{
|
||||
if (ctx->TCLOChannel != -1)
|
||||
MessageClose(ctx);
|
||||
OpenMessageChannel(ctx, MESSAGE_TCLO);
|
||||
|
||||
char EmptyBuffer[256] = {'\0'};
|
||||
MessageSend(ctx, EmptyBuffer);
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* FIXME: buf memory leak */
|
||||
char *buf;
|
||||
size_t len;
|
||||
|
||||
int status = MessageReceive(ctx, &buf, &len);
|
||||
if (status == -EAGAIN)
|
||||
{
|
||||
Sleep(1000);
|
||||
continue;
|
||||
}
|
||||
else if (status < 0)
|
||||
{
|
||||
KernelLog("Failed to receive message");
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf[StringLength(buf)] = '\0';
|
||||
if (MsgEqual(buf, "reset"))
|
||||
{
|
||||
if (MessageSend(ctx, "OK ATR toolbox") < 0)
|
||||
return 1;
|
||||
}
|
||||
else if (MsgEqual(buf, "ping"))
|
||||
{
|
||||
if (MessageSend(ctx, "OK ") < 0)
|
||||
return 1;
|
||||
}
|
||||
else if (MsgEqual(buf, "Capabilities_Register"))
|
||||
{
|
||||
SendRPCI(ctx, "tools.capability.resolution_set 1");
|
||||
SendRPCI(ctx, "tools.capability.resolution_server toolbox 1");
|
||||
SendRPCI(ctx, "tools.capability.display_topology_set 1");
|
||||
SendRPCI(ctx, "tools.capability.color_depth_set 1");
|
||||
SendRPCI(ctx, "tools.capability.resolution_min 0 0");
|
||||
SendRPCI(ctx, "tools.capability.unity 1");
|
||||
|
||||
if (MessageSend(ctx, "OK ") < 0)
|
||||
return 1;
|
||||
}
|
||||
else if (MsgEqual(buf, "Resolution_Set"))
|
||||
{
|
||||
DebugLog("%s", buf);
|
||||
if (MessageSend(ctx, "OK ") < 0)
|
||||
return 1;
|
||||
MessageClose(ctx);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MessageSend(ctx, "ERROR Unknown command") < 0)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pid_t dst_id = -1;
|
||||
pid_t dst_pid = -1;
|
||||
ToolboxContext *tb_ctx = NULL;
|
||||
void DisplayScaleThread()
|
||||
{
|
||||
/* sizeof ToolboxContext */
|
||||
tb_ctx = AllocateMemory(1);
|
||||
Sleep(2000);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (DisplayGetSize(tb_ctx) != 0)
|
||||
KernelLog("Failed to scale display");
|
||||
Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandSend(VMwareCommand *cmd)
|
||||
{
|
||||
cmd->magic = VMWARE_MAGIC;
|
||||
cmd->port = VMWARE_PORT;
|
||||
asm volatile("in %%dx, %0"
|
||||
: "+a"(cmd->ax), "+b"(cmd->bx),
|
||||
"+c"(cmd->cx), "+d"(cmd->dx),
|
||||
"+S"(cmd->si), "+D"(cmd->di));
|
||||
}
|
||||
|
||||
void Absolute()
|
||||
{
|
||||
VMwareCommand cmd = {0};
|
||||
|
||||
/* Enable */
|
||||
cmd.bx = ABSPOINTER_ENABLE;
|
||||
cmd.command = CMD_ABSPOINTER_COMMAND;
|
||||
CommandSend(&cmd);
|
||||
|
||||
/* Status */
|
||||
cmd.bx = 0;
|
||||
cmd.command = CMD_ABSPOINTER_STATUS;
|
||||
CommandSend(&cmd);
|
||||
|
||||
/* Read data (1) */
|
||||
cmd.bx = 1;
|
||||
cmd.command = CMD_ABSPOINTER_DATA;
|
||||
CommandSend(&cmd);
|
||||
|
||||
/* Enable absolute */
|
||||
cmd.bx = ABSPOINTER_ABSOLUTE;
|
||||
cmd.command = CMD_ABSPOINTER_COMMAND;
|
||||
CommandSend(&cmd);
|
||||
}
|
||||
|
||||
void Relative()
|
||||
{
|
||||
VMwareCommand cmd = {0};
|
||||
cmd.bx = ABSPOINTER_RELATIVE;
|
||||
cmd.command = CMD_ABSPOINTER_COMMAND;
|
||||
CommandSend(&cmd);
|
||||
}
|
||||
|
||||
InputReport ir = {0};
|
||||
void InterruptHandler(TrapFrame *)
|
||||
{
|
||||
uint8_t Data = inb(0x60);
|
||||
(void)Data;
|
||||
|
||||
VMwareCommand cmd = {0};
|
||||
cmd.bx = 0;
|
||||
cmd.command = CMD_ABSPOINTER_STATUS;
|
||||
CommandSend(&cmd);
|
||||
|
||||
if (cmd.ax == 0xFFFF0000)
|
||||
{
|
||||
KernelLog("VMware mouse is not connected?");
|
||||
Relative();
|
||||
Absolute();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((cmd.ax & 0xFFFF) < 4)
|
||||
return;
|
||||
|
||||
cmd.bx = 4;
|
||||
cmd.command = CMD_ABSPOINTER_DATA;
|
||||
CommandSend(&cmd);
|
||||
|
||||
int Buttons = (cmd.ax & 0xFFFF);
|
||||
|
||||
/**
|
||||
* How should I handle this?
|
||||
* (cmd.[bx,cx] * Width) / 0xFFFF
|
||||
* Maybe TODO: Width and Height API?
|
||||
*/
|
||||
uintptr_t AbsoluteX = cmd.bx;
|
||||
uintptr_t AbsoluteY = cmd.cx;
|
||||
|
||||
ir.Type = INPUT_TYPE_MOUSE;
|
||||
ir.Device = MouseDevID;
|
||||
ir.Mouse.X = AbsoluteX;
|
||||
ir.Mouse.Y = AbsoluteY;
|
||||
ir.Mouse.Z = (int8_t)cmd.dx;
|
||||
ir.Mouse.Absolute = 1;
|
||||
ir.Mouse.LeftButton = Buttons & 0x20;
|
||||
ir.Mouse.RightButton = Buttons & 0x10;
|
||||
ir.Mouse.MiddleButton = Buttons & 0x08;
|
||||
// ir.Mouse.Button4 = 0x0;
|
||||
// ir.Mouse.Button5 = 0x0;
|
||||
// ir.Mouse.Button6 = 0x0;
|
||||
// ir.Mouse.Button7 = 0x0;
|
||||
// ir.Mouse.Button8 = 0x0;
|
||||
ReportInputEvent(&ir);
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *, unsigned long Request, void *)
|
||||
{
|
||||
switch (Request)
|
||||
{
|
||||
case 0x1:
|
||||
Relative();
|
||||
break;
|
||||
case 0x2:
|
||||
Absolute();
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct InodeOperations MouseOps = {
|
||||
.Ioctl = __fs_Ioctl,
|
||||
};
|
||||
|
||||
bool ToolboxSupported = false;
|
||||
int DriverEntry()
|
||||
{
|
||||
ToolboxContext tb_ctx = {0};
|
||||
/* Test if it's supported */
|
||||
int status = OpenMessageChannel(&tb_ctx, MESSAGE_TCLO);
|
||||
if (status == 0)
|
||||
{
|
||||
ToolboxSupported = true;
|
||||
MessageClose(&tb_ctx);
|
||||
dst_id = CreateKernelThread(0, "VMware Display Scale",
|
||||
(void *)DisplayScaleThread, NULL);
|
||||
dst_pid = GetCurrentProcess();
|
||||
}
|
||||
|
||||
PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
|
||||
PS2WriteCommand(PS2_CMD_READ_CONFIG);
|
||||
PS2_CONFIGURATION config = {.Raw = PS2ReadData()};
|
||||
config.Port2Interrupt = 1;
|
||||
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
|
||||
PS2WriteData(config.Raw);
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
|
||||
PS2ReadData();
|
||||
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
|
||||
PS2ReadData();
|
||||
Absolute();
|
||||
|
||||
/**
|
||||
* If we have another driver using the PS/2 mouse, we need to
|
||||
* override its interrupt handler.
|
||||
*/
|
||||
OverrideInterruptHandler(12, InterruptHandler);
|
||||
|
||||
MouseDevID = RegisterDevice(INPUT_TYPE_MOUSE, &MouseOps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverFinal()
|
||||
{
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||
|
||||
Relative();
|
||||
|
||||
UnregisterDevice(MouseDevID);
|
||||
|
||||
if (ToolboxSupported)
|
||||
{
|
||||
KillThread(dst_id, dst_pid, 0);
|
||||
if (tb_ctx->TCLOChannel != -1)
|
||||
MessageClose(tb_ctx);
|
||||
FreeMemory(tb_ctx, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverPanic()
|
||||
{
|
||||
Relative();
|
||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverProbe()
|
||||
{
|
||||
if (!IsVMwareBackdoorAvailable())
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DriverInfo("vmware",
|
||||
"VMware Tools Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
@ -1,512 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <netools.h>
|
||||
#include <errno.h>
|
||||
#include <regs.h>
|
||||
#include <base.h>
|
||||
#include <pci.h>
|
||||
#include <network.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "e1000.hpp"
|
||||
|
||||
class E1000Device
|
||||
{
|
||||
private:
|
||||
PCIHeader0 *Header;
|
||||
uint16_t DeviceID;
|
||||
bool Initialized = false;
|
||||
|
||||
bool EEPROMAvailable;
|
||||
|
||||
struct BARData
|
||||
{
|
||||
uint8_t Type;
|
||||
uint16_t IOBase;
|
||||
uint64_t MemoryBase;
|
||||
} BAR;
|
||||
|
||||
#define E1000_NUM_RX_DESC 32
|
||||
#define E1000_NUM_TX_DESC 8
|
||||
RXDescriptor *RX[E1000_NUM_RX_DESC];
|
||||
TXDescriptor *TX[E1000_NUM_TX_DESC];
|
||||
|
||||
uint16_t RXCurrent;
|
||||
uint16_t TXCurrent;
|
||||
|
||||
const int BaseBufferSize = 8192;
|
||||
const int AdditionalBytes = 16;
|
||||
|
||||
uint32_t CurrentPacket;
|
||||
|
||||
void WriteCMD(uint16_t Address, uint32_t Value)
|
||||
{
|
||||
if (BAR.Type == 0)
|
||||
mmoutl((void *)(BAR.MemoryBase + Address), Value);
|
||||
else
|
||||
{
|
||||
outl(BAR.IOBase, Address);
|
||||
outl(BAR.IOBase + 4, Value);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ReadCMD(uint16_t Address)
|
||||
{
|
||||
if (BAR.Type == 0)
|
||||
return mminl((void *)(BAR.MemoryBase + Address));
|
||||
else
|
||||
{
|
||||
outl(BAR.IOBase, Address);
|
||||
return inl(BAR.IOBase + 0x4);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ReadEEPROM(uint8_t Address)
|
||||
{
|
||||
uint16_t Data = 0;
|
||||
uint32_t temp = 0;
|
||||
if (EEPROMAvailable)
|
||||
{
|
||||
WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 8));
|
||||
while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 4)))
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 2));
|
||||
while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 1)))
|
||||
;
|
||||
}
|
||||
Data = (uint16_t)((temp >> 16) & 0xFFFF);
|
||||
return Data;
|
||||
}
|
||||
|
||||
void InitializeRX()
|
||||
{
|
||||
DebugLog("Initializing RX...");
|
||||
uintptr_t Ptr = (uintptr_t)AllocateMemory(TO_PAGES(sizeof(RXDescriptor) *
|
||||
E1000_NUM_RX_DESC +
|
||||
AdditionalBytes));
|
||||
|
||||
for (int i = 0; i < E1000_NUM_RX_DESC; i++)
|
||||
{
|
||||
RX[i] = (RXDescriptor *)(Ptr + i * 16);
|
||||
RX[i]->Address = (uint64_t)AllocateMemory(TO_PAGES(BaseBufferSize + AdditionalBytes));
|
||||
RX[i]->Status = 0;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
||||
|
||||
WriteCMD(REG::TXDESCLO, (uint32_t)(Ptr >> 32));
|
||||
WriteCMD(REG::TXDESCHI, (uint32_t)(Ptr & 0xFFFFFFFF));
|
||||
|
||||
WriteCMD(REG::RXDESCLO, (uint32_t)Ptr);
|
||||
WriteCMD(REG::RXDESCHI, 0);
|
||||
|
||||
WriteCMD(REG::RXDESCLEN, E1000_NUM_RX_DESC * 16);
|
||||
|
||||
WriteCMD(REG::RXDESCHEAD, 0);
|
||||
WriteCMD(REG::RXDESCTAIL, E1000_NUM_RX_DESC - 1);
|
||||
RXCurrent = 0;
|
||||
WriteCMD(REG::RCTRL, RCTL::EN | RCTL::SBP | RCTL::UPE |
|
||||
RCTL::MPE | RCTL::LBM_NONE |
|
||||
RTCL::RDMTS_HALF | RCTL::BAM |
|
||||
RCTL::SECRC | RCTL::BSIZE_8192);
|
||||
}
|
||||
|
||||
void InitializeTX()
|
||||
{
|
||||
DebugLog("Initializing TX...");
|
||||
uintptr_t Ptr = (uintptr_t)AllocateMemory(TO_PAGES(sizeof(TXDescriptor) *
|
||||
E1000_NUM_RX_DESC +
|
||||
AdditionalBytes));
|
||||
|
||||
for (short i = 0; i < E1000_NUM_TX_DESC; i++)
|
||||
{
|
||||
TX[i] = (TXDescriptor *)((uintptr_t)Ptr + i * 16);
|
||||
TX[i]->Address = 0;
|
||||
TX[i]->Command = 0;
|
||||
TX[i]->Status = TSTA::DD;
|
||||
}
|
||||
|
||||
WriteCMD(REG::TXDESCHI, (uint32_t)((uint64_t)Ptr >> 32));
|
||||
WriteCMD(REG::TXDESCLO, (uint32_t)((uint64_t)Ptr & 0xFFFFFFFF));
|
||||
|
||||
WriteCMD(REG::TXDESCLEN, E1000_NUM_TX_DESC * 16);
|
||||
|
||||
WriteCMD(REG::TXDESCHEAD, 0);
|
||||
WriteCMD(REG::TXDESCTAIL, 0);
|
||||
TXCurrent = 0;
|
||||
WriteCMD(REG::TCTRL, TCTL::EN_ | TCTL::PSP |
|
||||
(15 << TCTL::CT_SHIFT) |
|
||||
(64 << TCTL::COLD_SHIFT) |
|
||||
TCTL::RTLC);
|
||||
|
||||
WriteCMD(REG::TCTRL, 0b0110000000000111111000011111010);
|
||||
WriteCMD(REG::TIPG, 0x0060200A);
|
||||
}
|
||||
|
||||
public:
|
||||
dev_t ID;
|
||||
|
||||
bool IsInitialized() { return Initialized; }
|
||||
|
||||
size_t write(uint8_t *Buffer, size_t Size)
|
||||
{
|
||||
TX[TXCurrent]->Address = (uint64_t)Buffer;
|
||||
TX[TXCurrent]->Length = (uint16_t)Size;
|
||||
TX[TXCurrent]->Command = CMD::EOP | CMD::IFCS | CMD::RS;
|
||||
TX[TXCurrent]->Status = 0;
|
||||
uint16_t OldTXCurrent = TXCurrent;
|
||||
TXCurrent = (uint16_t)((TXCurrent + 1) % E1000_NUM_TX_DESC);
|
||||
WriteCMD(REG::TXDESCTAIL, TXCurrent);
|
||||
while (!(TX[OldTXCurrent]->Status & 0xFF))
|
||||
Yield();
|
||||
return Size;
|
||||
}
|
||||
|
||||
MediaAccessControl GetMAC()
|
||||
{
|
||||
MediaAccessControl mac;
|
||||
if (EEPROMAvailable)
|
||||
{
|
||||
uint32_t temp;
|
||||
temp = ReadEEPROM(0);
|
||||
mac.Address[0] = temp & 0xff;
|
||||
mac.Address[1] = (uint8_t)(temp >> 8);
|
||||
temp = ReadEEPROM(1);
|
||||
mac.Address[2] = temp & 0xff;
|
||||
mac.Address[3] = (uint8_t)(temp >> 8);
|
||||
temp = ReadEEPROM(2);
|
||||
mac.Address[4] = temp & 0xff;
|
||||
mac.Address[5] = (uint8_t)(temp >> 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t *BaseMac8 = (uint8_t *)(BAR.MemoryBase + 0x5400);
|
||||
uint32_t *BaseMac32 = (uint32_t *)(BAR.MemoryBase + 0x5400);
|
||||
if (BaseMac32[0] != 0)
|
||||
for (int i = 0; i < 6; i++)
|
||||
mac.Address[i] = BaseMac8[i];
|
||||
else
|
||||
{
|
||||
KernelLog("No MAC address found.");
|
||||
return MediaAccessControl();
|
||||
}
|
||||
}
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
int ioctl(NetIoctl req, void *arg)
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case IOCTL_NET_GET_MAC:
|
||||
{
|
||||
MediaAccessControl mac = GetMAC();
|
||||
*((uint48_t *)arg) = mac.ToHex(); /* UNTESTED */
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OnInterruptReceived(TrapFrame *)
|
||||
{
|
||||
WriteCMD(REG::IMASK, 0x1);
|
||||
uint32_t status = ReadCMD(0xC0);
|
||||
UNUSED(status);
|
||||
|
||||
while ((RX[RXCurrent]->Status & 0x1))
|
||||
{
|
||||
uint8_t *data = (uint8_t *)RX[RXCurrent]->Address;
|
||||
uint16_t dataSz = RX[RXCurrent]->Length;
|
||||
|
||||
// ReportNetworkPacket(ID, data, dataSz);
|
||||
/* FIXME: Implement */
|
||||
KernelLog("FIXME: Received packet");
|
||||
(void)data;
|
||||
(void)dataSz;
|
||||
|
||||
RX[RXCurrent]->Status = 0;
|
||||
uint16_t OldRXCurrent = RXCurrent;
|
||||
RXCurrent = (uint16_t)((RXCurrent + 1) % E1000_NUM_RX_DESC);
|
||||
WriteCMD(REG::RXDESCTAIL, OldRXCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
void Panic()
|
||||
{
|
||||
WriteCMD(REG::IMASK, 0x00000000);
|
||||
WriteCMD(REG::ITR, 0x00000000);
|
||||
WriteCMD(REG::IAM, 0x00000000);
|
||||
}
|
||||
|
||||
E1000Device(PCIHeader0 *_Header, uint16_t _DeviceID)
|
||||
: Header(_Header),
|
||||
DeviceID(_DeviceID)
|
||||
{
|
||||
uint32_t PCIBAR0 = Header->BAR0;
|
||||
uint32_t PCIBAR1 = Header->BAR1;
|
||||
BAR.Type = PCIBAR0 & 1;
|
||||
BAR.IOBase = (uint16_t)(PCIBAR0 & (~3));
|
||||
BAR.MemoryBase = PCIBAR1 & (~15);
|
||||
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x100E:
|
||||
{
|
||||
KernelLog("Found Intel 82540EM Gigabit Ethernet Controller.");
|
||||
|
||||
/* Detect EEPROM */
|
||||
WriteCMD(REG::EEPROM, 0x1);
|
||||
for (int i = 0; i < 1000 && !EEPROMAvailable; i++)
|
||||
if (ReadCMD(REG::EEPROM) & 0x10)
|
||||
EEPROMAvailable = true;
|
||||
else
|
||||
EEPROMAvailable = false;
|
||||
|
||||
if (!GetMAC().Valid())
|
||||
{
|
||||
KernelLog("Failed to get MAC");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start link */
|
||||
uint32_t cmdret = ReadCMD(REG::CTRL);
|
||||
WriteCMD(REG::CTRL, cmdret | ECTRL::SLU);
|
||||
|
||||
for (int i = 0; i < 0x80; i++)
|
||||
WriteCMD((uint16_t)(0x5200 + i * 4), 0);
|
||||
|
||||
WriteCMD(REG::IMASK, 0x1F6DC);
|
||||
WriteCMD(REG::IMASK, 0xFF & ~4);
|
||||
ReadCMD(0xC0);
|
||||
|
||||
InitializeRX();
|
||||
InitializeTX();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
KernelLog("Unimplemented E1000 device.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
~E1000Device()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x100E:
|
||||
{
|
||||
// Clearing Enable bit in Receive Control Register
|
||||
uint32_t cmdret = ReadCMD(REG::RCTRL);
|
||||
WriteCMD(REG::RCTRL, cmdret & ~RCTL::EN);
|
||||
|
||||
// Masking Interrupt Mask, Interrupt Throttling Rate & Interrupt Auto-Mask
|
||||
WriteCMD(REG::IMASK, 0x00000000);
|
||||
WriteCMD(REG::ITR, 0x00000000);
|
||||
WriteCMD(REG::IAM, 0x00000000);
|
||||
|
||||
// Clearing SLU bit in Device Control Register
|
||||
cmdret = ReadCMD(REG::CTRL);
|
||||
WriteCMD(REG::CTRL, cmdret & ~ECTRL::SLU);
|
||||
|
||||
// Clear the Interrupt Cause Read register by reading it
|
||||
ReadCMD(REG::ICR);
|
||||
|
||||
// Powering down the device (?)
|
||||
WriteCMD(REG::CTRL, PCTRL::POWER_DOWN);
|
||||
/* TODO: Stop link; further testing required */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
KernelLog("Unimplemented E1000 device.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
E1000Device *Drivers[4] = {nullptr};
|
||||
dev_t NetID[4] = {(dev_t)-1};
|
||||
|
||||
#define OIR(x) OIR_##x
|
||||
#define CREATE_OIR(x) \
|
||||
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
|
||||
|
||||
CREATE_OIR(0);
|
||||
CREATE_OIR(1);
|
||||
CREATE_OIR(2);
|
||||
CREATE_OIR(3);
|
||||
|
||||
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
|
||||
int __fs_Close(struct Inode *) { return 0; }
|
||||
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
|
||||
|
||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
||||
{
|
||||
return Drivers[NetID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
return Drivers[NetID[Node->GetMinor()]]->ioctl((NetIoctl)Request, Argp);
|
||||
}
|
||||
|
||||
const struct InodeOperations NetOps = {
|
||||
.Lookup = nullptr,
|
||||
.Create = nullptr,
|
||||
.Remove = nullptr,
|
||||
.Rename = nullptr,
|
||||
.Read = __fs_Read,
|
||||
.Write = __fs_Write,
|
||||
.Truncate = nullptr,
|
||||
.Open = __fs_Open,
|
||||
.Close = __fs_Close,
|
||||
.Ioctl = __fs_Ioctl,
|
||||
.ReadDir = nullptr,
|
||||
.MkDir = nullptr,
|
||||
.RmDir = nullptr,
|
||||
.SymLink = nullptr,
|
||||
.ReadLink = nullptr,
|
||||
.Seek = nullptr,
|
||||
.Stat = nullptr,
|
||||
};
|
||||
|
||||
PCIArray *Devices;
|
||||
EXTERNC int cxx_Panic()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
short Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Drivers[Count] != nullptr)
|
||||
Drivers[Count]->Panic();
|
||||
Count++;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Probe()
|
||||
{
|
||||
uint16_t VendorIDs[] = {0x8086, /* Intel */
|
||||
PCI_END};
|
||||
uint16_t DeviceIDs[] = {0x100E, /* 82540EM */
|
||||
0x100F, /* 82545EM */
|
||||
0x10D3, /* 82574L */
|
||||
0x10EA, /* I217-LM */
|
||||
0x153A, /* 82577LM */
|
||||
PCI_END};
|
||||
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
|
||||
if (Devices == nullptr)
|
||||
{
|
||||
KernelLog("No E1000 device found.");
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Initialize()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count > sizeof(Drivers) / sizeof(E1000Device *))
|
||||
break;
|
||||
|
||||
InitializePCI(ctx->Device);
|
||||
|
||||
Drivers[Count] = new E1000Device((PCIHeader0 *)ctx->Device->Header,
|
||||
ctx->Device->Header->DeviceID);
|
||||
|
||||
if (Drivers[Count]->IsInitialized())
|
||||
{
|
||||
dev_t ret = RegisterDevice(NETWORK_TYPE_ETHERNET, &NetOps);
|
||||
NetID[Count] = ret;
|
||||
Drivers[Count]->ID = ret;
|
||||
|
||||
/* FIXME: bad code */
|
||||
switch (Count)
|
||||
{
|
||||
case 0:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
|
||||
break;
|
||||
case 1:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
|
||||
break;
|
||||
case 2:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
|
||||
break;
|
||||
case 3:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Count++;
|
||||
}
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
KernelLog("No valid E1000 device found.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Finalize()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count++ > sizeof(Drivers) / sizeof(E1000Device *))
|
||||
break;
|
||||
|
||||
delete Drivers[Count++];
|
||||
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(NetID) / sizeof(dev_t); i++)
|
||||
{
|
||||
if (NetID[i] != (dev_t)-1)
|
||||
UnregisterDevice(NetID[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
enum REG
|
||||
{
|
||||
CTRL = 0x0000,
|
||||
STATUS = 0x0008,
|
||||
ICR = 0x000C,
|
||||
EEPROM = 0x0014,
|
||||
CTRL_EXT = 0x0018,
|
||||
ITR = 0x00C4,
|
||||
IMASK = 0x00D0,
|
||||
IAM = 0x00D8,
|
||||
RCTRL = 0x0100,
|
||||
RXDESCLO = 0x2800,
|
||||
RXDESCHI = 0x2804,
|
||||
RXDESCLEN = 0x2808,
|
||||
RXDESCHEAD = 0x2810,
|
||||
RXDESCTAIL = 0x2818,
|
||||
TCTRL = 0x0400,
|
||||
TXDESCLO = 0x3800,
|
||||
TXDESCHI = 0x3804,
|
||||
TXDESCLEN = 0x3808,
|
||||
TXDESCHEAD = 0x3810,
|
||||
TXDESCTAIL = 0x3818,
|
||||
RDTR = 0x2820,
|
||||
RXDCTL = 0x3828,
|
||||
RADV = 0x282C,
|
||||
RSRPD = 0x2C00,
|
||||
TIPG = 0x0410
|
||||
};
|
||||
|
||||
enum PCTRL
|
||||
{
|
||||
RESERVED = 0b000000,
|
||||
SPEED_SELECTION_MSB = 0b010000,
|
||||
UPDATE_COLLISION_TEST = 0b001000,
|
||||
DUPLEX_MODE = 0b000100,
|
||||
RESTART_AUTO_NEGOTIATION = 0b000010,
|
||||
ISOLATE = 0b000001,
|
||||
POWER_DOWN = 0b100000,
|
||||
SPEED_SELECTION_LSB = 0b100000,
|
||||
};
|
||||
|
||||
enum ECTRL
|
||||
{
|
||||
SLU = 0x40
|
||||
};
|
||||
|
||||
enum RTCL
|
||||
{
|
||||
RDMTS_HALF = (0 << 8),
|
||||
RDMTS_QUARTER = (1 << 8),
|
||||
RDMTS_EIGHTH = (2 << 8)
|
||||
};
|
||||
|
||||
enum RCTL
|
||||
{
|
||||
EN = (1 << 1),
|
||||
SBP = (1 << 2),
|
||||
UPE = (1 << 3),
|
||||
MPE = (1 << 4),
|
||||
LPE = (1 << 5),
|
||||
LBM_NONE = (0 << 6),
|
||||
LBM_PHY = (3 << 6),
|
||||
MO_36 = (0 << 12),
|
||||
MO_35 = (1 << 12),
|
||||
MO_34 = (2 << 12),
|
||||
MO_32 = (3 << 12),
|
||||
BAM = (1 << 15),
|
||||
VFE = (1 << 18),
|
||||
CFIEN = (1 << 19),
|
||||
CFI = (1 << 20),
|
||||
DPF = (1 << 22),
|
||||
PMCF = (1 << 23),
|
||||
SECRC = (1 << 26),
|
||||
BSIZE_256 = (3 << 16),
|
||||
BSIZE_512 = (2 << 16),
|
||||
BSIZE_1024 = (1 << 16),
|
||||
BSIZE_2048 = (0 << 16),
|
||||
BSIZE_4096 = ((3 << 16) | (1 << 25)),
|
||||
BSIZE_8192 = ((2 << 16) | (1 << 25)),
|
||||
BSIZE_16384 = ((1 << 16) | (1 << 25))
|
||||
};
|
||||
|
||||
enum CMD
|
||||
{
|
||||
EOP = (1 << 0),
|
||||
IFCS = (1 << 1),
|
||||
IC = (1 << 2),
|
||||
RS = (1 << 3),
|
||||
RPS = (1 << 4),
|
||||
VLE = (1 << 6),
|
||||
IDE = (1 << 7)
|
||||
};
|
||||
|
||||
enum TCTL
|
||||
{
|
||||
EN_ = (1 << 1),
|
||||
PSP = (1 << 3),
|
||||
CT_SHIFT = 4,
|
||||
COLD_SHIFT = 12,
|
||||
SWXOFF = (1 << 22),
|
||||
RTLC = (1 << 24)
|
||||
};
|
||||
|
||||
enum TSTA
|
||||
{
|
||||
DD = (1 << 0),
|
||||
EC = (1 << 1),
|
||||
LC = (1 << 2)
|
||||
};
|
||||
|
||||
enum LSTA
|
||||
{
|
||||
LSTA_TU = (1 << 3)
|
||||
};
|
||||
|
||||
struct RXDescriptor
|
||||
{
|
||||
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 TXDescriptor
|
||||
{
|
||||
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));
|
||||
#endif
|
||||
|
||||
EXTERNC int cxx_Panic();
|
||||
EXTERNC int cxx_Probe();
|
||||
EXTERNC int cxx_Initialize();
|
||||
EXTERNC int cxx_Finalize();
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <base.h>
|
||||
|
||||
#include "e1000.hpp"
|
||||
|
||||
int DriverEntry() { return cxx_Initialize(); }
|
||||
int DriverFinal() { return cxx_Finalize(); }
|
||||
int DriverPanic() { return cxx_Panic(); }
|
||||
int DriverProbe() { return cxx_Probe(); }
|
||||
|
||||
DriverInfo("e1000",
|
||||
"Intel(R) PRO/1000 Network Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <base.h>
|
||||
|
||||
#include "rtl8139.hpp"
|
||||
|
||||
int DriverEntry() { return cxx_Initialize(); }
|
||||
int DriverFinal() { return cxx_Finalize(); }
|
||||
int DriverPanic() { return cxx_Panic(); }
|
||||
int DriverProbe() { return cxx_Probe(); }
|
||||
|
||||
DriverInfo("rtl8139",
|
||||
"Realtek RTL8139 Network Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
@ -1,325 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <netools.h>
|
||||
#include <errno.h>
|
||||
#include <regs.h>
|
||||
#include <base.h>
|
||||
#include <pci.h>
|
||||
#include <network.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "rtl8139.hpp"
|
||||
|
||||
class RTL8139Device
|
||||
{
|
||||
private:
|
||||
PCIHeader0 *Header;
|
||||
bool Initialized = false;
|
||||
|
||||
struct BARData
|
||||
{
|
||||
uint8_t Type;
|
||||
uint16_t IOBase;
|
||||
uint64_t MemoryBase;
|
||||
} BAR;
|
||||
|
||||
const int BaseBufferSize = 8192;
|
||||
const int WRAPBytes = 1500;
|
||||
const int AdditionalBytes = 16;
|
||||
const int BufferSize = BaseBufferSize +
|
||||
WRAPBytes +
|
||||
AdditionalBytes;
|
||||
|
||||
uint8_t *RXBuffer = nullptr;
|
||||
int TXCurrent = 0;
|
||||
uint16_t CurrentPacket = 0;
|
||||
|
||||
uint8_t TSAD[4] = {0x20, 0x24, 0x28, 0x2C};
|
||||
uint8_t TSD[4] = {0x10, 0x14, 0x18, 0x1C};
|
||||
|
||||
public:
|
||||
dev_t ID;
|
||||
|
||||
bool IsInitialized() { return Initialized; }
|
||||
|
||||
size_t write(uint8_t *Buffer, size_t Size)
|
||||
{
|
||||
outl(TSAD[TXCurrent], (uint32_t)(reinterpret_cast<uint64_t>(Buffer)));
|
||||
outl(TSD[TXCurrent++], (uint32_t)Size);
|
||||
if (TXCurrent > 3)
|
||||
TXCurrent = 0;
|
||||
return Size;
|
||||
}
|
||||
|
||||
MediaAccessControl GetMAC()
|
||||
{
|
||||
return MediaAccessControl();
|
||||
}
|
||||
|
||||
int ioctl(NetIoctl req, void *)
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case IOCTL_NET_GET_MAC:
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OnInterruptReceived(TrapFrame *)
|
||||
{
|
||||
/* Acknowledge interrupt */
|
||||
uint16_t status = inw(RegISR);
|
||||
DebugLog("%#lx", status);
|
||||
|
||||
/* Read status */
|
||||
if (status & RecOK)
|
||||
{
|
||||
/* Get the current packet */
|
||||
uint16_t *data = (uint16_t *)(RXBuffer + CurrentPacket);
|
||||
uint16_t dataSz = *(data + 1);
|
||||
data += 2;
|
||||
|
||||
// ReportNetworkPacket(ID, data, dataSz);
|
||||
/* FIXME: Implement */
|
||||
KernelLog("FIXME: Received packet");
|
||||
(void)data;
|
||||
(void)dataSz;
|
||||
|
||||
/* Update CAPR */
|
||||
#define RX_READ_PTR_MASK (~0x3)
|
||||
CurrentPacket = (uint16_t)((CurrentPacket + dataSz + 4 + 3) & RX_READ_PTR_MASK);
|
||||
if (CurrentPacket > BufferSize)
|
||||
CurrentPacket -= uint16_t(BufferSize);
|
||||
outw(RegCAPR, CurrentPacket - 0x10);
|
||||
}
|
||||
|
||||
/* Clear interrupt */
|
||||
outw(RegISR, (RecOK | RecBad | SendOK | SendBad));
|
||||
}
|
||||
|
||||
void Panic()
|
||||
{
|
||||
}
|
||||
|
||||
RTL8139Device(PCIHeader0 *_Header)
|
||||
: Header(_Header)
|
||||
{
|
||||
uint32_t PCIBAR0 = Header->BAR0;
|
||||
uint32_t PCIBAR1 = Header->BAR1;
|
||||
BAR.Type = PCIBAR0 & 1;
|
||||
BAR.IOBase = (uint16_t)(PCIBAR0 & (~3));
|
||||
BAR.MemoryBase = PCIBAR1 & (~15);
|
||||
|
||||
RXBuffer = (uint8_t *)AllocateMemory(TO_PAGES(BufferSize));
|
||||
|
||||
/* Power on */
|
||||
outb(RegCONFIG1, 0x0);
|
||||
|
||||
/* Software Reset */
|
||||
outb(RegCMD, 0x10);
|
||||
while (inb(RegCMD) & 0x10)
|
||||
Yield();
|
||||
|
||||
/* Initialize receive buffer */
|
||||
outl(RegRBSTART, (uint32_t)(reinterpret_cast<uintptr_t>(RXBuffer)));
|
||||
|
||||
/* Configure interrupt mask register */
|
||||
outw(RegIMR, (RecOK | RecBad | SendOK | SendBad));
|
||||
outl(regRCR, (RcAB | RcAM | RcAPM | RcAAP) | RcWRAP);
|
||||
|
||||
/* Enable receive and transmit */
|
||||
outb(RegCMD, 0xC); /* 0xC = RE and TE bit */
|
||||
|
||||
uint32_t MAC1 = inl(RegMAC);
|
||||
uint16_t MAC2 = inw(RegMAR);
|
||||
MediaAccessControl mac = {
|
||||
mac.Address[0] = (uint8_t)MAC1,
|
||||
mac.Address[1] = (uint8_t)(MAC1 >> 8),
|
||||
mac.Address[2] = (uint8_t)(MAC1 >> 16),
|
||||
mac.Address[3] = (uint8_t)(MAC1 >> 24),
|
||||
mac.Address[4] = (uint8_t)MAC2,
|
||||
mac.Address[5] = (uint8_t)(MAC2 >> 8)};
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
~RTL8139Device()
|
||||
{
|
||||
if (!Initialized)
|
||||
return;
|
||||
|
||||
/* FIXME: Shutdown code */
|
||||
}
|
||||
};
|
||||
|
||||
RTL8139Device *Drivers[4] = {nullptr};
|
||||
dev_t NetID[4] = {(dev_t)-1};
|
||||
|
||||
#define OIR(x) OIR_##x
|
||||
#define CREATE_OIR(x) \
|
||||
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
|
||||
|
||||
CREATE_OIR(0);
|
||||
CREATE_OIR(1);
|
||||
CREATE_OIR(2);
|
||||
CREATE_OIR(3);
|
||||
|
||||
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
|
||||
int __fs_Close(struct Inode *) { return 0; }
|
||||
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
|
||||
|
||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
||||
{
|
||||
return Drivers[NetID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
return Drivers[NetID[Node->GetMinor()]]->ioctl((NetIoctl)Request, Argp);
|
||||
}
|
||||
|
||||
const struct InodeOperations NetOps = {
|
||||
.Lookup = nullptr,
|
||||
.Create = nullptr,
|
||||
.Remove = nullptr,
|
||||
.Rename = nullptr,
|
||||
.Read = __fs_Read,
|
||||
.Write = __fs_Write,
|
||||
.Truncate = nullptr,
|
||||
.Open = __fs_Open,
|
||||
.Close = __fs_Close,
|
||||
.Ioctl = __fs_Ioctl,
|
||||
.ReadDir = nullptr,
|
||||
.MkDir = nullptr,
|
||||
.RmDir = nullptr,
|
||||
.SymLink = nullptr,
|
||||
.ReadLink = nullptr,
|
||||
.Seek = nullptr,
|
||||
.Stat = nullptr,
|
||||
};
|
||||
|
||||
PCIArray *Devices;
|
||||
EXTERNC int cxx_Panic()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
short Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Drivers[Count] != nullptr)
|
||||
Drivers[Count]->Panic();
|
||||
Count++;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Probe()
|
||||
{
|
||||
uint16_t VendorIDs[] = {0x10EC, /* Realtek */
|
||||
PCI_END};
|
||||
uint16_t DeviceIDs[] = {0x8139, /* RTL8139 */
|
||||
PCI_END};
|
||||
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
|
||||
if (Devices == nullptr)
|
||||
{
|
||||
KernelLog("No RTL8139 device found.");
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Initialize()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count > sizeof(Drivers) / sizeof(RTL8139Device *))
|
||||
break;
|
||||
|
||||
InitializePCI(ctx->Device);
|
||||
|
||||
Drivers[Count] = new RTL8139Device((PCIHeader0 *)ctx->Device->Header);
|
||||
|
||||
if (Drivers[Count]->IsInitialized())
|
||||
{
|
||||
dev_t ret = RegisterDevice(NETWORK_TYPE_ETHERNET, &NetOps);
|
||||
NetID[Count] = ret;
|
||||
Drivers[Count]->ID = ret;
|
||||
|
||||
/* FIXME: bad code */
|
||||
switch (Count)
|
||||
{
|
||||
case 0:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
|
||||
break;
|
||||
case 1:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
|
||||
break;
|
||||
case 2:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
|
||||
break;
|
||||
case 3:
|
||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Count++;
|
||||
}
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
KernelLog("No valid RTL8139 device found.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int cxx_Finalize()
|
||||
{
|
||||
PCIArray *ctx = Devices;
|
||||
size_t Count = 0;
|
||||
while (ctx != nullptr)
|
||||
{
|
||||
if (Count++ > sizeof(Drivers) / sizeof(RTL8139Device *))
|
||||
break;
|
||||
|
||||
delete Drivers[Count++];
|
||||
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
|
||||
ctx = (PCIArray *)ctx->Next;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(NetID) / sizeof(dev_t); i++)
|
||||
{
|
||||
if (NetID[i] != (dev_t)-1)
|
||||
UnregisterDevice(NetID[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
struct RXQueueEntry
|
||||
{
|
||||
uint8_t *Buffer;
|
||||
uint16_t Size;
|
||||
} __attribute__((packed));
|
||||
|
||||
enum InterruptStatus
|
||||
{
|
||||
RecOK = 0x1,
|
||||
RecBad = 0x2,
|
||||
SendOK = 0x4,
|
||||
SendBad = 0x8,
|
||||
};
|
||||
|
||||
enum ReceiveConfig
|
||||
{
|
||||
/**
|
||||
* Accept broadcast packets
|
||||
* sent to mac ff:ff:ff:ff:ff:ff
|
||||
*/
|
||||
RcAB = 0x1,
|
||||
|
||||
/**
|
||||
* Accept packets sent to the
|
||||
* multicast address
|
||||
*/
|
||||
RcAM = 0x2,
|
||||
|
||||
/**
|
||||
* Accept packets sent to the
|
||||
* NIC's MAC address
|
||||
*/
|
||||
RcAPM = 0x4,
|
||||
|
||||
/**
|
||||
* Accept all packets
|
||||
* (promiscuous mode)
|
||||
*/
|
||||
RcAAP = 0x8,
|
||||
|
||||
/**
|
||||
* The WRAP bit is used to tell the
|
||||
* NIC to wrap around the ring
|
||||
* buffer when it reaches the end
|
||||
* of the buffer.
|
||||
*
|
||||
* @note If this bit is set, the
|
||||
* buffer must have an additional
|
||||
* 1500 bytes of space at the end
|
||||
* of the buffer to prevent the
|
||||
* NIC from overflowing the buffer.
|
||||
*/
|
||||
RcWRAP = 0x80,
|
||||
};
|
||||
|
||||
enum Registers
|
||||
{
|
||||
RegMAC = 0x0,
|
||||
RegMAR = 0x8,
|
||||
RegRBSTART = 0x30,
|
||||
RegCMD = 0x37,
|
||||
RegCAPR = 0x38,
|
||||
regRCR = 0x44,
|
||||
RegCONFIG1 = 0x52,
|
||||
RegIMR = 0x3C,
|
||||
RegISR = 0x3E,
|
||||
};
|
||||
|
||||
EXTERNC int cxx_Panic();
|
||||
EXTERNC int cxx_Probe();
|
||||
EXTERNC int cxx_Initialize();
|
||||
EXTERNC int cxx_Finalize();
|
@ -1,7 +1,9 @@
|
||||
build:
|
||||
make -C ahci build
|
||||
make -C ata build
|
||||
MAKE_TARGETS := build clean
|
||||
DIRECTORIES := $(sort $(dir $(wildcard ./*/)))
|
||||
|
||||
clean:
|
||||
make -C ahci clean
|
||||
make -C ata clean
|
||||
.PHONY: $(MAKE_TARGETS) $(DIRECTORIES)
|
||||
|
||||
$(MAKE_TARGETS): $(DIRECTORIES)
|
||||
|
||||
$(DIRECTORIES):
|
||||
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||
|
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
File diff suppressed because it is too large
Load Diff
@ -1,25 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
EXTERNC int cxx_Panic();
|
||||
EXTERNC int cxx_Probe();
|
||||
EXTERNC int cxx_Initialize();
|
||||
EXTERNC int cxx_Finalize();
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <base.h>
|
||||
|
||||
#include "ahci.hpp"
|
||||
|
||||
int DriverEntry() { return cxx_Initialize(); }
|
||||
int DriverFinal() { return cxx_Finalize(); }
|
||||
int DriverPanic() { return cxx_Panic(); }
|
||||
int DriverProbe() { return cxx_Probe(); }
|
||||
|
||||
DriverInfo("ahci",
|
||||
"Advanced Host Controller Interface Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
@ -1,35 +0,0 @@
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
|
||||
FILENAME = $(notdir $(shell pwd)).drv
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
||||
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Drivers.
|
||||
|
||||
Fennix Drivers 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.
|
||||
|
||||
Fennix Drivers 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 Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <regs.h>
|
||||
#include <base.h>
|
||||
#include <io.h>
|
||||
|
||||
bool IsATAPresent()
|
||||
{
|
||||
outb(0x1F0 + 2, 0);
|
||||
outb(0x1F0 + 3, 0);
|
||||
outb(0x1F0 + 4, 0);
|
||||
outb(0x1F0 + 5, 0);
|
||||
outb(0x1F0 + 7, 0xEC);
|
||||
if (inb(0x1F0 + 7) == 0 || inb(0x1F0 + 1) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MasterInterruptHandler(TrapFrame *)
|
||||
{
|
||||
}
|
||||
|
||||
void SlaveInterruptHandler(TrapFrame *)
|
||||
{
|
||||
}
|
||||
|
||||
int DriverEntry()
|
||||
{
|
||||
RegisterInterruptHandler(14, MasterInterruptHandler);
|
||||
RegisterInterruptHandler(15, SlaveInterruptHandler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverFinal()
|
||||
{
|
||||
UnregisterInterruptHandler(14, MasterInterruptHandler);
|
||||
UnregisterInterruptHandler(15, SlaveInterruptHandler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverPanic()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DriverProbe()
|
||||
{
|
||||
if (!IsATAPresent())
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DriverInfo("ata",
|
||||
"Advanced Technology Attachment Driver",
|
||||
"EnderIce2",
|
||||
0, 0, 1,
|
||||
"GPLv3");
|
Loading…
x
Reference in New Issue
Block a user