#!/bin/bash -eu # usb-charger.sh: Enable USB charging for devices on Linux. function usage { # show usage echo "usb-charger.sh: Enable USB charging for devices on Linux." echo "Usage: $0 [bus port [on|auto]]" echo echo "If no arguments are given, the script will detect your device and ask you to confirm." echo "If you specify bus and port, the script will set the control to 'on' for that port." echo "If you specify 'on' or 'auto' as the third argument, the script will set the control to that value." } function set_usb_power { # set control to on or auto for the given bus and port local bus=$1 local port=$2 local control=${3:-on} echo "Setting control to '$control' for port $bus-$port." echo "$control" | sudo tee "/sys/bus/usb/devices/$bus-$port/power/control" } function list_usb_power { # list the current control setting for all ports cd /sys/bus/usb/devices || exit for dir in [0-9]*-[0-9]*; do if [[ $dir == *:* ]]; then continue fi if [ -d "$dir" ]; then echo -n "Port $dir: " cat "$dir/power/control" fi done } function usbinfo { # list the current USB topology lsusb -t | perl -ne ' $bus = 0+$1 if m{^/: Bus (\d+)\.}; if (/Port (\d+)/) { print "bus=$bus port=$1\n"; } ' } function detect_usb_port { # detect the port your device is plugged into local tmpfile1=$(mktemp) local tmpfile2=$(mktemp) read -p "Please ensure your device is unplugged and press Enter." usbinfo > $tmpfile1 read -p "Please plug in your device and press Enter." usbinfo > $tmpfile2 local controller_and_port=$(diff $tmpfile1 $tmpfile2 | sed -n '/^> / { s/^> //; p; q; }') if [ -z "$controller_and_port" ]; then echo "Could not detect your device. Please run the script again." exit 1 fi echo "$controller_and_port" } function confirm_change { # confirm the change with the user, and do it local bus=$1 local port=$2 read -p "Detected your device on port $bus-$port. Set control to 'on' for this port? (y/n) " answer if [ "$answer" != "${answer#[Yy]}" ]; then echo on | sudo tee "$bus-$port/power/control" echo "Done. Your device should continue charging now." else echo "Okay, no changes made." fi } function usb_charger { # main function if [ "${1:-}" = "-h" -o "${1:-}" = "--help" ]; then usage exit 0 fi local bus=${1:-} local port=${2:-} local control=${3:-auto} # if $# > 3 or bus or port not numeric, or if provided, not both provided, or control if provided not "on" or "auto", error out if [[ "$#" -gt 3 || -n "${bus//[0-9]/}" || -n "${port//[0-9]/}" || ( -n "$bus" && -z "$port" ) || ( -z "$bus" && -n "$port" ) || ( -n "$control" && "$control" != "on" && "$control" != "auto" ) ]]; then usage >&2 exit 1 fi if [ -n "$bus" -a -n "$port" ]; then set_usb_power $bus $port $control else list_usb_power controller_and_port=$(detect_usb_port) eval $controller_and_port confirm_change $bus $port fi } # if script is being run directly, run the main function # otherwise, this could be sourced and used as a library if [ "$0" = "$BASH_SOURCE" ]; then usb_charger "$@" fi