]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
hid: jarvis: protect against corner case segfaults
authorXia Yang <xiay@nvidia.com>
Wed, 28 Jan 2015 02:06:19 +0000 (18:06 -0800)
committerXia Yang <xiay@nvidia.com>
Thu, 19 Mar 2015 22:47:03 +0000 (15:47 -0700)
Use mutex to protect slow hid operations against corner cases.

Bug 1599000

Change-Id: I3f21c2d0d4db08c2d3a3a0a1883f407351e0e82d
Signed-off-by: Xia Yang <xiay@nvidia.com>
Reviewed-on: http://git-master/r/678104
(cherry picked from commit 09f14d3640af448b778aea1705c7c80ad6a1c274)
Reviewed-on: http://git-master/r/716502
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
drivers/hid/hid-atv-jarvis.c

index b3347e872f13e787521b24f0c039b3c794f06768..a3f1b6f99fbfc68dbe9fa023ed920dd6023f5016 100644 (file)
@@ -343,6 +343,7 @@ struct snd_atvr {
 
        /* pointer to hid device */
        struct hid_device *hdev;
+       struct mutex hdev_lock;
 };
 
 static int atvr_mic_ctrl(struct hid_device *hdev, bool enable)
@@ -1051,12 +1052,15 @@ static int snd_atvr_pcm_open(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        int ret;
 
+       mutex_lock(&atvr_snd->hdev_lock);
        if (atvr_snd->hdev == NULL) {
                pr_warn("%s: remote is not ready\n", __func__);
+               mutex_unlock(&atvr_snd->hdev_lock);
                return -EAGAIN;
        }
 
        ret = atvr_mic_ctrl(atvr_snd->hdev, true);
+       mutex_unlock(&atvr_snd->hdev_lock);
 
        if (ret)
                return ret;
@@ -1135,10 +1139,12 @@ static int snd_atvr_pcm_close(struct snd_pcm_substream *substream)
        }
        spin_unlock(&s_substream_lock);
 
+       mutex_lock(&atvr_snd->hdev_lock);
        if (atvr_snd->hdev)
                atvr_mic_ctrl(atvr_snd->hdev, false);
        else
                pr_warn("%s: unexpected remote connection lost\n", __func__);
+       mutex_unlock(&atvr_snd->hdev_lock);
 
        return 0;
 }
@@ -1251,6 +1257,7 @@ static int atvr_snd_initialize(struct hid_device *hdev)
        }
        atvr_snd = atvr_card->private_data;
        atvr_snd->card = atvr_card;
+       mutex_init(&atvr_snd->hdev_lock);
 
        /* dummy initialization */
        setup_timer(&atvr_snd->decoding_timer,
@@ -1470,9 +1477,16 @@ err_parse:
 
 static void atvr_remove(struct hid_device *hdev)
 {
-       struct snd_atvr *atvr_snd = hid_get_drvdata(hdev);
+       struct snd_atvr *atvr_snd;
+       unsigned long flags;
+
+       if (atvr_card == NULL)
+               return -EIO;
 
+       atvr_snd = atvr_card->private_data;
+       mutex_lock(&atvr_snd->hdev_lock);
        atvr_snd->hdev = NULL;
+       mutex_unlock(&atvr_snd->hdev_lock);
 
        switch_set_state(&shdr_mic_switch, false);
        hid_set_drvdata(hdev, NULL);
@@ -1556,6 +1570,13 @@ static void atvr_exit(void)
        misc_deregister(&pcm_dev_node);
 #endif
 
+       if (atvr_card) {
+               struct snd_atvr *atvr_snd = atvr_card->private_data;
+               mutex_destroy(&atvr_snd->hdev_lock);
+               snd_card_free(atvr_card);
+               atvr_card = NULL;
+       }
+
        hid_unregister_driver(&atvr_driver);
 }