diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 250df52822ba0b..27e890379d861b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -283,6 +283,7 @@ struct mxt_data { u8 t100_aux_ampl; u8 t100_aux_area; u8 t100_aux_vect; + struct bin_attribute mem_access_attr; bool debug_enabled; u8 max_reportid; u32 config_crc; @@ -3024,6 +3025,56 @@ static ssize_t mxt_debug_enable_store(struct device *dev, return ret; } +static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off, + size_t *count) +{ + if (off >= data->mem_size) + return -EIO; + + if (off + *count > data->mem_size) + *count = data->mem_size - off; + + if (*count > MXT_MAX_BLOCK_WRITE) + *count = MXT_MAX_BLOCK_WRITE; + + return 0; +} + +static ssize_t mxt_mem_access_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct mxt_data *data = dev_get_drvdata(dev); + int ret = 0; + + ret = mxt_check_mem_access_params(data, off, &count); + if (ret < 0) + return ret; + + if (count > 0) + ret = __mxt_read_reg(data->client, off, count, buf); + + return ret == 0 ? count : ret; +} + +static ssize_t mxt_mem_access_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, loff_t off, + size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct mxt_data *data = dev_get_drvdata(dev); + int ret = 0; + + ret = mxt_check_mem_access_params(data, off, &count); + if (ret < 0) + return ret; + + if (count > 0) + ret = __mxt_write_reg(data->client, off, count, buf); + + return ret == 0 ? count : ret; +} + static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store); static struct attribute *mxt_fw_attrs[] = { @@ -3069,13 +3120,36 @@ static int mxt_sysfs_init(struct mxt_data *data) return error; } + sysfs_bin_attr_init(&data->mem_access_attr); + data->mem_access_attr.attr.name = "mem_access"; + data->mem_access_attr.attr.mode = S_IRUGO | S_IWUSR; + data->mem_access_attr.read = mxt_mem_access_read; + data->mem_access_attr.write = mxt_mem_access_write; + data->mem_access_attr.size = data->mem_size; + + error = sysfs_create_bin_file(&client->dev.kobj, + &data->mem_access_attr); + if (error) { + dev_err(&client->dev, "Failed to create %s\n", + data->mem_access_attr.attr.name); + goto err_remove_sysfs_group; + } + return 0; + +err_remove_sysfs_group: + sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); + return error; } static void mxt_sysfs_remove(struct mxt_data *data) { struct i2c_client *client = data->client; + if (data->mem_access_attr.attr.name) + sysfs_remove_bin_file(&client->dev.kobj, + &data->mem_access_attr); + sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); }