misc: bluedroid_pm: Add uevent for resume
Jinyoung Park [Thu, 12 Feb 2015 10:32:20 +0000 (19:32 +0900)]
Added uevent to notify userspace that the bluedroid_pm driver is resumed.

Bug 200065134

Change-Id: Ie42d01140242ea48a6358b3f18ea1748659f2605
Signed-off-by: Jinyoung Park <jinyoungp@nvidia.com>
Reviewed-on: http://git-master/r/707746
Reviewed-by: Nagarjuna Kristam <nkristam@nvidia.com>
Reviewed-by: Joshua Cha <joshuac@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>

drivers/misc/bluedroid_pm.c

index 5d984a7..9d5d307 100644 (file)
@@ -64,6 +64,7 @@
 #define BT_WAKE        0x01
 
 struct bluedroid_pm_data {
+       struct platform_device *pdev;
        int gpio_reset;
        int gpio_shutdown;
        int host_wake;
@@ -77,6 +78,9 @@ struct bluedroid_pm_data {
        struct rfkill *rfkill;
        struct wake_lock wake_lock;
        struct pm_qos_request resume_cpu_freq_req;
+       bool resumed;
+       struct work_struct work;
+       spinlock_t lock;
 };
 
 struct proc_dir_entry *proc_bt_dir, *bluetooth_sleep_dir;
@@ -105,6 +109,31 @@ static DEFINE_TIMER(bluedroid_pm_timer, bluedroid_pm_timer_expire, 0, 0);
 static int bluedroid_pm_gpio_get_value(unsigned int gpio);
 static void bluedroid_pm_gpio_set_value(unsigned int gpio, int value);
 
+static void bluedroid_work(struct work_struct *data)
+{
+       struct bluedroid_pm_data *bluedroid_pm =
+                       container_of(data, struct bluedroid_pm_data, work);
+       struct device *dev = &bluedroid_pm->pdev->dev;
+       char *resumed[2] = { "BT_STATE=RESUMED", NULL };
+       char **uevent_envp = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bluedroid_pm->lock, flags);
+       if (!bluedroid_pm->is_blocked && bluedroid_pm->resumed)
+               uevent_envp = resumed;
+       spin_unlock_irqrestore(&bluedroid_pm->lock, flags);
+
+       if (uevent_envp) {
+               kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, uevent_envp);
+               BDP_DBG("is_blocked=%d, resumed=%d, uevent %s\n",
+                       bluedroid_pm->is_blocked, bluedroid_pm->resumed,
+                       uevent_envp[0]);
+       } else {
+               BDP_DBG("is_blocked=%d, resumed=%d, no uevent\n",
+                       bluedroid_pm->is_blocked, bluedroid_pm->resumed);
+       }
+}
+
 static irqreturn_t bluedroid_pm_hostwake_isr(int irq, void *dev_id)
 {
        /* schedule a tasklet to handle the change in the host wake line */
@@ -389,6 +418,10 @@ static int bluedroid_pm_probe(struct platform_device *pdev)
                bluedroid_pm->resume_min_frequency =
                                                pdata->resume_min_frequency;
 
+       INIT_WORK(&bluedroid_pm->work, bluedroid_work);
+       spin_lock_init(&bluedroid_pm->lock);
+
+       bluedroid_pm->pdev = pdev;
        platform_set_drvdata(pdev, bluedroid_pm);
        BDP_DBG("driver successfully registered");
        return 0;
@@ -419,6 +452,8 @@ static int bluedroid_pm_remove(struct platform_device *pdev)
 {
        struct bluedroid_pm_data *bluedroid_pm = platform_get_drvdata(pdev);
 
+       cancel_work_sync(&bluedroid_pm->work);
+
        if (bluedroid_pm->host_wake)
                gpio_free(bluedroid_pm->host_wake);
        if (bluedroid_pm->host_wake_irq)
@@ -452,20 +487,34 @@ static int bluedroid_pm_suspend(struct platform_device *pdev,
                                                pm_message_t state)
 {
        struct bluedroid_pm_data *bluedroid_pm = platform_get_drvdata(pdev);
+       unsigned long flags;
+
        if (bluedroid_pm->host_wake)
                if (!bluedroid_pm->is_blocked || !bluedroid_pm_blocked)
                        enable_irq_wake(bluedroid_pm->host_wake_irq);
 
+       spin_lock_irqsave(&bluedroid_pm->lock, flags);
+       bluedroid_pm->resumed = false;
+       cancel_work_sync(&bluedroid_pm->work);
+       spin_unlock_irqrestore(&bluedroid_pm->lock, flags);
+
        return 0;
 }
 
 static int bluedroid_pm_resume(struct platform_device *pdev)
 {
        struct bluedroid_pm_data *bluedroid_pm = platform_get_drvdata(pdev);
+       unsigned long flags;
+
        if (bluedroid_pm->host_wake)
                if (!bluedroid_pm->is_blocked || !bluedroid_pm_blocked)
                        disable_irq_wake(bluedroid_pm->host_wake_irq);
 
+       spin_lock_irqsave(&bluedroid_pm->lock, flags);
+       bluedroid_pm->resumed = true;
+       schedule_work(&bluedroid_pm->work);
+       spin_unlock_irqrestore(&bluedroid_pm->lock, flags);
+
        return 0;
 }
 
@@ -473,6 +522,8 @@ static void bluedroid_pm_shutdown(struct platform_device *pdev)
 {
        struct bluedroid_pm_data *bluedroid_pm = platform_get_drvdata(pdev);
 
+       cancel_work_sync(&bluedroid_pm->work);
+
        if (gpio_is_valid(bluedroid_pm->gpio_shutdown))
                bluedroid_pm_gpio_set_value(
                        bluedroid_pm->gpio_shutdown, 0);