To simplify resource management in commit that follows as well as to save a couple of extra kfree()s and simplify hidpp_ff_deinit() switch driver code to use devres to manage the life-cycle of FF private data. Signed-off-by: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> Cc: Jiri Kosina <jikos@xxxxxxxxxx> Cc: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxxx> Cc: Henrik Rydberg <rydberg@xxxxxxxxxxx> Cc: Sam Bazely <sambazley@xxxxxxxxxxxx> Cc: Pierre-Loup A. Griffais <pgriffais@xxxxxxxxxxxxxxxxx> Cc: Austin Palmer <austinp@xxxxxxxxxxxxxxxxx> Cc: linux-input@xxxxxxxxxxxxxxx Cc: linux-kernel@xxxxxxxxxxxxxxx Cc: stable@xxxxxxxxxxxxxxx --- drivers/hid/hid-logitech-hidpp.c | 53 +++++++++++++++++--------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 0179f7ed77e5..58eb928224e5 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -2079,6 +2079,11 @@ static void hidpp_ff_destroy(struct ff_device *ff) struct hidpp_ff_private_data *data = ff->private; kfree(data->effect_ids); + /* + * Set private to NULL to prevent input_ff_destroy() from + * freeing our devres allocated memory + */ + ff->private = NULL; } static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) @@ -2090,7 +2095,7 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice); struct ff_device *ff; struct hidpp_report response; - struct hidpp_ff_private_data *data; + struct hidpp_ff_private_data *data = hidpp->private_data; int error, j, num_slots; u8 version; @@ -2129,18 +2134,13 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) return error; } - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; data->effect_ids = kcalloc(num_slots, sizeof(int), GFP_KERNEL); - if (!data->effect_ids) { - kfree(data); + if (!data->effect_ids) return -ENOMEM; - } + data->wq = create_singlethread_workqueue("hidpp-ff-sendqueue"); if (!data->wq) { kfree(data->effect_ids); - kfree(data); return -ENOMEM; } @@ -2199,28 +2199,15 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) return 0; } -static int hidpp_ff_deinit(struct hid_device *hid) +static void hidpp_ff_deinit(struct hid_device *hid) { - struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); - struct input_dev *dev = hidinput->input; - struct hidpp_ff_private_data *data; - - if (!dev) { - hid_err(hid, "Struct input_dev not found!\n"); - return -EINVAL; - } + struct hidpp_device *hidpp = hid_get_drvdata(hid); + struct hidpp_ff_private_data *data = hidpp->private_data; hid_info(hid, "Unloading HID++ force feedback.\n"); - data = dev->ff->private; - if (!data) { - hid_err(hid, "Private data not found!\n"); - return -EINVAL; - } destroy_workqueue(data->wq); device_remove_file(&hid->dev, &dev_attr_range); - - return 0; } @@ -2725,6 +2712,20 @@ static int k400_connect(struct hid_device *hdev, bool connected) #define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123 +static int g920_allocate(struct hid_device *hdev) +{ + struct hidpp_device *hidpp = hid_get_drvdata(hdev); + struct hidpp_ff_private_data *data; + + data = devm_kzalloc(&hdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + hidpp->private_data = data; + + return 0; +} + static int g920_get_config(struct hidpp_device *hidpp) { u8 feature_type; @@ -3561,6 +3562,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = k400_allocate(hdev); if (ret) return ret; + } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { + ret = g920_allocate(hdev); + if (ret) + return ret; } INIT_WORK(&hidpp->work, delayed_work_cb); -- 2.21.0