8960_BT: Added sleep support on Host side.

Signed-off-by: Bhasker Neti <bneti@codeaurora.org>

Conflicts:

	drivers/bluetooth/hci_smd.c
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index 7132c7c..6555e21 100644
--- a/drivers/bluetooth/hci_smd.c
+++ b/drivers/bluetooth/hci_smd.c
@@ -28,18 +28,74 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci.h>
 #include <mach/msm_smd.h>
+#include <linux/wakelock.h>
 
-#define EVENT_CHANNEL "APPS_RIVA_BT_CMD"
-#define DATA_CHANNEL "APPS_RIVA_BT_ACL"
+#define EVENT_CHANNEL		"APPS_RIVA_BT_CMD"
+#define DATA_CHANNEL		"APPS_RIVA_BT_ACL"
+#define RX_Q_MONITOR		(1)	/* 1 milli second */
 
 struct hci_smd_data {
 	struct hci_dev *hdev;
 
 	struct smd_channel *event_channel;
 	struct smd_channel *data_channel;
+	struct wake_lock wake_lock_tx;
+	struct wake_lock wake_lock_rx;
+	struct timer_list rx_q_timer;
 };
 struct hci_smd_data hs;
 
+/* Rx queue monitor timer function */
+static int is_rx_q_empty(unsigned long arg)
+{
+	struct hci_dev *hdev = (struct hci_dev *) arg;
+	struct sk_buff_head *list_ = &hdev->rx_q;
+	struct sk_buff *list = ((struct sk_buff *)list_)->next;
+	BT_DBG("%s Rx timer triggered", hdev->name);
+
+	if (list == (struct sk_buff *)list_) {
+		BT_DBG("%s RX queue empty", hdev->name);
+		return 1;
+	} else{
+		BT_DBG("%s RX queue not empty", hdev->name);
+		return 0;
+	}
+}
+
+static void release_lock(void)
+{
+	struct hci_smd_data *hsmd = &hs;
+	BT_DBG("Releasing Rx Lock");
+	if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
+		wake_lock_active(&hs.wake_lock_rx))
+			wake_unlock(&hs.wake_lock_rx);
+}
+
+/* Rx timer callback function */
+static void schedule_timer(unsigned long arg)
+{
+	struct hci_dev *hdev = (struct hci_dev *) arg;
+	struct hci_smd_data *hsmd = &hs;
+	BT_DBG("%s Schedule Rx timer", hdev->name);
+
+	if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
+		BT_DBG("%s RX queue empty", hdev->name);
+		/*
+		 * Since the queue is empty, its ideal
+		 * to release the wake lock on Rx
+		 */
+		wake_unlock(&hs.wake_lock_rx);
+	} else{
+		BT_DBG("%s RX queue not empty", hdev->name);
+		/*
+		 * Restart the timer to monitor whether the Rx queue is
+		 * empty for releasing the Rx wake lock
+		 */
+		mod_timer(&hsmd->rx_q_timer,
+			jiffies + msecs_to_jiffies(RX_Q_MONITOR));
+	}
+}
+
 static int hci_smd_open(struct hci_dev *hdev)
 {
 	set_bit(HCI_RUNNING, &hdev->flags);
@@ -63,32 +119,36 @@
 
 static void hci_smd_recv_data(unsigned long arg)
 {
-	int len;
-	int rc;
-	struct sk_buff *skb;
-	unsigned  char *buf;
+	int len = 0;
+	int rc = 0;
+	struct sk_buff *skb = NULL;
+	unsigned  char *buf = NULL;
 	struct hci_smd_data *hsmd = &hs;
+	wake_lock(&hs.wake_lock_rx);
 
 	len = smd_read_avail(hsmd->data_channel);
-
+	if (len <= 0) {
+		BT_ERR("Nothing to read from SMD channel\n");
+		goto out_data;
+	}
 	while (len > 0) {
 		skb = bt_skb_alloc(len, GFP_KERNEL);
 		if (!skb) {
 			BT_ERR("Error in allocating  socket buffer\n");
-			return;
+			goto out_data;
 		}
 
 		buf = kmalloc(len, GFP_KERNEL);
 		if (!buf)  {
 			BT_ERR("Error in allocating  buffer\n");
-			kfree_skb(skb);
-			return;
+			rc = -ENOMEM;
+			goto out_data;
 		}
 
 		rc = smd_read_from_cb(hsmd->data_channel, (void *)buf, len);
 		if (rc < len) {
 			BT_ERR("Error in reading from the channel");
-			return;
+			goto out_data;
 		}
 
 		memcpy(skb_put(skb, len), buf, len);
@@ -100,40 +160,64 @@
 		rc = hci_recv_frame(skb);
 		if (rc < 0) {
 			BT_ERR("Error in passing the packet to HCI Layer");
-			return;
+			goto out_data;
 		}
 
 		kfree(buf);
+		buf = NULL;
 		len = smd_read_avail(hsmd->data_channel);
+		/*
+		 * Start the timer to monitor whether the Rx queue is
+		 * empty for releasing the Rx wake lock
+		 */
+		BT_DBG("Rx Timer is starting\n");
+		mod_timer(&hsmd->rx_q_timer,
+				jiffies + msecs_to_jiffies(RX_Q_MONITOR));
+	}
+out_data:
+	release_lock();
+	if (rc) {
+		if (skb)
+			kfree_skb(skb);
+		kfree(buf);
 	}
 }
 
 static void hci_smd_recv_event(unsigned long arg)
 {
-	int len;
-	int rc;
-	struct sk_buff *skb;
-	unsigned  char *buf;
+	int len = 0;
+	int rc = 0;
+	struct sk_buff *skb = NULL;
+	unsigned  char *buf = NULL;
 	struct hci_smd_data *hsmd = &hs;
+	wake_lock(&hs.wake_lock_rx);
 
 	len = smd_read_avail(hsmd->event_channel);
 	if (len > HCI_MAX_FRAME_SIZE) {
 		BT_ERR("Frame larger than the allowed size");
-		return;
+		goto out_event;
+	} else if (len <= 0) {
+		BT_ERR("Nothing to read from SMD channel\n");
+		goto out_event;
 	}
 
 	while (len > 0) {
 		skb = bt_skb_alloc(len, GFP_KERNEL);
-		if (!skb)
-			return;
-
+		if (!skb) {
+			BT_ERR("Error in allocating  socket buffer\n");
+			goto out_event;
+		}
 		buf = kmalloc(len, GFP_KERNEL);
 		if (!buf) {
-			kfree_skb(skb);
-			return;
+			BT_ERR("Error in allocating  buffer\n");
+			rc = -ENOMEM;
+			goto out_event;
 		}
-
 		rc = smd_read_from_cb(hsmd->event_channel, (void *)buf, len);
+		if (rc < len) {
+			BT_ERR("Error in reading from the event channel");
+			goto out_event;
+		}
 
 		memcpy(skb_put(skb, len), buf, len);
 		skb->dev = (void *)hsmd->hdev;
@@ -144,40 +228,70 @@
 		rc = hci_recv_frame(skb);
 		if (rc < 0) {
 			BT_ERR("Error in passing the packet to HCI Layer");
-			return;
+			goto out_event;
 		}
 
 		kfree(buf);
+		buf = NULL;
 		len = smd_read_avail(hsmd->event_channel);
+		/*
+		 * Start the timer to monitor whether the Rx queue is
+		 * empty for releasing the Rx wake lock
+		 */
+		BT_DBG("Rx Timer is starting\n");
+		mod_timer(&hsmd->rx_q_timer,
+				jiffies + msecs_to_jiffies(RX_Q_MONITOR));
+	}
+out_event:
+	release_lock();
+	if (rc) {
+		if (skb)
+			kfree_skb(skb);
+		kfree(buf);
 	}
 }
 
 static int hci_smd_send_frame(struct sk_buff *skb)
 {
 	int len;
+	int avail;
+	int ret = 0;
+	wake_lock(&hs.wake_lock_tx);
 
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
+		avail = smd_write_avail(hs.event_channel);
+		if (!avail) {
+			BT_ERR("No space available for smd frame");
+			ret =  -ENOSPC;
+		}
 		len = smd_write(hs.event_channel, skb->data, skb->len);
 		if (len < skb->len) {
 			BT_ERR("Failed to write Command %d", len);
-			return -ENODEV;
+			ret = -ENODEV;
 		}
 		break;
 	case HCI_ACLDATA_PKT:
 	case HCI_SCODATA_PKT:
+		avail = smd_write_avail(hs.event_channel);
+		if (!avail) {
+			BT_ERR("No space available for smd frame");
+			ret = -ENOSPC;
+		}
 		len = smd_write(hs.data_channel, skb->data, skb->len);
 		if (len < skb->len) {
 			BT_ERR("Failed to write Data %d", len);
-			return -ENODEV;
+			ret = -ENODEV;
 		}
 		break;
 	default:
 		BT_ERR("Uknown packet type\n");
-		return -ENODEV;
+		ret = -ENODEV;
 		break;
 	}
-	return 0;
+
+	wake_unlock(&hs.wake_lock_tx);
+	return ret;
 }
 
 
@@ -250,6 +364,15 @@
 	hdev->destruct = hci_smd_destruct;
 	hdev->owner = THIS_MODULE;
 
+	wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND, "msm_smd_Rx");
+	wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND, "msm_smd_Tx");
+	/*
+	 * Setup the timer to monitor whether the Rx queue is empty,
+	 * to control the wake lock release
+	 */
+	setup_timer(&hsmd->rx_q_timer, schedule_timer,
+			(unsigned long) hsmd->hdev);
+
 	/* Open the SMD Channel and device and register the callback function */
 	rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
 			&hsmd->event_channel, hdev, hci_smd_notify_event);
@@ -286,6 +409,11 @@
 	hs.event_channel = 0;
 	smd_close(hs.data_channel);
 	hs.data_channel = 0;
+	wake_lock_destroy(&hs.wake_lock_rx);
+	wake_lock_destroy(&hs.wake_lock_tx);
+
+	/*Destroy the timer used to monitor the Rx queue for emptiness */
+	del_timer_sync(&hs.rx_q_timer);
 }
 
 static int hci_smd_init(void)