linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: marcoshalano@gmail.com
To: Angela Czubak <acz@semihalf.com>,
	linux-input@vger.kernel.org, upstream@semihalf.com,
	benjamin.tissoires@redhat.com, jikos@kernel.org,
	dmitry.torokhov@gmail.com, Angela Czubak <acz@semihalf.com>
Subject: Re: [PATCH v3 17/17] HID: multitouch: Add lid handler for touchpad on Redrix chromebook
Date: Sat, 14 May 2022 21:07:39 -0300	[thread overview]
Message-ID: <eaa15224-50d9-e3b4-f5df-a29ef6a9043b@gmail.com> (raw)
In-Reply-To: <20220513093927.1632262-18-acz@semihalf.com>

On 13/05/2022 06:39, Angela Czubak <acz@semihalf.com> wrote:
> If user closes the lid the touchscreen gets close to the touchpad surface,
> which causes interference and makes the touchpad enter noise mode.
> Right after opening the lid the cursor is unresponsive because of the mode
> mentioned.
> To fix this issue we switch the surface off and on so that Elan's FW
> performs recalibration once the lid has been opened.
> 
A non related question: this hid-haptic module is made just for newer touchpads which have a haptic response instead of regular clicks, or the haptic logic could be extended for other haptic devices, like Sony's DualSense controller triggers?

> Signed-off-by: Angela Czubak <acz@semihalf.com>
> ---
>   drivers/hid/hid-multitouch.c | 220 ++++++++++++++++++++++++++++++++++-
>   1 file changed, 219 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> index 2d1b8c400c2f..73e47fe7d773 100644
> --- a/drivers/hid/hid-multitouch.c
> +++ b/drivers/hid/hid-multitouch.c
> @@ -32,11 +32,14 @@
>    */
>   
>   #include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/dmi.h>
>   #include <linux/hid.h>
>   #include <linux/module.h>
>   #include <linux/slab.h>
>   #include <linux/input/mt.h>
>   #include <linux/jiffies.h>
> +#include <linux/sched.h>
>   #include <linux/string.h>
>   #include <linux/timer.h>
>   
> @@ -159,6 +162,7 @@ struct mt_report_data {
>   };
>   
>   struct mt_device {
> +	struct list_head list;	/* for list of devices needing input handler */
>   	struct mt_class mtclass;	/* our mt device class */
>   	struct timer_list release_timer;	/* to release sticky fingers */
>   	struct hid_haptic_device *haptic;	/* haptic related configuration */
> @@ -173,8 +177,15 @@ struct mt_device {
>   
>   	struct list_head applications;
>   	struct list_head reports;
> +
> +	struct work_struct lid_work;
> +	struct mutex mode_mutex;
> +	bool lid_switch;
>   };
>   
> +static struct workqueue_struct *mt_mode_wq;
> +static LIST_HEAD(mt_devices_with_lid_handler);
> +
>   static void mt_post_parse_default_settings(struct mt_device *td,
>   					   struct mt_application *app);
>   static void mt_post_parse(struct mt_device *td, struct mt_application *app);
> @@ -394,6 +405,91 @@ static const struct mt_class mt_classes[] = {
>   	{ }
>   };
>   
> +static void mt_input_lid_event(struct input_handle *handle, unsigned int type,
> +			     unsigned int code, int value)
> +{
> +	struct mt_device *td, *n;
> +
> +	if (type == EV_SW && code == SW_LID && !value) {
> +		list_for_each_entry_safe(td, n, &mt_devices_with_lid_handler, list)
> +			queue_work(mt_mode_wq, &td->lid_work);
> +	}
> +}
> +
> +struct mt_input_lid {
> +	struct input_handle handle;
> +};
> +
> +static int mt_input_lid_connect(struct input_handler *handler,
> +				struct input_dev *dev,
> +				const struct input_device_id *id)
> +{
> +	struct mt_input_lid *lid;
> +	char *name;
> +	int error;
> +
> +	lid = kzalloc(sizeof(*lid), GFP_KERNEL);
> +	if (!lid)
> +		return -ENOMEM;
> +
> +	name = kasprintf(GFP_KERNEL, "hid-mt-lid-%s", dev_name(&dev->dev));
> +	if (!name) {
> +		error = -ENOMEM;
> +		goto err_free_lid;
> +	}
> +
> +	lid->handle.dev = dev;
> +	lid->handle.handler = handler;
> +	lid->handle.name = name;
> +	lid->handle.private = lid;
> +
> +	error = input_register_handle(&lid->handle);
> +	if (error)
> +		goto err_free_name;
> +
> +	error = input_open_device(&lid->handle);
> +	if (error)
> +		goto err_unregister_handle;
> +
> +	return 0;
> +
> +err_unregister_handle:
> +	input_unregister_handle(&lid->handle);
> +err_free_name:
> +	kfree(name);
> +err_free_lid:
> +	kfree(lid);
> +	return error;
> +}
> +
> +static void mt_input_lid_disconnect(struct input_handle *handle)
> +{
> +	struct mt_input_lid *lid = handle->private;
> +
> +	input_close_device(handle);
> +	input_unregister_handle(handle);
> +
> +	kfree(handle->name);
> +	kfree(lid);
> +}
> +
> +static const struct input_device_id mt_input_lid_ids[] = {
> +	{
> +		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
> +		.evbit = { BIT_MASK(EV_SW) },
> +		.swbit = { [BIT_WORD(SW_LID)] = BIT_MASK(SW_LID) },
> +	},
> +	{ },
> +};
> +
> +static struct input_handler mt_input_lid_handler = {
> +	.event =	mt_input_lid_event,
> +	.connect =	mt_input_lid_connect,
> +	.disconnect =	mt_input_lid_disconnect,
> +	.name =		"hid-mt-lid",
> +	.id_table =	mt_input_lid_ids,
> +};
> +
>   static ssize_t mt_show_quirks(struct device *dev,
>   			   struct device_attribute *attr,
>   			   char *buf)
> @@ -548,6 +644,83 @@ static struct mt_usages *mt_allocate_usage(struct hid_device *hdev,
>   	return usage;
>   }
>   
> +static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency,
> +			 bool surface_switch, bool button_switch);
> +
> +static void lid_work_handler(struct work_struct *work)
> +{
> +
> +	struct mt_device *td = container_of(work, struct mt_device,
> +					    lid_work);
> +	struct hid_device *hdev = td->hdev;
> +
> +	mutex_lock(&td->mode_mutex);
> +	mt_set_modes(hdev, HID_LATENCY_NORMAL, false, false);
> +	/* Elan's touchpad VID 323B needs this delay to handle both switch
> +	 * surface off and switch surface on and trigger recalibration
> +	 * properly.
> +	 */
> +	msleep(50);
> +	mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
> +	mutex_unlock(&td->mode_mutex);
> +}
> +
> +static const struct dmi_system_id mt_lid_handler_dmi_table[] = {
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Redrix"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Redrix4ES"),
> +		},
> +	},
> +	{}
> +};
> +
> +static int mt_create_lid_handler(void)
> +{
> +	int error = 0;
> +
> +	if (!dmi_check_system(mt_lid_handler_dmi_table))
> +		return 0;
> +
> +	mt_mode_wq = alloc_ordered_workqueue("hid-mt-lid", WQ_FREEZABLE);
> +	if (mt_mode_wq == NULL)
> +		return -ENOMEM;
> +
> +	error = input_register_handler(&mt_input_lid_handler);
> +	if (error)
> +		goto remove_wq;
> +
> +	return 0;
> +
> +remove_wq:
> +	destroy_workqueue(mt_mode_wq);
> +	mt_mode_wq = NULL;
> +	return error;
> +}
> +
> +static void mt_configure_lid_handler(struct mt_device *td)
> +{
> +	struct hid_device *hdev = td->hdev;
> +
> +	if (hdev->bus != BUS_I2C)
> +		return;
> +
> +	td->lid_switch = true;
> +	list_add_tail(&td->list, &mt_devices_with_lid_handler);
> +}
> +
> +static void mt_destroy_lid_handler(void)
> +{
> +	input_unregister_handler(&mt_input_lid_handler);
> +	destroy_workqueue(mt_mode_wq);
> +}
> +
>   static struct mt_application *mt_allocate_application(struct mt_device *td,
>   						      struct hid_report *report)
>   {
> @@ -571,6 +744,8 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
>   	if (application == HID_DG_TOUCHPAD) {
>   		mt_application->mt_flags |= INPUT_MT_POINTER;
>   		td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
> +		if (mt_mode_wq)
> +			mt_configure_lid_handler(td);
>   	}
>   
>   	mt_application->scantime = DEFAULT_ZERO;
> @@ -1767,6 +1942,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
>   	INIT_LIST_HEAD(&td->applications);
>   	INIT_LIST_HEAD(&td->reports);
>   
> +	INIT_LIST_HEAD(&td->list);
> +	INIT_WORK(&td->lid_work, lid_work_handler);
> +	mutex_init(&td->mode_mutex);
> +
>   	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
>   		td->serial_maybe = true;
>   
> @@ -1830,12 +2009,18 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state)
>   	struct mt_device *td = hid_get_drvdata(hdev);
>   	struct hid_haptic_device *haptic = td->haptic;
>   
> +	/* Wait for switch on completion */
> +	if (td->lid_switch)
> +		flush_workqueue(mt_mode_wq);
> +
> +	mutex_lock(&td->mode_mutex);
>   	/* High latency is desirable for power savings during S3/S0ix */
>   	if ((td->mtclass.quirks & MT_QUIRK_DISABLE_WAKEUP) ||
>   	    !hid_hw_may_wakeup(hdev))
>   		mt_set_modes(hdev, HID_LATENCY_HIGH, false, false);
>   	else
>   		mt_set_modes(hdev, HID_LATENCY_HIGH, true, true);
> +	mutex_unlock(&td->mode_mutex);
>   
>   	if (td->is_haptic_touchpad)
>   		hid_haptic_suspend(hdev, haptic);
> @@ -1849,7 +2034,10 @@ static int mt_reset_resume(struct hid_device *hdev)
>   	struct hid_haptic_device *haptic = td->haptic;
>   
>   	mt_release_contacts(hdev);
> +
> +	mutex_lock(&td->mode_mutex);
>   	mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
> +	mutex_unlock(&td->mode_mutex);
>   
>   	if (td->is_haptic_touchpad)
>   		hid_haptic_resume(hdev, haptic);
> @@ -1868,7 +2056,9 @@ static int mt_resume(struct hid_device *hdev)
>   
>   	hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE);
>   
> +	mutex_lock(&td->mode_mutex);
>   	mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
> +	mutex_unlock(&td->mode_mutex);
>   
>   	if (td->is_haptic_touchpad)
>   		hid_haptic_resume(hdev, haptic);
> @@ -1883,7 +2073,9 @@ static int mt_reset(struct hid_device *hdev)
>   	struct hid_haptic_device *haptic = td->haptic;
>   
>   	mt_release_contacts(hdev);
> +	mutex_lock(&td->mode_mutex);
>   	mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
> +	mutex_unlock(&td->mode_mutex);
>   
>   	if (td->is_haptic_touchpad)
>   		hid_haptic_reset(hdev, haptic);
> @@ -1899,6 +2091,8 @@ static void mt_remove(struct hid_device *hdev)
>   
>   	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
>   	hid_hw_stop(hdev);
> +
> +	list_del(&td->list);
>   }
>   
>   /*
> @@ -2302,4 +2496,28 @@ static struct hid_driver mt_driver = {
>   	.resume = mt_resume,
>   #endif
>   };
> -module_hid_driver(mt_driver);
> +
> +static int __init mt_init(void)
> +{
> +	int ret;
> +
> +	ret = hid_register_driver(&mt_driver);
> +	if (ret)
> +		return ret;
> +
> +	ret = mt_create_lid_handler();
> +	if (ret)
> +		hid_unregister_driver(&mt_driver);
> +
> +	return ret;
> +}
> +module_init(mt_init);
> +
> +static void __exit mt_exit(void)
> +{
> +	if (mt_mode_wq)
> +		mt_destroy_lid_handler();
> +
> +	hid_unregister_driver(&mt_driver);
> +}
> +module_exit(mt_exit);
> 


  reply	other threads:[~2022-05-15  0:07 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-13  9:39 [PATCH v3 00/17] *** Implement simple haptic HID support *** Angela Czubak
2022-05-13  9:39 ` [PATCH v3 01/17] HID: add haptics page defines Angela Czubak
2022-05-13  9:39 ` [PATCH v3 02/17] Input: add FF_HID effect type Angela Czubak
2022-05-13  9:39 ` [PATCH v3 03/17] HID: haptic: introduce hid_haptic_device Angela Czubak
2022-05-13  9:39 ` [PATCH v3 04/17] HID: input: allow mapping of haptic output Angela Czubak
2022-05-13  9:39 ` [PATCH v3 05/17] HID: haptic: initialize haptic device Angela Czubak
2022-05-13  9:39 ` [PATCH v3 06/17] Input: add shared effects Angela Czubak
2022-05-13  9:39 ` [PATCH v3 07/17] HID: haptic: implement release and press effects Angela Czubak
2022-05-13  9:39 ` [PATCH v3 08/17] HID: input: calculate resolution for pressure Angela Czubak
2022-05-13  9:39 ` [PATCH v3 09/17] HID: haptic: add functions handling events Angela Czubak
2022-05-13  9:39 ` [PATCH v3 10/17] Input: MT - add INPUT_MT_MAX_FORCE flags Angela Czubak
2022-05-13  9:39 ` [PATCH v3 11/17] HID: haptic: add hid_haptic_switch_mode Angela Czubak
2022-05-13  9:39 ` [PATCH v3 12/17] HID: multitouch: add haptic multitouch support Angela Czubak
2022-05-13  9:39 ` [PATCH v3 13/17] Input: introduce EVIOCFF(TAKE|RELEASE)CONTROL Angela Czubak
2022-05-13  9:39 ` [PATCH v3 14/17] HID: haptic: add hid_haptic_change_control Angela Czubak
2022-05-13  9:39 ` [PATCH v3 15/17] HID: add HID device reset callback Angela Czubak
2022-05-13  9:39 ` [PATCH v3 16/17] HID: haptic: implement HID haptic " Angela Czubak
2022-05-13  9:39 ` [PATCH v3 17/17] HID: multitouch: Add lid handler for touchpad on Redrix chromebook Angela Czubak
2022-05-15  0:07   ` marcoshalano [this message]
2022-05-22 17:55 ` [PATCH v3 00/17] *** Implement simple haptic HID support *** Angela Czubak
2022-05-23  6:57   ` Jiri Kosina

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=eaa15224-50d9-e3b4-f5df-a29ef6a9043b@gmail.com \
    --to=marcoshalano@gmail.com \
    --cc=acz@semihalf.com \
    --cc=benjamin.tissoires@redhat.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=upstream@semihalf.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).