diff options
Diffstat (limited to 'drivers')
| -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 | ||
