aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorBruno Prémont <bonbons@linux-vserver.org>2010-06-28 16:31:20 -0400
committerJiri Kosina <jkosina@suse.cz>2010-07-12 12:07:35 -0400
commit365f1fcd0d5a40f933bed55e515fce2077c40e9a (patch)
tree9abd7a6a49dc9aabbe507024cb27839c954e939a /drivers/hid
parentb70884ff3a5314c2eb702f85599e722cccdd2f5b (diff)
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: Bruno Prémont <bonbons@linux-vserver.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-picolcd.c27
1 files changed, 12 insertions, 15 deletions
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index dc19501a786f..f7204541591c 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -563,19 +563,18 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i
563static int picolcd_set_par(struct fb_info *info) 563static int picolcd_set_par(struct fb_info *info)
564{ 564{
565 struct picolcd_data *data = info->par; 565 struct picolcd_data *data = info->par;
566 u8 *o_fb, *n_fb; 566 u8 *tmp_fb, *o_fb;
567 if (info->var.bits_per_pixel == data->fb_bpp) 567 if (info->var.bits_per_pixel == data->fb_bpp)
568 return 0; 568 return 0;
569 /* switch between 1/8 bit depths */ 569 /* switch between 1/8 bit depths */
570 if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8) 570 if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
571 return -EINVAL; 571 return -EINVAL;
572 572
573 o_fb = data->fb_bitmap; 573 o_fb = data->fb_bitmap;
574 n_fb = vmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel); 574 tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
575 if (!n_fb) 575 if (!tmp_fb)
576 return -ENOMEM; 576 return -ENOMEM;
577 577
578 fb_deferred_io_cleanup(info);
579 /* translate FB content to new bits-per-pixel */ 578 /* translate FB content to new bits-per-pixel */
580 if (info->var.bits_per_pixel == 1) { 579 if (info->var.bits_per_pixel == 1) {
581 int i, b; 580 int i, b;
@@ -585,24 +584,22 @@ static int picolcd_set_par(struct fb_info *info)
585 p <<= 1; 584 p <<= 1;
586 p |= o_fb[i*8+b] ? 0x01 : 0x00; 585 p |= o_fb[i*8+b] ? 0x01 : 0x00;
587 } 586 }
587 tmp_fb[i] = p;
588 } 588 }
589 memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
589 info->fix.visual = FB_VISUAL_MONO01; 590 info->fix.visual = FB_VISUAL_MONO01;
590 info->fix.line_length = PICOLCDFB_WIDTH / 8; 591 info->fix.line_length = PICOLCDFB_WIDTH / 8;
591 } else { 592 } else {
592 int i; 593 int i;
594 memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
593 for (i = 0; i < PICOLCDFB_SIZE * 8; i++) 595 for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
594 n_fb[i] = o_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00; 596 o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
595 info->fix.visual = FB_VISUAL_TRUECOLOR; 597 info->fix.visual = FB_VISUAL_DIRECTCOLOR;
596 info->fix.line_length = PICOLCDFB_WIDTH; 598 info->fix.line_length = PICOLCDFB_WIDTH;
597 } 599 }
598 600
599 data->fb_bitmap = n_fb; 601 kfree(tmp_fb);
600 data->fb_bpp = info->var.bits_per_pixel; 602 data->fb_bpp = info->var.bits_per_pixel;
601 info->screen_base = (char __force __iomem *)n_fb;
602 info->fix.smem_start = (unsigned long)n_fb;
603 info->fix.smem_len = PICOLCDFB_SIZE*data->fb_bpp;
604 fb_deferred_io_init(info);
605 vfree(o_fb);
606 return 0; 603 return 0;
607} 604}
608 605
@@ -692,7 +689,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
692 u8 *fb_bitmap = NULL; 689 u8 *fb_bitmap = NULL;
693 u32 *palette; 690 u32 *palette;
694 691
695 fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel); 692 fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
696 if (fb_bitmap == NULL) { 693 if (fb_bitmap == NULL) {
697 dev_err(dev, "can't get a free page for framebuffer\n"); 694 dev_err(dev, "can't get a free page for framebuffer\n");
698 goto err_nomem; 695 goto err_nomem;
@@ -728,7 +725,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
728 info->fbops = &picolcdfb_ops; 725 info->fbops = &picolcdfb_ops;
729 info->var = picolcdfb_var; 726 info->var = picolcdfb_var;
730 info->fix = picolcdfb_fix; 727 info->fix = picolcdfb_fix;
731 info->fix.smem_len = PICOLCDFB_SIZE; 728 info->fix.smem_len = PICOLCDFB_SIZE*8;
732 info->fix.smem_start = (unsigned long)fb_bitmap; 729 info->fix.smem_start = (unsigned long)fb_bitmap;
733 info->par = data; 730 info->par = data;
734 info->flags = FBINFO_FLAG_DEFAULT; 731 info->flags = FBINFO_FLAG_DEFAULT;