Compare commits

..
Author SHA1 Message Date
LeencyandClaude Opus 5 1159103075 kernel/net: release the socket mutex before tcp_close in tcp_input
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 19s
Test PR / Build (es_ES) (pull_request) Successful in 2m50s
Test PR / Build (en_US) (pull_request) Successful in 2m54s
Test PR / Build (ru_RU) (pull_request) Successful in 2m55s
Summary: three paths in tcp_process_input called tcp_close/tcp_drop while
still holding the socket's mutex, which socket_free then tries to take
itself -- a self-deadlock of the TCP input thread, and, now that socket_free
also holds socket_mutex, a freeze of every socket syscall behind it.

Подробно:
tcp_process_input locks the socket's own mutex right after .found_socket and
keeps it for the whole state processing. Three of its paths reached
socket_free without releasing it:

- data arriving for a terminated process (tcp_close, then a reset reply);
- a new SYN arriving in TIME_WAIT (tcp_close, then restart at .findpcb);
- a SYN inside the window (tcp_drop, then .drop_with_reset).

socket_free has always locked the socket's mutex at its top, and the mutex is
not recursive, so these paths hung the TCP input thread the moment they were
taken. Since socket_free now also takes socket_mutex first, the hung thread
would additionally hold the list lock, stalling every socket syscall in every
process -- which is what turned this from a latent bug into one worth fixing
on the same branch.

Each site now unlocks the socket mutex first, the shape the file already uses
in .unlock_and_close and in the refused-connection path of .state_syn_sent.
The terminated-process path preserves edx across tcp_close because the reset
reply is built from the segment header; the TIME_WAIT path preserves ecx and
edx because .findpcb and everything after it still need the data count and the
header. The SYN-in-window path now leaves through .drop_no_socket instead of
.drop_with_reset: the old exit would have unlocked the freed socket's mutex
and built the reply out of freed memory, and the reply itself is redundant --
the connection is synchronized here, so tcp_drop already sends the RST via
tcp_output (tcp_outflags for TCPS_CLOSED is RST+ACK).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:46:41 +03:00
LeencyandClaude Opus 5 3051fae0ec kernel/net: serialize socket_free against walks of net_sockets
Summary: socket_free() unlinked a socket from net_sockets without holding
socket_mutex, so a socket freed by the TCP timers could rewrite the list while
tcp_process_input was walking it, leaving a garbage pointer that faulted in
ring 0 on the next incoming segment.

Подробно:
The header of socket_free already stated the rule -- "Caller should lock and
unlock socket_mutex" -- but no live caller obeyed it. socket_close, the
socket_pair out-of-memory paths, the DROPSOCKET path in tcp_input, and
tcp_close (reached from tcp_timer_640ms and from tcp_usreq) all called it with
the mutex free. The only caller that did hold it, socket_process_end, is
disabled by a `ret` at its first instruction.

Meanwhile tcp_process_input.findpcb walks net_sockets under socket_mutex and
dereferences whatever NextPtr it reads, and tcp_timer_160ms/640ms walk the same
list with no lock at all -- the second of them calling tcp_close, hence
socket_free, from inside the walk. The mutex therefore protected nothing: one
side honoured it, the other rewrote the list underneath.

Observed as a kernel page fault inside tcp_process_input with EBX = 0x0000047A,
where ebx is by contract the socket pointer taken from the list walk. It was
preceded by a flood of "SOCKET_notify: error finding thread", i.e. an
application had died leaving sockets behind -- socket_process_end being
disabled, those stay on net_sockets, go to FIN_WAIT/TIME_WAIT and are then
closed by the timers, which is exactly the unlocked socket_free path, at the
same time as traffic keeps arriving.

The mutex is acquired at the top of socket_free rather than around the unlink
alone. socket_alloc takes socket_mutex first and the neighbour's SOCKET.mutex
second; wrapping only the unlink would have acquired them in the opposite
order, since SOCKET.mutex is taken earlier in this function, and deadlocked
against socket_alloc. Taking it first also covers the socket_check walk at the
top, which reads net_sockets as well. No live caller holds socket_mutex, and
the mutex is not recursive, so no nesting is introduced; socket_process_end
gets a note explaining what its dead body would have to change before it can be
revived.

Not addressed here: the timer walks themselves still run unlocked, so two
concurrent walks are still unserialized. Holding socket_mutex across
tcp_timer_640ms would span tcp_output, tcp_disconnect and tcp_close, which is
the deadlock class that got socket_process_end disabled in the first place, and
belongs in its own change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:39:49 +03:00
673 changed files with 277799 additions and 80211 deletions

No files matched your search

-54
View File
@@ -1,54 +0,0 @@
# =============================================================================
# Apps
# User-facing applications, games, multimedia, UI and desktop resources
# =============================================================================
^programs/(cmm|demos|emulator|games|media|other)/.* @KolibriOS/apps
^contrib/(games|media|other)/.* @KolibriOS/apps
^skins/.* @KolibriOS/apps
# =============================================================================
# System
# Kernel, drivers, filesystems, SDK, libraries, toolchain and system utilities
# =============================================================================
^kernel/.* @KolibriOS/system
^drivers/.* @KolibriOS/system
^programs/(bcc32|develop|fs|hd_load|system|testing)/.* @KolibriOS/system
^contrib/(C_Layer|sdk|toolchain)/.* @KolibriOS/system
# Shared system/API includes in programs/
^programs/[^/]+\\.inc$ @KolibriOS/system
# =============================================================================
# Network
# Network stack, network drivers, protocols, libraries and network applications
# =============================================================================
^kernel/trunk/network/.* @KolibriOS/network
^drivers/ethernet/.* @KolibriOS/network
^drivers/(mii|netdrv)\\.inc$ @KolibriOS/network
^programs/network/.* @KolibriOS/network
^programs/network\\.inc$ @KolibriOS/network
^programs/develop/libraries/(http|network|kos_mbedtls)/.* @KolibriOS/network
^contrib/network/.* @KolibriOS/network
# =============================================================================
# DevOps
# CI/CD, repository infrastructure, build system and autobuild configuration
# =============================================================================
^\\.gitea/.* @KolibriOS/devops
^_tools/.* @KolibriOS/devops
^\\.gitmodules$ @KolibriOS/devops
^build\\.txt$ @KolibriOS/devops
^tup\\.config\\.template$ @KolibriOS/devops
-59
View File
@@ -19,62 +19,3 @@
owner: "{{ storage_user }}"
group: "{{ storage_user }}"
mode: preserve
# per-program binaries browsable at <version>/<lang>/data/, like on the old builds server
- name: Creating build tree folders
ansible.builtin.file:
path: "{{ storage_path }}/{{ version }}/{{ item | basename | regex_replace('\\.tar\\.gz$', '') }}/data"
state: directory
owner: "{{ storage_user }}"
group: "{{ storage_user }}"
mode: '0755'
with_fileglob: "{{ tree_artifact_path }}/*.tar.gz"
- name: Unpacking build trees
ansible.builtin.unarchive:
src: "{{ item }}"
dest: "{{ storage_path }}/{{ version }}/{{ item | basename | regex_replace('\\.tar\\.gz$', '') }}/data"
owner: "{{ storage_user }}"
group: "{{ storage_user }}"
with_fileglob: "{{ tree_artifact_path }}/*.tar.gz"
# stable URL for the newest build: <storage_path>/latest/<lang>/...
- name: Updating latest symlink
ansible.builtin.file:
src: "{{ version }}"
dest: "{{ storage_path }}/latest"
state: link
force: true
owner: "{{ storage_user }}"
group: "{{ storage_user }}"
# emulators hardcode <site root>/<lang>/data/data/kolibri.img; storage_path is the ci folder, one level under the site root
- name: Sending bare images to stable emulator paths
ansible.builtin.copy:
src: "{{ stable_artifact_path }}/"
dest: "{{ storage_path }}/../"
mode: preserve
# older builds shrink to compressed images and lose their unpacked tree; the newest few keep both
- name: Looking for zstd on the storage server
ansible.builtin.shell: command -v zstd
register: zstd_present
changed_when: false
failed_when: false
- name: Requiring zstd for compaction
ansible.builtin.assert:
that: zstd_present.rc == 0
fail_msg: >-
zstd is not installed on the storage server, so older builds cannot
be compacted. Install it and re-run this build.
- name: Compacting older builds
ansible.builtin.script:
cmd: >-
../../utils/compact-builds.sh
{{ storage_path | quote }}
{{ compact_keep | default(5) | int }}
{{ compact_max | default(10) | int }}
register: compaction
changed_when: "'compacted 0 of' not in compaction.stdout"
-74
View File
@@ -1,74 +0,0 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: 2026 KolibriOS team
# Shrink older builds on the storage server: compress their images and drop
# their unpacked tree, which is rebuildable from the commit. sha256sums.txt
# keeps naming the bare images, so a compacted build has to be decompressed
# before it can be verified.
#
# Layout: <root>/<version>/<lang>/kolibrios-<descr>-<lang>.{img,iso,raw} -> .zst
# <root>/<version>/<lang>/data/ -> removed
#
# Usage: compact-builds.sh <storage-root> [keep] [max-per-run]
# DRY_RUN=1 walks the same selection and changes nothing
set -euo pipefail
root=${1:?storage root required}
# the build just published is always among these, so an upload in flight is safe
keep=${2:-5}
# a build is hundreds of MiB to re-compress: cap the first pass over the backlog
max=${3:-10}
dry=${DRY_RUN:-0}
verb=compacted
[ "$dry" = 1 ] && verb="would compact"
# --rm drops the source only once the archive is written; the box serves the
# site over NFS, so compaction yields to it
compress_image() {
nice -n 10 ionice -c3 zstd -12 -T1 -q --rm "$1"
}
export -f compress_image
leftovers() {
local build=$1
find "$build" -mindepth 2 -maxdepth 2 \
\( -type d -name data \
-o -type f \( -name '*.img' -o -name '*.iso' -o -name '*.raw' \) \) \
-print -quit
}
compacted=0
pending=0
while IFS= read -r version; do
dir="$root/$version"
[ -n "$(leftovers "$dir")" ] || continue
pending=$((pending + 1))
[ "$compacted" -lt "$max" ] || continue
if [ "$dry" = 1 ]; then
compacted=$((compacted + 1))
echo "$verb $version"
continue
fi
# a build holds nine images: one per core, each zstd kept to one thread so
# the two levels of parallelism do not fight. Archive before dropping the
# tree, so a failure here leaves the build merely uncompacted and the next
# run picks it up again
find "$dir" -mindepth 2 -maxdepth 2 -type f \
\( -name '*.img' -o -name '*.iso' -o -name '*.raw' \) -print0 \
| xargs -0 -r -P "$(nproc)" -I{} bash -c 'compress_image "$@"' _ {}
find "$dir" -mindepth 2 -maxdepth 2 -type d -name data -exec rm -rf {} +
compacted=$((compacted + 1))
echo "$verb $version"
# <tag>-<commit count>-g<sha>: order by the count, never by mtime
done < <(find "$root" -mindepth 1 -maxdepth 1 -type d -name '*-*-g*' -printf '%f\n' \
| sort -t- -k2,2n | head -n "-$keep")
echo "$verb $compacted of $pending older build(s), $((pending - compacted)) left for the next run"
+24 -90
View File
@@ -62,7 +62,7 @@ jobs:
make -f Makefile.lin32
chmod +x c--
mv c-- /home/autobuild/tools/win32/bin/c--
cp ${{ gitea.workspace }}/programs/develop/cmm/c--.ini /home/autobuild/tools/win32/bin/c--.ini
cp ${{ gitea.workspace }}/programs/cmm/c--/c--.ini /home/autobuild/tools/win32/bin/c--.ini
make -f Makefile.lin32 clean
- name: Install TCC
@@ -128,8 +128,7 @@ jobs:
fi
# cache restore resets ctimes; realign tup DB to skip a full rebuild,
# but keep files changed since the cache's commit dirty so tup rebuilds them.
# A submodule bump diffs as a bare gitlink, so expand it to its whole subtree
# but keep files changed since the cache's commit dirty so tup rebuilds them
- name: Sync tup DB with filesystem ctime
if: steps.check-tup-cache.outputs.cache_restored == 'true'
run: |
@@ -137,10 +136,6 @@ jobs:
BASE=$(cat .tup/build-commit 2>/dev/null || true)
if [ -n "$BASE" ] && git cat-file -e "${BASE}^{commit}" 2>/dev/null; then
git -c core.quotePath=false diff --name-only "$BASE" HEAD > "$DIRTY"
git diff --raw "$BASE" HEAD | awk '$2 == "160000" { print $NF }' |
while read -r sub; do
git -C "$sub" -c core.quotePath=false ls-files | sed "s|^|$sub/|"
done >> "$DIRTY"
echo "Cache built at $BASE; $(wc -l < "$DIRTY") changed files kept dirty"
python3 .gitea/utils/sync-tup-ctime.py .tup/db "$DIRTY"
else
@@ -167,13 +162,12 @@ jobs:
tup init
tup variant ${{ matrix.lang }}.config
# build the image for language variant; keep the tup log for publishing
# build the image for language variant
- name: Build KolibriOS
run: |
set -o pipefail
export PATH=/home/autobuild/tools/win32/bin:$PATH
source kos32-export-env-vars ${{ gitea.workspace }}
tup build-${{ matrix.lang }} 2>&1 | tee build.log
tup build-${{ matrix.lang }}
# stamp the cache with its commit so later builds diff against it
- name: Record cache base commit
@@ -187,26 +181,15 @@ jobs:
id: vars
run: echo "descr=$(git describe --tags)" >> $GITEA_OUTPUT
# stage build outputs under their final names, plus distribution kit and checksums
- name: Prepare artifacts
# rename build outputs to their final names so artifacts are bare files
- name: Rename images
run: |
set -e
BASE="kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}"
for ext in img iso raw; do
cp "build-${{ matrix.lang }}/data/kolibri.$ext" "$BASE.$ext"
cp "build-${{ matrix.lang }}/data/kolibri.$ext" \
"kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.$ext"
done
# zip: distr targets Windows/DOS users, Explorer opens it natively
(cd "build-${{ matrix.lang }}/data" && zip -r -9 -q "${{ gitea.workspace }}/$BASE.distr.zip" distribution_kit)
# whole build tree for per-program downloads; the big images ship separately
tar -C "build-${{ matrix.lang }}" \
--exclude './data/kolibri.iso' \
--exclude './data/kolibri.raw' \
--exclude './data/distribution_kit' \
-czf "$BASE.tree.tar.gz" .
sha256sum "$BASE".img "$BASE".iso "$BASE".raw "$BASE".distr.zip > "$BASE.sha256sums.txt"
mv build.log "$BASE.build.log"
# publish the images; longer retention for the floppy image
#publish the three images; longer retention for the floppy image.
- name: Upload floppy image
uses: actions/upload-artifact@v3
with:
@@ -228,34 +211,6 @@ jobs:
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.raw
retention-days: 15
- name: Upload distribution kit
uses: actions/upload-artifact@v3
with:
name: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.distr.zip
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.distr.zip
retention-days: 30
- name: Upload checksums
uses: actions/upload-artifact@v3
with:
name: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.sha256sums.txt
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.sha256sums.txt
retention-days: 90
- name: Upload build log
uses: actions/upload-artifact@v3
with:
name: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.build.log
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.build.log
retention-days: 90
- name: Upload build tree
uses: actions/upload-artifact@v3
with:
name: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.tree.tar.gz
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.tree.tar.gz
retention-days: 15
deploy:
name: "Publish Images"
runs-on: ubuntu-latest
@@ -280,50 +235,31 @@ jobs:
run: |
set -eu
rm -rf ./norm-artifacts ./stable-artifacts ./tree-artifacts
mkdir -p ./norm-artifacts ./stable-artifacts ./tree-artifacts
rm -rf ./norm-artifacts
mkdir -p ./norm-artifacts
find ./artifacts -type f -name 'kolibrios-*' | while read -r file; do
fname="$(basename "$file")" # kolibrios-<descr>-<lang>.<suffix>
case "$fname" in
*.tree.tar.gz) stem="${fname%.tree.tar.gz}";;
*.distr.zip) stem="${fname%.distr.zip}";;
*.sha256sums.txt) stem="${fname%.sha256sums.txt}";;
*.build.log) stem="${fname%.build.log}";;
*.img) stem="${fname%.img}";;
*.iso) stem="${fname%.iso}";;
*.raw) stem="${fname%.raw}";;
*) continue;;
esac
lang="${stem##*-}" # <lang> has no dashes, <descr> may
find ./artifacts -type f \( \
-name 'kolibrios-*.img' -o \
-name 'kolibrios-*.iso' -o \
-name 'kolibrios-*.raw' \
\) | while read -r file; do
fname="$(basename "$file")" # kolibrios-<descr>-<lang>.<ext>
name_without_ext="${fname%.*}"
lang="${name_without_ext##*-}"
mkdir -p "./norm-artifacts/$lang"
case "$fname" in
*.tree.tar.gz)
# unpacked on the server into <version>/<lang>/data/ for per-program downloads
cp "$file" "./tree-artifacts/$lang.tar.gz";;
*.sha256sums.txt)
cp "$file" "./norm-artifacts/$lang/sha256sums.txt";;
*.build.log)
cp "$file" "./norm-artifacts/$lang/build.log";;
*.img)
cp "$file" "./norm-artifacts/$lang/$fname"
# emulators (e.g. v86) hardcode <lang>/data/data/kolibri.img at the site root
mkdir -p "./stable-artifacts/$lang/data/data"
cp "$file" "./stable-artifacts/$lang/data/data/kolibri.img";;
*)
cp "$file" "./norm-artifacts/$lang/$fname";;
esac
cp "$file" "./norm-artifacts/$lang/$fname"
done
# derive the version (git describe) from an artifact name: kolibrios-<descr>-<lang>.iso -> <descr>
sample="$(find ./norm-artifacts -type f -name 'kolibrios-*.iso' | head -n1)"
# derive the version (git describe) from an artifact name:
# kolibrios-<descr>-<lang>.<ext> -> <descr>
sample="$(find ./norm-artifacts -type f -name 'kolibrios-*' | head -n1)"
base="$(basename "${sample%.*}")" # kolibrios-<descr>-<lang>
version="${base%-*}" # kolibrios-<descr>
version="${version#kolibrios-}" # <descr>
echo "version=$version" >> $GITEA_OUTPUT
find ./norm-artifacts ./stable-artifacts ./tree-artifacts -type f -print
find ./norm-artifacts -type f -print
- name: Setup SSH
run: |
@@ -349,6 +285,4 @@ jobs:
-e "storage_path=${{ secrets.STORAGE_PATH }}" \
-e "version=${{ steps.normalize.outputs.version }}" \
-e "artifact_path=${{ gitea.workspace }}/norm-artifacts" \
-e "stable_artifact_path=${{ gitea.workspace }}/stable-artifacts" \
-e "tree_artifact_path=${{ gitea.workspace }}/tree-artifacts" \
-v
+1 -1
View File
@@ -64,7 +64,7 @@ jobs:
make -f Makefile.lin32
chmod +x c--
mv c-- /home/autobuild/tools/win32/bin/c--
cp ${{ gitea.workspace }}/programs/develop/cmm/c--.ini /home/autobuild/tools/win32/bin/c--.ini
cp ${{ gitea.workspace }}/programs/cmm/c--/c--.ini /home/autobuild/tools/win32/bin/c--.ini
make -f Makefile.lin32 clean
- name: Install TCC
+2 -4
View File
@@ -24,8 +24,6 @@ jobs:
path: programs/develop/cmm
- name: oberon07
path: programs/develop/oberon07
- name: cmm_apps
path: programs/cmm
- name: kterm
path: programs/other/kterm
@@ -70,7 +68,7 @@ jobs:
git config user.name "kolibri-bot"
git config user.email "bot@kolibrios.org"
git checkout -B "$BRANCH"
git commit -m "chore/submodules: bump $NAME to $WANT" -- "$PATH_"
git commit -m "$NAME: bump submodule to $WANT" -- "$PATH_"
git push -f origin "$BRANCH"
# Open a PR via the Gitea API.
@@ -79,7 +77,7 @@ jobs:
http=$(curl -sS -o /tmp/pr.json -w '%{http_code}' -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"head\":\"${BRANCH}\",\"base\":\"main\",\"title\":\"chore/submodules: bump ${NAME} to upstream\"}" \
-d "{\"head\":\"${BRANCH}\",\"base\":\"main\",\"title\":\"${NAME}: bump submodule to upstream\"}" \
"${API}/repos/${REPO}/pulls")
echo "PR API HTTP status: $http"
cat /tmp/pr.json; echo
+1 -5
View File
@@ -4,12 +4,8 @@
branch = main
[submodule "programs/develop/oberon07"]
path = programs/develop/oberon07
url = https://git.kolibrios.org/KolibriOS/oberon-07-compiler.git
url = https://github.com/AntKrotov/oberon-07-compiler.git
branch = master
[submodule "programs/cmm"]
path = programs/cmm
url = https://git.kolibrios.org/KolibriOS/cmm_apps.git
branch = main
[submodule "programs/other/kterm"]
path = programs/other/kterm
url = https://git.kolibrios.org/b00bl1k/kterm.git
-6
View File
@@ -59,12 +59,6 @@ Co-authored-by: ANOTHER-NAME <ANOTHER-NAME@EXAMPLE.COM>
to the end commit message body on a new line.
If you used AI tools while preparing the commit, you are encouraged to include an Assisted-by tag:
```
Assisted-by: AGENT_NAME:MODEL_VERSION
```
### Merge commits
> [!WARNING]
+27 -41
View File
@@ -41,6 +41,10 @@ img_files = {
{"LIB/KMENU.OBJ", "common/lib/kmenu.obj"},
{"LIB/PIXLIB.OBJ", "common/lib/pixlib.obj"},
{"MEDIA/AC97SND", "common/media/ac97snd"},
{"MEDIA/IMGF/IMGF", "common/media/ImgF/ImgF"},
{"MEDIA/IMGF/CEDG.OBJ", "common/media/ImgF/cEdg.obj"},
{"MEDIA/IMGF/DITHER.OBJ", "common/media/ImgF/dither.obj"},
{"MEDIA/IMGF/INVSOL.OBJ", "common/media/ImgF/invSol.obj"},
{"NETWORK/FTPC.INI", SRC_PROGS .. "/network/ftpc/ftpc.ini"},
{"NETWORK/FTPD.INI", "common/network/ftpd.ini"},
{"NETWORK/KNMAP", "common/network/knmap"},
@@ -54,7 +58,8 @@ img_files = {
{"SETTINGS/FB2READ.INI", "common/settings/fb2read.ini"},
{"SETTINGS/HA.CFG", SRC_PROGS .. "/other/ha/SETTINGS/HA.CFG"},
{"SETTINGS/ICON.INI", build_type .. "/settings/icon.ini"},
{"SETTINGS/KEYMAP.KEY", VAR_PROGS .. "/system/taskbar/keymap.key.kpack"},
{"SETTINGS/KEYMAP.KEY", SRC_PROGS .. "/system/taskbar/KEYMAP.KEY"},
{"SETTINGS/KOLIBRI.LBL", build_type .. "/settings/kolibri.lbl"},
{"SETTINGS/LANG.INI", build_type .. "/settings/lang.ini"},
{"SETTINGS/MENU.DAT", build_type .. "/settings/menu.dat"},
{"SETTINGS/NETWORK.INI", "common/settings/network.ini"},
@@ -69,6 +74,7 @@ if build_type == "ru_RU" then tup.append_table(img_files, {
{"WELCOME.HTM", VAR_DATA .. "/" .. build_type .. "/welcome.htm.kpack"},
{"EXAMPLE.ASM", SRC_PROGS .. "/develop/examples/example/rus/example.asm"},
{"DEVELOP/BACKY", SRC_PROGS .. "/develop/backy/Backy_ru"},
{"GAMES/BASEKURS.KLA", build_type .. "/games/basekurs.kla"},
{"File Managers/KFAR.INI", build_type .. "/File Managers/kfar.ini"},
{"GAMES/DESCENT", build_type .. "/games/descent"},
{"SETTINGS/.shell", SRC_PROGS .. "/system/shell/bin/rus/.shell"},
@@ -164,6 +170,8 @@ extra_files = {
{"kolibrios/demos/life2", "common/demos/life2"},
{"kolibrios/demos/relay.lif", "common/demos/relay.lif"},
{"kolibrios/demos/rpento.lif", "common/demos/rpento.lif"},
{"kolibrios/develop/c--/c--.ini", SRC_PROGS .. "/cmm/c--/c--.ini"},
{"kolibrios/develop/c--/manual_c--.htm", SRC_PROGS .. "/cmm/c--/manual_c--.htm"},
{"kolibrios/develop/fpc/", "common/develop/fpc/*"},
{"kolibrios/develop/fpc/examples/", "../programs/develop/fp/examples/src/*"},
{"kolibrios/develop/oberon07/compiler.kex", SRC_PROGS .. "/develop/oberon07/Compiler.kex"},
@@ -186,12 +194,6 @@ extra_files = {
{"kolibrios/develop/tcc/samples/", SRC_PROGS .. "/develop/ktcc/libc.obj/samples/*.sh"},
{"kolibrios/develop/tcc/samples/clayer/", SRC_PROGS .. "/develop/ktcc/libc.obj/samples/clayer/*"},
{"kolibrios/develop/utils/SPEDump", SRC_PROGS .. "/develop/SPEDump/SPEDump.kex"},
{"kolibrios/develop/XDPascal/", SRC_PROGS .. "/develop/XDPascal/xdpk/*"},
{"kolibrios/develop/XDPascal/projects2025/", SRC_PROGS .. "/develop/XDPascal/xdpk/projects2025/*"},
{"kolibrios/develop/XDPascal/projects2025/Compiler/", SRC_PROGS .. "/develop/XDPascal/xdpk/projects2025/Compiler/*"},
{"kolibrios/develop/XDPascal/projects2026/", SRC_PROGS .. "/develop/XDPascal/xdpk/projects2026/*"},
{"kolibrios/develop/XDPascal/source/", SRC_PROGS .. "/develop/XDPascal/xdpk/source/*"},
{"kolibrios/develop/XDPascal/units/", SRC_PROGS .. "/develop/XDPascal/xdpk/units/*"},
{"kolibrios/emul/", "common/emul/*"},
{"kolibrios/emul/dosbox/", "common/emul/DosBox/*"},
{"kolibrios/emul/e80/readme.txt", SRC_PROGS .. "/emulator/e80/readme.txt"},
@@ -268,10 +270,6 @@ extra_files = {
{"kolibrios/lib/i915_dri.drv", "common/lib/i915_dri.drv"},
{"kolibrios/media/fplay", "common/media/fplay"},
{"kolibrios/media/fplay_run", "common/media/fplay_run"},
{"kolibrios/media/ImgF/ImgF", "common/media/ImgF/ImgF"},
{"kolibrios/media/ImgF/cEdg.obj", "common/media/ImgF/cEdg.obj"},
{"kolibrios/media/ImgF/dither.obj", "common/media/ImgF/dither.obj"},
{"kolibrios/media/ImgF/invSol.obj", "common/media/ImgF/invSol.obj"},
{"kolibrios/media/minimp3", "common/media/minimp3"},
{"kolibrios/media/updf", SRC .. "/contrib/media/updf/build/uPDF"},
{"kolibrios/media/vttf", "common/media/vttf"},
@@ -295,6 +293,8 @@ extra_files = {
{"kolibrios/utils/vmode", "common/vmode"},
{"kolibrios/utils/texture", "common/utils/texture"},
{"kolibrios/utils/kterm/kterm", VAR_PROGS .. "/other/kterm/kterm"},
{"kolibrios/utils/kterm/serial.sys", VAR_DRVS .. "/serial/serial.sys"},
{"kolibrios/utils/kterm/install.sh", SRC .. "/drivers/serial/install.sh"},
{"kolibrios/utils/cnc_editor/cnc_editor", VAR_PROGS .. "/other/cnc_editor/cnc_editor"},
{"kolibrios/utils/cnc_editor/kolibri.NC", SRC_PROGS .. "/other/cnc_editor/kolibri.NC"},
{"kolibrios/utils/kfm/kfm.ini", "common/File Managers/kfm.ini"},
@@ -428,6 +428,7 @@ tup.append_table(img_files, {
{"DISPTEST", VAR_PROGS .. "/testing/disptest/disptest"},
{"END", VAR_PROGS .. "/system/end/light/end"},
{"ESKIN", VAR_PROGS .. "/system/eskin/eskin"},
{"FSPEED", VAR_PROGS .. "/testing/fspeed/fspeed"},
{"GMON", VAR_PROGS .. "/system/gmon/gmon"},
{"HDD_INFO", VAR_PROGS .. "/system/hdd_info/hdd_info"},
{"KBD", VAR_PROGS .. "/testing/kbd/kbd"},
@@ -436,6 +437,7 @@ tup.append_table(img_files, {
{"LOADDRV", VAR_PROGS .. "/system/loaddrv/loaddrv"},
{"MAGNIFY", VAR_PROGS .. "/system/magnify/magnify"},
{"MADMOUSE", VAR_PROGS .. "/other/madmouse/madmouse"},
{"MGB", VAR_PROGS .. "/testing/mgb/mgb"},
{"MOUSEMUL", VAR_PROGS .. "/system/mousemul/mousemul"},
{"MOUSEPOS", VAR_PROGS .. "/other/mousepos/mousepos"},
{"MYKEY", VAR_PROGS .. "/system/MyKey/MyKey"},
@@ -486,6 +488,11 @@ tup.append_table(img_files, {
{"DEVELOP/MTDBG", VAR_PROGS .. "/develop/mtdbg/mtdbg"},
{"DEVELOP/MSTATE", VAR_PROGS .. "/develop/mstate/mstate"},
{"DEVELOP/SCANCODE", VAR_PROGS .. "/develop/scancode/scancode"},
{"DEVELOP/EXAMPLES/CIRCLE", VAR_PROGS .. "/develop/examples/circle/circle"},
{"DEVELOP/EXAMPLES/COLORREF", VAR_PROGS .. "/demos/colorref/colorref"},
{"DEVELOP/EXAMPLES/CONGET", VAR_PROGS .. "/develop/libraries/console_coff/examples/test_gets"},
{"DEVELOP/EXAMPLES/CSLIDE", VAR_PROGS .. "/demos/cslide/cslide"},
{"DEVELOP/EXAMPLES/THREAD", VAR_PROGS .. "/develop/examples/thread/thread"},
{"File Managers/KFAR", VAR_PROGS .. "/fs/kfar/kfar"},
{"File Managers/OPENDIAL", VAR_PROGS .. "/fs/opendial/opendial"},
{"LOD", VAR_PROGS .. "/fs/lod/lod"},
@@ -536,7 +543,7 @@ tup.append_table(img_files, {
{"NETWORK/PING", VAR_PROGS .. "/network/ping/ping"},
{"NETWORK/NETCFG", VAR_PROGS .. "/network/netcfg/netcfg"},
{"NETWORK/NETSTAT", VAR_PROGS .. "/network/netstat/netstat"},
{"NETWORK/NETSURF", VAR_PROGS .. "/network/netsurf/netsurf"},
{"NETWORK/NSINST", VAR_PROGS .. "/network/netsurf/nsinstall"},
{"NETWORK/NSLOOKUP", VAR_PROGS .. "/network/nslookup/nslookup"},
{"NETWORK/PASTA", VAR_PROGS .. "/network/pasta/pasta"},
{"NETWORK/SYNERGYC", VAR_PROGS .. "/network/synergyc/synergyc"},
@@ -567,15 +574,10 @@ tup.append_table(img_files, {
{"DRIVERS/UHCI.SYS", VAR_DRVS .. "/usb/uhci.sys"},
{"DRIVERS/OHCI.SYS", VAR_DRVS .. "/usb/ohci.sys"},
{"DRIVERS/EHCI.SYS", VAR_DRVS .. "/usb/ehci.sys"},
{"DRIVERS/XHCI.SYS", VAR_DRVS .. "/usb/xhci/xhci.sys"},
{"DRIVERS/USBHID.SYS", VAR_DRVS .. "/usb/usbhid/usbhid.sys"},
{"DRIVERS/USBFTDI.SYS", VAR_DRVS .. "/usb/usbftdi/usbftdi.sys"},
{"DRIVERS/USBOTHER.SYS",VAR_DRVS .. "/usb/usbother/usbother.sys"},
{"DRIVERS/USBCDC.SYS", VAR_DRVS .. "/usb/usbnet/usbcdc.sys"},
{"DRIVERS/USBRNDIS.SYS", VAR_DRVS .. "/usb/usbnet/usbrndis.sys"},
{"DRIVERS/USBSTOR.SYS", VAR_DRVS .. "/usb/usbstor.sys"},
{"DRIVERS/RDC.SYS", VAR_DRVS .. "/video/rdc.sys"},
{"DRIVERS/SERIAL.SYS", VAR_DRVS .. "/serial/serial.sys"},
{"DRIVERS/COMMOUSE.SYS", VAR_DRVS .. "/mouse/commouse.sys"},
{"DRIVERS/PS2MOUSE.SYS", VAR_DRVS .. "/mouse/ps2mouse4d/ps2mouse.sys"},
{"DRIVERS/TMPDISK.SYS", VAR_DRVS .. "/disk/tmpdisk.sys"},
@@ -592,8 +594,6 @@ tup.append_table(img_files, {
{"DRIVERS/VT823X.SYS", VAR_DRVS .. "/audio/vt823x.sys"},
{"DRIVERS/SIS.SYS", VAR_DRVS .. "/audio/sis.sys"},
{"DRIVERS/SDHCI.SYS", "../drivers/sdhci/sdhci.sys"},
{"DRIVERS/I2CHID.SYS", VAR_DRVS .. "/i2chid/i2chid.sys"},
{"DRIVERS/NVME.SYS", VAR_DRVS .. "/nvme/nvme.sys"},
})
tup.append_table(extra_files, {
{"HD_Load/9x2klbr/", VAR_PROGS .. "/hd_load/9x2klbr/9x2klbr.exe"},
@@ -640,35 +640,24 @@ tup.append_table(extra_files, {
{"kolibrios/media/zsea/plugins/rotate.obj", VAR_PROGS .. "/media/zsea/plugins/rotate/rotate.obj"},
{"kolibrios/media/zsea/plugins/scaling.obj", VAR_PROGS .. "/media/zsea/plugins/scaling/scaling.obj"},
{"kolibrios/utils/AMDtemp", VAR_PROGS .. "/system/amd_temp_view/AMDtemp"},
{"kolibrios/utils/fspeed", VAR_PROGS .. "/testing/fspeed/fspeed"},
{"kolibrios/utils/mgb", VAR_PROGS .. "/testing/mgb/mgb"},
{"kolibrios/utils/kfm/kfm", VAR_PROGS .. "/fs/kfm/kfm"},
{"kolibrios/utils/tedit/t_edit", VAR_PROGS .. "/other/t_edit/t_edit"},
{"kolibrios/3D/blocks/block.bin", VAR_PROGS .. "/bcc32/games/blocks/block.bin"},
{"kolibrios/develop/tcc/lib/crt0.o", VAR_PROGS .. "/develop/ktcc/bin/lib/crt0.o", group = "../programs/develop/ktcc/<crt0.o>"},
{"kolibrios/develop/tcc/lib/tiny.o", VAR_PROGS .. "/develop/ktcc/bin/lib/tiny.o", group = "../programs/develop/ktcc/<tiny.o>"},
{"kolibrios/develop/tcc/lib/libsound.a", VAR_PROGS .. "/develop/ktcc/bin/lib/libsound.a", group = "../programs/develop/ktcc/<libsound.a>"},
{"kolibrios/develop/examples/circle", VAR_PROGS .. "/develop/examples/circle/circle"},
{"kolibrios/develop/examples/colorref", VAR_PROGS .. "/demos/colorref/colorref"},
{"kolibrios/develop/examples/conget", VAR_PROGS .. "/develop/libraries/console_coff/examples/test_gets"},
{"kolibrios/develop/examples/cslide", VAR_PROGS .. "/demos/cslide/cslide"},
{"kolibrios/develop/examples/thread", VAR_PROGS .. "/develop/examples/thread/thread"}
{"kolibrios/develop/tcc/lib/libsound.a", VAR_PROGS .. "/develop/ktcc/bin/lib/libsound.a", group = "../programs/develop/ktcc/<libsound.a>"}
})
-- -- For russian build, add russian-only programs.
-- if build_type == "ru_RU" then tup.append_table(img_files, {
-- {"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_rus"},
-- }) else tup.append_table(img_files, {
-- {"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_eng"},
-- }) end
-- For russian build, add russian-only programs.
if build_type == "ru_RU" then tup.append_table(img_files, {
{"GAMES/KLAVISHA", VAR_PROGS .. "/games/klavisha/klavisha"},
{"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_rus"},
}) else tup.append_table(img_files, {
{"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_eng"},
}) end
if build_type == "ru_RU" then tup.append_table(extra_files, {
{"kolibrios/develop/examples/testcon2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_rus"},
{"kolibrios/utils/period", VAR_PROGS .. "/other/period/period"},
{"kolibrios/games/Dungeons/Dungeons", VAR_PROGS .. "/games/Dungeons/Dungeons"},
{"kolibrios/games/klavisha/klavisha", VAR_PROGS .. "/games/klavisha/klavisha"},
{"kolibrios/games/klavisha/basekurs.kla", "ru_RU/games/basekurs.kla"},
}) else tup.append_table(extra_files, {
{"kolibrios/develop/examples/testcon2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_eng"},
}) end
end -- tup.getconfig('NO_FASM') ~= 'full'
@@ -692,7 +681,6 @@ tup.append_table(img_files, {
{"EASYSHOT", VAR_PROGS .. "/cmm/misc/easyshot.com"},
{"MOUSECFG", VAR_PROGS .. "/cmm/mousecfg/mousecfg.com"},
{"BARSCFG", VAR_PROGS .. "/cmm/barscfg/barscfg.com"},
{"BBENCH", VAR_PROGS .. "/cmm/bbench/bbench.com"},
{"SEARCH", VAR_PROGS .. "/cmm/misc/search.com"},
{"SYSPANEL", VAR_PROGS .. "/cmm/misc/software_widget.com"},
{"SYSMON", VAR_PROGS .. "/cmm/sysmon/sysmon.com"},
@@ -821,8 +809,6 @@ tup.append_table(extra_files, {
{"kolibrios/utils/minizip/minizip", VAR_PROGS .. "/fs/minizip/minizip"},
{"kolibrios/utils/minizip/miniunz", VAR_PROGS .. "/fs/minizip/miniunz"},
{"kolibrios/develop/c--/c--", VAR_PROGS .. "/develop/cmm/cmm"},
{"kolibrios/develop/c--/c--.ini", SRC_PROGS .. "/develop/cmm/c--.ini"},
{"kolibrios/develop/c--/manual_c--.htm", SRC_PROGS .. "/develop/cmm/manual_c--.htm"},
{"kolibrios/develop/tcc/tcc", VAR_PROGS .. "/develop/ktcc/source/tcc"},
{"kolibrios/develop/sqlite3/sqlite3", VAR_CONTRIB .. "/sdk/sources/sqlite3/shell/sqlite3"},
{"kolibrios/develop/utils/objconv", VAR_PROGS .. "/develop/objconv/objconv"},
+1 -2
View File
@@ -29,7 +29,6 @@ xcf=/sys/media/kiv
rtf=/sys/RtfRead
3ds=/sys/3d/view3ds
asc=/sys/3d/view3ds
stl=/sys/3d/view3ds
lif=/kolibrios/demos/life2
skn=/sys/skincfg
dtp=/sys/skincfg
@@ -48,7 +47,7 @@ mht=/sys/network/WebView
docx=/sys/network/WebView
url=/sys/network/WebView
fb2=/sys/fb2read
kla=/kolibrios/games/klavisha/klavisha
kla=/sys/games/klavisha
pdf=/kolibrios/media/updf
avi=/kolibrios/media/fplay_run
mpg=/kolibrios/media/fplay_run
Binary file not shown.
+1 -3
View File
@@ -6,16 +6,14 @@
#/SYS/CROPFLAT "XS800 YS480" 1 # set limits of screen
#/SYS/LOADDRV COMMOUSE 1 # serial mouse driver
#/SYS/DEVELOP/BOARD "" 0 # Load DEBUG board
#/SYS/LOADDRV RDC 0 # videodriver for RDC M2010/M2012
/SYS/SETUP BOOT 0 # Load device settings
/SYS/LOADDRV I2CHID 0 # Start I2C touchpad driver
/SYS/LOADDRV RDC 0 # videodriver for RDC M2010/M2012
/SYS/@TASKBAR "" 0 # Start taskbar
/SYS/ESKIN "" 0 # Set style
/SYS/@ICON "" 0 # Multithread desktop icons
/SYS/TMPDISK A0 0 # Add virtual RAM disk /tmp0/1
/SYS/@RESHARE "" 0 # Shared resources
/SYS/LOADDRV SDHCI 0 # Start SDHCI driver
/SYS/LOADDRV NVME 0 # Start NVMe driver
/SYS/@DOCKY "" 0 # Start docky
/SYS/NETWORK/NETCFG A 0 # Init network driver
/SYS/NETWORK/@ZEROCONF "" 0 # Network configuration
+1 -2
View File
@@ -174,12 +174,11 @@ sh=/sys/shell
3ds=/sys/3d/view3ds
asc=/sys/3d/view3ds
stl=/sys/3d/view3ds
skn=/sys/skincfg
dtp=/sys/skincfg
lif=/kolibrios/demos/life2
kla=/kolibrios/games/klavisha/klavisha
kla=/sys/games/klavisha
pdf=/kolibrios/media/updf
smc=/kolibrios/emul/zsnes/zsnes
+1 -1
View File
@@ -39,7 +39,7 @@ Donkey=/kg/donkey
Loderunner=/kg/LRL/LRL,41
; 21days=/kg/21days,104 ;rus only
BabyPainter=/kg/BabyPainter,87
Klavisha=/kg/klavisha/klavisha,69
Klavisha=games/klavisha,69
Millioneer=/kg/WHOWTBAM/whowtbam,114
StarTrek71=/kg/sstartrek/SStarTrek
Descent=games/descent
+2 -1
View File
@@ -35,6 +35,7 @@ Console Board=develop/dbgboard,19
PCI Devices=pcidev,38
CPU Info=cpuid,37
Display Test=disptest,113
Benchmark=bbench,121
Graphic Bench=mgb,121
HDD Info=hdd_info,50
File Speed=fspeed,45
Network Speed=network/dl|-test,51
-16
View File
@@ -5,22 +5,6 @@ font smoothing=sbp
font height=9
speaker mute=off
[touchpad]
speed=100
; how far a finger must move before the pointer follows, in pad units;
; larger is steadier under a pressing finger, 0 turns the filter off
jitter=1
; the same, for a finger that landed on the button strip: it is pressing
; rather than steering there, so it needs a stricter margin
jitter_buttons=45
scroll_step=64
scroll_invert=0
tap_enable=1
tap_drag=1
right_click=1
button_zone=15
right_split=50
[mouse]
speed=4
acceleration=3
+1 -1
View File
@@ -243,7 +243,7 @@ x=204
y=0
[22]
name=NETSURF
path=/sys/NETWORK/NETSURF
path=/sys/NETWORK/NSINST
param=
ico=125
x=204
+1 -2
View File
@@ -40,7 +40,7 @@
06 zSea Image Viewer * |/kolibrios/media/zsea/zsea
38 Animage |media/animage
38 IconEdit |media/iconedit
40 Image Filtering * |/kolibrios/media/ImgF/ImgF
40 Image Filtering |media/imgf/imgf
52 Palitra |media/palitra
39 Pipet |develop/pipet
#4 **** MULTIMEDIA
@@ -116,7 +116,6 @@
33 HTTPGet |network/httpget
33 Downloader |network/dl
12 WebView Browser |network/webview
12 NetSurf |network/netsurf
#13 **** SERVERS
24 FTP |network/ftpd
#14 **** OTHER
+1 -1
View File
@@ -243,7 +243,7 @@ x=204
y=0
[22]
name=NETSURF
path=/sys/NETWORK/NETSURF
path=/sys/NETWORK/NSINST
param=
ico=125
x=204
+1 -2
View File
@@ -41,7 +41,7 @@
16 Image viewer KIV |media/kiv
16 Image viewer zSea * |/kolibrios/media/zsea/zsea
16 Animage |media/animage
16 Efectos de imаgenes * |/kolibrios/media/ImgF/ImgF
16 Efectos de imаgenes |media/imgf/imgf
16 Palitra |media/palitra
#4 **** MULTIMEDIA
16 Pixie Audioplayer |media/pixie
@@ -121,7 +121,6 @@
16 HTTPGet |network/httpget
16 Descargas |network/dl
16 Navegador WebView |network/webview
12 NetSurf |network/netsurf
#15 **** OTROS
16 Reloj analвgico |demos/aclock
16 Reloj binario |demos/bcdclk
+2 -1
View File
@@ -35,6 +35,7 @@ Consola de depuracion=develop/dbgboard,19
Dispositivos PCI=pcidev,38
CPU Info=cpuid,37
Prueba de pantalla=disptest,113
Benchmark=bbench,121
Rendimiento grafico=mgb,121
Info de disco=hdd_info,50
Velocidad FS=fspeed,45
Velocidad de red=network/dl|-test,51
+1 -1
View File
@@ -41,7 +41,7 @@
06 Image viewer zSea * |/kolibrios/media/zsea/zsea
38 Animage |media/animage
38 IconEdit |media/iconedit
16 Image Filtering * |/kolibrios/media/ImgF/ImgF
16 Image Filtering |media/imgf/imgf
52 Palitra |media/palitra
39 Pipet |develop/pipet
#4 **** MULTIMEDIA ****
+1 -1
View File
@@ -41,7 +41,7 @@
06 Image viewer zSea * |/kolibrios/media/zsea/zsea
38 Animage |media/animage
38 IconEdit |media/iconedit
40 Image Filtering * |/kolibrios/media/ImgF/ImgF
40 Image Filtering |media/imgf/imgf
52 Palitra |media/palitra
39 Pipet |develop/pipet
#4 **** MULTIMEDIA
+1 -1
View File
@@ -39,7 +39,7 @@ docx=/sys/network/WebView
url=/sys/network/WebView
fb2=/sys/fb2read
mht=/sys/network/WebView
kla=/kolibrios/games/klavisha/klavisha
kla=/sys/games/klavisha
pdf=/kolibrios/media/updf
avi=/kolibrios/media/fplay_run
mpg=/kolibrios/media/fplay_run
+1 -1
View File
@@ -39,7 +39,7 @@ Donkey=/kg/donkey
Loderunner=/kg/LRL/LRL,41
21days=/kg/21days,104 ;rus only
BabyPainter=/kg/BabyPainter,87
Klavisha=/kg/klavisha/klavisha,69
Klavisha=games/klavisha,69
Millioneer=/kg/WHOWTBAM/whowtbam,114
StarTrek71=/kg/sstartrek/SStarTrek
Descent=games/descent
+1 -1
View File
@@ -243,7 +243,7 @@ x=204
y=0
[22]
name=NETSURF
path=/sys/NETWORK/NETSURF
path=/sys/NETWORK/NSINST
param=
ico=125
x=204
+2 -3
View File
@@ -40,7 +40,7 @@
06 Просмотр фото zSea |/kolibrios/media/zsea/zsea
38 Редактор Animage |media/animage
38 Редактор иконок |media/iconedit
40 Наложение фильтров * |/kolibrios/media/ImgF/ImgF
40 Наложение фильтров |media/imgf/imgf
52 Палитра |media/palitra
39 Пипетка |develop/pipet
#4 **** Звук и видео
@@ -115,7 +115,6 @@
33 HTTPGet |network/httpget
33 Загрузчик |network/dl
12 Браузер WebView |network/webview
12 Браузер NetSurf |network/netsurf
#14 **** Разное
00 Эмуляторы* > |@6
45 Создание скриншотов |scrshoot
@@ -123,7 +122,7 @@
18 FB2 Читалка |fb2read
16 Аналоговые часы |aclock
21 Таблица Менделеева |/kolibrios/utils/period
59 Тренажёр KJIABuIIIA |/kolibrios/games/klavisha/klavisha
59 Тренажёр KJ|ABuIIIA |games/klavisha
16 Бинарные часы |demos/bcdclk
53 Таймер |timer
09 Разархиватор Unz |unz
+2 -1
View File
@@ -35,6 +35,7 @@ AMDtemp=/k/utils/AMDtemp,128
Устройства PCI=pcidev,38
CPU Info=cpuid,37
Тест экрана=disptest,113
Benchmark=bbench,121
Скорость графики=mgb,121
Информация о дисках=hdd_info,50
Скорость ФС=fspeed,45
Скорость сети=network/dl|-test,51
+13 -11
View File
@@ -515,18 +515,20 @@ HDA_AMP_VOLMASK equ 0x7F
; unsolicited event handler
HDA_UNSOL_QUEUE_SIZE equ 64 ; must stay a power of 2 (used as a bitmask for wrap)
HDA_UNSOL_QUEUE_SIZE equ 64
struc HDA_BUS_UNSOLICITED
{
; ring buffer
.queue rd HDA_UNSOL_QUEUE_SIZE * 2 ; 2 dword for each event (res and res_ex)
.rp dd ? ; Read pointer
.wp dd ? ; Write pointer
; ; workqueue
; .work dd ? ;struct work_struct work;
; .bus dd ? ;struct hda_bus ;bus
}
;struc HDA_BUS_UNSOLICITED
;{
; ; ring buffer
; .queue:
; times HDA_UNSOL_QUEUE_SIZE*2 dd ?
; .rp dd ?
; .wp dd ?
;
; ; workqueue
; .work dd ?;struct work_struct work;
; .bus dd ? ;struct hda_bus ;bus
;};
; Helper for automatic ping configuration
AUTO_PIN_MIC equ 0
+35 -169
View File
@@ -273,8 +273,8 @@ RIRB_INT_RESPONSE equ 0x01
RIRB_INT_OVERRUN equ 0x04
RIRB_INT_MASK equ 0x05
; STATESTS int mask: SDIWAKE[14:0], a 16-bit register
STATESTS_INT_MASK equ 0x7FFF
; STATESTS int mask: SD2,SD1,SD0
STATESTS_INT_MASK equ 0x07
AZX_MAX_CODECS equ 4
; SD_CTL bits
@@ -402,7 +402,6 @@ struc AC_CNTRL ;AC controller base class
.response_reset dd 0
.polling_mode db 0
.poll_count db 0
.no_irq db 0 ; no interrupt line: a thread runs hda_irq
.posbuf dd ?
.start_wallclk dd ? ; start + minimum wallclk
.period_wallclk dd ? ; wallclk for period
@@ -506,6 +505,8 @@ macro spin_unlock
pop ebx eax
}
data fixups
end data
include '../../struct.inc'
include '../../macros.inc'
@@ -606,6 +607,9 @@ if IRQ_REMAP
invoke SysMsgBoardStr
end if
mov ebx, [ctrl.int_line]
invoke AttachIntHandler, ebx, hda_irq, dword 0
;Asper This part is from "azx_probe" proc. [
call azx_codec_create
cmp eax, 0
@@ -650,15 +654,7 @@ end if
stdcall hda_codec_setup_stream, eax, SDO_TAG, 0, 0x11 ; Left & Right channels (Back panel)
;Asper+ ]
if USE_UNSOL_EV = 0
invoke TimerHS, 1, 0, snd_hda_automute, 1
else
; Keep the unsolicited-event mode on the event-driven path. Running
; snd_hda_automute at startup can issue codec commands before the new
; unsolicited-response flow is ready, which hangs some systems.
invoke TimerHS, 1, 0, process_unsol_events, 0
end if
invoke TimerHS, 1, 0, snd_hda_automute, 0
if USE_SINGLE_MODE
mov esi, msgSingleMode
invoke SysMsgBoardStr
@@ -854,13 +850,13 @@ end if
mov edx, ICH6_REG_SD_STS + SDO_OFS
call azx_readb
mov cl, al
mov bl, al
mov al, SD_INT_MASK
mov edx, ICH6_REG_SD_STS + SDO_OFS
call azx_writeb
test cl, SD_INT_COMPLETE
test bl, SD_INT_COMPLETE
jz @f
mov eax, [ctrl.civ_val]
@@ -897,13 +893,13 @@ end if
;if 0
; clear state status int
mov edx, ICH6_REG_STATESTS
call azx_readw
and eax, STATESTS_INT_MASK
call azx_readb
test al, 0x04
jz @f
; ack all state-change bits, else the level IRQ line stays asserted
mov al, 0x04
mov edx, ICH6_REG_STATESTS
call azx_writew
call azx_writeb
@@:
;end if
or eax, 1
@@ -911,24 +907,6 @@ end if
ret
endp
; Stand-in for the interrupt when no interrupt line is available. A thread,
; not a TimerHS callback: the kernel calls timer callbacks with the global
; timer list lock held, and hda_irq may stall and refill the audio buffer.
; hda_irq runs with interrupts off, as it would in IRQ context: it holds
; aspinlock, which azx_rirb_get_response waits for with interrupts off, so
; a holder that could be preempted would hang the machine.
proc hda_poll_thread
.loop:
pushfd
cli
call hda_irq
popfd
mov eax, 5 ; delay, sleeping instead of spinning
mov ebx, 1 ; 10 ms; a 16 KB period is ~85 ms at 48 kHz
int 0x40
jmp .loop
endp
align 4
proc create_primary_buff
@@ -1217,26 +1195,6 @@ end if
; allocate CORB/RIRB
call azx_alloc_cmd_io
; attach the IRQ handler BEFORE the controller may raise interrupts:
; azx_init_chip enables GIE/CIE and a codec state-change can fire
; right away; an unclaimed level IRQ makes the
; kernel poll foreign handlers and relink their IRQH nodes onto our
; line (see irq_serv .try_other_irqs), corrupting the dispatch list
; a warm reboot can leave GIE and a stale completion bit behind, and
; civ_val is never resynced, so silence the controller before attaching
call azx_int_disable
mov ebx, [ctrl.int_line]
invoke AttachIntHandler, ebx, hda_irq, dword 0
test eax, eax
jnz @f
; No usable interrupt line (INTLINE=0xFF on boards that route INTx only
; through ACPI _PRT or MSI, which the kernel does not parse). The
; controller still latches INTSTS/SD_STS, we only lose the wakeup - so
; poll the RIRB for codec replies and run the interrupt handler from a
; thread. A flag of its own: polling_mode is the timeout recovery state.
mov [ctrl.no_irq], 1
@@:
; initialize chip
call azx_init_pci
@@ -1244,32 +1202,6 @@ end if
call azx_init_chip
;] Asper
; no IRQ line: let a polling thread stand in for the interrupt.
; Started only now - earlier, hda_irq could ack STATESTS in the window
; before reset_controller reads it into codec_mask
cmp [ctrl.no_irq], 0
je @f
push esi edi ; CreateThread clobbers them, START needs esi
mov ebx, 1
mov ecx, hda_poll_thread
xor edx, edx
invoke CreateThread
pop edi esi
test eax, eax
jns .thread_ok
; nothing would ever complete a period and playback would stall,
; so fail the init rather than register a service that hangs
mov esi, msgNoIrqThread
invoke SysMsgBoardStr
xor eax, eax
ret
.thread_ok:
if DEBUG
mov esi, msgNoIrqPoll
invoke SysMsgBoardStr
end if
@@:
xor eax, eax
inc eax
ret
@@ -1303,7 +1235,7 @@ endl
; clear STATESTS
mov eax, STATESTS_INT_MASK
mov edx, ICH6_REG_STATESTS
call azx_writew
call azx_writeb
; reset controller
mov edx, ICH6_REG_GCTL
@@ -1514,12 +1446,6 @@ endp
proc azx_alloc_cmd_io
push eax ecx edx
; the unsolicited-event ring lives in reserved storage, so its
; pointers hold garbage until we clear them here - do it before
; reset_controller enables unsolicited responses in GCTL
mov [unsol_events.rp], 0
mov [unsol_events.wp], 0
; single page (at least 4096 bytes) must suffice for both ringbuffers
invoke KernelAlloc, 4096
mov [ctrl.rb], eax
@@ -1720,24 +1646,14 @@ endl
mov ecx, 1000;+1000
.next_try:
mov al, [ctrl.polling_mode]
or al, [ctrl.no_irq]
test al, al
jnz .poll
mov ah, [do_poll]
test ah, ah
jz @f
.poll:
spin_lock_irq
; take the lock hda_irq holds so two RIRB readers never overlap
push eax ebx
mov eax, aspinlock
.poll_lock:
mov ebx, SPINLOCK_BUSY
lock xchg [eax], ebx
cmp ebx, SPINLOCK_FREE
jnz .poll_lock
pop ebx eax
call azx_update_rirb
mov [aspinlock], SPINLOCK_FREE
spin_unlock_irq
@@:
mov eax, [ctrl.rirb_cmd]
@@ -2018,7 +1934,6 @@ proc azx_int_disable
mov ebx, ICH6_INT_CTRL_EN or ICH6_INT_GLOBAL_EN
xor ebx, -1
and eax, ebx
mov edx, ICH6_REG_INTCTL ; azx_readl turned edx into the absolute address
call azx_writel
pop edx ebx eax
ret
@@ -2034,9 +1949,9 @@ proc azx_int_clear
call azx_writeb
; clear STATESTS
mov ax, STATESTS_INT_MASK
mov al, STATESTS_INT_MASK
mov edx, ICH6_REG_STATESTS
call azx_writew
call azx_writeb
; clear rirb status
mov al, RIRB_INT_MASK
@@ -2720,7 +2635,7 @@ proc snd_hda_automute stdcall, data:dword
test eax, eax
jz .out
stdcall snd_hda_read_pin_sense, edx, [data]
stdcall snd_hda_read_pin_sense, edx, 1
test eax, AC_PINSENSE_PRESENCE
jnz @f
xchg ecx, esi
@@ -2749,65 +2664,24 @@ proc snd_hda_automute stdcall, data:dword
endp
; ;Asper remember to add this functions:
; proc snd_hda_queue_unsol_event stdcall, par1:dword, par2:dword
; ;if DEBUG
; ; push esi
; ; mov esi, msgUnsolEvent
; ; invoke SysMsgBoardStr
; ; pop esi
; ;end if
; if USE_UNSOL_EV = 1
; ;Test. Do not make queue, process immediately!
; ;stdcall here snd_hda_read_pin_sense stdcall, nid:dword, trigger_sense:dword
; ;and then mute/unmute pin based on the results
; invoke TimerHS, 1, 0, snd_hda_automute, 0
; end if
; ret
; endp
; ;...
align 4
proc snd_hda_queue_unsol_event stdcall, res:dword, res_ex:dword
; Single-producer (HDA IRQ) lock-free enqueue. The caller azx_update_rirb
; only carries EBX across iterations and reloads the rest, and TimerHS
; preserves EBX too - so by using scratch regs only we need no saves.
mov eax, [unsol_events.wp]
and eax, HDA_UNSOL_QUEUE_SIZE - 1 ; never index the ring wild
lea edx, [eax+1]
and edx, HDA_UNSOL_QUEUE_SIZE - 1 ; next write pos (size must be 2^n)
cmp edx, [unsol_events.rp]
je .full ; ring full -> drop, keep 1 slot free
mov ecx, [res]
mov [unsol_events.queue + eax*8], ecx
mov ecx, [res_ex]
mov [unsol_events.queue + eax*8 + 4], ecx
mov [unsol_events.wp], edx ; publish only after data is stored
invoke TimerHS, 1, 0, process_unsol_events, 0
.full:
ret
;Asper remember to add this functions:
proc snd_hda_queue_unsol_event stdcall, par1:dword, par2:dword
;if DEBUG
; push esi
; mov esi, msgUnsolEvent
; invoke SysMsgBoardStr
; pop esi
;end if
if USE_UNSOL_EV = 1
;Test. Do not make queue, process immediately!
;stdcall here snd_hda_read_pin_sense stdcall, nid:dword, trigger_sense:dword
;and then mute/unmute pin based on the results
invoke TimerHS, 1, 0, snd_hda_automute, 0
end if
ret
endp
;...
align 4
proc process_unsol_events stdcall, data:dword
; Runs from TimerHS (single consumer). Uses only EAX (scratch) and calls
; snd_hda_automute, which preserves every register, so nothing is saved.
.loop:
mov eax, [unsol_events.rp]
cmp eax, [unsol_events.wp]
je .done
; The event payload is at [unsol_events.queue + eax*8] (res) and +4 (res_ex).
; Per-pin tag parsing is not implemented yet, so just re-evaluate jack state.
inc eax
and eax, HDA_UNSOL_QUEUE_SIZE - 1
mov [unsol_events.rp], eax
stdcall snd_hda_automute, 0
jmp .loop
.done:
ret
endp
align 4
proc fdword2str stdcall, flags:dword ; bit 0 - skipLeadZeroes; bit 1 - newLine; other bits undefined
@@ -3076,7 +2950,6 @@ sz_sound_srv db 'SOUND',0
msgInit db 'detect hardware...',13,10,0
msgFail db 'device not found',13,10,0
msgNoIrqThread db 'no IRQ line: cannot create polling thread',13,10,0
msgAttchIRQ db 'IRQ line not supported', 13,10,0
msgInvIRQ db 'IRQ line not assigned or invalid', 13,10,0
msgPlay db 'start play', 13,10,0
@@ -3146,7 +3019,6 @@ if DEBUG
msgTCSEL db 'PCI TCSEL ',0
msgTV db 'HDA test version ',TEST_VERSION_NUMBER,13,10,0
msgGCap db 'GCAP = ',0
msgNoIrqPoll db 'no IRQ line: polling thread',13,10,0
end if
if USE_SINGLE_MODE
@@ -3181,16 +3053,10 @@ end if
;] Asper
; relocation table lives after all code and initialized data: placed before the
; code its size feeds back into every relocation site and fasm may never converge
data fixups
end data
aspinlock dd SPINLOCK_FREE
codec CODEC
ctrl AC_CNTRL
unsol_events HDA_BUS_UNSOLICITED
;Asper: BDL must be aligned to 128 according to HDA specification.
pcmout_bdl rd 1
+14 -100
View File
@@ -130,8 +130,6 @@ RU_STATUS_IDLE = 0000b shl 2
RU_STATUS_SUSPENDED = 0001b shl 2
RU_STATUS_NO_RESOURCES = 0010b shl 2
RU_STATUS_READY = 0100b shl 2
SCB_STATUS_CUS = 11000000b ; CU Status
CU_STATUS_ACTIVE = 10b shl 6
SCB_STATUS_FCP = 1 shl 8 ; Flow Control Pause
SCB_STATUS_SWI = 1 shl 10 ; Software Interrupt
SCB_STATUS_MDI = 1 shl 11 ; MDI read/write complete
@@ -185,8 +183,6 @@ struct txfd
ends
TXFD_STATUS_C = 1 shl 15
TXFD_CMD_IA = 1 shl 0
TXFD_CMD_CFG = 1 shl 1
TXFD_CMD_TX = 1 shl 2
@@ -632,9 +628,6 @@ reset:
mov ax, CU_START or INT_MASK
out dx, ax
call cmd_wait
; cmd_wait only means the SCB accepted the command. The Configure below
; reuses confcmd, so a slow chip would read it instead of our MAC.
call confcmd_wait
;-------------
; Configure CU
@@ -659,7 +652,6 @@ reset:
mov ax, CU_START ; expect Interrupts from now on
out dx, ax
call cmd_wait
call confcmd_wait
; Start media check timer
mov [ebx + device.state], ETH_LINK_DOWN
@@ -686,11 +678,6 @@ init_rx_ring:
;---------------------
; build rxfd structure
cmp [ebx + device.rx_desc], 0 ; the RFD of an earlier reset
je @f
invoke NetFree, [ebx + device.rx_desc]
mov [ebx + device.rx_desc], 0
@@:
invoke NetAlloc, 2000
test eax, eax
jz .out_of_mem
@@ -702,7 +689,6 @@ init_rx_ring:
mov [esi + sizeof.NET_BUFF + rxfd.command], RXFD_CMD_EL or RXFD_CMD_SUSPEND
mov [esi + sizeof.NET_BUFF + rxfd.link], eax
mov [esi + sizeof.NET_BUFF + rxfd.count], 0
mov [esi + sizeof.NET_BUFF + rxfd.rx_buf_addr], 0xffffffff ; simplified mode, no RBD
mov [esi + sizeof.NET_BUFF + rxfd.size], 1528
ret
@@ -723,15 +709,6 @@ init_tx_ring:
invoke GetPhysAddr
mov ecx, TX_RING_SIZE
.next_desc:
; after a reset with frames still unreclaimed: free them, or transmit sees the
; descriptor busy (virt_addr) and reports TX overrun forever
cmp [esi + txfd.virt_addr], 0
je @f
push eax ecx
invoke NetFree, [esi + txfd.virt_addr]
pop ecx eax
mov [esi + txfd.virt_addr], 0
@@:
mov [esi + txfd.status], 0
mov [esi + txfd.command], 0
lea edx, [eax + txfd.buf_addr]
@@ -786,7 +763,7 @@ proc transmit stdcall bufferptr
lea edi, [ebx + device.tx_ring + eax]
; Check if current descriptor is free or still in use
cmp [edi + txfd.virt_addr], 0 ; buffer not reclaimed yet
cmp [edi + txfd.status], 0
jne .overrun
; Fill in status and command values
@@ -809,22 +786,6 @@ proc transmit stdcall bufferptr
mov eax, edi
invoke GetPhysAddr
set_io [ebx + device.io_addr], 0
; CU_START is only valid while the CU is idle or suspended:
; wait for the previous frame to leave (1.2 ms at 10 Mbit)
push eax ecx
set_io [ebx + device.io_addr], REG_SCB_STATUS
mov ecx, 100000
.cu_busy:
in al, dx
and al, SCB_STATUS_CUS
cmp al, CU_STATUS_ACTIVE
jne .cu_free
dec ecx
jnz .cu_busy
DEBUGF 2, "CU still active, starting anyway\n"
.cu_free:
pop ecx eax
set_io [ebx + device.io_addr], REG_SCB_PTR
out dx, eax
@@ -893,7 +854,7 @@ int_handler:
DEBUGF 1,"Status: %x\n", ax
test ax, SCB_STATUS_FR or SCB_STATUS_RNR ; frame received or receiver stopped?
test ax, SCB_STATUS_FR ; did we receive a frame?
jz .no_rx
push ax
@@ -940,7 +901,6 @@ int_handler:
mov [esi + sizeof.NET_BUFF + rxfd.command], RXFD_CMD_EL or RXFD_CMD_SUSPEND
mov [esi + sizeof.NET_BUFF + rxfd.link], eax
mov [esi + sizeof.NET_BUFF + rxfd.count], 0
mov [esi + sizeof.NET_BUFF + rxfd.rx_buf_addr], 0xffffffff ; simplified mode, no RBD
mov [esi + sizeof.NET_BUFF + rxfd.size], 1528
; restart RX
@@ -956,22 +916,11 @@ int_handler:
mov ax, RX_START
out dx, ax
call cmd_wait
.out_of_mem:
; Hand the frame over to the kernel
jmp [EthInput]
.out_of_mem:
; The buffer is still our only RFD: drop the frame and reuse it
mov esi, [esp] ; the buffer
mov ecx, [esi + NET_BUFF.length]
dec [ebx + device.packets_rx] ; counted above, before the allocation
sub dword [ebx + device.bytes_rx], ecx
sbb dword [ebx + device.bytes_rx + 4], 0
inc [ebx + device.packets_rx_drop]
add esp, 12 ; buffer, .rx_loop, ebx
mov esi, [ebx + device.rx_desc]
jmp .not_ok
.not_ok:
; Reset the FD
mov [esi + sizeof.NET_BUFF + rxfd.status], 0
@@ -996,27 +945,6 @@ int_handler:
.no_rx_:
DEBUGF 1, "no more data\n"
; With a single RFD the receiver sits in No Resources/Suspended whenever a
; frame arrived before we re-armed it. Nothing restarts it but us.
set_io [ebx + device.io_addr], 0
set_io [ebx + device.io_addr], REG_SCB_STATUS
in al, dx
and al, SCB_STATUS_RUS
cmp al, RU_STATUS_READY
je .ru_ready
test byte[esp], 1 ; bit 0 of the saved status is reserved,
jnz .ru_ready ; we mark it: one restart per IRQ
or byte[esp], 1
movzx eax, al
DEBUGF 1, "Restarting receiver, RU status %x\n", eax:2
mov esi, [ebx + device.rx_desc]
push ebx
test [esi + sizeof.NET_BUFF + rxfd.status], RXFD_STATUS_C
jnz .rx_loop ; a frame completed meanwhile
add esp, 4
jmp .not_ok ; re-arm the empty RFD
.ru_ready:
pop ax
.no_rx:
@@ -1027,13 +955,13 @@ int_handler:
push eax
.loop_tx:
mov eax, [ebx + device.last_tx]
mov edx, sizeof.txfd
mul edx
mov edi, [ebx + device.last_tx]
mov eax, sizeof.txfd
mul eax
lea edi, [ebx + device.tx_ring + eax]
test [edi + txfd.status], TXFD_STATUS_C ; sent by the device?
jz .tx_done
cmp [edi + txfd.status], 0
je .tx_done
cmp [edi + txfd.virt_addr], 0
je .tx_done
@@ -1042,7 +970,6 @@ int_handler:
push [edi + txfd.virt_addr]
mov [edi + txfd.virt_addr], 0
mov [edi + txfd.status], 0 ; free for transmit again
invoke NetFree
inc [ebx + device.last_tx]
@@ -1053,6 +980,12 @@ int_handler:
pop eax
.no_tx:
test ax, RU_STATUS_NO_RESOURCES
jz .not_out_of_resources
DEBUGF 2, "Out of resources!\n"
.not_out_of_resources:
pop edi esi ebx
xor eax, eax
inc eax
@@ -1146,25 +1079,6 @@ proc check_media_mii stdcall dev:dword
endp
; Wait (up to 1 s) until the device has executed the command in confcmd.
align 4
confcmd_wait:
mov ecx, 1000 ; udelay = Sleep(1), 1 ms
.loop:
test [ebx + device.confcmd.status], TXFD_STATUS_C
jnz .done
call udelay
dec ecx
jnz .loop
movzx eax, [ebx + device.confcmd.command]
DEBUGF 2, "Command 0x%x not completed\n", eax:4
ret
.done:
movzx eax, [ebx + device.confcmd.command]
movzx ecx, [ebx + device.confcmd.status]
DEBUGF 1, "Command 0x%x done, status 0x%x\n", eax:4, ecx:4
ret
align 4
cmd_wait:
-3
View File
@@ -1,3 +0,0 @@
if tup.getconfig("NO_FASM") ~= "" then return end
ROOT = "../.."
tup.rule("i2chid.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "%B.sys")
-438
View File
@@ -1,438 +0,0 @@
; Synopsys DesignWare I2C master, polled (PIO) mode only.
; This is the controller inside Intel LPSS blocks (Skylake and newer, plus
; Atom-derived SoCs); the same IP is used by many other vendors.
;
; The register file is always accessed as dwords. The controller must be
; disabled to change IC_TAR, so every transfer disables it, programs the
; target address, enables it back and feeds the TX FIFO by hand.
; ------------------------------ Registers ------------------------------------
DwIcCon = 0x00
DwIcTar = 0x04
DwIcDataCmd = 0x10
DwIcSsSclHcnt = 0x14
DwIcSsSclLcnt = 0x18
DwIcFsSclHcnt = 0x1C
DwIcFsSclLcnt = 0x20
DwIcIntrStat = 0x2C
DwIcIntrMask = 0x30
DwIcRawIntrStat = 0x34
DwIcRxTl = 0x38
DwIcTxTl = 0x3C
DwIcClrIntr = 0x40
DwIcClrTxAbrt = 0x54
DwIcEnable = 0x6C
DwIcStatus = 0x70
DwIcTxflr = 0x74
DwIcRxflr = 0x78
DwIcSdaHold = 0x7C
DwIcTxAbrtSource = 0x80
DwIcEnableStatus = 0x9C
DwIcCompParam1 = 0xF4
DwIcCompVersion = 0xF8
DwIcCompType = 0xFC
; "DW_apb_i2c" component signature ('DW' + 0x0140).
DW_COMP_TYPE_VALUE = 0x44570140
; IC_CON: master, standard speed (100 kHz), restarts allowed, slave disabled.
DW_CON_MASTER = 1 shl 0
DW_CON_SPEED_STD = 1 shl 1
DW_CON_SPEED_FAST = 2 shl 1
DW_CON_RESTART_EN = 1 shl 5
DW_CON_SLAVE_DIS = 1 shl 6
; IC_DATA_CMD bits above the data byte.
DW_CMD_READ = 1 shl 8
DW_CMD_STOP = 1 shl 9
DW_CMD_RESTART = 1 shl 10
; IC_STATUS bits
DW_STAT_TFNF = 1 shl 1 ; TX FIFO not full
DW_STAT_TFE = 1 shl 2 ; TX FIFO empty
DW_STAT_RFNE = 1 shl 3 ; RX FIFO not empty
DW_STAT_MST_ACT = 1 shl 5 ; master FSM busy
; IC_RAW_INTR_STAT bits
DW_INT_TX_ABRT = 1 shl 6
; SCL timing for standard mode. The LPSS input clock is 100 MHz on the PCH
; parts and 133 MHz on the Atom-derived SoCs (Apollo Lake, Gemini Lake), and
; nothing in PCI config space says which one this is, so the counts are
; picked to satisfy the fast-mode minimums at the fastest of them: at
; 133 MHz that is tHIGH = 0.98 us and tLOW = 1.5 us, 400 kHz. On a 100 MHz
; part the same counts run the bus at 300 kHz, which is just as legal.
; Fast mode rather than standard: HID over I2C requires every device to
; support it, that is what Windows drives them at, and a polled host pays
; for every byte with busy-waiting - at 100 kHz a 64-byte input read costs
; 6 ms, more than a fast pad takes to produce the next report, and the
; backlog that builds up plays back as the cursor coasting after the finger
; has stopped. SDA hold stays well below tLOW.
DW_FS_HCNT = 130
DW_FS_LCNT = 200
DW_SDA_HOLD = 28
; The AMD FCH feeds its DesignWare masters from a 150 MHz reference, so
; the same minimums need more counts there: 145/225 give tHIGH = 0.97 us,
; tLOW = 1.5 us, again 400 kHz; SDA hold 45 = 300 ns.
DW_AMD_FS_HCNT = 145
DW_AMD_FS_LCNT = 225
DW_AMD_SDA_HOLD = 45
; A transfer gives up after [XferTimeout] hundredths of a second. The init
; value must cover a full report descriptor read: descriptors run up to 2 KB
; and the bus may be as slow as 77 kHz, so at 9 SCL cycles per byte a single
; transfer takes ~240 ms of wall-clock time. Polling is generous too now that it runs in its own thread
; rather than in a timer callback - a wedged bus costs this thread its slice
; and nothing else.
DW_TIMEOUT_INIT = 60
DW_TIMEOUT_POLL = 20
; Disables the controller and waits until it reports itself disabled.
; in: ebx = MMIO base. Clobbers eax, ecx.
proc dw_ctrl_disable
mov dword [ebx+DwIcEnable], 0
mov ecx, 100000
@@:
test dword [ebx+DwIcEnableStatus], 1
jz .done
pause
loop @b
.done:
ret
endp
; Aborts a stuck transfer cleanly: the ABORT bit makes the master issue STOP,
; flush the TX FIFO and raise TX_ABRT, which releases a slave that is holding
; the bus (a clock-stretching touchpad, for instance). Simply disabling the
; controller in the middle of a byte would leave SDA held low and every
; following transfer would time out too. Older cores without the ABORT bit
; just ignore the write and fall through after the wait.
; in: ebx = MMIO base. Clobbers eax, ecx.
proc dw_ctrl_abort
mov dword [ebx+DwIcEnable], 3
mov ecx, 100000
@@:
test dword [ebx+DwIcRawIntrStat], DW_INT_TX_ABRT
jnz @f
pause
loop @b
@@:
mov eax, [ebx+DwIcClrTxAbrt]
call dw_ctrl_disable
ret
endp
; One idle step of a transfer wait loop.
; A healthy transfer is over within a few milliseconds, well inside the
; first two timer ticks, and spins through them: a transfer that yields
; its slice is at the scheduler's mercy for the rest of it. Past that the
; bus is stuck or crawling, and the wait gives up the CPU a tick at a time
; instead of burning a core until XferTimeout.
; in: eax = ticks elapsed since the transfer began. Preserves all but eax.
DW_SPIN_TICKS = 2
proc dw_wait_step
cmp eax, DW_SPIN_TICKS
jae .yield
pause
ret
.yield:
push ebx
movi ebx, 1
invoke Delay ; preserves every register
pop ebx
ret
endp
; One-time controller setup after mapping.
; in: ebx = MMIO base.
proc dw_ctrl_init
push eax ecx
call dw_ctrl_disable
mov dword [ebx+DwIcCon], DW_CON_MASTER + DW_CON_SPEED_FAST + \
DW_CON_RESTART_EN + DW_CON_SLAVE_DIS
; The counts come from variables: they depend on the reference clock, which
; is decided by whoever found the controller (PCI LPSS or AMD FCH). The
; standard-mode registers get the same values scaled up so that they are
; sane should anything ever switch the speed bits back.
mov eax, [DwHcnt]
mov [ebx+DwIcFsSclHcnt], eax
lea eax, [eax*4]
mov [ebx+DwIcSsSclHcnt], eax
mov eax, [DwLcnt]
mov [ebx+DwIcFsSclLcnt], eax
lea eax, [eax*4]
mov [ebx+DwIcSsSclLcnt], eax
mov eax, [DwSdaHold]
mov [ebx+DwIcSdaHold], eax
mov dword [ebx+DwIcIntrMask], 0
mov dword [ebx+DwIcRxTl], 0
mov dword [ebx+DwIcTxTl], 0
mov eax, [ebx+DwIcClrIntr]
pop ecx eax
ret
endp
; One combined I2C transaction: optional write phase, then optional read phase
; with a repeated START between them. Fully polled.
; out: eax = 0 on success, IC_TX_ABRT_SOURCE value on NAK/abort, -1 on timeout.
proc dw_xfer stdcall uses ebx esi edi, addr:dword, wbuf:dword, wlen:dword, \
rbuf:dword, rlen:dword
locals
wsent dd ?
rqueued dd ?
rgot dd ?
t0 dd ?
endl
mov ebx, [I2cMmio]
call dw_ctrl_disable
mov eax, [addr]
mov [ebx+DwIcTar], eax
mov eax, [ebx+DwIcClrIntr]
mov dword [ebx+DwIcEnable], 1
xor eax, eax
mov [wsent], eax
mov [rqueued], eax
mov [rgot], eax
invoke GetTimerTicks
mov [t0], eax
.loop:
; Abort (NAK and friends) ends the transfer immediately.
test dword [ebx+DwIcRawIntrStat], DW_INT_TX_ABRT
jnz .abort
; Drain the RX FIFO first so it can never overflow.
test dword [ebx+DwIcStatus], DW_STAT_RFNE
jz .no_rx
mov edx, [rgot]
cmp edx, [rlen]
jae .no_rx
mov eax, [ebx+DwIcDataCmd]
mov edi, [rbuf]
mov [edi+edx], al
inc edx
mov [rgot], edx
jmp .loop
.no_rx:
; Feed the write phase.
mov eax, [wsent]
cmp eax, [wlen]
jae .push_reads
test dword [ebx+DwIcStatus], DW_STAT_TFNF
jz .check_done
mov esi, [wbuf]
movzx edx, byte [esi+eax]
inc eax
cmp eax, [wlen]
jne @f
cmp [rlen], 0
jne @f
or edx, DW_CMD_STOP ; last byte of a write-only transfer
@@:
mov [ebx+DwIcDataCmd], edx
mov [wsent], eax
jmp .loop
.push_reads:
; Feed read commands, at most 8 outstanding so the RX FIFO keeps up.
mov eax, [rqueued]
cmp eax, [rlen]
jae .check_done
mov edx, eax
sub edx, [rgot]
cmp edx, 8
jae .check_done
test dword [ebx+DwIcStatus], DW_STAT_TFNF
jz .check_done
mov edx, DW_CMD_READ
test eax, eax
jnz @f
cmp [wlen], 0
je @f
or edx, DW_CMD_RESTART ; repeated START after the write phase
@@:
mov ecx, [rlen]
dec ecx
cmp eax, ecx
jne @f
or edx, DW_CMD_STOP
@@:
mov [ebx+DwIcDataCmd], edx
inc eax
mov [rqueued], eax
jmp .loop
.check_done:
mov eax, [rgot]
cmp eax, [rlen]
jne .not_done
mov eax, [wsent]
cmp eax, [wlen]
jne .not_done
mov eax, [ebx+DwIcStatus]
test eax, DW_STAT_TFE
jz .not_done
test eax, DW_STAT_MST_ACT
jnz .not_done
call dw_ctrl_disable
xor eax, eax
ret
.not_done:
invoke GetTimerTicks
sub eax, [t0]
cmp eax, [XferTimeout]
jae .timeout
call dw_wait_step
jmp .loop
.abort:
mov esi, [ebx+DwIcTxAbrtSource]
mov eax, [ebx+DwIcClrTxAbrt]
call dw_ctrl_disable
mov eax, esi
test eax, eax
jnz @f
or eax, 0x80000000
@@:
ret
.timeout:
call dw_ctrl_abort
or eax, -1
ret
endp
; Reads one HID input report as a single continuous bus transaction, the way
; interrupt-driven hosts (Windows, Linux) do it: the optional register-address
; write and every read command are queued into the TX FIFO before the bytes
; start flowing, so nothing on the wire depends on how fast the host loop
; runs. The previous adaptive read (fetch 2 length bytes, decide, fetch the
; rest, stop short) was cut down on the wire to 3 bytes for an empty poll -
; and the SIPODEV/Hantick touchpad firmwares are exactly the kind of thing
; that wedges when an input read is shorter than the frame they prepared.
; rlen should not exceed the TX FIFO depth (IC_COMP_PARAM_1 bits 23:16, plus
; one) or the queue loop degrades to feeding the FIFO on the fly, which
; reintroduces pauses.
; in: addr = slave, wlen bytes at wbuf written first (0 = plain read),
; rlen bytes read into buf.
; out: eax = 0 ok, IC_TX_ABRT_SOURCE on NAK/abort, -1 on timeout.
; Timeout check for the dw_read_block wait spots; expands inside the proc so
; [t0] and [XferTimeout] resolve in the caller's own frame.
macro BLOCK_TICK fail_label {
invoke GetTimerTicks
sub eax, [t0]
cmp eax, [XferTimeout]
jae fail_label
call dw_wait_step
}
proc dw_read_block stdcall uses ebx esi edi, addr:dword, wbuf:dword, wlen:dword, buf:dword, rlen:dword
locals
rgot dd ?
t0 dd ?
endl
mov ebx, [I2cMmio]
call dw_ctrl_disable
mov eax, [addr]
mov [ebx+DwIcTar], eax
mov eax, [ebx+DwIcClrIntr]
mov dword [ebx+DwIcEnable], 1
invoke GetTimerTicks
mov [t0], eax
mov [rgot], 0
; Write phase: the register address bytes, no STOP - the read continues the
; same transaction after a repeated START.
xor ecx, ecx
.wr:
cmp ecx, [wlen]
jae .queue_reads
test dword [ebx+DwIcRawIntrStat], DW_INT_TX_ABRT
jnz .abort
test dword [ebx+DwIcStatus], DW_STAT_TFNF
jz .wr_wait
mov esi, [wbuf]
movzx edx, byte [esi+ecx]
mov [ebx+DwIcDataCmd], edx
inc ecx
jmp .wr
.wr_wait:
BLOCK_TICK .timeout
jmp .wr
.queue_reads:
xor ecx, ecx
.rq:
cmp ecx, [rlen]
jae .drain
test dword [ebx+DwIcRawIntrStat], DW_INT_TX_ABRT
jnz .abort
test dword [ebx+DwIcStatus], DW_STAT_TFNF
jz .rq_wait
mov edx, DW_CMD_READ
test ecx, ecx
jnz .not_first
cmp [wlen], 0
je .not_first
or edx, DW_CMD_RESTART
.not_first:
mov eax, [rlen]
dec eax
cmp ecx, eax
jne @f
or edx, DW_CMD_STOP
@@:
mov [ebx+DwIcDataCmd], edx
inc ecx
; Drain opportunistically so a FIFO shallower than rlen cannot deadlock the
; queue loop (the RX side fills while the TX side is full).
test dword [ebx+DwIcStatus], DW_STAT_RFNE
jz .rq
call .take_byte
jmp .rq
.rq_wait:
BLOCK_TICK .timeout
jmp .rq
.drain:
test dword [ebx+DwIcRawIntrStat], DW_INT_TX_ABRT
jnz .abort
test dword [ebx+DwIcStatus], DW_STAT_RFNE
jz .chk
call .take_byte
jmp .drain
; Moves one byte from the RX FIFO into the caller's buffer. Exactly rlen
; reads are queued into freshly flushed FIFOs, so a byte beyond rlen should
; never arrive; if one does anyway it is still taken off the FIFO, so the
; drain loop cannot stall on it, but it is dropped rather than written
; past the end of the buffer.
.take_byte:
mov edx, [rgot]
mov eax, [ebx+DwIcDataCmd]
cmp edx, [rlen]
jae @f
mov edi, [buf]
mov [edi+edx], al
inc edx
mov [rgot], edx
@@:
retn
.chk:
mov eax, [rgot]
cmp eax, [rlen]
jne .wait
test dword [ebx+DwIcStatus], DW_STAT_MST_ACT
jnz .wait
call dw_ctrl_disable
xor eax, eax
ret
.wait:
BLOCK_TICK .timeout
jmp .drain
.abort:
mov esi, [ebx+DwIcTxAbrtSource]
mov eax, [ebx+DwIcClrTxAbrt]
call dw_ctrl_disable
mov eax, esi
test eax, eax
jnz @f
or eax, 0x80000000
@@:
ret
.timeout:
call dw_ctrl_abort
or eax, -1
ret
endp
-646
View File
@@ -1,646 +0,0 @@
; Minimal HID report descriptor parser.
;
; The goal is not a full HID implementation: the parser walks the descriptor
; once and remembers the bit layout of the first input report that contains
; relative X and relative Y (Generic Desktop / X, Y) - i.e. the mouse
; compatibility collection that every I2C mouse and every Windows Precision
; Touchpad exposes. Buttons (Usage Page 9) and a relative wheel found in the
; same report are picked up too. Absolute (digitizer) reports are advanced
; over but otherwise ignored.
;
; Report IDs are honoured: bit positions are counted separately per report ID
; and the chosen ID is checked in every incoming packet.
;
; Alongside the mouse report, the parser also maps the touchpad (Windows
; Precision Touchpad) report: the report that carries Tip Switch usages.
; Each Tip Switch opens a new finger block; the absolute X and Y that follow
; it belong to that finger; Contact Count and the Button-page fields of the
; same report are recorded too. Once the pad is switched into touchpad mode
; those offsets are what the frame decoder reads - every vendor lays the
; frame out differently, and only the descriptor knows how.
HID_MAX_FINGERS = 5
HID_MAX_USAGES = 16
HID_MAX_REPIDS = 16
; Returns the pointer to the input bit counter of the current report ID,
; allocating a new slot on first use.
; out: ebx -> dword bit counter. Clobbers eax, ecx.
proc hid_get_bits_slot
mov eax, [p_report_id]
xor ecx, ecx
.scan:
cmp ecx, [p_idcnt]
jae .add
cmp eax, [p_ids+ecx*4]
jz .found
inc ecx
jmp .scan
.add:
cmp ecx, HID_MAX_REPIDS
jb @f
dec ecx ; table full: reuse the last slot
jmp .found
@@:
mov [p_ids+ecx*4], eax
mov dword [p_bits+ecx*4], 0
mov dword [p_fbits+ecx*4], 0
inc [p_idcnt]
.found:
lea ebx, [p_bits+ecx*4]
ret
endp
; Handles one Input main item. v_flags = item data (bit 2 = relative).
proc hid_process_input
push eax ebx ecx edx
call hid_get_bits_slot
mov eax, [ebx]
mov [v_base], eax
; Advance the counter over this field right away.
mov eax, [p_report_size]
imul eax, [p_report_count]
add [ebx], eax
; Remember the largest logical maximum ever attached to Generic Desktop X
; and Y. The mouse collection declares a tiny relative range there while
; the touchpad collection declares the real surface extents, so the
; maximum over the whole descriptor is the size of the pad - which is what
; the button zones are measured against, and it differs per model.
cmp [p_usage_cnt], 0
je .no_extent
xor ecx, ecx
.ext_loop:
cmp ecx, [p_usage_cnt]
jae .no_extent
mov eax, [p_usages+ecx*4]
cmp eax, 0x00010030
jne .ext_y
mov eax, [p_log_max]
cmp eax, [t_padmaxx]
jbe .ext_next
mov [t_padmaxx], eax
jmp .ext_next
.ext_y:
cmp eax, 0x00010031
jne .ext_next
mov eax, [p_log_max]
cmp eax, [t_padmaxy]
jbe .ext_next
mov [t_padmaxy], eax
.ext_next:
inc ecx
jmp .ext_loop
.no_extent:
; Button-style field: Usage Minimum/Maximum on the Button page.
cmp [p_usage_min], -1
je .not_buttons
cmp [p_usage_max], -1
je .not_buttons
cmp [p_usage_page], 9
jne .not_buttons
cmp [p_report_size], 1 ; buttons are always 1-bit fields
jne .done
mov eax, [v_base]
mov ecx, [p_report_count]
call hid_note_buttons
jmp .done
.not_buttons:
cmp [p_usage_cnt], 0
je .done
call hid_note_touchpad
; Usage-list field: look for GD/X, GD/Y, GD/Wheel among the usages.
test [v_flags], 4 ; only relative fields are interesting
jz .done
xor ecx, ecx
.usage_loop:
cmp ecx, [p_report_count]
jae .done
; usage index = min(field index, usage count - 1): a short usage list
; applies its last usage to the remaining fields.
mov edx, [p_usage_cnt]
dec edx
mov eax, ecx
cmp eax, edx
jbe @f
mov eax, edx
@@:
mov eax, [p_usages+eax*4]
cmp eax, 0x00010030
je .is_x
cmp eax, 0x00010031
je .is_y
cmp eax, 0x00010038
je .is_wheel
.next_usage:
inc ecx
jmp .usage_loop
.is_x:
test [t_have], 1
jnz .next_usage
call hid_claim_report_id
jc .next_usage
call hid_field_offset
mov [t_xoff], eax
mov eax, [p_report_size]
mov [t_xsize], eax
or [t_have], 1
jmp .next_usage
.is_y:
test [t_have], 2
jnz .next_usage
call hid_claim_report_id
jc .next_usage
call hid_field_offset
mov [t_yoff], eax
mov eax, [p_report_size]
mov [t_ysize], eax
or [t_have], 2
jmp .next_usage
.is_wheel:
test [t_have], 8
jnz .next_usage
mov eax, [t_id]
cmp eax, -1 ; wheel never claims a report on its own
je .next_usage
cmp eax, [p_report_id]
jne .next_usage
call hid_field_offset
mov [t_woff], eax
mov eax, [p_report_size]
mov [t_wsize], eax
or [t_have], 8
jmp .next_usage
.done:
pop edx ecx ebx eax
ret
endp
; Records a run of 1-bit Button-page fields starting at bit eax, ecx of them.
; The mouse decoder wants the buttons of ITS report: an item from some other
; report is kept only until a better one turns up, and .eof drops it if it
; still does not match. The touchpad report keeps its own copy.
proc hid_note_buttons
push eax ecx edx
cmp ecx, 8
jbe @f
mov ecx, 8
@@:
mov edx, [p_report_id]
cmp edx, [t_ptp_id]
jne .mouse
cmp [t_pbtn_cnt], 0
jne .mouse
mov [t_pbtn_off], eax
mov [t_pbtn_cnt], ecx
.mouse:
cmp [t_btncnt], 0
je .take
mov edx, [t_btnid]
cmp edx, [t_id] ; already the chosen report's: keep
je .done
mov edx, [p_report_id]
cmp edx, [t_btnid] ; a second run in the same report: keep the first
je .done
.take:
mov [t_btnoff], eax
mov [t_btncnt], ecx
mov eax, [p_report_id]
mov [t_btnid], eax
.done:
pop edx ecx eax
ret
endp
; Walks the usages of the current input item looking for the touchpad
; fields. Field k takes usage min(k, count-1), as in the mouse search.
proc hid_note_touchpad
push eax ebx ecx edx
xor ecx, ecx
.field:
cmp ecx, [p_report_count]
jae .done
mov edx, [p_usage_cnt]
dec edx
mov eax, ecx
cmp eax, edx
jbe @f
mov eax, edx
@@:
mov ebx, [p_usages+eax*4] ; ebx = usage of field ecx
call hid_field_offset ; eax = its bit offset
cmp ebx, 0x000D0042 ; Tip Switch: a new finger
je .tip
cmp ebx, 0x000D0054 ; Contact Count
je .count
cmp ebx, 0x000D0051 ; Contact Identifier
je .cid
cmp ebx, 0x00010030
je .x
cmp ebx, 0x00010031
je .y
shr ebx, 16
cmp ebx, 9 ; buttons written as a usage list
jne .next
push ecx
neg ecx
add ecx, [p_report_count] ; the fields from here to the end
call hid_note_buttons
pop ecx
jmp .done ; one run per item is enough
.tip:
cmp [t_ptp_id], -1
jne @f
mov edx, [p_report_id]
mov [t_ptp_id], edx ; the first report with fingers is the one
@@:
call hid_in_ptp
jne .next
mov edx, [t_fcount]
cmp edx, HID_MAX_FINGERS
jae .next
mov [t_ftip+edx*4], eax
mov dword [t_fxs+edx*4], 0
mov dword [t_fys+edx*4], 0
mov dword [t_fcids+edx*4], 0
inc [t_fcount]
jmp .next
.cid:
call hid_in_ptp
jne .next
mov edx, [t_fcount]
test edx, edx
jz .next
dec edx
cmp dword [t_fcids+edx*4], 0
jne .next
mov [t_fcid+edx*4], eax
mov eax, [p_report_size]
mov [t_fcids+edx*4], eax
jmp .next
.count:
call hid_in_ptp
jne .next
mov [t_ccnt_off], eax
mov eax, [p_report_size]
mov [t_ccnt_size], eax
jmp .next
.x:
test [v_flags], 4 ; absolute only; relative is the mouse
jnz .next
call hid_in_ptp
jne .next
mov edx, [t_fcount]
test edx, edx
jz .next
dec edx
cmp dword [t_fxs+edx*4], 0
jne .next
mov [t_fx+edx*4], eax
mov eax, [p_report_size]
mov [t_fxs+edx*4], eax
jmp .next
.y:
test [v_flags], 4
jnz .next
call hid_in_ptp
jne .next
mov edx, [t_fcount]
test edx, edx
jz .next
dec edx
cmp dword [t_fys+edx*4], 0
jne .next
mov [t_fy+edx*4], eax
mov eax, [p_report_size]
mov [t_fys+edx*4], eax
.next:
inc ecx
jmp .field
.done:
pop edx ecx ebx eax
ret
endp
; ZF set when the current item belongs to the touchpad report.
proc hid_in_ptp
push eax
mov eax, [p_report_id]
cmp eax, [t_ptp_id]
pop eax
ret
endp
; Size in bytes of the feature report with id eax; 0 when the descriptor
; never mentioned one.
proc hid_feature_bytes
push ecx
xor ecx, ecx
@@:
cmp ecx, [p_idcnt]
jae .none
cmp eax, [p_ids+ecx*4]
je .found
inc ecx
jmp @b
.found:
mov eax, [p_fbits+ecx*4]
add eax, 7
shr eax, 3
pop ecx
ret
.none:
xor eax, eax
pop ecx
ret
endp
; Locks the candidate report ID to the current one, or fails (CF=1) when a
; different report already holds X/Y.
proc hid_claim_report_id
mov eax, [t_id]
cmp eax, -1
jne @f
mov eax, [p_report_id]
mov [t_id], eax
clc
ret
@@:
cmp eax, [p_report_id]
jne .taken
clc
ret
.taken:
stc
ret
endp
; Bit offset of field #ecx of the current item.
; in: ecx = field index. out: eax = v_base + ecx * report_size.
proc hid_field_offset
mov eax, [p_report_size]
imul eax, ecx
add eax, [v_base]
ret
endp
; Parses the report descriptor.
; in: esi -> descriptor, ecx = length.
; out: eax = 1 and f_* variables filled if a usable report was found.
proc hid_parse_report_desc uses ebx esi edi
lea edi, [esi+ecx]
xor eax, eax
mov [p_usage_page], eax
mov [p_report_size], eax
mov [p_report_count], eax
mov [p_report_id], eax
mov [p_uses_repid], eax
mov [p_usage_cnt], eax
mov [p_idcnt], eax
mov [p_log_max], eax
mov [t_padmaxx], eax
mov [t_padmaxy], eax
mov [t_have], eax
mov [t_btncnt], eax
mov [t_wsize], eax
mov [p_usage_min], -1
mov [p_usage_max], -1
mov [t_id], -1
mov [t_btnid], -2
mov [t_ptp_id], -1
mov [t_fcount], eax
mov [t_ccnt_size], eax
mov [t_pbtn_cnt], eax
mov [t_ptp_bytes], eax
.loop:
cmp esi, edi
jae .eof
movzx eax, byte [esi]
inc esi
cmp al, 0xFE
je .long_item
mov ecx, eax
and ecx, 3
cmp ecx, 3
jne @f
inc ecx ; size code 3 means 4 bytes
@@:
lea ebx, [esi+ecx]
cmp ebx, edi
ja .eof
xor edx, edx
jecxz .no_data
cmp ecx, 1
jne @f
movzx edx, byte [esi]
jmp .have_data
@@:
cmp ecx, 2
jne @f
movzx edx, word [esi]
jmp .have_data
@@:
mov edx, [esi]
.have_data:
add esi, ecx
.no_data:
and eax, 0xFC
; Global items
cmp al, 0x04
je .g_usage_page
cmp al, 0x84
je .g_report_id
cmp al, 0x74
je .g_report_size
cmp al, 0x94
je .g_report_count
cmp al, 0x24
je .g_log_max
; Local items
cmp al, 0x08
je .l_usage
cmp al, 0x18
je .l_usage_min
cmp al, 0x28
je .l_usage_max
; Main items
cmp al, 0x80
je .m_input
cmp al, 0x90
je .m_clear_locals
cmp al, 0xB0
je .m_feature
cmp al, 0xA0
je .m_clear_locals
cmp al, 0xC0
je .m_clear_locals
jmp .loop
.g_usage_page:
and edx, 0xFFFF
mov [p_usage_page], edx
jmp .loop
.g_report_id:
mov [p_report_id], edx
mov [p_uses_repid], 1
jmp .loop
.g_report_size:
mov [p_report_size], edx
jmp .loop
.g_report_count:
mov [p_report_count], edx
jmp .loop
.g_log_max:
mov [p_log_max], edx
jmp .loop
.l_usage:
mov ebx, [p_usage_cnt]
cmp ebx, HID_MAX_USAGES
jae .loop
cmp ecx, 4 ; 4-byte usage carries its own page
je @f
mov eax, [p_usage_page]
shl eax, 16
or edx, eax
@@:
mov [p_usages+ebx*4], edx
inc [p_usage_cnt]
jmp .loop
.l_usage_min:
mov [p_usage_min], edx
jmp .loop
.l_usage_max:
mov [p_usage_max], edx
jmp .loop
.m_input:
mov [v_flags], edx
call hid_process_input
jmp .m_clear_locals ; input bits are not feature bits
.m_feature:
; Feature reports are only ever written, never decoded, but writing one
; needs its exact size: a SET_REPORT shorter than the report is ignored by
; some firmwares (the Elan Input Mode report has two bytes, mode and the
; selective-reporting switches - one byte does nothing there).
call hid_get_bits_slot
mov eax, [p_report_size]
imul eax, [p_report_count]
add [p_fbits+ecx*4], eax
.m_clear_locals:
xor eax, eax
mov [p_usage_cnt], eax
mov [p_usage_min], -1
mov [p_usage_max], -1
jmp .loop
.long_item:
cmp esi, edi
jae .eof
movzx ecx, byte [esi]
lea esi, [esi+ecx+2]
jmp .loop
.eof:
; Size of the touchpad report, when there is one.
mov eax, [t_ptp_id]
cmp eax, -1
je .no_ptp
xor ecx, ecx
@@:
cmp ecx, [p_idcnt]
jae .no_ptp
cmp eax, [p_ids+ecx*4]
je @f
inc ecx
jmp @b
@@:
mov eax, [p_bits+ecx*4]
add eax, 7
shr eax, 3
mov [t_ptp_bytes], eax
.no_ptp:
; Success needs relative X and Y in the same report - or, failing that, a
; touchpad report with at least one complete finger, which is then the only
; thing the device will be driven through.
mov eax, [t_have]
and eax, 3
cmp eax, 3
je .have_mouse
cmp [t_fcount], 0
je .fail
cmp dword [t_fxs], 0
je .fail
cmp dword [t_fys], 0
je .fail
mov [f_repid], -1 ; no mouse report to match
mov [f_bytes], 0
mov [t_btncnt], 0
movi eax, 1
ret
.have_mouse:
; Keep buttons/wheel only when they live in the chosen report.
mov eax, [t_btnid]
cmp eax, [t_id]
je @f
mov [t_btncnt], 0
@@:
; Final layout.
mov eax, [t_id]
mov [f_repid], eax
xor ecx, ecx
@@:
cmp ecx, [p_idcnt]
jae .no_bits
cmp eax, [p_ids+ecx*4]
je .got_bits
inc ecx
jmp @b
.got_bits:
mov eax, [p_bits+ecx*4]
add eax, 7
shr eax, 3
mov [f_bytes], eax
movi eax, 1
ret
.no_bits:
.fail:
xor eax, eax
ret
endp
; Extracts an unsigned field from an input report.
; in: esi -> report data, eax = bit offset, ecx = bit count (1..24).
; out: eax = value.
proc hid_extract_u
push ebx ecx edx
mov edx, eax
shr edx, 3
mov ebx, [esi+edx] ; buffer has spare bytes at the end
and eax, 7
push ecx
mov ecx, eax
shr ebx, cl
pop ecx
neg ecx
add ecx, 32
shl ebx, cl
shr ebx, cl
mov eax, ebx
pop edx ecx ebx
ret
endp
; Same, sign-extended.
proc hid_extract_s
push ebx ecx edx
mov edx, eax
shr edx, 3
mov ebx, [esi+edx]
and eax, 7
push ecx
mov ecx, eax
shr ebx, cl
pop ecx
neg ecx
add ecx, 32
shl ebx, cl
sar ebx, cl
mov eax, ebx
pop edx ecx ebx
ret
endp
File diff suppressed because it is too large. Load diff
-26
View File
@@ -1,26 +0,0 @@
[touchpad]
; pointer speed in percent of the driver's default (on top of the [mouse]
; speed above; pads differ in resolution)
speed=100
; how far a finger must move before the pointer follows, in pad units;
; larger is steadier under a pressing finger, 0 turns the filter off
jitter=1
; the same, for a finger that landed on the button strip: it is pressing
; rather than steering there, so it needs a stricter margin
jitter_buttons=45
; pad units of two-finger travel per wheel step, and the direction
scroll_step=64
scroll_invert=0
; turn a short, still touch into a click: one finger left, two right,
; three middle
tap_enable=1
; tap, then touch again at once and move: the button stays down for that
; second touch - this is how text is selected and how one draws
tap_drag=1
; right click: 0 never, 1 bottom-right corner, 2 by finger count (two
; fingers right, three middle), 3 either
right_click=1
; button strip along the bottom edge, in percent of the surface: its
; height, and where its left half ends
button_zone=15
right_split=50
-72
View File
@@ -1,72 +0,0 @@
; Asks the I2C touchpad driver to read its settings again.
;
; The driver takes everything it can be tuned with from the [touchpad] section
; of /sys/settings/system.ini, and it reads that file once while loading. This
; tells it to read the file again, so editing a setting takes effect straight
; away instead of at the next boot.
;
; There is no window: the outcome goes to the debug board, the way the driver
; reports everything else.
format binary as ""
use32
db 'MENUET01'
dd 1, start, i_end, mem, mem, 0, 0
include '../../programs/macros.inc'
SRV_RELOAD_CONF = 1
start:
; 1. Find the driver's service by name.
mcall 68, 16, srv_name
test eax, eax
jz .no_driver
mov [ioctl.handle], eax
; 2. Ask it to reload. No data travels either way: the driver reads the file
; itself, so the settings file stays the only place they are written down.
mcall 68, 17, ioctl
test eax, eax
jnz .refused
mov esi, msg_ok
jmp .say
.no_driver:
mov esi, msg_no_driver
jmp .say
.refused:
mov esi, msg_refused
.say:
call board_str
or eax, -1
mcall
; Writes a zero-terminated string to the debug board.
; in: esi -> string
board_str:
lodsb
test al, al
jz .done
mov cl, al
mcall 63, 1
jmp board_str
.done:
ret
srv_name db 'I2CHID', 0
align 4
ioctl:
.handle dd 0
.io_code dd SRV_RELOAD_CONF
.input dd 0
.inp_size dd 0
.output dd 0
.out_size dd 0
msg_ok db 'tpreload: touchpad settings reloaded', 13, 10, 0
msg_no_driver db 'tpreload: the I2C touchpad driver is not loaded', 13, 10, 0
msg_refused db 'tpreload: the driver refused the request', 13, 10, 0
i_end:
rb 1024
mem:
-95
View File
@@ -1,95 +0,0 @@
# NVMe driver
Driver for NVM Express controllers. Registers the first active namespace of every
NVMe controller it finds as a KolibriOS disk named `nvme<controller>n<namespace>`, so
that of the first controller usually shows up as `/nvme0n1/`.
## Origin
Written by Abdur-Rahman Mansoor for Google Summer of Code 2024, developed at
<https://git.kolibrios.org/GSoC/kolibrios-nvme-driver> and proposed for the main tree
as <https://git.kolibrios.org/KolibriOS/kolibrios/pulls/91>. Imported here from that
repository's last commit (53c04b9, September 2024), which is newer than the pull
request itself.
Licensed under the GNU General Public License, version 2.
## State
| Feature | Implemented | Notes |
|------------------------------------|-------------|--------------------------------------------------------------------|
| Mandatory administrator commands | Yes | |
| Mandatory I/O commands | Yes | Reading and writing; requests are split to respect IDENTC.MDTS. |
| Namespace identification | Yes | Across all controller versions. |
| Multiple NVMe controllers | Yes | Up to `TOTAL_PCIDEVS`. |
| Multiple namespaces per controller | No | Only the first active namespace is registered. |
| Flush | Yes | Issued once the kernel has written out its own cache. |
| Interrupts | No | Completions are polled; INTx, MSI and MSI-X are all disabled. |
| Asynchronous API | No | Every command blocks the calling thread until it completes. |
| SMART/health reporting | No | |
Sector sizes other than 512 bytes are rejected, because that is what KolibriOS
supports, and so are LBA formats with metadata. The format checked is the one in use
(FLBAS), not the first in the table.
## Interrupts
The driver does not use one. A thread that submits a command spins briefly on its
completion and then reads the completion queues itself, using the phase tag; the
controller's interrupt vectors are masked and INTx is disabled in the PCI command
register, so the controller never signals anything. Since every command blocks its
caller anyway, an interrupt would not make a completion arrive any sooner, while
asking for one has real costs: many machines give an NVMe controller no usable INTx
at all (MSI-X only, or firmware leaving the interrupt line at 0xFF), and the kernel's
shared-IRQ heuristic can relink a handler onto the wrong line the first time an
unrelated IRQ fires while a completion is pending - after which a level-triggered
interrupt nobody services storms and freezes the machine. That last case was seen
under QEMU while the driver still registered a handler.
Once the completion path becomes asynchronous, an MSI-X vector is the interrupt to
add; there is nothing to gain from INTx before then.
Every wait on the controller (reset, enable, shutdown, command completion) is bounded,
so a controller that never answers makes the driver give up rather than hang the boot.
An I/O command that times out gets the controller reset and taken out of service, so
that it cannot DMA into freed memory or complete a stale command later.
Calls into the driver are serialised per controller, since the kernel may issue disk
requests from several threads at once and the driver keeps one command in flight.
## Testing
Verified under QEMU (`-device nvme`) against controller version 1.4.0: driver load,
partition detection, small and multi-megabyte file round trips, transfers from
unaligned buffers checked against what actually landed on the disk image, and a boot
of the same image with no NVMe controller present, where the driver has to back off
without disturbing anything else.
Also verified on VMware Workstation 17.6 (its controller reports firmware 1.3 and
MDTS 8): the disk tests pass and the machine powers off cleanly, where the last
upstream build faults during the 2 MB transfer and then hangs on shutdown. And on
VirtualBox 7.2 (controller version 1.2.0, MDTS 0, i.e. no limit of its own): the same
tests pass, the image is correct on the host, and the machine powers off. Real
hardware is still untested.
Watch out when writing tests for this: a round trip done from inside KolibriOS can pass
over corrupt data, because the kernel buffer the file was read back into may still hold
the correct bytes from the write. What a transfer really left on the medium has to be
checked from outside.
Two problems reported upstream are addressed here, both reproduced first and then
confirmed fixed by running the last upstream build and this one against the same
machine. The file corruption of
[issue #7](https://git.kolibrios.org/GSoC/kolibrios-nvme-driver/issues/7) was PRP2
being built as a list for transfers that fit in two memory pages, which the controller
reads as a plain data pointer. The shutdown hang of
[issue #5](https://git.kolibrios.org/GSoC/kolibrios-nvme-driver/issues/5) is visible on
VMware Workstation, where the upstream build also faults inside the driver during a
multi-megabyte transfer - VMware reports MDTS 8, so a 2 MB request is more than one
command may carry, and the request was not being split.
## Building
The driver builds with the tree (`drivers/nvme/Tupfile.lua`) and is copied into the
image as `DRIVERS/NVME.SYS`. To build it by hand:
fasm nvme.asm nvme.sys
kpack nvme.sys
-3
View File
@@ -1,3 +0,0 @@
if tup.getconfig("NO_FASM") ~= "" then return end
ROOT = "../.."
tup.rule("nvme.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "%B.sys")
-243
View File
@@ -1,243 +0,0 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
proc set_cdw0 stdcall, pci:dword, y:dword, opcode:byte
stdcall get_new_cid, [pci], [y]
shl eax, 16
or al, [opcode]
ret
endp
; See pages 161-205 of the NVMe 1.4 specification for reference
proc nvme_identify stdcall, pci:dword, nsid:dword, prp1:dword, cns:byte
push esi
mov esi, [pci]
mov dword [esi + pcidev.spinlock], 1
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
mov eax, [nsid]
mov dword [esp + SQ_ENTRY.nsid], eax
mov eax, [prp1]
mov dword [esp + SQ_ENTRY.prp1], eax
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_IDENTIFY
mov dword [esp + SQ_ENTRY.cdw0], eax
mov al, [cns]
mov byte [esp + SQ_ENTRY.cdw10], al
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
add esp, sizeof.SQ_ENTRY
stdcall nvme_poll, esi
pop esi
ret
endp
; See page 101 of the NVMe 1.4 specification for reference
proc create_io_completion_queue stdcall, pci:dword, prp1:dword, qid:dword, ien:byte
push esi
mov esi, [pci]
mov dword [esi + pcidev.spinlock], 1
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_CRE_IO_COMPLETION_QUEUE
mov dword [esp + SQ_ENTRY.cdw0], eax
mov eax, [prp1]
mov dword [esp + SQ_ENTRY.prp1], eax
mov eax, (CQ_ENTRIES - 1) shl 16 ; CDW10.QSIZE (0's based)
or eax, [qid] ; CDW10.QID
mov dword [esp + SQ_ENTRY.cdw10], eax
movzx eax, [ien] ; CDW11.IEN
or eax, 0x1 ; CDW11.PC
; Don't set CDW11.IV since we're not using MSI-X or MSI vector
mov dword [esp + SQ_ENTRY.cdw11], eax
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
add esp, sizeof.SQ_ENTRY
stdcall nvme_poll, esi
pop esi
ret
endp
; See page 103-104 of the NVMe 1.4 specification for reference
proc create_io_submission_queue stdcall, pci:dword, prp1:dword, qid:dword, cqid:word
push esi
mov esi, [pci]
mov dword [esi + pcidev.spinlock], 1
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_CRE_IO_SUBMISSION_QUEUE
mov dword [esp + SQ_ENTRY.cdw0], eax
mov eax, [prp1]
mov dword [esp + SQ_ENTRY.prp1], eax
mov eax, (SQ_ENTRIES - 1) shl 16 ; CDW10.QSIZE (0's based)
or eax, [qid]
mov dword [esp + SQ_ENTRY.cdw10], eax
movzx eax, [cqid]
shl eax, 16 ; CDW11.CQID
or eax, 0x1 ; CDW11.PC (always set this to 1 as some devices may not support non-contiguous pages)
; TODO: Set CDW10.QPRIO
mov dword [esp + SQ_ENTRY.cdw11], eax
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
add esp, sizeof.SQ_ENTRY
stdcall nvme_poll, esi
pop esi
ret
endp
; See page 95-96 of the NVMe 1.4 specification for reference
proc abort stdcall, pci:dword, cid:word, sqid:word
push esi
mov esi, [pci]
mov dword [esi + pcidev.spinlock], 1
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_ABORT
mov dword [esp + SQ_ENTRY.cdw0], eax
movzx eax, [cid]
shl eax, 16
mov ax, [sqid]
mov dword [esp + SQ_ENTRY.cdw10], eax
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
add esp, sizeof.SQ_ENTRY
stdcall nvme_poll, esi
pop esi
ret
endp
; See page 205 of the NVMe 1.4 specification for reference
proc set_features stdcall, pci:dword, prp1:dword, fid:byte, cdw11:dword
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
stdcall set_cdw0, [pci], ADMIN_QUEUE, ADM_CMD_SET_FEATURES
mov dword [esp + SQ_ENTRY.cdw0], eax
mov eax, [prp1]
mov dword [esp + SQ_ENTRY.prp1], eax
movzx eax, [fid]
mov dword [esp + SQ_ENTRY.cdw10], eax
mov eax, [cdw11]
mov dword [esp + SQ_ENTRY.cdw11], eax
stdcall sqytdbl_write, [pci], ADMIN_QUEUE, esp
add esp, sizeof.SQ_ENTRY
ret
endp
; See page 105 of the NVMe 1.4 specification for reference
proc delete_io_completion_queue stdcall, pci:dword, qid:word
push esi
mov esi, [pci]
mov dword [esi + pcidev.spinlock], 1
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_DEL_IO_COMPLETION_QUEUE
mov dword [esp + SQ_ENTRY.cdw0], eax
mov ax, [qid]
mov word [esp + SQ_ENTRY.cdw10], ax
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
add esp, sizeof.SQ_ENTRY
stdcall nvme_poll, esi
pop esi
ret
endp
; See page 114-116 of the NVMe 1.4 specification for reference
proc get_features stdcall, pci:dword, prp1:dword, sel:byte, fid:byte
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
stdcall set_cdw0, [pci], ADMIN_QUEUE, ADM_CMD_GET_FEATURES
mov dword [esp + SQ_ENTRY.cdw0], eax
movzx eax, [sel]
and eax, 111b
shl eax, 8 ; CDW10.SEL
mov al, [fid] ; CDW10.FID
mov dword [esp + SQ_ENTRY.cdw10], eax
mov eax, [prp1]
mov dword [esp + SQ_ENTRY.prp1], eax
; TODO: Implement CDW14.UUID?
stdcall sqytdbl_write, [pci], ADMIN_QUEUE, esp
add esp, sizeof.SQ_ENTRY
ret
endp
; See page 105-106 of the NVMe 1.4 specification for reference
proc delete_io_submission_queue stdcall, pci:dword, qid:word
push esi
mov esi, [pci]
mov dword [esi + pcidev.spinlock], 1
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_DEL_IO_SUBMISSION_QUEUE
mov dword [esp + SQ_ENTRY.cdw0], eax
mov ax, [qid]
mov word [esp + SQ_ENTRY.cdw10], ax
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
add esp, sizeof.SQ_ENTRY
stdcall nvme_poll, esi
pop esi
ret
endp
; See page 258-261 (read) and 269-271 (write) of the NVMe 1.4 specification for reference
proc nvme_io_rw stdcall, pci:dword, qid:word, nsid:dword, prps:qword, slba:qword, nlb:dword, opcode:dword
; TODO: Use IDENTC.NOIOB to construct read/write commands that don't
; cross the I/O boundary to achieve optimal performance
;
; TODO: Read AWUN/NAWUN
sub esp, sizeof.SQ_ENTRY
mov eax, esp
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
movzx ecx, [qid]
stdcall set_cdw0, [pci], ecx, [opcode]
mov dword [esp + SQ_ENTRY.cdw0], eax ; CDW0
mov eax, dword [prps]
mov dword [esp + SQ_ENTRY.prp1], eax
mov eax, dword [prps + 4]
mov dword [esp + SQ_ENTRY.prp2], eax
mov eax, [nsid]
mov dword [esp + SQ_ENTRY.nsid], eax
mov eax, dword [slba] ; slba_lo
mov dword [esp + SQ_ENTRY.cdw10], eax
mov eax, dword [slba + 4] ; slba_hi
mov dword [esp + SQ_ENTRY.cdw11], eax
mov eax, [nlb]
mov word [esp + SQ_ENTRY.cdw12], ax
movzx ecx, [qid]
stdcall sqytdbl_write, [pci], ecx, esp
add esp, sizeof.SQ_ENTRY
ret
endp
-34
View File
@@ -1,34 +0,0 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
proc memsetdz stdcall, dest:dword, sz:dword
push edi
mov edi, [dest]
mov ecx, [sz]
xor eax, eax
rep stosd
pop edi
ret
endp
proc memcpyd stdcall, dest:dword, src:dword, sz:dword
push esi edi
mov esi, [src]
mov edi, [dest]
mov ecx, [sz]
rep movsd
pop edi esi
ret
endp
File diff suppressed because it is too large. Load diff
-602
View File
@@ -1,602 +0,0 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
define LOG2 bsr
; NVMe Controller Versions
VS100 = 0x00010000 ; (v1.0.0)
VS110 = 0x00010100 ; (v1.1.0)
VS120 = 0x00010200 ; (V1.2.0)
VS121 = 0x00010201 ; (v1.2.1)
VS130 = 0x00010300 ; (v1.3.0)
VS140 = 0x00010400 ; (v1.4.0)
NVM_MPS = 0 ; Memory Page Size (2 ^ (12 + MPS))
NVM_ASQS = 64 ; Admin Submission Queue Size
NVM_ACQS = NVM_ASQS ; Admin Completion Queue Size
LAST_QUEUE_ID = 1 ; Index of the last queue
SQ_ENTRIES = NVM_ASQS ; I/O and Admin Submission Queue Size
CQ_ENTRIES = NVM_ACQS ; I/O and Admin Completion Queue Size
PAGE_SIZE = 4096 shl NVM_MPS ; Use 4KiB pages
SUPPORTED_LBADS = 9 ; KolibriOS only supports LBADS of 512, later on we may remove this restriction
SQ_ALLOC_SIZE = 0x1000
CQ_ALLOC_SIZE = 0x1000
QUEUE_ALLOC_SIZE = SQ_ALLOC_SIZE + CQ_ALLOC_SIZE
; Upper bound on the number of memory pages a single I/O command may span. A PRP
; list holds PAGE_SIZE/8 entries, so staying well below that keeps every transfer
; describable by one non-chained PRP list.
MAX_PRP_PAGES = 256
PCI_MAX_CAPS = 48 ; a config space holds at most 48 capabilities
; Registers take the first page of the BAR, the doorbells start at 0x1000 with a
; stride of 4 << CAP.DSTRD bytes; this much is mapped before CAP.DSTRD is known.
MMIO_MIN_MAP_SIZE = 0x2000
; How long to wait on the controller, in milliseconds.
CTRL_POLL_MS = 10
SHUTDOWN_WAIT_MS = 5000
IO_TIMEOUT_MS = 30000 ; how long a single I/O command may take
POLL_SPINS = 64 ; lock checks between two looks at the completion queue
IO_BUSY_ROUNDS = 20000 ; rounds to spend spinning before falling back to sleeping
MSIXCAP_CID = 0x11
MSIXCAP_MXE = 1 shl 15 ; MSI-X Enable bit
MSICAP_CID = 0x05
MSICAP_MSIE = 1 ; MSI Enable bit
ADMIN_QUEUE = 0 ; Admin Queue ID
IEN_ON = 2
IEN_OFF = 0
; Opcodes for NVM commands
NVM_CMD_FLUSH = 0x00
NVM_CMD_WRITE = 0x01
NVM_CMD_READ = 0x02
NVM_CMD_WRITE_UNCORRECTABLE = 0x04
NVM_CMD_COMPARE = 0x05
NVM_CMD_WRITE_ZEROES = 0x08
NVM_CMD_DATASET_MANAGEMENT = 0x09
NVM_CMD_VERIFY = 0x0C
NVM_CMD_RESERVATION_REG = 0x0D
NVM_CMD_RESERVATION_REPORT = 0x0E
NVM_CMD_RESERVATION_ACQUIRE = 0x11
NVM_CMD_RESERVATION_RELEASE = 0x15
NVM_CMD_COPY = 0x19
; Opcodes for admin commands (Page 94 of NVMe 1.4 spec)
ADM_CMD_DEL_IO_SUBMISSION_QUEUE = 0x00
ADM_CMD_CRE_IO_SUBMISSION_QUEUE = 0x01
ADM_CMD_GET_LOG_PAGE = 0x02
ADM_CMD_DEL_IO_COMPLETION_QUEUE = 0x04
ADM_CMD_CRE_IO_COMPLETION_QUEUE = 0x05
ADM_CMD_IDENTIFY = 0x06
ADM_CMD_ABORT = 0x08
ADM_CMD_SET_FEATURES = 0x09
ADM_CMD_GET_FEATURES = 0x0A
; fuse (fused operation): In a fused operation, a complex command is created by 'fusing' together
; two simpler commands. This field specifies whether this command is part
; of a fused operation, and if so, which command it is in the sequence:
; 00b -> Normal operation
; 01b -> Fused operation, first command
; 10b -> Fused operation, second command
; 11b -> Reserved
NO_FUSE = 0
FUSE_OP_FIRST_CMD = 1 shl 8
FUSE_OP_SECOND_CMD = 2 shl 8
; sel (PRP or SGL for data transfer): This field specifies whether PRPs or SGLs are used for any
; data transfer associated with the command. PRPs shall be
; used for all Admin commands for NVMe over PCIe implementations.
; SGLs shall be used for all Admin and I/O commands for NVMe over
; Fabrics implementations (i.e., field set to 01b):
; 00b -> PRPs are used for this transfer
; 01b -> SGLs are used for this transfer, MPTR will contain address of
; a single contiguous physical buffer that is byte aligned
; 10b -> SGLs are used for this transfer. MPTR will contain address of
; an SGL segment containing exactly one SGL descriptor that is
; QWORD aligned
; 11b -> Reserved
SEL_PRP = 0
SEL_SGL = 1 shl 14
; Controller or Namespace Structure (CNS) specifies the information to be returned to the host.
CNS_IDNS = 0x0 ; Namespace data structure (NSID)
CNS_IDCS = 0x1 ; Controller data structure
CNS_ANIDL = 0x2 ; Active namespace ID list (NSID)
CNS_NIDL = 0x3 ; Namespace identification descriptor list (NSID)
CNS_NVM_SL = 0x4 ; NVM Set List
; Optional Admin Command Support (OACS) values
OACS_SEC_SEN_RECV_SUPPORTED = 1 shl 0
OACS_FMT_NVM_SUPPORTED = 1 shl 1
OACS_FIRM_COMDL_SUPPORTED = 1 shl 2
OACS_NSMAN_SUPPORTED = 1 shl 3
; scope is all attached namespaces or all namespaces in NVM subsystem
NSID_BROADCAST = 0xFFFFFFFF
NSSRC_RESET = 0x4E564D65 ; "NVMe" (initiates a NVMe subsystem reset)
; NVMe Capabilities
CAP_MQES = 0xffff
CAP_CQR = 1 shl 16
CAP_AMS = (1 shl 17) or (1 shl 18)
CAP_TO = 0xff000000
CAP_DSTRD = 1 or (1 shl 1) or (1 shl 2) or (1 shl 3)
CAP_NSSRS = 1 shl 4
CAP_CSS_NVM_CMDSET = 1 shl 5
CAP_CSS_NOIO = 1 shl 12
CAP_BPS = 1 shl 13
CAP_CPS_COSCOP = 1 shl 15
CAP_CPS_DOSCOP = 1 shl 16
CAP_CPS_NVMSCOP = CAP_CPS_COSCOP or CAP_CPS_DOSCOP
CAP_MPSMIN = 0xf shl 16 ; CAP bits 51:48
CAP_MPSMAX = 0xf shl 20 ; CAP bits 55:52
CAP_PMRS = 1 shl 24
CAP_CMBS = 1 shl 25
CAP_NSSS = 1 shl 27
CAP_CRMS_CRWMS = 1 shl 28
CAP_CRMS_CRIMS = 1 shl 29
; Controller Configuration Bits
CC_EN = 1
CC_CSS = (1 shl 4) or (1 shl 5) or (1 shl 6)
CC_MPS = (1 shl 7) or (1 shl 8) or (1 shl 9) or (1 shl 10)
CC_AMS = (1 shl 11) or (1 shl 12) or (1 shl 13)
CC_SHN = (1 shl 14) or (1 shl 15)
CC_IOSQES = (1 shl 16) or (1 shl 17) or (1 shl 18) or (1 shl 19)
CC_IOCQES = (1 shl 20) or (1 shl 21) or (1 shl 22) or (1 shl 23)
CC_CRIME = 1 shl 24
CC_SHN_NORMAL_SHUTDOWN = 1 shl 14
CC_SHN_ABRUPT_SHUTDOWN = 1 shl 15
CC_DEFAULT_IOSQES = LOG2 sizeof.SQ_ENTRY shl 16
CC_DEFAULT_IOCQES = LOG2 sizeof.CQ_ENTRY shl 20
; Completion Queue Entry Status Field Values
CQ_PHASE_TAG = 1 shl 0
CQ_STATUS_SC = 0xfe
CQ_STATUS_SCT = (1 shl 9) or (1 shl 10) or (1 shl 11)
CQ_STATUS_CRD = (1 shl 12) or (1 shl 13)
CQ_STATUS_M = 1 shl 14
CQ_STATUS_DNR = 1 shl 15
; Completion Queue Entry Status Field - Status Code Type Values
CQ_STATUS_SCT_GCS = 0x0 ; Generic Command Status
CQ_STATUS_SCT_CSS = 0x1 ; Command Specific Status
CQ_STATUS_SCT_MADIE = 0x2 ; Media and Data Integrity Errors
CQ_STATUS_SCT_PRS = 0x3 ; Path Related Status
; Completion Queue Entry Status Field - Status Code Generic Command Values
CQ_STATUS_SC_GCS_SUCCESS = 0x00 ; Successful Completion
CQ_STATUS_SC_GCS_ICOP = 0x01 ; Invalid Command Opcode
CQ_STATUS_SC_GCS_IFIC = 0x02 ; Invalid Field in Command
CQ_STATUS_SC_GCS_CIDC = 0x03 ; Command ID Conflict
CQ_STATUS_SC_GCS_DTE = 0x04 ; Data Transfer Error
CQ_STATUS_SC_GCS_CAPLN = 0x05 ; Commands Aborted due to Power Loss Notification
CQ_STATUS_SC_GCS_INERR = 0x06 ; Internal Error
CQ_STATUS_SC_GCS_CAR = 0x07 ; Command Abort Requested
CQ_STATUS_SC_GCS_CASQD = 0x08 ; Command Aborted due to SQ Deletion
CQ_STATUS_SC_GCS_CAFFC = 0x09 ; Command Aborted due to Failed Fused Command
CQ_STATUS_SC_GCS_CAMFC = 0x0A ; Command Aborted due to Missing Fused Command
CQ_STATUS_SC_GCS_INNOF = 0x0B ; Invalid Namespace or Format
CQ_STATUS_SC_GCS_CSE = 0x0C ; Command Sequence Error
CQ_STATUS_SC_GCS_INSGL = 0x0D ; Invalid SGL Segment Descriptor
CQ_STATUS_SC_GCS_INNSGL = 0x0E ; Invalid Number of SGL Descriptors
CQ_STATUS_SC_GCS_OPDEN = 0x15 ; Operation Denied
CQ_STATUS_SC_GCS_NSIWP = 0x20 ; Namespace is Write Protected
CQ_STATUS_SC_GCS_CINT = 0x21 ; Command Interrupted
CQ_STATUS_SC_GCS_TTE = 0x22 ; Transient Transport Error
; Completion Queue Entry Status Field - Status Code Media and Data Integrity Errors
CQ_STATUS_SC_MADIE_WF = 0x80 ; Write Fault
CQ_STATUS_SC_MADIE_URE = 0x81 ; Unrecovered Read Error
CQ_STATUS_SC_MADIE_ACDEN = 0x86 ; Access Denied
CQ_STATUS_SC_MADIE_DOULB = 0x87 ; Deallocated or Unwritten Logical Block
; Controller Status (CSTS) Values
CSTS_RDY = 1
CSTS_CFS = 1 shl 1
CSTS_SHST = (1 shl 2) or (1 shl 3)
CSTS_NSSRO = 1 shl 4
CSTS_PP = 1 shl 5
CSTS_SHST_SHUTDOWN_OCCURRING = 1 shl 2
CSTS_SHST_SHUTDOWN_COMPLETE = 1 shl 3
; Admin Queue Attributes (AQA) Values
AQA_ASQS = 0xfff
AQA_ACQS = 0xfff shl 16
; CDW10.SEL Values (Page 115 of NVMe 1.4 specification)
CDW10_SEL_CURRENT = 000b
CDW10_SEL_DEFAULT = 001b
CDW10_SEL_SAVED = 010b
CDW10_SEL_SUPPORTED_CAPABILITIES = 011b
; Feature Identifiers (FID) Values (Page 206 of NVMe 1.4 specification)
; Used in Get/Set Features Commands
FID_ARBITRATION = 0x01
FID_POWER_MANAGEMENT = 0x02
FID_LBA_RANGE_TYPE = 0x03
FID_TEMPERATURE_THRESHOLD = 0x04
FID_ERROR_RECOVERY = 0x05
FID_VOLATILE_WRITE_CACHE = 0x06
FID_NUMBER_OF_QUEUES = 0x07
FID_INTERRUPT_COALESCING = 0x08
FID_INTERRUPT_VECTOR_CONFIGURATION = 0x09
FID_WRITE_ATOMICITY_NORMAL = 0x0A
FID_ASYNCHRONOUS_EVENT_CONFIGURATION = 0x0B
FID_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C
FID_HOST_MEMORY_BUFFER = 0x0D
FID_TIMESTAMP = 0x0E
FID_KEEP_ALIVE_TIMER = 0x0F
FID_HOST_CONTROLLED_THERMAL_MANAGEMENT = 0x10
FID_NON_OPERATIONAL_POWER_STATE_CONFIG = 0x11
FID_READ_RECOVERY_LEVEL_CONFIG = 0x12
FID_PREDICTABLE_LATENCY_MODE_CONFIG = 0x13
FID_PREDICTABLE_LATENCY_MODE_WINDOW = 0x14
FID_LBA_STATUS_INFORMATION_REPORT_INTERVAL = 0x15
FID_HOST_BEHAVIOR_SUPPORT = 0x16
FID_SANITIZE_CONFIG = 0x17
FID_ENDURANCE_GROUP_EVENT_CONFIGURATION = 0x18
; NVM Command Set Specific - FID
FID_SOFTWARE_PROGRESS_MARKER = 0x80
FID_HOST_IDENTIFIER = 0x81
FID_RESERVATION_NOTIFICATION_MASK = 0x82
FID_RESERVATION_PERSISTENCE = 0x83
FID_NAMESPACE_WRITE_PROTECTION_CONFIG = 0x84
; Get Log Page - Log Page Identifiers (Page 118-119 of NVMe 1.4 specification)
LID_ERROR_INFORMATION = 0x01
LID_SMARTHEALTH_INFORMATION = 0x02
LID_FIRMWARE_SLOT_INFORMATION = 0x03
LID_CHANGED_NAMESPACE_LIST = 0x04
LID_COMMANDS_SUPPORTED_AND_EFFECTS = 0x05
LID_DEVICE_SELF_TEST = 0x06
LID_TELEMETRY_HOST_INITIATED = 0x07
LID_TELEMETRY_CONTROLLER_INITIATED = 0x08
LID_ENDURANCE_GROUP_INFORMATION = 0x09
LID_PREDICTABLE_LATENCY_PER_NVM_SET = 0x0A
LID_PREDICTABLE_LATENCY_EVENT_AGGREGATE = 0x0B
LID_ASYMMETRIC_NAMESPACE_ACCESS = 0x0C
LID_PERSISTENT_EVENT_LOG = 0x0D
LID_LBA_STATUS_INFORMATION = 0x0E
LID_ENDURANCE_GROUP_EVENT_AGGREGATE = 0x0F
; I/O Command Set Specific - Log Page Identifiers
LID_RESERVATION_NOTIFICATION = 0x80
LID_SANITIZE_STATUS = 0x81
; Controller Type Values
CNTRLTYPE_IO_CONTROLLER = 0x1
CNTRLTYPE_DISCOVERY_CONTROLLER = 0x2
CNTRLTYPE_ADMIN_CONTROLLER = 0x3
struct NVME_MMIO
CAP dq ? ; Controller Capabilities
VS dd ? ; Version
INTMS dd ? ; Interrupt Mask Set
INTMC dd ? ; Interrupt Mask Clear
CC dd ? ; Controller Configuration
rd 1 ; Reserved
CSTS dd ? ; Controller Status
NSSR dd ? ; NVM Subsystem Reset
AQA dd ? ; Admin Queue Attributes
ASQ dq ? ; Admin Submission Queue Base Address
ACQ dq ? ; Admin Completion Queue Base Address
CMBLOC dd ? ; Controller Memory Buffer Location
CMBSZ dd ? ; Controller Memory Buffer Size
BPINFO dd ? ; Boot Partition Information
BPRSEL dd ? ; Boot Partition Read Select
BPMBL dq ? ; Boot Partition Memory Buffer Location
CMBMSC dd ? ; Controller Memory Buffer Memory Space
CMBSTS dd ? ; Controller Memory Buffer Status
rb 3492 ; Reserved
PMRCAP dd ? ; Persistent Memory Capabilities
PMRCTL dd ? ; Persistent Memory Region Control
PMRSTS dd ? ; Persistent Memory Region Status
PMREBS dd ? ; Persistent Memory Region Elasticity Buffer Size
PMRSWTP dd ? ; Persistent Memory Region Sustained Write Throughput
PMRMSC dq ? ; Persistent Memory Region Controller Memory Space Control
rb 484 ; Reserved
SQ0TDBL dd ? ; Submission Queue 0 Tail Doorbell (Admin)
ends
; Submission Queue Entry (64 bytes)
struct SQ_ENTRY
cdw0 dd ?
nsid dd ?
cdw2 dd ?
cdw3 dd ?
mptr dq ?
prp1 dq ?
prp2 dq ?
cdw10 dd ?
cdw11 dd ?
cdw12 dd ?
cdw13 dd ?
cdw14 dd ?
cdw15 dd ?
ends
; Completion Queue Entry (16 bytes) - See page 77 of the NVMe 1.4 spec
struct CQ_ENTRY
cdw0 dd ?
rd 1 ; reserved
sqhd dw ?
sqid dw ?
cid dw ?
status dw ?
ends
struct NSINFO
capacity dq ?
size dq ?
nsid dd ?
pci dd ?
lbads db ?
features db ?
ends
struct pcidev
bus db ?
devfn db ?
rb 2 ; align
num dd ?
io_addr dd ?
queue_entries dd ?
version dd ?
nsid dd ?
spinlock dd ?
nsinfo dd ?
last_status dd ? ; status field of the last completion, 0 when all went well
nn dd ?
last_cdw0 dd ? ; command specific result of the last completion
max_sectors dd ? ; biggest transfer a single I/O command may carry
disk dd ? ; handle from DiskAdd, 0 if none
pcidev dd ? ; the kernel's PCIDEV, claimed through its owner field
iolock MUTEX ; taken by whoever is using the I/O queue
dstrd db ?
mdts db ? ; Maximum Data Transfer Size, in 2^(12+MPSMIN) byte units
ready db ? ; 1 while the controller serves I/O; 0 before, after cleanup or once it hung
stuck db ? ; 1 if it hung and would not even go idle, so it may still DMA
hung db ? ; 1 once any command timed out, init and cleanup included
rb 3 ; align
ends
TOTAL_PCIDEVS = 4
TOTAL_PCIDEVS_MALLOC_SZ = TOTAL_PCIDEVS * sizeof.pcidev
struct NVM_QUEUE_ENTRY
tail dw ?
head dw ?
sq_ptr dd ?
cq_ptr dd ?
phase db ? ; phase tag the next completion of this queue will carry
rb 19 ; pad to a power of two, the queue index is shifted by LOG2 of it
ends
; Identify Controller Data Structure
struct IDENTC
vid dw ?
ssvid dw ?
sn dt ?, ?
mn rt 4
fr dq ?
rab db ?
ieee db ?, ?, ?
cmic db ?
mdts db ?
cntlid dw ?
ver dd ?
rtd3r dd ?
rtd3e dd ?
oaes dd ?
ctratt dd ?
rrls dw ?
rb 9 ; reserved
cntrltype db ?
fguid dq ?, ?
crdt1 dw ?
crdt2 dw ?
crdt3 dw ?
rb 106 ; reserved
rb 16 ; reserved (NVMMI)
oacs dw ?
acl db ?
aerl db ?
frmw db ?
lpa db ?
elpe db ?
npss db ?
avscc db ?
apsta db ?
wctemp dw ?
cctemp dw ?
mtfa dw ?
hmpre dd ?
hmmin dd ?
tnvmcap dq ?, ?
unvmcap dq ?, ?
rpmbs dd ?
edstt dw ?
dsto db ?
fwug db ?
kas dw ?
hctma dw ?
mntmt dw ?
mxtmt dw ?
sanicap dd ?
hmminds dd ?
hmmaxd dw ?
nsetidmax dw ?
endgidmax dw ?
anatt db ?
anacap db ?
anagrpmax dd ?
nanagrpid dd ?
pels dd ?
rb 156
sqes db ?
cqes db ?
maxcmd dw ?
nn dd ?
oncs dw ?
fuses dw ?
fna db ?
vwc db ?
awun dw ?
awupf dw ?
nvscc db ?
nwpc db ?
acwu dw ?
rb 2
sgls dd ?
mnan dd ?
rb 224
subnqn rq 32
rb 768
rb 256
psd0 rq 4
psd1 rq 4
psd2 rq 4
psd3 rq 4
psd4 rq 4
psd5 rq 4
psd6 rq 4
psd7 rq 4
psd8 rq 4
psd9 rq 4
psd10 rq 4
psd11 rq 4
psd12 rq 4
psd13 rq 4
psd14 rq 4
psd15 rq 4
psd16 rq 4
psd17 rq 4
psd18 rq 4
psd19 rq 4
psd20 rq 4
psd21 rq 4
psd22 rq 4
psd23 rq 4
psd24 rq 4
psd25 rq 4
psd26 rq 4
psd27 rq 4
psd28 rq 4
psd29 rq 4
psd30 rq 4
psd31 rq 4
rb 1024
ends
; Identify Namespace Data Structure
struct IDENTN
nsze dq ?
ncap dq ?
nuse dq ?
nsfeat db ?
nlbaf db ?
flbas db ?
mc db ?
dpc db ?
dps db ?
nmic db ?
rescap db ?
fpi db ?
dlfeat db ?
nawun dw ?
nawupf dw ?
nacwu dw ?
nabsn dw ?
nabo dw ?
nabspf dw ?
noiob dw ?
nvmcap dq ?
dq ?
npwg dw ?
npwa dw ?
npdg dw ?
npda dw ?
nows dw ?
rb 18
anagrpid dd ?
rb 3
nsattr db ?
nvmsetid dw ?
endgid dw ?
nguid dq ?
dq ?
eui64 dq ?
lbaf0 dd ?
lbaf1 dd ?
lbaf2 dd ?
lbaf3 dd ?
lbaf4 dd ?
lbaf5 dd ?
lbaf6 dd ?
lbaf7 dd ?
lbaf8 dd ?
lbaf9 dd ?
lbaf10 dd ?
lbaf11 dd ?
lbaf12 dd ?
lbaf13 dd ?
lbaf14 dd ?
lbaf15 dd ?
rb 3904
ends
; Namespace Granularity List (CNS 16h - Page 199 of NVMe specification 1.4)
struct NSGRANLS
nga dd ?
nod db ?
rb 27 ; reserved
ngd0 dq ?, ?
ngd1 dq ?, ?
ngd2 dq ?, ?
ngd3 dq ?, ?
ngd4 dq ?, ?
ngd5 dq ?, ?
ngd6 dq ?, ?
ngd7 dq ?, ?
ngd8 dq ?, ?
ngd9 dq ?, ?
ngd10 dq ?, ?
ngd11 dq ?, ?
ngd12 dq ?, ?
ngd13 dq ?, ?
ngd14 dq ?, ?
ngd15 dq ?, ?
ends
assert NVM_ASQS = NVM_ACQS
assert SQ_ENTRIES = NVM_ASQS
assert CQ_ENTRIES = NVM_ACQS
assert NVM_MPS = 0
assert CTRL_POLL_MS mod 10 = 0 ; nvme_poll waits it out in 1/100 s ticks
assert PAGE_SIZE = 0x1000
assert sizeof.NVME_MMIO = 4096
assert sizeof.SQ_ENTRY = 64
assert sizeof.CQ_ENTRY = 16
assert sizeof.IDENTC = 4096
assert sizeof.IDENTN = 4096
assert sizeof.NSGRANLS = 288
assert sizeof.NVM_QUEUE_ENTRY = 32
-1
View File
@@ -139,7 +139,6 @@ import core,\
RegKeyboard,\
DelKeyboard,\
Sleep,\
Delay,\
GetTimerTicks,\
\
strncat,\
+5 -59
View File
@@ -1,4 +1,4 @@
SERIAL_COMPATIBLE_API_VER = 1 ; increments in case of breaking changes
SERIAL_COMPATIBLE_API_VER = 0 ; increments in case of breaking changes
SERIAL_API_GET_VERSION = 0
SERIAL_API_SRV_ADD_PORT = 1
@@ -9,7 +9,6 @@ SERIAL_API_CLOSE_PORT = 5
SERIAL_API_SETUP_PORT = 6
SERIAL_API_READ = 7
SERIAL_API_WRITE = 8
SERIAL_API_ENUM_PORTS = 9
SERIAL_API_ERR_PORT_INVALID = 1
SERIAL_API_ERR_PORT_BUSY = 2
@@ -30,9 +29,6 @@ SERIAL_CONF_STOP_BITS_2 = 2
SERIAL_CONF_FLOW_CTRL_NONE = 0
SERIAL_INFO_DRIVER_LEN = 16
SERIAL_INFO_DESCR_LEN = 64
struct SP_DRIVER
size dd ? ; size of this struct
startup dd ? ; int __stdcall (*startup)(void *drv_data, const struct serial_conf *conf);
@@ -50,20 +46,7 @@ struct SP_CONF
flow_ctrl db ?
ends
struct SP_PORT_INFO
size dd ? ; size of this struct
driver dd ? ; ASCIIZ driver name, e.g. "uart16550", "usb-cdc"
descr dd ? ; ASCIIZ description, may be NULL
ends
struct SP_PORT_ENUM_ENTRY
id dd ? ; unique port number (SERIAL_PORT.id)
busy dd ? ; 0 = free, non-zero = port is opened
driver rb SERIAL_INFO_DRIVER_LEN
descr rb SERIAL_INFO_DESCR_LEN
ends
proc serial_add_port stdcall, drv:dword, drv_data:dword, info:dword
proc serial_add_port stdcall, drv:dword, drv_data:dword
locals
handler dd ?
io_code dd ?
@@ -77,7 +60,7 @@ endl
mov [io_code], SERIAL_API_SRV_ADD_PORT
lea eax, [drv]
mov [input], eax
mov [inp_size], 12
mov [inp_size], 8
xor eax, eax
mov [output], eax
mov [out_size], eax
@@ -146,7 +129,7 @@ proc serial_port_init
ret
endp
proc serial_port_get_version stdcall uses ebx, version:dword
proc serial_port_get_version stdcall, version:dword
locals
.handler dd ?
.io_code dd ?
@@ -166,7 +149,7 @@ endl
lea ecx, [.handler]
mcall SF_SYS_MISC, SSF_CONTROL_DRIVER
ret
endp
@@ -314,43 +297,6 @@ endl
ret
endp
proc serial_port_enum stdcall uses ebx, buf:dword, buf_size:dword, \
total:dword, filled:dword
locals
.handler dd ?
.io_code dd ?
.input dd ?
.inp_size dd ?
.output dd ?
.out_size dd ?
endl
push [buf_size]
push [buf]
mov eax, [serial_drv_handle]
mov [.handler], eax
mov dword [.io_code], SERIAL_API_ENUM_PORTS
mov [.input], esp
mov dword [.inp_size], 8
sub esp, 8
mov [.output], esp
mov dword [.out_size], 8
lea ecx, [.handler]
mcall SF_SYS_MISC, SSF_CONTROL_DRIVER
pop ebx edx
cmp eax, -1
je .err
mov ecx, [total]
mov [ecx], ebx
mov ecx, [filled]
mov [ecx], edx
.err:
add esp, 8
ret
endp
align 4
serial_drv_name db "SERIAL", 0
serial_drv_handle dd ?
+5
View File
@@ -0,0 +1,5 @@
#SHS
echo Installing serial driver for kterm...
cp /kolibrios/utils/kterm/serial.sys /sys/drivers/
/sys/loaddrv serial
echo Serial driver successfully installed!
+7 -148
View File
@@ -44,8 +44,6 @@ struct SERIAL_PORT
rx_buf RING_BUF
tx_buf RING_BUF
conf SP_CONF
driver rb SERIAL_INFO_DRIVER_LEN ; ASCIIZ, copied from SP_PORT_INFO.driver in add_port
descr rb SERIAL_INFO_DESCR_LEN ; ASCIIZ, copied from SP_PORT_INFO.descr in add_port (may be empty)
ends
proc START c, reason:dword, cmdline:dword
@@ -59,7 +57,7 @@ proc START c, reason:dword, cmdline:dword
stdcall uart_probe, 0x2f8, 3
stdcall uart_probe, 0x3e8, 4
stdcall uart_probe, 0x2e8, 3
invoke RegService, serial_drv_name, service_proc
invoke RegService, drv_name, service_proc
ret
.fail:
@@ -77,7 +75,7 @@ srv_calls:
dd service_proc.setup
dd service_proc.read
dd service_proc.write
dd service_proc.enum_ports
; TODO enumeration
srv_calls_end:
proc service_proc stdcall uses ebx esi edi, ioctl:dword
@@ -99,13 +97,11 @@ proc service_proc stdcall uses ebx esi edi, ioctl:dword
; in:
; +0: driver
; +4: driver data
; +8: port info (SP_PORT_INFO*)
cmp [edx + IOCTL.inp_size], 12
cmp [edx + IOCTL.inp_size], 8
jb .err
mov ebx, [edx + IOCTL.input]
mov ecx, [ebx]
mov edx, [ebx + 4]
mov ebx, [ebx + 8]
call add_port
ret
@@ -141,7 +137,6 @@ proc service_proc stdcall uses ebx esi edi, ioctl:dword
; +4 addr to SERIAL_CONF
; out:
; +0 port handle if success
; eax = 0 if success, otherwise an error code SERIAL_API_ERR_*
cmp [edx + IOCTL.inp_size], 8
jb .err
cmp [edx + IOCTL.out_size], 4
@@ -225,60 +220,25 @@ proc service_proc stdcall uses ebx esi edi, ioctl:dword
mov [ebx], ecx
ret
.enum_ports:
; in:
; +0 output buffer (array of SP_PORT_ENUM_ENTRY), may be NULL
; +4 output buffer size in bytes
; out:
; +0 total number of ports in the system
; +4 number of entries actually filled into the buffer
; eax = 0 if success, -1 otherwise
cmp [edx + IOCTL.inp_size], 8
jb .err
cmp [edx + IOCTL.out_size], 8
jb .err
mov ebx, [edx + IOCTL.input]
push edx
mov eax, [ebx]
mov edx, [ebx + 4]
call sp_enum
pop edx
mov ebx, [edx + IOCTL.output]
mov [ebx], eax
mov [ebx + 4], ecx
xor eax, eax
ret
.err:
or eax, -1
ret
endp
; struct SERIAL_PORT __fastcall *add_port(const struct SP_DRIVER *drv, const void *drv_data);
align 4
; @param ecx pointer to SP_DRIVER
; @param edx driver-specific argument
; @param ebx pointer to SP_PORT_INFO
; @return SERIAL_PORT descriptor
proc add_port uses edi
DEBUGF L_DBG, "serial.sys: add port drv=%x drv_data=%x info=%x\n", ecx, edx, ebx
DEBUGF L_DBG, "serial.sys: add port drv=%x drv_data=%x\n", ecx, edx
mov eax, [ecx + SP_DRIVER.size]
cmp eax, sizeof.SP_DRIVER
jne .fail
test ebx, ebx
jz .fail
mov eax, [ebx + SP_PORT_INFO.size]
cmp eax, sizeof.SP_PORT_INFO
jne .fail
; alloc memory for serial port descriptor
push ecx
push edx
push ebx
movi eax, sizeof.SERIAL_PORT
invoke Kmalloc
pop ebx
pop edx
pop ecx
test eax, eax
@@ -292,17 +252,6 @@ proc add_port uses edi
invoke MutexInit
and [edi + SERIAL_PORT.con], 0
; copy port info strings
mov eax, [ebx + SP_PORT_INFO.driver]
lea edx, [edi + SERIAL_PORT.driver]
mov ecx, SERIAL_INFO_DRIVER_LEN
call copy_bounded_str
mov eax, [ebx + SP_PORT_INFO.descr]
lea edx, [edi + SERIAL_PORT.descr]
mov ecx, SERIAL_INFO_DESCR_LEN
call copy_bounded_str
mov ecx, port_list_mutex
invoke MutexLock
@@ -333,35 +282,7 @@ proc add_port uses edi
endp
align 4
; copies an ASCIIZ string into a fixed-size buffer: copies up to (size - 1)
; bytes or until the NUL, then zero-pads the rest of the buffer
; @param eax source ASCIIZ ptr, may be NULL
; @param edx dest buffer ptr
; @param ecx dest buffer size in bytes, must be >= 1
proc copy_bounded_str uses esi edi
mov esi, eax
mov edi, edx
dec ecx ; reserve the last byte for the NUL terminator
.copy:
test ecx, ecx
jz .pad
test esi, esi
jz .pad
lodsb
test al, al
jz .pad
stosb
dec ecx
jmp .copy
.pad:
inc ecx ; account for the reserved NUL byte
xor al, al
rep stosb
ret
endp
align 4
; @param ecx serial port descriptor
; u32 __fastcall *remove_port(struct SERIAL_PORT *port);
proc remove_port uses esi
mov esi, ecx
mov ecx, port_list_mutex
@@ -736,69 +657,7 @@ proc sp_write
ret
endp
align 4
; @param eax buf
; @param edx buf_size (bytes)
; @return eax total port count in the system
; ecx entries filled into buf
proc sp_enum uses ebx esi edi
mov ecx, eax
mov eax, edx
xor edx, edx
mov ebx, sizeof.SP_PORT_ENUM_ENTRY
div ebx
; eax max entries count
mov edi, ecx
imul eax, sizeof.SP_PORT_ENUM_ENTRY
add eax, ecx
mov edx, eax ; end-of-buffer boundary
xor ebx, ebx ; total port count
xor ecx, ecx ; filled count
push ecx edx
mov ecx, port_list_mutex
invoke MutexLock
pop edx ecx
mov esi, port_list
.next:
mov esi, [esi + SERIAL_PORT.fd]
cmp esi, port_list
jz .done
inc ebx
cmp edi, edx
jae .next
mov eax, [esi + SERIAL_PORT.id]
mov [edi + SP_PORT_ENUM_ENTRY.id], eax
xor eax, eax
cmp dword [esi + SERIAL_PORT.con], 0
setnz al
mov [edi + SP_PORT_ENUM_ENTRY.busy], eax
push ecx esi edi
lea esi, [esi + SERIAL_PORT.driver]
lea edi, [edi + SP_PORT_ENUM_ENTRY.driver]
mov ecx, (SERIAL_INFO_DRIVER_LEN + SERIAL_INFO_DESCR_LEN) / 4
rep movsd
pop edi esi ecx
add edi, sizeof.SP_PORT_ENUM_ENTRY
inc ecx
jmp .next
.done:
push ecx
mov ecx, port_list_mutex
invoke MutexUnlock
pop ecx
mov eax, ebx
ret
endp
drv_name db 'SERIAL', 0
include_debug_strings
align 4
-9
View File
@@ -169,7 +169,6 @@ proc uart_probe stdcall uses ebx esi edi, io_addr:dword, irqn:dword
; register port
lea ecx, [uart_drv]
mov edx, edi
lea ebx, [uart_port_info]
call add_port
test eax, eax
jz .free_desc ; TODO detach_int_handler?
@@ -407,11 +406,3 @@ uart_drv:
dd uart_reconf
dd uart_tx
uart_drv_end:
align 4
uart_port_info:
dd uart_port_end - uart_port_info
dd uart_port_name
dd 0
uart_port_end:
uart_port_name db 'uart16550', 0
+310 -203
View File
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2026. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; FTDI chips driver for KolibriOS ;;
@@ -15,11 +15,10 @@
format PE DLL native 0.05
entry START
L_DBG = 1
L_ERR = 2
DEBUG = 1
__DEBUG__ = 1
__DEBUG_LEVEL__ = L_ERR
__DEBUG_LEVEL__ = 1
node equ ftdi_context
node.next equ ftdi_context.next_context
@@ -123,10 +122,9 @@ TYPE_232H=6
TYPE_230X=7
;strings
my_driver db 'usbftdi',0
my_driver db 'usbother',0
serial_driver db 'SERIAL',0
nomemory_msg db 'ftdi: no memory',13,10,0
ftdi_port_name db 'ftdi',0
nomemory_msg db 'K : no memory',13,10,0
; Structures
struct ftdi_context
@@ -202,13 +200,10 @@ endp
proc AddDevice stdcall uses ebx esi edi, .config_pipe:DWORD, .config_descr:DWORD, .interface:DWORD
locals
.pinfo rb sizeof.SP_PORT_INFO
endl
invoke USBGetParam, [.config_pipe], 0
mov edx, eax
DEBUGF L_DBG, 'ftdi: Detected device vendor: 0x%x\n', [eax+usb_descr.idVendor]
DEBUGF 2,'K : Detected device vendor: 0x%x\n', [eax+usb_descr.idVendor]
cmp word[eax+usb_descr.idVendor], 0x0403
jnz .notftdi
mov eax, sizeof.ftdi_context
@@ -219,7 +214,7 @@ endl
invoke SysMsgBoardStr
jmp .nothing
@@:
DEBUGF L_DBG, 'ftdi: Adding struct to list 0x%x\n', eax
DEBUGF 2,'K : Adding struct to list 0x%x\n', eax
call linkedlist_add
mov ebx, [.config_pipe]
@@ -238,7 +233,7 @@ endl
jmp .slow
mov cx, [edx+usb_descr.bcdDevice]
DEBUGF L_DBG, 'ftdi: Chip type 0x%x\n', ecx
DEBUGF 2, 'K : Chip type 0x%x\n', ecx
cmp cx, 0x400
jnz @f
mov [eax + ftdi_context.chipType], TYPE_BM
@@ -292,13 +287,8 @@ endl
mov eax, [serial_drv_entry]
test eax, eax
jz @f
mov dword [.pinfo + SP_PORT_INFO.size], sizeof.SP_PORT_INFO
mov dword [.pinfo + SP_PORT_INFO.driver], ftdi_port_name
; TODO obtain iManufacturer, iProduct and iSerial strings
mov dword [.pinfo + SP_PORT_INFO.descr], 0
lea ecx, [.pinfo]
stdcall serial_add_port, uart_drv, ebx, ecx
DEBUGF L_DBG, 'ftdi: add serial port with result %x\n', eax
stdcall serial_add_port, uart_drv, ebx
DEBUGF 1, "usbftdi: add serial port with result %x\n", eax
@@:
mov [ebx + ftdi_context.port_handle], eax
@@ -306,7 +296,7 @@ endl
ret
.notftdi:
DEBUGF L_DBG, 'ftdi: Skipping not FTDI device\n'
DEBUGF 1,'K : Skipping not FTDI device\n'
.nothing:
xor eax, eax
ret
@@ -327,7 +317,7 @@ EventData rd 3
endl
mov edi, [ioctl]
mov eax, [edi+io_code]
DEBUGF L_DBG, 'ftdi: FTDI got the request: %d\n', eax
DEBUGF 1,'K : FTDI got the request: %d\n', eax
test eax, eax ;0
jz .version
dec eax ;1
@@ -426,7 +416,7 @@ endl
.version:
jmp .endswitch
.error:
DEBUGF L_ERR, 'ftdi: error occured! %d\n', eax
DEBUGF 1, 'K : FTDI error occured! %d\n', eax
;mov esi, [edi+output]
;mov [esi], dword 'ERR0'
;or [esi], eax
@@ -459,7 +449,7 @@ endl
mov word[ConfPacket+6], cx
.own_index:
mov ebx, [edi+4]
DEBUGF L_DBG, 'ftdi: ConfPacket 0x%x 0x%x\n', [ConfPacket], [ConfPacket+4]
DEBUGF 2,'K : ConfPacket 0x%x 0x%x\n', [ConfPacket], [ConfPacket+4]
lea esi, [ConfPacket]
lea edi, [EventData]
invoke USBControlTransferAsync, [ebx + ftdi_context.nullP], esi, 0,\
@@ -475,7 +465,7 @@ endl
jmp .error
.ftdi_setrtshigh:
DEBUGF L_DBG, 'ftdi: Setting RTS pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2,'K : FTDI Setting RTS pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
@@ -483,7 +473,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_setrtslow:
DEBUGF L_DBG, 'ftdi: Setting RTS pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2,'K : FTDI Setting RTS pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
@@ -491,7 +481,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_setdtrhigh:
DEBUGF L_DBG, 'ftdi: Setting DTR pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2,'K : FTDI Setting DTR pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
@@ -499,7 +489,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_setdtrlow:
DEBUGF L_DBG, 'ftdi: Setting DTR pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2,'K : FTDI Setting DTR pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
@@ -507,7 +497,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_usb_reset:
DEBUGF L_DBG, 'ftdi: Reseting PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2,'K : FTDI Reseting PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_RESET_REQUEST shl 8) \
@@ -515,7 +505,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_purge_rx_buf:
DEBUGF L_DBG, 'ftdi: Purge TX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2, 'K : FTDI Purge TX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_RESET_REQUEST shl 8) \
@@ -523,7 +513,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_purge_tx_buf:
DEBUGF L_DBG, 'ftdi: Purge RX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2, 'K : FTDI Purge RX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_RESET_REQUEST shl 8) \
@@ -531,42 +521,42 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_set_bitmode:
DEBUGF L_DBG, 'ftdi: Set bitmode 0x%x, bitmask 0x%x %d PID: %d Dev handler 0x0x%x\n', \
DEBUGF 2, 'K : FTDI Set bitmode 0x%x, bitmask 0x%x %d PID: %d Dev handler 0x0x%x\n', \
[edi+8]:2,[edi+10]:2,[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_BITMODE_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_set_line_property:
DEBUGF L_DBG, 'ftdi: Set line property 0x%x PID: %d Dev handler 0x0x%x\n', \
DEBUGF 2, 'K : FTDI Set line property 0x%x PID: %d Dev handler 0x0x%x\n', \
[edi+8]:4,[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_DATA_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_set_latency_timer:
DEBUGF L_DBG, 'ftdi: Set latency %d PID: %d Dev handler 0x0x%x\n', \
DEBUGF 2, 'K : FTDI Set latency %d PID: %d Dev handler 0x0x%x\n', \
[edi+8],[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_LATENCY_TIMER_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_set_event_char:
DEBUGF L_DBG, 'ftdi: Set event char %c PID: %d Dev handler 0x0x%x\n', \
DEBUGF 2, 'K : FTDI Set event char %c PID: %d Dev handler 0x0x%x\n', \
[edi+8],[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_EVENT_CHAR_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_set_error_char:
DEBUGF L_DBG, 'ftdi: Set error char %c PID: %d Dev handler 0x0x%x\n', \
DEBUGF 2, 'K : FTDI Set error char %c PID: %d Dev handler 0x0x%x\n', \
[edi+8],[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_ERROR_CHAR_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_setflowctrl:
DEBUGF L_DBG, 'ftdi: Set flow control PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2, 'K : FTDI Set flow control PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_FLOW_CTRL_REQUEST shl 8) + (0 shl 16)
@@ -579,7 +569,7 @@ endl
jmp .own_index
.ftdi_read_pins:
DEBUGF L_DBG, 'ftdi: Read pins PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2, 'K : FTDI Read pins PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov ebx, [edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_IN_REQTYPE) \
@@ -608,7 +598,7 @@ endl
jmp .error
.ftdi_set_wchunksize:
DEBUGF L_DBG, 'ftdi: Set write chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
DEBUGF 2, 'K : FTDI Set write chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
[edi+8], [edi], [edi+4]
mov ebx, [edi+4]
mov ecx, [edi+8]
@@ -618,7 +608,7 @@ endl
jmp .endswitch
.ftdi_get_wchunksize:
DEBUGF L_DBG, 'ftdi: Get write chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2, 'K : FTDI Get write chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov esi, [edi+output]
mov edi, [edi+input]
@@ -628,7 +618,7 @@ endl
jmp .endswitch
.ftdi_set_rchunksize:
DEBUGF L_DBG, 'ftdi: Set read chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
DEBUGF 2, 'K : FTDI Set read chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
[edi+8], [edi], [edi+4]
mov ebx, [edi+4]
mov ecx, [edi+8]
@@ -638,7 +628,7 @@ endl
jmp .endswitch
.ftdi_get_rchunksize:
DEBUGF L_DBG, 'ftdi: Get read chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2, 'K : FTDI Get read chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov esi, [edi+output]
mov edi, [edi+input]
@@ -648,7 +638,7 @@ endl
jmp .endswitch
.ftdi_write_data:
DEBUGF L_DBG, 'ftdi: Write %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
DEBUGF 2, 'K : FTDI Write %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
[edi], [edi+4]
mov esi, edi
add esi, 12
@@ -695,7 +685,7 @@ endl
jmp .write_loop
.ftdi_read_data:
DEBUGF L_DBG, 'ftdi: Read %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
DEBUGF 2, 'K : FTDI Read %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
[edi], [edi+4]
mov edi, [ioctl]
mov esi, [edi+input]
@@ -753,7 +743,7 @@ endl
;---Dirty hack end
.ftdi_poll_modem_status:
DEBUGF L_DBG, 'ftdi: Poll modem status PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2, 'K : FTDI Poll modem status PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov ebx, [edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_IN_REQTYPE) \
@@ -777,7 +767,7 @@ endl
jmp .endswitch
.ftdi_get_latency_timer:
DEBUGF L_DBG, 'ftdi: Get latency timer PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF 2, 'K : FTDI Get latency timer PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov ebx, [edi+4]
mov dword[ConfPacket], FTDI_DEVICE_IN_REQTYPE \
@@ -797,7 +787,7 @@ endl
jmp .endswitch
.ftdi_get_list:
DEBUGF L_DBG, 'ftdi: devices list request\n'
DEBUGF 2, 'K : FTDI devices list request\n'
mov edi, [edi+output]
xor ecx, ecx
call linkedlist_gethead
@@ -827,7 +817,7 @@ endl
jmp .endswitch
.ftdi_lock:
DEBUGF L_DBG, 'ftdi: Lock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
DEBUGF 2, 'K : FTDI Lock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
mov esi, [edi+input]
mov ebx, [esi+4]
mov eax, [ebx + ftdi_context.lockPID]
@@ -841,7 +831,7 @@ endl
jmp .endswitch
.ftdi_unlock:
DEBUGF L_DBG, 'ftdi: Unlock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
DEBUGF 2, 'K : FTDI Unlock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
mov esi, [edi+input]
mov edi, [edi+output]
mov ebx, [esi+4]
@@ -855,19 +845,145 @@ endl
mov [edi], eax
jmp .endswitch
H_CLK = 120000000
C_CLK = 48000000
.ftdi_set_baudrate:
DEBUGF L_DBG, 'ftdi: Set baudrate to %d PID: %d Dev handle: 0x%x\n',\
DEBUGF 2, 'K : FTDI Set baudrate to %d PID: %d Dev handle: 0x%x\n',\
[edi+8], [edi], [edi+4]
mov ebx, [edi+4]
mov esi, [edi+8]
call ftdi_calc_baud_divisor
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jl .c_clk
imul eax, [edi+8], 10
cmp eax, H_CLK / 0x3FFF
jle .c_clk
.h_clk:
cmp dword[edi+8], H_CLK/10
jl .h_nextbaud1
xor edx, edx
mov ecx, H_CLK/10
jmp .calcend
.c_clk:
cmp dword[edi+8], C_CLK/16
jl .c_nextbaud1
xor edx, edx
mov ecx, C_CLK/16
jmp .calcend
.h_nextbaud1:
cmp dword[edi+8], H_CLK/(10 + 10/2)
jl .h_nextbaud2
mov edx, 1
mov ecx, H_CLK/(10 + 10/2)
jmp .calcend
.c_nextbaud1:
cmp dword[edi+8], C_CLK/(16 + 16/2)
jl .c_nextbaud2
mov edx, 1
mov ecx, C_CLK/(16 + 16/2)
jmp .calcend
.h_nextbaud2:
cmp dword[edi+8], H_CLK/(2*10)
jl .h_nextbaud3
mov edx, 2
mov ecx, H_CLK/(2*10)
jmp .calcend
.c_nextbaud2:
cmp dword[edi+8], C_CLK/(2*16)
jl .c_nextbaud3
mov edx, 2
mov ecx, C_CLK/(2*16)
jmp .calcend
.h_nextbaud3:
mov eax, H_CLK*16/10 ; eax - best_divisor
xor edx, edx
div dword[edi+8] ; [edi+8] - baudrate
push eax
and eax, 1
pop eax
shr eax, 1
jz .h_rounddowndiv ; jump by result of and eax, 1
inc eax
.h_rounddowndiv:
cmp eax, 0x20000
jle .h_best_divok
mov eax, 0x1FFFF
.h_best_divok:
mov ecx, eax
mov eax, H_CLK*16/10
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jz .rounddownbaud
inc ecx
jmp .rounddownbaud
.c_nextbaud3:
mov eax, C_CLK ; eax - best_divisor
xor edx, edx
div dword[edi+8] ; [edi+8] - baudrate
push eax
and eax, 1
pop eax
shr eax, 1
jnz .c_rounddowndiv ; jump by result of and eax, 1
inc eax
.c_rounddowndiv:
cmp eax, 0x20000
jle .c_best_divok
mov eax, 0x1FFFF
.c_best_divok:
mov ecx, eax
mov eax, C_CLK
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jnz .rounddownbaud
inc ecx
.rounddownbaud:
mov edx, eax ; edx - encoded_divisor
shr edx, 3
and eax, 0x7
push 7 6 5 1 4 2 3 0
mov eax, [esp+eax*4]
shl eax, 14
or edx, eax
add esp, 32
.calcend:
mov eax, edx ; eax - *value
mov ecx, edx ; ecx - *index
and eax, 0xFFFF
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jge .foxyindex
shr ecx, 16
jmp .preparepacket
.foxyindex:
shr ecx, 8
and ecx, 0xFF00
or ecx, [ebx + ftdi_context.index]
.preparepacket:
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_BAUDRATE_REQUEST shl 8)
mov word[ConfPacket+2], ax
mov word[ConfPacket+4], cx
mov word[ConfPacket+6], 0
jmp .own_index
jmp .own_index
endp
restore handle
restore io_code
@@ -877,143 +993,10 @@ restore output
restore out_size
proc ftdi_calc_baud_divisor
; in: ebx = ftdi_context pointer
; esi = baud rate
; out: ax = encoded value
; cx = encoded index
; destroys: eax, ecx, edx, esi
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jl .c_clk
imul eax, esi, 10
cmp eax, H_CLK / 0x3FFF
jle .c_clk
.h_clk:
cmp esi, H_CLK / 10
jl .h_nextbaud1
xor edx, edx
mov ecx, H_CLK / 10
jmp .calcend
.c_clk:
cmp esi, C_CLK / 16
jl .c_nextbaud1
xor edx, edx
mov ecx, C_CLK / 16
jmp .calcend
.h_nextbaud1:
cmp esi, H_CLK / (10 + 10 / 2)
jl .h_nextbaud2
mov edx, 1
mov ecx, H_CLK / (10 + 10 / 2)
jmp .calcend
.c_nextbaud1:
cmp esi, C_CLK / (16 + 16 / 2)
jl .c_nextbaud2
mov edx, 1
mov ecx, C_CLK/(16 + 16 / 2)
jmp .calcend
.h_nextbaud2:
cmp esi, H_CLK / (2 * 10)
jl .h_nextbaud3
mov edx, 2
mov ecx, H_CLK / (2 * 10)
jmp .calcend
.c_nextbaud2:
cmp esi, C_CLK / (2 * 16)
jl .c_nextbaud3
mov edx, 2
mov ecx, C_CLK / (2 * 16)
jmp .calcend
.h_nextbaud3:
mov eax, H_CLK * 16 / 10 ; eax - best_divisor
xor edx, edx
div esi
push eax
and eax, 1
pop eax
shr eax, 1
jz .h_rounddowndiv ; jump by result of and eax, 1
inc eax
.h_rounddowndiv:
cmp eax, 0x20000
jle .h_best_divok
mov eax, 0x1FFFF
.h_best_divok:
mov ecx, eax
mov eax, H_CLK * 16 / 10
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jz .rounddownbaud
inc ecx
jmp .rounddownbaud
.c_nextbaud3:
mov eax, C_CLK ; eax - best_divisor
xor edx, edx
div esi
push eax
and eax, 1
pop eax
shr eax, 1
jnz .c_rounddowndiv ; jump by result of and eax, 1
inc eax
.c_rounddowndiv:
cmp eax, 0x20000
jle .c_best_divok
mov eax, 0x1FFFF
.c_best_divok:
mov ecx, eax
mov eax, C_CLK
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jnz .rounddownbaud
inc ecx
.rounddownbaud:
mov edx, eax ; edx - encoded_divisor
shr edx, 3
and eax, 0x7
push 7 6 5 1 4 2 3 0
mov eax, [esp + eax * 4]
shl eax, 14
or edx, eax
add esp, 32
.calcend:
mov eax, edx ; eax - *value
mov ecx, edx ; ecx - *index
and eax, 0xFFFF
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jge .foxyindex
shr ecx, 16
ret
.foxyindex:
shr ecx, 8
and ecx, 0xFF00
or ecx, [ebx + ftdi_context.index]
ret
endp
proc control_callback stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
.buffer:DWORD, .length:DWORD, .calldata:DWORD
DEBUGF L_DBG, 'ftdi: status is %d\n', [.status]
DEBUGF 1, 'K : status is %d\n', [.status]
mov ecx, [.calldata]
mov eax, [ecx]
mov ebx, [ecx+4]
@@ -1028,7 +1011,7 @@ endp
proc bulk_callback stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
.buffer:DWORD, .length:DWORD, .calldata:DWORD
DEBUGF L_DBG, 'ftdi: status is %d\n', [.status]
DEBUGF 1, 'K : status is %d\n', [.status]
mov ecx, [.calldata]
mov eax, [ecx]
mov ebx, [ecx+4]
@@ -1051,7 +1034,7 @@ endp
proc DeviceDisconnected stdcall uses ebx esi edi, .device_data:DWORD
DEBUGF L_DBG, 'ftdi: deleting device data 0x%x\n', [.device_data]
DEBUGF 1, 'K : FTDI deleting device data 0x%x\n', [.device_data]
mov esi, [.device_data]
mov eax, [esi + ftdi_context.readBufPtr]
test eax, eax
@@ -1079,7 +1062,7 @@ proc bulk_in_complete stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
mov eax, [.status]
test eax, eax
jz @f
DEBUGF L_ERR, 'ftdi: bulk in error %x\n', eax
DEBUGF 2, 'ftdi: bulk in error %x\n', eax
@@:
mov ebx, [.calldata]
btr dword [ebx + ftdi_context.writeBufLock], 0
@@ -1092,7 +1075,7 @@ proc bulk_out_complete stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
mov eax, [.status]
test eax, eax
jz @f
DEBUGF L_ERR, 'ftdi: bulk out error %x\n', eax
DEBUGF 2, 'ftdi: bulk out error %x\n', eax
@@:
mov ebx, [.calldata]
mov ecx, [.length]
@@ -1109,18 +1092,18 @@ proc bulk_out_complete stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
endp
proc uart_startup stdcall uses ebx, data:dword, conf:dword
DEBUGF L_DBG, "ftdi: startup %x %x\n", [data], [conf]
DEBUGF 1, "ftdi: startup %x %x\n", [data], [conf]
stdcall uart_reconf, [data], [conf]
test eax, eax
jz @f
DEBUGF L_ERR, "ftdi: uart reconf error %x\n", eax
DEBUGF 2, "ftdi: uart reconf error %x\n", eax
jmp .exit
@@:
mov ebx, [data]
invoke TimerHS, 2, 2, uart_rx, ebx
test eax, eax
jnz @f
DEBUGF L_ERR, "ftdi: timer creation error\n"
DEBUGF 2, "ftdi: timer creation error\n"
or eax, -1
jmp .exit
@@:
@@ -1131,7 +1114,7 @@ proc uart_startup stdcall uses ebx, data:dword, conf:dword
endp
proc uart_shutdown stdcall uses ebx, data:dword
DEBUGF L_DBG, "ftdi: shutdown %x\n", [data]
DEBUGF 1, "ftdi: shutdown %x\n", [data]
mov ebx, [data]
cmp [ebx + ftdi_context.rx_timer], 0
jz @f
@@ -1263,14 +1246,137 @@ proc uart_rx stdcall uses ebx esi, data:dword
ret
endp
proc ftdi_set_baudrate stdcall uses ebx esi, dev:dword, baud:dword
proc ftdi_set_baudrate stdcall uses ebx, dev:dword, baud:dword
locals
ConfPacket rb 8
endl
mov ebx, [dev]
mov esi, [baud]
call ftdi_calc_baud_divisor
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jl .c_clk
imul eax, [baud], 10
cmp eax, H_CLK / 0x3FFF
jle .c_clk
.h_clk:
cmp dword [baud], H_CLK / 10
jl .h_nextbaud1
xor edx, edx
mov ecx, H_CLK / 10
jmp .calcend
.c_clk:
cmp dword [baud], C_CLK / 16
jl .c_nextbaud1
xor edx, edx
mov ecx, C_CLK / 16
jmp .calcend
.h_nextbaud1:
cmp dword [baud], H_CLK / (10 + 10 / 2)
jl .h_nextbaud2
mov edx, 1
mov ecx, H_CLK / (10 + 10 / 2)
jmp .calcend
.c_nextbaud1:
cmp dword [baud], C_CLK / (16 + 16 / 2)
jl .c_nextbaud2
mov edx, 1
mov ecx, C_CLK/(16 + 16 / 2)
jmp .calcend
.h_nextbaud2:
cmp dword [baud], H_CLK / (2 * 10)
jl .h_nextbaud3
mov edx, 2
mov ecx, H_CLK / (2 * 10)
jmp .calcend
.c_nextbaud2:
cmp dword [baud], C_CLK / (2 * 16)
jl .c_nextbaud3
mov edx, 2
mov ecx, C_CLK / (2 * 16)
jmp .calcend
.h_nextbaud3:
mov eax, H_CLK * 16 / 10 ; eax - best_divisor
xor edx, edx
div dword [baud]
push eax
and eax, 1
pop eax
shr eax, 1
jz .h_rounddowndiv ; jump by result of and eax, 1
inc eax
.h_rounddowndiv:
cmp eax, 0x20000
jle .h_best_divok
mov eax, 0x1FFFF
.h_best_divok:
mov ecx, eax
mov eax, H_CLK * 16 / 10
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jz .rounddownbaud
inc ecx
jmp .rounddownbaud
.c_nextbaud3:
mov eax, C_CLK ; eax - best_divisor
xor edx, edx
div dword [baud]
push eax
and eax, 1
pop eax
shr eax, 1
jnz .c_rounddowndiv ; jump by result of and eax, 1
inc eax
.c_rounddowndiv:
cmp eax, 0x20000
jle .c_best_divok
mov eax, 0x1FFFF
.c_best_divok:
mov ecx, eax
mov eax, C_CLK
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jnz .rounddownbaud
inc ecx
.rounddownbaud:
mov edx, eax ; edx - encoded_divisor
shr edx, 3
and eax, 0x7
push 7 6 5 1 4 2 3 0
mov eax, [esp + eax * 4]
shl eax, 14
or edx, eax
add esp, 32
.calcend:
mov eax, edx ; eax - *value
mov ecx, edx ; ecx - *index
and eax, 0xFFFF
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jge .foxyindex
shr ecx, 16
jmp .preparepacket
.foxyindex:
shr ecx, 8
and ecx, 0xFF00
or ecx, [ebx + ftdi_context.index]
.preparepacket:
mov word [ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_BAUDRATE_REQUEST shl 8)
mov word [ConfPacket + 2], ax
@@ -1345,9 +1451,10 @@ uart_drv:
dd uart_tx
uart_drv_end:
include_debug_strings
serial_drv_entry dd 0
data fixups
end data
serial_drv_entry dd ?
;for DEBUGF macro
include_debug_strings
-3
View File
@@ -1,3 +0,0 @@
if tup.getconfig("NO_FASM") ~= "" then return end
ROOT = "../../.."
tup.foreach_rule("*.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "%B.sys")
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+2 -12
View File
@@ -79,7 +79,7 @@ macro ADD_CLASS drv_name, class, subclass, protocol {
..class_code = ..length or (class shl 8)
if ..length = 3
..class_code = ..class_code or (subclass shl 16) or (protocol shl 24)
..class_code = ..class_code or (protocol shl 24)
end if
if ..length = 2
..class_code = ..class_code or (subclass shl 16)
@@ -172,17 +172,7 @@ macro ADD_IDL drv_name, [vendor_id, device_id] {
INIT_USBDRV_FILE
; CDC (Communications Device Class): NCM network + ACM serial
ADD_CLASS 'usbcdc' , 0x02, X , X
; RNDIS network (Remote NDIS): LTE modems in HiLink mode, USB tethering.
; Three encodings exist: Wireless-Controller/RF/RNDIS, Miscellaneous/
; RNDIS-over-Ethernet (phone tethering) and an ACM masquerade (the
; latter is declined by usbcdc, so the scan falls through to us).
ADD_CLASS 'usbrndis' , 0xE0, 0x01, 0x03
ADD_CLASS 'usbrndis' , 0xEF, 0x04, 0x01
ADD_CLASS 'usbrndis' , 0x02, 0x02, 0xFF
;ADD_CLASS 'usbcdc-ctrl' , 0x02, X , X
;ADD_CLASS 'usbimage' , 0x06, 1 , 1
;ADD_CLASS 'usbcdc-data' , 0x0A, X , X
;ADD_CLASS 'ccid' , 0x0B, X , X
+2 -476
View File
@@ -722,225 +722,6 @@ endp
; callback inquiry_callback;
; * inquiry_callback checks that a logical device is a block device
; and the unit was ready; if so, it notifies the kernel about new disk device.
; Open the bulk pipes of the Zero-CD device and send the switch message
; chosen for it (optionally preceded by an INQUIRY exchange). Used as
; the fallback when the device has no MS OS 2.0 alternate enumeration.
proc modeswitch_send_cbw
push ebx
mov ebx, [modeswitch_pipe0]
cmp dword [modeswitch_in_ep], 0
jz @f
invoke USBOpenPipe, ebx, [modeswitch_in_ep], [modeswitch_in_mps], \
BULK_PIPE, 0
mov [modeswitch_in_pipe], eax
@@:
invoke USBOpenPipe, ebx, [modeswitch_out_ep], [modeswitch_out_mps], \
BULK_PIPE, 0
test eax, eax
jz .fail
mov [modeswitch_out_pipe], eax
; warm up the firmware with an INQUIRY exchange first, if the method
; asks for it (and the CSW pipe is available)
cmp dword [modeswitch_inq], 0
jz .magic
cmp dword [modeswitch_in_pipe], 0
jz .magic
invoke USBNormalTransferAsync, eax, modeswitch_cbw_inq, 31, \
modeswitch_inq_cbw_callback, 0, 0
DEBUGF 1,'K : modeswitch INQUIRY CBW submitted, handle %x\n', eax
test eax, eax
jz .fail
pop ebx
ret
.magic:
invoke USBNormalTransferAsync, [modeswitch_out_pipe], [modeswitch_msg], 31, \
modeswitch_callback, 0, 0
DEBUGF 1,'K : modeswitch CBW submitted, handle %x\n', eax
test eax, eax
jz .fail
pop ebx
ret
.fail:
mov dword [modeswitch_pipe0], 0 ; transaction over
pop ebx
ret
endp
; The INQUIRY CBW went out: read the 36 data bytes.
proc modeswitch_inq_cbw_callback stdcall uses ebx esi edi, .pipe:dword, .status:dword, .buffer:dword, .length:dword, .calldata:dword
DEBUGF 1,'K : modeswitch INQUIRY CBW done, status %d\n', [.status]
cmp [.status], 0
jne .fail
invoke USBNormalTransferAsync, [modeswitch_in_pipe], modeswitch_bos_buf, \
36, modeswitch_inq_data_callback, 0, 1
test eax, eax
jz .fail
ret
.fail:
mov dword [modeswitch_pipe0], 0 ; transaction over
ret
endp
; The INQUIRY data arrived: read the CSW.
proc modeswitch_inq_data_callback stdcall uses ebx esi edi, .pipe:dword, .status:dword, .buffer:dword, .length:dword, .calldata:dword
DEBUGF 1,'K : modeswitch INQUIRY data done, status %d len %d\n', [.status], [.length]
invoke USBNormalTransferAsync, [modeswitch_in_pipe], modeswitch_csw, \
13, modeswitch_inq_csw_callback, 0, 1
test eax, eax
jz .fail
ret
.fail:
mov dword [modeswitch_pipe0], 0 ; transaction over
ret
endp
; The INQUIRY transaction is complete: now the switch message itself.
proc modeswitch_inq_csw_callback stdcall uses ebx esi edi, .pipe:dword, .status:dword, .buffer:dword, .length:dword, .calldata:dword
DEBUGF 1,'K : modeswitch INQUIRY CSW done, status %d\n', [.status]
invoke USBNormalTransferAsync, [modeswitch_out_pipe], [modeswitch_msg], 31, \
modeswitch_callback, 0, 0
DEBUGF 1,'K : modeswitch CBW submitted, handle %x\n', eax
test eax, eax
jz .fail
ret
.fail:
mov dword [modeswitch_pipe0], 0 ; transaction over
ret
endp
; The BOS descriptor has been read. If the device carries an
; MS OS 2.0 platform capability with a nonzero bAltEnumCode, switch it
; the way Windows does: a vendor control request "set alternate
; enumeration". Otherwise fall back to the bulk switch message.
proc modeswitch_bos_callback stdcall uses ebx esi edi, .pipe:dword, .status:dword, .buffer:dword, .length:dword, .calldata:dword
DEBUGF 1,'K : modeswitch BOS done, status %d len %d\n', [.status], [.length]
cmp [.status], 0
jne .fallback
mov ecx, [.length]
sub ecx, 8 ; minus the setup packet
cmp ecx, 5
jb .fallback
mov esi, modeswitch_bos_buf
cmp byte [esi+1], 0x0F ; BOS descriptor type
jne .fallback
movzx edx, word [esi+2] ; wTotalLength
cmp edx, ecx
jbe @f
mov edx, ecx ; clamp to what was received
@@:
add edx, esi ; edx = end of BOS data
add esi, 5 ; first device capability
.cap_loop:
lea eax, [esi+3]
cmp eax, edx
ja .fallback ; no more capabilities
movzx ecx, byte [esi] ; bLength
test ecx, ecx
jz .fallback
cmp byte [esi+1], 0x10 ; DEVICE_CAPABILITY
jne .next_cap
cmp byte [esi+2], 0x05 ; PLATFORM capability
jne .next_cap
cmp ecx, 20+8 ; header + GUID + one set info
jb .next_cap
lea eax, [esi+ecx]
cmp eax, edx
ja .fallback ; capability sticks out of BOS
; is it the MS OS 2.0 platform GUID?
push esi edi ecx
add esi, 4
mov edi, msos20_guid
mov ecx, 16
repe cmpsb
pop ecx edi esi
jne .next_cap
; walk the descriptor set info structures, take one with bAltEnumCode
push ecx
sub ecx, 20
shr ecx, 3 ; number of 8-byte set infos
lea eax, [esi+20]
.set_loop:
test ecx, ecx
jz .no_alt_enum
cmp byte [eax+7], 0 ; bAltEnumCode
jne .set_found
add eax, 8
dec ecx
jmp .set_loop
.set_found:
pop ecx
mov cl, [eax+6] ; bMS_VendorCode
mov [modeswitch_alt_setup+1], cl
mov cl, [eax+7] ; bAltEnumCode -> wValue high byte
mov [modeswitch_alt_setup+3], cl
DEBUGF 1,'K : modeswitch: MS OS 2.0 alt enum supported\n'
mov ebx, [.calldata] ; pipe 0
invoke USBControlTransferAsync, ebx, modeswitch_alt_setup, 0, 0, \
modeswitch_alt_callback, ebx, 0
DEBUGF 1,'K : modeswitch SET_ALT_ENUMERATION submit %x\n', eax
test eax, eax
jz .fallback
ret
.no_alt_enum:
pop ecx
jmp .fallback
.next_cap:
add esi, ecx
jmp .cap_loop
.fallback:
DEBUGF 1,'K : modeswitch: no MS OS 2.0, using bulk message\n'
call modeswitch_send_cbw
ret
endp
; SET_ALT_ENUMERATION completed: on success the device re-enumerates
; by itself; if it stalled the request, try the bulk message instead.
proc modeswitch_alt_callback stdcall uses ebx esi edi, .pipe:dword, .status:dword, .buffer:dword, .length:dword, .calldata:dword
DEBUGF 1,'K : modeswitch SET_ALT_ENUMERATION done, status %d\n', [.status]
cmp [.status], 0
je .ret
call modeswitch_send_cbw
.ret:
ret
endp
; The mode-switch CBW has completed. Read the CSW status like
; usb_modeswitch does: some firmwares only switch after the host has
; completed the whole Bulk-Only transaction.
proc modeswitch_callback stdcall uses ebx esi edi, .pipe:dword, .status:dword, .buffer:dword, .length:dword, .calldata:dword
DEBUGF 1,'K : modeswitch CBW done, status %d\n', [.status]
cmp [.status], 0
jne .done
mov eax, [modeswitch_in_pipe]
test eax, eax
jz .done
invoke USBNormalTransferAsync, eax, modeswitch_csw, 13, \
modeswitch_csw_callback, 0, 1
test eax, eax
jnz .ret
.done:
mov dword [modeswitch_pipe0], 0 ; transaction over
.ret:
ret
endp
; The CSW arrived (or errored); nothing more to do, the device should
; drop off the bus and re-enumerate in its real configuration.
proc modeswitch_csw_callback stdcall uses ebx esi edi, .pipe:dword, .status:dword, .buffer:dword, .length:dword, .calldata:dword
DEBUGF 1,'K : modeswitch CSW done, status %d len %d\n', [.status], [.length]
mov dword [modeswitch_pipe0], 0 ; transaction over
ret
endp
; SET_FEATURE(1) completed; the device either resets into its real
; configuration or (newer firmwares) just resets back into Zero-CD,
; which re-triggers the quirk with the next method of the list.
proc modeswitch_sf_callback stdcall uses ebx esi edi, .pipe:dword, .status:dword, .buffer:dword, .length:dword, .calldata:dword
DEBUGF 1,'K : modeswitch SET_FEATURE done, status %d\n', [.status]
mov dword [modeswitch_pipe0], 0 ; transaction over
ret
endp
proc AddDevice
push ebx esi
virtual at esp
@@ -956,134 +737,6 @@ end virtual
; bInterfaceProtocol are subsequent in interface_descr, just one
; memory reference is used for both.
mov esi, [.interface]
; Some 3G/LTE modems enumerate as a mass-storage-only "Zero-CD" (a
; virtual CD-ROM with Windows drivers) and must be switched to their
; real configuration by a magic vendor SCSI command sent to the bulk
; OUT endpoint (usb_modeswitch's "HuaweiNewMode"; a SET_FEATURE(1)
; only resets these devices back into Zero-CD). Match by VID:PID,
; fire the command and do not bind: the device drops off the bus and
; re-enumerates with a new PID.
mov ebx, [.pipe0]
invoke USBGetParam, ebx, 0 ; 0 = get device descriptor
test eax, eax
jz .no_modeswitch
mov ecx, [eax+8] ; idVendor | idProduct shl 16
mov edx, modeswitch_ids
.modeswitch_scan:
cmp dword [edx], 0
jz .no_modeswitch
cmp ecx, [edx]
jz .do_modeswitch
add edx, 8
jmp .modeswitch_scan
.do_modeswitch:
; one switch transaction at a time: some Zero-CDs (12d1:14ad) carry TWO
; storage interfaces and AddDevice fires for each; a second concurrent
; CBW confuses the firmware
cmp [modeswitch_pipe0], ebx
je .nothing
; pick the method: repeated appearances of the same id walk its method
; list (wrapping around), a different id starts from the first method
cmp ecx, [modeswitch_last_id]
je @f
mov [modeswitch_last_id], ecx
mov dword [modeswitch_attempt], 0
jmp .method_select
@@:
inc [modeswitch_attempt]
.method_select:
mov eax, [edx+4] ; start of the method list
mov ecx, [modeswitch_attempt]
.method_walk:
cmp dword [eax], -1 ; end of list: wrap around
jne @f
mov eax, [edx+4]
@@:
test ecx, ecx
jz .method_found
add eax, 8
dec ecx
jmp .method_walk
.method_found:
mov [modeswitch_pipe0], ebx
push esi
mov esi, switchdevice
invoke SysMsgBoardStr
pop esi
DEBUGF 1,'K : modeswitch attempt %d, method %d\n', [modeswitch_attempt], [eax]
cmp dword [eax], MSW_SET_FEATURE
je .method_set_feature
xor ecx, ecx
cmp dword [eax], MSW_CBW_INQ
jne @f
inc ecx
@@:
mov [modeswitch_inq], ecx
mov eax, [eax+4] ; the CBW for this attempt
mov [modeswitch_msg], eax
jmp .method_cbw
; SET_FEATURE(1) needs no endpoints: fire the control request and let
; the device drop off the bus by itself
.method_set_feature:
invoke USBControlTransferAsync, ebx, modeswitch_sf_setup, 0, 0, \
modeswitch_sf_callback, 0, 0
DEBUGF 1,'K : modeswitch SET_FEATURE submit %x\n', eax
test eax, eax
jnz .nothing
mov dword [modeswitch_pipe0], 0
jmp .nothing
.method_cbw:
; collect the bulk IN and bulk OUT endpoints of this interface
mov dword [modeswitch_in_pipe], 0
mov dword [modeswitch_in_ep], 0
mov dword [modeswitch_out_ep], 0
mov edx, [.config]
movzx ecx, [edx+config_descr.wTotalLength]
add edx, ecx ; edx = end of configuration data
.modeswitch_ep_scan:
movzx ecx, byte [esi] ; bLength
test ecx, ecx
jz .modeswitch_send ; malformed, use what we have
add esi, ecx
lea ecx, [esi+sizeof.endpoint_descr]
cmp ecx, edx
ja .modeswitch_send ; ran out of descriptors
cmp byte [esi+1], ENDPOINT_DESCR_TYPE
jne .modeswitch_ep_scan
mov cl, [esi+endpoint_descr.bmAttributes]
and cl, 3
cmp cl, BULK_PIPE
jne .modeswitch_ep_scan
movzx ecx, [esi+endpoint_descr.bEndpointAddress]
push edx
movzx edx, [esi+endpoint_descr.wMaxPacketSize]
and edx, 0xFFF
test cl, 80h
jz .modeswitch_ep_out
mov [modeswitch_in_ep], ecx
mov [modeswitch_in_mps], edx
pop edx
jmp .modeswitch_ep_scan
.modeswitch_ep_out:
mov [modeswitch_out_ep], ecx
mov [modeswitch_out_mps], edx
pop edx
jmp .modeswitch_ep_scan
.modeswitch_send:
cmp dword [modeswitch_out_ep], 0
jz .nothing ; no bulk OUT: cannot switch
mov [modeswitch_pipe0], ebx
; try the Windows mechanism first (MS OS 2.0 alternate enumeration,
; this is how E3372h switches); its callback falls back to the classic
; bulk switch message if the device has no such capability
invoke USBControlTransferAsync, ebx, modeswitch_bos_setup, \
modeswitch_bos_buf, 256, modeswitch_bos_callback, ebx, 1
DEBUGF 1,'K : modeswitch BOS read submit %x\n', eax
test eax, eax
jnz .nothing
call modeswitch_send_cbw ; could not even ask: fall back
jmp .nothing
.no_modeswitch:
xor ebx, ebx
mov cx, word [esi+interface_descr.bInterfaceSubClass]
; 1b. For Mass-storage SCSI-command-set Bulk-only devices subclass must be 6
@@ -1338,16 +991,6 @@ proc inquiry_callback
test al, al
jnz .nothing
DEBUGF 1,'K : direct-access mass storage device detected\n'
; Units that report 'medium not present' (the empty card slot of an LTE
; modem or card reader) are not registered: the kernel has no media
; change detection, so such a disk would only sit dead in the file
; managers. Replugging the device after inserting a card registers it.
mov edx, [esp+8]
cmp [edx+usb_unit_data.MediaPresent], 0
jnz @f
DEBUGF 1,'K : no media, not registering the disk\n'
ret 8
@@:
; 3. We have found a new disk device. Increment number of references.
lock inc [ecx+usb_device_data.NumReferences]
; Unfortunately, we are now in the context of the USB thread,
@@ -1754,14 +1397,8 @@ proc disk_read_write stdcall uses ebx esi edi, \
mov eax, [numsectors]
mov eax, [eax]
; 2. The transfer length for SCSI_{READ,WRITE}10 commands can not be greater
; than 0xFFFF sectors, but that is not the practical limit: the field size is
; the only thing the standard bounds, while real sticks hang their firmware on
; multi-megabyte single commands. The kernel disk cache asks for as much as
; CACHE_MAX_ALLOC_SIZE (4 MB) in one call, i.e. 8192 sectors, and that is
; exactly where such sticks stop answering and re-enumerate. Linux caps
; usb-storage at 240 sectors (120 KB) for the same reason; do the same and
; split larger requests into slices.
max_sectors_at_time = 240
; than 0xFFFF, so split the request to slices with <= 0xFFFF sectors.
max_sectors_at_time = 0xFFFF
.split:
push eax ; .length_rest
cmp eax, max_sectors_at_time
@@ -1931,117 +1568,6 @@ inquiry_fail db 'K : INQUIRY command failed',13,10,0
;read_capacity_fail db 'K : READ CAPACITY command failed',13,10,0
;read_fail db 'K : READ command failed',13,10,0
noindex db 'K : failed to generate disk name',13,10,0
switchdevice db 'K : Zero-CD modem detected, switching mode',13,10,0
; Zero-CD devices to switch: pairs of (idVendor + idProduct shl 16,
; pointer to a method list). Different firmware generations accept
; different switch methods and silently ignore (or merely ACK) the
; others, and some do not react to the method the usb_modeswitch
; database prescribes. So every id gets a LIST of methods and each
; (re)appearance of the same id tries the next one, wrapping around.
; No timers needed: an unswitched stick resets itself about half a
; minute after a swallowed command (observed on K3806), and the user
; can always just replug.
MSW_CBW = 0 ; method: bulk message, param = CBW ptr
MSW_SET_FEATURE = 1 ; method: SET_FEATURE(1) control request
MSW_CBW_INQ = 2 ; method: INQUIRY exchange, then the CBW;
; some firmwares accept the switch only
; after normal SCSI traffic (on Linux and
; Windows the storage driver reads the
; virtual CD before any switch tool runs)
align 4
modeswitch_ids dd 0x1F0112D1, modeswitch_list_1f01 ; Huawei E3372 etc
dd 0x14AD12D1, modeswitch_list_14ad ; Vodafone K3806
dd 0
; E3372h-153: the 10-byte command is the only one this firmware
; reacts to (verified on hardware; SET_FEATURE only resets it)
modeswitch_list_1f01:
dd MSW_CBW, modeswitch_cbw_new
dd -1
; K3806: the plain usb_modeswitch message (classic Huawei), the eject
; and the E3372 message are all ACKed but ignored, SET_FEATURE stalls
; (verified on hardware) - so lead with INQUIRY+message
modeswitch_list_14ad:
dd MSW_CBW_INQ, modeswitch_cbw_old
dd MSW_SET_FEATURE, 0
dd MSW_CBW, modeswitch_cbw_eject
dd MSW_CBW, modeswitch_cbw_new
dd MSW_CBW, modeswitch_cbw_old
dd -1
; usb_modeswitch's message for the 1F01 Zero-CD family: a CBW with the
; 10-byte vendor command 11 06 20 00 00 00 00 00 01 00 (note the 01 in
; byte 8; the older 6-byte 11 06 20 00 00 01 variant is ignored by
; E3372h firmwares) and no data stage
modeswitch_cbw_new:
db 'USBC' ; dCBWSignature
dd 0x12345678 ; dCBWTag
dd 0 ; dCBWDataTransferLength
db 0 ; bmCBWFlags
db 0 ; bCBWLUN
db 10 ; bCBWCBLength
db 0x11, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
db 0, 0, 0, 0, 0, 0
; the classic Huawei message for older sticks (usb_modeswitch 12d1:14ad
; etc): the 6-byte vendor command 11 06 20 00 00 01, byte-for-byte as
; usb_modeswitch sends it (bCBWCBLength is 0 in the original message)
modeswitch_cbw_old:
db 'USBC' ; dCBWSignature
dd 0x12345678 ; dCBWTag
dd 0 ; dCBWDataTransferLength
db 0 ; bmCBWFlags
db 0 ; bCBWLUN
db 0 ; bCBWCBLength
db 0x11, 0x06, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
db 0, 0, 0, 0, 0, 0
; the standard eject (START STOP UNIT with LoEj|Stop): the generic
; Zero-CD switch used by many non-Huawei sticks
modeswitch_cbw_eject:
db 'USBC' ; dCBWSignature
dd 0x12345678 ; dCBWTag
dd 0 ; dCBWDataTransferLength
db 0 ; bmCBWFlags
db 0 ; bCBWLUN
db 6 ; bCBWCBLength
db 0x1B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
db 0, 0, 0, 0, 0, 0
; SET_FEATURE(1) to the device: the switch of the oldest Huawei sticks
modeswitch_sf_setup db 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
; standard INQUIRY (36 bytes of data IN), the warm-up for MSW_CBW_INQ
modeswitch_cbw_inq:
db 'USBC' ; dCBWSignature
dd 0x12345678 ; dCBWTag
dd 36 ; dCBWDataTransferLength
db 0x80 ; bmCBWFlags: data IN
db 0 ; bCBWLUN
db 6 ; bCBWCBLength
db 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00
db 0, 0, 0, 0, 0, 0
; scratch state of the mode-switch transaction
modeswitch_pipe0 dd 0 ; config pipe of the device
; (nonzero = transaction running)
modeswitch_msg dd 0 ; the CBW chosen for this device
modeswitch_inq dd 0 ; run an INQUIRY before the CBW
modeswitch_out_pipe dd 0 ; bulk OUT pipe handle
modeswitch_last_id dd 0 ; VID:PID of the last attempt
modeswitch_attempt dd 0 ; method index for that id
modeswitch_in_pipe dd 0 ; bulk IN pipe handle (for the CSW)
modeswitch_in_ep dd 0
modeswitch_in_mps dd 0
modeswitch_out_ep dd 0
modeswitch_out_mps dd 0
; GET_DESCRIPTOR(BOS), up to 256 bytes
modeswitch_bos_setup db 0x80, 0x06, 0x00, 0x0F, 0x00, 0x00
dw 256
; MS OS 2.0 "set alternate enumeration": vendor request to the device,
; bRequest (+1) and wValue high byte (+3) are patched in at runtime
modeswitch_alt_setup db 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00
; platform capability GUID of MS OS 2.0: D8DD60DF-4589-4CC7-9CD2-659D9E648A9F
msos20_guid db 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C
db 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F
modeswitch_csw rb 16 ; CSW receive buffer
modeswitch_bos_buf rb 256 ; BOS descriptor buffer
align 4
; Structure with callback functions.
-3
View File
@@ -1,3 +0,0 @@
if tup.getconfig("NO_FASM") ~= "" then return end
ROOT = "../../.."
tup.rule("xhci.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "%B.sys")
File diff suppressed because it is too large. Load diff
-993
View File
@@ -1,993 +0,0 @@
; Device slots, contexts and pipes for the xHCI driver.
; This file is included from xhci.asm.
; =============================================================================
; ============================ Context helpers ================================
; =============================================================================
; Returns the address of one context inside a context structure.
; in: eax = base of the structure, ecx = index of the context,
; esi -> usb_controller.
; out: eax = address of the context.
proc xhci_context
push ecx edx
mov edx, [esi+xhci_controller.ContextSize-XCD]
imul edx, ecx
add eax, edx
pop edx ecx
ret
endp
; Zeroes the Input Context. The caller must hold CmdLock.
; in: esi -> usb_controller.
proc xhci_clear_input_ctx
push eax ecx edi
mov edi, [esi+xhci_controller.InputCtx-XCD]
xor eax, eax
mov ecx, 33*64/4
rep stosd
pop edi ecx eax
ret
endp
; Returns the pipe of the default control endpoint of the same device, which
; represents the device as a whole.
; in: ebx -> xhci_pipe. out: eax -> xhci_pipe or 0.
proc xhci_ctrl_pipe
mov eax, [ebx+xhci_pipe.DevPage]
test eax, eax
jz .nothing
mov eax, [eax+XHCI_PIPES_OFS+1*4]
test eax, eax
jz .nothing
sub eax, sizeof.xhci_pipe
.nothing:
ret
endp
; Fills the Slot Context of the Input Context from the device description kept
; in a pipe. The caller must hold CmdLock.
; in: esi -> usb_controller, ebx -> xhci_pipe describing the device,
; ecx = value for the Context Entries field.
proc xhci_fill_slot_ctx
push eax ecx edx edi
mov eax, [esi+xhci_controller.InputCtx-XCD]
push ecx
movi ecx, 1
call xhci_context
pop ecx
mov edi, eax
; dword 0: Route String, Speed and Context Entries.
mov eax, [ebx+xhci_pipe.Route]
and eax, 0FFFFFh
if XHCI_SUPERSPEED
; A SuperSpeed root-port device carries the raw PORTSC speed identifier;
; its kernel-visible Speed pretends high-speed and must not get here.
mov edx, [ebx+xhci_pipe.PSIV]
test edx, edx
jnz .havespeed
end if
mov edx, [ebx+xhci_pipe.Speed]
cmp edx, USB_SPEED_FS
jz .fs
cmp edx, USB_SPEED_LS
jz .ls
movi edx, XHCI_PSI_HS
jmp .havespeed
.fs:
movi edx, XHCI_PSI_FS
jmp .havespeed
.ls:
movi edx, XHCI_PSI_LS
.havespeed:
shl edx, 20
or eax, edx
shl ecx, 27
or eax, ecx
mov [edi], eax
; dword 1: Root Hub Port Number.
mov eax, [ebx+xhci_pipe.RootPort]
shl eax, 16
mov [edi+4], eax
; dword 2: the Transaction Translator, if the device is served by one.
mov eax, [ebx+xhci_pipe.TTSlot]
test eax, eax
jz @f
mov edx, [ebx+xhci_pipe.TTPort]
shl edx, 8
or eax, edx
@@:
mov [edi+8], eax
and dword [edi+12], 0
pop edi edx ecx eax
ret
endp
; Fills the Endpoint Context of the Input Context for the given pipe.
; The caller must hold CmdLock.
; in: esi -> usb_controller, ebx -> xhci_pipe.
proc xhci_fill_ep_ctx
push eax ecx edx edi
mov eax, [esi+xhci_controller.InputCtx-XCD]
mov ecx, [ebx+xhci_pipe.DCI]
inc ecx
call xhci_context
mov edi, eax
; dword 0: Interval.
mov eax, [ebx+xhci_pipe.Interval]
shl eax, 16
mov [edi], eax
; dword 1: Error Count, Endpoint Type, Max Burst Size and Max Packet Size.
mov eax, [ebx+xhci_pipe.EpType]
shl eax, 3
or eax, 3 shl 1 ; three retries before giving up
mov edx, [ebx+xhci_pipe.MaxPacket]
mov ecx, edx
shr ecx, 11
and ecx, 3 ; extra transactions per microframe
shl ecx, 8
or eax, ecx
if XHCI_SUPERSPEED
; A SuperSpeed bulk endpoint may allow bursts of several packets; the field
; shares its bits with the extra-transactions ones, which are zero then.
mov ecx, [ebx+xhci_pipe.MaxBurst]
shl ecx, 8
or eax, ecx
end if
and edx, 7FFh
shl edx, 16
or eax, edx
mov [edi+4], eax
; dwords 2 and 3: the TR Dequeue Pointer with the Dequeue Cycle State.
mov eax, [ebx+xhci_pipe.Enqueue]
shl eax, 4
add eax, [ebx+xhci_pipe.RingPhys]
or eax, [ebx+xhci_pipe.Cycle]
mov [edi+8], eax
and dword [edi+12], 0
; dword 4: Average TRB Length, only a hint for the bandwidth scheduler.
mov eax, [ebx+xhci_pipe.MaxPacket]
and eax, 7FFh
cmp [ebx+xhci_pipe.EpType], XHCI_EP_CONTROL
jnz @f
movi eax, 8
@@:
mov [edi+16], eax
and dword [edi+20], 0
pop edi edx ecx eax
ret
endp
; =============================================================================
; ============================== Slot commands ================================
; =============================================================================
; Issues the Address Device command for a newly created default control pipe.
; in: esi -> usb_controller, ebx -> xhci_pipe. out: eax = 0 on failure.
proc xhci_address_device
push ebx ecx edx edi
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
mov edx, [esi+xhci_controller.InputCtx-XCD]
mov dword [edx+4], 3 ; add the Slot Context and endpoint zero
movi ecx, 1
call xhci_fill_slot_ctx
call xhci_fill_ep_ctx
mov [ebx+xhci_pipe.MaxDCI], 1
; Point the DCBAA entry of the slot at the Device Context.
mov eax, [esi+xhci_controller.CommonPage-XCD]
mov ecx, [ebx+xhci_pipe.SlotId]
mov edx, [ebx+xhci_pipe.DevPagePhys]
mov [eax+ecx*8], edx
and dword [eax+ecx*8+4], 0
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_ADDRESS_DEV shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
push ebx
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
pop ebx
push eax
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
pop eax
cmp eax, XHCI_CC_SUCCESS
jz .ok
DEBUGF 1,'K : XHCI: Address Device failed, code %d\n',eax
xor eax, eax
jmp .nothing
.ok:
movi eax, 1
.nothing:
pop edi edx ecx ebx
ret
endp
; Issues a Configure Endpoint command that adds the given endpoint.
; in: esi -> usb_controller, ebx -> xhci_pipe of the endpoint,
; edi -> xhci_pipe of the default control endpoint of the same device.
; out: eax = completion code.
proc xhci_configure_endpoint
push ebx ecx edx esi edi
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
; Drop the endpoint and add it again, so that reopening an endpoint that has
; been closed before also works.
mov ecx, [ebx+xhci_pipe.DCI]
movi eax, 1
shl eax, cl
mov edx, [esi+xhci_controller.InputCtx-XCD]
mov [edx], eax
or eax, 1 ; the Slot Context is always added
mov [edx+4], eax
call xhci_fill_ep_ctx
; The Context Entries field must cover every endpoint in use by the device.
mov ecx, [ebx+xhci_pipe.DCI]
cmp ecx, [edi+xhci_pipe.MaxDCI]
jae @f
mov ecx, [edi+xhci_pipe.MaxDCI]
@@:
mov [edi+xhci_pipe.MaxDCI], ecx
push ebx
mov ebx, edi
call xhci_fill_slot_ctx
pop ebx
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_CONFIG_EP shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
push ebx
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
pop ebx
push eax
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
pop eax
pop edi esi edx ecx ebx
ret
endp
; Tells the controller where the endpoint has to continue from.
; in: esi -> usb_controller, ebx -> xhci_pipe.
proc xhci_set_dequeue
pushad
cmp [ebx+xhci_pipe.SlotId], 0
jz .nothing
mov eax, [ebx+xhci_pipe.Dequeue]
shl eax, 4
add eax, [ebx+xhci_pipe.RingPhys]
or eax, [ebx+xhci_pipe.Cycle]
mov ecx, [ebx+xhci_pipe.DCI]
shl ecx, 16
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, ecx
or edx, XHCI_TRB_SET_DEQ shl 10
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_sync
cmp eax, XHCI_CC_SUCCESS
jz .nothing
DEBUGF 1,'K : XHCI: Set TR Dequeue Pointer failed, code %d\n',eax
.nothing:
popad
ret
endp
; =============================================================================
; =============================== New device ==================================
; =============================================================================
; Called from xhci_port_init and from the hub support code when a new device
; has been connected and reset. Enables a device slot for it and hands it over
; to the protocol layer.
; in: esi -> usb_controller, eax = speed. out: eax = 0 on failure.
proc xhci_new_device
push ebx ecx edx edi
mov [esi+usb_controller.ResettingSpeed], al
; 1. Reserve room for the pseudo-pipe that describes the new device. Only the
; fields read by xhci_init_pipe are filled in; the layout matches a real pipe,
; so the result can be passed to usb_new_device as a usb_pipe pointer.
sub esp, sizeof.xhci_pipe + 4
mov ebx, esp
push ebx
mov edi, ebx
xor eax, eax
mov ecx, (sizeof.xhci_pipe + 4)/4
rep stosd
pop ebx
mov [ebx+sizeof.xhci_pipe], esi ; usb_pipe.Controller
movzx eax, [esi+usb_controller.ResettingSpeed]
mov [ebx+xhci_pipe.Speed], eax
; 2. Compute the root hub port, the route string and the tier of the device.
movzx edx, [esi+usb_controller.ResettingPort]
mov edi, [esi+usb_controller.ResettingHub]
test edi, edi
jnz .behind_hub
mov eax, [esi+xhci_controller.PortMap-XCD+edx*4]
mov [ebx+xhci_pipe.RootPort], eax
if XHCI_SUPERSPEED
mov eax, [esi+xhci_controller.ResettingPSIV-XCD]
mov [ebx+xhci_pipe.PSIV], eax
end if
jmp .have_topology
.behind_hub:
; The parent hub is a device too, and its own pipe carries the topology data.
mov eax, [edi+USB_HUB_CONFIGPIPE]
sub eax, sizeof.xhci_pipe
mov ecx, [eax+xhci_pipe.RootPort]
mov [ebx+xhci_pipe.RootPort], ecx
mov ecx, [eax+xhci_pipe.Depth]
mov eax, [eax+xhci_pipe.Route]
; The route string holds one nibble per tier, at most five of them.
cmp ecx, 5
jae .have_route
push ecx edx
shl ecx, 2
inc edx ; the route uses 1-based port numbers
cmp edx, 15
jbe @f
movi edx, 15
@@:
shl edx, cl
or eax, edx
pop edx ecx
.have_route:
inc ecx
mov [ebx+xhci_pipe.Depth], ecx
mov [ebx+xhci_pipe.Route], eax
; 3. Low- and full-speed devices behind a high-speed hub need the address of
; the Transaction Translator that serves them.
cmp [ebx+xhci_pipe.Speed], USB_SPEED_HS
jz .have_topology
push ebx
mov ecx, edx
mov edx, edi
invoke usbhc_api.usb_get_tt
pop ebx
test edx, edx
jz .have_topology
sub edx, sizeof.xhci_pipe
mov eax, [edx+xhci_pipe.SlotId]
mov [ebx+xhci_pipe.TTSlot], eax
inc ecx
mov [ebx+xhci_pipe.TTPort], ecx
.have_topology:
; 4. Ask the controller for a device slot.
xor eax, eax
push ebx
xor ebx, ebx
xor ecx, ecx
mov edx, XHCI_TRB_ENABLE_SLOT shl 10
call xhci_cmd_sync
pop ebx
cmp eax, XHCI_CC_SUCCESS
jnz .fail
test edx, edx
jz .fail
mov [ebx+xhci_pipe.SlotId], edx
DEBUGF 1,'K : XHCI new device: slot %d, root port %d, route %x, speed %d\n',edx,[ebx+xhci_pipe.RootPort],[ebx+xhci_pipe.Route],[ebx+xhci_pipe.Speed]
; 5. Hand the device over to the protocol layer. It opens the pipe of the
; default control endpoint, and that is where the slot is really addressed.
lea ecx, [ebx+sizeof.xhci_pipe]
invoke usbhc_api.usb_new_device
test eax, eax
jnz .done
; 6. The protocol layer has failed; release the slot again.
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_DISABLE_SLOT shl 10
xor eax, eax
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_sync
xor eax, eax
jmp .done
.fail:
dbgstr 'XHCI: Enable Slot failed'
xor eax, eax
.done:
add esp, sizeof.xhci_pipe + 4
pop edi edx ecx ebx
ret
endp
; =============================================================================
; ================================= Pipes =====================================
; =============================================================================
proc xhci_alloc_pipe
push ebx ecx edi
mov ebx, xhci_ep_mutex
invoke usbhc_api.usb_allocate_common, sizeof.xhci_pipe + sizeof.usb_pipe
test eax, eax
jz @f
; Zero the whole block: the kernel may call FreePipe for a pipe whose InitPipe
; has never run, and that path must not act on garbage.
mov edi, eax
push eax
xor eax, eax
movi ecx, (sizeof.xhci_pipe + sizeof.usb_pipe + 3)/4
rep stosd
pop eax
add eax, sizeof.xhci_pipe
@@:
pop edi ecx ebx
ret
endp
proc xhci_free_pipe stdcall, ptr:dword
push ebx esi edi
mov ebx, [ptr]
sub ebx, sizeof.xhci_pipe
mov esi, [ebx+sizeof.xhci_pipe+usb_pipe.Controller]
test esi, esi
jz .free
cmp [ebx+xhci_pipe.SlotId], 0
jz .drop_pipe
cmp [ebx+xhci_pipe.DCI], 1
jnz .drop_pipe
; This is the default control endpoint, that is, the handle of the whole
; device: release the slot together with the per-device page.
mov ecx, [ebx+xhci_pipe.SlotId]
mov edx, ecx
shl edx, 24
or edx, XHCI_TRB_DISABLE_SLOT shl 10
xor eax, eax
push ebx
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_sync
pop ebx
; The controller may access the Device Context until the command above
; completes, so only now may the DCBAA entry and the slot table forget it.
mov ecx, [ebx+xhci_pipe.SlotId]
mov edi, [esi+xhci_controller.CommonPage-XCD]
and dword [edi+ecx*8], 0
and dword [edi+ecx*8+4], 0
and [esi+xhci_controller.SlotPages-XCD+ecx*4], 0
mov eax, [ebx+xhci_pipe.DevPage]
test eax, eax
jz .drop_ring
invoke KernelFree, eax
and [ebx+xhci_pipe.DevPage], 0
jmp .drop_ring
.drop_pipe:
; Remove the pipe from the per-device table, if it is still listed there.
; On disconnect the kernel releases the pipes of a device in arbitrary order,
; and the pipe of the default control endpoint - the owner of the per-device
; page - may well be freed before this one, taking the page with it. The
; authoritative pointer is the one in SlotPages: it is cleared when the slot
; is released, so it can never point to freed memory.
mov ecx, [ebx+xhci_pipe.SlotId]
test ecx, ecx
jz .drop_ring
mov eax, [esi+xhci_controller.SlotPages-XCD+ecx*4]
test eax, eax
jz .drop_ring
mov ecx, [ebx+xhci_pipe.DCI]
cmp ecx, 32
jae .drop_ring
and dword [eax+XHCI_PIPES_OFS+ecx*4], 0
.drop_ring:
mov eax, [ebx+xhci_pipe.Ring]
test eax, eax
jz @f
invoke KernelFree, eax
and [ebx+xhci_pipe.Ring], 0
@@:
mov eax, [ebx+xhci_pipe.RingMap]
test eax, eax
jz .free
invoke KernelFree, eax
and [ebx+xhci_pipe.RingMap], 0
.free:
pop edi esi ebx
mov eax, [ptr]
sub eax, sizeof.xhci_pipe
invoke usbhc_api.usb_free_common, eax
ret
endp
; Allocates the transfer ring of a pipe.
; in: ebx -> xhci_pipe. out: eax = 0 on failure.
proc xhci_alloc_ring
push ecx edx
call xhci_alloc_page
test eax, eax
jz .nothing
mov [ebx+xhci_pipe.RingMap], eax
call xhci_alloc_page
test eax, eax
jnz @f
invoke KernelFree, [ebx+xhci_pipe.RingMap]
and [ebx+xhci_pipe.RingMap], 0
xor eax, eax
jmp .nothing
@@:
mov [ebx+xhci_pipe.Ring], eax
mov [ebx+xhci_pipe.RingPhys], edx
; The last entry returns to the beginning of the ring and toggles the cycle.
lea ecx, [eax+(XHCI_RING_TRBS-1)*16]
mov [ecx], edx
mov dword [ecx+12], (XHCI_TRB_LINK shl 10) + XHCI_TRB_TC
and [ebx+xhci_pipe.Enqueue], 0
and [ebx+xhci_pipe.Dequeue], 0
and [ebx+xhci_pipe.Reserved], 0
and [ebx+xhci_pipe.FirstFix], 0
mov [ebx+xhci_pipe.Cycle], XHCI_TRB_C
movi eax, 1
.nothing:
pop edx ecx
ret
endp
; Stores the pipe in the per-device table used by the event ring handler.
; in: ebx -> xhci_pipe.
proc xhci_register_pipe
push eax ecx edx
mov eax, [ebx+xhci_pipe.DevPage]
test eax, eax
jz @f
mov ecx, [ebx+xhci_pipe.DCI]
cmp ecx, 32
jae @f
lea edx, [ebx+sizeof.xhci_pipe]
mov [eax+XHCI_PIPES_OFS+ecx*4], edx
@@:
pop edx ecx eax
ret
endp
; Computes the Interval field of the Endpoint Context of an interrupt endpoint.
; The kernel passes bInterval from the endpoint descriptor: for high-speed
; devices it is an exponent of 125 us periods, for low- and full-speed devices
; it is a number of frames.
; in: ebx -> xhci_pipe, eax = bInterval.
proc xhci_calc_interval
push eax ecx
cmp [ebx+xhci_pipe.Speed], USB_SPEED_HS
jnz .low_speed
test eax, eax
jz @f
dec eax
@@:
jmp .clamp
.low_speed:
; One frame equals eight periods of 125 us, hence the offset of three.
test eax, eax
jnz @f
movi eax, 1
@@:
bsr ecx, eax
lea eax, [ecx+3]
.clamp:
cmp eax, 15
jbe @f
movi eax, 15
@@:
mov [ebx+xhci_pipe.Interval], eax
pop ecx eax
ret
endp
; Called from usb_open_pipe.
; in: edi -> usb_pipe for the target, ecx -> usb_pipe of the config pipe,
; esi -> usb_controller, eax -> usb_gtd of the first descriptor,
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type,
; [ebp+24] = interval.
; out: eax = 0 on failure.
proc xhci_init_pipe
virtual at ebp+8
.config_pipe dd ?
.endpoint dd ?
.maxpacket dd ?
.type dd ?
.interval dd ?
end virtual
push ebx
sub edi, sizeof.xhci_pipe
sub ecx, sizeof.xhci_pipe
mov ebx, edi ; ebx -> xhci_pipe being initialized
; 1. Copy the description of the device from the config pipe.
mov eax, [ecx+xhci_pipe.SlotId]
mov [ebx+xhci_pipe.SlotId], eax
mov eax, [ecx+xhci_pipe.DevPage]
mov [ebx+xhci_pipe.DevPage], eax
mov eax, [ecx+xhci_pipe.DevPagePhys]
mov [ebx+xhci_pipe.DevPagePhys], eax
mov eax, [ecx+xhci_pipe.Speed]
mov [ebx+xhci_pipe.Speed], eax
mov eax, [ecx+xhci_pipe.RootPort]
mov [ebx+xhci_pipe.RootPort], eax
mov eax, [ecx+xhci_pipe.Route]
mov [ebx+xhci_pipe.Route], eax
mov eax, [ecx+xhci_pipe.Depth]
mov [ebx+xhci_pipe.Depth], eax
mov eax, [ecx+xhci_pipe.TTSlot]
mov [ebx+xhci_pipe.TTSlot], eax
mov eax, [ecx+xhci_pipe.TTPort]
mov [ebx+xhci_pipe.TTPort], eax
if XHCI_SUPERSPEED
mov eax, [ecx+xhci_pipe.PSIV]
mov [ebx+xhci_pipe.PSIV], eax
end if
; 2. Work out the Device Context Index and the endpoint type.
mov eax, [.endpoint]
test eax, eax
jz .control_ep
mov ecx, eax
and ecx, 15
add ecx, ecx
test al, 80h
jz @f
inc ecx
or [ebx+xhci_pipe.Flags], XHCI_PIPE_IN
@@:
mov [ebx+xhci_pipe.DCI], ecx
mov eax, [.type]
cmp eax, BULK_PIPE
jz .bulk
cmp eax, INTERRUPT_PIPE
jz .interrupt
; A control endpoint other than endpoint zero is unusual but legal.
mov [ebx+xhci_pipe.EpType], XHCI_EP_CONTROL
jmp .have_type
.bulk:
movi eax, XHCI_EP_BULK_OUT
test [ebx+xhci_pipe.Flags], XHCI_PIPE_IN
jz @f
movi eax, XHCI_EP_BULK_IN
@@:
mov [ebx+xhci_pipe.EpType], eax
jmp .have_type
.interrupt:
movi eax, XHCI_EP_INT_OUT
test [ebx+xhci_pipe.Flags], XHCI_PIPE_IN
jz @f
movi eax, XHCI_EP_INT_IN
@@:
mov [ebx+xhci_pipe.EpType], eax
mov eax, [.interval]
call xhci_calc_interval
.have_type:
mov eax, [.maxpacket]
mov [ebx+xhci_pipe.MaxPacket], eax
if XHCI_SUPERSPEED
call xhci_ss_get_burst
end if
jmp .alloc_ring
.control_ep:
; The default control endpoint always has index one. Until the real packet size
; is known from the device descriptor, use the value the specification requires
; for the speed of the device: the kernel asks for 64 regardless of the speed,
; which is wrong for low- and full-speed devices.
mov [ebx+xhci_pipe.DCI], 1
mov [ebx+xhci_pipe.EpType], XHCI_EP_CONTROL
movi eax, 64
cmp [ebx+xhci_pipe.Speed], USB_SPEED_HS
jz @f
movi eax, 8
@@:
if XHCI_SUPERSPEED
; A SuperSpeed device always uses 512 bytes on the default control endpoint.
cmp [ebx+xhci_pipe.PSIV], XHCI_PSI_SS
jb @f
mov eax, 512
@@:
end if
mov [ebx+xhci_pipe.MaxPacket], eax
.alloc_ring:
; 3. Allocate the transfer ring.
call xhci_alloc_ring
test eax, eax
jz .fail
; 4. Choose the software list the pipe belongs to and insert it there. The
; hardware knows nothing about these lists; they exist only so that the kernel
; can walk all pipes and reinsert an aborted one.
lea edx, [esi+xhci_controller.ControlED-XCD]
cmp [.type], BULK_PIPE
jb @f
lea edx, [esi+xhci_controller.BulkED-XCD]
jz @f
lea edx, [esi+xhci_controller.IntED-XCD]
@@:
lea edi, [ebx+sizeof.xhci_pipe]
mov [edi+usb_pipe.BaseList], edx
mov ecx, [edx+usb_pipe.NextVirt]
mov [edi+usb_pipe.NextVirt], ecx
mov [edi+usb_pipe.PrevVirt], edx
mov [ecx+usb_pipe.PrevVirt], edi
mov [edx+usb_pipe.NextVirt], edi
; 5. Now do the hardware part.
cmp [.endpoint], 0
jz .address_device
call xhci_register_pipe
mov edi, [.config_pipe]
sub edi, sizeof.xhci_pipe
call xhci_configure_endpoint
xhci_trace 'K : XHCI open pipe: slot %d dci %d\n', [ebx+xhci_pipe.SlotId], [ebx+xhci_pipe.DCI]
cmp eax, XHCI_CC_SUCCESS
jz .success
DEBUGF 1,'K : XHCI: Configure Endpoint failed, code %d\n',eax
jmp .unlink_fail
.address_device:
; 6. This is a new device: allocate its Device Context, publish the slot and
; let the controller give the device a bus address.
call xhci_alloc_page
test eax, eax
jz .unlink_fail
mov [ebx+xhci_pipe.DevPage], eax
mov [ebx+xhci_pipe.DevPagePhys], edx
mov ecx, [ebx+xhci_pipe.SlotId]
mov [esi+xhci_controller.SlotPages-XCD+ecx*4], eax
call xhci_register_pipe
call xhci_address_device
test eax, eax
jz .free_devpage
.success:
; usb_open_pipe keeps the pointer to the new pipe in edi across this call, so
; it has to be handed back untouched; the branch above has overwritten it with
; the pipe of the default control endpoint.
lea edi, [ebx+sizeof.xhci_pipe]
pop ebx
movi eax, 1
ret
.free_devpage:
mov ecx, [ebx+xhci_pipe.SlotId]
and [esi+xhci_controller.SlotPages-XCD+ecx*4], 0
mov eax, [ebx+xhci_pipe.DevPage]
invoke KernelFree, eax
and [ebx+xhci_pipe.DevPage], 0
.unlink_fail:
; Undo the insertion into the software list before failing.
lea edi, [ebx+sizeof.xhci_pipe]
mov eax, [edi+usb_pipe.NextVirt]
mov edx, [edi+usb_pipe.PrevVirt]
mov [eax+usb_pipe.PrevVirt], edx
mov [edx+usb_pipe.NextVirt], eax
.fail:
lea edi, [ebx+sizeof.xhci_pipe]
pop ebx
xor eax, eax
ret
endp
; Removes the pipe from the hardware configuration of the device.
; in: esi -> usb_controller, ebx -> usb_pipe.
proc xhci_unlink_pipe
pushad
sub ebx, sizeof.xhci_pipe
cmp [ebx+xhci_pipe.SlotId], 0
jz .nothing
cmp [ebx+xhci_pipe.DCI], 1
jz .nothing ; the slot itself is released by FreePipe
call xhci_ctrl_pipe
test eax, eax
jz .nothing
mov edi, eax ; edi -> pipe of endpoint zero
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
mov ecx, [ebx+xhci_pipe.DCI]
movi eax, 1
shl eax, cl
mov edx, [esi+xhci_controller.InputCtx-XCD]
mov [edx], eax ; drop this endpoint
mov dword [edx+4], 1 ; keep the Slot Context
mov ecx, [edi+xhci_pipe.MaxDCI]
test ecx, ecx
jnz @f
movi ecx, 1
@@:
push ebx
mov ebx, edi
call xhci_fill_slot_ctx
pop ebx
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_CONFIG_EP shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
.nothing:
popad
ret
endp
; Temporarily removes the pipe from the hardware schedule.
; in: esi -> usb_controller, ebx -> usb_pipe.
proc xhci_disable_pipe
pushad
sub ebx, sizeof.xhci_pipe
cmp [ebx+xhci_pipe.SlotId], 0
jz .nothing
mov ecx, [ebx+xhci_pipe.DCI]
shl ecx, 16
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, ecx
or edx, XHCI_TRB_STOP_EP shl 10
xor eax, eax
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_sync
.nothing:
popad
ret
endp
; Reinserts the pipe into the hardware schedule after xhci_disable_pipe, with
; an empty transfer queue.
; in: esi -> usb_controller, ebx -> usb_pipe,
; edx -> current descriptor, eax -> new last descriptor.
proc xhci_enable_pipe
pushad
sub ebx, sizeof.xhci_pipe
mov eax, [ebx+xhci_pipe.Ring]
test eax, eax
jz .nothing
; The queue is empty now, so the ring can be restarted from its beginning.
mov edi, eax
xor eax, eax
mov ecx, 0x1000/4
rep stosd
mov edi, [ebx+xhci_pipe.RingMap]
mov ecx, 0x1000/4
rep stosd
mov edi, [ebx+xhci_pipe.Ring]
add edi, (XHCI_RING_TRBS-1)*16
mov eax, [ebx+xhci_pipe.RingPhys]
mov [edi], eax
mov dword [edi+12], (XHCI_TRB_LINK shl 10) + XHCI_TRB_TC
and [ebx+xhci_pipe.Enqueue], 0
and [ebx+xhci_pipe.Dequeue], 0
and [ebx+xhci_pipe.Reserved], 0
and [ebx+xhci_pipe.FirstFix], 0
mov [ebx+xhci_pipe.Cycle], XHCI_TRB_C
call xhci_set_dequeue
.nothing:
popad
ret
endp
; =============================================================================
; ========================== Address and packet size ==========================
; =============================================================================
; Called from usb_set_address_callback. The bus address is chosen by the
; controller itself while executing the Address Device command, so the only
; thing left to do is to remember the number the kernel has reserved: it asks
; for it back on disconnect in order to mark it free again.
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address.
proc xhci_set_device_address
movzx eax, cl
mov [ebx+xhci_pipe.Address-sizeof.xhci_pipe], eax
jmp [usbhc_api.usb_subscribe_control]
endp
; in: esi -> usb_controller, ebx -> usb_pipe. out: eax = address.
proc xhci_get_device_address
mov eax, [ebx+xhci_pipe.Address-sizeof.xhci_pipe]
ret
endp
; Called from usb_get_descr8_callback once the real packet size of the default
; control endpoint is known. On xHCI that value lives in the Endpoint Context,
; so an Evaluate Context command is needed to update it.
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size.
proc xhci_set_endpoint_packet_size
push ebx ecx edx edi
sub ebx, sizeof.xhci_pipe
if XHCI_SUPERSPEED
; For a SuperSpeed device bMaxPacketSize0 is an exponent, and the only value
; the specification allows is 9: use 512 directly instead of the raw byte.
cmp [ebx+xhci_pipe.PSIV], XHCI_PSI_SS
jb @f
mov ecx, 512
@@:
end if
mov [ebx+xhci_pipe.MaxPacket], ecx
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
mov edx, [esi+xhci_controller.InputCtx-XCD]
mov dword [edx+4], 2 ; evaluate the default control endpoint
call xhci_fill_ep_ctx
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_EVAL_CTX shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
push ebx
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
pop ebx
cmp eax, XHCI_CC_SUCCESS
jz @f
DEBUGF 1,'K : XHCI: Evaluate Context failed, code %d\n',eax
@@:
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
pop edi edx ecx ebx
jmp [usbhc_api.usb_subscribe_control]
endp
; If the descriptor that has just completed is the answer to a request for the
; hub descriptor, tell the controller that the device is a hub: it has to know
; that in order to serve the devices behind it.
; in: ebx -> usb_gtd.
proc xhci_check_hub_descriptor
pushad
cmp [ebx+usb_gtd.Callback], 0
jz .nothing
mov eax, [ebx+usb_gtd.Pipe]
mov esi, [eax+usb_pipe.Controller]
sub eax, sizeof.xhci_pipe
test [eax+xhci_pipe.Flags], XHCI_PIPE_HUBPEND
jz .nothing
and [eax+xhci_pipe.Flags], not XHCI_PIPE_HUBPEND
cmp [ebx+xhci_gtd.Status-sizeof.xhci_gtd], XHCI_CC_SUCCESS
jnz .nothing
mov edx, [eax+xhci_pipe.HubBuf]
test edx, edx
jz .nothing
cmp byte [edx+1], 29h ; bDescriptorType
jnz .nothing
or [eax+xhci_pipe.Flags], XHCI_PIPE_ISHUB
mov ebx, eax ; ebx -> xhci_pipe of the hub
movzx edi, byte [edx+2] ; bNbrPorts
movzx ebp, byte [edx+3] ; low byte of wHubCharacteristics
shr ebp, 5
and ebp, 3 ; Transaction Translator Think Time
DEBUGF 1,'K : XHCI: device on slot %d is a hub with %d ports\n',[ebx+xhci_pipe.SlotId],edi
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
mov eax, [esi+xhci_controller.InputCtx-XCD]
mov dword [eax+4], 1 ; only the Slot Context is evaluated
mov ecx, [ebx+xhci_pipe.MaxDCI]
test ecx, ecx
jnz @f
movi ecx, 1
@@:
call xhci_fill_slot_ctx
; Patch the Slot Context with the fields that describe a hub. Only Configure
; Endpoint takes them into account, Evaluate Context would ignore them.
mov eax, [esi+xhci_controller.InputCtx-XCD]
movi ecx, 1
call xhci_context
or dword [eax], 1 shl 26 ; this device is a hub
cmp [ebx+xhci_pipe.Speed], USB_SPEED_HS
jnz @f
shl ebp, 16
or [eax+8], ebp
@@:
shl edi, 24
or [eax+4], edi ; Number of Ports
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_CONFIG_EP shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
cmp eax, XHCI_CC_SUCCESS
jz @f
DEBUGF 1,'K : XHCI: cannot mark the device as a hub, code %d\n',eax
@@:
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
.nothing:
popad
ret
endp
-135
View File
@@ -1,135 +0,0 @@
; SuperSpeed support for the xHCI driver, included from xhci.asm when
; XHCI_SUPERSPEED is enabled. The pieces too small to live here - the port
; map, the Slot Context speed, the 512-byte default control endpoint, the
; Max Burst field of the Endpoint Context - sit in the other files under
; "if XHCI_SUPERSPEED" guards; this file keeps the self-contained procedures.
;
; The kernel USB stack knows nothing about SuperSpeed, so it never learns
; about it: a SuperSpeed device is announced as a high-speed one, which also
; keeps the Transaction Translator logic away from it. The raw PORTSC speed
; identifier travels in xhci_pipe.PSIV instead and reaches everything that
; really needs it. SuperSpeed hubs are not supported: the kernel only speaks
; the USB2 hub protocol, so a device behind a USB3 hub is served by the USB2
; half of that hub at high speed.
; =============================================================================
; ============================ SuperSpeed ports ===============================
; =============================================================================
; Called from xhci_new_port for a SuperSpeed root port instead of the USB2
; reset entry point: a SuperSpeed link trains itself and the port enables
; itself on connect, reporting the speed with no reset at all. When the link
; is already up, skip straight to the reset recovery stage, after which
; xhci_port_init picks the device up; otherwise try a warm reset.
; in: esi -> usb_controller, ecx = port index.
proc xhci_ss_start_port
push eax edx
and [esi+usb_controller.ResettingHub], 0
mov [esi+usb_controller.ResettingPort], cl
push ecx
invoke GetTimerTicks
pop ecx
mov [esi+usb_controller.ResetTime], eax
mov [esi+xhci_controller.ResetStart-XCD], eax
call xhci_port_reg
mov eax, [edx]
test al, XHCI_PORT_PED
jz .warm_reset
mov [esi+usb_controller.ResettingStatus], 2
DEBUGF 1,'K : XHCI %x: SS port %d link is up, PORTSC=%x\n',esi,ecx,eax
jmp .nothing
.warm_reset:
; Connected, but the link has not come up. The Port Reset bit is set while a
; warm reset is running, so the ordinary reset-wait machinery in
; xhci_port_reset_done serves this case unchanged; the extra WRC change bit is
; acknowledged there together with the usual ones.
mov dword [edx], XHCI_PORT_PP + XHCI_PORT_WPR
mov [esi+usb_controller.ResettingStatus], 1
DEBUGF 1,'K : XHCI %x: warm-resetting port %d, PORTSC=%x\n',esi,ecx,eax
.nothing:
pop edx eax
ret
endp
; The kernel restarts pending root ports through the NewPortReset entry of
; usb_hardware_func directly, bypassing xhci_new_port; SuperSpeed ports must
; not get the USB2 reset on that path either, so the entry points here.
; in: esi -> usb_controller, ecx = port index.
proc xhci_ss_port_reset
bt [esi+xhci_controller.SSPortMask-XCD], ecx
jnc xhci_new_port.reset
call xhci_ss_start_port
ret
endp
; =============================================================================
; ===================== Endpoint Companion descriptors ========================
; =============================================================================
; Reads the SuperSpeed Endpoint Companion descriptor of a bulk endpoint and
; keeps its bMaxBurst for the Endpoint Context, allowing bursts of up to
; bMaxBurst+1 packets per transaction. Zero (no bursts) is always legal, so
; any failure just leaves the field alone. Only bulk endpoints are considered:
; a nonzero burst on a periodic endpoint would also require the Max ESIT
; Payload fields, and real interrupt endpoints do not burst anyway.
; Relies on the stack frame of usb_open_pipe exactly like xhci_init_pipe does:
; [ebp+8] is the config pipe of the device.
; in: ebx -> xhci_pipe of a non-control endpoint being opened.
proc xhci_ss_get_burst
push eax ecx edx edi
; 1. Only SuperSpeed bulk endpoints are of interest.
cmp [ebx+xhci_pipe.PSIV], XHCI_PSI_SS
jb .nothing
mov eax, [ebx+xhci_pipe.EpType]
and al, 3
cmp al, 2 ; bulk endpoint types are 2 and 6
jnz .nothing
; 2. Find the configuration data kept by the kernel behind the device
; descriptor; it holds the endpoint descriptors with their companions.
mov eax, [ebp+8]
mov eax, [eax+usb_pipe.DeviceData]
test eax, eax
jz .nothing
movzx edx, [eax+usb_device_data.DeviceDescrSize]
mov edi, [eax+usb_device_data.ConfigDataSize]
lea ecx, [eax+edx+usb_device_data.DeviceDescriptor]
add edi, ecx ; edi -> end of the configuration data
; 3. Reconstruct bEndpointAddress from the Device Context Index.
mov edx, [ebx+xhci_pipe.DCI]
shr edx, 1
test [ebx+xhci_pipe.Flags], XHCI_PIPE_IN
jz @f
or dl, 80h
@@:
; 4. Walk the descriptors to the one of this endpoint.
.walk:
lea eax, [ecx+2]
cmp eax, edi
ja .nothing
movzx eax, byte [ecx] ; bLength
test eax, eax
jz .nothing ; malformed data, stop
cmp byte [ecx+1], 5 ; an endpoint descriptor?
jnz .advance
cmp [ecx+2], dl ; bEndpointAddress
jnz .advance
; 5. The companion descriptor (type 30h) immediately follows its endpoint.
add ecx, eax
lea eax, [ecx+3]
cmp eax, edi
ja .nothing
cmp byte [ecx+1], 30h ; SuperSpeed Endpoint Companion
jnz .nothing
movzx eax, byte [ecx+2] ; bMaxBurst
cmp eax, 15
ja .nothing
mov [ebx+xhci_pipe.MaxBurst], eax
DEBUGF 1,'K : XHCI: slot %d dci %d bursts %d+1 packets\n',[ebx+xhci_pipe.SlotId],[ebx+xhci_pipe.DCI],eax
jmp .nothing
.advance:
add ecx, eax
jmp .walk
.nothing:
pop edi edx ecx eax
ret
endp
File diff suppressed because it is too large. Load diff
+187 -1764
View File
File diff suppressed because it is too large. Load diff
+5 -16
View File
@@ -842,7 +842,8 @@ disk_scan_partitions:
cmp ebx, mbr_buffer
jz .release_partition_buffer
; 15b. If we have allocated it, free it.
stdcall kernel_free, ebx
xchg eax, ebx
call free
jmp .nothing
; 15c. Otherwise, release reference.
.release_partition_buffer:
@@ -1488,31 +1489,19 @@ dyndisk_handler:
; 12. The fs operation has specified some partition.
push edx ecx
xor eax, eax
mov ecx, eax
lodsb
@@:
lea ecx, [ecx*4 + ecx]
shl ecx, 1
sub eax, '0'
jb .dyndisk_cleanup
jz .dyndisk_cleanup
cmp eax, 10
jnc .dyndisk_cleanup
add ecx, eax
cmp ecx, MAX_NUM_PARTITIONS
ja .dyndisk_cleanup
mov ecx, eax
lodsb
cmp eax, '/'
jz @f
test eax, eax
jnz @b
jnz .dyndisk_cleanup
dec esi
@@:
test ecx, ecx
jz .dyndisk_cleanup
cmp byte [esi], 0
jnz @f
; partition info
+1 -6
View File
@@ -183,8 +183,6 @@ EFLAGS_ID = 0x200000 ; id flag
IRQ_PIC = 0
IRQ_APIC = 1
IO_MAP_SIZE = 65536/8 ; 8192 or 2 PAGE_SIZE
struct TSS
_back rw 2
_esp0 rd 1
@@ -292,9 +290,6 @@ sys_proc = OS_BASE + 0x008E000
SLOT_BASE = OS_BASE + 0x0090000
APPDATA_IDLE_THREAD = SLOT_BASE + sizeof.APPDATA*1 ; poiner to IDLE thread
APPDATA_OS_THREAD = SLOT_BASE + sizeof.APPDATA*2 ; poiner to OS thread
VGABasePtr = OS_BASE + 0x00A0000
virtual at OS_BASE + 0x05FFF80
@@ -575,7 +570,7 @@ struct APPDATA
ipc_start dd ? ;+160
ipc_size dd ? ;+164
occurred_events dd ? ;+168 ; mask which accumulates occurred events
debugger_thread dd ? ;+172 ; pointer to APPDATA or 0
debugger_slot dd ? ;+172 ; index in SLOT_BASE array
terminate_protection dd ? ;+176
keyboard_mode db ? ;+180
rb 3
+77 -41
View File
@@ -8,8 +8,8 @@
; diamond, 2006
sys_debug_services:
cmp ebx, sys_debug_services_table.count
jae @f
cmp ebx, 9
ja @f
jmp dword [sys_debug_services_table + ebx*4]
@@:
ret
@@ -26,9 +26,7 @@ sys_debug_services_table:
dd debug_write_process_memory
dd debug_terminate
dd debug_set_drx
.count = ($ - sys_debug_services_table)/4
endg
debug_set_event_data:
; in: ecx = pointer
; destroys eax
@@ -36,20 +34,22 @@ debug_set_event_data:
mov [eax + APPDATA.dbg_event_mem], ecx
ret
get_debuggee_thread:
get_debuggee_slot:
; in: ecx=PID
; out: CF=1 if error
; CF=0 and eax = pointer to APPDATA if ok
; CF=0 and eax=slot*0x20 if ok
; out: interrupts disabled
cli
mov eax, ecx
call pid_to_thread
call pid_to_slot
;call pid_to_appdata
test eax, eax
jz .ret_bad
shl eax, BSF sizeof.APPDATA
push ebx
mov ebx, [current_slot]
cmp [eax + APPDATA.debugger_thread], ebx
mov ebx, [current_slot_idx]
cmp [SLOT_BASE + eax + APPDATA.debugger_slot], ebx
;cmp [eax + APPDATA.debugger_slot], ebx
pop ebx
jnz .ret_bad
; clc ; automatically
@@ -61,9 +61,10 @@ get_debuggee_thread:
debug_detach:
; in: ecx=pid
; destroys eax,ebx
call get_debuggee_thread
call get_debuggee_slot
jc .ret
and dword [eax + APPDATA.debugger_thread], 0
and dword [eax + SLOT_BASE + APPDATA.debugger_slot], 0
;and dword [eax + APPDATA.debugger_slot], 0
call do_resume
.ret:
sti
@@ -71,27 +72,40 @@ debug_detach:
debug_terminate:
; in: ecx=pid
call get_debuggee_thread
call get_debuggee_slot
jc debug_detach.ret
mov ecx, eax
movzx ecx, ch ; del when sysfn_term... will using APPDATA
shr ecx, BSF sizeof.APPDATA
;movzx ecx, ch ; del when sysfn_term... will using APPDATA
; push 2
; pop ebx
mov edx, esi ; what?
jmp sysfn_terminate
debug_suspend:
; in: ecx=pid
; destroys eax,ecx
call get_debuggee_thread
; { Patch by Coldy (rev. 7125), reason: http://board.kolibrios.org/viewtopic.php?f=1&t=1712&p=75957#p75957
; cli
; mov eax, ecx
; call pid_to_slot
; shl eax, 5
; jz .ret
call get_debuggee_slot
jc .ret
mov cl, [eax + APPDATA.state] ; process state
; } End patch
mov cl, [SLOT_BASE + eax + APPDATA.state] ; process state
;mov cl, [eax + APPDATA.state] ; process state
test cl, cl
jz .1
cmp cl, TSTATE_WAITING
jnz .ret
mov cl, TSTATE_WAIT_SUSPENDED
.2:
mov [eax + APPDATA.state], cl
mov [SLOT_BASE + eax + APPDATA.state], cl
;mov [eax + APPDATA.state], cl
.ret:
sti
ret
@@ -100,14 +114,16 @@ debug_suspend:
jmp .2
do_resume:
mov cl, [eax + APPDATA.state]
mov cl, [SLOT_BASE + eax + APPDATA.state]
;mov cl, [eax + APPDATA.state]
cmp cl, TSTATE_RUN_SUSPENDED
jz .1
cmp cl, TSTATE_WAIT_SUSPENDED
jnz .ret
mov cl, TSTATE_WAITING
.2:
mov [eax + APPDATA.state], cl
mov [SLOT_BASE + eax + APPDATA.state], cl
;mov [eax + APPDATA.state], cl
.ret:
ret
.1:
@@ -117,9 +133,11 @@ do_resume:
debug_resume:
; in: ecx=pid
; destroys eax,ebx
call get_debuggee_thread
jc .ret
cli
mov eax, ecx
call pid_to_slot
shl eax, BSF sizeof.APPDATA
jz .ret
call do_resume
.ret:
sti
@@ -142,15 +160,21 @@ debug_getcontext:
inc ebx ; 1 - get sse context
; TODO legacy 32-bit FPU/MMX context
.std_ctx:
call get_debuggee_thread
call get_debuggee_slot
jc .ret
shr eax, BSF sizeof.APPDATA
;movzx ebp, ah
cmp eax, [fpu_owner]
;cmp ebp, [fpu_owner]
jne @f
inc bh ; set swap context flag
@@:
shl eax, BSF sizeof.APPDATA
mov edi, esi
mov eax, [eax + APPDATA.pl0_stack]
mov eax, [SLOT_BASE + eax + APPDATA.pl0_stack]
;mov eax, [eax + APPDATA.pl0_stack]
lea esi, [eax + RING0_STACK_SIZE]
.ring0:
@@ -216,10 +240,11 @@ debug_setcontext:
cmp edx, 28h
jnz .ret
call get_debuggee_thread
call get_debuggee_slot
jc .stiret
mov eax, [eax + APPDATA.pl0_stack]
; mov esi, edx
mov eax, [eax + SLOT_BASE+APPDATA.pl0_stack]
;mov eax, [eax + APPDATA.pl0_stack]
lea edi, [eax + RING0_STACK_SIZE]
.ring0:
@@ -252,16 +277,15 @@ debug_setcontext:
ret
debug_set_drx:
call get_debuggee_thread
call get_debuggee_slot
jc .errret
mov ebp, eax
lea eax, [eax + APPDATA.dbg_regs]
lea eax, [eax + SLOT_BASE + APPDATA.dbg_regs]
;lea eax, [eax + APPDATA.dbg_regs]
; [eax]=dr0, [eax+4]=dr1, [eax+8]=dr2, [eax+C]=dr3
; [eax+10]=dr7
cmp esi, OS_BASE
jae .errret
cmp dl, 3
ja .errret
mov ecx, dr7
@@ -282,7 +306,10 @@ debug_set_drx:
btr dword [eax + 10h], edx ; clear L<i> bit
test byte [eax + 10h], 55h
jnz .okret
and [ebp + APPDATA.dbg_state], not 1
; imul eax, ebp, tss_step/32
; and byte [eax + tss_data + TSS._trap], not 1
and [SLOT_BASE + ebp + APPDATA.dbg_state], not 1
;and [ebp + APPDATA.dbg_state], not 1
.okret:
and dword [esp + SYSCALL_STACK.eax], 0
sti
@@ -327,7 +354,10 @@ debug_set_drx:
not ebx
and [eax + 10h+2], bx
or [eax + 10h+2], dx ; set R/W and LEN fields
or [ebp + APPDATA.dbg_state], 1
; imul eax, ebp, tss_step/32
; or byte [eax + tss_data + TSS._trap], 1
or [SLOT_BASE + ebp + APPDATA.dbg_state], 1
;or [ebp + APPDATA.dbg_state], 1
jmp .okret
debug_read_process_memory:
@@ -338,9 +368,10 @@ debug_read_process_memory:
; esi=address in debuggee
; out: [esp+36]=sizeof(read)
; destroys all
call get_debuggee_thread
call get_debuggee_slot
jc .err
shr eax, BSF sizeof.APPDATA
;movzx eax,ah
mov ecx, edi
call read_process_memory
sti
@@ -358,9 +389,10 @@ debug_write_process_memory:
; esi=address in debuggee
; out: [esp+36]=sizeof(write)
; destroys all
call get_debuggee_thread
call get_debuggee_slot
jc debug_read_process_memory.err
shr eax, BSF sizeof.APPDATA
;movzx eax,ah
mov ecx, edi
call write_process_memory
sti
@@ -368,7 +400,7 @@ debug_write_process_memory:
ret
debugger_notify:
; in: eax=debugger thread
; in: eax=debugger slot
; ecx=size of debug message
; [esp+4]..[esp+4+ecx]=message
; interrupts must be disabled!
@@ -378,7 +410,9 @@ debugger_notify:
mov edi, [timer_ticks]
add edi, 500 ; 5 sec timeout
.1:
mov esi, [ebp + APPDATA.dbg_event_mem]
mov eax, ebp
shl eax, BSF sizeof.APPDATA
mov esi, [SLOT_BASE + eax + APPDATA.dbg_event_mem]
test esi, esi
jz .ret
; read buffer header
@@ -432,6 +466,8 @@ debugger_notify:
pop edx
call write_process_memory
; new debug event
or [ebp + APPDATA.occurred_events], EVENT_DEBUG
mov eax, ebp
shl eax, BSF sizeof.APPDATA
or [SLOT_BASE + eax + APPDATA.occurred_events], EVENT_DEBUG
.ret:
ret
+37 -49
View File
@@ -150,10 +150,10 @@ init_avx512:
ret
; param
; eax= 512 bytes memory area aligned on a 16-byte boundary
align 4
; @brief Export function - Save FPU context in buffer
; @param eax - 512 bytes memory area aligned on a 16-byte boundary
; @return not return
fpu_save:
push ecx
push esi
@@ -166,7 +166,7 @@ fpu_save:
mov edi, eax
mov ecx, [fpu_owner]
mov esi, [current_slot]
mov esi, [current_slot_idx]
cmp ecx, esi
jne .save
@@ -175,11 +175,14 @@ fpu_save:
.save:
mov [fpu_owner], esi
mov eax, [ecx + APPDATA.fpu_state]
shl ecx, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + ecx + APPDATA.fpu_state]
call save_context
; first 512 bytes of XSAVE area have the same format as FXSAVE
mov esi, [esi + APPDATA.fpu_state]
shl esi, BSF sizeof.APPDATA
mov esi, [SLOT_BASE + esi + APPDATA.fpu_state]
mov ecx, 512/4
cld
rep movsd
@@ -191,16 +194,14 @@ fpu_save:
pop ecx
ret
; @brief Export function - Get size from AVX context
; @return size of buffer
avx_save_size:
mov eax, [xsave_area_size]
ret
; param
; eax= avx_save_size() bytes memory area aligned on a 64-byte boundary
align 4
; @brief Export function - Save AVX context in buffer
; @param eax - avx_save_size() bytes memory area aligned on a 64-byte boundary
; @return not return
avx_save:
push ecx
push esi
@@ -213,7 +214,7 @@ avx_save:
mov edi, eax
mov ecx, [fpu_owner]
mov esi, [current_slot]
mov esi, [current_slot_idx]
cmp ecx, esi
jne .save
@@ -222,10 +223,13 @@ avx_save:
.save:
mov [fpu_owner], esi
mov eax, [ecx + APPDATA.fpu_state]
shl ecx, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + ecx + APPDATA.fpu_state]
call save_context
mov esi, [esi + APPDATA.fpu_state]
shl esi, BSF sizeof.APPDATA
mov esi, [SLOT_BASE + esi + APPDATA.fpu_state]
mov ecx, [xsave_area_size]
add ecx, 3
shr ecx, 2
@@ -260,13 +264,9 @@ save_fpu_context:
align 4
; @brief Export function - Restore FPU context
; @param eax - 512 bytes memory area aligned on a 16-byte boundary
; @return not return
fpu_restore:
push ecx
push esi
push edi
mov esi, eax
@@ -274,7 +274,7 @@ fpu_restore:
cli
mov ecx, [fpu_owner]
mov eax, [current_slot]
mov eax, [current_slot_idx]
cmp ecx, eax
jne .copy
@@ -284,8 +284,6 @@ fpu_restore:
fxrstor [esi]
popfd
pop edi
pop esi
pop ecx
ret
@@ -293,31 +291,24 @@ fpu_restore:
fnclex ;fix possible problems
frstor [esi]
popfd
pop edi
pop esi
pop ecx
ret
.copy:
mov edi, [eax + APPDATA.fpu_state]
shl eax, BSF sizeof.APPDATA
mov edi, [SLOT_BASE + eax + APPDATA.fpu_state]
mov ecx, 512/4
cld
rep movsd
popfd
pop edi
pop esi
pop ecx
ret
align 4
; @brief Export function - Restore AVX context
; @param eax - avx_save_size() bytes memory area aligned on a 64-byte boundary
; @return not return
avx_restore:
push ecx
push esi
push edi
mov esi, eax
@@ -325,7 +316,7 @@ avx_restore:
cli
mov ecx, [fpu_owner]
mov eax, [current_slot]
mov eax, [current_slot_idx]
cmp ecx, eax
jne .copy
@@ -338,8 +329,6 @@ avx_restore:
xrstor [esi]
pop edx
popfd
pop edi
pop esi
pop ecx
ret
@@ -349,8 +338,6 @@ avx_restore:
fxrstor [esi]
popfd
pop edi
pop esi
pop ecx
ret
@@ -358,21 +345,18 @@ avx_restore:
fnclex ;fix possible problems
frstor [esi]
popfd
pop edi
pop esi
pop ecx
ret
.copy:
mov edi, [eax + APPDATA.fpu_state]
shl eax, BSF sizeof.APPDATA
mov edi, [SLOT_BASE + eax + APPDATA.fpu_state]
mov ecx, [xsave_area_size]
add ecx, 3
shr ecx, 2
cld
rep movsd
popfd
pop edi
pop esi
pop ecx
ret
@@ -386,19 +370,21 @@ except_7: ;#NM exception handler
mov es, ax
mov ebx, [fpu_owner]
cmp ebx, [current_slot]
cmp ebx, [current_slot_idx]
je .exit
mov eax, [ebx + APPDATA.fpu_state]
shl ebx, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + ebx + APPDATA.fpu_state]
bt [cpu_caps + (CAPS_OSXSAVE/32)*4], CAPS_OSXSAVE mod 32
jnc .no_xsave
mov ecx, eax
mov eax, [xsave_eax]
mov edx, [xsave_edx]
xsave [ecx]
mov ebx, [current_slot]
mov ebx, [current_slot_idx]
mov [fpu_owner], ebx
mov ecx, [ebx + APPDATA.fpu_state]
shl ebx, BSF sizeof.APPDATA
mov ecx, [SLOT_BASE + ebx + APPDATA.fpu_state]
xrstor [ecx]
.exit:
restore_ring3_context
@@ -408,22 +394,24 @@ except_7: ;#NM exception handler
jnc .no_SSE
fxsave [eax]
mov ebx, [current_slot]
mov ebx, [current_slot_idx]
mov [fpu_owner], ebx
mov eax, [ebx + APPDATA.fpu_state]
shl ebx, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + ebx + APPDATA.fpu_state]
fxrstor [eax]
restore_ring3_context
iret
.no_SSE:
fnsave [eax]
mov ebx, [current_slot]
mov ebx, [current_slot_idx]
mov [fpu_owner], ebx
mov eax, [ebx + APPDATA.fpu_state]
shl ebx, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + ebx + APPDATA.fpu_state]
frstor [eax]
restore_ring3_context
iret
iglobal
fpu_owner dd APPDATA_OS_THREAD
fpu_owner dd 2
endg
+26 -20
View File
@@ -605,7 +605,7 @@ proc page_fault_handler
mov edi, [.err_addr]
and edi, -PAGE_SIZE
mov ecx, PAGE_SIZE/4
mov ecx, 1024
xor eax, eax
;cld ;caller is duty for this
rep stosd
@@ -664,7 +664,7 @@ proc page_fault_handler
cmp ebx, tss._io_map_0
jb .fail
cmp ebx, tss._io_map_0 + IO_MAP_SIZE
cmp ebx, tss._io_map_0+8192
jae .fail
; io permission map
@@ -695,7 +695,7 @@ proc page_fault_handler
endp
; returns number of mapped bytes
proc map_mem_ipc stdcall, lin_addr:dword,thread:dword,\
proc map_mem_ipc stdcall, lin_addr:dword,slot:dword,\
ofs:dword,buf_size:dword,req_access:dword
locals
count dd ?
@@ -706,8 +706,9 @@ proc map_mem_ipc stdcall, lin_addr:dword,thread:dword,\
cmp [buf_size], 0
jz .exit
mov eax, [thread]
mov eax, [eax + APPDATA.process]
mov eax, [slot]
shl eax, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + eax + APPDATA.process]
test eax, eax
jz .exit
@@ -731,7 +732,7 @@ proc map_mem_ipc stdcall, lin_addr:dword,thread:dword,\
shr edx, 12
and edx, 0x3FF
.map:
stdcall safe_map_page, [process], [req_access], [ofs]
stdcall safe_map_page, [slot], [req_access], [ofs]
jnc .exit
add [count], PAGE_SIZE
add [ofs], PAGE_SIZE
@@ -757,7 +758,7 @@ proc map_mem_ipc stdcall, lin_addr:dword,thread:dword,\
ret
endp
proc map_memEx stdcall, lin_addr:dword,thread:dword,\
proc map_memEx stdcall, lin_addr:dword,slot:dword,\
ofs:dword,buf_size:dword,req_access:dword
locals
count dd ?
@@ -768,8 +769,9 @@ proc map_memEx stdcall, lin_addr:dword,thread:dword,\
cmp [buf_size], 0
jz .exit
mov eax, [thread]
mov eax, [eax + APPDATA.process]
mov eax, [slot]
shl eax, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + eax + APPDATA.process]
test eax, eax
jz .exit
@@ -793,7 +795,7 @@ proc map_memEx stdcall, lin_addr:dword,thread:dword,\
shr edx, 12
and edx, 0x3FF
.map:
stdcall safe_map_page, [process], [req_access], [ofs]
stdcall safe_map_page, [slot], [req_access], [ofs]
jnc .exit
add [count], PAGE_SIZE
add [ofs], PAGE_SIZE
@@ -824,7 +826,7 @@ endp
; in: edi = linear address to map
; out: CF cleared <=> failed
; destroys: only eax
proc safe_map_page stdcall, process:dword, req_access:dword, ofs:dword
proc safe_map_page stdcall, slot:dword, req_access:dword, ofs:dword
mov eax, [esi + edx*4]
test al, PG_READ
jz .not_present
@@ -859,7 +861,9 @@ proc safe_map_page stdcall, process:dword, req_access:dword, ofs:dword
cli
cld
push ebx ecx
mov eax, [process]
mov eax, [slot]
shl eax, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + eax + APPDATA.process]
mov eax, [eax + PROC.dlls_list_ptr]
test eax, eax
jz .no_hdll
@@ -949,7 +953,7 @@ sys_IPC:
proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
locals
dst_thread dd ?
dst_slot dd ?
dst_offset dd ?
buf_size dd ?
used_buf dd ?
@@ -959,12 +963,13 @@ proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
cli
mov eax, [PID]
call pid_to_thread
call pid_to_slot
test eax, eax
jz .no_pid
mov [dst_thread], eax
mov edi, [eax + APPDATA.ipc_start] ;is ipc area defined?
mov [dst_slot], eax
shl eax, BSF sizeof.APPDATA
mov edi, [SLOT_BASE + eax + APPDATA.ipc_start] ;is ipc area defined?
test edi, edi
jz .no_ipc_area
@@ -972,7 +977,7 @@ proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
and ebx, 0xFFF
mov [dst_offset], ebx
mov esi, [eax + APPDATA.ipc_size]
mov esi, [SLOT_BASE + eax + APPDATA.ipc_size]
mov [buf_size], esi
mov ecx, [ipc_tmp]
@@ -985,7 +990,7 @@ proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
pop edi esi
@@:
mov [used_buf], ecx
stdcall map_mem_ipc, ecx, [dst_thread], \
stdcall map_mem_ipc, ecx, [dst_slot], \
edi, esi, PG_SWR
mov edi, [dst_offset]
@@ -1034,8 +1039,9 @@ proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
mov [page_tabs + ebx*4], eax
invlpg [edx]
mov eax, [dst_thread]
or [eax + APPDATA.occurred_events], EVENT_IPC
mov eax, [dst_slot]
shl eax, BSF sizeof.APPDATA
or [SLOT_BASE + eax + APPDATA.occurred_events], EVENT_IPC
push 0
jmp .ret
.no_pid:
+3 -2
View File
@@ -139,13 +139,14 @@ do_change_task:
mov eax, [xsave_eax]
mov edx, [xsave_edx]
xsave [ecx]
mov ecx, [current_slot]
mov ecx, [current_slot_idx]
mov [fpu_owner], ecx
mov ecx, [current_slot]
mov ecx, [ecx + APPDATA.fpu_state]
xrstor [ecx]
.no_xsave:
; set CR0.TS
cmp ebx, [fpu_owner] ;ebx == incoming task (new)
cmp bh, byte[fpu_owner] ;bh == incoming task (new)
clts ;clear a task switch flag
je @f
mov eax, cr0 ;and set it again if the owner
+16 -19
View File
@@ -165,7 +165,7 @@ exc_c: ; exceptions (all but 7th - #NM)
jnz IRetToUserHook
@@:
cli
mov eax, [esi + APPDATA.debugger_thread]
mov eax, [esi + APPDATA.debugger_slot]
test eax, eax
jnz .debug
; not debuggee => say error and terminate
@@ -514,30 +514,28 @@ destroy_thread:
@@:
mov eax, [esi + APPOBJ.fd]
test eax, eax
jz @f
jz @F
cmp eax, esi
je @f
je @F
push esi
call [eax + APPOBJ.destroy]
DEBUGF 1,"%s",msg_obj_destroy
pop esi
jmp @b
jmp @B
@@:
mov esi, [.slot]
shl esi, BSF sizeof.APPDATA
add esi, SLOT_BASE
cmp [fpu_owner], esi ; if user fpu last -> fpu user = 2
jne @f
jne @F
mov [fpu_owner], APPDATA_OS_THREAD
mov eax, [APPDATA_OS_THREAD + APPDATA.fpu_state]
mov [fpu_owner], 2
mov eax, [SLOT_BASE + sizeof.APPDATA*2 + APPDATA.fpu_state]
clts
bt [cpu_caps], CAPS_SSE
jnc .no_SSE
fxrstor [eax]
jmp @f
jmp @F
.no_SSE:
fnclex
frstor [eax]
@@ -546,8 +544,8 @@ destroy_thread:
mov [KEY_COUNT], byte 0 ; empty keyboard buffer
mov [BTN_COUNT], byte 0 ; empty button buffer
; remove defined hotkeys
mov esi, [.slot]
mov eax, hotkey_list
.loop:
cmp [eax+8], esi
@@ -640,7 +638,7 @@ destroy_thread:
pushad
mov edi, esi
shl edi, BSF sizeof.APPDATA
mov eax, [SLOT_BASE + edi + APPDATA.debugger_thread]
mov eax, [SLOT_BASE + edi + APPDATA.debugger_slot]
test eax, eax
jz .nodebug
movi ecx, 8
@@ -668,12 +666,12 @@ destroy_thread:
add edi, SLOT_BASE
mov eax, [edi + APPDATA.io_map]
cmp eax, [APPDATA_IDLE_THREAD + APPDATA.io_map]
cmp eax, [SLOT_BASE + sizeof.APPDATA+APPDATA.io_map]
je @F
call free_page
@@:
mov eax, [edi+APPDATA.io_map+4]
cmp eax, [APPDATA_IDLE_THREAD + APPDATA.io_map+4]
cmp eax, [SLOT_BASE+sizeof.APPDATA+APPDATA.io_map+4]
je @F
call free_page
@@:
@@ -714,12 +712,12 @@ destroy_thread:
call free_cd_channel
and [cd_status], 0
@@:
pop esi
cmp [bgrlockpid], esi
jnz @f
and [bgrlockpid], 0
and [bgrlock], 0
@@:
pop esi
pusha ; remove all port reservations
mov edx, esi
@@ -780,15 +778,14 @@ destroy_thread:
mov edi, esi ; do not run this process slot
shl edi, BSF sizeof.APPDATA
add edi, SLOT_BASE
mov [edi + APPDATA.state], TSTATE_FREE
mov [SLOT_BASE + edi + APPDATA.state], TSTATE_FREE
; debugger test - terminate all debuggees
mov eax, 2
mov ecx, APPDATA_OS_THREAD + APPDATA.debugger_thread
mov ecx, SLOT_BASE + 2*sizeof.APPDATA + APPDATA.debugger_slot
.xd0:
cmp eax, [thread_count]
ja .xd1
cmp dword [ecx], edi
cmp dword [ecx], esi
jnz @f
and dword [ecx], 0
pushad
+22 -19
View File
@@ -537,21 +537,21 @@ pid_to_slot:
align 4
proc read_process_memory
;Input:
; eax - process thread
; eax - process slot
; ecx - buffer address
; edx - buffer size
; esi - start address in other process
;Output:
; eax - number of bytes read.
locals
thread dd ?
slot dd ?
buff dd ?
r_count dd ?
offset dd ?
tmp_r_cnt dd ?
endl
mov [thread], eax
mov [slot], eax
mov [buff], ecx
and [r_count], 0
mov [tmp_r_cnt], edx
@@ -577,7 +577,7 @@ proc read_process_memory
push ecx
stdcall map_memEx, [proc_mem_map], \
[thread], ebx, ecx, PG_READ
[slot], ebx, ecx, PG_READ
pop ecx
mov esi, [offset]
@@ -607,7 +607,7 @@ endp
align 4
proc write_process_memory
;Input:
; eax - process thread
; eax - process slot
; ecx - buffer address
; edx - buffer size
; esi - start address in other process
@@ -615,14 +615,14 @@ proc write_process_memory
; eax - number of bytes written
locals
thread dd ?
slot dd ?
buff dd ?
w_count dd ?
offset dd ?
tmp_w_cnt dd ?
endl
mov [thread], eax
mov [slot], eax
mov [buff], ecx
and [w_count], 0
mov [tmp_w_cnt], edx
@@ -647,7 +647,7 @@ proc write_process_memory
mov ebx, [offset]
push ecx
stdcall map_memEx, [proc_mem_map], \
[thread], ebx, ecx, PG_SWR
[slot], ebx, ecx, PG_SWR
pop ecx
mov edi, [offset]
@@ -906,7 +906,7 @@ common_app_entry:
stdcall free_kernel_space, [ebp+APP_HDR.img_base]
stdcall kernel_free, ebp
mov ebx, [current_slot]
cmp [ebx + APPDATA.debugger_thread], 0
cmp [ebx + APPDATA.debugger_slot], 0
je .exit
mov [ebx + APPDATA.state], TSTATE_RUN_SUSPENDED
mov [ebx + APPDATA.state], TSTATE_RUN_SUSPENDED
@@ -1054,8 +1054,8 @@ proc set_app_params stdcall,slot:dword, params:dword, flags:dword
; set if debuggee
test byte [flags], 1
jz .no_debug
mov eax, [current_slot]
mov [SLOT_BASE + ebx + APPDATA.debugger_thread], eax
mov eax, [current_slot_idx]
mov [SLOT_BASE + ebx + APPDATA.debugger_slot], eax
.no_debug:
mov [SLOT_BASE + ebx + APPDATA.state], dl
lea edx, [SLOT_BASE + ebx]
@@ -1074,24 +1074,27 @@ get_curr_slot:
mov eax, [current_slot]
ret
; @brief Get pointer to APPDATA by PID
; @param eax - TID of thread
; @return eax - 0 - not found or pointer on APPDATA
pid_to_thread:
pid_to_appdata:
;Input:
; eax - pid of process
;Output:
; eax - 0 - not found or pointer on APPDATA
push ebx
push ecx
mov ebx, [thread_count]
shl ebx, BSF sizeof.APPDATA ; multiply by size
; skip first process in the task table
mov ecx, APPDATA_IDLE_THREAD
mov ecx, SLOT_BASE
add ebx, ecx
.loop:
add ecx, sizeof.APPDATA
cmp [ecx + APPDATA.state], TSTATE_FREE
jz @f ;skip empty slots
cmp [ecx + APPDATA.tid], eax
jz .pid_found
@@:
add ecx, sizeof.APPDATA
dec ebx
jnz .loop
cmp ecx, ebx
jb .loop
pop ecx
pop ebx
+1 -1
View File
@@ -48,7 +48,7 @@ endg
; This internal function acquires the lock for the global list.
lock_timer_list:
mov edx, [current_slot]
mov edx, [current_slot_idx]
@@:
xor eax, eax
lock cmpxchg [timer_list_owner], edx
+16 -76
View File
@@ -2507,7 +2507,7 @@ dword-значение цвета 0x00RRGGBB
* иначе eax = TID - идентификатор потока
---------------------- Константы для регистров: ----------------------
eax - SF_THREAD_CONTROL (51) /
eax - SF_CREATE_THREAD (51) /
ebx - SSF_CREATE_THREAD (1), SSF_GET_CURR_THREAD_SLOT (2),
SSF_GET_THREAD_PRIORITY (3), SSF_SET_THREAD_PRIORITY (4)
@@ -4098,9 +4098,6 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* подфункция 7 - запуск программы
* подфункция 8 - удаление файла/папки
* подфункция 9 - создание папки
* подфункция 10 - переименование/перемещение
* подфункция 11 - создание симлинка
* подфункция 12 - чтение симлинка
Для CD-приводов в связи с аппаратными ограничениями доступны
только подфункции 0,1,5 и 7, вызов других подфункций завершится
ошибкой с кодом 2.
@@ -4115,8 +4112,7 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
[ebx] - SSF_READ_FILE (0), SSF_READ_FOLDER (1), SSF_CREATE_FILE (2),
SSF_WRITE_FILE (3), SSF_SET_END (4), SSF_GET_INFO (5),
SSF_SET_INFO (6), SSF_START_APP (7), SSF_DELETE (8),
SSF_CREATE_FOLDER (9), SSF_RENAME (10), SSF_CREATE_SYMLINK (11),
SSF_READ_SYMLINK (12)
SSF_CREATE_FOLDER (9)
======================================================================
= Функция 70, подфункция 0 - чтение файла с поддержкой длинных имён. =
======================================================================
@@ -4468,62 +4464,6 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* Формирование нового пути отличается от общих правил:
относительный путь относится к папке целевого файла (или папки),
абсолютный путь считается от корня раздела.
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_RENAME (10)
======================================================================
=========== Функция 70, подфункция 11 - создание симлинка. ===========
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 11 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: указатель на строку с целевым путём
* +20 = +0x14: путь, правила формирования имён указаны в общем
описании (путь ссылки)
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx разрушается
Замечания:
* Родительская папка должна существовать.
* Для CD функция не поддерживается (возвращает код ошибки 2).
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_CREATE_SYMLINK (11)
======================================================================
============ Функция 70, подфункция 12 - чтение симлинка. ============
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 12 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: размер буфера в байтах
* +16 = +0x10: dword: указатель на буфер для целевого пути
* +20 = +0x14: путь, правила формирования имён указаны в общем
описании (путь ссылки)
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx = число байт, записанных в буфер
Замечания:
* Функция не следует по симлинку; она читает целевой путь,
на который указывает симлинк.
* Целевой путь всегда завершается нулём, в том числе при обрезании;
записывается не более (размер буфера - 1) байт пути.
* Значение в ebx включает завершающий 0, как в подфункции 2
функции 30.
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_SYMLINK (12)
======================================================================
========== Функция 71 - установить заголовок окна программы ==========
======================================================================
@@ -5119,8 +5059,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* eax = дескриптор фьютекса, 0 при ошибке
---------------------- Константы для регистров: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FUTEX_CREATE (0)
eax - SF_FUTEX (77)
ebx - SSF_CREATE (0)
======================================================================
============= Функция 77, подфункция 1, Удалить фьютекс. =============
======================================================================
@@ -5134,8 +5074,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* Ядро автоматически удаляет фьютексы при завершении процесса.
---------------------- Константы для регистров: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FUTEX_DESTROY (1)
eax - SF_FUTEX (77)
ebx - SSF_DESTROY (1)
======================================================================
================= Функция 77, подфункция 2, Ожидать. =================
======================================================================
@@ -5151,8 +5091,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
-2 - контрольное значение фьютекса не соответствует
---------------------- Константы для регистров: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FUTEX_WAIT (2)
eax - SF_FUTEX (77)
ebx - SSF_WAIT (2)
======================================================================
================ Функция 77, подфункция 3, Разбудить. ================
======================================================================
@@ -5165,8 +5105,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* eax = количество разбуженых
---------------------- Константы для регистров: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FUTEX_WAKE (3)
eax - SF_FUTEX (77)
ebx - SSF_WAKE (3)
======================================================================
Замечания:
* Подфункции 4-7 зарезервированы и сейчас возвращают -1.
@@ -5188,8 +5128,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* Поддерживаются только pipe-дескрипторы.
---------------------- Константы для регистров: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FD_READ (10)
eax - SF_FUTEX (77)
ebx - SSF_FILE_READ (10)
======================================================================
======== Функция 77, подфункция 11, Записать из буфера в файл. =======
@@ -5208,8 +5148,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* Поддерживаются только pipe-дескрипторы.
---------------------- Константы для регистров: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FD_WRITE (11)
eax - SF_FUTEX (77)
ebx - SSF_FILE_WRITE (11)
======================================================================
=========== Функция 77, подфункция 13, Создать новый pipe. ===========
@@ -5233,8 +5173,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
- дескриптором записи.
---------------------- Константы для регистров: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FD_PIPE2 (13)
eax - SF_FUTEX (77)
ebx - SSF_PIPE_CREATE (13)
======================================================================
========== Функция -1 - завершить выполнение потока/процесса =========
+16 -75
View File
@@ -2492,7 +2492,7 @@ Returned value:
* otherwise eax = TID - thread identifier
---------------------- Constants for registers: ----------------------
eax - SF_THREAD_CONTROL (51)
eax - SF_CREATE_THREAD (51)
ebx - SSF_CREATE_THREAD (1), SSF_GET_CURR_THREAD_SLOT (2),
SSF_GET_THREAD_PRIORITY (3), SSF_SET_THREAD_PRIORITY (4)
======================================================================
@@ -4060,9 +4060,6 @@ Available subfunctions:
* subfunction 7 - start application
* subfunction 8 - delete file/folder
* subfunction 9 - create folder
* subfunction 10 - rename/move
* subfunction 11 - create symlink
* subfunction 12 - read symlink
For CD-drives due to hardware limitations only subfunctions
0,1,5 and 7 are available, other subfunctions return error
with code 2.
@@ -4076,8 +4073,7 @@ is called for corresponding device.
[ebx] - SSF_READ_FILE (0), SSF_READ_FOLDER (1), SSF_CREATE_FILE (2),
SSF_WRITE_FILE (3), SSF_SET_END (4), SSF_GET_INFO (5),
SSF_SET_INFO (6), SSF_START_APP (7), SSF_DELETE (8),
SSF_CREATE_FOLDER (9), SSF_RENAME (10), SSF_CREATE_SYMLINK (11),
SSF_READ_SYMLINK (12)
SSF_CREATE_FOLDER (9)
======================================================================
=== Function 70, subfunction 0 - read file with long names support. ==
======================================================================
@@ -4148,7 +4144,6 @@ Structure of block of data for folder entry (BDFE):
and after archiving this bit is cleared - it can be useful
for automatically creating of backup-archives as at writing
this bit is usually set
* bit 6 (mask 0x40): this is a symbolic link (currently only set by the ext driver).
* +4: dword: encoding, equals to field +8 in the information structure
* +8: 4*byte: time of file creation
* +12 = +0xC: 4*byte: date of file creation
@@ -4428,60 +4423,6 @@ Remarks:
* New path forming differs from general rules:
relative path relates to the target's parent folder,
absolute path relates to the partition's root folder.
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_RENAME (10)
======================================================================
=========== Function 70, subfunction 11 - create symlink. ============
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 11 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: pointer to the target path string
* +20 = +0x14: path, general rules of names forming (link path)
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx destroyed
Remarks:
* The parent folder must already exist.
* The function is not supported for CD (returns error code 2).
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_CREATE_SYMLINK (11)
======================================================================
============ Function 70, subfunction 12 - read symlink. =============
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 12 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: buffer size in bytes
* +16 = +0x10: dword: pointer to buffer for target path
* +20 = +0x14: path, general rules of names forming (link path)
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx = number of bytes written to the buffer
Remarks:
* The function does not follow the symlink; it reads the target path
that the symlink points to.
* The target path is always terminated with 0, even when truncated;
at most (buffer size - 1) path bytes are written.
* The value returned in ebx includes the terminating 0, as in
subfunction 2 of function 30.
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_SYMLINK (12)
======================================================================
================== Function 71 - set window caption ==================
======================================================================
@@ -5332,8 +5273,8 @@ Returned value:
* eax = futex handle, 0 on error
---------------------- Constants for registers: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FUTEX_CREATE (0)
eax - SF_FUTEX (77)
ebx - SSF_CREATE (0)
======================================================================
========= Function 77, Subfunction 1, Destroy futex object ===========
======================================================================
@@ -5348,8 +5289,8 @@ Remarks:
terminates.
---------------------- Constants for registers: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FUTEX_DESTROY (1)
eax - SF_FUTEX (77)
ebx - SSF_DESTROY (1)
======================================================================
=============== Function 77, Subfunction 2, Futex wait ===============
======================================================================
@@ -5365,8 +5306,8 @@ Returned value:
-2 - futex control value doesn't match
---------------------- Constants for registers: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FUTEX_WAIT (2)
eax - SF_FUTEX (77)
ebx - SSF_WAIT (2)
======================================================================
=============== Function 77, Subfunction 3, Futex wake ===============
======================================================================
@@ -5379,8 +5320,8 @@ Returned value:
* eax = number of waiters that were woken up
---------------------- Constants for registers: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FUTEX_WAKE (3)
eax - SF_FUTEX (77)
ebx - SSF_WAKE (3)
======================================================================
Remarks:
* Subfunctions 4-7 are reserved and currently return -1.
@@ -5402,8 +5343,8 @@ Remarks:
* Only pipe descriptors are supported.
---------------------- Constants for registers: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FD_READ (10)
eax - SF_FUTEX (77)
ebx - SSF_FILE_READ (10)
======================================================================
=========== Function 77, Subfunction 11, Write to file. =============
======================================================================
@@ -5421,8 +5362,8 @@ Remarks:
* Only pipe descriptors are supported.
---------------------- Constants for registers: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FD_WRITE (11)
eax - SF_FUTEX (77)
ebx - SSF_FILE_WRITE (11)
======================================================================
========== Function 77, Subfunction 13, Create pipe. ================
======================================================================
@@ -5440,8 +5381,8 @@ Remarks:
write handle.
---------------------- Constants for registers: ----------------------
eax - SF_POSIX (77)
ebx - SSF_FD_PIPE2 (13)
eax - SF_FUTEX (77)
ebx - SSF_PIPE_CREATE (13)
======================================================================
=== Function 80 - file system interface with parameter of encoding ===
======================================================================
+72 -1041
View File
File diff suppressed because it is too large. Load diff
+1 -2
View File
@@ -2405,12 +2405,11 @@ fat_Write:
; hd_extend_file can return three error codes: FAT table error, device error or disk full.
; First two cases are fatal errors, in third case we may write some data
cmp al, ERROR_DISK_FULL
jnz .noWrite
jnz @f
; correct number of bytes to write
mov ecx, [edi+28]
cmp ecx, ebx
ja .length_ok
.noWrite:
push 0
.ret:
pop eax eax eax ecx ecx
+1 -13
View File
@@ -182,20 +182,8 @@ proc file_system_is_operation_safe stdcall, inf_struct_ptr: dword
.case6:
cmp dword [ebx], 6
jnz .case11
mov ecx, 32
jmp .end_switch
.case11:
cmp dword [ebx], 11
jnz .case12
stdcall is_string_userspace, edx
jmp .ret
.case12:
cmp dword [ebx], 12
jnz .switch_none
mov ecx, dword [ebx + 12]
mov ecx, 32
jmp .end_switch
.switch_none:
+1 -2
View File
@@ -253,10 +253,9 @@ UTF16to8_string:
UTF16to8:
; in:
; ax = UTF-16 char
; eax = UTF-16 char
; edi -> buffer for UTF-8 char (increasing)
; ecx = byte counter (decreasing)
movzx eax, ax
dec ecx
js .ret
cmp eax, 80h
+2 -4
View File
@@ -193,8 +193,7 @@ align 4
;--------------------------------------
align 4
@@:
mov eax, [current_slot]
mov eax, [eax + APPDATA.tid]
mov eax, [current_slot_idx]
mov [bgrlockpid], eax
cmp [img_background], static_background_data
jz .nomem
@@ -242,8 +241,7 @@ nosb6:
jnz nosb7
cmp [bgrlock], 0
jz .err
mov eax, [current_slot]
mov eax, [eax + APPDATA.tid]
mov eax, [current_slot_idx]
cmp [bgrlockpid], eax
jnz .err
mov eax, ecx
-6
View File
@@ -48,10 +48,6 @@ dtext:
add esp, 28
ret
.nomem:
add esp, 40
ret
.redirect:
mov ebp, [edi]
add edi, 8
@@ -85,8 +81,6 @@ dtext:
mov [esp+32], eax
imul ebp, eax
stdcall kernel_alloc, ebp
test eax, eax
jz .nomem
mov ecx, ebp
shr ecx, 2
mov [esp+36], eax
-2
View File
@@ -1997,8 +1997,6 @@ align 4
; esi - slot
push eax ecx edx esi
xchg eax, esi
shl eax, BSF sizeof.APPDATA
add eax, SLOT_BASE
lea ecx, [esp + 12]
mov edx, 1
call read_process_memory
+18 -17
View File
@@ -55,6 +55,7 @@ launcher_start db 1
endg
max_processes = 255
tss_step = 128 + 8192 ; tss & i/o - 65535 ports, * 256=557056*4
os_stack = os_data_l - gdts ; GDTs
os_code = os_code_l - gdts
@@ -388,7 +389,7 @@ high_code:
mov edi, tss._io_map_0
xor eax, eax
not eax
mov ecx, IO_MAP_SIZE/4
mov ecx, 8192/4
rep stosd ; access to 4096*8=65536 ports
mov ax, tss0
@@ -409,7 +410,7 @@ high_code:
stdcall alloc_kernel_space, 0x50000 ; FIXME check size
mov [default_io_map], eax
add eax, IO_MAP_SIZE
add eax, 0x2000
mov [ipc_tmp], eax
mov ebx, 0x1000
@@ -534,7 +535,7 @@ high_code:
dec ecx
jns @b
mov edx, APPDATA_IDLE_THREAD
mov edx, SLOT_BASE + sizeof.APPDATA*1
mov ebx, [os_stack_seg]
add ebx, RING0_STACK_SIZE
add ebx, [xsave_area_size]
@@ -546,7 +547,7 @@ high_code:
mov ecx, IDLE_PRIORITY
call scheduler_add_thread
mov edx, APPDATA_OS_THREAD
mov edx, SLOT_BASE + sizeof.APPDATA*2
mov ebx, [os_stack_seg]
call setup_os_slot
mov dword [edx], 'OS'
@@ -555,7 +556,7 @@ high_code:
mov [current_slot_idx], 2
mov [thread_count], 2
mov [current_slot], APPDATA_OS_THREAD
mov [current_slot], SLOT_BASE + sizeof.APPDATA*2
; Move other CPUs to deep sleep, if it is useful
uglobal
@@ -847,15 +848,15 @@ include "detect/vortex86.inc" ; Vortex86 SoC detection code
call reserve_irqs_ports
mov [SLOT_BASE + APPDATA.window], window_data
mov [APPDATA_IDLE_THREAD + APPDATA.window], background_window
mov [APPDATA_OS_THREAD + APPDATA.window], window_data + sizeof.WDATA*2
mov [SLOT_BASE + sizeof.APPDATA + APPDATA.window], window_data + sizeof.WDATA
mov [SLOT_BASE + sizeof.APPDATA*2 + APPDATA.window], window_data + sizeof.WDATA*2
mov [window_data + WDATA.thread], SLOT_BASE
mov [background_window + WDATA.thread], APPDATA_IDLE_THREAD
mov [window_data + sizeof.WDATA*2 + WDATA.thread], APPDATA_OS_THREAD
mov [window_data + sizeof.WDATA + WDATA.thread], SLOT_BASE + sizeof.APPDATA
mov [window_data + sizeof.WDATA*2 + WDATA.thread], SLOT_BASE + sizeof.APPDATA*2
call init_display
mov eax, [def_cursor]
mov [background_window + WDATA.cursor], eax
mov [window_data + sizeof.WDATA + WDATA.cursor], eax
mov [window_data + sizeof.WDATA*2 + WDATA.cursor], eax
; PRINT CPU FREQUENCY
@@ -952,14 +953,14 @@ include "detect/vortex86.inc" ; Vortex86 SoC detection code
; Protect I/O permission map
mov esi, [default_io_map]
stdcall map_page, esi, [APPDATA_IDLE_THREAD + APPDATA.io_map], PG_READ
stdcall map_page, esi, [SLOT_BASE + sizeof.APPDATA + APPDATA.io_map], PG_READ
add esi, 0x1000
stdcall map_page, esi, [APPDATA_IDLE_THREAD + APPDATA.io_map + 4], PG_READ
stdcall map_page, esi, [SLOT_BASE + sizeof.APPDATA + APPDATA.io_map + 4], PG_READ
stdcall map_page, tss._io_map_0, \
[APPDATA_IDLE_THREAD + APPDATA.io_map], PG_READ
[SLOT_BASE + sizeof.APPDATA + APPDATA.io_map], PG_READ
stdcall map_page, tss._io_map_1, \
[APPDATA_IDLE_THREAD + APPDATA.io_map + 4], PG_READ
[SLOT_BASE + sizeof.APPDATA + APPDATA.io_map + 4], PG_READ
; SET KEYBOARD PARAMETERS
mov al, 0xf6 ; reset keyboard, scan enabled
@@ -1864,7 +1865,7 @@ sysfn_shutdown: ; 18.9 = system shutdown
; out: Z/z -- is/not kernel thread
is_kernel_thread:
mov eax, [eax + APPDATA.process]
cmp eax, [APPDATA_OS_THREAD + APPDATA.process] ; OS
cmp eax, [SLOT_BASE + 2*sizeof.APPDATA + APPDATA.process] ; OS
ret
;------------------------------------------------------------------------------
sysfn_terminate: ; 18.2 = TERMINATE
@@ -2064,7 +2065,7 @@ sysfn_zmodif:
;------------------------------------------------------------------------------
sysfn_getidletime: ; 18.4 = GET IDLETIME
mov eax, [APPDATA_IDLE_THREAD + APPDATA.cpu_usage]
mov eax, [SLOT_BASE + sizeof.APPDATA + APPDATA.cpu_usage]
mov [esp + SYSCALL_STACK.eax], eax
ret
;------------------------------------------------------------------------------
@@ -2824,7 +2825,7 @@ no_mark_system_shutdown:
align 4
noshutdown:
mov eax, [thread_count] ; termination
mov ebx, APPDATA_IDLE_THREAD + APPDATA.state
mov ebx, SLOT_BASE + sizeof.APPDATA + APPDATA.state
mov esi, 1
;--------------------------------------
align 4
-28
View File
@@ -83,31 +83,6 @@ macro arp_init {
}
;-----------------------------------------------------------------;
; ;
; arp_clear_device: Empty the ARP table and counters of a removed ;
; device. ;
; ;
; IN: edi = device number * 4 ;
; ;
;-----------------------------------------------------------------;
macro arp_clear_device {
xor eax, eax
mov [ARP_entries + edi], eax
mov [ARP_packets_tx + edi], eax
mov [ARP_packets_rx + edi], eax
mov [ARP_conflicts + edi], eax
push edi
imul edi, (ARP_TABLE_SIZE * sizeof.ARP_entry)/4
add edi, ARP_table
mov ecx, (ARP_TABLE_SIZE * sizeof.ARP_entry)/2
rep stosw
pop edi
}
;-----------------------------------------------------------------;
; ;
; arp_decrease_entry_ttls ;
@@ -338,9 +313,6 @@ arp_output_request:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u device=0x%x\n",\
[esp]:1, [esp + 1]:1, [esp + 2]:1, [esp + 3]:1, ebx
test ebx, ebx ; device is gone
jz .exit
mov ax, ETHER_PROTO_ARP
mov ecx, sizeof.ARP_header
mov edx, ETH_BROADCAST ; broadcast mac
+7 -93
View File
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2026. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; IPv4.INC ;;
@@ -105,29 +105,6 @@ macro ipv4_init {
}
;-----------------------------------------------------------------;
; ;
; ipv4_clear_device: Reset the IPv4 settings of a removed device, ;
; so no route points to it anymore. ;
; ;
; IN: edi = device number * 4 ;
; ;
;-----------------------------------------------------------------;
macro ipv4_clear_device {
xor eax, eax
mov [IPv4_address + edi], eax
mov [IPv4_subnet + edi], eax
mov [IPv4_nameserver + edi], eax
mov [IPv4_gateway + edi], eax
mov [IPv4_broadcast + edi], eax
mov [IPv4_packets_tx + edi], eax
mov [IPv4_packets_rx + edi], eax
mov [IPv4_packets_dumped + edi], eax
}
;-----------------------------------------------------------------;
; ;
; Decrease TimeToLive of all fragment slots ;
@@ -780,8 +757,6 @@ ipv4_output_raw:
push esi eax
call ipv4_route
test eax, eax
jz .arp_error
call arp_ip_to_mac
test eax, 0xffff0000 ; error bits
@@ -790,9 +765,9 @@ ipv4_output_raw:
push ebx ; push the mac
push ax
inc [IPv4_packets_tx + edi]
inc [IPv4_packets_tx + 4*edi]
mov ax, ETHER_PROTO_IPv4
mov ebx, [net_device_list + edi]
mov ebx, [net_device_list + 4*edi]
mov ecx, [esp + 6 + 4]
add ecx, sizeof.IPv4_header
mov edx, esp
@@ -976,7 +951,7 @@ endp
; edi = device number*4 ;
; ;
; DESTROYED: ;
; ebx, ecx ;
; ecx ;
; ;
;-----------------------------------------------------------------;
align 4
@@ -989,11 +964,8 @@ ipv4_route:
cmp eax, 0xffffffff
je .broadcast
; Check for on-link
xor edi, edi
.loop:
cmp [net_device_list + edi], 0 ; skip slots without a device
je .next
mov ebx, [IPv4_address + edi]
and ebx, [IPv4_subnet + edi]
jz .next
@@ -1006,58 +978,9 @@ ipv4_route:
cmp edi, 4*NET_DEVICES_MAX
jb .loop
; no on-link match, find first device with a gateway
mov edi, 4 ; skip loopback device
.loop_gw:
cmp [IPv4_gateway + edi], 0
je .next_gw
cmp [net_device_list + edi], 0
jne .found_gw
.next_gw:
add edi, 4
cmp edi, 4*NET_DEVICES_MAX
jb .loop_gw
jmp .loopback ; no gateway found, fall-back to loopback device
.found_gw:
mov eax, [IPv4_gateway + edi]
jmp .got_it
mov eax, [IPv4_gateway + 4] ; TODO: let user (or a user space daemon) configure default route
.broadcast:
; broadcast: we will do our best without full routing..
; find the first non loopback device which has an active link without IP address
mov edi, 4 ; skip loopback device
.bc_loop1:
mov ebx, [net_device_list + edi]
test ebx, ebx
jz @f
cmp [ebx + NET_DEVICE.link_state], 0
je @f
cmp [IPv4_address + edi], 0
je .got_it
@@:
add edi, 4
cmp edi, 4*NET_DEVICES_MAX
jb .bc_loop1
; If there is no such device, try the one with active link and IP address
mov edi, 4 ; skip loopback device
.bc_loop2:
mov ebx, [net_device_list + edi]
test ebx, ebx
jz @f
cmp [ebx + NET_DEVICE.link_state], 0
jne .got_it
@@:
add edi, 4
cmp edi, 4*NET_DEVICES_MAX
jb .bc_loop2
; jmp .loopback ; no gateway found, fall-back to loopback device
.loopback:
xor edi, edi ; nowhere to go for now.. route it to the loopback device
mov edi, 4 ; TODO: same as above
.got_it:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
test edx, edx
@@ -1079,23 +1002,14 @@ ipv4_route:
cmp eax, 0xffffffff
je @f
; An interface without an address (DHCP not done yet, or the lease
; dropped when the link went down) can send nothing but broadcasts: with
; address and mask both zero every destination compared as on-link, and
; the stack went asking ARP for internet addresses on behalf of 0.0.0.0.
test edx, edx
jz .fail
; Check if we should route to gateway or not
mov ebx, edx
mov ebx, [IPv4_address + edi]
and ebx, [IPv4_subnet + edi]
mov ecx, eax
and ecx, [IPv4_subnet + edi]
cmp ecx, ebx
je @f
mov eax, [IPv4_gateway + edi]
test eax, eax
jz .fail ; off-link and no gateway
@@:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
ret
+1 -44
View File
@@ -61,41 +61,6 @@ macro eth_init {
}
;-----------------------------------------------------------------;
; ;
; eth_clear_device: Drop the frames of a removed device that are ;
; still waiting in the input queue, their ;
; NET_BUFF.device will not be valid anymore. ;
; ;
; IN: ebx = device ptr ;
; ;
;-----------------------------------------------------------------;
macro eth_clear_device {
local .loop, .done
spin_lock_irqsave
mov esi, [ETH_frame_head]
.loop:
cmp esi, ETH_frame_head
je .done
mov eax, esi
mov esi, [esi + NET_BUFF.NextPtr]
cmp [eax + NET_BUFF.device], ebx
jne .loop
; unlink it, ETH_frame_head/tail double as the NextPtr/PrevPtr of the list head
mov ecx, [eax + NET_BUFF.PrevPtr]
mov [ecx + NET_BUFF.NextPtr], esi
mov [esi + NET_BUFF.PrevPtr], ecx
dec [ETH_frame_queued]
stdcall net_buff_free, eax
jmp .loop
.done:
spin_unlock_irqrestore
}
align 4
; This function is called by ethernet drivers.
; Push the received ethernet packet onto the ethernet input queue.
@@ -280,9 +245,6 @@ eth_output:
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_output: size=%u device=%x\n", ecx, ebx
test ebx, ebx
jz .no_device
cmp ecx, [ebx + ETH_DEVICE.mtu]
ja .too_large
@@ -333,16 +295,11 @@ eth_output:
ret
.too_large:
inc [ebx + NET_DEVICE.packets_tx_err]
inc [eax + NET_DEVICE.packets_tx_err]
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_output: Packet too large!\n"
xor eax, eax
ret
.no_device:
DEBUGF DEBUG_NETWORK_ERROR, "ETH_output: no device!\n"
xor eax, eax
ret
;-----------------------------------------------------------------;
+33 -3
View File
@@ -780,6 +780,8 @@ socket_close:
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
jne .free
test [eax + SOCKET.state], SS_ISCONNECTED
jz @f
test [eax + SOCKET.state], SS_ISDISCONNECTING
jnz @f
call tcp_disconnect
@@ -2096,7 +2098,7 @@ socket_alloc:
;-----------------------------------------------------------------;
; ;
; socket_free: Free socket data memory and remove socket from ;
; the list. Caller should lock and unlock socket_mutex. ;
; the list. Takes socket_mutex itself; callers must not hold it. ;
; ;
; IN: eax = socket ptr ;
; ;
@@ -2108,6 +2110,22 @@ socket_free:
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_free: %x\n", eax
; Unlinking below writes NextPtr/PrevPtr of the neighbours, so it has to be
; serialized against every walk of net_sockets -- tcp_process_input.findpcb
; above all, which walks the list under socket_mutex and dereferences whatever
; NextPtr it reads. Nothing used to hold the mutex here, so a socket freed by
; the TCP timers could rewrite the list from under that walk.
;
; The mutex is taken here, at the very top, and not merely around the unlink:
; socket_alloc locks socket_mutex and then the neighbour's SOCKET.mutex, so
; taking them in the opposite order -- SOCKET.mutex first, as the code below
; does -- would be an ABBA deadlock against it. Locking here also covers the
; socket_check walk, which reads net_sockets too.
pusha
mov ecx, socket_mutex
call mutex_lock
popa
call socket_check
jz .error
@@ -2124,11 +2142,11 @@ socket_free:
mov ebx, eax
cmp [eax + STREAM_SOCKET.rcv.start_ptr], 0
je @f
stdcall kernel_free, [eax + STREAM_SOCKET.rcv.start_ptr]
stdcall free_kernel_space, [eax + STREAM_SOCKET.rcv.start_ptr]
@@:
cmp [ebx + STREAM_SOCKET.snd.start_ptr], 0
je @f
stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr]
stdcall free_kernel_space, [ebx + STREAM_SOCKET.snd.start_ptr]
@@:
mov eax, ebx
.no_stream:
@@ -2155,7 +2173,13 @@ socket_free:
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_free: success!\n"
; Both exits converge here: the success path falls through, and a failed
; socket_check jumps in.
.error:
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
ret
.error1:
@@ -2379,6 +2403,12 @@ socket_process_end:
ret ; FIXME
; NOTE: the body below is disabled by the ret above, and cannot be re-enabled
; as it stands: it holds socket_mutex across tcp_disconnect and socket_free,
; and socket_free now takes that mutex itself. Whoever revives this has to drop
; the lock around those calls (or hand the work to another thread, as the TODO
; below suggests), not put the lock back into socket_free -- the ordering there
; is what keeps it from deadlocking against socket_alloc.
cmp [net_sockets + SOCKET.NextPtr], 0 ; Are there any active sockets at all?
je .quickret ; nope, exit immediately
+1 -11
View File
@@ -118,7 +118,7 @@ SS_MORETOCOME = 0x4000
SS_BLOCKED = 0x8000
SOCKET_BUFFER_SIZE = 4096*32 ; must be 4096*(power of 2) where 'power of 2' is at least 8
SOCKET_BUFFER_SIZE = 4096*8 ; must be 4096*(power of 2) where 'power of 2' is at least 8
MAX_backlog = 20 ; maximum backlog for stream sockets
; Error Codes
@@ -597,16 +597,6 @@ net_remove_device:
mov dword [edi-4], eax
dec [net_device_count]
;-----------------------------------------------------------------
; Forget everything the protocols still know about this interface.
; Otherwise its IP address keeps matching in ipv4_route, and output
; ends up calling through the now empty net_device_list slot.
sub edi, net_device_list + 4 ; device number * 4
ipv4_clear_device
arp_clear_device
eth_clear_device
call net_send_event
xor eax, eax
+41 -14
View File
@@ -355,14 +355,9 @@ endl
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Got window scale option\n"
or [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
; remember the peer's scale factor; it is applied to SND_SCALE when the
; connection is established (together with our RCV_SCALE)
lodsb
cmp al, TCP_max_winshift
jbe .wscale_capped
mov al, TCP_max_winshift
.wscale_capped:
mov [ebx + TCP_SOCKET.requested_s_scale], al
mov [ebx + TCP_SOCKET.SND_SCALE], al
;;;;; TODO
@@:
jmp .opt_loop
@@ -731,8 +726,20 @@ endl
test ecx, ecx
jz .not_terminated
; tcp_close ends in socket_free, which locks the socket's own mutex (held here
; since .found_socket) and socket_mutex: release ours first or deadlock. Same
; shape as .unlock_and_close. The reset reply below only needs the segment
; header, so edx is preserved across the call and the socket is never touched
; again.
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
mov eax, ebx
push edx
call tcp_close
pop edx
inc [TCPS_rcvafterclose]
jmp .respond_seg_reset
.not_terminated:
@@ -766,8 +773,20 @@ endl
; mov edx, [ebx + TCP_SOCKET.RCV_NXT]
; cmp edx, [edx + TCP_header.SequenceNumber]
; add edx, 64000 ; TCP_ISSINCR FIXME
; tcp_close ends in socket_free, which locks the socket's own mutex (held here
; since .found_socket) and socket_mutex: release ours first or deadlock. The
; segment header (edx) and data count (ecx) survive the call because .findpcb
; and everything after it still need them; the freed socket is off the list by
; the time the walk restarts.
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
mov eax, ebx
push ecx edx
call tcp_close
pop edx ecx
jmp .findpcb ; FIXME: skip code for unscaling window, ...
.no_new_request:
@@ -886,10 +905,22 @@ endl
test [edx + TCP_header.Flags], TH_SYN
jz .not_syn_full
; tcp_drop ends in tcp_close -> socket_free, which locks the socket's own mutex
; (held here since .found_socket) and socket_mutex: release ours first or
; deadlock. Same shape as the refused-connection path in .state_syn_sent.
; Exiting through .drop_with_reset afterwards would unlock the freed mutex and
; build the reply from the freed socket; it is also redundant -- the connection
; is synchronized here, so tcp_drop itself sends the RST via tcp_output
; (tcp_outflags for TCPS_CLOSED is RST+ACK). Leave through .drop_no_socket.
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
mov eax, ebx
mov ebx, ECONNRESET
call tcp_drop
jmp .drop_with_reset
jmp .drop_no_socket
.not_syn_full:
; If ACK bit is off, we drop the segment and return
@@ -1422,14 +1453,10 @@ endl
test [edx + TCP_header.Flags], TH_ACK
jz .drop
push ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
pop eax
mov eax, ebx
mov ebx, ECONNREFUSED
call tcp_drop
jmp .drop_no_socket
jmp .drop
@@:
;-----------------------------------------------------------------------------------
+8 -10
View File
@@ -234,25 +234,23 @@ endl
mov ebx, TCP_max_win
shl ebx, cl
pop ecx
; Clamp to available window first, then subtract what the peer already knows (as in BSD)
cmp ebx, ecx
jbe @f
mov ebx, ecx
@@:
sub ebx, [eax + TCP_SOCKET.RCV_ADV]
add ebx, [eax + TCP_SOCKET.RCV_NXT]
cmp ebx, ecx
jl @f
mov ebx, ecx
@@:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: we can increase window by %d bytes\n", ebx
mov edi, [eax + TCP_SOCKET.t_maxseg]
shl edi, 1
cmp ebx, edi ; signed: may be negative if window shrank
jge .send
cmp ebx, edi
jae .send
cmp ebx, SOCKET_BUFFER_SIZE/2
jge .send
jae .send
.no_window:
+4 -4
View File
@@ -320,12 +320,12 @@ tcp_respond:
stosb
mov eax, SOCKET_BUFFER_SIZE
sub eax, [esi + STREAM_SOCKET.rcv.size]
mov cl, [esi + TCP_SOCKET.RCV_SCALE]
shr eax, cl ; scale first, then clamp to the
cmp eax, TCP_max_win ; 16-bit field maximum
cmp eax, TCP_max_win
jbe .lessthanmax
mov eax, TCP_max_win
.lessthanmax:
mov cl, [esi + TCP_SOCKET.RCV_SCALE]
shr eax, cl
xchg al, ah
stosw ; window
@@ -488,7 +488,7 @@ tcp_set_persist:
; Start/restart persistence timer.
tcpt_rangeset [eax + TCP_SOCKET.timer_persist], ebx, TCP_time_pers_min, TCP_time_pers_max
or [eax + TCP_SOCKET.timer_flags], timer_flag_persist
or [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
pop ebx
cmp [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift
+4 -4
View File
@@ -111,13 +111,13 @@ proc tcp_timer_640ms
DEBUGF DEBUG_NETWORK_VERBOSE, "socket %x: Keepalive expired\n", eax
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
jae .dont_kill
cmp [eax + TCP_SOCKET.state], TCPS_ESTABLISHED
ja .dont_kill
push [eax + SOCKET.NextPtr]
push eax
call tcp_disconnect
pop eax
jmp .check_only
jmp .loop
.dont_kill:
test [eax + SOCKET.options], SO_KEEPALIVE
-4
View File
@@ -180,8 +180,6 @@ tcp_connect:
.nomem:
pop edx eax
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
xor eax, eax
dec eax
mov ebx, ENOMEM
@@ -196,8 +194,6 @@ tcp_connect:
.enoroute:
pop eax
popa
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
xor eax, eax
dec eax
mov ebx, EADDRNOTAVAIL
+1 -2
View File
@@ -148,10 +148,9 @@ ReadNoteByte:
push esi
mov eax, [pidProcessNote]
call pid_to_thread
call pid_to_slot
test eax, eax
jz .failed
lea ecx, [esp+12]
mov edx, 1
mov esi, [memAdrNote]
+9 -9
View File
@@ -125,7 +125,7 @@ SF_STYLE_SETTINGS=48
SSF_SET_FONT_SIZE=12
SF_APM=49
SF_SET_WINDOW_SHAPE=50
SF_THREAD_CONTROL=51
SF_CREATE_THREAD=51
SSF_CREATE_THREAD=1
SSF_GET_CURR_THREAD_SLOT=2
SSF_GET_THREAD_PRIORITY=3
@@ -281,14 +281,14 @@ SF_NETWORK_PROTOCOL=76
SSF_ARP_DEL_ENTRY=50005h
SSF_ARP_SEND_ANNOUNCE=50006h
SSF_ARP_CONFLICTS_COUNT=50007h
SF_POSIX=77
SSF_FUTEX_CREATE=0
SSF_FUTEX_DESTROY=1
SSF_FUTEX_WAIT=2
SSF_FUTEX_WAKE=3
SSF_FD_READ=10
SSF_FD_WRITE=11
SSF_FD_PIPE2=13
SF_FUTEX=77
SSF_CREATE=0
SSF_DESTROY=1
SSF_WAIT=2
SSF_WAKE=3
SSF_FILE_READ=10
SSF_FILE_WRITE=11
SSF_PIPE_CREATE=13
; File system errors:
FSERR_SUCCESS=0
+1 -1
View File
@@ -1111,7 +1111,7 @@ end if
mov dword [edx+8],ebx
mov dword [edx+4],ecx
mov dword [edx],Kolibri_ThreadFinish
mov eax,SF_THREAD_CONTROL
mov eax,SF_CREATE_THREAD
mov ebx,1
mov ecx,@Kolibri@ThreadMain$qpvt1
int 0x40
Submodule programs/cmm deleted from 86b0211da7.
+6
View File
@@ -0,0 +1,6 @@
if tup.getconfig("NO_CMM") ~= "" then return end
if tup.getconfig("LANG") == "ru_RU"
then C_LANG = "LANG_RUS"
else C_LANG = "LANG_ENG" -- this includes default case without config
end
tup.rule("app_plus.c", "c-- /D=$(C_LANG) /OPATH=%o %f" .. tup.getconfig("KPACK_CMD"), "app_plus.com")
+18
View File
@@ -0,0 +1,18 @@
struct sysdir
{
char name[64];
char path[64];
} sysdir;
:int SetAdditionalSystemDirectory(dword tName, tPath)
{
int i;
strcpy(#sysdir.name, tName);
strcpy(#sysdir.path, tPath);
$mov eax, 30
$mov ebx, 3
ECX = #sysdir;
$int 0x40
}
+162
View File
@@ -0,0 +1,162 @@
#define MEMSIZE 1024*60
#include "..\lib\gui.h"
#include "..\lib\obj\proc_lib.h"
#include "..\lib\patterns\simple_open_dialog.h"
#include "..\lib\patterns\restart_process.h"
#include "added_sysdir.c"
//===================================================//
// //
// DATA //
// //
//===================================================//
#define WINW 570
#define WINH 300
#define CONX 28 //content X pos
#define CONY 25 //content Y pos
char default_dir[] = "/sys";
od_filter filter2;
#define BTN_MANUAL_SEARCH 10
#define BTN_OPEN_ANYWAY 11
#define APP_PLUS_INI_PATH "/sys/settings/app_plus.ini"
//===================================================//
// //
// TRANSLATIONS //
// //
//===================================================//
#ifdef LANG_RUS
?define WINDOW_TITLE_TEXT "Внимание!"
?define CONTENT_HEADER_TEXT "KolibriOS работает в режиме дискеты"
?define DESCRIPTION_TEXT "Многие приложения сейчас недоступны.
Причина в том, что не смонтирован дополнительный системный
каталог. Но вы можете найти и задать его вручную. Его название
'kolibrios'. Вы также можете загрузить latest-dirstr.7z через
WebView и найти его внутри."
?define MANUALLY_BUTTON_TEXT "Указать папку /kolibrios/..."
?define OPEN_ANYWAY_BUTTON_TEXT "Запустить APP+ (некоторые программы будут недоступны)"
#else
?define WINDOW_TITLE_TEXT "Warning!"
?define CONTENT_HEADER_TEXT "KolibriOS is running in floppy mode"
?define DESCRIPTION_TEXT "A lot of apps aren't available.
The reason is that additional system directory is not mounted.
But you can find and set it manually. Its name is 'kolibrios'.
You can also download latest-dirstr.7z via WebView and find
it inside."
?define MANUALLY_BUTTON_TEXT "Choose /kolibrios/ folder..."
?define OPEN_ANYWAY_BUTTON_TEXT "Open APP+ anyway (some programs won't be available)"
#endif
//===================================================//
// //
// CODE //
// //
//===================================================//
void main()
{
if (param) {
SetAdditionalSystemDirectory("kolibrios", #param+1);
ExitProcess();
}
WaitAutosearch();
CheckKosMounted();
o_dialog.type = 2;
#define NO_DLL_INIT
load_dll(Proc_lib, #OpenDialog_init,0);
OpenDialog_init stdcall (#o_dialog);
active_button_id = BTN_MANUAL_SEARCH;
loop() switch(@WaitEvent())
{
case evButton:
EventButton(GetButtonID());
break;
case evKey:
@GetKeyScancode();
if (AL == SCAN_CODE_ENTER) {
EventButton(active_button_id);
} else if (AL == SCAN_CODE_TAB) {
active_button_id = active_button_id-10^1 + 10;
DrawButtons();
}
break;
case evReDraw:
draw_window();
}
}
void draw_window()
{
sc.get();
DefineAndDrawWindow(screen.w-WINW/2, 100, WINW, WINH+skin_h, 0x34, sc.work, WINDOW_TITLE_TEXT,0);
draw_icon_16w(CONX+2, CONY-3, 5);
WriteTextB(CONX+27+2,CONY+2,0x81,MixColors(sc.work, 0xB92234,220),CONTENT_HEADER_TEXT);
WriteTextB(CONX+27,CONY,0x81,0xB92234,CONTENT_HEADER_TEXT);
WriteTextLines(CONX,CONY+42,0x90,sc.work_text,DESCRIPTION_TEXT,20);
DrawButtons();
}
void DrawButtons()
{
DrawStandartCaptButton(CONX, WINH-CONY-58, BTN_MANUAL_SEARCH, MANUALLY_BUTTON_TEXT);
DrawStandartCaptButton(CONX, WINH-CONY-22, BTN_OPEN_ANYWAY, OPEN_ANYWAY_BUTTON_TEXT);
}
void CheckKosMounted()
{
if (dir_exists("/kolibrios"))
{
if (file_exists(APP_PLUS_INI_PATH)) EventOpenApp();
ExitProcess();
}
}
void WaitAutosearch()
{
while (CheckProcessExists("SEARCHAP")) pause(2);
}
//===================================================//
// //
// EVENTS //
// //
//===================================================//
void EventManualSearch()
{
OpenDialog_start stdcall (#o_dialog);
if (o_dialog.status) SetAdditionalSystemDirectory("kolibrios", #openfile_path+1);
pause(3);
CheckKosMounted();
}
void EventOpenApp()
{
if (RunProgram("/sys/syspanel", APP_PLUS_INI_PATH) < 0) {
notify("'App+ cannot start because\n/sys/syspanel does not exist' -E");
}
}
void EventButton(dword id)
{
if (id==CLOSE_BTN) ExitProcess();
else if (id==BTN_MANUAL_SEARCH) EventManualSearch();
else if (id==BTN_OPEN_ANYWAY) {
EventOpenApp();
ExitProcess();
}
}
stop:
+6
View File
@@ -0,0 +1,6 @@
@c-- /D=LANG_ENG app_plus.c
@del *.
@rename *.com *.
@del warning.txt
@pause
+5
View File
@@ -0,0 +1,5 @@
@c-- /D=LANG_RUS app_plus.c
@del *.
@rename *.com *.
@del warning.txt
@pause
+6
View File
@@ -0,0 +1,6 @@
if tup.getconfig("NO_CMM") ~= "" then return end
if tup.getconfig("LANG") == "ru_RU"
then C_LANG = "LANG_RUS"
else C_LANG = "LANG_ENG" -- this includes default case without config
end
tup.rule("appearance.c", "c-- /D=AUTOBUILD /D=$(C_LANG) /OPATH=%o %f" .. tup.getconfig("KPACK_CMD"), "appearance.com")
+472
View File
@@ -0,0 +1,472 @@
//11.03.12 - start!
#define MEMSIZE 1024*70
#include "../lib/mem.h"
#include "../lib/strings.h"
#include "../lib/io.h"
#include "../lib/list_box.h"
#include "../lib/gui.h"
#include "../lib/obj/box_lib.h"
#include "../lib/obj/proc_lib.h"
#include "../lib/obj/libini.h"
#include "../lib/patterns/select_list.h"
#include "../lib/patterns/simple_open_dialog.h"
#include "../lib/patterns/restart_process.h"
dword fmas;
#include "ui_elements_preview.h"
#include "const.h"
//===================================================//
// //
// DATA //
// //
//===================================================//
int active_skin=-1, active_wallpaper=-1, active_screensaver=-1;
checkbox optionbox_stretch = { T_CHECKBOX_STRETCH, false };
checkbox optionbox_tiled = { T_CHECKBOX_TILED, false };
checkbox optionbox_auto = { T_CHECKBOX_AUTO, true };
char ss_available[200];
collection list;
//===================================================//
// //
// CODE //
// //
//===================================================//
void main()
{
int id, i;
load_dll(boxlib, #box_lib_init,0);
load_dll(libini, #lib_init,1);
load_dll(Proc_lib, #OpenDialog_init,0);
OpenDialog_init stdcall (#o_dialog);
GetIniSettings();
tabs.add(#t_skins, #EventTabSkinsClick);
tabs.add(#t_wallpapers, #EventTabWallpappersClick);
tabs.add(#t_screensaver, #EventTabScreensaverClick);
tabs.draw_active_tab();
SetEventMask(EVM_REDRAW + EVM_KEY + EVM_BUTTON + EVM_MOUSE + EVM_MOUSE_FILTER);
loop() switch(WaitEvent())
{
case evMouse:
SelectList_ProcessMouse();
if (tabs.active_tab == TAB_SCREENSAVERS) {
scrollbar_h_mouse stdcall (#ss_timeout);
if (ss_timeout.redraw) {
draw_timeout();
ss_timeout.redraw = false; //reset flag
}
}
break;
case evButton:
id=GetButtonID();
if (id==1) EventExit();
tabs.click(id);
if (tabs.active_tab == TAB_SKINS) {
checkbox1.click(id);
spinbox1.click(id);
}
if (tabs.active_tab == TAB_WALLPAPERS) {
if (id==BTN_SELECT_WALLP_FOLDER) EventSelectWallpFolder();
if (optionbox_stretch.click(id)) EventSetWallpMode(1,0,0);
if (optionbox_tiled.click(id)) EventSetWallpMode(0,1,0);
if (optionbox_auto.click(id)) EventSetWallpMode(0,0,1);
}
if (tabs.active_tab == TAB_SCREENSAVERS) {
if (id==BTN_TEST_SCREENSAVER) EventOpenFile();
if (id==BTN_SET_SCREENSAVER) EventSetSs();
}
break;
case evKey:
GetKeys();
if (select_list.ProcessKey(key_scancode)) { EventApply(); break; }
if (key_scancode==SCAN_CODE_ENTER) { EventOpenFile(); break; }
if (key_scancode==SCAN_CODE_DEL) { EventDeleteFile(); break; }
if (key_scancode==SCAN_CODE_TAB) {
id = tabs.active_tab+1;
if(id==3)id=0;
tabs.click(id + tabs.base_id);
break;
}
for (i=select_list.cur_y+1; i<select_list.count; i++)
{
id = list.get(i) + strrchr(list.get(i), '/');
if (ESBYTE[id]==key_ascii) || (ESBYTE[id]==key_ascii-32)
{
select_list.cur_y = i - 1;
select_list.KeyDown();
EventApply();
break;
}
}
break;
case evReDraw:
draw_window();
}
}
void draw_window()
{
sc.get();
DefineAndDrawWindow(screen.w-WIN_W-9/2,80,WIN_W+9,WIN_H+4+skin_h,0x74,sc.work,WINDOW_HEADER,0);
DrawBar(0, 0, WIN_W, PANEL_H-2, sc.work); //top
DrawBar(0, PANEL_H-2, LP-2, WIN_H-PANEL_H-LP+4, EDX); //left
DrawBar(LIST_W+LP+20, PANEL_H-2, WIN_W-LIST_W-26, WIN_H-PANEL_H-LP+4, EDX); //right
DrawBar(0, WIN_H-LP+2, WIN_W, LP-2, EDX); //bottom
tabs.draw();
draw_icon_16w(tabs.x + TAB_P, LP+5, 17);
draw_icon_16w(sizeof(t_skins)-1*8 + TAB_P + TAB_P + tabs.x, LP+5, 6);
draw_icon_16w(sizeof(t_wallpapers)+sizeof(t_skins)-2*8 + TAB_P + TAB_P + TAB_P + tabs.x, LP+5, 61);
if (tabs.active_tab == TAB_SKINS)
{
DrawFrame(RIGHTx, PANEL_H+5, RIGHTw, RIGHTh, T_UI_PREVIEW);
DrawUiElementsPreview(RIGHTx+20, PANEL_H+5, RIGHTh);
}
if (tabs.active_tab == TAB_WALLPAPERS)
{
DrawFrame(RIGHTx, PANEL_H+5, 180, 105, T_PICTURE_MODE);
optionbox_stretch.draw(RIGHTx+14, PANEL_H+25);
optionbox_tiled.draw(RIGHTx+14, PANEL_H+52);
optionbox_auto.draw(RIGHTx+14, PANEL_H+79);
DrawStandartCaptButton(RIGHTx, PANEL_H+130, BTN_SELECT_WALLP_FOLDER, T_SELECT_FOLDER);
}
if (tabs.active_tab == TAB_SCREENSAVERS)
{
draw_timeout();
ss_timeout.line_col = sc.line;
ss_timeout.frnt_col = sc.work;
scrollbar_h_draw stdcall (#ss_timeout);
DrawRectangle(RIGHTx, RIGHTy+25, RIGHTw-20, 15, sc.line);
ESI = DrawStandartCaptButton(RIGHTx, PANEL_H + 65, BTN_TEST_SCREENSAVER, T_SS_PREVIEW);
DrawStandartCaptButton(RIGHTx+ESI, PANEL_H + 65, BTN_SET_SCREENSAVER, T_SS_SET);
}
$push select_list.cur_y
SelectList_Init(
LP,
PANEL_H,
LIST_W,
WIN_H - LP - PANEL_H
);
$pop select_list.cur_y
SelectList_Draw();
SelectList_DrawBorder();
}
void draw_timeout()
{
miniprintf(#param, T_SS_TIMEOUT, ss_timeout.position+1);
WriteTextWithBg(RIGHTx, PANEL_H, 0xD0, sc.work_text, #param, sc.work);
}
void add_filesnames_into_the_list()
{
int j;
for (j=0; j<select_list.count; j++) {
miniprintf(#param,"%s/",#folder_path);
strcat(#param, io.dir.position(ESDWORD[j*4+fmas]));
list.add(#param);
}
}
void Open_Dir()
{
int j;
dword ext;
select_list.ClearList();
if (io.dir.buffer) free(io.dir.buffer);
io.dir.load(#folder_path,DIR_ONLYREAL);
if (fmas) free(fmas);
fmas = malloc(io.dir.count * 4);
for (j=0; j<io.dir.count; j++)
{
strncpy(#param, io.dir.position(j), PATHLEN);
strlwr(#param);
ext = #param + strrchr(#param,'.');
if (tabs.active_tab==TAB_SKINS) {
if (!streq(ext,"skn")) continue;
}
if (tabs.active_tab==TAB_WALLPAPERS) {
if (!streq(ext,"png")) && (!streq(ext,"jpg"))
&& (!streq(ext,"jpeg")) && (!streq(ext,"bmp"))
&& (!streq(ext,"gif")) continue;
}
ESDWORD[select_list.count*4 + fmas] = j;
select_list.count++;
}
sort_by_name(0, select_list.count-1);
list.drop();
//save current item for tab change
//add default item
if(tabs.active_tab == TAB_SKINS)
{
select_list.count++;
list.add(#default_skin);
add_filesnames_into_the_list();
if (active_skin==-1) && (ESBYTE[#previous_skin])
{
for (j=0; j<select_list.count; j++) {
if (streq(list.get(j), #previous_skin)) {
active_skin = j;
break;
}
}
}
select_list.cur_y = active_skin;
} else {
select_list.count++;
list.add(#default_wallp);
add_filesnames_into_the_list();
if (active_wallpaper==-1) && (ESBYTE[#previous_wallp]=='\\')
{
for (j=0; j<select_list.count; j++) {
if (streq(list.get(j), #previous_wallp+4)) {
active_wallpaper = j;
break;
}
}
}
select_list.cur_y = active_wallpaper;
}
if (!select_list.count) notify(T_NO_FILES);
if (select_list.cur_y>SL_VISIBLE) {
select_list.first = -SL_VISIBLE/2 + select_list.cur_y;
}
select_list.CheckDoesValuesOkey();
if (LIST_W) draw_window();
}
void SelectList_DrawLine(dword i)
{
int draw_y = i*SELECT_LIST_ITEMH+PANEL_H;
int i_abs = select_list.first + i;
dword text_color = 0xFFFfff;
dword bg_color = 0x000000;
char filename_buf[PATHLEN];
char* filename = #filename_buf;
strcpy(filename, list.get(i_abs));
if (EAX = strrchr(filename,'/')) filename += EAX;
if (ESBYTE[filename]=='T') && (ESBYTE[filename+1]=='_') filename+=2;
EAX = math.min(strrchr(filename,'.')-1, LIST_W - 24 / 8);
if(EAX) ESBYTE[filename+EAX] = '\0';
//save current item for tab change
switch(tabs.active_tab) {
CASE TAB_SKINS:
active_skin = select_list.cur_y;
if (!i_abs) filename = T_DEFAULT;
BREAK;
CASE TAB_WALLPAPERS:
active_wallpaper = select_list.cur_y;
if (!i_abs) filename = T_DEFAULT;
BREAK;
CASE TAB_SCREENSAVERS:
active_screensaver = select_list.cur_y;
if (!i_abs) filename = T_NO_SS;
}
if (select_list.cur_y == i_abs) {
text_color = sc.button;
bg_color = sc.button_text;
}
DrawBar(select_list.x, draw_y, LIST_W, SELECT_LIST_ITEMH, text_color);
WriteText(select_list.x+12,draw_y+select_list.text_y,select_list.font_type,bg_color, filename);
}
void GetIniSettings()
{
ini.section = "style";
ini.GetString("default_skin", #default_skin, PATHLEN, 0);
ini.GetString("default_wallp", #default_wallp, PATHLEN, 0);
ini.GetString("skin", #previous_skin, PATHLEN, 0);
ini.GetString("bg_param", #previous_wallp, PATHLEN, 0);
ini.section = "screensaver";
ss_timeout.position = ini.GetInt("timeout", 10) - 1;
ini.GetString("available", #ss_available, sizeof(ss_available), 0);
ini.GetString("program", #previous_ss, PATHLEN, 0);
}
//===================================================//
// //
// EVENTS //
// //
//===================================================//
void EventTabSkinsClick()
{
miniprintf(#folder_path, "%s/res/skins", get_real_kolibrios_path());
Open_Dir();
}
void EventTabWallpappersClick()
{
if (opendir_path) {
strcpy(#folder_path, #opendir_path);
} else {
miniprintf(#folder_path, "%s/res/wallpapers", get_real_kolibrios_path());
}
Open_Dir();
}
void EventTabScreensaverClick()
{
dword j;
char ssmas[sizeof(ss_available)];
list.drop();
select_list.ClearList();
select_list.count++;
list.add("");
strcpy(#ssmas, #ss_available);
do {
j = strrchr(#ssmas, '|');
if (ssmas[j]=='/') {
strcpy(#param, #ssmas + j);
} else {
miniprintf(#param, "/sys/%s", #ssmas + j);
}
list.add(#param);
ESBYTE[#ssmas + j - 1] = '\0';
select_list.count++;
} while (j);
if (active_screensaver == -1) && (ESBYTE[#previous_ss]) {
for (j=0; j<select_list.count; j++) {
if (strstr(list.get(j), #previous_ss)) active_screensaver = j;
}
}
select_list.cur_y = active_screensaver;
if (LIST_W) draw_window();
}
void EventDeleteFile()
{
if (select_list.cur_y) DeleteFile(list.get(select_list.cur_y)); //no not delete default
Open_Dir();
EventApply();
}
void EventSelectWallpFolder()
{
o_dialog.type = 2; //select folder
OpenDialog_start stdcall (#o_dialog);
if (o_dialog.status) EventTabWallpappersClick();
}
void EventSetWallpMode(dword _stretch, _titled, _auto)
{
optionbox_stretch.checked = _stretch;
optionbox_tiled.checked = _titled;
optionbox_auto.checked = _auto;
optionbox_tiled.redraw();
optionbox_stretch.redraw();
optionbox_auto.redraw();
EventApply();
}
void EventApply()
{
char kivparam[4096+10];
dword file_name = list.get(select_list.cur_y);
if (tabs.active_tab==TAB_SKINS)
{
strcpy(#cur_skin_path, list.get(select_list.cur_y));
SetSystemSkin(#cur_skin_path);
MoveSize(OLD, OLD, OLD, WIN_H+4+GetSkinHeight());
}
if (tabs.active_tab==TAB_WALLPAPERS)
{
SelectList_Draw();
miniprintf(#kivparam, "\\S__%s", list.get(select_list.cur_y));
if (optionbox_tiled.checked) || (!select_list.cur_y) kivparam[1]='T';
if (optionbox_auto.checked) {
file_name += strrchr(file_name, '/');
if (ESBYTE[file_name] == 'T') && (ESBYTE[file_name+1] == '_') {
kivparam[1]='T';
}
}
RunProgram("/sys/media/kiv", #kivparam);
}
if (tabs.active_tab==TAB_SCREENSAVERS)
{
SelectList_Draw();
}
}
void EventOpenFile()
{
switch (tabs.active_tab) {
case TAB_SKINS:
RunProgram("/sys/skincfg", list.get(select_list.cur_y));
break;
case TAB_WALLPAPERS:
RunProgram("/sys/media/kiv", list.get(select_list.cur_y));
break;
case TAB_SCREENSAVERS:
if(select_list.cur_y) {
KillProcessByName("@ss", MULTIPLE);
RunProgram(list.get(select_list.cur_y), "@ss");
}
}
}
void EventExit()
{
if (get_real_kolibrios_path()) && (ESBYTE[#cur_skin_path]) {
ini.section = "style";
ini.SetString("skin", #cur_skin_path, strlen(#cur_skin_path));
}
ExitProcess();
}
void EventSetSs()
{
dword cur_ss = list.get(select_list.cur_y);
ini.section = "screensaver";
ini.SetString("program", cur_ss, strlen(cur_ss));
ini.SetInt("timeout", ss_timeout.position+1);
RestartProcessByName("/sys/@ss", MULTIPLE);
}
stop:
char folder_path[PATHLEN];
char cur_skin_path[PATHLEN];
char default_skin[PATHLEN];
char default_wallp[PATHLEN];
char previous_skin[PATHLEN];
char previous_wallp[PATHLEN];
char previous_ss[PATHLEN];
Loaded 100 of 673 files, more files were not shown because too many files have changed in this diff. Show more