Commit af13f9ed authored by Dexuan Cui's avatar Dexuan Cui Committed by Sasha Levin
Browse files

HID: hyperv: Add the support of hibernation



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: default avatarDexuan Cui <decui@microsoft.com>
Acked-by: default avatarJiri Kosina <jkosina@suse.cz>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 25bd2b2f
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -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,
	},