Commit 365f1fcd authored by Bruno Prémont's avatar Bruno Prémont Committed by Jiri Kosina

HID: picolcd: do not reallocate memory on depth change

Reallocating memory in depth change does not work well if some
userspace application has mmapped() the framebuffer as that mapping
does not get adjusted (thus application continues to write to old
buffer).
In addition doing deferred_io_cleanup() and init() inside of set_par()
tends to deadlock with fbcon's flashing cursor.

Avoid all this by allocating a buffer that can hold 8bpp framebuffer
and just use 1/8 of it while running at 1bpp.
Signed-off-by: default avatarBruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent b70884ff
...@@ -563,19 +563,18 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i ...@@ -563,19 +563,18 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i
static int picolcd_set_par(struct fb_info *info) static int picolcd_set_par(struct fb_info *info)
{ {
struct picolcd_data *data = info->par; struct picolcd_data *data = info->par;
u8 *o_fb, *n_fb; u8 *tmp_fb, *o_fb;
if (info->var.bits_per_pixel == data->fb_bpp) if (info->var.bits_per_pixel == data->fb_bpp)
return 0; return 0;
/* switch between 1/8 bit depths */ /* switch between 1/8 bit depths */
if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8) if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
return -EINVAL; return -EINVAL;
o_fb = data->fb_bitmap; o_fb = data->fb_bitmap;
n_fb = vmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel); tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
if (!n_fb) if (!tmp_fb)
return -ENOMEM; return -ENOMEM;
fb_deferred_io_cleanup(info);
/* translate FB content to new bits-per-pixel */ /* translate FB content to new bits-per-pixel */
if (info->var.bits_per_pixel == 1) { if (info->var.bits_per_pixel == 1) {
int i, b; int i, b;
...@@ -585,24 +584,22 @@ static int picolcd_set_par(struct fb_info *info) ...@@ -585,24 +584,22 @@ static int picolcd_set_par(struct fb_info *info)
p <<= 1; p <<= 1;
p |= o_fb[i*8+b] ? 0x01 : 0x00; p |= o_fb[i*8+b] ? 0x01 : 0x00;
} }
tmp_fb[i] = p;
} }
memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
info->fix.visual = FB_VISUAL_MONO01; info->fix.visual = FB_VISUAL_MONO01;
info->fix.line_length = PICOLCDFB_WIDTH / 8; info->fix.line_length = PICOLCDFB_WIDTH / 8;
} else { } else {
int i; int i;
memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
for (i = 0; i < PICOLCDFB_SIZE * 8; i++) for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
n_fb[i] = o_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00; o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.visual = FB_VISUAL_DIRECTCOLOR;
info->fix.line_length = PICOLCDFB_WIDTH; info->fix.line_length = PICOLCDFB_WIDTH;
} }
data->fb_bitmap = n_fb; kfree(tmp_fb);
data->fb_bpp = info->var.bits_per_pixel; data->fb_bpp = info->var.bits_per_pixel;
info->screen_base = (char __force __iomem *)n_fb;
info->fix.smem_start = (unsigned long)n_fb;
info->fix.smem_len = PICOLCDFB_SIZE*data->fb_bpp;
fb_deferred_io_init(info);
vfree(o_fb);
return 0; return 0;
} }
...@@ -692,7 +689,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) ...@@ -692,7 +689,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
u8 *fb_bitmap = NULL; u8 *fb_bitmap = NULL;
u32 *palette; u32 *palette;
fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel); fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
if (fb_bitmap == NULL) { if (fb_bitmap == NULL) {
dev_err(dev, "can't get a free page for framebuffer\n"); dev_err(dev, "can't get a free page for framebuffer\n");
goto err_nomem; goto err_nomem;
...@@ -728,7 +725,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) ...@@ -728,7 +725,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
info->fbops = &picolcdfb_ops; info->fbops = &picolcdfb_ops;
info->var = picolcdfb_var; info->var = picolcdfb_var;
info->fix = picolcdfb_fix; info->fix = picolcdfb_fix;
info->fix.smem_len = PICOLCDFB_SIZE; info->fix.smem_len = PICOLCDFB_SIZE*8;
info->fix.smem_start = (unsigned long)fb_bitmap; info->fix.smem_start = (unsigned long)fb_bitmap;
info->par = data; info->par = data;
info->flags = FBINFO_FLAG_DEFAULT; info->flags = FBINFO_FLAG_DEFAULT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment