Commit 87447e7a authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] fbdev cursor fix

From: James Simmons <jsimmons@infradead.org>

This patch creates a separate cursor image drawing region and regular drawing
region.
parent 737cff56
...@@ -324,7 +324,7 @@ static void putcs_unaligned(struct vc_data *vc, struct fb_info *info, ...@@ -324,7 +324,7 @@ static void putcs_unaligned(struct vc_data *vc, struct fb_info *info,
unsigned int buf_align = info->pixmap.buf_align - 1; unsigned int buf_align = info->pixmap.buf_align - 1;
unsigned int scan_align = info->pixmap.scan_align - 1; unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int idx = vc->vc_font.width >> 3; unsigned int idx = vc->vc_font.width >> 3;
u8 mask, *src, *dst, *dst0; u8 *src, *dst, *dst0;
while (count) { while (count) {
if (count > maxcnt) if (count > maxcnt)
...@@ -337,15 +337,15 @@ static void putcs_unaligned(struct vc_data *vc, struct fb_info *info, ...@@ -337,15 +337,15 @@ static void putcs_unaligned(struct vc_data *vc, struct fb_info *info,
pitch &= ~scan_align; pitch &= ~scan_align;
size = pitch * vc->vc_font.height + buf_align; size = pitch * vc->vc_font.height + buf_align;
size &= ~buf_align; size &= ~buf_align;
dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size); dst0 = fb_get_buffer_offset(info, &info->pixmap, size);
image->data = dst0; image->data = dst0;
while (k--) { while (k--) {
src = vc->vc_font.data + (scr_readw(s++) & charmask)* src = vc->vc_font.data + (scr_readw(s++) & charmask)*
cellsize; cellsize;
dst = dst0; dst = dst0;
mask = (u8) (0xfff << shift_high); fb_move_buf_unaligned(info, &info->pixmap, dst, pitch, src,
move_buf_unaligned(info, dst, src, pitch, image->height, idx, image->height, shift_high,
mask, shift_high, shift_low, mod, idx); shift_low, mod);
shift_low += mod; shift_low += mod;
dst0 += (shift_low >= 8) ? width : width - 1; dst0 += (shift_low >= 8) ? width : width - 1;
shift_low &= 7; shift_low &= 7;
...@@ -381,12 +381,13 @@ static void putcs_aligned(struct vc_data *vc, struct fb_info *info, ...@@ -381,12 +381,13 @@ static void putcs_aligned(struct vc_data *vc, struct fb_info *info,
size = pitch * vc->vc_font.height + buf_align; size = pitch * vc->vc_font.height + buf_align;
size &= ~buf_align; size &= ~buf_align;
image->width = vc->vc_font.width * cnt; image->width = vc->vc_font.width * cnt;
dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size); dst0 = fb_get_buffer_offset(info, &info->pixmap, size);
image->data = dst0; image->data = dst0;
while (k--) { while (k--) {
src = vc->vc_font.data + (scr_readw(s++)&charmask)*cellsize; src = vc->vc_font.data + (scr_readw(s++)&charmask)*cellsize;
dst = dst0; dst = dst0;
move_buf_aligned(info, dst, src, pitch, width, image->height); fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src,
width, image->height);
dst0 += width; dst0 += width;
} }
info->fbops->fb_imageblit(info, image); info->fbops->fb_imageblit(info, image);
...@@ -455,11 +456,11 @@ static void accel_putc(struct vc_data *vc, struct fb_info *info, ...@@ -455,11 +456,11 @@ static void accel_putc(struct vc_data *vc, struct fb_info *info,
size = pitch * vc->vc_font.height; size = pitch * vc->vc_font.height;
size += buf_align; size += buf_align;
size &= ~buf_align; size &= ~buf_align;
dst = info->pixmap.addr + fb_get_buffer_offset(info, size); dst = fb_get_buffer_offset(info, &info->pixmap, size);
image.data = dst; image.data = dst;
src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width; src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * width;
move_buf_aligned(info, dst, src, pitch, width, image.height); fb_move_buf_aligned(info, &info->pixmap, dst, pitch, src, width, image.height);
info->fbops->fb_imageblit(info, &image); info->fbops->fb_imageblit(info, &image);
} }
......
...@@ -395,7 +395,7 @@ static struct { ...@@ -395,7 +395,7 @@ static struct {
}; };
#define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers)) #define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
#define FBPIXMAPSIZE 8192 #define FBPIXMAPSIZE 16384
extern const char *global_mode_option; extern const char *global_mode_option;
...@@ -412,52 +412,54 @@ static int ofonly __initdata = 0; ...@@ -412,52 +412,54 @@ static int ofonly __initdata = 0;
/* /*
* Drawing helpers. * Drawing helpers.
*/ */
u8 sys_inbuf(u8 *src) u8 sys_inbuf(struct fb_info *info, u8 *src)
{ {
return *src; return *src;
} }
void sys_outbuf(u8 *src, u8 *dst, unsigned int size) void sys_outbuf(struct fb_info *info, u8 *dst, u8 *src, unsigned int size)
{ {
memcpy(dst, src, size); memcpy(dst, src, size);
} }
void move_buf_aligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch, void fb_move_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
u32 s_pitch, u32 height) u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
u32 height)
{ {
int i; int i;
for (i = height; i--; ) { for (i = height; i--; ) {
info->pixmap.outbuf(src, dst, s_pitch); buf->outbuf(info, dst, src, s_pitch);
src += s_pitch; src += s_pitch;
dst += d_pitch; dst += d_pitch;
} }
} }
void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch, void fb_move_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
u32 height, u32 mask, u32 shift_high, u32 shift_low, u8 *dst, u32 d_pitch, u8 *src, u32 idx,
u32 mod, u32 idx) u32 height, u32 shift_high, u32 shift_low,
u32 mod)
{ {
u8 mask = (u8) (0xfff << shift_high), tmp;
int i, j; int i, j;
u8 tmp;
for (i = height; i--; ) { for (i = height; i--; ) {
for (j = 0; j < idx; j++) { for (j = 0; j < idx; j++) {
tmp = info->pixmap.inbuf(dst+j); tmp = buf->inbuf(info, dst+j);
tmp &= mask; tmp &= mask;
tmp |= *src >> shift_low; tmp |= *src >> shift_low;
info->pixmap.outbuf(&tmp, dst+j, 1); buf->outbuf(info, dst+j, &tmp, 1);
tmp = *src << shift_high; tmp = *src << shift_high;
info->pixmap.outbuf(&tmp, dst+j+1, 1); buf->outbuf(info, dst+j+1, &tmp, 1);
src++; src++;
} }
tmp = info->pixmap.inbuf(dst+idx); tmp = buf->inbuf(info, dst+idx);
tmp &= mask; tmp &= mask;
tmp |= *src >> shift_low; tmp |= *src >> shift_low;
info->pixmap.outbuf(&tmp, dst+idx, 1); buf->outbuf(info, dst+idx, &tmp, 1);
if (shift_high < mod) { if (shift_high < mod) {
tmp = *src << shift_high; tmp = *src << shift_high;
info->pixmap.outbuf(&tmp, dst+idx+1, 1); buf->outbuf(info, dst+idx+1, &tmp, 1);
} }
src++; src++;
dst += d_pitch; dst += d_pitch;
...@@ -468,10 +470,10 @@ void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch, ...@@ -468,10 +470,10 @@ void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
* we need to lock this section since fb_cursor * we need to lock this section since fb_cursor
* may use fb_imageblit() * may use fb_imageblit()
*/ */
u32 fb_get_buffer_offset(struct fb_info *info, u32 size) char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
{ {
struct fb_pixmap *buf = &info->pixmap;
u32 align = buf->buf_align - 1, offset; u32 align = buf->buf_align - 1, offset;
char *addr = buf->addr;
/* If IO mapped, we need to sync before access, no sharing of /* If IO mapped, we need to sync before access, no sharing of
* the pixmap is done * the pixmap is done
...@@ -479,7 +481,7 @@ u32 fb_get_buffer_offset(struct fb_info *info, u32 size) ...@@ -479,7 +481,7 @@ u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
if (buf->flags & FB_PIXMAP_IO) { if (buf->flags & FB_PIXMAP_IO) {
if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
info->fbops->fb_sync(info); info->fbops->fb_sync(info);
return 0; return addr;
} }
/* See if we fit in the remaining pixmap space */ /* See if we fit in the remaining pixmap space */
...@@ -495,8 +497,9 @@ u32 fb_get_buffer_offset(struct fb_info *info, u32 size) ...@@ -495,8 +497,9 @@ u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
offset = 0; offset = 0;
} }
buf->offset = offset + size; buf->offset = offset + size;
addr += offset;
return offset; return addr;
} }
#ifdef CONFIG_LOGO #ifdef CONFIG_LOGO
...@@ -869,6 +872,15 @@ static void try_to_load(int fb) ...@@ -869,6 +872,15 @@ static void try_to_load(int fb)
} }
#endif /* CONFIG_KMOD */ #endif /* CONFIG_KMOD */
void
fb_load_cursor_image(struct fb_info *info)
{
unsigned int width = (info->cursor.image.width + 7) >> 3;
u8 *data = (u8 *) info->cursor.image.data;
info->sprite.outbuf(info, info->sprite.addr, data, width);
}
int int
fb_cursor(struct fb_info *info, struct fb_cursor *sprite) fb_cursor(struct fb_info *info, struct fb_cursor *sprite)
{ {
...@@ -1276,6 +1288,21 @@ register_framebuffer(struct fb_info *fb_info) ...@@ -1276,6 +1288,21 @@ register_framebuffer(struct fb_info *fb_info)
if (fb_info->pixmap.inbuf == NULL) if (fb_info->pixmap.inbuf == NULL)
fb_info->pixmap.inbuf = sys_inbuf; fb_info->pixmap.inbuf = sys_inbuf;
if (fb_info->sprite.addr == NULL) {
fb_info->sprite.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
if (fb_info->sprite.addr) {
fb_info->sprite.size = FBPIXMAPSIZE;
fb_info->sprite.buf_align = 1;
fb_info->sprite.scan_align = 1;
fb_info->sprite.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->sprite.offset = 0;
if (fb_info->sprite.outbuf == NULL)
fb_info->sprite.outbuf = sys_outbuf;
if (fb_info->sprite.inbuf == NULL)
fb_info->sprite.inbuf = sys_inbuf;
registered_fb[i] = fb_info; registered_fb[i] = fb_info;
devfs_mk_cdev(MKDEV(FB_MAJOR, i), devfs_mk_cdev(MKDEV(FB_MAJOR, i),
...@@ -1304,8 +1331,10 @@ unregister_framebuffer(struct fb_info *fb_info) ...@@ -1304,8 +1331,10 @@ unregister_framebuffer(struct fb_info *fb_info)
return -EINVAL; return -EINVAL;
devfs_remove("fb/%d", i); devfs_remove("fb/%d", i);
if (fb_info->pixmap.addr) if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
kfree(fb_info->pixmap.addr); kfree(fb_info->pixmap.addr);
if (fb_info->sprite.addr && (fb_info->sprite.flags & FB_PIXMAP_DEFAULT))
kfree(fb_info->sprite.addr);
registered_fb[i]=NULL; registered_fb[i]=NULL;
num_registered_fb--; num_registered_fb--;
return 0; return 0;
...@@ -1460,8 +1489,9 @@ EXPORT_SYMBOL(fb_set_var); ...@@ -1460,8 +1489,9 @@ EXPORT_SYMBOL(fb_set_var);
EXPORT_SYMBOL(fb_blank); EXPORT_SYMBOL(fb_blank);
EXPORT_SYMBOL(fb_pan_display); EXPORT_SYMBOL(fb_pan_display);
EXPORT_SYMBOL(fb_get_buffer_offset); EXPORT_SYMBOL(fb_get_buffer_offset);
EXPORT_SYMBOL(move_buf_unaligned); EXPORT_SYMBOL(fb_move_buf_unaligned);
EXPORT_SYMBOL(move_buf_aligned); EXPORT_SYMBOL(fb_move_buf_aligned);
EXPORT_SYMBOL(fb_load_cursor_image);
EXPORT_SYMBOL(fb_set_suspend); EXPORT_SYMBOL(fb_set_suspend);
EXPORT_SYMBOL(fb_register_client); EXPORT_SYMBOL(fb_register_client);
EXPORT_SYMBOL(fb_unregister_client); EXPORT_SYMBOL(fb_unregister_client);
......
...@@ -1530,9 +1530,9 @@ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor) ...@@ -1530,9 +1530,9 @@ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
break; break;
} }
move_buf_aligned(info, data, src, d_pitch, s_pitch, info->cursor.image.height); fb_move_buf_aligned(info, &info->sprite, data, d_pitch, src, s_pitch, info->cursor.image.height);
move_buf_aligned(info, mask, msk, d_pitch, s_pitch, info->cursor.image.height); fb_move_buf_aligned(info, &info->sprite, mask, d_pitch, msk, s_pitch, info->cursor.image.height);
bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) | bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
((info->cmap.green[bg_idx] & 0xf8) << 2) | ((info->cmap.green[bg_idx] & 0xf8) << 2) |
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
{ {
unsigned int scan_align = info->pixmap.scan_align - 1; unsigned int scan_align = info->sprite.scan_align - 1;
unsigned int buf_align = info->pixmap.buf_align - 1; unsigned int buf_align = info->sprite.buf_align - 1;
unsigned int i, size, dsize, s_pitch, d_pitch; unsigned int i, size, dsize, s_pitch, d_pitch;
u8 *dst, src[64]; u8 *dst, src[64];
...@@ -56,7 +56,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) ...@@ -56,7 +56,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
d_pitch = (s_pitch + scan_align) & ~scan_align; d_pitch = (s_pitch + scan_align) & ~scan_align;
size = d_pitch * info->cursor.image.height + buf_align; size = d_pitch * info->cursor.image.height + buf_align;
size &= ~buf_align; size &= ~buf_align;
dst = info->pixmap.addr + fb_get_buffer_offset(info, size); dst = fb_get_buffer_offset(info, &info->sprite, size);
if (info->cursor.enable) { if (info->cursor.enable) {
switch (info->cursor.rop) { switch (info->cursor.rop) {
...@@ -73,7 +73,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) ...@@ -73,7 +73,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
} else } else
memcpy(src, cursor->image.data, dsize); memcpy(src, cursor->image.data, dsize);
move_buf_aligned(info, dst, src, d_pitch, s_pitch, info->cursor.image.height); fb_move_buf_aligned(info, &info->sprite, dst, d_pitch, src, s_pitch, info->cursor.image.height);
info->cursor.image.data = dst; info->cursor.image.data = dst;
info->fbops->fb_imageblit(info, &info->cursor.image); info->fbops->fb_imageblit(info, &info->cursor.image);
......
...@@ -379,8 +379,8 @@ struct fb_pixmap { ...@@ -379,8 +379,8 @@ struct fb_pixmap {
u32 access_align; /* alignment per read/write */ u32 access_align; /* alignment per read/write */
u32 flags; /* see FB_PIXMAP_* */ u32 flags; /* see FB_PIXMAP_* */
/* access methods */ /* access methods */
void (*outbuf)(u8 *dst, u8 *addr, unsigned int size); void (*outbuf)(struct fb_info *info, u8 *addr, u8 *src, unsigned int size);
u8 (*inbuf) (u8 *addr); u8 (*inbuf) (struct fb_info *info, u8 *addr);
}; };
/* /*
...@@ -394,43 +394,34 @@ struct fb_ops { ...@@ -394,43 +394,34 @@ struct fb_ops {
int (*fb_release)(struct fb_info *info, int user); int (*fb_release)(struct fb_info *info, int user);
/* For framebuffers with strange non linear layouts */ /* For framebuffers with strange non linear layouts */
ssize_t(*fb_read) (struct file * file, char *buf, size_t count, ssize_t (*fb_read)(struct file *file, char *buf, size_t count, loff_t *ppos);
loff_t * ppos); ssize_t (*fb_write)(struct file *file, const char *buf, size_t count, loff_t *ppos);
ssize_t(*fb_write) (struct file * file, const char *buf,
size_t count, loff_t * ppos);
/* checks var and eventually tweaks it to something supported, /* checks var and eventually tweaks it to something supported,
* DO NOT MODIFY PAR */ * DO NOT MODIFY PAR */
int (*fb_check_var) (struct fb_var_screeninfo * var, int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
struct fb_info * info);
/* set the video mode according to info->var */ /* set the video mode according to info->var */
int (*fb_set_par)(struct fb_info *info); int (*fb_set_par)(struct fb_info *info);
/* set color register */ /* set color register */
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, unsigned blue, unsigned transp, struct fb_info *info);
struct fb_info * info);
/* blank display */ /* blank display */
int (*fb_blank)(int blank, struct fb_info *info); int (*fb_blank)(int blank, struct fb_info *info);
/* pan display */ /* pan display */
int (*fb_pan_display) (struct fb_var_screeninfo * var, int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
struct fb_info * info);
/* draws a rectangle */ /* Draws a rectangle */
void (*fb_fillrect) (struct fb_info * info, void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
const struct fb_fillrect * rect);
/* Copy data from area to another */ /* Copy data from area to another */
void (*fb_copyarea) (struct fb_info * info, void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
const struct fb_copyarea * region);
/* Draws a image to the display */ /* Draws a image to the display */
void (*fb_imageblit) (struct fb_info * info, void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
const struct fb_image * image);
/* Draws cursor */ /* Draws cursor */
int (*fb_cursor) (struct fb_info * info, int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
struct fb_cursor * cursor);
/* Rotates the display */ /* Rotates the display */
void (*fb_rotate)(struct fb_info *info, int angle); void (*fb_rotate)(struct fb_info *info, int angle);
...@@ -439,13 +430,11 @@ struct fb_ops { ...@@ -439,13 +430,11 @@ struct fb_ops {
int (*fb_sync)(struct fb_info *info); int (*fb_sync)(struct fb_info *info);
/* perform fb specific ioctl (optional) */ /* perform fb specific ioctl (optional) */
int (*fb_ioctl) (struct inode * inode, struct file * file, int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg, unsigned long arg, struct fb_info *info);
struct fb_info * info);
/* perform fb specific mmap */ /* perform fb specific mmap */
int (*fb_mmap) (struct fb_info * info, struct file * file, int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
struct vm_area_struct * vma);
}; };
struct fb_info { struct fb_info {
...@@ -459,6 +448,7 @@ struct fb_info { ...@@ -459,6 +448,7 @@ struct fb_info {
struct fb_cursor cursor; /* Current cursor */ struct fb_cursor cursor; /* Current cursor */
struct work_struct queue; /* Framebuffer event queue */ struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image Hardware Mapper */ struct fb_pixmap pixmap; /* Image Hardware Mapper */
struct fb_pixmap sprite; /* Cursor hardware Mapper */
struct fb_cmap cmap; /* Current cmap */ struct fb_cmap cmap; /* Current cmap */
struct fb_ops *fbops; struct fb_ops *fbops;
char *screen_base; /* Virtual address */ char *screen_base; /* Virtual address */
...@@ -537,14 +527,16 @@ extern int register_framebuffer(struct fb_info *fb_info); ...@@ -537,14 +527,16 @@ extern int register_framebuffer(struct fb_info *fb_info);
extern int unregister_framebuffer(struct fb_info *fb_info); extern int unregister_framebuffer(struct fb_info *fb_info);
extern int fb_prepare_logo(struct fb_info *fb_info); extern int fb_prepare_logo(struct fb_info *fb_info);
extern int fb_show_logo(struct fb_info *fb_info); extern int fb_show_logo(struct fb_info *fb_info);
extern u32 fb_get_buffer_offset(struct fb_info *info, u32 size); extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
extern void move_buf_unaligned(struct fb_info *info, u8 * dst, u8 * src, extern void fb_move_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
u32 d_pitch, u32 height, u32 mask, u8 *dst, u32 d_pitch, u8 *src, u32 idx,
u32 shift_high, u32 shift_low, u32 mod, u32 height, u32 shift_high, u32 shift_low, u32 mod);
u32 idx); extern void fb_move_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
extern void move_buf_aligned(struct fb_info *info, u8 * dst, u8 * src, u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
u32 d_pitch, u32 s_pitch, u32 height); u32 height);
extern void fb_load_cursor_image(struct fb_info *);
extern void fb_set_suspend(struct fb_info *info, int state); extern void fb_set_suspend(struct fb_info *info, int state);
extern struct fb_info *registered_fb[FB_MAX]; extern struct fb_info *registered_fb[FB_MAX];
extern int num_registered_fb; extern int num_registered_fb;
......
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