From: Nick Dyer <nick.d...@itdev.co.uk>

An error in the sysfs init may otherwise interfere with the async return
from the firmware loader

Signed-off-by: Nick Dyer <nick.d...@itdev.co.uk>
(cherry picked from ndyer/linux/for-upstream commit 
3114584ae77c2b03b6dad87174f010d002e9c05d)
[gdavis: Forward port and fixup conflicts. Also fixed sysfs leaks in
         both the mxt_initialize() and mxt_probe() error return cases.]
Signed-off-by: George G. Davis <george_da...@mentor.com>
Signed-off-by: Jiada Wang <jiada_w...@mentor.com>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 71 +++++++++++++++++++-----
 1 file changed, 57 insertions(+), 14 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c 
b/drivers/input/touchscreen/atmel_mxt_ts.c
index 573b94a049b2..79e35c929857 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2090,6 +2090,9 @@ static int mxt_initialize_input_device(struct mxt_data 
*data)
        return error;
 }
 
+static int mxt_sysfs_init(struct mxt_data *data);
+static void mxt_sysfs_remove(struct mxt_data *data);
+
 static int mxt_configure_objects(struct mxt_data *data,
                                 const struct firmware *cfg);
 
@@ -2141,16 +2144,24 @@ static int mxt_initialize(struct mxt_data *data)
        if (error)
                return error;
 
+       error = mxt_sysfs_init(data);
+       if (error)
+               return error;
+
        error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
                                        &client->dev, GFP_KERNEL, data,
                                        mxt_config_cb);
        if (error) {
                dev_err(&client->dev, "Failed to invoke firmware loader: %d\n",
                        error);
-               return error;
+               goto err_free_sysfs;
        }
 
        return 0;
+
+err_free_sysfs:
+       mxt_sysfs_remove(data);
+       return error;
 }
 
 static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep)
@@ -2803,6 +2814,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
                if (ret)
                        goto release_firmware;
 
+               mxt_sysfs_remove(data);
                mxt_free_input_device(data);
                mxt_free_object_table(data);
        } else {
@@ -2909,16 +2921,25 @@ static ssize_t mxt_update_fw_store(struct device *dev,
        return count;
 }
 
+static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
+
+static struct attribute *mxt_fw_attrs[] = {
+       &dev_attr_update_fw.attr,
+       NULL
+};
+
+static const struct attribute_group mxt_fw_attr_group = {
+       .attrs = mxt_fw_attrs,
+};
+
 static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL);
 static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL);
 static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
-static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
 
 static struct attribute *mxt_attrs[] = {
        &dev_attr_fw_version.attr,
        &dev_attr_hw_version.attr,
        &dev_attr_object.attr,
-       &dev_attr_update_fw.attr,
        NULL
 };
 
@@ -2926,6 +2947,28 @@ static const struct attribute_group mxt_attr_group = {
        .attrs = mxt_attrs,
 };
 
+static int mxt_sysfs_init(struct mxt_data *data)
+{
+       struct i2c_client *client = data->client;
+       int error;
+
+       error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
+       if (error) {
+               dev_err(&client->dev, "Failure %d creating sysfs group\n",
+                       error);
+               return error;
+       }
+
+       return 0;
+}
+
+static void mxt_sysfs_remove(struct mxt_data *data)
+{
+       struct i2c_client *client = data->client;
+
+       sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
+}
+
 static void mxt_start(struct mxt_data *data)
 {
        switch (data->suspend_mode) {
@@ -3109,22 +3152,21 @@ static int mxt_probe(struct i2c_client *client, const 
struct i2c_device_id *id)
                msleep(MXT_RESET_INVALID_CHG);
        }
 
-       error = mxt_initialize(data);
-       if (error)
-               return error;
-
-       error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
+       error = sysfs_create_group(&client->dev.kobj, &mxt_fw_attr_group);
        if (error) {
-               dev_err(&client->dev, "Failure %d creating sysfs group\n",
+               dev_err(&client->dev, "Failure %d creating fw sysfs group\n",
                        error);
-               goto err_free_object;
+               return error;
        }
 
+       error = mxt_initialize(data);
+       if (error)
+               goto err_sysfs_remove_group;
+
        return 0;
 
-err_free_object:
-       mxt_free_input_device(data);
-       mxt_free_object_table(data);
+err_sysfs_remove_group:
+       sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
        return error;
 }
 
@@ -3133,7 +3175,8 @@ static int mxt_remove(struct i2c_client *client)
        struct mxt_data *data = i2c_get_clientdata(client);
 
        disable_irq(data->irq);
-       sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
+       sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
+       mxt_sysfs_remove(data);
        mxt_free_input_device(data);
        mxt_free_object_table(data);
 
-- 
2.19.2

Reply via email to