linux-old/drivers/video/fbcon-iplan2p2.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/video/fbcon-iplan2p2.c -- Low level frame buffer operations
   3 *                                for interleaved bitplanes à la Atari (2
   4 *                                planes, 2 bytes interleave)
   5 *
   6 *      Created 5 Apr 1997 by Geert Uytterhoeven
   7 *
   8 *  This file is subject to the terms and conditions of the GNU General Public
   9 *  License.  See the file COPYING in the main directory of this archive for
  10 *  more details.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/tty.h>
  15#include <linux/console.h>
  16#include <linux/string.h>
  17#include <linux/fb.h>
  18
  19#include <asm/byteorder.h>
  20
  21#ifdef __mc68000__
  22#include <asm/setup.h>
  23#endif
  24
  25#include <video/fbcon.h>
  26#include <video/fbcon-iplan2p2.h>
  27
  28
  29    /*
  30     *  Interleaved bitplanes à la Atari (2 planes, 2 bytes interleave)
  31     */
  32
  33/* Increment/decrement 2 plane addresses */
  34
  35#define INC_2P(p)       do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0)
  36#define DEC_2P(p)       do { if ((long)(--(p)) & 1) (p) -= 2; } while(0)
  37
  38    /*  Convert a standard 4 bit color to our 2 bit color assignment:
  39     *  If at least two RGB channels are active, the low bit is turned on;
  40     *  The intensity bit (b3) is shifted into b1.
  41     */
  42
  43static const u8 color_2p[] = { 0, 0, 0, 1, 0, 1, 1, 1, 2, 2, 2, 3, 2, 3, 3, 3 };
  44#define COLOR_2P(c)     color_2p[c]
  45
  46/* Perform the m68k movepw operation.  */
  47static inline void movepw(u8 *d, u16 val)
  48{
  49#if defined __mc68000__ && !defined CPU_M68060_ONLY
  50    asm volatile ("movepw %1,%0@(0)" : : "a" (d), "d" (val));
  51#else
  52    d[0] = (val >> 16) & 0xff;
  53    d[2] = val & 0xff;
  54#endif
  55}
  56
  57/* Sets the bytes in the visible column at d, height h, to the value
  58 * val for a 2 plane screen. The bits of the color in 'color' are
  59 * moved (8 times) to the respective bytes. This means:
  60 *
  61 * for(h times; d += bpr)
  62 *   *d     = (color & 1) ? 0xff : 0;
  63 *   *(d+2) = (color & 2) ? 0xff : 0;
  64 */
  65
  66static __inline__ void memclear_2p_col(void *d, size_t h, u16 val, int bpr)
  67{
  68    u8 *dd = d;
  69    do {
  70        movepw(dd, val);
  71        dd += bpr;
  72    } while (--h);
  73}
  74
  75/* Sets a 2 plane region from 'd', length 'count' bytes, to the color
  76 * in val1. 'd' has to be an even address and count must be divisible
  77 * by 8, because only whole words and all planes are accessed. I.e.:
  78 *
  79 * for(count/4 times)
  80 *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
  81 *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
  82 */
  83
  84static __inline__ void memset_even_2p(void *d, size_t count, u32 val)
  85{
  86    u32 *dd = d;
  87
  88    count /= 4;
  89    while (count--)
  90        *dd++ = val;
  91}
  92
  93/* Copies a 2 plane column from 's', height 'h', to 'd'. */
  94
  95static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr)
  96{
  97    u8 *dd = d, *ss = s;
  98
  99    while (h--) {
 100        dd[0] = ss[0];
 101        dd[2] = ss[2];
 102        dd += bpr;
 103        ss += bpr;
 104    }
 105}
 106
 107
 108/* This expands a 2 bit color into a short for movepw (2 plane) operations. */
 109
 110static const u16 two2byte[] = {
 111    0x0000, 0xff00, 0x00ff, 0xffff
 112};
 113
 114static __inline__ u16 expand2w(u8 c)
 115{
 116    return two2byte[c];
 117}
 118
 119
 120/* This expands a 2 bit color into one long for a movel operation
 121 * (2 planes).
 122 */
 123
 124static const u32 two2word[] = {
 125#ifndef __LITTLE_ENDIAN
 126    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
 127#else
 128    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
 129#endif
 130};
 131
 132static __inline__ u32 expand2l(u8 c)
 133{
 134    return two2word[c];
 135}
 136
 137
 138/* This duplicates a byte 2 times into a short. */
 139
 140static __inline__ u16 dup2w(u8 c)
 141{
 142    u16 rv;
 143
 144    rv = c;
 145    rv |= c << 8;
 146    return rv;
 147}
 148
 149
 150void fbcon_iplan2p2_setup(struct display *p)
 151{
 152    p->next_line = p->var.xres_virtual>>2;
 153    p->next_plane = 2;
 154}
 155
 156void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
 157                          int height, int width)
 158{
 159    /*  bmove() has to distinguish two major cases: If both, source and
 160     *  destination, start at even addresses or both are at odd
 161     *  addresses, just the first odd and last even column (if present)
 162     *  require special treatment (memmove_col()). The rest between
 163     *  then can be copied by normal operations, because all adjacent
 164     *  bytes are affected and are to be stored in the same order.
 165     *    The pathological case is when the move should go from an odd
 166     *  address to an even or vice versa. Since the bytes in the plane
 167     *  words must be assembled in new order, it seems wisest to make
 168     *  all movements by memmove_col().
 169     */
 170
 171    if (sx == 0 && dx == 0 && width * 2 == p->next_line) {
 172        /*  Special (but often used) case: Moving whole lines can be
 173         *  done with memmove()
 174         */
 175        fb_memmove(p->screen_base + dy * p->next_line * fontheight(p),
 176                  p->screen_base + sy * p->next_line * fontheight(p),
 177                  p->next_line * height * fontheight(p));
 178    } else {
 179        int rows, cols;
 180        u8 *src;
 181        u8 *dst;
 182        int bytes = p->next_line;
 183        int linesize;
 184        u_int colsize;
 185        u_int upwards  = (dy < sy) || (dy == sy && dx < sx);
 186
 187        if (fontheightlog(p)) {
 188            linesize = bytes << fontheightlog(p);
 189            colsize = height << fontheightlog(p);
 190        } else {
 191            linesize = bytes * fontheight(p);
 192            colsize = height * fontheight(p);
 193        }
 194        if ((sx & 1) == (dx & 1)) {
 195            /* odd->odd or even->even */
 196            if (upwards) {
 197                src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
 198                dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
 199                if (sx & 1) {
 200                    memmove_2p_col(dst, src, colsize, bytes);
 201                    src += 3;
 202                    dst += 3;
 203                    --width;
 204                }
 205                if (width > 1) {
 206                    for (rows = colsize; rows > 0; --rows) {
 207                        fb_memmove(dst, src, (width>>1)*4);
 208                        src += bytes;
 209                        dst += bytes;
 210                    }
 211                }
 212                if (width & 1) {
 213                    src -= colsize * bytes;
 214                    dst -= colsize * bytes;
 215                    memmove_2p_col(dst + (width>>1)*4, src + (width>>1)*4,
 216                                   colsize, bytes);
 217                }
 218            } else {
 219                if (!((sx+width-1) & 1)) {
 220                    src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*4;
 221                    dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*4;
 222                    memmove_2p_col(dst, src, colsize, bytes);
 223                    --width;
 224                }
 225                src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
 226                dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
 227                if (width > 1) {
 228                    src += colsize * bytes + (sx & 1)*3;
 229                    dst += colsize * bytes + (sx & 1)*3;
 230                    for(rows = colsize; rows > 0; --rows) {
 231                        src -= bytes;
 232                        dst -= bytes;
 233                        fb_memmove(dst, src, (width>>1)*4);
 234                    }
 235                }
 236                if (width & 1)
 237                    memmove_2p_col(dst-3, src-3, colsize, bytes);
 238            }
 239        } else {
 240            /* odd->even or even->odd */
 241            if (upwards) {
 242                src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
 243                dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
 244                for (cols = width; cols > 0; --cols) {
 245                    memmove_2p_col(dst, src, colsize, bytes);
 246                    INC_2P(src);
 247                    INC_2P(dst);
 248                }
 249            } else {
 250                sx += width-1;
 251                dx += width-1;
 252                src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
 253                dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
 254                for(cols = width; cols > 0; --cols) {
 255                    memmove_2p_col(dst, src, colsize, bytes);
 256                    DEC_2P(src);
 257                    DEC_2P(dst);
 258                }
 259            }
 260        }
 261    }
 262}
 263
 264void fbcon_iplan2p2_clear(struct vc_data *conp, struct display *p, int sy,
 265                          int sx, int height, int width)
 266{
 267    u32 offset;
 268    u8 *start;
 269    int rows;
 270    int bytes = p->next_line;
 271    int lines;
 272    u32 size;
 273    u32 cval;
 274    u16 pcval;
 275
 276    cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp)));
 277
 278    if (fontheightlog(p))
 279        lines = height << fontheightlog(p);
 280    else
 281        lines = height * fontheight(p);
 282
 283    if (sx == 0 && width * 2 == bytes) {
 284        if (fontheightlog(p))
 285            offset = (sy * bytes) << fontheightlog(p);
 286        else
 287            offset = sy * bytes * fontheight(p);
 288        size = lines * bytes;
 289        memset_even_2p(p->screen_base+offset, size, cval);
 290    } else {
 291        if (fontheightlog(p))
 292            offset = ((sy * bytes) << fontheightlog(p)) + (sx>>1)*4 + (sx & 1);
 293        else
 294            offset = sy * bytes * fontheight(p) + (sx>>1)*4 + (sx & 1);
 295        start = p->screen_base + offset;
 296        pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp)));
 297
 298        /*  Clears are split if the region starts at an odd column or
 299         *  end at an even column. These extra columns are spread
 300         *  across the interleaved planes. All in between can be
 301         *  cleared by normal fb_memclear_small(), because both bytes of
 302         *  the single plane words are affected.
 303         */
 304
 305        if (sx & 1) {
 306            memclear_2p_col(start, lines, pcval, bytes);
 307            start += 3;
 308            width--;
 309        }
 310        if (width & 1) {
 311            memclear_2p_col(start + (width>>1)*4, lines, pcval, bytes);
 312            width--;
 313        }
 314        if (width) {
 315            for (rows = lines; rows-- ; start += bytes)
 316            memset_even_2p(start, width*2, cval);
 317        }
 318    }
 319}
 320
 321void fbcon_iplan2p2_putc(struct vc_data *conp, struct display *p, int c,
 322                         int yy, int xx)
 323{
 324    u8 *dest;
 325    u8 *cdat;
 326    int rows;
 327    int bytes = p->next_line;
 328    u16 eorx, fgx, bgx, fdx;
 329
 330    if (fontheightlog(p)) {
 331        dest = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
 332                (xx>>1)*4 + (xx & 1));
 333        cdat = p->fontdata + ((c & p->charmask) << fontheightlog(p));
 334    } else {
 335        dest = (p->screen_base + yy * bytes * fontheight(p) +
 336                (xx>>1)*4 + (xx & 1));
 337        cdat = p->fontdata + (c & p->charmask) * fontheight(p);
 338    }
 339
 340    fgx = expand2w(COLOR_2P(attr_fgcol(p,c)));
 341    bgx = expand2w(COLOR_2P(attr_bgcol(p,c)));
 342    eorx = fgx ^ bgx;
 343
 344    for (rows = fontheight(p) ; rows-- ; dest += bytes) {
 345        fdx = dup2w(*cdat++);
 346        movepw(dest, (fdx & eorx) ^ bgx);
 347    }
 348}
 349
 350void fbcon_iplan2p2_putcs(struct vc_data *conp, struct display *p,
 351                          const unsigned short *s, int count, int yy, int xx)
 352{
 353    u8 *dest, *dest0;
 354    u8 *cdat;
 355    u16 c;
 356    int rows;
 357    int bytes;
 358    u16 eorx, fgx, bgx, fdx;
 359
 360    bytes = p->next_line;
 361    if (fontheightlog(p))
 362        dest0 = (p->screen_base + ((yy * bytes) << fontheightlog(p)) +
 363                 (xx>>1)*4 + (xx & 1));
 364    else
 365        dest0 = (p->screen_base + yy * bytes * fontheight(p) +
 366                 (xx>>1)*4 + (xx & 1));
 367    c = scr_readw(s);
 368    fgx = expand2w(COLOR_2P(attr_fgcol(p, c)));
 369    bgx = expand2w(COLOR_2P(attr_bgcol(p, c)));
 370    eorx = fgx ^ bgx;
 371
 372    while (count--) {
 373        c = scr_readw(s++) & p->charmask;
 374        if (fontheightlog(p))
 375            cdat = p->fontdata + (c << fontheightlog(p));
 376        else
 377            cdat = p->fontdata + c * fontheight(p);
 378
 379        for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
 380            fdx = dup2w(*cdat++);
 381            movepw(dest, (fdx & eorx) ^ bgx);
 382        }
 383        INC_2P(dest0);
 384    }
 385}
 386
 387void fbcon_iplan2p2_revc(struct display *p, int xx, int yy)
 388{
 389    u8 *dest;
 390    int j;
 391    int bytes;
 392
 393    if (fontheightlog(p))
 394        dest = (p->screen_base + ((yy * p->next_line) << fontheightlog(p)) +
 395                (xx>>1)*4 + (xx & 1));
 396    else
 397        dest = (p->screen_base + yy * p->next_line * fontheight(p) +
 398                (xx>>1)*4 + (xx & 1));
 399    j = fontheight(p);
 400    bytes = p->next_line;
 401    while (j--) {
 402        /*  This should really obey the individual character's
 403         *  background and foreground colors instead of simply
 404         *  inverting.
 405         */
 406        dest[0] = ~dest[0];
 407        dest[2] = ~dest[2];
 408        dest += bytes;
 409    }
 410}
 411
 412void fbcon_iplan2p2_clear_margins(struct vc_data *conp, struct display *p,
 413                                  int bottom_only)
 414{
 415    u32 offset;
 416    int bytes;
 417    int lines;
 418    u32 cval;
 419
 420/* No need to handle right margin, cannot occur with fontwidth == 8 */
 421
 422    bytes = p->next_line;
 423    if (fontheightlog(p)) {
 424        lines = p->var.yres - (conp->vc_rows << fontheightlog(p));
 425        offset = ((p->yscroll + conp->vc_rows) * bytes) << fontheightlog(p);
 426    } else {
 427        lines = p->var.yres - conp->vc_rows * fontheight(p);
 428        offset = (p->yscroll + conp->vc_rows) * bytes * fontheight(p);
 429    }
 430    if (lines) {
 431        cval = expand2l(COLOR_2P(attr_bgcol_ec(p,conp)));
 432        memset_even_2p(p->screen_base+offset, lines * bytes, cval);
 433    }
 434}
 435
 436
 437    /*
 438     *  `switch' for the low level operations
 439     */
 440
 441struct display_switch fbcon_iplan2p2 = {
 442    setup:              fbcon_iplan2p2_setup,
 443    bmove:              fbcon_iplan2p2_bmove,
 444    clear:              fbcon_iplan2p2_clear,
 445    putc:               fbcon_iplan2p2_putc,
 446    putcs:              fbcon_iplan2p2_putcs,
 447    revc:               fbcon_iplan2p2_revc,
 448    clear_margins:      fbcon_iplan2p2_clear_margins,
 449    fontwidthmask:      FONTWIDTH(8)
 450};
 451
 452
 453#ifdef MODULE
 454MODULE_LICENSE("GPL");
 455
 456int init_module(void)
 457{
 458    return 0;
 459}
 460
 461void cleanup_module(void)
 462{}
 463#endif /* MODULE */
 464
 465
 466    /*
 467     *  Visible symbols for modules
 468     */
 469
 470EXPORT_SYMBOL(fbcon_iplan2p2);
 471EXPORT_SYMBOL(fbcon_iplan2p2_setup);
 472EXPORT_SYMBOL(fbcon_iplan2p2_bmove);
 473EXPORT_SYMBOL(fbcon_iplan2p2_clear);
 474EXPORT_SYMBOL(fbcon_iplan2p2_putc);
 475EXPORT_SYMBOL(fbcon_iplan2p2_putcs);
 476EXPORT_SYMBOL(fbcon_iplan2p2_revc);
 477EXPORT_SYMBOL(fbcon_iplan2p2_clear_margins);
 478
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.