Created
April 14, 2019 23:10
-
-
Save andmarios/a3165cf01d56ceb9233662e44f99307f to your computer and use it in GitHub Desktop.
Script to control battery charge and fn lock for Matebook X Pro. Requires vim (xxd), hexdump, dd, ec_sys module and bash.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
help() { | |
cat <<EOF | |
Options: | |
- cc-disable | |
Disable charging control | |
- cc-home | |
Charging control to Home mode (40%-70%) | |
- cc-work | |
Charging control to Work mode (70%-90%) | |
- cc-travel | |
Charging control to Travel mode (95%) | |
- fn-keys | |
Set default FN (LED off) to F-keys | |
- fn-functions | |
Set default FN (LED off) to Functions | |
- ec | |
Try to load ec_sys module and enable write support for it | |
It is required for any other option to work | |
EOF | |
} | |
load_ec_write() { | |
if modprobe ec_sys write_support=1; then | |
return | |
fi | |
if echo Y > /sys/module/ec_sys/parameters/write_support; then | |
return | |
fi | |
echo "Failed to load ec_sys or enable write_support." | |
exit 1 | |
} | |
battery_charge_control_disable() { | |
# Load byte-register for charge control: | |
CHARGE_CONTROL_BYTE_REGISTER=$(dd if=/sys/kernel/debug/ec/ec0/io bs=1 count=1 skip=67 conv=notrunc 2>/dev/null | hexdump -e '"%02x"') | |
if [[ ${#CHARGE_CONTROL_BYTE_REGISTER} -lt 1 || ${#CHARGE_CONTROL_BYTE_REGISTER} -gt 2 ]]; then | |
echo "Something went wrong when reading the register that holds the charge control status." | |
# echo "Content: $CHARGE_CONTROL_BYTE_REGISTER. Length: ${#CHARGE_CONTROL_BYTE_REGISTER}." | |
exit 1 | |
fi | |
# We need to zero the second Most Significant Bit | |
CCBR_VALUE=$(( 0x$CHARGE_CONTROL_BYTE_REGISTER & 2#10111111 )) | |
# Write the new value back to the register | |
CCBR_VALUE_HEX=$(printf "%02x" $CCBR_VALUE) | |
echo -n "0000 $CCBR_VALUE_HEX" \ | |
| xxd -r \ | |
| dd of=/sys/kernel/debug/ec/ec0/io bs=1 count=1 seek=67 conv=notrunc | |
# Write 0s to threshold registers | |
printf '\x00\x00' \ | |
| dd of=/sys/kernel/debug/ec/ec0/io bs=2 count=1 seek=114 conv=notrunc | |
} | |
battery_charge_control_enable() { | |
LOW_THRESH=$1 | |
HIGH_THRESH=$2 | |
if [[ $LOW_THRESH -lt 40 || | |
$LOW_THRESH -gt 95 || | |
$HIGH_THRESH -lt 40 || | |
$HIGH_THRESH -gt 95 || | |
$LOW_THRESH -gt $HIGH_THRESH ]]; then | |
cat <<EOF | |
Wrong thresholds. You should set: | |
40 <= low threshold <= 95 | |
40 <= high threshold <= 95 | |
low threshold <= high threshold | |
EOF | |
exit 1 | |
fi | |
# Set limits: | |
LOW_THRESH_HEX=$(printf "%02x" $LOW_THRESH) | |
HIGH_THRESH_HEX=$(printf "%02x" $HIGH_THRESH) | |
echo "0000 $LOW_THRESH_HEX $HIGH_THRESH_HEX" \ | |
| xxd -r \ | |
| dd of=/sys/kernel/debug/ec/ec0/io bs=2 count=1 seek=114 conv=notrunc | |
# Load byte-register for charge control: | |
CHARGE_CONTROL_BYTE_REGISTER=$(dd if=/sys/kernel/debug/ec/ec0/io bs=1 count=1 skip=67 conv=notrunc | hexdump -e '"%02x"') | |
if [[ ${#CHARGE_CONTROL_BYTE_REGISTER} -lt 1 || ${#CHARGE_CONTROL_BYTE_REGISTER} -gt 2 ]]; then | |
echo "Something went wrong when reading the register that holds the charge control status." | |
exit 1 | |
fi | |
# We need to raise the second Most Significant Bit | |
CCBR_VALUE=$(( 0x$CHARGE_CONTROL_BYTE_REGISTER | 2#01000000 )) | |
# Write the new value back to the register | |
CCBR_VALUE_HEX=$(printf "%02x" $CCBR_VALUE) | |
echo "0000 $CCBR_VALUE_HEX" \ | |
| xxd -r \ | |
| dd of=/sys/kernel/debug/ec/ec0/io bs=1 count=1 seek=67 conv=notrunc | |
} | |
fn_lock() { | |
BW_OP="" | |
case $1 in | |
keys) | |
BW_OP=" | 2#00000001" | |
;; | |
functions) | |
BW_OP=" & 2#11111110" | |
;; | |
*) | |
echo "Wrong toggle." | |
exit 1 | |
;; | |
esac | |
# Load 2 byte-registers for FN lock: | |
FN_LOCK_BYTE_REGISTER_1=$(dd if=/sys/kernel/debug/ec/ec0/io bs=1 count=1 skip=230 conv=notrunc | hexdump -e '"%02x"') | |
FN_LOCK_BYTE_REGISTER_2=$(dd if=/sys/kernel/debug/ec/ec0/io bs=1 count=1 skip=231 conv=notrunc | hexdump -e '"%02x"') | |
if [[ ${#FN_LOCK_BYTE_REGISTER_1} -lt 1 || ${#FN_LOCK_BYTE_REGISTER_1} -gt 2 ]]; then | |
echo "Something went wrong when reading the register #1 that holds the FN Lock status." | |
exit 1 | |
fi | |
if [[ ${#FN_LOCK_BYTE_REGISTER_2} -lt 1 || ${#FN_LOCK_BYTE_REGISTER_2} -gt 2 ]]; then | |
echo "Something went wrong when reading the register #2 that holds the FN Lock status." | |
exit 1 | |
fi | |
# New values: | |
REGISTER_1_HEX=$(printf "%02x" $(( 0x$FN_LOCK_BYTE_REGISTER_1 $BW_OP )) ) | |
REGISTER_2_HEX=$(printf "%02x" $(( 0x$FN_LOCK_BYTE_REGISTER_2 $BW_OP )) ) | |
echo "0000 $REGISTER_1_HEX $REGISTER_2_HEX" \ | |
| xxd -r \ | |
| dd of=/sys/kernel/debug/ec/ec0/io bs=2 count=1 seek=115 conv=notrunc | |
} | |
case $1 in | |
cc-disable) | |
battery_charge_control_disable | |
;; | |
cc-home) | |
battery_charge_control_enable 40 70 | |
;; | |
cc-work) | |
battery_charge_control_enable 70 90 | |
;; | |
cc-travel) | |
battery_charge_control_enable 95 95 | |
;; | |
fn-keys) | |
fn_lock keys | |
;; | |
fn-functions) | |
fn_lock functions | |
;; | |
ec) | |
load_ec_write | |
;; | |
*) | |
help | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How do you reverse-engineer the sys_ec data?