* [PATCH v1 31/63] Input: atmel_mxt_ts - add memory access interface via sysfs
2019-08-16 8:34 [PATCH v1 30/63] Input: atmel_mxt_ts - implement debug output for messages Jiada Wang
@ 2019-08-16 8:34 ` Jiada Wang
2019-08-16 17:29 ` Dmitry Torokhov
2019-08-16 8:34 ` [PATCH v1 32/63] Input: atmel_mxt_ts - implement improved debug message interface Jiada Wang
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Jiada Wang @ 2019-08-16 8:34 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
From: Nick Dyer <nick.dyer@itdev.co.uk>
Atmel maXTouch chips can be addressed via an "Object Based Protocol" which
defines how i2c registers are mapped to different functions within the
chips. This interface exposes the register map and allows user-space
utilities to inspect and alter object configuration, and to view diagnostic
data, while the device is running.
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Acked-by: Benson Leung <bleung@chromium.org>
(cherry picked from ndyer/linux/for-upstream commit 80731e95c888d09b663ad9eeaf4163939bfe17f8)
Signed-off-by: George G. Davis <george_davis@mentor.com>
[jiada: Fix compilation warnings]
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 74 ++++++++++++++++++++++++
1 file changed, 74 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index e317900279ed..05b21c9c0c04 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -335,6 +335,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;
@@ -3553,6 +3554,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 ? (ssize_t)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 ? (ssize_t)count : ret;
+}
+
static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
static struct attribute *mxt_fw_attrs[] = {
@@ -3598,13 +3649,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);
}
--
2.19.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v1 32/63] Input: atmel_mxt_ts - implement improved debug message interface
2019-08-16 8:34 [PATCH v1 30/63] Input: atmel_mxt_ts - implement debug output for messages Jiada Wang
2019-08-16 8:34 ` [PATCH v1 31/63] Input: atmel_mxt_ts - add memory access interface via sysfs Jiada Wang
@ 2019-08-16 8:34 ` Jiada Wang
2019-08-16 8:34 ` [PATCH v1 33/63] Input: atmel_mxt_ts - eliminate data->raw_info_block Jiada Wang
2019-08-16 8:34 ` [PATCH v1 34/63] Input: atmel_mxt_ts - Change call-points of mxt_free_* functions Jiada Wang
3 siblings, 0 replies; 7+ messages in thread
From: Jiada Wang @ 2019-08-16 8:34 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
From: Nick Dyer <nick.dyer@itdev.co.uk>
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
(cherry picked from ndyer/linux/for-upstream commit 078569c13c88dcb6f8d882bfe17168587712df7d)
[gdavis: Resolve forward port conflicts due to v4.14.51 commit
960fe000b1d3 ("Input: atmel_mxt_ts - fix the firmware
update").]
Signed-off-by: George G. Davis <george_davis@mentor.com>
[gdavis: Squash fixes from Dirk Behme:
- Input: atmel_mxt_ts - add missing unlock in error path
- Input: atmel_mxt_ts - add missing unlock in error path
- Input: atmel_mxt_ts - call mxt_debug_msg_remove() in error path
- Input: atmel_mxt_ts - protect debug_v2_enabled by mutex
Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
[gdavis: Squash fix from Vladimir Zapolskiy:
- Input: atmel_mxt_ts - simplify debug_msg binary attribute
handling]
Signed-off-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
---
Notes:
- Squash fixes from Dirk Behme:
+ Input: atmel_mxt_ts - add missing unlock in error path
Unlock the mutex in case the function is exited in the error case.
+ Input: atmel_mxt_ts - add missing unlock in error path
+ Input: atmel_mxt_ts - protect debug_v2_enabled by mutex
Put the modification of debug_v2_enabled into the protected section.
Same as in mxt_debug_msg_enable().
+ Input: atmel_mxt_ts - call mxt_debug_msg_remove() in error path
Add the missing mxt_debug_msg_remove() to the error path.
- Squash fix from Vladimir Zapolskiy:
+ Input: atmel_mxt_ts - simplify debug_msg binary attribute handling
The change introduces several updates, but all of them are related to
"debug_msg" binary attribute:
* removed dynamic initialization of data->debug_msg_attr
* removed mxt_debug_msg_write callback
* removed wrong check in mxt_debug_msg_remove()
* mxt_debug_msg_remove() now is not called from mxt_free_object_table()
avoiding multiple double deallocations.
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 189 ++++++++++++++++++++++-
1 file changed, 187 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 05b21c9c0c04..e185d10c2cac 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -242,6 +242,8 @@ enum t100_type {
#define MXT_PIXELS_PER_MM 20
+#define DEBUG_MSG_MAX 200
+
struct mxt_info {
u8 family_id;
u8 variant_id;
@@ -337,6 +339,11 @@ struct mxt_data {
u8 t100_aux_vect;
struct bin_attribute mem_access_attr;
bool debug_enabled;
+ bool debug_v2_enabled;
+ u8 *debug_msg_data;
+ u16 debug_msg_count;
+ struct bin_attribute *debug_msg_attr;
+ struct mutex debug_msg_lock;
u8 max_reportid;
u32 config_crc;
u32 info_crc;
@@ -466,6 +473,139 @@ static void mxt_dump_message(struct mxt_data *data, u8 *message)
data->T5_msg_size, message);
}
+static void mxt_debug_msg_enable(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+
+ if (data->debug_v2_enabled)
+ return;
+
+ mutex_lock(&data->debug_msg_lock);
+
+ data->debug_msg_data = kcalloc(DEBUG_MSG_MAX,
+ data->T5_msg_size, GFP_KERNEL);
+ if (!data->debug_msg_data) {
+ mutex_unlock(&data->debug_msg_lock);
+ return;
+ }
+
+ data->debug_v2_enabled = true;
+ mutex_unlock(&data->debug_msg_lock);
+
+ dev_dbg(dev, "Enabled message output\n");
+}
+
+static void mxt_debug_msg_disable(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+
+ if (!data->debug_v2_enabled)
+ return;
+
+ mutex_lock(&data->debug_msg_lock);
+
+ data->debug_v2_enabled = false;
+
+ kfree(data->debug_msg_data);
+ data->debug_msg_data = NULL;
+ data->debug_msg_count = 0;
+ mutex_unlock(&data->debug_msg_lock);
+ dev_dbg(dev, "Disabled message output\n");
+}
+
+static void mxt_debug_msg_add(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+
+ mutex_lock(&data->debug_msg_lock);
+
+ if (!data->debug_msg_data) {
+ mutex_unlock(&data->debug_msg_lock);
+ dev_err(dev, "No buffer!\n");
+ return;
+ }
+
+ if (data->debug_msg_count < DEBUG_MSG_MAX) {
+ memcpy(data->debug_msg_data +
+ data->debug_msg_count * data->T5_msg_size,
+ msg,
+ data->T5_msg_size);
+ data->debug_msg_count++;
+ } else {
+ dev_dbg(dev, "Discarding %u messages\n", data->debug_msg_count);
+ data->debug_msg_count = 0;
+ }
+
+ mutex_unlock(&data->debug_msg_lock);
+
+ sysfs_notify(&data->client->dev.kobj, NULL, "debug_notify");
+}
+
+static ssize_t mxt_debug_msg_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off, size_t bytes)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+ size_t bytes_read;
+
+ if (!data->debug_msg_data) {
+ dev_err(dev, "No buffer!\n");
+ return 0;
+ }
+
+ count = bytes / data->T5_msg_size;
+
+ if (count > DEBUG_MSG_MAX)
+ count = DEBUG_MSG_MAX;
+
+ mutex_lock(&data->debug_msg_lock);
+
+ if (count > data->debug_msg_count)
+ count = data->debug_msg_count;
+
+ bytes_read = count * data->T5_msg_size;
+
+ memcpy(buf, data->debug_msg_data, bytes_read);
+ data->debug_msg_count = 0;
+
+ mutex_unlock(&data->debug_msg_lock);
+
+ return bytes_read;
+}
+
+static struct bin_attribute debug_msg_attr = {
+ .attr = {
+ .name = "debug_msg",
+ .mode = 0444,
+ },
+ .read = mxt_debug_msg_read,
+};
+
+static int mxt_debug_msg_init(struct mxt_data *data)
+{
+ /*
+ * Binary attribute is not used in callback, removal is done by name,
+ * so it is safe to update a single struct bin_attribute entity
+ */
+ debug_msg_attr.size = data->T5_msg_size * DEBUG_MSG_MAX;
+ data->debug_msg_attr = &debug_msg_attr;
+
+ if (sysfs_create_bin_file(&data->client->dev.kobj,
+ data->debug_msg_attr) < 0) {
+ dev_err(&data->client->dev, "Failed to create %s\n",
+ debug_msg_attr.attr.name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void mxt_debug_msg_remove(struct mxt_data *data)
+{
+ sysfs_remove_bin_file(&data->client->dev.kobj, data->debug_msg_attr);
+}
+
static int mxt_wait_for_completion(struct mxt_data *data,
struct completion *comp,
unsigned int timeout_ms)
@@ -1256,6 +1396,9 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
if (dump)
mxt_dump_message(data, message);
+ if (data->debug_v2_enabled)
+ mxt_debug_msg_add(data, message);
+
return 1;
}
@@ -2671,6 +2814,10 @@ static int mxt_initialize(struct mxt_data *data)
if (error)
return error;
+ error = mxt_debug_msg_init(data);
+ if (error)
+ goto err_free_sysfs;
+
if (data->cfg_name) {
error = request_firmware_nowait(THIS_MODULE, true,
data->cfg_name,
@@ -2680,16 +2827,18 @@ static int mxt_initialize(struct mxt_data *data)
if (error) {
dev_err(&client->dev, "Failed to invoke firmware loader: %d\n",
error);
- goto err_free_sysfs;
+ goto err_free_dbg_msg;
}
} else {
error = mxt_configure_objects(data, NULL);
if (error)
- goto err_free_sysfs;
+ goto err_free_dbg_msg;
}
return 0;
+err_free_dbg_msg:
+ mxt_debug_msg_remove(data);
err_free_sysfs:
mxt_sysfs_remove(data);
return error;
@@ -3351,6 +3500,7 @@ static int mxt_enter_bootloader(struct mxt_data *data)
return ret;
data->in_bootloader = true;
+ mxt_debug_msg_remove(data);
mxt_sysfs_remove(data);
mxt_free_input_device(data);
mxt_free_object_table(data);
@@ -3534,6 +3684,34 @@ static ssize_t mxt_debug_enable_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%c\n", c);
}
+static ssize_t mxt_debug_notify_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t mxt_debug_v2_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ u8 i;
+ ssize_t ret;
+
+ if (kstrtou8(buf, 0, &i) == 0 && i < 2) {
+ if (i == 1)
+ mxt_debug_msg_enable(data);
+ else
+ mxt_debug_msg_disable(data);
+
+ ret = count;
+ } else {
+ dev_dbg(dev, "debug_enabled write error\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
static ssize_t mxt_debug_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -3622,6 +3800,9 @@ static DEVICE_ATTR(update_cfg, S_IWUSR, NULL, mxt_update_cfg_store);
static DEVICE_ATTR(config_crc, S_IRUGO, mxt_config_crc_show, NULL);
static DEVICE_ATTR(debug_enable, S_IWUSR | S_IRUSR, mxt_debug_enable_show,
mxt_debug_enable_store);
+static DEVICE_ATTR(debug_v2_enable, S_IWUSR | S_IRUSR, NULL,
+ mxt_debug_v2_enable_store);
+static DEVICE_ATTR(debug_notify, S_IRUGO, mxt_debug_notify_show, NULL);
static struct attribute *mxt_attrs[] = {
&dev_attr_fw_version.attr,
@@ -3630,6 +3811,8 @@ static struct attribute *mxt_attrs[] = {
&dev_attr_update_cfg.attr,
&dev_attr_config_crc.attr,
&dev_attr_debug_enable.attr,
+ &dev_attr_debug_v2_enable.attr,
+ &dev_attr_debug_notify.attr,
NULL
};
@@ -3914,6 +4097,7 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
init_completion(&data->chg_completion);
init_completion(&data->reset_completion);
init_completion(&data->crc_completion);
+ mutex_init(&data->debug_msg_lock);
data->suspend_mode = dmi_check_system(chromebook_T9_suspend_dmi) ?
MXT_SUSPEND_T9_CTRL : MXT_SUSPEND_DEEP_SLEEP;
@@ -3976,6 +4160,7 @@ static int mxt_remove(struct i2c_client *client)
disable_irq(data->irq);
sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
+ mxt_debug_msg_remove(data);
mxt_sysfs_remove(data);
mxt_free_input_device(data);
mxt_free_object_table(data);
--
2.19.2
^ permalink raw reply related [flat|nested] 7+ messages in thread