@@ -3989,6 +3989,106 @@ static ssize_t touch_dev_stat_show(struct device *dev, struct
return ret;
}
+static ssize_t t38_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ struct mxt_object *object;
+ size_t count = 0, size;
+ u8 i, *t38_buf;
+
+ if (!data->object_table)
+ return -ENXIO;
+
+ object = mxt_get_object(data, MXT_SPT_USERDATA_T38);
+ size = mxt_obj_size(object);
+
+ /* Pre-allocate buffer large enough to hold max size of t38 object.*/
+ t38_buf = kmalloc(size, GFP_KERNEL);
+ if (!t38_buf)
+ return -ENOMEM;
+
+ count = __mxt_read_reg(data->client, object->start_address,
+ size, t38_buf);
+ if (count)
+ goto end;
+
+ for (i = 0; i < size; i++)
+ count += scnprintf(buf + count, PAGE_SIZE - count,
+ "[%2u]: %02x\n", i, t38_buf[i]);
+ count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
+end:
+ kfree(t38_buf);
+ return count;
+}
+
+static ssize_t t38_data_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ struct mxt_object *object;
+ ssize_t ret = 0, pos, offset;
+ unsigned int i, len, index;
+ u8 *t38_buf;
+
+ if (!data->object_table)
+ return -ENXIO;
+
+ object = mxt_get_object(data, MXT_SPT_USERDATA_T38);
+
+ /* Pre-allocate buffer large enough to hold max size of t38 object.*/
+ t38_buf = kmalloc(mxt_obj_size(object), GFP_KERNEL);
+ if (!t38_buf)
+ return -ENOMEM;
+
+ ret = sscanf(buf, "%zd %d%zd", &offset, &len, &pos);
+ if (ret != 2) {
+ dev_err(dev, "Bad format: Invalid parameter to update t38\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (len == 0) {
+ dev_err(dev,
+ "Bad format: Data length should not be equal to 0\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (offset < 0 || ((offset + len) > 64)) {
+ dev_err(dev, "Invalid offset value to update t38\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ index = pos;
+ for (i = 0; i < len; i++) {
+ ret = sscanf(buf + index, "%hhx%zd", t38_buf + i, &pos);
+ if (ret != 1) {
+ dev_err(dev, "Bad format: Invalid Data\n");
+ ret = -EINVAL;
+ goto end;
+ }
+ index += pos;
+ }
+
+ ret = __mxt_write_reg(data->client, object->start_address + offset,
+ len, t38_buf);
+ if (ret)
+ goto end;
+
+ ret = mxt_t6_command(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE,
+ true);
+ if (ret)
+ dev_err(dev, "backup command failed\n");
+ else
+ ret = count;
+end:
+ kfree(t38_buf);
+ return ret;
+}
+
static DEVICE_ATTR_RO(fw_version);
static DEVICE_ATTR_RO(hw_version);
static DEVICE_ATTR_RO(object);
@@ -3999,6 +4099,7 @@ static DEVICE_ATTR_RW(debug_v2_enable);
static DEVICE_ATTR_RO(debug_notify);
static DEVICE_ATTR_RW(t25_selftest);
static DEVICE_ATTR_RO(touch_dev_stat);
+static DEVICE_ATTR_RW(t38_data);
static struct attribute *mxt_attrs[] = {
&dev_attr_fw_version.attr,
@@ -4011,6 +4112,7 @@ static struct attribute *mxt_attrs[] = {
&dev_attr_debug_notify.attr,
&dev_attr_t25_selftest.attr,
&dev_attr_touch_dev_stat.attr,
+ &dev_attr_t38_data.attr,
NULL
};