mirror of
https://github.com/Fennix-Project/Drivers.git
synced 2025-05-25 22:14:31 +00:00
Update drivers
This commit is contained in:
parent
2ee57b9756
commit
da4a6317ea
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
out
|
out
|
||||||
*.map
|
*.map
|
||||||
*.o
|
*.o
|
||||||
|
*.a
|
||||||
|
*.su
|
||||||
.dccache
|
.dccache
|
||||||
|
24
.vscode/c_boilerplates.code-snippets
vendored
24
.vscode/c_boilerplates.code-snippets
vendored
@ -24,5 +24,29 @@
|
|||||||
"/** @brief $0 */"
|
"/** @brief $0 */"
|
||||||
],
|
],
|
||||||
"description": "Create documentation brief."
|
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +0,0 @@
|
|||||||
build:
|
|
||||||
|
|
||||||
clean:
|
|
10
Doxyfile
10
Doxyfile
@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
|
|||||||
# title of most generated pages and in a few other places.
|
# title of most generated pages and in a few other places.
|
||||||
# The default value is: My Project.
|
# The default value is: My Project.
|
||||||
|
|
||||||
PROJECT_NAME = "Fennix Modules"
|
PROJECT_NAME = "Fennix Drivers"
|
||||||
|
|
||||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
@ -44,7 +44,7 @@ PROJECT_NUMBER = 1.0.0
|
|||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
# quick idea about the purpose of the project. Keep the description short.
|
# quick idea about the purpose of the project. Keep the description short.
|
||||||
|
|
||||||
PROJECT_BRIEF = "Fennix Userspace Documentation"
|
PROJECT_BRIEF = "Driver API Documentation"
|
||||||
|
|
||||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||||
# in the documentation. The maximum height of the logo should not exceed 55
|
# in the documentation. The maximum height of the logo should not exceed 55
|
||||||
@ -864,7 +864,7 @@ WARN_LOGFILE =
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = Modules tools/Doxygen_README.md
|
INPUT = Drivers/include tools/doxymds/drivers.md
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
@ -1064,7 +1064,7 @@ FILTER_SOURCE_PATTERNS =
|
|||||||
# (index.html). This can be useful if you have a project on for instance GitHub
|
# (index.html). This can be useful if you have a project on for instance GitHub
|
||||||
# and want to reuse the introduction page also for the doxygen output.
|
# and want to reuse the introduction page also for the doxygen output.
|
||||||
|
|
||||||
USE_MDFILE_AS_MAINPAGE = tools/Doxygen_README.md
|
USE_MDFILE_AS_MAINPAGE = tools/doxymds/drivers.md
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to source browsing
|
# Configuration options related to source browsing
|
||||||
@ -1224,7 +1224,7 @@ GENERATE_HTML = YES
|
|||||||
# The default directory is: html.
|
# The default directory is: html.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_OUTPUT = doxygen-doc/modules
|
HTML_OUTPUT = doxygen-doc/drivers
|
||||||
|
|
||||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
||||||
# generated HTML page (for example: .htm, .php, .asp).
|
# generated HTML page (for example: .htm, .php, .asp).
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
build:
|
|
||||||
|
|
||||||
clean:
|
|
@ -1,92 +0,0 @@
|
|||||||
#include "../../../Kernel/mapi.hpp"
|
|
||||||
#include "../../../Kernel/Fex.hpp"
|
|
||||||
|
|
||||||
extern "C" int ModuleEntry(void *Data);
|
|
||||||
int CallbackHandler(KernelCallback *Data);
|
|
||||||
int InterruptCallback(CPURegisters *Registers);
|
|
||||||
|
|
||||||
/* The module is
|
|
||||||
* This is a module for Fennix Module Entry Extended Header
|
|
||||||
* * * * */
|
|
||||||
HEAD(FexFormatType_Module, FexOSType_Fennix, ModuleEntry);
|
|
||||||
|
|
||||||
/* Ignore the warning about missing field initializers. */
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
|
||||||
|
|
||||||
/* Extended header which is used to give additional information to the kernel. */
|
|
||||||
__attribute__((section(".extended"))) FexExtended ExtendedHeader = {
|
|
||||||
.Module = {
|
|
||||||
.Name = "Example Module",
|
|
||||||
.Type = FexModuleType_Generic,
|
|
||||||
.Callback = CallbackHandler,
|
|
||||||
.InterruptCallback = InterruptCallback,
|
|
||||||
.Bind = {
|
|
||||||
.Type = BIND_INTERRUPT,
|
|
||||||
.Interrupt = {
|
|
||||||
.Vector = {222}, /* IRQ222 */
|
|
||||||
}}}};
|
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
/* Global structure that holds the kernel API. */
|
|
||||||
KernelAPI KAPI{};
|
|
||||||
|
|
||||||
/* Macro that prints a message to the kernel debugger. */
|
|
||||||
#define print(msg) KAPI.Util.DebugPrint((char *)(msg), KAPI.Info.modUniqueID)
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/* Module entry point. This is called at initialization.
|
|
||||||
"Data" argument points to the kernel API structure. */
|
|
||||||
int ModuleEntry(void *Data)
|
|
||||||
{
|
|
||||||
/* Check if kernel API is valid */
|
|
||||||
if (!Data)
|
|
||||||
return INVALID_KERNEL_API;
|
|
||||||
|
|
||||||
/* Set the global structure to the kernel API. */
|
|
||||||
KAPI = *(KernelAPI *)Data;
|
|
||||||
|
|
||||||
/* Check if kernel API version is valid.
|
|
||||||
This is important because the kernel
|
|
||||||
API may change in the future. */
|
|
||||||
if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0)
|
|
||||||
return KERNEL_API_VERSION_NOT_SUPPORTED;
|
|
||||||
|
|
||||||
/* We print "Hello World!" to the kernel debugger. */
|
|
||||||
print("Hello World!");
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is called when the module is bound to an interrupt, process,
|
|
||||||
or PCI device or when the kernel wants to send a message to the module. */
|
|
||||||
int CallbackHandler(KernelCallback *Data)
|
|
||||||
{
|
|
||||||
switch (Data->Reason)
|
|
||||||
{
|
|
||||||
case AcknowledgeReason:
|
|
||||||
{
|
|
||||||
print("Kernel acknowledged the module.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case StopReason:
|
|
||||||
{
|
|
||||||
print("Module stopped.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
print("Unknown reason.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interrupt handler. */
|
|
||||||
int InterruptCallback(CPURegisters *)
|
|
||||||
{
|
|
||||||
print("Interrupt received.");
|
|
||||||
return OK;
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
# Config file
|
|
||||||
include ../../../Makefile.conf
|
|
||||||
|
|
||||||
FILENAME = ExampleDriver.fex
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
GIT_COMMIT = $(shell git rev-parse HEAD)
|
|
||||||
GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
|
|
||||||
|
|
||||||
ifeq ($(OSARCH), amd64)
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
|
||||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
|
||||||
else ifeq ($(OSARCH), i386)
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
|
||||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
|
||||||
else ifeq ($(OSARCH), aarch64)
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
|
||||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
|
||||||
endif
|
|
||||||
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)
|
|
||||||
INCLUDE_DIR = ../../include
|
|
||||||
|
|
||||||
LDFLAGS := \
|
|
||||||
-fPIC -fPIE -pie -Wl,-eDriverEntry \
|
|
||||||
-Wl,-static,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
|
||||||
-nostdlib -nodefaultlibs -nolibc \
|
|
||||||
-zmax-page-size=0x1000 \
|
|
||||||
-Wl,-Map file.map -static
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
CFLAGS := \
|
|
||||||
-I$(INCLUDE_DIR) \
|
|
||||||
-DGIT_COMMIT='"$(GIT_COMMIT)"' \
|
|
||||||
-DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"'
|
|
||||||
|
|
||||||
ifeq ($(OSARCH), amd64)
|
|
||||||
|
|
||||||
LDFLAGS += -Tlinker_amd64.ld
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
LDFLAGS += -Tlinker_i386.ld
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
LDFLAGS += -Tlinker_aarch64.ld
|
|
||||||
|
|
||||||
CFLAGS += -pipe -fno-builtin -fPIC
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
ifeq ($(OSARCH), amd64)
|
|
||||||
$(OBJDUMP) -b binary -D -m i386:x86-64 -d $(FILENAME) > file_dump.map
|
|
||||||
else ifeq ($(OSARCH), i386)
|
|
||||||
$(OBJDUMP) -b binary -D -m i386 -d $(FILENAME) > file_dump.map
|
|
||||||
else ifeq ($(OSARCH), aarch64)
|
|
||||||
$(OBJDUMP) -b binary -D -m aarch64 -d $(FILENAME) > file_dump.map
|
|
||||||
endif
|
|
||||||
mv $(FILENAME) ../../out/$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(LDFLAGS) $(OBJ) -o $@
|
|
||||||
|
|
||||||
%.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 file.map file_dump.map $(OBJ)
|
|
@ -1,40 +0,0 @@
|
|||||||
OUTPUT_FORMAT(binary)
|
|
||||||
OUTPUT_ARCH(i386:x86-64)
|
|
||||||
|
|
||||||
ENTRY(DriverEntry)
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.header :
|
|
||||||
{
|
|
||||||
*(.header .header.*)
|
|
||||||
*(.extended .extended.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
*(.text .text.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.data :
|
|
||||||
{
|
|
||||||
*(.data .data.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.rodata :
|
|
||||||
{
|
|
||||||
*(.rodata .rodata.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.bss :
|
|
||||||
{
|
|
||||||
*(COMMON)
|
|
||||||
*(.bss .bss.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
/DISCARD/ :
|
|
||||||
{
|
|
||||||
*(.eh_frame)
|
|
||||||
*(.note .note.*)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
OUTPUT_FORMAT(binary)
|
|
||||||
OUTPUT_ARCH(i386)
|
|
||||||
|
|
||||||
ENTRY(DriverEntry)
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.header :
|
|
||||||
{
|
|
||||||
*(.header .header.*)
|
|
||||||
*(.extended .extended.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
*(.text .text.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.data :
|
|
||||||
{
|
|
||||||
*(.data .data.*)
|
|
||||||
PROVIDE(_GLOBAL_OFFSET_TABLE_ = .);
|
|
||||||
}
|
|
||||||
|
|
||||||
.rodata :
|
|
||||||
{
|
|
||||||
*(.rodata .rodata.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.bss :
|
|
||||||
{
|
|
||||||
*(COMMON)
|
|
||||||
*(.bss .bss.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
/DISCARD/ :
|
|
||||||
{
|
|
||||||
*(.eh_frame)
|
|
||||||
*(.note .note.*)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
build:
|
|
||||||
make -C ExampleDriver build
|
|
||||||
|
|
||||||
clean:
|
|
||||||
make -C ExampleDriver clean
|
|
@ -1,3 +0,0 @@
|
|||||||
build:
|
|
||||||
|
|
||||||
clean:
|
|
27
Makefile
27
Makefile
@ -1,22 +1,21 @@
|
|||||||
build:
|
build:
|
||||||
|
cp -f ../Kernel/driver.h include/driver.h
|
||||||
mkdir -p out
|
mkdir -p out
|
||||||
make -C Input build
|
make -C library build
|
||||||
make -C Storage build
|
make -C audio build
|
||||||
make -C Audio build
|
make -C input build
|
||||||
make -C FileSystem build
|
make -C misc build
|
||||||
make -C Generic build
|
make -C network build
|
||||||
make -C Network build
|
make -C storage build
|
||||||
make -C Video build
|
|
||||||
|
|
||||||
prepare:
|
prepare:
|
||||||
$(info Nothing to prepare)
|
$(info Nothing to prepare)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf out
|
rm -rf out
|
||||||
make -C Input clean
|
make -C library clean
|
||||||
make -C Storage clean
|
make -C audio clean
|
||||||
make -C Audio clean
|
make -C input clean
|
||||||
make -C FileSystem clean
|
make -C misc clean
|
||||||
make -C Generic clean
|
make -C network clean
|
||||||
make -C Network clean
|
make -C storage clean
|
||||||
make -C Video clean
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
build:
|
|
||||||
|
|
||||||
clean:
|
|
@ -1,6 +1,6 @@
|
|||||||
# Modules
|
# Drivers
|
||||||
|
|
||||||
Modules for [Fennix](https://github.com/Fennix-Project/Fennix).
|
Drivers for [Fennix](https://github.com/Fennix-Project/Fennix).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
build:
|
|
||||||
|
|
||||||
clean:
|
|
@ -1,3 +0,0 @@
|
|||||||
build:
|
|
||||||
|
|
||||||
clean:
|
|
7
audio/Makefile
Normal file
7
audio/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
build:
|
||||||
|
make -C ac97 build
|
||||||
|
make -C hda build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C ac97 clean
|
||||||
|
make -C hda clean
|
83
audio/ac97/Makefile
Normal file
83
audio/ac97/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = ac97.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
857
audio/ac97/ac97.cpp
Normal file
857
audio/ac97/ac97.cpp
Normal file
@ -0,0 +1,857 @@
|
|||||||
|
/*
|
||||||
|
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>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
Log("Invalid buffer.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Size == 0) || (Size % (SampleSize * Channels)))
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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);
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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] = {0};
|
||||||
|
|
||||||
|
#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 drvOpen(dev_t, dev_t, int, mode_t) { return 0; }
|
||||||
|
int drvClose(dev_t, dev_t) { return 0; }
|
||||||
|
size_t drvRead(dev_t, dev_t, uint8_t *, size_t, off_t) { return 0; }
|
||||||
|
|
||||||
|
size_t drvWrite(dev_t, dev_t min, uint8_t *Buffer, size_t Size, off_t)
|
||||||
|
{
|
||||||
|
return Drivers[AudioID[min]]->write(Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int drvIoctl(dev_t, dev_t min, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
return Drivers[AudioID[min]]->ioctl((AudioIoctl)Request, Argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = FindPCIDevices(VendorIDs, DeviceIDs);
|
||||||
|
if (Devices == nullptr)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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 = RegisterAudioDevice(ddt_Audio,
|
||||||
|
drvOpen, drvClose,
|
||||||
|
drvRead, drvWrite,
|
||||||
|
drvIoctl);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Log("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
25
audio/ac97/ac97.hpp
Normal file
25
audio/ac97/ac97.hpp
Normal 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
audio/ac97/main.c
Normal file
31
audio/ac97/main.c
Normal 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.1",
|
||||||
|
"GPLv3");
|
83
audio/hda/Makefile
Normal file
83
audio/hda/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = hda.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
239
audio/hda/hda.cpp
Normal file
239
audio/hda/hda.cpp
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
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 "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;
|
||||||
|
Log("Unimplemented HDA driver");
|
||||||
|
return;
|
||||||
|
Initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~HDADevice()
|
||||||
|
{
|
||||||
|
if (!Initialized)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HDADevice *Drivers[4] = {nullptr};
|
||||||
|
dev_t AudioID[4] = {0};
|
||||||
|
|
||||||
|
#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 drvOpen(dev_t, dev_t, int, mode_t) { return 0; }
|
||||||
|
int drvClose(dev_t, dev_t) { return 0; }
|
||||||
|
size_t drvRead(dev_t, dev_t, uint8_t *, size_t, off_t) { return 0; }
|
||||||
|
|
||||||
|
size_t drvWrite(dev_t, dev_t min, uint8_t *Buffer, size_t Size, off_t)
|
||||||
|
{
|
||||||
|
return Drivers[AudioID[min]]->write(Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int drvIoctl(dev_t, dev_t min, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
return Drivers[AudioID[min]]->ioctl((AudioIoctl)Request, Argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = FindPCIDevices(VendorIDs, DeviceIDs);
|
||||||
|
if (Devices == nullptr)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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 = RegisterAudioDevice(ddt_Audio,
|
||||||
|
drvOpen, drvClose,
|
||||||
|
drvRead, drvWrite,
|
||||||
|
drvIoctl);
|
||||||
|
AudioID[Count] = ret;
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
ctx = (PCIArray *)ctx->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Count == 0)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
635
audio/hda/hda.hpp
Normal file
635
audio/hda/hda.hpp
Normal 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
audio/hda/main.c
Normal file
31
audio/hda/main.c
Normal 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.1",
|
||||||
|
"GPLv3");
|
50
driver.template
Normal file
50
driver.template
Normal 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",
|
||||||
|
"version",
|
||||||
|
"license");
|
123
include/aip.h
Normal file
123
include/aip.h
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
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>
|
||||||
|
#include <aip/kbd.h>
|
||||||
|
#include <aip/mouse.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(true)
|
||||||
|
#define WaitInput PS2Wait(false)
|
||||||
|
|
||||||
|
#endif // !__FENNIX_API_AIP_H__
|
93
include/aip/kbd.h
Normal file
93
include/aip/kbd.h
Normal 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__
|
89
include/aip/mouse.h
Normal file
89
include/aip/mouse.h
Normal 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__
|
45
include/audio.h
Normal file
45
include/audio.h
Normal 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FENNIX_API_AUDIO_H__
|
||||||
|
#define __FENNIX_API_AUDIO_H__
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <driver.h>
|
||||||
|
|
||||||
|
typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t);
|
||||||
|
typedef int (*drvClose_t)(dev_t, dev_t);
|
||||||
|
typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
|
||||||
|
typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
|
||||||
|
typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
dev_t RegisterAudioDevice(DeviceDriverType Type,
|
||||||
|
drvOpen_t Open, drvClose_t Close,
|
||||||
|
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl);
|
||||||
|
|
||||||
|
int UnregisterAudioDevice(dev_t DeviceID, DeviceDriverType Type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !__FENNIX_API_AUDIO_H__
|
277
include/base.h
Normal file
277
include/base.h
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
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 screen
|
||||||
|
* @param Format The format string
|
||||||
|
* @param ... The arguments to the format string
|
||||||
|
*
|
||||||
|
* @note The newline character is automatically appended
|
||||||
|
*/
|
||||||
|
void KPrint(const char *Format, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Print to the kernel logger
|
||||||
|
* @param Format The format string
|
||||||
|
* @param ... The arguments to the format string
|
||||||
|
*/
|
||||||
|
void Log(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 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 ExitCode The exit code of the thread
|
||||||
|
* @return 0 on success, errno on failure
|
||||||
|
*/
|
||||||
|
int KillThread(pid_t tId, 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, Version, License) \
|
||||||
|
void __IdentifyDriver( \
|
||||||
|
dev_t ID, \
|
||||||
|
int (*GetDriverInfo)(dev_t, const char *, const char *, \
|
||||||
|
const char *, const char *, const char *)) \
|
||||||
|
{ \
|
||||||
|
GetDriverInfo(ID, Name, Description, Author, Version, License); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DebugLog(m, ...) Log(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__
|
45
include/block.h
Normal file
45
include/block.h
Normal 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FENNIX_API_BLOCK_H__
|
||||||
|
#define __FENNIX_API_BLOCK_H__
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <driver.h>
|
||||||
|
|
||||||
|
typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t);
|
||||||
|
typedef int (*drvClose_t)(dev_t, dev_t);
|
||||||
|
typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
|
||||||
|
typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
|
||||||
|
typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
dev_t RegisterBlockDevice(DeviceDriverType Type,
|
||||||
|
drvOpen_t Open, drvClose_t Close,
|
||||||
|
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl);
|
||||||
|
|
||||||
|
int UnregisterBlockDevice(dev_t DeviceID, DeviceDriverType Type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !__FENNIX_API_BLOCK_H__
|
326
include/driver.h
Normal file
326
include/driver.h
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
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 enum
|
||||||
|
{
|
||||||
|
_drf_Entry,
|
||||||
|
_drf_Final,
|
||||||
|
_drf_Panic,
|
||||||
|
_drf_Probe,
|
||||||
|
} __driverRegFunc;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
uint8_t Value;
|
||||||
|
} __MouseButtons;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* PCIDevice */ void *Device;
|
||||||
|
/* __PCIArray */ void *Next;
|
||||||
|
} __PCIArray;
|
||||||
|
|
||||||
|
/* ========================================== */
|
||||||
|
|
||||||
|
#define PCI_END 0x0000
|
||||||
|
#define KEY_NULL 0x00
|
||||||
|
|
||||||
|
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 enum
|
||||||
|
{
|
||||||
|
ddt_Keyboard,
|
||||||
|
ddt_Mouse,
|
||||||
|
ddt_Joystick,
|
||||||
|
ddt_Gamepad,
|
||||||
|
ddt_Touchpad,
|
||||||
|
ddt_Touchscreen,
|
||||||
|
|
||||||
|
ddt_SATA,
|
||||||
|
ddt_ATA,
|
||||||
|
ddt_NVMe,
|
||||||
|
|
||||||
|
ddt_Audio,
|
||||||
|
|
||||||
|
ddt_Network,
|
||||||
|
} DeviceDriverType;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
IOCTL_AUDIO_GET_VOLUME,
|
||||||
|
IOCTL_AUDIO_SET_VOLUME,
|
||||||
|
|
||||||
|
IOCTL_AUDIO_GET_MUTE,
|
||||||
|
IOCTL_AUDIO_SET_MUTE,
|
||||||
|
|
||||||
|
IOCTL_AUDIO_GET_SAMPLE_RATE,
|
||||||
|
IOCTL_AUDIO_SET_SAMPLE_RATE,
|
||||||
|
|
||||||
|
IOCTL_AUDIO_GET_CHANNELS,
|
||||||
|
IOCTL_AUDIO_SET_CHANNELS,
|
||||||
|
} AudioIoctl;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
IOCTL_NET_GET_MAC,
|
||||||
|
} 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;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t Major;
|
||||||
|
uint8_t Minor;
|
||||||
|
uint8_t Patch;
|
||||||
|
} APIVersion;
|
||||||
|
|
||||||
|
dev_t MajorID;
|
||||||
|
uintptr_t Base;
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
int (*RegisterFunction)(dev_t MajorID, void *Function, __driverRegFunc Type);
|
||||||
|
int (*GetDriverInfo)(dev_t MajorID, const char *Name, const char *Description, const char *Author, const char *Version, const char *License);
|
||||||
|
|
||||||
|
/* Interrupts */
|
||||||
|
int (*RegisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler);
|
||||||
|
int (*OverrideInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler);
|
||||||
|
int (*UnregisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler);
|
||||||
|
int (*UnregisterAllInterruptHandlers)(dev_t MajorID, void *Handler);
|
||||||
|
|
||||||
|
/* Input */
|
||||||
|
dev_t (*RegisterInputDevice)(dev_t MajorID, DeviceDriverType Type);
|
||||||
|
int (*UnregisterInputDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type);
|
||||||
|
int (*ReportKeyboardEvent)(dev_t MajorID, dev_t MinorID, uint8_t ScanCode);
|
||||||
|
int (*ReportRelativeMouseEvent)(dev_t MajorID, dev_t MinorID, __MouseButtons Button, int X, int Y, int8_t Z);
|
||||||
|
int (*ReportAbsoluteMouseEvent)(dev_t MajorID, dev_t MinorID, __MouseButtons Button, uintptr_t X, uintptr_t Y, int8_t Z);
|
||||||
|
|
||||||
|
/* Storage */
|
||||||
|
dev_t (*RegisterBlockDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl);
|
||||||
|
int (*UnregisterBlockDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type);
|
||||||
|
|
||||||
|
/* Audio */
|
||||||
|
dev_t (*RegisterAudioDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl);
|
||||||
|
int (*UnregisterAudioDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type);
|
||||||
|
|
||||||
|
/* Network */
|
||||||
|
dev_t (*RegisterNetDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl);
|
||||||
|
int (*UnregisterNetDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type);
|
||||||
|
int (*ReportNetworkPacket)(dev_t MajorID, dev_t MinorID, void *Buffer, size_t Size);
|
||||||
|
|
||||||
|
/* Logging */
|
||||||
|
void (*KPrint)(dev_t MajorID, const char *Format, va_list args);
|
||||||
|
void (*KernelLog)(dev_t MajorID, const char *Format, va_list args);
|
||||||
|
|
||||||
|
/* Memory */
|
||||||
|
void *(*RequestPages)(dev_t MajorID, size_t Pages);
|
||||||
|
void (*FreePages)(dev_t MajorID, void *Pointer, size_t Pages);
|
||||||
|
|
||||||
|
/* Mapping */
|
||||||
|
void (*AppendMapFlag)(dev_t MajorID, void *Address, PageMapFlags Flag);
|
||||||
|
void (*RemoveMapFlag)(dev_t MajorID, void *Address, PageMapFlags Flag);
|
||||||
|
void (*MapPages)(dev_t MajorID, void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags);
|
||||||
|
void (*UnmapPages)(dev_t MajorID, void *VirtualAddress, size_t Pages);
|
||||||
|
|
||||||
|
/* Scheduling */
|
||||||
|
pid_t (*CreateKernelProcess)(dev_t MajorID, const char *Name);
|
||||||
|
pid_t (*CreateKernelThread)(dev_t MajorID, pid_t pId, const char *Name, void *EntryPoint, void *Argument);
|
||||||
|
int (*KillProcess)(dev_t MajorID, pid_t pId, int ExitCode);
|
||||||
|
int (*KillThread)(dev_t MajorID, pid_t tId, int ExitCode);
|
||||||
|
void (*Yield)(dev_t MajorID);
|
||||||
|
void (*Sleep)(dev_t MajorID, uint64_t Milliseconds);
|
||||||
|
|
||||||
|
/* PCI */
|
||||||
|
__PCIArray *(*GetPCIDevices)(dev_t MajorID, uint16_t Vendors[], uint16_t Devices[]);
|
||||||
|
void (*InitializePCI)(dev_t MajorID, void *Header);
|
||||||
|
uint32_t (*GetBAR)(dev_t MajorID, uint8_t Index, void *Header);
|
||||||
|
|
||||||
|
/* Kernel std API */
|
||||||
|
void *(*memcpy)(dev_t MajorID, void *Destination, const void *Source, size_t Length);
|
||||||
|
void *(*memset)(dev_t MajorID, void *Destination, int Value, size_t Length);
|
||||||
|
void *(*memmove)(dev_t MajorID, void *Destination, const void *Source, size_t Length);
|
||||||
|
int (*memcmp)(dev_t MajorID, const void *Left, const void *Right, size_t Length);
|
||||||
|
size_t (*strlen)(dev_t MajorID, const char *String);
|
||||||
|
char *(*strcpy)(dev_t MajorID, char *Destination, const char *Source);
|
||||||
|
char *(*strcat)(dev_t MajorID, char *Destination, const char *Source);
|
||||||
|
int (*strcmp)(dev_t MajorID, const char *Left, const char *Right);
|
||||||
|
int (*strncmp)(dev_t MajorID, const char *Left, const char *Right, size_t Length);
|
||||||
|
char *(*strchr)(dev_t MajorID, const char *String, int Character);
|
||||||
|
char *(*strrchr)(dev_t MajorID, const char *String, int Character);
|
||||||
|
char *(*strstr)(dev_t MajorID, const char *Haystack, const char *Needle);
|
||||||
|
} __driverAPI;
|
||||||
|
|
||||||
|
#endif // !__FENNIX_API_DRIVER_FUNCTIONS_H__
|
408
include/errno.h
Normal file
408
include/errno.h
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
/*
|
||||||
|
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 _ERRNO_H
|
||||||
|
#define _ERRNO_H
|
||||||
|
|
||||||
|
/** Operation not permitted */
|
||||||
|
#define EPERM 1
|
||||||
|
|
||||||
|
/** No such file or directory */
|
||||||
|
#define ENOENT 2
|
||||||
|
|
||||||
|
/** No such process */
|
||||||
|
#define ESRCH 3
|
||||||
|
|
||||||
|
/** Interrupted system call */
|
||||||
|
#define EINTR 4
|
||||||
|
|
||||||
|
/** I/O error */
|
||||||
|
#define EIO 5
|
||||||
|
|
||||||
|
/** No such device or address */
|
||||||
|
#define ENXIO 6
|
||||||
|
|
||||||
|
/** Argument list too long */
|
||||||
|
#define E2BIG 7
|
||||||
|
|
||||||
|
/** Exec format error */
|
||||||
|
#define ENOEXEC 8
|
||||||
|
|
||||||
|
/** Bad file number */
|
||||||
|
#define EBADF 9
|
||||||
|
|
||||||
|
/** No child processes */
|
||||||
|
#define ECHILD 10
|
||||||
|
|
||||||
|
/** Try again */
|
||||||
|
#define EAGAIN 11
|
||||||
|
|
||||||
|
/** Out of memory */
|
||||||
|
#define ENOMEM 12
|
||||||
|
|
||||||
|
/** Permission denied */
|
||||||
|
#define EACCES 13
|
||||||
|
|
||||||
|
/** Bad address */
|
||||||
|
#define EFAULT 14
|
||||||
|
|
||||||
|
/** Block device required */
|
||||||
|
#define ENOTBLK 15
|
||||||
|
|
||||||
|
/** Device or resource busy */
|
||||||
|
#define EBUSY 16
|
||||||
|
|
||||||
|
/** File exists */
|
||||||
|
#define EEXIST 17
|
||||||
|
|
||||||
|
/** Cross-device link */
|
||||||
|
#define EXDEV 18
|
||||||
|
|
||||||
|
/** No such device */
|
||||||
|
#define ENODEV 19
|
||||||
|
|
||||||
|
/** Not a directory */
|
||||||
|
#define ENOTDIR 20
|
||||||
|
|
||||||
|
/** Is a directory */
|
||||||
|
#define EISDIR 21
|
||||||
|
|
||||||
|
/** Invalid argument */
|
||||||
|
#define EINVAL 22
|
||||||
|
|
||||||
|
/** File table overflow */
|
||||||
|
#define ENFILE 23
|
||||||
|
|
||||||
|
/** Too many open files */
|
||||||
|
#define EMFILE 24
|
||||||
|
|
||||||
|
/** Not a typewriter */
|
||||||
|
#define ENOTTY 25
|
||||||
|
|
||||||
|
/** Text file busy */
|
||||||
|
#define ETXTBSY 26
|
||||||
|
|
||||||
|
/** File too large */
|
||||||
|
#define EFBIG 27
|
||||||
|
|
||||||
|
/** No space left on device */
|
||||||
|
#define ENOSPC 28
|
||||||
|
|
||||||
|
/** Illegal seek */
|
||||||
|
#define ESPIPE 29
|
||||||
|
|
||||||
|
/** Read-only file system */
|
||||||
|
#define EROFS 30
|
||||||
|
|
||||||
|
/** Too many links */
|
||||||
|
#define EMLINK 31
|
||||||
|
|
||||||
|
/** Broken pipe */
|
||||||
|
#define EPIPE 32
|
||||||
|
|
||||||
|
/** Math argument out of domain of func */
|
||||||
|
#define EDOM 33
|
||||||
|
|
||||||
|
/** Math result not representable */
|
||||||
|
#define ERANGE 34
|
||||||
|
|
||||||
|
/** Resource deadlock would occur */
|
||||||
|
#define EDEADLK 35
|
||||||
|
|
||||||
|
/** File name too long */
|
||||||
|
#define ENAMETOOLONG 36
|
||||||
|
|
||||||
|
/** No record locks available */
|
||||||
|
#define ENOLCK 37
|
||||||
|
|
||||||
|
/** Function not implemented */
|
||||||
|
#define ENOSYS 38
|
||||||
|
|
||||||
|
/** Directory not empty */
|
||||||
|
#define ENOTEMPTY 39
|
||||||
|
|
||||||
|
/** Too many symbolic links encountered */
|
||||||
|
#define ELOOP 40
|
||||||
|
|
||||||
|
/** No message of desired type */
|
||||||
|
#define ENOMSG 42
|
||||||
|
|
||||||
|
/** Identifier removed */
|
||||||
|
#define EIDRM 43
|
||||||
|
|
||||||
|
/** Channel number out of range */
|
||||||
|
#define ECHRNG 44
|
||||||
|
|
||||||
|
/** Level 2 not synchronized */
|
||||||
|
#define EL2NSYNC 45
|
||||||
|
|
||||||
|
/** Level 3 halted */
|
||||||
|
#define EL3HLT 46
|
||||||
|
|
||||||
|
/** Level 3 reset */
|
||||||
|
#define EL3RST 47
|
||||||
|
|
||||||
|
/** Link number out of range */
|
||||||
|
#define ELNRNG 48
|
||||||
|
|
||||||
|
/** Protocol driver not attached */
|
||||||
|
#define EUNATCH 49
|
||||||
|
|
||||||
|
/** No CSI structure available */
|
||||||
|
#define ENOCSI 50
|
||||||
|
|
||||||
|
/** Level 2 halted */
|
||||||
|
#define EL2HLT 51
|
||||||
|
|
||||||
|
/** Invalid exchange */
|
||||||
|
#define EBADE 52
|
||||||
|
|
||||||
|
/** Invalid request descriptor */
|
||||||
|
#define EBADR 53
|
||||||
|
|
||||||
|
/** Exchange full */
|
||||||
|
#define EXFULL 54
|
||||||
|
|
||||||
|
/** No anode */
|
||||||
|
#define ENOANO 55
|
||||||
|
|
||||||
|
/** Invalid request code */
|
||||||
|
#define EBADRQC 56
|
||||||
|
|
||||||
|
/** Invalid slot */
|
||||||
|
#define EBADSLT 57
|
||||||
|
|
||||||
|
/** Bad font file format */
|
||||||
|
#define EBFONT 59
|
||||||
|
|
||||||
|
/** Device not a stream */
|
||||||
|
#define ENOSTR 60
|
||||||
|
|
||||||
|
/** No data available */
|
||||||
|
#define ENODATA 61
|
||||||
|
|
||||||
|
/** Timer expired */
|
||||||
|
#define ETIME 62
|
||||||
|
|
||||||
|
/** Out of streams resources */
|
||||||
|
#define ENOSR 63
|
||||||
|
|
||||||
|
/** Machine is not on the network */
|
||||||
|
#define ENONET 64
|
||||||
|
|
||||||
|
/** Package not installed */
|
||||||
|
#define ENOPKG 65
|
||||||
|
|
||||||
|
/** Object is remote */
|
||||||
|
#define EREMOTE 66
|
||||||
|
|
||||||
|
/** Link has been severed */
|
||||||
|
#define ENOLINK 67
|
||||||
|
|
||||||
|
/** Advertise error */
|
||||||
|
#define EADV 68
|
||||||
|
|
||||||
|
/** Srmount error */
|
||||||
|
#define ESRMNT 69
|
||||||
|
|
||||||
|
/** Communication error on send */
|
||||||
|
#define ECOMM 70
|
||||||
|
|
||||||
|
/** Protocol error */
|
||||||
|
#define EPROTO 71
|
||||||
|
|
||||||
|
/** Multihop attempted */
|
||||||
|
#define EMULTIHOP 72
|
||||||
|
|
||||||
|
/** RFS specific error */
|
||||||
|
#define EDOTDOT 73
|
||||||
|
|
||||||
|
/** Not a data message */
|
||||||
|
#define EBADMSG 74
|
||||||
|
|
||||||
|
/** Value too large for defined data type */
|
||||||
|
#define EOVERFLOW 75
|
||||||
|
|
||||||
|
/** Name not unique on network */
|
||||||
|
#define ENOTUNIQ 76
|
||||||
|
|
||||||
|
/** File descriptor in bad state */
|
||||||
|
#define EBADFD 77
|
||||||
|
|
||||||
|
/** Remote address changed */
|
||||||
|
#define EREMCHG 78
|
||||||
|
|
||||||
|
/** Can not access a needed shared library */
|
||||||
|
#define ELIBACC 79
|
||||||
|
|
||||||
|
/** Accessing a corrupted shared library */
|
||||||
|
#define ELIBBAD 80
|
||||||
|
|
||||||
|
/** .lib section in a.out corrupted */
|
||||||
|
#define ELIBSCN 81
|
||||||
|
|
||||||
|
/** Attempting to link in too many shared libraries */
|
||||||
|
#define ELIBMAX 82
|
||||||
|
|
||||||
|
/** Cannot exec a shared library directly */
|
||||||
|
#define ELIBEXEC 83
|
||||||
|
|
||||||
|
/** Illegal byte sequence */
|
||||||
|
#define EILSEQ 84
|
||||||
|
|
||||||
|
/** Interrupted system call should be restarted */
|
||||||
|
#define ERESTART 85
|
||||||
|
|
||||||
|
/** Streams pipe error */
|
||||||
|
#define ESTRPIPE 86
|
||||||
|
|
||||||
|
/** Too many users */
|
||||||
|
#define EUSERS 87
|
||||||
|
|
||||||
|
/** Socket operation on non-socket */
|
||||||
|
#define ENOTSOCK 88
|
||||||
|
|
||||||
|
/** Destination address required */
|
||||||
|
#define EDESTADDRREQ 89
|
||||||
|
|
||||||
|
/** Message too long */
|
||||||
|
#define EMSGSIZE 90
|
||||||
|
|
||||||
|
/** Protocol wrong type for socket */
|
||||||
|
#define EPROTOTYPE 91
|
||||||
|
|
||||||
|
/** Protocol not available */
|
||||||
|
#define ENOPROTOOPT 92
|
||||||
|
|
||||||
|
/** Protocol not supported */
|
||||||
|
#define EPROTONOSUPPORT 93
|
||||||
|
|
||||||
|
/** Socket type not supported */
|
||||||
|
#define ESOCKTNOSUPPORT 94
|
||||||
|
|
||||||
|
/** Operation not supported on transport endpoint */
|
||||||
|
#define EOPNOTSUPP 95
|
||||||
|
|
||||||
|
/** Protocol family not supported */
|
||||||
|
#define EPFNOSUPPORT 96
|
||||||
|
|
||||||
|
/** Address family not supported by protocol */
|
||||||
|
#define EAFNOSUPPORT 97
|
||||||
|
|
||||||
|
/** Address already in use */
|
||||||
|
#define EADDRINUSE 98
|
||||||
|
|
||||||
|
/** Cannot assign requested address */
|
||||||
|
#define EADDRNOTAVAIL 99
|
||||||
|
|
||||||
|
/** Network is down */
|
||||||
|
#define ENETDOWN 100
|
||||||
|
|
||||||
|
/** Network is unreachable */
|
||||||
|
#define ENETUNREACH 101
|
||||||
|
|
||||||
|
/** Network dropped connection because of reset */
|
||||||
|
#define ENETRESET 102
|
||||||
|
|
||||||
|
/** Software caused connection abort */
|
||||||
|
#define ECONNABORTED 103
|
||||||
|
|
||||||
|
/** Connection reset by peer */
|
||||||
|
#define ECONNRESET 104
|
||||||
|
|
||||||
|
/** No buffer space available */
|
||||||
|
#define ENOBUFS 105
|
||||||
|
|
||||||
|
/** Transport endpoint is already connected */
|
||||||
|
#define EISCONN 106
|
||||||
|
|
||||||
|
/** Transport endpoint is not connected */
|
||||||
|
#define ENOTCONN 107
|
||||||
|
|
||||||
|
/** Cannot send after transport endpoint shutdown */
|
||||||
|
#define ESHUTDOWN 108
|
||||||
|
|
||||||
|
/** Too many references: cannot splice */
|
||||||
|
#define ETOOMANYREFS 109
|
||||||
|
|
||||||
|
/** Connection timed out */
|
||||||
|
#define ETIMEDOUT 110
|
||||||
|
|
||||||
|
/** Connection refused */
|
||||||
|
#define ECONNREFUSED 111
|
||||||
|
|
||||||
|
/** Host is down */
|
||||||
|
#define EHOSTDOWN 112
|
||||||
|
|
||||||
|
/** No route to host */
|
||||||
|
#define EHOSTUNREACH 113
|
||||||
|
|
||||||
|
/** Operation already in progress */
|
||||||
|
#define EALREADY 114
|
||||||
|
|
||||||
|
/** Operation now in progress */
|
||||||
|
#define EINPROGRESS 115
|
||||||
|
|
||||||
|
/** Stale NFS file handle */
|
||||||
|
#define ESTALE 116
|
||||||
|
|
||||||
|
/** Structure needs cleaning */
|
||||||
|
#define EUCLEAN 117
|
||||||
|
|
||||||
|
/** Not a XENIX named type file */
|
||||||
|
#define ENOTNAM 118
|
||||||
|
|
||||||
|
/** No XENIX semaphores available */
|
||||||
|
#define ENAVAIL 119
|
||||||
|
|
||||||
|
/** Is a named type file */
|
||||||
|
#define EISNAM 120
|
||||||
|
|
||||||
|
/** Remote I/O error */
|
||||||
|
#define EREMOTEIO 121
|
||||||
|
|
||||||
|
/** Quota exceeded */
|
||||||
|
#define EDQUOT 122
|
||||||
|
|
||||||
|
/** No medium found */
|
||||||
|
#define ENOMEDIUM 123
|
||||||
|
|
||||||
|
/** Wrong medium type */
|
||||||
|
#define EMEDIUMTYPE 124
|
||||||
|
|
||||||
|
/** Operation Canceled */
|
||||||
|
#define ECANCELED 125
|
||||||
|
|
||||||
|
/** Required key not available */
|
||||||
|
#define ENOKEY 126
|
||||||
|
|
||||||
|
/** Key has expired */
|
||||||
|
#define EKEYEXPIRED 127
|
||||||
|
|
||||||
|
/** Key has been revoked */
|
||||||
|
#define EKEYREVOKED 128
|
||||||
|
|
||||||
|
/** Key was rejected by service */
|
||||||
|
#define EKEYREJECTED 129
|
||||||
|
|
||||||
|
/** Owner died */
|
||||||
|
#define EOWNERDEAD 130
|
||||||
|
|
||||||
|
/** State not recoverable */
|
||||||
|
#define ENOTRECOVERABLE 131
|
||||||
|
|
||||||
|
#endif // !_ERRNO_H
|
66
include/input.h
Normal file
66
include/input.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
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_INPUT_H__
|
||||||
|
#define __FENNIX_API_INPUT_H__
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <driver.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t LeftButton : 1;
|
||||||
|
uint8_t RightButton : 1;
|
||||||
|
uint8_t MiddleButton : 1;
|
||||||
|
uint8_t Button4 : 1;
|
||||||
|
uint8_t Button5 : 1;
|
||||||
|
};
|
||||||
|
uint8_t Buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note Ignored if is absolute
|
||||||
|
*/
|
||||||
|
int X;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note Ignored if is absolute
|
||||||
|
*/
|
||||||
|
int Y;
|
||||||
|
int8_t Z;
|
||||||
|
} MouseReport;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
dev_t RegisterInputDevice(DeviceDriverType Type);
|
||||||
|
int UnregisterInputDevice(dev_t DeviceID, DeviceDriverType Type);
|
||||||
|
int ReportKeyboardEvent(dev_t DeviceID, KeyScanCodes ScanCode, uint8_t Pressed);
|
||||||
|
int ReportRelativeMouseEvent(dev_t DeviceID, MouseReport Report);
|
||||||
|
int ReportAbsoluteMouseEvent(dev_t DeviceID, MouseReport Report, uintptr_t X, uintptr_t Y);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !__FENNIX_API_INPUT_H__
|
367
include/io.h
367
include/io.h
@ -1,3 +1,20 @@
|
|||||||
|
/*
|
||||||
|
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__
|
#ifndef __FENNIX_API_IO_H__
|
||||||
#define __FENNIX_API_IO_H__
|
#define __FENNIX_API_IO_H__
|
||||||
|
|
||||||
@ -9,201 +26,203 @@
|
|||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#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)
|
static inline uint8_t inportb(uint16_t Port)
|
||||||
{
|
{
|
||||||
uint16_t Result;
|
uint8_t Result;
|
||||||
__asm__("in %%dx, %%ax"
|
__asm__("in %%dx, %%al"
|
||||||
: "=a"(Result)
|
: "=a"(Result)
|
||||||
: "d"(Port));
|
: "d"(Port));
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t inportl(uint16_t Port)
|
static inline uint16_t inportw(uint16_t Port)
|
||||||
{
|
{
|
||||||
uint32_t Result;
|
uint16_t Result;
|
||||||
__asm__ volatile("inl %1, %0"
|
__asm__("in %%dx, %%ax"
|
||||||
: "=a"(Result)
|
: "=a"(Result)
|
||||||
: "dN"(Port));
|
: "d"(Port));
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void outportb(uint16_t Port, uint8_t Data)
|
static inline uint32_t inportl(uint16_t Port)
|
||||||
{
|
{
|
||||||
__asm__ volatile("out %%al, %%dx"
|
uint32_t Result;
|
||||||
:
|
__asm__ volatile("inl %1, %0"
|
||||||
: "a"(Data), "d"(Port));
|
: "=a"(Result)
|
||||||
}
|
: "dN"(Port));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void outportw(uint16_t Port, uint16_t Data)
|
static inline void outportb(uint16_t Port, uint8_t Data)
|
||||||
{
|
{
|
||||||
__asm__ volatile("out %%ax, %%dx"
|
__asm__ volatile("out %%al, %%dx"
|
||||||
:
|
:
|
||||||
: "a"(Data), "d"(Port));
|
: "a"(Data), "d"(Port));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void outportl(uint16_t Port, uint32_t Data)
|
static inline void outportw(uint16_t Port, uint16_t Data)
|
||||||
{
|
{
|
||||||
__asm__ volatile("outl %1, %0"
|
__asm__ volatile("out %%ax, %%dx"
|
||||||
:
|
:
|
||||||
: "dN"(Port), "a"(Data));
|
: "a"(Data), "d"(Port));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t mmioin8(uint64_t Address)
|
static inline void outportl(uint16_t Port, uint32_t Data)
|
||||||
{
|
{
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("outl %1, %0"
|
||||||
: "memory");
|
:
|
||||||
uint8_t Result = *(volatile uint8_t *)Address;
|
: "dN"(Port), "a"(Data));
|
||||||
__asm__ volatile("" ::
|
}
|
||||||
: "memory");
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint16_t mmioin16(uint64_t Address)
|
static inline uint8_t mmioin8(uint64_t Address)
|
||||||
{
|
{
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
uint16_t Result = *(volatile uint16_t *)Address;
|
uint8_t Result = *(volatile uint8_t *)Address;
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t mmioin32(uint64_t Address)
|
static inline uint16_t mmioin16(uint64_t Address)
|
||||||
{
|
{
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
uint32_t Result = *(volatile uint32_t *)Address;
|
uint16_t Result = *(volatile uint16_t *)Address;
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t mmioin64(uint64_t Address)
|
static inline uint32_t mmioin32(uint64_t Address)
|
||||||
{
|
{
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
uint64_t Result = *(volatile uint64_t *)Address;
|
uint32_t Result = *(volatile uint32_t *)Address;
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mmioout8(uint64_t Address, uint8_t Data)
|
static inline uint64_t mmioin64(uint64_t Address)
|
||||||
{
|
{
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
*(volatile uint8_t *)Address = Data;
|
uint64_t Result = *(volatile uint64_t *)Address;
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
}
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void mmioout16(uint64_t Address, uint16_t Data)
|
static inline void mmioout8(uint64_t Address, uint8_t Data)
|
||||||
{
|
{
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
*(volatile uint16_t *)Address = Data;
|
*(volatile uint8_t *)Address = Data;
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mmioout32(uint64_t Address, uint32_t Data)
|
static inline void mmioout16(uint64_t Address, uint16_t Data)
|
||||||
{
|
{
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
*(volatile uint32_t *)Address = Data;
|
*(volatile uint16_t *)Address = Data;
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mmioout64(uint64_t Address, uint64_t Data)
|
static inline void mmioout32(uint64_t Address, uint32_t Data)
|
||||||
{
|
{
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
*(volatile uint64_t *)Address = Data;
|
*(volatile uint32_t *)Address = Data;
|
||||||
__asm__ volatile("" ::
|
__asm__ volatile("" ::
|
||||||
: "memory");
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mmoutb(void *Address, uint8_t Value)
|
static inline void mmioout64(uint64_t Address, uint64_t Data)
|
||||||
{
|
{
|
||||||
__asm__ volatile("mov %1, %0"
|
__asm__ volatile("" ::
|
||||||
: "=m"((*(uint8_t *)(Address)))
|
: "memory");
|
||||||
: "r"(Value)
|
*(volatile uint64_t *)Address = Data;
|
||||||
: "memory");
|
__asm__ volatile("" ::
|
||||||
}
|
: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
static inline void mmoutw(void *Address, uint16_t Value)
|
static inline void mmoutb(void *Address, uint8_t Value)
|
||||||
{
|
{
|
||||||
__asm__ volatile("mov %1, %0"
|
__asm__ volatile("mov %1, %0"
|
||||||
: "=m"((*(uint16_t *)(Address)))
|
: "=m"((*(uint8_t *)(Address)))
|
||||||
: "r"(Value)
|
: "r"(Value)
|
||||||
: "memory");
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mmoutl(void *Address, uint32_t Value)
|
static inline void mmoutw(void *Address, uint16_t Value)
|
||||||
{
|
{
|
||||||
__asm__ volatile("mov %1, %0"
|
__asm__ volatile("mov %1, %0"
|
||||||
: "=m"((*(uint32_t *)(Address)))
|
: "=m"((*(uint16_t *)(Address)))
|
||||||
: "r"(Value)
|
: "r"(Value)
|
||||||
: "memory");
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mmoutq(void *Address, uint64_t Value)
|
static inline void mmoutl(void *Address, uint32_t Value)
|
||||||
{
|
{
|
||||||
__asm__ volatile("mov %1, %0"
|
__asm__ volatile("mov %1, %0"
|
||||||
: "=m"((*(uint64_t *)(Address)))
|
: "=m"((*(uint32_t *)(Address)))
|
||||||
: "r"(Value)
|
: "r"(Value)
|
||||||
: "memory");
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t mminb(void *Address)
|
static inline void mmoutq(void *Address, uint64_t Value)
|
||||||
{
|
{
|
||||||
uint8_t Result;
|
__asm__ volatile("mov %1, %0"
|
||||||
__asm__ volatile("mov %1, %0"
|
: "=m"((*(uint64_t *)(Address)))
|
||||||
: "=r"(Result)
|
: "r"(Value)
|
||||||
: "m"((*(uint8_t *)(Address)))
|
: "memory");
|
||||||
: "memory");
|
}
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint16_t mminw(void *Address)
|
static inline uint8_t mminb(void *Address)
|
||||||
{
|
{
|
||||||
uint16_t Result;
|
uint8_t Result;
|
||||||
__asm__ volatile("mov %1, %0"
|
__asm__ volatile("mov %1, %0"
|
||||||
: "=r"(Result)
|
: "=r"(Result)
|
||||||
: "m"((*(uint16_t *)(Address)))
|
: "m"((*(uint8_t *)(Address)))
|
||||||
: "memory");
|
: "memory");
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t mminl(void *Address)
|
static inline uint16_t mminw(void *Address)
|
||||||
{
|
{
|
||||||
uint32_t Result;
|
uint16_t Result;
|
||||||
__asm__ volatile("mov %1, %0"
|
__asm__ volatile("mov %1, %0"
|
||||||
: "=r"(Result)
|
: "=r"(Result)
|
||||||
: "m"((*(uint32_t *)(Address)))
|
: "m"((*(uint16_t *)(Address)))
|
||||||
: "memory");
|
: "memory");
|
||||||
return Result;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
47
include/net.h
Normal file
47
include/net.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
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_AUDIO_H__
|
||||||
|
#define __FENNIX_API_AUDIO_H__
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <driver.h>
|
||||||
|
|
||||||
|
typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t);
|
||||||
|
typedef int (*drvClose_t)(dev_t, dev_t);
|
||||||
|
typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
|
||||||
|
typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
|
||||||
|
typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
dev_t RegisterNetDevice(DeviceDriverType Type,
|
||||||
|
drvOpen_t Open, drvClose_t Close,
|
||||||
|
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl);
|
||||||
|
|
||||||
|
int UnregisterNetDevice(dev_t DeviceID, DeviceDriverType Type);
|
||||||
|
|
||||||
|
int ReportNetworkPacket(dev_t DeviceID, void *Buffer, size_t Size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // !__FENNIX_API_AUDIO_H__
|
@ -1,3 +1,20 @@
|
|||||||
|
/*
|
||||||
|
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__
|
#ifndef __FENNIX_API_NETWORK_UTILS_H__
|
||||||
#define __FENNIX_API_NETWORK_UTILS_H__
|
#define __FENNIX_API_NETWORK_UTILS_H__
|
||||||
|
|
||||||
|
274
include/pci.h
274
include/pci.h
@ -1,3 +1,20 @@
|
|||||||
|
/*
|
||||||
|
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__
|
#ifndef __FENNIX_API_PCI_H__
|
||||||
#define __FENNIX_API_PCI_H__
|
#define __FENNIX_API_PCI_H__
|
||||||
|
|
||||||
@ -6,123 +23,162 @@
|
|||||||
/* https://sites.uclouvain.be/SystInfo/usr/include/linux/pci_regs.h.html */
|
/* https://sites.uclouvain.be/SystInfo/usr/include/linux/pci_regs.h.html */
|
||||||
enum PCICommands
|
enum PCICommands
|
||||||
{
|
{
|
||||||
/** @brief Enable response in I/O space */
|
/** @brief Enable response in I/O space */
|
||||||
PCI_COMMAND_IO = 0x1,
|
PCI_COMMAND_IO = 0x1,
|
||||||
/** @brief Enable response in Memory space */
|
/** @brief Enable response in Memory space */
|
||||||
PCI_COMMAND_MEMORY = 0x2,
|
PCI_COMMAND_MEMORY = 0x2,
|
||||||
/** @brief Enable bus mastering */
|
/** @brief Enable bus mastering */
|
||||||
PCI_COMMAND_MASTER = 0x4,
|
PCI_COMMAND_MASTER = 0x4,
|
||||||
/** @brief Enable response to special cycles */
|
/** @brief Enable response to special cycles */
|
||||||
PCI_COMMAND_SPECIAL = 0x8,
|
PCI_COMMAND_SPECIAL = 0x8,
|
||||||
/** @brief Use memory write and invalidate */
|
/** @brief Use memory write and invalidate */
|
||||||
PCI_COMMAND_INVALIDATE = 0x10,
|
PCI_COMMAND_INVALIDATE = 0x10,
|
||||||
/** @brief Enable palette snooping */
|
/** @brief Enable palette snooping */
|
||||||
PCI_COMMAND_VGA_PALETTE = 0x20,
|
PCI_COMMAND_VGA_PALETTE = 0x20,
|
||||||
/** @brief Enable parity checking */
|
/** @brief Enable parity checking */
|
||||||
PCI_COMMAND_PARITY = 0x40,
|
PCI_COMMAND_PARITY = 0x40,
|
||||||
/** @brief Enable address/data stepping */
|
/** @brief Enable address/data stepping */
|
||||||
PCI_COMMAND_WAIT = 0x80,
|
PCI_COMMAND_WAIT = 0x80,
|
||||||
/** @brief Enable SERR */
|
/** @brief Enable SERR */
|
||||||
PCI_COMMAND_SERR = 0x100,
|
PCI_COMMAND_SERR = 0x100,
|
||||||
/** @brief Enable back-to-back writes */
|
/** @brief Enable back-to-back writes */
|
||||||
PCI_COMMAND_FAST_BACK = 0x200,
|
PCI_COMMAND_FAST_BACK = 0x200,
|
||||||
/** @brief INTx Emulation Disable */
|
/** @brief INTx Emulation Disable */
|
||||||
PCI_COMMAND_INTX_DISABLE = 0x400
|
PCI_COMMAND_INTX_DISABLE = 0x400
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PCIDeviceHeader
|
typedef struct
|
||||||
{
|
{
|
||||||
uint16_t VendorID;
|
uint16_t VendorID;
|
||||||
uint16_t DeviceID;
|
uint16_t DeviceID;
|
||||||
uint16_t Command;
|
uint16_t Command;
|
||||||
uint16_t Status;
|
uint16_t Status;
|
||||||
uint8_t RevisionID;
|
uint8_t RevisionID;
|
||||||
uint8_t ProgIF;
|
uint8_t ProgIF;
|
||||||
uint8_t Subclass;
|
uint8_t Subclass;
|
||||||
uint8_t Class;
|
uint8_t Class;
|
||||||
uint8_t CacheLineSize;
|
uint8_t CacheLineSize;
|
||||||
uint8_t LatencyTimer;
|
uint8_t LatencyTimer;
|
||||||
uint8_t HeaderType;
|
uint8_t HeaderType;
|
||||||
uint8_t BIST;
|
uint8_t BIST;
|
||||||
};
|
} __attribute__((packed)) PCIDeviceHeader;
|
||||||
|
|
||||||
struct PCIHeader0
|
typedef struct
|
||||||
{
|
{
|
||||||
PCIDeviceHeader Header;
|
PCIDeviceHeader Header;
|
||||||
uint32_t BAR0;
|
uint32_t BAR0;
|
||||||
uint32_t BAR1;
|
uint32_t BAR1;
|
||||||
uint32_t BAR2;
|
uint32_t BAR2;
|
||||||
uint32_t BAR3;
|
uint32_t BAR3;
|
||||||
uint32_t BAR4;
|
uint32_t BAR4;
|
||||||
uint32_t BAR5;
|
uint32_t BAR5;
|
||||||
uint32_t CardbusCISPointer;
|
uint32_t CardbusCISPointer;
|
||||||
uint16_t SubsystemVendorID;
|
uint16_t SubsystemVendorID;
|
||||||
uint16_t SubsystemID;
|
uint16_t SubsystemID;
|
||||||
uint32_t ExpansionROMBaseAddress;
|
uint32_t ExpansionROMBaseAddress;
|
||||||
uint8_t CapabilitiesPointer;
|
uint8_t CapabilitiesPointer;
|
||||||
uint8_t Reserved0;
|
uint8_t Reserved0;
|
||||||
uint16_t Reserved1;
|
uint16_t Reserved1;
|
||||||
uint32_t Reserved2;
|
uint32_t Reserved2;
|
||||||
uint8_t InterruptLine;
|
uint8_t InterruptLine;
|
||||||
uint8_t InterruptPin;
|
uint8_t InterruptPin;
|
||||||
uint8_t MinGrant;
|
uint8_t MinGrant;
|
||||||
uint8_t MaxLatency;
|
uint8_t MaxLatency;
|
||||||
};
|
} __attribute__((packed)) PCIHeader0;
|
||||||
|
|
||||||
struct PCIHeader1
|
typedef struct
|
||||||
{
|
{
|
||||||
PCIDeviceHeader Header;
|
PCIDeviceHeader Header;
|
||||||
uint32_t BAR0;
|
uint32_t BAR0;
|
||||||
uint32_t BAR1;
|
uint32_t BAR1;
|
||||||
uint8_t PrimaryBusNumber;
|
uint8_t PrimaryBusNumber;
|
||||||
uint8_t SecondaryBusNumber;
|
uint8_t SecondaryBusNumber;
|
||||||
uint8_t SubordinateBusNumber;
|
uint8_t SubordinateBusNumber;
|
||||||
uint8_t SecondaryLatencyTimer;
|
uint8_t SecondaryLatencyTimer;
|
||||||
uint8_t IOBase;
|
uint8_t IOBase;
|
||||||
uint8_t IOLimit;
|
uint8_t IOLimit;
|
||||||
uint16_t SecondaryStatus;
|
uint16_t SecondaryStatus;
|
||||||
uint16_t MemoryBase;
|
uint16_t MemoryBase;
|
||||||
uint16_t MemoryLimit;
|
uint16_t MemoryLimit;
|
||||||
uint16_t PrefetchableMemoryBase;
|
uint16_t PrefetchableMemoryBase;
|
||||||
uint16_t PrefetchableMemoryLimit;
|
uint16_t PrefetchableMemoryLimit;
|
||||||
uint32_t PrefetchableMemoryBaseUpper32;
|
uint32_t PrefetchableMemoryBaseUpper32;
|
||||||
uint32_t PrefetchableMemoryLimitUpper32;
|
uint32_t PrefetchableMemoryLimitUpper32;
|
||||||
uint16_t IOBaseUpper16;
|
uint16_t IOBaseUpper16;
|
||||||
uint16_t IOLimitUpper16;
|
uint16_t IOLimitUpper16;
|
||||||
uint8_t CapabilitiesPointer;
|
uint8_t CapabilitiesPointer;
|
||||||
uint8_t Reserved0;
|
uint8_t Reserved0;
|
||||||
uint16_t Reserved1;
|
uint16_t Reserved1;
|
||||||
uint32_t ExpansionROMBaseAddress;
|
uint32_t ExpansionROMBaseAddress;
|
||||||
uint8_t InterruptLine;
|
uint8_t InterruptLine;
|
||||||
uint8_t InterruptPin;
|
uint8_t InterruptPin;
|
||||||
uint16_t BridgeControl;
|
uint16_t BridgeControl;
|
||||||
};
|
} __attribute__((packed)) PCIHeader1;
|
||||||
|
|
||||||
struct PCIHeader2
|
typedef struct
|
||||||
{
|
{
|
||||||
PCIDeviceHeader Header;
|
PCIDeviceHeader Header;
|
||||||
uint32_t CardbusSocketRegistersBaseAddress;
|
uint32_t CardbusSocketRegistersBaseAddress;
|
||||||
uint8_t CapabilitiesPointer;
|
uint8_t CapabilitiesPointer;
|
||||||
uint8_t Reserved0;
|
uint8_t Reserved0;
|
||||||
uint16_t SecondaryStatus;
|
uint16_t SecondaryStatus;
|
||||||
uint8_t PCIbusNumber;
|
uint8_t PCIbusNumber;
|
||||||
uint8_t CardbusBusNumber;
|
uint8_t CardbusBusNumber;
|
||||||
uint8_t SubordinateBusNumber;
|
uint8_t SubordinateBusNumber;
|
||||||
uint8_t CardbusLatencyTimer;
|
uint8_t CardbusLatencyTimer;
|
||||||
uint32_t MemoryBase0;
|
uint32_t MemoryBase0;
|
||||||
uint32_t MemoryLimit0;
|
uint32_t MemoryLimit0;
|
||||||
uint32_t MemoryBase1;
|
uint32_t MemoryBase1;
|
||||||
uint32_t MemoryLimit1;
|
uint32_t MemoryLimit1;
|
||||||
uint32_t IOBase0;
|
uint32_t IOBase0;
|
||||||
uint32_t IOLimit0;
|
uint32_t IOLimit0;
|
||||||
uint32_t IOBase1;
|
uint32_t IOBase1;
|
||||||
uint32_t IOLimit1;
|
uint32_t IOLimit1;
|
||||||
uint8_t InterruptLine;
|
uint8_t InterruptLine;
|
||||||
uint8_t InterruptPin;
|
uint8_t InterruptPin;
|
||||||
uint16_t BridgeControl;
|
uint16_t BridgeControl;
|
||||||
uint16_t SubsystemVendorID;
|
uint16_t SubsystemVendorID;
|
||||||
uint16_t SubsystemID;
|
uint16_t SubsystemID;
|
||||||
uint32_t LegacyBaseAddress;
|
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 *FindPCIDevices(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__
|
#endif // !__FENNIX_API_PCI_H__
|
||||||
|
100
include/regs.h
Normal file
100
include/regs.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
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 TrapFrame
|
||||||
|
{
|
||||||
|
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 TrapFrame
|
||||||
|
{
|
||||||
|
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__
|
231
include/syscall.h
Normal file
231
include/syscall.h
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2023, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FENNIX_KERNEL_SYSCALLS_LIST_H__
|
||||||
|
#define __FENNIX_KERNEL_SYSCALLS_LIST_H__
|
||||||
|
|
||||||
|
/* mmap */
|
||||||
|
|
||||||
|
#define sc_PROT_NONE 0
|
||||||
|
#define sc_PROT_READ 1
|
||||||
|
#define sc_PROT_WRITE 2
|
||||||
|
#define sc_PROT_EXEC 4
|
||||||
|
|
||||||
|
#define sc_MAP_SHARED 1
|
||||||
|
#define sc_MAP_PRIVATE 2
|
||||||
|
#define sc_MAP_FIXED 4
|
||||||
|
#define sc_MAP_ANONYMOUS 8
|
||||||
|
|
||||||
|
/* lseek */
|
||||||
|
|
||||||
|
#define sc_SEEK_SET 0
|
||||||
|
#define sc_SEEK_CUR 1
|
||||||
|
#define sc_SEEK_END 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of all the native syscalls
|
||||||
|
* available in the kernel
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This syscall is used to exit the current
|
||||||
|
* process with the provided exit code.
|
||||||
|
*
|
||||||
|
* @fn void exit(int status);
|
||||||
|
*
|
||||||
|
* @param Code The exit code
|
||||||
|
* @return This syscall does not return
|
||||||
|
*
|
||||||
|
* @note No permissions are required to call
|
||||||
|
* this syscall
|
||||||
|
*/
|
||||||
|
sc_exit = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map pages of memory
|
||||||
|
*
|
||||||
|
* @fn void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
|
||||||
|
*/
|
||||||
|
sc_mmap,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmap pages of memory
|
||||||
|
*
|
||||||
|
* @fn int munmap(void *addr, size_t len);
|
||||||
|
*/
|
||||||
|
sc_munmap,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the protection of a page of memory
|
||||||
|
*
|
||||||
|
* @fn int mprotect(void *addr, size_t len, int prot);
|
||||||
|
*/
|
||||||
|
sc_mprotect,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a file
|
||||||
|
*
|
||||||
|
* @fn int open(const char *path, int oflag, ... );
|
||||||
|
*/
|
||||||
|
sc_open,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a file descriptor
|
||||||
|
*
|
||||||
|
* @fn int close(int fildes);
|
||||||
|
*/
|
||||||
|
sc_close,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from a file descriptor
|
||||||
|
*
|
||||||
|
* @fn ssize_t read(int fildes, void *buf, size_t nbyte);
|
||||||
|
*/
|
||||||
|
sc_read,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to a file descriptor
|
||||||
|
*
|
||||||
|
* @fn ssize_t write(int fildes, const void *buf, size_t nbyte);
|
||||||
|
*/
|
||||||
|
sc_write,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek to a position in a file descriptor
|
||||||
|
*
|
||||||
|
* @fn off_t lseek(int fildes, off_t offset, int whence);
|
||||||
|
*/
|
||||||
|
sc_lseek,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new process
|
||||||
|
*
|
||||||
|
* @fn pid_t fork(void);
|
||||||
|
*/
|
||||||
|
sc_fork,
|
||||||
|
|
||||||
|
/** Not a real syscall */
|
||||||
|
sc_MaxSyscall
|
||||||
|
} NativeSyscalls;
|
||||||
|
|
||||||
|
#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_KERNEL_SYSCALLS_LIST_H__
|
@ -1,3 +1,20 @@
|
|||||||
|
/*
|
||||||
|
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__
|
#ifndef __FENNIX_API_TYPES_H__
|
||||||
#define __FENNIX_API_TYPES_H__
|
#define __FENNIX_API_TYPES_H__
|
||||||
|
|
||||||
@ -37,6 +54,58 @@ typedef __UINTMAX_TYPE__ uintmax_t;
|
|||||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||||
typedef __SIZE_TYPE__ size_t;
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
|
||||||
|
typedef __SIZE_TYPE__ dev_t;
|
||||||
|
typedef __SIZE_TYPE__ off_t;
|
||||||
|
typedef __INT32_TYPE__ mode_t;
|
||||||
|
typedef int pid_t;
|
||||||
|
|
||||||
#define UNUSED(x) (void)(x)
|
#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)
|
||||||
|
|
||||||
#endif // !__FENNIX_API_TYPES_H__
|
#endif // !__FENNIX_API_TYPES_H__
|
||||||
|
25
include/vm.h
Normal file
25
include/vm.h
Normal 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FENNIX_API_VM_H__
|
||||||
|
#define __FENNIX_API_VM_H__
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
bool IsVMwareBackdoorAvailable();
|
||||||
|
|
||||||
|
#endif // !__FENNIX_API_VM_H__
|
5
input/Makefile
Normal file
5
input/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
build:
|
||||||
|
make -C aip build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C aip clean
|
83
input/aip/Makefile
Normal file
83
input/aip/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = aip.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
38
input/aip/aip.h
Normal file
38
input/aip/aip.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
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();
|
||||||
|
|
||||||
|
#endif // !__FENNIX_DRIVER_AIP_H__
|
309
input/aip/keyboard.c
Normal file
309
input/aip/keyboard.c
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
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 <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};
|
||||||
|
|
||||||
|
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;
|
||||||
|
Log("Unknown PS/2 Keyboard Scan Code Set: %#x", KeyboardScanCodeSet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int InitializeKeyboard()
|
||||||
|
{
|
||||||
|
// PS2WriteData(PS2_KBD_CMD_RESET);
|
||||||
|
// uint8_t test = PS2ReadData();
|
||||||
|
// if (test != PS2_KBD_RESP_TEST_PASSED &&
|
||||||
|
// test != PS2_KBD_RESP_ACK)
|
||||||
|
// {
|
||||||
|
// Log("PS/2 keyboard reset failed (%#x)", test);
|
||||||
|
// return -EFAULT;
|
||||||
|
// }
|
||||||
|
|
||||||
|
PS2WriteData(PS2_KBD_CMD_DEFAULTS);
|
||||||
|
if (PS2ACKTimeout() != 0)
|
||||||
|
Log("PS/2 keyboard failed to set defaults");
|
||||||
|
|
||||||
|
PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
|
||||||
|
if (PS2ACKTimeout() != 0)
|
||||||
|
Log("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)
|
||||||
|
Log("PS/2 keyboard failed to set scan code set 2");
|
||||||
|
|
||||||
|
PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
|
||||||
|
if (PS2ACKTimeout() != 0)
|
||||||
|
Log("PS/2 keyboard failed to set scan code set");
|
||||||
|
|
||||||
|
PS2WriteData(PS2_KBD_SCAN_CODE_GET_CURRENT);
|
||||||
|
if (PS2ACKTimeout() != 0)
|
||||||
|
Log("PS/2 keyboard failed to get current scan code set");
|
||||||
|
|
||||||
|
KeyboardScanCodeSet = PS2ReadAfterACK();
|
||||||
|
Log("PS/2 Keyboard Scan Code Set: 0x%X", KeyboardScanCodeSet);
|
||||||
|
PS2ClearOutputBuffer();
|
||||||
|
|
||||||
|
PS2WriteData(PS2_KBD_CMD_ENABLE_SCANNING);
|
||||||
|
|
||||||
|
RegisterInterruptHandler(1, PS2KbdInterruptHandler);
|
||||||
|
KeyboardDevID = RegisterInputDevice(ddt_Keyboard);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FinalizeKeyboard()
|
||||||
|
{
|
||||||
|
UnregisterInputDevice(KeyboardDevID, ddt_Keyboard);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DetectPS2Keyboard()
|
||||||
|
{
|
||||||
|
PS2WriteData(PS2_KBD_CMD_DISABLE_SCANNING);
|
||||||
|
if (PS2ACKTimeout() != 0)
|
||||||
|
Log("PS/2 keyboard failed to disable scanning");
|
||||||
|
|
||||||
|
PS2WriteData(PS2_KBD_CMD_IDENTIFY);
|
||||||
|
if (PS2ACKTimeout() != 0)
|
||||||
|
Log("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)
|
||||||
|
Log("PS/2 keyboard second byte timed out");
|
||||||
|
else
|
||||||
|
Device1ID[1] = recByte;
|
||||||
|
|
||||||
|
Log("PS2 Keyboard Device: 0x%X 0x%X", Device1ID[0], Device1ID[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
234
input/aip/main.c
Normal file
234
input/aip/main.c
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
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)
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("PS/2 Port 1 self test failed (%#x)", test);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DualChannel)
|
||||||
|
{
|
||||||
|
PS2WriteCommand(PS2_CMD_TEST_PORT_2);
|
||||||
|
test = PS2ReadData();
|
||||||
|
if (test != 0x00)
|
||||||
|
{
|
||||||
|
Log("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();
|
||||||
|
|
||||||
|
UnregisterAllInterruptHandlers(__intStub);
|
||||||
|
|
||||||
|
if (kbd != 0 && mouse != 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (kbd == 0)
|
||||||
|
{
|
||||||
|
if (!IsKeyboard(Device1ID[0]))
|
||||||
|
{
|
||||||
|
Log("PS/2 Port 1 is not a keyboard");
|
||||||
|
// return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse == 0)
|
||||||
|
{
|
||||||
|
if (!IsMouse(Device2ID[0]))
|
||||||
|
{
|
||||||
|
Log("PS/2 Port 2 is not a mouse");
|
||||||
|
// return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrint("PS/2 Port 1: %s (0x%X 0x%X)",
|
||||||
|
GetPS2DeviceName(Device1ID[0], Device1ID[1]),
|
||||||
|
Device1ID[0], Device1ID[1]);
|
||||||
|
KPrint("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.1",
|
||||||
|
"GPLv3");
|
233
input/aip/mouse.c
Normal file
233
input/aip/mouse.c
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
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 <input.h>
|
||||||
|
#include <base.h>
|
||||||
|
|
||||||
|
dev_t MouseDevID = -1;
|
||||||
|
bool PacketReady = false;
|
||||||
|
bool FourPackets = false;
|
||||||
|
bool MouseButton45 = false;
|
||||||
|
uint8_t Cycle = 0;
|
||||||
|
PS2_MOUSE_PACKET Packet = {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;
|
||||||
|
|
||||||
|
MouseReport mr = {
|
||||||
|
.LeftButton = Packet.Base.LeftButton,
|
||||||
|
.RightButton = Packet.Base.RightButton,
|
||||||
|
.MiddleButton = Packet.Base.MiddleButton,
|
||||||
|
.Button4 = Packet.ZMovement.Button4,
|
||||||
|
.Button5 = Packet.ZMovement.Button5,
|
||||||
|
.X = X,
|
||||||
|
.Y = -Y,
|
||||||
|
.Z = Packet.ZMovement.Z,
|
||||||
|
};
|
||||||
|
ReportRelativeMouseEvent(MouseDevID, mr);
|
||||||
|
|
||||||
|
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 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)
|
||||||
|
{
|
||||||
|
Log("PS/2 mouse reset failed! (%#x)", test);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterInterruptHandler(12, PS2MouseInterruptHandler);
|
||||||
|
MouseDevID = RegisterInputDevice(ddt_Mouse);
|
||||||
|
|
||||||
|
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();
|
||||||
|
Log("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();
|
||||||
|
Log("PS/2 Mouse ID: %#x", Device2ID);
|
||||||
|
|
||||||
|
if (Device2ID >= 3 && Device2ID <= 4)
|
||||||
|
FourPackets = true;
|
||||||
|
if (Device2ID == 4)
|
||||||
|
MouseButton45 = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FinalizeMouse()
|
||||||
|
{
|
||||||
|
UnregisterInputDevice(MouseDevID, ddt_Mouse);
|
||||||
|
|
||||||
|
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||||
|
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)
|
||||||
|
Log("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)
|
||||||
|
Log("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;
|
||||||
|
|
||||||
|
Log("PS2 Mouse Device: 0x%X 0x%X", Device2ID[0], Device2ID[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
82
library/Makefile
Normal file
82
library/Makefile
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = libdriver.a
|
||||||
|
|
||||||
|
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 driver.map -static -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -shared -c crt/crt0.c -o dcrt0.o
|
||||||
|
mv dcrt0.o ../out/dcrt0.o
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(AR) rcs $@ $(OBJ)
|
||||||
|
mv $(FILENAME) ../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 driver.map $(OBJ) $(FILENAME) $(STACK_USAGE_OBJ) dcrt0.su
|
146
library/aip.c
Normal file
146
library/aip.c
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
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 <io.h>
|
||||||
|
|
||||||
|
extern void Log(const char *Format, ...);
|
||||||
|
|
||||||
|
void PIC_EOI(uint8_t IRQ)
|
||||||
|
{
|
||||||
|
if (IRQ >= 8)
|
||||||
|
outb(PIC2_CMD, _PIC_EOI);
|
||||||
|
outb(PIC1_CMD, _PIC_EOI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRQ_MASK(uint8_t IRQ)
|
||||||
|
{
|
||||||
|
uint16_t port;
|
||||||
|
uint8_t value;
|
||||||
|
|
||||||
|
if (IRQ < 8)
|
||||||
|
port = PIC1_DATA;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port = PIC2_DATA;
|
||||||
|
IRQ -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = inb(port) | (1 << IRQ);
|
||||||
|
outb(port, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRQ_UNMASK(uint8_t IRQ)
|
||||||
|
{
|
||||||
|
uint16_t port;
|
||||||
|
uint8_t value;
|
||||||
|
|
||||||
|
if (IRQ < 8)
|
||||||
|
port = PIC1_DATA;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port = PIC2_DATA;
|
||||||
|
IRQ -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = inb(port) & ~(1 << IRQ);
|
||||||
|
outb(port, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Wait(const bool Output)
|
||||||
|
{
|
||||||
|
int Timeout = 100000;
|
||||||
|
PS2_STATUSES Status = {.Raw = inb(PS2_STATUS)};
|
||||||
|
while (Timeout--)
|
||||||
|
{
|
||||||
|
if (!Output) /* FIXME: Reverse? */
|
||||||
|
{
|
||||||
|
if (Status.OutputBufferFull == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Status.InputBufferFull == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Status.Raw = inb(PS2_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("PS/2 controller timeout! (Status: %#x, %d)", Status, Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2WriteCommand(uint8_t Command)
|
||||||
|
{
|
||||||
|
WaitInput;
|
||||||
|
outb(PS2_CMD, Command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2WriteData(uint8_t Data)
|
||||||
|
{
|
||||||
|
WaitInput;
|
||||||
|
outb(PS2_DATA, Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PS2ReadData()
|
||||||
|
{
|
||||||
|
WaitOutput;
|
||||||
|
return inb(PS2_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PS2ReadStatus()
|
||||||
|
{
|
||||||
|
WaitOutput;
|
||||||
|
return inb(PS2_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PS2ReadAfterACK()
|
||||||
|
{
|
||||||
|
uint8_t ret = PS2ReadData();
|
||||||
|
while (ret == PS2_ACK)
|
||||||
|
{
|
||||||
|
WaitOutput;
|
||||||
|
ret = inb(PS2_DATA);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2ClearOutputBuffer()
|
||||||
|
{
|
||||||
|
PS2_STATUSES Status;
|
||||||
|
int timeout = 0x500;
|
||||||
|
while (timeout--)
|
||||||
|
{
|
||||||
|
Status.Raw = inb(PS2_STATUS);
|
||||||
|
if (Status.OutputBufferFull == 0)
|
||||||
|
return;
|
||||||
|
inb(PS2_DATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS2ACKTimeout()
|
||||||
|
{
|
||||||
|
int timeout = 0x500;
|
||||||
|
while (timeout > 0)
|
||||||
|
{
|
||||||
|
if (PS2ReadData() == PS2_ACK)
|
||||||
|
return 0;
|
||||||
|
timeout--;
|
||||||
|
}
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
31
library/audio.c
Normal file
31
library/audio.c
Normal 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 <audio.h>
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
dev_t RegisterAudioDevice(DeviceDriverType Type, drvOpen_t Open, drvClose_t Close,
|
||||||
|
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
|
||||||
|
{
|
||||||
|
return API->RegisterAudioDevice(API->MajorID, Type, Open, Close, Read, Write, Ioctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnregisterAudioDevice(dev_t DeviceID, DeviceDriverType Type)
|
||||||
|
{
|
||||||
|
return API->UnregisterAudioDevice(API->MajorID, DeviceID, Type);
|
||||||
|
}
|
182
library/base.c
Normal file
182
library/base.c
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
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>
|
||||||
|
|
||||||
|
__driverAPI *API = NULL;
|
||||||
|
|
||||||
|
int RegisterInterruptHandler(uint8_t IRQ, void *Handler)
|
||||||
|
{
|
||||||
|
if (Handler == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return API->RegisterInterruptHandler(API->MajorID,
|
||||||
|
IRQ,
|
||||||
|
Handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
int OverrideInterruptHandler(uint8_t IRQ, void *Handler)
|
||||||
|
{
|
||||||
|
if (Handler == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return API->OverrideInterruptHandler(API->MajorID,
|
||||||
|
IRQ,
|
||||||
|
Handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnregisterInterruptHandler(uint8_t IRQ, void *Handler)
|
||||||
|
{
|
||||||
|
if (Handler == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return API->UnregisterInterruptHandler(API->MajorID,
|
||||||
|
IRQ,
|
||||||
|
Handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnregisterAllInterruptHandlers(void *Handler)
|
||||||
|
{
|
||||||
|
if (Handler == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return API->UnregisterAllInterruptHandlers(API->MajorID,
|
||||||
|
Handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *AllocateMemory(size_t Pages)
|
||||||
|
{
|
||||||
|
if (Pages == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return API->RequestPages(API->MajorID,
|
||||||
|
Pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeMemory(void *Pointer, size_t Pages)
|
||||||
|
{
|
||||||
|
if (Pointer == NULL || Pages == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
API->FreePages(API->MajorID,
|
||||||
|
Pointer,
|
||||||
|
Pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendMapFlag(void *Address, PageMapFlags Flag)
|
||||||
|
{
|
||||||
|
API->AppendMapFlag(API->MajorID,
|
||||||
|
Address,
|
||||||
|
Flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveMapFlag(void *Address, PageMapFlags Flag)
|
||||||
|
{
|
||||||
|
API->RemoveMapFlag(API->MajorID,
|
||||||
|
Address,
|
||||||
|
Flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapPages(void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags)
|
||||||
|
{
|
||||||
|
API->MapPages(API->MajorID,
|
||||||
|
PhysicalAddress,
|
||||||
|
VirtualAddress,
|
||||||
|
Pages,
|
||||||
|
Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnmapPages(void *VirtualAddress, size_t Pages)
|
||||||
|
{
|
||||||
|
API->UnmapPages(API->MajorID,
|
||||||
|
VirtualAddress,
|
||||||
|
Pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KPrint(const char *Format, ...)
|
||||||
|
{
|
||||||
|
va_list Args;
|
||||||
|
va_start(Args, Format);
|
||||||
|
|
||||||
|
API->KPrint(API->MajorID,
|
||||||
|
Format,
|
||||||
|
Args);
|
||||||
|
|
||||||
|
va_end(Args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log(const char *Format, ...)
|
||||||
|
{
|
||||||
|
va_list Args;
|
||||||
|
va_start(Args, Format);
|
||||||
|
|
||||||
|
API->KernelLog(API->MajorID,
|
||||||
|
Format,
|
||||||
|
Args);
|
||||||
|
|
||||||
|
va_end(Args);
|
||||||
|
}
|
||||||
|
|
||||||
|
CriticalState EnterCriticalSection()
|
||||||
|
{
|
||||||
|
CriticalState cs;
|
||||||
|
|
||||||
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
|
||||||
|
uintptr_t Flags;
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
asmv("pushfq");
|
||||||
|
asmv("popq %0"
|
||||||
|
: "=r"(Flags));
|
||||||
|
#else
|
||||||
|
asmv("pushfl");
|
||||||
|
asmv("popl %0"
|
||||||
|
: "=r"(Flags));
|
||||||
|
#endif
|
||||||
|
cs = Flags & (1 << 9);
|
||||||
|
asmv("cli");
|
||||||
|
|
||||||
|
#elif defined(__arm__) || defined(__aarch64__)
|
||||||
|
|
||||||
|
uintptr_t Flags;
|
||||||
|
asmv("mrs %0, cpsr"
|
||||||
|
: "=r"(Flags));
|
||||||
|
cs = Flags & (1 << 7);
|
||||||
|
asmv("cpsid i");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LeaveCriticalSection(CriticalState PreviousState)
|
||||||
|
{
|
||||||
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
|
||||||
|
if (PreviousState)
|
||||||
|
asmv("sti");
|
||||||
|
|
||||||
|
#elif defined(__arm__) || defined(__aarch64__)
|
||||||
|
|
||||||
|
if (PreviousState)
|
||||||
|
asmv("cpsie i");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
31
library/block.c
Normal file
31
library/block.c
Normal 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 <block.h>
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
dev_t RegisterBlockDevice(DeviceDriverType Type, drvOpen_t Open, drvClose_t Close,
|
||||||
|
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
|
||||||
|
{
|
||||||
|
return API->RegisterBlockDevice(API->MajorID, Type, Open, Close, Read, Write, Ioctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnregisterBlockDevice(dev_t DeviceID, DeviceDriverType Type)
|
||||||
|
{
|
||||||
|
return API->UnregisterBlockDevice(API->MajorID, DeviceID, Type);
|
||||||
|
}
|
85
library/crt/crt0.c
Normal file
85
library/crt/crt0.c
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
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>
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
int DriverEntry();
|
||||||
|
int DriverFinal();
|
||||||
|
int DriverPanic();
|
||||||
|
int DriverProbe();
|
||||||
|
void __IdentifyDriver(
|
||||||
|
dev_t ID,
|
||||||
|
int (*GetDriverInfo)(dev_t, const char *, const char *,
|
||||||
|
const char *, const char *, const char *));
|
||||||
|
|
||||||
|
typedef void (*CallPtr)(void);
|
||||||
|
extern CallPtr __init_array_start[0], __init_array_end[0];
|
||||||
|
extern CallPtr __fini_array_start[0], __fini_array_end[0];
|
||||||
|
|
||||||
|
int _entry()
|
||||||
|
{
|
||||||
|
for (CallPtr *func = __init_array_start; func != __init_array_end; func++)
|
||||||
|
(*func)();
|
||||||
|
|
||||||
|
return DriverEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
int _final()
|
||||||
|
{
|
||||||
|
int err = DriverFinal();
|
||||||
|
|
||||||
|
for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++)
|
||||||
|
(*func)();
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define API_MajorRequiredVersion 0
|
||||||
|
#define API_MinorRequiredVersion 0
|
||||||
|
#define API_PatchRequiredVersion 0
|
||||||
|
|
||||||
|
int _start(__driverAPI *__API)
|
||||||
|
{
|
||||||
|
if (unlikely(__API == NULL))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (unlikely(__API->APIVersion.Major != API_MajorRequiredVersion ||
|
||||||
|
__API->APIVersion.Minor != API_MinorRequiredVersion ||
|
||||||
|
__API->APIVersion.Patch != API_PatchRequiredVersion))
|
||||||
|
return -EPROTO;
|
||||||
|
|
||||||
|
if (unlikely(__API->RegisterFunction == NULL))
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
if (unlikely(DriverEntry == NULL ||
|
||||||
|
DriverFinal == NULL ||
|
||||||
|
DriverPanic == NULL ||
|
||||||
|
DriverProbe == NULL ||
|
||||||
|
__IdentifyDriver == NULL))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
API = __API;
|
||||||
|
__API->RegisterFunction(__API->MajorID, _entry, _drf_Entry);
|
||||||
|
__API->RegisterFunction(__API->MajorID, _final, _drf_Final);
|
||||||
|
__API->RegisterFunction(__API->MajorID, DriverPanic, _drf_Panic);
|
||||||
|
__API->RegisterFunction(__API->MajorID, DriverProbe, _drf_Probe);
|
||||||
|
__IdentifyDriver(__API->MajorID, __API->GetDriverInfo);
|
||||||
|
return 0;
|
||||||
|
}
|
61
library/input.c
Normal file
61
library/input.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
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 <input.h>
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
dev_t RegisterInputDevice(DeviceDriverType Type)
|
||||||
|
{
|
||||||
|
return API->RegisterInputDevice(API->MajorID, Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnregisterInputDevice(dev_t DeviceID, DeviceDriverType Type)
|
||||||
|
{
|
||||||
|
return API->UnregisterInputDevice(API->MajorID, DeviceID, Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReportKeyboardEvent(dev_t DeviceID, KeyScanCodes ScanCode, uint8_t Pressed)
|
||||||
|
{
|
||||||
|
if (Pressed)
|
||||||
|
ScanCode |= KEY_PRESSED;
|
||||||
|
return API->ReportKeyboardEvent(API->MajorID, DeviceID, ScanCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReportRelativeMouseEvent(dev_t DeviceID, MouseReport Report)
|
||||||
|
{
|
||||||
|
__MouseButtons mb = {
|
||||||
|
.LeftButton = Report.LeftButton,
|
||||||
|
.RightButton = Report.RightButton,
|
||||||
|
.MiddleButton = Report.MiddleButton,
|
||||||
|
.Button4 = Report.Button4,
|
||||||
|
.Button5 = Report.Button5,
|
||||||
|
};
|
||||||
|
return API->ReportRelativeMouseEvent(API->MajorID, DeviceID, mb, Report.X, Report.Y, Report.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReportAbsoluteMouseEvent(dev_t DeviceID, MouseReport Report, uintptr_t X, uintptr_t Y)
|
||||||
|
{
|
||||||
|
__MouseButtons mb = {
|
||||||
|
.LeftButton = Report.LeftButton,
|
||||||
|
.RightButton = Report.RightButton,
|
||||||
|
.MiddleButton = Report.MiddleButton,
|
||||||
|
.Button4 = Report.Button4,
|
||||||
|
.Button5 = Report.Button5,
|
||||||
|
};
|
||||||
|
return API->ReportAbsoluteMouseEvent(API->MajorID, DeviceID, mb, X, Y, Report.Z);
|
||||||
|
}
|
36
library/net.c
Normal file
36
library/net.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
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 <net.h>
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
dev_t RegisterNetDevice(DeviceDriverType Type, drvOpen_t Open, drvClose_t Close,
|
||||||
|
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
|
||||||
|
{
|
||||||
|
return API->RegisterNetDevice(API->MajorID, Type, Open, Close, Read, Write, Ioctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnregisterNetDevice(dev_t DeviceID, DeviceDriverType Type)
|
||||||
|
{
|
||||||
|
return API->UnregisterNetDevice(API->MajorID, DeviceID, Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReportNetworkPacket(dev_t DeviceID, void *Buffer, size_t Size)
|
||||||
|
{
|
||||||
|
return API->ReportNetworkPacket(API->MajorID, DeviceID, Buffer, Size);
|
||||||
|
}
|
57
library/pci.c
Normal file
57
library/pci.c
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
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 <pci.h>
|
||||||
|
|
||||||
|
#include <driver.h>
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
static_assert(sizeof(PCIArray) == sizeof(__PCIArray),
|
||||||
|
"PCIArray size mismatch");
|
||||||
|
|
||||||
|
PCIArray *FindPCIDevices(uint16_t Vendors[], uint16_t Devices[])
|
||||||
|
{
|
||||||
|
return (PCIArray *)API->GetPCIDevices(API->MajorID,
|
||||||
|
Vendors,
|
||||||
|
Devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializePCI(PCIDevice *Device)
|
||||||
|
{
|
||||||
|
API->InitializePCI(API->MajorID,
|
||||||
|
(void *)Device->Header);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetBAR(uint8_t Index, PCIDevice *Device)
|
||||||
|
{
|
||||||
|
return API->GetBAR(API->MajorID,
|
||||||
|
Index,
|
||||||
|
(void *)Device->Header);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t iLine(PCIDevice *Device)
|
||||||
|
{
|
||||||
|
PCIHeader0 *Header = (PCIHeader0 *)Device->Header;
|
||||||
|
return Header->InterruptLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t iPin(PCIDevice *Device)
|
||||||
|
{
|
||||||
|
PCIHeader0 *Header = (PCIHeader0 *)Device->Header;
|
||||||
|
return Header->InterruptPin;
|
||||||
|
}
|
51
library/std.c
Normal file
51
library/std.c
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
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>
|
||||||
|
|
||||||
|
#undef memcpy
|
||||||
|
#undef memset
|
||||||
|
#undef memmove
|
||||||
|
#undef strlen
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
void *MemoryCopy(void *Destination, const void *Source, size_t Length)
|
||||||
|
{
|
||||||
|
return API->memcpy(API->MajorID, Destination, Source, Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemorySet(void *Destination, int Value, size_t Length)
|
||||||
|
{
|
||||||
|
return API->memset(API->MajorID, Destination, Value, Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemoryMove(void *Destination, const void *Source, size_t Length)
|
||||||
|
{
|
||||||
|
return API->memmove(API->MajorID, Destination, Source, Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t StringLength(const char String[])
|
||||||
|
{
|
||||||
|
return API->strlen(API->MajorID, String);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strstr(const char *Haystack, const char *Needle)
|
||||||
|
{
|
||||||
|
return API->strstr(API->MajorID, Haystack, Needle);
|
||||||
|
}
|
73
library/stdcpp.cpp
Normal file
73
library/stdcpp.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
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>
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: memory allocator
|
||||||
|
* we can't really call kernel's malloc because the
|
||||||
|
* kernel keep track of memory usage for each driver
|
||||||
|
*
|
||||||
|
* maybe implement the allocator in vma?
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *__new_alloc_page(std::size_t Size)
|
||||||
|
{
|
||||||
|
/* Do not allow allocations larger than 4 KiB */
|
||||||
|
if (Size > PAGE_SIZE)
|
||||||
|
asmv("ud2");
|
||||||
|
|
||||||
|
return API->RequestPages(API->MajorID, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __delete_alloc_page(void *Pointer)
|
||||||
|
{
|
||||||
|
API->FreePages(API->MajorID, Pointer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new(std::size_t Size)
|
||||||
|
{
|
||||||
|
return __new_alloc_page(Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new[](std::size_t Size)
|
||||||
|
{
|
||||||
|
return __new_alloc_page(Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void *Pointer)
|
||||||
|
{
|
||||||
|
__delete_alloc_page(Pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void *Pointer)
|
||||||
|
{
|
||||||
|
__delete_alloc_page(Pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void *Pointer, std::size_t)
|
||||||
|
{
|
||||||
|
__delete_alloc_page(Pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void *Pointer, std::size_t)
|
||||||
|
{
|
||||||
|
__delete_alloc_page(Pointer);
|
||||||
|
}
|
59
library/task.c
Normal file
59
library/task.c
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
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 <base.h>
|
||||||
|
|
||||||
|
extern __driverAPI *API;
|
||||||
|
|
||||||
|
pid_t CreateKernelProcess(const char *Name)
|
||||||
|
{
|
||||||
|
return API->CreateKernelProcess(API->MajorID,
|
||||||
|
Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t CreateKernelThread(pid_t pId, const char *Name, void *EntryPoint, void *Argument)
|
||||||
|
{
|
||||||
|
return API->CreateKernelThread(API->MajorID,
|
||||||
|
pId,
|
||||||
|
Name,
|
||||||
|
EntryPoint,
|
||||||
|
Argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
int KillProcess(pid_t pId, int ExitCode)
|
||||||
|
{
|
||||||
|
return API->KillProcess(API->MajorID,
|
||||||
|
pId, ExitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int KillThread(pid_t tId, int ExitCode)
|
||||||
|
{
|
||||||
|
return API->KillThread(API->MajorID,
|
||||||
|
tId, ExitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Yield()
|
||||||
|
{
|
||||||
|
API->Yield(API->MajorID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sleep(uint64_t Milliseconds)
|
||||||
|
{
|
||||||
|
API->Sleep(API->MajorID,
|
||||||
|
Milliseconds);
|
||||||
|
}
|
114
library/vm.c
Normal file
114
library/vm.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
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 <vm.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
7
misc/Makefile
Normal file
7
misc/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
build:
|
||||||
|
make -C example build
|
||||||
|
make -C vmware build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C example clean
|
||||||
|
make -C vmware clean
|
83
misc/example/Makefile
Normal file
83
misc/example/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = example.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
87
misc/example/main.c
Normal file
87
misc/example/main.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
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 is called when the driver is loaded.
|
||||||
|
* This function should be used to initialize the PCI device
|
||||||
|
* and allocate resources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Print a message to the screen */
|
||||||
|
KPrint("Hello World from Example Driver!");
|
||||||
|
|
||||||
|
/* Print a message to the kernel log */
|
||||||
|
Log("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
|
||||||
|
* receiving 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.
|
||||||
|
* We can use this function to test if the driver is
|
||||||
|
* compatible with the hardware.
|
||||||
|
* Like if we have a specific PCI device or if we have
|
||||||
|
* a specific CPU feature.
|
||||||
|
*
|
||||||
|
* Return 0 if the driver is compatible with the hardware.
|
||||||
|
* Otherwise, we return a value from the errno.h header.
|
||||||
|
*
|
||||||
|
* 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("example",
|
||||||
|
"Example Driver",
|
||||||
|
"EnderIce2",
|
||||||
|
"0.1",
|
||||||
|
"GPLv3");
|
83
misc/vmware/Makefile
Normal file
83
misc/vmware/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = vmware.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
753
misc/vmware/main.c
Normal file
753
misc/vmware/main.c
Normal file
@ -0,0 +1,753 @@
|
|||||||
|
/*
|
||||||
|
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 <input.h>
|
||||||
|
#include <regs.h>
|
||||||
|
#include <base.h>
|
||||||
|
#include <aip.h>
|
||||||
|
#include <vm.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 or in if available
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int TCLOChannel;
|
||||||
|
uint16_t ChannelID;
|
||||||
|
uint32_t CookieHigh;
|
||||||
|
uint32_t CookieLow;
|
||||||
|
} ToolboxContext;
|
||||||
|
|
||||||
|
dev_t MouseDevID = -1;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("Checkpoint occurred for message \"%s\"", Message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("Failed to receive message size: %d", cx);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
else if ((HighWord(cx) & STATUS_DORECV) == 0)
|
||||||
|
{
|
||||||
|
// Log("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)
|
||||||
|
{
|
||||||
|
Log("Checkpoint occurred for message payload");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("Retrying message receive");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("Failed to receive message status: %d", HighWord(cx));
|
||||||
|
FreeMemory(ReplyBuf, ReplyBufPages);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReplyBuf == NULL)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("Failed to open RPCI channel: %d", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = MessageSend(&rpci_ctx, Request);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
Log("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)
|
||||||
|
{
|
||||||
|
Log("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;
|
||||||
|
ToolboxContext *tb_ctx = NULL;
|
||||||
|
void DisplayScaleThread()
|
||||||
|
{
|
||||||
|
/* sizeof ToolboxContext */
|
||||||
|
tb_ctx = AllocateMemory(1);
|
||||||
|
Sleep(2000);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (DisplayGetSize(tb_ctx) != 0)
|
||||||
|
Log("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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Log("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);
|
||||||
|
|
||||||
|
MouseReport mr = {
|
||||||
|
.LeftButton = Buttons & 0x20,
|
||||||
|
.RightButton = Buttons & 0x10,
|
||||||
|
.MiddleButton = Buttons & 0x08,
|
||||||
|
.Button4 = 0x0,
|
||||||
|
.Button5 = 0x0,
|
||||||
|
.X = 0,
|
||||||
|
.Y = 0,
|
||||||
|
.Z = (int8_t)cmd.dx,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
ReportAbsoluteMouseEvent(MouseDevID, mr, AbsoluteX, AbsoluteY);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = RegisterInputDevice(ddt_Mouse);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DriverFinal()
|
||||||
|
{
|
||||||
|
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||||
|
|
||||||
|
Relative();
|
||||||
|
UnregisterInputDevice(MouseDevID, ddt_Mouse);
|
||||||
|
|
||||||
|
if (ToolboxSupported)
|
||||||
|
{
|
||||||
|
KillThread(dst_id, 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.1",
|
||||||
|
"GPLv3");
|
7
network/Makefile
Normal file
7
network/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
build:
|
||||||
|
make -C e1000 build
|
||||||
|
make -C rtl8139 build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C e1000 clean
|
||||||
|
make -C rtl8139 clean
|
83
network/e1000/Makefile
Normal file
83
network/e1000/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = e1000.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
485
network/e1000/e1000.cpp
Normal file
485
network/e1000/e1000.cpp
Normal file
@ -0,0 +1,485 @@
|
|||||||
|
/*
|
||||||
|
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 <net.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
|
||||||
|
{
|
||||||
|
Log("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);
|
||||||
|
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
Log("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())
|
||||||
|
{
|
||||||
|
Log("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:
|
||||||
|
{
|
||||||
|
Log("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:
|
||||||
|
{
|
||||||
|
Log("Unimplemented E1000 device.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
E1000Device *Drivers[4] = {nullptr};
|
||||||
|
dev_t AudioID[4] = {0};
|
||||||
|
|
||||||
|
#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 drvOpen(dev_t, dev_t, int, mode_t) { return 0; }
|
||||||
|
int drvClose(dev_t, dev_t) { return 0; }
|
||||||
|
size_t drvRead(dev_t, dev_t, uint8_t *, size_t, off_t) { return 0; }
|
||||||
|
|
||||||
|
size_t drvWrite(dev_t, dev_t min, uint8_t *Buffer, size_t Size, off_t)
|
||||||
|
{
|
||||||
|
return Drivers[AudioID[min]]->write(Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int drvIoctl(dev_t, dev_t min, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
return Drivers[AudioID[min]]->ioctl((NetIoctl)Request, Argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = FindPCIDevices(VendorIDs, DeviceIDs);
|
||||||
|
if (Devices == nullptr)
|
||||||
|
{
|
||||||
|
Log("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 = RegisterNetDevice(ddt_Network,
|
||||||
|
drvOpen, drvClose,
|
||||||
|
drvRead, drvWrite,
|
||||||
|
drvIoctl);
|
||||||
|
AudioID[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)
|
||||||
|
{
|
||||||
|
Log("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
163
network/e1000/e1000.hpp
Normal file
163
network/e1000/e1000.hpp
Normal 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();
|
31
network/e1000/main.c
Normal file
31
network/e1000/main.c
Normal 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.1",
|
||||||
|
"GPLv3");
|
83
network/rtl8139/Makefile
Normal file
83
network/rtl8139/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = rtl8139.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
31
network/rtl8139/main.c
Normal file
31
network/rtl8139/main.c
Normal 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.1",
|
||||||
|
"GPLv3");
|
298
network/rtl8139/rtl8139.cpp
Normal file
298
network/rtl8139/rtl8139.cpp
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
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 <net.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);
|
||||||
|
|
||||||
|
/* 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 AudioID[4] = {0};
|
||||||
|
|
||||||
|
#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 drvOpen(dev_t, dev_t, int, mode_t) { return 0; }
|
||||||
|
int drvClose(dev_t, dev_t) { return 0; }
|
||||||
|
size_t drvRead(dev_t, dev_t, uint8_t *, size_t, off_t) { return 0; }
|
||||||
|
|
||||||
|
size_t drvWrite(dev_t, dev_t min, uint8_t *Buffer, size_t Size, off_t)
|
||||||
|
{
|
||||||
|
return Drivers[AudioID[min]]->write(Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int drvIoctl(dev_t, dev_t min, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
return Drivers[AudioID[min]]->ioctl((NetIoctl)Request, Argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = FindPCIDevices(VendorIDs, DeviceIDs);
|
||||||
|
if (Devices == nullptr)
|
||||||
|
{
|
||||||
|
Log("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 = RegisterNetDevice(ddt_Network,
|
||||||
|
drvOpen, drvClose,
|
||||||
|
drvRead, drvWrite,
|
||||||
|
drvIoctl);
|
||||||
|
AudioID[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)
|
||||||
|
{
|
||||||
|
Log("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
93
network/rtl8139/rtl8139.hpp
Normal file
93
network/rtl8139/rtl8139.hpp
Normal 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
storage/Makefile
Normal file
7
storage/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
build:
|
||||||
|
make -C ahci build
|
||||||
|
make -C ata build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C ahci clean
|
||||||
|
make -C ata clean
|
83
storage/ahci/Makefile
Normal file
83
storage/ahci/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = ahci.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
517
storage/ahci/ahci.cpp
Normal file
517
storage/ahci/ahci.cpp
Normal file
@ -0,0 +1,517 @@
|
|||||||
|
/*
|
||||||
|
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 <block.h>
|
||||||
|
#include <regs.h>
|
||||||
|
#include <base.h>
|
||||||
|
#include <pci.h>
|
||||||
|
|
||||||
|
#define ATA_DEV_BUSY 0x80
|
||||||
|
#define ATA_DEV_DRQ 0x08
|
||||||
|
#define ATA_CMD_WRITE_DMA_EX 0x35
|
||||||
|
#define ATA_CMD_READ_DMA_EX 0x25
|
||||||
|
#define HBA_PxIS_TFES (1 << 30)
|
||||||
|
|
||||||
|
#define HBA_PORT_DEV_PRESENT 0x3
|
||||||
|
#define HBA_PORT_IPM_ACTIVE 0x1
|
||||||
|
#define SATA_SIG_ATAPI 0xEB140101
|
||||||
|
#define SATA_SIG_ATA 0x00000101
|
||||||
|
#define SATA_SIG_SEMB 0xC33C0101
|
||||||
|
#define SATA_SIG_PM 0x96690101
|
||||||
|
|
||||||
|
#define HBA_PxCMD_CR 0x8000
|
||||||
|
#define HBA_PxCMD_FRE 0x0010
|
||||||
|
#define HBA_PxCMD_ST 0x0001
|
||||||
|
#define HBA_PxCMD_FR 0x4000
|
||||||
|
|
||||||
|
enum PortType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
SATA = 1,
|
||||||
|
SEMB = 2,
|
||||||
|
PM = 3,
|
||||||
|
SATAPI = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FIS_TYPE
|
||||||
|
{
|
||||||
|
FIS_TYPE_REG_H2D = 0x27,
|
||||||
|
FIS_TYPE_REG_D2H = 0x34,
|
||||||
|
FIS_TYPE_DMA_ACT = 0x39,
|
||||||
|
FIS_TYPE_DMA_SETUP = 0x41,
|
||||||
|
FIS_TYPE_DATA = 0x46,
|
||||||
|
FIS_TYPE_BIST = 0x58,
|
||||||
|
FIS_TYPE_PIO_SETUP = 0x5F,
|
||||||
|
FIS_TYPE_DEV_BITS = 0xA1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HBAPort
|
||||||
|
{
|
||||||
|
uint32_t CommandListBase;
|
||||||
|
uint32_t CommandListBaseUpper;
|
||||||
|
uint32_t FISBaseAddress;
|
||||||
|
uint32_t FISBaseAddressUpper;
|
||||||
|
uint32_t InterruptStatus;
|
||||||
|
uint32_t InterruptEnable;
|
||||||
|
uint32_t CommandStatus;
|
||||||
|
uint32_t Reserved0;
|
||||||
|
uint32_t TaskFileData;
|
||||||
|
uint32_t Signature;
|
||||||
|
uint32_t SataStatus;
|
||||||
|
uint32_t SataControl;
|
||||||
|
uint32_t SataError;
|
||||||
|
uint32_t SataActive;
|
||||||
|
uint32_t CommandIssue;
|
||||||
|
uint32_t SataNotification;
|
||||||
|
uint32_t FISSwitchControl;
|
||||||
|
uint32_t Reserved1[11];
|
||||||
|
uint32_t Vendor[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HBAMemory
|
||||||
|
{
|
||||||
|
uint32_t HostCapability;
|
||||||
|
uint32_t GlobalHostControl;
|
||||||
|
uint32_t InterruptStatus;
|
||||||
|
uint32_t PortsImplemented;
|
||||||
|
uint32_t Version;
|
||||||
|
uint32_t CCCControl;
|
||||||
|
uint32_t CCCPorts;
|
||||||
|
uint32_t EnclosureManagementLocation;
|
||||||
|
uint32_t EnclosureManagementControl;
|
||||||
|
uint32_t HostCapabilitiesExtended;
|
||||||
|
uint32_t BIOSHandoffControlStatus;
|
||||||
|
uint8_t Reserved0[0x74];
|
||||||
|
uint8_t Vendor[0x60];
|
||||||
|
HBAPort Ports[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HBACommandHeader
|
||||||
|
{
|
||||||
|
uint8_t CommandFISLength : 5;
|
||||||
|
uint8_t ATAPI : 1;
|
||||||
|
uint8_t Write : 1;
|
||||||
|
uint8_t Preferable : 1;
|
||||||
|
uint8_t Reset : 1;
|
||||||
|
uint8_t BIST : 1;
|
||||||
|
uint8_t ClearBusy : 1;
|
||||||
|
uint8_t Reserved0 : 1;
|
||||||
|
uint8_t PortMultiplier : 4;
|
||||||
|
uint16_t PRDTLength;
|
||||||
|
uint32_t PRDBCount;
|
||||||
|
uint32_t CommandTableBaseAddress;
|
||||||
|
uint32_t CommandTableBaseAddressUpper;
|
||||||
|
uint32_t Reserved1[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HBAPRDTEntry
|
||||||
|
{
|
||||||
|
uint32_t DataBaseAddress;
|
||||||
|
uint32_t DataBaseAddressUpper;
|
||||||
|
uint32_t Reserved0;
|
||||||
|
uint32_t ByteCount : 22;
|
||||||
|
uint32_t Reserved1 : 9;
|
||||||
|
uint32_t InterruptOnCompletion : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HBACommandTable
|
||||||
|
{
|
||||||
|
uint8_t CommandFIS[64];
|
||||||
|
uint8_t ATAPICommand[16];
|
||||||
|
uint8_t Reserved[48];
|
||||||
|
HBAPRDTEntry PRDTEntry[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FIS_REG_H2D
|
||||||
|
{
|
||||||
|
uint8_t FISType;
|
||||||
|
uint8_t PortMultiplier : 4;
|
||||||
|
uint8_t Reserved0 : 3;
|
||||||
|
uint8_t CommandControl : 1;
|
||||||
|
uint8_t Command;
|
||||||
|
uint8_t FeatureLow;
|
||||||
|
uint8_t LBA0;
|
||||||
|
uint8_t LBA1;
|
||||||
|
uint8_t LBA2;
|
||||||
|
uint8_t DeviceRegister;
|
||||||
|
uint8_t LBA3;
|
||||||
|
uint8_t LBA4;
|
||||||
|
uint8_t LBA5;
|
||||||
|
uint8_t FeatureHigh;
|
||||||
|
uint8_t CountLow;
|
||||||
|
uint8_t CountHigh;
|
||||||
|
uint8_t ISOCommandCompletion;
|
||||||
|
uint8_t Control;
|
||||||
|
uint8_t Reserved1[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Port
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PortType AHCIPortType;
|
||||||
|
HBAPort *HBAPortPtr;
|
||||||
|
uint8_t *Buffer;
|
||||||
|
uint8_t PortNumber;
|
||||||
|
|
||||||
|
Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber)
|
||||||
|
{
|
||||||
|
this->AHCIPortType = Type;
|
||||||
|
this->HBAPortPtr = PortPtr;
|
||||||
|
this->Buffer = static_cast<uint8_t *>(AllocateMemory(1));
|
||||||
|
MemorySet(this->Buffer, 0, PAGE_SIZE);
|
||||||
|
this->PortNumber = PortNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Port()
|
||||||
|
{
|
||||||
|
FreeMemory(this->Buffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartCMD()
|
||||||
|
{
|
||||||
|
while (HBAPortPtr->CommandStatus & HBA_PxCMD_CR)
|
||||||
|
Yield();
|
||||||
|
HBAPortPtr->CommandStatus |= HBA_PxCMD_FRE;
|
||||||
|
HBAPortPtr->CommandStatus |= HBA_PxCMD_ST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopCMD()
|
||||||
|
{
|
||||||
|
HBAPortPtr->CommandStatus &= ~HBA_PxCMD_ST;
|
||||||
|
HBAPortPtr->CommandStatus &= ~HBA_PxCMD_FRE;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (HBAPortPtr->CommandStatus & HBA_PxCMD_FR)
|
||||||
|
continue;
|
||||||
|
if (HBAPortPtr->CommandStatus & HBA_PxCMD_CR)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Configure()
|
||||||
|
{
|
||||||
|
this->StopCMD();
|
||||||
|
void *CmdBase = AllocateMemory(1);
|
||||||
|
HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase;
|
||||||
|
HBAPortPtr->CommandListBaseUpper = (uint32_t)((uint64_t)CmdBase >> 32);
|
||||||
|
MemorySet(reinterpret_cast<void *>(HBAPortPtr->CommandListBase), 0, 1024);
|
||||||
|
|
||||||
|
void *FISBase = AllocateMemory(1);
|
||||||
|
HBAPortPtr->FISBaseAddress = (uint32_t)(uint64_t)FISBase;
|
||||||
|
HBAPortPtr->FISBaseAddressUpper = (uint32_t)((uint64_t)FISBase >> 32);
|
||||||
|
MemorySet(FISBase, 0, 256);
|
||||||
|
|
||||||
|
HBACommandHeader *CommandHeader = (HBACommandHeader *)((uint64_t)HBAPortPtr->CommandListBase + ((uint64_t)HBAPortPtr->CommandListBaseUpper << 32));
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
CommandHeader[i].PRDTLength = 8;
|
||||||
|
void *CommandTableAddress = AllocateMemory(1);
|
||||||
|
uint64_t Address = (uint64_t)CommandTableAddress + (i << 8);
|
||||||
|
CommandHeader[i].CommandTableBaseAddress = (uint32_t)(uint64_t)Address;
|
||||||
|
CommandHeader[i].CommandTableBaseAddressUpper = (uint32_t)((uint64_t)Address >> 32);
|
||||||
|
MemorySet(CommandTableAddress, 0, 256);
|
||||||
|
}
|
||||||
|
this->StartCMD();
|
||||||
|
|
||||||
|
Log("Port %d \"%x %x %x %x\" configured", PortNumber,
|
||||||
|
HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1],
|
||||||
|
HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadWrite(uint64_t Sector, uint32_t SectorCount, uint8_t *Buffer, bool Write)
|
||||||
|
{
|
||||||
|
if (this->AHCIPortType == PortType::SATAPI &&
|
||||||
|
Write == true)
|
||||||
|
{
|
||||||
|
Log("SATAPI port does not support write.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SectorL = (uint32_t)Sector;
|
||||||
|
uint32_t SectorH = (uint32_t)(Sector >> 32);
|
||||||
|
|
||||||
|
HBAPortPtr->InterruptStatus = 0xFFFFFFFF; /* Clear pending interrupt bits */
|
||||||
|
|
||||||
|
HBACommandHeader *CommandHeader = reinterpret_cast<HBACommandHeader *>(HBAPortPtr->CommandListBase);
|
||||||
|
CommandHeader->CommandFISLength = sizeof(FIS_REG_H2D) / sizeof(uint32_t);
|
||||||
|
if (Write)
|
||||||
|
CommandHeader->Write = 1;
|
||||||
|
else
|
||||||
|
CommandHeader->Write = 0;
|
||||||
|
CommandHeader->PRDTLength = 1;
|
||||||
|
|
||||||
|
HBACommandTable *CommandTable = reinterpret_cast<HBACommandTable *>(CommandHeader->CommandTableBaseAddress);
|
||||||
|
MemorySet(CommandTable, 0, sizeof(HBACommandTable) + (CommandHeader->PRDTLength - 1) * sizeof(HBAPRDTEntry));
|
||||||
|
|
||||||
|
CommandTable->PRDTEntry[0].DataBaseAddress = (uint32_t)(uint64_t)Buffer;
|
||||||
|
CommandTable->PRDTEntry[0].DataBaseAddressUpper = (uint32_t)((uint64_t)Buffer >> 32);
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
/* conversion from 'uint32_t' {aka 'unsigned int'} to 'unsigned int:22' may change value */
|
||||||
|
#pragma GCC diagnostic ignored "-Wconversion"
|
||||||
|
CommandTable->PRDTEntry[0].ByteCount = (SectorCount << 9) - 1; /* 512 bytes per sector */
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
CommandTable->PRDTEntry[0].InterruptOnCompletion = 1;
|
||||||
|
|
||||||
|
FIS_REG_H2D *CommandFIS = (FIS_REG_H2D *)(&CommandTable->CommandFIS);
|
||||||
|
|
||||||
|
CommandFIS->FISType = FIS_TYPE_REG_H2D;
|
||||||
|
CommandFIS->CommandControl = 1;
|
||||||
|
if (Write)
|
||||||
|
CommandFIS->Command = ATA_CMD_WRITE_DMA_EX;
|
||||||
|
else
|
||||||
|
CommandFIS->Command = ATA_CMD_READ_DMA_EX;
|
||||||
|
|
||||||
|
CommandFIS->LBA0 = (uint8_t)SectorL;
|
||||||
|
CommandFIS->LBA1 = (uint8_t)(SectorL >> 8);
|
||||||
|
CommandFIS->LBA2 = (uint8_t)(SectorL >> 16);
|
||||||
|
CommandFIS->LBA3 = (uint8_t)SectorH;
|
||||||
|
CommandFIS->LBA4 = (uint8_t)(SectorH >> 8);
|
||||||
|
CommandFIS->LBA5 = (uint8_t)(SectorH >> 16);
|
||||||
|
|
||||||
|
CommandFIS->DeviceRegister = 1 << 6; // LBA mode
|
||||||
|
CommandFIS->CountLow = SectorCount & 0xFF;
|
||||||
|
CommandFIS->CountHigh = (SectorCount >> 8) & 0xFF;
|
||||||
|
|
||||||
|
uint64_t Spin = 0;
|
||||||
|
|
||||||
|
while ((HBAPortPtr->TaskFileData & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && Spin < 1000000)
|
||||||
|
Spin++;
|
||||||
|
|
||||||
|
if (Spin == 1000000)
|
||||||
|
{
|
||||||
|
Log("Port not responding.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HBAPortPtr->CommandIssue = 1;
|
||||||
|
|
||||||
|
Spin = 0;
|
||||||
|
int TryCount = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (Spin > 100000000)
|
||||||
|
{
|
||||||
|
Log("Port %d not responding. (%d)",
|
||||||
|
this->PortNumber, TryCount);
|
||||||
|
|
||||||
|
Spin = 0;
|
||||||
|
TryCount++;
|
||||||
|
if (TryCount > 10)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HBAPortPtr->CommandIssue == 0)
|
||||||
|
break;
|
||||||
|
Spin++;
|
||||||
|
|
||||||
|
if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES)
|
||||||
|
{
|
||||||
|
Log("Error reading/writing (%d).", Write);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Port *Ports[64];
|
||||||
|
int PortCount = 0;
|
||||||
|
|
||||||
|
const char *PortTypeName[] = {"None",
|
||||||
|
"SATA",
|
||||||
|
"SEMB",
|
||||||
|
"PM",
|
||||||
|
"SATAPI"};
|
||||||
|
|
||||||
|
PortType CheckPortType(HBAPort *Port)
|
||||||
|
{
|
||||||
|
uint32_t SataStatus = Port->SataStatus;
|
||||||
|
uint8_t InterfacePowerManagement = (SataStatus >> 8) & 0b111;
|
||||||
|
uint8_t DeviceDetection = SataStatus & 0b111;
|
||||||
|
|
||||||
|
if (DeviceDetection != HBA_PORT_DEV_PRESENT)
|
||||||
|
return PortType::None;
|
||||||
|
if (InterfacePowerManagement != HBA_PORT_IPM_ACTIVE)
|
||||||
|
return PortType::None;
|
||||||
|
|
||||||
|
switch (Port->Signature)
|
||||||
|
{
|
||||||
|
case SATA_SIG_ATAPI:
|
||||||
|
return PortType::SATAPI;
|
||||||
|
case SATA_SIG_ATA:
|
||||||
|
return PortType::SATA;
|
||||||
|
case SATA_SIG_PM:
|
||||||
|
return PortType::PM;
|
||||||
|
case SATA_SIG_SEMB:
|
||||||
|
return PortType::SEMB;
|
||||||
|
default:
|
||||||
|
return PortType::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t drvRead(dev_t, dev_t min,
|
||||||
|
uint8_t *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
bool ok = Ports[min]->ReadWrite(Offset / 512,
|
||||||
|
uint32_t(Size / 512),
|
||||||
|
Buffer,
|
||||||
|
false);
|
||||||
|
return ok ? Size : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t drvWrite(dev_t, dev_t min,
|
||||||
|
uint8_t *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
bool ok = Ports[min]->ReadWrite(Offset / 512,
|
||||||
|
uint32_t(Size / 512),
|
||||||
|
Buffer,
|
||||||
|
true);
|
||||||
|
return ok ? Size : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnInterruptReceived(TrapFrame *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERNC int cxx_Panic()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < PortCount; i++)
|
||||||
|
Ports[i]->StopCMD();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PCIArray *Devices;
|
||||||
|
EXTERNC int cxx_Probe()
|
||||||
|
{
|
||||||
|
uint16_t VendorIDs[] = {0x8086, /* Intel */
|
||||||
|
0x15AD, /* VMware */
|
||||||
|
PCI_END};
|
||||||
|
uint16_t DeviceIDs[] = {0x2922, /* ICH9 */
|
||||||
|
0x2829, /* ICH8 */
|
||||||
|
0x07E0, /* SATA AHCI (VMware) */
|
||||||
|
PCI_END};
|
||||||
|
Devices = FindPCIDevices(VendorIDs, DeviceIDs);
|
||||||
|
if (Devices == nullptr)
|
||||||
|
{
|
||||||
|
Log("No AHCI device found.");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERNC int cxx_Initialize()
|
||||||
|
{
|
||||||
|
PCIArray *ctx = Devices;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We loop through all the devices and initialize them
|
||||||
|
*/
|
||||||
|
while (ctx != nullptr)
|
||||||
|
{
|
||||||
|
/* We don't use the interrupt handler now... maybe we will in the future */
|
||||||
|
// RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived);
|
||||||
|
|
||||||
|
InitializePCI(ctx->Device);
|
||||||
|
HBAMemory *HBA = (HBAMemory *)(uintptr_t)GetBAR(5, ctx->Device);
|
||||||
|
|
||||||
|
uint32_t PortsImplemented = HBA->PortsImplemented;
|
||||||
|
Log("AHCI ports implemented: %x", PortsImplemented);
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
if (PortCount > 64)
|
||||||
|
{
|
||||||
|
Log("There are more than 64 AHCI ports implemented");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PortsImplemented & (1 << i))
|
||||||
|
{
|
||||||
|
Log("Port %d implemented", i);
|
||||||
|
PortType portType = CheckPortType(&HBA->Ports[i]);
|
||||||
|
if (portType == PortType::SATA || portType == PortType::SATAPI)
|
||||||
|
{
|
||||||
|
KPrint("%s drive found at port %d", PortTypeName[portType], i);
|
||||||
|
Ports[PortCount] = new Port(portType, &HBA->Ports[i], PortCount);
|
||||||
|
dev_t ret = RegisterBlockDevice(ddt_SATA,
|
||||||
|
nullptr, nullptr,
|
||||||
|
drvRead, drvWrite,
|
||||||
|
nullptr);
|
||||||
|
if (ret != (dev_t)PortCount)
|
||||||
|
{
|
||||||
|
KPrint("Failed to register block device %d", ret);
|
||||||
|
return -EBADSLT;
|
||||||
|
}
|
||||||
|
|
||||||
|
PortCount++;
|
||||||
|
Ports[PortCount] = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (portType != PortType::None)
|
||||||
|
{
|
||||||
|
KPrint("Unsupported drive type %s found at port %d",
|
||||||
|
PortTypeName[portType], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = (PCIArray *)ctx->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("Initializing AHCI ports");
|
||||||
|
for (int i = 0; i < PortCount; i++)
|
||||||
|
Ports[i]->Configure();
|
||||||
|
|
||||||
|
return PortCount > 0 ? 0 : -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERNC int cxx_Finalize()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < PortCount; i++)
|
||||||
|
{
|
||||||
|
Ports[i]->StopCMD();
|
||||||
|
delete Ports[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
PortCount = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
UnregisterBlockDevice(PortCount, ddt_SATA);
|
||||||
|
PortCount--;
|
||||||
|
} while (PortCount >= 0);
|
||||||
|
|
||||||
|
PCIArray *ctx = Devices;
|
||||||
|
|
||||||
|
while (ctx != nullptr)
|
||||||
|
{
|
||||||
|
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
|
||||||
|
ctx = (PCIArray *)ctx->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::list<PCI::PCIDevice> Devices = PCIManager->FindPCIDevice(VendorIDs, DeviceIDs);
|
||||||
|
// foreach (auto dev in Devices)
|
||||||
|
// Interrupts::RemoveHandler(OnInterruptReceived, iLine(dev));
|
||||||
|
return 0;
|
||||||
|
}
|
25
storage/ahci/ahci.hpp
Normal file
25
storage/ahci/ahci.hpp
Normal 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
storage/ahci/main.c
Normal file
31
storage/ahci/main.c
Normal 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.1",
|
||||||
|
"GPLv3");
|
83
storage/ata/Makefile
Normal file
83
storage/ata/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = ata.drv
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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) $(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
|
||||||
|
|
||||||
|
LIBS := ../../out/dcrt0.o -L../../out -ldriver
|
||||||
|
|
||||||
|
LDFLAGS := \
|
||||||
|
-fPIC -fPIE -pie \
|
||||||
|
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
|
||||||
|
-nostdlib -nodefaultlibs -nolibc \
|
||||||
|
-zmax-page-size=0x1000 \
|
||||||
|
-Wl,-Map file.map -shared -fvisibility=hidden
|
||||||
|
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
CFLAGS += -fverbose-asm
|
||||||
|
endif
|
||||||
|
ifneq ($(OSARCH), aarch64)
|
||||||
|
CFLAGS += -fstack-check
|
||||||
|
endif
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) ../../out/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
76
storage/ata/main.c
Normal file
76
storage/ata/main.c
Normal 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.1",
|
||||||
|
"GPLv3");
|
Loading…
x
Reference in New Issue
Block a user