diff options
| author | Yang <yangxu@codeaurora.org> | 2015-05-05 19:11:20 +0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:41:52 -0700 |
| commit | e1d1320556eb96cb52bc8bf8ec3885e4f0d19842 (patch) | |
| tree | 3ac9fc751dc6ce757f437aa0dae68d25a219836a | |
| parent | 7ebe5976ea1bbdd8f1786dc6114275b8700d442c (diff) | |
msm: mdss: Support reading/writing large length of DSI command
For DSI on/off commands with command length exceeds PAGE_SIZE,
need to support multiple readings to get the complete results.
Change-Id: I372be86b8a40880a36b3dd0be5f761b2f9efb605
Signed-off-by: Yang <yangxu@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 162 |
1 files changed, 104 insertions, 58 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 1c8ebe765a69..32b4604d2783 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -536,8 +536,10 @@ static int mdss_dsi_get_panel_cfg(char *panel_cfg, } struct buf_data { - char *buf; - int blen; + char *buf; /* cmd buf */ + int blen; /* cmd buf length */ + char *string_buf; /* cmd buf as string, 3 bytes per number */ + int sblen; /* string buffer length */ int sync_flag; }; @@ -620,86 +622,129 @@ static int mdss_dsi_cmd_open(struct inode *inode, struct file *file) } static ssize_t mdss_dsi_cmd_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct buf_data *pcmds = file->private_data; - char *buffer, *bp; - int blen = 0, bsize = 0; + char *bp; ssize_t ret = 0; - if (*ppos) - return 0; /* the end */ - - /* - * Max size: - * - 2 digits + ' '/'\n' = 3 bytes per number - * - terminating NUL character - */ - bsize = ((pcmds->blen)*3 + 1); - buffer = kmalloc(bsize, GFP_KERNEL); - if (!buffer) { - pr_err("%s: Failed to allocate memory\n", __func__); - return -ENOMEM; + if (*ppos == 0) { + kfree(pcmds->string_buf); + pcmds->string_buf = NULL; + pcmds->sblen = 0; } - bp = pcmds->buf; - while (blen < bsize-1) { - struct dsi_ctrl_hdr dchdr = *((struct dsi_ctrl_hdr *)bp); - int dhrlen = sizeof(dchdr), dlen; - char *tmp = (char *)(&dchdr); - dlen = dchdr.dlen; - dchdr.dlen = htons(dchdr.dlen); - while (dhrlen--) - blen += snprintf(buffer+blen, bsize-blen, - "%02x ", (*tmp++)); - - bp += sizeof(dchdr); - while (dlen--) - blen += snprintf(buffer+blen, bsize-blen, - "%02x ", (*bp++)); + if (!pcmds->string_buf) { + /* + * Buffer size is the sum of cmd length (3 bytes per number) + * with NULL terminater + */ + int bsize = ((pcmds->blen)*3 + 1); + int blen = 0; + char *buffer; + + buffer = kmalloc(bsize, GFP_KERNEL); + if (!buffer) { + pr_err("%s: Failed to allocate memory\n", __func__); + return -ENOMEM; + } - buffer[blen-1] = '\n'; + bp = pcmds->buf; + while ((blen < (bsize-1)) && + (bp < ((pcmds->buf) + (pcmds->blen)))) { + struct dsi_ctrl_hdr dchdr = + *((struct dsi_ctrl_hdr *)bp); + int dhrlen = sizeof(dchdr), dlen; + char *tmp = (char *)(&dchdr); + dlen = dchdr.dlen; + dchdr.dlen = htons(dchdr.dlen); + while (dhrlen--) + blen += snprintf(buffer+blen, bsize-blen, + "%02x ", (*tmp++)); + + bp += sizeof(dchdr); + while (dlen--) + blen += snprintf(buffer+blen, bsize-blen, + "%02x ", (*bp++)); + buffer[blen-1] = '\n'; + } + buffer[blen] = '\0'; + pcmds->string_buf = buffer; + pcmds->sblen = blen; } - ret = simple_read_from_buffer(buf, count, ppos, buffer, blen); - kfree(buffer); + /* + * The max value of count is PAGE_SIZE(4096). + * It may need multiple times of reading if string buf is too large + */ + if (*ppos >= (pcmds->sblen)) { + kfree(pcmds->string_buf); + pcmds->string_buf = NULL; + pcmds->sblen = 0; + return 0; /* the end */ + } + ret = simple_read_from_buffer(buf, count, ppos, pcmds->string_buf, + pcmds->sblen); return ret; } static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct buf_data *pcmds = file->private_data; - char *input = NULL, *bufp = NULL, *buf = NULL, *bp; - ssize_t res; - int i = 0, blen, len; - struct dsi_ctrl_hdr *dchdr; + ssize_t ret = 0; + int blen = 0; + char *string_buf; - input = kmalloc(count+1, GFP_KERNEL); - if (!input) { + if (*ppos == 0) { + kfree(pcmds->string_buf); + pcmds->string_buf = NULL; + pcmds->sblen = 0; + } + + /* Allocate memory for the received string */ + blen = count + (pcmds->sblen); + string_buf = krealloc(pcmds->string_buf, blen + 1, GFP_KERNEL); + if (!string_buf) { pr_err("%s: Failed to allocate memory\n", __func__); return -ENOMEM; } - res = simple_write_to_buffer(input, count, ppos, p, count); - if (res) - *ppos += res; - input[count] = '\0'; + /* Writing in batches is possible */ + ret = simple_write_to_buffer(string_buf, blen, ppos, p, count); + + string_buf[blen] = '\0'; + pcmds->string_buf = string_buf; + pcmds->sblen = blen; + return ret; +} + +static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id) +{ + struct buf_data *pcmds = file->private_data; + int blen, len, i; + char *buf, *bufp, *bp; + struct dsi_ctrl_hdr *dchdr; + + if (!pcmds->string_buf) + return 0; /* - * - 2 digits + ' '/'\n' = 3 bytes per number - * - terminating NUL character + * Allocate memory for command buffer + * 3 bytes per number, and 2 bytes for the last one */ - blen = count/3; - buf = kzalloc(blen * sizeof(char), GFP_KERNEL); + blen = ((pcmds->sblen) + 2) / 3; + buf = kzalloc(blen, GFP_KERNEL); if (!buf) { pr_err("%s: Failed to allocate memory\n", __func__); - kfree(input); + kfree(pcmds->string_buf); + pcmds->string_buf = NULL; + pcmds->sblen = 0; return -ENOMEM; } - /* translate the input string to command array */ - bufp = input; + /* Translate the input string to command array */ + bufp = pcmds->string_buf; for (i = 0; i < blen; i++) { uint32_t value = 0; int step = 0; @@ -708,9 +753,8 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, bufp += step; } } - kfree(input); - /* scan dcs commands */ + /* Scan dcs commands */ bp = buf; len = blen; while (len >= sizeof(*dchdr)) { @@ -743,14 +787,14 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, pcmds->buf = buf; pcmds->blen = blen; } - - return res; + return 0; } static const struct file_operations mdss_dsi_cmd_fop = { .open = mdss_dsi_cmd_open, .read = mdss_dsi_cmd_read, .write = mdss_dsi_cmd_write, + .flush = mdss_dsi_cmd_flush, }; struct dentry *dsi_debugfs_create_dcs_cmd(const char *name, umode_t mode, @@ -759,6 +803,8 @@ struct dentry *dsi_debugfs_create_dcs_cmd(const char *name, umode_t mode, { cmd->buf = ctrl_cmds.buf; cmd->blen = ctrl_cmds.blen; + cmd->string_buf = NULL; + cmd->sblen = 0; cmd->sync_flag = 1; return debugfs_create_file(name, mode, parent, |
