diff options
author | Bruno Prémont <bonbons@linux-vserver.org> | 2010-06-28 16:30:29 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-07-12 12:07:35 -0400 |
commit | b70884ff3a5314c2eb702f85599e722cccdd2f5b (patch) | |
tree | bc150912d161459336e9811909b7cbed4d4371a9 | |
parent | a7c9a0aa175aee8a66301264bff2a5ff014ca0e7 (diff) |
HID: picolcd: Add minimal palette required by fbcon on 8bpp
Add a minimal palette so fbcon does not try to dereference
a NULL point when fb is set to 8bpp.
fbcon stores pixels the other way around in bytes for 1bpp
than intially implemented, correct this.
Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-picolcd.c | 62 |
1 files changed, 51 insertions, 11 deletions
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 839a5ac0ad82..dc19501a786f 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c | |||
@@ -127,6 +127,26 @@ static const struct fb_var_screeninfo picolcdfb_var = { | |||
127 | .height = 26, | 127 | .height = 26, |
128 | .bits_per_pixel = 1, | 128 | .bits_per_pixel = 1, |
129 | .grayscale = 1, | 129 | .grayscale = 1, |
130 | .red = { | ||
131 | .offset = 0, | ||
132 | .length = 1, | ||
133 | .msb_right = 0, | ||
134 | }, | ||
135 | .green = { | ||
136 | .offset = 0, | ||
137 | .length = 1, | ||
138 | .msb_right = 0, | ||
139 | }, | ||
140 | .blue = { | ||
141 | .offset = 0, | ||
142 | .length = 1, | ||
143 | .msb_right = 0, | ||
144 | }, | ||
145 | .transp = { | ||
146 | .offset = 0, | ||
147 | .length = 0, | ||
148 | .msb_right = 0, | ||
149 | }, | ||
130 | }; | 150 | }; |
131 | #endif /* CONFIG_HID_PICOLCD_FB */ | 151 | #endif /* CONFIG_HID_PICOLCD_FB */ |
132 | 152 | ||
@@ -188,6 +208,7 @@ struct picolcd_data { | |||
188 | /* Framebuffer stuff */ | 208 | /* Framebuffer stuff */ |
189 | u8 fb_update_rate; | 209 | u8 fb_update_rate; |
190 | u8 fb_bpp; | 210 | u8 fb_bpp; |
211 | u8 fb_force; | ||
191 | u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */ | 212 | u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */ |
192 | u8 *fb_bitmap; /* framebuffer */ | 213 | u8 *fb_bitmap; /* framebuffer */ |
193 | struct fb_info *fb_info; | 214 | struct fb_info *fb_info; |
@@ -346,7 +367,7 @@ static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp, | |||
346 | const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32; | 367 | const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32; |
347 | for (i = 0; i < 64; i++) { | 368 | for (i = 0; i < 64; i++) { |
348 | tdata[i] <<= 1; | 369 | tdata[i] <<= 1; |
349 | tdata[i] |= (bdata[i/8] >> (7 - i % 8)) & 0x01; | 370 | tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01; |
350 | } | 371 | } |
351 | } | 372 | } |
352 | } else if (bpp == 8) { | 373 | } else if (bpp == 8) { |
@@ -399,13 +420,10 @@ static int picolcd_fb_reset(struct picolcd_data *data, int clear) | |||
399 | 420 | ||
400 | if (data->fb_bitmap) { | 421 | if (data->fb_bitmap) { |
401 | if (clear) { | 422 | if (clear) { |
402 | memset(data->fb_vbitmap, 0xff, PICOLCDFB_SIZE); | 423 | memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE); |
403 | memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp); | 424 | memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp); |
404 | } else { | ||
405 | /* invert 1 byte in each tile to force resend */ | ||
406 | for (i = 0; i < PICOLCDFB_SIZE; i += 64) | ||
407 | data->fb_vbitmap[i] = ~data->fb_vbitmap[i]; | ||
408 | } | 425 | } |
426 | data->fb_force = 1; | ||
409 | } | 427 | } |
410 | 428 | ||
411 | /* schedule first output of framebuffer */ | 429 | /* schedule first output of framebuffer */ |
@@ -440,7 +458,8 @@ static void picolcd_fb_update(struct picolcd_data *data) | |||
440 | for (chip = 0; chip < 4; chip++) | 458 | for (chip = 0; chip < 4; chip++) |
441 | for (tile = 0; tile < 8; tile++) | 459 | for (tile = 0; tile < 8; tile++) |
442 | if (picolcd_fb_update_tile(data->fb_vbitmap, | 460 | if (picolcd_fb_update_tile(data->fb_vbitmap, |
443 | data->fb_bitmap, data->fb_bpp, chip, tile)) { | 461 | data->fb_bitmap, data->fb_bpp, chip, tile) || |
462 | data->fb_force) { | ||
444 | n += 2; | 463 | n += 2; |
445 | if (n >= HID_OUTPUT_FIFO_SIZE / 2) { | 464 | if (n >= HID_OUTPUT_FIFO_SIZE / 2) { |
446 | usbhid_wait_io(data->hdev); | 465 | usbhid_wait_io(data->hdev); |
@@ -448,6 +467,7 @@ static void picolcd_fb_update(struct picolcd_data *data) | |||
448 | } | 467 | } |
449 | picolcd_fb_send_tile(data->hdev, chip, tile); | 468 | picolcd_fb_send_tile(data->hdev, chip, tile); |
450 | } | 469 | } |
470 | data->fb_force = false; | ||
451 | if (n) | 471 | if (n) |
452 | usbhid_wait_io(data->hdev); | 472 | usbhid_wait_io(data->hdev); |
453 | } | 473 | } |
@@ -526,10 +546,17 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i | |||
526 | /* only allow 1/8 bit depth (8-bit is grayscale) */ | 546 | /* only allow 1/8 bit depth (8-bit is grayscale) */ |
527 | *var = picolcdfb_var; | 547 | *var = picolcdfb_var; |
528 | var->activate = activate; | 548 | var->activate = activate; |
529 | if (bpp >= 8) | 549 | if (bpp >= 8) { |
530 | var->bits_per_pixel = 8; | 550 | var->bits_per_pixel = 8; |
531 | else | 551 | var->red.length = 8; |
552 | var->green.length = 8; | ||
553 | var->blue.length = 8; | ||
554 | } else { | ||
532 | var->bits_per_pixel = 1; | 555 | var->bits_per_pixel = 1; |
556 | var->red.length = 1; | ||
557 | var->green.length = 1; | ||
558 | var->blue.length = 1; | ||
559 | } | ||
533 | return 0; | 560 | return 0; |
534 | } | 561 | } |
535 | 562 | ||
@@ -660,9 +687,10 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) | |||
660 | { | 687 | { |
661 | struct device *dev = &data->hdev->dev; | 688 | struct device *dev = &data->hdev->dev; |
662 | struct fb_info *info = NULL; | 689 | struct fb_info *info = NULL; |
663 | int error = -ENOMEM; | 690 | int i, error = -ENOMEM; |
664 | u8 *fb_vbitmap = NULL; | 691 | u8 *fb_vbitmap = NULL; |
665 | u8 *fb_bitmap = NULL; | 692 | u8 *fb_bitmap = NULL; |
693 | u32 *palette; | ||
666 | 694 | ||
667 | fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel); | 695 | fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel); |
668 | if (fb_bitmap == NULL) { | 696 | if (fb_bitmap == NULL) { |
@@ -678,12 +706,23 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) | |||
678 | 706 | ||
679 | data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; | 707 | data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; |
680 | data->fb_defio = picolcd_fb_defio; | 708 | data->fb_defio = picolcd_fb_defio; |
681 | info = framebuffer_alloc(0, dev); | 709 | /* The extra memory is: |
710 | * - struct picolcd_fb_cleanup_item | ||
711 | * - u32 for ref_count | ||
712 | * - 256*u32 for pseudo_palette | ||
713 | */ | ||
714 | info = framebuffer_alloc(257 * sizeof(u32), dev); | ||
682 | if (info == NULL) { | 715 | if (info == NULL) { |
683 | dev_err(dev, "failed to allocate a framebuffer\n"); | 716 | dev_err(dev, "failed to allocate a framebuffer\n"); |
684 | goto err_nomem; | 717 | goto err_nomem; |
685 | } | 718 | } |
686 | 719 | ||
720 | palette = info->par; | ||
721 | *palette = 1; | ||
722 | palette++; | ||
723 | for (i = 0; i < 256; i++) | ||
724 | palette[i] = i > 0 && i < 16 ? 0xff : 0; | ||
725 | info->pseudo_palette = palette; | ||
687 | info->fbdefio = &data->fb_defio; | 726 | info->fbdefio = &data->fb_defio; |
688 | info->screen_base = (char __force __iomem *)fb_bitmap; | 727 | info->screen_base = (char __force __iomem *)fb_bitmap; |
689 | info->fbops = &picolcdfb_ops; | 728 | info->fbops = &picolcdfb_ops; |
@@ -715,6 +754,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) | |||
715 | goto err_sysfs; | 754 | goto err_sysfs; |
716 | } | 755 | } |
717 | /* schedule first output of framebuffer */ | 756 | /* schedule first output of framebuffer */ |
757 | data->fb_force = 1; | ||
718 | schedule_delayed_work(&info->deferred_work, 0); | 758 | schedule_delayed_work(&info->deferred_work, 0); |
719 | return 0; | 759 | return 0; |
720 | 760 | ||