1/* 2 * linux/drivers/video/afb.c -- Low level frame buffer operations for 3 * 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-afb.h> 20 21 22 /* 23 * Bitplanes � la Amiga 24 */ 25 26static u8 expand_table[1024] = { 27 /* bg = fg = 0 */ 28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 /* bg = 0, fg = 1 */ 61 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 62 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 63 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 64 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 65 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 66 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 67 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 68 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 69 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 70 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 71 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 72 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 73 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 74 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 75 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 76 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 77 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 78 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 79 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 80 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 81 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 82 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 83 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 84 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 85 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 86 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 87 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 88 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 89 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 90 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 91 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 92 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 93 /* bg = 1, fg = 0 */ 94 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 95 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, 96 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8, 97 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 98 0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8, 99 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0, 100 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8, 101 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 102 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, 103 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 104 0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8, 105 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0, 106 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 107 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 108 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 109 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 110 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 111 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 112 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 113 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 114 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 115 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 116 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 117 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 118 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 119 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 120 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 121 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 122 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 123 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 124 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 125 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 126 /* bg = fg = 1 */ 127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 136 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 137 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 138 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 139 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 140 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 141 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 142 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 143 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 144 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 145 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 146 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 147 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 148 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 149 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 152 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 153 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 155 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 158 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 159}; 160 161void fbcon_afb_setup(struct display *p) 162{ 163 if (p->line_length) 164 p->next_line = p->line_length; 165 else 166 p->next_line = p->var.xres_virtual>>3; 167 p->next_plane = p->var.yres_virtual*p->next_line; 168} 169 170void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx, 171 int height, int width) 172{ 173 u8 *src, *dest, *src0, *dest0; 174 u_short i, j; 175 176 if (sx == 0 && dx == 0 && width == p->next_line) { 177 src = p->screen_base+sy*fontheight(p)*width; 178 dest = p->screen_base+dy*fontheight(p)*width; 179 i = p->var.bits_per_pixel; 180 do { 181 fb_memmove(dest, src, height*fontheight(p)*width); 182 src += p->next_plane; 183 dest += p->next_plane; 184 } while (--i); 185 } else if (dy <= sy) { 186 src0 = p->screen_base+sy*fontheight(p)*p->next_line+sx; 187 dest0 = p->screen_base+dy*fontheight(p)*p->next_line+dx; 188 i = p->var.bits_per_pixel; 189 do { 190 src = src0; 191 dest = dest0; 192 j = height*fontheight(p); 193 do { 194 fb_memmove(dest, src, width); 195 src += p->next_line; 196 dest += p->next_line; 197 } while (--j); 198 src0 += p->next_plane; 199 dest0 += p->next_plane; 200 } while (--i); 201 } else { 202 src0 = p->screen_base+(sy+height)*fontheight(p)*p->next_line+sx; 203 dest0 = p->screen_base+(dy+height)*fontheight(p)*p->next_line+dx; 204 i = p->var.bits_per_pixel; 205 do { 206 src = src0; 207 dest = dest0; 208 j = height*fontheight(p); 209 do { 210 src -= p->next_line; 211 dest -= p->next_line; 212 fb_memmove(dest, src, width); 213 } while (--j); 214 src0 += p->next_plane; 215 dest0 += p->next_plane; 216 } while (--i); 217 } 218} 219 220void fbcon_afb_clear(struct vc_data *conp, struct display *p, int sy, int sx, 221 int height, int width) 222{ 223 u8 *dest, *dest0; 224 u_short i, j; 225 int bg; 226 227 dest0 = p->screen_base+sy*fontheight(p)*p->next_line+sx; 228 229 bg = attr_bgcol_ec(p,conp); 230 i = p->var.bits_per_pixel; 231 do { 232 dest = dest0; 233 j = height*fontheight(p); 234 do { 235 if (bg & 1) 236 fb_memset255(dest, width); 237 else 238 fb_memclear(dest, width); 239 dest += p->next_line; 240 } while (--j); 241 bg >>= 1; 242 dest0 += p->next_plane; 243 } while (--i); 244} 245 246void fbcon_afb_putc(struct vc_data *conp, struct display *p, int c, int yy, 247 int xx) 248{ 249 u8 *dest, *dest0, *cdat, *cdat0, *expand; 250 u_short i, j; 251 int fg, bg; 252 253 dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; 254 cdat0 = p->fontdata+(c&p->charmask)*fontheight(p); 255 fg = attr_fgcol(p,c); 256 bg = attr_bgcol(p,c); 257 258 i = p->var.bits_per_pixel; 259 do { 260 dest = dest0; 261 cdat = cdat0; 262 expand = expand_table; 263 if (bg & 1) 264 expand += 512; 265 if (fg & 1) 266 expand += 256; 267 j = fontheight(p); 268 do { 269 *dest = expand[*cdat++]; 270 dest += p->next_line; 271 } while (--j); 272 bg >>= 1; 273 fg >>= 1; 274 dest0 += p->next_plane; 275 } while (--i); 276} 277 278 /* 279 * I've split the console character loop in two parts 280 * (cfr. fbcon_putcs_ilbm()) 281 */ 282 283void fbcon_afb_putcs(struct vc_data *conp, struct display *p, 284 const unsigned short *s, int count, int yy, int xx) 285{ 286 u8 *dest, *dest0, *dest1, *expand; 287 u8 *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40; 288 u_short i, j; 289 u16 c1, c2, c3, c4; 290 int fg0, bg0, fg, bg; 291 292 dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; 293 c1 = scr_readw(s); 294 fg0 = attr_fgcol(p, c1); 295 bg0 = attr_bgcol(p, c1); 296 297 while (count--) 298 if (xx&3 || count < 3) { /* Slow version */ 299 c1 = scr_readw(s++) & p->charmask; 300 dest1 = dest0++; 301 xx++; 302 303 cdat10 = p->fontdata+c1*fontheight(p); 304 fg = fg0; 305 bg = bg0; 306 307 i = p->var.bits_per_pixel; 308 do { 309 dest = dest1; 310 cdat1 = cdat10; 311 expand = expand_table; 312 if (bg & 1) 313 expand += 512; 314 if (fg & 1) 315 expand += 256; 316 j = fontheight(p); 317 do { 318 *dest = expand[*cdat1++]; 319 dest += p->next_line; 320 } while (--j); 321 bg >>= 1; 322 fg >>= 1; 323 dest1 += p->next_plane; 324 } while (--i); 325 } else { /* Fast version */ 326 c1 = scr_readw(&s[0]) & p->charmask; 327 c2 = scr_readw(&s[1]) & p->charmask; 328 c3 = scr_readw(&s[2]) & p->charmask; 329 c4 = scr_readw(&s[3]) & p->charmask; 330 331 dest1 = dest0; 332 cdat10 = p->fontdata+c1*fontheight(p); 333 cdat20 = p->fontdata+c2*fontheight(p); 334 cdat30 = p->fontdata+c3*fontheight(p); 335 cdat40 = p->fontdata+c4*fontheight(p); 336 fg = fg0; 337 bg = bg0; 338 339 i = p->var.bits_per_pixel; 340 do { 341 dest = dest1; 342 cdat1 = cdat10; 343 cdat2 = cdat20; 344 cdat3 = cdat30; 345 cdat4 = cdat40; 346 expand = expand_table; 347 if (bg & 1) 348 expand += 512; 349 if (fg & 1) 350 expand += 256; 351 j = fontheight(p); 352 do { 353#if defined(__BIG_ENDIAN) 354 *(u32 *)dest = expand[*cdat1++]<<24 | 355 expand[*cdat2++]<<16 | 356 expand[*cdat3++]<<8 | 357 expand[*cdat4++]; 358#elif defined(__LITTLE_ENDIAN) 359 *(u32 *)dest = expand[*cdat1++] | 360 expand[*cdat2++]<<8 | 361 expand[*cdat3++]<<16 | 362 expand[*cdat4++]<<24; 363#else 364#error FIXME: No endianness?? 365#endif 366 dest += p->next_line; 367 } while (--j); 368 bg >>= 1; 369 fg >>= 1; 370 dest1 += p->next_plane; 371 } while (--i); 372 s += 4; 373 dest0 += 4; 374 xx += 4; 375 count -= 3; 376 } 377} 378 379void fbcon_afb_revc(struct display *p, int xx, int yy) 380{ 381 u8 *dest, *dest0; 382 u_short i, j; 383 int mask; 384 385 dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; 386 mask = p->fgcol ^ p->bgcol; 387 388 /* 389 * This should really obey the individual character's 390 * background and foreground colors instead of simply 391 * inverting. 392 */ 393 394 i = p->var.bits_per_pixel; 395 do { 396 if (mask & 1) { 397 dest = dest0; 398 j = fontheight(p); 399 do { 400 *dest = ~*dest; 401 dest += p->next_line; 402 } while (--j); 403 } 404 mask >>= 1; 405 dest0 += p->next_plane; 406 } while (--i); 407} 408 409 410 /* 411 * `switch' for the low level operations 412 */ 413 414struct display_switch fbcon_afb = { 415 setup: fbcon_afb_setup, 416 bmove: fbcon_afb_bmove, 417 clear: fbcon_afb_clear, 418 putc: fbcon_afb_putc, 419 putcs: fbcon_afb_putcs, 420 revc: fbcon_afb_revc, 421 fontwidthmask: FONTWIDTH(8) 422}; 423 424 425#ifdef MODULE 426MODULE_LICENSE("GPL"); 427 428int init_module(void) 429{ 430 return 0; 431} 432 433void cleanup_module(void) 434{} 435#endif /* MODULE */ 436 437 438 /* 439 * Visible symbols for modules 440 */ 441 442EXPORT_SYMBOL(fbcon_afb); 443EXPORT_SYMBOL(fbcon_afb_setup); 444EXPORT_SYMBOL(fbcon_afb_bmove); 445EXPORT_SYMBOL(fbcon_afb_clear); 446EXPORT_SYMBOL(fbcon_afb_putc); 447EXPORT_SYMBOL(fbcon_afb_putcs); 448EXPORT_SYMBOL(fbcon_afb_revc); 449