root/arch/m68k/console/fbcon.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CURSOR_UNDRAWN
  2. fbcon_startup
  3. fbcon_init
  4. fbcon_deinit
  5. fbcon_changevar
  6. fbcon_setup
  7. mymemclear_small
  8. mymemclear
  9. mymemset
  10. mymemmove
  11. fast_memmove
  12. memclear_4p_col
  13. memset_even_4p
  14. memmove_4p_col
  15. expand4l
  16. expand4dl
  17. dup4l
  18. memclear_8p_col
  19. memset_even_8p
  20. memmove_8p_col
  21. expand8dl
  22. memclear_2p_col
  23. memset_even_2p
  24. memmove_2p_col
  25. expand2w
  26. expand2l
  27. dup2w
  28. real_y
  29. fbcon_clear
  30. fbcon_putc
  31. fbcon_putcs
  32. fbcon_cursor
  33. fbcon_vbl_handler
  34. fbcon_scroll
  35. fbcon_bmove
  36. fbcon_bmove_rec
  37. fbcon_switch
  38. fbcon_blank
  39. fbcon_get_font
  40. fbcon_set_font
  41. bmove_mono
  42. clear_mono
  43. putc_mono
  44. putcs_mono
  45. rev_char_mono
  46. bmove_ilbm
  47. clear_ilbm
  48. putc_ilbm
  49. putcs_ilbm
  50. rev_char_ilbm
  51. bmove_plan
  52. clear_plan
  53. putc_plan
  54. putcs_plan
  55. rev_char_plan
  56. bmove_2_plane
  57. clear_2_plane
  58. putc_2_plane
  59. putcs_2_plane
  60. rev_char_2_plane
  61. bmove_4_plane
  62. clear_4_plane
  63. putc_4_plane
  64. putcs_4_plane
  65. rev_char_4_plane
  66. bmove_8_plane
  67. clear_8_plane
  68. putc_8_plane
  69. putcs_8_plane
  70. rev_char_8_plane
  71. bmove_8_packed
  72. clear_8_packed
  73. putc_8_packed
  74. putcs_8_packed
  75. rev_char_8_packed
  76. bmove_16_packed
  77. clear_16_packed
  78. putc_16_packed
  79. putcs_16_packed
  80. rev_char_16_packed
  81. bmove_cyber
  82. clear_cyber
  83. putc_cyber
  84. putcs_cyber
  85. rev_char_cyber

   1 /*
   2  * linux/arch/m68k/console/fbcon.c -- Low level frame buffer based console
   3  *                                    driver
   4  *
   5  *    Copyright (C) 1995 Geert Uytterhoeven
   6  *
   7  *
   8  * This file is based on the original Amiga console driver (amicon.c):
   9  *
  10  *    Copyright (C) 1993 Hamish Macdonald
  11  *                       Greg Harp
  12  *    Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
  13  *
  14  *          with work by William Rucklidge (wjr@cs.cornell.edu)
  15  *                       Geert Uytterhoeven
  16  *                       Jes Sorensen (jds@kom.auc.dk)
  17  *                       Martin Apel
  18  *
  19  * and on the original Atari console driver (atacon.c):
  20  *
  21  *    Copyright (C) 1993 Bjoern Brauel
  22  *                       Roman Hodek
  23  *
  24  *          with work by Guenther Kelleter
  25  *                       Martin Schaller
  26  *                       Andreas Schwab
  27  *
  28  *
  29  * This file is subject to the terms and conditions of the GNU General Public
  30  * License.  See the file README.legal in the main directory of this archive
  31  * for more details.
  32  */
  33 
  34 /*
  35  * To do:
  36  *  - Implement 16 plane mode.
  37  *  - Add support for 16/24/32 bit packed pixels
  38  *  - Hardware cursor
  39  */
  40 
  41 
  42 #include <linux/types.h>
  43 #include <linux/fs.h>
  44 #include <linux/kernel.h>
  45 #include <linux/tty.h>
  46 #include <linux/console.h>
  47 #include <linux/string.h>
  48 #include <linux/config.h>
  49 #include <linux/kd.h>
  50 #include <linux/malloc.h>
  51 
  52 #include <asm/bootinfo.h>
  53 #include <asm/irq.h>
  54 #ifdef CONFIG_AMIGA
  55 #include <asm/amigahw.h>
  56 #include <asm/amigaints.h>
  57 #endif /* CONFIG_AMIGA */
  58 #ifdef CONFIG_ATARI
  59 #include <asm/atariints.h>
  60 #endif
  61 #ifdef CONFIG_FB_CYBER
  62 #include "../amiga/s3blit.h"
  63 #endif /* CONFIG_FB_CYBER */
  64 #include <linux/fb.h>
  65 #include <asm/font.h>
  66 #include <asm/machdep.h>
  67 
  68 #include <asm/system.h>
  69 
  70 #include "../../../drivers/char/vt_kern.h"   /* vt_cons and vc_resize_con() */
  71 
  72 
  73 /* Import console_blanked from console.c */
  74 
  75 extern int console_blanked;
  76 
  77 
  78    /*
  79     *    The following symbols select what modes are supported. They should
  80     *    be settable by the user ("make config") later.
  81     */
  82 
  83 /* Clear all definitions */
  84 
  85 #undef CONFIG_FBCON_MONO
  86 #undef CONFIG_FBCON_ILBM
  87 #undef CONFIG_FBCON_PLANES
  88 #undef CONFIG_FBCON_2PLANE
  89 #undef CONFIG_FBCON_4PLANE
  90 #undef CONFIG_FBCON_8PLANE
  91 #undef CONFIG_FBCON_8PACKED
  92 #undef CONFIG_FBCON_16PACKED
  93 #undef CONFIG_FBCON_24PACKED
  94 #undef CONFIG_FBCON_32PACKED
  95 #undef CONFIG_FBCON_CYBER
  96 
  97 
  98 /* Monochrome is default */
  99 
 100 #define CONFIG_FBCON_MONO
 101 
 102 /* Amiga support */
 103 
 104 #ifdef CONFIG_AMIGA
 105 #ifndef CONFIG_FBCON_ILBM
 106 #define CONFIG_FBCON_ILBM
 107 #endif
 108 #ifndef CONFIG_FBCON_PLANES
 109 #define CONFIG_FBCON_PLANES
 110 #endif
 111 
 112 /* Cybervision Graphics Board */
 113 
 114 #ifdef CONFIG_FB_CYBER
 115 #ifndef CONFIG_FBCON_CYBER
 116 #define CONFIG_FBCON_CYBER
 117 #endif
 118 #endif /* CONFIG_FB_CYBER */
 119 
 120 #endif /* CONFIG_AMIGA */
 121 
 122 /* Atari support */
 123 
 124 #ifdef CONFIG_ATARI
 125 #ifndef CONFIG_FBCON_2PLANE
 126 #define CONFIG_FBCON_2PLANE
 127 #endif
 128 #ifndef CONFIG_FBCON_4PLANE
 129 #define CONFIG_FBCON_4PLANE
 130 #endif
 131 #ifndef CONFIG_FBCON_8PLANE
 132 #define CONFIG_FBCON_8PLANE
 133 #endif
 134 #ifndef CONFIG_FBCON_8PACKED
 135 #define CONFIG_FBCON_8PACKED
 136 #endif
 137 #ifndef CONFIG_FBCON_16PACKED
 138 #define CONFIG_FBCON_16PACKED
 139 #endif
 140 #endif /* CONFIG_ATARI */
 141 
 142 
 143 /* Extra definitions to make the code more readable */
 144 
 145 #if defined(CONFIG_FBCON_2PLANE) || defined(CONFIG_FBCON_4PLANE) || \
 146     defined(CONFIG_FBCON_8PLANE)
 147 #define CONFIG_FBCON_IPLAN2
 148 #else
 149 #undef CONFIG_FBCON_IPLAN2
 150 #endif
 151 
 152 #if defined(CONFIG_FBCON_CYBER) || defined(CONFIG_FBCON_8PACKED) || \
 153     defined(CONFIG_FBCON_16PACKED) || defined(CONFIG_FBCON_24PACKED) || \
 154     defined(CONFIG_FBCON_32PACKED)
 155 #define CONFIG_FBCON_PACKED
 156 #else
 157 #undef CONFIG_FBCON_PACKED
 158 #endif
 159 
 160 
 161 struct fb_info *fb_info;
 162 struct display *disp;
 163 
 164 
 165 /* ++Geert: Sorry, no hardware cursor support at the moment;
 166    use Atari alike software cursor */
 167 
 168 static int cursor_drawn = 0;
 169 
 170 #define CURSOR_DRAW_DELAY           (2)
 171 
 172 /* # VBL ints between cursor state changes */
 173 #define AMIGA_CURSOR_BLINK_RATE   (20)
 174 #define ATARI_CURSOR_BLINK_RATE   (42)
 175 
 176 static int vbl_cursor_cnt = 0;
 177 static int cursor_on = 0;
 178 static int cursor_blink_rate;
 179 
 180 static __inline__ int CURSOR_UNDRAWN(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182    int cursor_was_drawn;
 183    vbl_cursor_cnt = 0;
 184    cursor_was_drawn = cursor_drawn;
 185    cursor_drawn = 0;
 186    return(cursor_was_drawn);
 187 }
 188 
 189    /*
 190     *    Attribute Decoding
 191     */
 192 
 193 /* Color */
 194 #define attr_fgcol(p,conp)    \
 195         (((conp)->vc_attr >> ((p)->inverse ? 4 : 0)) & 0x0f)
 196 #define attr_bgcol(p,conp)    \
 197         (((conp)->vc_attr >> ((p)->inverse ? 0 : 4)) & 0x0f)
 198 #define attr_bgcol_ec(p,conp) \
 199         (((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f)
 200 
 201 /* Monochrome */
 202 #define attr_bold(p,conp)     \
 203         (((conp)->vc_attr & 3) == 2)
 204 #define attr_reverse(p,conp)  \
 205         (((conp)->vc_attr & 8) ^ ((p)->inverse ? 8 : 0))
 206 #define attr_underline(p,conp) \
 207         (((conp)->vc_attr) & 4)
 208 
 209 
 210    /*
 211     *    Scroll Method
 212     */
 213 
 214 #define SCROLL_YWRAP          (0)
 215 #define SCROLL_YPAN           (1)
 216 #define SCROLL_YMOVE          (2)
 217 
 218 #define divides(a, b)         ((!(a) || (b)%(a)) ? 0 : 1)
 219 
 220 
 221    /*
 222     *    Interface used by the world
 223     */
 224 
 225 static u_long fbcon_startup(u_long kmem_start, char **display_desc);
 226 static void fbcon_init(struct vc_data *conp);
 227 static int fbcon_deinit(struct vc_data *conp);
 228 static int fbcon_changevar(int con);
 229 static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
 230                        int width);
 231 static int fbcon_putc(struct vc_data *conp, int c, int y, int x);
 232 static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y,
 233                        int x);
 234 static int fbcon_cursor(struct vc_data *conp, int mode);
 235 static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count);
 236 static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
 237                        int height, int width);
 238 static int fbcon_switch(struct vc_data *conp);
 239 static int fbcon_blank(int blank);
 240 
 241 
 242    /*
 243     *    Internal routines
 244     */
 245 
 246 static void fbcon_setup(int con, int setcol, int cls);
 247 static __inline__ void *mymemclear_small(void *s, size_t count);
 248 static __inline__ void *mymemclear(void *s, size_t count);
 249 static __inline__ void *mymemset(void *s, size_t count);
 250 static __inline__ void *mymemmove(void *d, void *s, size_t count);
 251 static __inline__ void fast_memmove(char *dst, char *src, size_t size);
 252 static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr);
 253 static __inline__ void memset_even_4p(void *d, size_t count, u_long val1,
 254                                       u_long val2);
 255 static __inline__ void memmove_4p_col(void *d, void *s, int h, int bpr);
 256 static __inline__ u_long expand4l(u_char c);
 257 static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2);
 258 static __inline__ u_long dup4l(u_char c);
 259 static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1,
 260                                        u_long val2, int bpr);
 261 static __inline__ void memset_even_8p(void *d, size_t count, u_long val1,
 262                                       u_long val2, u_long val3, u_long val4);
 263 static __inline__ void memmove_8p_col(void *d, void *s, int h, int bpr);
 264 static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2);
 265 static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr);
 266 static __inline__ void memset_even_2p(void *d, size_t count, u_long val);
 267 static __inline__ void memmove_2p_col(void *d, void *s, int h, int bpr);
 268 static __inline__ u_short expand2w(u_char c);
 269 static __inline__ u_long expand2l(u_char c);
 270 static __inline__ u_short dup2w(u_char c);
 271 static __inline__ int real_y(struct display *p, int y);
 272 static void fbcon_vbl_handler(int irq, struct pt_regs *fp, void *dummy);
 273 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
 274                             int height, int width, u_int y_break);
 275 
 276 
 277    /*
 278     *    Monochrome
 279     */
 280 
 281 #ifdef CONFIG_FBCON_MONO
 282 static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx,
 283                        int height, int width);
 284 static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx,
 285                        int height, int width);
 286 static void putc_mono(struct vc_data *conp, struct display *p, int c, int y,
 287                       int x);
 288 static void putcs_mono(struct vc_data *conp, struct display *p, const char *s,
 289                        int count, int y, int x);
 290 static void rev_char_mono(struct display *p, int x, int y);
 291 #endif /* CONFIG_FBCON_MONO */
 292 
 293 
 294    /*
 295     *    Color Interleaved Planes
 296     */
 297 
 298 #ifdef CONFIG_FBCON_ILBM
 299 static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
 300                        int height, int width);
 301 static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
 302                        int height, int width);
 303 static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y,
 304                       int x);
 305 static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
 306                        int count, int y, int x);
 307 static void rev_char_ilbm(struct display *p, int x, int y);
 308 #endif /* CONFIG_FBCON_ILBM */
 309 
 310 
 311    /*
 312     *    Color Planes
 313     */
 314 
 315 #ifdef CONFIG_FBCON_PLANES
 316 static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx,
 317                        int height, int width);
 318 static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx,
 319                        int height, int width);
 320 static void putc_plan(struct vc_data *conp, struct display *p, int c, int y,
 321                       int x);
 322 static void putcs_plan(struct vc_data *conp, struct display *p, const char *s,
 323                        int count, int y, int x);
 324 static void rev_char_plan(struct display *p, int x, int y);
 325 #endif /* CONFIG_FBCON_PLANES */
 326 
 327 
 328    /*
 329     *    2 Planes (2-bytes interleave)
 330     */
 331 
 332 #ifdef CONFIG_FBCON_2PLANE
 333 static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx,
 334                           int height, int width);
 335 static void clear_2_plane(struct vc_data *conp, struct display *p, int sy,
 336                           int sx, int height, int width);
 337 static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int y,
 338                          int x);
 339 static void putcs_2_plane(struct vc_data *conp, struct display *p,
 340                           const char *s, int count, int y, int x);
 341 static void rev_char_2_plane(struct display *display, int x, int y);
 342 #endif /* CONFIG_FBCON_2PLANE */
 343 
 344 
 345    /*
 346     *    4 Planes (2-bytes interleave)
 347     */
 348 
 349 #ifdef CONFIG_FBCON_4PLANE
 350 static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx,
 351                           int height, int width);
 352 static void clear_4_plane(struct vc_data *conp, struct display *p, int sy,
 353                           int sx, int height, int width);
 354 static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int y,
 355                          int x);
 356 static void putcs_4_plane(struct vc_data *conp, struct display *p,
 357                           const char *s, int count, int y, int x);
 358 static void rev_char_4_plane(struct display *p, int x, int y);
 359 #endif /* CONFIG_FBCON_4PLANE */
 360 
 361 
 362    /*
 363     *    8 Planes (2-bytes interleave)
 364     */
 365 
 366 #ifdef CONFIG_FBCON_8PLANE
 367 static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx,
 368                           int height, int width);
 369 static void clear_8_plane(struct vc_data *conp, struct display *p, int sy,
 370                           int sx, int height, int width);
 371 static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int y,
 372                          int x);
 373 static void putcs_8_plane(struct vc_data *conp, struct display *p,
 374                           const char *s, int count, int y, int x);
 375 static void rev_char_8_plane(struct display *display, int x, int y);
 376 #endif /* CONFIG_FBCON_8PLANE */
 377 
 378 
 379    /*
 380     *    8 bpp Packed Pixels
 381     */
 382 
 383 #ifdef CONFIG_FBCON_8PACKED
 384 static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx,
 385                            int height, int width);
 386 static void clear_8_packed(struct vc_data *conp, struct display *p, int sy,
 387                            int sx, int height, int width);
 388 static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int y,
 389                           int x);
 390 static void putcs_8_packed(struct vc_data *conp, struct display *p,
 391                            const char *s, int count, int y, int x);
 392 static void rev_char_8_packed(struct display *p, int x, int y);
 393 #endif /* CONFIG_FBCON_8PACKED */
 394 
 395 
 396    /*
 397     *    16 bpp Packed Pixels
 398     */
 399 
 400 #ifdef CONFIG_FBCON_16PACKED
 401 static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx,
 402                             int height, int width);
 403 static void clear_16_packed(struct vc_data *conp, struct display *p, int sy,
 404                             int sx, int height, int width);
 405 static void putc_16_packed(struct vc_data *conp, struct display *p, int c,
 406                            int y, int x);
 407 static void putcs_16_packed(struct vc_data *conp, struct display *p,
 408                             const char *s, int count, int y, int x);
 409 static void rev_char_16_packed(struct display *p, int x, int y);
 410 #endif */ CONFIG_FBCON_8PACKED */
 411 
 412 
 413    /*
 414     *    Cybervision (accelerated)
 415     */
 416 
 417 #ifdef CONFIG_FBCON_CYBER
 418 static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx,
 419                         int height, int width);
 420 static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx,
 421                         int height, int width);
 422 static void putc_cyber(struct vc_data *conp, struct display *p, int c, int y,
 423                        int x);
 424 static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
 425                         int count, int y, int x);
 426 static void rev_char_cyber(struct display *p, int x, int y);
 427 
 428 extern void Cyber_WaitQueue(u_short fifo);
 429 extern void Cyber_WaitBlit(void);
 430 extern void Cyber_BitBLT(u_short curx, u_short cury, u_short destx,
 431                          u_short desty, u_short width, u_short height,
 432                          u_short mode);
 433 extern void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
 434                            u_short mode, u_short color);
 435 extern void Cyber_MoveCursor(u_short x, u_short y);
 436 #endif /* CONFIG_FBCON_CYBER */
 437 
 438 
 439    /*
 440     *    `switch' for the Low Level Operations
 441     */
 442 
 443 struct display_switch {
 444     void (*bmove)(struct display *p, int sy, int sx, int dy, int dx, int height,
 445                   int width);
 446     void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx,
 447                   int height, int width);
 448     void (*putc)(struct vc_data *conp, struct display *p, int c, int y, int x);
 449     void (*putcs)(struct vc_data *conp, struct display *p, const char *s,
 450                   int count, int y, int x);
 451     void (*rev_char)(struct display *p, int x, int y);
 452 };
 453 
 454 
 455 #ifdef CONFIG_FBCON_MONO
 456 struct display_switch dispsw_mono = {
 457    bmove_mono, clear_mono, putc_mono, putcs_mono, rev_char_mono
 458 };
 459 #endif /* CONFIG_FBCON_MONO */
 460 
 461 #ifdef CONFIG_FBCON_ILBM
 462 struct display_switch dispsw_ilbm = {
 463    bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm, rev_char_ilbm
 464 };
 465 #endif /* CONFIG_FBCON_ILBM */
 466 
 467 #ifdef CONFIG_FBCON_PLANES
 468 struct display_switch dispsw_plan = {
 469    bmove_plan, clear_plan, putc_plan, putcs_plan, rev_char_plan
 470 };
 471 #endif /* CONFIG_FBCON_PLANES */
 472 
 473 #ifdef CONFIG_FBCON_2PLANE
 474 struct display_switch dispsw_2_plane = {
 475    bmove_2_plane, clear_2_plane, putc_2_plane, putcs_2_plane, rev_char_2_plane
 476 };
 477 #endif /* CONFIG_FBCON_2PLANE */
 478 
 479 #ifdef CONFIG_FBCON_4PLANE
 480 struct display_switch dispsw_4_plane = {
 481    bmove_4_plane, clear_4_plane, putc_4_plane, putcs_4_plane, rev_char_4_plane
 482 };
 483 #endif /* CONFIG_FBCON_4PLANE */
 484 
 485 #ifdef CONFIG_FBCON_8PLANE
 486 struct display_switch dispsw_8_plane = {
 487    bmove_8_plane, clear_8_plane, putc_8_plane, putcs_8_plane, rev_char_8_plane
 488 };
 489 #endif /* CONFIG_FBCON_8PLANE */
 490 
 491 #ifdef CONFIG_FBCON_8PACKED
 492 struct display_switch dispsw_8_packed = {
 493    bmove_8_packed, clear_8_packed, putc_8_packed, putcs_8_packed, rev_char_8_packed
 494 };
 495 #endif /* CONFIG_FBCON_8PACKED */
 496 
 497 #ifdef CONFIG_FBCON_16PACKED
 498 struct display_switch dispsw_16_packed = {
 499    bmove_16_packed, clear_16_packed, putc_16_packed, putcs_16_packed,
 500    rev_char_16_packed
 501 };
 502 #endif /* CONFIG_FBCON_16PACKED */
 503 
 504 #ifdef CONFIG_FBCON_CYBER
 505 struct display_switch dispsw_cyber = {
 506    bmove_cyber, clear_cyber, putc_cyber, putcs_cyber, rev_char_cyber
 507 };
 508 #endif /* CONFIG_FBCON_CYBER */
 509 
 510 
 511 static u_long fbcon_startup(u_long kmem_start, char **display_desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 512 {
 513    int irqres = 0;
 514 
 515    fb_info = mach_fb_init(&kmem_start);
 516    disp = fb_info->disp;
 517    *display_desc = fb_info->modename;
 518    fb_info->changevar = &fbcon_changevar;
 519 
 520 #ifdef CONFIG_AMIGA
 521    if (MACH_IS_AMIGA) {
 522       cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE;
 523       irqres = add_isr(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0, NULL,
 524                        "console/cursor");
 525    }
 526 #endif /* CONFIG_AMIGA */
 527 #ifdef CONFIG_ATARI
 528    if (MACH_IS_ATARI) {
 529       cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
 530       irqres = add_isr(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO, NULL,
 531                        "console/cursor");
 532    }
 533 #endif /* CONFIG_ATARI */
 534 
 535    if (!irqres)
 536       panic("fbcon_startup: Couldn't add vblank interrupt");
 537 
 538    return(kmem_start);
 539 }
 540 
 541 
 542 static void fbcon_init(struct vc_data *conp)
     /* [previous][next][first][last][top][bottom][index][help] */
 543 {
 544    int unit = conp->vc_num;
 545 
 546    if (unit)
 547       disp[unit] = disp[0];
 548    disp[unit].conp = conp;
 549    fbcon_setup(unit, 1, 0);
 550 }
 551 
 552 
 553 static int fbcon_deinit(struct vc_data *conp)
     /* [previous][next][first][last][top][bottom][index][help] */
 554 {
 555    disp[conp->vc_num].conp = 0;
 556    return(0);
 557 }
 558 
 559 
 560 static int fbcon_changevar(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
 561 {
 562    fbcon_setup(con, 1, 1);
 563    return(0);
 564 }
 565 
 566 
 567 static void fbcon_setup(int con, int setcol, int cls)
     /* [previous][next][first][last][top][bottom][index][help] */
 568 {
 569    struct display *p = &disp[con];
 570    struct vc_data *conp = p->conp;
 571 
 572    p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
 573 
 574    if (!fb_info->fontname[0] ||
 575        !findsoftfont(fb_info->fontname, &p->fontwidth, &p->fontheight,
 576                      &p->fontdata) || p->fontwidth != 8)
 577            getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth,
 578                           &p->fontheight, &p->fontdata);
 579    if (p->fontwidth != 8)
 580       panic("fbcon_setup: No support for fontwidth != 8");
 581 
 582    if (divides(p->ywrapstep, p->fontheight) && divides(p->fontheight, p->var.yres_virtual))
 583       p->scrollmode = SCROLL_YWRAP;
 584    else if (divides(p->ypanstep, p->fontheight) &&
 585             p->var.yres_virtual >= p->var.yres+p->fontheight)
 586       p->scrollmode = SCROLL_YPAN;
 587    else
 588       p->scrollmode = SCROLL_YMOVE;
 589 
 590    conp->vc_cols = p->var.xres/p->fontwidth;
 591    conp->vc_rows = p->var.yres/p->fontheight;
 592    p->vrows = p->var.yres_virtual/p->fontheight;
 593    conp->vc_can_do_color = p->var.bits_per_pixel != 1;
 594 
 595 #ifdef CONFIG_FBCON_MONO
 596    if (p->var.bits_per_pixel == 1) {
 597       if (p->line_length)
 598          p->next_line = p->line_length;
 599       else
 600          p->next_line = p->var.xres_virtual>>3;
 601       p->next_plane = 0;
 602       p->dispsw = &dispsw_mono;
 603    } else
 604 #endif /* CONFIG_FBCON_MONO */
 605 #ifdef CONFIG_FBCON_IPLAN2
 606    if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux == 2) {
 607       p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3;
 608       p->next_plane = 0;
 609 #ifdef CONFIG_FBCON_2PLANE
 610       if (p->var.bits_per_pixel == 2)
 611          p->dispsw = &dispsw_2_plane;
 612       else
 613 #endif /* CONFIG_FBCON_2PLANE */
 614 #ifdef CONFIG_FBCON_4PLANE
 615       if (p->var.bits_per_pixel == 4)
 616          p->dispsw = &dispsw_4_plane;
 617       else
 618 #endif /* CONFIG_FBCON_4PLANE */
 619 #ifdef CONFIG_FBCON_8PLANE
 620       if (p->var.bits_per_pixel == 8)
 621          p->dispsw = &dispsw_8_plane;
 622       else
 623 #endif /* CONFIG_FBCON_8PLANE */
 624       goto fail;
 625    } else
 626 #endif /* CONFIG_FBCON_IPLAN2 */
 627 #ifdef CONFIG_FBCON_ILBM
 628    if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux != 2) {
 629       if (p->line_length) {
 630          p->next_line = p->line_length*p->var.bits_per_pixel;
 631          p->next_plane = p->line_length;
 632       } else {
 633          p->next_line = p->type_aux;
 634          p->next_plane = p->type_aux/p->var.bits_per_pixel;
 635       }
 636       p->dispsw = &dispsw_ilbm;
 637    } else
 638 #endif /* CONFIG_FBCON_ILBM */
 639 #ifdef CONFIG_FBCON_PLANES
 640    if (p->type == FB_TYPE_PLANES) {
 641       if (p->line_length)
 642          p->next_line = p->line_length;
 643       else
 644          p->next_line = p->var.xres_virtual>>3;
 645       p->next_plane = p->var.yres_virtual*p->next_line;
 646       p->dispsw = &dispsw_plan;
 647    } else
 648 #endif /* CONFIG_FBCON_PLANES */
 649 #ifdef CONFIG_FBCON_PACKED
 650    if (p->type == FB_TYPE_PACKED_PIXELS) {
 651       p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3;
 652       p->next_plane = 0;
 653 #ifdef CONFIG_FBCON_CYBER
 654       if (p->var.accel == FB_ACCEL_CYBERVISION)
 655          p->dispsw = &dispsw_cyber;
 656       else
 657 #endif /* CONFIG_FBCON_CYBER */
 658 #ifdef CONFIG_FBCON_8PACKED
 659       if (p->var.bits_per_pixel == 8)
 660          p->dispsw = &dispsw_8_packed;
 661       else
 662 #endif /* CONFIG_FBCON_8PACKED */
 663 #ifdef CONFIG_FBCON_16PACKED
 664       if (p->var.bits_per_pixel == 16)
 665          p->dispsw = &dispsw_16_packed;
 666       else
 667 #endif /* CONFIG_FBCON_16PACKED */
 668 #ifdef CONFIG_FBCON_24PACKED
 669       if (p->var.bits_per_pixel == 24)
 670          p->dispsw = &dispsw_24_packed;
 671       else
 672 #endif /* CONFIG_FBCON_24PACKED */
 673 #ifdef CONFIG_FBCON_32PACKED
 674       if (p->var.bits_per_pixel == 32)
 675          p->dispsw = &dispsw_32_packed;
 676       else
 677 #endif /* CONFIG_FBCON_32PACKED */
 678       goto fail;
 679    } else
 680 #endif /* CONFIG_FBCON_PACKED */
 681    {
 682 fail:
 683 #ifdef CONFIG_FBCON_MONO
 684       printk("fbcon_setup: type %d (aux %d) not supported, trying mono\n",
 685              p->type, p->type_aux);
 686       if (p->line_length)
 687          p->next_line = p->line_length;
 688       else
 689          p->next_line = p->var.xres_virtual>>3;
 690       p->next_plane = 0;
 691       p->var.bits_per_pixel = 1;
 692       p->dispsw = &dispsw_mono;
 693 #else /* CONFIG_FBCON_MONO */
 694       panic("fbcon_setup: no default driver");
 695 #endif /* CONFIG_FBCON_MONO */
 696    }
 697 
 698    if (setcol) {
 699       p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
 700       p->bgcol = 0;
 701    }
 702 
 703    if (cls)
 704       vc_resize_con(conp->vc_rows, conp->vc_cols, con);
 705 }
 706 
 707 
 708 /* ================================================================= */
 709 /*                      Utility Assembler Functions                  */
 710 /* ================================================================= */
 711 
 712 
 713 /* ====================================================================== */
 714 
 715 /* Those of a delicate disposition might like to skip the next couple of
 716  * pages.
 717  *
 718  * These functions are drop in replacements for memmove and
 719  * memset(_, 0, _). However their five instances add at least a kilobyte
 720  * to the object file. You have been warned.
 721  *
 722  * Not a great fan of assembler for the sake of it, but I think
 723  * that these routines are at least 10 times faster than their C
 724  * equivalents for large blits, and thats important to the lowest level of
 725  * a graphics driver. Question is whether some scheme with the blitter
 726  * would be faster. I suspect not for simple text system - not much
 727  * asynchrony.
 728  *
 729  * Code is very simple, just gruesome expansion. Basic strategy is to
 730  * increase data moved/cleared at each step to 16 bytes to reduce
 731  * instruction per data move overhead. movem might be faster still
 732  * For more than 15 bytes, we try to align the write direction on a
 733  * longword boundary to get maximum speed. This is even more gruesome.
 734  * Unaligned read/write used requires 68020+ - think this is a problem?
 735  *
 736  * Sorry!
 737  */
 738 
 739 
 740 /* ++roman: I've optimized Robert's original versions in some minor
 741  * aspects, e.g. moveq instead of movel, let gcc choose the registers,
 742  * use movem in some places...
 743  * For other modes than 1 plane, lots of more such assembler functions
 744  * were needed (e.g. the ones using movep or expanding color values).
 745  */
 746 
 747 /* ++andreas: more optimizations:
 748    subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
 749    addal is faster than addaw
 750    movep is rather expensive compared to ordinary move's
 751    some functions rewritten in C for clarity, no speed loss */
 752 
 753 static __inline__ void *mymemclear_small(void *s, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
 754 {
 755    if (!count)
 756       return(0);
 757 
 758    __asm__ __volatile__(
 759          "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
 760       "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
 761       "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
 762       "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
 763       "1: subql  #1,%1 ; jcs 3f\n\t"
 764       "2: moveml %2/%3/%4/%5,%0@-\n\t"
 765          "dbra %1,2b\n\t"
 766       "3:"
 767          : "=a" (s), "=d" (count)
 768          :  "d" (0), "d" (0), "d" (0), "d" (0),
 769             "0" ((char *)s+count), "1" (count)
 770   );
 771 
 772    return(0);
 773 }
 774 
 775 
 776 static __inline__ void *mymemclear(void *s, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
 777 {
 778    if (!count)
 779       return(0);
 780 
 781    if (count < 16) {
 782       __asm__ __volatile__(
 783             "lsrl   #1,%1 ; jcc 1f ; clrb %0@+\n\t"
 784          "1: lsrl   #1,%1 ; jcc 1f ; clrw %0@+\n\t"
 785          "1: lsrl   #1,%1 ; jcc 1f ; clrl %0@+\n\t"
 786          "1: lsrl   #1,%1 ; jcc 1f ; clrl %0@+ ; clrl %0@+\n\t"
 787          "1:"
 788             : "=a" (s), "=d" (count)
 789             : "0" (s), "1" (count)
 790      );
 791    } else {
 792       long tmp;
 793       __asm__ __volatile__(
 794             "movel %1,%2\n\t"
 795             "lsrl   #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t"
 796             "lsrl   #1,%2 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
 797             "clrw   %0@+  ; subqw  #2,%1 ; jra 2f\n\t"
 798          "1: lsrl   #1,%2 ; jcc 2f\n\t"
 799             "clrw   %0@+  ; subqw  #2,%1\n\t"
 800          "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t"
 801             "lsrl   #1,%1 ; jcc 3f ; clrl %0@+\n\t"
 802          "3: lsrl   #1,%1 ; jcc 4f ; clrl %0@+ ; clrl %0@+\n\t"
 803          "4: subql  #1,%1 ; jcs 6f\n\t"
 804          "5: clrl %0@+; clrl %0@+ ; clrl %0@+ ; clrl %0@+\n\t"
 805             "dbra %1,5b   ; clrw %1; subql #1,%1; jcc 5b\n\t"
 806          "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0@+\n\t"
 807          "7:            ; btst #0,%1 ; jeq 8f ; clrb %0@+\n\t"
 808          "8:"
 809             : "=a" (s), "=d" (count), "=d" (tmp)
 810             : "0" (s), "1" (count)
 811      );
 812    }
 813 
 814    return(0);
 815 }
 816 
 817 
 818 static __inline__ void *mymemset(void *s, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
 819 {
 820    if (!count)
 821       return(0);
 822 
 823    __asm__ __volatile__(
 824          "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
 825       "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
 826       "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
 827       "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
 828       "1: subql  #1,%1 ; jcs 3f\n\t"
 829       "2: moveml %2/%3/%4/%5,%0@-\n\t"
 830          "dbra %1,2b\n\t"
 831       "3:"
 832          : "=a" (s), "=d" (count)
 833          :  "d" (-1), "d" (-1), "d" (-1), "d" (-1),
 834             "0" ((char *) s + count), "1" (count)
 835   );
 836 
 837    return(0);
 838 }
 839 
 840 
 841 static __inline__ void *mymemmove(void *d, void *s, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
 842 {
 843    if (d < s) {
 844       if (count < 16) {
 845          __asm__ __volatile__(
 846                "lsrl   #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t"
 847             "1: lsrl   #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t"
 848             "1: lsrl   #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t"
 849             "1: lsrl   #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
 850             "1:"
 851                : "=a" (d), "=a" (s), "=d" (count)
 852                : "0" (d), "1" (s), "2" (count)
 853         );
 854       } else {
 855          long tmp;
 856          __asm__ __volatile__(
 857                "movel  %0,%3\n\t"
 858                "lsrl   #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t"
 859                "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
 860                "movew  %1@+,%0@+  ; subqw  #2,%2 ; jra 2f\n\t"
 861             "1: lsrl   #1,%3 ; jcc 2f\n\t"
 862                "movew  %1@+,%0@+  ; subqw  #2,%2\n\t"
 863             "2: movew  %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
 864                "lsrl   #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t"
 865             "3: lsrl   #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
 866             "4: subql  #1,%2 ; jcs 6f\n\t"
 867             "5: movel  %1@+,%0@+;movel %1@+,%0@+\n\t"
 868                "movel  %1@+,%0@+;movel %1@+,%0@+\n\t"
 869                "dbra   %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
 870             "6: movew  %+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t"
 871             "7:              ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t"
 872             "8:"
 873                : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
 874                : "0" (d), "1" (s), "2" (count)
 875         );
 876       }
 877    } else {
 878       if (count < 16) {
 879          __asm__ __volatile__(
 880                "lsrl   #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t"
 881             "1: lsrl   #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t"
 882             "1: lsrl   #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t"
 883             "1: lsrl   #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
 884             "1:"
 885                : "=a" (d), "=a" (s), "=d" (count)
 886                : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
 887         );
 888       } else {
 889          long tmp;
 890          __asm__ __volatile__(
 891                "movel %0,%3\n\t"
 892                "lsrl   #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t"
 893                "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
 894                "movew  %1@-,%0@-  ; subqw  #2,%2 ; jra 2f\n\t"
 895             "1: lsrl   #1,%3 ; jcc 2f\n\t"
 896                "movew  %1@-,%0@-  ; subqw  #2,%2\n\t"
 897             "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
 898                "lsrl   #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t"
 899             "3: lsrl   #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
 900             "4: subql  #1,%2 ; jcs 6f\n\t"
 901             "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t"
 902                "movel %1@-,%0@-;movel %1@-,%0@-\n\t"
 903                "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
 904             "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t"
 905             "7:              ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t"
 906             "8:"
 907                : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
 908                : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
 909         );
 910       }
 911    }
 912 
 913    return(0);
 914 }
 915 
 916 
 917 /* ++andreas: Simple and fast version of memmove, assumes size is
 918    divisible by 16, suitable for moving the whole screen bitplane */
 919 static __inline__ void fast_memmove(char *dst, char *src, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 920 {
 921   if (!size)
 922     return;
 923   if (dst < src)
 924     __asm__ __volatile__
 925       ("1:"
 926        "  moveml %0@+,%/d0/%/d1/%/a0/%/a1\n"
 927        "  moveml %/d0/%/d1/%/a0/%/a1,%1@\n"
 928        "  addql #8,%1; addql #8,%1\n"
 929        "  dbra %2,1b\n"
 930        "  clrw %2; subql #1,%2\n"
 931        "  jcc 1b"
 932        : "=a" (src), "=a" (dst), "=d" (size)
 933        : "0" (src), "1" (dst), "2" (size / 16 - 1)
 934        : "d0", "d1", "a0", "a1", "memory");
 935   else
 936     __asm__ __volatile__
 937       ("1:"
 938        "  subql #8,%0; subql #8,%0\n"
 939        "  moveml %0@,%/d0/%/d1/%/a0/%/a1\n"
 940        "  moveml %/d0/%/d1/%/a0/%/a1,%1@-\n"
 941        "  dbra %2,1b\n"
 942        "  clrw %2; subql #1,%2\n"
 943        "  jcc 1b"
 944        : "=a" (src), "=a" (dst), "=d" (size)
 945        : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1)
 946        : "d0", "d1", "a0", "a1", "memory");
 947 }
 948 
 949 
 950 /* Sets the bytes in the visible column at d, height h, to the value
 951  * val for a 4 plane screen. The the bis of the color in 'color' are
 952  * moved (8 times) to the respective bytes. This means:
 953  *
 954  * for(h times; d += bpr)
 955  *   *d     = (color & 1) ? 0xff : 0;
 956  *   *(d+2) = (color & 2) ? 0xff : 0;
 957  *   *(d+4) = (color & 4) ? 0xff : 0;
 958  *   *(d+6) = (color & 8) ? 0xff : 0;
 959  */
 960 
 961 static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr)
     /* [previous][next][first][last][top][bottom][index][help] */
 962 {
 963         __asm__ __volatile__
 964                 ("1: movepl %4,%0@(0)\n\t"
 965                   "addal  %5,%0\n\t"
 966                   "dbra   %1,1b"
 967                   : "=a" (d), "=d" (h)
 968                   : "0" (d), "1" (h - 1), "d" (val), "r" (bpr)
 969                 );
 970 }
 971 
 972 /* Sets a 4 plane region from 'd', length 'count' bytes, to the color
 973  * in val1/val2. 'd' has to be an even address and count must be divisible
 974  * by 8, because only whole words and all planes are accessed. I.e.:
 975  *
 976  * for(count/8 times)
 977  *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
 978  *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
 979  *   *(d+4) = *(d+5) = (color & 4) ? 0xff : 0;
 980  *   *(d+6) = *(d+7) = (color & 8) ? 0xff : 0;
 981  */
 982 
 983 static __inline__ void memset_even_4p(void *d, size_t count, u_long val1,
     /* [previous][next][first][last][top][bottom][index][help] */
 984                                       u_long val2)
 985 {
 986   u_long *dd = d;
 987 
 988   count /= 8;
 989   while (count--)
 990     {
 991       *dd++ = val1;
 992       *dd++ = val2;
 993     }
 994 }
 995 
 996 /* Copies a 4 plane column from 's', height 'h', to 'd'. */
 997 
 998 static __inline__ void memmove_4p_col (void *d, void *s, int h, int bpr)
     /* [previous][next][first][last][top][bottom][index][help] */
 999 {
1000   u_char *dd = d, *ss = s;
1001 
1002   while (h--)
1003     {
1004       dd[0] = ss[0];
1005       dd[2] = ss[2];
1006       dd[4] = ss[4];
1007       dd[6] = ss[6];
1008       dd += bpr;
1009       ss += bpr;
1010     }
1011 }
1012 
1013 
1014 /* This expands a 4 bit color into a long for movepl (4 plane) operations. */
1015 
1016 static __inline__ u_long expand4l(u_char c)
     /* [previous][next][first][last][top][bottom][index][help] */
1017 {
1018         u_long  rv;
1019 
1020         __asm__ __volatile__
1021                 ("lsrb   #1,%2\n\t"
1022                   "scs   %0\n\t"
1023                   "lsll  #8,%0\n\t"
1024                   "lsrb  #1,%2\n\t"
1025                   "scs   %0\n\t"
1026                   "lsll  #8,%0\n\t"
1027                   "lsrb  #1,%2\n\t"
1028                   "scs   %0\n\t"
1029                   "lsll  #8,%0\n\t"
1030                   "lsrb  #1,%2\n\t"
1031                   "scs   %0\n\t"
1032                   : "=&d" (rv), "=d" (c)
1033                   : "1" (c)
1034                 );
1035         return(rv);
1036 }
1037 
1038 /* This expands a 4 bit color into two longs for two movel operations
1039  * (4 planes).
1040  */
1041 
1042 static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2)
     /* [previous][next][first][last][top][bottom][index][help] */
1043 {
1044         u_long  rv1, rv2;
1045 
1046         __asm__ __volatile__
1047                 ("lsrb   #1,%3\n\t"
1048                   "scs   %0\n\t"
1049                   "extw  %0\n\t"
1050                   "swap  %0\n\t"
1051                   "lsrb  #1,%3\n\t"
1052                   "scs   %0\n\t"
1053                   "extw  %0\n\t"
1054                   "lsrb  #1,%3\n\t"
1055                   "scs   %1\n\t"
1056                   "extw  %1\n\t"
1057                   "swap  %1\n\t"
1058                   "lsrb  #1,%3\n\t"
1059                   "scs   %1\n\t"
1060                   "extw  %1"
1061                   : "=&d" (rv1), "=&d" (rv2), "=d" (c)
1062                   : "2" (c)
1063                 );
1064         *ret1 = rv1;
1065         *ret2 = rv2;
1066 }
1067 
1068 
1069 /* This duplicates a byte 4 times into a long. */
1070 
1071 static __inline__ u_long dup4l(u_char c)
     /* [previous][next][first][last][top][bottom][index][help] */
1072 {
1073         ushort  tmp;
1074         ulong   rv;
1075 
1076         __asm__ __volatile__
1077                 ("moveb  %2,%0\n\t"
1078                   "lslw   #8,%0\n\t"
1079                   "moveb  %2,%0\n\t"
1080                   "movew  %0,%1\n\t"
1081                   "swap   %0\n\t"
1082                   "movew  %1,%0"
1083                   : "=&d" (rv), "=d" (tmp)
1084                   : "d" (c)
1085                 );
1086 
1087         return(rv);
1088 }
1089 
1090 
1091 /* Sets the bytes in the visible column at d, height h, to the value
1092  * val1,val2 for a 8 plane screen. The the bis of the color in 'color' are
1093  * moved (8 times) to the respective bytes. This means:
1094  *
1095  * for(h times; d += bpr)
1096  *   *d      = (color & 1) ? 0xff : 0;
1097  *   *(d+2)  = (color & 2) ? 0xff : 0;
1098  *   *(d+4)  = (color & 4) ? 0xff : 0;
1099  *   *(d+6)  = (color & 8) ? 0xff : 0;
1100  *   *(d+8)  = (color & 16) ? 0xff : 0;
1101  *   *(d+10) = (color & 32) ? 0xff : 0;
1102  *   *(d+12) = (color & 64) ? 0xff : 0;
1103  *   *(d+14) = (color & 128) ? 0xff : 0;
1104  */
1105 
1106 static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1,
     /* [previous][next][first][last][top][bottom][index][help] */
1107                                        u_long val2, int bpr)
1108 {
1109         __asm__ __volatile__
1110                 ("1: movepl %4,%0@(0)\n\t"
1111               "movepl %5,%0@(8)\n\t"
1112                   "addal  %6,%0\n\t"
1113                   "dbra   %1,1b"
1114                   : "=a" (d), "=d" (h)
1115                   : "0" (d), "1" (h - 1), "d" (val1), "d" (val2), "r" (bpr)
1116                 );
1117 }
1118 
1119 /* Sets a 8 plane region from 'd', length 'count' bytes, to the color
1120  * val1..val4. 'd' has to be an even address and count must be divisible
1121  * by 16, because only whole words and all planes are accessed. I.e.:
1122  *
1123  * for(count/16 times)
1124  *   *d      = *(d+1)  = (color & 1) ? 0xff : 0;
1125  *   *(d+2)  = *(d+3)  = (color & 2) ? 0xff : 0;
1126  *   *(d+4)  = *(d+5)  = (color & 4) ? 0xff : 0;
1127  *   *(d+6)  = *(d+7)  = (color & 8) ? 0xff : 0;
1128  *   *(d+8)  = *(d+9)  = (color & 16) ? 0xff : 0;
1129  *   *(d+10) = *(d+11) = (color & 32) ? 0xff : 0;
1130  *   *(d+12) = *(d+13) = (color & 64) ? 0xff : 0;
1131  *   *(d+14) = *(d+15) = (color & 128) ? 0xff : 0;
1132  */
1133 
1134 static __inline__ void memset_even_8p(void *d, size_t count, u_long val1,
     /* [previous][next][first][last][top][bottom][index][help] */
1135                                       u_long val2, u_long val3, u_long val4)
1136 {
1137   u_long *dd = d;
1138 
1139   count /= 16;
1140   while (count--)
1141     {
1142       *dd++ = val1;
1143       *dd++ = val2;
1144       *dd++ = val3;
1145       *dd++ = val4;
1146     }
1147 }
1148 
1149 /* Copies a 8 plane column from 's', height 'h', to 'd'. */
1150 
1151 static __inline__ void memmove_8p_col (void *d, void *s, int h, int bpr)
     /* [previous][next][first][last][top][bottom][index][help] */
1152 {
1153   u_char *dd = d, *ss = s;
1154 
1155   while (h--)
1156     {
1157       dd[0] = ss[0];
1158       dd[2] = ss[2];
1159       dd[4] = ss[4];
1160       dd[6] = ss[6];
1161       dd[8] = ss[8];
1162       dd[10] = ss[10];
1163       dd[12] = ss[12];
1164       dd[14] = ss[14];
1165       dd += bpr;
1166       ss += bpr;
1167     }
1168 }
1169 
1170 
1171 /* This expands a 8 bit color into two longs for two movepl (8 plane)
1172  * operations.
1173  */
1174 
1175 static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2)
     /* [previous][next][first][last][top][bottom][index][help] */
1176 {
1177         u_long  rv1, rv2;
1178 
1179         __asm__ __volatile__
1180                 ("lsrb   #1,%3\n\t"
1181                   "scs   %0\n\t"
1182                   "lsll  #8,%0\n\t"
1183                   "lsrb  #1,%3\n\t"
1184                   "scs   %0\n\t"
1185                   "lsll  #8,%0\n\t"
1186                   "lsrb  #1,%3\n\t"
1187                   "scs   %0\n\t"
1188                   "lsll  #8,%0\n\t"
1189                   "lsrb  #1,%3\n\t"
1190                   "scs   %0\n\t"
1191                   "lsrb  #1,%3\n\t"
1192                   "scs   %1\n\t"
1193                   "lsll  #8,%1\n\t"
1194                   "lsrb  #1,%3\n\t"
1195                   "scs   %1\n\t"
1196                   "lsll  #8,%1\n\t"
1197                   "lsrb  #1,%3\n\t"
1198                   "scs   %1\n\t"
1199                   "lsll  #8,%1\n\t"
1200                   "lsrb  #1,%3\n\t"
1201                   "scs   %1"
1202                   : "=&d" (rv1), "=&d" (rv2),"=d" (c)
1203                   : "2" (c)
1204                 );
1205 
1206         *ret1 = rv1;
1207         *ret2 = rv2;
1208 }
1209 
1210 /* This expands a 8 bit color into four longs for four movel operations
1211  * (8 planes).
1212  */
1213 
1214 /* ++andreas: use macro to avoid taking address of return values */
1215 #define expand8ql(c, rv1, rv2, rv3, rv4) \
1216 do {    u_char tmp = c;                                         \
1217         __asm__ __volatile__                                    \
1218                 ("lsrb   #1,%5\n\t"                             \
1219                   "scs   %0\n\t"                                \
1220                   "extw  %0\n\t"                                \
1221                   "swap  %0\n\t"                                \
1222                   "lsrb  #1,%5\n\t"                             \
1223                   "scs   %0\n\t"                                \
1224                   "extw  %0\n\t"                                \
1225                   "lsrb  #1,%5\n\t"                             \
1226                   "scs   %1\n\t"                                \
1227                   "extw  %1\n\t"                                \
1228                   "swap  %1\n\t"                                \
1229                   "lsrb  #1,%5\n\t"                             \
1230                   "scs   %1\n\t"                                \
1231                   "extw  %1\n\t"                                \
1232                   "lsrb  #1,%5\n\t"                             \
1233                   "scs   %2\n\t"                                \
1234                   "extw  %2\n\t"                                \
1235                   "swap  %2\n\t"                                \
1236                   "lsrb  #1,%5\n\t"                             \
1237                   "scs   %2\n\t"                                \
1238                   "extw  %2\n\t"                                \
1239                   "lsrb  #1,%5\n\t"                             \
1240                   "scs   %3\n\t"                                \
1241                   "extw  %3\n\t"                                \
1242                   "swap  %3\n\t"                                \
1243                   "lsrb  #1,%5\n\t"                             \
1244                   "scs   %3\n\t"                                \
1245                   "extw  %3"                                    \
1246                   : "=&d" (rv1), "=&d" (rv2), "=&d" (rv3),      \
1247                     "=&d" (rv4), "=d" (tmp)                     \
1248                   : "4" (tmp)                                   \
1249                 );                                              \
1250 } while (0)
1251 
1252 
1253 /* Sets the bytes in the visible column at d, height h, to the value
1254  * val for a 2 plane screen. The the bis of the color in 'color' are
1255  * moved (8 times) to the respective bytes. This means:
1256  *
1257  * for(h times; d += bpr)
1258  *   *d     = (color & 1) ? 0xff : 0;
1259  *   *(d+2) = (color & 2) ? 0xff : 0;
1260  */
1261 
1262 static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr)
     /* [previous][next][first][last][top][bottom][index][help] */
1263 {
1264         __asm__ __volatile__
1265                 ("1: movepw %4,%0@(0)\n\t"
1266                   "addal  %5,%0\n\t"
1267                   "dbra   %1,1b"
1268                   : "=a" (d), "=d" (h)
1269                   : "0" (d), "1" (h - 1), "d" (val), "r" (bpr)
1270                 );
1271 }
1272 
1273 /* Sets a 2 plane region from 'd', length 'count' bytes, to the color
1274  * in val1. 'd' has to be an even address and count must be divisible
1275  * by 8, because only whole words and all planes are accessed. I.e.:
1276  *
1277  * for(count/4 times)
1278  *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
1279  *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
1280  */
1281 
1282 static __inline__ void memset_even_2p(void *d, size_t count, u_long val)
     /* [previous][next][first][last][top][bottom][index][help] */
1283 {
1284   u_long *dd = d;
1285 
1286   count /= 4;
1287   while (count--)
1288     *dd++ = val;
1289 }
1290 
1291 /* Copies a 2 plane column from 's', height 'h', to 'd'. */
1292 
1293 static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr)
     /* [previous][next][first][last][top][bottom][index][help] */
1294 {
1295   u_char *dd = d, *ss = s;
1296 
1297   while (h--)
1298     {
1299       dd[0] = ss[0];
1300       dd[2] = ss[2];
1301       dd += bpr;
1302       ss += bpr;
1303     }
1304 }
1305 
1306 
1307 /* This expands a 2 bit color into a short for movepw (2 plane) operations. */
1308 
1309 static __inline__ u_short expand2w(u_char c)
     /* [previous][next][first][last][top][bottom][index][help] */
1310 {
1311         u_short rv;
1312 
1313         __asm__ __volatile__
1314                 ("lsrb   #1,%2\n\t"
1315                   "scs   %0\n\t"
1316                   "lsll  #8,%0\n\t"
1317                   "lsrb  #1,%2\n\t"
1318                   "scs   %0\n\t"
1319                   : "=&d" (rv), "=d" (c)
1320                   : "1" (c)
1321                 );
1322         return(rv);
1323 }
1324 
1325 /* This expands a 2 bit color into one long for a movel operation
1326  * (2 planes).
1327  */
1328 
1329 static __inline__ u_long expand2l(u_char c)
     /* [previous][next][first][last][top][bottom][index][help] */
1330 {
1331         u_long  rv;
1332 
1333         __asm__ __volatile__
1334                 ("lsrb   #1,%2\n\t"
1335                   "scs   %0\n\t"
1336                   "extw  %0\n\t"
1337                   "swap  %0\n\t"
1338                   "lsrb  #1,%2\n\t"
1339                   "scs   %0\n\t"
1340                   "extw  %0\n\t"
1341                   : "=&d" (rv), "=d" (c)
1342                   : "1" (c)
1343                 );
1344 
1345         return rv;
1346 }
1347 
1348 
1349 /* This duplicates a byte 2 times into a short. */
1350 
1351 static __inline__ u_short dup2w(u_char c)
     /* [previous][next][first][last][top][bottom][index][help] */
1352 {
1353     ushort  rv;
1354 
1355     __asm__ __volatile__
1356         ( "moveb  %1,%0\n\t"
1357           "lslw   #8,%0\n\t"
1358           "moveb  %1,%0\n\t"
1359           : "=&d" (rv)
1360           : "d" (c)
1361         );
1362 
1363     return( rv );
1364 }
1365 
1366 
1367 /* ====================================================================== */
1368 
1369 /* fbcon_XXX routines - interface used by the world
1370  *
1371  * This system is now divided into two levels because of complications
1372  * caused by hardware scrolling. Top level functions:
1373  *
1374  *    fbcon_bmove(), fbcon_clear(), fbcon_putc()
1375  *
1376  * handles y values in range [0, scr_height-1] that correspond to real
1377  * screen positions. y_wrap shift means that first line of bitmap may be
1378  * anywhere on this display. These functions convert lineoffsets to
1379  * bitmap offsets and deal with the wrap-around case by splitting blits.
1380  *
1381  *    fbcon_bmove_physical_8()   -- These functions fast implementations
1382  *    fbcon_clear_physical_8()   -- of original fbcon_XXX fns.
1383  *    fbcon_putc_physical_8()    -- (fontwidth != 8) may be added later
1384  *
1385  * WARNING:
1386  *
1387  * At the moment fbcon_putc() cannot blit across vertical wrap boundary
1388  * Implies should only really hardware scroll in rows. Only reason for
1389  * restriction is simplicity & efficiency at the moment.
1390  */
1391 
1392 static __inline__ int real_y(struct display *p, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
1393 {
1394    int rows = p->vrows;
1395 
1396    y += p->yscroll;
1397    return(y < rows ? y : y-rows);
1398 }
1399 
1400 
1401 static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
     /* [previous][next][first][last][top][bottom][index][help] */
1402                        int width)
1403 {
1404    int unit = conp->vc_num;
1405    struct display *p = &disp[unit];
1406    u_int y_break;
1407 
1408    if (!p->can_soft_blank && console_blanked)
1409       return(0);
1410 
1411    if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
1412        (sx <= p->cursor_x) && (p->cursor_x < sx+width))
1413       CURSOR_UNDRAWN();
1414 
1415    /* Split blits that cross physical y_wrap boundary */
1416 
1417    y_break = p->vrows-p->yscroll;
1418    if (sy < y_break && sy+height-1 >= y_break) {
1419       u_int b = y_break-sy;
1420       p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width);
1421       p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width);
1422    } else
1423       p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width);
1424 
1425    return(0);
1426 }
1427 
1428 
1429 static int fbcon_putc(struct vc_data *conp, int c, int y, int x)
     /* [previous][next][first][last][top][bottom][index][help] */
1430 {
1431    int unit = conp->vc_num;
1432    struct display *p = &disp[unit];
1433 
1434    if (!p->can_soft_blank && console_blanked)
1435       return(0);
1436 
1437    if ((p->cursor_x == x) && (p->cursor_y == y))
1438        CURSOR_UNDRAWN();
1439 
1440    p->dispsw->putc(conp, p, c, real_y(p, y), x);
1441 
1442    return(0);
1443 }
1444 
1445 
1446 static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
1447                        int x)
1448 {
1449    int unit = conp->vc_num;
1450    struct display *p = &disp[unit];
1451 
1452    if (!p->can_soft_blank && console_blanked)
1453       return(0);
1454 
1455    if ((p->cursor_y == y) && (x <= p->cursor_x) && (p->cursor_x < x+count))
1456       CURSOR_UNDRAWN();
1457 
1458    p->dispsw->putcs(conp, p, s, count, real_y(p, y), x);
1459 
1460    return(0);
1461 }
1462 
1463 
1464 static int fbcon_cursor(struct vc_data *conp, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
1465 {
1466    int unit = conp->vc_num;
1467    struct display *p = &disp[unit];
1468 
1469    if (CURSOR_UNDRAWN ())
1470       p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
1471    p->cursor_x = conp->vc_x;
1472    p->cursor_y = conp->vc_y;
1473 
1474    switch (mode) {
1475       case CM_ERASE:
1476          cursor_on = 0;
1477          break;
1478 
1479       case CM_MOVE:
1480       case CM_DRAW:
1481          vbl_cursor_cnt = CURSOR_DRAW_DELAY;
1482          cursor_on = 1;
1483          break;
1484    }
1485 
1486    return(0);
1487 }
1488 
1489 
1490 static void fbcon_vbl_handler(int irq, struct pt_regs *fp, void *dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
1491 {
1492    struct display *p;
1493 
1494    if (!cursor_on)
1495       return;
1496 
1497    if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
1498       /* Here no check is possible for console changing. The console
1499        * switching code should set vbl_cursor_cnt to an appropriate value.
1500        */
1501       p = &disp[fg_console];
1502       p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
1503       cursor_drawn ^= 1;
1504       vbl_cursor_cnt = cursor_blink_rate;
1505    }
1506 }
1507 
1508 
1509 static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
1510 {
1511    int unit = conp->vc_num;
1512    struct display *p = &disp[unit];
1513 
1514    if (!p->can_soft_blank && console_blanked)
1515       return(0);
1516 
1517    fbcon_cursor(conp, CM_ERASE);
1518 
1519    /*
1520     * ++Geert: Only use ywrap/ypan if the console is in text mode
1521     */
1522 
1523    switch (dir) {
1524       case SM_UP:
1525          if (t == 0 && b == conp->vc_rows &&
1526              vt_cons[unit]->vc_mode == KD_TEXT) {
1527             if (count > conp->vc_rows)             /* Maximum realistic size */
1528                count = conp->vc_rows;
1529             switch (p->scrollmode) {
1530                case SCROLL_YWRAP:
1531                   p->yscroll += count;
1532                   if (p->yscroll >= p->vrows) /* Deal with wrap */
1533                      p->yscroll -= p->vrows;
1534                   p->var.xoffset = 0;
1535                   p->var.yoffset = p->yscroll*p->fontheight;
1536                   p->var.vmode |= FB_VMODE_YWRAP;
1537                   fb_info->updatevar(unit);
1538                   break;
1539 
1540                case SCROLL_YPAN:
1541                   p->yscroll += count;
1542                   if (p->yscroll+conp->vc_rows > p->vrows) {
1543                      p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-count,
1544                                       conp->vc_cols);
1545                      p->yscroll = 0;
1546                   }
1547                   p->var.xoffset = 0;
1548                   p->var.yoffset = p->yscroll*p->fontheight;
1549                   p->var.vmode &= ~FB_VMODE_YWRAP;
1550                   fb_info->updatevar(unit);
1551                   break;
1552 
1553                case SCROLL_YMOVE:
1554                   p->dispsw->bmove(p, count, 0, 0, 0, b-count, conp->vc_cols);
1555                   break;
1556             }
1557          } else
1558             fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols);
1559          fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
1560          break;
1561 
1562       case SM_DOWN:
1563          if (t == 0 && b == conp->vc_rows &&
1564              vt_cons[unit]->vc_mode == KD_TEXT) {
1565             if (count > conp->vc_rows)             /* Maximum realistic size */
1566                count = conp->vc_rows;
1567             switch (p->scrollmode) {
1568                case SCROLL_YWRAP:
1569                   p->yscroll -= count;
1570                   if (p->yscroll < 0)              /* Deal with wrap */
1571                      p->yscroll += p->vrows;
1572                   p->var.xoffset = 0;
1573                   p->var.yoffset = p->yscroll*p->fontheight;
1574                   p->var.vmode |= FB_VMODE_YWRAP;
1575                   fb_info->updatevar(unit);
1576                   break;
1577 
1578                case SCROLL_YPAN:
1579                   p->yscroll -= count;
1580                   if (p->yscroll < 0) {
1581                      p->yscroll = p->vrows-conp->vc_rows;
1582                      p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-count,
1583                                       conp->vc_cols);
1584                   }
1585                   p->var.xoffset = 0;
1586                   p->var.yoffset = p->yscroll*p->fontheight;
1587                   p->var.vmode &= ~FB_VMODE_YWRAP;
1588                   fb_info->updatevar(unit);
1589                   break;
1590 
1591                case SCROLL_YMOVE:
1592                   p->dispsw->bmove(p, 0, 0, count, 0, b-count, conp->vc_cols);
1593                   break;
1594             }
1595          } else
1596             fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
1597 
1598          /* Fixed bmove() should end Arno's frustration with copying?
1599           * Confucius says:
1600           *    Man who copies in wrong direction, end up with trashed data
1601           */
1602          fbcon_clear(conp, t, 0, count, conp->vc_cols);
1603          break;
1604 
1605       case SM_LEFT:
1606          fbcon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count);
1607          fbcon_clear(conp, 0, b-count, conp->vc_rows, count);
1608          break;
1609 
1610       case SM_RIGHT:
1611          fbcon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count);
1612          fbcon_clear(conp, 0, t, conp->vc_rows, count);
1613          break;
1614    }
1615 
1616    return(0);
1617 }
1618 
1619 
1620 static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
1621                        int height, int width)
1622 {
1623    int unit = conp->vc_num;
1624    struct display *p = &disp[unit];
1625 
1626    if (!p->can_soft_blank && console_blanked)
1627       return(0);
1628 
1629    if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
1630         (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
1631        ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
1632         (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
1633       fbcon_cursor(conp, CM_ERASE);
1634 
1635    /* Split blits that cross physical y_wrap case.
1636     * Pathological case involves 4 blits, better to use recursive
1637     * code rather than unrolled case
1638     *
1639     * Recursive invocations don't need to erase the cursor over and
1640     * over again, so we use fbcon_bmove_rec()
1641     */
1642    fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
1643 
1644    return(0);
1645 }
1646 
1647 
1648 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
1649                             int height, int width, u_int y_break)
1650 {
1651    u_int b;
1652 
1653    if (sy < y_break && sy+height > y_break) {
1654       b = y_break-sy;
1655       if (dy < sy) {       /* Avoid trashing self */
1656          fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
1657          fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
1658       } else {
1659          fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
1660          fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
1661       }
1662       return;
1663    }
1664 
1665    if (dy < y_break && dy+height > y_break) {
1666       b = y_break-dy;
1667       if (dy < sy) {       /* Avoid trashing self */
1668          fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
1669          fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
1670       } else {
1671          fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
1672          fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
1673       }
1674       return;
1675    }
1676    p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
1677 }
1678 
1679 
1680 static int fbcon_switch(struct vc_data *conp)
     /* [previous][next][first][last][top][bottom][index][help] */
1681 {
1682    if (fb_info && fb_info->switch_con)
1683       (*fb_info->switch_con)(conp->vc_num);
1684    return(0);
1685 }
1686 
1687 
1688 static int fbcon_blank(int blank)
     /* [previous][next][first][last][top][bottom][index][help] */
1689 {
1690    struct display *p = &disp[fg_console];
1691 
1692    fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
1693 
1694    if (!p->can_soft_blank)
1695       if (blank) {
1696          if (p->visual == FB_VISUAL_MONO01)
1697              mymemset(p->screen_base, p->var.xres_virtual*p->var.yres_virtual*
1698                                       p->var.bits_per_pixel>>3);
1699           else
1700              mymemclear(p->screen_base, p->var.xres_virtual*p->var.yres_virtual*
1701                                         p->var.bits_per_pixel>>3);
1702          return(0);
1703       } else {
1704          /* Tell console.c that it has to restore the screen itself */
1705          return(1);
1706       }
1707    (*fb_info->blank)(blank);
1708    return(0);
1709 }
1710 
1711 
1712 static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1713 {
1714         int unit = conp->vc_num;
1715         struct display *p = &disp[unit];
1716         int i, size, alloc;
1717 
1718         size = (p->fontwidth+7)/8 * p->fontheight * 256;
1719         alloc = (*w+7)/8 * *h * 256;
1720         *w = p->fontwidth;
1721         *h = p->fontheight;
1722    
1723         if (alloc < size)
1724                 /* allocation length not sufficient */
1725                 return( -ENAMETOOLONG );
1726 
1727         if ((i = verify_area( VERIFY_WRITE, (void *)data, size )))
1728                 return i;
1729 
1730         memcpy_tofs( data, p->fontdata, size );
1731         return( 0 );
1732 }
1733 
1734 
1735 #define REFCOUNT(fd)    (((int *)(fd))[-1])
1736 
1737 static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1738 {
1739         int unit = conp->vc_num;
1740         struct display *p = &disp[unit];
1741         int i, size, userspace = 1, resize;
1742         char *old_data = NULL, *new_data;
1743 
1744         if (w < 0)
1745                 w = p->fontwidth;
1746         if (h < 0)
1747                 h = p->fontheight;
1748         
1749         if (w == 0) {
1750                 /* engage predefined font, name in 'data' */
1751                 char name[MAX_FONT_NAME+1];
1752            
1753                 if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME )))
1754                         return i;
1755                 memcpy_fromfs( name, data, MAX_FONT_NAME );
1756                 name[sizeof(name)-1] = 0;
1757                 
1758                 if (!findsoftfont( name, &w, &h, (u_char **)&data ))
1759                         return( -ENOENT );
1760                 userspace = 0;
1761         }
1762         else if (w == 1) {
1763                 /* copy font from some other console in 'h'*/
1764                 struct display *op;
1765 
1766                 if (h < 0 || !vc_cons_allocated( h ))
1767                         return( -ENOTTY );
1768                 if (h == unit)
1769                         return( 0 ); /* nothing to do */
1770                 op = &disp[h];
1771                 if (op->fontdata == p->fontdata)
1772                         return( 0 ); /* already the same font... */
1773 
1774                 resize = (op->fontwidth != p->fontwidth) ||
1775                              (op->fontheight != p->fontheight);
1776                 if (p->userfont)
1777                         old_data = p->fontdata;
1778                 p->fontdata = op->fontdata;
1779                 w = p->fontwidth = op->fontwidth;
1780                 h = p->fontheight = op->fontheight;
1781                 if ((p->userfont = op->userfont))
1782                         REFCOUNT(p->fontdata)++; /* increment usage counter */
1783                 goto activate;
1784         }
1785 
1786         if (w != 8)
1787                 /* Currently only fontwidth == 8 supported */
1788                 return( -ENXIO );
1789         
1790         resize = (w != p->fontwidth) || (h != p->fontheight);
1791         size = (w+7)/8 * h * 256;
1792         
1793         if (p->userfont)
1794                 old_data = p->fontdata;
1795         
1796         if (userspace) {
1797                 if ((i = verify_area( VERIFY_READ, (void *)data, size )))
1798                         return i;
1799                 if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER )))
1800                         return( -ENOMEM );
1801                 new_data += sizeof(int);
1802                 REFCOUNT(new_data) = 1; /* usage counter */
1803                 memcpy_fromfs( new_data, data, size );
1804                 p->fontdata = new_data;
1805                 p->userfont = 1;
1806         }
1807         else {
1808                 p->fontdata = data;
1809                 p->userfont = 0;
1810         }
1811         p->fontwidth = w;
1812         p->fontheight = h;
1813 
1814   activate:
1815         if (resize) {
1816                 p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
1817                 if (divides(p->ywrapstep, p->fontheight))
1818                         p->scrollmode = SCROLL_YWRAP;
1819                 else if (divides(p->ypanstep, p->fontheight) &&
1820                                  p->var.yres_virtual >= p->var.yres+p->fontheight)
1821                         p->scrollmode = SCROLL_YPAN;
1822                 else
1823                         p->scrollmode = SCROLL_YMOVE;
1824 
1825                 vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
1826         }
1827         else if (unit == fg_console)
1828                 update_screen( unit );
1829         
1830         if (old_data) {
1831                 if (--REFCOUNT(old_data) == 0) {
1832                         kfree( old_data - sizeof(int) );
1833                 }
1834         }
1835         
1836         return( 0 );
1837 }
1838 
1839 
1840 /* ====================================================================== */
1841 
1842 /*
1843  *    Low Level Operations for the various display memory organizations.
1844  *
1845  *    Currently only the following organizations are supported here:
1846  *
1847  *      - Monochrome
1848  *      - Color Interleaved Planes à la Amiga
1849  *      - Color Normal Planes
1850  *      - Color Interleaved Planes à la Atari (2, 4 and 8 planes)
1851  *      - Color Packed Pixels (8 and 16 bpp)
1852  *      - Cybervision Color Packed Pixels (accelerated)
1853  */
1854 
1855 #ifdef CONFIG_FBCON_MONO
1856 
1857    /*
1858     *    Monochrome
1859     */
1860 
1861 static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
1862                        int height, int width)
1863 {
1864    u_char *src, *dest;
1865    u_int rows;
1866 
1867    if (sx == 0 && sy == 0 && width == p->next_line) {
1868       src = p->screen_base;
1869       dest = p->screen_base+dy*p->fontheight*width;
1870       mymemmove(dest, src, height*p->fontheight*width);
1871    } else if (dy <= sy) {
1872       src = p->screen_base+sy*p->fontheight*p->next_line+sx;
1873       dest = p->screen_base+dy*p->fontheight*p->next_line+dx;
1874       for (rows = height*p->fontheight; rows--;) {
1875          mymemmove(dest, src, width);
1876          src += p->next_line;
1877          dest += p->next_line;
1878       }
1879    } else {
1880       src = p->screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx;
1881       dest = p->screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx;
1882       for (rows = height*p->fontheight; rows--;) {
1883          mymemmove(dest, src, width);
1884          src -= p->next_line;
1885          dest -= p->next_line;
1886       }
1887    }
1888 }
1889 
1890 
1891 static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx,
     /* [previous][next][first][last][top][bottom][index][help] */
1892                        int height, int width)
1893 {
1894    u_char *dest;
1895    u_int rows;
1896 
1897    dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
1898 
1899    if (sx == 0 && width == p->next_line)
1900       if (attr_reverse(p,conp))
1901          mymemset(dest, height*p->fontheight*width);
1902       else
1903          mymemclear(dest, height*p->fontheight*width);
1904    else
1905       for (rows = height*p->fontheight; rows--; dest += p->next_line)
1906          if (attr_reverse(p,conp))
1907             mymemset(dest, width);
1908          else
1909             mymemclear_small(dest, width);
1910 }
1911 
1912 
1913 static void putc_mono(struct vc_data *conp, struct display *p, int c, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
1914                       int x)
1915 {
1916    u_char *dest, *cdat;
1917    u_int rows, bold, reverse, underline;
1918    u_char d;
1919 
1920    c &= 0xff;
1921 
1922    dest = p->screen_base+y*p->fontheight*p->next_line+x;
1923    cdat = p->fontdata+c*p->fontheight;
1924    bold = attr_bold(p,conp);
1925    reverse = attr_reverse(p,conp);
1926    underline = attr_underline(p,conp);
1927 
1928    for (rows = p->fontheight; rows--; dest += p->next_line) {
1929       d = *cdat++;
1930       if (underline && !rows)
1931          d = 0xff;
1932       else if (bold)
1933          d |= d>>1;
1934       if (reverse)
1935          d = ~d;
1936       *dest = d;
1937    }
1938 }
1939 
1940 
1941 static void putcs_mono(struct vc_data *conp, struct display *p, const char *s,
     /* [previous][next][first][last][top][bottom][index][help] */
1942                        int count, int y, int x)
1943 {
1944    u_char *dest, *dest0, *cdat;
1945    u_int rows, bold, reverse, underline;
1946    u_char c, d;
1947 
1948    dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
1949    bold = attr_bold(p,conp);
1950    reverse = attr_reverse(p,conp);
1951    underline = attr_underline(p,conp);
1952 
1953    while (count--) {
1954       c = *s++;
1955       dest = dest0++;
1956       cdat = p->fontdata+c*p->fontheight;
1957       for (rows = p->fontheight; rows--; dest += p->next_line) {
1958          d = *cdat++;
1959          if (underline && !rows)
1960             d = 0xff;
1961          else if (bold)
1962             d |= d>>1;
1963          if (reverse)
1964             d = ~d;
1965          *dest = d;
1966       }
1967    }
1968 }
1969 
1970 
1971 static void rev_char_mono(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
1972 {
1973    u_char *dest;
1974    u_int rows;
1975 
1976    dest = p->screen_base+y*p->fontheight*p->next_line+x;
1977    for (rows = p->fontheight; rows--; dest += p->next_line)
1978       *dest = ~*dest;
1979 }
1980 
1981 #endif /* CONFIG_FBCON_MONO */
1982 
1983 
1984 /* ====================================================================== */
1985 
1986 #ifdef CONFIG_FBCON_ILBM
1987 
1988    /*
1989     *    Color Interleaved Planes
1990     *
1991     *    This code heavily relies on the fact that
1992     *
1993     *       next_line == interleave == next_plane*bits_per_pixel
1994     *
1995     *    But maybe it can be merged with the code for normal bitplanes without
1996     *    much performance loss?
1997     */
1998 
1999 static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
2000                        int height, int width)
2001 {
2002    if (sx == 0 && sy == 0 && width == p->next_plane)
2003       mymemmove(p->screen_base+dy*p->fontheight*p->next_line, p->screen_base,
2004                 height*p->fontheight*p->next_line);
2005    else {
2006       u_char *src, *dest;
2007       u_int i;
2008 
2009       if (dy <= sy) {
2010          src = p->screen_base+sy*p->fontheight*p->next_line+sx;
2011          dest = p->screen_base+dy*p->fontheight*p->next_line+dx;
2012          for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) {
2013             mymemmove(dest, src, width);
2014             src += p->next_plane;
2015             dest += p->next_plane;
2016          }
2017       } else {
2018          src = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx;
2019          dest = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx;
2020          for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) {
2021             src -= p->next_plane;
2022             dest -= p->next_plane;
2023             mymemmove(dest, src, width);
2024          }
2025       }
2026    }
2027 }
2028 
2029 
2030 static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
     /* [previous][next][first][last][top][bottom][index][help] */
2031                        int height, int width)
2032 {
2033    u_char *dest;
2034    u_int i, rows;
2035    int bg, bg0;
2036 
2037    dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
2038 
2039    bg0 = attr_bgcol_ec(p,conp);
2040    for (rows = height*p->fontheight; rows--;) {
2041       bg = bg0;
2042       for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
2043          if (bg & 1)
2044             mymemset(dest, width);
2045          else
2046             mymemclear(dest, width);
2047          bg >>= 1;
2048       }
2049    }
2050 }
2051 
2052 
2053 static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
2054                       int x)
2055 {
2056    u_char *dest, *cdat;
2057    u_int rows, i;
2058    u_char d;
2059    int fg0, bg0, fg, bg;
2060 
2061    c &= 0xff;
2062 
2063    dest = p->screen_base+y*p->fontheight*p->next_line+x;
2064    cdat = p->fontdata+c*p->fontheight;
2065    fg0 = attr_fgcol(p,conp);
2066    bg0 = attr_bgcol(p,conp);
2067 
2068    for (rows = p->fontheight; rows--;) {
2069       d = *cdat++;
2070       fg = fg0;
2071       bg = bg0;
2072       for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
2073          if (bg & 1)
2074             if (fg & 1)
2075                *dest = 0xff;
2076             else
2077                *dest = ~d;
2078          else
2079             if (fg & 1)
2080                *dest = d;
2081             else
2082                *dest = 0x00;
2083          bg >>= 1;
2084          fg >>= 1;
2085       }
2086    }
2087 }
2088 
2089 
2090 /*
2091  *    I split the console character loop in two parts:
2092  *
2093  *      - slow version: this blits one character at a time
2094  *
2095  *      - fast version: this blits 4 characters at a time at a longword aligned
2096  *                      address, to reduce the number of expensive Chip RAM
2097  *                      accesses.
2098  *
2099  *    Experiments on my A4000/040 revealed that this makes a console switch on a
2100  *    640x400 screen with 256 colors about 3 times faster.
2101  *
2102  *                                                                Geert
2103  */
2104 
2105 static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
     /* [previous][next][first][last][top][bottom][index][help] */
2106                        int count, int y, int x)
2107 {
2108    u_char *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
2109    u_int rows, i;
2110    u_char c1, c2, c3, c4;
2111    u_long d;
2112    int fg0, bg0, fg, bg;
2113 
2114    dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
2115    fg0 = attr_fgcol(p,conp);
2116    bg0 = attr_bgcol(p,conp);
2117 
2118    while (count--)
2119       if (x&3 || count < 3) {   /* Slow version */
2120          c1 = *s++;
2121          dest = dest0++;
2122          x++;
2123 
2124          cdat1 = p->fontdata+c1*p->fontheight;
2125          for (rows = p->fontheight; rows--;) {
2126             d = *cdat1++;
2127             fg = fg0;
2128             bg = bg0;
2129             for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
2130                if (bg & 1)
2131                   if (fg & 1)
2132                      *dest = 0xff;
2133                   else
2134                      *dest = ~d;
2135                else
2136                   if (fg & 1)
2137                      *dest = d;
2138                   else
2139                      *dest = 0x00;
2140                bg >>= 1;
2141                fg >>= 1;
2142             }
2143          }
2144       } else {                      /* Fast version */
2145          c1 = s[0];
2146          c2 = s[1];
2147          c3 = s[2];
2148          c4 = s[3];
2149 
2150          dest = dest0;
2151          cdat1 = p->fontdata+c1*p->fontheight;
2152          cdat2 = p->fontdata+c2*p->fontheight;
2153          cdat3 = p->fontdata+c3*p->fontheight;
2154          cdat4 = p->fontdata+c4*p->fontheight;
2155          for (rows = p->fontheight; rows--;) {
2156             d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
2157             fg = fg0;
2158             bg = bg0;
2159             for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
2160                if (bg & 1)
2161                   if (fg & 1)
2162                      *(u_long *)dest = 0xffffffff;
2163                   else
2164                      *(u_long *)dest = ~d;
2165                else
2166                   if (fg & 1)
2167                      *(u_long *)dest = d;
2168                   else
2169                      *(u_long *)dest = 0x00000000;
2170                bg >>= 1;
2171                fg >>= 1;
2172             }
2173          }
2174          s += 4;
2175          dest0 += 4;
2176          x += 4;
2177          count -= 3;
2178       }
2179 }
2180 
2181 
2182 static void rev_char_ilbm(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
2183 {
2184    u_char *dest, *dest0;
2185    u_int rows, i;
2186    int mask;
2187 
2188    dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
2189    mask = p->fgcol ^ p->bgcol;
2190 
2191    /*
2192     *    This should really obey the individual character's
2193     *    background and foreground colors instead of simply
2194     *    inverting.
2195     */
2196 
2197    for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
2198       if (mask & 1) {
2199          dest = dest0;
2200          for (rows = p->fontheight; rows--; dest += p->next_line)
2201             *dest = ~*dest;
2202       }
2203       mask >>= 1;
2204    }
2205 }
2206 
2207 #endif /* CONFIG_FBCON_ILBM */
2208 
2209 
2210 /* ====================================================================== */
2211 
2212 #ifdef CONFIG_FBCON_PLANES
2213 
2214    /*
2215     *    Color Planes
2216     */
2217 
2218 static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
2219                        int height, int width)
2220 {
2221    u_char *src, *dest, *src0, *dest0;
2222    u_int i, rows;
2223 
2224    if (sx == 0 && sy == 0 && width == p->next_line) {
2225       src = p->screen_base;
2226       dest = p->screen_base+dy*p->fontheight*width;
2227       for (i = p->var.bits_per_pixel; i--;) {
2228          mymemmove(dest, src, height*p->fontheight*width);
2229          src += p->next_plane;
2230          dest += p->next_plane;
2231       }
2232    } else if (dy <= sy) {
2233       src0 = p->screen_base+sy*p->fontheight*p->next_line+sx;
2234       dest0 = p->screen_base+dy*p->fontheight*p->next_line+dx;
2235       for (i = p->var.bits_per_pixel; i--;) {
2236          src = src0;
2237          dest = dest0;
2238          for (rows = height*p->fontheight; rows--;) {
2239             mymemmove(dest, src, width);
2240             src += p->next_line;
2241             dest += p->next_line;
2242          }
2243          src0 += p->next_plane;
2244          dest0 += p->next_plane;
2245       }
2246    } else {
2247       src0 = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx;
2248       dest0 = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx;
2249       for (i = p->var.bits_per_pixel; i--;) {
2250          src = src0;
2251          dest = dest0;
2252          for (rows = height*p->fontheight; rows--;) {
2253             src -= p->next_line;
2254             dest -= p->next_line;
2255             mymemmove(dest, src, width);
2256          }
2257          src0 += p->next_plane;
2258          dest0 += p->next_plane;
2259       }
2260    }
2261 }
2262 
2263 
2264 static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx,
     /* [previous][next][first][last][top][bottom][index][help] */
2265                        int height, int width)
2266 {
2267    u_char *dest, *dest0;
2268    u_int i, rows;
2269    int bg;
2270 
2271    dest0 = p->screen_base+sy*p->fontheight*p->next_line+sx;
2272 
2273    bg = attr_bgcol_ec(p,conp);
2274    for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
2275       dest = dest0;
2276       for (rows = height*p->fontheight; rows--; dest += p->next_line)
2277          if (bg & 1)
2278             mymemset(dest, width);
2279          else
2280             mymemclear(dest, width);
2281       bg >>= 1;
2282    }
2283 }
2284 
2285 
2286 static void putc_plan(struct vc_data *conp, struct display *p, int c, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
2287                       int x)
2288 {
2289    u_char *dest, *dest0, *cdat, *cdat0;
2290    u_int rows, i;
2291    u_char d;
2292    int fg, bg;
2293 
2294    c &= 0xff;
2295 
2296    dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
2297    cdat0 = p->fontdata+c*p->fontheight;
2298    fg = attr_fgcol(p,conp);
2299    bg = attr_bgcol(p,conp);
2300 
2301    for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
2302       dest = dest0;
2303       cdat = cdat0;
2304       for (rows = p->fontheight; rows--; dest += p->next_line) {
2305          d = *cdat++;
2306          if (bg & 1)
2307             if (fg & 1)
2308                *dest = 0xff;
2309             else
2310                *dest = ~d;
2311          else
2312             if (fg & 1)
2313                *dest = d;
2314             else
2315                *dest = 0x00;
2316       }
2317       bg >>= 1;
2318       fg >>= 1;
2319    }
2320 }
2321 
2322 
2323 /*
2324  *    I split the console character loop in two parts
2325  *    (cfr. fbcon_putcs_ilbm())
2326  */
2327 
2328 static void putcs_plan(struct vc_data *conp, struct display *p, const char *s,
     /* [previous][next][first][last][top][bottom][index][help] */
2329                        int count, int y, int x)
2330 {
2331    u_char *dest, *dest0, *dest1;
2332    u_char *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
2333    u_int rows, i;
2334    u_char c1, c2, c3, c4;
2335    u_long d;
2336    int fg0, bg0, fg, bg;
2337 
2338    dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
2339    fg0 = attr_fgcol(p,conp);
2340    bg0 = attr_bgcol(p,conp);
2341 
2342    while (count--)
2343       if (x&3 || count < 3) {   /* Slow version */
2344          c1 = *s++;
2345          dest1 = dest0++;
2346          x++;
2347 
2348          cdat10 = p->fontdata+c1*p->fontheight;
2349          fg = fg0;
2350          bg = bg0;
2351 
2352          for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) {
2353             dest = dest1;
2354             cdat1 = cdat10;
2355             for (rows = p->fontheight; rows--; dest += p->next_line) {
2356                d = *cdat1++;
2357                if (bg & 1)
2358                   if (fg & 1)
2359                      *dest = 0xff;
2360                   else
2361                      *dest = ~d;
2362                else
2363                   if (fg & 1)
2364                      *dest = d;
2365                   else
2366                      *dest = 0x00;
2367             }
2368             bg >>= 1;
2369             fg >>= 1;
2370          }
2371       } else {                      /* Fast version */
2372          c1 = s[0];
2373          c2 = s[1];
2374          c3 = s[2];
2375          c4 = s[3];
2376 
2377          dest1 = dest0;
2378          cdat10 = p->fontdata+c1*p->fontheight;
2379          cdat20 = p->fontdata+c2*p->fontheight;
2380          cdat30 = p->fontdata+c3*p->fontheight;
2381          cdat40 = p->fontdata+c4*p->fontheight;
2382          fg = fg0;
2383          bg = bg0;
2384 
2385          for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) {
2386             dest = dest1;
2387             cdat1 = cdat10;
2388             cdat2 = cdat20;
2389             cdat3 = cdat30;
2390             cdat4 = cdat40;
2391             for (rows = p->fontheight; rows--; dest += p->next_line) {
2392                d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
2393                if (bg & 1)
2394                   if (fg & 1)
2395                      *(u_long *)dest = 0xffffffff;
2396                   else
2397                      *(u_long *)dest = ~d;
2398                else
2399                   if (fg & 1)
2400                      *(u_long *)dest = d;
2401                   else
2402                      *(u_long *)dest = 0x00000000;
2403             }
2404             bg >>= 1;
2405             fg >>= 1;
2406          }
2407          s += 4;
2408          dest0 += 4;
2409          x += 4;
2410          count -= 3;
2411       }
2412 }
2413 
2414 
2415 static void rev_char_plan(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
2416 {
2417    u_char *dest, *dest0;
2418    u_int rows, i;
2419    int mask;
2420 
2421    dest0 = p->screen_base+y*p->fontheight*p->next_line+x;
2422    mask = p->fgcol ^ p->bgcol;
2423 
2424    /*
2425     *    This should really obey the individual character's
2426     *    background and foreground colors instead of simply
2427     *    inverting.
2428     */
2429 
2430    for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
2431       if (mask & 1) {
2432          dest = dest0;
2433          for (rows = p->fontheight; rows--; dest += p->next_line)
2434             *dest = ~*dest;
2435       }
2436       mask >>= 1;
2437    }
2438 }
2439 
2440 #endif /* CONFIG_FBCON_PLANES */
2441 
2442 
2443 /* ====================================================================== */
2444 
2445 #ifdef CONFIG_FBCON_2PLANE
2446 
2447    /*
2448     *    2 Planes (2-bytes interleave)
2449     */
2450 
2451 /* Increment/decrement 2 plane addresses */
2452 
2453 #define INC_2P(p)       do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0)
2454 #define DEC_2P(p)       do { if ((long)(--(p)) & 1) (p) -= 2; } while(0)
2455 
2456 /* Convert a standard 4 bit color to our 2 bit color assignment:
2457  * If at least two RGB channels are active, the low bit is turned on;
2458  * The intensity bit (b3) is shifted into b1.
2459  */
2460 
2461 #define COLOR_2P(c)     (((c & 7) >= 3 && (c & 7) != 4) | (c & 8) >> 2)
2462 
2463 
2464 static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
2465                           int height, int width)
2466 {
2467         /* bmove() has to distinguish two major cases: If both, source and
2468          * destination, start at even addresses or both are at odd
2469          * addresses, just the first odd and last even column (if present)
2470          * require special treatment (memmove_col()). The rest between
2471          * then can be copied by normal operations, because all adjacent
2472          * bytes are affected and are to be stored in the same order.
2473          *   The pathological case is when the move should go from an odd
2474          * address to an even or vice versa. Since the bytes in the plane
2475          * words must be assembled in new order, it seems wisest to make
2476          * all movements by memmove_col().
2477          */
2478 
2479     if (sx == 0 && dx == 0 && width == p->next_line/2) {
2480                 /* Special (but often used) case: Moving whole lines can be
2481                  * done with memmove()
2482                  */
2483                 mymemmove(p->screen_base + dy * p->next_line * p->fontheight,
2484                                    p->screen_base + sy * p->next_line * p->fontheight,
2485                                    p->next_line * height * p->fontheight);
2486     } else {
2487         int rows, cols;
2488         u_char *src;
2489         u_char *dst;
2490         int bytes = p->next_line;
2491         int linesize = bytes * p->fontheight;
2492                        u_int colsize  = height * p->fontheight;
2493                        u_int upwards  = (dy < sy) || (dy == sy && dx < sx);
2494 
2495                 if ((sx & 1) == (dx & 1)) {
2496                         /* odd->odd or even->even */
2497 
2498                         if (upwards) {
2499 
2500                                 src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
2501                                 dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
2502 
2503                                 if (sx & 1) {
2504                                         memmove_2p_col(dst, src, colsize, bytes);
2505                                         src += 3;
2506                                         dst += 3;
2507                                         --width;
2508                                 }
2509 
2510                                 if (width > 1) {
2511                                         for(rows = colsize; rows > 0; --rows) {
2512                                                 mymemmove(dst, src, (width>>1)*4);
2513                                                 src += bytes;
2514                                                 dst += bytes;
2515                                         }
2516                                 }
2517 
2518                                 if (width & 1) {
2519                                         src -= colsize * bytes;
2520                                         dst -= colsize * bytes;
2521                                         memmove_2p_col(dst + (width>>1)*4, src + (width>>1)*4,
2522                                                                         colsize, bytes);
2523                                 }
2524                         }
2525                         else {
2526 
2527                                 if (!((sx+width-1) & 1)) {
2528                                         src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*4;
2529                                         dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*4;
2530                                         memmove_2p_col(dst, src, colsize, bytes);
2531                                         --width;
2532                                 }
2533 
2534                                 src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
2535                                 dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
2536 
2537                                 if (width > 1) {
2538                                         src += colsize * bytes + (sx & 1)*3;
2539                                         dst += colsize * bytes + (sx & 1)*3;
2540                                         for(rows = colsize; rows > 0; --rows) {
2541                                                 src -= bytes;
2542                                                 dst -= bytes;
2543                                                 mymemmove(dst, src, (width>>1)*4);
2544                                         }
2545                                 }
2546 
2547                                 if (width & 1) {
2548                                         memmove_2p_col(dst-3, src-3, colsize, bytes);
2549                                 }
2550 
2551                         }
2552                 }
2553                 else {
2554                         /* odd->even or even->odd */
2555 
2556                         if (upwards) {
2557                                 src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
2558                                 dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
2559                                 for(cols = width; cols > 0; --cols) {
2560                                         memmove_2p_col(dst, src, colsize, bytes);
2561                                         INC_2P(src);
2562                                         INC_2P(dst);
2563                                 }
2564                         }
2565                         else {
2566                                 sx += width-1;
2567                                 dx += width-1;
2568                                 src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
2569                                 dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
2570                                 for(cols = width; cols > 0; --cols) {
2571                                         memmove_2p_col(dst, src, colsize, bytes);
2572                                         DEC_2P(src);
2573                                         DEC_2P(dst);
2574                                 }
2575                         }
2576                 }
2577 
2578 
2579     }
2580 }
2581 
2582 
2583 static void clear_2_plane(struct vc_data *conp, struct display *p, int sy,
     /* [previous][next][first][last][top][bottom][index][help] */
2584                           int sx, int height, int width)
2585 {
2586     ulong offset;
2587     u_char *start;
2588     int rows;
2589     int bytes = p->next_line;
2590     int lines = height * p->fontheight;
2591     ulong  size;
2592         u_long          cval;
2593         u_short                 pcval;
2594 
2595     cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp)));
2596 
2597     if (sx == 0 && width == bytes/2) {
2598 
2599         offset = sy * bytes * p->fontheight;
2600         size   = lines * bytes;
2601                 memset_even_2p(p->screen_base+offset, size, cval);
2602 
2603     } else {
2604 
2605         offset = (sy * bytes * p->fontheight) + (sx>>1)*4 + (sx & 1);
2606                 start = p->screen_base + offset;
2607                 pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp)));
2608 
2609                 /* Clears are split if the region starts at an odd column or
2610                  * end at an even column. These extra columns are spread
2611                  * across the interleaved planes. All in between can be
2612                  * cleared by normal mymemclear_small(), because both bytes of
2613                  * the single plane words are affected.
2614                  */
2615 
2616                 if (sx & 1) {
2617                         memclear_2p_col(start, lines, pcval, bytes);
2618                         start += 3;
2619                         width--;
2620                 }
2621 
2622                 if (width & 1) {
2623                         memclear_2p_col(start + (width>>1)*4, lines, pcval, bytes);
2624                         width--;
2625                 }
2626 
2627                 if (width) {
2628                         for(rows = lines; rows-- ; start += bytes)
2629                                 memset_even_2p(start, width*2, cval);
2630                 }
2631     }
2632 }
2633 
2634 
2635 static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
2636                          int x)
2637 {
2638    u_char   *dest;
2639     u_char   *cdat;
2640     int rows;
2641     int bytes = p->next_line;
2642         ulong                     eorx, fgx, bgx, fdx;
2643 
2644         c &= 0xff;
2645 
2646     dest  = p->screen_base + y * p->fontheight * bytes + (x>>1)*4 + (x & 1);
2647     cdat  = p->fontdata + (c * p->fontheight);
2648 
2649         fgx   = expand2w(COLOR_2P(attr_fgcol(p,conp)));
2650         bgx   = expand2w(COLOR_2P(attr_bgcol(p,conp)));
2651         eorx  = fgx ^ bgx;
2652 
2653     for(rows = p->fontheight ; rows-- ; dest += bytes) {
2654                 fdx = dup2w(*cdat++);
2655                 __asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */
2656                                                            : "a" (dest), "d" ((fdx & eorx) ^ bgx));
2657         }
2658 }
2659 
2660 
2661 static void putcs_2_plane(struct vc_data *conp, struct display *p,
     /* [previous][next][first][last][top][bottom][index][help] */
2662                           const char *s, int count, int y, int x)
2663 {
2664         u_char   *dest, *dest0;
2665     u_char   *cdat, c;
2666     int rows;
2667     int bytes;
2668         ulong                     eorx, fgx, bgx, fdx;
2669 
2670     bytes = p->next_line;
2671     dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*4 + (x & 1);
2672         fgx   = expand2w(COLOR_2P(attr_fgcol(p,conp)));
2673         bgx   = expand2w(COLOR_2P(attr_bgcol(p,conp)));
2674         eorx  = fgx ^ bgx;
2675 
2676         while (count--) {
2677 
2678                 c = *s++;
2679                 cdat  = p->fontdata + (c * p->fontheight);
2680 
2681                 for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
2682                         fdx = dup2w(*cdat++);
2683                         __asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */
2684                                                                    : "a" (dest), "d" ((fdx & eorx) ^ bgx));
2685                 }
2686                 INC_2P(dest0);
2687         }
2688 }
2689 
2690 
2691 static void rev_char_2_plane(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
2692 {
2693    u_char *dest;
2694    int j;
2695    int bytes;
2696 
2697    dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*4 + (x & 1);
2698    j = p->fontheight;
2699    bytes = p->next_line;
2700    while (j--)
2701      {
2702       /* This should really obey the individual character's
2703        * background and foreground colors instead of simply
2704        * inverting.
2705        */
2706        dest[0] = ~dest[0];
2707        dest[2] = ~dest[2];
2708        dest += bytes;
2709      }
2710 }
2711 #endif /* CONFIG_FBCON_2PLANE */
2712 
2713 
2714 /* ====================================================================== */
2715 
2716 #ifdef CONFIG_FBCON_4PLANE
2717 
2718    /*
2719     *    4 Planes (2-bytes interleave)
2720     */
2721 
2722 /* Increment/decrement 4 plane addresses */
2723 
2724 #define INC_4P(p)       do { if (!((long)(++(p)) & 1)) (p) += 6; } while(0)
2725 #define DEC_4P(p)       do { if ((long)(--(p)) & 1) (p) -= 6; } while(0)
2726 
2727 
2728 static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
2729                           int height, int width)
2730 {
2731         /* bmove() has to distinguish two major cases: If both, source and
2732          * destination, start at even addresses or both are at odd
2733          * addresses, just the first odd and last even column (if present)
2734          * require special treatment (memmove_col()). The rest between
2735          * then can be copied by normal operations, because all adjacent
2736          * bytes are affected and are to be stored in the same order.
2737          *   The pathological case is when the move should go from an odd
2738          * address to an even or vice versa. Since the bytes in the plane
2739          * words must be assembled in new order, it seems wisest to make
2740          * all movements by memmove_col().
2741          */
2742 
2743     if (sx == 0 && dx == 0 && width == p->next_line/4) {
2744                 /* Special (but often used) case: Moving whole lines can be
2745                  * done with memmove()
2746                  */
2747                 mymemmove(p->screen_base + dy * p->next_line * p->fontheight,
2748                                    p->screen_base + sy * p->next_line * p->fontheight,
2749                                    p->next_line * height * p->fontheight);
2750     } else {
2751         int rows, cols;
2752         u_char *src;
2753         u_char *dst;
2754         int bytes = p->next_line;
2755         int linesize = bytes * p->fontheight;
2756                        u_int colsize  = height * p->fontheight;
2757                        u_int upwards  = (dy < sy) || (dy == sy && dx < sx);
2758 
2759                 if ((sx & 1) == (dx & 1)) {
2760                         /* odd->odd or even->even */
2761 
2762                         if (upwards) {
2763 
2764                                 src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
2765                                 dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
2766 
2767                                 if (sx & 1) {
2768                                         memmove_4p_col(dst, src, colsize, bytes);
2769                                         src += 7;
2770                                         dst += 7;
2771                                         --width;
2772                                 }
2773 
2774                                 if (width > 1) {
2775                                         for(rows = colsize; rows > 0; --rows) {
2776                                                 mymemmove(dst, src, (width>>1)*8);
2777                                                 src += bytes;
2778                                                 dst += bytes;
2779                                         }
2780                                 }
2781 
2782                                 if (width & 1) {
2783                                         src -= colsize * bytes;
2784                                         dst -= colsize * bytes;
2785                                         memmove_4p_col(dst + (width>>1)*8, src + (width>>1)*8,
2786                                                                         colsize, bytes);
2787                                 }
2788                         }
2789                         else {
2790 
2791                                 if (!((sx+width-1) & 1)) {
2792                                         src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*8;
2793                                         dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*8;
2794                                         memmove_4p_col(dst, src, colsize, bytes);
2795                                         --width;
2796                                 }
2797 
2798                                 src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
2799                                 dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
2800 
2801                                 if (width > 1) {
2802                                         src += colsize * bytes + (sx & 1)*7;
2803                                         dst += colsize * bytes + (sx & 1)*7;
2804                                         for(rows = colsize; rows > 0; --rows) {
2805                                                 src -= bytes;
2806                                                 dst -= bytes;
2807                                                 mymemmove(dst, src, (width>>1)*8);
2808                                         }
2809                                 }
2810 
2811                                 if (width & 1) {
2812                                         memmove_4p_col(dst-7, src-7, colsize, bytes);
2813                                 }
2814 
2815                         }
2816                 }
2817                 else {
2818                         /* odd->even or even->odd */
2819 
2820                         if (upwards) {
2821                                 src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
2822                                 dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
2823                                 for(cols = width; cols > 0; --cols) {
2824                                         memmove_4p_col(dst, src, colsize, bytes);
2825                                         INC_4P(src);
2826                                         INC_4P(dst);
2827                                 }
2828                         }
2829                         else {
2830                                 sx += width-1;
2831                                 dx += width-1;
2832                                 src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
2833                                 dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
2834                                 for(cols = width; cols > 0; --cols) {
2835                                         memmove_4p_col(dst, src, colsize, bytes);
2836                                         DEC_4P(src);
2837                                         DEC_4P(dst);
2838                                 }
2839                         }
2840                 }
2841 
2842 
2843     }
2844 }
2845 
2846 
2847 static void clear_4_plane(struct vc_data *conp, struct display *p, int sy,
     /* [previous][next][first][last][top][bottom][index][help] */
2848                           int sx, int height, int width)
2849 {
2850     ulong offset;
2851     u_char *start;
2852     int rows;
2853     int bytes = p->next_line;
2854     int lines = height * p->fontheight;
2855     ulong  size;
2856         u_long          cval1, cval2, pcval;
2857 
2858         expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2);
2859 
2860     if (sx == 0 && width == bytes/4) {
2861 
2862         offset = sy * bytes * p->fontheight;
2863         size   = lines * bytes;
2864                 memset_even_4p(p->screen_base+offset, size, cval1, cval2);
2865 
2866     } else {
2867 
2868         offset = (sy * bytes * p->fontheight) + (sx>>1)*8 + (sx & 1);
2869                 start = p->screen_base + offset;
2870                 pcval = expand4l(attr_bgcol_ec(p,conp));
2871 
2872                 /* Clears are split if the region starts at an odd column or
2873                  * end at an even column. These extra columns are spread
2874                  * across the interleaved planes. All in between can be
2875                  * cleared by normal mymemclear_small(), because both bytes of
2876                  * the single plane words are affected.
2877                  */
2878 
2879                 if (sx & 1) {
2880                         memclear_4p_col(start, lines, pcval, bytes);
2881                         start += 7;
2882                         width--;
2883                 }
2884 
2885                 if (width & 1) {
2886                         memclear_4p_col(start + (width>>1)*8, lines, pcval, bytes);
2887                         width--;
2888                 }
2889 
2890                 if (width) {
2891                         for(rows = lines; rows-- ; start += bytes)
2892                                 memset_even_4p(start, width*4, cval1, cval2);
2893                 }
2894     }
2895 }
2896 
2897 
2898 static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
2899                          int x)
2900 {
2901         u_char   *dest;
2902     u_char   *cdat;
2903     int rows;
2904     int bytes = p->next_line;
2905         ulong                     eorx, fgx, bgx, fdx;
2906 
2907         c &= 0xff;
2908 
2909     dest  = p->screen_base + y * p->fontheight * bytes + (x>>1)*8 + (x & 1);
2910     cdat  = p->fontdata + (c * p->fontheight);
2911 
2912         fgx   = expand4l(attr_fgcol(p,conp));
2913         bgx   = expand4l(attr_bgcol(p,conp));
2914         eorx  = fgx ^ bgx;
2915 
2916     for(rows = p->fontheight ; rows-- ; dest += bytes) {
2917                 fdx = dup4l(*cdat++);
2918                 __asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */
2919                                                            : "a" (dest), "d" ((fdx & eorx) ^ bgx));
2920         }
2921 }
2922 
2923 
2924 static void putcs_4_plane(struct vc_data *conp, struct display *p,
     /* [previous][next][first][last][top][bottom][index][help] */
2925                           const char *s, int count, int y, int x)
2926 {
2927         u_char   *dest, *dest0;
2928     u_char   *cdat, c;
2929     int rows;
2930     int bytes;
2931         ulong                     eorx, fgx, bgx, fdx;
2932 
2933     bytes = p->next_line;
2934     dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*8 + (x & 1);
2935         fgx   = expand4l(attr_fgcol(p,conp));
2936         bgx   = expand4l(attr_bgcol(p,conp));
2937         eorx  = fgx ^ bgx;
2938 
2939         while (count--) {
2940 
2941                 /* I think, unrolling the loops like in the 1 plane case isn't
2942                  * practicable here, because the body is much longer for 4
2943                  * planes (mostly the dup4l()). I guess, unrolling this would
2944                  * need more than 256 bytes and so exceed the instruction
2945                  * cache :-(
2946                  */
2947 
2948                 c = *s++;
2949                 cdat  = p->fontdata + (c * p->fontheight);
2950 
2951                 for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
2952                         fdx = dup4l(*cdat++);
2953                         __asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */
2954                                                                    : "a" (dest), "d" ((fdx & eorx) ^ bgx));
2955                 }
2956                 INC_4P(dest0);
2957         }
2958 }
2959 
2960 
2961 static void rev_char_4_plane(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
2962 {
2963    u_char *dest;
2964    int j;
2965    int bytes;
2966 
2967    dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*8 + (x & 1);
2968    j = p->fontheight;
2969    bytes = p->next_line;
2970 
2971    while (j--)
2972      {
2973       /* This should really obey the individual character's
2974        * background and foreground colors instead of simply
2975        * inverting.
2976        */
2977        dest[0] = ~dest[0];
2978        dest[2] = ~dest[2];
2979        dest[4] = ~dest[4];
2980        dest[6] = ~dest[6];
2981        dest += bytes;
2982      }
2983 }
2984 #endif /* CONFIG_FBCON_4PLANE */
2985 
2986 
2987 /* ====================================================================== */
2988 
2989 #ifdef CONFIG_FBCON_8PLANE
2990 
2991    /*
2992     *    8 Planes (2-bytes interleave)
2993     */
2994 
2995 /* In 8 plane mode, 256 colors would be possible, but only the first
2996  * 16 are used by the console code (the upper 4 bits are
2997  * background/unused). For that, the following functions mask off the
2998  * higher 4 bits of each color.
2999  */
3000 
3001 /* Increment/decrement 8 plane addresses */
3002 
3003 #define INC_8P(p)       do { if (!((long)(++(p)) & 1)) (p) += 14; } while(0)
3004 #define DEC_8P(p)       do { if ((long)(--(p)) & 1) (p) -= 14; } while(0)
3005 
3006 
3007 static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
3008                           int height, int width)
3009 {
3010         /* bmove() has to distinguish two major cases: If both, source and
3011          * destination, start at even addresses or both are at odd
3012          * addresses, just the first odd and last even column (if present)
3013          * require special treatment (memmove_col()). The rest between
3014          * then can be copied by normal operations, because all adjacent
3015          * bytes are affected and are to be stored in the same order.
3016          *   The pathological case is when the move should go from an odd
3017          * address to an even or vice versa. Since the bytes in the plane
3018          * words must be assembled in new order, it seems wisest to make
3019          * all movements by memmove_col().
3020          */
3021 
3022     if (sx == 0 && dx == 0 && width == p->next_line/8) {
3023                 /* Special (but often used) case: Moving whole lines can be
3024                  * done with memmove()
3025                  */
3026       fast_memmove (p->screen_base + dy * p->next_line * p->fontheight,
3027                     p->screen_base + sy * p->next_line * p->fontheight,
3028                     p->next_line * height * p->fontheight);
3029     } else {
3030         int rows, cols;
3031         u_char *src;
3032         u_char *dst;
3033         int bytes = p->next_line;
3034         int linesize = bytes * p->fontheight;
3035                        u_int colsize  = height * p->fontheight;
3036                        u_int upwards  = (dy < sy) || (dy == sy && dx < sx);
3037 
3038                 if ((sx & 1) == (dx & 1)) {
3039                         /* odd->odd or even->even */
3040 
3041                         if (upwards) {
3042 
3043                                 src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
3044                                 dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
3045 
3046                                 if (sx & 1) {
3047                                         memmove_8p_col(dst, src, colsize, bytes);
3048                                         src += 15;
3049                                         dst += 15;
3050                                         --width;
3051                                 }
3052 
3053                                 if (width > 1) {
3054                                         for(rows = colsize; rows > 0; --rows) {
3055                                                 fast_memmove (dst, src, (width >> 1) * 16);
3056                                                 src += bytes;
3057                                                 dst += bytes;
3058                                         }
3059                                 }
3060 
3061                                 if (width & 1) {
3062                                         src -= colsize * bytes;
3063                                         dst -= colsize * bytes;
3064                                         memmove_8p_col(dst + (width>>1)*16, src + (width>>1)*16,
3065                                                                         colsize, bytes);
3066                                 }
3067                         }
3068                         else {
3069 
3070                                 if (!((sx+width-1) & 1)) {
3071                                         src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*16;
3072                                         dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*16;
3073                                         memmove_8p_col(dst, src, colsize, bytes);
3074                                         --width;
3075                                 }
3076 
3077                                 src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
3078                                 dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
3079 
3080                                 if (width > 1) {
3081                                         src += colsize * bytes + (sx & 1)*15;
3082                                         dst += colsize * bytes + (sx & 1)*15;
3083                                         for(rows = colsize; rows > 0; --rows) {
3084                                                 src -= bytes;
3085                                                 dst -= bytes;
3086                                                 fast_memmove (dst, src, (width>>1)*16);
3087                                         }
3088                                 }
3089 
3090                                 if (width & 1) {
3091                                         memmove_8p_col(dst-15, src-15, colsize, bytes);
3092                                 }
3093 
3094                         }
3095                 }
3096                 else {
3097                         /* odd->even or even->odd */
3098 
3099                         if (upwards) {
3100                                 src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
3101                                 dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
3102                                 for(cols = width; cols > 0; --cols) {
3103                                         memmove_8p_col(dst, src, colsize, bytes);
3104                                         INC_8P(src);
3105                                         INC_8P(dst);
3106                                 }
3107                         }
3108                         else {
3109                                 sx += width-1;
3110                                 dx += width-1;
3111                                 src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
3112                                 dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
3113                                 for(cols = width; cols > 0; --cols) {
3114                                         memmove_8p_col(dst, src, colsize, bytes);
3115                                         DEC_8P(src);
3116                                         DEC_8P(dst);
3117                                 }
3118                         }
3119                 }
3120 
3121 
3122     }
3123 }
3124 
3125 
3126 static void clear_8_plane(struct vc_data *conp, struct display *p, int sy,
     /* [previous][next][first][last][top][bottom][index][help] */
3127                           int sx, int height, int width)
3128 {
3129     ulong offset;
3130     u_char *start;
3131     int rows;
3132     int bytes = p->next_line;
3133     int lines = height * p->fontheight;
3134     ulong  size;
3135         u_long          cval1, cval2, cval3, cval4, pcval1, pcval2;
3136 
3137         expand8ql(attr_bgcol_ec(p,conp), cval1, cval2, cval3, cval4);
3138 
3139     if (sx == 0 && width == bytes/8) {
3140 
3141         offset = sy * bytes * p->fontheight;
3142         size   = lines * bytes;
3143                 memset_even_8p(p->screen_base+offset, size, cval1, cval2, cval3, cval4);
3144 
3145     } else {
3146 
3147         offset = (sy * bytes * p->fontheight) + (sx>>1)*16 + (sx & 1);
3148                 start = p->screen_base + offset;
3149                 expand8dl(attr_bgcol_ec(p,conp), &pcval1, &pcval2);
3150 
3151                 /* Clears are split if the region starts at an odd column or
3152                  * end at an even column. These extra columns are spread
3153                  * across the interleaved planes. All in between can be
3154                  * cleared by normal mymemclear_small(), because both bytes of
3155                  * the single plane words are affected.
3156                  */
3157 
3158                 if (sx & 1) {
3159                         memclear_8p_col(start, lines, pcval1, pcval2, bytes);
3160                         start += 7;
3161                         width--;
3162                 }
3163 
3164                 if (width & 1) {
3165                         memclear_8p_col(start + (width>>1)*16, lines, pcval1,
3166                                                          pcval2, bytes);
3167                         width--;
3168                 }
3169 
3170                 if (width) {
3171                         for(rows = lines; rows-- ; start += bytes)
3172                                 memset_even_8p(start, width*8, cval1, cval2, cval3, cval4);
3173                 }
3174     }
3175 }
3176 
3177 
3178 static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
3179                          int x)
3180 {
3181         u_char   *dest;
3182     u_char   *cdat;
3183     int rows;
3184     int bytes = p->next_line;
3185         ulong                     eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
3186 
3187         c &= 0xff;
3188 
3189     dest  = p->screen_base + y * p->fontheight * bytes + (x>>1)*16 + (x & 1);
3190     cdat  = p->fontdata + (c * p->fontheight);
3191 
3192         expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2);
3193         expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2);
3194         eorx1  = fgx1 ^ bgx1; eorx2  = fgx2 ^ bgx2;
3195 
3196     for(rows = p->fontheight ; rows-- ; dest += bytes) {
3197                 fdx = dup4l(*cdat++);
3198                 __asm__ __volatile__
3199                         ("movepl %1,%0@(0)\n\t"
3200                           "movepl %2,%0@(8)"
3201                           : /* no outputs */
3202                           : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
3203                             "d" ((fdx & eorx2) ^ bgx2)
3204                         );
3205         }
3206 }
3207 
3208 
3209 static void putcs_8_plane(struct vc_data *conp, struct display *p,
     /* [previous][next][first][last][top][bottom][index][help] */
3210                           const char *s, int count, int y, int x)
3211 {
3212         u_char   *dest, *dest0;
3213     u_char   *cdat, c;
3214     int rows;
3215     int bytes;
3216         ulong                     eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
3217 
3218     bytes = p->next_line;
3219     dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*16 + (x & 1);
3220 
3221         expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2);
3222         expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2);
3223         eorx1  = fgx1 ^ bgx1; eorx2  = fgx2 ^ bgx2;
3224 
3225         while (count--) {
3226 
3227                 /* I think, unrolling the loops like in the 1 plane case isn't
3228                  * practicable here, because the body is much longer for 4
3229                  * planes (mostly the dup4l()). I guess, unrolling this would
3230                  * need more than 256 bytes and so exceed the instruction
3231                  * cache :-(
3232                  */
3233 
3234                 c = *s++;
3235                 cdat  = p->fontdata + (c * p->fontheight);
3236 
3237                 for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
3238                         fdx = dup4l(*cdat++);
3239                         __asm__ __volatile__
3240                                 ("movepl %1,%0@(0)\n\t"
3241                                   "movepl %2,%0@(8)"
3242                                   : /* no outputs */
3243                                   : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
3244                                   "d" ((fdx & eorx2) ^ bgx2)
3245                                 );
3246                 }
3247                 INC_8P(dest0);
3248         }
3249 }
3250 
3251 
3252 static void rev_char_8_plane(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
3253 {
3254    u_char *dest;
3255    int j;
3256    int bytes;
3257 
3258    dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*16 + (x & 1);
3259    j = p->fontheight;
3260    bytes = p->next_line;
3261 
3262    while (j--)
3263      {
3264       /* This should really obey the individual character's
3265        * background and foreground colors instead of simply
3266        * inverting. For 8 plane mode, only the lower 4 bits of the
3267        * color are inverted, because only that color registers have
3268        * been set up.
3269        */
3270        dest[0] = ~dest[0];
3271        dest[2] = ~dest[2];
3272        dest[4] = ~dest[4];
3273        dest[6] = ~dest[6];
3274        dest += bytes;
3275      }
3276 }
3277 #endif /* CONFIG_FBCON_8PLANE */
3278 
3279 
3280 /* ====================================================================== */
3281 
3282 #ifdef CONFIG_FBCON_8PACKED
3283 
3284    /*
3285     *    8 bpp Packed Pixels
3286     */
3287 
3288 static u_long nibbletab_8_packed[]={
3289 0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
3290 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
3291 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
3292 0xffff0000,0xffff00ff,0xffffff00,0xffffffff};
3293 
3294 static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
3295                            int height, int width)
3296 {
3297         int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
3298         u_char *src,*dst;
3299 
3300         if (sx == 0 && dx == 0 && width * 8 == bytes) {
3301                 mymemmove(p->screen_base + dy * linesize,
3302                           p->screen_base + sy * linesize,
3303                           height * linesize);
3304         }
3305         else {
3306                 if (dy < sy || (dy == sy && dx < sx)) {
3307                         src = p->screen_base + sy * linesize + sx * 8;
3308                         dst = p->screen_base + dy * linesize + dx * 8;
3309                         for (rows = height * p->fontheight ; rows-- ;) {
3310                                 mymemmove(dst, src, width * 8);
3311                                 src += bytes;
3312                                 dst += bytes;
3313                         }
3314                 }
3315                 else {
3316                         src = p->screen_base + (sy+height) * linesize + sx * 8
3317                                 - bytes;
3318                         dst = p->screen_base + (dy+height) * linesize + dx * 8
3319                                 - bytes;
3320                         for (rows = height * p->fontheight ; rows-- ;) {
3321                                 mymemmove(dst, src, width * 8);
3322                                 src -= bytes;
3323                                 dst -= bytes;
3324                         }
3325                 }
3326         }
3327 }
3328 
3329 
3330 static void clear_8_packed(struct vc_data *conp, struct display *p, int sy,
     /* [previous][next][first][last][top][bottom][index][help] */
3331                            int sx, int height, int width)
3332 {
3333         u_char *dest0,*dest;
3334         int bytes=p->next_line,lines=height * p->fontheight, rows, i;
3335         u_long bgx;
3336 
3337         dest = p->screen_base + sy * p->fontheight * bytes + sx * 8;
3338 
3339         bgx=attr_bgcol_ec(p,conp);
3340         bgx |= (bgx << 8);
3341         bgx |= (bgx << 16);
3342 
3343         if (sx == 0 && width * 8 == bytes) {
3344                 for (i = 0 ; i < lines * width ; i++) {
3345                         ((u_long *)dest)[0]=bgx;
3346                         ((u_long *)dest)[1]=bgx;
3347                         dest+=8;
3348                 }
3349         } else {
3350                 dest0=dest;
3351                 for (rows = lines; rows-- ; dest0 += bytes) {
3352                         dest=dest0;
3353                         for (i = 0 ; i < width ; i++) {
3354                                 ((u_long *)dest)[0]=bgx;
3355                                 ((u_long *)dest)[1]=bgx;
3356                                 dest+=8;
3357                         }
3358                 }
3359         }
3360 }
3361 
3362 
3363 static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
3364                           int x)
3365 {
3366         u_char *dest,*cdat;
3367         int bytes=p->next_line,rows;
3368         ulong eorx,fgx,bgx;
3369 
3370         c &= 0xff;
3371 
3372         dest = p->screen_base + y * p->fontheight * bytes + x * 8;
3373         cdat = p->fontdata + c * p->fontheight;
3374 
3375         fgx=attr_fgcol(p,conp);
3376         bgx=attr_bgcol(p,conp);
3377         fgx |= (fgx << 8);
3378         fgx |= (fgx << 16);
3379         bgx |= (bgx << 8);
3380         bgx |= (bgx << 16);
3381         eorx = fgx ^ bgx;
3382 
3383         for (rows = p->fontheight ; rows-- ; dest += bytes) {
3384                 ((u_long *)dest)[0]=
3385                         (nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx;
3386                 ((u_long *)dest)[1]=
3387                         (nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx;
3388         }
3389 }
3390 
3391 
3392 static void putcs_8_packed(struct vc_data *conp, struct display *p,
     /* [previous][next][first][last][top][bottom][index][help] */
3393                            const char *s, int count, int y, int x)
3394 {
3395         u_char *cdat, c, *dest, *dest0;
3396         int rows,bytes=p->next_line;
3397         u_long eorx, fgx, bgx;
3398 
3399         dest0 = p->screen_base + y * p->fontheight * bytes + x * 8;
3400         fgx=attr_fgcol(p,conp);
3401         bgx=attr_bgcol(p,conp);
3402         fgx |= (fgx << 8);
3403         fgx |= (fgx << 16);
3404         bgx |= (bgx << 8);
3405         bgx |= (bgx << 16);
3406         eorx = fgx ^ bgx;
3407         while (count--) {
3408                 c = *s++;
3409                 cdat = p->fontdata + c * p->fontheight;
3410 
3411                 for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
3412                         ((u_long *)dest)[0]=
3413                         (nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx;
3414                         ((u_long *)dest)[1]=
3415                         (nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx;
3416                 }
3417                 dest0+=8;
3418         }
3419 }
3420 
3421 
3422 static void rev_char_8_packed(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
3423 {
3424         u_char *dest;
3425         int bytes=p->next_line, rows;
3426 
3427         dest = p->screen_base + y * p->fontheight * bytes + x * 8;
3428         for (rows = p->fontheight ; rows-- ; dest += bytes) {
3429                 ((u_long *)dest)[0] ^= 0x0f0f0f0f;
3430                 ((u_long *)dest)[1] ^= 0x0f0f0f0f;
3431         }
3432 }
3433 
3434 #endif /* CONFIG_FBCON_8PACKED */
3435 
3436 
3437 /* ====================================================================== */
3438 
3439 #ifdef CONFIG_FBCON_16PACKED
3440 
3441    /*
3442     *    16 bpp Packed Pixels
3443     */
3444 
3445 u_short packed16_cmap[16];
3446 
3447 static u_long tab_16_packed[]={
3448 0x00000000,0x0000ffff,0xffff0000,0xffffffff};
3449 
3450 static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
3451                             int height, int width)
3452 {
3453         int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
3454         u_char *src,*dst;
3455 
3456         if (sx == 0 && dx == 0 && width * 16 == bytes) {
3457                 mymemmove(p->screen_base + dy * linesize,
3458                           p->screen_base + sy * linesize,
3459                           height * linesize);
3460         }
3461         else {
3462                 if (dy < sy || (dy == sy && dx < sx)) {
3463                         src = p->screen_base + sy * linesize + sx * 16;
3464                         dst = p->screen_base + dy * linesize + dx * 16;
3465                         for (rows = height * p->fontheight ; rows-- ;) {
3466                                 mymemmove(dst, src, width * 16);
3467                                 src += bytes;
3468                                 dst += bytes;
3469                         }
3470                 }
3471                 else {
3472                         src = p->screen_base + (sy+height) * linesize + sx * 16
3473                                 - bytes;
3474                         dst = p->screen_base + (dy+height) * linesize + dx * 16
3475                                 - bytes;
3476                         for (rows = height * p->fontheight ; rows-- ;) {
3477                                 mymemmove(dst, src, width * 16);
3478                                 src -= bytes;
3479                                 dst -= bytes;
3480                         }
3481                 }
3482         }
3483 }
3484 
3485 
3486 static void clear_16_packed(struct vc_data *conp, struct display *p, int sy,
     /* [previous][next][first][last][top][bottom][index][help] */
3487                             int sx, int height, int width)
3488 {
3489         u_char *dest0,*dest;
3490         int bytes=p->next_line,lines=height * p->fontheight, rows, i;
3491         u_long bgx;
3492 
3493         dest = p->screen_base + sy * p->fontheight * bytes + sx * 16;
3494 
3495         bgx = attr_bgcol_ec(p,conp);
3496         bgx = packed16_cmap[bgx];
3497         bgx |= (bgx << 16);
3498 
3499         if (sx == 0 && width * 16 == bytes) {
3500                 for (i = 0 ; i < lines * width ; i++) {
3501                         ((u_long *)dest)[0]=bgx;
3502                         ((u_long *)dest)[1]=bgx;
3503                         ((u_long *)dest)[2]=bgx;
3504                         ((u_long *)dest)[3]=bgx;
3505                         dest+=16;
3506                 }
3507         } else {
3508                 dest0=dest;
3509                 for (rows = lines; rows-- ; dest0 += bytes) {
3510                         dest=dest0;
3511                         for (i = 0 ; i < width ; i++) {
3512                                 ((u_long *)dest)[0]=bgx;
3513                                 ((u_long *)dest)[1]=bgx;
3514                                 ((u_long *)dest)[2]=bgx;
3515                                 ((u_long *)dest)[3]=bgx;
3516                                 dest+=16;
3517                         }
3518                 }
3519         }
3520 }
3521 
3522 
3523 static void putc_16_packed(struct vc_data *conp, struct display *p, int c,
     /* [previous][next][first][last][top][bottom][index][help] */
3524                            int y, int x)
3525 {
3526         u_char *dest,*cdat;
3527         int bytes=p->next_line,rows;
3528         ulong eorx,fgx,bgx;
3529 
3530         c &= 0xff;
3531 
3532         dest = p->screen_base + y * p->fontheight * bytes + x * 16;
3533         cdat = p->fontdata + c * p->fontheight;
3534 
3535         fgx = attr_fgcol(p,conp);
3536         fgx = packed16_cmap[fgx];
3537         bgx = attr_bgcol(p,conp);
3538         bgx = packed16_cmap[bgx];
3539         fgx |= (fgx << 16);
3540         bgx |= (bgx << 16);
3541         eorx = fgx ^ bgx;
3542 
3543         for (rows = p->fontheight ; rows-- ; dest += bytes) {
3544                 ((u_long *)dest)[0]=
3545                         (tab_16_packed[*cdat >> 6] & eorx) ^ bgx;
3546                 ((u_long *)dest)[1]=
3547                         (tab_16_packed[*cdat >> 4 & 0x3] & eorx) ^ bgx;
3548                 ((u_long *)dest)[2]=
3549                         (tab_16_packed[*cdat >> 2 & 0x3] & eorx) ^ bgx;
3550                 ((u_long *)dest)[3]=
3551                         (tab_16_packed[*cdat++ & 0x3] & eorx) ^ bgx;
3552         }
3553 }
3554 
3555 
3556 /* TODO */
3557 static void putcs_16_packed(struct vc_data *conp, struct display *p,
     /* [previous][next][first][last][top][bottom][index][help] */
3558                             const char *s, int count, int y, int x)
3559 {
3560         u_char *cdat, c, *dest, *dest0;
3561         int rows,bytes=p->next_line;
3562         u_long eorx, fgx, bgx;
3563 
3564         dest0 = p->screen_base + y * p->fontheight * bytes + x * 16;
3565         fgx = attr_fgcol(p,conp);
3566         fgx = packed16_cmap[fgx];
3567         bgx = attr_bgcol(p,conp);
3568         bgx = packed16_cmap[bgx];
3569         fgx |= (fgx << 16);
3570         bgx |= (bgx << 16);
3571         eorx = fgx ^ bgx;
3572         while (count--) {
3573                 c = *s++;
3574                 cdat = p->fontdata + c * p->fontheight;
3575 
3576                 for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
3577                         ((u_long *)dest)[0]=
3578                                 (tab_16_packed[*cdat >> 6] & eorx) ^ bgx;
3579                         ((u_long *)dest)[1]=
3580                                 (tab_16_packed[*cdat >> 4 & 0x3] & eorx) ^ bgx;
3581                         ((u_long *)dest)[2]=
3582                                 (tab_16_packed[*cdat >> 2 & 0x3] & eorx) ^ bgx;
3583                         ((u_long *)dest)[3]=
3584                                 (tab_16_packed[*cdat++ & 0x3] & eorx) ^ bgx;
3585                 }
3586                 dest0+=16;
3587         }
3588 }
3589 
3590 
3591 static void rev_char_16_packed(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
3592 {
3593         u_char *dest;
3594         int bytes=p->next_line, rows;
3595 
3596         dest = p->screen_base + y * p->fontheight * bytes + x * 16;
3597         for (rows = p->fontheight ; rows-- ; dest += bytes) {
3598                 ((u_long *)dest)[0] ^= 0xffffffff;
3599                 ((u_long *)dest)[1] ^= 0xffffffff;
3600                 ((u_long *)dest)[2] ^= 0xffffffff;
3601                 ((u_long *)dest)[3] ^= 0xffffffff;
3602         }
3603 }
3604 
3605 #endif /* CONFIG_FBCON_16PACKED */
3606 
3607 
3608 /* ====================================================================== */
3609 
3610 #ifdef CONFIG_FBCON_CYBER
3611 
3612    /*
3613     *    Cybervision (accelerated)
3614     */
3615 
3616 static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx,
     /* [previous][next][first][last][top][bottom][index][help] */
3617                         int height, int width)
3618 {
3619         sx *= 8; dx *= 8; width *= 8;
3620         Cyber_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx,
3621                 (u_short)(dy*p->fontheight), (u_short)width,
3622                 (u_short)(height*p->fontheight), (u_short)S3_NEW);
3623 }
3624 
3625 
3626 static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx,
     /* [previous][next][first][last][top][bottom][index][help] */
3627                         int height, int width)
3628 {
3629    u_char bg;
3630         
3631         sx *= 8; width *= 8;
3632         bg = attr_bgcol_ec(p,conp);
3633    Cyber_RectFill((u_short)sx, (u_short)(sy*p->fontheight), (u_short)width,
3634                   (u_short)(height*p->fontheight), (u_short)S3_NEW,
3635                   (u_short)bg); 
3636 }
3637 
3638 
3639 static void putc_cyber(struct vc_data *conp, struct display *p, int c, int y,
     /* [previous][next][first][last][top][bottom][index][help] */
3640                        int x)
3641 {
3642         u_char *dest, *cdat;
3643         u_long tmp;
3644         u_int rows, reverse, underline; 
3645         u_char d;
3646    u_char fg, bg;
3647 
3648    c &= 0xff;
3649 
3650         dest = p->screen_base+y*p->fontheight*p->next_line+8*x;
3651         cdat = p->fontdata+(c*p->fontheight);
3652    fg = disp->fgcol;
3653    bg = disp->bgcol;
3654         reverse = conp->vc_reverse;
3655         underline = conp->vc_underline;
3656 
3657    Cyber_WaitBlit();
3658         for (rows = p->fontheight; rows--; dest += p->next_line) {
3659                 d = *cdat++;
3660 
3661                 if (underline && !rows)
3662                         d = 0xff;
3663                 if (reverse)
3664                         d = ~d;
3665 
3666       tmp =  ((d & 0x80) ? fg : bg) << 24;
3667       tmp |= ((d & 0x40) ? fg : bg) << 16;
3668       tmp |= ((d & 0x20) ? fg : bg) << 8;
3669       tmp |= ((d & 0x10) ? fg : bg);
3670       *((u_long*) dest) = tmp;
3671       tmp =  ((d & 0x8) ? fg : bg) << 24;
3672       tmp |= ((d & 0x4) ? fg : bg) << 16;
3673       tmp |= ((d & 0x2) ? fg : bg) << 8;
3674       tmp |= ((d & 0x1) ? fg : bg);
3675       *((u_long*) dest + 1) = tmp;
3676         }
3677 }
3678 
3679 
3680 static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
     /* [previous][next][first][last][top][bottom][index][help] */
3681                         int count, int y, int x)
3682 {
3683         u_char *dest, *dest0, *cdat;
3684    u_long tmp;
3685         u_int rows, reverse, underline;
3686         u_char c, d;
3687    u_char fg, bg;
3688 
3689         dest0 = p->screen_base+y*p->fontheight*p->next_line+8*x;
3690    fg = disp->fgcol;
3691    bg = disp->bgcol;
3692         reverse = conp->vc_reverse;
3693         underline = conp->vc_underline;
3694 
3695    Cyber_WaitBlit();
3696         while (count--) {
3697                 c = *s++;
3698                 dest = dest0;
3699       dest0 += 8;
3700                 cdat = p->fontdata+(c*p->fontheight);
3701                 for (rows = p->fontheight; rows--; dest += p->next_line) {
3702                         d = *cdat++;
3703 
3704                         if (underline && !rows)
3705                                 d = 0xff;
3706                         if (reverse)
3707                                 d = ~d;
3708 
3709          tmp =  ((d & 0x80) ? fg : bg) << 24;
3710          tmp |= ((d & 0x40) ? fg : bg) << 16;
3711          tmp |= ((d & 0x20) ? fg : bg) << 8;
3712          tmp |= ((d & 0x10) ? fg : bg);
3713          *((u_long*) dest) = tmp;
3714          tmp =  ((d & 0x8) ? fg : bg) << 24;
3715          tmp |= ((d & 0x4) ? fg : bg) << 16;
3716          tmp |= ((d & 0x2) ? fg : bg) << 8;
3717          tmp |= ((d & 0x1) ? fg : bg);
3718          *((u_long*) dest + 1) = tmp;
3719                 }
3720         }
3721 }
3722 
3723 
3724 static void rev_char_cyber(struct display *p, int x, int y)
     /* [previous][next][first][last][top][bottom][index][help] */
3725 {
3726         u_char *dest;
3727         u_int rows;
3728    u_char fg, bg;
3729 
3730    fg = disp->fgcol;
3731    bg = disp->bgcol;
3732 
3733         dest = p->screen_base+y*p->fontheight*p->next_line+8*x;
3734    Cyber_WaitBlit();
3735         for (rows = p->fontheight; rows--; dest += p->next_line) {
3736                 *dest = (*dest == fg) ? bg : fg;
3737       *(dest+1) = (*(dest + 1) == fg) ? bg : fg;
3738       *(dest+2) = (*(dest + 2) == fg) ? bg : fg;
3739       *(dest+3) = (*(dest + 3) == fg) ? bg : fg;
3740       *(dest+4) = (*(dest + 4) == fg) ? bg : fg;
3741       *(dest+5) = (*(dest + 5) == fg) ? bg : fg;
3742       *(dest+6) = (*(dest + 6) == fg) ? bg : fg;
3743       *(dest+7) = (*(dest + 7) == fg) ? bg : fg;
3744         }
3745 }
3746 
3747 #endif /* CONFIG_FBCON_CYBER */
3748 
3749 
3750 /* ====================================================================== */
3751 
3752    /*
3753     *    The console `switch' structure for the frame buffer based console
3754     */
3755 
3756 struct consw fb_con = {
3757    fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
3758    fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
3759    fbcon_blank, fbcon_get_font, fbcon_set_font
3760 };

/* [previous][next][first][last][top][bottom][index][help] */