]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
HID: hyperv: Add the support of hibernation
authorDexuan Cui <decui@microsoft.com>
Wed, 20 Nov 2019 07:14:56 +0000 (23:14 -0800)
committerSasha Levin <sashal@kernel.org>
Fri, 22 Nov 2019 01:10:45 +0000 (20:10 -0500)
During the suspend process and resume process, if there is any mouse
event, there is a small chance the suspend and the resume process can be
aborted because of mousevsc_on_receive() -> pm_wakeup_hard_event().

This behavior can be avoided by disabling the Hyper-V mouse device as
a wakeup source:

echo disabled > /sys/bus/vmbus/drivers/hid_hyperv/XXX/power/wakeup
(XXX is the device's GUID).

Signed-off-by: Dexuan Cui <decui@microsoft.com>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/hid/hid-hyperv.c

index 79a28fc9152162c695a05eb55fe989c48f74612d..dddfca555df958306fd89dfcd41a14e03648e090 100644 (file)
@@ -192,6 +192,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
        if (desc->bLength == 0)
                goto cleanup;
 
+       /* The pointer is not NULL when we resume from hibernation */
+       if (input_device->hid_desc != NULL)
+               kfree(input_device->hid_desc);
        input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
 
        if (!input_device->hid_desc)
@@ -203,6 +206,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
                goto cleanup;
        }
 
+       /* The pointer is not NULL when we resume from hibernation */
+       if (input_device->report_desc != NULL)
+               kfree(input_device->report_desc);
        input_device->report_desc = kzalloc(input_device->report_desc_size,
                                          GFP_ATOMIC);
 
@@ -342,6 +348,8 @@ static int mousevsc_connect_to_vsp(struct hv_device *device)
        struct mousevsc_prt_msg *request;
        struct mousevsc_prt_msg *response;
 
+       reinit_completion(&input_dev->wait_event);
+
        request = &input_dev->protocol_req;
        memset(request, 0, sizeof(struct mousevsc_prt_msg));
 
@@ -541,6 +549,30 @@ static int mousevsc_remove(struct hv_device *dev)
        return 0;
 }
 
+static int mousevsc_suspend(struct hv_device *dev)
+{
+       vmbus_close(dev->channel);
+
+       return 0;
+}
+
+static int mousevsc_resume(struct hv_device *dev)
+{
+       int ret;
+
+       ret = vmbus_open(dev->channel,
+                        INPUTVSC_SEND_RING_BUFFER_SIZE,
+                        INPUTVSC_RECV_RING_BUFFER_SIZE,
+                        NULL, 0,
+                        mousevsc_on_channel_callback,
+                        dev);
+       if (ret)
+               return ret;
+
+       ret = mousevsc_connect_to_vsp(dev);
+       return ret;
+}
+
 static const struct hv_vmbus_device_id id_table[] = {
        /* Mouse guid */
        { HV_MOUSE_GUID, },
@@ -554,6 +586,8 @@ static struct  hv_driver mousevsc_drv = {
        .id_table = id_table,
        .probe = mousevsc_probe,
        .remove = mousevsc_remove,
+       .suspend = mousevsc_suspend,
+       .resume = mousevsc_resume,
        .driver = {
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },