Add Fastboot/EDL reboot modes and SIM contact import/export

This commit is contained in:
Luxferre
2026-10-25 07:56:44 +02:00
parent a1e4f6ef8c
commit a117e74452
17 changed files with 864 additions and 37 deletions
+3
View File
@@ -30,5 +30,8 @@ permit nopass :wheel as root cmd rtcwake
permit nopass :wheel as root cmd tee args -a /sys/power/wake_lock
permit nopass :wheel as root cmd tee args -a /sys/power/wake_unlock
permit nopass :wheel as root cmd tee args /sys/power/wakeup_count
permit nopass :wheel as root cmd tee args /sys/module/leds_msm8905_torch/parameters/next_reboot_mode
permit nopass :wheel as root cmd /usr/bin/sxmo_power.sh
permit nopass :wheel as root cmd sxmo_power.sh
permit nopass :wheel as root cmd rc-service args hexagonrpcd-adsp-sensorspd stop
permit nopass :wheel as root cmd systemctl args stop hexagonrpcd-adsp-sensorspd
+2
View File
@@ -210,6 +210,8 @@ getprogchoices() {
$icon_lck Lock (Screen off)^0^sxmo_state.sh set screenoff
$icon_out Logout^0^confirm Logout && sxmo_power.sh logout
$icon_rld Reboot^0^confirm Reboot && sxmo_power.sh reboot
$icon_rld Reboot to Fastboot^0^confirm Fastboot && sxmo_power.sh fastboot
$icon_rld Reboot to EDL^0^confirm EDL && sxmo_power.sh edl
$icon_pwr Poweroff^0^confirm Poweroff && sxmo_power.sh poweroff"
;;
modem)
+41 -1
View File
@@ -8,7 +8,7 @@ export PATH="/sbin:/usr/sbin:$PATH"
. sxmo_common.sh
usage() {
printf "usage: %s [reboot|poweroff|logout|togglewm]\n" "$(basename "$0")"
printf "usage: %s [reboot|fastboot|bootloader|edl|poweroff|logout|togglewm]\n" "$(basename "$0")"
}
run_polkit_login1() {
@@ -89,9 +89,29 @@ run_priv_power() {
return 1
}
set_kernel_reboot_mode() {
rmode="$1"
param_path="/sys/module/leds_msm8905_torch/parameters/next_reboot_mode"
if [ -e "$param_path" ]; then
printf "%s\n" "$rmode" | /usr/bin/doas tee "$param_path" >/dev/null 2>&1 || \
printf "%s\n" "$rmode" > "$param_path" 2>/dev/null || true
fi
}
force_reboot_cmd() {
rmode="$1"
/usr/bin/doas python3 -c "
import ctypes, os
os.sync()
libc = ctypes.CDLL(None)
libc.syscall(88, 0xfee1dead, 672274793, 0xa1b2c3d4, b'$rmode')
" >/dev/null 2>&1 || /usr/bin/doas /sbin/reboot -f >/dev/null 2>&1 || true
}
case "$1" in
reboot)
sync
set_kernel_reboot_mode ""
sxmo_hook_power.sh reboot || true
(sleep 4; [ -u /usr/bin/doas ] && /usr/bin/doas /sbin/reboot -f >/dev/null 2>&1 || [ -u /usr/bin/sudo ] && /usr/bin/sudo -n /sbin/reboot -f >/dev/null 2>&1) &
if ! run_priv_power reboot; then
@@ -102,6 +122,26 @@ case "$1" in
fi
sxmo_jobs.sh stop all >/dev/null 2>&1 || true
;;
fastboot|bootloader)
sync
set_kernel_reboot_mode "bootloader"
sxmo_hook_power.sh reboot || true
(sleep 4; force_reboot_cmd "bootloader") &
if ! run_priv_power reboot; then
force_reboot_cmd "bootloader"
fi
sxmo_jobs.sh stop all >/dev/null 2>&1 || true
;;
edl)
sync
set_kernel_reboot_mode "edl"
sxmo_hook_power.sh reboot || true
(sleep 4; force_reboot_cmd "edl") &
if ! run_priv_power reboot; then
force_reboot_cmd "edl"
fi
sxmo_jobs.sh stop all >/dev/null 2>&1 || true
;;
poweroff)
sync
sxmo_hook_power.sh poweroff || true
Binary file not shown.
Binary file not shown.
@@ -558,8 +558,331 @@ case "$cmd" in
exit 1
;;
sim-contacts-import)
req_slot="${2:-auto}"
if ! wait_for_qmicli_modem 3; then
echo "ERROR: No modem available"
exit 1
fi
QMI_CARDS="$($QMICLI_MODEM --uim-get-card-status 2>/dev/null || true)"
if [ -z "$QMI_CARDS" ]; then
echo "ERROR: Cannot read SIM card status"
exit 1
fi
eval "$(parse_uim_card_status "$QMI_CARDS" "$PREFERRED_SIM_SLOT")"
target_slot=""
target_aid=""
if [ "$req_slot" = "1" ]; then
if [ "$SLOT1_STATE" != "present" ]; then
echo "ERROR: SIM 1 is not inserted"
exit 1
fi
target_slot="1"
target_aid="$SLOT1_AID"
elif [ "$req_slot" = "2" ]; then
if [ "$SLOT2_STATE" != "present" ]; then
echo "ERROR: SIM 2 is not inserted"
exit 1
fi
target_slot="2"
target_aid="$SLOT2_AID"
else
if [ "$PRIMARY_GW_SLOT" = "1" ] && [ "$SLOT1_STATE" = "present" ]; then
target_slot="1"
target_aid="$SLOT1_AID"
elif [ "$PRIMARY_GW_SLOT" = "2" ] && [ "$SLOT2_STATE" = "present" ]; then
target_slot="2"
target_aid="$SLOT2_AID"
elif [ "$SLOT1_STATE" = "present" ]; then
target_slot="1"
target_aid="$SLOT1_AID"
elif [ "$SLOT2_STATE" = "present" ]; then
target_slot="2"
target_aid="$SLOT2_AID"
else
echo "ERROR: No SIM card detected"
exit 1
fi
fi
orig_gw_slot="$PRIMARY_GW_SLOT"
orig_gw_aid=""
if [ "$orig_gw_slot" = "1" ]; then
orig_gw_aid="$SLOT1_AID"
elif [ "$orig_gw_slot" = "2" ]; then
orig_gw_aid="$SLOT2_AID"
fi
switched_gw=0
restore_gw_slot() {
if [ "$switched_gw" = "1" ]; then
$QMICLI_MODEM --uim-change-provisioning-session='activate=no,session-type=primary-gw-provisioning' >/dev/null 2>&1 || true
if [ -n "$orig_gw_slot" ] && [ "$orig_gw_slot" != "0" ] && [ -n "$orig_gw_aid" ]; then
$QMICLI_MODEM --uim-change-provisioning-session="slot=$orig_gw_slot,activate=yes,session-type=primary-gw-provisioning,aid=$orig_gw_aid" >/dev/null 2>&1 || true
fi
switched_gw=0
fi
}
trap restore_gw_slot EXIT INT TERM
if [ "$PRIMARY_GW_SLOT" != "$target_slot" ] && [ -n "$target_aid" ]; then
if [ "$PRIMARY_GW_SLOT" != "0" ]; then
$QMICLI_MODEM --uim-change-provisioning-session='activate=no,session-type=primary-gw-provisioning' >/dev/null 2>&1 || true
fi
if $QMICLI_MODEM --uim-change-provisioning-session="slot=$target_slot,activate=yes,session-type=primary-gw-provisioning,aid=$target_aid" >/dev/null 2>&1; then
switched_gw=1
sleep 1
fi
fi
tmp_contacts="/tmp/sim_import_$$.tsv"
rm -f "$tmp_contacts"
: > "$tmp_contacts"
# Method 1: Standard 3GPP AT+CPBS="SM" / AT+CPBR
at_info="$("$0" at auto 'AT+CMEE=2;+CSCS="GSM";+CPBS="SM";+CPBR=?' 2>/dev/null || true)"
max_idx="$(printf "%s\n" "$at_info" | sed -n 's/.*+CPBR:[[:space:]]*([0-9]*-\([0-9]*\)).*/\1/p' | head -n1)"
if [ -n "$max_idx" ] && [ "$max_idx" -gt 0 ] 2>/dev/null; then
if [ "$max_idx" -gt 500 ]; then
max_idx=500
fi
start_idx=1
while [ "$start_idx" -le "$max_idx" ]; do
end_idx=$((start_idx + 49))
if [ "$end_idx" -gt "$max_idx" ]; then
end_idx="$max_idx"
fi
chunk="$("$0" at auto "AT+CPBR=${start_idx},${end_idx}" 2>/dev/null || true)"
if [ -n "$chunk" ]; then
printf "%s\n" "$chunk" | awk '
/^\+CPBR:[[:space:]]*[0-9]+,/ {
line = $0
sub(/^\+CPBR:[[:space:]]*[0-9]+,[[:space:]]*"/, "", line)
q1 = index(line, "\"")
if (q1 <= 0) next
num = substr(line, 1, q1 - 1)
rest = substr(line, q1 + 1)
sub(/^[[:space:]]*,[[:space:]]*/, "", rest)
c2 = index(rest, ",")
if (c2 <= 0) next
ton = substr(rest, 1, c2 - 1) + 0
name = substr(rest, c2 + 1)
sub(/^[[:space:]]*"/, "", name)
sub(/"[[:space:]]*$/, "", name)
gsub(/[\t\r\n]/, " ", name)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", name)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", num)
if (num == "") next
if (ton == 145 && substr(num, 1, 1) != "+") {
num = "+" num
}
if (name == "") name = num
printf "%s\t%s\n", num, name
}
' >> "$tmp_contacts"
fi
start_idx=$((end_idx + 1))
done
fi
# Method 2: Direct QMI UIM EF_ADN (3F00:7F10:6F3A) record fallback
if [ ! -s "$tmp_contacts" ]; then
adn_attr="$($QMICLI_MODEM --uim-get-file-attributes=0x3F00,0x7F10,0x6F3A 2>/dev/null || true)"
reclen="$(printf "%s\n" "$adn_attr" | awk -F"'" '/Record length:/ {print $2 + 0; exit}')"
reccount="$(printf "%s\n" "$adn_attr" | awk -F"'" '/Record count:/ {print $2 + 0; exit}')"
if [ -n "$reclen" ] && [ -n "$reccount" ] && [ "$reclen" -ge 14 ] 2>/dev/null && [ "$reccount" -ge 1 ] 2>/dev/null; then
if [ "$reccount" -gt 250 ]; then
reccount=250
fi
rec=1
while [ "$rec" -le "$reccount" ]; do
raw_rec="$($QMICLI_MODEM --uim-read-record="file=0x3F00,0x7F10,0x6F3A,record-number=${rec},record-length=${reclen}" 2>/dev/null || true)"
if [ -n "$raw_rec" ]; then
printf "%s\n" "$raw_rec" | awk -v rlen="$reclen" '
function hex2val(h, i, c, v, res) {
res = 0
h = toupper(h)
for (i = 1; i <= length(h); i++) {
c = substr(h, i, 1)
v = index("0123456789ABCDEF", c) - 1
if (v < 0) return -1
res = res * 16 + v
}
return res
}
function bcd_digit(n) {
if (n >= 0 && n <= 9) return "" n
if (n == 10) return "*"
if (n == 11) return "#"
return ""
}
/^[[:space:]]*([0-9A-Fa-f]{2}:)+[0-9A-Fa-f]{2}[[:space:]]*$/ {
line = $0
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
n = split(line, hex, ":")
if (n < 14) next
alpha_len = n - 14
bcd_len = hex2val(hex[alpha_len + 1])
ton_npi = hex2val(hex[alpha_len + 2])
if (bcd_len <= 0 || bcd_len > 11 || bcd_len == 255) next
num = ""
if (int(ton_npi / 16) % 8 == 1) {
num = "+"
}
bcd_bytes = bcd_len - 1
if (bcd_bytes > 10) bcd_bytes = 10
for (i = 1; i <= bcd_bytes; i++) {
b = hex2val(hex[alpha_len + 2 + i])
if (b < 0 || b == 255) break
lo = b % 16
hi = int(b / 16)
d1 = bcd_digit(lo)
if (d1 == "") break
num = num d1
d2 = bcd_digit(hi)
if (d2 == "") break
num = num d2
}
if (num == "" || num == "+") next
name = ""
for (i = 1; i <= alpha_len; i++) {
b = hex2val(hex[i])
if (b < 0 || b == 255) break
if (b >= 32 && b < 127 && b != 9) {
name = name sprintf("%c", b)
}
}
gsub(/^[[:space:]]+|[[:space:]]+$/, "", name)
if (name == "") name = num
printf "%s\t%s\n", num, name
}
' >> "$tmp_contacts"
fi
rec=$((rec + 1))
done
fi
fi
cat "$tmp_contacts"
rm -f "$tmp_contacts"
exit 0
;;
sim-contacts-export)
req_slot="${2:-auto}"
src_tsv="${3:-/home/user/.config/sxmo/contacts.tsv}"
if [ ! -r "$src_tsv" ]; then
echo "ERROR: Contacts file not found"
exit 1
fi
if ! wait_for_qmicli_modem 3; then
echo "ERROR: No modem available"
exit 1
fi
QMI_CARDS="$($QMICLI_MODEM --uim-get-card-status 2>/dev/null || true)"
if [ -z "$QMI_CARDS" ]; then
echo "ERROR: Cannot read SIM card status"
exit 1
fi
eval "$(parse_uim_card_status "$QMI_CARDS" "$PREFERRED_SIM_SLOT")"
target_slot=""
target_aid=""
if [ "$req_slot" = "1" ]; then
if [ "$SLOT1_STATE" != "present" ]; then
echo "ERROR: SIM 1 is not inserted"
exit 1
fi
target_slot="1"
target_aid="$SLOT1_AID"
elif [ "$req_slot" = "2" ]; then
if [ "$SLOT2_STATE" != "present" ]; then
echo "ERROR: SIM 2 is not inserted"
exit 1
fi
target_slot="2"
target_aid="$SLOT2_AID"
else
if [ "$PRIMARY_GW_SLOT" = "1" ] && [ "$SLOT1_STATE" = "present" ]; then
target_slot="1"
target_aid="$SLOT1_AID"
elif [ "$PRIMARY_GW_SLOT" = "2" ] && [ "$SLOT2_STATE" = "present" ]; then
target_slot="2"
target_aid="$SLOT2_AID"
elif [ "$SLOT1_STATE" = "present" ]; then
target_slot="1"
target_aid="$SLOT1_AID"
elif [ "$SLOT2_STATE" = "present" ]; then
target_slot="2"
target_aid="$SLOT2_AID"
else
echo "ERROR: No SIM card detected"
exit 1
fi
fi
orig_gw_slot="$PRIMARY_GW_SLOT"
orig_gw_aid=""
if [ "$orig_gw_slot" = "1" ]; then
orig_gw_aid="$SLOT1_AID"
elif [ "$orig_gw_slot" = "2" ]; then
orig_gw_aid="$SLOT2_AID"
fi
switched_gw=0
restore_gw_slot_exp() {
if [ "$switched_gw" = "1" ]; then
$QMICLI_MODEM --uim-change-provisioning-session='activate=no,session-type=primary-gw-provisioning' >/dev/null 2>&1 || true
if [ -n "$orig_gw_slot" ] && [ "$orig_gw_slot" != "0" ] && [ -n "$orig_gw_aid" ]; then
$QMICLI_MODEM --uim-change-provisioning-session="slot=$orig_gw_slot,activate=yes,session-type=primary-gw-provisioning,aid=$orig_gw_aid" >/dev/null 2>&1 || true
fi
switched_gw=0
fi
}
trap restore_gw_slot_exp EXIT INT TERM
if [ "$PRIMARY_GW_SLOT" != "$target_slot" ] && [ -n "$target_aid" ]; then
if [ "$PRIMARY_GW_SLOT" != "0" ]; then
$QMICLI_MODEM --uim-change-provisioning-session='activate=no,session-type=primary-gw-provisioning' >/dev/null 2>&1 || true
fi
if $QMICLI_MODEM --uim-change-provisioning-session="slot=$target_slot,activate=yes,session-type=primary-gw-provisioning,aid=$target_aid" >/dev/null 2>&1; then
switched_gw=1
sleep 1
fi
fi
at_info="$("$0" at auto 'AT+CMEE=2;+CSCS="GSM";+CPBS="SM";+CPBR=?' 2>/dev/null || true)"
if printf "%s\n" "$at_info" | grep -qE "ERROR"; then
echo "ERROR: SIM $target_slot phonebook not ready"
exit 1
fi
tlen="$(printf "%s\n" "$at_info" | sed -n 's/.*+CPBR:[[:space:]]*([0-9]*-[0-9]*),[0-9]*,\([0-9]*\).*/\1/p' | head -n1)"
if [ -z "$tlen" ] || [ "$tlen" -le 0 ] 2>/dev/null; then
tlen=14
fi
exported=0
while IFS="$(printf '\t')" read -r raw_num raw_name; do
num="$(printf "%s" "$raw_num" | tr -cd '+0-9*#')"
name="$(printf "%s" "$raw_name" | tr -d '"\r\n\t\\' | cut -c1-"$tlen")"
[ -n "$num" ] || continue
[ -n "$name" ] || name="$(printf "%s" "$num" | cut -c1-"$tlen")"
ton=129
case "$num" in
+*) ton=145 ;;
esac
res="$("$0" at auto "AT+CPBW=,\"${num}\",${ton},\"${name}\"" 2>/dev/null || true)"
if printf "%s\n" "$res" | grep -q "OK"; then
exported=$((exported + 1))
fi
done < "$src_tsv"
echo "EXPORTED=${exported}"
echo "SLOT=${target_slot}"
exit 0
;;
*)
echo "Usage: $0 [boot|status|switch <1|2>|verify-pin <slot> <pin>|unblock-puk <slot> <puk> <newpin>|set-pin-lock <slot> <enable|disable> <pin>|change-pin <slot> <oldpin> <newpin>|imei|usb-tether <on|off|status>|at <port> <cmd>]" >&2
echo "Usage: $0 [boot|status|switch <1|2>|verify-pin <slot> <pin>|unblock-puk <slot> <puk> <newpin>|set-pin-lock <slot> <enable|disable> <pin>|change-pin <slot> <oldpin> <newpin>|imei|usb-tether <on|off|status>|at <port> <cmd>|sim-contacts-import [1|2|auto]|sim-contacts-export [1|2|auto] [tsv_file]]" >&2
exit 1
;;
esac
@@ -91,6 +91,8 @@ case "$WMCLASS" in
$icon_lck Lock (Screen off) ^ 0 ^ sxmo_state.sh set screenoff
$icon_out Logout ^ 0 ^ confirm Logout && sxmo_power.sh logout
$icon_rld Reboot ^ 0 ^ confirm Reboot && sxmo_power.sh reboot
$icon_rld Reboot to Fastboot ^ 0 ^ confirm Fastboot && sxmo_power.sh fastboot
$icon_rld Reboot to EDL ^ 0 ^ confirm EDL && sxmo_power.sh edl
$icon_pwr Poweroff ^ 0 ^ confirm Poweroff && sxmo_power.sh poweroff
"
WINNAME=Power