#!/bin/bash # ============================================================================= # Tablette Athesi AP1001CL (Cherry Trail x5-Z8350) - MX Linux 25 (systemd) # Installation / mise a jour de tous les reglages. Relancable sans risque. # # Usage : sudo ./installer-tablette.sh # Fichiers optionnels a cote du script : # wallpaper.png fond d'ecran # jeton-rustdesk.txt jeton API de la console RustDesk Pro (jamais dans git) # ============================================================================= set -euo pipefail [ "$(id -u)" = 0 ] || exec sudo "$0" "$@" ICI=$(cd "$(dirname "$0")" && pwd) UTIL=tablette RD_SERVEUR=rust.makeitsimple.be RD_CLE='OhOcYR3xOjsI+4EInYR74DB3Ot1dd0aAl5W0odZXNVk=' RD_CARNET=PainAntan PART=/usr/local/share/tablette # fichiers partages (fond d'ecran, raccourcis) etape() { echo; echo "=== $* ==="; } # Ecrit un fichier seulement si son contenu change (stdin -> chemin, mode) ecrire() { local f=$1 m=${2:-644} t; t=$(mktemp); cat >"$t" if ! cmp -s "$t" "$f" 2>/dev/null; then install -D -m "$m" "$t" "$f"; echo " ecrit : $f"; fi; rm -f "$t"; } # Fixe VAR=valeur dans /etc/environment env_var() { sed -i "/^$1=/d" /etc/environment; echo "$1=$2" >> /etc/environment; } id "$UTIL" >/dev/null 2>&1 || { echo "Utilisateur $UTIL absent : cree-le pendant l'installation de MX."; exit 1; } HOME_U=$(getent passwd "$UTIL" | cut -d: -f6) # ----------------------------------------------------------------------------- etape "Paquets" export DEBIAN_FRONTEND=noninteractive apt-get update -q apt-get install -y -q onboard iio-sensor-proxy xinput xdotool x11-xserver-utils \ v4l-utils yad curl ca-certificates dconf-cli at-spi2-core # ----------------------------------------------------------------------------- etape "Demarrage (GRUB)" # Cherry Trail : C-states profonds -> gels ; reboot ACPI qui ne redemarre pas. # Pas de 'splash' : il bloquait l'interface graphique sur cette tablette. CMDLINE="quiet intel_idle.max_cstate=1 reboot=hard pcie_aspm=off" if ! grep -q "^GRUB_CMDLINE_LINUX_DEFAULT=\"$CMDLINE\"" /etc/default/grub; then sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$CMDLINE\"|" /etc/default/grub update-grub fi # ----------------------------------------------------------------------------- etape "Wi-Fi Intel (iwlwifi)" ecrire /etc/modprobe.d/tablette-iwlwifi.conf <<'EOF' # Stabilite Wi-Fi : pas d'economie d'energie, pas de 802.11n, pas de coexistence BT, # chiffrement logiciel options iwlwifi power_save=0 11n_disable=1 bt_coex_active=0 swcrypto=1 EOF # ----------------------------------------------------------------------------- etape "Firmware camera (atomisp / OV2680)" FW_SHA=e89359f4e4934c410c83d525e283f34c5fcce9cb5caa75ad8a32d66d3842d95c FW=/lib/firmware/intel/ipu/shisp_2401a0_v21.bin if ! echo "$FW_SHA $FW" | sha256sum -c --quiet 2>/dev/null; then t=$(mktemp) curl -fsSL -o "$t" https://raw.githubusercontent.com/intel-aero/meta-intel-aero-base/master/recipes-kernel/linux/linux-yocto/shisp_2401a0_v21.bin echo "$FW_SHA $t" | sha256sum -c --quiet install -D -m644 "$t" "$FW"; ln -sf intel/ipu/shisp_2401a0_v21.bin /lib/firmware/shisp_2401a0_v21.bin rm -f "$t" fi # intel_atomisp2_pm s'accroche a l'ISP et empeche le pilote atomisp de le prendre ecrire /etc/modprobe.d/tablette-camera.conf <<'EOF' blacklist intel_atomisp2_pm EOF # ----------------------------------------------------------------------------- etape "Affichage et tactile (Xorg)" ecrire /etc/X11/xorg.conf.d/20-tablette.conf <<'EOF' # Pilote modesetting en DRI2 : necessaire pour la capture d'ecran RustDesk Section "Device" Identifier "Intel" Driver "modesetting" Option "DRI" "2" Option "Monitor-DSI-1" "DSI-1" Option "Monitor-HDMI-2" "HDMI-2" EndSection # Dalle native en portrait (1200x1920). La rotation en paysage est faite par la session # (tablette-ui) : tournee des le demarrage de X, la dalle restait noire avec seulement # le curseur jusqu'a la premiere rotation. Section "Monitor" Identifier "DSI-1" Option "Primary" "true" EndSection # HDMI (PiKVM) superpose a l'ecran integre Section "Monitor" Identifier "HDMI-2" Option "Position" "0 0" EndSection # Ecran tactile Goodix : meme rotation que l'affichage Section "InputClass" Identifier "tactile tourne" MatchIsTouchscreen "on" Option "TransformationMatrix" "0 1 0 -1 0 1 0 0 1" EndSection # Libre-service : jamais de mise en veille de l'ecran Section "ServerFlags" Option "BlankTime" "0" Option "StandbyTime" "0" Option "SuspendTime" "0" Option "OffTime" "0" EndSection EOF # ----------------------------------------------------------------------------- etape "Session : connexion automatique, variables, Firefox, onboard" groupadd -rf autologin; usermod -aG autologin,video,audio,input,netdev "$UTIL" 2>/dev/null || true ecrire /etc/lightdm/lightdm.conf.d/50-tablette.conf </dev/null || echo "$HOME/Bureau"); mkdir -p "$desk" for f in "$PART"/raccourcis/*.desktop; do dst="$desk/$(basename "$f")"; install -m755 "$f" "$dst" gio set "$dst" metadata::xfce-exe-checksum "$(sha256sum "$dst" | cut -d' ' -f1)" 2>/dev/null || true done xfdesktop --reload 2>/dev/null || true # sinon une icone ajoutee apres son demarrage reste invisible # Fenetres : pas de compositeur (perfs), theme a gros boutons q -c xfwm4 -p /general/use_compositing -n -t bool -s false q -c xfwm4 -p /general/theme -n -t string -s Default-xhdpi q -c xfwm4 -p /general/title_font -n -t string -s "Sans Bold 11" # Polices / DPI / curseur q -c xsettings -p /Xft/DPI -n -t int -s 144 q -c xsettings -p /Gtk/CursorThemeSize -n -t int -s 48 # Tableaux de bord et icones plus grands for p in $(q -c xfce4-panel -l | grep -oE '^/panels/panel-[0-9]+' | sort -u); do q -c xfce4-panel -p "$p/size" -n -t uint -s 56 q -c xfce4-panel -p "$p/icon-size" -n -t uint -s 40 done q -c xfce4-desktop -p /desktop-icons/icon-size -n -t uint -s 72 # Jamais de mise en veille ni de verrouillage pm=/xfce4-power-manager q -c xfce4-power-manager -p $pm/dpms-enabled -n -t bool -s false q -c xfce4-power-manager -p $pm/blank-on-ac -n -t int -s 0 q -c xfce4-power-manager -p $pm/blank-on-battery -n -t int -s 0 q -c xfce4-power-manager -p $pm/lock-screen-suspend-hibernate -n -t bool -s false xset s off -dpms 2>/dev/null || true # Fond d'ecran sur chaque sortie connectee if [ -f "$PART/wallpaper.png" ]; then for out in $(xrandr --query | awk '/ connected/{print $1}'); do b=/backdrop/screen0/monitor$out/workspace0 q -c xfce4-desktop -p $b/last-image -n -t string -s "$PART/wallpaper.png" q -c xfce4-desktop -p $b/image-style -n -t int -s 5 done fi EOF ecrire /etc/xdg/autostart/tablette-ui.desktop <<'EOF' [Desktop Entry] Type=Application Name=Reglages tablette Exec=/usr/local/bin/tablette-ui X-GNOME-Autostart-enabled=true EOF # ----------------------------------------------------------------------------- etape "Rotation automatique (accelerometre)" ecrire /usr/local/bin/tablette-rotation 755 <<'EOF' #!/bin/bash # Orientation physique (iio-sensor-proxy) -> rotation xrandr + matrice du tactile Goodix touch="Goodix Capacitive TouchScreen" last= apply() { case "$1" in # Correspondance validee sur la tablette (capteur monte tete-beche) normal) rot=inverted; m="-1 0 1 0 -1 1 0 0 1" ;; left-up) rot=left; m="0 -1 1 1 0 0 0 0 1" ;; right-up) rot=right; m="0 1 0 -1 0 1 0 0 1" ;; bottom-up) rot=normal; m="1 0 0 0 1 0 0 0 1" ;; *) return ;; esac # HDMI branche (PiKVM) : on reste en paysage. Tourner l'ecran integre tout en le # recopiant sur l'HDMI a donne ecran noir et gels sur cette puce. if xrandr | grep -q '^HDMI-2 connected'; then rot=right; m="0 1 0 -1 0 1 0 0 1"; fi [ "$rot" = "$last" ] && return last=$rot xrandr --output DSI-1 --rotate "$rot" --transform none --scale 1x1 for id in $(xinput list | grep -F "$touch" | grep -o 'id=[0-9]*' | cut -d= -f2); do xinput set-prop "$id" "Coordinate Transformation Matrix" $m 2>/dev/null done } sleep 8 # apres les reglages de session monitor-sensor | while read -r line; do case "$line" in *"orientation changed:"*|*"Has accelerometer"*orientation:*) apply "$(echo "$line" | grep -oE '(normal|left-up|right-up|bottom-up)' | tail -1)" ;; esac done EOF ecrire /etc/xdg/autostart/tablette-rotation.desktop <<'EOF' [Desktop Entry] Type=Application Name=Rotation automatique Exec=/usr/local/bin/tablette-rotation X-GNOME-Autostart-enabled=true EOF # ----------------------------------------------------------------------------- etape "Theme aux couleurs Le Pain d'Antan" # Icones Papirus avec des dossiers bruns (au lieu du bleu) : on repointe les liens # symboliques des dossiers *-blue* vers leur equivalent *-brown* livre avec Papirus for d in /usr/share/icons/Papirus/*/places; do for l in "$d"/*.svg; do [ -L "$l" ] || continue c=$(readlink "$l") case "$c" in *-blue*) n=${c//-blue/-brown}; [ -e "$d/$n" ] && ln -sfn "$n" "$l" ;; esac done done gtk-update-icon-cache -qf /usr/share/icons/Papirus 2>/dev/null || true # Brun fonce du fond d'ecran, creme du logo, caramel pour les selections install -d -o "$UTIL" -g "$UTIL" "$HOME_U/.config/gtk-3.0" ecrire "$HOME_U/.config/gtk-3.0/gtk.css" <<'EOF' /* Couleurs Le Pain d'Antan (tablette) */ @define-color theme_selected_bg_color #9a6a45; @define-color theme_selected_fg_color #ffffff; *:selected, selection, menuitem:hover, row:selected, treeview:selected { background-color: #9a6a45; color: #ffffff; } progressbar progress, scale highlight { background-color: #9a6a45; border-color: #6e4a30; } #XfcePanelWindow, .xfce4-panel { background-color: #2e1d15; color: #f3e9d8; } #XfcePanelWindow button, #XfcePanelWindow label, .xfce4-panel button, .xfce4-panel label { color: #f3e9d8; } #XfcePanelWindow button:hover, #XfcePanelWindow button:checked { background-color: #4a2e20; } EOF chown "$UTIL:" "$HOME_U/.config/gtk-3.0/gtk.css" ecrire /usr/local/bin/tablette-theme 755 <<'EOF' #!/bin/bash # Theme neutre + accents bruns ; retrait des icones MX par defaut du bureau sleep 6 xfconf-query -c xsettings -p /Net/ThemeName -n -t string -s Greybird xfconf-query -c xsettings -p /Net/IconThemeName -n -t string -s Papirus xfconf-query -c xfce4-panel -p /panels/panel-1/background-style -n -t uint -s 0 2>/dev/null desk=$(xdg-user-dir DESKTOP 2>/dev/null || echo "$HOME/Bureau") rm -f "$desk/FAQ.desktop" "$desk/Help.desktop" "$desk/Quick_System_Info.desktop" EOF ecrire /etc/xdg/autostart/tablette-theme.desktop <<'EOF' [Desktop Entry] Type=Application Name=Theme tablette Exec=/usr/local/bin/tablette-theme X-GNOME-Autostart-enabled=true EOF # ----------------------------------------------------------------------------- etape "Performances (memoire, services, eMMC, video)" apt-get install -y -q zram-tools i965-va-driver python3-pil # Memoire compressee : moins d'echanges avec l'eMMC, lente ecrire /etc/default/zramswap <<'EOF' ALGO=zstd PERCENT=50 PRIORITY=100 EOF systemctl unmask zramswap >/dev/null 2>&1 || true; systemctl enable zramswap >/dev/null 2>&1 || true; systemctl restart zramswap || true ecrire /etc/sysctl.d/90-tablette.conf <<'EOF' vm.swappiness=100 EOF sysctl -q --system || true env_var LIBVA_DRIVER_NAME i965 # decodage video materiel (Cherry Trail) # Services inutiles sur la tablette (Bluetooth conserve) for s in cups cups-browsed ModemManager; do systemctl disable --now "$s" >/dev/null 2>&1 || true; done # Pas de verification des mises a jour MX en arriere-plan (mises a jour faites a la main) for f in /etc/xdg/autostart/*.desktop; do if grep -qiE 'apt-notifier|mx-updater' "$f"; then a=$(basename "$f") printf '[Desktop Entry]\nType=Application\nName=%s\nHidden=true\n' "$a" | ecrire "$HOME_U/.config/autostart/$a" chown "$UTIL:" "$HOME_U/.config/autostart/$a" fi done # eMMC : pas d'ecriture a chaque lecture (noatime), TRIM hebdomadaire, journal limite if ! awk '$2=="/" {print $4}' /etc/fstab | grep -q noatime; then cp /etc/fstab /etc/fstab.avant-tablette awk 'BEGIN{OFS="\t"} $1 !~ /^#/ && $2=="/" {$4=$4",noatime"} {print}' /etc/fstab.avant-tablette > /etc/fstab fi systemctl enable fstrim.timer >/dev/null 2>&1 || true ecrire /etc/systemd/journald.conf.d/tablette.conf <<'EOF' [Journal] SystemMaxUse=64M EOF # ----------------------------------------------------------------------------- etape "Image du menu de demarrage (GRUB)" # GRUB s'affiche sur la dalle en portrait natif : l'image est composee en paysage # (logo centre sur le brun du fond d'ecran) puis tournee d'un quart de tour. if [ -f "$ICI/bootloader.png" ]; then python3 - "$ICI/bootloader.png" /boot/grub/tablette-fond.png <<'PY' import sys from PIL import Image src = Image.open(sys.argv[1]).convert("RGBA") fond = Image.new("RGBA", (1920, 1200), (74, 46, 32, 255)) boite = (1920, 1200) if src.width >= 1600 else (1150, 720) src.thumbnail(boite) fond.alpha_composite(src, ((1920 - src.width) // 2, (1200 - src.height) // 2)) fond.convert("RGB").transpose(Image.Transpose.ROTATE_270).save(sys.argv[2]) PY sed -i -e '/^GRUB_THEME=/s/^/#/' -e '/^GRUB_BACKGROUND=/d' /etc/default/grub echo 'GRUB_BACKGROUND="/boot/grub/tablette-fond.png"' >> /etc/default/grub update-grub fi # ----------------------------------------------------------------------------- etape "RustDesk" if ! command -v rustdesk >/dev/null; then url=$(curl -fsSL https://api.github.com/repos/rustdesk/rustdesk/releases/latest \ | grep -oE '"browser_download_url": *"[^"]+x86_64\.deb"' | tail -n1 | cut -d'"' -f4) t=$(mktemp --suffix=.deb); curl -fsSL -o "$t" "$url" apt-get install -y -q "$t"; rm -f "$t" fi install -d -m700 /etc/rustdesk [ -f "$ICI/jeton-rustdesk.txt" ] && install -m600 "$ICI/jeton-rustdesk.txt" /etc/rustdesk/token ecrire /usr/local/sbin/tablette-rustdesk 755 <>/usr/local/sbin/tablette-rustdesk <<'EOF' toml() { cat <&1) && case "$out" in *refused*|*rror*) ;; *) return 0 ;; esac sleep 2 done; return 1 } case "${1:-}" in config) systemctl stop rustdesk 2>/dev/null || true h=$(getent passwd "$UTIL" | cut -d: -f6) for d in /root/.config/rustdesk "$h/.config/rustdesk"; do install -d -m700 "$d"; toml > "$d/RustDesk2.toml"; chmod 600 "$d/RustDesk2.toml" done chown -R "$UTIL:" "$h/.config/rustdesk" systemctl enable --now rustdesk ;; motdepasse) [ -s /etc/rustdesk/password ] || ( umask 077; tr -dc 'A-Za-z0-9' /etc/rustdesk/password ) attendre_service "$(cat /etc/rustdesk/password)" && echo "mot de passe permanent applique" ;; enregistrer) nom=${2:?nom} [ -s /etc/rustdesk/token ] || { echo "pas de jeton (/etc/rustdesk/token) : enregistrement ignore"; exit 0; } sleep 10 # laisser le service s'annoncer aupres du serveur out=$(rustdesk --assign --token "$(cat /etc/rustdesk/token)" --address_book_name "$CARNET" \ --address_book_alias "$nom" --address_book_password "$(cat /etc/rustdesk/password)" 2>&1) echo "$out"; case "$out" in *rror*|*ailed*) exit 1 ;; esac echo "ID RustDesk : $(rustdesk --get-id)" ;; *) echo "usage : $0 config|motdepasse|enregistrer NOM"; exit 2 ;; esac EOF chmod 755 /usr/local/sbin/tablette-rustdesk tablette-rustdesk config tablette-rustdesk motdepasse || echo " (mot de passe : le service n'a pas repondu, relancer le script)" # ----------------------------------------------------------------------------- etape "Clonage : preparation et premier demarrage" # 1) tablette-preparer-clonage : a lancer sur la tablette modele juste avant l'image Clonezilla ecrire /usr/local/sbin/tablette-preparer-clonage 755 <<'EOF' #!/bin/bash # Efface l'identite de cette tablette puis l'eteint. Au prochain demarrage (modele ou clone), # un nom est demande a l'ecran et une nouvelle identite est creee. set -e [ "$(id -u)" = 0 ] || exec sudo "$0" "$@" [ -s /etc/rustdesk/token ] || echo "ATTENTION : pas de jeton RustDesk, les clones ne s'inscriront pas dans le carnet." read -r -p "Effacer l'identite de cette tablette et l'eteindre ? [o/N] " r; [ "$r" = o ] || exit 1 systemctl stop rustdesk || true rm -f /root/.config/rustdesk/RustDesk.toml /home/*/.config/rustdesk/RustDesk.toml # -> nouvel ID rm -f /etc/rustdesk/password # -> nouveau mot de passe rm -f /etc/ssh/ssh_host_* # -> nouvelles cles SSH truncate -s0 /etc/machine-id; rm -f /var/lib/dbus/machine-id # -> nouveau machine-id install -d /etc/tablette; touch /etc/tablette/a-personnaliser journalctl --rotate >/dev/null 2>&1 && journalctl --vacuum-time=1s >/dev/null 2>&1 || true echo "Prete pour l'image Clonezilla. Extinction."; sleep 2; poweroff EOF # 2) Au demarrage (root) : nouvelle identite, puis attente du nom saisi dans la session ecrire /usr/local/sbin/tablette-premier-demarrage 755 <<'EOF' #!/bin/bash set -u [ -s /var/lib/dbus/machine-id ] || ln -sf /etc/machine-id /var/lib/dbus/machine-id ls /etc/ssh/ssh_host_*_key >/dev/null 2>&1 || ssh-keygen -A 2>/dev/null || true install -d -m 770 -o root -g tablette /run/tablette # le nom y sera depose par la session EOF ecrire /etc/systemd/system/tablette-premier-demarrage.service <<'EOF' [Unit] Description=Tablette : nouvelle identite apres clonage ConditionPathExists=/etc/tablette/a-personnaliser Before=display-manager.service ssh.service rustdesk.service [Service] Type=oneshot ExecStart=/usr/local/sbin/tablette-premier-demarrage [Install] WantedBy=multi-user.target EOF # 3) Dans la session : demande du nom (clavier visuel affiche) ecrire /usr/local/bin/tablette-demander-nom 755 <<'EOF' #!/bin/bash [ -e /etc/tablette/a-personnaliser ] || exit 0 sleep 12; pgrep -x onboard >/dev/null || (setxkbmap be; onboard &) while :; do nom=$(yad --entry --center --on-top --title "Nouvelle tablette" --width 600 \ --text "Nom de cette tablette ?\n(minuscules, chiffres et tirets - ex. pa-ixl-tab-02)" \ --button="Valider:0") || continue nom=$(echo "$nom" | tr 'A-Z' 'a-z') if [[ "$nom" =~ ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ ]]; then break; fi yad --error --center --text "Nom invalide : $nom" --button=OK:0 done echo "$nom" > /run/tablette/nom yad --info --center --no-buttons --timeout 120 --text "Configuration de '$nom'...\nLa tablette va redemarrer." & EOF ecrire /etc/xdg/autostart/tablette-demander-nom.desktop <<'EOF' [Desktop Entry] Type=Application Name=Nom de la tablette Exec=/usr/local/bin/tablette-demander-nom X-GNOME-Autostart-enabled=true EOF # 4) Des que le nom est depose (root) : nom de machine, RustDesk, puis redemarrage ecrire /usr/local/sbin/tablette-nommer 755 <<'EOF' #!/bin/bash set -u nom=$(head -c 63 /run/tablette/nom | tr -cd 'a-z0-9-'); rm -f /run/tablette/nom [ -n "$nom" ] || exit 1 hostnamectl set-hostname "$nom" sed -i "/^127\.0\.1\.1/d" /etc/hosts; echo -e "127.0.1.1\t$nom" >> /etc/hosts systemctl restart rustdesk; sleep 5 tablette-rustdesk motdepasse if tablette-rustdesk enregistrer "$nom"; then echo "Inscrite dans le carnet RustDesk sous '$nom'" else echo "Inscription RustDesk echouee : relancer 'sudo tablette-rustdesk enregistrer $nom'" fi rm -f /etc/tablette/a-personnaliser sleep 3; systemctl reboot EOF ecrire /etc/systemd/system/tablette-nommer.path <<'EOF' [Unit] Description=Tablette : nom saisi au premier demarrage ConditionPathExists=/etc/tablette/a-personnaliser [Path] PathExists=/run/tablette/nom [Install] WantedBy=multi-user.target EOF ecrire /etc/systemd/system/tablette-nommer.service <<'EOF' [Unit] Description=Tablette : nom, RustDesk, redemarrage [Service] Type=oneshot ExecStart=/usr/local/sbin/tablette-nommer EOF systemctl daemon-reload systemctl enable tablette-premier-demarrage.service tablette-nommer.path # ----------------------------------------------------------------------------- etape "Inscription RustDesk de cette tablette" tablette-rustdesk enregistrer "$(hostname)" || echo " (a relancer plus tard : sudo tablette-rustdesk enregistrer $(hostname))" etape "Termine" echo "ID RustDesk : $(rustdesk --get-id 2>/dev/null)" echo "Mot de passe permanent : sudo cat /etc/rustdesk/password" echo "Redemarre la tablette pour appliquer GRUB, Xorg et la session."