#!/bin/sh
### BEGIN INIT INFO
# Provides:          bluealsa
# Required-Start:    $remote_fs $syslog dbus bluetooth
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Bluetooth Audio ALSA Backend (BlueALSA)
### END INIT INFO

DAEMON=/usr/bin/bluealsa
NAME=bluealsa
DESC="Bluetooth Audio ALSA Backend"

UART_DEV="/dev/ttyS1"
UART_SPEED_INIT="115200"
UART_SPEED_WORK="1500000"

BT_GPIO_SHUTDOWN="493"
BT_GPIO_WAKE="495"

_find_uart_hci() {
    for h in /sys/class/bluetooth/hci*; do
        [ -e "$h" ] || continue
        if readlink -f "$h" 2>/dev/null | grep -q "/ttyS1/"; then
            basename "$h"
            return 0
        fi
    done
    return 1
}

_hci_exists() {
    [ -d /sys/class/bluetooth/hci0 ] && return 0
    HCI=$(_find_uart_hci 2>/dev/null)
    [ -n "$HCI" ] && [ -d "/sys/class/bluetooth/${HCI}" ]
}

_unblock_bt_rfkill() {
    for t in /sys/class/rfkill/rfkill*/type; do
        [ -e "$t" ] || continue
        if [ "$(cat "$t" 2>/dev/null)" = "bluetooth" ]; then
            soft="${t%/type}/soft"
            [ -w "$soft" ] && echo 0 > "$soft" 2>/dev/null || true
        fi
    done
}

_ensure_fw_path() {
    if [ ! -e /etc/firmware ]; then
        ln -s /lib/firmware /etc/firmware 2>/dev/null || true
    fi
}

_unbind_kernel_bcm() {
    if [ -w /sys/bus/platform/drivers/hci_bcm/unbind ]; then
        echo bluetooth > /sys/bus/platform/drivers/hci_bcm/unbind 2>/dev/null || true
        sleep 1
    fi
}

_export_gpio_out() {
    num="$1"
    [ -d "/sys/class/gpio/gpio${num}" ] || echo "$num" > /sys/class/gpio/export 2>/dev/null || true
    [ -d "/sys/class/gpio/gpio${num}" ] || return 1
    echo out > "/sys/class/gpio/gpio${num}/direction" 2>/dev/null || true
    return 0
}

_pulse_internal_bt() {
    _unbind_kernel_bcm

    _export_gpio_out "$BT_GPIO_SHUTDOWN" || return 1
    _export_gpio_out "$BT_GPIO_WAKE" || return 1

    echo 1 > "/sys/class/gpio/gpio${BT_GPIO_WAKE}/value" 2>/dev/null || true
    echo 0 > "/sys/class/gpio/gpio${BT_GPIO_SHUTDOWN}/value" 2>/dev/null || true
    sleep 0.2
    echo 1 > "/sys/class/gpio/gpio${BT_GPIO_SHUTDOWN}/value" 2>/dev/null || true
    sleep 0.2

    return 0
}

_wait_for_hci() {
    i=0
    while [ $i -lt 8 ]; do
        HCI=$(_find_uart_hci 2>/dev/null)
        if [ -n "$HCI" ] && [ -d "/sys/class/bluetooth/${HCI}" ]; then
            echo "$HCI"
            return 0
        fi
        if [ -d /sys/class/bluetooth/hci0 ]; then
            echo "hci0"
            return 0
        fi
        sleep 1
        i=$((i+1))
    done
    return 1
}

_attach_internal_bt() {
    if _hci_exists; then
        HCI=$(_find_uart_hci 2>/dev/null)
        [ -z "$HCI" ] && HCI="hci0"
        hciconfig "$HCI" up 2>/dev/null || hciconfig hci0 up 2>/dev/null || true
        echo "$HCI"
        return 0
    fi

    command -v hciattach >/dev/null 2>&1 || return 1
    [ -c "$UART_DEV" ] || return 1

    _pulse_internal_bt || return 1

    if ! pidof hciattach >/dev/null 2>&1; then
        hciattach -n -s "$UART_SPEED_INIT" "$UART_DEV" bcm43xx "$UART_SPEED_WORK" flow >/dev/null 2>&1 &
    fi

    HCI=$(_wait_for_hci) || return 1
    hciconfig "$HCI" up 2>/dev/null || true
    echo "$HCI"
    return 0
}

_start_bluetoothd() {
    if pidof bluetoothd >/dev/null 2>&1; then
        return 0
    fi
    if [ -x /etc/init.d/bluetooth ]; then
        /etc/init.d/bluetooth start >/dev/null 2>&1 || true
    else
        /usr/sbin/bluetoothd -E >/dev/null 2>&1 || /usr/bin/bluetoothd -E >/dev/null 2>&1 || true
    fi
    sleep 2
    pidof bluetoothd >/dev/null 2>&1
}

test -x $DAEMON || exit 0

case "$1" in
    start)
        echo -n "* starting $DESC: $NAME... "

        _unblock_bt_rfkill
        _ensure_fw_path

        HCI_DEV=$(_attach_internal_bt)
        if [ -z "$HCI_DEV" ] || [ ! -d "/sys/class/bluetooth/${HCI_DEV}" ]; then
            echo "failed (no bluetooth controller)"
            exit 1
        fi

        _start_bluetoothd || {
            echo "failed (bluetoothd not running)"
            exit 1
        }

        if pidof bluealsa >/dev/null 2>&1; then
            echo "already running."
            exit 0
        fi

        if [ -e /var/run/bluealsa/hci0 ] || [ -d /var/run/bluealsa ]; then
            rm -rf /var/run/bluealsa 2>/dev/null || true
        fi
        mkdir -p /var/run/bluealsa 2>/dev/null || true

        ARGS="-i ${HCI_DEV} --a2dp-keep-alive=5 -p a2dp-source"
        start-stop-daemon -S -b -x $DAEMON -- $ARGS
        sleep 1
        if pidof bluealsa >/dev/null 2>&1; then
            echo "done."
            exit 0
        fi

        echo "failed (bluealsa did not stay up)"
        exit 1
        ;;
    stop)
        echo -n "* stopping $DESC: $NAME... "
        start-stop-daemon -K -x $DAEMON >/dev/null 2>&1 || true
        echo "done."
        ;;
    restart)
        echo "* restarting $DESC: $NAME... "
        $0 stop || true
        $0 start
        ;;
    status)
        echo "bluealsa: $(pidof bluealsa >/dev/null 2>&1 && echo RUNNING || echo STOPPED)"
        echo "bluetoothd: $(pidof bluetoothd >/dev/null 2>&1 && echo RUNNING || echo STOPPED)"
        echo "hciattach: $(pidof hciattach >/dev/null 2>&1 && echo RUNNING || echo STOPPED)"
        if [ -d /sys/class/bluetooth/hci0 ]; then
            hciconfig hci0 2>/dev/null || true
        else
            echo "hci0: missing"
        fi
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac

exit 0
