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>
This commit is contained in:
Bruno Prémont 2010-06-28 22:30:29 +02:00 коммит произвёл Jiri Kosina
Родитель a7c9a0aa17
Коммит b70884ff3a
1 изменённых файлов: 51 добавлений и 11 удалений

Просмотреть файл

@ -127,6 +127,26 @@ static const struct fb_var_screeninfo picolcdfb_var = {
.height = 26, .height = 26,
.bits_per_pixel = 1, .bits_per_pixel = 1,
.grayscale = 1, .grayscale = 1,
.red = {
.offset = 0,
.length = 1,
.msb_right = 0,
},
.green = {
.offset = 0,
.length = 1,
.msb_right = 0,
},
.blue = {
.offset = 0,
.length = 1,
.msb_right = 0,
},
.transp = {
.offset = 0,
.length = 0,
.msb_right = 0,
},
}; };
#endif /* CONFIG_HID_PICOLCD_FB */ #endif /* CONFIG_HID_PICOLCD_FB */
@ -188,6 +208,7 @@ struct picolcd_data {
/* Framebuffer stuff */ /* Framebuffer stuff */
u8 fb_update_rate; u8 fb_update_rate;
u8 fb_bpp; u8 fb_bpp;
u8 fb_force;
u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */ u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */
u8 *fb_bitmap; /* framebuffer */ u8 *fb_bitmap; /* framebuffer */
struct fb_info *fb_info; struct fb_info *fb_info;
@ -346,7 +367,7 @@ static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32; const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
tdata[i] <<= 1; tdata[i] <<= 1;
tdata[i] |= (bdata[i/8] >> (7 - i % 8)) & 0x01; tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
} }
} }
} else if (bpp == 8) { } else if (bpp == 8) {
@ -399,13 +420,10 @@ static int picolcd_fb_reset(struct picolcd_data *data, int clear)
if (data->fb_bitmap) { if (data->fb_bitmap) {
if (clear) { if (clear) {
memset(data->fb_vbitmap, 0xff, PICOLCDFB_SIZE); memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp); memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
} else {
/* invert 1 byte in each tile to force resend */
for (i = 0; i < PICOLCDFB_SIZE; i += 64)
data->fb_vbitmap[i] = ~data->fb_vbitmap[i];
} }
data->fb_force = 1;
} }
/* schedule first output of framebuffer */ /* schedule first output of framebuffer */
@ -440,7 +458,8 @@ static void picolcd_fb_update(struct picolcd_data *data)
for (chip = 0; chip < 4; chip++) for (chip = 0; chip < 4; chip++)
for (tile = 0; tile < 8; tile++) for (tile = 0; tile < 8; tile++)
if (picolcd_fb_update_tile(data->fb_vbitmap, if (picolcd_fb_update_tile(data->fb_vbitmap,
data->fb_bitmap, data->fb_bpp, chip, tile)) { data->fb_bitmap, data->fb_bpp, chip, tile) ||
data->fb_force) {
n += 2; n += 2;
if (n >= HID_OUTPUT_FIFO_SIZE / 2) { if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
usbhid_wait_io(data->hdev); usbhid_wait_io(data->hdev);
@ -448,6 +467,7 @@ static void picolcd_fb_update(struct picolcd_data *data)
} }
picolcd_fb_send_tile(data->hdev, chip, tile); picolcd_fb_send_tile(data->hdev, chip, tile);
} }
data->fb_force = false;
if (n) if (n)
usbhid_wait_io(data->hdev); usbhid_wait_io(data->hdev);
} }
@ -526,10 +546,17 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i
/* only allow 1/8 bit depth (8-bit is grayscale) */ /* only allow 1/8 bit depth (8-bit is grayscale) */
*var = picolcdfb_var; *var = picolcdfb_var;
var->activate = activate; var->activate = activate;
if (bpp >= 8) if (bpp >= 8) {
var->bits_per_pixel = 8; var->bits_per_pixel = 8;
else var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
} else {
var->bits_per_pixel = 1; var->bits_per_pixel = 1;
var->red.length = 1;
var->green.length = 1;
var->blue.length = 1;
}
return 0; return 0;
} }
@ -660,9 +687,10 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
{ {
struct device *dev = &data->hdev->dev; struct device *dev = &data->hdev->dev;
struct fb_info *info = NULL; struct fb_info *info = NULL;
int error = -ENOMEM; int i, error = -ENOMEM;
u8 *fb_vbitmap = NULL; u8 *fb_vbitmap = NULL;
u8 *fb_bitmap = NULL; u8 *fb_bitmap = NULL;
u32 *palette;
fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel); fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel);
if (fb_bitmap == NULL) { if (fb_bitmap == NULL) {
@ -678,12 +706,23 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
data->fb_defio = picolcd_fb_defio; data->fb_defio = picolcd_fb_defio;
info = framebuffer_alloc(0, dev); /* The extra memory is:
* - struct picolcd_fb_cleanup_item
* - u32 for ref_count
* - 256*u32 for pseudo_palette
*/
info = framebuffer_alloc(257 * sizeof(u32), dev);
if (info == NULL) { if (info == NULL) {
dev_err(dev, "failed to allocate a framebuffer\n"); dev_err(dev, "failed to allocate a framebuffer\n");
goto err_nomem; goto err_nomem;
} }
palette = info->par;
*palette = 1;
palette++;
for (i = 0; i < 256; i++)
palette[i] = i > 0 && i < 16 ? 0xff : 0;
info->pseudo_palette = palette;
info->fbdefio = &data->fb_defio; info->fbdefio = &data->fb_defio;
info->screen_base = (char __force __iomem *)fb_bitmap; info->screen_base = (char __force __iomem *)fb_bitmap;
info->fbops = &picolcdfb_ops; info->fbops = &picolcdfb_ops;
@ -715,6 +754,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
goto err_sysfs; goto err_sysfs;
} }
/* schedule first output of framebuffer */ /* schedule first output of framebuffer */
data->fb_force = 1;
schedule_delayed_work(&info->deferred_work, 0); schedule_delayed_work(&info->deferred_work, 0);
return 0; return 0;