1/* 2 * linux/drivers/video/ilbm.c -- Low level frame buffer operations for 3 * interleaved bitplanes � la Amiga 4 * 5 * Created 5 Apr 1997 by Geert Uytterhoeven 6 * 7 * This file is subject to the terms and conditions of the GNU General Public 8 * License. See the file COPYING in the main directory of this archive for 9 * more details. 10 */ 11 12#include <linux/module.h> 13#include <linux/tty.h> 14#include <linux/console.h> 15#include <linux/string.h> 16#include <linux/fb.h> 17 18#include <video/fbcon.h> 19#include <video/fbcon-ilbm.h> 20 21 22 /* 23 * Interleaved bitplanes � la Amiga 24 * 25 * This code heavily relies on the fact that 26 * 27 * next_line == interleave == next_plane*bits_per_pixel 28 * 29 * But maybe it can be merged with the code for normal bitplanes without 30 * much performance loss? 31 */ 32 33void fbcon_ilbm_setup(struct display *p) 34{ 35 if (p->line_length) { 36 p->next_line = p->line_length*p->var.bits_per_pixel; 37 p->next_plane = p->line_length; 38 } else { 39 p->next_line = p->type_aux; 40 p->next_plane = p->type_aux/p->var.bits_per_pixel; 41 } 42} 43 44void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx, 45 int height, int width) 46{ 47 if (sx == 0 && dx == 0 && width == p->next_plane) 48 fb_memmove(p->screen_base+dy*fontheight(p)*p->next_line, 49 p->screen_base+sy*fontheight(p)*p->next_line, 50 height*fontheight(p)*p->next_line); 51 else { 52 u8 *src, *dest; 53 u_int i; 54 55 if (dy <= sy) { 56 src = p->screen_base+sy*fontheight(p)*p->next_line+sx; 57 dest = p->screen_base+dy*fontheight(p)*p->next_line+dx; 58 for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) { 59 fb_memmove(dest, src, width); 60 src += p->next_plane; 61 dest += p->next_plane; 62 } 63 } else { 64 src = p->screen_base+(sy+height)*fontheight(p)*p->next_line+sx; 65 dest = p->screen_base+(dy+height)*fontheight(p)*p->next_line+dx; 66 for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) { 67 src -= p->next_plane; 68 dest -= p->next_plane; 69 fb_memmove(dest, src, width); 70 } 71 } 72 } 73} 74 75void fbcon_ilbm_clear(struct vc_data *conp, struct display *p, int sy, int sx, 76 int height, int width) 77{ 78 u8 *dest; 79 u_int i, rows; 80 int bg, bg0; 81 82 dest = p->screen_base+sy*fontheight(p)*p->next_line+sx; 83 84 bg0 = attr_bgcol_ec(p,conp); 85 for (rows = height*fontheight(p); rows--;) { 86 bg = bg0; 87 for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { 88 if (bg & 1) 89 fb_memset255(dest, width); 90 else 91 fb_memclear(dest, width); 92 bg >>= 1; 93 } 94 } 95} 96 97void fbcon_ilbm_putc(struct vc_data *conp, struct display *p, int c, int yy, 98 int xx) 99{ 100 u8 *dest, *cdat; 101 u_int rows, i; 102 u8 d; 103 int fg0, bg0, fg, bg; 104 105 dest = p->screen_base+yy*fontheight(p)*p->next_line+xx; 106 cdat = p->fontdata+(c&p->charmask)*fontheight(p); 107 fg0 = attr_fgcol(p,c); 108 bg0 = attr_bgcol(p,c); 109 110 for (rows = fontheight(p); rows--;) { 111 d = *cdat++; 112 fg = fg0; 113 bg = bg0; 114 for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { 115 if (bg & 1){ 116 if (fg & 1) 117 *dest = 0xff; 118 else 119 *dest = ~d; 120 }else{ 121 if (fg & 1) 122 *dest = d; 123 else 124 *dest = 0x00; 125 } 126 bg >>= 1; 127 fg >>= 1; 128 } 129 } 130} 131 132 /* 133 * I've split the console character loop in two parts: 134 * 135 * - slow version: this blits one character at a time 136 * 137 * - fast version: this blits 4 characters at a time at a longword 138 * aligned address, to reduce the number of expensive 139 * Chip RAM accesses. 140 * 141 * Experiments on my A4000/040 revealed that this makes a console switch 142 * on a 640x400 screen with 256 colors about 3 times faster. 143 * 144 * -- Geert 145 */ 146 147void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, 148 const unsigned short *s, int count, int yy, int xx) 149{ 150 u8 *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4; 151 u_int rows, i; 152 u16 c1, c2, c3, c4; 153 u32 d; 154 int fg0, bg0, fg, bg; 155 156 dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; 157 c1 = scr_readw(s); 158 fg0 = attr_fgcol(p, c1); 159 bg0 = attr_bgcol(p, c1); 160 161 while (count--) 162 if (xx&3 || count < 3) { /* Slow version */ 163 c1 = scr_readw(s++) & p->charmask; 164 dest = dest0++; 165 xx++; 166 167 cdat1 = p->fontdata+c1*fontheight(p); 168 for (rows = fontheight(p); rows--;) { 169 d = *cdat1++; 170 fg = fg0; 171 bg = bg0; 172 for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { 173 if (bg & 1){ 174 if (fg & 1) 175 *dest = 0xff; 176 else 177 *dest = ~d; 178 }else{ 179 if (fg & 1) 180 *dest = d; 181 else 182 *dest = 0x00; 183 } 184 bg >>= 1; 185 fg >>= 1; 186 } 187 } 188 } else { /* Fast version */ 189 c1 = scr_readw(&s[0]) & p->charmask; 190 c2 = scr_readw(&s[1]) & p->charmask; 191 c3 = scr_readw(&s[2]) & p->charmask; 192 c4 = scr_readw(&s[3]) & p->charmask; 193 194 dest = dest0; 195 cdat1 = p->fontdata+c1*fontheight(p); 196 cdat2 = p->fontdata+c2*fontheight(p); 197 cdat3 = p->fontdata+c3*fontheight(p); 198 cdat4 = p->fontdata+c4*fontheight(p); 199 for (rows = fontheight(p); rows--;) { 200#if defined(__BIG_ENDIAN) 201 d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++; 202#elif defined(__LITTLE_ENDIAN) 203 d = *cdat1++ | *cdat2++<<8 | *cdat3++<<16 | *cdat4++<<24; 204#else 205#error FIXME: No endianness?? 206#endif 207 fg = fg0; 208 bg = bg0; 209 for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { 210 if (bg & 1){ 211 if (fg & 1) 212 *(u32 *)dest = 0xffffffff; 213 else 214 *(u32 *)dest = ~d; 215 }else{ 216 if (fg & 1) 217 *(u32 *)dest = d; 218 else 219 *(u32 *)dest = 0x00000000; 220 } 221 bg >>= 1; 222 fg >>= 1; 223 } 224 } 225 s += 4; 226 dest0 += 4; 227 xx += 4; 228 count -= 3; 229 } 230} 231 232void fbcon_ilbm_revc(struct display *p, int xx, int yy) 233{ 234 u8 *dest, *dest0; 235 u_int rows, i; 236 int mask; 237 238 dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; 239 mask = p->fgcol ^ p->bgcol; 240 241 /* 242 * This should really obey the individual character's 243 * background and foreground colors instead of simply 244 * inverting. 245 */ 246 247 for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { 248 if (mask & 1) { 249 dest = dest0; 250 for (rows = fontheight(p); rows--; dest += p->next_line) 251 *dest = ~*dest; 252 } 253 mask >>= 1; 254 } 255} 256 257 258 /* 259 * `switch' for the low level operations 260 */ 261 262struct display_switch fbcon_ilbm = { 263 setup: fbcon_ilbm_setup, 264 bmove: fbcon_ilbm_bmove, 265 clear: fbcon_ilbm_clear, 266 putc: fbcon_ilbm_putc, 267 putcs: fbcon_ilbm_putcs, 268 revc: fbcon_ilbm_revc, 269 fontwidthmask: FONTWIDTH(8) 270}; 271 272 273#ifdef MODULE 274MODULE_LICENSE("GPL"); 275 276int init_module(void) 277{ 278 return 0; 279} 280 281void cleanup_module(void) 282{} 283#endif /* MODULE */ 284 285 286 /* 287 * Visible symbols for modules 288 */ 289 290EXPORT_SYMBOL(fbcon_ilbm); 291EXPORT_SYMBOL(fbcon_ilbm_setup); 292EXPORT_SYMBOL(fbcon_ilbm_bmove); 293EXPORT_SYMBOL(fbcon_ilbm_clear); 294EXPORT_SYMBOL(fbcon_ilbm_putc); 295EXPORT_SYMBOL(fbcon_ilbm_putcs); 296EXPORT_SYMBOL(fbcon_ilbm_revc); 297