mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-28 23:44:31 +00:00
Compare commits
110 Commits
23a17fae00
...
958a3ed263
Author | SHA1 | Date | |
---|---|---|---|
958a3ed263 | |||
a0e3993a3f | |||
edeecf7831 | |||
90fb9c7952 | |||
0a52ef4f68 | |||
5e0a80fa1c | |||
784f3c3df9 | |||
68acf428a2 | |||
9105c63465 | |||
659805960b | |||
451c5405e0 | |||
bd02b976a2 | |||
9bffe3e013 | |||
84298fc4eb | |||
87a2dc9444 | |||
426a84a1a9 | |||
8eed8909da | |||
09d0af1ea6 | |||
7b85636f8f | |||
95585fce5f | |||
bf1e3432d7 | |||
f824df9aad | |||
426499090e | |||
1af2cf657d | |||
f31d11f7ad | |||
851a8c140f | |||
ae2617dca2 | |||
adba9cc348 | |||
232e06f8f3 | |||
aea8a7bb08 | |||
65ab83b42b | |||
d3f6d51ed2 | |||
ca8dc6429b | |||
cfb5d9a0f4 | |||
8dab45ecfd | |||
88a5f06325 | |||
aab84cd3ab | |||
a3719eef3e | |||
0769a82f4b | |||
f978f2487e | |||
8859bfc438 | |||
5202601c4f | |||
78141b28c7 | |||
3f2584ac09 | |||
a2ce579a61 | |||
0958cdf7f8 | |||
7f3b2b4dbb | |||
f6f46d1bbe | |||
c12ee67592 | |||
74ff9579f3 | |||
d7cbeb9eba | |||
4d333f94bc | |||
e003af38ff | |||
d1c504f9a6 | |||
d46ed57dd7 | |||
a6d372aaad | |||
b3e0b30147 | |||
93e57f5dbe | |||
db5a42289a | |||
77136acccd | |||
258ac6e2f6 | |||
fbe4b94805 | |||
2c2e7d9de3 | |||
9dfa750444 | |||
4240183fa1 | |||
42f26787fb | |||
8d08ab933a | |||
c83c542f5b | |||
08319ef4c7 | |||
f4168e2815 | |||
123d11e4e3 | |||
b1a107fb65 | |||
d375acd0ec | |||
5e6e63ab1a | |||
ab4bc55270 | |||
e5acf4a99e | |||
5089cfa81b | |||
b5fce27037 | |||
0238f62894 | |||
ce59b6ea03 | |||
9dcb5abe89 | |||
4ac29bbce1 | |||
155f3bfab5 | |||
e960f9fcc8 | |||
4bb8ce6d00 | |||
2ae18af9a0 | |||
e61b5824db | |||
0f9a1915d1 | |||
6dfefc90c4 | |||
c688bd7a97 | |||
e927d93a48 | |||
d9235c6f90 | |||
afa87ec5f3 | |||
22d01c7a51 | |||
dfe9bbdbfa | |||
92ef18b412 | |||
d0a8d9dd62 | |||
f3e145e6f7 | |||
d9433256ab | |||
ade1c77361 | |||
3e656854bc | |||
6c3eefa85d | |||
2384791793 | |||
97af4d855f | |||
b0f0982fd4 | |||
bd1d117283 | |||
a1b040360c | |||
8f7938a1e5 | |||
b05868d120 | |||
24fd486764 |
112
.devcontainer/Dockerfile
Normal file
112
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
FROM mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04
|
||||||
|
|
||||||
|
ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="none"
|
||||||
|
|
||||||
|
COPY ./reinstall-cmake.sh /tmp/
|
||||||
|
RUN <<EOF
|
||||||
|
if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then
|
||||||
|
chmod +x /tmp/reinstall-cmake.sh && /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE};
|
||||||
|
fi
|
||||||
|
rm -f /tmp/reinstall-cmake.sh
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Update system and set noninteractive env
|
||||||
|
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update
|
||||||
|
|
||||||
|
# Required packages for building gcc & binutils
|
||||||
|
RUN apt-get -y install --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
bison \
|
||||||
|
flex \
|
||||||
|
libgmp-dev \
|
||||||
|
libmpfr-dev \
|
||||||
|
texinfo \
|
||||||
|
file \
|
||||||
|
python3-dev
|
||||||
|
|
||||||
|
# Required packages for building gcc & binutils
|
||||||
|
RUN <<EOF
|
||||||
|
wget https://launchpad.net/ubuntu/+archive/primary/+files/autoconf_2.69-11.1_all.deb -O /tmp/autoconf.deb
|
||||||
|
sudo dpkg --force-all -i /tmp/autoconf.deb
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Required packages for building gcc & binutils
|
||||||
|
RUN <<EOF
|
||||||
|
wget https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz -O /tmp/automake.tar.gz
|
||||||
|
tar -xzf /tmp/automake.tar.gz -C /tmp
|
||||||
|
cd /tmp/automake-1.15.1
|
||||||
|
./configure && make && sudo make install
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Required packages for building qemu
|
||||||
|
RUN apt-get -y install --no-install-recommends \
|
||||||
|
git \
|
||||||
|
libglib2.0-dev \
|
||||||
|
libfdt-dev \
|
||||||
|
libpixman-1-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
ninja-build \
|
||||||
|
libaio-dev \
|
||||||
|
libbluetooth-dev \
|
||||||
|
libcapstone-dev \
|
||||||
|
libbrlapi-dev \
|
||||||
|
libbz2-dev \
|
||||||
|
libcap-ng-dev \
|
||||||
|
libcurl4-gnutls-dev \
|
||||||
|
libgtk-3-dev \
|
||||||
|
libibverbs-dev \
|
||||||
|
libjpeg8-dev \
|
||||||
|
libncurses5-dev \
|
||||||
|
libnuma-dev \
|
||||||
|
librbd-dev \
|
||||||
|
librdmacm-dev \
|
||||||
|
libsasl2-dev \
|
||||||
|
libsdl2-dev \
|
||||||
|
libseccomp-dev \
|
||||||
|
libsnappy-dev \
|
||||||
|
libssh-dev \
|
||||||
|
libvde-dev \
|
||||||
|
libvdeplug-dev \
|
||||||
|
libvte-2.91-dev \
|
||||||
|
libxen-dev \
|
||||||
|
liblzo2-dev \
|
||||||
|
valgrind \
|
||||||
|
xfslibs-dev \
|
||||||
|
libnfs-dev \
|
||||||
|
libiscsi-dev \
|
||||||
|
python3-venv \
|
||||||
|
libslirp-dev \
|
||||||
|
ovmf
|
||||||
|
|
||||||
|
# Required packages for building test apps in userspace
|
||||||
|
RUN apt-get -y install --no-install-recommends \
|
||||||
|
mingw-w64
|
||||||
|
|
||||||
|
# Required packages for building the OS
|
||||||
|
RUN apt-get -y install --no-install-recommends \
|
||||||
|
grub2-common \
|
||||||
|
xorriso \
|
||||||
|
mtools \
|
||||||
|
grub-common \
|
||||||
|
grub-efi-amd64-bin \
|
||||||
|
grub-efi-amd64-signed \
|
||||||
|
grub-gfxpayload-lists \
|
||||||
|
grub-pc-bin \
|
||||||
|
grub-pc \
|
||||||
|
grub2-common
|
||||||
|
|
||||||
|
# Configure git
|
||||||
|
RUN <<EOF
|
||||||
|
git config --global advice.detachedHead false
|
||||||
|
git config --global core.autocrlf input
|
||||||
|
git config --global init.defaultbranch master
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Set display environment variable for QEMU
|
||||||
|
ENV DISPLAY=:0
|
||||||
|
ENV NO_AT_BRIDGE=1
|
||||||
|
|
||||||
|
# Set PATH
|
||||||
|
RUN <<EOF
|
||||||
|
echo PATH=$PATH:/workspaces/Fennix/cross/bin >> /etc/profile
|
||||||
|
EOF
|
51
.devcontainer/devcontainer.json
Normal file
51
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
|
||||||
|
{
|
||||||
|
"name": "Fennix",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "Dockerfile"
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"ms-azuretools.vscode-docker",
|
||||||
|
"eamodio.gitlens",
|
||||||
|
"EditorConfig.EditorConfig",
|
||||||
|
"naumovs.color-highlight",
|
||||||
|
"Gruntfuggly.todo-tree",
|
||||||
|
"ms-vscode.hexeditor",
|
||||||
|
"vivaxy.vscode-conventional-commits",
|
||||||
|
"webfreak.debug",
|
||||||
|
"maziac.asm-code-lens",
|
||||||
|
"Seven1bit.vscode-ext-ansi-color-highlight",
|
||||||
|
"ms-vsliveshare.vsliveshare",
|
||||||
|
"maziac.hex-hover-converter",
|
||||||
|
"ms-vscode.makefile-tools"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// From this line below are for qemu, so not that important.
|
||||||
|
"mounts": [
|
||||||
|
"source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached",
|
||||||
|
"source=${localEnv:XAUTHORITY},target=/home/vscode/.Xauthority,type=bind,consistency=cached",
|
||||||
|
"source=/dev/kvm,target=/dev/kvm,type=bind,consistency=cached",
|
||||||
|
"source=/run/user/1000/pulse/native,target=/run/user/1000/pulse/native,type=bind,consistency=cached"
|
||||||
|
],
|
||||||
|
"runArgs": [
|
||||||
|
"--privileged"
|
||||||
|
]
|
||||||
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
// "features": {},
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
// "forwardPorts": [],
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
// "postCreateCommand": "gcc -v",
|
||||||
|
|
||||||
|
// Configure tool-specific properties.
|
||||||
|
// "customizations": {},
|
||||||
|
|
||||||
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
|
// "remoteUser": "root"
|
||||||
|
}
|
59
.devcontainer/reinstall-cmake.sh
Normal file
59
.devcontainer/reinstall-cmake.sh
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CMAKE_VERSION=${1:-"none"}
|
||||||
|
|
||||||
|
if [ "${CMAKE_VERSION}" = "none" ]; then
|
||||||
|
echo "No CMake version specified, skipping CMake reinstallation"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cleanup temporary directory and associated files when exiting the script.
|
||||||
|
cleanup() {
|
||||||
|
EXIT_CODE=$?
|
||||||
|
set +e
|
||||||
|
if [[ -n "${TMP_DIR}" ]]; then
|
||||||
|
echo "Executing cleanup of tmp files"
|
||||||
|
rm -Rf "${TMP_DIR}"
|
||||||
|
fi
|
||||||
|
exit $EXIT_CODE
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
|
||||||
|
echo "Installing CMake..."
|
||||||
|
apt-get -y purge --auto-remove cmake
|
||||||
|
mkdir -p /opt/cmake
|
||||||
|
|
||||||
|
architecture=$(dpkg --print-architecture)
|
||||||
|
case "${architecture}" in
|
||||||
|
arm64)
|
||||||
|
ARCH=aarch64 ;;
|
||||||
|
amd64)
|
||||||
|
ARCH=x86_64 ;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported architecture ${architecture}."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CMAKE_BINARY_NAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh"
|
||||||
|
CMAKE_CHECKSUM_NAME="cmake-${CMAKE_VERSION}-SHA-256.txt"
|
||||||
|
TMP_DIR=$(mktemp -d -t cmake-XXXXXXXXXX)
|
||||||
|
|
||||||
|
echo "${TMP_DIR}"
|
||||||
|
cd "${TMP_DIR}"
|
||||||
|
|
||||||
|
curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_BINARY_NAME}" -O
|
||||||
|
curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_CHECKSUM_NAME}" -O
|
||||||
|
|
||||||
|
sha256sum -c --ignore-missing "${CMAKE_CHECKSUM_NAME}"
|
||||||
|
sh "${TMP_DIR}/${CMAKE_BINARY_NAME}" --prefix=/opt/cmake --skip-license
|
||||||
|
|
||||||
|
ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake
|
||||||
|
ln -s /opt/cmake/bin/ctest /usr/local/bin/ctest
|
@ -15,3 +15,7 @@ indent_style = tab
|
|||||||
[.github/**]
|
[.github/**]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
|
[{CMakeLists.txt,*.cmake}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
38
.vscode/launch.json
vendored
38
.vscode/launch.json
vendored
@ -20,14 +20,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
||||||
"description": "Load /bin/utest",
|
"description": "/bin/utest (0x00400000)",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/libc_test",
|
||||||
|
"description": "/bin/libc_test (0x00600000)",
|
||||||
"ignoreFailures": true
|
"ignoreFailures": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "source ${workspaceFolder}/../tools/.gdbinit"
|
"text": "source ${workspaceFolder}/../tools/.gdbinit"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"preLaunchTask": "launch-qemu"
|
"preLaunchTask": "QEMU"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Debug Kernel (x86)",
|
"name": "Debug Kernel (x86)",
|
||||||
@ -48,14 +53,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
||||||
"description": "Load /bin/utest",
|
"description": "/bin/utest (0x00400000)",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/libc_test",
|
||||||
|
"description": "/bin/libc_test (0x00600000)",
|
||||||
"ignoreFailures": true
|
"ignoreFailures": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "source ${workspaceFolder}/../tools/.gdbinit"
|
"text": "source ${workspaceFolder}/../tools/.gdbinit"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"preLaunchTask": "launch-qemu"
|
"preLaunchTask": "QEMU"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Debug Kernel (arm64)",
|
"name": "Debug Kernel (arm64)",
|
||||||
@ -76,14 +86,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
||||||
"description": "Load /bin/utest",
|
"description": "/bin/utest (0x00400000)",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/libc_test",
|
||||||
|
"description": "/bin/libc_test (0x00600000)",
|
||||||
"ignoreFailures": true
|
"ignoreFailures": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "source ${workspaceFolder}/../tools/.gdbinit"
|
"text": "source ${workspaceFolder}/../tools/.gdbinit"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"preLaunchTask": "launch-qemu"
|
"preLaunchTask": "QEMU"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Debug Kernel (arm)",
|
"name": "Debug Kernel (arm)",
|
||||||
@ -104,14 +119,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
||||||
"description": "Load /bin/utest",
|
"description": "/bin/utest (0x00400000)",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/libc_test",
|
||||||
|
"description": "/bin/libc_test (0x00600000)",
|
||||||
"ignoreFailures": true
|
"ignoreFailures": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "source ${workspaceFolder}/../tools/.gdbinit"
|
"text": "source ${workspaceFolder}/../tools/.gdbinit"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"preLaunchTask": "launch-qemu"
|
"preLaunchTask": "QEMU"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "gdb",
|
"type": "gdb",
|
||||||
@ -129,7 +149,7 @@
|
|||||||
],
|
],
|
||||||
"internalConsoleOptions": "neverOpen",
|
"internalConsoleOptions": "neverOpen",
|
||||||
"printCalls": false,
|
"printCalls": false,
|
||||||
"preLaunchTask": "launch-qemu"
|
"preLaunchTask": "QEMU"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
157
.vscode/tasks.json
vendored
157
.vscode/tasks.json
vendored
@ -2,13 +2,160 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "launch-qemu",
|
"label": "Build Bootloader",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "make -C ../ build && make -C ../ vscode_debug_only",
|
"command": "make -C ../ build_bootloader",
|
||||||
"isBackground": true,
|
"isBackground": false,
|
||||||
"problemMatcher": [],
|
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"shell": {
|
||||||
|
"executable": "bash",
|
||||||
|
"args": [
|
||||||
|
"-c"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Build Kernel",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make -C ../ build_kernel",
|
||||||
|
"isBackground": false,
|
||||||
|
"dependsOn": [
|
||||||
|
"Build Bootloader"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"shell": {
|
||||||
|
"executable": "bash",
|
||||||
|
"args": [
|
||||||
|
"-c"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Build Drivers",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make -C ../ build_drivers",
|
||||||
|
"isBackground": false,
|
||||||
|
"dependsOn": [
|
||||||
|
"Build Kernel"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"shell": {
|
||||||
|
"executable": "bash",
|
||||||
|
"args": [
|
||||||
|
"-c"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Build Userspace",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make -C ../ build_userspace",
|
||||||
|
"isBackground": false,
|
||||||
|
"dependsOn": [
|
||||||
|
"Build Drivers"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"shell": {
|
||||||
|
"executable": "bash",
|
||||||
|
"args": [
|
||||||
|
"-c"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Build Image",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make -C ../ build_image",
|
||||||
|
"isBackground": false,
|
||||||
|
"dependsOn": [
|
||||||
|
"Build Userspace"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"shell": {
|
||||||
|
"executable": "bash",
|
||||||
|
"args": [
|
||||||
|
"-c"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "QEMU",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make",
|
||||||
|
"args": [
|
||||||
|
"-C",
|
||||||
|
"../",
|
||||||
|
"vscode_debug_only"
|
||||||
|
],
|
||||||
|
"isBackground": true,
|
||||||
|
// "problemMatcher": "$tsc-watch",
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": ".",
|
||||||
|
"file": 1,
|
||||||
|
"location": 2,
|
||||||
|
"message": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": ".",
|
||||||
|
"endsPattern": "CR0 update",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependsOn": [
|
||||||
|
"Build Image"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "test",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
},
|
},
|
||||||
"presentation": {
|
"presentation": {
|
||||||
@ -25,4 +172,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
@ -1,881 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Kernel.
|
|
||||||
|
|
||||||
Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <audio.h>
|
|
||||||
#include <regs.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <pci.h>
|
|
||||||
#include <io.h>
|
|
||||||
#include <fs.h>
|
|
||||||
|
|
||||||
#define DescriptorListLength 0x20
|
|
||||||
|
|
||||||
enum AudioVolumeValues
|
|
||||||
{
|
|
||||||
AV_Maximum = 0x0,
|
|
||||||
AV_Minimum = 0x3F,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum AudioEncodingValues
|
|
||||||
{
|
|
||||||
AE_PCMs8,
|
|
||||||
AE_PCMu8,
|
|
||||||
|
|
||||||
AE_PCMs16le,
|
|
||||||
AE_PCMs20le,
|
|
||||||
AE_PCMs24le,
|
|
||||||
AE_PCMs32le,
|
|
||||||
|
|
||||||
AE_PCMu16le,
|
|
||||||
AE_PCMu20le,
|
|
||||||
AE_PCMu24le,
|
|
||||||
AE_PCMu32le,
|
|
||||||
|
|
||||||
AE_PCMs16be,
|
|
||||||
AE_PCMs20be,
|
|
||||||
AE_PCMs24be,
|
|
||||||
AE_PCMs32be,
|
|
||||||
|
|
||||||
AE_PCMu16be,
|
|
||||||
AE_PCMu20be,
|
|
||||||
AE_PCMu24be,
|
|
||||||
AE_PCMu32be,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum NativeAudioMixerRegisters
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Reset Register
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NAM_Reset = 0x00,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Master Volume Register
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NAM_MasterVolume = 0x02,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Microphone Volume Register
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NAM_MicrophoneVolume = 0x0E,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief PCM Out Volume Register
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NAM_PCMOutVolume = 0x18,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Select Record Input Register
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NAM_SelectRecordInput = 0x1A,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Record Gain Register
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NAM_RecordGain = 0x1C,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Record Gain Microphone Register
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NAM_RecordGainMicrophone = 0x1E,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum NativeAudioBusMasterRegisters
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Register box for PCM IN
|
|
||||||
* @note Length: below
|
|
||||||
*/
|
|
||||||
NABM_PCMInBox = 0x00,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Register box for PCM OUT
|
|
||||||
* @note Length: below
|
|
||||||
*/
|
|
||||||
NABM_PCMOutBox = 0x10,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Register box for Microphone
|
|
||||||
* @note Length: below
|
|
||||||
*/
|
|
||||||
NABM_MicrophoneBox = 0x20,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Global Control Register
|
|
||||||
* @note Length: dword
|
|
||||||
*/
|
|
||||||
NABM_GlobalControl = 0x2C, /* 0x30 */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Global Status Register
|
|
||||||
* @note Length: dword
|
|
||||||
*/
|
|
||||||
NABM_GlobalStatus = 0x30, /* 0x34 */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum NativeAudioBusMasterBoxOffsets
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Physical Address of Buffer Descriptor List
|
|
||||||
* @note Length: dword
|
|
||||||
*/
|
|
||||||
NABMBOFF_BufferDescriptorList = 0x00,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of Actual Processed Buffer Descriptor Entry
|
|
||||||
* @note Length: byte
|
|
||||||
*/
|
|
||||||
NABMBOFF_BufferDescriptorEntry = 0x04,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of all Descriptor Entries
|
|
||||||
* @note Length: byte
|
|
||||||
*/
|
|
||||||
NABMBOFF_DescriptorEntries = 0x05,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Status of transferring Data
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NABMBOFF_Status = 0x06,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of transferred Samples in Actual Processed Entry
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
NABMBOFF_TransferredSamples = 0x08,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of next processed Buffer Entry
|
|
||||||
* @note Length: byte
|
|
||||||
*/
|
|
||||||
NABMBOFF_NextProcessedBufferEntry = 0x0A,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Transfer Control
|
|
||||||
* @note Length: byte
|
|
||||||
*/
|
|
||||||
NABMBOFF_TransferControl = 0x0B,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum OutputPulseCodeModulationRegisters
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Physical Address of Buffer Descriptor List
|
|
||||||
* @note Length: dword
|
|
||||||
*/
|
|
||||||
PCMOUT_BufferDescriptorList = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorList,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of Actual Processed Buffer Descriptor Entry
|
|
||||||
* @note Length: byte
|
|
||||||
*/
|
|
||||||
PCMOUT_BufferDescriptorEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorEntry,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of all Descriptor Entries
|
|
||||||
* @note Length: byte
|
|
||||||
*/
|
|
||||||
PCMOUT_DescriptorEntries = (int)NABM_PCMOutBox + (int)NABMBOFF_DescriptorEntries,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Status of transferring Data
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
PCMOUT_Status = (int)NABM_PCMOutBox + (int)NABMBOFF_Status,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of transferred Samples in Actual Processed Entry
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
PCMOUT_TransferredSamples = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferredSamples,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of next processed Buffer Entry
|
|
||||||
* @note Length: byte
|
|
||||||
*/
|
|
||||||
PCMOUT_NextProcessedBufferEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_NextProcessedBufferEntry,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Transfer Control
|
|
||||||
* @note Length: byte
|
|
||||||
*/
|
|
||||||
PCMOUT_TransferControl = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferControl,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TransferControlRegisters
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief DMA controller control
|
|
||||||
*
|
|
||||||
* 0 = Pause transfer
|
|
||||||
* 1 = Transfer sound data
|
|
||||||
*/
|
|
||||||
TC_DMAControllerControl = 0x01,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reset
|
|
||||||
*
|
|
||||||
* 0 = Remove reset condition
|
|
||||||
* 1 = Reset this NABM register box, this bit is cleared by card when is reset complete
|
|
||||||
*/
|
|
||||||
TC_TransferReset = 0x02,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Last Buffer Entry Interrupt enable
|
|
||||||
*
|
|
||||||
* 0 = Disable interrupt
|
|
||||||
* 1 = Enable interrupt
|
|
||||||
*/
|
|
||||||
TC_LastBufferEntryInterruptEnable = 0x04,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief IOC Interrupt enable
|
|
||||||
*
|
|
||||||
* 0 = Disable interrupt
|
|
||||||
* 1 = Enable interrupt
|
|
||||||
*/
|
|
||||||
TC_IOCInterruptEnable = 0x08,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Fifo ERROR Interrupt enable
|
|
||||||
*
|
|
||||||
* 0 = Disable interrupt
|
|
||||||
* 1 = Enable interrupt
|
|
||||||
*/
|
|
||||||
TC_FifoERRORInterruptEnable = 0x10,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum GlobalControlRegisters
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Global Interrupt Enable
|
|
||||||
*
|
|
||||||
* 0 = Disable Interrupts
|
|
||||||
* 1 = Enable Interrupts
|
|
||||||
*/
|
|
||||||
GC_GlobalInterruptEnable = 0x01,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Cold reset
|
|
||||||
*
|
|
||||||
* 0 = Device is in reset and can not be used
|
|
||||||
* 1 = Resume to operational state
|
|
||||||
*/
|
|
||||||
GC_ColdReset = 0x02,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Warm reset
|
|
||||||
*/
|
|
||||||
GC_WarmReset = 0x04,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Shut down
|
|
||||||
*
|
|
||||||
* 0 = Device is powered
|
|
||||||
* 1 = Shut down
|
|
||||||
*/
|
|
||||||
GC_ShutDown = 0x08,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Channels for PCM Output
|
|
||||||
*
|
|
||||||
* 00 = 2 channels
|
|
||||||
* 01 = 4 channels
|
|
||||||
* 10 = 6 channels
|
|
||||||
* 11 = Reserved
|
|
||||||
*/
|
|
||||||
GC_ChannelsForPCMOutput = 0x30,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief PCM Output mode
|
|
||||||
*
|
|
||||||
* 00 = 16 bit samples
|
|
||||||
* 01 = 20 bit samples
|
|
||||||
*/
|
|
||||||
GC_PCMOutputMode = 0xC0,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BufferDescriptorList
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Physical Address to sound data in memory
|
|
||||||
* @note Length: dword
|
|
||||||
*/
|
|
||||||
uint32_t Address;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of samples in this buffer
|
|
||||||
* @note Length: word
|
|
||||||
*/
|
|
||||||
uint16_t SampleCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Flags
|
|
||||||
* @note Length: word
|
|
||||||
*
|
|
||||||
* Bit 15 = Interrupt fired when data from this entry is transferred
|
|
||||||
* Bit 14 = Last entry of buffer, stop playing
|
|
||||||
* Other bits = Reserved
|
|
||||||
*/
|
|
||||||
uint16_t Flags;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
uint16_t MixerVolume(uint8_t Left, uint8_t Right, bool Mute)
|
|
||||||
{
|
|
||||||
return ((uint16_t)((Right & 0x3F) |
|
|
||||||
((Left & 0x3F) << 0x8) |
|
|
||||||
(Mute & 1 << 0xF)));
|
|
||||||
}
|
|
||||||
|
|
||||||
class AC97Device
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
PCIHeader0 *Header;
|
|
||||||
BufferDescriptorList *DescriptorList = nullptr;
|
|
||||||
|
|
||||||
uint16_t MixerAddress;
|
|
||||||
uint16_t BusMasterAddress;
|
|
||||||
|
|
||||||
AudioEncodingValues Encoding = AE_PCMs16le;
|
|
||||||
char Channels = 2;
|
|
||||||
uint8_t Volume = AV_Maximum;
|
|
||||||
bool Mute = false;
|
|
||||||
int SampleRate = 48000;
|
|
||||||
char SampleSize = 2;
|
|
||||||
|
|
||||||
public:
|
|
||||||
size_t write(uint8_t *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
if (Buffer == nullptr)
|
|
||||||
{
|
|
||||||
KernelLog("Invalid buffer.");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Size == 0) || (Size % (SampleSize * Channels)))
|
|
||||||
{
|
|
||||||
KernelLog("Invalid buffer length.");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TotalBDLToFill = (int)((Size + PAGE_SIZE - 1) >> 12);
|
|
||||||
|
|
||||||
while (Size > 0)
|
|
||||||
{
|
|
||||||
bool ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
|
|
||||||
|
|
||||||
if (ActiveDMA)
|
|
||||||
{
|
|
||||||
int RemainingBDL = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
int CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
|
|
||||||
int LastBDL = inb(BusMasterAddress + PCMOUT_DescriptorEntries);
|
|
||||||
|
|
||||||
RemainingBDL = LastBDL - CurrentBDL;
|
|
||||||
if (RemainingBDL < 0)
|
|
||||||
RemainingBDL += DescriptorListLength;
|
|
||||||
|
|
||||||
RemainingBDL += 1;
|
|
||||||
|
|
||||||
if (RemainingBDL >= DescriptorListLength - 1)
|
|
||||||
{
|
|
||||||
long SampleCount = DescriptorList[(CurrentBDL + 1) % DescriptorListLength].SampleCount / Channels;
|
|
||||||
if (SampleCount > 0)
|
|
||||||
Sleep(SampleCount * 1000 / SampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (RemainingBDL >= DescriptorListLength - 1 &&
|
|
||||||
!(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
|
|
||||||
uint8_t LastBDL = inb(BusMasterAddress + PCMOUT_DescriptorEntries);
|
|
||||||
uint8_t NextBDL = LastBDL % DescriptorListLength;
|
|
||||||
|
|
||||||
ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
|
|
||||||
if (ActiveDMA)
|
|
||||||
{
|
|
||||||
NextBDL = (uint8_t)((LastBDL + 1) % DescriptorListLength);
|
|
||||||
if (NextBDL == CurrentBDL)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
size_t Wrote = (PAGE_SIZE > Size) ? size_t(Size)
|
|
||||||
: size_t(PAGE_SIZE);
|
|
||||||
|
|
||||||
if (Wrote == 0)
|
|
||||||
{
|
|
||||||
KernelLog("Wrote 0 bytes.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy((void *)((uint64_t)DescriptorList[NextBDL].Address), Buffer, Wrote);
|
|
||||||
DescriptorList[NextBDL].Flags = 0;
|
|
||||||
|
|
||||||
Buffer += Wrote;
|
|
||||||
Size -= (unsigned int)Wrote;
|
|
||||||
|
|
||||||
DescriptorList[NextBDL].SampleCount = uint16_t(Wrote / SampleSize);
|
|
||||||
TotalBDLToFill--;
|
|
||||||
NextBDL = (uint8_t)((NextBDL + 1) % DescriptorListLength);
|
|
||||||
} while (TotalBDLToFill-- && NextBDL != CurrentBDL);
|
|
||||||
|
|
||||||
outb(BusMasterAddress + PCMOUT_DescriptorEntries, NextBDL - 1);
|
|
||||||
|
|
||||||
ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
|
|
||||||
if (!ActiveDMA)
|
|
||||||
{
|
|
||||||
// Start DMA
|
|
||||||
outb(BusMasterAddress + PCMOUT_TransferControl,
|
|
||||||
inb(BusMasterAddress + PCMOUT_TransferControl) | TC_DMAControllerControl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ioctl(AudioIoctl, void *)
|
|
||||||
{
|
|
||||||
// if (Data->AudioCallback.Adjust._Volume)
|
|
||||||
// {
|
|
||||||
// Volume = (uint8_t)(0x3F - (0x3F * Data->AudioCallback.Adjust.Volume / 100));
|
|
||||||
// outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
|
|
||||||
// // outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute));
|
|
||||||
// }
|
|
||||||
// else if (Data->AudioCallback.Adjust._Encoding)
|
|
||||||
// {
|
|
||||||
// fixme("Encoding changing not supported yet.");
|
|
||||||
// }
|
|
||||||
// else if (Data->AudioCallback.Adjust._SampleRate)
|
|
||||||
// {
|
|
||||||
// switch (Data->AudioCallback.Adjust.SampleRate)
|
|
||||||
// {
|
|
||||||
// case 0:
|
|
||||||
// {
|
|
||||||
// SampleRate = 8000;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 1:
|
|
||||||
// {
|
|
||||||
// SampleRate = 11025;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 2:
|
|
||||||
// {
|
|
||||||
// SampleRate = 16000;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 3:
|
|
||||||
// {
|
|
||||||
// SampleRate = 22050;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 4:
|
|
||||||
// {
|
|
||||||
// SampleRate = 32000;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 5:
|
|
||||||
// {
|
|
||||||
// SampleRate = 44100;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 6:
|
|
||||||
// {
|
|
||||||
// SampleRate = 48000;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 7:
|
|
||||||
// {
|
|
||||||
// SampleRate = 88200;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 8:
|
|
||||||
// {
|
|
||||||
// SampleRate = 96000;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// default:
|
|
||||||
// {
|
|
||||||
// SampleRate = 16000;
|
|
||||||
// error("Invalid sample rate. Defaulting to 16000.");
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if (Data->AudioCallback.Adjust._Channels)
|
|
||||||
// {
|
|
||||||
// switch (Data->AudioCallback.Adjust.Channels)
|
|
||||||
// {
|
|
||||||
// case 0:
|
|
||||||
// {
|
|
||||||
// Channels = 1; // Mono
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// case 1:
|
|
||||||
// {
|
|
||||||
// Channels = 2; // Stereo
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// default:
|
|
||||||
// {
|
|
||||||
// Channels = 2;
|
|
||||||
// error("Invalid channel count. Defaulting to 2.");
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnInterruptReceived(TrapFrame *)
|
|
||||||
{
|
|
||||||
uint16_t Status = inw(MixerAddress + PCMOUT_Status);
|
|
||||||
if (Status & TC_IOCInterruptEnable)
|
|
||||||
{
|
|
||||||
DebugLog("IOC");
|
|
||||||
outw(MixerAddress + PCMOUT_Status, TC_IOCInterruptEnable);
|
|
||||||
uint16_t CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
|
|
||||||
uint16_t LastBDL = (CurrentBDL + 2) & (DescriptorListLength - 1);
|
|
||||||
outb(BusMasterAddress + PCMOUT_DescriptorEntries, LastBDL);
|
|
||||||
KernelLog("FIXME: CurrentBDL: %d, LastBDL: %d", CurrentBDL, LastBDL);
|
|
||||||
}
|
|
||||||
else if (Status & TC_LastBufferEntryInterruptEnable)
|
|
||||||
{
|
|
||||||
DebugLog("Last buffer entry");
|
|
||||||
// Stop DMA
|
|
||||||
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
|
|
||||||
TransferControl &= ~TC_DMAControllerControl;
|
|
||||||
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
|
|
||||||
|
|
||||||
outw(MixerAddress + PCMOUT_Status, TC_LastBufferEntryInterruptEnable);
|
|
||||||
}
|
|
||||||
else if (Status & TC_FifoERRORInterruptEnable)
|
|
||||||
{
|
|
||||||
KernelLog("FIFO error");
|
|
||||||
outw(MixerAddress + PCMOUT_Status, TC_FifoERRORInterruptEnable);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DebugLog("Unknown interrupt status %#x", Status);
|
|
||||||
outw(MixerAddress + PCMOUT_Status, 0xFFFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Panic()
|
|
||||||
{
|
|
||||||
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
|
|
||||||
TransferControl &= ~(TC_LastBufferEntryInterruptEnable |
|
|
||||||
TC_IOCInterruptEnable |
|
|
||||||
TC_FifoERRORInterruptEnable);
|
|
||||||
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
|
|
||||||
|
|
||||||
uint32_t GlobalControl = inl((uint16_t)(BusMasterAddress + NABM_GlobalControl));
|
|
||||||
GlobalControl &= ~GC_GlobalInterruptEnable;
|
|
||||||
GlobalControl |= GC_ShutDown;
|
|
||||||
outl((uint16_t)(BusMasterAddress + NABM_GlobalControl), GlobalControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
AC97Device(PCIHeader0 *_Header)
|
|
||||||
: Header(_Header)
|
|
||||||
{
|
|
||||||
/* Native Audio Mixer Base Address */
|
|
||||||
uint32_t PCIBAR0 = Header->BAR0;
|
|
||||||
|
|
||||||
/* Native Audio Bus Master Base Address */
|
|
||||||
uint32_t PCIBAR1 = Header->BAR1;
|
|
||||||
|
|
||||||
// uint8_t Type = PCIBAR0 & 1;
|
|
||||||
MixerAddress = (uint16_t)(PCIBAR0 & (~3));
|
|
||||||
BusMasterAddress = PCIBAR1 & (~15);
|
|
||||||
|
|
||||||
uint16_t OutputPCMTransferControl = BusMasterAddress + PCMOUT_TransferControl;
|
|
||||||
|
|
||||||
/* DescriptorList address MUST be physical. */
|
|
||||||
DescriptorList = (BufferDescriptorList *)AllocateMemory(TO_PAGES(sizeof(BufferDescriptorList) * DescriptorListLength));
|
|
||||||
memset(DescriptorList, 0, sizeof(BufferDescriptorList) * DescriptorListLength);
|
|
||||||
|
|
||||||
uint16_t DLSampleCount = (uint16_t)(PAGE_SIZE / SampleSize);
|
|
||||||
for (int i = 0; i < DescriptorListLength; i++)
|
|
||||||
{
|
|
||||||
DescriptorList[i].Address = (uint32_t)(uintptr_t)AllocateMemory(TO_PAGES(sizeof(uint16_t *)));
|
|
||||||
DescriptorList[i].SampleCount = DLSampleCount;
|
|
||||||
DescriptorList[i].Flags = 0;
|
|
||||||
DebugLog("DescriptorList[%d] = { Address: %#lx, SampleCount: %d, Flags: %#lx }",
|
|
||||||
i,
|
|
||||||
DescriptorList[i].Address,
|
|
||||||
DescriptorList[i].SampleCount,
|
|
||||||
DescriptorList[i].Flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
outw(MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
|
|
||||||
outw(MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute));
|
|
||||||
|
|
||||||
Volume = 0x3F - (0x3F * /* VOL 50% */ 50 / 100);
|
|
||||||
outw(MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
|
|
||||||
|
|
||||||
outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) | TC_TransferReset);
|
|
||||||
while (inb(OutputPCMTransferControl) & TC_TransferReset)
|
|
||||||
;
|
|
||||||
|
|
||||||
uint32_t GlobalControl = inl(BusMasterAddress + NABM_GlobalControl);
|
|
||||||
GlobalControl = (GlobalControl & ~((0x3U) << 0x16)); /* PCM 16-bit mode */
|
|
||||||
GlobalControl = (GlobalControl & ~((0x3U) << 20)); /* 2 channels */
|
|
||||||
GlobalControl |= GC_GlobalInterruptEnable;
|
|
||||||
GlobalControl &= ~GC_ShutDown;
|
|
||||||
|
|
||||||
outl(BusMasterAddress + PCMOUT_BufferDescriptorList,
|
|
||||||
(uint32_t)(uint64_t)DescriptorList);
|
|
||||||
|
|
||||||
outl(BusMasterAddress + NABM_GlobalControl, GlobalControl);
|
|
||||||
|
|
||||||
uint8_t TransferControl = inb(OutputPCMTransferControl);
|
|
||||||
TransferControl |= TC_IOCInterruptEnable |
|
|
||||||
TC_FifoERRORInterruptEnable;
|
|
||||||
outb(OutputPCMTransferControl, TransferControl);
|
|
||||||
|
|
||||||
// Stop DMA
|
|
||||||
outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) & ~TC_DMAControllerControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
~AC97Device()
|
|
||||||
{
|
|
||||||
outw(MixerAddress + NAM_MasterVolume, MixerVolume(AV_Maximum, AV_Maximum, true));
|
|
||||||
outw(MixerAddress + NAM_PCMOutVolume, MixerVolume(AV_Maximum, AV_Maximum, true));
|
|
||||||
|
|
||||||
// Stop DMA
|
|
||||||
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl),
|
|
||||||
inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl)) & ~TC_DMAControllerControl);
|
|
||||||
|
|
||||||
// Disable interrupts
|
|
||||||
uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
|
|
||||||
|
|
||||||
TransferControl &= ~(TC_LastBufferEntryInterruptEnable |
|
|
||||||
TC_IOCInterruptEnable |
|
|
||||||
TC_FifoERRORInterruptEnable);
|
|
||||||
outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
|
|
||||||
|
|
||||||
// Disable global control
|
|
||||||
uint32_t GlobalControl = inl((uint16_t)(BusMasterAddress + NABM_GlobalControl));
|
|
||||||
GlobalControl &= ~GC_GlobalInterruptEnable;
|
|
||||||
GlobalControl |= GC_ShutDown;
|
|
||||||
outl((uint16_t)(BusMasterAddress + NABM_GlobalControl), GlobalControl);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AC97Device *Drivers[4] = {nullptr};
|
|
||||||
dev_t AudioID[4] = {(dev_t)-1};
|
|
||||||
|
|
||||||
#define OIR(x) OIR_##x
|
|
||||||
#define CREATE_OIR(x) \
|
|
||||||
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
|
|
||||||
|
|
||||||
CREATE_OIR(0);
|
|
||||||
CREATE_OIR(1);
|
|
||||||
CREATE_OIR(2);
|
|
||||||
CREATE_OIR(3);
|
|
||||||
|
|
||||||
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
|
|
||||||
int __fs_Close(struct Inode *) { return 0; }
|
|
||||||
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
|
|
||||||
|
|
||||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
|
||||||
{
|
|
||||||
return Drivers[AudioID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
|
||||||
{
|
|
||||||
return Drivers[AudioID[Node->GetMinor()]]->ioctl((AudioIoctl)Request, Argp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct InodeOperations AudioOps = {
|
|
||||||
.Lookup = nullptr,
|
|
||||||
.Create = nullptr,
|
|
||||||
.Remove = nullptr,
|
|
||||||
.Rename = nullptr,
|
|
||||||
.Read = __fs_Read,
|
|
||||||
.Write = __fs_Write,
|
|
||||||
.Truncate = nullptr,
|
|
||||||
.Open = __fs_Open,
|
|
||||||
.Close = __fs_Close,
|
|
||||||
.Ioctl = __fs_Ioctl,
|
|
||||||
.ReadDir = nullptr,
|
|
||||||
.MkDir = nullptr,
|
|
||||||
.RmDir = nullptr,
|
|
||||||
.SymLink = nullptr,
|
|
||||||
.ReadLink = nullptr,
|
|
||||||
.Seek = nullptr,
|
|
||||||
.Stat = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
PCIArray *Devices;
|
|
||||||
EXTERNC int cxx_Panic()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
short Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Drivers[Count] != nullptr)
|
|
||||||
Drivers[Count]->Panic();
|
|
||||||
Count++;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Probe()
|
|
||||||
{
|
|
||||||
uint16_t VendorIDs[] = {0x8086, PCI_END};
|
|
||||||
uint16_t DeviceIDs[] = {0x2415, PCI_END};
|
|
||||||
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
|
|
||||||
if (Devices == nullptr)
|
|
||||||
{
|
|
||||||
KernelLog("No AC'97 device found.");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
bool Found = false;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count++ > sizeof(Drivers) / sizeof(AC97Device *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
|
||||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
|
||||||
uint8_t Type = PCIBAR0 & 1;
|
|
||||||
if (Type != 1)
|
|
||||||
{
|
|
||||||
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
|
|
||||||
PCIBaseAddress->Header.VendorID,
|
|
||||||
PCIBaseAddress->Header.DeviceID,
|
|
||||||
PCIBaseAddress->Header.ProgIF);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Found = true;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Found)
|
|
||||||
{
|
|
||||||
KernelLog("No valid AC'97 device found.");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Initialize()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count > sizeof(Drivers) / sizeof(AC97Device *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
|
||||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
|
||||||
uint8_t Type = PCIBAR0 & 1;
|
|
||||||
if (Type != 1)
|
|
||||||
{
|
|
||||||
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
|
|
||||||
PCIBaseAddress->Header.VendorID,
|
|
||||||
PCIBaseAddress->Header.DeviceID,
|
|
||||||
PCIBaseAddress->Header.ProgIF);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializePCI(ctx->Device);
|
|
||||||
|
|
||||||
Drivers[Count] = new AC97Device((PCIHeader0 *)ctx->Device->Header);
|
|
||||||
/* FIXME: bad code */
|
|
||||||
switch (Count)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dev_t ret = RegisterDevice(AUDIO_TYPE_PCM, &AudioOps);
|
|
||||||
AudioID[Count] = ret;
|
|
||||||
Count++;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Finalize()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count++ > sizeof(Drivers) / sizeof(AC97Device *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
|
||||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
|
||||||
uint8_t Type = PCIBAR0 & 1;
|
|
||||||
if (Type != 1)
|
|
||||||
{
|
|
||||||
KernelLog("Device %x:%x.%d BAR0 is not I/O.",
|
|
||||||
PCIBaseAddress->Header.VendorID,
|
|
||||||
PCIBaseAddress->Header.DeviceID,
|
|
||||||
PCIBaseAddress->Header.ProgIF);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete Drivers[Count++];
|
|
||||||
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(AudioID) / sizeof(dev_t); i++)
|
|
||||||
{
|
|
||||||
if (AudioID[i] != (dev_t)-1)
|
|
||||||
UnregisterDevice(AudioID[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <types.h>
|
|
||||||
|
|
||||||
EXTERNC int cxx_Panic();
|
|
||||||
EXTERNC int cxx_Probe();
|
|
||||||
EXTERNC int cxx_Initialize();
|
|
||||||
EXTERNC int cxx_Finalize();
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base.h>
|
|
||||||
|
|
||||||
#include "ac97.hpp"
|
|
||||||
|
|
||||||
int DriverEntry() { return cxx_Initialize(); }
|
|
||||||
int DriverFinal() { return cxx_Finalize(); }
|
|
||||||
int DriverPanic() { return cxx_Panic(); }
|
|
||||||
int DriverProbe() { return cxx_Probe(); }
|
|
||||||
|
|
||||||
DriverInfo("ac97",
|
|
||||||
"Audio Codec '97 Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
@ -1,263 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Kernel.
|
|
||||||
|
|
||||||
Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <audio.h>
|
|
||||||
#include <regs.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <pci.h>
|
|
||||||
#include <io.h>
|
|
||||||
#include <fs.h>
|
|
||||||
|
|
||||||
#include "hda.hpp"
|
|
||||||
|
|
||||||
class HDADevice
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
PCIHeader0 *Header;
|
|
||||||
bool Initialized = false;
|
|
||||||
|
|
||||||
ControllerRegisters *CTL;
|
|
||||||
|
|
||||||
uint32_t *CORB;
|
|
||||||
uint64_t *RIRB;
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool IsInitialized() { return Initialized; }
|
|
||||||
|
|
||||||
size_t write(uint8_t *, size_t Size)
|
|
||||||
{
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ioctl(AudioIoctl, void *)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnInterruptReceived(TrapFrame *)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Panic()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HDADevice(PCIHeader0 *_Header)
|
|
||||||
: Header(_Header),
|
|
||||||
CORB((uint32_t *)(uintptr_t)AllocateMemory(1)),
|
|
||||||
RIRB((uint64_t *)AllocateMemory(1))
|
|
||||||
{
|
|
||||||
CTL = (ControllerRegisters *)(uintptr_t)Header->BAR0;
|
|
||||||
KernelLog("Unimplemented HDA driver");
|
|
||||||
return;
|
|
||||||
Initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
~HDADevice()
|
|
||||||
{
|
|
||||||
if (!Initialized)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
HDADevice *Drivers[4] = {nullptr};
|
|
||||||
dev_t AudioID[4] = {(dev_t)-1};
|
|
||||||
|
|
||||||
#define OIR(x) OIR_##x
|
|
||||||
#define CREATE_OIR(x) \
|
|
||||||
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
|
|
||||||
|
|
||||||
CREATE_OIR(0);
|
|
||||||
CREATE_OIR(1);
|
|
||||||
CREATE_OIR(2);
|
|
||||||
CREATE_OIR(3);
|
|
||||||
|
|
||||||
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
|
|
||||||
int __fs_Close(struct Inode *) { return 0; }
|
|
||||||
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
|
|
||||||
|
|
||||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
|
||||||
{
|
|
||||||
return Drivers[AudioID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
|
||||||
{
|
|
||||||
return Drivers[AudioID[Node->GetMinor()]]->ioctl((AudioIoctl)Request, Argp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct InodeOperations AudioOps = {
|
|
||||||
.Lookup = nullptr,
|
|
||||||
.Create = nullptr,
|
|
||||||
.Remove = nullptr,
|
|
||||||
.Rename = nullptr,
|
|
||||||
.Read = __fs_Read,
|
|
||||||
.Write = __fs_Write,
|
|
||||||
.Truncate = nullptr,
|
|
||||||
.Open = __fs_Open,
|
|
||||||
.Close = __fs_Close,
|
|
||||||
.Ioctl = __fs_Ioctl,
|
|
||||||
.ReadDir = nullptr,
|
|
||||||
.MkDir = nullptr,
|
|
||||||
.RmDir = nullptr,
|
|
||||||
.SymLink = nullptr,
|
|
||||||
.ReadLink = nullptr,
|
|
||||||
.Seek = nullptr,
|
|
||||||
.Stat = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
PCIArray *Devices;
|
|
||||||
EXTERNC int cxx_Panic()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
short Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Drivers[Count] != nullptr)
|
|
||||||
Drivers[Count]->Panic();
|
|
||||||
Count++;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Probe()
|
|
||||||
{
|
|
||||||
uint16_t VendorIDs[] = {0x8086, /* Intel */
|
|
||||||
0x15AD, /* VMware */
|
|
||||||
PCI_END};
|
|
||||||
uint16_t DeviceIDs[] = {0x9D71 /* Sunrise Point-LP HD Audio */,
|
|
||||||
0x2668 /* ICH6 */,
|
|
||||||
0x293E /* ICH9 */,
|
|
||||||
PCI_END};
|
|
||||||
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
|
|
||||||
if (Devices == nullptr)
|
|
||||||
{
|
|
||||||
KernelLog("No HDA device found.");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
bool Found = false;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count++ > sizeof(Drivers) / sizeof(HDADevice *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
|
||||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
|
||||||
uint8_t Type = PCIBAR0 & 1;
|
|
||||||
if (Type == 1)
|
|
||||||
{
|
|
||||||
KernelLog("Device %x:%x.%d BAR0 is I/O.",
|
|
||||||
PCIBaseAddress->Header.VendorID,
|
|
||||||
PCIBaseAddress->Header.DeviceID,
|
|
||||||
PCIBaseAddress->Header.ProgIF);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Found = true;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Found)
|
|
||||||
{
|
|
||||||
KernelLog("No valid HDA device found.");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Initialize()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count > sizeof(Drivers) / sizeof(HDADevice *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
|
||||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
|
||||||
uint8_t Type = PCIBAR0 & 1;
|
|
||||||
if (Type == 1)
|
|
||||||
{
|
|
||||||
KernelLog("Device %x:%x.%d BAR0 is I/O.",
|
|
||||||
PCIBaseAddress->Header.VendorID,
|
|
||||||
PCIBaseAddress->Header.DeviceID,
|
|
||||||
PCIBaseAddress->Header.ProgIF);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializePCI(ctx->Device);
|
|
||||||
|
|
||||||
Drivers[Count] = new HDADevice((PCIHeader0 *)ctx->Device->Header);
|
|
||||||
|
|
||||||
if (Drivers[Count]->IsInitialized())
|
|
||||||
{
|
|
||||||
dev_t ret = RegisterDevice(AUDIO_TYPE_PCM, &AudioOps);
|
|
||||||
AudioID[Count] = ret;
|
|
||||||
Count++;
|
|
||||||
}
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Count == 0)
|
|
||||||
{
|
|
||||||
KernelLog("No valid HDA device found.");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Finalize()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count++ > sizeof(Drivers) / sizeof(HDADevice *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
|
|
||||||
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
|
||||||
uint8_t Type = PCIBAR0 & 1;
|
|
||||||
if (Type == 1)
|
|
||||||
{
|
|
||||||
KernelLog("Device %x:%x.%d BAR0 is I/O.",
|
|
||||||
PCIBaseAddress->Header.VendorID,
|
|
||||||
PCIBaseAddress->Header.DeviceID,
|
|
||||||
PCIBaseAddress->Header.ProgIF);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete Drivers[Count++];
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(AudioID) / sizeof(dev_t); i++)
|
|
||||||
{
|
|
||||||
if (AudioID[i] != (dev_t)-1)
|
|
||||||
UnregisterDevice(AudioID[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base.h>
|
|
||||||
|
|
||||||
#include "hda.hpp"
|
|
||||||
|
|
||||||
int DriverEntry() { return cxx_Initialize(); }
|
|
||||||
int DriverFinal() { return cxx_Finalize(); }
|
|
||||||
int DriverPanic() { return cxx_Panic(); }
|
|
||||||
int DriverProbe() { return cxx_Probe(); }
|
|
||||||
|
|
||||||
DriverInfo("hda",
|
|
||||||
"Intel High Definition Audio Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base.h>
|
|
||||||
|
|
||||||
int DriverEntry()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverFinal()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverPanic()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverProbe()
|
|
||||||
{
|
|
||||||
/* Nothing to do */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DriverInfo("fat",
|
|
||||||
"File Allocation Table Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -103,6 +103,7 @@ typedef union
|
|||||||
uint8_t Raw;
|
uint8_t Raw;
|
||||||
} PS2_OUTPUT_PORT;
|
} PS2_OUTPUT_PORT;
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
void PIC_EOI(uint8_t IRQ);
|
void PIC_EOI(uint8_t IRQ);
|
||||||
void IRQ_MASK(uint8_t IRQ);
|
void IRQ_MASK(uint8_t IRQ);
|
||||||
void IRQ_UNMASK(uint8_t IRQ);
|
void IRQ_UNMASK(uint8_t IRQ);
|
||||||
@ -114,11 +115,11 @@ uint8_t PS2ReadStatus();
|
|||||||
uint8_t PS2ReadAfterACK();
|
uint8_t PS2ReadAfterACK();
|
||||||
void PS2ClearOutputBuffer();
|
void PS2ClearOutputBuffer();
|
||||||
int PS2ACKTimeout();
|
int PS2ACKTimeout();
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#define WaitOutput PS2Wait(DriverID, true)
|
#define WaitOutput PS2Wait(DriverID, true)
|
||||||
#define WaitInput PS2Wait(DriverID, false)
|
#define WaitInput PS2Wait(DriverID, false)
|
||||||
|
|
||||||
|
|
||||||
#define PS2_KBD_CMD_SET_LEDS 0xED
|
#define PS2_KBD_CMD_SET_LEDS 0xED
|
||||||
#define PS2_KBD_CMD_ECHO 0xEE
|
#define PS2_KBD_CMD_ECHO 0xEE
|
||||||
#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0
|
#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0
|
||||||
@ -189,7 +190,6 @@ typedef union
|
|||||||
uint8_t Raw;
|
uint8_t Raw;
|
||||||
} PS2_KBD_TYPEMATIC;
|
} PS2_KBD_TYPEMATIC;
|
||||||
|
|
||||||
|
|
||||||
#define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6
|
#define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6
|
||||||
#define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7
|
#define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7
|
||||||
#define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8
|
#define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8
|
||||||
|
@ -69,7 +69,10 @@ typedef enum
|
|||||||
BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128,
|
BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128,
|
||||||
} DeviceType;
|
} DeviceType;
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
|
EXTERNC dev_t CreateDeviceFile(const char *name, mode_t mode, const struct InodeOperations *Operations);
|
||||||
EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations);
|
EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations);
|
||||||
EXTERNC int UnregisterDevice(dev_t Device);
|
EXTERNC int UnregisterDevice(dev_t Device);
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#endif // !__FENNIX_API_DEVICE_H__
|
#endif // !__FENNIX_API_DEVICE_H__
|
||||||
|
@ -377,7 +377,9 @@ struct FileSystemInfo
|
|||||||
void *PrivateData;
|
void *PrivateData;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
||||||
int UnregisterFileSystem(dev_t Device);
|
int UnregisterFileSystem(dev_t Device);
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#endif // !__FENNIX_API_FILESYSTEM_H__
|
#endif // !__FENNIX_API_FILESYSTEM_H__
|
||||||
|
@ -239,6 +239,8 @@ typedef struct
|
|||||||
};
|
};
|
||||||
} InputReport;
|
} InputReport;
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
EXTERNC int ReportInputEvent(InputReport *Report);
|
EXTERNC int ReportInputEvent(InputReport *Report);
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#endif // !__FENNIX_API_INPUT_H__
|
#endif // !__FENNIX_API_INPUT_H__
|
||||||
|
@ -171,11 +171,13 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
PCIArray *GetPCIDevices(uint16_t Vendors[], uint16_t Devices[]);
|
PCIArray *GetPCIDevices(uint16_t Vendors[], uint16_t Devices[]);
|
||||||
void InitializePCI(PCIDevice *Device);
|
void InitializePCI(PCIDevice *Device);
|
||||||
uint32_t GetBAR(uint8_t Index, PCIDevice *Device);
|
uint32_t GetBAR(uint8_t Index, PCIDevice *Device);
|
||||||
uint8_t iLine(PCIDevice *Device);
|
uint8_t iLine(PCIDevice *Device);
|
||||||
uint8_t iPin(PCIDevice *Device);
|
uint8_t iPin(PCIDevice *Device);
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -531,6 +531,28 @@ static_assert((int)__SYS_SIG_IGN == (int)___SYS_SIG_IGN, "SIG_IGN values do not
|
|||||||
typedef int __SYS_clockid_t;
|
typedef int __SYS_clockid_t;
|
||||||
typedef unsigned int __SYS_socklen_t;
|
typedef unsigned int __SYS_socklen_t;
|
||||||
|
|
||||||
|
typedef struct FramebufferScreenInfo
|
||||||
|
{
|
||||||
|
__UINT32_TYPE__ Width;
|
||||||
|
__UINT32_TYPE__ Height;
|
||||||
|
__UINT32_TYPE__ Pitch;
|
||||||
|
__UINT32_TYPE__ Bpp;
|
||||||
|
__UINT32_TYPE__ Size;
|
||||||
|
} FramebufferScreenInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get framebuffer screen info
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* struct FramebufferScreenInfo info;
|
||||||
|
* int ioctl(fd, FBIOGET_SCREEN_INFO, &info);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param fd File descriptor of the framebuffer device
|
||||||
|
* @param info Pointer to the framebuffer screen info structure
|
||||||
|
*/
|
||||||
|
#define FBIOGET_SCREEN_INFO 0xf0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief List of syscalls
|
* @brief List of syscalls
|
||||||
*
|
*
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FENNIX_DRIVER_AIP_H__
|
|
||||||
#define __FENNIX_DRIVER_AIP_H__
|
|
||||||
|
|
||||||
#include <types.h>
|
|
||||||
#include <aip.h>
|
|
||||||
#include <regs.h>
|
|
||||||
|
|
||||||
extern uint8_t Device1ID[];
|
|
||||||
extern uint8_t Device2ID[];
|
|
||||||
|
|
||||||
void PS2KbdInterruptHandler(TrapFrame *);
|
|
||||||
int InitializeKeyboard();
|
|
||||||
int FinalizeKeyboard();
|
|
||||||
int DetectPS2Keyboard();
|
|
||||||
|
|
||||||
void PS2MouseInterruptHandler(TrapFrame *);
|
|
||||||
int InitializeMouse();
|
|
||||||
int FinalizeMouse();
|
|
||||||
int DetectPS2Mouse();
|
|
||||||
int DetectUART();
|
|
||||||
|
|
||||||
#endif // !__FENNIX_DRIVER_AIP_H__
|
|
@ -1,235 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "aip.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <base.h>
|
|
||||||
|
|
||||||
bool IsKeyboard(uint8_t ID)
|
|
||||||
{
|
|
||||||
/* Common keyboard IDs */
|
|
||||||
return ID == 0xAB || ID == 0xAC || ID == 0x5D ||
|
|
||||||
ID == 0x2B || ID == 0x47 || ID == 0x60;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsMouse(uint8_t ID)
|
|
||||||
{
|
|
||||||
/* Common mouse IDs */
|
|
||||||
return ID == 0x00 || ID == 0x03 || ID == 0x04;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *GetPS2DeviceName(uint8_t ID, uint8_t SubID)
|
|
||||||
{
|
|
||||||
switch (ID)
|
|
||||||
{
|
|
||||||
case 0x00:
|
|
||||||
return "Standard PS/2 Mouse";
|
|
||||||
case 0x03:
|
|
||||||
return "Mouse with scroll wheel";
|
|
||||||
case 0x04:
|
|
||||||
return "Mouse 5 buttons";
|
|
||||||
case 0xAB:
|
|
||||||
{
|
|
||||||
switch (SubID)
|
|
||||||
{
|
|
||||||
case 0x83: /* Normal */
|
|
||||||
case 0x41: /* Translated */
|
|
||||||
case 0xC1: /* Normal + Translated */
|
|
||||||
return "Standard PS/2 Keyboard";
|
|
||||||
case 0x84:
|
|
||||||
case 0x54:
|
|
||||||
return "IBM Thinkpad/Spacesaver Keyboard";
|
|
||||||
case 0x85:
|
|
||||||
return "NCD N-97/122-Key Host Connect(ed) Keyboard";
|
|
||||||
case 0x86:
|
|
||||||
return "122-Key Keyboard";
|
|
||||||
case 0x90:
|
|
||||||
return "Japanese \"G\" Keyboard";
|
|
||||||
case 0x91:
|
|
||||||
return "Japanese \"P\" Keyboard";
|
|
||||||
case 0x92:
|
|
||||||
return "Japanese \"A\" Keyboard";
|
|
||||||
default:
|
|
||||||
return "Unknown PS/2 Keyboard";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 0xAC:
|
|
||||||
{
|
|
||||||
switch (SubID)
|
|
||||||
{
|
|
||||||
case 0xA1:
|
|
||||||
return "NCD Sun Keyboard";
|
|
||||||
default:
|
|
||||||
return "Unknown NCD Sun Keyboard";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 0x5D:
|
|
||||||
case 0x2B:
|
|
||||||
return "Trust Keyboard";
|
|
||||||
case 0x47:
|
|
||||||
case 0x60:
|
|
||||||
return "NMB SGI Keyboard";
|
|
||||||
default:
|
|
||||||
return "Unknown PS/2 Device";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t Device1ID[2] = {0x00, 0x00};
|
|
||||||
uint8_t Device2ID[2] = {0x00, 0x00};
|
|
||||||
bool DualChannel = false;
|
|
||||||
|
|
||||||
int DriverEntry()
|
|
||||||
{
|
|
||||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
|
|
||||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
|
|
||||||
PS2ClearOutputBuffer();
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_READ_CONFIG);
|
|
||||||
PS2_CONFIGURATION cfg = {.Raw = PS2ReadData()};
|
|
||||||
|
|
||||||
DualChannel = cfg.Port2Clock;
|
|
||||||
if (DualChannel)
|
|
||||||
KernelLog("Dual channel PS/2 controller detected");
|
|
||||||
cfg.Port1Interrupt = 1;
|
|
||||||
cfg.Port2Interrupt = 1;
|
|
||||||
cfg.Port1Translation = 1;
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
|
|
||||||
PS2WriteData(cfg.Raw);
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_TEST_CONTROLLER);
|
|
||||||
uint8_t test = PS2ReadData();
|
|
||||||
if (test != PS2_TEST_PASSED)
|
|
||||||
{
|
|
||||||
KernelLog("PS/2 controller self test failed (%#x)", test);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
|
|
||||||
PS2WriteData(cfg.Raw);
|
|
||||||
|
|
||||||
// bool port2avail = false;
|
|
||||||
// if (DualChannel)
|
|
||||||
// {
|
|
||||||
// PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
|
|
||||||
// PS2WriteCommand(PS2_CMD_READ_CONFIG);
|
|
||||||
// cfg.Raw = PS2ReadData();
|
|
||||||
// port2avail = cfg.Port2Clock;
|
|
||||||
// PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_TEST_PORT_1);
|
|
||||||
test = PS2ReadData();
|
|
||||||
if (test != 0x00)
|
|
||||||
{
|
|
||||||
KernelLog("PS/2 Port 1 self test failed (%#x)", test);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DualChannel)
|
|
||||||
{
|
|
||||||
PS2WriteCommand(PS2_CMD_TEST_PORT_2);
|
|
||||||
test = PS2ReadData();
|
|
||||||
if (test != 0x00)
|
|
||||||
{
|
|
||||||
KernelLog("PS/2 Port 2 self test failed (%#x)", test);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
|
|
||||||
if (DualChannel)
|
|
||||||
PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
|
|
||||||
|
|
||||||
int errK = InitializeKeyboard();
|
|
||||||
|
|
||||||
int errM = 0;
|
|
||||||
if (DualChannel)
|
|
||||||
errM = InitializeMouse();
|
|
||||||
|
|
||||||
/** A device may fail, but if the other one works,
|
|
||||||
* we can still use it.
|
|
||||||
*/
|
|
||||||
if (errK != 0 && errM != 0)
|
|
||||||
return -ENODEV;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverFinal()
|
|
||||||
{
|
|
||||||
FinalizeKeyboard();
|
|
||||||
FinalizeMouse();
|
|
||||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
|
|
||||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverPanic()
|
|
||||||
{
|
|
||||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
|
|
||||||
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __intStub() {}
|
|
||||||
int DriverProbe()
|
|
||||||
{
|
|
||||||
RegisterInterruptHandler(1, __intStub);
|
|
||||||
RegisterInterruptHandler(12, __intStub);
|
|
||||||
|
|
||||||
int kbd = DetectPS2Keyboard();
|
|
||||||
int mouse = DetectPS2Mouse();
|
|
||||||
int uart = DetectUART();
|
|
||||||
|
|
||||||
UnregisterAllInterruptHandlers(__intStub);
|
|
||||||
|
|
||||||
if (kbd != 0 && mouse != 0 && uart != 0)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (kbd == 0)
|
|
||||||
{
|
|
||||||
if (!IsKeyboard(Device1ID[0]))
|
|
||||||
{
|
|
||||||
KernelLog("PS/2 Port 1 is not a keyboard");
|
|
||||||
// return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mouse == 0)
|
|
||||||
{
|
|
||||||
if (!IsMouse(Device2ID[0]))
|
|
||||||
{
|
|
||||||
KernelLog("PS/2 Port 2 is not a mouse");
|
|
||||||
// return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelPrint("PS/2 Port 1: %s (0x%X 0x%X)",
|
|
||||||
GetPS2DeviceName(Device1ID[0], Device1ID[1]),
|
|
||||||
Device1ID[0], Device1ID[1]);
|
|
||||||
KernelPrint("PS/2 Port 2: %s (0x%X 0x%X)",
|
|
||||||
GetPS2DeviceName(Device2ID[0], Device2ID[1]),
|
|
||||||
Device2ID[0], Device2ID[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DriverInfo("aip",
|
|
||||||
"Advanced Integrated Peripheral Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -1,244 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "aip.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <fs.h>
|
|
||||||
#include <input.h>
|
|
||||||
|
|
||||||
dev_t MouseDevID = -1;
|
|
||||||
bool PacketReady = false;
|
|
||||||
bool FourPackets = false;
|
|
||||||
bool MouseButton45 = false;
|
|
||||||
uint8_t Cycle = 0;
|
|
||||||
PS2_MOUSE_PACKET Packet = {0};
|
|
||||||
|
|
||||||
InputReport mir = {0};
|
|
||||||
void PS2MouseInterruptHandler(TrapFrame *)
|
|
||||||
{
|
|
||||||
uint8_t data = PS2ReadData();
|
|
||||||
if (data == PS2_MOUSE_RESP_ACK ||
|
|
||||||
data == PS2_MOUSE_RESP_RESEND)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!PacketReady)
|
|
||||||
{
|
|
||||||
switch (Cycle)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
if ((data & 0b00001000 /* Always 1 */) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Packet.Base.Raw = data;
|
|
||||||
Cycle++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
Packet.XMovement = data;
|
|
||||||
Cycle++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
Packet.YMovement = data;
|
|
||||||
if (FourPackets)
|
|
||||||
Cycle++;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Cycle = 0;
|
|
||||||
PacketReady = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
Packet.ZMovement.Raw = data;
|
|
||||||
Cycle = 0;
|
|
||||||
PacketReady = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* https://stackoverflow.com/a/3208376/9352057 */
|
|
||||||
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
|
|
||||||
#define BYTE_TO_BINARY(byte) \
|
|
||||||
((byte) & 0x80 ? '1' : '0'), \
|
|
||||||
((byte) & 0x40 ? '1' : '0'), \
|
|
||||||
((byte) & 0x20 ? '1' : '0'), \
|
|
||||||
((byte) & 0x10 ? '1' : '0'), \
|
|
||||||
((byte) & 0x08 ? '1' : '0'), \
|
|
||||||
((byte) & 0x04 ? '1' : '0'), \
|
|
||||||
((byte) & 0x02 ? '1' : '0'), \
|
|
||||||
((byte) & 0x01 ? '1' : '0')
|
|
||||||
|
|
||||||
DebugLog("PS/2 Mouse Packet: [" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN "] LB:%d RB:%d MB:%d A1:%d XS:%d YS:%d XO:%d YO:%d | X:%03d Y:%03d | Z:%d B4:%d B5:%d A0:%d A0:%d",
|
|
||||||
BYTE_TO_BINARY(Packet.Base.Raw),
|
|
||||||
BYTE_TO_BINARY(Packet.XMovement),
|
|
||||||
BYTE_TO_BINARY(Packet.YMovement),
|
|
||||||
BYTE_TO_BINARY(Packet.ZMovement.Raw),
|
|
||||||
Packet.Base.LeftButton, Packet.Base.RightButton, Packet.Base.MiddleButton,
|
|
||||||
Packet.Base.Always1,
|
|
||||||
Packet.Base.XSign, Packet.Base.YSign,
|
|
||||||
Packet.Base.XOverflow, Packet.Base.YOverflow,
|
|
||||||
Packet.XMovement, Packet.YMovement,
|
|
||||||
Packet.ZMovement.Z, Packet.ZMovement.Button4, Packet.ZMovement.Button5,
|
|
||||||
Packet.ZMovement.Always0, Packet.ZMovement.Always0_2);
|
|
||||||
|
|
||||||
int X, Y;
|
|
||||||
X = Packet.XMovement - (Packet.Base.XSign ? 256 : 0);
|
|
||||||
Y = Packet.YMovement - (Packet.Base.YSign ? 256 : 0);
|
|
||||||
|
|
||||||
if (Packet.Base.XOverflow)
|
|
||||||
X = 0;
|
|
||||||
|
|
||||||
if (Packet.Base.YOverflow)
|
|
||||||
Y = 0;
|
|
||||||
|
|
||||||
mir.Type = INPUT_TYPE_MOUSE;
|
|
||||||
mir.Device = MouseDevID;
|
|
||||||
mir.Mouse.LeftButton = Packet.Base.LeftButton;
|
|
||||||
mir.Mouse.RightButton = Packet.Base.RightButton;
|
|
||||||
mir.Mouse.MiddleButton = Packet.Base.MiddleButton;
|
|
||||||
mir.Mouse.Button4 = Packet.ZMovement.Button4;
|
|
||||||
mir.Mouse.Button5 = Packet.ZMovement.Button5;
|
|
||||||
mir.Mouse.X = X;
|
|
||||||
mir.Mouse.Y = -Y;
|
|
||||||
mir.Mouse.Z = Packet.ZMovement.Z;
|
|
||||||
ReportInputEvent(&mir);
|
|
||||||
PacketReady = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseSampleRate(uint8_t SampleRate)
|
|
||||||
{
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_SET_SAMPLE_RATE);
|
|
||||||
PS2ReadData();
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(SampleRate);
|
|
||||||
PS2ReadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
int __fs_ms_Ioctl(struct Inode *, unsigned long, void *)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct InodeOperations MouseOps = {
|
|
||||||
.Ioctl = __fs_ms_Ioctl,
|
|
||||||
};
|
|
||||||
|
|
||||||
int InitializeMouse()
|
|
||||||
{
|
|
||||||
PS2WriteData(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_RESET);
|
|
||||||
uint8_t test = PS2ReadData();
|
|
||||||
if (test != PS2_MOUSE_RESP_TEST_PASSED &&
|
|
||||||
test != PS2_MOUSE_RESP_ACK)
|
|
||||||
{
|
|
||||||
KernelLog("PS/2 mouse reset failed! (%#x)", test);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegisterInterruptHandler(12, PS2MouseInterruptHandler);
|
|
||||||
|
|
||||||
MouseDevID = RegisterDevice(INPUT_TYPE_MOUSE, &MouseOps);
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
|
|
||||||
PS2ReadData();
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
|
|
||||||
|
|
||||||
MouseSampleRate(200);
|
|
||||||
MouseSampleRate(100);
|
|
||||||
MouseSampleRate(80);
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
|
|
||||||
uint8_t Device2ID = PS2ReadData();
|
|
||||||
KernelLog("PS/2 Mouse ID: %#x", Device2ID);
|
|
||||||
|
|
||||||
MouseSampleRate(200);
|
|
||||||
MouseSampleRate(200);
|
|
||||||
MouseSampleRate(80);
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
|
|
||||||
Device2ID = PS2ReadData();
|
|
||||||
KernelLog("PS/2 Mouse ID: %#x", Device2ID);
|
|
||||||
|
|
||||||
if (Device2ID >= 3 && Device2ID <= 4)
|
|
||||||
FourPackets = true;
|
|
||||||
if (Device2ID == 4)
|
|
||||||
MouseButton45 = true;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FinalizeMouse()
|
|
||||||
{
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
|
||||||
|
|
||||||
UnregisterDevice(MouseDevID);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DetectPS2Mouse()
|
|
||||||
{
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 mouse failed to disable data reporting!");
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 mouse failed to read ID!");
|
|
||||||
|
|
||||||
uint8_t recByte;
|
|
||||||
int timeout = 1000000;
|
|
||||||
while (timeout--)
|
|
||||||
{
|
|
||||||
recByte = PS2ReadData();
|
|
||||||
if (recByte != PS2_ACK)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Device2ID[0] = recByte;
|
|
||||||
|
|
||||||
timeout = 1000000;
|
|
||||||
while (timeout--)
|
|
||||||
{
|
|
||||||
recByte = PS2ReadData();
|
|
||||||
if (recByte != PS2_ACK)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Device2ID[1] = recByte;
|
|
||||||
|
|
||||||
KernelLog("PS2 Mouse Device: 0x%X 0x%X", Device2ID[0], Device2ID[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,646 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "aip.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <fs.h>
|
|
||||||
#include <input.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
#define SERIAL_ENABLE_DLAB 0x80
|
|
||||||
#define SERIAL_BUFFER_EMPTY 0x20
|
|
||||||
|
|
||||||
enum Ports
|
|
||||||
{
|
|
||||||
COM1 = 0x3F8,
|
|
||||||
COM2 = 0x2F8,
|
|
||||||
COM3 = 0x3E8,
|
|
||||||
COM4 = 0x2E8,
|
|
||||||
COM5 = 0x5F8,
|
|
||||||
COM6 = 0x4F8,
|
|
||||||
COM7 = 0x5E8,
|
|
||||||
COM8 = 0x4E8,
|
|
||||||
|
|
||||||
LPT1 = 0x378,
|
|
||||||
LPT2 = 0x278,
|
|
||||||
LPT3 = 0x3BC
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SerialSpeed
|
|
||||||
{
|
|
||||||
RATE_50_HI = 0x09,
|
|
||||||
RATE_50_LO = 0x00,
|
|
||||||
|
|
||||||
RATE_300_HI = 0x01,
|
|
||||||
RATE_300_LO = 0x80,
|
|
||||||
|
|
||||||
RATE_600_HI = 0x00,
|
|
||||||
RATE_600_LO = 0xC0,
|
|
||||||
|
|
||||||
RATE_2400_HI = 0x00,
|
|
||||||
RATE_2400_LO = 0x30,
|
|
||||||
|
|
||||||
RATE_4800_HI = 0x00,
|
|
||||||
RATE_4800_LO = 0x18,
|
|
||||||
|
|
||||||
RATE_9600_HI = 0x00,
|
|
||||||
RATE_9600_LO = 0x0C,
|
|
||||||
|
|
||||||
RATE_19200_HI = 0x00,
|
|
||||||
RATE_19200_LO = 0x06,
|
|
||||||
|
|
||||||
RATE_38400_HI = 0x00,
|
|
||||||
RATE_38400_LO = 0x03,
|
|
||||||
|
|
||||||
RATE_57600_HI = 0x00,
|
|
||||||
RATE_57600_LO = 0x02,
|
|
||||||
|
|
||||||
RATE_115200_HI = 0x00,
|
|
||||||
RATE_115200_LO = 0x01
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
. Table of Registers .
|
|
||||||
/---------------------------------------------------------------------\
|
|
||||||
| Base Address | DLAB | R/W | Abr | Register Name |
|
|
||||||
|---------------------------------------------------------------------|
|
|
||||||
| +0 | =0 | W | - | Transmitter Holding Buffer |
|
|
||||||
| | =0 | R | - | Receiver Buffer |
|
|
||||||
| | =1 | R/W | - | Divisor Latch Low Byte |
|
|
||||||
| +1 | =0 | R/W | IER | Interrupt Enable Register |
|
|
||||||
| | =1 | R/W | - | Divisor Latch High Byte |
|
|
||||||
| +2 | - | R | IIR | Interrupt Identification Register |
|
|
||||||
| | - | W | FCR | FIFO Control Register |
|
|
||||||
| +3 | - | R/W | LCR | Line Control Register |
|
|
||||||
| +4 | - | R/W | MCR | Modem Control Register |
|
|
||||||
| +5 | - | R | LSR | Line Status Register |
|
|
||||||
| +6 | - | R | MSR | Modem Status Register |
|
|
||||||
| +7 | - | R/W | - | Scratch Register |
|
|
||||||
\---------------------------------------------------------------------/
|
|
||||||
|
|
||||||
Source:
|
|
||||||
Interfacing the Serial / RS232 Port V5.0
|
|
||||||
Table 5 : Table of Registers
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Interrupt Enable Register */
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/* Enable Received Data Available Interrupt */
|
|
||||||
uint8_t InterruptOnReceive : 1;
|
|
||||||
|
|
||||||
/* Enable Transmitter Holding Register Empty Interrupt */
|
|
||||||
uint8_t InterruptOnTransmitter : 1;
|
|
||||||
|
|
||||||
/* Enable Receiver Line Status Interrupt */
|
|
||||||
uint8_t LineStatusInterrupt : 1;
|
|
||||||
|
|
||||||
/* Enable Modem Status Interrupt */
|
|
||||||
uint8_t ModemStatusInterrupt : 1;
|
|
||||||
|
|
||||||
/* Enables Sleep Mode (16750) */
|
|
||||||
uint8_t SleepMode : 1;
|
|
||||||
|
|
||||||
/* Enables Low Power Mode (16750) */
|
|
||||||
uint8_t LowPowerMode : 1;
|
|
||||||
|
|
||||||
/* Reserved */
|
|
||||||
uint8_t __reserved : 2;
|
|
||||||
};
|
|
||||||
uint8_t raw;
|
|
||||||
} IER;
|
|
||||||
|
|
||||||
/** Interrupt Identification Register */
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/* Interrupt pending */
|
|
||||||
uint8_t InterruptPending : 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt Status
|
|
||||||
*
|
|
||||||
* 00b = Modem Status Interrupt
|
|
||||||
* 01b = Transmitter Holding Register Empty Interrupt
|
|
||||||
* 10b = Received Data Available Interrupt
|
|
||||||
* 11b = Receiver Line Status Interrupt
|
|
||||||
*/
|
|
||||||
uint8_t InterruptStatus : 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 16550 Time-out Interrupt Pending
|
|
||||||
*
|
|
||||||
* @note Reserved on 8250, 16450
|
|
||||||
*/
|
|
||||||
uint8_t TimeOutIP : 1;
|
|
||||||
|
|
||||||
/** Reserved */
|
|
||||||
uint8_t __reserved : 1;
|
|
||||||
|
|
||||||
/** 64 Byte Fifo Enabled (16750 only) */
|
|
||||||
uint8_t FIFO64 : 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable FIFO
|
|
||||||
*
|
|
||||||
* 00b = No FIFO
|
|
||||||
* 01b = FIFO Enabled but Unusable
|
|
||||||
* 11b = FIFO Enabled
|
|
||||||
*/
|
|
||||||
uint8_t FIFO : 2;
|
|
||||||
};
|
|
||||||
uint8_t raw;
|
|
||||||
} IIR;
|
|
||||||
|
|
||||||
/** First In / First Out Control Register */
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/** Enable FIFO's */
|
|
||||||
uint8_t FIFO : 1;
|
|
||||||
|
|
||||||
/** Clear Receive FIFO */
|
|
||||||
uint8_t ClearRX : 1;
|
|
||||||
|
|
||||||
/** Clear Transmit FIFO */
|
|
||||||
uint8_t ClearTX : 1;
|
|
||||||
|
|
||||||
/** DMA Mode Select.
|
|
||||||
*
|
|
||||||
* Change status of RXRDY & TXRDY pins from mode 1 to mode 2.
|
|
||||||
*/
|
|
||||||
uint8_t DMAMode : 1;
|
|
||||||
|
|
||||||
/** Reserved */
|
|
||||||
uint8_t __reserved : 1;
|
|
||||||
|
|
||||||
/** Enable 64 Byte FIFO (16750 only) */
|
|
||||||
uint8_t FIFO64 : 1;
|
|
||||||
|
|
||||||
/** Interrupt Trigger Level
|
|
||||||
*
|
|
||||||
* 00b = 1 Byte
|
|
||||||
* 01b = 4 Bytes
|
|
||||||
* 10b = 8 Bytes
|
|
||||||
* 11b = 14 Bytes
|
|
||||||
*/
|
|
||||||
uint8_t TriggerLevel : 2;
|
|
||||||
};
|
|
||||||
uint8_t raw;
|
|
||||||
} FCR;
|
|
||||||
|
|
||||||
/** Line Control Register */
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/** Word Length
|
|
||||||
*
|
|
||||||
* 00b = 5 bits
|
|
||||||
* 01b = 6 bits
|
|
||||||
* 10b = 7 bits
|
|
||||||
* 11b = 8 bits
|
|
||||||
*/
|
|
||||||
uint8_t WordLength : 2;
|
|
||||||
|
|
||||||
/** Length of Stop Bit
|
|
||||||
*
|
|
||||||
* 0b = One Stop Bit
|
|
||||||
* 1b = 2 Stop bits for words of length 6,7 or 8 bits or 1.5 Stop Bits for Word lengths of 5 bits.
|
|
||||||
*/
|
|
||||||
uint8_t StopBit : 1;
|
|
||||||
|
|
||||||
/** Parity Select
|
|
||||||
*
|
|
||||||
* 0b = No Parity
|
|
||||||
* 001b = Odd Parity
|
|
||||||
* 011b = Even Parity
|
|
||||||
* 101b = High Parity (Sticky)
|
|
||||||
* 111b = Low Parity (Sticky)
|
|
||||||
*/
|
|
||||||
uint8_t Parity : 3;
|
|
||||||
|
|
||||||
/** Set Break Enable */
|
|
||||||
uint8_t SetBreak : 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Divisor Latch Access
|
|
||||||
*
|
|
||||||
* 0b = Access to Receiver buffer, Transmitter buffer & Interrupt Enable Register
|
|
||||||
* 1b = Divisor Latch Access Bit
|
|
||||||
*/
|
|
||||||
uint8_t DLAB : 1;
|
|
||||||
};
|
|
||||||
uint8_t raw;
|
|
||||||
} LCR;
|
|
||||||
|
|
||||||
/** Modem Control Register */
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/** Force Data Terminal Ready */
|
|
||||||
uint8_t DataTerminalReady : 1;
|
|
||||||
|
|
||||||
/** Force Request to Send */
|
|
||||||
uint8_t RequestToSend : 1;
|
|
||||||
|
|
||||||
/** Auxiliary Output 1 */
|
|
||||||
uint8_t Out1 : 1;
|
|
||||||
|
|
||||||
/** Auxiliary Output 2 */
|
|
||||||
uint8_t Out2 : 1;
|
|
||||||
|
|
||||||
/** Loopback Mode */
|
|
||||||
uint8_t Loopback : 1;
|
|
||||||
|
|
||||||
/** Autoflow Control Enabled (16750 only) */
|
|
||||||
uint8_t Autoflow : 1;
|
|
||||||
|
|
||||||
/** Reserved */
|
|
||||||
uint8_t __reserved : 2;
|
|
||||||
};
|
|
||||||
uint8_t raw;
|
|
||||||
} MCR;
|
|
||||||
|
|
||||||
/** Line Status Register */
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/** Data Ready */
|
|
||||||
uint8_t DataReady : 1;
|
|
||||||
|
|
||||||
/** Overrun Error */
|
|
||||||
uint8_t OverrunError : 1;
|
|
||||||
|
|
||||||
/** Parity Error */
|
|
||||||
uint8_t ParityError : 1;
|
|
||||||
|
|
||||||
/** Framing Error */
|
|
||||||
uint8_t FramingError : 1;
|
|
||||||
|
|
||||||
/** Break Interrupt */
|
|
||||||
uint8_t BreakInterrupt : 1;
|
|
||||||
|
|
||||||
/** Empty Transmitter Holding Register */
|
|
||||||
uint8_t EmptyTransmitterHolding : 1;
|
|
||||||
|
|
||||||
/** Empty Data Holding Registers */
|
|
||||||
uint8_t EmptyDataHolding : 1;
|
|
||||||
|
|
||||||
/** Error in Received FIFO */
|
|
||||||
uint8_t ErrorReceivedFIFO : 1;
|
|
||||||
};
|
|
||||||
uint8_t raw;
|
|
||||||
} LSR;
|
|
||||||
|
|
||||||
/** Modem Status Register */
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
/** Delta Clear to Send */
|
|
||||||
uint8_t DeltaClearToSend : 1;
|
|
||||||
|
|
||||||
/** Delta Data Set Ready */
|
|
||||||
uint8_t DeltaDataSetReady : 1;
|
|
||||||
|
|
||||||
/** Trailing Edge Ring Indicator */
|
|
||||||
uint8_t TrailingEdgeRingIndicator : 1;
|
|
||||||
|
|
||||||
/** Delta Data Carrier Detect */
|
|
||||||
uint8_t DeltaDataCarrierDetect : 1;
|
|
||||||
|
|
||||||
/** Clear To Send */
|
|
||||||
uint8_t ClearToSend : 1;
|
|
||||||
|
|
||||||
/** Data Set Ready */
|
|
||||||
uint8_t DataSetReady : 1;
|
|
||||||
|
|
||||||
/** Ring Indicator */
|
|
||||||
uint8_t RingIndicator : 1;
|
|
||||||
|
|
||||||
/** Carrier Detect */
|
|
||||||
uint8_t CarrierDetect : 1;
|
|
||||||
};
|
|
||||||
uint8_t raw;
|
|
||||||
} MSR;
|
|
||||||
|
|
||||||
union UARTs
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8_t com1 : 1;
|
|
||||||
uint8_t com2 : 1;
|
|
||||||
uint8_t com3 : 1;
|
|
||||||
uint8_t com4 : 1;
|
|
||||||
uint8_t com5 : 1;
|
|
||||||
uint8_t com6 : 1;
|
|
||||||
uint8_t com7 : 1;
|
|
||||||
uint8_t com8 : 1;
|
|
||||||
|
|
||||||
uint8_t lpt1 : 1;
|
|
||||||
uint8_t lpt2 : 1;
|
|
||||||
uint8_t lpt3 : 1;
|
|
||||||
|
|
||||||
uint8_t __reserved : 5;
|
|
||||||
};
|
|
||||||
uint16_t raw;
|
|
||||||
} uart;
|
|
||||||
|
|
||||||
bool IsDataReady(uint16_t Port)
|
|
||||||
{
|
|
||||||
LSR lsr;
|
|
||||||
lsr.raw = inb(Port + 5);
|
|
||||||
return lsr.DataReady;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsTransmitEmpty(uint16_t Port)
|
|
||||||
{
|
|
||||||
LSR lsr;
|
|
||||||
lsr.raw = inb(Port + 5);
|
|
||||||
return lsr.EmptyTransmitterHolding;
|
|
||||||
}
|
|
||||||
|
|
||||||
char ReadSerial(uint16_t Port)
|
|
||||||
{
|
|
||||||
while (!IsDataReady(Port))
|
|
||||||
Yield();
|
|
||||||
return inb(Port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteSerial(uint16_t Port, char Character)
|
|
||||||
{
|
|
||||||
while (!IsTransmitEmpty(Port))
|
|
||||||
Yield();
|
|
||||||
outb(Port, Character);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReportSerialReceived(uint8_t Data)
|
|
||||||
{
|
|
||||||
DebugLog("%c", Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UartCOM24(TrapFrame *)
|
|
||||||
{
|
|
||||||
LSR lsr2, lsr4;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
lsr2.raw = inb(COM2 + 5);
|
|
||||||
if (lsr2.DataReady)
|
|
||||||
ReportSerialReceived(inb(COM2));
|
|
||||||
lsr4.raw = inb(COM4 + 5);
|
|
||||||
if (lsr4.DataReady)
|
|
||||||
ReportSerialReceived(inb(COM4));
|
|
||||||
} while (lsr2.DataReady || lsr4.DataReady);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UartCOM13(TrapFrame *)
|
|
||||||
{
|
|
||||||
LSR lsr1, lsr3;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
lsr1.raw = inb(COM1 + 5);
|
|
||||||
if (lsr1.DataReady)
|
|
||||||
ReportSerialReceived(inb(COM1));
|
|
||||||
lsr3.raw = inb(COM3 + 5);
|
|
||||||
if (lsr3.DataReady)
|
|
||||||
ReportSerialReceived(inb(COM3));
|
|
||||||
} while (lsr1.DataReady || lsr3.DataReady);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InitializePort(uint16_t Port)
|
|
||||||
{
|
|
||||||
ECS;
|
|
||||||
LCR lcr = {0};
|
|
||||||
IER ier = {0};
|
|
||||||
FCR fcr = {0};
|
|
||||||
MCR mcr = {0};
|
|
||||||
|
|
||||||
outb(Port + 3, lcr.raw);
|
|
||||||
outb(Port + 1, ier.raw);
|
|
||||||
|
|
||||||
lcr.DLAB = 1;
|
|
||||||
outb(Port + 3, lcr.raw);
|
|
||||||
|
|
||||||
outb(Port + 0, RATE_115200_LO);
|
|
||||||
outb(Port + 1, RATE_115200_HI);
|
|
||||||
|
|
||||||
lcr.DLAB = 0;
|
|
||||||
lcr.WordLength = 0b11;
|
|
||||||
outb(Port + 3, lcr.raw);
|
|
||||||
|
|
||||||
fcr.FIFO = 1;
|
|
||||||
fcr.ClearRX = 1;
|
|
||||||
fcr.ClearTX = 1;
|
|
||||||
fcr.TriggerLevel = 0b11;
|
|
||||||
outb(Port + 2, fcr.raw);
|
|
||||||
|
|
||||||
mcr.DataTerminalReady = 1;
|
|
||||||
mcr.RequestToSend = 1;
|
|
||||||
mcr.Out2 = 1;
|
|
||||||
mcr.Loopback = 1;
|
|
||||||
outb(Port + 4, mcr.raw);
|
|
||||||
|
|
||||||
/* Test the serial port */
|
|
||||||
outb(Port + 0, 0x48);
|
|
||||||
uint8_t result = inb(Port + 0);
|
|
||||||
if (result != 0x48)
|
|
||||||
{
|
|
||||||
/* FIXME: DETECT BAUD RATE
|
|
||||||
Do multiple test to check if the output is garbage.
|
|
||||||
If so, reduce the baud rate until it works. */
|
|
||||||
|
|
||||||
LCS;
|
|
||||||
KernelPrint("Port %#X test failed!", Port);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set normal operation mode */
|
|
||||||
mcr.DataTerminalReady = 1;
|
|
||||||
mcr.RequestToSend = 1;
|
|
||||||
mcr.Out1 = 1;
|
|
||||||
mcr.Out2 = 1;
|
|
||||||
mcr.Loopback = 0;
|
|
||||||
outb(Port + 4, mcr.raw);
|
|
||||||
|
|
||||||
/* Enable interrupts on receive */
|
|
||||||
ier.InterruptOnReceive = 1;
|
|
||||||
outb(Port + 1, ier.raw);
|
|
||||||
RegisterInterruptHandler(3, UartCOM24);
|
|
||||||
RegisterInterruptHandler(4, UartCOM13);
|
|
||||||
|
|
||||||
LCS;
|
|
||||||
KernelPrint("Port %#X initialized", Port);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DetectUART()
|
|
||||||
{
|
|
||||||
uart.com1 = inb(COM1) != 0xFF ? true : false;
|
|
||||||
uart.com2 = inb(COM2) != 0xFF ? true : false;
|
|
||||||
uart.com3 = inb(COM3) != 0xFF ? true : false;
|
|
||||||
uart.com4 = inb(COM4) != 0xFF ? true : false;
|
|
||||||
uart.com5 = inb(COM5) != 0xFF ? true : false;
|
|
||||||
uart.com6 = inb(COM6) != 0xFF ? true : false;
|
|
||||||
uart.com7 = inb(COM7) != 0xFF ? true : false;
|
|
||||||
uart.com8 = inb(COM8) != 0xFF ? true : false;
|
|
||||||
|
|
||||||
uart.lpt1 = inb(LPT1) != 0xFF ? true : false;
|
|
||||||
uart.lpt2 = inb(LPT2) != 0xFF ? true : false;
|
|
||||||
uart.lpt3 = inb(LPT3) != 0xFF ? true : false;
|
|
||||||
|
|
||||||
if (uart.com1 == true)
|
|
||||||
if (InitializePort(COM1) == false)
|
|
||||||
uart.com1 = false;
|
|
||||||
|
|
||||||
if (uart.com2 == true)
|
|
||||||
if (InitializePort(COM2) == false)
|
|
||||||
uart.com1 = false;
|
|
||||||
|
|
||||||
if (uart.com3 == true)
|
|
||||||
if (InitializePort(COM3) == false)
|
|
||||||
uart.com1 = false;
|
|
||||||
|
|
||||||
if (uart.com4 == true)
|
|
||||||
if (InitializePort(COM4) == false)
|
|
||||||
uart.com1 = false;
|
|
||||||
|
|
||||||
if (uart.com5 == true)
|
|
||||||
if (InitializePort(COM5) == false)
|
|
||||||
uart.com1 = false;
|
|
||||||
|
|
||||||
if (uart.com6 == true)
|
|
||||||
if (InitializePort(COM6) == false)
|
|
||||||
uart.com1 = false;
|
|
||||||
|
|
||||||
if (uart.com7 == true)
|
|
||||||
if (InitializePort(COM7) == false)
|
|
||||||
uart.com1 = false;
|
|
||||||
|
|
||||||
if (uart.com8 == true)
|
|
||||||
if (InitializePort(COM8) == false)
|
|
||||||
uart.com1 = false;
|
|
||||||
|
|
||||||
if (uart.lpt1 == true)
|
|
||||||
KernelPrint("LPT1 is present");
|
|
||||||
|
|
||||||
if (uart.lpt2 == true)
|
|
||||||
KernelPrint("LPT2 is present");
|
|
||||||
|
|
||||||
if (uart.lpt3 == true)
|
|
||||||
KernelPrint("LPT3 is present");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static int once = 0;
|
|
||||||
// static uint8_t com4 = 0xFF;
|
|
||||||
// if (!once++)
|
|
||||||
// com4 = inb(0x2E8);
|
|
||||||
// if (com4 == 0xFF)
|
|
||||||
// CPU::Halt(true);
|
|
||||||
// char UserInputBuffer[256]{'\0'};
|
|
||||||
// int BackSpaceLimit = 0;
|
|
||||||
// while (true)
|
|
||||||
// {
|
|
||||||
// while ((inb(0x2E8 + 5) & 1) == 0)
|
|
||||||
// CPU::Pause();
|
|
||||||
// char key = inb(0x2E8);
|
|
||||||
// // debug("key: %d", key);
|
|
||||||
// if (key == '\x7f') /* Backspace (DEL) */
|
|
||||||
// {
|
|
||||||
// if (BackSpaceLimit <= 0)
|
|
||||||
// continue;
|
|
||||||
// char keyBuf[5] = {'\b', '\x1b', '[', 'K', '\0'};
|
|
||||||
// ExPrint(keyBuf);
|
|
||||||
// backspace(UserInputBuffer);
|
|
||||||
// BackSpaceLimit--;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// else if (key == '\x0d') /* Enter (CR) */
|
|
||||||
// {
|
|
||||||
// UserInput(UserInputBuffer);
|
|
||||||
// BackSpaceLimit = 0;
|
|
||||||
// UserInputBuffer[0] = '\0';
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// else if (key == '\x1b') /* Escape */
|
|
||||||
// {
|
|
||||||
// char tmp[16]{'\0'};
|
|
||||||
// append(tmp, key);
|
|
||||||
// while ((inb(0x2E8 + 5) & 1) == 0)
|
|
||||||
// CPU::Pause();
|
|
||||||
// char key = inb(0x2E8);
|
|
||||||
// append(tmp, key);
|
|
||||||
// if (key == '[')
|
|
||||||
// {
|
|
||||||
// // 27 91
|
|
||||||
// // < 68
|
|
||||||
// // > 67
|
|
||||||
// // down 66
|
|
||||||
// // up 65
|
|
||||||
// while ((inb(0x2E8 + 5) & 1) == 0)
|
|
||||||
// CPU::Pause();
|
|
||||||
// key = inb(0x2E8);
|
|
||||||
// append(tmp, key);
|
|
||||||
// switch (key)
|
|
||||||
// {
|
|
||||||
// case 'A':
|
|
||||||
// key = KEY_D_UP;
|
|
||||||
// break;
|
|
||||||
// case 'B':
|
|
||||||
// key = KEY_D_DOWN;
|
|
||||||
// break;
|
|
||||||
// case 'C':
|
|
||||||
// key = KEY_D_RIGHT;
|
|
||||||
// break;
|
|
||||||
// case 'D':
|
|
||||||
// key = KEY_D_LEFT;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// {
|
|
||||||
// for (size_t i = 0; i < strlen(tmp); i++)
|
|
||||||
// {
|
|
||||||
// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
|
|
||||||
// continue;
|
|
||||||
// append(UserInputBuffer, tmp[i]);
|
|
||||||
// BackSpaceLimit++;
|
|
||||||
// char keyBuf[2] = {(char)tmp[i], '\0'};
|
|
||||||
// ExPrint(keyBuf);
|
|
||||||
// }
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ArrowInput(key);
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
|
|
||||||
// continue;
|
|
||||||
// append(UserInputBuffer, key);
|
|
||||||
// BackSpaceLimit++;
|
|
||||||
// char keyBuf[2] = {(char)key, '\0'};
|
|
||||||
// ExPrint(keyBuf);
|
|
||||||
// }
|
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
@ -1,897 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <driver.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fs.h>
|
|
||||||
#include <input.h>
|
|
||||||
#include <regs.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <aip.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
enum RPCMessages
|
|
||||||
{
|
|
||||||
MSG_OPEN,
|
|
||||||
MSG_SENDSIZE,
|
|
||||||
MSG_SENDPAYLOAD,
|
|
||||||
MSG_RECVSIZE,
|
|
||||||
MSG_RECVPAYLOAD,
|
|
||||||
MSG_RECVSTATUS,
|
|
||||||
MSG_CLOSE,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RPCStatus
|
|
||||||
{
|
|
||||||
STATUS_SUCCESS = 0x1,
|
|
||||||
STATUS_DORECV = 0x2,
|
|
||||||
STATUS_CPT = 0x10,
|
|
||||||
STATUS_HB = 0x80,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t ax;
|
|
||||||
uint32_t magic;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t bx;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t cx;
|
|
||||||
uint16_t command;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t dx;
|
|
||||||
uint16_t port;
|
|
||||||
};
|
|
||||||
uint32_t si;
|
|
||||||
uint32_t di;
|
|
||||||
} VMwareCommand;
|
|
||||||
|
|
||||||
#define VMWARE_MAGIC 0x564D5868
|
|
||||||
|
|
||||||
#define VMWARE_PORT 0x5658
|
|
||||||
#define VMWARE_PORTHB 0x5659
|
|
||||||
|
|
||||||
#define VMWARE_HYPERVISOR_HB 0x00000000
|
|
||||||
#define VMWARE_HYPERVISOR_OUT 0x00000001
|
|
||||||
|
|
||||||
#define CMD_GETVERSION 0xA
|
|
||||||
#define CMD_MESSAGE 0x1E
|
|
||||||
#define CMD_ABSPOINTER_DATA 0x27
|
|
||||||
#define CMD_ABSPOINTER_STATUS 0x28
|
|
||||||
#define CMD_ABSPOINTER_COMMAND 0x29
|
|
||||||
|
|
||||||
#define ABSPOINTER_ENABLE 0x45414552
|
|
||||||
#define ABSPOINTER_RELATIVE 0xF5
|
|
||||||
#define ABSPOINTER_ABSOLUTE 0x53424152
|
|
||||||
|
|
||||||
#define MESSAGE_RPCI 0x49435052
|
|
||||||
#define MESSAGE_TCLO 0x4f4c4354
|
|
||||||
|
|
||||||
#define FLAG_COOKIE 0x80000000
|
|
||||||
|
|
||||||
#define ToMsg(x) ((x) << 16 | CMD_MESSAGE)
|
|
||||||
#define HighWord(x) ((x & 0xFFFF0000) >> 16)
|
|
||||||
|
|
||||||
#define MESSAGE_HB_MSG 0
|
|
||||||
|
|
||||||
#define MESSAGE_OPEN_CHANNEL ToMsg(MSG_OPEN)
|
|
||||||
#define MESSAGE_CLOSE_CHANNEL ToMsg(MSG_CLOSE)
|
|
||||||
|
|
||||||
#define MESSAGE_SEND_SIZE ToMsg(MSG_SENDSIZE)
|
|
||||||
#define MESSAGE_SEND_PAYLOAD ToMsg(MSG_SENDPAYLOAD)
|
|
||||||
|
|
||||||
#define MESSAGE_RECV_SIZE ToMsg(MSG_RECVSIZE)
|
|
||||||
#define MESSAGE_RECV_PAYLOAD ToMsg(MSG_RECVPAYLOAD)
|
|
||||||
#define MESSAGE_RECV_STATUS ToMsg(MSG_RECVSTATUS)
|
|
||||||
|
|
||||||
#if defined(__amd64__)
|
|
||||||
|
|
||||||
#define VM_PORT(cmd, in_ebx, isi, idi, \
|
|
||||||
flags, magic, \
|
|
||||||
ax, bx, cx, dx, si, di) \
|
|
||||||
__asm__ __volatile__("movw $0x5658, %%dx\n" \
|
|
||||||
"inl %%dx, %%eax\n" \
|
|
||||||
: "=a"(ax), \
|
|
||||||
"=b"(bx), \
|
|
||||||
"=c"(cx), \
|
|
||||||
"=d"(dx), \
|
|
||||||
"=S"(si), \
|
|
||||||
"=D"(di) \
|
|
||||||
: "a"(magic), \
|
|
||||||
"b"(in_ebx), \
|
|
||||||
"c"(cmd), \
|
|
||||||
"d"(flags), \
|
|
||||||
"S"(isi), \
|
|
||||||
"D"(idi) : "memory")
|
|
||||||
|
|
||||||
#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
|
|
||||||
flags, magic, bp, \
|
|
||||||
ax, bx, cx, dx, si, di) \
|
|
||||||
__asm__ __volatile__("push %%rbp\n" \
|
|
||||||
"mov %12, %%rbp\n" \
|
|
||||||
"movw $0x5659, %%dx\n" \
|
|
||||||
"rep outsb\n" \
|
|
||||||
"pop %%rbp\n" \
|
|
||||||
: "=a"(ax), \
|
|
||||||
"=b"(bx), \
|
|
||||||
"=c"(cx), \
|
|
||||||
"=d"(dx), \
|
|
||||||
"=S"(si), \
|
|
||||||
"=D"(di) \
|
|
||||||
: "a"(magic), \
|
|
||||||
"b"(cmd), \
|
|
||||||
"c"(in_ecx), \
|
|
||||||
"d"(flags), \
|
|
||||||
"S"(isi), \
|
|
||||||
"D"(idi), \
|
|
||||||
"r"(bp) : "memory", "cc")
|
|
||||||
|
|
||||||
#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
|
|
||||||
flags, magic, bp, \
|
|
||||||
ax, bx, cx, dx, si, di) \
|
|
||||||
__asm__ __volatile__("push %%rbp\n" \
|
|
||||||
"mov %12, %%rbp\n" \
|
|
||||||
"movw $0x5659, %%dx\n" \
|
|
||||||
"rep insb\n" \
|
|
||||||
"pop %%rbp\n" \
|
|
||||||
: "=a"(ax), \
|
|
||||||
"=b"(bx), \
|
|
||||||
"=c"(cx), \
|
|
||||||
"=d"(dx), \
|
|
||||||
"=S"(si), \
|
|
||||||
"=D"(di) \
|
|
||||||
: "a"(magic), \
|
|
||||||
"b"(cmd), \
|
|
||||||
"c"(in_ecx), \
|
|
||||||
"d"(flags), \
|
|
||||||
"S"(isi), \
|
|
||||||
"D"(idi), \
|
|
||||||
"r"(bp) : "memory", "cc")
|
|
||||||
|
|
||||||
#elif defined(__i386__)
|
|
||||||
|
|
||||||
#define VM_PORT(cmd, in_ebx, isi, idi, \
|
|
||||||
flags, magic, \
|
|
||||||
ax, bx, cx, dx, si, di)
|
|
||||||
|
|
||||||
#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
|
|
||||||
flags, \
|
|
||||||
magic, bp, ax, \
|
|
||||||
bx, cx, dx, si, di)
|
|
||||||
|
|
||||||
#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
|
|
||||||
flags, magic, bp, \
|
|
||||||
ax, bx, cx, dx, si, di)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* TODO:
|
|
||||||
- use vmcall or vmmcall instead of "out" and "in" if available
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int TCLOChannel;
|
|
||||||
uint16_t ChannelID;
|
|
||||||
uint32_t CookieHigh;
|
|
||||||
uint32_t CookieLow;
|
|
||||||
} ToolboxContext;
|
|
||||||
|
|
||||||
dev_t MouseDevID = -1;
|
|
||||||
|
|
||||||
int __strcmp(const char *l, const char *r)
|
|
||||||
{
|
|
||||||
for (; *l == *r && *l; l++, r++)
|
|
||||||
;
|
|
||||||
|
|
||||||
return *(unsigned char *)l - *(unsigned char *)r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __cpuid(uint32_t Function,
|
|
||||||
uint32_t *eax, uint32_t *ebx,
|
|
||||||
uint32_t *ecx, uint32_t *edx)
|
|
||||||
{
|
|
||||||
asmv("cpuid"
|
|
||||||
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
|
|
||||||
: "a"(Function));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool __CheckHypervisorBit()
|
|
||||||
{
|
|
||||||
uint32_t eax, ebx, ecx, edx;
|
|
||||||
__cpuid(0x1, &eax, &ebx, &ecx, &edx);
|
|
||||||
if (!(ecx & (1 << 31)))
|
|
||||||
return false; /* Hypervisor not detected */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool __VMwareBackdoorHypervisors()
|
|
||||||
{
|
|
||||||
const char hv[13] = {0};
|
|
||||||
uint32_t eax, ebx, ecx, edx;
|
|
||||||
__cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
|
|
||||||
|
|
||||||
*(uint32_t *)hv = ebx;
|
|
||||||
*(uint32_t *)(hv + 4) = ecx;
|
|
||||||
*(uint32_t *)(hv + 8) = edx;
|
|
||||||
|
|
||||||
if (__strcmp(hv, "VMwareVMware") != 0 &&
|
|
||||||
__strcmp(hv, "KVMKVMKVM") != 0 &&
|
|
||||||
__strcmp(hv, "TCGTCGTCGTCG") != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsVMwareBackdoorAvailable()
|
|
||||||
{
|
|
||||||
if (!__CheckHypervisorBit())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!__VMwareBackdoorHypervisors())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t ax;
|
|
||||||
uint32_t magic;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t bx;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t cx;
|
|
||||||
uint16_t command;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t dx;
|
|
||||||
uint16_t port;
|
|
||||||
};
|
|
||||||
uint32_t si;
|
|
||||||
uint32_t di;
|
|
||||||
} cmd;
|
|
||||||
|
|
||||||
cmd.si = cmd.di = 0;
|
|
||||||
cmd.bx = ~0x564D5868;
|
|
||||||
cmd.command = 0xA;
|
|
||||||
cmd.magic = 0x564D5868;
|
|
||||||
cmd.port = 0x5658;
|
|
||||||
|
|
||||||
asmv("in %%dx, %0"
|
|
||||||
: "+a"(cmd.ax), "+b"(cmd.bx),
|
|
||||||
"+c"(cmd.cx), "+d"(cmd.dx),
|
|
||||||
"+S"(cmd.si), "+D"(cmd.di));
|
|
||||||
|
|
||||||
if (cmd.bx != 0x564D5868 ||
|
|
||||||
cmd.ax == 0xFFFFFFFF)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int OpenMessageChannel(ToolboxContext *ctx, uint32_t Protocol)
|
|
||||||
{
|
|
||||||
uintptr_t ax, bx, cx, dx, si = 0, di = 0;
|
|
||||||
|
|
||||||
VM_PORT(MESSAGE_OPEN_CHANNEL,
|
|
||||||
(Protocol | FLAG_COOKIE), si, di,
|
|
||||||
0, VMWARE_MAGIC,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
|
|
||||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
|
||||||
{
|
|
||||||
KernelLog("Failed to open message channel %#lx", Protocol);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugLog("Opened message channel %d (Protocol: %#lx)",
|
|
||||||
HighWord(dx), Protocol);
|
|
||||||
ctx->ChannelID = (uint16_t)HighWord(dx);
|
|
||||||
ctx->CookieHigh = si;
|
|
||||||
ctx->CookieLow = di;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MessageClose(ToolboxContext *ctx)
|
|
||||||
{
|
|
||||||
uintptr_t ax, bx, cx, dx,
|
|
||||||
si = ctx->CookieHigh,
|
|
||||||
di = ctx->CookieLow;
|
|
||||||
|
|
||||||
VM_PORT(MESSAGE_CLOSE_CHANNEL,
|
|
||||||
0, si, di,
|
|
||||||
ctx->ChannelID << 16,
|
|
||||||
VMWARE_MAGIC,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
|
|
||||||
DebugLog("Closed message channel %d", ctx->ChannelID);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uintptr_t MessageSendHB(ToolboxContext *ctx,
|
|
||||||
const char *Message)
|
|
||||||
{
|
|
||||||
uintptr_t ax, bx, cx, dx,
|
|
||||||
si = (uintptr_t)Message,
|
|
||||||
di = ctx->CookieLow,
|
|
||||||
bp = ctx->CookieHigh;
|
|
||||||
|
|
||||||
uint32_t ChannelID = ctx->ChannelID << 16;
|
|
||||||
size_t Size = StringLength(Message);
|
|
||||||
|
|
||||||
VM_PORT_HB_OUT((STATUS_SUCCESS << 16) | MESSAGE_HB_MSG,
|
|
||||||
Size, si, di,
|
|
||||||
VMWARE_HYPERVISOR_HB | ChannelID | VMWARE_HYPERVISOR_OUT,
|
|
||||||
VMWARE_MAGIC, bp,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
|
|
||||||
return bx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uintptr_t MessageSendLB(ToolboxContext *ctx,
|
|
||||||
const char *Message)
|
|
||||||
{
|
|
||||||
uintptr_t ax, bx,
|
|
||||||
cx = STATUS_SUCCESS << 16,
|
|
||||||
dx, si, di;
|
|
||||||
|
|
||||||
size_t Size = StringLength(Message);
|
|
||||||
while (Size &&
|
|
||||||
(HighWord(cx) & STATUS_SUCCESS))
|
|
||||||
{
|
|
||||||
uint32_t TotalBytes = MIN((uint32_t)Size, (uint32_t)4);
|
|
||||||
uint32_t Word = 0;
|
|
||||||
MemoryCopy(&Word, Message, TotalBytes);
|
|
||||||
Message += TotalBytes;
|
|
||||||
|
|
||||||
si = ctx->CookieHigh;
|
|
||||||
di = ctx->CookieLow;
|
|
||||||
|
|
||||||
VM_PORT(MESSAGE_SEND_PAYLOAD,
|
|
||||||
Word, si, di,
|
|
||||||
ctx->ChannelID << 16,
|
|
||||||
VMWARE_MAGIC,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uintptr_t MessageReceiveHB(ToolboxContext *ctx,
|
|
||||||
char *Buffer,
|
|
||||||
size_t BufferSize)
|
|
||||||
{
|
|
||||||
uintptr_t ax, bx, cx, dx,
|
|
||||||
si = ctx->CookieHigh,
|
|
||||||
di = (uintptr_t)Buffer,
|
|
||||||
bp = ctx->CookieLow;
|
|
||||||
|
|
||||||
uint32_t ChannelID = ctx->ChannelID << 16;
|
|
||||||
|
|
||||||
VM_PORT_HB_IN((STATUS_SUCCESS << 16) | MESSAGE_HB_MSG,
|
|
||||||
BufferSize, si, di,
|
|
||||||
VMWARE_HYPERVISOR_HB | ChannelID | VMWARE_HYPERVISOR_OUT,
|
|
||||||
VMWARE_MAGIC, bp,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
|
|
||||||
return bx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uintptr_t MessageReceiveLB(ToolboxContext *ctx,
|
|
||||||
char *Buffer,
|
|
||||||
size_t BufferSize)
|
|
||||||
{
|
|
||||||
uintptr_t ax, bx,
|
|
||||||
cx = STATUS_SUCCESS << 16,
|
|
||||||
dx, si, di;
|
|
||||||
|
|
||||||
while (BufferSize)
|
|
||||||
{
|
|
||||||
uint32_t TotalBytes = MIN((uint32_t)BufferSize, (uint32_t)4);
|
|
||||||
|
|
||||||
si = ctx->CookieHigh;
|
|
||||||
di = ctx->CookieLow;
|
|
||||||
|
|
||||||
VM_PORT(MESSAGE_RECV_PAYLOAD,
|
|
||||||
STATUS_SUCCESS, si, di,
|
|
||||||
ctx->ChannelID << 16,
|
|
||||||
VMWARE_MAGIC,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
|
|
||||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
MemoryCopy(Buffer, &bx, TotalBytes);
|
|
||||||
Buffer += TotalBytes;
|
|
||||||
BufferSize -= TotalBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int MessageSend(ToolboxContext *ctx,
|
|
||||||
const char *Message)
|
|
||||||
{
|
|
||||||
uintptr_t ax, bx, cx, dx, si, di;
|
|
||||||
size_t Size = StringLength(Message);
|
|
||||||
int Retries = 0;
|
|
||||||
|
|
||||||
while (Retries < 2)
|
|
||||||
{
|
|
||||||
Retries++;
|
|
||||||
si = ctx->CookieHigh;
|
|
||||||
di = ctx->CookieLow;
|
|
||||||
|
|
||||||
VM_PORT(MESSAGE_SEND_SIZE,
|
|
||||||
Size, si, di,
|
|
||||||
ctx->ChannelID << 16,
|
|
||||||
VMWARE_MAGIC,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
|
|
||||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
|
||||||
{
|
|
||||||
KernelLog("Failed to send message size for \"%s\": %d",
|
|
||||||
Message, cx);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HighBand = (HighWord(cx) & STATUS_HB) != 0;
|
|
||||||
if (HighBand)
|
|
||||||
bx = MessageSendHB(ctx, Message);
|
|
||||||
else
|
|
||||||
bx = MessageSendLB(ctx, Message);
|
|
||||||
|
|
||||||
int status = HighWord(bx);
|
|
||||||
|
|
||||||
if ((status & STATUS_SUCCESS) != 0)
|
|
||||||
{
|
|
||||||
DebugLog("Message \"%s\" sent", Message);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if ((status & STATUS_CPT) == 0)
|
|
||||||
{
|
|
||||||
KernelLog("Checkpoint occurred for message \"%s\"", Message);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelLog("Failed to send message \"%s\": %#lx", Message, bx);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int MessageReceive(ToolboxContext *ctx,
|
|
||||||
char **Buffer,
|
|
||||||
size_t *BufferSize)
|
|
||||||
{
|
|
||||||
uintptr_t ax, bx, cx, dx, si, di;
|
|
||||||
int Retries = 0;
|
|
||||||
|
|
||||||
*Buffer = NULL;
|
|
||||||
*BufferSize = 0;
|
|
||||||
|
|
||||||
char *ReplyBuf = NULL;
|
|
||||||
size_t ReplyBufPages = 0;
|
|
||||||
size_t ReplySize = 0;
|
|
||||||
while (Retries < 2)
|
|
||||||
{
|
|
||||||
Retries++;
|
|
||||||
si = ctx->CookieHigh;
|
|
||||||
di = ctx->CookieLow;
|
|
||||||
|
|
||||||
VM_PORT(MESSAGE_RECV_SIZE,
|
|
||||||
0, si, di,
|
|
||||||
ctx->ChannelID << 16,
|
|
||||||
VMWARE_MAGIC,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
|
|
||||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
|
||||||
{
|
|
||||||
KernelLog("Failed to receive message size: %d", cx);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
else if ((HighWord(cx) & STATUS_DORECV) == 0)
|
|
||||||
{
|
|
||||||
DebugLog("No message to receive");
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReplySize = bx;
|
|
||||||
|
|
||||||
if (ReplyBuf != NULL)
|
|
||||||
FreeMemory(ReplyBuf, ReplyBufPages);
|
|
||||||
ReplyBufPages = ReplySize / 0x1000 + 1;
|
|
||||||
ReplyBuf = AllocateMemory(ReplyBufPages);
|
|
||||||
|
|
||||||
bool HighBand = (HighWord(cx) & STATUS_HB) != 0;
|
|
||||||
if (HighBand)
|
|
||||||
bx = MessageReceiveHB(ctx, ReplyBuf, ReplySize);
|
|
||||||
else
|
|
||||||
bx = MessageReceiveLB(ctx, ReplyBuf, ReplySize);
|
|
||||||
|
|
||||||
if ((HighWord(bx) & STATUS_SUCCESS) == 0)
|
|
||||||
{
|
|
||||||
if ((HighWord(bx) & STATUS_CPT) == 0)
|
|
||||||
{
|
|
||||||
KernelLog("Checkpoint occurred for message payload");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelLog("Failed to receive message payload: %d", HighWord(bx));
|
|
||||||
FreeMemory(ReplyBuf, ReplyBufPages);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReplyBuf[ReplySize] = '\0';
|
|
||||||
|
|
||||||
si = ctx->CookieHigh;
|
|
||||||
di = ctx->CookieLow;
|
|
||||||
|
|
||||||
VM_PORT(MESSAGE_RECV_STATUS,
|
|
||||||
STATUS_SUCCESS, si, di,
|
|
||||||
ctx->ChannelID << 16,
|
|
||||||
VMWARE_MAGIC,
|
|
||||||
ax, bx, cx, dx, si, di);
|
|
||||||
|
|
||||||
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
|
||||||
{
|
|
||||||
if ((HighWord(cx) & STATUS_CPT) == 0)
|
|
||||||
{
|
|
||||||
KernelLog("Retrying message receive");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelLog("Failed to receive message status: %d", HighWord(cx));
|
|
||||||
FreeMemory(ReplyBuf, ReplyBufPages);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReplyBuf == NULL)
|
|
||||||
{
|
|
||||||
KernelLog("Failed to receive message");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*Buffer = ReplyBuf;
|
|
||||||
*BufferSize = ReplySize;
|
|
||||||
DebugLog("Received message \"%s\"", ReplyBuf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int SendRPCI(ToolboxContext *, const char *Request)
|
|
||||||
{
|
|
||||||
ToolboxContext rpci_ctx = {0};
|
|
||||||
int status = OpenMessageChannel(&rpci_ctx, MESSAGE_RPCI);
|
|
||||||
if (status < 0)
|
|
||||||
{
|
|
||||||
KernelLog("Failed to open RPCI channel: %d", status);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = MessageSend(&rpci_ctx, Request);
|
|
||||||
if (status < 0)
|
|
||||||
{
|
|
||||||
KernelLog("Failed to send RPCI request: %d", status);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageClose(&rpci_ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MsgEqual(const char *haystack, const char *needle)
|
|
||||||
{
|
|
||||||
return strstr(haystack, needle) == haystack;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int DisplayGetSize(ToolboxContext *ctx)
|
|
||||||
{
|
|
||||||
if (ctx->TCLOChannel != -1)
|
|
||||||
MessageClose(ctx);
|
|
||||||
OpenMessageChannel(ctx, MESSAGE_TCLO);
|
|
||||||
|
|
||||||
char EmptyBuffer[256] = {'\0'};
|
|
||||||
MessageSend(ctx, EmptyBuffer);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
/* FIXME: buf memory leak */
|
|
||||||
char *buf;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
int status = MessageReceive(ctx, &buf, &len);
|
|
||||||
if (status == -EAGAIN)
|
|
||||||
{
|
|
||||||
Sleep(1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (status < 0)
|
|
||||||
{
|
|
||||||
KernelLog("Failed to receive message");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[StringLength(buf)] = '\0';
|
|
||||||
if (MsgEqual(buf, "reset"))
|
|
||||||
{
|
|
||||||
if (MessageSend(ctx, "OK ATR toolbox") < 0)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if (MsgEqual(buf, "ping"))
|
|
||||||
{
|
|
||||||
if (MessageSend(ctx, "OK ") < 0)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if (MsgEqual(buf, "Capabilities_Register"))
|
|
||||||
{
|
|
||||||
SendRPCI(ctx, "tools.capability.resolution_set 1");
|
|
||||||
SendRPCI(ctx, "tools.capability.resolution_server toolbox 1");
|
|
||||||
SendRPCI(ctx, "tools.capability.display_topology_set 1");
|
|
||||||
SendRPCI(ctx, "tools.capability.color_depth_set 1");
|
|
||||||
SendRPCI(ctx, "tools.capability.resolution_min 0 0");
|
|
||||||
SendRPCI(ctx, "tools.capability.unity 1");
|
|
||||||
|
|
||||||
if (MessageSend(ctx, "OK ") < 0)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if (MsgEqual(buf, "Resolution_Set"))
|
|
||||||
{
|
|
||||||
DebugLog("%s", buf);
|
|
||||||
if (MessageSend(ctx, "OK ") < 0)
|
|
||||||
return 1;
|
|
||||||
MessageClose(ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (MessageSend(ctx, "ERROR Unknown command") < 0)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t dst_id = -1;
|
|
||||||
pid_t dst_pid = -1;
|
|
||||||
ToolboxContext *tb_ctx = NULL;
|
|
||||||
void DisplayScaleThread()
|
|
||||||
{
|
|
||||||
/* sizeof ToolboxContext */
|
|
||||||
tb_ctx = AllocateMemory(1);
|
|
||||||
Sleep(2000);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (DisplayGetSize(tb_ctx) != 0)
|
|
||||||
KernelLog("Failed to scale display");
|
|
||||||
Sleep(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandSend(VMwareCommand *cmd)
|
|
||||||
{
|
|
||||||
cmd->magic = VMWARE_MAGIC;
|
|
||||||
cmd->port = VMWARE_PORT;
|
|
||||||
asm volatile("in %%dx, %0"
|
|
||||||
: "+a"(cmd->ax), "+b"(cmd->bx),
|
|
||||||
"+c"(cmd->cx), "+d"(cmd->dx),
|
|
||||||
"+S"(cmd->si), "+D"(cmd->di));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Absolute()
|
|
||||||
{
|
|
||||||
VMwareCommand cmd = {0};
|
|
||||||
|
|
||||||
/* Enable */
|
|
||||||
cmd.bx = ABSPOINTER_ENABLE;
|
|
||||||
cmd.command = CMD_ABSPOINTER_COMMAND;
|
|
||||||
CommandSend(&cmd);
|
|
||||||
|
|
||||||
/* Status */
|
|
||||||
cmd.bx = 0;
|
|
||||||
cmd.command = CMD_ABSPOINTER_STATUS;
|
|
||||||
CommandSend(&cmd);
|
|
||||||
|
|
||||||
/* Read data (1) */
|
|
||||||
cmd.bx = 1;
|
|
||||||
cmd.command = CMD_ABSPOINTER_DATA;
|
|
||||||
CommandSend(&cmd);
|
|
||||||
|
|
||||||
/* Enable absolute */
|
|
||||||
cmd.bx = ABSPOINTER_ABSOLUTE;
|
|
||||||
cmd.command = CMD_ABSPOINTER_COMMAND;
|
|
||||||
CommandSend(&cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Relative()
|
|
||||||
{
|
|
||||||
VMwareCommand cmd = {0};
|
|
||||||
cmd.bx = ABSPOINTER_RELATIVE;
|
|
||||||
cmd.command = CMD_ABSPOINTER_COMMAND;
|
|
||||||
CommandSend(&cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
InputReport ir = {0};
|
|
||||||
void InterruptHandler(TrapFrame *)
|
|
||||||
{
|
|
||||||
uint8_t Data = inb(0x60);
|
|
||||||
(void)Data;
|
|
||||||
|
|
||||||
VMwareCommand cmd = {0};
|
|
||||||
cmd.bx = 0;
|
|
||||||
cmd.command = CMD_ABSPOINTER_STATUS;
|
|
||||||
CommandSend(&cmd);
|
|
||||||
|
|
||||||
if (cmd.ax == 0xFFFF0000)
|
|
||||||
{
|
|
||||||
KernelLog("VMware mouse is not connected?");
|
|
||||||
Relative();
|
|
||||||
Absolute();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cmd.ax & 0xFFFF) < 4)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cmd.bx = 4;
|
|
||||||
cmd.command = CMD_ABSPOINTER_DATA;
|
|
||||||
CommandSend(&cmd);
|
|
||||||
|
|
||||||
int Buttons = (cmd.ax & 0xFFFF);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How should I handle this?
|
|
||||||
* (cmd.[bx,cx] * Width) / 0xFFFF
|
|
||||||
* Maybe TODO: Width and Height API?
|
|
||||||
*/
|
|
||||||
uintptr_t AbsoluteX = cmd.bx;
|
|
||||||
uintptr_t AbsoluteY = cmd.cx;
|
|
||||||
|
|
||||||
ir.Type = INPUT_TYPE_MOUSE;
|
|
||||||
ir.Device = MouseDevID;
|
|
||||||
ir.Mouse.X = AbsoluteX;
|
|
||||||
ir.Mouse.Y = AbsoluteY;
|
|
||||||
ir.Mouse.Z = (int8_t)cmd.dx;
|
|
||||||
ir.Mouse.Absolute = 1;
|
|
||||||
ir.Mouse.LeftButton = Buttons & 0x20;
|
|
||||||
ir.Mouse.RightButton = Buttons & 0x10;
|
|
||||||
ir.Mouse.MiddleButton = Buttons & 0x08;
|
|
||||||
// ir.Mouse.Button4 = 0x0;
|
|
||||||
// ir.Mouse.Button5 = 0x0;
|
|
||||||
// ir.Mouse.Button6 = 0x0;
|
|
||||||
// ir.Mouse.Button7 = 0x0;
|
|
||||||
// ir.Mouse.Button8 = 0x0;
|
|
||||||
ReportInputEvent(&ir);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __fs_Ioctl(struct Inode *, unsigned long Request, void *)
|
|
||||||
{
|
|
||||||
switch (Request)
|
|
||||||
{
|
|
||||||
case 0x1:
|
|
||||||
Relative();
|
|
||||||
break;
|
|
||||||
case 0x2:
|
|
||||||
Absolute();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct InodeOperations MouseOps = {
|
|
||||||
.Ioctl = __fs_Ioctl,
|
|
||||||
};
|
|
||||||
|
|
||||||
bool ToolboxSupported = false;
|
|
||||||
int DriverEntry()
|
|
||||||
{
|
|
||||||
ToolboxContext tb_ctx = {0};
|
|
||||||
/* Test if it's supported */
|
|
||||||
int status = OpenMessageChannel(&tb_ctx, MESSAGE_TCLO);
|
|
||||||
if (status == 0)
|
|
||||||
{
|
|
||||||
ToolboxSupported = true;
|
|
||||||
MessageClose(&tb_ctx);
|
|
||||||
dst_id = CreateKernelThread(0, "VMware Display Scale",
|
|
||||||
(void *)DisplayScaleThread, NULL);
|
|
||||||
dst_pid = GetCurrentProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
|
|
||||||
PS2WriteCommand(PS2_CMD_READ_CONFIG);
|
|
||||||
PS2_CONFIGURATION config = {.Raw = PS2ReadData()};
|
|
||||||
config.Port2Interrupt = 1;
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
|
|
||||||
PS2WriteData(config.Raw);
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
|
|
||||||
PS2ReadData();
|
|
||||||
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
|
|
||||||
PS2ReadData();
|
|
||||||
Absolute();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If we have another driver using the PS/2 mouse, we need to
|
|
||||||
* override its interrupt handler.
|
|
||||||
*/
|
|
||||||
OverrideInterruptHandler(12, InterruptHandler);
|
|
||||||
|
|
||||||
MouseDevID = RegisterDevice(INPUT_TYPE_MOUSE, &MouseOps);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverFinal()
|
|
||||||
{
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
|
||||||
|
|
||||||
Relative();
|
|
||||||
|
|
||||||
UnregisterDevice(MouseDevID);
|
|
||||||
|
|
||||||
if (ToolboxSupported)
|
|
||||||
{
|
|
||||||
KillThread(dst_id, dst_pid, 0);
|
|
||||||
if (tb_ctx->TCLOChannel != -1)
|
|
||||||
MessageClose(tb_ctx);
|
|
||||||
FreeMemory(tb_ctx, 1);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverPanic()
|
|
||||||
{
|
|
||||||
Relative();
|
|
||||||
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
|
||||||
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverProbe()
|
|
||||||
{
|
|
||||||
if (!IsVMwareBackdoorAvailable())
|
|
||||||
return -ENODEV;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DriverInfo("vmware",
|
|
||||||
"VMware Tools Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
@ -1,512 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Kernel.
|
|
||||||
|
|
||||||
Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <netools.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <regs.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <pci.h>
|
|
||||||
#include <network.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
#include "e1000.hpp"
|
|
||||||
|
|
||||||
class E1000Device
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
PCIHeader0 *Header;
|
|
||||||
uint16_t DeviceID;
|
|
||||||
bool Initialized = false;
|
|
||||||
|
|
||||||
bool EEPROMAvailable;
|
|
||||||
|
|
||||||
struct BARData
|
|
||||||
{
|
|
||||||
uint8_t Type;
|
|
||||||
uint16_t IOBase;
|
|
||||||
uint64_t MemoryBase;
|
|
||||||
} BAR;
|
|
||||||
|
|
||||||
#define E1000_NUM_RX_DESC 32
|
|
||||||
#define E1000_NUM_TX_DESC 8
|
|
||||||
RXDescriptor *RX[E1000_NUM_RX_DESC];
|
|
||||||
TXDescriptor *TX[E1000_NUM_TX_DESC];
|
|
||||||
|
|
||||||
uint16_t RXCurrent;
|
|
||||||
uint16_t TXCurrent;
|
|
||||||
|
|
||||||
const int BaseBufferSize = 8192;
|
|
||||||
const int AdditionalBytes = 16;
|
|
||||||
|
|
||||||
uint32_t CurrentPacket;
|
|
||||||
|
|
||||||
void WriteCMD(uint16_t Address, uint32_t Value)
|
|
||||||
{
|
|
||||||
if (BAR.Type == 0)
|
|
||||||
mmoutl((void *)(BAR.MemoryBase + Address), Value);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
outl(BAR.IOBase, Address);
|
|
||||||
outl(BAR.IOBase + 4, Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ReadCMD(uint16_t Address)
|
|
||||||
{
|
|
||||||
if (BAR.Type == 0)
|
|
||||||
return mminl((void *)(BAR.MemoryBase + Address));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
outl(BAR.IOBase, Address);
|
|
||||||
return inl(BAR.IOBase + 0x4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ReadEEPROM(uint8_t Address)
|
|
||||||
{
|
|
||||||
uint16_t Data = 0;
|
|
||||||
uint32_t temp = 0;
|
|
||||||
if (EEPROMAvailable)
|
|
||||||
{
|
|
||||||
WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 8));
|
|
||||||
while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 4)))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 2));
|
|
||||||
while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 1)))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
Data = (uint16_t)((temp >> 16) & 0xFFFF);
|
|
||||||
return Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeRX()
|
|
||||||
{
|
|
||||||
DebugLog("Initializing RX...");
|
|
||||||
uintptr_t Ptr = (uintptr_t)AllocateMemory(TO_PAGES(sizeof(RXDescriptor) *
|
|
||||||
E1000_NUM_RX_DESC +
|
|
||||||
AdditionalBytes));
|
|
||||||
|
|
||||||
for (int i = 0; i < E1000_NUM_RX_DESC; i++)
|
|
||||||
{
|
|
||||||
RX[i] = (RXDescriptor *)(Ptr + i * 16);
|
|
||||||
RX[i]->Address = (uint64_t)AllocateMemory(TO_PAGES(BaseBufferSize + AdditionalBytes));
|
|
||||||
RX[i]->Status = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
|
||||||
|
|
||||||
WriteCMD(REG::TXDESCLO, (uint32_t)(Ptr >> 32));
|
|
||||||
WriteCMD(REG::TXDESCHI, (uint32_t)(Ptr & 0xFFFFFFFF));
|
|
||||||
|
|
||||||
WriteCMD(REG::RXDESCLO, (uint32_t)Ptr);
|
|
||||||
WriteCMD(REG::RXDESCHI, 0);
|
|
||||||
|
|
||||||
WriteCMD(REG::RXDESCLEN, E1000_NUM_RX_DESC * 16);
|
|
||||||
|
|
||||||
WriteCMD(REG::RXDESCHEAD, 0);
|
|
||||||
WriteCMD(REG::RXDESCTAIL, E1000_NUM_RX_DESC - 1);
|
|
||||||
RXCurrent = 0;
|
|
||||||
WriteCMD(REG::RCTRL, RCTL::EN | RCTL::SBP | RCTL::UPE |
|
|
||||||
RCTL::MPE | RCTL::LBM_NONE |
|
|
||||||
RTCL::RDMTS_HALF | RCTL::BAM |
|
|
||||||
RCTL::SECRC | RCTL::BSIZE_8192);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeTX()
|
|
||||||
{
|
|
||||||
DebugLog("Initializing TX...");
|
|
||||||
uintptr_t Ptr = (uintptr_t)AllocateMemory(TO_PAGES(sizeof(TXDescriptor) *
|
|
||||||
E1000_NUM_RX_DESC +
|
|
||||||
AdditionalBytes));
|
|
||||||
|
|
||||||
for (short i = 0; i < E1000_NUM_TX_DESC; i++)
|
|
||||||
{
|
|
||||||
TX[i] = (TXDescriptor *)((uintptr_t)Ptr + i * 16);
|
|
||||||
TX[i]->Address = 0;
|
|
||||||
TX[i]->Command = 0;
|
|
||||||
TX[i]->Status = TSTA::DD;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteCMD(REG::TXDESCHI, (uint32_t)((uint64_t)Ptr >> 32));
|
|
||||||
WriteCMD(REG::TXDESCLO, (uint32_t)((uint64_t)Ptr & 0xFFFFFFFF));
|
|
||||||
|
|
||||||
WriteCMD(REG::TXDESCLEN, E1000_NUM_TX_DESC * 16);
|
|
||||||
|
|
||||||
WriteCMD(REG::TXDESCHEAD, 0);
|
|
||||||
WriteCMD(REG::TXDESCTAIL, 0);
|
|
||||||
TXCurrent = 0;
|
|
||||||
WriteCMD(REG::TCTRL, TCTL::EN_ | TCTL::PSP |
|
|
||||||
(15 << TCTL::CT_SHIFT) |
|
|
||||||
(64 << TCTL::COLD_SHIFT) |
|
|
||||||
TCTL::RTLC);
|
|
||||||
|
|
||||||
WriteCMD(REG::TCTRL, 0b0110000000000111111000011111010);
|
|
||||||
WriteCMD(REG::TIPG, 0x0060200A);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
dev_t ID;
|
|
||||||
|
|
||||||
bool IsInitialized() { return Initialized; }
|
|
||||||
|
|
||||||
size_t write(uint8_t *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
TX[TXCurrent]->Address = (uint64_t)Buffer;
|
|
||||||
TX[TXCurrent]->Length = (uint16_t)Size;
|
|
||||||
TX[TXCurrent]->Command = CMD::EOP | CMD::IFCS | CMD::RS;
|
|
||||||
TX[TXCurrent]->Status = 0;
|
|
||||||
uint16_t OldTXCurrent = TXCurrent;
|
|
||||||
TXCurrent = (uint16_t)((TXCurrent + 1) % E1000_NUM_TX_DESC);
|
|
||||||
WriteCMD(REG::TXDESCTAIL, TXCurrent);
|
|
||||||
while (!(TX[OldTXCurrent]->Status & 0xFF))
|
|
||||||
Yield();
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaAccessControl GetMAC()
|
|
||||||
{
|
|
||||||
MediaAccessControl mac;
|
|
||||||
if (EEPROMAvailable)
|
|
||||||
{
|
|
||||||
uint32_t temp;
|
|
||||||
temp = ReadEEPROM(0);
|
|
||||||
mac.Address[0] = temp & 0xff;
|
|
||||||
mac.Address[1] = (uint8_t)(temp >> 8);
|
|
||||||
temp = ReadEEPROM(1);
|
|
||||||
mac.Address[2] = temp & 0xff;
|
|
||||||
mac.Address[3] = (uint8_t)(temp >> 8);
|
|
||||||
temp = ReadEEPROM(2);
|
|
||||||
mac.Address[4] = temp & 0xff;
|
|
||||||
mac.Address[5] = (uint8_t)(temp >> 8);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint8_t *BaseMac8 = (uint8_t *)(BAR.MemoryBase + 0x5400);
|
|
||||||
uint32_t *BaseMac32 = (uint32_t *)(BAR.MemoryBase + 0x5400);
|
|
||||||
if (BaseMac32[0] != 0)
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
mac.Address[i] = BaseMac8[i];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KernelLog("No MAC address found.");
|
|
||||||
return MediaAccessControl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mac;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ioctl(NetIoctl req, void *arg)
|
|
||||||
{
|
|
||||||
switch (req)
|
|
||||||
{
|
|
||||||
case IOCTL_NET_GET_MAC:
|
|
||||||
{
|
|
||||||
MediaAccessControl mac = GetMAC();
|
|
||||||
*((uint48_t *)arg) = mac.ToHex(); /* UNTESTED */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnInterruptReceived(TrapFrame *)
|
|
||||||
{
|
|
||||||
WriteCMD(REG::IMASK, 0x1);
|
|
||||||
uint32_t status = ReadCMD(0xC0);
|
|
||||||
UNUSED(status);
|
|
||||||
|
|
||||||
while ((RX[RXCurrent]->Status & 0x1))
|
|
||||||
{
|
|
||||||
uint8_t *data = (uint8_t *)RX[RXCurrent]->Address;
|
|
||||||
uint16_t dataSz = RX[RXCurrent]->Length;
|
|
||||||
|
|
||||||
// ReportNetworkPacket(ID, data, dataSz);
|
|
||||||
/* FIXME: Implement */
|
|
||||||
KernelLog("FIXME: Received packet");
|
|
||||||
(void)data;
|
|
||||||
(void)dataSz;
|
|
||||||
|
|
||||||
RX[RXCurrent]->Status = 0;
|
|
||||||
uint16_t OldRXCurrent = RXCurrent;
|
|
||||||
RXCurrent = (uint16_t)((RXCurrent + 1) % E1000_NUM_RX_DESC);
|
|
||||||
WriteCMD(REG::RXDESCTAIL, OldRXCurrent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Panic()
|
|
||||||
{
|
|
||||||
WriteCMD(REG::IMASK, 0x00000000);
|
|
||||||
WriteCMD(REG::ITR, 0x00000000);
|
|
||||||
WriteCMD(REG::IAM, 0x00000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
E1000Device(PCIHeader0 *_Header, uint16_t _DeviceID)
|
|
||||||
: Header(_Header),
|
|
||||||
DeviceID(_DeviceID)
|
|
||||||
{
|
|
||||||
uint32_t PCIBAR0 = Header->BAR0;
|
|
||||||
uint32_t PCIBAR1 = Header->BAR1;
|
|
||||||
BAR.Type = PCIBAR0 & 1;
|
|
||||||
BAR.IOBase = (uint16_t)(PCIBAR0 & (~3));
|
|
||||||
BAR.MemoryBase = PCIBAR1 & (~15);
|
|
||||||
|
|
||||||
switch (DeviceID)
|
|
||||||
{
|
|
||||||
case 0x100E:
|
|
||||||
{
|
|
||||||
KernelLog("Found Intel 82540EM Gigabit Ethernet Controller.");
|
|
||||||
|
|
||||||
/* Detect EEPROM */
|
|
||||||
WriteCMD(REG::EEPROM, 0x1);
|
|
||||||
for (int i = 0; i < 1000 && !EEPROMAvailable; i++)
|
|
||||||
if (ReadCMD(REG::EEPROM) & 0x10)
|
|
||||||
EEPROMAvailable = true;
|
|
||||||
else
|
|
||||||
EEPROMAvailable = false;
|
|
||||||
|
|
||||||
if (!GetMAC().Valid())
|
|
||||||
{
|
|
||||||
KernelLog("Failed to get MAC");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start link */
|
|
||||||
uint32_t cmdret = ReadCMD(REG::CTRL);
|
|
||||||
WriteCMD(REG::CTRL, cmdret | ECTRL::SLU);
|
|
||||||
|
|
||||||
for (int i = 0; i < 0x80; i++)
|
|
||||||
WriteCMD((uint16_t)(0x5200 + i * 4), 0);
|
|
||||||
|
|
||||||
WriteCMD(REG::IMASK, 0x1F6DC);
|
|
||||||
WriteCMD(REG::IMASK, 0xFF & ~4);
|
|
||||||
ReadCMD(0xC0);
|
|
||||||
|
|
||||||
InitializeRX();
|
|
||||||
InitializeTX();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
KernelLog("Unimplemented E1000 device.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
~E1000Device()
|
|
||||||
{
|
|
||||||
if (!Initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (DeviceID)
|
|
||||||
{
|
|
||||||
case 0x100E:
|
|
||||||
{
|
|
||||||
// Clearing Enable bit in Receive Control Register
|
|
||||||
uint32_t cmdret = ReadCMD(REG::RCTRL);
|
|
||||||
WriteCMD(REG::RCTRL, cmdret & ~RCTL::EN);
|
|
||||||
|
|
||||||
// Masking Interrupt Mask, Interrupt Throttling Rate & Interrupt Auto-Mask
|
|
||||||
WriteCMD(REG::IMASK, 0x00000000);
|
|
||||||
WriteCMD(REG::ITR, 0x00000000);
|
|
||||||
WriteCMD(REG::IAM, 0x00000000);
|
|
||||||
|
|
||||||
// Clearing SLU bit in Device Control Register
|
|
||||||
cmdret = ReadCMD(REG::CTRL);
|
|
||||||
WriteCMD(REG::CTRL, cmdret & ~ECTRL::SLU);
|
|
||||||
|
|
||||||
// Clear the Interrupt Cause Read register by reading it
|
|
||||||
ReadCMD(REG::ICR);
|
|
||||||
|
|
||||||
// Powering down the device (?)
|
|
||||||
WriteCMD(REG::CTRL, PCTRL::POWER_DOWN);
|
|
||||||
/* TODO: Stop link; further testing required */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
KernelLog("Unimplemented E1000 device.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
E1000Device *Drivers[4] = {nullptr};
|
|
||||||
dev_t NetID[4] = {(dev_t)-1};
|
|
||||||
|
|
||||||
#define OIR(x) OIR_##x
|
|
||||||
#define CREATE_OIR(x) \
|
|
||||||
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
|
|
||||||
|
|
||||||
CREATE_OIR(0);
|
|
||||||
CREATE_OIR(1);
|
|
||||||
CREATE_OIR(2);
|
|
||||||
CREATE_OIR(3);
|
|
||||||
|
|
||||||
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
|
|
||||||
int __fs_Close(struct Inode *) { return 0; }
|
|
||||||
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
|
|
||||||
|
|
||||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
|
||||||
{
|
|
||||||
return Drivers[NetID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
|
||||||
{
|
|
||||||
return Drivers[NetID[Node->GetMinor()]]->ioctl((NetIoctl)Request, Argp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct InodeOperations NetOps = {
|
|
||||||
.Lookup = nullptr,
|
|
||||||
.Create = nullptr,
|
|
||||||
.Remove = nullptr,
|
|
||||||
.Rename = nullptr,
|
|
||||||
.Read = __fs_Read,
|
|
||||||
.Write = __fs_Write,
|
|
||||||
.Truncate = nullptr,
|
|
||||||
.Open = __fs_Open,
|
|
||||||
.Close = __fs_Close,
|
|
||||||
.Ioctl = __fs_Ioctl,
|
|
||||||
.ReadDir = nullptr,
|
|
||||||
.MkDir = nullptr,
|
|
||||||
.RmDir = nullptr,
|
|
||||||
.SymLink = nullptr,
|
|
||||||
.ReadLink = nullptr,
|
|
||||||
.Seek = nullptr,
|
|
||||||
.Stat = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
PCIArray *Devices;
|
|
||||||
EXTERNC int cxx_Panic()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
short Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Drivers[Count] != nullptr)
|
|
||||||
Drivers[Count]->Panic();
|
|
||||||
Count++;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Probe()
|
|
||||||
{
|
|
||||||
uint16_t VendorIDs[] = {0x8086, /* Intel */
|
|
||||||
PCI_END};
|
|
||||||
uint16_t DeviceIDs[] = {0x100E, /* 82540EM */
|
|
||||||
0x100F, /* 82545EM */
|
|
||||||
0x10D3, /* 82574L */
|
|
||||||
0x10EA, /* I217-LM */
|
|
||||||
0x153A, /* 82577LM */
|
|
||||||
PCI_END};
|
|
||||||
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
|
|
||||||
if (Devices == nullptr)
|
|
||||||
{
|
|
||||||
KernelLog("No E1000 device found.");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Initialize()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count > sizeof(Drivers) / sizeof(E1000Device *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
InitializePCI(ctx->Device);
|
|
||||||
|
|
||||||
Drivers[Count] = new E1000Device((PCIHeader0 *)ctx->Device->Header,
|
|
||||||
ctx->Device->Header->DeviceID);
|
|
||||||
|
|
||||||
if (Drivers[Count]->IsInitialized())
|
|
||||||
{
|
|
||||||
dev_t ret = RegisterDevice(NETWORK_TYPE_ETHERNET, &NetOps);
|
|
||||||
NetID[Count] = ret;
|
|
||||||
Drivers[Count]->ID = ret;
|
|
||||||
|
|
||||||
/* FIXME: bad code */
|
|
||||||
switch (Count)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Count++;
|
|
||||||
}
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Count == 0)
|
|
||||||
{
|
|
||||||
KernelLog("No valid E1000 device found.");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Finalize()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count++ > sizeof(Drivers) / sizeof(E1000Device *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
delete Drivers[Count++];
|
|
||||||
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(NetID) / sizeof(dev_t); i++)
|
|
||||||
{
|
|
||||||
if (NetID[i] != (dev_t)-1)
|
|
||||||
UnregisterDevice(NetID[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base.h>
|
|
||||||
|
|
||||||
#include "e1000.hpp"
|
|
||||||
|
|
||||||
int DriverEntry() { return cxx_Initialize(); }
|
|
||||||
int DriverFinal() { return cxx_Finalize(); }
|
|
||||||
int DriverPanic() { return cxx_Panic(); }
|
|
||||||
int DriverProbe() { return cxx_Probe(); }
|
|
||||||
|
|
||||||
DriverInfo("e1000",
|
|
||||||
"Intel(R) PRO/1000 Network Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base.h>
|
|
||||||
|
|
||||||
#include "rtl8139.hpp"
|
|
||||||
|
|
||||||
int DriverEntry() { return cxx_Initialize(); }
|
|
||||||
int DriverFinal() { return cxx_Finalize(); }
|
|
||||||
int DriverPanic() { return cxx_Panic(); }
|
|
||||||
int DriverProbe() { return cxx_Probe(); }
|
|
||||||
|
|
||||||
DriverInfo("rtl8139",
|
|
||||||
"Realtek RTL8139 Network Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -1,325 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Kernel.
|
|
||||||
|
|
||||||
Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <netools.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <regs.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <pci.h>
|
|
||||||
#include <network.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
#include "rtl8139.hpp"
|
|
||||||
|
|
||||||
class RTL8139Device
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
PCIHeader0 *Header;
|
|
||||||
bool Initialized = false;
|
|
||||||
|
|
||||||
struct BARData
|
|
||||||
{
|
|
||||||
uint8_t Type;
|
|
||||||
uint16_t IOBase;
|
|
||||||
uint64_t MemoryBase;
|
|
||||||
} BAR;
|
|
||||||
|
|
||||||
const int BaseBufferSize = 8192;
|
|
||||||
const int WRAPBytes = 1500;
|
|
||||||
const int AdditionalBytes = 16;
|
|
||||||
const int BufferSize = BaseBufferSize +
|
|
||||||
WRAPBytes +
|
|
||||||
AdditionalBytes;
|
|
||||||
|
|
||||||
uint8_t *RXBuffer = nullptr;
|
|
||||||
int TXCurrent = 0;
|
|
||||||
uint16_t CurrentPacket = 0;
|
|
||||||
|
|
||||||
uint8_t TSAD[4] = {0x20, 0x24, 0x28, 0x2C};
|
|
||||||
uint8_t TSD[4] = {0x10, 0x14, 0x18, 0x1C};
|
|
||||||
|
|
||||||
public:
|
|
||||||
dev_t ID;
|
|
||||||
|
|
||||||
bool IsInitialized() { return Initialized; }
|
|
||||||
|
|
||||||
size_t write(uint8_t *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
outl(TSAD[TXCurrent], (uint32_t)(reinterpret_cast<uint64_t>(Buffer)));
|
|
||||||
outl(TSD[TXCurrent++], (uint32_t)Size);
|
|
||||||
if (TXCurrent > 3)
|
|
||||||
TXCurrent = 0;
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaAccessControl GetMAC()
|
|
||||||
{
|
|
||||||
return MediaAccessControl();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ioctl(NetIoctl req, void *)
|
|
||||||
{
|
|
||||||
switch (req)
|
|
||||||
{
|
|
||||||
case IOCTL_NET_GET_MAC:
|
|
||||||
{
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnInterruptReceived(TrapFrame *)
|
|
||||||
{
|
|
||||||
/* Acknowledge interrupt */
|
|
||||||
uint16_t status = inw(RegISR);
|
|
||||||
DebugLog("%#lx", status);
|
|
||||||
|
|
||||||
/* Read status */
|
|
||||||
if (status & RecOK)
|
|
||||||
{
|
|
||||||
/* Get the current packet */
|
|
||||||
uint16_t *data = (uint16_t *)(RXBuffer + CurrentPacket);
|
|
||||||
uint16_t dataSz = *(data + 1);
|
|
||||||
data += 2;
|
|
||||||
|
|
||||||
// ReportNetworkPacket(ID, data, dataSz);
|
|
||||||
/* FIXME: Implement */
|
|
||||||
KernelLog("FIXME: Received packet");
|
|
||||||
(void)data;
|
|
||||||
(void)dataSz;
|
|
||||||
|
|
||||||
/* Update CAPR */
|
|
||||||
#define RX_READ_PTR_MASK (~0x3)
|
|
||||||
CurrentPacket = (uint16_t)((CurrentPacket + dataSz + 4 + 3) & RX_READ_PTR_MASK);
|
|
||||||
if (CurrentPacket > BufferSize)
|
|
||||||
CurrentPacket -= uint16_t(BufferSize);
|
|
||||||
outw(RegCAPR, CurrentPacket - 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear interrupt */
|
|
||||||
outw(RegISR, (RecOK | RecBad | SendOK | SendBad));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Panic()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RTL8139Device(PCIHeader0 *_Header)
|
|
||||||
: Header(_Header)
|
|
||||||
{
|
|
||||||
uint32_t PCIBAR0 = Header->BAR0;
|
|
||||||
uint32_t PCIBAR1 = Header->BAR1;
|
|
||||||
BAR.Type = PCIBAR0 & 1;
|
|
||||||
BAR.IOBase = (uint16_t)(PCIBAR0 & (~3));
|
|
||||||
BAR.MemoryBase = PCIBAR1 & (~15);
|
|
||||||
|
|
||||||
RXBuffer = (uint8_t *)AllocateMemory(TO_PAGES(BufferSize));
|
|
||||||
|
|
||||||
/* Power on */
|
|
||||||
outb(RegCONFIG1, 0x0);
|
|
||||||
|
|
||||||
/* Software Reset */
|
|
||||||
outb(RegCMD, 0x10);
|
|
||||||
while (inb(RegCMD) & 0x10)
|
|
||||||
Yield();
|
|
||||||
|
|
||||||
/* Initialize receive buffer */
|
|
||||||
outl(RegRBSTART, (uint32_t)(reinterpret_cast<uintptr_t>(RXBuffer)));
|
|
||||||
|
|
||||||
/* Configure interrupt mask register */
|
|
||||||
outw(RegIMR, (RecOK | RecBad | SendOK | SendBad));
|
|
||||||
outl(regRCR, (RcAB | RcAM | RcAPM | RcAAP) | RcWRAP);
|
|
||||||
|
|
||||||
/* Enable receive and transmit */
|
|
||||||
outb(RegCMD, 0xC); /* 0xC = RE and TE bit */
|
|
||||||
|
|
||||||
uint32_t MAC1 = inl(RegMAC);
|
|
||||||
uint16_t MAC2 = inw(RegMAR);
|
|
||||||
MediaAccessControl mac = {
|
|
||||||
mac.Address[0] = (uint8_t)MAC1,
|
|
||||||
mac.Address[1] = (uint8_t)(MAC1 >> 8),
|
|
||||||
mac.Address[2] = (uint8_t)(MAC1 >> 16),
|
|
||||||
mac.Address[3] = (uint8_t)(MAC1 >> 24),
|
|
||||||
mac.Address[4] = (uint8_t)MAC2,
|
|
||||||
mac.Address[5] = (uint8_t)(MAC2 >> 8)};
|
|
||||||
|
|
||||||
Initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
~RTL8139Device()
|
|
||||||
{
|
|
||||||
if (!Initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* FIXME: Shutdown code */
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
RTL8139Device *Drivers[4] = {nullptr};
|
|
||||||
dev_t NetID[4] = {(dev_t)-1};
|
|
||||||
|
|
||||||
#define OIR(x) OIR_##x
|
|
||||||
#define CREATE_OIR(x) \
|
|
||||||
void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
|
|
||||||
|
|
||||||
CREATE_OIR(0);
|
|
||||||
CREATE_OIR(1);
|
|
||||||
CREATE_OIR(2);
|
|
||||||
CREATE_OIR(3);
|
|
||||||
|
|
||||||
int __fs_Open(struct Inode *, int, mode_t) { return 0; }
|
|
||||||
int __fs_Close(struct Inode *) { return 0; }
|
|
||||||
ssize_t __fs_Read(struct Inode *, void *, size_t, off_t) { return 0; }
|
|
||||||
|
|
||||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
|
||||||
{
|
|
||||||
return Drivers[NetID[Node->GetMinor()]]->write((uint8_t *)Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
|
||||||
{
|
|
||||||
return Drivers[NetID[Node->GetMinor()]]->ioctl((NetIoctl)Request, Argp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct InodeOperations NetOps = {
|
|
||||||
.Lookup = nullptr,
|
|
||||||
.Create = nullptr,
|
|
||||||
.Remove = nullptr,
|
|
||||||
.Rename = nullptr,
|
|
||||||
.Read = __fs_Read,
|
|
||||||
.Write = __fs_Write,
|
|
||||||
.Truncate = nullptr,
|
|
||||||
.Open = __fs_Open,
|
|
||||||
.Close = __fs_Close,
|
|
||||||
.Ioctl = __fs_Ioctl,
|
|
||||||
.ReadDir = nullptr,
|
|
||||||
.MkDir = nullptr,
|
|
||||||
.RmDir = nullptr,
|
|
||||||
.SymLink = nullptr,
|
|
||||||
.ReadLink = nullptr,
|
|
||||||
.Seek = nullptr,
|
|
||||||
.Stat = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
PCIArray *Devices;
|
|
||||||
EXTERNC int cxx_Panic()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
short Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Drivers[Count] != nullptr)
|
|
||||||
Drivers[Count]->Panic();
|
|
||||||
Count++;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Probe()
|
|
||||||
{
|
|
||||||
uint16_t VendorIDs[] = {0x10EC, /* Realtek */
|
|
||||||
PCI_END};
|
|
||||||
uint16_t DeviceIDs[] = {0x8139, /* RTL8139 */
|
|
||||||
PCI_END};
|
|
||||||
Devices = GetPCIDevices(VendorIDs, DeviceIDs);
|
|
||||||
if (Devices == nullptr)
|
|
||||||
{
|
|
||||||
KernelLog("No RTL8139 device found.");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Initialize()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count > sizeof(Drivers) / sizeof(RTL8139Device *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
InitializePCI(ctx->Device);
|
|
||||||
|
|
||||||
Drivers[Count] = new RTL8139Device((PCIHeader0 *)ctx->Device->Header);
|
|
||||||
|
|
||||||
if (Drivers[Count]->IsInitialized())
|
|
||||||
{
|
|
||||||
dev_t ret = RegisterDevice(NETWORK_TYPE_ETHERNET, &NetOps);
|
|
||||||
NetID[Count] = ret;
|
|
||||||
Drivers[Count]->ID = ret;
|
|
||||||
|
|
||||||
/* FIXME: bad code */
|
|
||||||
switch (Count)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Count++;
|
|
||||||
}
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Count == 0)
|
|
||||||
{
|
|
||||||
KernelLog("No valid RTL8139 device found.");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERNC int cxx_Finalize()
|
|
||||||
{
|
|
||||||
PCIArray *ctx = Devices;
|
|
||||||
size_t Count = 0;
|
|
||||||
while (ctx != nullptr)
|
|
||||||
{
|
|
||||||
if (Count++ > sizeof(Drivers) / sizeof(RTL8139Device *))
|
|
||||||
break;
|
|
||||||
|
|
||||||
delete Drivers[Count++];
|
|
||||||
ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
|
|
||||||
ctx = (PCIArray *)ctx->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(NetID) / sizeof(dev_t); i++)
|
|
||||||
{
|
|
||||||
if (NetID[i] != (dev_t)-1)
|
|
||||||
UnregisterDevice(NetID[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,7 +1,9 @@
|
|||||||
build:
|
MAKE_TARGETS := build clean
|
||||||
make -C ahci build
|
DIRECTORIES := $(sort $(dir $(wildcard ./*/)))
|
||||||
make -C ata build
|
|
||||||
|
|
||||||
clean:
|
.PHONY: $(MAKE_TARGETS) $(DIRECTORIES)
|
||||||
make -C ahci clean
|
|
||||||
make -C ata clean
|
$(MAKE_TARGETS): $(DIRECTORIES)
|
||||||
|
|
||||||
|
$(DIRECTORIES):
|
||||||
|
$(MAKE) -C $@ $(MAKECMDGOALS)
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
File diff suppressed because it is too large
Load Diff
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <types.h>
|
|
||||||
|
|
||||||
EXTERNC int cxx_Panic();
|
|
||||||
EXTERNC int cxx_Probe();
|
|
||||||
EXTERNC int cxx_Initialize();
|
|
||||||
EXTERNC int cxx_Finalize();
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base.h>
|
|
||||||
|
|
||||||
#include "ahci.hpp"
|
|
||||||
|
|
||||||
int DriverEntry() { return cxx_Initialize(); }
|
|
||||||
int DriverFinal() { return cxx_Finalize(); }
|
|
||||||
int DriverPanic() { return cxx_Panic(); }
|
|
||||||
int DriverProbe() { return cxx_Probe(); }
|
|
||||||
|
|
||||||
DriverInfo("ahci",
|
|
||||||
"Advanced Host Controller Interface Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -1,35 +0,0 @@
|
|||||||
default:
|
|
||||||
$(error Do not run this Makefile directly!)
|
|
||||||
|
|
||||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
|
||||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
|
||||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
|
||||||
HEADERS = $(sort $(dir $(wildcard ../../include/*)))
|
|
||||||
OBJ = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) $(S_SOURCES:.S=.o)
|
|
||||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
|
||||||
|
|
||||||
FILENAME = $(notdir $(shell pwd)).drv
|
|
||||||
|
|
||||||
build: $(FILENAME)
|
|
||||||
mv $(FILENAME) $(OUTPUT_DIR)$(FILENAME)
|
|
||||||
|
|
||||||
$(FILENAME): $(OBJ)
|
|
||||||
$(info Linking $@)
|
|
||||||
$(CC) $(DRIVER_LDFLAGS) $(OBJ) $(OUTPUT_DIR)dcrt0.o -L$(OUTPUT_DIR) -lkernel -o $@
|
|
||||||
|
|
||||||
WARNCFLAG = -Wall -Wextra
|
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CC) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(CXX) $(DRIVER_CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(info Compiling $<)
|
|
||||||
$(AS) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
|
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Drivers.
|
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <regs.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
bool IsATAPresent()
|
|
||||||
{
|
|
||||||
outb(0x1F0 + 2, 0);
|
|
||||||
outb(0x1F0 + 3, 0);
|
|
||||||
outb(0x1F0 + 4, 0);
|
|
||||||
outb(0x1F0 + 5, 0);
|
|
||||||
outb(0x1F0 + 7, 0xEC);
|
|
||||||
if (inb(0x1F0 + 7) == 0 || inb(0x1F0 + 1) != 0)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MasterInterruptHandler(TrapFrame *)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SlaveInterruptHandler(TrapFrame *)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverEntry()
|
|
||||||
{
|
|
||||||
RegisterInterruptHandler(14, MasterInterruptHandler);
|
|
||||||
RegisterInterruptHandler(15, SlaveInterruptHandler);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverFinal()
|
|
||||||
{
|
|
||||||
UnregisterInterruptHandler(14, MasterInterruptHandler);
|
|
||||||
UnregisterInterruptHandler(15, SlaveInterruptHandler);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverPanic()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DriverProbe()
|
|
||||||
{
|
|
||||||
if (!IsATAPresent())
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DriverInfo("ata",
|
|
||||||
"Advanced Technology Attachment Driver",
|
|
||||||
"EnderIce2",
|
|
||||||
0, 0, 1,
|
|
||||||
"GPLv3");
|
|
@ -26,6 +26,15 @@
|
|||||||
"git.alwaysSignOff": true,
|
"git.alwaysSignOff": true,
|
||||||
"git.defaultBranchName": "master",
|
"git.defaultBranchName": "master",
|
||||||
"git.openRepositoryInParentFolders": "always",
|
"git.openRepositoryInParentFolders": "always",
|
||||||
"C_Cpp.autoAddFileAssociations": false
|
"C_Cpp.autoAddFileAssociations": false,
|
||||||
|
"conventionalCommits.scopes": [
|
||||||
|
"kernel/api",
|
||||||
|
"kernel/syscalls",
|
||||||
|
"vscode",
|
||||||
|
"kernel",
|
||||||
|
"kernel/pci",
|
||||||
|
"kernel/driver",
|
||||||
|
"kernel/drivers"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,15 @@
|
|||||||
"git.alwaysSignOff": true,
|
"git.alwaysSignOff": true,
|
||||||
"git.defaultBranchName": "master",
|
"git.defaultBranchName": "master",
|
||||||
"git.openRepositoryInParentFolders": "always",
|
"git.openRepositoryInParentFolders": "always",
|
||||||
"C_Cpp.autoAddFileAssociations": false
|
"C_Cpp.autoAddFileAssociations": false,
|
||||||
|
"conventionalCommits.scopes": [
|
||||||
|
"userspace/libc",
|
||||||
|
"vscode",
|
||||||
|
"userspace/apps/sys/init",
|
||||||
|
"userspace/libs/libm",
|
||||||
|
"devcontainer",
|
||||||
|
"userspace/libs",
|
||||||
|
"userspace/apps/test"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
"git.alwaysSignOff": true,
|
"git.alwaysSignOff": true,
|
||||||
"git.defaultBranchName": "master",
|
"git.defaultBranchName": "master",
|
||||||
"git.openRepositoryInParentFolders": "always",
|
"git.openRepositoryInParentFolders": "always",
|
||||||
"C_Cpp.autoAddFileAssociations": false
|
"C_Cpp.autoAddFileAssociations": false,
|
||||||
|
"conventionalCommits.scopes": [
|
||||||
|
"initrd",
|
||||||
|
"tools",
|
||||||
|
"devcontainer"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
Kernel/.vscode/extensions.json
vendored
Normal file
16
Kernel/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"ms-vscode.cpptools",
|
||||||
|
"maziac.asm-code-lens",
|
||||||
|
"editorconfig.editorconfig",
|
||||||
|
"vivaxy.vscode-conventional-commits",
|
||||||
|
"ms-vscode.hexeditor",
|
||||||
|
"webfreak.debug",
|
||||||
|
"ibm.output-colorizer",
|
||||||
|
"gruntfuggly.todo-tree",
|
||||||
|
"naumovs.color-highlight",
|
||||||
|
"seven1bit.vscode-ext-ansi-color-highlight",
|
||||||
|
"jeff-hykin.better-cpp-syntax",
|
||||||
|
"aaron-bond.better-comments"
|
||||||
|
]
|
||||||
|
}
|
@ -77,6 +77,14 @@ SECTIONS
|
|||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
} :rodata
|
} :rodata
|
||||||
|
|
||||||
|
.builtin_drivers ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.builtin_drivers) - KERNEL_VMA)
|
||||||
|
{
|
||||||
|
__kernel_builtin_drivers_start = .;
|
||||||
|
KEEP(*(SORT(.builtin_drivers.*)))
|
||||||
|
KEEP(*(.builtin_drivers))
|
||||||
|
__kernel_builtin_drivers_end = .;
|
||||||
|
} :rodata
|
||||||
|
|
||||||
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
|
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
|
||||||
{
|
{
|
||||||
PROVIDE_HIDDEN(__init_array_start = .);
|
PROVIDE_HIDDEN(__init_array_start = .);
|
||||||
|
@ -80,6 +80,14 @@ SECTIONS
|
|||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
} :rodata
|
} :rodata
|
||||||
|
|
||||||
|
.builtin_drivers ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.builtin_drivers) - KERNEL_VMA)
|
||||||
|
{
|
||||||
|
__kernel_builtin_drivers_start = .;
|
||||||
|
KEEP(*(SORT(.builtin_drivers.*)))
|
||||||
|
KEEP(*(.builtin_drivers))
|
||||||
|
__kernel_builtin_drivers_end = .;
|
||||||
|
} :rodata
|
||||||
|
|
||||||
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
|
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
|
||||||
{
|
{
|
||||||
PROVIDE_HIDDEN(__init_array_start = .);
|
PROVIDE_HIDDEN(__init_array_start = .);
|
||||||
|
@ -58,6 +58,14 @@ SECTIONS
|
|||||||
}
|
}
|
||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
|
|
||||||
|
.builtin_drivers :
|
||||||
|
{
|
||||||
|
__kernel_builtin_drivers_start = .;
|
||||||
|
KEEP(*(SORT(.builtin_drivers.*)))
|
||||||
|
KEEP(*(.builtin_drivers))
|
||||||
|
__kernel_builtin_drivers_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
.init_array :
|
.init_array :
|
||||||
{
|
{
|
||||||
PROVIDE_HIDDEN(__init_array_start = .);
|
PROVIDE_HIDDEN(__init_array_start = .);
|
||||||
|
@ -80,6 +80,14 @@ SECTIONS
|
|||||||
*(.rodata .rodata.*)
|
*(.rodata .rodata.*)
|
||||||
} :rodata
|
} :rodata
|
||||||
|
|
||||||
|
.builtin_drivers ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.builtin_drivers) - KERNEL_VMA)
|
||||||
|
{
|
||||||
|
__kernel_builtin_drivers_start = .;
|
||||||
|
KEEP(*(SORT(.builtin_drivers.*)))
|
||||||
|
KEEP(*(.builtin_drivers))
|
||||||
|
__kernel_builtin_drivers_end = .;
|
||||||
|
} :rodata
|
||||||
|
|
||||||
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
|
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
|
||||||
{
|
{
|
||||||
PROVIDE_HIDDEN(__init_array_start = .);
|
PROVIDE_HIDDEN(__init_array_start = .);
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define NO_API_IN_HEADER 1
|
||||||
#include <driver.hpp>
|
#include <driver.hpp>
|
||||||
#include <interface/driver.h>
|
#include <interface/driver.h>
|
||||||
#include <interface/fs.h>
|
#include <interface/fs.h>
|
||||||
@ -66,12 +67,10 @@ namespace v0
|
|||||||
uintptr_t Flags;
|
uintptr_t Flags;
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
asmv("pushfq");
|
asmv("pushfq");
|
||||||
asmv("popq %0"
|
asmv("popq %0" : "=r"(Flags));
|
||||||
: "=r"(Flags));
|
|
||||||
#else
|
#else
|
||||||
asmv("pushfl");
|
asmv("pushfl");
|
||||||
asmv("popl %0"
|
asmv("popl %0" : "=r"(Flags));
|
||||||
: "=r"(Flags));
|
|
||||||
#endif
|
#endif
|
||||||
cs = Flags & (1 << 9);
|
cs = Flags & (1 << 9);
|
||||||
asmv("cli");
|
asmv("cli");
|
||||||
@ -453,29 +452,13 @@ namespace v0
|
|||||||
void *AllocateMemory(dev_t DriverID, size_t Pages)
|
void *AllocateMemory(dev_t DriverID, size_t Pages)
|
||||||
{
|
{
|
||||||
dbg_api("%d, %d", DriverID, Pages);
|
dbg_api("%d, %d", DriverID, Pages);
|
||||||
|
return DriverManager->AllocateMemory(DriverID, Pages);
|
||||||
std::unordered_map<dev_t, Driver::DriverObject> &Drivers =
|
|
||||||
DriverManager->GetDrivers();
|
|
||||||
|
|
||||||
auto itr = Drivers.find(DriverID);
|
|
||||||
assert(itr != Drivers.end());
|
|
||||||
|
|
||||||
void *ptr = itr->second.vma->RequestPages(Pages);
|
|
||||||
memset(ptr, 0, FROM_PAGES(Pages));
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
|
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
|
||||||
{
|
{
|
||||||
dbg_api("%d, %#lx, %d", DriverID, Pointer, Pages);
|
dbg_api("%d, %#lx, %d", DriverID, Pointer, Pages);
|
||||||
|
DriverManager->FreeMemory(DriverID, Pointer, Pages);
|
||||||
std::unordered_map<dev_t, Driver::DriverObject> &Drivers =
|
|
||||||
DriverManager->GetDrivers();
|
|
||||||
|
|
||||||
auto itr = Drivers.find(DriverID);
|
|
||||||
assert(itr != Drivers.end());
|
|
||||||
|
|
||||||
itr->second.vma->FreePages(Pointer, Pages);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MemoryCopy(dev_t DriverID, void *Destination, const void *Source, size_t Length)
|
void *MemoryCopy(dev_t DriverID, void *Destination, const void *Source, size_t Length)
|
||||||
@ -621,131 +604,7 @@ namespace v0
|
|||||||
void InitializePCI(dev_t DriverID, void *_Header)
|
void InitializePCI(dev_t DriverID, void *_Header)
|
||||||
{
|
{
|
||||||
dbg_api("%d, %#lx", DriverID, _Header);
|
dbg_api("%d, %#lx", DriverID, _Header);
|
||||||
|
PCIManager->InitializeDevice(*(PCI::PCIDevice *)_Header, KernelPageTable);
|
||||||
PCI::PCIDevice *__device = (PCI::PCIDevice *)_Header;
|
|
||||||
PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)__device->Header;
|
|
||||||
|
|
||||||
debug("Header Type: %d", Header->HeaderType);
|
|
||||||
switch (Header->HeaderType)
|
|
||||||
{
|
|
||||||
case 128:
|
|
||||||
warn("Unknown header type %d! Guessing PCI Header 0",
|
|
||||||
Header->HeaderType);
|
|
||||||
[[fallthrough]];
|
|
||||||
case 0: /* PCI Header 0 */
|
|
||||||
{
|
|
||||||
PCI::PCIHeader0 *hdr0 = (PCI::PCIHeader0 *)Header;
|
|
||||||
|
|
||||||
uint32_t BAR[6];
|
|
||||||
size_t BARsSize[6];
|
|
||||||
|
|
||||||
BAR[0] = hdr0->BAR0;
|
|
||||||
BAR[1] = hdr0->BAR1;
|
|
||||||
BAR[2] = hdr0->BAR2;
|
|
||||||
BAR[3] = hdr0->BAR3;
|
|
||||||
BAR[4] = hdr0->BAR4;
|
|
||||||
BAR[5] = hdr0->BAR5;
|
|
||||||
|
|
||||||
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx",
|
|
||||||
BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
|
|
||||||
|
|
||||||
/* BARs Size */
|
|
||||||
for (short i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
if (BAR[i] == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
size_t size;
|
|
||||||
if ((BAR[i] & 1) == 0) /* Memory Base */
|
|
||||||
{
|
|
||||||
hdr0->BAR0 = 0xFFFFFFFF;
|
|
||||||
size = hdr0->BAR0;
|
|
||||||
hdr0->BAR0 = BAR[i];
|
|
||||||
BARsSize[i] = size & (~15);
|
|
||||||
BARsSize[i] = ~BARsSize[i] + 1;
|
|
||||||
BARsSize[i] = BARsSize[i] & 0xFFFFFFFF;
|
|
||||||
debug("BAR%d %#lx size: %d",
|
|
||||||
i, BAR[i], BARsSize[i]);
|
|
||||||
}
|
|
||||||
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
|
||||||
{
|
|
||||||
hdr0->BAR1 = 0xFFFFFFFF;
|
|
||||||
size = hdr0->BAR1;
|
|
||||||
hdr0->BAR1 = BAR[i];
|
|
||||||
BARsSize[i] = size & (~3);
|
|
||||||
BARsSize[i] = ~BARsSize[i] + 1;
|
|
||||||
BARsSize[i] = BARsSize[i] & 0xFFFF;
|
|
||||||
debug("BAR%d %#lx size: %d",
|
|
||||||
i, BAR[i], BARsSize[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Memory::Virtual vmm(KernelPageTable);
|
|
||||||
|
|
||||||
/* Mapping the BARs */
|
|
||||||
for (short i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
if (BAR[i] == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((BAR[i] & 1) == 0) /* Memory Base */
|
|
||||||
{
|
|
||||||
uintptr_t BARBase = BAR[i] & (~15);
|
|
||||||
size_t BARSize = BARsSize[i];
|
|
||||||
|
|
||||||
debug("Mapping BAR%d %#lx-%#lx",
|
|
||||||
i, BARBase, BARBase + BARSize);
|
|
||||||
|
|
||||||
if (BARSize == 0)
|
|
||||||
{
|
|
||||||
warn("BAR%d size is zero!", i);
|
|
||||||
BARSize++;
|
|
||||||
}
|
|
||||||
|
|
||||||
vmm.Map((void *)BARBase, (void *)BARBase,
|
|
||||||
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
|
||||||
}
|
|
||||||
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
|
||||||
{
|
|
||||||
uintptr_t BARBase = BAR[i] & (~3);
|
|
||||||
size_t BARSize = BARsSize[i];
|
|
||||||
|
|
||||||
debug("Mapping BAR%d %#x-%#x",
|
|
||||||
i, BARBase, BARBase + BARSize);
|
|
||||||
|
|
||||||
if (BARSize == 0)
|
|
||||||
{
|
|
||||||
warn("BAR%d size is zero!", i);
|
|
||||||
BARSize++;
|
|
||||||
}
|
|
||||||
|
|
||||||
vmm.Map((void *)BARBase, (void *)BARBase,
|
|
||||||
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: /* PCI Header 1 (PCI-to-PCI Bridge) */
|
|
||||||
{
|
|
||||||
fixme("PCI Header 1 (PCI-to-PCI Bridge) not implemented yet");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: /* PCI Header 2 (PCI-to-CardBus Bridge) */
|
|
||||||
{
|
|
||||||
fixme("PCI Header 2 (PCI-to-CardBus Bridge) not implemented yet");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
error("Unknown header type %d", Header->HeaderType);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Header->Command |= PCI_COMMAND_MASTER |
|
|
||||||
PCI_COMMAND_IO |
|
|
||||||
PCI_COMMAND_MEMORY;
|
|
||||||
Header->Command &= ~PCI_COMMAND_INTX_DISABLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GetBAR(dev_t DriverID, uint8_t i, void *_Header)
|
uint32_t GetBAR(dev_t DriverID, uint8_t i, void *_Header)
|
||||||
@ -824,6 +683,13 @@ namespace v0
|
|||||||
|
|
||||||
/* --------- */
|
/* --------- */
|
||||||
|
|
||||||
|
dev_t CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
|
||||||
|
{
|
||||||
|
dbg_api("%d, %s, %#o, %#lx", DriverID, name, mode, Operations);
|
||||||
|
|
||||||
|
return DriverManager->CreateDeviceFile(DriverID, name, mode, Operations);
|
||||||
|
}
|
||||||
|
|
||||||
dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
||||||
{
|
{
|
||||||
dbg_api("%d, %d, %#lx", DriverID, Type, Operations);
|
dbg_api("%d, %d, %#lx", DriverID, Type, Operations);
|
||||||
@ -907,6 +773,7 @@ static struct APISymbols APISymbols_v0[] = {
|
|||||||
{"__iLine", (void *)v0::iLine},
|
{"__iLine", (void *)v0::iLine},
|
||||||
{"__iPin", (void *)v0::iPin},
|
{"__iPin", (void *)v0::iPin},
|
||||||
|
|
||||||
|
{"__CreateDeviceFile", (void *)v0::CreateDeviceFile},
|
||||||
{"__RegisterDevice", (void *)v0::RegisterDevice},
|
{"__RegisterDevice", (void *)v0::RegisterDevice},
|
||||||
{"__UnregisterDevice", (void *)v0::UnregisterDevice},
|
{"__UnregisterDevice", (void *)v0::UnregisterDevice},
|
||||||
{"__ReportInputEvent", (void *)v0::ReportInputEvent},
|
{"__ReportInputEvent", (void *)v0::ReportInputEvent},
|
||||||
|
@ -40,23 +40,14 @@ namespace Driver
|
|||||||
* min:
|
* min:
|
||||||
* 0 - <ROOT>
|
* 0 - <ROOT>
|
||||||
* 1 - /proc/self
|
* 1 - /proc/self
|
||||||
* 2 - /dev/null
|
|
||||||
* 3 - /dev/zero
|
|
||||||
* 4 - /dev/random
|
|
||||||
* 5 - /dev/mem
|
|
||||||
* 6 - /dev/kcon
|
|
||||||
* 7 - /dev/tty
|
|
||||||
* 8 - /dev/ptmx
|
|
||||||
*
|
*
|
||||||
* maj = 1
|
* maj = 1
|
||||||
* min:
|
* min:
|
||||||
* 0 - /dev/input/keyboard
|
* 0 - /dev/input/keyboard
|
||||||
* 1 - /dev/input/mouse
|
* 1 - /dev/input/mouse
|
||||||
* ..- /dev/input/eventX
|
* ..- /dev/input/eventN
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TTY::PTMXDevice *ptmx = nullptr;
|
|
||||||
|
|
||||||
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||||
{
|
{
|
||||||
func("%#lx %s %#lx", _Parent, Name, Result);
|
func("%#lx %s %#lx", _Parent, Name, Result);
|
||||||
@ -99,8 +90,10 @@ namespace Driver
|
|||||||
_dev->Parent = nullptr;
|
_dev->Parent = nullptr;
|
||||||
_dev->ParentInode = _Parent;
|
_dev->ParentInode = _Parent;
|
||||||
_dev->Name = Name;
|
_dev->Name = Name;
|
||||||
|
_dev->Node.Device = Parent->Node.Device;
|
||||||
_dev->Node.Mode = Mode;
|
_dev->Node.Mode = Mode;
|
||||||
_dev->Node.Index = Parent->Node.Index + Parent->Children.size();
|
_dev->Node.Index = Parent->Node.Index + Parent->Children.size();
|
||||||
|
_dev->Node.Offset = Parent->Children.size();
|
||||||
Parent->Children.push_back(_dev);
|
Parent->Children.push_back(_dev);
|
||||||
|
|
||||||
*Result = &_dev->Node;
|
*Result = &_dev->Node;
|
||||||
@ -112,61 +105,6 @@ namespace Driver
|
|||||||
func("%#lx %d %d", Node, Size, Offset);
|
func("%#lx %d %d", Node, Size, Offset);
|
||||||
switch (Node->GetMajor())
|
switch (Node->GetMajor())
|
||||||
{
|
{
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
switch (Node->GetMinor())
|
|
||||||
{
|
|
||||||
case 2: /* /dev/null */
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case 3: /* /dev/zero */
|
|
||||||
{
|
|
||||||
if (Size <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memset(Buffer, 0, Size);
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
case 4: /* /dev/random */
|
|
||||||
{
|
|
||||||
if (Size <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (Size < sizeof(uint64_t))
|
|
||||||
{
|
|
||||||
uint8_t *buf = (uint8_t *)Buffer;
|
|
||||||
for (size_t i = 0; i < Size; i++)
|
|
||||||
buf[i] = (uint8_t)(Random::rand16() & 0xFF);
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t *buf = (uint64_t *)Buffer;
|
|
||||||
for (size_t i = 0; i < Size / sizeof(uint64_t); i++)
|
|
||||||
buf[i] = Random::rand64();
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
case 5: /* /dev/mem */
|
|
||||||
{
|
|
||||||
stub;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case 6: /* /dev/kcon */
|
|
||||||
return KernelConsole::CurrentTerminal.load()->Read(Buffer, Size, Offset);
|
|
||||||
case 7: /* /dev/tty */
|
|
||||||
{
|
|
||||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
|
||||||
if (tty == nullptr)
|
|
||||||
return -ENOTTY;
|
|
||||||
return tty->Read(Buffer, Size, Offset);
|
|
||||||
}
|
|
||||||
case 8: /* /dev/ptmx */
|
|
||||||
return -ENOSYS;
|
|
||||||
default:
|
|
||||||
return -ENOENT;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
switch (Node->GetMinor())
|
switch (Node->GetMinor())
|
||||||
@ -231,42 +169,6 @@ namespace Driver
|
|||||||
|
|
||||||
switch (Node->GetMajor())
|
switch (Node->GetMajor())
|
||||||
{
|
{
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
switch (Node->GetMinor())
|
|
||||||
{
|
|
||||||
case 2: /* /dev/null */
|
|
||||||
{
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
case 3: /* /dev/zero */
|
|
||||||
{
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
case 4: /* /dev/random */
|
|
||||||
{
|
|
||||||
return Size;
|
|
||||||
}
|
|
||||||
case 5: /* /dev/mem */
|
|
||||||
{
|
|
||||||
stub;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case 6: /* /dev/kcon */
|
|
||||||
return KernelConsole::CurrentTerminal.load()->Write(Buffer, Size, Offset);
|
|
||||||
case 7: /* /dev/tty */
|
|
||||||
{
|
|
||||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
|
||||||
if (tty == nullptr)
|
|
||||||
return -ENOTTY;
|
|
||||||
return tty->Write(Buffer, Size, Offset);
|
|
||||||
}
|
|
||||||
case 8: /* /dev/ptmx */
|
|
||||||
return -ENOSYS;
|
|
||||||
default:
|
|
||||||
return -ENOENT;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
switch (Node->GetMinor())
|
switch (Node->GetMinor())
|
||||||
@ -309,30 +211,6 @@ namespace Driver
|
|||||||
|
|
||||||
switch (Node->GetMajor())
|
switch (Node->GetMajor())
|
||||||
{
|
{
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
switch (Node->GetMinor())
|
|
||||||
{
|
|
||||||
case 2: /* /dev/null */
|
|
||||||
case 3: /* /dev/zero */
|
|
||||||
case 4: /* /dev/random */
|
|
||||||
case 5: /* /dev/mem */
|
|
||||||
return -ENOSYS;
|
|
||||||
case 6: /* /dev/kcon */
|
|
||||||
return KernelConsole::CurrentTerminal.load()->Open(Flags, Mode);
|
|
||||||
case 7: /* /dev/tty */
|
|
||||||
{
|
|
||||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
|
||||||
if (tty == nullptr)
|
|
||||||
return -ENOTTY;
|
|
||||||
return tty->Open(Flags, Mode);
|
|
||||||
}
|
|
||||||
case 8: /* /dev/ptmx */
|
|
||||||
return ptmx->Open();
|
|
||||||
default:
|
|
||||||
return -ENOENT;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
switch (Node->GetMinor())
|
switch (Node->GetMinor())
|
||||||
@ -370,30 +248,6 @@ namespace Driver
|
|||||||
|
|
||||||
switch (Node->GetMajor())
|
switch (Node->GetMajor())
|
||||||
{
|
{
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
switch (Node->GetMinor())
|
|
||||||
{
|
|
||||||
case 2: /* /dev/null */
|
|
||||||
case 3: /* /dev/zero */
|
|
||||||
case 4: /* /dev/random */
|
|
||||||
case 5: /* /dev/mem */
|
|
||||||
return -ENOSYS;
|
|
||||||
case 6: /* /dev/kcon */
|
|
||||||
return KernelConsole::CurrentTerminal.load()->Close();
|
|
||||||
case 7: /* /dev/tty */
|
|
||||||
{
|
|
||||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
|
||||||
if (tty == nullptr)
|
|
||||||
return -ENOTTY;
|
|
||||||
return tty->Close();
|
|
||||||
}
|
|
||||||
case 8: /* /dev/ptmx */
|
|
||||||
return ptmx->Close();
|
|
||||||
default:
|
|
||||||
return -ENOENT;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
switch (Node->GetMinor())
|
switch (Node->GetMinor())
|
||||||
@ -431,31 +285,6 @@ namespace Driver
|
|||||||
|
|
||||||
switch (Node->GetMajor())
|
switch (Node->GetMajor())
|
||||||
{
|
{
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
switch (Node->GetMinor())
|
|
||||||
{
|
|
||||||
case 2: /* /dev/null */
|
|
||||||
case 3: /* /dev/zero */
|
|
||||||
case 4: /* /dev/random */
|
|
||||||
case 5: /* /dev/mem */
|
|
||||||
return -ENOSYS;
|
|
||||||
case 6: /* /dev/kcon */
|
|
||||||
return KernelConsole::CurrentTerminal.load()->Ioctl(Request, Argp);
|
|
||||||
case 7: /* /dev/tty */
|
|
||||||
{
|
|
||||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
|
||||||
if (tty == nullptr)
|
|
||||||
return -ENOTTY;
|
|
||||||
return tty->Ioctl(Request, Argp);
|
|
||||||
}
|
|
||||||
case 8: /* /dev/ptmx */
|
|
||||||
return -ENOSYS;
|
|
||||||
default:
|
|
||||||
return -ENOENT;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
switch (Node->GetMinor())
|
switch (Node->GetMinor())
|
||||||
@ -666,8 +495,7 @@ namespace Driver
|
|||||||
|
|
||||||
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
||||||
{
|
{
|
||||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||||
DriverManager->GetDrivers();
|
|
||||||
const auto it = drivers.find(DriverID);
|
const auto it = drivers.find(DriverID);
|
||||||
if (it == drivers.end())
|
if (it == drivers.end())
|
||||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||||
@ -696,10 +524,46 @@ namespace Driver
|
|||||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
|
||||||
|
{
|
||||||
|
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||||
|
const auto it = drivers.find(DriverID);
|
||||||
|
if (it == drivers.end())
|
||||||
|
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||||
|
const Driver::DriverObject *drv = &it->second;
|
||||||
|
|
||||||
|
auto dop = drv->DeviceOperations;
|
||||||
|
for (size_t i = 0; i < 128; i++)
|
||||||
|
{
|
||||||
|
const auto dOps = dop->find(i);
|
||||||
|
if (dOps != dop->end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FileNode *node = fs->GetByPath(name, devNode);
|
||||||
|
if (node)
|
||||||
|
ReturnLogError(-EEXIST, "Device file %s already exists", name);
|
||||||
|
|
||||||
|
node = fs->Create(devNode, name, mode);
|
||||||
|
if (node == nullptr)
|
||||||
|
ReturnLogError(-ENOMEM, "Failed to create device file %s", name);
|
||||||
|
|
||||||
|
node->Node->SetDevice(DriverID, i);
|
||||||
|
|
||||||
|
DriverHandlers dh{};
|
||||||
|
dh.Ops = Operations;
|
||||||
|
dh.Node = node->Node;
|
||||||
|
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||||
|
dop->insert({i, std::move(dh)});
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||||
|
return -1; /* -Werror=return-type */
|
||||||
|
}
|
||||||
|
|
||||||
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
|
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
|
||||||
{
|
{
|
||||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||||
DriverManager->GetDrivers();
|
|
||||||
const auto it = drivers.find(DriverID);
|
const auto it = drivers.find(DriverID);
|
||||||
if (it == drivers.end())
|
if (it == drivers.end())
|
||||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||||
@ -715,6 +579,22 @@ namespace Driver
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *Manager::AllocateMemory(dev_t DriverID, size_t Pages)
|
||||||
|
{
|
||||||
|
auto itr = Drivers.find(DriverID);
|
||||||
|
assert(itr != Drivers.end());
|
||||||
|
void *ptr = itr->second.vma->RequestPages(Pages);
|
||||||
|
memset(ptr, 0, FROM_PAGES(Pages));
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
|
||||||
|
{
|
||||||
|
auto itr = Drivers.find(DriverID);
|
||||||
|
assert(itr != Drivers.end());
|
||||||
|
itr->second.vma->FreePages(Pointer, Pages);
|
||||||
|
}
|
||||||
|
|
||||||
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
|
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
|
||||||
{
|
{
|
||||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||||
@ -753,8 +633,6 @@ namespace Driver
|
|||||||
|
|
||||||
void Manager::InitializeDaemonFS()
|
void Manager::InitializeDaemonFS()
|
||||||
{
|
{
|
||||||
ptmx = new TTY::PTMXDevice;
|
|
||||||
|
|
||||||
dev_t MinorID = 0;
|
dev_t MinorID = 0;
|
||||||
DeviceInode *_dev = new DeviceInode;
|
DeviceInode *_dev = new DeviceInode;
|
||||||
_dev->Name = "dev";
|
_dev->Name = "dev";
|
||||||
@ -775,12 +653,21 @@ namespace Driver
|
|||||||
fsi->SuperOps = {};
|
fsi->SuperOps = {};
|
||||||
fsi->Ops.Lookup = __fs_Lookup;
|
fsi->Ops.Lookup = __fs_Lookup;
|
||||||
fsi->Ops.Create = __fs_Create;
|
fsi->Ops.Create = __fs_Create;
|
||||||
|
fsi->Ops.Remove = nullptr;
|
||||||
|
fsi->Ops.Rename = nullptr;
|
||||||
fsi->Ops.Read = __fs_Read;
|
fsi->Ops.Read = __fs_Read;
|
||||||
fsi->Ops.Write = __fs_Write;
|
fsi->Ops.Write = __fs_Write;
|
||||||
|
fsi->Ops.Truncate = nullptr;
|
||||||
fsi->Ops.Open = __fs_Open;
|
fsi->Ops.Open = __fs_Open;
|
||||||
fsi->Ops.Close = __fs_Close;
|
fsi->Ops.Close = __fs_Close;
|
||||||
fsi->Ops.Ioctl = __fs_Ioctl;
|
fsi->Ops.Ioctl = __fs_Ioctl;
|
||||||
fsi->Ops.ReadDir = __fs_Readdir;
|
fsi->Ops.ReadDir = __fs_Readdir;
|
||||||
|
fsi->Ops.MkDir = nullptr;
|
||||||
|
fsi->Ops.RmDir = nullptr;
|
||||||
|
fsi->Ops.SymLink = nullptr;
|
||||||
|
fsi->Ops.ReadLink = nullptr;
|
||||||
|
fsi->Ops.Seek = nullptr;
|
||||||
|
fsi->Ops.Stat = nullptr;
|
||||||
|
|
||||||
dev->Device = fs->RegisterFileSystem(fsi, dev);
|
dev->Device = fs->RegisterFileSystem(fsi, dev);
|
||||||
dev->SetDevice(0, MinorID++);
|
dev->SetDevice(0, MinorID++);
|
||||||
@ -820,57 +707,6 @@ namespace Driver
|
|||||||
p1->Children.push_back(device);
|
p1->Children.push_back(device);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* c rw- rw- rw- */
|
|
||||||
mode = S_IRUSR | S_IWUSR |
|
|
||||||
S_IRGRP | S_IWGRP |
|
|
||||||
S_IROTH | S_IWOTH |
|
|
||||||
S_IFCHR;
|
|
||||||
createDevice(_dev, devNode, "null", 0, MinorID++, mode);
|
|
||||||
|
|
||||||
/* c rw- rw- rw- */
|
|
||||||
mode = S_IRUSR | S_IWUSR |
|
|
||||||
S_IRGRP | S_IWGRP |
|
|
||||||
S_IROTH | S_IWOTH |
|
|
||||||
S_IFCHR;
|
|
||||||
createDevice(_dev, devNode, "zero", 0, MinorID++, mode);
|
|
||||||
|
|
||||||
/* c rw- rw- rw- */
|
|
||||||
mode = S_IRUSR | S_IWUSR |
|
|
||||||
S_IRGRP | S_IWGRP |
|
|
||||||
S_IROTH | S_IWOTH |
|
|
||||||
S_IFCHR;
|
|
||||||
createDevice(_dev, devNode, "random", 0, MinorID++, mode);
|
|
||||||
|
|
||||||
/* c rw- r-- --- */
|
|
||||||
mode = S_IRUSR | S_IWUSR |
|
|
||||||
S_IRGRP |
|
|
||||||
|
|
||||||
S_IFCHR;
|
|
||||||
createDevice(_dev, devNode, "mem", 0, MinorID++, mode);
|
|
||||||
|
|
||||||
/* c rw- r-- --- */
|
|
||||||
mode = S_IRUSR | S_IWUSR |
|
|
||||||
S_IRGRP |
|
|
||||||
|
|
||||||
S_IFCHR;
|
|
||||||
createDevice(_dev, devNode, "kcon", 0, MinorID++, mode);
|
|
||||||
|
|
||||||
/* c rw- rw- rw- */
|
|
||||||
mode = S_IRUSR | S_IWUSR |
|
|
||||||
S_IRGRP | S_IWGRP |
|
|
||||||
S_IRUSR | S_IWUSR |
|
|
||||||
S_IFCHR;
|
|
||||||
createDevice(_dev, devNode, "tty", 0, MinorID++, mode);
|
|
||||||
|
|
||||||
/* c rw- rw- rw- */
|
|
||||||
mode = S_IRUSR | S_IWUSR |
|
|
||||||
S_IRGRP | S_IWGRP |
|
|
||||||
S_IRUSR | S_IWUSR |
|
|
||||||
S_IFCHR;
|
|
||||||
createDevice(_dev, devNode, "ptmx", 0, MinorID++, mode);
|
|
||||||
|
|
||||||
/* ------------------------------------------------------ */
|
|
||||||
|
|
||||||
MinorID = 0;
|
MinorID = 0;
|
||||||
|
|
||||||
/* c rw- r-- --- */
|
/* c rw- r-- --- */
|
||||||
|
@ -37,6 +37,36 @@ namespace Driver
|
|||||||
void Manager::PreloadDrivers()
|
void Manager::PreloadDrivers()
|
||||||
{
|
{
|
||||||
debug("Initializing driver manager");
|
debug("Initializing driver manager");
|
||||||
|
|
||||||
|
auto &bs = __kernel_builtin_drivers_start;
|
||||||
|
auto &be = __kernel_builtin_drivers_end;
|
||||||
|
for (const BuiltInDriver *drv = bs; drv < be; ++drv)
|
||||||
|
{
|
||||||
|
debug("Loading built-in driver %s", drv->Name);
|
||||||
|
|
||||||
|
DriverObject drvObj = {};
|
||||||
|
strncpy(drvObj.Name, drv->Name, sizeof(drvObj.Name));
|
||||||
|
strncpy(drvObj.Description, drv->Description, sizeof(drvObj.Description));
|
||||||
|
strncpy(drvObj.Author, drv->Author, sizeof(drvObj.Author));
|
||||||
|
drvObj.Version.Major = drv->Version.Major;
|
||||||
|
drvObj.Version.Minor = drv->Version.Minor;
|
||||||
|
drvObj.Version.Patch = drv->Version.Patch;
|
||||||
|
drvObj.Entry = drv->Entry;
|
||||||
|
drvObj.Final = drv->Final;
|
||||||
|
drvObj.Panic = drv->Panic;
|
||||||
|
drvObj.Probe = drv->Probe;
|
||||||
|
|
||||||
|
drvObj.IsBuiltIn = true;
|
||||||
|
drvObj.BaseAddress = 0;
|
||||||
|
drvObj.EntryPoint = drv->EntryPoint;
|
||||||
|
drvObj.vma = new Memory::VirtualMemoryArea(thisProcess->PageTable);
|
||||||
|
drvObj.Path = "<builtin>";
|
||||||
|
drvObj.InterruptHandlers = new std::unordered_map<uint8_t, void *>();
|
||||||
|
drvObj.DeviceOperations = new std::unordered_map<dev_t, DriverHandlers>();
|
||||||
|
drvObj.ID = DriverIDCounter;
|
||||||
|
Drivers.insert({DriverIDCounter++, drvObj});
|
||||||
|
}
|
||||||
|
|
||||||
const char *DriverDirectory = Config.DriverDirectory;
|
const char *DriverDirectory = Config.DriverDirectory;
|
||||||
FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr);
|
FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr);
|
||||||
if (!drvDirNode)
|
if (!drvDirNode)
|
||||||
@ -58,13 +88,15 @@ namespace Driver
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DriverObject drvObj = {.BaseAddress = 0,
|
DriverObject drvObj = {};
|
||||||
.EntryPoint = 0,
|
drvObj.IsBuiltIn = false;
|
||||||
.vma = new Memory::VirtualMemoryArea(thisProcess->PageTable),
|
drvObj.BaseAddress = 0;
|
||||||
.Path = drvNode->Path,
|
drvObj.EntryPoint = 0;
|
||||||
.InterruptHandlers = new std::unordered_map<uint8_t, void *>(),
|
drvObj.vma = new Memory::VirtualMemoryArea(thisProcess->PageTable);
|
||||||
.DeviceOperations = new std::unordered_map<dev_t, DriverHandlers>(),
|
drvObj.Path = drvNode->Path;
|
||||||
.ID = DriverIDCounter};
|
drvObj.InterruptHandlers = new std::unordered_map<uint8_t, void *>();
|
||||||
|
drvObj.DeviceOperations = new std::unordered_map<dev_t, DriverHandlers>();
|
||||||
|
drvObj.ID = DriverIDCounter;
|
||||||
|
|
||||||
int err = this->LoadDriverFile(drvObj, drvNode);
|
int err = this->LoadDriverFile(drvObj, drvNode);
|
||||||
debug("err = %d (%s)", err, strerror(err));
|
debug("err = %d (%s)", err, strerror(err));
|
||||||
@ -111,7 +143,7 @@ namespace Driver
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
KPrint("Loading driver %s", Drv.Name);
|
KPrint("Loading driver %s (%d)", Drv.Name, Drv.ID);
|
||||||
|
|
||||||
debug("Calling Probe()=%#lx on driver %s",
|
debug("Calling Probe()=%#lx on driver %s",
|
||||||
Drv.Probe, Drv.Path.c_str());
|
Drv.Probe, Drv.Path.c_str());
|
||||||
@ -514,6 +546,102 @@ namespace Driver
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::ReloadDriver(dev_t driverID)
|
||||||
|
{
|
||||||
|
auto it = Drivers.find(driverID);
|
||||||
|
if (it == Drivers.end())
|
||||||
|
{
|
||||||
|
error("Driver with ID %d not found", driverID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DriverObject &Drv = it->second;
|
||||||
|
if (!Drv.Initialized)
|
||||||
|
{
|
||||||
|
error("Driver %s is not initialized", Drv.Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Reloading driver %s", Drv.Name);
|
||||||
|
|
||||||
|
/* Unload the driver */
|
||||||
|
int err = Drv.Final();
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
warn("Failed to unload driver %s: %s", Drv.Name, strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free resources */
|
||||||
|
Drv.vma->FreeAllPages();
|
||||||
|
delete Drv.vma;
|
||||||
|
delete Drv.InterruptHandlers;
|
||||||
|
delete Drv.DeviceOperations;
|
||||||
|
|
||||||
|
/* Reload the driver */
|
||||||
|
FileNode *drvNode = fs->GetByPath(Drv.Path.c_str(), nullptr);
|
||||||
|
if (!drvNode)
|
||||||
|
{
|
||||||
|
error("Failed to open driver file %s", Drv.Path.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DriverObject newDrvObj = {};
|
||||||
|
newDrvObj.IsBuiltIn = false;
|
||||||
|
newDrvObj.BaseAddress = 0;
|
||||||
|
newDrvObj.EntryPoint = 0;
|
||||||
|
newDrvObj.vma = new Memory::VirtualMemoryArea(thisProcess->PageTable);
|
||||||
|
newDrvObj.Path = drvNode->Path;
|
||||||
|
newDrvObj.InterruptHandlers = new std::unordered_map<uint8_t, void *>();
|
||||||
|
newDrvObj.DeviceOperations = new std::unordered_map<dev_t, DriverHandlers>();
|
||||||
|
newDrvObj.ID = driverID;
|
||||||
|
|
||||||
|
err = this->LoadDriverFile(newDrvObj, drvNode);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
error("Failed to load driver %s: %s", drvNode->Path.c_str(), strerror(err));
|
||||||
|
delete newDrvObj.vma;
|
||||||
|
delete newDrvObj.InterruptHandlers;
|
||||||
|
delete newDrvObj.DeviceOperations;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Drivers[driverID] = newDrvObj;
|
||||||
|
|
||||||
|
/* Initialize the driver */
|
||||||
|
int (*DrvInit)(dev_t) = (int (*)(dev_t))newDrvObj.EntryPoint;
|
||||||
|
newDrvObj.ErrorCode = DrvInit(newDrvObj.ID);
|
||||||
|
if (newDrvObj.ErrorCode < 0)
|
||||||
|
{
|
||||||
|
KPrint("FATAL: _start() failed for %s: %s", newDrvObj.Name, strerror(newDrvObj.ErrorCode));
|
||||||
|
error("Failed to load driver %s: %s", newDrvObj.Path.c_str(), strerror(newDrvObj.ErrorCode));
|
||||||
|
newDrvObj.vma->FreeAllPages();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrint("Loading driver %s", newDrvObj.Name);
|
||||||
|
|
||||||
|
newDrvObj.ErrorCode = newDrvObj.Probe();
|
||||||
|
if (newDrvObj.ErrorCode < 0)
|
||||||
|
{
|
||||||
|
KPrint("Probe() failed for %s: %s", newDrvObj.Name, strerror(newDrvObj.ErrorCode));
|
||||||
|
error("Failed to probe driver %s: %s", newDrvObj.Path.c_str(), strerror(newDrvObj.ErrorCode));
|
||||||
|
newDrvObj.vma->FreeAllPages();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newDrvObj.ErrorCode = newDrvObj.Entry();
|
||||||
|
if (newDrvObj.ErrorCode < 0)
|
||||||
|
{
|
||||||
|
KPrint("Entry() failed for %s: %s", newDrvObj.Name, strerror(newDrvObj.ErrorCode));
|
||||||
|
error("Failed to initialize driver %s: %s", newDrvObj.Path.c_str(), strerror(newDrvObj.ErrorCode));
|
||||||
|
newDrvObj.vma->FreeAllPages();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Reloaded driver %s", newDrvObj.Path.c_str());
|
||||||
|
newDrvObj.Initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
Manager::Manager() { this->InitializeDaemonFS(); }
|
Manager::Manager() { this->InitializeDaemonFS(); }
|
||||||
|
|
||||||
Manager::~Manager()
|
Manager::~Manager()
|
||||||
|
@ -887,8 +887,8 @@ namespace PCI
|
|||||||
{
|
{
|
||||||
PCIHeader0 *hdr0 = (PCIHeader0 *)Device.Header;
|
PCIHeader0 *hdr0 = (PCIHeader0 *)Device.Header;
|
||||||
|
|
||||||
uint32_t BAR[6];
|
uint32_t BAR[6] = {};
|
||||||
size_t BARsSize[6];
|
size_t BARsSize[6] = {};
|
||||||
|
|
||||||
BAR[0] = hdr0->BAR0;
|
BAR[0] = hdr0->BAR0;
|
||||||
BAR[1] = hdr0->BAR1;
|
BAR[1] = hdr0->BAR1;
|
||||||
@ -909,26 +909,46 @@ namespace PCI
|
|||||||
size_t size;
|
size_t size;
|
||||||
if ((BAR[i] & 1) == 0) /* Memory Base */
|
if ((BAR[i] & 1) == 0) /* Memory Base */
|
||||||
{
|
{
|
||||||
hdr0->BAR0 = 0xFFFFFFFF;
|
hdr0->BAR0 = UINT32_MAX;
|
||||||
size = hdr0->BAR0;
|
size = hdr0->BAR0;
|
||||||
hdr0->BAR0 = BAR[i];
|
hdr0->BAR0 = BAR[i];
|
||||||
BARsSize[i] = size & (~15);
|
|
||||||
BARsSize[i] = ~BARsSize[i] + 1;
|
/* FIXME: further testing required */
|
||||||
BARsSize[i] = BARsSize[i] & 0xFFFFFFFF;
|
// if ((BAR[i] & 0x6) == 0x4) /* 64-bit address */
|
||||||
debug("BAR%d %#lx size: %d",
|
// {
|
||||||
i, BAR[i], BARsSize[i]);
|
// hdr0->BAR1 = UINT32_MAX;
|
||||||
|
// size |= ((size_t)hdr0->BAR1 << 32);
|
||||||
|
// hdr0->BAR1 = BAR[i + 1];
|
||||||
|
// i++; /* Skip the next BAR since it's part of the 64-bit address */
|
||||||
|
// }
|
||||||
|
|
||||||
|
size = size & (~15);
|
||||||
|
size = ~size + 1;
|
||||||
|
size = size & UINT32_MAX;
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
warn("BAR%d size is zero! Device: %#x:%#x", i, Device.Header->VendorID, Device.Header->DeviceID);
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
BARsSize[i] = size;
|
||||||
}
|
}
|
||||||
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
||||||
{
|
{
|
||||||
hdr0->BAR1 = 0xFFFFFFFF;
|
hdr0->BAR1 = UINT32_MAX;
|
||||||
size = hdr0->BAR1;
|
size = hdr0->BAR1;
|
||||||
hdr0->BAR1 = BAR[i];
|
hdr0->BAR1 = BAR[i];
|
||||||
BARsSize[i] = size & (~3);
|
|
||||||
BARsSize[i] = ~BARsSize[i] + 1;
|
size = size & (~3);
|
||||||
BARsSize[i] = BARsSize[i] & 0xFFFF;
|
size = ~size + 1;
|
||||||
debug("BAR%d %#lx size: %d",
|
size = size & UINT16_MAX;
|
||||||
i, BAR[i], BARsSize[i]);
|
if (size == 0)
|
||||||
|
{
|
||||||
|
warn("BAR%d size is zero! Device: %#x:%#x", i, Device.Header->VendorID, Device.Header->DeviceID);
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
BARsSize[i] = size;
|
||||||
}
|
}
|
||||||
|
debug("BAR%d %#lx size: %zu", i, BAR[i], BARsSize[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mapping the BARs */
|
/* Mapping the BARs */
|
||||||
@ -942,24 +962,20 @@ namespace PCI
|
|||||||
uintptr_t BARBase = BAR[i] & (~15);
|
uintptr_t BARBase = BAR[i] & (~15);
|
||||||
size_t BARSize = BARsSize[i];
|
size_t BARSize = BARsSize[i];
|
||||||
|
|
||||||
debug("Mapping BAR%d %#lx-%#lx",
|
debug("Mapping BAR%d %#lx-%#lx", i, BARBase, BARBase + BARSize);
|
||||||
i, BARBase, BARBase + BARSize);
|
|
||||||
|
|
||||||
if (BARSize > 0)
|
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase,
|
||||||
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase,
|
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
||||||
BARSize, Memory::RW | Memory::PWT);
|
|
||||||
}
|
}
|
||||||
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
||||||
{
|
{
|
||||||
uintptr_t BARBase = BAR[i] & (~3);
|
uintptr_t BARBase = BAR[i] & (~3);
|
||||||
size_t BARSize = BARsSize[i];
|
size_t BARSize = BARsSize[i];
|
||||||
|
|
||||||
debug("Mapping BAR%d %#x-%#x",
|
debug("Mapping BAR%d %#x-%#x", i, BARBase, BARBase + BARSize);
|
||||||
i, BARBase, BARBase + BARSize);
|
|
||||||
|
|
||||||
if (BARSize > 0)
|
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase,
|
||||||
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase,
|
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
||||||
BARSize, Memory::RW | Memory::PWT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -982,6 +998,18 @@ namespace PCI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::InitializeDevice(PCIDevice Device, Memory::PageTable *Table)
|
||||||
|
{
|
||||||
|
this->MapPCIAddresses(Device, Table);
|
||||||
|
|
||||||
|
PCI::PCIDeviceHeader *Header = Device.Header;
|
||||||
|
|
||||||
|
Header->Command |= PCI_COMMAND_MASTER |
|
||||||
|
PCI_COMMAND_IO |
|
||||||
|
PCI_COMMAND_MEMORY;
|
||||||
|
Header->Command &= ~PCI_COMMAND_INTX_DISABLE;
|
||||||
|
}
|
||||||
|
|
||||||
void Manager::EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev)
|
void Manager::EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev)
|
||||||
{
|
{
|
||||||
dev.Function = Function;
|
dev.Function = Function;
|
||||||
|
820
Kernel/drivers/audio/ac97/ac97.cpp
Normal file
820
Kernel/drivers/audio/ac97/ac97.cpp
Normal file
@ -0,0 +1,820 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
#include <pci.hpp>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
extern PCI::Manager *PCIManager;
|
||||||
|
namespace Driver::AC97
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
#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:
|
||||||
|
PCI::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)
|
||||||
|
{
|
||||||
|
info("Invalid buffer.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Size == 0) || (Size % (SampleSize * Channels)))
|
||||||
|
{
|
||||||
|
info("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)
|
||||||
|
v0::Sleep(DriverID, 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)
|
||||||
|
{
|
||||||
|
info("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(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
uint16_t Status = inw(MixerAddress + PCMOUT_Status);
|
||||||
|
if (Status & TC_IOCInterruptEnable)
|
||||||
|
{
|
||||||
|
debug("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);
|
||||||
|
info("FIXME: CurrentBDL: %d, LastBDL: %d", CurrentBDL, LastBDL);
|
||||||
|
}
|
||||||
|
else if (Status & TC_LastBufferEntryInterruptEnable)
|
||||||
|
{
|
||||||
|
debug("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)
|
||||||
|
{
|
||||||
|
info("FIFO error");
|
||||||
|
outw(MixerAddress + PCMOUT_Status, TC_FifoERRORInterruptEnable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug("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(PCI::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 *)v0::AllocateMemory(DriverID, 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)v0::AllocateMemory(DriverID, TO_PAGES(sizeof(uint16_t *)));
|
||||||
|
DescriptorList[i].SampleCount = DLSampleCount;
|
||||||
|
DescriptorList[i].Flags = 0;
|
||||||
|
debug("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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<dev_t, AC97Device *> Drivers;
|
||||||
|
|
||||||
|
int Open(struct Inode *, int, mode_t)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Close(struct Inode *)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Read(struct Inode *, void *, size_t, off_t)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
||||||
|
{
|
||||||
|
return Drivers[Node->GetMinor()]->write((uint8_t *)Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
return Drivers[Node->GetMinor()]->ioctl((AudioIoctl)Request, Argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct InodeOperations ops = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = Read,
|
||||||
|
.Write = Write,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = Open,
|
||||||
|
.Close = Close,
|
||||||
|
.Ioctl = Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = nullptr,
|
||||||
|
.Stat = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::list<PCI::PCIDevice> Devices;
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
for (auto &&dev : Devices)
|
||||||
|
{
|
||||||
|
PCIManager->InitializeDevice(dev, KernelPageTable);
|
||||||
|
AC97Device *ac97 = new AC97Device((PCI::PCIHeader0 *)dev.Header);
|
||||||
|
dev_t ret = v0::RegisterDevice(DriverID, NETWORK_TYPE_ETHERNET, &ops);
|
||||||
|
Drivers[ret] = ac97;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Drivers.empty())
|
||||||
|
{
|
||||||
|
info("No valid AC'97 device found.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
for (auto &&dev : Drivers)
|
||||||
|
{
|
||||||
|
dev_t ret = dev.first;
|
||||||
|
v0::UnregisterDevice(DriverID, ret);
|
||||||
|
delete dev.second;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic()
|
||||||
|
{
|
||||||
|
for (auto &&i : Drivers)
|
||||||
|
i.second->Panic();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Probe()
|
||||||
|
{
|
||||||
|
Devices = PCIManager->FindPCIDevice(
|
||||||
|
{
|
||||||
|
0x8086, /* Intel */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0x2415, /* AC'97 */
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto &&i : Devices)
|
||||||
|
{
|
||||||
|
PCI::PCIHeader0 *hdr0 = (PCI::PCIHeader0 *)i.Header;
|
||||||
|
uint8_t type = hdr0->BAR0 & 1;
|
||||||
|
if (type != 1)
|
||||||
|
{
|
||||||
|
warn("Device %x:%x.%d BAR0 is not I/O.",
|
||||||
|
hdr0->Header.VendorID,
|
||||||
|
hdr0->Header.DeviceID,
|
||||||
|
hdr0->Header.ProgIF);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Devices.empty())
|
||||||
|
{
|
||||||
|
info("No AC'97 device found.");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(ac97,
|
||||||
|
"Audio Codec '97 Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
210
Kernel/drivers/audio/hda/hda.cpp
Normal file
210
Kernel/drivers/audio/hda/hda.cpp
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
#include <pci.hpp>
|
||||||
|
#include "hda.hpp"
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
extern PCI::Manager *PCIManager;
|
||||||
|
namespace Driver::HighDefinitionAudio
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
class HDADevice
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PCI::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(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panic()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HDADevice(PCI::PCIHeader0 *_Header)
|
||||||
|
: Header(_Header),
|
||||||
|
CORB((uint32_t *)(uintptr_t)DriverManager->AllocateMemory(DriverID, 1)),
|
||||||
|
RIRB((uint64_t *)DriverManager->AllocateMemory(DriverID, 1))
|
||||||
|
{
|
||||||
|
CTL = (ControllerRegisters *)(uintptr_t)Header->BAR0;
|
||||||
|
fixme("Unimplemented HDA driver");
|
||||||
|
return;
|
||||||
|
Initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~HDADevice()
|
||||||
|
{
|
||||||
|
if (!Initialized)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<dev_t, HDADevice *> Drivers;
|
||||||
|
|
||||||
|
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
return Drivers[Node->GetMinor()]->ioctl((AudioIoctl)Request, Argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
return Drivers[Node->GetMinor()]->write((uint8_t *)Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct InodeOperations ops = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = nullptr,
|
||||||
|
.Write = Write,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = nullptr,
|
||||||
|
.Close = nullptr,
|
||||||
|
.Ioctl = Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = nullptr,
|
||||||
|
.Stat = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::list<PCI::PCIDevice> Devices;
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
for (auto &&dev : Devices)
|
||||||
|
{
|
||||||
|
PCI::PCIHeader0 *hdr0 = (PCI::PCIHeader0 *)dev.Header;
|
||||||
|
uint8_t type = hdr0->BAR0 & 1;
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
debug("Device %x:%x.%d BAR0 is I/O.",
|
||||||
|
hdr0->Header.VendorID,
|
||||||
|
hdr0->Header.DeviceID,
|
||||||
|
hdr0->Header.ProgIF);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PCIManager->InitializeDevice(dev, KernelPageTable);
|
||||||
|
|
||||||
|
HDADevice *driver = new HDADevice((PCI::PCIHeader0 *)dev.Header);
|
||||||
|
|
||||||
|
if (driver->IsInitialized())
|
||||||
|
{
|
||||||
|
dev_t ret = v0::RegisterDevice(DriverID, AUDIO_TYPE_PCM, &ops);
|
||||||
|
Drivers[ret] = driver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Drivers.empty())
|
||||||
|
{
|
||||||
|
debug("No valid HDA device found.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
for (auto &&dev : Drivers)
|
||||||
|
{
|
||||||
|
dev_t ret = dev.first;
|
||||||
|
v0::UnregisterDevice(DriverID, ret);
|
||||||
|
delete dev.second;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic()
|
||||||
|
{
|
||||||
|
for (auto &&i : Drivers)
|
||||||
|
i.second->Panic();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Probe()
|
||||||
|
{
|
||||||
|
Devices = PCIManager->FindPCIDevice(
|
||||||
|
{
|
||||||
|
0x8086, /* Intel */
|
||||||
|
0x15AD, /* VMware */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0x9D71, /* Sunrise Point-LP HD Audio */
|
||||||
|
0x2668, /* ICH6 */
|
||||||
|
0x293E, /* ICH9 */
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Devices.empty())
|
||||||
|
{
|
||||||
|
trace("No HDA device found.");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &&dev : Devices)
|
||||||
|
{
|
||||||
|
PCI::PCIHeader0 *PCIBaseAddress = (PCI::PCIHeader0 *)dev.Header;
|
||||||
|
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
|
||||||
|
uint8_t Type = PCIBAR0 & 1;
|
||||||
|
if (Type == 1)
|
||||||
|
{
|
||||||
|
debug("Device %x:%x.%d BAR0 is I/O.",
|
||||||
|
PCIBaseAddress->Header.VendorID,
|
||||||
|
PCIBaseAddress->Header.DeviceID,
|
||||||
|
PCIBaseAddress->Header.ProgIF);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(hda,
|
||||||
|
"Intel High Definition Audio Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
@ -1,26 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of Fennix Drivers.
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License as
|
modify it under the terms of the GNU General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of
|
published by the Free Software Foundation, either version 3 of
|
||||||
the License, or (at your option) any later version.
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
struct StreamDescriptor
|
struct StreamDescriptor
|
||||||
{
|
{
|
||||||
/** Control */
|
/** Control */
|
||||||
@ -627,9 +625,3 @@ struct __ControllerRegisters
|
|||||||
|
|
||||||
StreamDescriptor SD[];
|
StreamDescriptor SD[];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
#endif
|
|
||||||
|
|
||||||
EXTERNC int cxx_Panic();
|
|
||||||
EXTERNC int cxx_Probe();
|
|
||||||
EXTERNC int cxx_Initialize();
|
|
||||||
EXTERNC int cxx_Finalize();
|
|
37
Kernel/drivers/fs/fat/fat.cpp
Normal file
37
Kernel/drivers/fs/fat/fat.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
|
||||||
|
namespace Driver::FileAllocationTable
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
int Entry() { return 0; }
|
||||||
|
int Final() { return 0; }
|
||||||
|
int Panic() { return 0; }
|
||||||
|
int Probe() { return 0; }
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(fat,
|
||||||
|
"File Allocation Table Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
@ -1,22 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of Fennix Drivers.
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License as
|
modify it under the terms of the GNU General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of
|
published by the Free Software Foundation, either version 3 of
|
||||||
the License, or (at your option) any later version.
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FENNIX_DRIVER_FAT_H__
|
#pragma once
|
||||||
#define __FENNIX_DRIVER_FAT_H__
|
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
@ -286,5 +285,3 @@ struct exFATBootRecord
|
|||||||
/** Reserved (set to 0). */
|
/** Reserved (set to 0). */
|
||||||
uint8_t Reserved2[7];
|
uint8_t Reserved2[7];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#endif // !__FENNIX_DRIVER_FAT_H__
|
|
43
Kernel/drivers/misc/aip/aip.hpp
Normal file
43
Kernel/drivers/misc/aip/aip.hpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
|
||||||
|
namespace Driver::AdvancedIntegratedPeripheral
|
||||||
|
{
|
||||||
|
extern uint8_t Device1ID[];
|
||||||
|
extern uint8_t Device2ID[];
|
||||||
|
|
||||||
|
void PS2KbdInterruptHandler(CPU::TrapFrame *);
|
||||||
|
int InitializeKeyboard();
|
||||||
|
int FinalizeKeyboard();
|
||||||
|
int DetectPS2Keyboard();
|
||||||
|
|
||||||
|
void PS2MouseInterruptHandler(CPU::TrapFrame *);
|
||||||
|
int InitializeMouse();
|
||||||
|
int FinalizeMouse();
|
||||||
|
int DetectPS2Mouse();
|
||||||
|
int DetectUART();
|
||||||
|
|
||||||
|
void MasterInterruptHandler(CPU::TrapFrame *);
|
||||||
|
void SlaveInterruptHandler(CPU::TrapFrame *);
|
||||||
|
int InitializeATA();
|
||||||
|
int FinalizeATA();
|
||||||
|
}
|
70
Kernel/drivers/misc/aip/ata.cpp
Normal file
70
Kernel/drivers/misc/aip/ata.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
#include <pci.hpp>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
extern PCI::Manager *PCIManager;
|
||||||
|
namespace Driver::AdvancedIntegratedPeripheral
|
||||||
|
{
|
||||||
|
extern dev_t DriverID;
|
||||||
|
|
||||||
|
const struct InodeOperations opsATA = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = nullptr,
|
||||||
|
.Write = nullptr,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = nullptr,
|
||||||
|
.Close = nullptr,
|
||||||
|
.Ioctl = nullptr,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = nullptr,
|
||||||
|
.Stat = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
void MasterInterruptHandler(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlaveInterruptHandler(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int InitializeATA()
|
||||||
|
{
|
||||||
|
v0::RegisterInterruptHandler(DriverID, 14, (void *)MasterInterruptHandler);
|
||||||
|
v0::RegisterInterruptHandler(DriverID, 15, (void *)SlaveInterruptHandler);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FinalizeATA()
|
||||||
|
{
|
||||||
|
v0::UnregisterInterruptHandler(DriverID, 14, (void *)MasterInterruptHandler);
|
||||||
|
v0::UnregisterInterruptHandler(DriverID, 15, (void *)SlaveInterruptHandler);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
224
Kernel/drivers/misc/aip/keyboard.cpp
Normal file
224
Kernel/drivers/misc/aip/keyboard.cpp
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
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.hpp"
|
||||||
|
|
||||||
|
#include <driver.hpp>
|
||||||
|
#include <interface/input.h>
|
||||||
|
#include <interface/aip.h>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
extern const unsigned short ScanCodeSet1[];
|
||||||
|
extern const unsigned short ScanCodeSet1mm[];
|
||||||
|
extern const unsigned short ScanCodeSet3[];
|
||||||
|
|
||||||
|
namespace Driver::AdvancedIntegratedPeripheral
|
||||||
|
{
|
||||||
|
extern dev_t DriverID;
|
||||||
|
uint8_t KeyboardScanCodeSet = 0;
|
||||||
|
dev_t KeyboardDevID = -1;
|
||||||
|
|
||||||
|
InputReport kir = {};
|
||||||
|
int ReportKeyboardEvent(dev_t Device, const unsigned short ScanCode, uint8_t Pressed)
|
||||||
|
{
|
||||||
|
kir.Type = INPUT_TYPE_KEYBOARD;
|
||||||
|
kir.Device = Device;
|
||||||
|
kir.Keyboard.Key = (KeyScanCodes)(ScanCode);
|
||||||
|
kir.Keyboard.Key = (KeyScanCodes)((int)kir.Keyboard.Key | (Pressed ? KEY_PRESSED : 0));
|
||||||
|
// kir.Keyboard.Key |= Pressed ? KEY_PRESSED : 0;
|
||||||
|
v0::ReportInputEvent(DriverID, &kir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsE0 = false;
|
||||||
|
bool IsE1 = false;
|
||||||
|
void PS2KbdInterruptHandler(CPU::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;
|
||||||
|
trace("Unknown PS/2 Keyboard Scan Code Set: %#x", KeyboardScanCodeSet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int __fs_kb_Ioctl(struct Inode *, unsigned long, void *)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct InodeOperations KbdOps = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = nullptr,
|
||||||
|
.Write = nullptr,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = nullptr,
|
||||||
|
.Close = nullptr,
|
||||||
|
.Ioctl = __fs_kb_Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = nullptr,
|
||||||
|
.Stat = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
int InitializeKeyboard()
|
||||||
|
{
|
||||||
|
// v0::PS2WriteData(DriverID, PS2_KBD_CMD_RESET);
|
||||||
|
// uint8_t test = v0::PS2ReadData(DriverID);
|
||||||
|
// if (test != PS2_KBD_RESP_TEST_PASSED &&
|
||||||
|
// test != PS2_KBD_RESP_ACK)
|
||||||
|
// {
|
||||||
|
// trace("PS/2 keyboard reset failed (%#x)", test);
|
||||||
|
// return -EFAULT;
|
||||||
|
// }
|
||||||
|
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_CMD_DEFAULTS);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 keyboard failed to set defaults");
|
||||||
|
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_CMD_SCAN_CODE_SET);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 keyboard failed to set scan code set");
|
||||||
|
|
||||||
|
/* We want Scan Code Set 1 */
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_SCAN_CODE_SET_2); /* It will set to 1 but with translation? */
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 keyboard failed to set scan code set 2");
|
||||||
|
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_CMD_SCAN_CODE_SET);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 keyboard failed to set scan code set");
|
||||||
|
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_SCAN_CODE_GET_CURRENT);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 keyboard failed to get current scan code set");
|
||||||
|
|
||||||
|
KeyboardScanCodeSet = v0::PS2ReadAfterACK(DriverID);
|
||||||
|
trace("PS/2 Keyboard Scan Code Set: 0x%X", KeyboardScanCodeSet);
|
||||||
|
v0::PS2ClearOutputBuffer(DriverID);
|
||||||
|
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_CMD_ENABLE_SCANNING);
|
||||||
|
|
||||||
|
v0::RegisterInterruptHandler(DriverID, 1, (void *)PS2KbdInterruptHandler);
|
||||||
|
|
||||||
|
KeyboardDevID = v0::RegisterDevice(DriverID, INPUT_TYPE_KEYBOARD, &KbdOps);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FinalizeKeyboard()
|
||||||
|
{
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_CMD_DISABLE_SCANNING);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 keyboard failed to disable scanning");
|
||||||
|
|
||||||
|
v0::UnregisterDevice(DriverID, KeyboardDevID);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DetectPS2Keyboard()
|
||||||
|
{
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_CMD_DISABLE_SCANNING);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 keyboard failed to disable scanning");
|
||||||
|
|
||||||
|
v0::PS2WriteData(DriverID, PS2_KBD_CMD_IDENTIFY);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 keyboard failed to identify");
|
||||||
|
|
||||||
|
uint8_t recByte;
|
||||||
|
int timeout = 1000000;
|
||||||
|
while (timeout--)
|
||||||
|
{
|
||||||
|
recByte = v0::PS2ReadData(DriverID);
|
||||||
|
if (recByte != PS2_ACK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Device1ID[0] = recByte;
|
||||||
|
|
||||||
|
timeout = 1000000;
|
||||||
|
while (timeout--)
|
||||||
|
{
|
||||||
|
recByte = v0::PS2ReadData(DriverID);
|
||||||
|
if (recByte != PS2_ACK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (timeout == 0)
|
||||||
|
trace("PS/2 keyboard second byte timed out");
|
||||||
|
else
|
||||||
|
Device1ID[1] = recByte;
|
||||||
|
|
||||||
|
trace("PS2 Keyboard Device: 0x%X 0x%X", Device1ID[0], Device1ID[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
260
Kernel/drivers/misc/aip/main.cpp
Normal file
260
Kernel/drivers/misc/aip/main.cpp
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
#include <interface/aip.h>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
#include <pci.hpp>
|
||||||
|
|
||||||
|
#include "aip.hpp"
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
extern PCI::Manager *PCIManager;
|
||||||
|
EXTERNC void KPrint(const char *Format, ...);
|
||||||
|
namespace Driver::AdvancedIntegratedPeripheral
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
bool ATAPresent = false;
|
||||||
|
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_DISABLE_PORT_1);
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_DISABLE_PORT_2);
|
||||||
|
v0::PS2ClearOutputBuffer(DriverID);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_READ_CONFIG);
|
||||||
|
PS2_CONFIGURATION cfg = {.Raw = v0::PS2ReadData(DriverID)};
|
||||||
|
|
||||||
|
DualChannel = cfg.Port2Clock;
|
||||||
|
if (DualChannel)
|
||||||
|
trace("Dual channel PS/2 controller detected");
|
||||||
|
cfg.Port1Interrupt = 1;
|
||||||
|
cfg.Port2Interrupt = 1;
|
||||||
|
cfg.Port1Translation = 1;
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_CONFIG);
|
||||||
|
v0::PS2WriteData(DriverID, cfg.Raw);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_TEST_CONTROLLER);
|
||||||
|
uint8_t test = v0::PS2ReadData(DriverID);
|
||||||
|
if (test != PS2_TEST_PASSED)
|
||||||
|
{
|
||||||
|
trace("PS/2 controller self test failed (%#x)", test);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_CONFIG);
|
||||||
|
v0::PS2WriteData(DriverID, cfg.Raw);
|
||||||
|
|
||||||
|
// bool port2avail = false;
|
||||||
|
// if (DualChannel)
|
||||||
|
// {
|
||||||
|
// v0::PS2WriteCommand(DriverID, PS2_CMD_ENABLE_PORT_1);
|
||||||
|
// v0::PS2WriteCommand(DriverID, PS2_CMD_READ_CONFIG);
|
||||||
|
// cfg.Raw = v0::PS2ReadData(DriverID);
|
||||||
|
// port2avail = cfg.Port2Clock;
|
||||||
|
// v0::PS2WriteCommand(DriverID, PS2_CMD_DISABLE_PORT_1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_TEST_PORT_1);
|
||||||
|
test = v0::PS2ReadData(DriverID);
|
||||||
|
if (test != 0x00)
|
||||||
|
{
|
||||||
|
trace("PS/2 Port 1 self test failed (%#x)", test);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DualChannel)
|
||||||
|
{
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_TEST_PORT_2);
|
||||||
|
test = v0::PS2ReadData(DriverID);
|
||||||
|
if (test != 0x00)
|
||||||
|
{
|
||||||
|
trace("PS/2 Port 2 self test failed (%#x)", test);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_ENABLE_PORT_1);
|
||||||
|
if (DualChannel)
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_ENABLE_PORT_2);
|
||||||
|
|
||||||
|
int errK = InitializeKeyboard();
|
||||||
|
|
||||||
|
int errM = 0;
|
||||||
|
if (DualChannel)
|
||||||
|
errM = InitializeMouse();
|
||||||
|
|
||||||
|
ATAPresent = IsATAPresent();
|
||||||
|
|
||||||
|
if (errK != 0 && errM != 0 && ATAPresent == false)
|
||||||
|
return -ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
FinalizeKeyboard();
|
||||||
|
FinalizeMouse();
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_DISABLE_PORT_1);
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_DISABLE_PORT_2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic()
|
||||||
|
{
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_DISABLE_PORT_1);
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_DISABLE_PORT_2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __intStub() {}
|
||||||
|
int Probe()
|
||||||
|
{
|
||||||
|
v0::RegisterInterruptHandler(DriverID, 1, (void *)__intStub);
|
||||||
|
v0::RegisterInterruptHandler(DriverID, 12, (void *)__intStub);
|
||||||
|
|
||||||
|
int kbd = DetectPS2Keyboard();
|
||||||
|
int mouse = DetectPS2Mouse();
|
||||||
|
int uart = DetectUART();
|
||||||
|
|
||||||
|
v0::UnregisterAllInterruptHandlers(DriverID, (void *)__intStub);
|
||||||
|
|
||||||
|
if (kbd != 0 && mouse != 0 && uart != 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (kbd == 0)
|
||||||
|
{
|
||||||
|
if (!IsKeyboard(Device1ID[0]))
|
||||||
|
{
|
||||||
|
trace("PS/2 Port 1 is not a keyboard");
|
||||||
|
// return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse == 0)
|
||||||
|
{
|
||||||
|
if (!IsMouse(Device2ID[0]))
|
||||||
|
{
|
||||||
|
trace("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(aip,
|
||||||
|
"Advanced Integrated Peripheral Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
263
Kernel/drivers/misc/aip/mouse.cpp
Normal file
263
Kernel/drivers/misc/aip/mouse.cpp
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
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.hpp"
|
||||||
|
|
||||||
|
#include <driver.hpp>
|
||||||
|
#include <interface/aip.h>
|
||||||
|
#include <interface/input.h>
|
||||||
|
|
||||||
|
namespace Driver::AdvancedIntegratedPeripheral
|
||||||
|
{
|
||||||
|
extern dev_t DriverID;
|
||||||
|
dev_t MouseDevID = -1;
|
||||||
|
bool PacketReady = false;
|
||||||
|
bool FourPackets = false;
|
||||||
|
bool MouseButton45 = false;
|
||||||
|
uint8_t Cycle = 0;
|
||||||
|
PS2_MOUSE_PACKET Packet = {};
|
||||||
|
|
||||||
|
InputReport mir = {};
|
||||||
|
void PS2MouseInterruptHandler(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
uint8_t data = v0::PS2ReadData(DriverID);
|
||||||
|
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')
|
||||||
|
|
||||||
|
debug("PS/2 Mouse Packet: [" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN "] LB:%d RB:%d MB:%d A1:%d XS:%d YS:%d XO:%d YO:%d | X:%03d Y:%03d | Z:%d B4:%d B5:%d A0:%d A0:%d",
|
||||||
|
BYTE_TO_BINARY(Packet.Base.Raw),
|
||||||
|
BYTE_TO_BINARY(Packet.XMovement),
|
||||||
|
BYTE_TO_BINARY(Packet.YMovement),
|
||||||
|
BYTE_TO_BINARY(Packet.ZMovement.Raw),
|
||||||
|
Packet.Base.LeftButton, Packet.Base.RightButton, Packet.Base.MiddleButton,
|
||||||
|
Packet.Base.Always1,
|
||||||
|
Packet.Base.XSign, Packet.Base.YSign,
|
||||||
|
Packet.Base.XOverflow, Packet.Base.YOverflow,
|
||||||
|
Packet.XMovement, Packet.YMovement,
|
||||||
|
Packet.ZMovement.Z, Packet.ZMovement.Button4, Packet.ZMovement.Button5,
|
||||||
|
Packet.ZMovement.Always0, Packet.ZMovement.Always0_2);
|
||||||
|
|
||||||
|
int X, Y;
|
||||||
|
X = Packet.XMovement - (Packet.Base.XSign ? 256 : 0);
|
||||||
|
Y = Packet.YMovement - (Packet.Base.YSign ? 256 : 0);
|
||||||
|
|
||||||
|
if (Packet.Base.XOverflow)
|
||||||
|
X = 0;
|
||||||
|
|
||||||
|
if (Packet.Base.YOverflow)
|
||||||
|
Y = 0;
|
||||||
|
|
||||||
|
mir.Type = INPUT_TYPE_MOUSE;
|
||||||
|
mir.Device = MouseDevID;
|
||||||
|
mir.Mouse.LeftButton = Packet.Base.LeftButton;
|
||||||
|
mir.Mouse.RightButton = Packet.Base.RightButton;
|
||||||
|
mir.Mouse.MiddleButton = Packet.Base.MiddleButton;
|
||||||
|
mir.Mouse.Button4 = Packet.ZMovement.Button4;
|
||||||
|
mir.Mouse.Button5 = Packet.ZMovement.Button5;
|
||||||
|
mir.Mouse.X = X;
|
||||||
|
mir.Mouse.Y = -Y;
|
||||||
|
mir.Mouse.Z = Packet.ZMovement.Z;
|
||||||
|
v0::ReportInputEvent(DriverID, &mir);
|
||||||
|
PacketReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseSampleRate(uint8_t SampleRate)
|
||||||
|
{
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_SET_SAMPLE_RATE);
|
||||||
|
v0::PS2ReadData(DriverID);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, SampleRate);
|
||||||
|
v0::PS2ReadData(DriverID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __fs_ms_Ioctl(struct Inode *, unsigned long, void *)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct InodeOperations MouseOps = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = nullptr,
|
||||||
|
.Write = nullptr,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = nullptr,
|
||||||
|
.Close = nullptr,
|
||||||
|
.Ioctl = __fs_ms_Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = nullptr,
|
||||||
|
.Stat = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
int InitializeMouse()
|
||||||
|
{
|
||||||
|
v0::PS2WriteData(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_RESET);
|
||||||
|
uint8_t test = v0::PS2ReadData(DriverID);
|
||||||
|
if (test != PS2_MOUSE_RESP_TEST_PASSED &&
|
||||||
|
test != PS2_MOUSE_RESP_ACK)
|
||||||
|
{
|
||||||
|
trace("PS/2 mouse reset failed! (%#x)", test);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
v0::RegisterInterruptHandler(DriverID, 12, (void *)PS2MouseInterruptHandler);
|
||||||
|
|
||||||
|
MouseDevID = v0::RegisterDevice(DriverID, INPUT_TYPE_MOUSE, &MouseOps);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_SET_DEFAULTS);
|
||||||
|
v0::PS2ReadData(DriverID);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
|
||||||
|
|
||||||
|
MouseSampleRate(200);
|
||||||
|
MouseSampleRate(100);
|
||||||
|
MouseSampleRate(80);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_READ_ID);
|
||||||
|
uint8_t Device2ID = v0::PS2ReadData(DriverID);
|
||||||
|
trace("PS/2 Mouse ID: %#x", Device2ID);
|
||||||
|
|
||||||
|
MouseSampleRate(200);
|
||||||
|
MouseSampleRate(200);
|
||||||
|
MouseSampleRate(80);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_READ_ID);
|
||||||
|
Device2ID = v0::PS2ReadData(DriverID);
|
||||||
|
trace("PS/2 Mouse ID: %#x", Device2ID);
|
||||||
|
|
||||||
|
if (Device2ID >= 3 && Device2ID <= 4)
|
||||||
|
FourPackets = true;
|
||||||
|
if (Device2ID == 4)
|
||||||
|
MouseButton45 = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FinalizeMouse()
|
||||||
|
{
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||||
|
|
||||||
|
v0::UnregisterDevice(DriverID, MouseDevID);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DetectPS2Mouse()
|
||||||
|
{
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 mouse failed to disable data reporting!");
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_READ_ID);
|
||||||
|
if (v0::PS2ACKTimeout(DriverID) != 0)
|
||||||
|
trace("PS/2 mouse failed to read ID!");
|
||||||
|
|
||||||
|
uint8_t recByte;
|
||||||
|
int timeout = 1000000;
|
||||||
|
while (timeout--)
|
||||||
|
{
|
||||||
|
recByte = v0::PS2ReadData(DriverID);
|
||||||
|
if (recByte != PS2_ACK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Device2ID[0] = recByte;
|
||||||
|
|
||||||
|
timeout = 1000000;
|
||||||
|
while (timeout--)
|
||||||
|
{
|
||||||
|
recByte = v0::PS2ReadData(DriverID);
|
||||||
|
if (recByte != PS2_ACK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Device2ID[1] = recByte;
|
||||||
|
|
||||||
|
trace("PS2 Mouse Device: 0x%X 0x%X", Device2ID[0], Device2ID[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -1,31 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of Fennix Drivers.
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License as
|
modify it under the terms of the GNU General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of
|
published by the Free Software Foundation, either version 3 of
|
||||||
the License, or (at your option) any later version.
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "aip.h"
|
#include <interface/driver.h>
|
||||||
|
#include <interface/input.h>
|
||||||
#include <driver.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fs.h>
|
|
||||||
#include <input.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <io.h>
|
|
||||||
|
|
||||||
uint8_t KeyboardScanCodeSet = 0;
|
|
||||||
dev_t KeyboardDevID = -1;
|
|
||||||
|
|
||||||
const unsigned short ScanCodeSet1[] =
|
const unsigned short ScanCodeSet1[] =
|
||||||
{KEY_NULL, KEY_ESCAPE,
|
{KEY_NULL, KEY_ESCAPE,
|
||||||
@ -161,175 +152,3 @@ const unsigned short ScanCodeSet3[] = {
|
|||||||
[0x44] = KEY_O,
|
[0x44] = KEY_O,
|
||||||
[0x4B] = KEY_L,
|
[0x4B] = KEY_L,
|
||||||
[0x4D] = KEY_P};
|
[0x4D] = KEY_P};
|
||||||
|
|
||||||
InputReport kir = {0};
|
|
||||||
int ReportKeyboardEvent(dev_t Device, KeyScanCodes ScanCode, uint8_t Pressed)
|
|
||||||
{
|
|
||||||
kir.Type = INPUT_TYPE_KEYBOARD;
|
|
||||||
kir.Device = Device;
|
|
||||||
kir.Keyboard.Key = ScanCode;
|
|
||||||
kir.Keyboard.Key |= Pressed ? KEY_PRESSED : 0;
|
|
||||||
ReportInputEvent(&kir);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsE0 = false;
|
|
||||||
bool IsE1 = false;
|
|
||||||
void PS2KbdInterruptHandler(TrapFrame *)
|
|
||||||
{
|
|
||||||
uint8_t sc = inb(PS2_DATA);
|
|
||||||
if (sc == PS2_KBD_RESP_ACK ||
|
|
||||||
sc == PS2_KBD_RESP_ECHO ||
|
|
||||||
sc == PS2_KBD_RESP_RESEND)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sc == 0xE0)
|
|
||||||
{
|
|
||||||
IsE0 = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sc == 0xE1)
|
|
||||||
{
|
|
||||||
IsE1 = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (KeyboardScanCodeSet)
|
|
||||||
{
|
|
||||||
case PS2_KBD_SC_SET_1:
|
|
||||||
case PS2_KBD_SC_SET_2:
|
|
||||||
{
|
|
||||||
if (IsE0)
|
|
||||||
{
|
|
||||||
IsE0 = false;
|
|
||||||
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet1mm[sc], sc < 0x90);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool released = sc & 0x80;
|
|
||||||
uint8_t scFinal = released ? sc & 0x7F : sc;
|
|
||||||
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet1[scFinal], !released);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* FIXME: https://wiki.osdev.org/PS/2_Keyboard */
|
|
||||||
// case PS2_KBD_SC_SET_2:
|
|
||||||
// {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
case PS2_KBD_SC_SET_3:
|
|
||||||
{
|
|
||||||
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet3[sc], true);
|
|
||||||
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet3[sc], false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (IsE0)
|
|
||||||
IsE0 = false;
|
|
||||||
KernelLog("Unknown PS/2 Keyboard Scan Code Set: %#x", KeyboardScanCodeSet);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int __fs_kb_Ioctl(struct Inode *, unsigned long, void *)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct InodeOperations KbdOps = {
|
|
||||||
.Ioctl = __fs_kb_Ioctl,
|
|
||||||
};
|
|
||||||
|
|
||||||
int InitializeKeyboard()
|
|
||||||
{
|
|
||||||
// PS2WriteData(PS2_KBD_CMD_RESET);
|
|
||||||
// uint8_t test = PS2ReadData();
|
|
||||||
// if (test != PS2_KBD_RESP_TEST_PASSED &&
|
|
||||||
// test != PS2_KBD_RESP_ACK)
|
|
||||||
// {
|
|
||||||
// KernelLog("PS/2 keyboard reset failed (%#x)", test);
|
|
||||||
// return -EFAULT;
|
|
||||||
// }
|
|
||||||
|
|
||||||
PS2WriteData(PS2_KBD_CMD_DEFAULTS);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 keyboard failed to set defaults");
|
|
||||||
|
|
||||||
PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 keyboard failed to set scan code set");
|
|
||||||
|
|
||||||
/* We want Scan Code Set 1 */
|
|
||||||
PS2WriteData(PS2_KBD_SCAN_CODE_SET_2); /* It will set to 1 but with translation? */
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 keyboard failed to set scan code set 2");
|
|
||||||
|
|
||||||
PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 keyboard failed to set scan code set");
|
|
||||||
|
|
||||||
PS2WriteData(PS2_KBD_SCAN_CODE_GET_CURRENT);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 keyboard failed to get current scan code set");
|
|
||||||
|
|
||||||
KeyboardScanCodeSet = PS2ReadAfterACK();
|
|
||||||
KernelLog("PS/2 Keyboard Scan Code Set: 0x%X", KeyboardScanCodeSet);
|
|
||||||
PS2ClearOutputBuffer();
|
|
||||||
|
|
||||||
PS2WriteData(PS2_KBD_CMD_ENABLE_SCANNING);
|
|
||||||
|
|
||||||
RegisterInterruptHandler(1, PS2KbdInterruptHandler);
|
|
||||||
|
|
||||||
KeyboardDevID = RegisterDevice(INPUT_TYPE_KEYBOARD, &KbdOps);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FinalizeKeyboard()
|
|
||||||
{
|
|
||||||
PS2WriteData(PS2_KBD_CMD_DISABLE_SCANNING);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 keyboard failed to disable scanning");
|
|
||||||
|
|
||||||
UnregisterDevice(KeyboardDevID);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DetectPS2Keyboard()
|
|
||||||
{
|
|
||||||
PS2WriteData(PS2_KBD_CMD_DISABLE_SCANNING);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 keyboard failed to disable scanning");
|
|
||||||
|
|
||||||
PS2WriteData(PS2_KBD_CMD_IDENTIFY);
|
|
||||||
if (PS2ACKTimeout() != 0)
|
|
||||||
KernelLog("PS/2 keyboard failed to identify");
|
|
||||||
|
|
||||||
uint8_t recByte;
|
|
||||||
int timeout = 1000000;
|
|
||||||
while (timeout--)
|
|
||||||
{
|
|
||||||
recByte = PS2ReadData();
|
|
||||||
if (recByte != PS2_ACK)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Device1ID[0] = recByte;
|
|
||||||
|
|
||||||
timeout = 1000000;
|
|
||||||
while (timeout--)
|
|
||||||
{
|
|
||||||
recByte = PS2ReadData();
|
|
||||||
if (recByte != PS2_ACK)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (timeout == 0)
|
|
||||||
KernelLog("PS/2 keyboard second byte timed out");
|
|
||||||
else
|
|
||||||
Device1ID[1] = recByte;
|
|
||||||
|
|
||||||
KernelLog("PS2 Keyboard Device: 0x%X 0x%X", Device1ID[0], Device1ID[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
647
Kernel/drivers/misc/aip/uart.cpp
Normal file
647
Kernel/drivers/misc/aip/uart.cpp
Normal file
@ -0,0 +1,647 @@
|
|||||||
|
/*
|
||||||
|
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.hpp>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#include "aip.hpp"
|
||||||
|
|
||||||
|
namespace Driver::AdvancedIntegratedPeripheral
|
||||||
|
{
|
||||||
|
extern dev_t DriverID;
|
||||||
|
|
||||||
|
#define SERIAL_ENABLE_DLAB 0x80
|
||||||
|
#define SERIAL_BUFFER_EMPTY 0x20
|
||||||
|
|
||||||
|
enum Ports
|
||||||
|
{
|
||||||
|
COM1 = 0x3F8,
|
||||||
|
COM2 = 0x2F8,
|
||||||
|
COM3 = 0x3E8,
|
||||||
|
COM4 = 0x2E8,
|
||||||
|
COM5 = 0x5F8,
|
||||||
|
COM6 = 0x4F8,
|
||||||
|
COM7 = 0x5E8,
|
||||||
|
COM8 = 0x4E8,
|
||||||
|
|
||||||
|
LPT1 = 0x378,
|
||||||
|
LPT2 = 0x278,
|
||||||
|
LPT3 = 0x3BC
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SerialSpeed
|
||||||
|
{
|
||||||
|
RATE_50_HI = 0x09,
|
||||||
|
RATE_50_LO = 0x00,
|
||||||
|
|
||||||
|
RATE_300_HI = 0x01,
|
||||||
|
RATE_300_LO = 0x80,
|
||||||
|
|
||||||
|
RATE_600_HI = 0x00,
|
||||||
|
RATE_600_LO = 0xC0,
|
||||||
|
|
||||||
|
RATE_2400_HI = 0x00,
|
||||||
|
RATE_2400_LO = 0x30,
|
||||||
|
|
||||||
|
RATE_4800_HI = 0x00,
|
||||||
|
RATE_4800_LO = 0x18,
|
||||||
|
|
||||||
|
RATE_9600_HI = 0x00,
|
||||||
|
RATE_9600_LO = 0x0C,
|
||||||
|
|
||||||
|
RATE_19200_HI = 0x00,
|
||||||
|
RATE_19200_LO = 0x06,
|
||||||
|
|
||||||
|
RATE_38400_HI = 0x00,
|
||||||
|
RATE_38400_LO = 0x03,
|
||||||
|
|
||||||
|
RATE_57600_HI = 0x00,
|
||||||
|
RATE_57600_LO = 0x02,
|
||||||
|
|
||||||
|
RATE_115200_HI = 0x00,
|
||||||
|
RATE_115200_LO = 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
. Table of Registers .
|
||||||
|
/---------------------------------------------------------------------\
|
||||||
|
| Base Address | DLAB | R/W | Abr | Register Name |
|
||||||
|
|---------------------------------------------------------------------|
|
||||||
|
| +0 | =0 | W | - | Transmitter Holding Buffer |
|
||||||
|
| | =0 | R | - | Receiver Buffer |
|
||||||
|
| | =1 | R/W | - | Divisor Latch Low Byte |
|
||||||
|
| +1 | =0 | R/W | IER | Interrupt Enable Register |
|
||||||
|
| | =1 | R/W | - | Divisor Latch High Byte |
|
||||||
|
| +2 | - | R | IIR | Interrupt Identification Register |
|
||||||
|
| | - | W | FCR | FIFO Control Register |
|
||||||
|
| +3 | - | R/W | LCR | Line Control Register |
|
||||||
|
| +4 | - | R/W | MCR | Modem Control Register |
|
||||||
|
| +5 | - | R | LSR | Line Status Register |
|
||||||
|
| +6 | - | R | MSR | Modem Status Register |
|
||||||
|
| +7 | - | R/W | - | Scratch Register |
|
||||||
|
\---------------------------------------------------------------------/
|
||||||
|
|
||||||
|
Source:
|
||||||
|
Interfacing the Serial / RS232 Port V5.0
|
||||||
|
Table 5 : Table of Registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Interrupt Enable Register */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* Enable Received Data Available Interrupt */
|
||||||
|
uint8_t InterruptOnReceive : 1;
|
||||||
|
|
||||||
|
/* Enable Transmitter Holding Register Empty Interrupt */
|
||||||
|
uint8_t InterruptOnTransmitter : 1;
|
||||||
|
|
||||||
|
/* Enable Receiver Line Status Interrupt */
|
||||||
|
uint8_t LineStatusInterrupt : 1;
|
||||||
|
|
||||||
|
/* Enable Modem Status Interrupt */
|
||||||
|
uint8_t ModemStatusInterrupt : 1;
|
||||||
|
|
||||||
|
/* Enables Sleep Mode (16750) */
|
||||||
|
uint8_t SleepMode : 1;
|
||||||
|
|
||||||
|
/* Enables Low Power Mode (16750) */
|
||||||
|
uint8_t LowPowerMode : 1;
|
||||||
|
|
||||||
|
/* Reserved */
|
||||||
|
uint8_t __reserved : 2;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
} IER;
|
||||||
|
|
||||||
|
/** Interrupt Identification Register */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* Interrupt pending */
|
||||||
|
uint8_t InterruptPending : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interrupt Status
|
||||||
|
*
|
||||||
|
* 00b = Modem Status Interrupt
|
||||||
|
* 01b = Transmitter Holding Register Empty Interrupt
|
||||||
|
* 10b = Received Data Available Interrupt
|
||||||
|
* 11b = Receiver Line Status Interrupt
|
||||||
|
*/
|
||||||
|
uint8_t InterruptStatus : 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16550 Time-out Interrupt Pending
|
||||||
|
*
|
||||||
|
* @note Reserved on 8250, 16450
|
||||||
|
*/
|
||||||
|
uint8_t TimeOutIP : 1;
|
||||||
|
|
||||||
|
/** Reserved */
|
||||||
|
uint8_t __reserved : 1;
|
||||||
|
|
||||||
|
/** 64 Byte Fifo Enabled (16750 only) */
|
||||||
|
uint8_t FIFO64 : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable FIFO
|
||||||
|
*
|
||||||
|
* 00b = No FIFO
|
||||||
|
* 01b = FIFO Enabled but Unusable
|
||||||
|
* 11b = FIFO Enabled
|
||||||
|
*/
|
||||||
|
uint8_t FIFO : 2;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
} IIR;
|
||||||
|
|
||||||
|
/** First In / First Out Control Register */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/** Enable FIFO's */
|
||||||
|
uint8_t FIFO : 1;
|
||||||
|
|
||||||
|
/** Clear Receive FIFO */
|
||||||
|
uint8_t ClearRX : 1;
|
||||||
|
|
||||||
|
/** Clear Transmit FIFO */
|
||||||
|
uint8_t ClearTX : 1;
|
||||||
|
|
||||||
|
/** DMA Mode Select.
|
||||||
|
*
|
||||||
|
* Change status of RXRDY & TXRDY pins from mode 1 to mode 2.
|
||||||
|
*/
|
||||||
|
uint8_t DMAMode : 1;
|
||||||
|
|
||||||
|
/** Reserved */
|
||||||
|
uint8_t __reserved : 1;
|
||||||
|
|
||||||
|
/** Enable 64 Byte FIFO (16750 only) */
|
||||||
|
uint8_t FIFO64 : 1;
|
||||||
|
|
||||||
|
/** Interrupt Trigger Level
|
||||||
|
*
|
||||||
|
* 00b = 1 Byte
|
||||||
|
* 01b = 4 Bytes
|
||||||
|
* 10b = 8 Bytes
|
||||||
|
* 11b = 14 Bytes
|
||||||
|
*/
|
||||||
|
uint8_t TriggerLevel : 2;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
} FCR;
|
||||||
|
|
||||||
|
/** Line Control Register */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/** Word Length
|
||||||
|
*
|
||||||
|
* 00b = 5 bits
|
||||||
|
* 01b = 6 bits
|
||||||
|
* 10b = 7 bits
|
||||||
|
* 11b = 8 bits
|
||||||
|
*/
|
||||||
|
uint8_t WordLength : 2;
|
||||||
|
|
||||||
|
/** Length of Stop Bit
|
||||||
|
*
|
||||||
|
* 0b = One Stop Bit
|
||||||
|
* 1b = 2 Stop bits for words of length 6,7 or 8 bits or 1.5 Stop Bits for Word lengths of 5 bits.
|
||||||
|
*/
|
||||||
|
uint8_t StopBit : 1;
|
||||||
|
|
||||||
|
/** Parity Select
|
||||||
|
*
|
||||||
|
* 0b = No Parity
|
||||||
|
* 001b = Odd Parity
|
||||||
|
* 011b = Even Parity
|
||||||
|
* 101b = High Parity (Sticky)
|
||||||
|
* 111b = Low Parity (Sticky)
|
||||||
|
*/
|
||||||
|
uint8_t Parity : 3;
|
||||||
|
|
||||||
|
/** Set Break Enable */
|
||||||
|
uint8_t SetBreak : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Divisor Latch Access
|
||||||
|
*
|
||||||
|
* 0b = Access to Receiver buffer, Transmitter buffer & Interrupt Enable Register
|
||||||
|
* 1b = Divisor Latch Access Bit
|
||||||
|
*/
|
||||||
|
uint8_t DLAB : 1;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
} LCR;
|
||||||
|
|
||||||
|
/** Modem Control Register */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/** Force Data Terminal Ready */
|
||||||
|
uint8_t DataTerminalReady : 1;
|
||||||
|
|
||||||
|
/** Force Request to Send */
|
||||||
|
uint8_t RequestToSend : 1;
|
||||||
|
|
||||||
|
/** Auxiliary Output 1 */
|
||||||
|
uint8_t Out1 : 1;
|
||||||
|
|
||||||
|
/** Auxiliary Output 2 */
|
||||||
|
uint8_t Out2 : 1;
|
||||||
|
|
||||||
|
/** Loopback Mode */
|
||||||
|
uint8_t Loopback : 1;
|
||||||
|
|
||||||
|
/** Autoflow Control Enabled (16750 only) */
|
||||||
|
uint8_t Autoflow : 1;
|
||||||
|
|
||||||
|
/** Reserved */
|
||||||
|
uint8_t __reserved : 2;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
} MCR;
|
||||||
|
|
||||||
|
/** Line Status Register */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/** Data Ready */
|
||||||
|
uint8_t DataReady : 1;
|
||||||
|
|
||||||
|
/** Overrun Error */
|
||||||
|
uint8_t OverrunError : 1;
|
||||||
|
|
||||||
|
/** Parity Error */
|
||||||
|
uint8_t ParityError : 1;
|
||||||
|
|
||||||
|
/** Framing Error */
|
||||||
|
uint8_t FramingError : 1;
|
||||||
|
|
||||||
|
/** Break Interrupt */
|
||||||
|
uint8_t BreakInterrupt : 1;
|
||||||
|
|
||||||
|
/** Empty Transmitter Holding Register */
|
||||||
|
uint8_t EmptyTransmitterHolding : 1;
|
||||||
|
|
||||||
|
/** Empty Data Holding Registers */
|
||||||
|
uint8_t EmptyDataHolding : 1;
|
||||||
|
|
||||||
|
/** Error in Received FIFO */
|
||||||
|
uint8_t ErrorReceivedFIFO : 1;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
} LSR;
|
||||||
|
|
||||||
|
/** Modem Status Register */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/** Delta Clear to Send */
|
||||||
|
uint8_t DeltaClearToSend : 1;
|
||||||
|
|
||||||
|
/** Delta Data Set Ready */
|
||||||
|
uint8_t DeltaDataSetReady : 1;
|
||||||
|
|
||||||
|
/** Trailing Edge Ring Indicator */
|
||||||
|
uint8_t TrailingEdgeRingIndicator : 1;
|
||||||
|
|
||||||
|
/** Delta Data Carrier Detect */
|
||||||
|
uint8_t DeltaDataCarrierDetect : 1;
|
||||||
|
|
||||||
|
/** Clear To Send */
|
||||||
|
uint8_t ClearToSend : 1;
|
||||||
|
|
||||||
|
/** Data Set Ready */
|
||||||
|
uint8_t DataSetReady : 1;
|
||||||
|
|
||||||
|
/** Ring Indicator */
|
||||||
|
uint8_t RingIndicator : 1;
|
||||||
|
|
||||||
|
/** Carrier Detect */
|
||||||
|
uint8_t CarrierDetect : 1;
|
||||||
|
};
|
||||||
|
uint8_t raw;
|
||||||
|
} MSR;
|
||||||
|
|
||||||
|
union UARTs
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t com1 : 1;
|
||||||
|
uint8_t com2 : 1;
|
||||||
|
uint8_t com3 : 1;
|
||||||
|
uint8_t com4 : 1;
|
||||||
|
uint8_t com5 : 1;
|
||||||
|
uint8_t com6 : 1;
|
||||||
|
uint8_t com7 : 1;
|
||||||
|
uint8_t com8 : 1;
|
||||||
|
|
||||||
|
uint8_t lpt1 : 1;
|
||||||
|
uint8_t lpt2 : 1;
|
||||||
|
uint8_t lpt3 : 1;
|
||||||
|
|
||||||
|
uint8_t __reserved : 5;
|
||||||
|
};
|
||||||
|
uint16_t raw;
|
||||||
|
} uart;
|
||||||
|
|
||||||
|
bool IsDataReady(uint16_t Port)
|
||||||
|
{
|
||||||
|
LSR lsr;
|
||||||
|
lsr.raw = inb(Port + 5);
|
||||||
|
return lsr.DataReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsTransmitEmpty(uint16_t Port)
|
||||||
|
{
|
||||||
|
LSR lsr;
|
||||||
|
lsr.raw = inb(Port + 5);
|
||||||
|
return lsr.EmptyTransmitterHolding;
|
||||||
|
}
|
||||||
|
|
||||||
|
char ReadSerial(uint16_t Port)
|
||||||
|
{
|
||||||
|
while (!IsDataReady(Port))
|
||||||
|
v0::Yield(DriverID);
|
||||||
|
return inb(Port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteSerial(uint16_t Port, char Character)
|
||||||
|
{
|
||||||
|
while (!IsTransmitEmpty(Port))
|
||||||
|
v0::Yield(DriverID);
|
||||||
|
outb(Port, Character);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportSerialReceived(uint8_t Data)
|
||||||
|
{
|
||||||
|
debug("%c", Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartCOM24(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
LSR lsr2, lsr4;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
lsr2.raw = inb(COM2 + 5);
|
||||||
|
if (lsr2.DataReady)
|
||||||
|
ReportSerialReceived(inb(COM2));
|
||||||
|
lsr4.raw = inb(COM4 + 5);
|
||||||
|
if (lsr4.DataReady)
|
||||||
|
ReportSerialReceived(inb(COM4));
|
||||||
|
} while (lsr2.DataReady || lsr4.DataReady);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartCOM13(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
LSR lsr1, lsr3;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
lsr1.raw = inb(COM1 + 5);
|
||||||
|
if (lsr1.DataReady)
|
||||||
|
ReportSerialReceived(inb(COM1));
|
||||||
|
lsr3.raw = inb(COM3 + 5);
|
||||||
|
if (lsr3.DataReady)
|
||||||
|
ReportSerialReceived(inb(COM3));
|
||||||
|
} while (lsr1.DataReady || lsr3.DataReady);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InitializePort(uint16_t Port)
|
||||||
|
{
|
||||||
|
v0::CriticalState cs = v0::EnterCriticalSection(DriverID);
|
||||||
|
LCR lcr = {};
|
||||||
|
IER ier = {};
|
||||||
|
FCR fcr = {};
|
||||||
|
MCR mcr = {};
|
||||||
|
|
||||||
|
outb(Port + 3, lcr.raw);
|
||||||
|
outb(Port + 1, ier.raw);
|
||||||
|
|
||||||
|
lcr.DLAB = 1;
|
||||||
|
outb(Port + 3, lcr.raw);
|
||||||
|
|
||||||
|
outb(Port + 0, RATE_115200_LO);
|
||||||
|
outb(Port + 1, RATE_115200_HI);
|
||||||
|
|
||||||
|
lcr.DLAB = 0;
|
||||||
|
lcr.WordLength = 0b11;
|
||||||
|
outb(Port + 3, lcr.raw);
|
||||||
|
|
||||||
|
fcr.FIFO = 1;
|
||||||
|
fcr.ClearRX = 1;
|
||||||
|
fcr.ClearTX = 1;
|
||||||
|
fcr.TriggerLevel = 0b11;
|
||||||
|
outb(Port + 2, fcr.raw);
|
||||||
|
|
||||||
|
mcr.DataTerminalReady = 1;
|
||||||
|
mcr.RequestToSend = 1;
|
||||||
|
mcr.Out2 = 1;
|
||||||
|
mcr.Loopback = 1;
|
||||||
|
outb(Port + 4, mcr.raw);
|
||||||
|
|
||||||
|
/* Test the serial port */
|
||||||
|
outb(Port + 0, 0x48);
|
||||||
|
uint8_t result = inb(Port + 0);
|
||||||
|
if (result != 0x48)
|
||||||
|
{
|
||||||
|
/* FIXME: DETECT BAUD RATE
|
||||||
|
Do multiple test to check if the output is garbage.
|
||||||
|
If so, reduce the baud rate until it works. */
|
||||||
|
|
||||||
|
v0::LeaveCriticalSection(DriverID, cs);
|
||||||
|
trace("Port %#X test failed!", Port);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set normal operation mode */
|
||||||
|
mcr.DataTerminalReady = 1;
|
||||||
|
mcr.RequestToSend = 1;
|
||||||
|
mcr.Out1 = 1;
|
||||||
|
mcr.Out2 = 1;
|
||||||
|
mcr.Loopback = 0;
|
||||||
|
outb(Port + 4, mcr.raw);
|
||||||
|
|
||||||
|
/* Enable interrupts on receive */
|
||||||
|
ier.InterruptOnReceive = 1;
|
||||||
|
outb(Port + 1, ier.raw);
|
||||||
|
v0::RegisterInterruptHandler(DriverID, 3, (void *)UartCOM24);
|
||||||
|
v0::RegisterInterruptHandler(DriverID, 4, (void *)UartCOM13);
|
||||||
|
|
||||||
|
v0::LeaveCriticalSection(DriverID, cs);
|
||||||
|
trace("Port %#X initialized", Port);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DetectUART()
|
||||||
|
{
|
||||||
|
uart.com1 = inb(COM1) != 0xFF ? true : false;
|
||||||
|
uart.com2 = inb(COM2) != 0xFF ? true : false;
|
||||||
|
uart.com3 = inb(COM3) != 0xFF ? true : false;
|
||||||
|
uart.com4 = inb(COM4) != 0xFF ? true : false;
|
||||||
|
uart.com5 = inb(COM5) != 0xFF ? true : false;
|
||||||
|
uart.com6 = inb(COM6) != 0xFF ? true : false;
|
||||||
|
uart.com7 = inb(COM7) != 0xFF ? true : false;
|
||||||
|
uart.com8 = inb(COM8) != 0xFF ? true : false;
|
||||||
|
|
||||||
|
uart.lpt1 = inb(LPT1) != 0xFF ? true : false;
|
||||||
|
uart.lpt2 = inb(LPT2) != 0xFF ? true : false;
|
||||||
|
uart.lpt3 = inb(LPT3) != 0xFF ? true : false;
|
||||||
|
|
||||||
|
if (uart.com1 == true)
|
||||||
|
if (InitializePort(COM1) == false)
|
||||||
|
uart.com1 = false;
|
||||||
|
|
||||||
|
if (uart.com2 == true)
|
||||||
|
if (InitializePort(COM2) == false)
|
||||||
|
uart.com1 = false;
|
||||||
|
|
||||||
|
if (uart.com3 == true)
|
||||||
|
if (InitializePort(COM3) == false)
|
||||||
|
uart.com1 = false;
|
||||||
|
|
||||||
|
if (uart.com4 == true)
|
||||||
|
if (InitializePort(COM4) == false)
|
||||||
|
uart.com1 = false;
|
||||||
|
|
||||||
|
if (uart.com5 == true)
|
||||||
|
if (InitializePort(COM5) == false)
|
||||||
|
uart.com1 = false;
|
||||||
|
|
||||||
|
if (uart.com6 == true)
|
||||||
|
if (InitializePort(COM6) == false)
|
||||||
|
uart.com1 = false;
|
||||||
|
|
||||||
|
if (uart.com7 == true)
|
||||||
|
if (InitializePort(COM7) == false)
|
||||||
|
uart.com1 = false;
|
||||||
|
|
||||||
|
if (uart.com8 == true)
|
||||||
|
if (InitializePort(COM8) == false)
|
||||||
|
uart.com1 = false;
|
||||||
|
|
||||||
|
if (uart.lpt1 == true)
|
||||||
|
trace("LPT1 is present");
|
||||||
|
|
||||||
|
if (uart.lpt2 == true)
|
||||||
|
trace("LPT2 is present");
|
||||||
|
|
||||||
|
if (uart.lpt3 == true)
|
||||||
|
trace("LPT3 is present");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static int once = 0;
|
||||||
|
// static uint8_t com4 = 0xFF;
|
||||||
|
// if (!once++)
|
||||||
|
// com4 = inb(0x2E8);
|
||||||
|
// if (com4 == 0xFF)
|
||||||
|
// CPU::Halt(true);
|
||||||
|
// char UserInputBuffer[256]{'\0'};
|
||||||
|
// int BackSpaceLimit = 0;
|
||||||
|
// while (true)
|
||||||
|
// {
|
||||||
|
// while ((inb(0x2E8 + 5) & 1) == 0)
|
||||||
|
// CPU::Pause();
|
||||||
|
// char key = inb(0x2E8);
|
||||||
|
// // debug("key: %d", key);
|
||||||
|
// if (key == '\x7f') /* Backspace (DEL) */
|
||||||
|
// {
|
||||||
|
// if (BackSpaceLimit <= 0)
|
||||||
|
// continue;
|
||||||
|
// char keyBuf[5] = {'\b', '\x1b', '[', 'K', '\0'};
|
||||||
|
// ExPrint(keyBuf);
|
||||||
|
// backspace(UserInputBuffer);
|
||||||
|
// BackSpaceLimit--;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// else if (key == '\x0d') /* Enter (CR) */
|
||||||
|
// {
|
||||||
|
// UserInput(UserInputBuffer);
|
||||||
|
// BackSpaceLimit = 0;
|
||||||
|
// UserInputBuffer[0] = '\0';
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// else if (key == '\x1b') /* Escape */
|
||||||
|
// {
|
||||||
|
// char tmp[16]{'\0'};
|
||||||
|
// append(tmp, key);
|
||||||
|
// while ((inb(0x2E8 + 5) & 1) == 0)
|
||||||
|
// CPU::Pause();
|
||||||
|
// char key = inb(0x2E8);
|
||||||
|
// append(tmp, key);
|
||||||
|
// if (key == '[')
|
||||||
|
// {
|
||||||
|
// // 27 91
|
||||||
|
// // < 68
|
||||||
|
// // > 67
|
||||||
|
// // down 66
|
||||||
|
// // up 65
|
||||||
|
// while ((inb(0x2E8 + 5) & 1) == 0)
|
||||||
|
// CPU::Pause();
|
||||||
|
// key = inb(0x2E8);
|
||||||
|
// append(tmp, key);
|
||||||
|
// switch (key)
|
||||||
|
// {
|
||||||
|
// case 'A':
|
||||||
|
// key = KEY_D_UP;
|
||||||
|
// break;
|
||||||
|
// case 'B':
|
||||||
|
// key = KEY_D_DOWN;
|
||||||
|
// break;
|
||||||
|
// case 'C':
|
||||||
|
// key = KEY_D_RIGHT;
|
||||||
|
// break;
|
||||||
|
// case 'D':
|
||||||
|
// key = KEY_D_LEFT;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// {
|
||||||
|
// for (size_t i = 0; i < strlen(tmp); i++)
|
||||||
|
// {
|
||||||
|
// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
|
||||||
|
// continue;
|
||||||
|
// append(UserInputBuffer, tmp[i]);
|
||||||
|
// BackSpaceLimit++;
|
||||||
|
// char keyBuf[2] = {(char)tmp[i], '\0'};
|
||||||
|
// ExPrint(keyBuf);
|
||||||
|
// }
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ArrowInput(key);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
|
||||||
|
// continue;
|
||||||
|
// append(UserInputBuffer, key);
|
||||||
|
// BackSpaceLimit++;
|
||||||
|
// char keyBuf[2] = {(char)key, '\0'};
|
||||||
|
// ExPrint(keyBuf);
|
||||||
|
// }
|
||||||
|
}
|
164
Kernel/drivers/misc/mem/mem.cpp
Normal file
164
Kernel/drivers/misc/mem/mem.cpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
#include <rand.hpp>
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
namespace Driver::MemoryDevices
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
dev_t null;
|
||||||
|
dev_t zero;
|
||||||
|
dev_t random;
|
||||||
|
dev_t urandom;
|
||||||
|
dev_t mem;
|
||||||
|
} ids;
|
||||||
|
|
||||||
|
int Open(struct Inode *Node, int Flags, mode_t Mode) { return -ENOENT; }
|
||||||
|
|
||||||
|
int Close(struct Inode *Node) { return -ENOSYS; }
|
||||||
|
|
||||||
|
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp) { return -ENOSYS; }
|
||||||
|
|
||||||
|
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.null)
|
||||||
|
return 0;
|
||||||
|
else if (min == ids.zero)
|
||||||
|
{
|
||||||
|
if (Size <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(Buffer, 0, Size);
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
else if (min == ids.random || min == ids.urandom)
|
||||||
|
{
|
||||||
|
if (Size <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (Size < sizeof(uint64_t))
|
||||||
|
{
|
||||||
|
uint8_t *buf = (uint8_t *)Buffer;
|
||||||
|
for (size_t i = 0; i < Size; i++)
|
||||||
|
buf[i] = (uint8_t)(Random::rand16() & 0xFF);
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t *buf = (uint64_t *)Buffer;
|
||||||
|
for (size_t i = 0; i < Size / sizeof(uint64_t); i++)
|
||||||
|
buf[i] = Random::rand64();
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
else if (min == ids.mem)
|
||||||
|
{
|
||||||
|
stub;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.null)
|
||||||
|
return Size;
|
||||||
|
else if (min == ids.zero)
|
||||||
|
return Size;
|
||||||
|
else if (min == ids.random || min == ids.urandom)
|
||||||
|
return Size;
|
||||||
|
else if (min == ids.mem)
|
||||||
|
return Size;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t Seek(struct Inode *Node, off_t Offset) { return -ENOSYS; }
|
||||||
|
|
||||||
|
int Stat(struct Inode *Node, struct kstat *Stat) { return -ENOSYS; }
|
||||||
|
|
||||||
|
const struct InodeOperations ops = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = Read,
|
||||||
|
.Write = Write,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = Open,
|
||||||
|
.Close = Close,
|
||||||
|
.Ioctl = Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = Seek,
|
||||||
|
.Stat = Stat,
|
||||||
|
};
|
||||||
|
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
mode_t mode = 0;
|
||||||
|
|
||||||
|
/* c rw- rw- rw- */
|
||||||
|
mode = S_IRUSR | S_IWUSR |
|
||||||
|
S_IRGRP | S_IWGRP |
|
||||||
|
S_IROTH | S_IWOTH |
|
||||||
|
S_IFCHR;
|
||||||
|
ids.null = DriverManager->CreateDeviceFile(DriverID, "null", mode, &ops);
|
||||||
|
ids.zero = DriverManager->CreateDeviceFile(DriverID, "zero", mode, &ops);
|
||||||
|
ids.random = DriverManager->CreateDeviceFile(DriverID, "random", mode, &ops);
|
||||||
|
ids.urandom = DriverManager->CreateDeviceFile(DriverID, "urandom", mode, &ops);
|
||||||
|
|
||||||
|
/* c rw- r-- --- */
|
||||||
|
mode = S_IRUSR | S_IWUSR |
|
||||||
|
S_IRGRP |
|
||||||
|
|
||||||
|
S_IFCHR;
|
||||||
|
ids.mem = DriverManager->CreateDeviceFile(DriverID, "mem", mode, &ops);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.null);
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.zero);
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.random);
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.urandom);
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.mem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic() { return 0; }
|
||||||
|
int Probe() { return 0; }
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(mem,
|
||||||
|
"Memory Devices Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
192
Kernel/drivers/misc/pty/pty.cpp
Normal file
192
Kernel/drivers/misc/pty/pty.cpp
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
#include <kcon.hpp>
|
||||||
|
#include <task.hpp>
|
||||||
|
#include <smp.hpp>
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
namespace Driver::TeleTypeDevices
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
TTY::PTMXDevice *ptmx = nullptr;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
dev_t kcon;
|
||||||
|
dev_t tty;
|
||||||
|
dev_t ptmx;
|
||||||
|
} ids;
|
||||||
|
|
||||||
|
int Open(struct Inode *Node, int Flags, mode_t Mode)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kcon)
|
||||||
|
return KernelConsole::CurrentTerminal.load()->Open(Flags, Mode);
|
||||||
|
else if (min == ids.tty)
|
||||||
|
{
|
||||||
|
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||||
|
if (tty == nullptr)
|
||||||
|
return -ENOTTY;
|
||||||
|
return tty->Open(Flags, Mode);
|
||||||
|
}
|
||||||
|
else if (min == ids.ptmx)
|
||||||
|
return ptmx->Open();
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Close(struct Inode *Node)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kcon)
|
||||||
|
return KernelConsole::CurrentTerminal.load()->Close();
|
||||||
|
else if (min == ids.tty)
|
||||||
|
{
|
||||||
|
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||||
|
if (tty == nullptr)
|
||||||
|
return -ENOTTY;
|
||||||
|
return tty->Close();
|
||||||
|
}
|
||||||
|
else if (min == ids.ptmx)
|
||||||
|
return ptmx->Close();
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kcon)
|
||||||
|
return KernelConsole::CurrentTerminal.load()->Ioctl(Request, Argp);
|
||||||
|
else if (min == ids.tty)
|
||||||
|
{
|
||||||
|
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||||
|
if (tty == nullptr)
|
||||||
|
return -ENOTTY;
|
||||||
|
return tty->Ioctl(Request, Argp);
|
||||||
|
}
|
||||||
|
else if (min == ids.ptmx)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kcon)
|
||||||
|
return KernelConsole::CurrentTerminal.load()->Read(Buffer, Size, Offset);
|
||||||
|
else if (min == ids.tty)
|
||||||
|
{
|
||||||
|
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||||
|
if (tty == nullptr)
|
||||||
|
return -ENOTTY;
|
||||||
|
return tty->Read(Buffer, Size, Offset);
|
||||||
|
}
|
||||||
|
else if (min == ids.ptmx)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kcon)
|
||||||
|
return KernelConsole::CurrentTerminal.load()->Write(Buffer, Size, Offset);
|
||||||
|
else if (min == ids.tty)
|
||||||
|
{
|
||||||
|
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||||
|
if (tty == nullptr)
|
||||||
|
return -ENOTTY;
|
||||||
|
return tty->Write(Buffer, Size, Offset);
|
||||||
|
}
|
||||||
|
else if (min == ids.ptmx)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t Seek(struct Inode *Node, off_t Offset) { return -ENOSYS; }
|
||||||
|
int Stat(struct Inode *Node, struct kstat *Stat) { return -ENOSYS; }
|
||||||
|
|
||||||
|
const struct InodeOperations ops = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = Read,
|
||||||
|
.Write = Write,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = Open,
|
||||||
|
.Close = Close,
|
||||||
|
.Ioctl = Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = Seek,
|
||||||
|
.Stat = Stat,
|
||||||
|
};
|
||||||
|
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
ptmx = new TTY::PTMXDevice;
|
||||||
|
mode_t mode = 0;
|
||||||
|
|
||||||
|
/* c rw- r-- --- */
|
||||||
|
mode = S_IRUSR | S_IWUSR |
|
||||||
|
S_IRGRP |
|
||||||
|
|
||||||
|
S_IFCHR;
|
||||||
|
ids.kcon = DriverManager->CreateDeviceFile(DriverID, "kcon", mode, &ops);
|
||||||
|
|
||||||
|
/* c rw- rw- rw- */
|
||||||
|
mode = S_IRUSR | S_IWUSR |
|
||||||
|
S_IRGRP | S_IWGRP |
|
||||||
|
S_IRUSR | S_IWUSR |
|
||||||
|
S_IFCHR;
|
||||||
|
ids.tty = DriverManager->CreateDeviceFile(DriverID, "tty", mode, &ops);
|
||||||
|
ids.ptmx = DriverManager->CreateDeviceFile(DriverID, "ptmx", mode, &ops);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.kcon);
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.tty);
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.ptmx);
|
||||||
|
delete ptmx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic() { return 0; }
|
||||||
|
int Probe() { return 0; }
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(pty,
|
||||||
|
"Pseudo Terminal Devices Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
917
Kernel/drivers/misc/vmware/vmware.cpp
Normal file
917
Kernel/drivers/misc/vmware/vmware.cpp
Normal file
@ -0,0 +1,917 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
#include <pci.hpp>
|
||||||
|
#include <io.h>
|
||||||
|
#include <interface/aip.h>
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
extern PCI::Manager *PCIManager;
|
||||||
|
namespace Driver::VMwareToolBox
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
enum RPCMessages
|
||||||
|
{
|
||||||
|
MSG_OPEN,
|
||||||
|
MSG_SENDSIZE,
|
||||||
|
MSG_SENDPAYLOAD,
|
||||||
|
MSG_RECVSIZE,
|
||||||
|
MSG_RECVPAYLOAD,
|
||||||
|
MSG_RECVSTATUS,
|
||||||
|
MSG_CLOSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RPCStatus
|
||||||
|
{
|
||||||
|
STATUS_SUCCESS = 0x1,
|
||||||
|
STATUS_DORECV = 0x2,
|
||||||
|
STATUS_CPT = 0x10,
|
||||||
|
STATUS_HB = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t ax;
|
||||||
|
uint32_t magic;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t bx;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t cx;
|
||||||
|
uint16_t command;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t dx;
|
||||||
|
uint16_t port;
|
||||||
|
};
|
||||||
|
uint32_t si;
|
||||||
|
uint32_t di;
|
||||||
|
} VMwareCommand;
|
||||||
|
|
||||||
|
#define VMWARE_MAGIC 0x564D5868
|
||||||
|
|
||||||
|
#define VMWARE_PORT 0x5658
|
||||||
|
#define VMWARE_PORTHB 0x5659
|
||||||
|
|
||||||
|
#define VMWARE_HYPERVISOR_HB 0x00000000
|
||||||
|
#define VMWARE_HYPERVISOR_OUT 0x00000001
|
||||||
|
|
||||||
|
#define CMD_GETVERSION 0xA
|
||||||
|
#define CMD_MESSAGE 0x1E
|
||||||
|
#define CMD_ABSPOINTER_DATA 0x27
|
||||||
|
#define CMD_ABSPOINTER_STATUS 0x28
|
||||||
|
#define CMD_ABSPOINTER_COMMAND 0x29
|
||||||
|
|
||||||
|
#define ABSPOINTER_ENABLE 0x45414552
|
||||||
|
#define ABSPOINTER_RELATIVE 0xF5
|
||||||
|
#define ABSPOINTER_ABSOLUTE 0x53424152
|
||||||
|
|
||||||
|
#define MESSAGE_RPCI 0x49435052
|
||||||
|
#define MESSAGE_TCLO 0x4f4c4354
|
||||||
|
|
||||||
|
#define FLAG_COOKIE 0x80000000
|
||||||
|
|
||||||
|
#define ToMsg(x) ((x) << 16 | CMD_MESSAGE)
|
||||||
|
#define HighWord(x) ((x & 0xFFFF0000) >> 16)
|
||||||
|
|
||||||
|
#define MESSAGE_HB_MSG 0
|
||||||
|
|
||||||
|
#define MESSAGE_OPEN_CHANNEL ToMsg(MSG_OPEN)
|
||||||
|
#define MESSAGE_CLOSE_CHANNEL ToMsg(MSG_CLOSE)
|
||||||
|
|
||||||
|
#define MESSAGE_SEND_SIZE ToMsg(MSG_SENDSIZE)
|
||||||
|
#define MESSAGE_SEND_PAYLOAD ToMsg(MSG_SENDPAYLOAD)
|
||||||
|
|
||||||
|
#define MESSAGE_RECV_SIZE ToMsg(MSG_RECVSIZE)
|
||||||
|
#define MESSAGE_RECV_PAYLOAD ToMsg(MSG_RECVPAYLOAD)
|
||||||
|
#define MESSAGE_RECV_STATUS ToMsg(MSG_RECVSTATUS)
|
||||||
|
|
||||||
|
#if defined(__amd64__)
|
||||||
|
|
||||||
|
#define VM_PORT(cmd, in_ebx, isi, idi, \
|
||||||
|
flags, magic, \
|
||||||
|
ax, bx, cx, dx, si, di) \
|
||||||
|
__asm__ __volatile__("movw $0x5658, %%dx\n" \
|
||||||
|
"inl %%dx, %%eax\n" \
|
||||||
|
: "=a"(ax), \
|
||||||
|
"=b"(bx), \
|
||||||
|
"=c"(cx), \
|
||||||
|
"=d"(dx), \
|
||||||
|
"=S"(si), \
|
||||||
|
"=D"(di) \
|
||||||
|
: "a"(magic), \
|
||||||
|
"b"(in_ebx), \
|
||||||
|
"c"(cmd), \
|
||||||
|
"d"(flags), \
|
||||||
|
"S"(isi), \
|
||||||
|
"D"(idi) : "memory")
|
||||||
|
|
||||||
|
#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
|
||||||
|
flags, magic, bp, \
|
||||||
|
ax, bx, cx, dx, si, di) \
|
||||||
|
__asm__ __volatile__("push %%rbp\n" \
|
||||||
|
"mov %12, %%rbp\n" \
|
||||||
|
"movw $0x5659, %%dx\n" \
|
||||||
|
"rep outsb\n" \
|
||||||
|
"pop %%rbp\n" \
|
||||||
|
: "=a"(ax), \
|
||||||
|
"=b"(bx), \
|
||||||
|
"=c"(cx), \
|
||||||
|
"=d"(dx), \
|
||||||
|
"=S"(si), \
|
||||||
|
"=D"(di) \
|
||||||
|
: "a"(magic), \
|
||||||
|
"b"(cmd), \
|
||||||
|
"c"(in_ecx), \
|
||||||
|
"d"(flags), \
|
||||||
|
"S"(isi), \
|
||||||
|
"D"(idi), \
|
||||||
|
"r"(bp) : "memory", "cc")
|
||||||
|
|
||||||
|
#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
|
||||||
|
flags, magic, bp, \
|
||||||
|
ax, bx, cx, dx, si, di) \
|
||||||
|
__asm__ __volatile__("push %%rbp\n" \
|
||||||
|
"mov %12, %%rbp\n" \
|
||||||
|
"movw $0x5659, %%dx\n" \
|
||||||
|
"rep insb\n" \
|
||||||
|
"pop %%rbp\n" \
|
||||||
|
: "=a"(ax), \
|
||||||
|
"=b"(bx), \
|
||||||
|
"=c"(cx), \
|
||||||
|
"=d"(dx), \
|
||||||
|
"=S"(si), \
|
||||||
|
"=D"(di) \
|
||||||
|
: "a"(magic), \
|
||||||
|
"b"(cmd), \
|
||||||
|
"c"(in_ecx), \
|
||||||
|
"d"(flags), \
|
||||||
|
"S"(isi), \
|
||||||
|
"D"(idi), \
|
||||||
|
"r"(bp) : "memory", "cc")
|
||||||
|
|
||||||
|
#elif defined(__i386__)
|
||||||
|
|
||||||
|
#define VM_PORT(cmd, in_ebx, isi, idi, \
|
||||||
|
flags, magic, \
|
||||||
|
ax, bx, cx, dx, si, di)
|
||||||
|
|
||||||
|
#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
|
||||||
|
flags, \
|
||||||
|
magic, bp, ax, \
|
||||||
|
bx, cx, dx, si, di)
|
||||||
|
|
||||||
|
#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
|
||||||
|
flags, magic, bp, \
|
||||||
|
ax, bx, cx, dx, si, di)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
- use vmcall or vmmcall instead of "out" and "in" if available
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int TCLOChannel;
|
||||||
|
uint16_t ChannelID;
|
||||||
|
uint32_t CookieHigh;
|
||||||
|
uint32_t CookieLow;
|
||||||
|
} ToolboxContext;
|
||||||
|
|
||||||
|
dev_t MouseDevID = -1;
|
||||||
|
|
||||||
|
int __strcmp(const char *l, const char *r)
|
||||||
|
{
|
||||||
|
for (; *l == *r && *l; l++, r++)
|
||||||
|
;
|
||||||
|
|
||||||
|
return *(unsigned char *)l - *(unsigned char *)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cpuid(uint32_t Function,
|
||||||
|
uint32_t *eax, uint32_t *ebx,
|
||||||
|
uint32_t *ecx, uint32_t *edx)
|
||||||
|
{
|
||||||
|
asmv("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(Function));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __CheckHypervisorBit()
|
||||||
|
{
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
__cpuid(0x1, &eax, &ebx, &ecx, &edx);
|
||||||
|
if (!(ecx & (1 << 31)))
|
||||||
|
return false; /* Hypervisor not detected */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __VMwareBackdoorHypervisors()
|
||||||
|
{
|
||||||
|
const char hv[13] = {0};
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
__cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
|
*(uint32_t *)hv = ebx;
|
||||||
|
*(uint32_t *)(hv + 4) = ecx;
|
||||||
|
*(uint32_t *)(hv + 8) = edx;
|
||||||
|
|
||||||
|
if (__strcmp(hv, "VMwareVMware") != 0 &&
|
||||||
|
__strcmp(hv, "KVMKVMKVM") != 0 &&
|
||||||
|
__strcmp(hv, "TCGTCGTCGTCG") != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsVMwareBackdoorAvailable()
|
||||||
|
{
|
||||||
|
if (!__CheckHypervisorBit())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!__VMwareBackdoorHypervisors())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t ax;
|
||||||
|
uint32_t magic;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t bx;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t cx;
|
||||||
|
uint16_t command;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t dx;
|
||||||
|
uint16_t port;
|
||||||
|
};
|
||||||
|
uint32_t si;
|
||||||
|
uint32_t di;
|
||||||
|
} cmd;
|
||||||
|
|
||||||
|
cmd.si = cmd.di = 0;
|
||||||
|
cmd.bx = ~0x564D5868;
|
||||||
|
cmd.command = 0xA;
|
||||||
|
cmd.magic = 0x564D5868;
|
||||||
|
cmd.port = 0x5658;
|
||||||
|
|
||||||
|
asmv("in %%dx, %0" : "+a"(cmd.ax), "+b"(cmd.bx),
|
||||||
|
"+c"(cmd.cx), "+d"(cmd.dx),
|
||||||
|
"+S"(cmd.si), "+D"(cmd.di));
|
||||||
|
|
||||||
|
if (cmd.bx != 0x564D5868 ||
|
||||||
|
cmd.ax == 0xFFFFFFFF)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int OpenMessageChannel(ToolboxContext *ctx, uint32_t Protocol)
|
||||||
|
{
|
||||||
|
uintptr_t ax, bx, cx, dx, si = 0, di = 0;
|
||||||
|
|
||||||
|
VM_PORT(MESSAGE_OPEN_CHANNEL,
|
||||||
|
(Protocol | FLAG_COOKIE), si, di,
|
||||||
|
0, VMWARE_MAGIC,
|
||||||
|
ax, bx, cx, dx, si, di);
|
||||||
|
|
||||||
|
if ((HighWord(cx) & STATUS_SUCCESS) == 0)
|
||||||
|
{
|
||||||
|
trace("Failed to open message channel %#lx", Protocol);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("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);
|
||||||
|
|
||||||
|
debug("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 = strlen(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 = strlen(Message);
|
||||||
|
while (Size &&
|
||||||
|
(HighWord(cx) & STATUS_SUCCESS))
|
||||||
|
{
|
||||||
|
uint32_t TotalBytes = MIN((uint32_t)Size, (uint32_t)4);
|
||||||
|
uint32_t Word = 0;
|
||||||
|
memcpy(&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;
|
||||||
|
|
||||||
|
memcpy(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 = strlen(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)
|
||||||
|
{
|
||||||
|
trace("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)
|
||||||
|
{
|
||||||
|
debug("Message \"%s\" sent", Message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if ((status & STATUS_CPT) == 0)
|
||||||
|
{
|
||||||
|
trace("Checkpoint occurred for message \"%s\"", Message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("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)
|
||||||
|
{
|
||||||
|
trace("Failed to receive message size: %d", cx);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
else if ((HighWord(cx) & STATUS_DORECV) == 0)
|
||||||
|
{
|
||||||
|
debug("No message to receive");
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplySize = bx;
|
||||||
|
|
||||||
|
if (ReplyBuf != NULL)
|
||||||
|
DriverManager->FreeMemory(DriverID, ReplyBuf, ReplyBufPages);
|
||||||
|
ReplyBufPages = ReplySize / 0x1000 + 1;
|
||||||
|
ReplyBuf = (char *)DriverManager->AllocateMemory(DriverID, 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)
|
||||||
|
{
|
||||||
|
trace("Checkpoint occurred for message payload");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("Failed to receive message payload: %d", HighWord(bx));
|
||||||
|
DriverManager->FreeMemory(DriverID, 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)
|
||||||
|
{
|
||||||
|
trace("Retrying message receive");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("Failed to receive message status: %d", HighWord(cx));
|
||||||
|
DriverManager->FreeMemory(DriverID, ReplyBuf, ReplyBufPages);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReplyBuf == NULL)
|
||||||
|
{
|
||||||
|
trace("Failed to receive message");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*Buffer = ReplyBuf;
|
||||||
|
*BufferSize = ReplySize;
|
||||||
|
debug("Received message \"%s\"", ReplyBuf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SendRPCI(ToolboxContext *, const char *Request)
|
||||||
|
{
|
||||||
|
ToolboxContext rpci_ctx = {};
|
||||||
|
int status = OpenMessageChannel(&rpci_ctx, MESSAGE_RPCI);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
trace("Failed to open RPCI channel: %d", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = MessageSend(&rpci_ctx, Request);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
trace("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)
|
||||||
|
{
|
||||||
|
v0::Sleep(DriverID, 1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (status < 0)
|
||||||
|
{
|
||||||
|
trace("Failed to receive message");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[strlen(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"))
|
||||||
|
{
|
||||||
|
debug("%s", buf);
|
||||||
|
if (MessageSend(ctx, "OK ") < 0)
|
||||||
|
return 1;
|
||||||
|
MessageClose(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (MessageSend(ctx, "ERROR Unknown command") < 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t dst_id = -1;
|
||||||
|
pid_t dst_pid = -1;
|
||||||
|
ToolboxContext *tb_ctx = NULL;
|
||||||
|
void DisplayScaleThread()
|
||||||
|
{
|
||||||
|
/* sizeof ToolboxContext */
|
||||||
|
tb_ctx = (ToolboxContext *)DriverManager->AllocateMemory(DriverID, 1);
|
||||||
|
v0::Sleep(DriverID, 2000);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (DisplayGetSize(tb_ctx) != 0)
|
||||||
|
trace("Failed to scale display");
|
||||||
|
v0::Sleep(DriverID, 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 = {};
|
||||||
|
|
||||||
|
/* 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 = {};
|
||||||
|
cmd.bx = ABSPOINTER_RELATIVE;
|
||||||
|
cmd.command = CMD_ABSPOINTER_COMMAND;
|
||||||
|
CommandSend(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputReport ir = {};
|
||||||
|
void InterruptHandler(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
uint8_t Data = inb(0x60);
|
||||||
|
(void)Data;
|
||||||
|
|
||||||
|
VMwareCommand cmd = {};
|
||||||
|
cmd.bx = 0;
|
||||||
|
cmd.command = CMD_ABSPOINTER_STATUS;
|
||||||
|
CommandSend(&cmd);
|
||||||
|
|
||||||
|
if (cmd.ax == 0xFFFF0000)
|
||||||
|
{
|
||||||
|
trace("VMware mouse is not connected?");
|
||||||
|
Relative();
|
||||||
|
Absolute();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cmd.ax & 0xFFFF) < 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cmd.bx = 4;
|
||||||
|
cmd.command = CMD_ABSPOINTER_DATA;
|
||||||
|
CommandSend(&cmd);
|
||||||
|
|
||||||
|
int Buttons = (cmd.ax & 0xFFFF);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How should I handle this?
|
||||||
|
* (cmd.[bx,cx] * Width) / 0xFFFF
|
||||||
|
* Maybe TODO: Width and Height API?
|
||||||
|
*/
|
||||||
|
uintptr_t AbsoluteX = cmd.bx;
|
||||||
|
uintptr_t AbsoluteY = cmd.cx;
|
||||||
|
|
||||||
|
ir.Type = INPUT_TYPE_MOUSE;
|
||||||
|
ir.Device = MouseDevID;
|
||||||
|
ir.Mouse.X = AbsoluteX;
|
||||||
|
ir.Mouse.Y = AbsoluteY;
|
||||||
|
ir.Mouse.Z = (int8_t)cmd.dx;
|
||||||
|
ir.Mouse.Absolute = 1;
|
||||||
|
ir.Mouse.LeftButton = Buttons & 0x20;
|
||||||
|
ir.Mouse.RightButton = Buttons & 0x10;
|
||||||
|
ir.Mouse.MiddleButton = Buttons & 0x08;
|
||||||
|
// ir.Mouse.Button4 = 0x0;
|
||||||
|
// ir.Mouse.Button5 = 0x0;
|
||||||
|
// ir.Mouse.Button6 = 0x0;
|
||||||
|
// ir.Mouse.Button7 = 0x0;
|
||||||
|
// ir.Mouse.Button8 = 0x0;
|
||||||
|
v0::ReportInputEvent(DriverID, &ir);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Ioctl(struct Inode *, unsigned long Request, void *)
|
||||||
|
{
|
||||||
|
switch (Request)
|
||||||
|
{
|
||||||
|
case 0x1:
|
||||||
|
Relative();
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
Absolute();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct InodeOperations ops = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = nullptr,
|
||||||
|
.Write = nullptr,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = nullptr,
|
||||||
|
.Close = nullptr,
|
||||||
|
.Ioctl = Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = nullptr,
|
||||||
|
.Stat = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ToolboxSupported = false;
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
ToolboxContext tb_ctx = {};
|
||||||
|
/* Test if it's supported */
|
||||||
|
int status = OpenMessageChannel(&tb_ctx, MESSAGE_TCLO);
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
ToolboxSupported = true;
|
||||||
|
MessageClose(&tb_ctx);
|
||||||
|
dst_id = v0::CreateKernelThread(DriverID, 0, "VMware Display Scale",
|
||||||
|
(void *)DisplayScaleThread, NULL);
|
||||||
|
dst_pid = v0::GetCurrentProcess(DriverID);
|
||||||
|
}
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_ENABLE_PORT_2);
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_READ_CONFIG);
|
||||||
|
PS2_CONFIGURATION config = {.Raw = v0::PS2ReadData(DriverID)};
|
||||||
|
config.Port2Interrupt = 1;
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_CONFIG);
|
||||||
|
v0::PS2WriteData(DriverID, config.Raw);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_SET_DEFAULTS);
|
||||||
|
v0::PS2ReadData(DriverID);
|
||||||
|
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
|
||||||
|
v0::PS2ReadData(DriverID);
|
||||||
|
Absolute();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we have another driver using the PS/2 mouse, we need to
|
||||||
|
* override its interrupt handler.
|
||||||
|
*/
|
||||||
|
v0::OverrideInterruptHandler(DriverID, 12, (void *)InterruptHandler);
|
||||||
|
|
||||||
|
MouseDevID = v0::RegisterDevice(DriverID, INPUT_TYPE_MOUSE, &ops);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||||
|
|
||||||
|
Relative();
|
||||||
|
|
||||||
|
v0::UnregisterDevice(DriverID, MouseDevID);
|
||||||
|
|
||||||
|
if (ToolboxSupported)
|
||||||
|
{
|
||||||
|
v0::KillThread(DriverID, dst_id, dst_pid, 0);
|
||||||
|
if (tb_ctx->TCLOChannel != -1)
|
||||||
|
MessageClose(tb_ctx);
|
||||||
|
DriverManager->FreeMemory(DriverID, tb_ctx, 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic()
|
||||||
|
{
|
||||||
|
Relative();
|
||||||
|
v0::PS2WriteCommand(DriverID, PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
|
||||||
|
v0::PS2WriteData(DriverID, PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Probe()
|
||||||
|
{
|
||||||
|
if (!IsVMwareBackdoorAvailable())
|
||||||
|
return -ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(vmware,
|
||||||
|
"VMware Tools Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
485
Kernel/drivers/net/e1000/e1000.cpp
Normal file
485
Kernel/drivers/net/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 <driver.hpp>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
#include <pci.hpp>
|
||||||
|
#include <net/net.hpp>
|
||||||
|
|
||||||
|
#include "e1000.hpp"
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
extern PCI::Manager *PCIManager;
|
||||||
|
namespace Driver::E1000
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
class E1000Device
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PCI::PCIHeader0 *Header;
|
||||||
|
uint16_t DeviceID;
|
||||||
|
bool Initialized = false;
|
||||||
|
|
||||||
|
bool EEPROMAvailable = false;
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
debug("Initializing RX...");
|
||||||
|
uintptr_t Ptr = (uintptr_t)v0::AllocateMemory(DriverID,
|
||||||
|
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)v0::AllocateMemory(DriverID,
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
debug("Initializing TX...");
|
||||||
|
uintptr_t Ptr = (uintptr_t)v0::AllocateMemory(DriverID,
|
||||||
|
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))
|
||||||
|
v0::Yield(DriverID);
|
||||||
|
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
|
||||||
|
{
|
||||||
|
trace("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(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
WriteCMD(REG::IMASK, 0x1);
|
||||||
|
uint32_t status = ReadCMD(0xC0);
|
||||||
|
UNUSED(status);
|
||||||
|
|
||||||
|
while ((RX[RXCurrent]->Status & 0x1))
|
||||||
|
{
|
||||||
|
uint8_t *data = (uint8_t *)RX[RXCurrent]->Address;
|
||||||
|
uint16_t dataSz = RX[RXCurrent]->Length;
|
||||||
|
|
||||||
|
// ReportNetworkPacket(ID, data, dataSz);
|
||||||
|
/* FIXME: Implement */
|
||||||
|
trace("FIXME: Received packet");
|
||||||
|
(void)data;
|
||||||
|
(void)dataSz;
|
||||||
|
|
||||||
|
RX[RXCurrent]->Status = 0;
|
||||||
|
uint16_t OldRXCurrent = RXCurrent;
|
||||||
|
RXCurrent = (uint16_t)((RXCurrent + 1) % E1000_NUM_RX_DESC);
|
||||||
|
WriteCMD(REG::RXDESCTAIL, OldRXCurrent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panic()
|
||||||
|
{
|
||||||
|
WriteCMD(REG::IMASK, 0x00000000);
|
||||||
|
WriteCMD(REG::ITR, 0x00000000);
|
||||||
|
WriteCMD(REG::IAM, 0x00000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
E1000Device(PCI::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:
|
||||||
|
{
|
||||||
|
trace("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())
|
||||||
|
{
|
||||||
|
trace("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:
|
||||||
|
{
|
||||||
|
trace("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:
|
||||||
|
{
|
||||||
|
trace("Unimplemented E1000 device.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
((PCI::PCIDeviceHeader *)Header)->Command |= PCI::PCI_COMMAND_INTX_DISABLE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<dev_t, E1000Device *> Drivers;
|
||||||
|
|
||||||
|
int Open(struct Inode *, int, mode_t)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Close(struct Inode *)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Read(struct Inode *, void *, size_t, off_t)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
||||||
|
{
|
||||||
|
return Drivers[Node->GetMinor()]->write((uint8_t *)Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
return Drivers[Node->GetMinor()]->ioctl((NetIoctl)Request, Argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct InodeOperations ops = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = Read,
|
||||||
|
.Write = Write,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = Open,
|
||||||
|
.Close = Close,
|
||||||
|
.Ioctl = Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = nullptr,
|
||||||
|
.Stat = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::list<PCI::PCIDevice> Devices;
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
for (auto &&dev : Devices)
|
||||||
|
{
|
||||||
|
PCIManager->InitializeDevice(dev, KernelPageTable);
|
||||||
|
E1000Device *e1000 = new E1000Device((PCI::PCIHeader0 *)dev.Header,
|
||||||
|
dev.Header->DeviceID);
|
||||||
|
|
||||||
|
if (e1000->IsInitialized())
|
||||||
|
{
|
||||||
|
dev_t ret = v0::RegisterDevice(DriverID, NETWORK_TYPE_ETHERNET, &ops);
|
||||||
|
Drivers[ret] = e1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Drivers.empty())
|
||||||
|
{
|
||||||
|
trace("No valid E1000 device found.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
for (auto &&dev : Drivers)
|
||||||
|
{
|
||||||
|
dev_t ret = dev.first;
|
||||||
|
v0::UnregisterDevice(DriverID, ret);
|
||||||
|
delete dev.second;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic()
|
||||||
|
{
|
||||||
|
for (auto &&i : Drivers)
|
||||||
|
i.second->Panic();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Probe()
|
||||||
|
{
|
||||||
|
Devices = PCIManager->FindPCIDevice(
|
||||||
|
{
|
||||||
|
0x8086, /* Intel */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0x100E, /* 82540EM */
|
||||||
|
0x100F, /* 82545EM */
|
||||||
|
0x10D3, /* 82574L */
|
||||||
|
0x10EA, /* I217-LM */
|
||||||
|
0x153A, /* 82577LM */
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Devices.empty())
|
||||||
|
{
|
||||||
|
trace("No E1000 device found.");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(e1000,
|
||||||
|
"Intel(R) PRO/1000 Network Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
@ -1,25 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of Fennix Drivers.
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License as
|
modify it under the terms of the GNU General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of
|
published by the Free Software Foundation, either version 3 of
|
||||||
the License, or (at your option) any later version.
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
enum REG
|
enum REG
|
||||||
{
|
{
|
||||||
CTRL = 0x0000,
|
CTRL = 0x0000,
|
||||||
@ -155,9 +154,3 @@ struct TXDescriptor
|
|||||||
volatile uint8_t css;
|
volatile uint8_t css;
|
||||||
volatile uint16_t Special;
|
volatile uint16_t Special;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
#endif
|
|
||||||
|
|
||||||
EXTERNC int cxx_Panic();
|
|
||||||
EXTERNC int cxx_Probe();
|
|
||||||
EXTERNC int cxx_Initialize();
|
|
||||||
EXTERNC int cxx_Finalize();
|
|
294
Kernel/drivers/net/rtl8139/rtl8139.cpp
Normal file
294
Kernel/drivers/net/rtl8139/rtl8139.cpp
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
#include <cpu.hpp>
|
||||||
|
#include <pci.hpp>
|
||||||
|
#include <net/net.hpp>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#include "rtl8139.hpp"
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
extern PCI::Manager *PCIManager;
|
||||||
|
namespace Driver::RTL8139
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
class RTL8139Device
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PCI::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(CPU::TrapFrame *)
|
||||||
|
{
|
||||||
|
/* Acknowledge interrupt */
|
||||||
|
uint16_t status = inw(RegISR);
|
||||||
|
debug("%#lx", status);
|
||||||
|
|
||||||
|
/* Read status */
|
||||||
|
if (status & RecOK)
|
||||||
|
{
|
||||||
|
/* Get the current packet */
|
||||||
|
uint16_t *data = (uint16_t *)(RXBuffer + CurrentPacket);
|
||||||
|
uint16_t dataSz = *(data + 1);
|
||||||
|
data += 2;
|
||||||
|
|
||||||
|
// ReportNetworkPacket(ID, data, dataSz);
|
||||||
|
/* FIXME: Implement */
|
||||||
|
fixme("Received packet");
|
||||||
|
(void)data;
|
||||||
|
(void)dataSz;
|
||||||
|
|
||||||
|
/* Update CAPR */
|
||||||
|
#define RX_READ_PTR_MASK (~0x3)
|
||||||
|
CurrentPacket = (uint16_t)((CurrentPacket + dataSz + 4 + 3) & RX_READ_PTR_MASK);
|
||||||
|
if (CurrentPacket > BufferSize)
|
||||||
|
CurrentPacket -= uint16_t(BufferSize);
|
||||||
|
outw(RegCAPR, CurrentPacket - 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear interrupt */
|
||||||
|
outw(RegISR, (RecOK | RecBad | SendOK | SendBad));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panic()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RTL8139Device(PCI::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 *)v0::AllocateMemory(DriverID, TO_PAGES(BufferSize));
|
||||||
|
|
||||||
|
/* Power on */
|
||||||
|
outb(RegCONFIG1, 0x0);
|
||||||
|
|
||||||
|
/* Software Reset */
|
||||||
|
outb(RegCMD, 0x10);
|
||||||
|
while (inb(RegCMD) & 0x10)
|
||||||
|
v0::Yield(DriverID);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
((PCI::PCIDeviceHeader *)Header)->Command |= PCI::PCI_COMMAND_INTX_DISABLE;
|
||||||
|
/* FIXME: Shutdown code */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<dev_t, RTL8139Device *> Drivers;
|
||||||
|
|
||||||
|
int Open(struct Inode *, int, mode_t)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Close(struct Inode *)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Read(struct Inode *, void *, size_t, off_t)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t)
|
||||||
|
{
|
||||||
|
return Drivers[Node->GetMinor()]->write((uint8_t *)Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
return Drivers[Node->GetMinor()]->ioctl((NetIoctl)Request, Argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct InodeOperations ops = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = Read,
|
||||||
|
.Write = Write,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = Open,
|
||||||
|
.Close = Close,
|
||||||
|
.Ioctl = Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = nullptr,
|
||||||
|
.Stat = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::list<PCI::PCIDevice> Devices;
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
for (auto &&dev : Devices)
|
||||||
|
{
|
||||||
|
PCIManager->InitializeDevice(dev, KernelPageTable);
|
||||||
|
RTL8139Device *rtl8139 = new RTL8139Device((PCI::PCIHeader0 *)dev.Header);
|
||||||
|
if (rtl8139->IsInitialized())
|
||||||
|
{
|
||||||
|
dev_t ret = v0::RegisterDevice(DriverID, NETWORK_TYPE_ETHERNET, &ops);
|
||||||
|
Drivers[ret] = rtl8139;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Drivers.empty())
|
||||||
|
{
|
||||||
|
trace("No valid RTL8139 device found.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
for (auto &&dev : Drivers)
|
||||||
|
{
|
||||||
|
dev_t ret = dev.first;
|
||||||
|
v0::UnregisterDevice(DriverID, ret);
|
||||||
|
delete dev.second;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic()
|
||||||
|
{
|
||||||
|
for (auto &&i : Drivers)
|
||||||
|
i.second->Panic();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Probe()
|
||||||
|
{
|
||||||
|
Devices = PCIManager->FindPCIDevice(
|
||||||
|
{
|
||||||
|
0x10EC, /* Realtek */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0x8139, /* RTL8139 */
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Devices.empty())
|
||||||
|
{
|
||||||
|
trace("No RTL8139 device found.");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(rtl8139,
|
||||||
|
"Realtek RTL8139 Network Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
@ -1,18 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of Fennix Drivers.
|
This file is part of Fennix Kernel.
|
||||||
|
|
||||||
Fennix Drivers is free software: you can redistribute it and/or
|
Fennix Kernel is free software: you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License as
|
modify it under the terms of the GNU General Public License as
|
||||||
published by the Free Software Foundation, either version 3 of
|
published by the Free Software Foundation, either version 3 of
|
||||||
the License, or (at your option) any later version.
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
Fennix Drivers is distributed in the hope that it will be useful,
|
Fennix Kernel is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -86,8 +86,3 @@ enum Registers
|
|||||||
RegIMR = 0x3C,
|
RegIMR = 0x3C,
|
||||||
RegISR = 0x3E,
|
RegISR = 0x3E,
|
||||||
};
|
};
|
||||||
|
|
||||||
EXTERNC int cxx_Panic();
|
|
||||||
EXTERNC int cxx_Probe();
|
|
||||||
EXTERNC int cxx_Initialize();
|
|
||||||
EXTERNC int cxx_Finalize();
|
|
1010
Kernel/drivers/storage/ahci/ahci.cpp
Normal file
1010
Kernel/drivers/storage/ahci/ahci.cpp
Normal file
File diff suppressed because it is too large
Load Diff
128
Kernel/drivers/video/kdm/kdm.cpp
Normal file
128
Kernel/drivers/video/kdm/kdm.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
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 <driver.hpp>
|
||||||
|
|
||||||
|
extern Driver::Manager *DriverManager;
|
||||||
|
namespace Driver::KernelDisplayManager
|
||||||
|
{
|
||||||
|
dev_t DriverID;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
dev_t kdm;
|
||||||
|
} ids;
|
||||||
|
|
||||||
|
int Open(struct Inode *Node, int Flags, mode_t Mode)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kdm)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Close(struct Inode *Node)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kdm)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kdm)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kdm)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||||
|
{
|
||||||
|
dev_t min = Node->GetMinor();
|
||||||
|
if (min == ids.kdm)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t Seek(struct Inode *Node, off_t Offset) { return -ENOSYS; }
|
||||||
|
int Stat(struct Inode *Node, struct kstat *Stat) { return -ENOSYS; }
|
||||||
|
|
||||||
|
const struct InodeOperations ops = {
|
||||||
|
.Lookup = nullptr,
|
||||||
|
.Create = nullptr,
|
||||||
|
.Remove = nullptr,
|
||||||
|
.Rename = nullptr,
|
||||||
|
.Read = Read,
|
||||||
|
.Write = Write,
|
||||||
|
.Truncate = nullptr,
|
||||||
|
.Open = Open,
|
||||||
|
.Close = Close,
|
||||||
|
.Ioctl = Ioctl,
|
||||||
|
.ReadDir = nullptr,
|
||||||
|
.MkDir = nullptr,
|
||||||
|
.RmDir = nullptr,
|
||||||
|
.SymLink = nullptr,
|
||||||
|
.ReadLink = nullptr,
|
||||||
|
.Seek = Seek,
|
||||||
|
.Stat = Stat,
|
||||||
|
};
|
||||||
|
|
||||||
|
int Entry()
|
||||||
|
{
|
||||||
|
mode_t mode = 0;
|
||||||
|
|
||||||
|
/* c rw- rw- rw- */
|
||||||
|
mode = S_IRUSR | S_IWUSR |
|
||||||
|
S_IRGRP | S_IWGRP |
|
||||||
|
S_IROTH | S_IWOTH |
|
||||||
|
S_IFCHR;
|
||||||
|
ids.kdm = DriverManager->CreateDeviceFile(DriverID, "kdm", mode, &ops);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Final()
|
||||||
|
{
|
||||||
|
DriverManager->UnregisterDevice(DriverID, ids.kdm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Panic() { return 0; }
|
||||||
|
int Probe() { return 0; }
|
||||||
|
|
||||||
|
REGISTER_BUILTIN_DRIVER(kdm,
|
||||||
|
"Kernel Display Manager Driver",
|
||||||
|
"enderice2",
|
||||||
|
1, 0, 0,
|
||||||
|
Entry,
|
||||||
|
Final,
|
||||||
|
Panic,
|
||||||
|
Probe);
|
||||||
|
}
|
@ -38,6 +38,51 @@
|
|||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
struct BuiltInDriver
|
||||||
|
{
|
||||||
|
char Name[32] = {'\0'};
|
||||||
|
char Description[64] = {'\0'};
|
||||||
|
char Author[32] = {'\0'};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int Major, Minor, Patch;
|
||||||
|
} Version = {0, 0, 0};
|
||||||
|
char License[32] = {'\0'};
|
||||||
|
bool Initialized = false;
|
||||||
|
int ErrorCode = 0;
|
||||||
|
|
||||||
|
int (*Entry)() = nullptr;
|
||||||
|
int (*Final)() = nullptr;
|
||||||
|
int (*Panic)() = nullptr;
|
||||||
|
int (*Probe)() = nullptr;
|
||||||
|
uintptr_t EntryPoint = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const BuiltInDriver __kernel_builtin_drivers_start[];
|
||||||
|
extern const BuiltInDriver __kernel_builtin_drivers_end[];
|
||||||
|
|
||||||
|
#define REGISTER_BUILTIN_DRIVER(driverName, desc, auth, maj, min, patch, \
|
||||||
|
entryFunc, finalFunc, panicFunc, initFunc) \
|
||||||
|
int __builtin_driver_start_##driverName(dev_t id) \
|
||||||
|
{ \
|
||||||
|
DriverID = id; \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
static const BuiltInDriver __builtin_driver_##driverName \
|
||||||
|
__attribute__((section(".builtin_drivers"), used)) = { \
|
||||||
|
#driverName, \
|
||||||
|
desc, \
|
||||||
|
auth, \
|
||||||
|
{maj, min, patch}, \
|
||||||
|
"", \
|
||||||
|
false, \
|
||||||
|
0, \
|
||||||
|
entryFunc, \
|
||||||
|
finalFunc, \
|
||||||
|
panicFunc, \
|
||||||
|
initFunc, \
|
||||||
|
(uintptr_t)__builtin_driver_start_##driverName}
|
||||||
|
|
||||||
namespace Driver
|
namespace Driver
|
||||||
{
|
{
|
||||||
char GetScanCode(uint8_t ScanCode, bool Upper);
|
char GetScanCode(uint8_t ScanCode, bool Upper);
|
||||||
@ -50,10 +95,10 @@ namespace Driver
|
|||||||
RingBuffer<InputReport> *InputReports;
|
RingBuffer<InputReport> *InputReports;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DriverObject
|
struct DriverObject : BuiltInDriver
|
||||||
{
|
{
|
||||||
|
bool IsBuiltIn = false;
|
||||||
uintptr_t BaseAddress = 0;
|
uintptr_t BaseAddress = 0;
|
||||||
uintptr_t EntryPoint = 0;
|
|
||||||
Memory::VirtualMemoryArea *vma;
|
Memory::VirtualMemoryArea *vma;
|
||||||
|
|
||||||
/* Path has the same pointer as in the Node */
|
/* Path has the same pointer as in the Node */
|
||||||
@ -61,22 +106,6 @@ namespace Driver
|
|||||||
std::unordered_map<uint8_t, void *> *InterruptHandlers;
|
std::unordered_map<uint8_t, void *> *InterruptHandlers;
|
||||||
std::unordered_map<dev_t, DriverHandlers> *DeviceOperations;
|
std::unordered_map<dev_t, DriverHandlers> *DeviceOperations;
|
||||||
dev_t ID = 0;
|
dev_t ID = 0;
|
||||||
|
|
||||||
char Name[32] = {'\0'};
|
|
||||||
char Description[64] = {'\0'};
|
|
||||||
char Author[32] = {'\0'};
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int Major, Minor, Patch;
|
|
||||||
} Version = {0, 0, 0};
|
|
||||||
char License[32] = {'\0'};
|
|
||||||
bool Initialized = false;
|
|
||||||
int ErrorCode = 0;
|
|
||||||
|
|
||||||
int (*Entry)() = nullptr;
|
|
||||||
int (*Final)() = nullptr;
|
|
||||||
int (*Panic)() = nullptr;
|
|
||||||
int (*Probe)() = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Manager
|
class Manager
|
||||||
@ -93,8 +122,8 @@ namespace Driver
|
|||||||
FileNode *devNode = nullptr;
|
FileNode *devNode = nullptr;
|
||||||
FileNode *devInputNode = nullptr;
|
FileNode *devInputNode = nullptr;
|
||||||
|
|
||||||
|
|
||||||
int LoadDriverFile(DriverObject &Drv, FileNode *File);
|
int LoadDriverFile(DriverObject &Drv, FileNode *File);
|
||||||
|
void ReloadDriver(dev_t driverID);
|
||||||
|
|
||||||
void InitializeDaemonFS();
|
void InitializeDaemonFS();
|
||||||
|
|
||||||
@ -148,11 +177,15 @@ namespace Driver
|
|||||||
*/
|
*/
|
||||||
dev_t CreateIncrementalDevice(dev_t DriverID, const std::string &Prefix, mode_t Mode, InodeOperations *Ops);
|
dev_t CreateIncrementalDevice(dev_t DriverID, const std::string &Prefix, mode_t Mode, InodeOperations *Ops);
|
||||||
|
|
||||||
|
dev_t CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations);
|
||||||
|
|
||||||
dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations);
|
dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations);
|
||||||
int ReportInputEvent(dev_t DriverID, InputReport *Report);
|
int ReportInputEvent(dev_t DriverID, InputReport *Report);
|
||||||
|
|
||||||
int UnregisterDevice(dev_t DriverID, dev_t Device);
|
int UnregisterDevice(dev_t DriverID, dev_t Device);
|
||||||
|
|
||||||
|
void *AllocateMemory(dev_t DriverID, size_t Pages);
|
||||||
|
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages);
|
||||||
|
|
||||||
Manager();
|
Manager();
|
||||||
~Manager();
|
~Manager();
|
||||||
};
|
};
|
||||||
@ -162,4 +195,73 @@ namespace Driver
|
|||||||
|
|
||||||
void *GetSymbolByName(const char *Name, int Version);
|
void *GetSymbolByName(const char *Name, int Version);
|
||||||
|
|
||||||
|
#ifndef NO_API_IN_HEADER
|
||||||
|
namespace v0
|
||||||
|
{
|
||||||
|
typedef int CriticalState;
|
||||||
|
|
||||||
|
void KernelPrint(dev_t DriverID, const char *Format, va_list args);
|
||||||
|
void KernelLog(dev_t DriverID, const char *Format, va_list args);
|
||||||
|
|
||||||
|
CriticalState EnterCriticalSection(dev_t DriverID);
|
||||||
|
void LeaveCriticalSection(dev_t DriverID, CriticalState PreviousState);
|
||||||
|
|
||||||
|
int RegisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler);
|
||||||
|
int OverrideInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler);
|
||||||
|
int UnregisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler);
|
||||||
|
int UnregisterAllInterruptHandlers(dev_t DriverID, void *Handler);
|
||||||
|
|
||||||
|
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root);
|
||||||
|
int UnregisterFileSystem(dev_t DriverID, dev_t Device);
|
||||||
|
|
||||||
|
pid_t CreateKernelProcess(dev_t DriverID, const char *Name);
|
||||||
|
pid_t CreateKernelThread(dev_t DriverID, pid_t pId, const char *Name, void *EntryPoint, void *Argument);
|
||||||
|
pid_t GetCurrentProcess(dev_t DriverID);
|
||||||
|
int KillProcess(dev_t DriverID, pid_t pId, int ExitCode);
|
||||||
|
int KillThread(dev_t DriverID, pid_t tId, pid_t pId, int ExitCode);
|
||||||
|
void Yield(dev_t DriverID);
|
||||||
|
void Sleep(dev_t DriverID, uint64_t Milliseconds);
|
||||||
|
|
||||||
|
void PIC_EOI(dev_t DriverID, uint8_t IRQ);
|
||||||
|
void IRQ_MASK(dev_t DriverID, uint8_t IRQ);
|
||||||
|
void IRQ_UNMASK(dev_t DriverID, uint8_t IRQ);
|
||||||
|
|
||||||
|
void PS2Wait(dev_t DriverID, const bool Output);
|
||||||
|
void PS2WriteCommand(dev_t DriverID, uint8_t Command);
|
||||||
|
void PS2WriteData(dev_t DriverID, uint8_t Data);
|
||||||
|
uint8_t PS2ReadData(dev_t DriverID);
|
||||||
|
uint8_t PS2ReadStatus(dev_t DriverID);
|
||||||
|
uint8_t PS2ReadAfterACK(dev_t DriverID);
|
||||||
|
void PS2ClearOutputBuffer(dev_t DriverID);
|
||||||
|
int PS2ACKTimeout(dev_t DriverID);
|
||||||
|
|
||||||
|
void *AllocateMemory(dev_t DriverID, size_t Pages);
|
||||||
|
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages);
|
||||||
|
void *MemoryCopy(dev_t DriverID, void *Destination, const void *Source, size_t Length);
|
||||||
|
void *MemorySet(dev_t DriverID, void *Destination, int Value, size_t Length);
|
||||||
|
void *MemoryMove(dev_t DriverID, void *Destination, const void *Source, size_t Length);
|
||||||
|
size_t StringLength(dev_t DriverID, const char String[]);
|
||||||
|
char *_strstr(dev_t DriverID, const char *Haystack, const char *Needle);
|
||||||
|
|
||||||
|
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);
|
||||||
|
void AppendMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag);
|
||||||
|
void RemoveMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag);
|
||||||
|
|
||||||
|
void *Znwm(size_t Size);
|
||||||
|
void ZdlPvm(void *Pointer, size_t Size);
|
||||||
|
|
||||||
|
__PCIArray *GetPCIDevices(dev_t DriverID, uint16_t _Vendors[], uint16_t _Devices[]);
|
||||||
|
void InitializePCI(dev_t DriverID, void *_Header);
|
||||||
|
uint32_t GetBAR(dev_t DriverID, uint8_t i, void *_Header);
|
||||||
|
uint8_t iLine(dev_t DriverID, PCI::PCIDevice *Device);
|
||||||
|
uint8_t iPin(dev_t DriverID, PCI::PCIDevice *Device);
|
||||||
|
|
||||||
|
dev_t CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations);
|
||||||
|
dev_t RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations);
|
||||||
|
int UnregisterDevice(dev_t DriverID, dev_t Device);
|
||||||
|
int ReportInputEvent(dev_t DriverID, InputReport *Report);
|
||||||
|
}
|
||||||
|
#endif // !NO_API_IN_HEADER
|
||||||
|
|
||||||
#endif // !__FENNIX_KERNEL_DRIVER_H__
|
#endif // !__FENNIX_KERNEL_DRIVER_H__
|
||||||
|
@ -31,6 +31,24 @@
|
|||||||
static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
|
static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
|
||||||
static_assert(IFTODT(S_IFCHR) == DT_CHR);
|
static_assert(IFTODT(S_IFCHR) == DT_CHR);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This macro is used to check if a filesystem operation is available.
|
||||||
|
*
|
||||||
|
* TL;DR
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* if FileSystemInfo.Ops.op == nullptr
|
||||||
|
* return -err
|
||||||
|
* else
|
||||||
|
* return FileSystemInfo.Ops.op(this->Node, ...);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param op The operation to check.
|
||||||
|
* @param err The error to return if the operation is not available.
|
||||||
|
* @param ... The arguments to pass to the operation.
|
||||||
|
*
|
||||||
|
* @return The result of the operation.
|
||||||
|
*/
|
||||||
#define __check_op(op, err, ...) \
|
#define __check_op(op, err, ...) \
|
||||||
if (fsi->Ops.op == nullptr) \
|
if (fsi->Ops.op == nullptr) \
|
||||||
return -err; \
|
return -err; \
|
||||||
|
@ -103,6 +103,7 @@ typedef union
|
|||||||
uint8_t Raw;
|
uint8_t Raw;
|
||||||
} PS2_OUTPUT_PORT;
|
} PS2_OUTPUT_PORT;
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
void PIC_EOI(uint8_t IRQ);
|
void PIC_EOI(uint8_t IRQ);
|
||||||
void IRQ_MASK(uint8_t IRQ);
|
void IRQ_MASK(uint8_t IRQ);
|
||||||
void IRQ_UNMASK(uint8_t IRQ);
|
void IRQ_UNMASK(uint8_t IRQ);
|
||||||
@ -114,11 +115,11 @@ uint8_t PS2ReadStatus();
|
|||||||
uint8_t PS2ReadAfterACK();
|
uint8_t PS2ReadAfterACK();
|
||||||
void PS2ClearOutputBuffer();
|
void PS2ClearOutputBuffer();
|
||||||
int PS2ACKTimeout();
|
int PS2ACKTimeout();
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#define WaitOutput PS2Wait(DriverID, true)
|
#define WaitOutput PS2Wait(DriverID, true)
|
||||||
#define WaitInput PS2Wait(DriverID, false)
|
#define WaitInput PS2Wait(DriverID, false)
|
||||||
|
|
||||||
|
|
||||||
#define PS2_KBD_CMD_SET_LEDS 0xED
|
#define PS2_KBD_CMD_SET_LEDS 0xED
|
||||||
#define PS2_KBD_CMD_ECHO 0xEE
|
#define PS2_KBD_CMD_ECHO 0xEE
|
||||||
#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0
|
#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0
|
||||||
@ -189,7 +190,6 @@ typedef union
|
|||||||
uint8_t Raw;
|
uint8_t Raw;
|
||||||
} PS2_KBD_TYPEMATIC;
|
} PS2_KBD_TYPEMATIC;
|
||||||
|
|
||||||
|
|
||||||
#define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6
|
#define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6
|
||||||
#define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7
|
#define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7
|
||||||
#define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8
|
#define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8
|
||||||
|
@ -69,7 +69,10 @@ typedef enum
|
|||||||
BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128,
|
BLOCK_TYPE_FLOPPY = DEVICE_TYPE_BLOCK + 128,
|
||||||
} DeviceType;
|
} DeviceType;
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
|
EXTERNC dev_t CreateDeviceFile(const char *name, mode_t mode, const struct InodeOperations *Operations);
|
||||||
EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations);
|
EXTERNC dev_t RegisterDevice(DeviceType Type, const struct InodeOperations *Operations);
|
||||||
EXTERNC int UnregisterDevice(dev_t Device);
|
EXTERNC int UnregisterDevice(dev_t Device);
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#endif // !__FENNIX_API_DEVICE_H__
|
#endif // !__FENNIX_API_DEVICE_H__
|
||||||
|
@ -377,7 +377,9 @@ struct FileSystemInfo
|
|||||||
void *PrivateData;
|
void *PrivateData;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
||||||
int UnregisterFileSystem(dev_t Device);
|
int UnregisterFileSystem(dev_t Device);
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#endif // !__FENNIX_API_FILESYSTEM_H__
|
#endif // !__FENNIX_API_FILESYSTEM_H__
|
||||||
|
@ -239,6 +239,8 @@ typedef struct
|
|||||||
};
|
};
|
||||||
} InputReport;
|
} InputReport;
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
EXTERNC int ReportInputEvent(InputReport *Report);
|
EXTERNC int ReportInputEvent(InputReport *Report);
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#endif // !__FENNIX_API_INPUT_H__
|
#endif // !__FENNIX_API_INPUT_H__
|
||||||
|
@ -171,11 +171,13 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __kernel__
|
||||||
PCIArray *GetPCIDevices(uint16_t Vendors[], uint16_t Devices[]);
|
PCIArray *GetPCIDevices(uint16_t Vendors[], uint16_t Devices[]);
|
||||||
void InitializePCI(PCIDevice *Device);
|
void InitializePCI(PCIDevice *Device);
|
||||||
uint32_t GetBAR(uint8_t Index, PCIDevice *Device);
|
uint32_t GetBAR(uint8_t Index, PCIDevice *Device);
|
||||||
uint8_t iLine(PCIDevice *Device);
|
uint8_t iLine(PCIDevice *Device);
|
||||||
uint8_t iPin(PCIDevice *Device);
|
uint8_t iPin(PCIDevice *Device);
|
||||||
|
#endif // !__kernel__
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -531,6 +531,28 @@ static_assert((int)__SYS_SIG_IGN == (int)___SYS_SIG_IGN, "SIG_IGN values do not
|
|||||||
typedef int __SYS_clockid_t;
|
typedef int __SYS_clockid_t;
|
||||||
typedef unsigned int __SYS_socklen_t;
|
typedef unsigned int __SYS_socklen_t;
|
||||||
|
|
||||||
|
typedef struct FramebufferScreenInfo
|
||||||
|
{
|
||||||
|
__UINT32_TYPE__ Width;
|
||||||
|
__UINT32_TYPE__ Height;
|
||||||
|
__UINT32_TYPE__ Pitch;
|
||||||
|
__UINT32_TYPE__ Bpp;
|
||||||
|
__UINT32_TYPE__ Size;
|
||||||
|
} FramebufferScreenInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get framebuffer screen info
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* struct FramebufferScreenInfo info;
|
||||||
|
* int ioctl(fd, FBIOGET_SCREEN_INFO, &info);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param fd File descriptor of the framebuffer device
|
||||||
|
* @param info Pointer to the framebuffer screen info structure
|
||||||
|
*/
|
||||||
|
#define FBIOGET_SCREEN_INFO 0xf0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief List of syscalls
|
* @brief List of syscalls
|
||||||
*
|
*
|
||||||
|
@ -232,6 +232,7 @@ namespace PCI
|
|||||||
public:
|
public:
|
||||||
std::list<PCIDevice> GetDevices() { return Devices; }
|
std::list<PCIDevice> GetDevices() { return Devices; }
|
||||||
void MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table);
|
void MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table);
|
||||||
|
void InitializeDevice(PCIDevice Device, Memory::PageTable *Table);
|
||||||
void EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev);
|
void EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev);
|
||||||
void EnumerateDevice(uint64_t BusAddress, uint32_t Device, PCIDevice dev);
|
void EnumerateDevice(uint64_t BusAddress, uint32_t Device, PCIDevice dev);
|
||||||
void EnumerateBus(uint64_t BaseAddress, uint32_t Bus, PCIDevice dev);
|
void EnumerateBus(uint64_t BaseAddress, uint32_t Bus, PCIDevice dev);
|
||||||
|
@ -1013,7 +1013,7 @@ namespace std
|
|||||||
_size = Traits::length(s);
|
_size = Traits::length(s);
|
||||||
_capacity = _size + 1;
|
_capacity = _size + 1;
|
||||||
_data = _alloc.allocate(_capacity);
|
_data = _alloc.allocate(_capacity);
|
||||||
memcpy(_data, s, _size);
|
memcpy(_data, s, _size > 0 ? _size : 1);
|
||||||
_data[_size] = '\0';
|
_data[_size] = '\0';
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,12 @@
|
|||||||
|
|
||||||
int SpawnInit()
|
int SpawnInit()
|
||||||
{
|
{
|
||||||
const char *envp[5] = {
|
const char *envp[6] = {
|
||||||
"PATH=/bin:/usr/bin",
|
"PATH=/bin:/usr/bin",
|
||||||
"TERM=tty",
|
"TERM=tty",
|
||||||
"HOME=/root",
|
"HOME=/root",
|
||||||
"USER=root",
|
"USER=root",
|
||||||
|
"TZ=UTC",
|
||||||
nullptr};
|
nullptr};
|
||||||
|
|
||||||
const char *argv[4] = {
|
const char *argv[4] = {
|
||||||
|
@ -398,10 +398,7 @@ uintptr_t HandleNativeSyscalls(SysFrm *Frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SyscallData sc = scTbl[Frame->ReturnValue()];
|
SyscallData sc = scTbl[Frame->ReturnValue()];
|
||||||
|
uintptr_t (*call)(SysFrm *, uintptr_t, ...) = r_cst(uintptr_t (*)(SysFrm *, uintptr_t, ...), sc.Handler);
|
||||||
uintptr_t (*call)(SysFrm *, uintptr_t, ...) =
|
|
||||||
r_cst(uintptr_t(*)(SysFrm *, uintptr_t, ...),
|
|
||||||
sc.Handler);
|
|
||||||
|
|
||||||
if (unlikely(!call))
|
if (unlikely(!call))
|
||||||
{
|
{
|
||||||
@ -410,16 +407,15 @@ uintptr_t HandleNativeSyscalls(SysFrm *Frame)
|
|||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("> [%d:\"%s\"]( %#lx %#lx %#lx %#lx %#lx %#lx )",
|
uintptr_t arg0 = Frame->Arg0();
|
||||||
Frame->ReturnValue(), sc.Name,
|
uintptr_t arg1 = Frame->Arg1();
|
||||||
Frame->Arg0(), Frame->Arg1(), Frame->Arg2(),
|
uintptr_t arg2 = Frame->Arg2();
|
||||||
Frame->Arg3(), Frame->Arg4(), Frame->Arg5());
|
uintptr_t arg3 = Frame->Arg3();
|
||||||
|
uintptr_t arg4 = Frame->Arg4();
|
||||||
|
uintptr_t arg5 = Frame->Arg5();
|
||||||
|
|
||||||
long sc_ret = call(Frame,
|
debug("> [%d:\"%s\"]( %#lx %#lx %#lx %#lx %#lx %#lx )", Frame->ReturnValue(), sc.Name, arg0, arg1, arg2, arg3, arg4, arg5);
|
||||||
Frame->Arg0(), Frame->Arg1(), Frame->Arg2(),
|
uintptr_t result = call(Frame, arg0, arg1, arg2, arg3, arg4, arg5);
|
||||||
Frame->Arg3(), Frame->Arg4(), Frame->Arg5());
|
debug("< [%d:\"%s\"] = %ld", Frame->ReturnValue(), sc.Name, result);
|
||||||
|
return result;
|
||||||
debug("< [%d:\"%s\"] = %ld",
|
|
||||||
Frame->ReturnValue(), sc.Name, sc_ret);
|
|
||||||
return sc_ret;
|
|
||||||
}
|
}
|
||||||
|
@ -105,10 +105,10 @@ namespace KernelConsole
|
|||||||
debug("string: \"%*s\"", Size, buf);
|
debug("string: \"%*s\"", Size, buf);
|
||||||
for (size_t i = 0; i < Size; i++)
|
for (size_t i = 0; i < Size; i++)
|
||||||
{
|
{
|
||||||
if (this->TerminalConfig.c_lflag & ICANON)
|
// if (this->TerminalConfig.c_lflag & ICANON)
|
||||||
this->Process(buf[i]);
|
this->Process(buf[i]);
|
||||||
else
|
// else
|
||||||
this->Append(buf[i]);
|
// this->Append(buf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("ret %ld", Size);
|
debug("ret %ld", Size);
|
||||||
|
@ -49,10 +49,22 @@ void ReapZombies()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HandleSignal(int signal)
|
||||||
|
{
|
||||||
|
if (signal == SIGTERM || signal == SIGINT)
|
||||||
|
{
|
||||||
|
printf("init: received termination signal, shutting down...\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
printf("init starting...\n");
|
printf("init starting...\n");
|
||||||
|
|
||||||
|
signal(SIGTERM, HandleSignal);
|
||||||
|
signal(SIGINT, HandleSignal);
|
||||||
|
|
||||||
char *shellArgs[] = {"/bin/sh", NULL};
|
char *shellArgs[] = {"/bin/sh", NULL};
|
||||||
StartProcess("/bin/sh", shellArgs);
|
StartProcess("/bin/sh", shellArgs);
|
||||||
|
|
||||||
|
@ -13,9 +13,6 @@ WARNCFLAG = -Wall -Wextra
|
|||||||
build: $(FILENAME).elf
|
build: $(FILENAME).elf
|
||||||
cp $(FILENAME).elf $(WORKSPACE_DIR)/out/bin/$(FILENAME)
|
cp $(FILENAME).elf $(WORKSPACE_DIR)/out/bin/$(FILENAME)
|
||||||
|
|
||||||
# Use static linking
|
|
||||||
LDFLAGS += -static -fno-pic -fno-pie -Wl,-static
|
|
||||||
|
|
||||||
$(FILENAME).elf: $(OBJ)
|
$(FILENAME).elf: $(OBJ)
|
||||||
$(info Linking $@)
|
$(info Linking $@)
|
||||||
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@
|
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@
|
119
Userspace/apps/sys/uname/uname.c
Normal file
119
Userspace/apps/sys/uname/uname.c
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
This file is part of Fennix Userspace.
|
||||||
|
|
||||||
|
Fennix Userspace 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 Userspace 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 Userspace. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void print_usage()
|
||||||
|
{
|
||||||
|
printf("Usage: uname [OPTION]...\n");
|
||||||
|
printf("Display specific system information. With no OPTION, defaults to -s.\n\n");
|
||||||
|
printf(" -a, --all display all information, in the following order,\n");
|
||||||
|
printf(" except omit -p and -i if unknown:\n");
|
||||||
|
printf(" -s, --kernel-name display the kernel name\n");
|
||||||
|
printf(" -n, --nodename display the network node hostname\n");
|
||||||
|
printf(" -r, --kernel-release display the kernel release\n");
|
||||||
|
printf(" -v, --kernel-version display the kernel version\n");
|
||||||
|
printf(" -m, --machine display the machine hardware name\n");
|
||||||
|
printf(" -p, --processor display the processor type (non-portable)\n");
|
||||||
|
printf(" -i, --hardware-platform display the hardware platform (non-portable)\n");
|
||||||
|
printf(" -o, --operating-system display the operating system\n");
|
||||||
|
printf(" --help show this help message and exit\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct utsname buffer;
|
||||||
|
if (uname(&buffer) != 0)
|
||||||
|
{
|
||||||
|
perror("uname");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool print_all = false;
|
||||||
|
bool print_kernel_name = false;
|
||||||
|
bool print_nodename = false;
|
||||||
|
bool print_kernel_release = false;
|
||||||
|
bool print_kernel_version = false;
|
||||||
|
bool print_machine = false;
|
||||||
|
bool print_processor = false;
|
||||||
|
bool print_hardware_platform = false;
|
||||||
|
bool print_operating_system = false;
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
print_kernel_name = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--all") == 0)
|
||||||
|
{
|
||||||
|
print_all = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--kernel-name") == 0)
|
||||||
|
print_kernel_name = true;
|
||||||
|
else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--nodename") == 0)
|
||||||
|
print_nodename = true;
|
||||||
|
else if (strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--kernel-release") == 0)
|
||||||
|
print_kernel_release = true;
|
||||||
|
else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--kernel-version") == 0)
|
||||||
|
print_kernel_version = true;
|
||||||
|
else if (strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--machine") == 0)
|
||||||
|
print_machine = true;
|
||||||
|
else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--processor") == 0)
|
||||||
|
print_processor = true;
|
||||||
|
else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--hardware-platform") == 0)
|
||||||
|
print_hardware_platform = true;
|
||||||
|
else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--operating-system") == 0)
|
||||||
|
print_operating_system = true;
|
||||||
|
else if (strcmp(argv[i], "--help") == 0)
|
||||||
|
{
|
||||||
|
print_usage();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "uname: invalid option -- '%s'\n", argv[i]);
|
||||||
|
print_usage();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_all || print_kernel_name)
|
||||||
|
printf("%s ", buffer.sysname);
|
||||||
|
if (print_all || print_nodename)
|
||||||
|
printf("%s ", buffer.nodename);
|
||||||
|
if (print_all || print_kernel_release)
|
||||||
|
printf("%s ", buffer.release);
|
||||||
|
if (print_all || print_kernel_version)
|
||||||
|
printf("%s ", buffer.version);
|
||||||
|
if (print_all || print_machine)
|
||||||
|
printf("%s ", buffer.machine);
|
||||||
|
if (print_all || print_processor)
|
||||||
|
printf("%s ", buffer.machine); /* FIXME */
|
||||||
|
if (print_all || print_hardware_platform)
|
||||||
|
printf("%s ", buffer.machine); /* FIXME */
|
||||||
|
if (print_all || print_operating_system)
|
||||||
|
printf("%s ", buffer.sysname); /* FIXME */
|
||||||
|
printf("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
19
Userspace/apps/test/libc_test/.devcontainer/Dockerfile
Normal file
19
Userspace/apps/test/libc_test/.devcontainer/Dockerfile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
FROM mcr.microsoft.com/devcontainers/cpp:ubuntu-24.04
|
||||||
|
|
||||||
|
ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="none"
|
||||||
|
|
||||||
|
# Optionally install the cmake for vcpkg
|
||||||
|
COPY ./reinstall-cmake.sh /tmp/
|
||||||
|
|
||||||
|
RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \
|
||||||
|
chmod +x /tmp/reinstall-cmake.sh && /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE}; \
|
||||||
|
fi \
|
||||||
|
&& rm -f /tmp/reinstall-cmake.sh
|
||||||
|
|
||||||
|
# [Optional] Uncomment this section to install additional vcpkg ports.
|
||||||
|
# RUN su vscode -c "${VCPKG_ROOT}/vcpkg install <your-port-name-here>"
|
||||||
|
|
||||||
|
# [Optional] Uncomment this section to install additional packages.
|
||||||
|
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
&& apt-get -y install --no-install-recommends build-essential make gdb git
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
|
||||||
|
{
|
||||||
|
"name": "libc test container",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "Dockerfile"
|
||||||
|
},
|
||||||
|
|
||||||
|
"customizations": {
|
||||||
|
// Configure properties specific to VS Code.
|
||||||
|
"vscode": {
|
||||||
|
"settings": {},
|
||||||
|
"extensions": [
|
||||||
|
"ms-vsliveshare.vsliveshare",
|
||||||
|
"ms-azuretools.vscode-docker",
|
||||||
|
"ms-vscode.cpptools",
|
||||||
|
"ms-vscode.makefile-tools",
|
||||||
|
"vivaxy.vscode-conventional-commits",
|
||||||
|
"EditorConfig.EditorConfig",
|
||||||
|
"eamodio.gitlens",
|
||||||
|
"ms-vscode.hexeditor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
// "features": {},
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
// "forwardPorts": [],
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
// "postCreateCommand": "gcc -v",
|
||||||
|
|
||||||
|
// Configure tool-specific properties.
|
||||||
|
// "customizations": {},
|
||||||
|
|
||||||
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
|
// "remoteUser": "root"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CMAKE_VERSION=${1:-"none"}
|
||||||
|
|
||||||
|
if [ "${CMAKE_VERSION}" = "none" ]; then
|
||||||
|
echo "No CMake version specified, skipping CMake reinstallation"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cleanup temporary directory and associated files when exiting the script.
|
||||||
|
cleanup() {
|
||||||
|
EXIT_CODE=$?
|
||||||
|
set +e
|
||||||
|
if [[ -n "${TMP_DIR}" ]]; then
|
||||||
|
echo "Executing cleanup of tmp files"
|
||||||
|
rm -Rf "${TMP_DIR}"
|
||||||
|
fi
|
||||||
|
exit $EXIT_CODE
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
|
||||||
|
echo "Installing CMake..."
|
||||||
|
apt-get -y purge --auto-remove cmake
|
||||||
|
mkdir -p /opt/cmake
|
||||||
|
|
||||||
|
architecture=$(dpkg --print-architecture)
|
||||||
|
case "${architecture}" in
|
||||||
|
arm64)
|
||||||
|
ARCH=aarch64 ;;
|
||||||
|
amd64)
|
||||||
|
ARCH=x86_64 ;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported architecture ${architecture}."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CMAKE_BINARY_NAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh"
|
||||||
|
CMAKE_CHECKSUM_NAME="cmake-${CMAKE_VERSION}-SHA-256.txt"
|
||||||
|
TMP_DIR=$(mktemp -d -t cmake-XXXXXXXXXX)
|
||||||
|
|
||||||
|
echo "${TMP_DIR}"
|
||||||
|
cd "${TMP_DIR}"
|
||||||
|
|
||||||
|
curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_BINARY_NAME}" -O
|
||||||
|
curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_CHECKSUM_NAME}" -O
|
||||||
|
|
||||||
|
sha256sum -c --ignore-missing "${CMAKE_CHECKSUM_NAME}"
|
||||||
|
sh "${TMP_DIR}/${CMAKE_BINARY_NAME}" --prefix=/opt/cmake --skip-license
|
||||||
|
|
||||||
|
ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake
|
||||||
|
ln -s /opt/cmake/bin/ctest /usr/local/bin/ctest
|
||||||
|
|
19
Userspace/apps/test/libc_test/.editorconfig
Normal file
19
Userspace/apps/test/libc_test/.editorconfig
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# EditorConfig is awesome: https://editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.json]
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
[compose.yaml]
|
||||||
|
indent_style = space
|
2
Userspace/apps/test/libc_test/.gitignore
vendored
Normal file
2
Userspace/apps/test/libc_test/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.o
|
||||||
|
*.elf
|
@ -1,6 +1,11 @@
|
|||||||
{
|
{
|
||||||
"libc_test stub macro": {
|
"libc_test stub macro": {
|
||||||
"prefix": "zxc",
|
"prefix": "zxc",
|
||||||
"body": "int test_$TM_FILENAME_BASE() { return 2; }"
|
"body": [
|
||||||
|
"int test_$TM_FILENAME_BASE()",
|
||||||
|
"{",
|
||||||
|
"\treturn 2;",
|
||||||
|
"}",
|
||||||
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
30
Userspace/apps/test/libc_test/.vscode/launch.json
vendored
Normal file
30
Userspace/apps/test/libc_test/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "(gdb) Launch",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/libc_test_n.elf",
|
||||||
|
"targetArchitecture": "x64",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb",
|
||||||
|
"internalConsoleOptions": "neverOpen",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "run-make"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
26
Userspace/apps/test/libc_test/.vscode/tasks.json
vendored
Normal file
26
Userspace/apps/test/libc_test/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "run-make",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make build_native",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"shell": {
|
||||||
|
"executable": "bash",
|
||||||
|
"args": [
|
||||||
|
"-c"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -10,6 +10,9 @@
|
|||||||
"git.alwaysSignOff": true,
|
"git.alwaysSignOff": true,
|
||||||
"git.defaultBranchName": "master",
|
"git.defaultBranchName": "master",
|
||||||
"git.openRepositoryInParentFolders": "always",
|
"git.openRepositoryInParentFolders": "always",
|
||||||
"C_Cpp.autoAddFileAssociations": false
|
"C_Cpp.autoAddFileAssociations": false,
|
||||||
|
"conventionalCommits.scopes": [
|
||||||
|
"userspace/apps/test/libc_test"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,24 @@ build: $(FILENAME).elf
|
|||||||
cp $(FILENAME).elf $(WORKSPACE_DIR)/out/bin/$(FILENAME)
|
cp $(FILENAME).elf $(WORKSPACE_DIR)/out/bin/$(FILENAME)
|
||||||
|
|
||||||
# Use static linking
|
# Use static linking
|
||||||
LDFLAGS += -static -fno-pic -fno-pie -Wl,-static
|
LDFLAGS += -ggdb3 -g -static -fno-pic -fno-pie -Wl,-static -Wl,-Ttext=0x00600000
|
||||||
|
CFLAGS += -ggdb3 -g -O0 -fdiagnostics-color=always
|
||||||
|
|
||||||
# Use default toolchain if not specified
|
# Use default toolchain if not specified
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CXX ?= g++
|
CXX ?= g++
|
||||||
AS ?= as
|
AS ?= as
|
||||||
|
GDBSERVER ?= /usr/bin/gdbserver
|
||||||
|
|
||||||
|
.PHONY: build_native run_native debug_native log_docker
|
||||||
|
|
||||||
|
log_docker:
|
||||||
|
# docker compose logs -f libc_test
|
||||||
|
|
||||||
|
debug_native:
|
||||||
|
$(MAKE) --quiet clean
|
||||||
|
$(MAKE) --quiet -j $(shell nproc) build_native
|
||||||
|
$(GDBSERVER) 0.0.0.0:9229 $(CURDIR)/$(FILENAME)_n.elf
|
||||||
|
|
||||||
build_native: $(FILENAME)_n.elf
|
build_native: $(FILENAME)_n.elf
|
||||||
|
|
||||||
@ -29,11 +41,11 @@ run_native:
|
|||||||
|
|
||||||
$(FILENAME)_n.elf $(FILENAME).elf: $(OBJ)
|
$(FILENAME)_n.elf $(FILENAME).elf: $(OBJ)
|
||||||
$(info Linking $@)
|
$(info Linking $@)
|
||||||
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@
|
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@ -lm
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
%.o: %.c $(HEADERS)
|
||||||
$(info Compiling $<)
|
$(info Compiling $<)
|
||||||
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@ -lm
|
||||||
|
|
||||||
%.o: %.cpp $(HEADERS)
|
%.o: %.cpp $(HEADERS)
|
||||||
$(info Compiling $<)
|
$(info Compiling $<)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user