diff -Naur linux-2.5.61/drivers/video/console/fbcon.c linux/drivers/video/console/fbcon.c --- linux-2.5.61/drivers/video/console/fbcon.c 2003-02-27 09:28:55.000000000 +0000 +++ linux/drivers/video/console/fbcon.c 2003-02-27 11:40:39.000000000 +0000 @@ -134,6 +134,8 @@ static int fbcon_set_origin(struct vc_data *); static int cursor_drawn; +#define FBCON_PIXMAPSIZE 8192 + #define CURSOR_DRAW_DELAY (1) /* # VBL ints between cursor state changes */ @@ -296,8 +298,191 @@ } /* + * drawing helpers + */ +static inline void sysmove_buf_aligned(u8 *dst, u8 *src, u32 d_pitch, + u32 s_pitch, u32 height, + struct fb_info *info) +{ + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < s_pitch; j++) + dst[j] = *src++; + dst += d_pitch; + } +} + +static inline void iomove_buf_aligned(u8 *dst, u8 *src, u32 d_pitch, + u32 s_pitch, u32 height, + struct fb_info *info) +{ + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < s_pitch; j++) + info->pixmap.outbuf(*src++, dst+j); + dst += d_pitch; + } +} + +static inline void sysmove_buf_unaligned(u8 *dst, u8 *src, u32 d_pitch, + u32 height, u32 mask, u32 shift_high, + u32 shift_low, u32 mod, u32 idx, + struct fb_info *info) +{ + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < idx; j++) { + dst[j] &= mask; + dst[j] |= *src >> shift_low; + dst[j+1] = *src << shift_high; + src++; + } + dst[idx] &= mask; + dst[idx] |= *src >> shift_low; + if (shift_high < mod) + dst[idx+1] = *src<pixmap.inbuf(dst+j); + tmp &= mask; + tmp |= *src >> shift_low; + info->pixmap.outbuf(tmp, dst+j); + info->pixmap.outbuf(*src << shift_high, dst+j+1); + src++; + } + tmp = info->pixmap.inbuf(dst+idx); + tmp &= mask; + tmp |= *src >> shift_low; + info->pixmap.outbuf(tmp, dst+idx); + if (shift_high < mod) + info->pixmap.outbuf(*src<vc_font.width + 7)/8; + unsigned int cellsize = vc->vc_font.height * width; + unsigned int maxcnt = info->pixmap.size/cellsize; + unsigned int pitch, cnt, k; + unsigned int shift_low = 0, mod = vc->vc_font.width % 8; + unsigned int shift_high = 8, size; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int idx = vc->vc_font.width/8; + unsigned short charmask = p->charmask; + u8 mask, *src, *dst, *dst0; + void (*move_data)(u8 *dst, u8 *src, u32 d_pitch, u32 height, u32 mask, + u32 shift_high, u32 shift_low, u32 mod, u32 idx, + struct fb_info *info); + + if (info->pixmap.outbuf != NULL) + move_data = iomove_buf_unaligned; + else + move_data = sysmove_buf_unaligned; + + while (count) { + if (count > maxcnt) + cnt = k = maxcnt; + else + cnt = k = count; + + image->width = vc->vc_font.width * cnt; + pitch = (image->width + 7)/8 + scan_align; + pitch &= ~scan_align; + size = pitch * vc->vc_font.height + buf_align; + size &= ~buf_align; + dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size); + image->data = dst0; + while (k--) { + src = p->fontdata + (scr_readw(s++) & charmask)* + cellsize; + dst = dst0; + mask = (u8) (0xfff << shift_high); + move_data(dst, src, pitch, image->height, mask, + shift_high, shift_low, mod, idx, info); + shift_low += mod; + dst0 += (shift_low >= 8) ? width : width - 1; + shift_low &= 7; + shift_high = 8 - shift_low; + } + + info->fbops->fb_imageblit(info, image); + image->dx += cnt * vc->vc_font.width; + count -= cnt; + } +} + +static void putcs_aligned(struct vc_data *vc, struct display *p, + struct fb_info *info, struct fb_image *image, + int count, const unsigned short *s) +{ + unsigned int width = vc->vc_font.width/8; + unsigned int cellsize = vc->vc_font.height * width; + unsigned int maxcnt = info->pixmap.size/cellsize; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int pitch, cnt, size, k; + unsigned short charmask = p->charmask; + void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, u32 d_pitch, + u32 height, struct fb_info *info); + u8 *src, *dst, *dst0; + + if (info->pixmap.outbuf != NULL) + move_data = iomove_buf_aligned; + else + move_data = sysmove_buf_aligned; + + while (count) { + if (count > maxcnt) + cnt = k = maxcnt; + else + cnt = k = count; + pitch = width * cnt + scan_align; + pitch &= ~scan_align; + size = pitch * vc->vc_font.height + buf_align; + size &= ~buf_align; + image->width = vc->vc_font.width * cnt; + dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size); + image->data = dst0; + while (k--) { + src = p->fontdata + (scr_readw(s++) & charmask)* + cellsize; + dst = dst0; + move_data(dst, src, pitch, width, image->height, info); + dst0 += width; + } + + info->fbops->fb_imageblit(info, image); + image->dx += cnt * vc->vc_font.width; + count -= cnt; + } +} + +/* * Accelerated handlers. */ + void accel_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { @@ -331,22 +516,52 @@ info->fbops->fb_fillrect(info, ®ion); } -#define FB_PIXMAPSIZE 8192 -/* - * FIXME: Break up this function, it's becoming too long... - */ -void accel_putcs(struct vc_data *vc, struct display *p, - const unsigned short *s, int count, int yy, int xx) +static void accel_putc(struct vc_data *vc, struct display *p, + int c, int ypos, int xpos) { - static u8 pixmap[FB_PIXMAPSIZE]; struct fb_image image; struct fb_info *info = p->fb_info; unsigned short charmask = p->charmask; - unsigned int width = ((vc->vc_font.width + 7)/8); - unsigned int cellsize = vc->vc_font.height * width; - unsigned int pitch, cnt, i, j, k; - unsigned int maxcnt = FB_PIXMAPSIZE/cellsize; - u8 *src, *dst, *dst0; + unsigned int width = (vc->vc_font.width + 7)/8; + unsigned int size, pitch; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, u32 d_pitch, + u32 height, struct fb_info *info); + u8 *src, *dst; + + if (info->pixmap.outbuf != NULL) + move_data = iomove_buf_aligned; + else + move_data = sysmove_buf_aligned; + + image.dx = xpos * vc->vc_font.width; + image.dy = ypos * vc->vc_font.height; + image.width = vc->vc_font.width; + image.height = vc->vc_font.height; + image.fg_color = attr_fgcol(p, c); + image.bg_color = attr_bgcol(p, c); + image.depth = 0; + + pitch = width + scan_align; + pitch &= ~scan_align; + size = pitch * vc->vc_font.height; + size += buf_align; + size &= ~buf_align; + dst = info->pixmap.addr + fb_get_buffer_offset(info, size); + image.data = dst; + src = p->fontdata + (c & charmask) * vc->vc_font.height * width; + + move_data(dst, src, pitch, width, image.height, info); + + info->fbops->fb_imageblit(info, &image); +} + +void accel_putcs(struct vc_data *vc, struct display *p, + const unsigned short *s, int count, int yy, int xx) +{ + struct fb_info *info = p->fb_info; + struct fb_image image; u16 c = scr_readw(s); image.fg_color = attr_fgcol(p, c); @@ -355,80 +570,11 @@ image.dy = yy * vc->vc_font.height; image.height = vc->vc_font.height; image.depth = 0; - image.data = pixmap; - if (!(vc->vc_font.width & 7)) { - while (count) { - if (count > maxcnt) - cnt = k = maxcnt; - else - cnt = k = count; - - dst0 = pixmap; - pitch = width * cnt; - image.width = vc->vc_font.width * cnt; - while (k--) { - src = p->fontdata + (scr_readw(s++)&charmask)* - cellsize; - dst = dst0; - for (i = image.height; i--; ) { - for (j = 0; j < width; j++) - dst[j] = *src++; - dst += pitch; - } - dst0 += width; - } - - info->fbops->fb_imageblit(info, &image); - image.dx += cnt * vc->vc_font.width; - count -= cnt; - } - - } else { - unsigned int shift_low = 0, mod = vc->vc_font.width % 8; - unsigned int shift_high = 8; - unsigned idx = vc->vc_font.width/8; - u8 mask; - - while (count) { - if (count > maxcnt) - cnt = k = maxcnt; - else - cnt = k = count; - - dst0 = pixmap; - image.width = vc->vc_font.width * cnt; - pitch = (image.width + 7)/8; - while (k--) { - src = p->fontdata + (scr_readw(s++)&charmask)* - cellsize; - dst = dst0; - mask = (u8) (0xfff << shift_high); - for (i = image.height; i--; ) { - for (j = 0; j < idx; j++) { - dst[j] &= mask; - dst[j] |= *src >> shift_low; - dst[j+1] = *src << shift_high; - src++; - } - dst[idx] &= mask; - dst[idx] |= *src >> shift_low; - if (shift_high < mod) - dst[idx+1] = *src << shift_high; - src++; - dst += pitch; - } - shift_low += mod; - dst0 += (shift_low >= 8) ? width : width - 1; - shift_low &= 7; - shift_high = 8 - shift_low; - } - - info->fbops->fb_imageblit(info, &image); - image.dx += cnt * vc->vc_font.width; - count -= cnt; - } - } + if (!(vc->vc_font.width & 7)) + putcs_aligned(vc, p, info, &image, count, s); + else + putcs_unaligned(vc, p, info, &image, count, s); } void accel_clear_margins(struct vc_data *vc, struct display *p, @@ -633,6 +779,18 @@ vc->vc_cols = info->var.xres/vc->vc_font.width; vc->vc_rows = info->var.yres/vc->vc_font.height; + if (info->pixmap.addr == NULL) { + info->pixmap.addr = kmalloc(FBCON_PIXMAPSIZE, GFP_KERNEL); + if (!info->pixmap.addr) + return NULL; + info->pixmap.size = FBCON_PIXMAPSIZE; + info->pixmap.buf_align = 1; + info->pixmap.scan_align = 1; + info->pixmap.flags = FB_PIXMAP_DEFAULT; + } + info->pixmap.offset = 0; + spin_lock_init(&info->pixmap.lock); + /* We trust the mode the driver supplies. */ if (info->fbops->fb_set_par) info->fbops->fb_set_par(info); @@ -1030,10 +1188,6 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) { struct display *p = &fb_display[vc->vc_num]; - struct fb_info *info = p->fb_info; - unsigned short charmask = p->charmask; - unsigned int width = ((vc->vc_font.width + 7) >> 3); - struct fb_image image; int redraw_cursor = 0; if (!p->can_soft_blank && console_blanked) @@ -1047,16 +1201,7 @@ redraw_cursor = 1; } - image.fg_color = attr_fgcol(p, c); - image.bg_color = attr_bgcol(p, c); - image.dx = xpos * vc->vc_font.width; - image.dy = real_y(p, ypos) * vc->vc_font.height; - image.width = vc->vc_font.width; - image.height = vc->vc_font.height; - image.depth = 1; - image.data = p->fontdata + (c & charmask) * vc->vc_font.height * width; - - info->fbops->fb_imageblit(info, &image); + accel_putc(vc, p, c, real_y(p, ypos), xpos); if (redraw_cursor) vbl_cursor_cnt = CURSOR_DRAW_DELAY; diff -Naur linux-2.5.61/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- linux-2.5.61/drivers/video/fbmem.c 2003-02-27 09:28:25.000000000 +0000 +++ linux/drivers/video/fbmem.c 2003-02-27 14:11:03.000000000 +0000 @@ -368,6 +368,31 @@ return n < 0 ? d >> -n : d << n; } +/* + * we need to lock this section since fbcon_cursor + * may use fb_imageblit() + */ +u32 fb_get_buffer_offset(struct fb_info *info, u32 size) +{ + u32 align = info->pixmap.buf_align - 1; + u32 offset; + + spin_lock_irqsave(&info->pixmap.lock, + info->pixmap.lock_flags); + offset = info->pixmap.offset + align; + offset &= ~align; + if (offset + size > info->pixmap.size) { + if (info->fbops->fb_sync && + info->pixmap.flags & FB_PIXMAP_SYNC) + info->fbops->fb_sync(info); + offset = 0; + } + info->pixmap.offset = offset + size; + spin_unlock_irqrestore(&info->pixmap.lock, + info->pixmap.lock_flags); + return offset; +} + #ifdef CONFIG_LOGO #include @@ -1240,5 +1265,6 @@ EXPORT_SYMBOL(fb_set_var); EXPORT_SYMBOL(fb_blank); EXPORT_SYMBOL(fb_pan_display); +EXPORT_SYMBOL(fb_get_buffer_offset); MODULE_LICENSE("GPL"); diff -Naur linux-2.5.61/drivers/video/softcursor.c linux/drivers/video/softcursor.c --- linux-2.5.61/drivers/video/softcursor.c 2002-12-16 02:07:59.000000000 +0000 +++ linux/drivers/video/softcursor.c 2003-02-27 11:40:28.000000000 +0000 @@ -17,30 +17,79 @@ #include #include +static inline void sysmove_buf(u8 *dst, u8 *src, u32 d_pitch, u32 s_pitch, + u32 height, struct fb_info *info) +{ + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < s_pitch; j++) + dst[j] = *src++; + dst += d_pitch; + } +} + +static inline void iomove_buf(u8 *dst, u8 *src, u32 d_pitch, u32 s_pitch, + u32 height, struct fb_info *info) +{ + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < s_pitch; j++) + info->pixmap.outbuf(*src++, dst+j); + dst += d_pitch; + } +} + int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) { - int i, size = ((cursor->image.width + 7) / 8) * cursor->image.height; + static u8 src[64]; struct fb_image image; - static char data[64]; + unsigned int i, size, s_pitch, d_pitch; + unsigned dsize = ((cursor->image.width + 7)/8) * cursor->image.height; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, + u32 d_pitch, u32 height, + struct fb_info *info); + u8 *dst; + + if (info->pixmap.outbuf != NULL) + move_data = iomove_buf; + else + move_data = sysmove_buf; + + s_pitch = (cursor->image.width + 7)/8; + d_pitch = (s_pitch + scan_align) & ~scan_align; + size = d_pitch * cursor->image.height + buf_align; + size &= ~buf_align; + dst = info->pixmap.addr + fb_get_buffer_offset(info, size); + image.data = dst; if (cursor->enable) { switch (cursor->rop) { case ROP_XOR: - for (i = 0; i < size; i++) - data[i] = (cursor->image.data[i] & + for (i = 0; i < dsize; i++) { + src[i] = (cursor->image.data[i] & cursor->mask[i]) ^ - cursor->dest[i]; + cursor->dest[i]; + } break; case ROP_COPY: default: - for (i = 0; i < size; i++) - data[i] = - cursor->image.data[i] & cursor->mask[i]; + for (i = 0; i < dsize; i++) { + src[i] = cursor->image.data[i] & + cursor->mask[i]; + } break; } - } else - memcpy(data, cursor->dest, size); - + move_data(dst, src, d_pitch, s_pitch, cursor->image.height, + info); + } else { + move_data(dst, cursor->dest, s_pitch, d_pitch, + cursor->image.height, info); + } + image.bg_color = cursor->image.bg_color; image.fg_color = cursor->image.fg_color; image.dx = cursor->image.dx; @@ -48,7 +97,6 @@ image.width = cursor->image.width; image.height = cursor->image.height; image.depth = cursor->image.depth; - image.data = data; if (info->fbops->fb_imageblit) info->fbops->fb_imageblit(info, &image); diff -Naur linux-2.5.61/include/linux/fb.h linux/include/linux/fb.h --- linux-2.5.61/include/linux/fb.h 2003-02-27 09:22:20.000000000 +0000 +++ linux/include/linux/fb.h 2003-02-27 11:40:08.000000000 +0000 @@ -325,6 +325,23 @@ struct fb_image image; /* Cursor image */ }; +#define FB_PIXMAP_DEFAULT 1 /* used internally by fbcon */ +#define FB_PIXMAP_SYSTEM 2 /* memory is in system RAM */ +#define FB_PIXMAP_IO 4 /* memory is iomapped */ +#define FB_PIXMAP_SYNC 256 /* set if GPU can DMA */ + +struct fb_pixmap { + __u8 *addr; /* pointer to memory */ + __u32 size; /* size of buffer in bytes */ + __u32 offset; /* current offset to buffer */ + __u32 buf_align; /* byte alignment of each bitmap */ + __u32 scan_align; /* alignment per scanline */ + __u32 flags; /* see FB_PIXMAP_* */ + void (*outbuf)(u8 dst, u8 *addr); /* access methods */ + u8 (*inbuf) (u8 *addr); + unsigned long lock_flags; /* flags for locking */ + spinlock_t lock; /* spinlock */ +}; #ifdef __KERNEL__ #include @@ -390,6 +407,7 @@ struct fb_monspecs monspecs; /* Current Monitor specs */ struct fb_cursor cursor; /* Current cursor */ struct fb_cmap cmap; /* Current cmap */ + struct fb_pixmap pixmap; /* Current pixmap */ struct fb_ops *fbops; char *screen_base; /* Virtual address */ struct vc_data *display_fg; /* Console visible on this display */ @@ -464,6 +482,7 @@ extern int unregister_framebuffer(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 u32 fb_get_buffer_offset(struct fb_info *info, u32 size); extern struct fb_info *registered_fb[FB_MAX]; extern int num_registered_fb;