Skip to content

Commit

Permalink
Input: atmel_mxt_ts - implement improved debug message interface
Browse files Browse the repository at this point in the history
Signed-off-by: Nick Dyer <[email protected]>
  • Loading branch information
ndyer committed Apr 26, 2016
1 parent 80731e9 commit 078569c
Showing 1 changed file with 180 additions and 0 deletions.
180 changes: 180 additions & 0 deletions drivers/input/touchscreen/atmel_mxt_ts.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ enum t100_type {

#define MXT_PIXELS_PER_MM 20

#define DEBUG_MSG_MAX 200

struct mxt_info {
u8 family_id;
u8 variant_id;
Expand Down Expand Up @@ -285,6 +287,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;
Expand Down Expand Up @@ -397,6 +404,136 @@ 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)
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;

data->debug_v2_enabled = false;

mutex_lock(&data->debug_msg_lock);
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) {
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_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf, loff_t off,
size_t count)
{
return -EIO;
}

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 int mxt_debug_msg_init(struct mxt_data *data)
{
sysfs_bin_attr_init(&data->debug_msg_attr);
data->debug_msg_attr.attr.name = "debug_msg";
data->debug_msg_attr.attr.mode = 0666;
data->debug_msg_attr.read = mxt_debug_msg_read;
data->debug_msg_attr.write = mxt_debug_msg_write;
data->debug_msg_attr.size = data->T5_msg_size * DEBUG_MSG_MAX;

if (sysfs_create_bin_file(&data->client->dev.kobj,
&data->debug_msg_attr) < 0) {
dev_err(&data->client->dev, "Failed to create %s\n",
data->debug_msg_attr.attr.name);
return -EINVAL;
}

return 0;
}

static void mxt_debug_msg_remove(struct mxt_data *data)
{
if (data->debug_msg_attr.attr.name)
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)
Expand Down Expand Up @@ -1188,6 +1325,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;
}

Expand Down Expand Up @@ -2570,6 +2710,10 @@ static int mxt_initialize(struct mxt_data *data)
if (error)
goto err_free_object_table;

error = mxt_debug_msg_init(data);
if (error)
goto err_free_object_table;

if (data->cfg_name) {
error = request_firmware_nowait(THIS_MODULE, true,
data->cfg_name, &data->client->dev,
Expand Down Expand Up @@ -2819,6 +2963,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);
Expand Down Expand Up @@ -3005,6 +3150,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)
{
Expand Down Expand Up @@ -3093,6 +3266,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,
Expand All @@ -3101,6 +3277,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
};

Expand Down Expand Up @@ -3526,6 +3704,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);

if (pdata->suspend_mode == MXT_SUSPEND_REGULATOR) {
error = mxt_acquire_irq(data);
Expand Down Expand Up @@ -3565,6 +3744,7 @@ static int mxt_remove(struct i2c_client *client)
struct mxt_data *data = i2c_get_clientdata(client);

sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
mxt_debug_msg_remove(data);
mxt_sysfs_remove(data);

if (data->irq)
Expand Down

0 comments on commit 078569c

Please sign in to comment.