diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c index 79b3a780550b830c525014d7eed742d01e4117df..ffa992b829a5a55e818d5a3993ea6e2c2454bd35 100644 --- a/drivers/input/touchscreen/synaptics_fw_update.c +++ b/drivers/input/touchscreen/synaptics_fw_update.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/mutex.h> #include <linux/delay.h> #include <linux/input.h> #include <linux/firmware.h> @@ -296,6 +297,7 @@ struct synaptics_rmi4_fwu_handle { static struct synaptics_rmi4_fwu_handle *fwu; DECLARE_COMPLETION(fwu_remove_complete); +DEFINE_MUTEX(fwu_sysfs_mutex); static unsigned int extract_uint(const unsigned char *ptr) { @@ -1713,34 +1715,47 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file, char *buf, loff_t pos, size_t count) { struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + ssize_t retval; + + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; if (count < fwu->config_size) { dev_err(&rmi4_data->i2c_client->dev, "%s: Not enough space (%zu bytes) in buffer\n", __func__, count); - return -EINVAL; + retval = -EINVAL; + goto show_image_exit; } memcpy(buf, fwu->read_config_buf, fwu->config_size); - - return fwu->config_size; + retval = fwu->config_size; +show_image_exit: + mutex_unlock(&fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_store_image(struct file *data_file, struct kobject *kobj, struct bin_attribute *attributes, char *buf, loff_t pos, size_t count) { + ssize_t retval; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (!fwu->ext_data_source) { dev_err(&fwu->rmi4_data->i2c_client->dev, "Cannot use this without setting imagesize!\n"); - return -EAGAIN; + retval = -EAGAIN; + goto store_image_exit; } if (count > fwu->image_size - fwu->data_pos) { dev_err(&fwu->rmi4_data->i2c_client->dev, "%s: Not enough space in buffer\n", __func__); - return -EINVAL; + retval = -EINVAL; + goto store_image_exit; } memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]), @@ -1749,8 +1764,11 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file, fwu->data_buffer = fwu->ext_data_source; fwu->data_pos += count; + retval = count; - return count; +store_image_exit: + mutex_unlock(&fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_image_name_store(struct device *dev, @@ -1758,11 +1776,15 @@ static ssize_t fwu_sysfs_image_name_store(struct device *dev, { struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; char *strptr; + ssize_t retval; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; if (count >= NAME_BUFFER_SIZE) { dev_err(&rmi4_data->i2c_client->dev, "Input over %d characters long\n", NAME_BUFFER_SIZE); - return -EINVAL; + retval = -EINVAL; + goto image_name_store_exit; } strptr = strnstr(buf, ".img", @@ -1770,21 +1792,32 @@ static ssize_t fwu_sysfs_image_name_store(struct device *dev, if (!strptr) { dev_err(&rmi4_data->i2c_client->dev, "Input is not valid .img file\n"); - return -EINVAL; + retval = -EINVAL; + goto image_name_store_exit; } strlcpy(rmi4_data->fw_image_name, buf, count); - return count; + retval = count; + +image_name_store_exit: + mutex_unlock(&fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_image_name_show(struct device *dev, struct device_attribute *attr, char *buf) { + ssize_t retval; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) > 0) - return snprintf(buf, PAGE_SIZE, "%s\n", + retval = snprintf(buf, PAGE_SIZE, "%s\n", fwu->rmi4_data->fw_image_name); else - return snprintf(buf, PAGE_SIZE, "No firmware name given\n"); + retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n"); + + mutex_unlock(&fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_force_reflash_store(struct device *dev, @@ -1794,14 +1827,17 @@ static ssize_t fwu_sysfs_force_reflash_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; - goto exit; + goto force_reflash_store_exit; } if (input != 1) { retval = -EINVAL; - goto exit; + goto force_reflash_store_exit; } if (LOCKDOWN) fwu->do_lockdown = true; @@ -1812,16 +1848,18 @@ static ssize_t fwu_sysfs_force_reflash_store(struct device *dev, dev_err(&rmi4_data->i2c_client->dev, "%s: Failed to do reflash\n", __func__); - goto exit; + goto force_reflash_store_free_exit; } retval = count; -exit: +force_reflash_store_free_exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; fwu->force_update = FORCE_UPDATE; fwu->do_lockdown = rmi4_data->board->do_lockdown; +force_reflash_store_exit: + mutex_unlock(&fwu_sysfs_mutex); return retval; } @@ -1832,9 +1870,12 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; - goto exit; + goto reflash_store_exit; } if (input & LOCKDOWN) { @@ -1844,7 +1885,7 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, if ((input != NORMAL) && (input != FORCE)) { retval = -EINVAL; - goto exit; + goto reflash_store_exit; } if (input == FORCE) @@ -1855,16 +1896,18 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, dev_err(&rmi4_data->i2c_client->dev, "%s: Failed to do reflash\n", __func__); - goto exit; + goto reflash_store_free_exit; } retval = count; -exit: +reflash_store_free_exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; fwu->force_update = FORCE_UPDATE; fwu->do_lockdown = rmi4_data->board->do_lockdown; +reflash_store_exit: + mutex_unlock(&fwu_sysfs_mutex); return retval; } @@ -1875,26 +1918,31 @@ static ssize_t fwu_sysfs_write_lockdown_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; - goto exit; + goto lockdown_store_exit; } if (input != 1) { retval = -EINVAL; - goto exit; + goto lockdown_store_exit; } if (!fwu->ext_data_source) { dev_err(&fwu->rmi4_data->i2c_client->dev, "Cannot use this without loading image in manual way!\n"); - return -EAGAIN; + retval = -EAGAIN; + goto lockdown_store_exit; } if (fwu->rmi4_data->suspended == true) { dev_err(&fwu->rmi4_data->i2c_client->dev, "Cannot lockdown while device is in suspend\n"); - return -EBUSY; + retval = -EBUSY; + goto lockdown_store_exit; } retval = fwu_start_write_lockdown(); @@ -1902,16 +1950,18 @@ static ssize_t fwu_sysfs_write_lockdown_store(struct device *dev, dev_err(&rmi4_data->i2c_client->dev, "%s: Failed to write lockdown block\n", __func__); - goto exit; + goto lockdown_store_free_exit; } retval = count; -exit: +lockdown_store_free_exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; fwu->force_update = FORCE_UPDATE; fwu->do_lockdown = rmi4_data->board->do_lockdown; +lockdown_store_exit: + mutex_unlock(&fwu_sysfs_mutex); return retval; } @@ -1920,6 +1970,8 @@ static ssize_t fwu_sysfs_check_fw_store(struct device *dev, { unsigned int input = 0; + /* Takes fwu_sysfs_mutex in the deferred work function. */ + if (sscanf(buf, "%u", &input) != 1) return -EINVAL; @@ -1942,26 +1994,31 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev, unsigned int input; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; + if (sscanf(buf, "%u", &input) != 1) { retval = -EINVAL; - goto exit; + goto write_config_store_exit; } if (input != 1) { retval = -EINVAL; - goto exit; + goto write_config_store_exit; } if (!fwu->ext_data_source) { dev_err(&fwu->rmi4_data->i2c_client->dev, "Cannot use this without loading image in manual way!\n"); - return -EAGAIN; + retval = -EAGAIN; + goto write_config_store_exit; } if (fwu->rmi4_data->suspended == true) { dev_err(&fwu->rmi4_data->i2c_client->dev, "Cannot write config while device is in suspend\n"); - return -EBUSY; + retval = -EBUSY; + goto write_config_store_exit; } retval = fwu_start_write_config(); @@ -1969,14 +2026,16 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev, dev_err(&rmi4_data->i2c_client->dev, "%s: Failed to write config\n", __func__); - goto exit; + goto write_config_store_free_exit; } retval = count; -exit: +write_config_store_free_exit: kfree(fwu->ext_data_source); fwu->ext_data_source = NULL; +write_config_store_exit: + mutex_unlock(&fwu_sysfs_mutex); return retval; } @@ -1999,7 +2058,11 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev, return -EBUSY; } + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; retval = fwu_do_read_config(); + mutex_unlock(&fwu_sysfs_mutex); + if (retval < 0) { dev_err(&rmi4_data->i2c_client->dev, "%s: Failed to read config\n", @@ -2028,7 +2091,10 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev, return -EINVAL; } + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; fwu->config_area = config_area; + mutex_unlock(&fwu_sysfs_mutex); return count; } @@ -2039,10 +2105,12 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, int retval; unsigned long size; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + if (!mutex_trylock(&fwu_sysfs_mutex)) + return -EBUSY; retval = kstrtoul(buf, 10, &size); if (retval) - return retval; + goto image_size_store_exit; fwu->image_size = size; fwu->data_pos = 0; @@ -2053,10 +2121,12 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev, dev_err(&rmi4_data->i2c_client->dev, "%s: Failed to alloc mem for image data\n", __func__); - return -ENOMEM; + retval = -ENOMEM; } - return count; +image_size_store_exit: + mutex_unlock(&fwu_sysfs_mutex); + return retval; } static ssize_t fwu_sysfs_block_size_show(struct device *dev, @@ -2241,6 +2311,8 @@ static void synaptics_rmi4_fwu_work(struct work_struct *work) container_of(to_delayed_work(work), struct synaptics_rmi4_fwu_handle, fwu_work); + mutex_lock(&fwu_sysfs_mutex); + if (fwu->fn_ptr->enable) fwu->fn_ptr->enable(fwu->rmi4_data, false); @@ -2248,6 +2320,8 @@ static void synaptics_rmi4_fwu_work(struct work_struct *work) if (fwu->fn_ptr->enable) fwu->fn_ptr->enable(fwu->rmi4_data, true); + + mutex_unlock(&fwu_sysfs_mutex); } static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) @@ -2338,7 +2412,7 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) INIT_DELAYED_WORK(&fwu->fwu_work, synaptics_rmi4_fwu_work); #endif - retval = sysfs_create_bin_file(&rmi4_data->i2c_client->dev.kobj, + retval = sysfs_create_bin_file(&rmi4_data->i2c_client->dev.kobj, &dev_attr_data); if (retval < 0) { dev_err(&rmi4_data->i2c_client->dev,