From 8dd91340660a14c55d12372a3e9a767863b7f316 Mon Sep 17 00:00:00 2001
From: Keng-Yu Lin <keng-yu....@canonical.com>
Date: Thu, 24 Feb 2011 13:59:14 +0800
Subject: [PATCH] Add the quirk support for stoping/restarting bluetooth service

It is found that the bluetooth modules with USB VID/PIDs [0a5c:219c]
[0a5c:21bc] and [413c:8187] are causing random S4 hangs on various
laptops with SandyBridge chipset.

The hangs can be observed by repeating hibernate/resume in a 250
iterations. The successful cycles number before the hang is
usually ranged in tens, though it varies on different types of
laptops.

This patch added a parameter for the use as

	"pm-hibernate --quirk-bluetooth-service-off"

and a couple of USB ID quirks I found with this S4 problem.

Signed-off-by: Keng-Yu Lin <keng-yu....@canonical.com>
---
 pm/sleep.d/44bluetooth-known-quirk |   34 +++++++++++++++++++++++++++++
 pm/sleep.d/45bluetooth-service     |   41 ++++++++++++++++++++++++++++++++++++
 pm/sleep.d/Makefile.am             |    2 +
 3 files changed, 77 insertions(+), 0 deletions(-)
 create mode 100755 pm/sleep.d/44bluetooth-known-quirk
 create mode 100755 pm/sleep.d/45bluetooth-service

diff --git a/pm/sleep.d/44bluetooth-known-quirk b/pm/sleep.d/44bluetooth-known-quirk
new file mode 100755
index 0000000..7241ec8
--- /dev/null
+++ b/pm/sleep.d/44bluetooth-known-quirk
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+. "${PM_FUNCTIONS}"
+
+quirks="0a5c:219c 0a5c:21bc 413c:8187"
+
+btusbget() {
+    local dev usb
+    usb="/sys/bus/usb/devices"
+    for dev in "$usb"/*; do
+	[[ -f "${dev}/bDeviceClass" ]] || continue
+	[[ "$(cat "${dev}/bDeviceClass")" = "e0" ]] || continue # Wireless
+	[[ -f "${dev}/bDeviceProtocol" ]] || continue
+	[[ "$(cat "${dev}/bDeviceProtocol")" = "01" ]] || continue # Bluetooth
+	case $1 in
+	    vendor) echo "$(cat "${dev}/idVendor")" ;;
+	    device) echo "$(cat "${dev}/idProduct")" ;;
+	esac
+	break
+    done
+}
+
+case "$1" in
+	hibernate|suspend)
+		# known bluetooth devices needing to stop bluetoothd
+		for usbid in $quirks; do
+			if [ "$(btusbget vendor):$(btusbget device)" == "$usbid" ] ; then
+				add_parameters --quirk-bluetooth-service-off
+			fi
+		done
+		;;
+	thaw|resume)
+		;;
+esac
diff --git a/pm/sleep.d/45bluetooth-service b/pm/sleep.d/45bluetooth-service
new file mode 100755
index 0000000..969ca86
--- /dev/null
+++ b/pm/sleep.d/45bluetooth-service
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+. "${PM_FUNCTIONS}"
+
+for opt in $PM_CMDLINE; do
+	case "${opt##--quirk-}" in # just quirks, please
+		bluetooth-service-off) 	   QUIRK_BLUETOOTH_SERVICE_OFF="true" ;;
+		bluetooth-none) 	   QUIRK_BLUETOOTH_NONE="true" ;;
+		*) continue ;;
+	esac
+done
+
+quirk() { is_set "$1" && [ -z $QUIRK_BLUETOOTH_NONE ]; }
+
+suspend_bluetooth_service()
+{
+	quirk "${QUIRK_BLUETOOTH_SERVICE_OFF}" &&	stopservice bluetooth
+}
+
+resume_bluetooth_service()
+{
+	quirk "${QUIRK_BLUETOOTH_SERVICE_OFF}" &&	restartservice bluetooth
+}
+
+help() {
+	echo  # first echo makes it look nicer.
+	echo "Bluetooth quirk handler options:"
+	echo
+	echo "  --quirk-bluetooth-service-off"
+	echo "  --quirk-bluetooth-none"
+}
+
+case "$1" in
+	hibernate|suspend)
+		suspend_bluetooth_service
+		;;
+	thaw|resume)
+		resume_bluetooth_service
+		;;
+	help) help ;;
+esac
diff --git a/pm/sleep.d/Makefile.am b/pm/sleep.d/Makefile.am
index 2350825..88df79c 100644
--- a/pm/sleep.d/Makefile.am
+++ b/pm/sleep.d/Makefile.am
@@ -4,6 +4,8 @@ sleep_SCRIPTS =			\
 	00logging		\
 	00powersave		\
 	01grub			\
+	44bluetooth-known-quirk	\
+	45bluetooth-service	\
 	49bluetooth		\
 	55NetworkManager	\
 	75modules		\
-- 
1.7.1

Reply via email to