Fixing the hard lockup caused by bluetooth in linux during sleep
Table of Contents
I basically stopped using the bluetooth subsystem on my machine for a while, since it would lockup my system during sleep. Today I decided to investigate a little, here’s what I found out:
- Stopping the bluetooth daemon will bring down the bluetooth
subsystem. You can check it’s state as follows:
anything besides 0 means it’s doing something.cat /sys/module/btusb/refcnt
- The freeze occurs when bluetooth is paired with a device and someone trys to bring down bluetooth. Subsequently playing music through A2DP and then stopping the bluetooth daemon results in a hard freeze.
- To fix all these issues you need to disconnect all connected bluetooth devices before going to sleep.
Copy & paste the following script (or simply download ) in your /etc/pm/sleep.d folder to fix the freeze. Feel free to adapt it to your distribution.
#!/bin/sh
# generic bluetooth hack based on the IBM specific hack
# Reza Jelveh
. "${PM_FUNCTIONS}"
[ -f /sys/module/btusb/refcnt ] || exit $NA
disconnect_devices()
{
# sorry not that good with bash scripting,
# so i'll use a space as string terminator
var="`hcitool con` "
while test -n "$var";do
res="${var%% *}"
var="${var#* }"
if [[ $res =~ ([[:alnum:]:]{17}) ]]; then sudo hcitool dc ${BASH_REMATCH[0]}; fi
done
}
suspend_bluetooth()
{
if grep -q 0 /sys/module/btusb/refcnt; then
savestate bluetooth_generic disable
else
savestate bluetooth_generic enable
# if we run stop while some bluetooth device is running
# the system will freeze, disconnect all devices first
disconnect_devices
/usr/sbin/rc.d stop bluetooth
# wait for up to 2 seconds for the module to actually get
# unused
TIMEOUT=20
while [ $TIMEOUT -ge 0 ]; do
[ `cat /sys/module/btusb/refcnt` = 0 ] && break
TIMEOUT=$((TIMEOUT-1))
sleep 0.1
done
/sbin/modprobe -r btusb
fi
}
resume_bluetooth()
{
state_exists bluetooth_generic || return
if [[ `restorestate bluetooth_generic` == "enable" ]]; then
/sbin/modprobe btusb
/usr/sbin/rc.d start bluetooth
fi
}
case "$1" in
hibernate|suspend)
suspend_bluetooth
;;
thaw|resume)
resume_bluetooth
;;
*) exit $NA
;;
esac