Merge remote-tracking branch 'Drivers/master'

This commit is contained in:
EnderIce2 2024-11-20 05:01:24 +02:00
commit c43e8d7b03
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
71 changed files with 13688 additions and 1 deletions

@ -1 +0,0 @@
Subproject commit 60391c032a7e37db0adf0365b75cb5ca1fb683b8

6
Drivers/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
out
*.map
*.o
*.a
*.su
.dccache

View File

@ -0,0 +1,52 @@
{
"Header": {
"prefix": [
"head",
],
"body": [
"#ifndef __FENNIX_DRIVER_${2:header}_H__",
"#define __FENNIX_DRIVER_${2:header}_H__",
"",
"#include <types.h>",
"",
"$0",
"",
"#endif // !__FENNIX_DRIVER_${2:header}_H__",
""
],
"description": "Create header."
},
"Brief": {
"prefix": [
"brief",
],
"body": [
"/** @brief $0 */"
],
"description": "Create documentation brief."
},
"License": {
"prefix": [
"license",
],
"body": [
"/*",
"\tThis file is part of Fennix Drivers.",
"",
"\tFennix Drivers is free software: you can redistribute it and/or",
"\tmodify it under the terms of the GNU General Public License as",
"\tpublished by the Free Software Foundation, either version 3 of",
"\tthe License, or (at your option) any later version.",
"",
"\tFennix Drivers is distributed in the hope that it will be useful,",
"\tbut WITHOUT ANY WARRANTY; without even the implied warranty of",
"\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
"\tGNU General Public License for more details.",
"",
"\tYou should have received a copy of the GNU General Public License",
"\talong with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.",
"*/"
],
"description": "Create kernel license."
}
}

120
Drivers/.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,120 @@
{
"configurations": [
{
"name": "Fennix x64 (Linux, GCC, debug)",
"includePath": [
"${workspaceFolder}/include",
"${workspaceFolder}/include/**"
],
"defines": [
"__debug_vscode__",
"KERNEL_NAME=\"Fennix\"",
"KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"",
"a64",
"DEBUG=\"1\""
],
"compilerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gcc",
"cStandard": "c17",
"cppStandard": "c++20",
"intelliSenseMode": "gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools",
"compilerArgs": [
// Compiler flags
"-fPIC",
"-fPIE",
"-pie",
"-mno-80387",
"-mno-mmx",
"-mno-3dnow",
"-mno-red-zone",
"-mno-sse",
"-mno-sse2",
"-march=x86-64",
"-pipe",
"-ffunction-sections",
"-msoft-float",
"-fno-builtin",
// C++ flags
"-fexceptions",
// Linker flags
"-fPIC",
"-fPIE",
"-pie",
"-Wl,-eDriverEntry",
"-Wl,-static,--no-dynamic-linker,-ztext,--no-warn-rwx-segment",
"-nostdlib",
"-nodefaultlibs",
"-nolibc",
"-zmax-page-size=0x1000",
"-static",
// VSCode flags
"-ffreestanding",
"-nostdinc",
"-nostdinc++"
]
},
{
"name": "Fennix x32 (Linux, GCC, debug)",
"includePath": [
"${workspaceFolder}/include/**"
],
"defines": [
"__debug_vscode__",
"KERNEL_NAME=\"Fennix\"",
"KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"",
"a32",
"DEBUG=\"1\""
],
"compilerPath": "${workspaceFolder}/../tools/cross/bin/i386-elf-gcc",
"cStandard": "c17",
"cppStandard": "c++20",
"intelliSenseMode": "gcc-x86",
"configurationProvider": "ms-vscode.makefile-tools",
"compilerArgs": [
// Compiler flags
"-fPIC",
"-fPIE",
"-pie",
"-mno-80387",
"-mno-mmx",
"-mno-3dnow",
"-mno-red-zone",
"-mno-sse",
"-mno-sse2",
"-march=i386",
"-pipe",
"-ffunction-sections",
"-msoft-float",
"-fno-builtin",
// C++ flags
"-fexceptions",
// Linker flags
"-fPIC",
"-fPIE",
"-pie",
"-Wl,-eDriverEntry",
"-Wl,-static,--no-dynamic-linker,-ztext,--no-warn-rwx-segment",
"-nostdlib",
"-nodefaultlibs",
"-nolibc",
"-zmax-page-size=0x1000",
"-static",
// VSCode flags
"-ffreestanding",
"-nostdinc",
"-nostdinc++"
]
}
],
"version": 4
}

2659
Drivers/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

29
Drivers/LICENSE Normal file
View File

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2022, EnderIce2
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

23
Drivers/Makefile Normal file
View File

@ -0,0 +1,23 @@
build:
cp -rf ../Kernel/include/interface/* include/
mkdir -p out
make -C library build
make -C audio build
make -C input build
make -C misc build
make -C network build
make -C storage build
make -C filesystem build
prepare:
$(info Nothing to prepare)
clean:
rm -rf out
make -C library clean
make -C audio clean
make -C input clean
make -C misc clean
make -C network clean
make -C storage clean
make -C filesystem clean

11
Drivers/README.md Normal file
View File

@ -0,0 +1,11 @@
# Drivers
Drivers for [Fennix](https://github.com/Fennix-Project/Fennix).
---
Use `Fennix` repo to build the operating system.
```bash
git clone --recurse-submodules https://github.com/Fennix-Project/Fennix.git
```

7
Drivers/audio/Makefile Normal file
View File

@ -0,0 +1,7 @@
build:
make -C ac97 build
make -C hda build
clean:
make -C ac97 clean
make -C hda clean

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = ac97.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

881
Drivers/audio/ac97/ac97.cpp Normal file
View File

@ -0,0 +1,881 @@
/*
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;
}

View File

@ -0,0 +1,25 @@
/*
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();

31
Drivers/audio/ac97/main.c Normal file
View File

@ -0,0 +1,31 @@
/*
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");

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = hda.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

263
Drivers/audio/hda/hda.cpp Normal file
View File

@ -0,0 +1,263 @@
/*
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;
}

635
Drivers/audio/hda/hda.hpp Normal file
View File

@ -0,0 +1,635 @@
/*
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();

31
Drivers/audio/hda/main.c Normal file
View File

@ -0,0 +1,31 @@
/*
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");

54
Drivers/config.mk Normal file
View File

@ -0,0 +1,54 @@
CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
DRIVER_LDFLAGS := -nostdlib -nodefaultlibs -nolibc -zmax-page-size=0x1000 \
-Wl,-Map file.map -fvisibility=hidden -Wl,--dynamic-linker=/boot/fennix.elf
ifeq ($(OSARCH), amd64)
DRIVER_CFLAGS := -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
-mno-red-zone -mno-sse -mno-sse2 \
-march=x86-64 -pipe -ffunction-sections \
-msoft-float -fno-builtin
else ifeq ($(OSARCH), i386)
DRIVER_CFLAGS := -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
-mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
-march=i386 -pipe -msoft-float -fno-builtin
else ifeq ($(OSARCH), aarch64)
DRIVER_CFLAGS += -pipe -fno-builtin -fPIC
endif
DRIVER_CFLAGS += -I../../include
ifeq ($(DEBUG), 1)
DRIVER_CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
ifeq ($(OSARCH), amd64)
DRIVER_CFLAGS += -fverbose-asm
endif
ifneq ($(OSARCH), aarch64)
DRIVER_CFLAGS += -fstack-check
endif
DRIVER_LDFLAGS += -ggdb3 -O0
endif
WARNCFLAG = -Wall -Wextra
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CPP) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<

50
Drivers/driver.template Normal file
View File

@ -0,0 +1,50 @@
/*
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>
void InterruptHandler(TrapFrame *Frame)
{
}
int DriverEntry()
{
return 0;
}
int DriverFinal()
{
return 0;
}
int DriverPanic()
{
return 0;
}
int DriverProbe()
{
return 0;
}
DriverInfo("name",
"description",
"author",
0, 0, 0,
"license");

View File

@ -0,0 +1,5 @@
build:
make -C fat build
clean:
make -C fat clean

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = fat.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -0,0 +1,290 @@
/*
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__

View File

@ -0,0 +1,45 @@
/*
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");

259
Drivers/include/aip.h Normal file
View File

@ -0,0 +1,259 @@
/*
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_API_AIP_H__
#define __FENNIX_API_AIP_H__
#include <types.h>
#define PIC1_CMD 0x20
#define PIC1_DATA (PIC1_CMD + 1)
#define PIC2_CMD 0xA0
#define PIC2_DATA (PIC2_CMD + 1)
#define _PIC_EOI 0x20
#define PS2_DATA 0x60
#define PS2_STATUS 0x64
#define PS2_CMD PS2_STATUS
#define PS2_ACK 0xFA
#define PS2_TEST_PASSED 0x55
#define PS2_TEST_FAILED 0xFC
#define PS2_CMD_READ_CONFIG 0x20
#define PS2_CMD_READ_CONFIG_N(n) (PS2_CMD_READ_CONFIG + n)
#define PS2_CMD_WRITE_CONFIG 0x60
#define PS2_CMD_WRITE_CONFIG_N(n) (PS2_CMD_WRITE_CONFIG + n)
#define PS2_CMD_DISABLE_PORT_2 0xA7
#define PS2_CMD_ENABLE_PORT_2 0xA8
#define PS2_CMD_TEST_PORT_2 0xA9
#define PS2_CMD_TEST_CONTROLLER 0xAA
#define PS2_CMD_TEST_PORT_1 0xAB
#define PS2_CMD_DIAGNOSTIC_DUMP 0xAC
#define PS2_CMD_DISABLE_PORT_1 0xAD
#define PS2_CMD_ENABLE_PORT_1 0xAE
#define PS2_CMD_READ_INPUT_PORT 0xC0
#define PS2_CMD_COPY_INPUT_0_3_TO_4_7_STATUS 0xC1
#define PS2_CMD_COPY_INPUT_4_7_TO_4_7_STATUS 0xC2
#define PS2_CMD_READ_OUTPUT_PORT 0xD0
#define PS2_CMD_WRITE_NEXT_BYTE_TO_OUTPUT_PORT 0xD1
#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_1_OUTPUT 0xD2
#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_OUTPUT 0xD3
#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT 0xD4
#define PS2_CMD_PULSE_OUTPUT_LINE(n) (0xF0 + n)
typedef union
{
struct
{
uint8_t OutputBufferFull : 1;
uint8_t InputBufferFull : 1;
uint8_t SystemFlag : 1;
uint8_t CommandData : 1;
uint8_t Unknown1 : 1;
uint8_t Unknown2 : 1;
uint8_t TimeoutError : 1;
uint8_t ParityError : 1;
};
uint8_t Raw;
} PS2_STATUSES;
typedef union
{
struct
{
uint8_t Port1Interrupt : 1;
uint8_t Port2Interrupt : 1;
uint8_t SystemFlag : 1;
uint8_t Zero0 : 1;
uint8_t Port1Clock : 1;
uint8_t Port2Clock : 1;
uint8_t Port1Translation : 1;
uint8_t Zero1 : 1;
};
uint8_t Raw;
} PS2_CONFIGURATION;
typedef union
{
struct
{
uint8_t SystemReset : 1;
uint8_t A20Gate : 1;
uint8_t Port2Clock : 1;
uint8_t Port2Data : 1;
uint8_t Port1OutputBufferFull : 1;
uint8_t Port2OutputBufferFull : 1;
uint8_t Port1InputBufferFull : 1;
uint8_t Port2InputBufferFull : 1;
};
uint8_t Raw;
} PS2_OUTPUT_PORT;
void PIC_EOI(uint8_t IRQ);
void IRQ_MASK(uint8_t IRQ);
void IRQ_UNMASK(uint8_t IRQ);
void PS2Wait(const bool Output);
void PS2WriteCommand(uint8_t Command);
void PS2WriteData(uint8_t Data);
uint8_t PS2ReadData();
uint8_t PS2ReadStatus();
uint8_t PS2ReadAfterACK();
void PS2ClearOutputBuffer();
int PS2ACKTimeout();
#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
#define PS2_KBD_CMD_IDENTIFY 0xF2
#define PS2_KBD_CMD_TYPEMATIC 0xF3
#define PS2_KBD_CMD_ENABLE_SCANNING 0xF4
#define PS2_KBD_CMD_DISABLE_SCANNING 0xF5
#define PS2_KBD_CMD_DEFAULTS 0xF6
#define PS2_KBD_CMD_ALL_TYPEMATIC 0xF7
#define PS2_KBD_CMD_ALL_MAKE_RELEASE 0xF8
#define PS2_KBD_CMD_ALL_MAKE 0xF9
#define PS2_KBD_CMD_ALL_TYPEMATIC_MAKE_RELEASE 0xFA
#define PS2_KBD_CMD_SPECIFIC_TYPEMATIC 0xFB
#define PS2_KBD_CMD_SPECIFIC_MAKE_RELEASE 0xFC
#define PS2_KBD_CMD_SPECIFIC_MAKE 0xFD
#define PS2_KBD_CMD_RESEND 0xFE
#define PS2_KBD_CMD_RESET 0xFF
#define PS2_KBD_RESP_ACK 0xFA
#define PS2_KBD_RESP_ECHO 0xEE
#define PS2_KBD_RESP_RESEND 0xFE
#define PS2_KBD_RESP_TEST_PASSED 0xAA
#define PS2_KBD_RESP_TEST_FAILED 0xFC
#define PS2_KBD_RESP_TEST_FAILED_2 0xFD
typedef enum
{
PS2_KBD_LED_SCROLL_LOCK = 1,
PS2_KBD_LED_NUM_LOCK = 2,
PS2_KBD_LED_CAPS_LOCK = 4
} PS2_KBD_LEDS;
typedef enum
{
PS2_KBD_SCAN_CODE_GET_CURRENT = 0,
PS2_KBD_SCAN_CODE_SET_1 = 1,
PS2_KBD_SCAN_CODE_SET_2 = 2,
PS2_KBD_SCAN_CODE_SET_3 = 3,
PS2_KBD_SC_SET_1 = 0x43,
PS2_KBD_SC_SET_2 = 0x41,
PS2_KBD_SC_SET_3 = 0x3F
} PS2_KBD_SCAN_CODE_SET;
typedef union
{
struct
{
/**
* 00000b - 30Hz
* 11111b - 2Hz
*/
uint8_t RepeatRate : 5;
/**
* 00b - 250ms
* 01b - 500ms
* 10b - 750ms
* 11b - 1000ms
*/
uint8_t Delay : 2;
/**
* Must be zero
*/
uint8_t Zero : 1;
};
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
#define PS2_MOUSE_CMD_GET_STATUS 0xE9
#define PS2_MOUSE_CMD_SET_STREAM_MODE 0xEA
#define PS2_MOUSE_CMD_READ_DATA 0xEB
#define PS2_MOUSE_CMD_RESET_WRAP_MODE 0xEC
#define PS2_MOUSE_CMD_SET_WRAP_MODE 0xEE
#define PS2_MOUSE_CMD_SET_REMOTE_MODE 0xF0
#define PS2_MOUSE_CMD_READ_ID 0xF2
/** Values: 10, 20, 40, 60, 80, 100, 200 */
#define PS2_MOUSE_CMD_SET_SAMPLE_RATE 0xF3
#define PS2_MOUSE_CMD_ENABLE_DATA_REPORTING 0xF4
#define PS2_MOUSE_CMD_DISABLE_DATA_REPORTING 0xF5
#define PS2_MOUSE_CMD_SET_DEFAULTS 0xF6
#define PS2_MOUSE_CMD_RESEND 0xFE
#define PS2_MOUSE_CMD_RESET 0xFF
#define PS2_MOUSE_RESP_ACK 0xFA
#define PS2_MOUSE_RESP_RESEND 0xFE
#define PS2_MOUSE_RESP_TEST_PASSED 0xAA
#define PS2_MOUSE_RESP_TEST_FAILED 0xFC
typedef enum
{
PS2_MOUSE_RES_1 = 0,
PS2_MOUSE_RES_2 = 1,
PS2_MOUSE_RES_4 = 2,
PS2_MOUSE_RES_8 = 3
} PS2_MOUSE_RESOLUTION;
typedef struct
{
union
{
struct
{
uint8_t LeftButton : 1;
uint8_t RightButton : 1;
uint8_t MiddleButton : 1;
uint8_t Always1 : 1;
uint8_t XSign : 1;
uint8_t YSign : 1;
uint8_t XOverflow : 1;
uint8_t YOverflow : 1;
} __attribute__((packed));
uint8_t Raw;
} Base;
uint8_t XMovement;
uint8_t YMovement;
union
{
struct
{
uint8_t Z : 4;
uint8_t Button4 : 1;
uint8_t Button5 : 1;
uint8_t Always0 : 1;
uint8_t Always0_2 : 1;
} __attribute__((packed));
uint8_t Raw;
} ZMovement;
} PS2_MOUSE_PACKET;
#endif // !__FENNIX_API_AIP_H__

93
Drivers/include/aip/kbd.h Normal file
View File

@ -0,0 +1,93 @@
/*
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_API_AIP_KBD_H__
#define __FENNIX_API_AIP_KBD_H__
#include <types.h>
#define PS2_KBD_CMD_SET_LEDS 0xED
#define PS2_KBD_CMD_ECHO 0xEE
#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0
#define PS2_KBD_CMD_IDENTIFY 0xF2
#define PS2_KBD_CMD_TYPEMATIC 0xF3
#define PS2_KBD_CMD_ENABLE_SCANNING 0xF4
#define PS2_KBD_CMD_DISABLE_SCANNING 0xF5
#define PS2_KBD_CMD_DEFAULTS 0xF6
#define PS2_KBD_CMD_ALL_TYPEMATIC 0xF7
#define PS2_KBD_CMD_ALL_MAKE_RELEASE 0xF8
#define PS2_KBD_CMD_ALL_MAKE 0xF9
#define PS2_KBD_CMD_ALL_TYPEMATIC_MAKE_RELEASE 0xFA
#define PS2_KBD_CMD_SPECIFIC_TYPEMATIC 0xFB
#define PS2_KBD_CMD_SPECIFIC_MAKE_RELEASE 0xFC
#define PS2_KBD_CMD_SPECIFIC_MAKE 0xFD
#define PS2_KBD_CMD_RESEND 0xFE
#define PS2_KBD_CMD_RESET 0xFF
#define PS2_KBD_RESP_ACK 0xFA
#define PS2_KBD_RESP_ECHO 0xEE
#define PS2_KBD_RESP_RESEND 0xFE
#define PS2_KBD_RESP_TEST_PASSED 0xAA
#define PS2_KBD_RESP_TEST_FAILED 0xFC
#define PS2_KBD_RESP_TEST_FAILED_2 0xFD
typedef enum
{
PS2_KBD_LED_SCROLL_LOCK = 1,
PS2_KBD_LED_NUM_LOCK = 2,
PS2_KBD_LED_CAPS_LOCK = 4
} PS2_KBD_LEDS;
typedef enum
{
PS2_KBD_SCAN_CODE_GET_CURRENT = 0,
PS2_KBD_SCAN_CODE_SET_1 = 1,
PS2_KBD_SCAN_CODE_SET_2 = 2,
PS2_KBD_SCAN_CODE_SET_3 = 3,
PS2_KBD_SC_SET_1 = 0x43,
PS2_KBD_SC_SET_2 = 0x41,
PS2_KBD_SC_SET_3 = 0x3F
} PS2_KBD_SCAN_CODE_SET;
typedef union
{
struct
{
/**
* 00000b - 30Hz
* 11111b - 2Hz
*/
uint8_t RepeatRate : 5;
/**
* 00b - 250ms
* 01b - 500ms
* 10b - 750ms
* 11b - 1000ms
*/
uint8_t Delay : 2;
/**
* Must be zero
*/
uint8_t Zero : 1;
};
uint8_t Raw;
} PS2_KBD_TYPEMATIC;
#endif // !__FENNIX_API_AIP_KBD_H__

View File

@ -0,0 +1,89 @@
/*
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_API_AIP_MOUSE_H__
#define __FENNIX_API_AIP_MOUSE_H__
#include <types.h>
#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
#define PS2_MOUSE_CMD_GET_STATUS 0xE9
#define PS2_MOUSE_CMD_SET_STREAM_MODE 0xEA
#define PS2_MOUSE_CMD_READ_DATA 0xEB
#define PS2_MOUSE_CMD_RESET_WRAP_MODE 0xEC
#define PS2_MOUSE_CMD_SET_WRAP_MODE 0xEE
#define PS2_MOUSE_CMD_SET_REMOTE_MODE 0xF0
#define PS2_MOUSE_CMD_READ_ID 0xF2
/** Values: 10, 20, 40, 60, 80, 100, 200 */
#define PS2_MOUSE_CMD_SET_SAMPLE_RATE 0xF3
#define PS2_MOUSE_CMD_ENABLE_DATA_REPORTING 0xF4
#define PS2_MOUSE_CMD_DISABLE_DATA_REPORTING 0xF5
#define PS2_MOUSE_CMD_SET_DEFAULTS 0xF6
#define PS2_MOUSE_CMD_RESEND 0xFE
#define PS2_MOUSE_CMD_RESET 0xFF
#define PS2_MOUSE_RESP_ACK 0xFA
#define PS2_MOUSE_RESP_RESEND 0xFE
#define PS2_MOUSE_RESP_TEST_PASSED 0xAA
#define PS2_MOUSE_RESP_TEST_FAILED 0xFC
typedef enum
{
PS2_MOUSE_RES_1 = 0,
PS2_MOUSE_RES_2 = 1,
PS2_MOUSE_RES_4 = 2,
PS2_MOUSE_RES_8 = 3
} PS2_MOUSE_RESOLUTION;
typedef struct
{
union
{
struct
{
uint8_t LeftButton : 1;
uint8_t RightButton : 1;
uint8_t MiddleButton : 1;
uint8_t Always1 : 1;
uint8_t XSign : 1;
uint8_t YSign : 1;
uint8_t XOverflow : 1;
uint8_t YOverflow : 1;
} __attribute__((packed));
uint8_t Raw;
} Base;
uint8_t XMovement;
uint8_t YMovement;
union
{
struct
{
uint8_t Z : 4;
uint8_t Button4 : 1;
uint8_t Button5 : 1;
uint8_t Always0 : 1;
uint8_t Always0_2 : 1;
} __attribute__((packed));
uint8_t Raw;
} ZMovement;
} PS2_MOUSE_PACKET;
#endif // !__FENNIX_API_AIP_MOUSE_H__

29
Drivers/include/audio.h Normal file
View File

@ -0,0 +1,29 @@
/*
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/>.
*/
#ifndef __FENNIX_API_AUDIO_H__
#define __FENNIX_API_AUDIO_H__
#include <types.h>
#if __has_include(<interface/device.h>)
#include <interface/device.h>
#else
#include <device.h>
#endif
#endif // !__FENNIX_API_AUDIO_H__

287
Drivers/include/base.h Normal file
View File

@ -0,0 +1,287 @@
/*
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_API_BASE_H__
#define __FENNIX_API_BASE_H__
#include <driver.h>
#define PAGE_SIZE 0x1000
typedef int CriticalState;
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
/**
* @brief Allocate an amount of memory pages
* @param Pages The amount of pages to allocate
* @return A pointer to the allocated memory, NULL if failed
*/
void *AllocateMemory(size_t Pages);
/**
* @brief Free an amount of memory pages
* @param Pointer The pointer to the memory to free
* @param Pages The amount of pages to free
*
* @note If the pointer is invalid, the error is ignored and the
* function returns
*/
void FreeMemory(void *Pointer, size_t Pages);
/**
* @brief Append a flag to a page
* @param Address The address of the page
* @param Flag The flag to append
*/
void AppendMapFlag(void *Address, PageMapFlags Flag);
/**
* @brief Remove a flag from a page
* @param Address The address of the page
* @param Flag The flag to remove
*/
void RemoveMapFlag(void *Address, PageMapFlags Flag);
/**
* @brief Map pages
* @param PhysicalAddress The physical address to map
* @param VirtualAddress The virtual address to map to
* @param Pages The amount of pages to map
* @param Flags The flags to map the pages with
*/
void MapPages(void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags);
/**
* @brief Unmap pages
* @param VirtualAddress The virtual address to unmap
* @param Pages The amount of pages to unmap
*/
void UnmapPages(void *VirtualAddress, size_t Pages);
/**
* @brief Print to the kernel terminal
* @param Format The format string
* @param ... The arguments to the format string
*
* @note The newline character is automatically appended
*/
void KernelPrint(const char *Format, ...);
/**
* @brief Print to the kernel logger
* @param Format The format string
* @param ... The arguments to the format string
*/
void KernelLog(const char *Format, ...);
/**
* @brief Register an interrupt handler
* @param IRQ The IRQ to register the handler for (IRQ0 != 0x32 but 0)
* @param Handler Function pointer to the handler
* @return 0 on success, errno on failure
*/
int RegisterInterruptHandler(uint8_t IRQ, void *Handler);
/**
* @brief Override an interrupt handler
*
* This function will check all registered handlers (by the drivers)
* for the given IRQ and remove them. Then it will register the new
* handler.
*
* @param IRQ The IRQ to override the handler for (IRQ0 != 0x32 but 0)
* @param Handler Function pointer to the handler
* @return 0 on success, errno on failure
*/
int OverrideInterruptHandler(uint8_t IRQ, void *Handler);
/**
* @brief Unregister an interrupt handler
* @param IRQ The IRQ to unregister the handler for (IRQ0 != 0x32 but 0)
* @param Handler Function pointer to the handler
* @return 0 on success, errno on failure
*/
int UnregisterInterruptHandler(uint8_t IRQ, void *Handler);
/**
* @brief Unregister all interrupt handlers for a given handler
* @param Handler Function pointer to the handler
* @return 0 on success, errno on failure
*/
int UnregisterAllInterruptHandlers(void *Handler);
/**
* @brief Copy memory
* @param Destination The destination
* @param Source The source
* @param Length The length of the memory to copy
* @return The destination
*/
void *MemoryCopy(void *Destination, const void *Source, size_t Length);
/**
* @brief Set memory
* @param Destination The destination
* @param Value The value to set
* @param Length The length of the memory to set
* @return The destination
*/
void *MemorySet(void *Destination, int Value, size_t Length);
/**
* @brief Move memory
* @param Destination The destination
* @param Source The source
* @param Length The length of the memory to move
* @return The destination
*/
void *MemoryMove(void *Destination, const void *Source, size_t Length);
/**
* @brief String length
* @param String The string
* @return The length of the string
*/
size_t StringLength(const char String[]);
char *strstr(const char *Haystack, const char *Needle);
/**
* @brief Create a kernel process
* @param Name The name of the process
* @return The PID of the process, this function never fails
*/
pid_t CreateKernelProcess(const char *Name);
/**
* @brief Create a kernel thread
* @param pId The PID of the process to create the thread in
* @param Name The name of the thread
* @param EntryPoint The entry point of the thread
* @param Argument The argument to pass to the thread (rdi)
* @return The TID of the thread, this function never fails
*/
pid_t CreateKernelThread(pid_t pId, const char *Name, void *EntryPoint,
void *Argument);
/**
* @brief Get the PID of the current process
* @return The PID of the current process
*/
pid_t GetCurrentProcess();
/**
* @brief Kill a process
* @param pId The PID of the process to kill
* @param ExitCode The exit code of the process
* @return 0 on success, errno on failure
*/
int KillProcess(pid_t pId, int ExitCode);
/**
* @brief Kill a thread
* @param tId The TID of the thread to kill
* @param pId The PID of the process the thread is in
* @param ExitCode The exit code of the thread
* @return 0 on success, errno on failure
*/
int KillThread(pid_t tId, pid_t pId, int ExitCode);
/**
* @brief Yield the current thread
*
* This function will yield the current thread to the scheduler.
*/
void Yield();
/**
* @brief Sleep for a given amount of milliseconds
* @param Milliseconds The amount of milliseconds to sleep
*/
void Sleep(uint64_t Milliseconds);
/**
* @brief Enter a critical section
* @return The previous interrupt state
*
* This function will disable interrupts and return the previous
* interrupt state.
*/
CriticalState EnterCriticalSection();
/**
* @brief Leave a critical section
* @param PreviousState The previous interrupt state
*
* This function will restore the previous interrupt state.
*/
void LeaveCriticalSection(CriticalState PreviousState);
/** @copydoc EnterCriticalSection */
#define ECS CriticalState __ECS = EnterCriticalSection()
/** @copydoc LeaveCriticalSection */
#define LCS LeaveCriticalSection(__ECS)
#define DriverInfo(_Name, _Description, _Author, _MajorVersion, \
_MinorVersion, _PathVersion, _License) \
__attribute__((section(".driver.info"))) struct __DriverInfo \
__di = {.Name = _Name, \
.Description = _Description, \
.Author = _Author, \
.Version = {.APIVersion = 0, \
.Major = _MajorVersion, \
.Minor = _MinorVersion, \
.Patch = _PathVersion}, \
.License = _License}
#ifdef DEBUG
#define DebugLog(m, ...) KernelLog(m, ##__VA_ARGS__)
#else
#define DebugLog(m, ...)
#endif // DEBUG
#ifdef __cplusplus
}
#endif // __cplusplus
#ifdef __cplusplus
namespace std
{
typedef decltype(sizeof(0)) size_t;
}
void *operator new(std::size_t Size);
void *operator new[](std::size_t Size);
void operator delete(void *Pointer);
void operator delete[](void *Pointer);
void operator delete(void *Pointer, std::size_t Size);
void operator delete[](void *Pointer, std::size_t Size);
#endif // __cplusplus
#define memcpy(dest, src, len) MemoryCopy(dest, src, len)
#define memset(dest, val, len) MemorySet(dest, val, len)
#define memmove(dest, src, len) MemoryMove(dest, src, len)
#define strlen(str) StringLength(str)
#endif // !__FENNIX_API_BASE_H__

75
Drivers/include/device.h Normal file
View File

@ -0,0 +1,75 @@
/*
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/>.
*/
#ifndef __FENNIX_API_DEVICE_H__
#define __FENNIX_API_DEVICE_H__
#include <types.h>
#ifndef __FENNIX_API_FILESYSTEM_H__
#if __has_include(<interface/fs.h>)
#include <interface/fs.h>
#else
#include <fs.h>
#endif
#endif // !__FENNIX_API_FILESYSTEM_H__
typedef enum
{
DEVICE_TYPE_MASK = 0b1111111100000000000000000000000000000000,
DEVICE_TYPE_NONE = 0b0000000000000000000000000000000000000000,
DEVICE_TYPE_INPUT = 0b0000000100000000000000000000000000000000,
DEVICE_TYPE_AUDIO = 0b0000001000000000000000000000000000000000,
DEVICE_TYPE_NETWORK = 0b0000010000000000000000000000000000000000,
DEVICE_TYPE_BLOCK = 0b0000100000000000000000000000000000000000,
INPUT_TYPE_NONE = DEVICE_TYPE_INPUT + 0,
INPUT_TYPE_KEYBOARD = DEVICE_TYPE_INPUT + 2,
INPUT_TYPE_MOUSE = DEVICE_TYPE_INPUT + 4,
INPUT_TYPE_JOYSTICK = DEVICE_TYPE_INPUT + 8,
INPUT_TYPE_TOUCHSCREEN = DEVICE_TYPE_INPUT + 16,
INPUT_TYPE_GAMEPAD = DEVICE_TYPE_INPUT + 32,
INPUT_TYPE_ACCELEROMETER = DEVICE_TYPE_INPUT + 64,
INPUT_TYPE_GYROSCOPE = DEVICE_TYPE_INPUT + 128,
INPUT_TYPE_MAGNETOMETER = DEVICE_TYPE_INPUT + 256,
AUDIO_TYPE_NONE = DEVICE_TYPE_AUDIO + 0,
AUDIO_TYPE_PWM = DEVICE_TYPE_AUDIO + 2,
AUDIO_TYPE_DSP = DEVICE_TYPE_AUDIO + 4,
AUDIO_TYPE_PCM = DEVICE_TYPE_AUDIO + 8,
AUDIO_TYPE_MIDI = DEVICE_TYPE_AUDIO + 16,
NETWORK_TYPE_NONE = DEVICE_TYPE_NETWORK + 0,
NETWORK_TYPE_ETHERNET = DEVICE_TYPE_NETWORK + 2,
NETWORK_TYPE_WIFI = DEVICE_TYPE_NETWORK + 4,
NETWORK_TYPE_BLUETOOTH = DEVICE_TYPE_NETWORK + 8,
NETWORK_TYPE_UART = DEVICE_TYPE_NETWORK + 16,
BLOCK_TYPE_NONE = DEVICE_TYPE_BLOCK + 0,
BLOCK_TYPE_SDCARD = DEVICE_TYPE_BLOCK + 2,
BLOCK_TYPE_HDD = DEVICE_TYPE_BLOCK + 4,
BLOCK_TYPE_SSD = DEVICE_TYPE_BLOCK + 8,
BLOCK_TYPE_USB = DEVICE_TYPE_BLOCK + 16,
BLOCK_TYPE_NVME = DEVICE_TYPE_BLOCK + 32,
BLOCK_TYPE_CDROM = DEVICE_TYPE_BLOCK + 64,
BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128,
} DeviceType;
EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations);
EXTERNC int UnregisterDevice(dev_t Device);
#endif // !__FENNIX_API_DEVICE_H__

76
Drivers/include/driver.h Normal file
View File

@ -0,0 +1,76 @@
/*
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/>.
*/
#ifndef __FENNIX_API_DRIVER_FUNCTIONS_H__
#define __FENNIX_API_DRIVER_FUNCTIONS_H__
#include <types.h>
typedef struct
{
/* PCIDevice */ void *Device;
/* __PCIArray */ void *Next;
} __PCIArray;
/* ========================================== */
#define PCI_END 0x0000
#define KEY_NULL 0x00
typedef enum
{
IOCTL_AUDIO_GET_VOLUME = 0,
IOCTL_AUDIO_SET_VOLUME = 1,
IOCTL_AUDIO_GET_MUTE = 2,
IOCTL_AUDIO_SET_MUTE = 3,
IOCTL_AUDIO_GET_SAMPLE_RATE = 4,
IOCTL_AUDIO_SET_SAMPLE_RATE = 5,
IOCTL_AUDIO_GET_CHANNELS = 6,
IOCTL_AUDIO_SET_CHANNELS = 7,
} AudioIoctl;
typedef enum
{
IOCTL_NET_GET_MAC = 0,
} NetIoctl;
typedef enum
{
MAP_PRESENT = 1 << 0,
MAP_WRITE = 1 << 1,
MAP_USER = 1 << 2,
MAP_WRITE_THROUGH = 1 << 3,
MAP_CACHE_DISABLE = 1 << 4,
} PageMapFlags;
struct __DriverInfo
{
const char *Name;
const char *Description;
const char *Author;
struct __DriverVersion
{
int APIVersion;
int Major, Minor, Patch;
} Version;
const char *License;
};
#endif // !__FENNIX_API_DRIVER_FUNCTIONS_H__

604
Drivers/include/errno.h Normal file
View File

@ -0,0 +1,604 @@
/*
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/>.
*/
#ifndef __FENNIX_KERNEL_ERRNO_H__
#define __FENNIX_KERNEL_ERRNO_H__
/**
* The documentation for these error codes are from:
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html
*
* Full list:
* https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/basedefs/errno.h.html
*/
typedef enum
{
/**
* No Error
*/
EOK = 0,
/**
* Argument list too long. The sum of the number of bytes used by the
* new process image's argument list and environment list is greater
* than the system-imposed limit of {ARG_MAX} bytes.
* or:
* Lack of space in an output buffer.
* or:
* Argument is greater than the system-imposed maximum.
*/
E2BIG = 1,
/**
* Permission denied. An attempt was made to access a file in a way
* forbidden by its file access permissions.
*/
EACCES = 2,
/**
* Address in use. The specified address is in use.
*/
EADDRINUSE = 3,
/**
* Address not available. The specified address is not available from
* the local system.
*/
EADDRNOTAVAIL = 4,
/**
* Address family not supported. The implementation does not support
* the specified address family, or the specified address is not a
* valid address for the address family of the specified socket.
*/
EAFNOSUPPORT = 5,
/**
* Resource temporarily unavailable. This is a temporary condition
* and later calls to the same routine may complete normally.
*/
EAGAIN = 6,
/**
* Connection already in progress. A connection request is already in
* progress for the specified socket.
*/
EALREADY = 7,
/**
* Bad file descriptor. A file descriptor argument is out of range,
* refers to no open file, or a read (write) request is made to a
* file that is only open for writing (reading).
*/
EBADF = 8,
/**
* Bad message. During a read(), getmsg(), getpmsg(), or ioctl()
* I_RECVFD request to a STREAMS device, a message arrived at the
* head of the STREAM that is inappropriate for the function
* receiving the message.
* read()
* Message waiting to be read on a STREAM is not a data message.
* getmsg() or getpmsg()
* A file descriptor was received instead of a control message.
* ioctl()
* Control or data information was received instead of a file
* descriptor when I_RECVFD was specified.
*/
EBADMSG = 9,
/**
* Resource busy. An attempt was made to make use of a system
* resource that is not currently available, as it is being
* used by another process in a manner that would have
* conflicted with the request being made by this process.
*/
EBUSY = 10,
/**
* Operation canceled. The associated asynchronous operation was
* canceled before completion.
*/
ECANCELED = 11,
/**
* No child process. A wait(), waitid(), or waitpid() function was
* executed by a process that had no existing or unwaited-for
* child process.
*/
ECHILD = 12,
/**
* Connection aborted. The connection has been aborted.
*/
ECONNABORTED = 13,
/**
* Connection refused. An attempt to connect to a socket was refused
* because there was no process listening or because the queue of
* connection requests was full and the underlying protocol does not
* support retransmissions.
*/
ECONNREFUSED = 14,
/**
* Connection reset. The connection was forcibly closed by the peer.
*/
ECONNRESET = 15,
/**
* Resource deadlock would occur. An attempt was made to lock a system
* resource that would have resulted in a deadlock situation.
*/
EDEADLK = 16,
/**
* Destination address required. No bind address was established.
*/
EDESTADDRREQ = 17,
/**
* Domain error. An input argument is outside the defined domain of the
* mathematical function (defined in the ISO C standard).
*/
EDOM = 18,
/**
* Reserved.
*/
EDQUOT = 19,
/**
* File exists. An existing file was mentioned in an inappropriate
* context; for example, as a new link name in the link() function.
*/
EEXIST = 20,
/**
* Bad address. The system detected an invalid address in attempting
* to use an argument of a call. The reliable detection of this error
* cannot be guaranteed, and when not detected may result in the
* generation of a signal, indicating an address violation, which is
* sent to the process.
*/
EFAULT = 21,
/**
* File too large. The size of a file would exceed the maximum file
* size of an implementation or offset maximum established in the
* corresponding file description.
*/
EFBIG = 22,
/**
* Host is unreachable. The destination host cannot be reached
* (probably because the host is down or a remote router cannot
* reach it).
*/
EHOSTUNREACH = 23,
/**
* Identifier removed. Returned during XSI interprocess communication
* if an identifier has been removed from the system.
*/
EIDRM = 24,
/**
* Illegal byte sequence. A wide-character code has been detected that
* does not correspond to a valid character, or a byte sequence does
* not form a valid wide-character code (defined in the ISO C standard).
*/
EILSEQ = 25,
/**
* Operation in progress. This code is used to indicate that an
* asynchronous operation has not yet completed.
* or:
* O_NONBLOCK is set for the socket file descriptor and the connection
* cannot be immediately established.
*/
EINPROGRESS = 26,
/**
* Interrupted function call. An asynchronous signal was caught by the
* process during the execution of an interruptible function. If the
* signal handler performs a normal return, the interrupted function
* call may return this condition (see the Base Definitions volume
* of POSIX.1-2017, <signal.h>).
*/
EINTR = 27,
/**
* Invalid argument. Some invalid argument was supplied; for example,
* specifying an undefined signal in a signal() function or a
* kill() function.
*/
EINVAL = 28,
/**
* Input/output error. Some physical input or output error has occurred.
* This error may be reported on a subsequent operation on the same
* file descriptor. Any other error-causing operation on the same file
* descriptor may cause the [EIO] error indication to be lost.
*/
EIO = 29,
/**
* Socket is connected. The specified socket is already connected.
*/
EISCONN = 30,
/**
* Is a directory. An attempt was made to open a directory with write
* mode specified.
*/
EISDIR = 31,
/**
* Symbolic link loop. A loop exists in symbolic links encountered
* during pathname resolution. This error may also be returned if
* more than {SYMLOOP_MAX} symbolic links are encountered during
* pathname resolution.
*/
ELOOP = 32,
/**
* File descriptor value too large or too many open streams. An
* attempt was made to open a file descriptor with a value greater
* than or equal to {OPEN_MAX}, or an attempt was made to open more
* than the maximum number of streams allowed in the process.
*/
EMFILE = 33,
/**
* Too many links. An attempt was made to have the link count of a
* single file exceed {LINK_MAX}.
*/
EMLINK = 34,
/**
* Message too large. A message sent on a transport provider was
* larger than an internal message buffer or some other network limit.
* or:
* Inappropriate message buffer length.
*/
EMSGSIZE = 35,
/**
* Reserved.
*/
EMULTIHOP = 36,
/**
* Filename too long. The length of a pathname exceeds {PATH_MAX} and
* the implementation considers this to be an error, or a pathname
* component is longer than {NAME_MAX}. This error may also occur
* when pathname substitution, as a result of encountering a
* symbolic link during pathname resolution, results in a pathname
* string the size of which exceeds {PATH_MAX}.
*/
ENAMETOOLONG = 37,
/**
* Network is down. The local network interface used to reach the
* destination is down.
*/
ENETDOWN = 38,
/**
* The connection was aborted by the network.
*/
ENETRESET = 39,
/**
* Network unreachable. No route to the network is present.
*/
ENETUNREACH = 40,
/**
* Too many files open in system. Too many files are currently open
* in the system. The system has reached its predefined limit for
* simultaneously open files and temporarily cannot accept requests
* to open another one.
*/
ENFILE = 41,
/**
* No buffer space available. Insufficient buffer resources were
* available in the system to perform the socket operation.
*/
ENOBUFS = 42,
/**
* No message available. No message is available on the STREAM head
* read queue.
*/
ENODATA = 43,
/**
* No such device. An attempt was made to apply an inappropriate
* function to a device; for example, trying to read a write-only
* device such as a printer.
*/
ENODEV = 44,
/**
* No such file or directory. A component of a specified pathname
* does not exist, or the pathname is an empty string.
*/
ENOENT = 45,
/**
* Executable file format error. A request is made to execute a file
* that, although it has appropriate privileges, is not in the
* format required by the implementation for executable files.
*/
ENOEXEC = 46,
/**
* No locks available. A system-imposed limit on the number of
* simultaneous file and record locks has been reached and no more
* are currently available.
*/
ENOLCK = 47,
/**
* Reserved.
*/
ENOLINK = 48,
/**
* Not enough space. The new process image requires more memory than
* is allowed by the hardware or system-imposed memory management
* constraints.
*/
ENOMEM = 49,
/**
* No message of the desired type. The message queue does not contain
* a message of the required type during XSI interprocess communication.
*/
ENOMSG = 50,
/**
* Protocol not available. The protocol option specified to
* setsockopt() is not supported by the implementation.
*/
ENOPROTOOPT = 51,
/**
* No space left on a device. During the write() function on a
* regular file or when extending a directory, there is no free
* space left on the device.
*/
ENOSPC = 52,
/**
* No STREAM resources. Insufficient STREAMS memory resources are
* available to perform a STREAMS-related function. This is a
* temporary condition; it may be recovered from if other
* processes release resources.
*/
ENOSR = 53,
/**
* Not a STREAM. A STREAM function was attempted on a file descriptor
* that was not associated with a STREAMS device.
*/
ENOSTR = 54,
/**
* Functionality not supported. An attempt was made to use optional
* functionality that is not supported in this implementation.
*/
ENOSYS = 55,
/**
* Socket not connected. The socket is not connected.
*/
ENOTCONN = 56,
/**
* Not a directory. A component of the specified pathname exists, but
* it is not a directory, when a directory was expected; or an
* attempt was made to create a non-directory file, and the specified
* pathname contains at least one non- <slash> character and ends
* with one or more trailing <slash> characters.
*/
ENOTDIR = 57,
/**
* Directory not empty. A directory other than an empty directory
* was supplied when an empty directory was expected.
*/
ENOTEMPTY = 58,
/**
* State not recoverable. The state protected by a robust mutex
* is not recoverable.
*/
ENOTRECOVERABLE = 59,
/**
* Not a socket. The file descriptor does not refer to a socket.
*/
ENOTSOCK = 60,
/**
* Not supported. The implementation does not support the requested
* feature or value.
*/
ENOTSUP = 61,
/**
* Inappropriate I/O control operation. A control function has been
* attempted for a file or special file for which the operation
* is inappropriate.
*/
ENOTTY = 62,
/**
* No such device or address. Input or output on a special file
* refers to a device that does not exist, or makes a request
* beyond the capabilities of the device. It may also occur when,
* for example, a tape drive is not on-line.
*/
ENXIO = 63,
/**
* Operation not supported on socket. The type of socket (address
* family or protocol) does not support the requested operation.
*/
EOPNOTSUPP = 64,
/**
* Value too large to be stored in data type. An operation was
* attempted which would generate a value that is outside the
* range of values that can be represented in the relevant data
* type or that are allowed for a given data item.
*/
EOVERFLOW = 65,
/**
* Previous owner died. The owner of a robust mutex terminated
* while holding the mutex lock.
*/
EOWNERDEAD = 66,
/**
* Operation not permitted. An attempt was made to perform an
* operation limited to processes with appropriate privileges or
* to the owner of a file or other resource.
*/
EPERM = 67,
/**
* Broken pipe. A write was attempted on a socket, pipe, or FIFO
* for which there is no process to read the data.
*/
EPIPE = 68,
/**
* Protocol error. Some protocol error occurred. This error is
* device-specific, but is generally not related to a
* hardware failure.
*/
EPROTO = 69,
/**
* Protocol not supported. The protocol is not supported by the
* address family, or the protocol is not supported by
* the implementation.
*/
EPROTONOSUPPORT = 70,
/**
* Protocol wrong type for socket. The socket type is not
* supported by the protocol.
*/
EPROTOTYPE = 71,
/**
* Result too large or too small. The result of the function
* is too large (overflow) or too small (underflow) to be
* represented in the available space.
*/
ERANGE = 72,
/**
* Read-only file system. An attempt was made to modify a file
* or directory on a file system that is read-only.
*/
EROFS = 73,
/**
* Invalid seek. An attempt was made to access the file offset
* associated with a pipe or FIFO.
*/
ESPIPE = 74,
/**
* No such process. No process can be found corresponding to that
* specified by the given process ID.
*/
ESRCH = 75,
/**
* Reserved.
*/
ESTALE = 76,
/**
* STREAM ioctl() timeout. The timer set for a STREAMS ioctl() call
* has expired. The cause of this error is device-specific and could
* indicate either a hardware or software failure, or a timeout
* value that is too short for the specific operation. The status
* of the ioctl() operation is unspecified.
*/
ETIME = 77,
/**
* Connection timed out. The connection to a remote machine has
* timed out.
* If the connection timed out during execution of the function that
* reported this error (as opposed to timing out prior to the
* function being called), it is unspecified whether the function
* has completed some or all of the documented behavior associated
* with a successful completion of the function.
* or:
* Operation timed out. The time limit associated with the operation
* was exceeded before the operation completed.
*/
ETIMEDOUT = 78,
/**
* Text file busy. An attempt was made to execute a pure-procedure
* program that is currently open for writing, or an attempt has
* been made to open for writing a pure-procedure program that
* is being executed.
*/
ETXTBSY = 79,
/**
* Operation would block. An operation on a socket marked as
* non-blocking has encountered a situation such as no data available
* that otherwise would have caused the function to suspend execution.
*/
EWOULDBLOCK = 80,
/**
* Improper link. A link to a file on another file system was attempted.
*/
EXDEV = 81,
__ERRNO_MAX
} KernelErrors;
#include <types.h>
EXTERNC int *__errno_location(void) __attribute__((const));
#define errno (*__errno_location())
#ifdef __cplusplus
extern "C"
{
#endif
char *strerror(int errnum);
#ifdef __cplusplus
}
#endif
#endif // !__FENNIX_KERNEL_ERRNO_H__

382
Drivers/include/fs.h Normal file
View File

@ -0,0 +1,382 @@
/*
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/>.
*/
#ifndef __FENNIX_API_FILESYSTEM_H__
#define __FENNIX_API_FILESYSTEM_H__
#include <types.h>
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
/**
* File type mask for the upper 32 bits of mode_t.
*
* @note Maybe it will be used in the future.
*/
#define S_IFMT32 037777600000
/**
* File type mask.
*
* This mask is used to extract the file type
* from the mode field of a stat structure.
*
* Doing bitwise AND with this mask will return
* the file type.
* Example: st_mode & S_IFMT
*
* Doing bitwise negation and AND with this mask
* will return the permissions.
* Example: st_mode & ~S_IFMT
*/
#define S_IFMT 0170000
/* Whiteout */
#define S_IFWHT 0160000
/* Socket */
#define S_IFSOCK 0140000
/* Symbolic link */
#define S_IFLNK 0120000
/* Regular file */
#define S_IFREG 0100000
/* Block device */
#define S_IFBLK 0060000
/* Directory */
#define S_IFDIR 0040000
/* Character device */
#define S_IFCHR 0020000
/* FIFO */
#define S_IFIFO 0010000
#define S_ISUID 04000
#define S_ISGID 02000
#define S_ISVTX 01000
/** Owner: RWX */
#define S_IRWXU 0700
/** Owner: R */
#define S_IRUSR 0400
/** Owner: W */
#define S_IWUSR 0200
/** Owner: X */
#define S_IXUSR 0100
/** Group: RWX */
#define S_IRWXG 0070
/** Group: R */
#define S_IRGRP 0040
/** Group: W */
#define S_IWGRP 0020
/** Group: X */
#define S_IXGRP 0010
/** Other: RWX */
#define S_IRWXO 0007
/** Other: R */
#define S_IROTH 0004
/** Other: W */
#define S_IWOTH 0002
/** Other: X */
#define S_IXOTH 0001
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_CREAT 0100
#define O_EXCL 0200
#define O_TRUNC 01000
#define O_APPEND 02000
#define O_NOFOLLOW 0400000
#define O_CLOEXEC 02000000
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#define DT_UNKNOWN 0x0
#define DT_FIFO 0x1
#define DT_CHR 0x2
#define DT_DIR 0x4
#define DT_BLK 0x6
#define DT_REG 0x8
#define DT_LNK 0xA
#define DT_SOCK 0xC
#define DT_WHT 0xE
#define IFTODT(x) ((x) >> 12 & 0xF)
#define DTTOIF(x) ((x) << 12)
#define SYMLOOP_MAX 40
#ifndef __cplusplus
#define static_assert _Static_assert
#endif
#ifdef __LP64__
static_assert(sizeof(dev_t) == 8, "dev_t must be 64 bits");
static_assert(sizeof(ino_t) == 8, "ino_t must be 64 bits");
static_assert(sizeof(mode_t) == 4, "mode_t must be 32 bits");
static_assert(sizeof(nlink_t) == 4, "nlink_t must be 32 bits");
static_assert(sizeof(uid_t) == 4, "uid_t must be 32 bits");
static_assert(sizeof(gid_t) == 4, "gid_t must be 32 bits");
static_assert(sizeof(off_t) == 8, "off_t must be 64 bits");
static_assert(sizeof(time_t) == 8, "time_t must be 64 bits");
static_assert(sizeof(blksize_t) == 8, "blksize_t must be 64 bits");
static_assert(sizeof(blkcnt_t) == 8, "blkcnt_t must be 64 bits");
#else
static_assert(sizeof(dev_t) == 4, "dev_t must be 32 bits");
static_assert(sizeof(ino_t) == 4, "ino_t must be 32 bits");
static_assert(sizeof(mode_t) == 2, "mode_t must be 16 bits");
static_assert(sizeof(nlink_t) == 2, "nlink_t must be 16 bits");
static_assert(sizeof(uid_t) == 2, "uid_t must be 16 bits");
static_assert(sizeof(gid_t) == 2, "gid_t must be 16 bits");
static_assert(sizeof(off_t) == 4, "off_t must be 32 bits");
static_assert(sizeof(time_t) == 4, "time_t must be 32 bits");
static_assert(sizeof(blksize_t) == 4, "blksize_t must be 32 bits");
static_assert(sizeof(blkcnt_t) == 4, "blkcnt_t must be 32 bits");
#endif
#undef static_assert
struct kstat
{
/** Device ID of the file. */
dev_t Device;
/** Inode number. */
ino_t Index;
/** File type and mode. */
mode_t Mode;
/** Number of hard links. */
nlink_t HardLinks;
/** User ID of the file's owner. */
uid_t UserID;
/** Group ID of the file's owner. */
gid_t GroupID;
/** Device ID for special files. */
dev_t RawDevice;
/** Size of the file in bytes. */
off_t Size;
/** Time of last access. */
time_t AccessTime;
/** Time of last modification. */
time_t ModifyTime;
/** Time of last status change. */
time_t ChangeTime;
/** Optimal I/O block size. */
blksize_t BlockSize;
/** Number of blocks allocated. */
blkcnt_t Blocks;
/** Additional file attributes. */
mode_t Attribute;
#ifdef __cplusplus
dev_t MakeDevice(int Major, int Minor)
{
return ((Major & 0xFFF) << 8) |
(Minor & 0xFF);
}
int GetMajor()
{
return ((unsigned int)(Device) >> 8) & 0xFFF;
}
int GetMinor()
{
return Device & 0xFF;
}
void SetFileType(mode_t Type)
{
Mode = (Mode & ~S_IFMT) |
(Type & S_IFMT);
}
mode_t GetFileType() { return Mode & S_IFMT; }
void ClearFileType() { Mode = Mode & ~S_IFMT; }
bool IsType(mode_t Type) { return (Mode & S_IFMT) == Type; }
void SetPermissions(mode_t Permissions)
{
Mode = (Mode & S_IFMT) |
(Permissions & ~S_IFMT);
}
mode_t GetPermissions() { return Mode & ~S_IFMT; }
void ClearPermissions() { Mode = Mode & S_IFMT; }
#endif // __cplusplus
};
struct kdirent
{
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[];
};
struct Inode
{
dev_t Device, RawDevice;
ino_t Index;
mode_t Mode;
uint32_t Flags;
off_t Offset;
uintptr_t KernelData;
void *PrivateData;
#ifdef __cplusplus
/* ... */
void SetDevice(int Major, int Minor)
{
this->RawDevice = ((Major & 0xFFF) << 8) |
(Minor & 0xFF);
}
int GetMajor()
{
return ((unsigned int)(this->RawDevice) >> 8) & 0xFFF;
}
int GetMinor()
{
return this->RawDevice & 0xFF;
}
Inode()
{
Device = 0;
RawDevice = 0;
Index = 0;
Mode = 0;
Flags = 0;
Offset = 0;
KernelData = 0x0;
PrivateData = nullptr;
}
~Inode() = default;
#else // __cplusplus
#define INODE_MAKEDEV(major, minor) \
((dev_t)(((major & 0xFFF) << 8) | \
(minor & 0xFF)))
#define INODE_MAJOR(rdev) \
((int)(((rdev) >> 8) & 0xFFF))
#define INODE_MINOR(rdev) \
((int)((rdev) & 0xFF))
#endif // __cplusplus
};
struct InodeOperations
{
int (*Lookup)(struct Inode *Parent, const char *Name, struct Inode **Result);
int (*Create)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result);
int (*Remove)(struct Inode *Parent, const char *Name);
int (*Rename)(struct Inode *Parent, const char *OldName, const char *NewName);
ssize_t (*Read)(struct Inode *Node, void *Buffer, size_t Size, off_t Offset);
ssize_t (*Write)(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset);
int (*Truncate)(struct Inode *Node, off_t Size);
int (*Open)(struct Inode *Node, int Flags, mode_t Mode);
int (*Close)(struct Inode *Node);
int (*Ioctl)(struct Inode *Node, unsigned long Request, void *Argp);
ssize_t (*ReadDir)(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries);
int (*MkDir)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result);
int (*RmDir)(struct Inode *Parent, const char *Name);
int (*SymLink)(struct Inode *Parent, const char *Name, const char *Target, struct Inode **Result);
ssize_t (*ReadLink)(struct Inode *Node, char *Buffer, size_t Size);
off_t (*Seek)(struct Inode *Node, off_t Offset);
int (*Stat)(struct Inode *Node, struct kstat *Stat);
} __attribute__((packed));
#define I_FLAG_ROOT 0x1
#define I_FLAG_MOUNTPOINT 0x2
#define I_FLAG_CACHE_KEEP 0x4
struct FileSystemInfo;
struct SuperBlockOperations
{
int (*AllocateInode)(struct FileSystemInfo *Info, struct Inode **Result);
int (*DeleteInode)(struct FileSystemInfo *Info, struct Inode *Node);
/**
* Synchronize the filesystem.
*
* Write all pending changes to the disk.
*
* @param Info Inode to synchronize. If NULL, synchronize all inodes.
*
* @return Zero on success, otherwise an error code.
*/
int (*Synchronize)(struct FileSystemInfo *Info, struct Inode *Node);
/**
* Destroy the filesystem.
*
* Unregister the filesystem and free all resources.
*
* @param Info Filesystem to destroy.
*
* @return Zero on success, otherwise an error code.
*/
int (*Destroy)(struct FileSystemInfo *Info);
} __attribute__((packed));
struct FileSystemInfo
{
const char *Name;
const char *RootName;
int Flags;
struct SuperBlockOperations SuperOps;
struct InodeOperations Ops;
void *PrivateData;
} __attribute__((packed));
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
int UnregisterFileSystem(dev_t Device);
#endif // !__FENNIX_API_FILESYSTEM_H__

244
Drivers/include/input.h Normal file
View File

@ -0,0 +1,244 @@
/*
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/>.
*/
#ifndef __FENNIX_API_INPUT_H__
#define __FENNIX_API_INPUT_H__
#include <types.h>
#if __has_include(<interface/device.h>)
#include <interface/device.h>
#else
#include <device.h>
#endif
struct InodeOperations;
typedef enum
{
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_0,
KEY_Q,
KEY_W,
KEY_E,
KEY_R,
KEY_T,
KEY_Y,
KEY_U,
KEY_I,
KEY_O,
KEY_P,
KEY_A,
KEY_S,
KEY_D,
KEY_F,
KEY_G,
KEY_H,
KEY_J,
KEY_K,
KEY_L,
KEY_Z,
KEY_X,
KEY_C,
KEY_V,
KEY_B,
KEY_N,
KEY_M,
KEY_F1,
KEY_F2,
KEY_F3,
KEY_F4,
KEY_F5,
KEY_F6,
KEY_F7,
KEY_F8,
KEY_F9,
KEY_F10,
KEY_F11,
KEY_F12,
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,
KEYPAD_RETURN,
KEYPAD_ASTERISK,
KEYPAD_SLASH,
KEY_LEFT_CTRL,
KEY_RIGHT_CTRL,
KEY_LEFT_SHIFT,
KEY_RIGHT_SHIFT,
KEY_LEFT_ALT,
KEY_RIGHT_ALT,
KEY_ESCAPE,
KEY_MINUS,
KEY_EQUAL,
KEY_BACKSPACE,
KEY_TAB,
KEY_LEFT_BRACKET,
KEY_RIGHT_BRACKET,
KEY_RETURN,
KEY_SEMICOLON,
KEY_APOSTROPHE,
KEY_BACK_TICK,
KEY_BACKSLASH,
KEY_COMMA,
KEY_PERIOD,
KEY_SLASH,
KEY_SPACE,
KEY_CAPS_LOCK,
KEY_NUM_LOCK,
KEY_SCROLL_LOCK,
KEY_PRINT_SCREEN,
KEY_HOME,
KEY_UP_ARROW,
KEY_LEFT_ARROW,
KEY_RIGHT_ARROW,
KEY_DOWN_ARROW,
KEY_PAGE_UP,
KEY_PAGE_DOWN,
KEY_END,
KEY_INSERT,
KEY_DELETE,
KEY_LEFT_GUI,
KEY_RIGHT_GUI,
KEY_APPS,
KEY_MULTIMEDIA_PREV_TRACK,
KEY_MULTIMEDIA_NEXT_TRACK,
KEY_MULTIMEDIA_MUTE,
KEY_MULTIMEDIA_CALCULATOR,
KEY_MULTIMEDIA_PLAY,
KEY_MULTIMEDIA_STOP,
KEY_MULTIMEDIA_VOL_DOWN,
KEY_MULTIMEDIA_VOL_UP,
KEY_MULTIMEDIA_WWW_HOME,
KEY_MULTIMEDIA_WWW_SEARCH,
KEY_MULTIMEDIA_WWW_FAVORITES,
KEY_MULTIMEDIA_WWW_REFRESH,
KEY_MULTIMEDIA_WWW_STOP,
KEY_MULTIMEDIA_WWW_FORWARD,
KEY_MULTIMEDIA_WWW_BACK,
KEY_MULTIMEDIA_MY_COMPUTER,
KEY_MULTIMEDIA_EMAIL,
KEY_MULTIMEDIA_MEDIA_SELECT,
KEY_ACPI_POWER,
KEY_ACPI_SLEEP,
KEY_ACPI_WAKE,
KEY_PRESSED = 0x80,
} KeyScanCodes;
typedef struct
{
KeyScanCodes Key;
union
{
struct
{
char IsScanCode : 1;
};
char Value;
};
unsigned char Character;
} KeyboardReport;
typedef struct
{
long X, Y;
int8_t Z;
uint8_t Absolute : 1;
uint8_t LeftButton : 1;
uint8_t RightButton : 1;
uint8_t MiddleButton : 1;
uint8_t Button4 : 1;
uint8_t Button5 : 1;
uint8_t Button6 : 1;
uint8_t Button7 : 1;
uint8_t Button8 : 1;
} MouseReport;
typedef struct
{
} JoystickReport;
typedef struct
{
uint16_t X, Y;
uint8_t Pressure;
} TouchScreenReport;
typedef struct
{
} GamepadReport;
typedef struct
{
} AccelerometerReport;
typedef struct
{
} GyroscopeReport;
typedef struct
{
} MagnetometerReport;
typedef struct
{
DeviceType Type;
dev_t Device;
union
{
KeyboardReport Keyboard;
MouseReport Mouse;
JoystickReport Joystick;
TouchScreenReport TouchScreen;
GamepadReport Gamepad;
AccelerometerReport Accelerometer;
GyroscopeReport Gyroscope;
MagnetometerReport Magnetometer;
/* ... */
};
} InputReport;
EXTERNC int ReportInputEvent(InputReport *Report);
#endif // !__FENNIX_API_INPUT_H__

239
Drivers/include/io.h Normal file
View File

@ -0,0 +1,239 @@
/*
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_API_IO_H__
#define __FENNIX_API_IO_H__
#include <types.h>
#if defined(__amd64__) || defined(__i386__)
#ifdef __cplusplus
extern "C"
{
#endif
static inline uint8_t inportb(uint16_t Port)
{
uint8_t Result;
__asm__("in %%dx, %%al"
: "=a"(Result)
: "d"(Port));
return Result;
}
static inline uint16_t inportw(uint16_t Port)
{
uint16_t Result;
__asm__("in %%dx, %%ax"
: "=a"(Result)
: "d"(Port));
return Result;
}
static inline uint32_t inportl(uint16_t Port)
{
uint32_t Result;
__asm__ volatile("inl %1, %0"
: "=a"(Result)
: "dN"(Port));
return Result;
}
static inline void outportb(uint16_t Port, uint8_t Data)
{
__asm__ volatile("out %%al, %%dx"
:
: "a"(Data), "d"(Port));
}
static inline void outportw(uint16_t Port, uint16_t Data)
{
__asm__ volatile("out %%ax, %%dx"
:
: "a"(Data), "d"(Port));
}
static inline void outportl(uint16_t Port, uint32_t Data)
{
__asm__ volatile("outl %1, %0"
:
: "dN"(Port), "a"(Data));
}
static inline uint8_t mmioin8(uint64_t Address)
{
__asm__ volatile("" ::
: "memory");
uint8_t Result = *(volatile uint8_t *)Address;
__asm__ volatile("" ::
: "memory");
return Result;
}
static inline uint16_t mmioin16(uint64_t Address)
{
__asm__ volatile("" ::
: "memory");
uint16_t Result = *(volatile uint16_t *)Address;
__asm__ volatile("" ::
: "memory");
return Result;
}
static inline uint32_t mmioin32(uint64_t Address)
{
__asm__ volatile("" ::
: "memory");
uint32_t Result = *(volatile uint32_t *)Address;
__asm__ volatile("" ::
: "memory");
return Result;
}
static inline uint64_t mmioin64(uint64_t Address)
{
__asm__ volatile("" ::
: "memory");
uint64_t Result = *(volatile uint64_t *)Address;
__asm__ volatile("" ::
: "memory");
return Result;
}
static inline void mmioout8(uint64_t Address, uint8_t Data)
{
__asm__ volatile("" ::
: "memory");
*(volatile uint8_t *)Address = Data;
__asm__ volatile("" ::
: "memory");
}
static inline void mmioout16(uint64_t Address, uint16_t Data)
{
__asm__ volatile("" ::
: "memory");
*(volatile uint16_t *)Address = Data;
__asm__ volatile("" ::
: "memory");
}
static inline void mmioout32(uint64_t Address, uint32_t Data)
{
__asm__ volatile("" ::
: "memory");
*(volatile uint32_t *)Address = Data;
__asm__ volatile("" ::
: "memory");
}
static inline void mmioout64(uint64_t Address, uint64_t Data)
{
__asm__ volatile("" ::
: "memory");
*(volatile uint64_t *)Address = Data;
__asm__ volatile("" ::
: "memory");
}
static inline void mmoutb(void *Address, uint8_t Value)
{
__asm__ volatile("mov %1, %0"
: "=m"((*(uint8_t *)(Address)))
: "r"(Value)
: "memory");
}
static inline void mmoutw(void *Address, uint16_t Value)
{
__asm__ volatile("mov %1, %0"
: "=m"((*(uint16_t *)(Address)))
: "r"(Value)
: "memory");
}
static inline void mmoutl(void *Address, uint32_t Value)
{
__asm__ volatile("mov %1, %0"
: "=m"((*(uint32_t *)(Address)))
: "r"(Value)
: "memory");
}
static inline void mmoutq(void *Address, uint64_t Value)
{
__asm__ volatile("mov %1, %0"
: "=m"((*(uint64_t *)(Address)))
: "r"(Value)
: "memory");
}
static inline uint8_t mminb(void *Address)
{
uint8_t Result;
__asm__ volatile("mov %1, %0"
: "=r"(Result)
: "m"((*(uint8_t *)(Address)))
: "memory");
return Result;
}
static inline uint16_t mminw(void *Address)
{
uint16_t Result;
__asm__ volatile("mov %1, %0"
: "=r"(Result)
: "m"((*(uint16_t *)(Address)))
: "memory");
return Result;
}
static inline uint32_t mminl(void *Address)
{
uint32_t Result;
__asm__ volatile("mov %1, %0"
: "=r"(Result)
: "m"((*(uint32_t *)(Address)))
: "memory");
return Result;
}
static inline uint64_t mminq(void *Address)
{
uint64_t Result;
__asm__ volatile("mov %1, %0"
: "=r"(Result)
: "m"((*(uint64_t *)(Address)))
: "memory");
return Result;
}
#ifdef __cplusplus
}
#endif
#define inb(Port) inportb(Port)
#define inw(Port) inportw(Port)
#define inl(Port) inportl(Port)
#define outb(Port, Data) outportb(Port, Data)
#define outw(Port, Data) outportw(Port, Data)
#define outl(Port, Data) outportl(Port, Data)
#endif // defined(__amd64__) || defined(__i386__)
#endif // !__FENNIX_API_IO_H__

145
Drivers/include/netools.h Normal file
View File

@ -0,0 +1,145 @@
/*
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_API_NETWORK_UTILS_H__
#define __FENNIX_API_NETWORK_UTILS_H__
#include <types.h>
typedef __UINT64_TYPE__ uint48_t;
struct MediaAccessControl
{
uint8_t Address[6];
inline bool operator==(const MediaAccessControl &lhs) const
{
return lhs.Address[0] == this->Address[0] &&
lhs.Address[1] == this->Address[1] &&
lhs.Address[2] == this->Address[2] &&
lhs.Address[3] == this->Address[3] &&
lhs.Address[4] == this->Address[4] &&
lhs.Address[5] == this->Address[5];
}
inline bool operator==(const uint48_t &lhs) const
{
MediaAccessControl MAC;
MAC.Address[0] = (uint8_t)((lhs >> 40) & 0xFF);
MAC.Address[1] = (uint8_t)((lhs >> 32) & 0xFF);
MAC.Address[2] = (uint8_t)((lhs >> 24) & 0xFF);
MAC.Address[3] = (uint8_t)((lhs >> 16) & 0xFF);
MAC.Address[4] = (uint8_t)((lhs >> 8) & 0xFF);
MAC.Address[5] = (uint8_t)(lhs & 0xFF);
return MAC.Address[0] == this->Address[0] &&
MAC.Address[1] == this->Address[1] &&
MAC.Address[2] == this->Address[2] &&
MAC.Address[3] == this->Address[3] &&
MAC.Address[4] == this->Address[4] &&
MAC.Address[5] == this->Address[5];
}
inline bool operator!=(const MediaAccessControl &lhs) const { return !(*this == lhs); }
inline bool operator!=(const uint48_t &lhs) const { return !(*this == lhs); }
inline uint48_t ToHex()
{
return ((uint48_t)this->Address[0] << 40) |
((uint48_t)this->Address[1] << 32) |
((uint48_t)this->Address[2] << 24) |
((uint48_t)this->Address[3] << 16) |
((uint48_t)this->Address[4] << 8) |
((uint48_t)this->Address[5]);
}
inline MediaAccessControl FromHex(uint48_t Hex)
{
this->Address[0] = (uint8_t)((Hex >> 40) & 0xFF);
this->Address[1] = (uint8_t)((Hex >> 32) & 0xFF);
this->Address[2] = (uint8_t)((Hex >> 24) & 0xFF);
this->Address[3] = (uint8_t)((Hex >> 16) & 0xFF);
this->Address[4] = (uint8_t)((Hex >> 8) & 0xFF);
this->Address[5] = (uint8_t)(Hex & 0xFF);
return *this;
}
inline bool Valid()
{
// TODO: More complex MAC validation
return (this->Address[0] != 0 ||
this->Address[1] != 0 ||
this->Address[2] != 0 ||
this->Address[3] != 0 ||
this->Address[4] != 0 ||
this->Address[5] != 0) &&
(this->Address[0] != 0xFF ||
this->Address[1] != 0xFF ||
this->Address[2] != 0xFF ||
this->Address[3] != 0xFF ||
this->Address[4] != 0xFF ||
this->Address[5] != 0xFF);
}
};
struct InternetProtocol4
{
uint8_t Address[4];
inline bool operator==(const InternetProtocol4 &lhs) const
{
return lhs.Address[0] == this->Address[0] &&
lhs.Address[1] == this->Address[1] &&
lhs.Address[2] == this->Address[2] &&
lhs.Address[3] == this->Address[3];
}
inline bool operator==(const uint32_t &lhs) const
{
InternetProtocol4 IP;
IP.Address[0] = (uint8_t)((lhs >> 24) & 0xFF);
IP.Address[1] = (uint8_t)((lhs >> 16) & 0xFF);
IP.Address[2] = (uint8_t)((lhs >> 8) & 0xFF);
IP.Address[3] = (uint8_t)(lhs & 0xFF);
return IP.Address[0] == this->Address[0] &&
IP.Address[1] == this->Address[1] &&
IP.Address[2] == this->Address[2] &&
IP.Address[3] == this->Address[3];
}
inline bool operator!=(const InternetProtocol4 &lhs) const { return !(*this == lhs); }
inline bool operator!=(const uint32_t &lhs) const { return !(*this == lhs); }
inline uint32_t ToHex()
{
return ((uint64_t)this->Address[0] << 24) |
((uint64_t)this->Address[1] << 16) |
((uint64_t)this->Address[2] << 8) |
((uint64_t)this->Address[3]);
}
inline InternetProtocol4 FromHex(uint32_t Hex)
{
this->Address[0] = (uint8_t)((Hex >> 24) & 0xFF);
this->Address[1] = (uint8_t)((Hex >> 16) & 0xFF);
this->Address[2] = (uint8_t)((Hex >> 8) & 0xFF);
this->Address[3] = (uint8_t)(Hex & 0xFF);
return *this;
}
};
#endif // !__FENNIX_API_NETWORK_UTILS_H__

29
Drivers/include/network.h Normal file
View File

@ -0,0 +1,29 @@
/*
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/>.
*/
#ifndef __FENNIX_API_NETWORK_H__
#define __FENNIX_API_NETWORK_H__
#include <types.h>
#if __has_include(<interface/device.h>)
#include <interface/device.h>
#else
#include <device.h>
#endif
#endif // !__FENNIX_API_NETWORK_H__

184
Drivers/include/pci.h Normal file
View File

@ -0,0 +1,184 @@
/*
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_API_PCI_H__
#define __FENNIX_API_PCI_H__
#include <types.h>
/* https://sites.uclouvain.be/SystInfo/usr/include/linux/pci_regs.h.html */
typedef enum
{
/** @brief Enable response in I/O space */
PCI_COMMAND_IO = 0x1,
/** @brief Enable response in Memory space */
PCI_COMMAND_MEMORY = 0x2,
/** @brief Enable bus mastering */
PCI_COMMAND_MASTER = 0x4,
/** @brief Enable response to special cycles */
PCI_COMMAND_SPECIAL = 0x8,
/** @brief Use memory write and invalidate */
PCI_COMMAND_INVALIDATE = 0x10,
/** @brief Enable palette snooping */
PCI_COMMAND_VGA_PALETTE = 0x20,
/** @brief Enable parity checking */
PCI_COMMAND_PARITY = 0x40,
/** @brief Enable address/data stepping */
PCI_COMMAND_WAIT = 0x80,
/** @brief Enable SERR */
PCI_COMMAND_SERR = 0x100,
/** @brief Enable back-to-back writes */
PCI_COMMAND_FAST_BACK = 0x200,
/** @brief INTx Emulation Disable */
PCI_COMMAND_INTX_DISABLE = 0x400
} PCI_COMMANDS;
typedef struct
{
uint16_t VendorID;
uint16_t DeviceID;
uint16_t Command;
uint16_t Status;
uint8_t RevisionID;
uint8_t ProgIF;
uint8_t Subclass;
uint8_t Class;
uint8_t CacheLineSize;
uint8_t LatencyTimer;
uint8_t HeaderType;
uint8_t BIST;
} __attribute__((packed)) PCIDeviceHeader;
typedef struct
{
PCIDeviceHeader Header;
uint32_t BAR0;
uint32_t BAR1;
uint32_t BAR2;
uint32_t BAR3;
uint32_t BAR4;
uint32_t BAR5;
uint32_t CardbusCISPointer;
uint16_t SubsystemVendorID;
uint16_t SubsystemID;
uint32_t ExpansionROMBaseAddress;
uint8_t CapabilitiesPointer;
uint8_t Reserved0;
uint16_t Reserved1;
uint32_t Reserved2;
uint8_t InterruptLine;
uint8_t InterruptPin;
uint8_t MinGrant;
uint8_t MaxLatency;
} __attribute__((packed)) PCIHeader0;
typedef struct
{
PCIDeviceHeader Header;
uint32_t BAR0;
uint32_t BAR1;
uint8_t PrimaryBusNumber;
uint8_t SecondaryBusNumber;
uint8_t SubordinateBusNumber;
uint8_t SecondaryLatencyTimer;
uint8_t IOBase;
uint8_t IOLimit;
uint16_t SecondaryStatus;
uint16_t MemoryBase;
uint16_t MemoryLimit;
uint16_t PrefetchableMemoryBase;
uint16_t PrefetchableMemoryLimit;
uint32_t PrefetchableMemoryBaseUpper32;
uint32_t PrefetchableMemoryLimitUpper32;
uint16_t IOBaseUpper16;
uint16_t IOLimitUpper16;
uint8_t CapabilitiesPointer;
uint8_t Reserved0;
uint16_t Reserved1;
uint32_t ExpansionROMBaseAddress;
uint8_t InterruptLine;
uint8_t InterruptPin;
uint16_t BridgeControl;
} __attribute__((packed)) PCIHeader1;
typedef struct
{
PCIDeviceHeader Header;
uint32_t CardbusSocketRegistersBaseAddress;
uint8_t CapabilitiesPointer;
uint8_t Reserved0;
uint16_t SecondaryStatus;
uint8_t PCIbusNumber;
uint8_t CardbusBusNumber;
uint8_t SubordinateBusNumber;
uint8_t CardbusLatencyTimer;
uint32_t MemoryBase0;
uint32_t MemoryLimit0;
uint32_t MemoryBase1;
uint32_t MemoryLimit1;
uint32_t IOBase0;
uint32_t IOLimit0;
uint32_t IOBase1;
uint32_t IOLimit1;
uint8_t InterruptLine;
uint8_t InterruptPin;
uint16_t BridgeControl;
uint16_t SubsystemVendorID;
uint16_t SubsystemID;
uint32_t LegacyBaseAddress;
} __attribute__((packed)) PCIHeader2;
typedef struct
{
uint64_t BaseAddress;
uint16_t PCISegGroup;
uint8_t StartBus;
uint8_t EndBus;
uint32_t Reserved;
} __attribute__((packed)) DeviceConfig;
typedef struct
{
PCIDeviceHeader *Header;
DeviceConfig *Config;
uint32_t Bus;
uint32_t Device;
uint32_t Function;
} __attribute__((packed)) PCIDevice;
typedef struct
{
PCIDevice *Device;
/* PCIArray */ void *Next;
} __attribute__((packed)) PCIArray;
#ifdef __cplusplus
extern "C"
{
#endif
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);
#ifdef __cplusplus
}
#endif
#endif // !__FENNIX_API_PCI_H__

106
Drivers/include/regs.h Normal file
View File

@ -0,0 +1,106 @@
/*
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_API_REGISTERS_H__
#define __FENNIX_API_REGISTERS_H__
#include <types.h>
#if defined(__amd64__)
typedef struct
{
uint64_t r15; // General purpose
uint64_t r14; // General purpose
uint64_t r13; // General purpose
uint64_t r12; // General purpose
uint64_t r11; // General purpose
uint64_t r10; // General purpose
uint64_t r9; // General purpose
uint64_t r8; // General purpose
uint64_t rbp; // Base Pointer (meant for stack frames)
uint64_t rdi; // Destination index for string operations
uint64_t rsi; // Source index for string operations
uint64_t rdx; // Data (commonly extends the A register)
uint64_t rcx; // Counter
uint64_t rbx; // Base
uint64_t rax; // Accumulator
uint64_t InterruptNumber; // Interrupt Number
uint64_t ErrorCode; // Error code
uint64_t rip; // Instruction Pointer
uint64_t cs; // Code Segment
uint64_t rflags; // Register Flags
uint64_t rsp; // Stack Pointer
uint64_t ss; // Stack Segment
} TrapFrame;
#elif defined(__i386__)
typedef struct
{
uint32_t edi; // Destination index for string operations
uint32_t esi; // Source index for string operations
uint32_t ebp; // Base Pointer (meant for stack frames)
uint32_t esp; // Stack Pointer
uint32_t ebx; // Base
uint32_t edx; // Data (commonly extends the A register)
uint32_t ecx; // Counter
uint32_t eax; // Accumulator
uint32_t InterruptNumber; // Interrupt Number
uint32_t ErrorCode; // Error code
uint32_t eip; // Instruction Pointer
uint32_t cs; // Code Segment
uint32_t eflags; // Register Flags
uint32_t r3_esp; // Stack Pointer
uint32_t r3_ss; // Stack Segment
} TrapFrame;
#elif defined(__aarch64__)
typedef struct
{
uint64_t x19; // General purpose
uint64_t x20; // General purpose
uint64_t x21; // General purpose
uint64_t x22; // General purpose
uint64_t x23; // General purpose
uint64_t x24; // General purpose
uint64_t x25; // General purpose
uint64_t x26; // General purpose
uint64_t x27; // Stack frame pointer
uint64_t x28; // Link register
uint64_t x29; // Frame pointer
uint64_t x30; // Program counter
uint64_t sp_el0; // Stack pointer
uint64_t elr_el1; // Exception Link Register
uint64_t spsr_el1; // Saved Program Status Register
uint64_t ErrorCode /* esr_el1 */; // Exception Syndrome Register
uint64_t InterruptNumber /* iar_el1 */; // Interrupt Acknowledge Register
} TrapFrame;
#endif
#endif // !__FENNIX_API_REGISTERS_H__

111
Drivers/include/syscalls.h Normal file
View File

@ -0,0 +1,111 @@
/*
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/>.
*/
#ifndef __FENNIX_API_SYSCALLS_LIST_H__
#define __FENNIX_API_SYSCALLS_LIST_H__
#ifndef syscall0
static inline long syscall0(long syscall)
{
long ret;
__asm__ __volatile__("syscall"
: "=a"(ret)
: "a"(syscall)
: "rcx", "r11", "memory");
return ret;
}
#endif
#ifndef syscall1
static inline long syscall1(long syscall, long arg1)
{
long ret;
__asm__ __volatile__("syscall"
: "=a"(ret)
: "a"(syscall), "D"(arg1)
: "rcx", "r11", "memory");
return ret;
}
#endif
#ifndef syscall2
static inline long syscall2(long syscall, long arg1, long arg2)
{
long ret;
__asm__ __volatile__("syscall"
: "=a"(ret)
: "a"(syscall), "D"(arg1), "S"(arg2)
: "rcx", "r11", "memory");
return ret;
}
#endif
#ifndef syscall3
static inline long syscall3(long syscall, long arg1, long arg2, long arg3)
{
long ret;
__asm__ __volatile__("syscall"
: "=a"(ret)
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3)
: "rcx", "r11", "memory");
return ret;
}
#endif
#ifndef syscall4
static inline long syscall4(long syscall, long arg1, long arg2, long arg3, long arg4)
{
long ret;
register long r10 __asm__("r10") = arg4;
__asm__ __volatile__("syscall"
: "=a"(ret)
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10)
: "rcx", "r11", "memory");
return ret;
}
#endif
#ifndef syscall5
static inline long syscall5(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5)
{
long ret;
register long r10 __asm__("r10") = arg4;
register long r8 __asm__("r8") = arg5;
__asm__ __volatile__("syscall"
: "=a"(ret)
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8)
: "rcx", "r11", "memory");
return ret;
}
#endif
#ifndef syscall6
static inline long syscall6(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6)
{
long ret;
register long r10 __asm__("r10") = arg4;
register long r8 __asm__("r8") = arg5;
register long r9 __asm__("r9") = arg6;
__asm__ __volatile__("syscall"
: "=a"(ret)
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9)
: "rcx", "r11", "memory");
return ret;
}
#endif
#endif // !__FENNIX_API_SYSCALLS_LIST_H__

186
Drivers/include/types.h Normal file
View File

@ -0,0 +1,186 @@
/*
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_API_TYPES_H__
#define __FENNIX_API_TYPES_H__
typedef __INT8_TYPE__ int8_t;
typedef __INT16_TYPE__ int16_t;
typedef __INT32_TYPE__ int32_t;
typedef __INT64_TYPE__ int64_t;
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINT64_TYPE__ uint64_t;
typedef __INT_LEAST8_TYPE__ int_least8_t;
typedef __INT_LEAST16_TYPE__ int_least16_t;
typedef __INT_LEAST32_TYPE__ int_least32_t;
typedef __INT_LEAST64_TYPE__ int_least64_t;
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
typedef __INT_FAST8_TYPE__ int_fast8_t;
typedef __INT_FAST16_TYPE__ int_fast16_t;
typedef __INT_FAST32_TYPE__ int_fast32_t;
typedef __INT_FAST64_TYPE__ int_fast64_t;
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
typedef __INTMAX_TYPE__ intmax_t;
typedef __UINTMAX_TYPE__ uintmax_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
typedef intptr_t ssize_t;
#if defined(__LP64__)
typedef int64_t off_t;
typedef int64_t off64_t;
typedef uint32_t mode_t;
typedef uint64_t dev_t;
typedef uint64_t ino64_t;
typedef uint64_t ino_t;
typedef uint32_t nlink_t;
typedef int64_t blksize_t;
typedef int64_t blkcnt_t;
typedef int64_t blkcnt64_t;
typedef int64_t time_t;
typedef uint32_t uid_t;
typedef uint32_t gid_t;
typedef int64_t clock_t;
typedef int32_t pid_t;
#elif defined(__LP32__)
typedef int32_t off_t;
typedef long long off64_t;
typedef __INT32_TYPE__ mode_t;
typedef int32_t dev_t;
typedef int32_t ino64_t;
typedef int32_t ino_t;
typedef unsigned int nlink_t;
typedef int blksize_t;
typedef int32_t blkcnt_t;
typedef int32_t blkcnt64_t;
typedef int32_t time_t;
typedef unsigned uid_t;
typedef unsigned gid_t;
typedef long clock_t;
typedef int pid_t;
#endif
#define UNUSED(x) (void)(x)
#ifdef __cplusplus
#define EXTERNC extern "C"
#define NULL 0
#else // __cplusplus
#define NULL ((void *)0)
#define bool _Bool
#define EXTERNC
#endif // __cplusplus
#define true 1
#define false 0
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define MAX(a, b) \
({ \
__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a > _b ? _a : _b; \
})
#define MIN(a, b) \
({ \
__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a < _b ? _a : _b; \
})
#ifndef __va_list__
typedef __builtin_va_list va_list;
#endif
#define asm __asm__
#define asmv __asm__ volatile
#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus)
#define static_assert _Static_assert
#endif
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, l) __builtin_va_arg(v, l)
#define TO_PAGES(d) (((d) + PAGE_SIZE - 1) / PAGE_SIZE)
#define FROM_PAGES(d) ((d) * PAGE_SIZE)
#define __unused __attribute__((unused))
#define __packed __attribute__((packed))
#define __naked __attribute__((naked))
#define __aligned(x) __attribute__((aligned(x)))
#define __section(x) __attribute__((section(x)))
#define __noreturn __attribute__((noreturn))
#define __weak __attribute__((weak))
#define __alias(x) __attribute__((alias(x)))
#define __always_inline __attribute__((always_inline))
#define __noinline __attribute__((noinline))
#define __pure __attribute__((pure))
#define __const __attribute__((const))
#define __malloc __attribute__((malloc))
#define __returns_twice __attribute__((returns_twice))
#define __used __attribute__((used))
#define __deprecated __attribute__((deprecated))
#define __deprecated_msg(x) __attribute__((deprecated(x)))
#define __weakref(x) __attribute__((weakref(x)))
#define __weakrefalias(x) __attribute__((weakref(#x)))
#define __visibility(x) __attribute__((visibility(x)))
#define __constructor __attribute__((constructor))
#define __destructor __attribute__((destructor))
#define __cleanup(x) __attribute__((cleanup(x)))
#define __fallthrough __attribute__((fallthrough))
#define __nonnull(x) __attribute__((nonnull x))
#define __nonnull_all __attribute__((nonnull))
#define __returns_nonnull __attribute__((returns_nonnull))
#define __sentinel __attribute__((sentinel))
#define __sentinel_all __attribute__((sentinel(0)))
#define __format(x, y, z) __attribute__((format(x, y, z)))
#define __format_arg(x) __attribute__((format_arg(x)))
#define __nonnull_params(x) __attribute__((nonnull x))
#define __nonnull_all __attribute__((nonnull))
#define __warn_unused_result __attribute__((warn_unused_result))
#define __no_stack_protector __attribute__((no_stack_protector))
#define __no_instrument_function __attribute__((no_instrument_function))
#define __no_debug __attribute__((no_debug))
#define __target(x) __attribute__((target(x)))
#define __min_vector_width(x) __attribute__((min_vector_width(x)))
#define __sync __sync_synchronize()
#define __unreachable __builtin_unreachable()
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif // !__FENNIX_API_TYPES_H__

5
Drivers/input/Makefile Normal file
View File

@ -0,0 +1,5 @@
build:
make -C aip build
clean:
make -C aip clean

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = aip.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

39
Drivers/input/aip/aip.h Normal file
View File

@ -0,0 +1,39 @@
/*
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__

View File

@ -0,0 +1,335 @@
/*
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;
}

235
Drivers/input/aip/main.c Normal file
View File

@ -0,0 +1,235 @@
/*
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");

244
Drivers/input/aip/mouse.c Normal file
View File

@ -0,0 +1,244 @@
/*
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;
}

646
Drivers/input/aip/uart.c Normal file
View File

@ -0,0 +1,646 @@
/*
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);
// }

83
Drivers/library/Makefile Normal file
View File

@ -0,0 +1,83 @@
# Config file
include ../../Makefile.conf
FILENAME = libkernel.so
CC = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
CPP = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
LD = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
AS = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
AR = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)ar
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./crt/*")
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./crt/*")
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./crt/*")
HEADERS = $(sort $(dir $(wildcard ../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
INCLUDE_DIR = ../include
LDFLAGS := -fPIC -fPIE -pie -nostdlib -nodefaultlibs -nolibc \
-zmax-page-size=0x1000 -Wl,-Map libkernel.map -shared
WARNCFLAG = -Wall -Wextra
CFLAGS := -I$(INCLUDE_DIR) -shared
ifeq ($(OSARCH), amd64)
CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
-mno-red-zone -mno-sse -mno-sse2 \
-march=x86-64 -pipe -ffunction-sections \
-msoft-float -fno-builtin
else ifeq ($(OSARCH), i386)
CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
-mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
-march=i386 -pipe -msoft-float -fno-builtin
else ifeq ($(OSARCH), aarch64)
CFLAGS += -pipe -fno-builtin -fPIC
endif
CRT_CFLAGS := -fPIC -fPIE -pie -mno-red-zone -std=c++20 -I../include
ifeq ($(DEBUG), 1)
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
CRT_CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
ifeq ($(OSARCH), amd64)
CFLAGS += -fverbose-asm
CRT_CFLAGS += -fverbose-asm
endif
ifneq ($(OSARCH), aarch64)
CFLAGS += -fstack-check
CRT_CFLAGS += -fstack-check
endif
LDFLAGS += -ggdb3 -O0
endif
build: $(FILENAME)
$(CPP) $(CRT_CFLAGS) -c crt/crt0.cpp -o dcrt0.o
mv dcrt0.o ../out/dcrt0.o
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(LDFLAGS) $(OBJ) -o ../out/$(FILENAME)
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f libkernel.map $(OBJ) $(FILENAME) $(STACK_USAGE_OBJ) dcrt0.su

94
Drivers/library/base.cpp Normal file
View File

@ -0,0 +1,94 @@
/*
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 <driver.h>
#include <errno.h>
#include <fs.h>
extern "C" dev_t DriverID;
#define KernelFunction(Name) \
extern "C" __attribute__((naked, used)) long \
__##Name(dev_t, long, long, long, \
long, long, long) { return 0; }
void *operator new(__SIZE_TYPE__) { return (void *)1; }
void *operator new[](__SIZE_TYPE__) { return (void *)1; }
void operator delete(void *) {}
void operator delete[](void *) {}
void operator delete(void *, __SIZE_TYPE__) {}
void operator delete[](void *, __SIZE_TYPE__) {}
KernelFunction(KernelPrint);
KernelFunction(KernelLog);
KernelFunction(RegisterInterruptHandler);
KernelFunction(OverrideInterruptHandler);
KernelFunction(UnregisterInterruptHandler);
KernelFunction(UnregisterAllInterruptHandlers);
KernelFunction(AllocateMemory);
KernelFunction(FreeMemory);
KernelFunction(AppendMapFlag);
KernelFunction(RemoveMapFlag);
KernelFunction(MapPages);
KernelFunction(UnmapPages);
KernelFunction(MemoryCopy);
KernelFunction(MemorySet);
KernelFunction(MemoryMove);
KernelFunction(StringLength);
KernelFunction(strstr);
KernelFunction(EnterCriticalSection);
KernelFunction(LeaveCriticalSection);
KernelFunction(CreateKernelProcess);
KernelFunction(CreateKernelThread);
KernelFunction(GetCurrentProcess);
KernelFunction(KillProcess);
KernelFunction(KillThread);
KernelFunction(Yield);
KernelFunction(Sleep);
KernelFunction(RegisterFileSystem);
KernelFunction(UnregisterFileSystem);
KernelFunction(PIC_EOI);
KernelFunction(IRQ_MASK);
KernelFunction(IRQ_UNMASK);
KernelFunction(PS2Wait);
KernelFunction(PS2WriteCommand);
KernelFunction(PS2WriteData);
KernelFunction(PS2ReadData);
KernelFunction(PS2ReadStatus);
KernelFunction(PS2ReadAfterACK);
KernelFunction(PS2ClearOutputBuffer);
KernelFunction(PS2ACKTimeout);
KernelFunction(RegisterDevice);
KernelFunction(UnregisterDevice);
KernelFunction(ReportInputEvent);
KernelFunction(InitializePCI);
KernelFunction(GetPCIDevices);
KernelFunction(GetBAR);
KernelFunction(iLine);
KernelFunction(iPin);

View File

@ -0,0 +1,144 @@
/*
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>
dev_t DriverID = -1;
extern "C" int DriverEntry();
extern "C" int DriverFinal();
extern "C" int DriverPanic();
extern "C" int DriverProbe();
typedef void (*CallPtr)(void);
extern "C" CallPtr __init_array_start[0], __init_array_end[0];
extern "C" CallPtr __fini_array_start[0], __fini_array_end[0];
extern "C" int _start(dev_t id)
{
DriverID = id;
for (CallPtr *func = __init_array_start; func != __init_array_end; func++)
(*func)();
return 0;
}
extern "C" int _final()
{
int err = DriverFinal();
for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++)
(*func)();
return err;
}
/* ---------------------------------------------------------- */
#define KCALL extern "C" __attribute__((used))
#define KernelFunction(Name) \
KCALL long __##Name(dev_t id, \
long arg0 = 0, long arg1 = 0, long arg2 = 0, \
long arg3 = 0, long arg4 = 0, long arg5 = 0);
#define DefineFunction(ReturnType, Name, ...) \
KernelFunction(Name); \
KCALL ReturnType Name(__VA_ARGS__)
#define DefineWrapper(Name) \
KernelFunction(Name); \
KCALL long Name(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) \
{ \
return __##Name(DriverID, arg0, arg1, arg2, arg3, arg4, arg5); \
}
DefineFunction(void, KernelPrint, const char *format, ...)
{
__builtin_va_list args;
__builtin_va_start(args, format);
__KernelPrint(DriverID, (long)format, (long)args);
__builtin_va_end(args);
}
DefineFunction(void, KernelLog, const char *format, ...)
{
__builtin_va_list args;
__builtin_va_start(args, format);
__KernelLog(DriverID, (long)format, (long)args);
__builtin_va_end(args);
}
DefineWrapper(RegisterInterruptHandler);
DefineWrapper(OverrideInterruptHandler);
DefineWrapper(UnregisterInterruptHandler);
DefineWrapper(UnregisterAllInterruptHandlers);
DefineWrapper(AllocateMemory);
DefineWrapper(FreeMemory);
DefineWrapper(AppendMapFlag);
DefineWrapper(RemoveMapFlag);
DefineWrapper(MapPages);
DefineWrapper(UnmapPages);
DefineWrapper(MemoryCopy);
DefineWrapper(MemorySet);
DefineWrapper(MemoryMove);
DefineWrapper(StringLength);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
DefineWrapper(strstr);
#pragma GCC diagnostic pop
DefineWrapper(EnterCriticalSection);
DefineWrapper(LeaveCriticalSection);
DefineWrapper(CreateKernelProcess);
DefineWrapper(CreateKernelThread);
DefineWrapper(GetCurrentProcess);
DefineWrapper(KillProcess);
DefineWrapper(KillThread);
DefineWrapper(Yield);
DefineWrapper(Sleep);
DefineWrapper(RegisterFileSystem);
DefineWrapper(UnregisterFileSystem);
DefineWrapper(PIC_EOI);
DefineWrapper(IRQ_MASK);
DefineWrapper(IRQ_UNMASK);
DefineWrapper(PS2Wait);
DefineWrapper(PS2WriteCommand);
DefineWrapper(PS2WriteData);
DefineWrapper(PS2ReadData);
DefineWrapper(PS2ReadStatus);
DefineWrapper(PS2ReadAfterACK);
DefineWrapper(PS2ClearOutputBuffer);
DefineWrapper(PS2ACKTimeout);
DefineWrapper(RegisterDevice);
DefineWrapper(UnregisterDevice);
DefineWrapper(ReportInputEvent);
DefineWrapper(InitializePCI);
DefineWrapper(GetPCIDevices);
DefineWrapper(GetBAR);
DefineWrapper(iLine);
DefineWrapper(iPin);

7
Drivers/misc/Makefile Normal file
View File

@ -0,0 +1,7 @@
build:
make -C example build
make -C vmware build
clean:
make -C example clean
make -C vmware clean

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = example.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -0,0 +1,97 @@
/*
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()
{
/** This is the main function of the driver.
* This function should be used to initialize the PCI device
* and allocate resources.
*/
/* Print a message to the kernel terminal */
KernelPrint("Hello World from Example Driver!");
/* Print a message to the kernel log */
KernelLog("Hello World from Example Driver!");
/* Print a message only if DEBUG is set */
DebugLog("Hello World from Example Driver!");
/* Return 0 to indicate success */
return 0;
}
int DriverFinal()
{
/** This function is called when the driver is unloaded.
* This function should be used to stop the PCI device and
* free any resources.
*/
return 0;
}
int DriverPanic()
{
/** This function is called when the kernel panics.
* This function should be used to stop the driver from
* sending interrupts or anything else that is not
* safe to do when the kernel panics.
*/
return 0;
}
int DriverProbe()
{
/** This is the first function that is called when the
* driver is loaded.
*
* This function is to test if the driver is compatible
* with the hardware.
* Example: Like if there is a PCI device that the driver
* is for, or a CPU feature that etc.
*
* Return 0 if the driver is compatible with the hardware.
* Otherwise, return a value that is not 0.
*
* Note: In this function you cannot use variables that
* have constructors or destructors. Before DriverEntry,
* the constructors are called and after DriverFinalize,
* the destructors are called.
*/
return 0;
}
/** DriverInfo() is a macro that is used to define the
* driver's information.
*
* The parameters are:
* - Name: Lowercase name
* - Description: A short description
* - Author: The author
* - Version: The version
* - License: The license
*/
DriverInfo("example",
"Example Driver",
"EnderIce2",
0, 0, 1,
"GPLv3");

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = vmware.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

878
Drivers/misc/vmware/main.c Normal file
View File

@ -0,0 +1,878 @@
/*
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)
#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")
/* 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");

7
Drivers/network/Makefile Normal file
View File

@ -0,0 +1,7 @@
build:
make -C e1000 build
make -C rtl8139 build
clean:
make -C e1000 clean
make -C rtl8139 clean

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = e1000.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -0,0 +1,512 @@
/*
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;
}

View File

@ -0,0 +1,163 @@
/*
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();

View File

@ -0,0 +1,31 @@
/*
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");

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = rtl8139.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -0,0 +1,31 @@
/*
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");

View File

@ -0,0 +1,325 @@
/*
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;
}

View File

@ -0,0 +1,93 @@
/*
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();

7
Drivers/storage/Makefile Normal file
View File

@ -0,0 +1,7 @@
build:
make -C ahci build
make -C ata build
clean:
make -C ahci clean
make -C ata clean

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = ahci.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
/*
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();

View File

@ -0,0 +1,31 @@
/*
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");

View File

@ -0,0 +1,22 @@
# Config files
include ../../../Makefile.conf
include ../../config.mk
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
FILENAME = ata.drv
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(DRIVER_LDFLAGS) $(OBJ) ../../out/dcrt0.o -L../../out -lkernel -o $@
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

View File

@ -0,0 +1,76 @@
/*
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");