vc_screen: extract vcs_read_buf
And finally, move the attributes buffer handling to a separate function. Leaving vcs_read quite compact. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20200818085706.12163-14-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
5a52baaab0
Коммит
6a6b76cc44
|
@ -297,14 +297,81 @@ static void vcs_read_buf_noattr(const struct vc_data *vc, char *con_buf,
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int vcs_read_buf(const struct vc_data *vc, char *con_buf,
|
||||
unsigned int pos, unsigned int count, bool viewed,
|
||||
unsigned int *skip)
|
||||
{
|
||||
u16 *org, *con_buf16;
|
||||
unsigned int col, maxcol = vc->vc_cols;
|
||||
unsigned int filled = count;
|
||||
|
||||
if (pos < HEADER_SIZE) {
|
||||
/* clamp header values if they don't fit */
|
||||
con_buf[0] = min(vc->vc_rows, 0xFFu);
|
||||
con_buf[1] = min(vc->vc_cols, 0xFFu);
|
||||
getconsxy(vc, con_buf + 2);
|
||||
|
||||
*skip += pos;
|
||||
count += pos;
|
||||
if (count > CON_BUF_SIZE) {
|
||||
count = CON_BUF_SIZE;
|
||||
filled = count - pos;
|
||||
}
|
||||
|
||||
/* Advance state pointers and move on. */
|
||||
count -= min(HEADER_SIZE, count);
|
||||
pos = HEADER_SIZE;
|
||||
con_buf += HEADER_SIZE;
|
||||
/* If count >= 0, then pos is even... */
|
||||
} else if (pos & 1) {
|
||||
/*
|
||||
* Skip first byte for output if start address is odd. Update
|
||||
* region sizes up/down depending on free space in buffer.
|
||||
*/
|
||||
(*skip)++;
|
||||
if (count < CON_BUF_SIZE)
|
||||
count++;
|
||||
else
|
||||
filled--;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return filled;
|
||||
|
||||
pos -= HEADER_SIZE;
|
||||
pos /= 2;
|
||||
col = pos % maxcol;
|
||||
|
||||
org = screen_pos(vc, pos, viewed);
|
||||
pos += maxcol - col;
|
||||
|
||||
/*
|
||||
* Buffer has even length, so we can always copy character + attribute.
|
||||
* We do not copy last byte to userspace if count is odd.
|
||||
*/
|
||||
count = (count + 1) / 2;
|
||||
con_buf16 = (u16 *)con_buf;
|
||||
|
||||
while (count) {
|
||||
*con_buf16++ = vcs_scr_readw(vc, org++);
|
||||
count--;
|
||||
if (++col == maxcol) {
|
||||
org = screen_pos(vc, pos, viewed);
|
||||
col = 0;
|
||||
pos += maxcol;
|
||||
}
|
||||
}
|
||||
|
||||
return filled;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct vc_data *vc;
|
||||
struct vcs_poll_data *poll;
|
||||
u16 *org;
|
||||
unsigned int read, col, maxcol;
|
||||
unsigned int read;
|
||||
ssize_t ret;
|
||||
char *con_buf;
|
||||
loff_t pos;
|
||||
|
@ -341,8 +408,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||
read = 0;
|
||||
ret = 0;
|
||||
while (count) {
|
||||
char *con_buf0, *con_buf_start;
|
||||
unsigned int this_round, orig_count, p = pos;
|
||||
unsigned int this_round, skip = 0;
|
||||
int size;
|
||||
|
||||
/* Check whether we are above size each round,
|
||||
|
@ -370,9 +436,6 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||
* attempt to move it to userspace.
|
||||
*/
|
||||
|
||||
con_buf_start = con_buf0 = con_buf;
|
||||
orig_count = this_round;
|
||||
maxcol = vc->vc_cols;
|
||||
if (uni_mode) {
|
||||
ret = vcs_read_buf_uni(vc, con_buf, pos, this_round,
|
||||
viewed);
|
||||
|
@ -382,61 +445,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||
vcs_read_buf_noattr(vc, con_buf, pos, this_round,
|
||||
viewed);
|
||||
} else {
|
||||
if (p < HEADER_SIZE) {
|
||||
/* clamp header values if they don't fit */
|
||||
con_buf0[0] = min(vc->vc_rows, 0xFFu);
|
||||
con_buf0[1] = min(vc->vc_cols, 0xFFu);
|
||||
getconsxy(vc, con_buf0 + 2);
|
||||
|
||||
con_buf_start += p;
|
||||
this_round += p;
|
||||
if (this_round > CON_BUF_SIZE) {
|
||||
this_round = CON_BUF_SIZE;
|
||||
orig_count = this_round - p;
|
||||
}
|
||||
|
||||
/* Advance state pointers and move on. */
|
||||
this_round -= min(HEADER_SIZE, this_round);
|
||||
p = HEADER_SIZE;
|
||||
con_buf0 = con_buf + HEADER_SIZE;
|
||||
/* If this_round >= 0, then p is even... */
|
||||
} else if (p & 1) {
|
||||
/* Skip first byte for output if start address is odd
|
||||
* Update region sizes up/down depending on free
|
||||
* space in buffer.
|
||||
*/
|
||||
con_buf_start++;
|
||||
if (this_round < CON_BUF_SIZE)
|
||||
this_round++;
|
||||
else
|
||||
orig_count--;
|
||||
}
|
||||
if (this_round > 0) {
|
||||
unsigned short *tmp_buf = (unsigned short *)con_buf0;
|
||||
|
||||
p -= HEADER_SIZE;
|
||||
p /= 2;
|
||||
col = p % maxcol;
|
||||
|
||||
org = screen_pos(vc, p, viewed);
|
||||
p += maxcol - col;
|
||||
|
||||
/* Buffer has even length, so we can always copy
|
||||
* character + attribute. We do not copy last byte
|
||||
* to userspace if this_round is odd.
|
||||
*/
|
||||
this_round = (this_round + 1) >> 1;
|
||||
|
||||
while (this_round) {
|
||||
*tmp_buf++ = vcs_scr_readw(vc, org++);
|
||||
this_round --;
|
||||
if (++col == maxcol) {
|
||||
org = screen_pos(vc, p, viewed);
|
||||
col = 0;
|
||||
p += maxcol;
|
||||
}
|
||||
}
|
||||
}
|
||||
this_round = vcs_read_buf(vc, con_buf, pos, this_round,
|
||||
viewed, &skip);
|
||||
}
|
||||
|
||||
/* Finally, release the console semaphore while we push
|
||||
|
@ -447,18 +457,18 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
|||
*/
|
||||
|
||||
console_unlock();
|
||||
ret = copy_to_user(buf, con_buf_start, orig_count);
|
||||
ret = copy_to_user(buf, con_buf + skip, this_round);
|
||||
console_lock();
|
||||
|
||||
if (ret) {
|
||||
read += (orig_count - ret);
|
||||
read += this_round - ret;
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
buf += orig_count;
|
||||
pos += orig_count;
|
||||
read += orig_count;
|
||||
count -= orig_count;
|
||||
buf += this_round;
|
||||
pos += this_round;
|
||||
read += this_round;
|
||||
count -= this_round;
|
||||
}
|
||||
*ppos += read;
|
||||
if (read)
|
||||
|
|
Загрузка…
Ссылка в новой задаче