root/arch/m68k/amiga/amifb.c

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

DEFINITIONS

This source file includes following definitions.
  1. mono_init_vblank
  2. mono_video_setup
  3. mono_build_clist_hdr
  4. mono_build_clist_dyn
  5. mono_build_cursor
  6. mono_build_ecs_colors
  7. mono_display_init
  8. mono_amifb_interrupt
  9. mono_amiga_fb_get_fix
  10. mono_amiga_fb_get_var
  11. mono_amiga_fb_set_disp
  12. mono_amiga_fb_set_var
  13. mono_amiga_fb_get_cmap
  14. mono_amiga_fb_set_cmap
  15. mono_amiga_fb_pan_display
  16. mono_amiga_fb_ioctl
  17. mono_amifb_switch
  18. mono_amifb_updatevar
  19. mono_amifb_blank
  20. mono_amiga_fb_init
  21. ocs_init
  22. ecs_init
  23. aga_init
  24. aga_encode_fix
  25. aga_decode_var
  26. aga_encode_var
  27. aga_getcolreg
  28. aga_setcolreg
  29. aga_pan_display
  30. aga_do_vmode
  31. aga_do_blank
  32. aga_do_movecursor
  33. aga_do_flashcursor
  34. aga_get_fix_cursorinfo
  35. aga_get_var_cursorinfo
  36. aga_set_var_cursorinfo
  37. aga_get_cursorstate
  38. aga_set_cursorstate
  39. aga_build_clist_hdr
  40. aga_update_clist_hdr
  41. aga_build_clist_dyn
  42. chipalloc
  43. amiga_fb_get_par
  44. amiga_fb_set_par
  45. do_fb_set_var
  46. get_default_colormap
  47. do_fb_get_cmap
  48. do_fb_set_cmap
  49. do_install_cmap
  50. memcpy_fs
  51. copy_cmap
  52. alloc_cmap
  53. amiga_fb_get_fix
  54. amiga_fb_get_var
  55. amiga_fb_set_disp
  56. amiga_fb_set_var
  57. amiga_fb_get_cmap
  58. amiga_fb_set_cmap
  59. amiga_fb_pan_display
  60. amiga_fb_ioctl
  61. amiga_fb_get_fix_cursorinfo
  62. amiga_fb_get_var_cursorinfo
  63. amiga_fb_set_var_cursorinfo
  64. amiga_fb_get_cursorstate
  65. amiga_fb_set_cursorstate
  66. amiga_video_setup
  67. amiga_fb_init
  68. amifb_switch
  69. amifb_updatevar
  70. amifb_blank
  71. amifb_interrupt
  72. strtoke
  73. get_video_mode
  74. check_default_mode

   1 /*
   2  * linux/arch/m68k/amiga/amifb.c -- Low level implementation of the Amiga frame
   3  *                                  buffer device
   4  *
   5  *    Copyright (C) 1995 Geert Uytterhoeven
   6  *
   7  *
   8  * This file is based on the Atari frame buffer device (atafb.c):
   9  *
  10  *    Copyright (C) 1994 Martin Schaller
  11  *                       Roman Hodek
  12  *
  13  *          with work by Andreas Schwab
  14  *                       Guenther Kelleter
  15  *
  16  * and on the original Amiga console driver (amicon.c):
  17  *
  18  *    Copyright (C) 1993 Hamish Macdonald
  19  *                       Greg Harp
  20  *    Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
  21  *
  22  *          with work by William Rucklidge (wjr@cs.cornell.edu)
  23  *                       Geert Uytterhoeven
  24  *                       Jes Sorensen (jds@kom.auc.dk)
  25  *
  26  *
  27  * History:
  28  *
  29  *   -  2 Dec 95: AGA version by Geert Uytterhoeven
  30  *
  31  *
  32  * This file is subject to the terms and conditions of the GNU General Public
  33  * License.  See the file README.legal in the main directory of this archive
  34  * for more details.
  35  */
  36 
  37 
  38 #include <linux/kernel.h>
  39 #include <linux/errno.h>
  40 #include <linux/string.h>
  41 #include <linux/mm.h>
  42 #include <linux/tty.h>
  43 #include <linux/malloc.h>
  44 #include <linux/delay.h>
  45 #include <linux/config.h>
  46 #include <linux/interrupt.h>
  47 #include <asm/segment.h>
  48 #include <asm/system.h>
  49 #include <asm/irq.h>
  50 #include <asm/amigahw.h>
  51 #include <asm/amigaints.h>
  52 #include <asm/bootinfo.h>
  53 #include <linux/fb.h>
  54 
  55 
  56 #undef  CONFIG_AMIFB_OCS
  57 #undef  CONFIG_AMIFB_ECS
  58 #define CONFIG_AMIFB_AGA   /* Only AGA support at the moment */
  59 
  60 #define USE_MONO_AMIFB_IF_NON_AGA
  61 
  62 
  63 /* -------------------- BEGIN: TODO ----------------------------------------- **
  64 
  65 
  66    - scan the sources for `TODO'
  67 
  68    - timings and monspecs can be set via the kernel command line (cfr. Atari)
  69 
  70    - OCS and ECS
  71 
  72    - hardware cursor
  73 
  74    - Interlaced screen -> Interlaced sprite/hardware cursor
  75 
  76 
  77 ** -------------------- END: TODO ------------------------------------------- */
  78 
  79 
  80 /*******************************************************************************
  81 
  82 
  83    Generic video timings
  84    ---------------------
  85 
  86    Timings used by the frame buffer interface:
  87 
  88    +----------+---------------------------------------------+----------+-------+
  89    |          |                ^                            |          |       |
  90    |          |                |upper_margin                |          |       |
  91    |          |                ¥                            |          |       |
  92    +----------###############################################----------+-------+
  93    |          #                ^                            #          |       |
  94    |          #                |                            #          |       |
  95    |          #                |                            #          |       |
  96    |          #                |                            #          |       |
  97    |   left   #                |                            #  right   | hsync |
  98    |  margin  #                |       xres                 #  margin  |  len  |
  99    |<-------->#<---------------+--------------------------->#<-------->|<----->|
 100    |          #                |                            #          |       |
 101    |          #                |                            #          |       |
 102    |          #                |                            #          |       |
 103    |          #                |yres                        #          |       |
 104    |          #                |                            #          |       |
 105    |          #                |                            #          |       |
 106    |          #                |                            #          |       |
 107    |          #                |                            #          |       |
 108    |          #                |                            #          |       |
 109    |          #                |                            #          |       |
 110    |          #                |                            #          |       |
 111    |          #                |                            #          |       |
 112    |          #                ¥                            #          |       |
 113    +----------###############################################----------+-------+
 114    |          |                ^                            |          |       |
 115    |          |                |lower_margin                |          |       |
 116    |          |                ¥                            |          |       |
 117    +----------+---------------------------------------------+----------+-------+
 118    |          |                ^                            |          |       |
 119    |          |                |vsync_len                   |          |       |
 120    |          |                ¥                            |          |       |
 121    +----------+---------------------------------------------+----------+-------+
 122 
 123 
 124    Amiga video timings
 125    -------------------
 126 
 127    The Amiga native chipsets uses another timing scheme:
 128 
 129       - hsstrt:   Start of horizontal synchronization pulse
 130       - hsstop:   End of horizontal synchronization pulse
 131       - htotal:   Last value on the line (i.e. line length = htotal+1)
 132       - vsstrt:   Start of vertical synchronization pulse
 133       - vsstop:   Start of vertical synchronization pulse
 134       - vtotal:   Last line value (i.e. number of lines = vtotal+1)
 135       - hcenter:  Start of vertical retrace for interlace
 136 
 137    You can specify the blanking timings independently. Currently I just set
 138    them equal to the respective synchronization values:
 139 
 140       - hbstrt:   Start of horizontal blank
 141       - hbstop:   End of horizontal blank
 142       - vbstrt:   Start of vertical blank
 143       - vbstop:   Start of vertical blank
 144 
 145    Horizontal values are in color clock cycles (280 ns), vertical values are in
 146    scanlines.
 147 
 148    (0, 0) is somewhere in the upper-left corner :-)
 149 
 150 
 151    Amiga visible window definitions
 152    --------------------------------
 153 
 154    Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
 155    make corrections and/or additions.
 156 
 157    Within the above synchronization specifications, the visible window is
 158    defined by the following parameters (actual register resolutions may be
 159    different; all horizontal values are normalized with respect to the pixel
 160    clock):
 161 
 162       - diwstrt_h:   Horizontal start of the visible window
 163       - diwstop_h:   Horizontal stop+1(*) of the visible window
 164       - diwstrt_v:   Vertical start of the visible window
 165       - diwstop_v:   Vertical stop of the visible window
 166       - ddfstrt:     Horizontal start of display DMA
 167       - ddfstop:     Horizontal stop of display DMA
 168       - hscroll:     Horizontal display output delay
 169 
 170    Sprite positioning:
 171 
 172       - sprstrt_h:   Horizontal start-4 of sprite
 173       - sprstrt_v:   Vertical start of sprite
 174 
 175    (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
 176 
 177    Horizontal values are in dotclock cycles (35 ns), vertical values are in
 178    scanlines.
 179 
 180    (0, 0) is somewhere in the upper-left corner :-)
 181 
 182 
 183    Dependencies (AGA, SHRES (35 ns dotclock))
 184    -------------------------------------------
 185 
 186    Since there are much more parameters for the Amiga display than for the
 187    frame buffer interface, there must be some dependencies among the Amiga display
 188    parameters. Here's what I found out:
 189 
 190       - ddfstrt and ddfstop are best aligned to 64 pixels.
 191       - the chipset needs 64+4 horizontal pixels after the DMA start before the
 192         first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to
 193         display the first pixel on the line too. Increase diwstrt_h for virtual
 194         screen panning.
 195       - the display DMA always fetches 64 pixels at a time (*).
 196       - ddfstop is ddfstrt+#pixels-64.
 197       - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1
 198         more than htotal.
 199       - hscroll simply adds a delay to the display output. Smooth horizontal
 200         panning needs an extra 64 pixels on the left to prefetch the pixels that
 201         `fall off' on the left.
 202       - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
 203         DMA, so it's best to make the DMA start as late as possible.
 204       - you really don't want to make ddfstrt < 128, since this will steal DMA
 205         cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
 206       - I make diwstop_h and diwstop_v as large as possible.
 207 
 208    (*) This is for fmode = 3. Lower fmodes allow for more freedom w.r.t. the
 209        timings, but they limit the maximum display depth, and cause more stress
 210        on the custom chip bus.
 211 
 212 
 213    DMA priorities
 214    --------------
 215 
 216    Since there are limits on the earliest start value for display DMA and the
 217    display of sprites, I use the following policy on horizontal panning and
 218    the hardware cursor:
 219 
 220       - if you want to start display DMA too early, you loose the ability to
 221         do smooth horizontal panning (xpanstep 1 -> 64).
 222       - if you want to go even further, you loose the hardware cursor too.
 223 
 224    IMHO a hardware cursor is more important for X than horizontal scrolling,
 225    so that's my motivation.
 226 
 227 
 228    Implementation
 229    --------------
 230 
 231    aga_decode_var() converts the frame buffer values to the Amiga values. It's
 232    just a `straightforward' implementation of the above rules.
 233 
 234 
 235    Standard VGA timings
 236    --------------------
 237 
 238                xres  yres    left  right  upper  lower    hsync    vsync
 239                ----  ----    ----  -----  -----  -----    -----    -----
 240       80x25     720   400      27     45     35     12      108        2
 241       80x30     720   480      27     45     30      9      108        2
 242 
 243    These were taken from a XFree86 configuration file, recalculated for a 28 MHz
 244    dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer
 245    generic timings.
 246 
 247    As a comparison, graphics/monitor.h suggests the following:
 248 
 249                xres  yres    left  right  upper  lower    hsync    vsync
 250                ----  ----    ----  -----  -----  -----    -----    -----
 251 
 252       VGA       640   480      52    112     24     19    112 -      2 +
 253       VGA70     640   400      52    112     27     21    112 -      2 -
 254 
 255 
 256    Sync polarities
 257    ---------------
 258 
 259       VSYNC    HSYNC    Vertical size    Vertical total
 260       -----    -----    -------------    --------------
 261         +        +           Reserved          Reserved
 262         +        -                400               414
 263         -        +                350               362
 264         -        -                480               496
 265 
 266    Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
 267 
 268 
 269    Broadcast video timings
 270    -----------------------
 271 
 272    Since broadcast video timings are `fixed' and only depend on the video
 273    system (PAL/NTSC), hsync_len and vsync_len are not used and must be set to
 274    zero. All xres/yres and margin values are defined within the `visible
 275    rectangle' of the display.
 276 
 277    According to the CCIR and RETMA specifications, we have the following values:
 278 
 279    CCIR -> PAL
 280    -----------
 281 
 282       - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
 283         736 visible 70 ns pixels per line.
 284       - we have 625 scanlines, of which 575 are visible (interlaced); after
 285         rounding this becomes 576.
 286 
 287    RETMA -> NTSC
 288    -------------
 289 
 290       - a scanline is 63.5 µs long, of which 53.5 µs are visible.  This is about
 291         736 visible 70 ns pixels per line.
 292       - we have 525 scanlines, of which 485 are visible (interlaced); after
 293         rounding this becomes 484.
 294 
 295    Thus if you want a PAL compatible display, you have to do the following:
 296 
 297       - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
 298         timings are to be used.
 299       - make sure upper_margin+yres+lower_margin = 576 for an interlaced, 288
 300         for a non-interlaced and 144 for a doublescanned display.
 301       - make sure (left_margin+xres+right_margin)*pixclock is a reasonable
 302         approximation to 52.48 µs.
 303 
 304    The settings for a NTSC compatible display are straightforward.
 305 
 306    Note that in a strict sense the PAL and NTSC standards only define the
 307    encoding of the color part (chrominance) of the video signal and don't say
 308    anything about horizontal/vertical synchronization nor refresh rates.
 309    But since Amigas have RGB output, this issue isn't of any importance here.
 310 
 311 
 312                                                             -- Geert --
 313 
 314 *******************************************************************************/
 315 
 316 
 317    /*
 318     *    Custom Chipset Definitions
 319     */
 320 
 321 #define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
 322 
 323 
 324    /*
 325     *    BPLCON0 -- Bitplane Control Register 0
 326     */
 327 
 328 #define BPC0_HIRES      (0x8000)
 329 #define BPC0_BPU2       (0x4000) /* Bit plane used count */
 330 #define BPC0_BPU1       (0x2000)
 331 #define BPC0_BPU0       (0x1000)
 332 #define BPC0_HAM        (0x0800) /* HAM mode */
 333 #define BPC0_DPF        (0x0400) /* Double playfield */
 334 #define BPC0_COLOR      (0x0200) /* Enable colorburst */
 335 #define BPC0_GAUD       (0x0100) /* Genlock audio enable */
 336 #define BPC0_UHRES      (0x0080) /* Ultrahi res enable */
 337 #define BPC0_SHRES      (0x0040) /* Super hi res mode */
 338 #define BPC0_BYPASS     (0x0020) /* Bypass LUT - AGA */
 339 #define BPC0_BPU3       (0x0010) /* AGA */
 340 #define BPC0_LPEN       (0x0008) /* Light pen enable */
 341 #define BPC0_LACE       (0x0004) /* Interlace */
 342 #define BPC0_ERSY       (0x0002) /* External resync */
 343 #define BPC0_ECSENA     (0x0001) /* ECS emulation disable */
 344 
 345 
 346    /*
 347     *    BPLCON2 -- Bitplane Control Register 2
 348     */
 349 
 350 #define BPC2_ZDBPSEL2   (0x4000) /* Bitplane to be used for ZD - AGA */
 351 #define BPC2_ZDBPSEL1   (0x2000)
 352 #define BPC2_ZDBPSEL0   (0x1000)
 353 #define BPC2_ZDBPEN     (0x0800) /* Enable ZD with ZDBPSELx - AGA */
 354 #define BPC2_ZDCTEN     (0x0400) /* Enable ZD with palette bit #31 - AGA */
 355 #define BPC2_KILLEHB    (0x0200) /* Kill EHB mode - AGA */
 356 #define BPC2_RDRAM      (0x0100) /* Color table accesses read, not write - AGA */
 357 #define BPC2_SOGEN      (0x0080) /* SOG output pin high - AGA */
 358 #define BPC2_PF2PRI     (0x0040) /* PF2 priority over PF1 */
 359 #define BPC2_PF2P2      (0x0020) /* PF2 priority wrt sprites */
 360 #define BPC2_PF2P1      (0x0010)
 361 #define BPC2_PF2P0      (0x0008)
 362 #define BPC2_PF1P2      (0x0004) /* ditto PF1 */
 363 #define BPC2_PF1P1      (0x0002)
 364 #define BPC2_PF1P0      (0x0001)
 365 
 366 
 367    /*
 368     *    BPLCON3 -- Bitplane Control Register 3 (AGA)
 369     */
 370 
 371 #define BPC3_BANK2      (0x8000) /* Bits to select color register bank */
 372 #define BPC3_BANK1      (0x4000)
 373 #define BPC3_BANK0      (0x2000)
 374 #define BPC3_PF2OF2     (0x1000) /* Bits for color table offset when PF2 */
 375 #define BPC3_PF2OF1     (0x0800)
 376 #define BPC3_PF2OF0     (0x0400)
 377 #define BPC3_LOCT       (0x0200) /* Color register writes go to low bits */
 378 #define BPC3_SPRES1     (0x0080) /* Sprite resolution bits */
 379 #define BPC3_SPRES0     (0x0040)
 380 #define BPC3_BRDRBLNK   (0x0020) /* Border blanked? */
 381 #define BPC3_BRDRTRAN   (0x0010) /* Border transparent? */
 382 #define BPC3_ZDCLKEN    (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
 383 #define BPC3_BRDRSPRT   (0x0002) /* Sprites in border? */
 384 #define BPC3_EXTBLKEN   (0x0001) /* BLANK programmable */
 385 
 386 
 387    /*
 388     *    BPLCON4 -- Bitplane Control Register 4 (AGA)
 389     */
 390 
 391 #define BPC4_BPLAM7     (0x8000) /* bitplane color XOR field */
 392 #define BPC4_BPLAM6     (0x4000)
 393 #define BPC4_BPLAM5     (0x2000)
 394 #define BPC4_BPLAM4     (0x1000)
 395 #define BPC4_BPLAM3     (0x0800)
 396 #define BPC4_BPLAM2     (0x0400)
 397 #define BPC4_BPLAM1     (0x0200)
 398 #define BPC4_BPLAM0     (0x0100)
 399 #define BPC4_ESPRM7     (0x0080) /* 4 high bits for even sprite colors */
 400 #define BPC4_ESPRM6     (0x0040)
 401 #define BPC4_ESPRM5     (0x0020)
 402 #define BPC4_ESPRM4     (0x0010)
 403 #define BPC4_OSPRM7     (0x0008) /* 4 high bits for odd sprite colors */
 404 #define BPC4_OSPRM6     (0x0004)
 405 #define BPC4_OSPRM5     (0x0002)
 406 #define BPC4_OSPRM4     (0x0001)
 407 
 408 
 409    /*
 410     *    BEAMCON0 -- Beam Control Register
 411     */
 412 
 413 #define BMC0_HARDDIS    (0x4000) /* Disable hardware limits */
 414 #define BMC0_LPENDIS    (0x2000) /* Disable light pen latch */
 415 #define BMC0_VARVBEN    (0x1000) /* Enable variable vertical blank */
 416 #define BMC0_LOLDIS     (0x0800) /* Disable long/short line toggle */
 417 #define BMC0_CSCBEN     (0x0400) /* Composite sync/blank */
 418 #define BMC0_VARVSYEN   (0x0200) /* Enable variable vertical sync */
 419 #define BMC0_VARHSYEN   (0x0100) /* Enable variable horizontal sync */
 420 #define BMC0_VARBEAMEN  (0x0080) /* Enable variable beam counters */
 421 #define BMC0_DUAL       (0x0080) /* Enable alternate horizontal beam counter */
 422 #define BMC0_PAL        (0x0020) /* Set decodes for PAL */
 423 #define BMC0_VARCSYEN   (0x0010) /* Enable variable composite sync */
 424 #define BMC0_BLANKEN    (0x0008) /* Blank enable (no longer used on AGA) */
 425 #define BMC0_CSYTRUE    (0x0004) /* CSY polarity */
 426 #define BMC0_VSYTRUE    (0x0002) /* VSY polarity */
 427 #define BMC0_HSYTRUE    (0x0001) /* HSY polarity */
 428 
 429 
 430    /*
 431     *    FMODE -- Fetch Mode Control Register (AGA)
 432     */
 433 
 434 #define FMODE_SSCAN2    (0x8000) /* Sprite scan-doubling */
 435 #define FMODE_BSCAN2    (0x4000) /* Use PF2 modulus every other line */
 436 #define FMODE_SPAGEM    (0x0008) /* Sprite page mode */
 437 #define FMODE_SPR32     (0x0004) /* Sprite 32 bit fetch */
 438 #define FMODE_BPAGEM    (0x0002) /* Bitplane page mode */
 439 #define FMODE_BPL32     (0x0001) /* Bitplane 32 bit fetch */
 440 
 441 
 442    /*
 443     *    Tags used to indicate a specific Pixel Clock
 444     *
 445     *    clk_shift is the shift value to get the timings in 35 ns units
 446     */
 447 
 448 #define TAG_SHRES       (1)      /* SHRES, clk_shift = TAG_SHRES-1 */
 449 #define TAG_HIRES       (2)      /* HIRES, clk_shift = TAG_HIRES-1 */
 450 #define TAG_LORES       (3)      /* LORES, clk_shift = TAG_LORES-1 */
 451 
 452 
 453    /*
 454     *    Clock Definitions, Maximum Display Depth
 455     *
 456     *    These depend on the E-Clock or the Chipset, so they are filled in
 457     *    dynamically
 458     */
 459 
 460 static u_long pixclock[3];       /* SHRES/HIRES/LORES: index = clk_shift */
 461 static u_short maxdepth[3];      /* SHRES/HIRES/LORES: index = clk_shift */
 462 
 463 
 464    /*
 465     *    Broadcast Video Timings
 466     *
 467     *    Horizontal values are in 35 ns (SHRES) units
 468     *    Vertical values are in non-interlaced scanlines
 469     */
 470 
 471 #define PAL_WINDOW_H    (1472)   /* PAL Window Limits */
 472 #define PAL_WINDOW_V    (288)
 473 #define PAL_DIWSTRT_H   (360)
 474 #define PAL_DIWSTRT_V   (24)
 475 
 476 #define NTSC_WINDOW_H   (1472)   /* NTSC Window Limits */
 477 #define NTSC_WINDOW_V   (242)
 478 #define NTSC_DIWSTRT_H  (360)
 479 #define NTSC_DIWSTRT_V  (20)
 480 
 481 #define PAL_HTOTAL      (1816)   /* Total line length */
 482 #define NTSC_HTOTAL     (1816)   /* Needed for YWRAP */
 483 
 484 
 485    /*
 486     *    Monitor Specifications
 487     *
 488     *    These are typical for a `generic' Amiga monitor (e.g. A1960)
 489     */
 490 
 491 static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000;
 492 
 493 static u_short pwrsave = 0;      /* VESA suspend mode (not for PAL/NTSC) */
 494 
 495 
 496    /*
 497     *    Various macros
 498     */
 499 
 500 #define up8(x)          (((x)+7) & ~7)
 501 #define down8(x)        ((x) & ~7)
 502 #define div8(x)         ((x)>>3)
 503 #define mod8(x)         ((x) & 7)
 504 
 505 #define up16(x)         (((x)+15) & ~15)
 506 #define down16(x)       ((x) & ~15)
 507 #define div16(x)        ((x)>>4)
 508 #define mod16(x)        ((x) & 15)
 509 
 510 #define up32(x)         (((x)+31) & ~31)
 511 #define down32(x)       ((x) & ~31)
 512 #define div32(x)        ((x)>>5)
 513 #define mod32(x)        ((x) & 31)
 514 
 515 #define up64(x)         (((x)+63) & ~63)
 516 #define down64(x)       ((x) & ~63)
 517 #define div64(x)        ((x)>>6)
 518 #define mod64(x)        ((x) & 63)
 519 
 520 #define min(a, b)       ((a) < (b) ? (a) : (b))
 521 #define max(a, b)       ((a) > (b) ? (a) : (b))
 522 
 523 #define highw(x)        ((u_long)(x)>>16 & 0xffff)
 524 #define loww(x)         ((u_long)(x) & 0xffff)
 525 
 526 #define arraysize(x)    (sizeof(x)/sizeof(*(x)))
 527 
 528 
 529    /*
 530     *    Chip RAM we reserve for the Frame Buffer
 531     *
 532     *    This defines the Maximum Virtual Screen Size
 533     */
 534 
 535 #define VIDEOMEMSIZE_AGA_2M   (1280*1024)    /* AGA (2MB) : max 1280*1024*256 */
 536 #define VIDEOMEMSIZE_AGA_1M   (1024*768)     /* AGA (1MB) : max 1024*768*256 */
 537 #define VIDEOMEMSIZE_ECS_2M   (1280*1024/2)  /* ECS (2MB) : max 1280*1024*16 */
 538 #define VIDEOMEMSIZE_ECS_1M   (1024*768/2)   /* ECS (1MB) : max 1024*768*16 */
 539 #define VIDEOMEMSIZE_OCS      (800*600/2)    /* OCS      : max 800*600*16 */
 540 
 541 
 542 static u_long videomemory;
 543 static u_long videomemorysize;
 544 
 545 #define assignchunk(name, type, ptr, size) \
 546 { \
 547    (name) = (type)(ptr); \
 548    ptr += size; \
 549 }
 550 
 551 
 552    /*
 553     *    Copper Instructions
 554     */
 555 
 556 #define CMOVE(val, reg)       (CUSTOM_OFS(reg)<<16 | (val))
 557 #define CMOVE2(val, reg)      ((CUSTOM_OFS(reg)+2)<<16 | (val))
 558 #define CWAIT(x, y)           (((y) & 0xff)<<24 | ((x) & 0xfe)<<16 | 0x0001fffe)
 559 #define CEND                  (0xfffffffe)
 560 
 561 
 562 typedef union {
 563    u_long l;
 564    u_short w[2];
 565 } copins;
 566 
 567 
 568    /*
 569     *    Frame Header Copper List
 570     */
 571 
 572 struct clist_hdr {
 573    copins bplcon0;
 574    copins diwstrt;
 575    copins diwstop;
 576    copins diwhigh;
 577    copins sprfix[8];
 578    copins sprstrtup[16];
 579    copins wait;
 580    copins jump;
 581    copins wait_forever;
 582 };
 583 
 584 
 585    /*
 586     *    Long Frame/Short Frame Copper List
 587     */
 588 
 589 struct clist_dyn {
 590    copins diwstrt;
 591    copins diwstop;
 592    copins diwhigh;
 593    copins bplcon0;
 594    copins sprpt[2];              /* Sprite 0 */
 595    copins rest[64];
 596 };
 597 
 598 
 599 static struct clist_hdr *clist_hdr;
 600 static struct clist_dyn *clist_lof;
 601 static struct clist_dyn *clist_shf;    /* Only used for Interlace */
 602 
 603 
 604    /*
 605     *    Hardware Cursor
 606     */
 607 
 608 #define CRSR_RATE       (20)     /* Number of frames/flash toggle */
 609 
 610 static u_long *lofsprite, *shfsprite, *dummysprite;
 611 static u_short cursormode = FB_CURSOR_FLASH;
 612 
 613 
 614    /*
 615     *    Current Video Mode
 616     */
 617 
 618 struct amiga_fb_par {
 619 
 620    /* General Values */
 621 
 622    int xres;                     /* vmode */
 623    int yres;                     /* vmode */
 624    int vxres;                    /* vmode */
 625    int vyres;                    /* vmode */
 626    int xoffset;                  /* vmode */
 627    int yoffset;                  /* vmode */
 628    u_short bpp;                  /* vmode */
 629    u_short clk_shift;            /* vmode */
 630    int vmode;                    /* vmode */
 631    u_short diwstrt_h;            /* vmode */
 632    u_short diwstrt_v;            /* vmode */
 633    u_long next_line;             /* modulo for next line */
 634    u_long next_plane;            /* modulo for next plane */
 635    short crsr_x;                 /* movecursor */
 636    short crsr_y;                 /* movecursor */
 637 
 638    /* OCS Hardware Registers */
 639 
 640    u_long bplpt0;                /* vmode, pan (Note: physical address) */
 641    u_short bplcon0;              /* vmode */
 642    u_short bplcon1;              /* vmode, pan */
 643    u_short bpl1mod;              /* vmode, pan */
 644    u_short bpl2mod;              /* vmode, pan */
 645    u_short diwstrt;              /* vmode */
 646    u_short diwstop;              /* vmode */
 647    u_short ddfstrt;              /* vmode, pan */
 648    u_short ddfstop;              /* vmode, pan */
 649 
 650 #if defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA)
 651    /* Additional ECS Hardware Registers */
 652 
 653    u_short diwhigh;              /* vmode */
 654    u_short bplcon3;              /* vmode */
 655    u_short beamcon0;             /* vmode */
 656    u_short htotal;               /* vmode */
 657    u_short hsstrt;               /* vmode */
 658    u_short hsstop;               /* vmode */
 659    u_short vtotal;               /* vmode */
 660    u_short vsstrt;               /* vmode */
 661    u_short vsstop;               /* vmode */
 662    u_short hcenter;              /* vmode */
 663 #endif /* defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA) */
 664 
 665 #if defined(CONFIG_AMIFB_AGA)
 666    /* Additional AGA Hardware Registers */
 667 
 668    u_short fmode;                /* vmode */
 669 #endif /* defined(CONFIG_AMIFB_AGA) */
 670 };
 671 
 672 static struct amiga_fb_par current_par;
 673 
 674 static int current_par_valid = 0;
 675 static int currcon = 0;
 676 
 677 static struct display disp[MAX_NR_CONSOLES];
 678 static struct fb_info fb_info;
 679 
 680 static int node;        /* node of the /dev/fb?current file */
 681 
 682 
 683    /*
 684     *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
 685     */
 686 
 687 volatile u_short amiga_audio_min_period = 124;   /* Default for pre-OCS */
 688 
 689 
 690    /*
 691     *    Since we can't read the palette on OCS/ECS, and since reading one
 692     *    single color palette entry requires 5 expensive custom chip bus
 693     *    accesses on AGA, we keep a copy of the current palette.
 694     */
 695 
 696 #ifdef CONFIG_AMIFB_AGA
 697 static struct { u_char red, green, blue, pad; } palette[256];
 698 #else /* CONFIG_AMIFB_AGA */
 699 static struct { u_char red, green, blue, pad; } palette[32];
 700 #endif /* CONFIG_AMIFB_AGA */
 701 
 702 
 703    /*
 704     *    Latches and Flags for display changes during VBlank
 705     */
 706 
 707 static volatile u_short do_vmode = 0;           /* Change the Video Mode */
 708 static volatile short do_blank = 0;             /* (Un)Blank the Screen (±1) */
 709 static volatile u_short do_movecursor = 0;      /* Move the Cursor */
 710 static volatile u_short full_vmode_change = 1;  /* Full Change or Only Pan */
 711 static volatile u_short is_blanked = 0;         /* Screen is Blanked */
 712 
 713 
 714    /*
 715     *    Switch for Chipset Independency
 716     */
 717 
 718 static struct fb_hwswitch {
 719 
 720    /* Initialization */
 721    int (*init)(void);
 722 
 723    /* Display Control */
 724    int (*encode_fix)(struct fb_fix_screeninfo *fix, struct amiga_fb_par *par);
 725    int (*decode_var)(struct fb_var_screeninfo *var, struct amiga_fb_par *par);
 726    int (*encode_var)(struct fb_var_screeninfo *var, struct amiga_fb_par *par);
 727    int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
 728                     u_int *transp);
 729    int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
 730                     u_int transp);
 731    int (*pan_display)(struct fb_var_screeninfo *var, struct amiga_fb_par *par);
 732 
 733    /* Routines Called by VBlank Interrupt to minimize flicker */
 734    void (*do_vmode)(void);
 735    void (*do_blank)(int blank);
 736    void (*do_movecursor)(void);
 737    void (*do_flashcursor)(void);
 738 } *fbhw;
 739 
 740 
 741    /*
 742     *    Frame Buffer Name
 743     *
 744     *    The rest of the name is filled in by amiga_fb_init
 745     */
 746 
 747 static char amiga_fb_name[16] = "Amiga ";
 748 
 749 
 750    /*
 751     *    Predefined Video Mode Names
 752     *
 753     *    The a2024-?? modes don't work yet because there's no A2024 driver.
 754     */
 755 
 756 static char *amiga_fb_modenames[] = {
 757 
 758    /*
 759     *    Autodetect (Default) Video Mode
 760     */
 761 
 762    "default",
 763 
 764    /*
 765     *    AmigaOS Video Modes
 766     */
 767     
 768    "ntsc",              /* 640x200, 15 kHz, 60 Hz (NTSC) */
 769    "ntsc-lace",         /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
 770    "pal",               /* 640x256, 15 kHz, 50 Hz (PAL) */
 771    "pal-lace",          /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
 772    "multiscan",         /* 640x480, 29 kHz, 57 Hz */
 773    "multiscan-lace",    /* 640x960, 29 kHz, 57 Hz interlaced */
 774    "a2024-10",          /* 1024x800, 10 Hz (Not yet supported) */
 775    "a2024-15",          /* 1024x800, 15 Hz (Not yet supported) */
 776    "euro36",            /* 640x200, 15 kHz, 72 Hz */
 777    "euro36-lace",       /* 640x400, 15 kHz, 72 Hz interlaced */
 778    "euro72",            /* 640x400, 29 kHz, 68 Hz */
 779    "euro72-lace",       /* 640x800, 29 kHz, 68 Hz interlaced */
 780    "super72",           /* 800x300, 23 kHz, 70 Hz */
 781    "super72-lace",      /* 800x600, 23 kHz, 70 Hz interlaced */
 782    "dblntsc",           /* 640x200, 27 kHz, 57 Hz doublescan */
 783    "dblntsc-ff",        /* 640x400, 27 kHz, 57 Hz */
 784    "dblntsc-lace",      /* 640x800, 27 kHz, 57 Hz interlaced */
 785    "dblpal",            /* 640x256, 27 kHz, 47 Hz doublescan */
 786    "dblpal-ff",         /* 640x512, 27 kHz, 47 Hz */
 787    "dblpal-lace",       /* 640x1024, 27 kHz, 47 Hz interlaced */
 788 
 789    /*
 790     *    VGA Video Modes
 791     */
 792 
 793    "vga",               /* 640x480, 31 kHz, 60 Hz (VGA) */
 794    "vga70",             /* 640x400, 31 kHz, 70 Hz (VGA) */
 795 
 796    /*
 797     *    User Defined Video Modes: to be set after boot up using e.g. fbset
 798     */
 799 
 800    "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
 801 };
 802 
 803 
 804    /*
 805     *    Predefined Video Mode Definitions
 806     *
 807     *    Since the actual pixclock values depend on the E-Clock, we use the
 808     *    TAG_* values and fill in the real values during initialization.
 809     *    Thus we assume no one has pixel clocks of 333, 500 or 1000 GHz :-)
 810     */
 811 
 812 static struct fb_var_screeninfo amiga_fb_predefined[] = {
 813 
 814    /*
 815     *    Autodetect (Default) Video Mode
 816     */
 817 
 818    { 0, },
 819 
 820    /*
 821     *    AmigaOS Video Modes
 822     */
 823     
 824    {
 825       /* ntsc */
 826       640, 200, 640, 200, 0, 0, 4, 0,
 827       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 828       0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 24, 18, 0, 0,
 829       FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
 830    }, {
 831       /* ntsc-lace */
 832       640, 400, 640, 400, 0, 0, 4, 0,
 833       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 834       0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 48, 36, 0, 0,
 835       FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
 836    }, {
 837       /* pal */
 838       640, 256, 640, 256, 0, 0, 4, 0,
 839       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 840       0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 20, 12, 0, 0,
 841       FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
 842    }, {
 843       /* pal-lace */
 844       640, 512, 640, 512, 0, 0, 4, 0,
 845       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 846       0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 78, 18, 40, 24, 0, 0,
 847       FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
 848    }, {
 849       /* multiscan */
 850       640, 480, 640, 480, 0, 0, 4, 0,
 851       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 852       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8,
 853       0, FB_VMODE_NONINTERLACED
 854    }, {
 855       /* multiscan-lace */
 856       640, 960, 640, 960, 0, 0, 4, 0,
 857       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 858       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16,
 859       0, FB_VMODE_INTERLACED
 860    }, {
 861       /* a2024-10 (Not yet supported) */
 862       1024, 800, 1024, 800, 0, 0, 2, 0,
 863       {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
 864       0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
 865       0, FB_VMODE_NONINTERLACED
 866    }, {
 867       /* a2024-15 (Not yet supported) */
 868       1024, 800, 1024, 800, 0, 0, 2, 0,
 869       {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
 870       0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
 871       0, FB_VMODE_NONINTERLACED
 872    }, {
 873       /* euro36 */
 874       640, 200, 640, 200, 0, 0, 4, 0,
 875       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 876       0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 6, 6, 52, 5,
 877       0, FB_VMODE_NONINTERLACED
 878    }, {
 879       /* euro36-lace */
 880       640, 400, 640, 400, 0, 0, 4, 0,
 881       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 882       0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 12, 12, 52, 10,
 883       0, FB_VMODE_INTERLACED
 884    }, {
 885       /* euro72 */
 886       640, 400, 640, 400, 0, 0, 4, 0,
 887       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 888       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8,
 889       0, FB_VMODE_NONINTERLACED
 890    }, {
 891       /* euro72-lace */
 892       640, 800, 640, 800, 0, 0, 4, 0,
 893       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 894       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16,
 895       0, FB_VMODE_INTERLACED
 896    }, {
 897       /* super72 */
 898       800, 300, 800, 300, 0, 0, 4, 0,
 899       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 900       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 10, 11, 80, 7,
 901       0, FB_VMODE_NONINTERLACED
 902    }, {
 903       /* super72-lace */
 904       800, 600, 800, 600, 0, 0, 4, 0,
 905       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 906       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 20, 22, 80, 14,
 907       0, FB_VMODE_INTERLACED
 908    }, {
 909       /* dblntsc */
 910       640, 200, 640, 200, 0, 0, 4, 0,
 911       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 912       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 18, 17, 80, 4,
 913       0, FB_VMODE_DOUBLE
 914    }, {
 915       /* dblntsc-ff */
 916       640, 400, 640, 400, 0, 0, 4, 0,
 917       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 918       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 36, 35, 80, 7,
 919       0, FB_VMODE_NONINTERLACED
 920    }, {
 921       /* dblntsc-lace */
 922       640, 800, 640, 800, 0, 0, 4, 0,
 923       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 924       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 72, 70, 80, 14,
 925       0, FB_VMODE_INTERLACED
 926    }, {
 927       /* dblpal */
 928       640, 256, 640, 256, 0, 0, 4, 0,
 929       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 930       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 14, 13, 80, 4,
 931       0, FB_VMODE_DOUBLE
 932    }, {
 933       /* dblpal-ff */
 934       640, 512, 640, 512, 0, 0, 4, 0,
 935       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 936       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 28, 27, 80, 7,
 937       0, FB_VMODE_NONINTERLACED
 938    }, {
 939       /* dblpal-lace */
 940       640, 1024, 640, 1024, 0, 0, 4, 0,
 941       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 942       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 56, 54, 80, 14,
 943       0, FB_VMODE_INTERLACED
 944    },
 945 
 946    /*
 947     *    VGA Video Modes
 948     */
 949 
 950    {
 951       /* vga */
 952       640, 480, 640, 480, 0, 0, 4, 0,
 953       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 954       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 30, 9, 112, 2,
 955       0, FB_VMODE_NONINTERLACED
 956    }, {
 957       /* vga70 */
 958       640, 400, 640, 400, 0, 0, 4, 0,
 959       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
 960       0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 35, 12, 112, 2,
 961       FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED
 962    },
 963 
 964    /*
 965     *    User Defined Video Modes
 966     */
 967 
 968    { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
 969 };
 970 
 971 
 972 #define NUM_USER_MODES     (8)
 973 #define NUM_TOTAL_MODES    arraysize(amiga_fb_predefined)
 974 #define NUM_PREDEF_MODES   (NUM_TOTAL_MODES-NUM_USER_MODES)
 975 
 976 
 977 static int amifb_ilbm = 0;       /* interleaved or normal bitplanes */
 978 
 979 static int amifb_inverse = 0;
 980 static int amifb_mode = 0;
 981 
 982 
 983    /*
 984     *    Support for Graphics Boards
 985     */
 986 
 987 #ifdef CONFIG_FB_CYBER        /* Cybervision */
 988 extern int Cyber_probe(void);
 989 extern void Cyber_video_setup(char *options, int *ints);
 990 extern struct fb_info *Cyber_fb_init(long *mem_start);
 991 
 992 static int amifb_Cyber = 0;
 993 #endif /* CONFIG_FB_CYBER */
 994 
 995 
 996    /*
 997     *    Some default modes
 998     */
 999 
1000 #define DEFMODE_PAL        "pal"       /* for PAL OCS/ECS */
1001 #define DEFMODE_NTSC       "ntsc"      /* for NTSC OCS/ECS */
1002 #define DEFMODE_AMBER_PAL  "pal-lace"  /* for flicker fixed PAL (A3000) */
1003 #define DEFMODE_AMBER_NTSC "ntsc-lace" /* for flicker fixed NTSC (A3000) */
1004 #define DEFMODE_AGA        "vga70"     /* for AGA */
1005 
1006 
1007    /*
1008     *    Interface used by the world
1009     */
1010 
1011 void amiga_video_setup(char *options, int *ints);
1012 
1013 static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
1014 static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con);
1015 static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con);
1016 static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
1017 static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
1018 static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con);
1019 
1020 static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
1021                           u_long arg, int con);
1022 
1023 static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
1024 static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
1025 static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
1026 static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con);
1027 static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con);
1028 
1029 
1030    /*
1031     *    Interface to the low level console driver
1032     */
1033 
1034 struct fb_info *amiga_fb_init(long *mem_start);
1035 static int amifb_switch(int con);
1036 static int amifb_updatevar(int con);
1037 static void amifb_blank(int blank);
1038 
1039 
1040    /*
1041     *    Support for OCS
1042     */
1043 
1044 #ifdef CONFIG_AMIFB_OCS
1045 #error "OCS support: not yet implemented"
1046 #endif /* CONFIG_AMIFB_OCS */
1047 
1048 
1049    /*
1050     *    Support for ECS
1051     */
1052 
1053 #ifdef CONFIG_AMIFB_ECS
1054 #error "ECS support: not yet implemented"
1055 #endif /* CONFIG_AMIFB_ECS */
1056 
1057 
1058    /*
1059     *    Support for AGA
1060     */
1061 
1062 #ifdef CONFIG_AMIFB_AGA
1063 static int aga_init(void);
1064 static int aga_encode_fix(struct fb_fix_screeninfo *fix,
1065                           struct amiga_fb_par *par);
1066 static int aga_decode_var(struct fb_var_screeninfo *var,
1067                           struct amiga_fb_par *par);
1068 static int aga_encode_var(struct fb_var_screeninfo *var,
1069                           struct amiga_fb_par *par);
1070 static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
1071                          u_int *transp);
1072 static int aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1073                          u_int transp);
1074 static int aga_pan_display(struct fb_var_screeninfo *var,
1075                            struct amiga_fb_par *par);
1076 static void aga_do_vmode(void);
1077 static void aga_do_blank(int blank);
1078 static void aga_do_movecursor(void);
1079 static void aga_do_flashcursor(void);
1080 
1081 static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
1082 static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
1083 static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con);
1084 static int aga_get_cursorstate(struct fb_cursorstate *state, int con);
1085 static int aga_set_cursorstate(struct fb_cursorstate *state, int con);
1086 
1087 static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop);
1088 static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop,
1089                                             struct amiga_fb_par *par);
1090 static void aga_build_clist_dyn(struct clist_dyn *cop,
1091                                 struct clist_dyn *othercop, u_short shf,
1092                                 struct amiga_fb_par *par);
1093 #endif /* CONFIG_AMIFB_AGA */
1094 
1095 
1096    /*
1097     *    Internal routines
1098     */
1099 
1100 static u_long chipalloc(u_long size);
1101 static void amiga_fb_get_par(struct amiga_fb_par *par);
1102 static void amiga_fb_set_par(struct amiga_fb_par *par);
1103 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
1104 static struct fb_cmap *get_default_colormap(int bpp);
1105 static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
1106                           int kspc);
1107 static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
1108                           int kspc);
1109 static void do_install_cmap(int con);
1110 static void memcpy_fs(int fsfromto, void *to, void *from, int len);
1111 static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
1112 static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
1113 static void amiga_fb_set_disp(int con);
1114 static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy);
1115 static char * strtoke(char * s,const char * ct);
1116 static int get_video_mode(const char *name);
1117 static void check_default_mode(void);
1118 
1119 
1120 #ifdef USE_MONO_AMIFB_IF_NON_AGA
1121 
1122 /******************************************************************************
1123 *
1124 * This is the old monochrome frame buffer device. It's invoked if we're running
1125 * on a non-AGA machine, until the color support for OCS/ECS is finished.
1126 *
1127 ******************************************************************************/
1128 
1129 /*
1130  * atari/atafb.c -- Low level implementation of Atari frame buffer device
1131  * amiga/amifb.c -- Low level implementation of Amiga frame buffer device
1132  *
1133  *  Copyright (C) 1994 Martin Schaller & Roman Hodek & Geert Uytterhoeven
1134  *  
1135  * This file is subject to the terms and conditions of the GNU General Public
1136  * License.  See the file README.legal in the main directory of this archive
1137  * for more details.
1138  *
1139  * History:
1140  *   - 03 Jan 95: Original version my Martin Schaller: The TT driver and
1141  *                all the device independent stuff
1142  *   - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
1143  *                and wrote the Falcon, ST(E), and External drivers
1144  *                based on the original TT driver.
1145  *   - 26 Jan 95: Geert: Amiga version
1146  *   - 19 Feb 95: Hamish: added Jes Sorensen's ECS patches to the Amiga
1147  *                frame buffer device.  This provides ECS support and the
1148  *                following screen-modes: multiscan, multiscan-lace,
1149  *                super72, super72-lace, dblntsc, dblpal & euro72.
1150  *                He suggests that we remove the old AGA screenmodes,
1151  *                as they are non-standard, and some of them doesn't work
1152  *                under ECS.
1153  */
1154 
1155 static struct mono_mono_amiga_fb_par {
1156         u_long smem_start;
1157         u_long smem_len;
1158         struct geometry *geometry;
1159         ushort scr_max_height;                  /* screen dimensions */
1160         ushort scr_max_width;
1161         ushort scr_height;
1162         ushort scr_width;
1163         ushort scr_depth;
1164         int bytes_per_row;                      /* offset to one line below */
1165         ulong fgcol;
1166         ulong bgcol;
1167         ulong crsrcol;
1168         ushort scroll_latch;                    /* Vblank support for hardware scroll */
1169         ushort y_wrap;
1170         ushort cursor_latch;                    /* Hardware cursor */
1171         ushort *cursor, *dummy;
1172         ushort cursor_flash;
1173         ushort cursor_visible;
1174         ushort diwstrt_v, diwstrt_h;            /* display window control */
1175         ushort diwstop_v, diwstop_h;
1176         ushort bplcon0;                         /* display mode */
1177         ushort htotal;
1178         u_char *bitplane[8];                    /* pointers to display bitplanes */
1179         ulong plane_size;
1180         ushort *coplist1hdr;                    /* List 1 static  component */
1181         ushort *coplist1dyn;                    /* List 1 dynamic component */
1182         ushort *coplist2hdr;                    /* List 2 static  component */
1183         ushort *coplist2dyn;                    /* List 2 dynamic component */
1184 } mono_current_par;
1185 
1186 
1187 static ushort mono_cursor_data[] =
1188 {
1189     0x2c81,0x2d00,
1190     0xf000,0x0000,
1191     0x0000,0x0000
1192 };
1193 
1194 
1195 /*
1196  *  Color definitions
1197  */
1198 
1199 #define FG_COLOR                (0x000000)      /* black */
1200 #define BG_COLOR                (0xaaaaaa)      /* lt. grey */
1201 #define CRSR_COLOR              (0xff0000)      /* bright red */
1202 
1203 #define FG_COLOR_INV            BG_COLOR
1204 #define BG_COLOR_INV            FG_COLOR
1205 #define CRSR_COLOR_INV          (0x6677aa)      /* a blue-ish color */
1206 
1207 /*
1208  *  Split 24-bit RGB colors in 12-bit MSB (for OCS/ECS/AGA) and LSB (for AGA)
1209  */
1210 
1211 #define COLOR_MSB(rgb)  (((rgb>>12)&0xf00)|((rgb>>8)&0x0f0)|((rgb>>4)&0x00f))
1212 #define COLOR_LSB(rgb)  (((rgb>>8) &0xf00)|((rgb>>4)&0x0f0)|((rgb)   &0x00f))
1213 
1214 /* Cursor definitions */
1215 
1216 #define CRSR_FLASH              1       /* Cursor flashing on(1)/off(0) */
1217 #define CRSR_BLOCK              1       /* Block(1) or line(0) cursor */
1218 
1219 
1220 /* controlling screen blanking (read in VBL handler) */
1221 static int mono_do_blank;
1222 static int mono_do_unblank;
1223 static unsigned short mono_save_bplcon3;
1224 
1225 /*
1226  * mono_ecs_color_zero is used to keep custom.color[0] for the special ECS color-
1227  * table, as custom.color[0] is cleared at vblank interrupts.
1228  * -Jes (jds@kom.auc.dk)
1229  */
1230 
1231 static ushort mono_ecs_color_zero;
1232 
1233 static struct {
1234         int right_count;
1235         int done;
1236 } mono_vblank;
1237 
1238 
1239 static __inline__ void mono_init_vblank(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1240 {
1241         mono_vblank.right_count = 0;
1242         mono_vblank.done = 0;
1243 }
1244 
1245 /* Geometry structure contains all useful information about given mode.
1246  *
1247  * Strictly speaking `scr_max_height' and `scr_max_width' is redundant
1248  * information with DIWSTRT value provided. Might be useful if modes
1249  * can be hotwired by user in future. It fits for the moment.
1250  *
1251  * At the moment, the code only distinguishes between OCS and AGA. ECS
1252  * lies somewhere in between - someone more familiar with it could make
1253  * appropriate modifications so that some advanced display modes are
1254  * available, without confusing the poor chipset. OCS modes use only the
1255  * bplcon0, diwstrt, diwstop, ddfstrt, ddfstop registers (a few others could
1256  * be used as well). -wjr
1257  *
1258  * The code now supports ECS as well, except for FMODE all control registers
1259  * are the same under ECS. A special color-table has to be generated though.
1260  * -Jes
1261  */
1262 struct geometry {
1263     char *modename;     /* Name this thing */
1264     char isOCS;         /* Is it OCS or ECS/AGA */
1265     ushort bplcon0;     /* Values for bit plane control register 0 */
1266     ushort scr_width;
1267     ushort scr_height;
1268     ushort scr_depth;
1269     ushort scr_max_width;     /* Historical, might be useful still */
1270     ushort scr_max_height;
1271     ushort diwstrt_h;   /* Where the display window starts */
1272     ushort diwstrt_v;
1273     ushort alignment;   /* Pixels per scanline must be a multiple of this */
1274     /* OCS doesn't need anything past here */
1275     ushort bplcon2;
1276     ushort bplcon3;
1277     /* The rest of these control variable sync */
1278     ushort htotal;      /* Total hclocks */
1279     ushort hsstrt;      /* HSYNC start and stop */
1280     ushort hsstop;
1281     ushort hbstrt;      /* HBLANK start and stop */
1282     ushort hbstop;
1283     ushort vtotal;      /* Total vlines */
1284     ushort vsstrt;      /* VSYNC, VBLANK ditto */
1285     ushort vsstop;
1286     ushort vbstrt;
1287     ushort vbstop;
1288     ushort hcenter;     /* Center of line, for interlaced modes */
1289     ushort beamcon0;    /* Beam control */
1290     ushort fmode;       /* Memory fetch mode */
1291 };
1292 
1293 #define MAX_COP_LIST_ENTS 64
1294 #define COP_MEM_REQ       (MAX_COP_LIST_ENTS*4*2)
1295 #define SPR_MEM_REQ       (24)
1296 
1297 
1298 static struct geometry mono_modes[] = {
1299         /* NTSC modes: !!! can't guarantee anything about overscan modes !!! */
1300         {
1301                 "ntsc-lace", 1,
1302                 BPC0_HIRES | BPC0_LACE,
1303                 640, 400, 1,
1304                 704, 480,
1305                 0x71, 0x18,             /* diwstrt h,v */
1306                 16                      /* WORD aligned */
1307         }, {
1308                 "ntsc", 1,
1309                 BPC0_HIRES,
1310                 640, 200, 1,
1311                 704, 240,
1312                 0x71, 0x18,
1313                 16                      /* WORD aligned */
1314         }, {
1315                 "ntsc-lace-over", 1,
1316                 BPC0_HIRES | BPC0_LACE,
1317                 704, 480, 1,
1318                 704, 480,
1319                 0x71, 0x18,
1320                 16                      /* WORD aligned */
1321         }, {
1322                 "ntsc-over", 1,
1323                 BPC0_HIRES,
1324                 704, 240, 1,
1325                 704, 240,
1326                 0x71, 0x18,
1327                 16                      /* WORD aligned */
1328         },
1329         /* PAL modes. Warning:
1330          * 
1331          * PAL overscan causes problems on my machine because maximum diwstop_h
1332          * value seems to be ~0x1c2, rather than 0x1e0+ inferred by RKM 1.1
1333          * and 0x1d5 inferred by original `amicon.c' source. Is this a hardware
1334          * limitation of OCS/pal or 1084?. Or am I doing something stupid here?
1335          *
1336          * Included a couple of overscan modes that DO work on my machine,
1337          * although not particularly useful.
1338          */
1339         {
1340                 "pal-lace", 1,
1341                 BPC0_HIRES | BPC0_LACE,
1342                 640, 512, 1,
1343                 704, 592,
1344                 0x71, 0x18,
1345                 16                      /* WORD aligned */
1346         }, {
1347                 "pal", 1,
1348                 BPC0_HIRES,
1349                 640, 256, 1,
1350                 704, 296,
1351                 0x71, 0x18,
1352                 16                      /* WORD aligned */
1353         }, {
1354                 "pal-lace-over", 1,
1355                 BPC0_HIRES | BPC0_LACE,
1356                 704, 592, 1,
1357                 704, 582,
1358                 0x5b, 0x18,
1359                 16                      /* WORD aligned */
1360         }, {
1361                 "pal-over", 1,
1362                 BPC0_HIRES,
1363                 704, 296, 1,
1364                 704, 296,
1365                 0x5b, 0x18,
1366                 16                      /* WORD aligned */
1367 
1368         },
1369         /* ECS modes, these are real ECS modes */
1370         {
1371                 "multiscan", 0,
1372                 BPC0_SHRES | BPC0_ECSENA,       /* bplcon0 */
1373                 640, 480, 1,
1374                 640, 480,
1375                 0x0041, 0x002c,                 /* diwstrt h,v */
1376                 64,                             /* 64-bit aligned */
1377                 BPC2_KILLEHB,                   /* bplcon2 */
1378                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1379                         BPC3_BRDRBLNK | BPC3_EXTBLKEN,  /* bplcon3 */
1380 
1381                 0x0072,                         /* htotal */
1382                 0x000a,                         /* hsstrt */
1383                 0x0013,                         /* hsstop */
1384                 0x0002,                         /* hbstrt */
1385                 0x001c,                         /* hbstop */
1386                 0x020c,                         /* vtotal */
1387                 0x0008,                         /* vsstrt */
1388                 0x0011,                         /* vsstop */
1389                 0x0000,                         /* vbstrt */
1390                 0x001c,                         /* vbstop */
1391                 0x0043,                         /* hcenter */
1392                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1393                         BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
1394                                                 /* beamcon0 */
1395                 FMODE_BPAGEM | FMODE_BPL32      /* fmode */
1396         },
1397         {
1398                 "multiscan-lace", 0,
1399                 BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,   /* bplcon0 */
1400                 640, 960, 1,
1401                 640, 960,
1402                 0x0041, 0x002c,                 /* diwstrt h,v */
1403                 64,                             /* 64-bit aligned */
1404                 BPC2_KILLEHB,                   /* bplcon2 */
1405                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1406                         BPC3_BRDRBLNK | BPC3_EXTBLKEN,  /* bplcon3 */
1407 
1408                 0x0072,                         /* htotal */
1409                 0x000a,                         /* hsstrt */
1410                 0x0013,                         /* hsstop */
1411                 0x0002,                         /* hbstrt */
1412                 0x001c,                         /* hbstop */
1413                 0x020c,                         /* vtotal */
1414                 0x0008,                         /* vsstrt */
1415                 0x0011,                         /* vsstop */
1416                 0x0000,                         /* vbstrt */
1417                 0x001c,                         /* vbstop */
1418                 0x0043,                         /* hcenter */
1419                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1420                         BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
1421                                                 /* beamcon0 */
1422                 FMODE_BPAGEM | FMODE_BPL32      /* fmode */
1423         },
1424         /* Super 72 - 800x300 72Hz noninterlaced mode. */
1425         {
1426                 "super72", 0,
1427                 BPC0_SHRES | BPC0_ECSENA,       /* bplcon0 */
1428                 800, 304, 1,                    /* need rows%8 == 0 */
1429                 800, 304,                       /* (cols too) */
1430                 0x0051, 0x0021,                 /* diwstrt h,v */
1431                 64,                             /* 64-bit aligned */
1432                 BPC2_KILLEHB,                   /* bplcon2 */
1433                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1434                         BPC3_BRDRBLNK | BPC3_EXTBLKEN,  /* bplcon3 */
1435                 0x0091,                         /* htotal */
1436                 0x000a,                         /* hsstrt */
1437                 0x0013,                         /* hsstop */
1438                 0x0001,                         /* hbstrt */
1439                 0x001e,                         /* hbstop */
1440                 0x0156,                         /* vtotal */
1441                 0x0009,                         /* vsstrt */
1442                 0x0012,                         /* vsstop */
1443                 0x0000,                         /* vbstrt */
1444                 0x001c,                         /* vbstop */
1445                 0x0052,                         /* hcenter */
1446                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1447                         BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
1448                                                 /* beamcon0 */
1449                 FMODE_BPAGEM | FMODE_BPL32      /* fmode */
1450         },
1451         /* Super 72 lace - 800x600 72Hz interlaced mode. */
1452         {
1453                 "super72-lace", 0,
1454                 BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,   /* bplcon0 */
1455                 800, 600, 1,                    /* need rows%8 == 0 */
1456                 800, 600,                       /* (cols too) */
1457                 0x0051, 0x0021,                 /* diwstrt h,v */
1458                 64,                             /* 64-bit aligned */
1459                 BPC2_KILLEHB,                   /* bplcon2 */
1460                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1461                         BPC3_BRDRBLNK | BPC3_EXTBLKEN,
1462                                                 /* bplcon3 */
1463                 0x0091,                         /* htotal */
1464                 0x000a,                         /* hsstrt */
1465                 0x0013,                         /* hsstop */
1466                 0x0001,                         /* hbstrt */
1467                 0x001e,                         /* hbstop */
1468                 0x0150,                         /* vtotal */
1469                 0x0009,                         /* vsstrt */
1470                 0x0012,                         /* vsstop */
1471                 0x0000,                         /* vbstrt */
1472                 0x001c,                         /* vbstop */
1473                 0x0052,                         /* hcenter */
1474                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1475                         BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
1476                                                 /* beamcon0 */
1477                 FMODE_BPAGEM | FMODE_BPL32      /* fmode */
1478         },
1479         /* DblNtsc - 640x400 59Hz noninterlaced mode. */
1480         {
1481                 "dblntsc", 0,
1482                 BPC0_SHRES | BPC0_ECSENA,       /* bplcon0 */
1483                 640, 400, 1,                    /* need rows%8 == 0 */
1484                 640, 400,                       /* (cols too) */
1485                 0x0049, 0x0021,                 /* diwstrt h,v */
1486                 64,                             /* 64-bit aligned */
1487                 BPC2_KILLEHB,                   /* bplcon2 */
1488                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1489                         BPC3_BRDRBLNK | BPC3_EXTBLKEN,
1490                                                 /* bplcon3 */
1491                 0x0079,                         /* htotal */
1492                 0x0007,                         /* hsstrt */
1493                 0x0013,                         /* hsstop */
1494                 0x0001,                         /* hbstrt */
1495                 0x001e,                         /* hbstop */
1496                 0x01ec,                         /* vtotal */
1497                 0x0008,                         /* vsstrt */
1498                 0x0010,                         /* vsstop */
1499                 0x0000,                         /* vbstrt */
1500                 0x0019,                         /* vbstop */
1501                 0x0046,                         /* hcenter */
1502                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1503                         BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
1504                                                 /* beamcon0 */
1505                 FMODE_BPAGEM | FMODE_BPL32      /* fmode */
1506         },
1507         /* DblPal - 640x512 52Hz noninterlaced mode. */
1508         {
1509                 "dblpal", 0,
1510                 BPC0_SHRES | BPC0_ECSENA,       /* bplcon0 */
1511                 640, 512, 1,                    /* need rows%8 == 0 */
1512                 640, 512,                       /* (cols too) */
1513                 0x0049, 0x0021,                 /* diwstrt h,v */
1514                 64,                             /* 64-bit aligned */
1515                 BPC2_KILLEHB,                   /* bplcon2 */
1516                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1517                         BPC3_BRDRBLNK | BPC3_EXTBLKEN,
1518                                                 /* bplcon3 */
1519                 0x0079,                         /* htotal */
1520                 0x0007,                         /* hsstrt */
1521                 0x0013,                         /* hsstop */
1522                 0x0001,                         /* hbstrt */
1523                 0x001e,                         /* hbstop */
1524                 0x0234,                         /* vtotal */
1525                 0x0008,                         /* vsstrt */
1526                 0x0010,                         /* vsstop */
1527                 0x0000,                         /* vbstrt */
1528                 0x0019,                         /* vbstop */
1529                 0x0046,                         /* hcenter */
1530                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1531                         BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
1532                                                 /* beamcon0 */
1533                 FMODE_BPAGEM | FMODE_BPL32      /* fmode */
1534         },
1535         /* Euro72 - productivity - 640x400 71Hz noninterlaced mode. */
1536         {
1537                 "euro72", 0,
1538                 BPC0_SHRES | BPC0_ECSENA,       /* bplcon0 */
1539                 640, 400, 1,                    /* need rows%8 == 0 */
1540                 640, 400,                       /* (cols too) */
1541                 0x0041, 0x0021,                 /* diwstrt h,v */
1542                 64,                             /* 64-bit aligned */
1543                 BPC2_KILLEHB,                   /* bplcon2 */
1544                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1545                         BPC3_BRDRBLNK | BPC3_EXTBLKEN,
1546                                                 /* bplcon3 */
1547                 0x0071,                         /* htotal */
1548                 0x0009,                         /* hsstrt */
1549                 0x0013,                         /* hsstop */
1550                 0x0001,                         /* hbstrt */
1551                 0x001e,                         /* hbstop */
1552                 0x01be,                         /* vtotal */
1553                 0x0008,                         /* vsstrt */
1554                 0x0016,                         /* vsstop */
1555                 0x0000,                         /* vbstrt */
1556                 0x001f,                         /* vbstop */
1557                 0x0041,                         /* hcenter */
1558                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1559                         BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,
1560                                                 /* beamcon0 */
1561                 FMODE_BPAGEM | FMODE_BPL32      /* fmode */
1562         },
1563         /* AGA modes */
1564         {
1565         /*
1566          * A 640x480, 60Hz noninterlaced AGA mode. It would be nice to be
1567          * able to have some of these values computed dynamically, but that
1568          * requires more knowledge of AGA than I have. At the moment,
1569          * the values make it centered on my 1960 monitor. -wjr
1570          *
1571          * For random reasons to do with the way arguments are parsed,
1572          * these names can't start with a digit.
1573          *
1574          * Don't count on being able to reduce scr_width and scr_height
1575          * and ending up with a smaller but well-formed screen - this
1576          * doesn't seem to work well at the moment.
1577          */
1578                 "aga640x480", 0,
1579                 BPC0_SHRES | BPC0_ECSENA,                       /* bplcon0 */
1580                 640, 480, 1,
1581                 640, 480,
1582                 0x0041, 0x002b,                                         /* diwstrt h,v */
1583                 64,                                                                             /* 64-bit aligned */
1584                 BPC2_KILLEHB,                                                   /* bplcon2 */
1585                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1586                 BPC3_BRDRBLNK | BPC3_EXTBLKEN,  /* bplcon3 */
1587                 0x0071,                                                                 /* htotal */
1588                 0x000c,                                                                 /* hsstrt */
1589                 0x001c,                                                                 /* hsstop */
1590                 0x0008,                                                                 /* hbstrt */
1591                 0x001e,                                                                 /* hbstop */
1592                 0x020c,                                                                 /* vtotal */
1593                 0x0001,                                                                 /* vsstrt */
1594                 0x0003,                                                                 /* vsstop */
1595                 0x0000,                                                                 /* vbstrt */
1596                 0x000f,                                                                 /* vbstop */
1597                 0x0046,                                                                 /* hcenter */
1598                 BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1599                         BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,  /* beamcon0 */
1600                 FMODE_BPAGEM | FMODE_BPL32                      /* fmode */
1601         }, {
1602                 /* An 800x600 72Hz interlaced mode. */
1603                 "aga800x600", 0,
1604                 BPC0_SHRES | BPC0_LACE | BPC0_ECSENA,   /* bplcon0 */
1605                 896, 624, 1,                                                    /* need rows%8 == 0 */
1606                 896, 624,                                                               /* (cols too) */
1607                 0x0041, 0x001e,                                         /* diwstrt h,v */
1608                 64,                                             /* 64-bit aligned */
1609                 BPC2_KILLEHB,                                                   /* bplcon2 */
1610                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1611                 BPC3_BRDRBLNK | BPC3_EXTBLKEN,  /* bplcon3 */
1612                 0x0091,                                                                 /* htotal */
1613                 0x000e,                                                                 /* hsstrt */
1614                 0x001d,                                                                 /* hsstop */
1615                 0x000a,                                                                 /* hbstrt */
1616                 0x001e,                                                                 /* hbstop */
1617                 0x0156,                                                                 /* vtotal */
1618                 0x0001,                                                                 /* vsstrt */
1619                 0x0003,                                                                 /* vsstop */
1620                 0x0000,                                                                 /* vbstrt */
1621                 0x000f,                                                                 /* vbstop */
1622                 0x0050,                                                                 /* hcenter */
1623                 BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN |
1624                 BMC0_VARHSYEN | BMC0_VARBEAMEN | BMC0_BLANKEN,  /* beamcon0 */
1625                 FMODE_BPAGEM | FMODE_BPL32                      /* fmode */
1626         },
1627         /*
1628          * Additional AGA modes by Geert Uytterhoeven
1629          */
1630         {
1631                 /*
1632                  * A 720x400, 70 Hz noninterlaced AGA mode (29.27 kHz)
1633                  */
1634                 "aga720x400", 0,
1635                 BPC0_SHRES | BPC0_ECSENA,                       /* bplcon0 */
1636                 720, 400, 1,
1637                 720, 400,
1638                 0x0041, 0x0013,                                         /* diwstrt h,v */
1639                 64,                                                                             /* 64-bit aligned */
1640                 BPC2_KILLEHB,                                                   /* bplcon2 */
1641                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1642                 BPC3_BRDRBLNK | BPC3_EXTBLKEN,  /* bplcon3 */
1643                 0x0079,                                                                 /* htotal */
1644                 0x000e,                                                                 /* hsstrt */
1645                 0x0018,                                                                 /* hsstop */
1646                 0x0001,                                                                 /* hbstrt */
1647                 0x0021,                                                                 /* hbstop */
1648                 0x01a2,                                                                 /* vtotal */
1649                 0x0003,                                                                 /* vsstrt */
1650                 0x0005,                                                                 /* vsstop */
1651                 0x0000,                                                                 /* vbstrt */
1652                 0x0012,                                                                 /* vbstop */
1653                 0x0046,                                                                 /* hcenter */
1654                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
1655                 BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
1656                 BMC0_VSYTRUE,                                                   /* beamcon0 */
1657                 FMODE_BPAGEM | FMODE_BPL32                      /* fmode */
1658         }, {
1659                 /*
1660                  * A 640x400, 76 Hz noninterlaced AGA mode (31.89 kHz)
1661                  */
1662                 "aga640x400", 0,
1663                 BPC0_SHRES | BPC0_ECSENA,                       /* bplcon0 */
1664                 640, 400, 1,
1665                 640, 400,
1666                 0x0041, 0x0015,                                         /* diwstrt h,v */
1667                 64,                                                                             /* 64-bit aligned */
1668                 BPC2_KILLEHB,                                                   /* bplcon2 */
1669                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1670                 BPC3_BRDRBLNK | BPC3_EXTBLKEN,  /* bplcon3 */
1671                 0x006f,                                                                 /* htotal */
1672                 0x000d,                                                                 /* hsstrt */
1673                 0x0018,                                                                 /* hsstop */
1674                 0x0001,                                                                 /* hbstrt */
1675                 0x0021,                                                                 /* hbstop */
1676                 0x01a4,                                                                 /* vtotal */
1677                 0x0003,                                                                 /* vsstrt */
1678                 0x0005,                                                                 /* vsstop */
1679                 0x0000,                                                                 /* vbstrt */
1680                 0x0014,                                                                 /* vbstop */
1681                 0x0046,                                                                 /* hcenter */
1682                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
1683                 BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
1684                 BMC0_VSYTRUE,                                                   /* beamcon0 */
1685                 FMODE_BPAGEM | FMODE_BPL32                      /* fmode */
1686         }, {
1687                 /*
1688                  * A 640x480, 64 Hz noninterlaced AGA mode (31.89 kHz)
1689                  */
1690                 "aga640x480a", 0,
1691                 BPC0_SHRES | BPC0_ECSENA,                       /* bplcon0 */
1692                 640, 480, 1,
1693                 640, 480,
1694                 0x0041, 0x0015,                                         /* diwstrt h,v */
1695                 64,                                                                             /* 64-bit aligned */
1696                 BPC2_KILLEHB,                                                   /* bplcon2 */
1697                 BPC3_PF2OF1 | BPC3_PF2OF0 | BPC3_SPRES1 | BPC3_SPRES0 |
1698                 BPC3_BRDRBLNK | BPC3_EXTBLKEN,  /* bplcon3 */
1699                 0x006f,                                                                 /* htotal */
1700                 0x000e,                                                                 /* hsstrt */
1701                 0x0018,                                                                 /* hsstop */
1702                 0x0001,                                                                 /* hbstrt */
1703                 0x0021,                                                                 /* hbstop */
1704                 0x01f4,                                                                 /* vtotal */
1705                 0x0003,                                                                 /* vsstrt */
1706                 0x0005,                                                                 /* vsstop */
1707                 0x0000,                                                                 /* vbstrt */
1708                 0x0014,                                                                 /* vbstop */
1709                 0x0046,                                                                 /* hcenter */
1710                 BMC0_VARVBEN | BMC0_LOLDIS | BMC0_VARVSYEN | BMC0_VARHSYEN |
1711                 BMC0_VARBEAMEN | BMC0_PAL | BMC0_VARCSYEN | BMC0_CSYTRUE |
1712                 BMC0_VSYTRUE,                                                   /* beamcon0 */
1713                 FMODE_BPAGEM | FMODE_BPL32                      /* fmode */
1714         }
1715 };
1716 
1717 #define NMODES  (sizeof(mono_modes) / sizeof(struct geometry))
1718 
1719 static struct fb_var_screeninfo mono_mono_amiga_fb_predefined[] = {
1720         { /* autodetect */
1721                 0, 0, 0, 0, 0, 0, 0, 0,                 /* xres-grayscale */
1722                 {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},     /* red green blue tran*/
1723                 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }
1724 };
1725 
1726 static int mono_num_mono_amiga_fb_predefined= sizeof(mono_mono_amiga_fb_predefined)/sizeof(struct fb_var_screeninfo);
1727 
1728 
1729 
1730 /* Some default modes */
1731 #define OCS_PAL_LOWEND_DEFMODE  5       /* PAL non-laced for 500/2000 */
1732 #define OCS_PAL_3000_DEFMODE            4       /* PAL laced for 3000 */
1733 #define OCS_NTSC_LOWEND_DEFMODE 1       /* NTSC non-laced for 500/2000 */
1734 #define OCS_NTSC_3000_DEFMODE           0       /* NTSC laced for 3000 */
1735 #define AGA_DEFMODE                                     8       /* 640x480 non-laced for AGA */
1736 
1737 static int mono_amifb_inverse = 0;
1738 static int mono_amifb_mode = -1;
1739 
1740 static void mono_video_setup (char *options, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
1741 {
1742         char *this_opt;
1743         int i;
1744 
1745         fb_info.fontname[0] = '\0';
1746 
1747         if (!options || !*options)
1748                 return;
1749 
1750         for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,","))
1751                 if (!strcmp (this_opt, "inverse"))
1752                         mono_amifb_inverse = 1;
1753       else if (!strncmp(this_opt, "font:", 5))
1754                strcpy(fb_info.fontname, this_opt+5);
1755                 else
1756                         for (i = 0; i < NMODES; i++)
1757                                 if (!strcmp(this_opt, mono_modes[i].modename)) {
1758                                         mono_amifb_mode = i;
1759                                         break;
1760                                 }
1761 }
1762 
1763 /* Notes about copper scrolling:
1764  *
1765  * 1. The VBLANK routine dynamically rewrites a LIVE copper list that is
1766  *    currently being executed. Don't mess with it unless you know the
1767  *    complications. Fairly sure that double buffered lists doesn't
1768  *    make our life any easier.
1769  *
1770  * 2. The vblank code starts executing at logical line 0. Display must be
1771  *    set up and ready to run by line DIWSTRT_V, typically 0x2c, minimum
1772  *    value is 0x18 for maximum overscan.
1773  *
1774  *    Tests on my A500/030 for dynamically generating a 37 element copper
1775  *    list during the VBLANK period under AmigaDos required between
1776  *    0x10 and 0x14 scanlines. This should be pathological case, and
1777  *    should do better under Linux/68k. It is however IMPERATIVE that I am
1778  *    first in the VBLANK isr chain. Try to keep 'buildclist' as fast as
1779  *    possible. Don't think that it justifies assembler thou'
1780  *
1781  * 3. PAL 640x256 display (no overscan) has copper-wait y positions in range
1782  *    0x02c -> 0x12c. NTSC overscan uses values > 256 too. However counter
1783  *    is 8 bit, will wrap. RKM 1.1 suggests use of a WAIT(0x00,0xff),
1784  *    WAIT(x,y-0x100) pair to handle this case. This is WRONG - must use
1785  *    WAIT(0xe2,0xff) to ensure that wrap occurred by next copper
1786  *    instruction. Argghh!
1787  *
1788  * 4. RKM 1.1 suggests Copper-wait x positions are in range [0,0xe2].
1789  *    Horizontal blanking occurs in range 0x0f -> 0x35. Black screen
1790  *    shown in range 0x04 -> 0x47.
1791  *
1792  *    Experiments suggest that using WAIT(0x00,y), we can replace up to
1793  *    7 bitplane pointers before display fetch start. Using a 
1794  *    WAIT(0xe0,y-1) instead, we can replace 8 pointers that should be
1795  *    all that we need for a full AGA display. Should work because of
1796  *    fetch latency with bitmapped display.
1797  *
1798  *    I think that this works. Someone please tell me if something breaks.
1799  *
1800  * Is diwstop_h the right value to use for "close to the end of line"?
1801  * It seems to work for me, at least for the modes I've defined. -wjr
1802  *
1803  * I changed the Wait(diwstop_h, 0xff) for 256-line chunk skipping to
1804  * Wait(diwstop_h-2, 0xff) to make it work with the additional
1805  * `get-all-you-can-get-out-of-it' AGA modes. Maybe we should derive the
1806  * wait position from the HTOTAL value? - G.U.
1807  *
1808  * The Wait(diwstop_h-2, 0xff) didn't work in Super72 under ECS, instead
1809  * I changed it to Wait(htotal-4, 0xff). Dunno whether it works under AGA,
1810  * and don't ask my why it works. I'm trying to get some facts on this issue
1811  * from Commodore.
1812  * -Jes
1813  */
1814 
1815 static __inline__ ushort *mono_build_clist_hdr(register struct display *p,
     /* [previous][next][first][last][top][bottom][index][help] */
1816                                                                                                                 ushort *cop,
1817                                                                                                                 ushort *othercop)       /* Interlace: List for next frame */
1818 {
1819         int i;
1820         ushort diwstrt_v = mono_current_par.diwstrt_v;
1821         ushort diwstop_h = mono_current_par.diwstop_h;
1822 
1823         if (othercop) {
1824                 *cop++ = CUSTOM_OFS(cop1lc);
1825                 *cop++ = (long)othercop >> 16;
1826                 *cop++ = CUSTOM_OFS(cop1lc) + 2;
1827                 *cop++ = (long)othercop;
1828         }
1829 
1830         /* Point Sprite 0 at cursor sprite: */
1831         *cop++ = CUSTOM_OFS(sprpt[0]);
1832         *cop++ = (ushort)((long)mono_current_par.cursor >> 16);
1833         *cop++ = CUSTOM_OFS(sprpt[0]) + 2;
1834         *cop++ = (ushort)((long)mono_current_par.cursor & 0x0000ffff);
1835 
1836         /* Point Sprites 1-7 at dummy sprite: */
1837         for (i=1; i<8; i++) {
1838                 *cop++ = CUSTOM_OFS(sprpt[i]);
1839                 *cop++ = (ushort)((long)mono_current_par.dummy >> 16);
1840                 *cop++ = CUSTOM_OFS(sprpt[i]) + 2;
1841                 *cop++ = (ushort)((long)mono_current_par.dummy & 0x0000ffff);
1842         }
1843 
1844         /* Halt copper until we have rebuilt the display list */
1845 
1846         *cop++ = ((diwstrt_v - 2) << 8) | (diwstop_h >> 1) | 0x1;
1847         *cop++ = 0xfffe;
1848 
1849         return(cop);
1850 }
1851 
1852 static __inline__ ushort *mono_build_clist_dyn(register struct display *p,
     /* [previous][next][first][last][top][bottom][index][help] */
1853                                                                                                                 ushort *cop,
1854                                                                                                                 int shf)                                /* Interlace: Short frame */
1855 {
1856         ushort diwstrt_v = mono_current_par.diwstrt_v;
1857         ushort diwstop_h = mono_current_par.diwstop_h;
1858         ushort y_wrap = mono_current_par.y_wrap;
1859         ulong offset = y_wrap * mono_current_par.bytes_per_row;
1860         long scrmem;
1861         int i;
1862 
1863         /* Set up initial bitplane ptrs */
1864 
1865         for (i = 0 ; i < mono_current_par.scr_depth ; i++) {
1866                 scrmem    = ((long)mono_current_par.bitplane[i]) + offset;
1867 
1868                 if (shf)
1869                         scrmem += mono_current_par.bytes_per_row;
1870 
1871                 *cop++ = CUSTOM_OFS(bplpt[i]);
1872                 *cop++ = (long)scrmem >> 16;
1873                 *cop++ = CUSTOM_OFS(bplpt[i]) + 2;
1874                 *cop++ = (long)scrmem;
1875         }
1876 
1877         /* If wrapped frame needed - wait for line then switch bitplXs */
1878 
1879         if (y_wrap) {
1880                 ushort line;
1881         
1882                 if (mono_current_par.bplcon0 & BPC0_LACE)
1883                         line = diwstrt_v + (mono_current_par.scr_height - y_wrap)/2;
1884                 else
1885                         line = diwstrt_v + mono_current_par.scr_height - y_wrap;
1886 
1887                 /* Handle skipping over 256-line chunks */
1888                 while (line > 256) {
1889                         /* Hardware limitation - 8 bit counter    */
1890                         /* Wait(diwstop_h-2, 0xff) */
1891                         if (mono_current_par.bplcon0 & BPC0_SHRES)
1892                                 /*
1893                                  * htotal-4 is used in SHRES-mode, as diwstop_h-2 doesn't work under ECS.
1894                                  * Does this work under AGA?
1895                                  * -Jes
1896                                  */
1897                                 *cop++ = 0xff00 | ((mono_current_par.htotal-4) | 1);
1898                         else 
1899                                 *cop++ = 0xff00 | ((diwstop_h-2) >> 1) | 0x1;
1900 
1901                         *cop++ = 0xfffe;
1902                         /* Wait(0, 0) - make sure we're in the new segment */
1903                         *cop++ = 0x0001;
1904                         *cop++ = 0xfffe;
1905                         line -= 256;
1906 
1907                         /*
1908                          * Under ECS we have to keep color[0], as it is part of a special color-table.
1909                          */
1910 
1911                         if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
1912                                 *cop++ = 0x0180;
1913                                 *cop++ = mono_ecs_color_zero;
1914                         }
1915                 }
1916         
1917                 /* Wait(diwstop_h, line - 1) */
1918                 *cop++ = ((line - 1)   << 8) | (diwstop_h >> 1) | 0x1;
1919                 *cop++ = 0xfffe;
1920 
1921                 for (i = 0 ; i < mono_current_par.scr_depth ; i++) {
1922                         scrmem = (long)mono_current_par.bitplane[i];
1923                         if (shf)
1924                                 scrmem += mono_current_par.bytes_per_row;
1925 
1926                                 *cop++ = CUSTOM_OFS(bplpt[i]); 
1927                                 *cop++ = (long)scrmem >> 16;
1928                                 *cop++ = CUSTOM_OFS(bplpt[i]) + 2;
1929                                 *cop++ = (long)scrmem;
1930                 }
1931         }
1932     
1933         /* End of Copper list */
1934         *cop++ = 0xffff;
1935         *cop++ = 0xfffe;
1936 
1937         return(cop);
1938 }
1939 
1940 
1941 static __inline__ void mono_build_cursor(register struct display *p)
     /* [previous][next][first][last][top][bottom][index][help] */
1942 {
1943         int vs, hs, ve;
1944         ushort diwstrt_v = mono_current_par.diwstrt_v;
1945         ushort diwstrt_h = mono_current_par.diwstrt_h;
1946 
1947         if (mono_current_par.bplcon0 & BPC0_LACE) {
1948                 vs = diwstrt_v + (p->cursor_y * p->fontheight)/2; 
1949                 ve = vs + p->fontheight/2;
1950         } else {
1951                 vs = diwstrt_v + (p->cursor_y * p->fontheight); 
1952                 ve = vs + p->fontheight;
1953         }
1954 
1955         if (mono_current_par.bplcon0 & BPC0_ECSENA)
1956                 /*
1957                  * It's an AGA mode. We'll assume that the sprite was set
1958                  * into 35ns resolution by the appropriate SPRES bits in bplcon3.
1959                  */
1960                 hs = diwstrt_h  * 4 + (p->cursor_x * p->fontwidth) - 4;
1961         else
1962                 hs = diwstrt_h + (p->cursor_x * p->fontwidth) / 2 - 1;
1963 
1964         if (mono_current_par.bplcon0 & BPC0_ECSENA) {
1965                 /* There are some high-order bits on the sprite position */
1966                 *((ulong *) mono_current_par.cursor) =
1967                 ((((vs & 0xff) << 24) | ((vs & 0x100) >> 6) |
1968                 ((vs & 0x200) >> 3)) |
1969                 (((hs & 0x7f8) << 13) | ((hs & 0x4) >> 2) |
1970                 ((hs & 0x3) << 3)) |
1971                 (((ve & 0xff) << 8) | ((ve & 0x100) >> 7) |
1972                 ((ve & 0x200) >> 4)));
1973         } else {
1974                 *((ulong *) mono_current_par.cursor) =
1975                 ((vs << 24) | ((vs & 0x00000100) >> 6) |
1976                 ((hs & 0x000001fe) << 15) | (hs & 0x00000001) | 
1977                 ((ve & 0x000000ff) << 8) | ((ve & 0x00000100) >> 7));
1978         }
1979 }
1980 
1981 static void mono_build_ecs_colors(ushort color1, ushort color2, ushort color3, 
     /* [previous][next][first][last][top][bottom][index][help] */
1982                       ushort color4, ushort *table)
1983 {
1984 /*
1985  * This function calculates the special ECS color-tables needed when running
1986  * new screen-modes available under ECS. See the hardware reference manual
1987  * 3rd edition for details.
1988  * -Jes
1989  */
1990 ushort  t;
1991 
1992         t = (color1 & 0x0ccc);
1993         table[0] = t;
1994         table[4] = t;
1995         table[8] = t;
1996         table[12] = t;
1997         t = t >> 2;
1998         table[0] = (table[0] | t);
1999         table[1] = t;
2000         table[2] = t;
2001         table[3] = t;
2002 
2003         t = (color2 & 0x0ccc);
2004         table[1] = (table[1] | t);
2005         table[5] = t;
2006         table[9] = t;
2007         table[13] = t;
2008         t = t >> 2;
2009         table[4] = (table[4] | t);
2010         table[5] = (table[5] | t);
2011         table[6] = t;
2012         table[7] = t;
2013 
2014         t = (color3 & 0x0ccc);
2015         table[2] = (table[2] | t);
2016         table[6] = (table[6] | t);
2017         table[10] = t;
2018         table[14] = t;
2019         t = t >> 2;
2020         table[8] = (table[8] | t);
2021         table[9] = (table[9] | t);
2022         table[10] = (table[10] | t);
2023         table[11] = t;
2024 
2025         t = (color4 & 0x0ccc);
2026         table[3] = (table[3] | t);
2027         table[7] = (table[7] | t);
2028         table[11] = (table[11] | t);
2029         table[15] = t;
2030         t = t >> 2;
2031         table[12] = (table[12] | t);
2032         table[13] = (table[13] | t);
2033         table[14] = (table[14] | t);
2034         table[15] = (table[15] | t);
2035 
2036 }
2037 
2038 /* mono_display_init():
2039  *
2040  *    Fills out (struct display *) given a geometry structure
2041  */
2042 
2043 static void mono_display_init(struct display *p,
     /* [previous][next][first][last][top][bottom][index][help] */
2044                          struct geometry *geom, ushort inverse)
2045 {
2046         ushort ecs_table[16];
2047         int    i;
2048         char   *chipptr;
2049         ushort diwstrt_v, diwstop_v;
2050         ushort diwstrt_h, diwstop_h;
2051         ushort diw_min_h, diw_min_v;
2052         ushort bplmod, diwstrt, diwstop, diwhigh, ddfstrt, ddfstop;
2053         ushort cursorheight, cursormask = 0;
2054         u_long size;
2055 
2056         /* Decide colour scheme */
2057 
2058         if (inverse) {
2059                 mono_current_par.fgcol   = FG_COLOR_INV;
2060                 mono_current_par.bgcol   = BG_COLOR_INV;
2061                 mono_current_par.crsrcol = CRSR_COLOR_INV;
2062         } else {
2063                 mono_current_par.fgcol   = FG_COLOR;
2064                 mono_current_par.bgcol   = BG_COLOR;
2065                 mono_current_par.crsrcol = CRSR_COLOR;
2066         }
2067 
2068         /* Define screen geometry */
2069    
2070         mono_current_par.scr_max_height = geom->scr_max_height;
2071         mono_current_par.scr_max_width  = geom->scr_max_width; 
2072         mono_current_par.scr_height     = geom->scr_height;
2073         mono_current_par.scr_width      = geom->scr_width;
2074         mono_current_par.scr_depth      = geom->scr_depth;
2075         mono_current_par.bplcon0        = geom->bplcon0 | BPC0_COLOR;
2076         mono_current_par.htotal         = geom->htotal;
2077 
2078         /* htotal was added, as I use it to calc the pal-line. -Jes */
2079 
2080         if (mono_current_par.scr_depth < 8)
2081                 mono_current_par.bplcon0 |= (mono_current_par.scr_depth << 12);
2082         else {
2083                 /* must be exactly 8 */
2084                 mono_current_par.bplcon0 |= BPC0_BPU3;
2085         }
2086 
2087         diw_min_v         = geom->diwstrt_v;
2088         diw_min_h         = geom->diwstrt_h;
2089 
2090         /* We can derive everything else from this, at least for OCS */
2091         /*
2092          * For AGA: we don't use the finer position control available for
2093          * diw* yet (could be set by 35ns increments).
2094          */
2095 
2096         /* Calculate line and plane size while respecting the alignment restrictions */
2097         mono_current_par.bytes_per_row  = ((mono_current_par.scr_width+geom->alignment-1)&~(geom->alignment-1)) >> 3;
2098         mono_current_par.plane_size     = mono_current_par.bytes_per_row * mono_current_par.scr_height;
2099 
2100 
2101         /*
2102          *              Quick hack for frame buffer mmap():
2103          *
2104          *              plane_size must be a multiple of the page size
2105          */
2106 
2107         mono_current_par.plane_size = PAGE_ALIGN(mono_current_par.plane_size);
2108 
2109 
2110         mono_current_par.y_wrap   = 0;                  mono_current_par.scroll_latch = 1;
2111         p->cursor_x = 0; p->cursor_y = 0; mono_current_par.cursor_latch = 1;
2112 
2113         if (mono_current_par.bplcon0 & BPC0_LACE) {
2114                 bplmod = mono_current_par.bytes_per_row;
2115                 diwstrt_v = diw_min_v + (mono_current_par.scr_max_height - mono_current_par.scr_height)/4;
2116                 diwstop_v = (diwstrt_v + mono_current_par.scr_height/2);
2117         } else {
2118                 bplmod = 0;
2119                 diwstrt_v = diw_min_v + (mono_current_par.scr_max_height - mono_current_par.scr_height)/2;
2120                 diwstop_v = (diwstrt_v + mono_current_par.scr_height);
2121         }
2122 
2123         if (mono_current_par.bplcon0 & BPC0_HIRES) {
2124                 diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/4;
2125                 diwstop_h = (diwstrt_h + mono_current_par.scr_width/2);
2126                 /* ??? Where did 0x1d5 come from in original code ??? */
2127         } else if (mono_current_par.bplcon0 & BPC0_SHRES) {
2128                 diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/8;
2129                 diwstop_h = (diwstrt_h + mono_current_par.scr_width/4);
2130         } else {
2131                 diwstrt_h =  diw_min_h + (mono_current_par.scr_max_width - mono_current_par.scr_width)/2;
2132                 diwstop_h = (diwstrt_h + mono_current_par.scr_width);
2133         }
2134 
2135         if (mono_current_par.bplcon0 & BPC0_HIRES) {
2136                 ddfstrt = (diwstrt_h >> 1) - 4;
2137                 ddfstop = ddfstrt + (4 * (mono_current_par.bytes_per_row>>1)) - 8;
2138         } else if (mono_current_par.bplcon0 & BPC0_SHRES && boot_info.bi_amiga.chipset == CS_AGA) {
2139                 /* There may be some interaction with FMODE here... -8 is magic. */
2140 
2141                 /*
2142                  * This should be fixed, so it supports all different
2143                  * FMODE's.  FMODE varies the speed with 1,2 & 4 the
2144                  * standard ECS speed.  Someone else has to do it, as
2145                  * I don't have an AGA machine with MMU available
2146                  * here.
2147                  *
2148                  * This particular speed looks like FMODE = 3 to me.
2149                  * ddfstop should be changed so it depends on FMODE under AGA.
2150                  * -Jes
2151                  */
2152                 ddfstrt = (diwstrt_h >> 1) - 8;
2153                 ddfstop = ddfstrt + (2 * (mono_current_par.bytes_per_row>>1)) - 8;
2154         } else if (mono_current_par.bplcon0 & BPC0_SHRES && boot_info.bi_amiga.chipset == CS_ECS){
2155                 /* 
2156                  * Normal speed for ECS, should be the same for FMODE = 0
2157                  * -Jes
2158                  */
2159                 ddfstrt = (diwstrt_h >> 1) - 2;
2160                 ddfstop = ddfstrt + (2 * (mono_current_par.bytes_per_row>>1)) - 8;
2161         } else {
2162                 ddfstrt = (diwstrt_h >> 1) - 8;
2163                 ddfstop = ddfstrt + (8 * (mono_current_par.bytes_per_row>>1)) - 8;
2164         }
2165 
2166         if (mono_current_par.bplcon0 & BPC0_LACE)
2167                 cursorheight = p->fontheight/2;
2168         else
2169                 cursorheight = p->fontheight;
2170 
2171         /*
2172          *              Quick hack for frame buffer mmap():
2173          *
2174          *              chipptr must be at a page boundary
2175          */
2176 
2177         size = mono_current_par.scr_depth*mono_current_par.plane_size+COP_MEM_REQ+SPR_MEM_REQ+4*(cursorheight-1);
2178         size += PAGE_SIZE-1;
2179         chipptr = amiga_chip_alloc(size);
2180         chipptr = (char *)PAGE_ALIGN((u_long)chipptr);
2181 
2182    
2183         /* locate the bitplanes */
2184         /* These MUST be 64 bit aligned for full AGA compatibility!! */
2185 
2186         mono_current_par.smem_start = (u_long)chipptr;
2187         mono_current_par.smem_len = mono_current_par.plane_size*mono_current_par.scr_depth;
2188         mono_current_par.geometry = geom;
2189 
2190         for (i = 0 ; i < mono_current_par.scr_depth ; i++, chipptr += mono_current_par.plane_size) {
2191                 mono_current_par.bitplane[i] = (u_char *) chipptr;
2192                 memset ((void *)chipptr, 0, mono_current_par.plane_size);  /* and clear */
2193         }
2194 
2195         /* locate the copper lists */
2196         mono_current_par.coplist1hdr = (ushort *) chipptr;  chipptr += MAX_COP_LIST_ENTS * 4;
2197         mono_current_par.coplist2hdr = (ushort *) chipptr;  chipptr += MAX_COP_LIST_ENTS * 4;
2198 
2199         /* locate the sprite data */
2200         mono_current_par.cursor      = (ushort *) chipptr;  chipptr += 8+4*cursorheight;
2201         mono_current_par.dummy       = (ushort *) chipptr;  chipptr += 12;
2202 
2203         /* create the sprite data for the cursor image */
2204         memset((void *)mono_current_par.cursor, 0, 8+4*cursorheight);
2205         /*
2206          * Only AGA supplies hires sprites.
2207          */
2208         if (mono_current_par.bplcon0 & BPC0_ECSENA && boot_info.bi_amiga.chipset == CS_AGA)
2209                 /* AGA cursor is SHIRES, ECS sprites differ */
2210                 for (i = 0; (i < p->fontwidth) && (i < 16); i++)
2211                         cursormask |= 1<<(15-i);
2212         else
2213                 /* For OCS & ECS sprites are pure LORES 8-< */
2214                 for (i = 0; (i < p->fontwidth/2) && (i < 8); i++)
2215                         cursormask |= 1<<(15-i);
2216 
2217         mono_current_par.cursor[0] = mono_cursor_data[0];
2218         mono_current_par.cursor[1] = mono_cursor_data[1];
2219 
2220 #if (CRSR_BLOCK == 1)
2221         for (i = 0; i < cursorheight; i++)
2222 #else
2223         for (i = cursorheight-2; i < cursorheight; i++)
2224 #endif
2225                 mono_current_par.cursor[2+2*i] = cursormask;
2226 
2227         /* set dummy sprite data to a blank sprite */
2228         memset((void *)mono_current_par.dummy, 0, 12);
2229   
2230         /* set cursor flashing */
2231         mono_current_par.cursor_flash = CRSR_FLASH;
2232 
2233         /* Make the cursor invisible */
2234         mono_current_par.cursor_visible = 0;
2235  
2236         /* Initialise the chipregs */
2237         mono_current_par.diwstrt_v = diwstrt_v;
2238         mono_current_par.diwstrt_h = diwstrt_h;
2239         mono_current_par.diwstop_v = diwstop_v;
2240         mono_current_par.diwstop_h = diwstop_h;
2241         diwstrt = ((diwstrt_v << 8) | diwstrt_h);
2242         diwstop = ((diwstop_v & 0xff) << 8) | (diwstop_h & 0xff);
2243 
2244         custom.bplcon0   = mono_current_par.bplcon0;    /* set the display mode */
2245         custom.bplcon1   = 0;           /* Needed for horizontal scrolling */
2246         custom.bplcon2   = 0;
2247         custom.bpl1mod   = bplmod;
2248         custom.bpl2mod   = bplmod;
2249         custom.diwstrt   = diwstrt;
2250         custom.diwstop   = diwstop;
2251         custom.ddfstrt   = ddfstrt;
2252         custom.ddfstop   = ddfstop;
2253 
2254         custom.color[0]  = COLOR_MSB(mono_current_par.bgcol);
2255         custom.color[1]  = COLOR_MSB(mono_current_par.fgcol);
2256         custom.color[17] = COLOR_MSB(mono_current_par.crsrcol); /* Sprite 0 color */
2257 
2258         if (boot_info.bi_amiga.chipset == CS_AGA) {
2259                 /* Fill in the LSB of the 24 bit color palette */
2260                 /* Must happen after MSB */
2261                 custom.bplcon3   = geom->bplcon3 | BPC3_LOCT;
2262                 custom.color[0]  = COLOR_LSB(mono_current_par.bgcol);
2263                 custom.color[1]  = COLOR_LSB(mono_current_par.fgcol);
2264                 custom.color[17] = COLOR_LSB(mono_current_par.crsrcol);
2265                 custom.bplcon3   = geom->bplcon3;
2266         }
2267 
2268         if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
2269                 /*
2270                  * Calculation of the special ECS color-tables for
2271                  * planes and sprites is done in the function
2272                  * build_ecs_table
2273                  */
2274 
2275                 /*
2276                  * Calcs a special ECS colortable for the bitplane,
2277                  * and copies it to the custom registers
2278                  */
2279                 mono_build_ecs_colors(COLOR_MSB(mono_current_par.bgcol), COLOR_MSB(mono_current_par.fgcol),
2280                                  0, 0, ecs_table); 
2281 
2282 #if 0
2283                 for (i = 0; i < 8; i++){
2284                         custom.color[i]   = ecs_table[i*2];
2285                         custom.color[i+8] = ecs_table[i*2+1];
2286                 }
2287 #else
2288                 for (i = 0; i < 16; i++){
2289                         custom.color[i]   = ecs_table[i];
2290                 }
2291 #endif
2292 
2293                 mono_ecs_color_zero = ecs_table[0];
2294 
2295                 /*
2296                  * Calcs a special ECS colortable for the cursor
2297                  * sprite, and copies it to the appropriate custom
2298                  * registers
2299                  */
2300                 mono_build_ecs_colors(0, COLOR_MSB(mono_current_par.crsrcol), 0, 0, ecs_table);
2301 
2302                 for (i = 0; i < 16; i++){
2303                         custom.color[i+16] = ecs_table[i];
2304                 }
2305         }
2306 
2307         if (!(geom->isOCS)) {
2308                 /* Need to set up a bunch more regs */
2309                 /* Assumes that diwstrt is in the (0,0) sector, but stop might not be */
2310                 diwhigh = (diwstop_v & 0x700) | ((diwstop_h & 0x100) << 5);
2311 
2312                 custom.bplcon2   = geom->bplcon2;
2313                 custom.bplcon3   = geom->bplcon3;
2314                 /* save bplcon3 for blanking */
2315                 mono_save_bplcon3 = geom->bplcon3;
2316 
2317                 custom.diwhigh   = diwhigh;     /* must happen AFTER diwstrt, stop */
2318 
2319                 custom.htotal   = geom->htotal;
2320                 custom.hsstrt   = geom->hsstrt;
2321                 custom.hsstop   = geom->hsstop;
2322                 custom.hbstrt   = geom->hbstrt;
2323                 custom.hbstop   = geom->hbstop;
2324                 custom.vtotal   = geom->vtotal;
2325                 custom.vsstrt   = geom->vsstrt;
2326                 custom.vsstop   = geom->vsstop;
2327                 custom.vbstrt   = geom->vbstrt;
2328                 custom.vbstop   = geom->vbstop;
2329                 custom.hcenter  = geom->hcenter;
2330                 custom.beamcon0 = geom->beamcon0;
2331                 if (boot_info.bi_amiga.chipset == CS_AGA) {
2332                         custom.fmode    = geom->fmode;
2333                 }
2334                 /* 
2335                  * fmode does NOT! exist under ECS, weird things might happen
2336                  */
2337 
2338                 /* We could load 8-bit colors here, if we wanted */
2339 
2340                 /*
2341                  *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
2342                  */
2343                 if (boot_info.bi_amiga.chipset != CS_STONEAGE)
2344                         amiga_audio_min_period = (geom->htotal>>1)+1;
2345         }
2346 
2347 
2348         /* Build initial copper lists. sprites must be set up, and mono_current_par.diwstrt. */
2349 
2350         if (mono_current_par.bplcon0 & BPC0_LACE) {
2351                 mono_current_par.coplist1dyn = mono_build_clist_hdr(p,mono_current_par.coplist1hdr, mono_current_par.coplist2hdr),
2352                 mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
2353 
2354                 mono_current_par.coplist2dyn = mono_build_clist_hdr(p,mono_current_par.coplist2hdr, mono_current_par.coplist1hdr),
2355                 mono_build_clist_dyn(p, mono_current_par.coplist2dyn, 1);
2356         } else {
2357                 mono_current_par.coplist1dyn = mono_build_clist_hdr(p,mono_current_par.coplist1hdr, NULL),
2358                 mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
2359         }
2360 
2361 
2362         /* Get ready to run first copper list */
2363         custom.cop1lc = mono_current_par.coplist1hdr;
2364         custom.copjmp1 = 0;
2365 
2366         /* turn on DMA for bitplane and sprites */
2367         custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
2368 
2369         if (mono_current_par.bplcon0 & BPC0_LACE) {
2370                 /* Make sure we get the fields in the right order */
2371 
2372                 /* wait for LOF frame bit to go low */
2373                 while (custom.vposr & 0x8000)
2374                         ;
2375 
2376                 /* wait for LOF frame bit to go high */
2377                 while (!(custom.vposr & 0x8000))
2378                         ;
2379 
2380                 /* start again at the beginning of copper list 1 */
2381                 custom.cop1lc = mono_current_par.coplist1hdr;
2382                 custom.copjmp1 = 0;
2383         }
2384 }
2385 
2386 
2387 static void mono_amifb_interrupt(int irq, struct pt_regs *fp, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
2388 {
2389         register struct display *p = disp;
2390 
2391         static ushort cursorcount = 0;
2392         static ushort cursorstate = 0;
2393 
2394         /* I *think* that you should only change display lists on long frame.
2395          * At least it goes awfully peculiar on my A500 without the following
2396          * test. Not really in a position to test this hypothesis, so sorry
2397          * for the slow scrolling, all you flicker-fixed souls
2398          */
2399 
2400         if (!(mono_current_par.bplcon0 & BPC0_LACE) || (custom.vposr & 0x8000)) {
2401                 if (mono_current_par.scroll_latch || mono_current_par.cursor_latch)
2402                         mono_build_cursor(p);
2403 
2404                 if (mono_current_par.scroll_latch)
2405                         if (mono_current_par.bplcon0 & BPC0_LACE) {
2406                                 mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
2407                                 mono_build_clist_dyn(p, mono_current_par.coplist2dyn, 1);
2408                         } else
2409                                 mono_build_clist_dyn(p, mono_current_par.coplist1dyn, 0);
2410                         mono_current_par.scroll_latch = 0;
2411                         mono_current_par.cursor_latch = 0;
2412         }
2413 
2414         if (!(custom.potgor & (1<<10)))
2415                 mono_vblank.right_count++;
2416 
2417         if (mono_current_par.cursor_visible) {
2418                 if (mono_current_par.cursor_flash) {
2419                         if (cursorcount)
2420                                 cursorcount--;
2421                         else {
2422                                 cursorcount = CRSR_RATE;
2423                                 if ((cursorstate = !cursorstate))
2424                                         custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
2425                                 else
2426                                         custom.dmacon = DMAF_SPRITE;
2427                         }
2428                 }
2429         } else
2430                 custom.dmacon = DMAF_SPRITE;
2431 
2432         if (mono_do_blank) {
2433                 custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
2434                 custom.color[0] = 0;
2435                 if (boot_info.bi_amiga.chipset == CS_AGA) {
2436                         /* Fill in the LSB of the 24 bit color palette */
2437                         /* Must happen after MSB */
2438                         custom.bplcon3 = mono_save_bplcon3 | BPC3_LOCT;
2439                         custom.color[0]= 0;
2440                         custom.bplcon3 = mono_save_bplcon3;
2441                 }
2442                 mono_do_blank = 0;
2443         }
2444 
2445         if (mono_do_unblank) {
2446                 if (mono_current_par.cursor_visible)
2447                         custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
2448                 else
2449                         custom.dmacon = DMAF_SETCLR | DMAF_RASTER;
2450                 custom.color[0] = COLOR_MSB(mono_current_par.bgcol);
2451                 if (boot_info.bi_amiga.chipset == CS_AGA) {
2452                         /* Fill in the LSB of the 24 bit color palette */
2453                         /* Must happen after MSB */
2454                         custom.bplcon3 = mono_save_bplcon3 | BPC3_LOCT;
2455                         custom.color[0] = COLOR_LSB(mono_current_par.bgcol);
2456                         custom.bplcon3 = mono_save_bplcon3;
2457                 }
2458                 /* color[0] is set to mono_ecs_color_zero under ECS */
2459                 if (boot_info.bi_amiga.chipset == CS_ECS && mono_current_par.bplcon0 & BPC0_ECSENA) {
2460                         custom.color[0]  = mono_ecs_color_zero;
2461                 }
2462                 mono_do_unblank = 0;
2463         }
2464 
2465         mono_vblank.done = 1;
2466 }
2467 
2468 
2469 static int mono_amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2470 {
2471         int i;
2472 
2473         strcpy(fix->id, mono_current_par.geometry->modename);
2474         fix->smem_start = mono_current_par.smem_start;
2475         fix->smem_len = mono_current_par.smem_len;
2476 
2477         /*
2478          *              Only monochrome bitmap at the moment
2479          */
2480 
2481         fix->type = FB_TYPE_PACKED_PIXELS;
2482 
2483         fix->type_aux = 0;
2484         if (mono_amifb_inverse)
2485                 fix->visual = FB_VISUAL_MONO10;
2486         else
2487                 fix->visual = FB_VISUAL_MONO01;
2488 
2489         fix->xpanstep = 0;
2490         fix->ypanstep = 0;
2491         fix->ywrapstep = 1;
2492 
2493         fix->line_length = 0;
2494         for (i = 0; i < arraysize(fix->reserved); i++)
2495                 fix->reserved[i] = 0;
2496         return(0);
2497 }
2498 
2499 
2500 static int mono_amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2501 {
2502         int i;
2503 
2504         var->xres = mono_current_par.geometry->scr_width;
2505         var->yres = mono_current_par.geometry->scr_height;
2506         var->xres_virtual = var->xres;
2507         var->yres_virtual = var->yres;
2508         var->xoffset = 0;
2509         var->yoffset = 0;
2510 
2511         var->bits_per_pixel = mono_current_par.geometry->scr_depth;
2512         var->grayscale = 0;
2513 
2514         if (boot_info.bi_amiga.chipset == CS_AGA) {
2515                 var->red.offset = 0;
2516                 var->red.length = 8;
2517                 var->red.msb_right = 0;
2518                 var->green = var->red;
2519                 var->blue = var->red;
2520         } else {
2521                 var->red.offset = 0;
2522                 var->red.length = 4;
2523                 var->red.msb_right = 0;
2524                 var->green = var->red;
2525                 var->blue = var->red;
2526         }
2527 
2528         var->nonstd = 0;
2529         var->activate = 0;
2530 
2531         var->width = -1;
2532         var->height = -1;
2533 
2534         var->accel = FB_ACCEL_NONE;
2535 
2536         var->pixclock = 35242;
2537         var->left_margin = (mono_current_par.geometry->hbstop-mono_current_par.geometry->hsstrt)*8;
2538         var->right_margin = (mono_current_par.geometry->hsstrt-mono_current_par.geometry->hbstrt)*8;
2539         var->upper_margin = (mono_current_par.geometry->vbstop-mono_current_par.geometry->vsstrt)*8;
2540         var->lower_margin = (mono_current_par.geometry->vsstrt-mono_current_par.geometry->vbstrt)*8;
2541         var->hsync_len = (mono_current_par.geometry->hsstop-mono_current_par.geometry->hsstrt)*8;
2542         var->vsync_len = (mono_current_par.geometry->vsstop-mono_current_par.geometry->vsstrt)*8;
2543         var->sync = 0;
2544         if (mono_current_par.geometry->bplcon0 & BPC0_LACE)
2545                 var->vmode = FB_VMODE_INTERLACED;
2546         else if ((boot_info.bi_amiga.chipset == CS_AGA) && (mono_current_par.geometry->fmode & FMODE_BSCAN2))
2547                 var->vmode = FB_VMODE_DOUBLE;
2548         else
2549                 var->vmode = FB_VMODE_NONINTERLACED;
2550 
2551         for (i = 0; i < arraysize(var->reserved); i++)
2552                 var->reserved[i] = 0;
2553 
2554         return(0);
2555 }
2556 
2557 
2558 static void mono_amiga_fb_set_disp(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2559 {
2560         struct fb_fix_screeninfo fix;
2561 
2562         mono_amiga_fb_get_fix(&fix, con);
2563         if (con == -1)
2564                 con = 0;
2565         disp[con].screen_base = (u_char *)fix.smem_start;
2566         disp[con].visual = fix.visual;
2567         disp[con].type = fix.type;
2568         disp[con].type_aux = fix.type_aux;
2569         disp[con].ypanstep = fix.ypanstep;
2570         disp[con].ywrapstep = fix.ywrapstep;
2571         disp[con].line_length = fix.line_length;
2572         disp[con].can_soft_blank = 1;
2573         disp[con].inverse = mono_amifb_inverse;
2574 }
2575 
2576 
2577 static int mono_amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2578 {
2579         /*
2580          *              Not yet implemented
2581          */
2582         return 0;                               /* The X server needs this */
2583         return(-EINVAL);
2584 }
2585 
2586 
2587 static short mono_red_normal[] = {
2588         ((BG_COLOR & 0xff0000)>>8) | ((BG_COLOR & 0xff0000)>>16),
2589         ((FG_COLOR & 0xff0000)>>8) | ((FG_COLOR & 0xff0000)>>16)
2590 };
2591 static short mono_green_normal[] = {
2592         ((BG_COLOR & 0x00ff00)) | ((BG_COLOR & 0x00ff00)>>8),
2593         ((FG_COLOR & 0x00ff00)) | ((FG_COLOR & 0x00ff00)>>8)
2594 };
2595 static short mono_blue_normal[] = {
2596         ((BG_COLOR & 0x0000ff)<<8) | ((BG_COLOR & 0x0000ff)),
2597         ((FG_COLOR & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff))
2598 };
2599 
2600 static short mono_red_inverse[] = {
2601         ((BG_COLOR_INV & 0xff0000)>>8) | ((BG_COLOR_INV & 0xff0000)>>16),
2602         ((FG_COLOR_INV & 0xff0000)>>8) | ((FG_COLOR_INV & 0xff0000)>>16)
2603 };
2604 static short mono_green_inverse[] = {
2605         ((BG_COLOR_INV & 0x00ff00)) | ((BG_COLOR_INV & 0x00ff00)>>8),
2606         ((FG_COLOR_INV & 0x00ff00)) | ((FG_COLOR_INV & 0x00ff00)>>8)
2607 };
2608 static short mono_blue_inverse[] = {
2609         ((BG_COLOR_INV & 0x0000ff)<<8) | ((BG_COLOR_INV & 0x0000ff)),
2610         ((FG_COLOR_INV & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff))
2611 };
2612 
2613 static struct fb_cmap mono_default_cmap_normal = { 0, 2, mono_red_normal, mono_green_normal, mono_blue_normal, NULL };
2614 static struct fb_cmap mono_default_cmap_inverse = { 0, 2, mono_red_inverse, mono_green_inverse, mono_blue_inverse, NULL };
2615 
2616 static int mono_amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2617 {
2618         int i, start;
2619         unsigned short *red, *green, *blue, *transp;
2620         unsigned int hred, hgreen, hblue, htransp;
2621         struct fb_cmap *def_cmap;
2622 
2623         red = cmap->red;
2624         green = cmap->green;
2625         blue = cmap->blue;
2626         transp = cmap->transp;
2627         start = cmap->start;
2628         if (start < 0)
2629                 return(-EINVAL);
2630 
2631         if (mono_amifb_inverse)
2632                 def_cmap = &mono_default_cmap_inverse;
2633         else
2634                 def_cmap = &mono_default_cmap_normal;
2635 
2636         for (i = 0; i < cmap->len; i++) {
2637                 if (i < def_cmap->len) {
2638                         hred = def_cmap->red[i];
2639                         hgreen = def_cmap->green[i];
2640                         hblue = def_cmap->blue[i];
2641                         if (def_cmap->transp)
2642                                 htransp = def_cmap->transp[i];
2643                         else
2644                                 htransp = 0;
2645                 } else
2646                         hred = hgreen = hblue = htransp = 0;
2647                 if (kspc) {
2648                         *red = hred;
2649                         *green = hgreen;
2650                         *blue = hblue;
2651                         if (transp)
2652                                 *transp = htransp;
2653                 } else {
2654                         put_fs_word(hred, red);
2655                         put_fs_word(hgreen, green);
2656                         put_fs_word(hblue, blue);
2657                         if (transp)
2658                                 put_fs_word(htransp, transp);
2659                 }
2660                 red++;
2661                 green++;
2662                 blue++;
2663                 if (transp)
2664                         transp++;
2665         }
2666         return(0);
2667 }
2668 
2669 
2670 static int mono_amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2671 {
2672         /*
2673          *              Not yet implemented
2674          */
2675         return(-EINVAL);
2676 }
2677 
2678 
2679 static int mono_amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2680 {
2681         /*
2682          *              Not yet implemented
2683          */
2684         return(-EINVAL);
2685 }
2686 
2687 
2688 static int mono_amiga_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
2689                                                                   unsigned long arg, int con)
2690 {
2691         return(-EINVAL);
2692 }
2693 
2694 static struct fb_ops mono_amiga_fb_ops = {
2695         mono_amiga_fb_get_fix, mono_amiga_fb_get_var, mono_amiga_fb_set_var, mono_amiga_fb_get_cmap,
2696         mono_amiga_fb_set_cmap, mono_amiga_fb_pan_display, mono_amiga_fb_ioctl  
2697 };
2698 
2699 
2700 static int mono_amifb_switch (int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2701 {
2702         mono_current_par.y_wrap = disp[con].var.yoffset;
2703         mono_current_par.cursor_latch = 1;
2704         mono_current_par.scroll_latch = 1;
2705         return(0);
2706 }
2707 
2708 
2709 static int mono_amifb_updatevar(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2710 {
2711         mono_current_par.y_wrap = disp[con].var.yoffset;
2712         mono_current_par.cursor_latch = 1;
2713         mono_current_par.scroll_latch = 1;
2714         return(0);
2715 }
2716 
2717 
2718 static void mono_amifb_blank(int blank)
     /* [previous][next][first][last][top][bottom][index][help] */
2719 {
2720         if (blank)
2721                 mono_do_blank = 1;
2722         else
2723                 mono_do_unblank = 1;
2724 }
2725 
2726 
2727 static struct fb_info *mono_amiga_fb_init(long *mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
2728 {
2729         int mode = mono_amifb_mode;
2730         ulong model;
2731         int inverse_video = mono_amifb_inverse;
2732         int err;
2733 
2734         err=register_framebuffer("Amiga Builtin", &node, &mono_amiga_fb_ops,  mono_num_mono_amiga_fb_predefined,
2735                                                                          mono_mono_amiga_fb_predefined);
2736 
2737         model = boot_info.bi_un.bi_ami.model;
2738         if (mode == -1)
2739                 if (boot_info.bi_amiga.chipset == CS_AGA)
2740                         mode = AGA_DEFMODE;
2741                 else if (model == AMI_3000)
2742                         mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_3000_DEFMODE : OCS_NTSC_3000_DEFMODE;
2743                 else
2744                         mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_LOWEND_DEFMODE : OCS_NTSC_LOWEND_DEFMODE;
2745 
2746         mono_init_vblank();
2747         mono_display_init(disp, &mono_modes[mode], inverse_video);
2748         if (!add_isr(IRQ_AMIGA_VERTB, mono_amifb_interrupt, 0, NULL, "frame buffer"))
2749                 panic("Couldn't add vblank interrupt");
2750 
2751         mono_amiga_fb_get_var(&disp[0].var, 0);
2752         if (mono_amifb_inverse)
2753                 disp[0].cmap = mono_default_cmap_inverse;
2754         else
2755                 disp[0].cmap = mono_default_cmap_normal;
2756         mono_amiga_fb_set_disp(-1);
2757 
2758         strcpy(fb_info.modename, "Amiga Builtin ");
2759         fb_info.disp = disp;
2760         fb_info.switch_con = &mono_amifb_switch;
2761         fb_info.updatevar = &mono_amifb_updatevar;
2762         fb_info.blank = &mono_amifb_blank;      
2763         strcat(fb_info.modename, mono_modes[mode].modename);
2764 
2765         return(&fb_info);
2766 }
2767 #endif /* USE_MONO_AMIFB_IF_NON_AGA */
2768 
2769 
2770 /* -------------------- OCS specific routines ------------------------------- */
2771 
2772 
2773 #ifdef CONFIG_AMIFB_OCS
2774    /*
2775     *    Initialization
2776     *
2777     *    Allocate the required chip memory.
2778     *    Set the default video mode for this chipset. If a video mode was
2779     *    specified on the command line, it will override the default mode.
2780     */
2781 
2782 static int ocs_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2783 {
2784    u_long p;
2785 
2786    /*
2787     *    Disable Display DMA
2788     */
2789 
2790    custom.dmacon = DMAF_ALL | DMAF_MASTER;
2791 
2792    /*
2793     *    Set the Default Video Mode
2794     */
2795 
2796    if (!amifb_mode)
2797       amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
2798                                   DEFMODE_PAL : DEFMODE_NTSC);
2799 
2800    /*
2801     *    Allocate Chip RAM Structures
2802     */
2803 
2804    videomemorysize = VIDEOMEMSIZE_OCS;
2805 
2806 
2807    ...
2808    ...
2809    ...
2810 
2811 
2812    /*
2813     *    Enable Display DMA
2814     */
2815 
2816    custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
2817                    DMAF_SPRITE;
2818 
2819    return(0);
2820 }
2821 #endif /* CONFIG_AMIFB_OCS */
2822 
2823 
2824 /* -------------------- ECS specific routines ------------------------------- */
2825 
2826 
2827 #ifdef CONFIG_AMIFB_ECS
2828    /*
2829     *    Initialization
2830     *
2831     *    Allocate the required chip memory.
2832     *    Set the default video mode for this chipset. If a video mode was
2833     *    specified on the command line, it will override the default mode.
2834     */
2835 
2836 static int ecs_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2837 {
2838    u_long p;
2839 
2840    /*
2841     *    Disable Display DMA
2842     */
2843 
2844    custom.dmacon = DMAF_ALL | DMAF_MASTER;
2845 
2846    /*
2847     *    Set the Default Video Mode
2848     */
2849 
2850    if (!amifb_mode)
2851       if (AMIGAHW_PRESENT(AMBER_FF))
2852          amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
2853                                      DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC);
2854       else
2855          amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
2856                                      DEFMODE_PAL : DEFMODE_NTSC);
2857 
2858    /*
2859     *    Allocate Chip RAM Structures
2860     */
2861 
2862    if (boot_info.bi_amiga.chip_size > 1048576)
2863       videomemorysize = VIDEOMEMSIZE_ECS_2M;
2864    else
2865       videomemorysize = VIDEOMEMSIZE_ECS_1M;
2866 
2867 
2868    ...
2869    ...
2870    ...
2871 
2872 
2873    /*
2874     *    Enable Display DMA
2875     */
2876 
2877    custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
2878                    DMAF_SPRITE;
2879 
2880    return(0);
2881 }
2882 #endif /* CONFIG_AMIFB_ECS */
2883 
2884 
2885 /* -------------------- AGA specific routines ------------------------------- */
2886 
2887 
2888 #ifdef CONFIG_AMIFB_AGA
2889    /*
2890     *    Macros for the conversion from real world values to hardware register
2891     *    values (and vice versa).
2892     *
2893     *    This helps us to keep our attention on the real stuff...
2894     *
2895     *    Hardware limits:
2896     *
2897     *       parameter     min      max     step
2898     *       ---------     ---     ----     ----
2899     *       diwstrt_h       0     2047        1
2900     *       diwstrt_v       0     2047        1
2901     *       diwstop_h       0     2047        1
2902     *       diwstop_v       0     2047        1
2903     *
2904     *       ddfstrt         0     2032       16
2905     *       ddfstop         0     2032       16
2906     *
2907     *       htotal          8     2048        8
2908     *       hsstrt          0     2040        8
2909     *       hsstop          0     2040        8
2910     *       vtotal          1     2048        1
2911     *       vsstrt          0     2047        1
2912     *       vsstop          0     2047        1
2913     *       hcenter         0     2040        8
2914     *
2915     *       hbstrt          0     2047        1
2916     *       hbstop          0     2047        1
2917     *       vbstrt          0     2047        1
2918     *       vbstop          0     2047        1
2919     *
2920     *    Horizontal values are in 35 ns (SHRES) pixels
2921     *    Vertical values are in scanlines
2922     */
2923 
2924 /* bplcon1 (smooth scrolling) */
2925 
2926 #define hscroll2hw(hscroll) \
2927    (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
2928     ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
2929 
2930 #define hw2hscroll(hscroll) \
2931    (((hscroll)>>8 & 0x00c3) | ((hscroll)<<2 & 0x003c))
2932 
2933 /* diwstrt/diwstop/diwhigh (visible display window) */
2934 
2935 #define diwstrt2hw(diwstrt_h, diwstrt_v) \
2936    (((diwstrt_v)<<8 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
2937 #define diwstop2hw(distop_h, diwstop_v) \
2938    (((diwstop_v)<<8 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
2939 #define diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v) \
2940    (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
2941     ((diwstop_v) & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
2942     ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>8 & 0x0007))
2943 
2944 #define hw2diwstrt_h(diwstrt, diwhigh) \
2945    (((diwhigh)<<5 & 0x0400) | ((diwstrt)<<2 & 0x03fc) | ((diwhigh)>>3 & 0x0003))
2946 #define hw2diwstrt_v(diwstrt, diwhigh) \
2947    (((diwhigh)<<8 & 0x0700) | ((diwstrt)>>8 & 0x00ff))
2948 #define hw2diwstop_h(diwstop, diwhigh) \
2949    (((diwhigh)>>3 & 0x0400) | ((diwstop)<<2 & 0x03fc) | \
2950     ((diwhigh)>>11 & 0x0003))
2951 #define hw2diwstop_v(diwstop, diwhigh) \
2952    (((diwhigh) & 0x0700) | ((diwstop)>>8 & 0x00ff))
2953 
2954 /* ddfstrt/ddfstop (display DMA) */
2955 
2956 #define ddfstrt2hw(ddfstrt)   (div8(ddfstrt) & 0x00fe)
2957 #define ddfstop2hw(ddfstop)   (div8(ddfstop) & 0x00fe)
2958 
2959 #define hw2ddfstrt(ddfstrt)   ((ddfstrt)<<3)
2960 #define hw2ddfstop(ddfstop)   ((ddfstop)<<3)
2961 
2962 /* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal (sync timings) */
2963 
2964 #define hsstrt2hw(hsstrt)     (div8(hsstrt))
2965 #define hsstop2hw(hsstop)     (div8(hsstop))
2966 #define htotal2hw(htotal)     (div8(htotal)-1)
2967 #define vsstrt2hw(vsstrt)     (vsstrt)
2968 #define vsstop2hw(vsstop)     (vsstop)
2969 #define vtotal2hw(vtotal)     ((vtotal)-1)
2970 
2971 #define hw2hsstrt(hsstrt)     ((hsstrt)<<3)
2972 #define hw2hsstop(hsstop)     ((hsstop)<<3)
2973 #define hw2htotal(htotal)     (((htotal)+1)<<3)
2974 #define hw2vsstrt(vsstrt)     (vsstrt)
2975 #define hw2vsstop(vsstop)     (vsstop)
2976 #define hw2vtotal(vtotal)     ((vtotal)+1)
2977 
2978 /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
2979 
2980 #define hbstrt2hw(hbstrt)     (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
2981 #define hbstop2hw(hbstop)     (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
2982 #define vbstrt2hw(vbstrt)     (vbstrt)
2983 #define vbstop2hw(vbstop)     (vbstop)
2984 
2985 #define hw2hbstrt(hbstrt)     (((hbstrt)<<3 & 0x07f8) | ((hbstrt)>>8 & 0x0007))
2986 #define hw2hbstop(hbstop)     (((hbstop)<<3 & 0x07f8) | ((hbstop)>>8 & 0x0007))
2987 #define hw2vbstrt(vbstrt)     (vbstrt)
2988 #define hw2vbstop(vbstop)     (vbstop)
2989 
2990 /* color */
2991 
2992 #define rgb2hw_high(red, green, blue) \
2993    (((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f))
2994 #define rgb2hw_low(red, green, blue) \
2995    (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
2996 
2997 #define hw2red(high, low)     (((high)>>4 & 0xf0) | ((low)>>8 & 0x0f))
2998 #define hw2green(high, low)   (((high) & 0xf0) | ((low)>>4 & 0x0f))
2999 #define hw2blue(high, low)    (((high)<<4 & 0xf0) | ((low) & 0x0f))
3000 
3001 /* sprpos/sprctl (sprite positioning) */
3002 
3003 #define spr2hw_pos(start_v, start_h) \
3004    (((start_v)<<8&0xff00) | ((start_h)>>3&0x00ff))
3005 #define spr2hw_ctl(start_v, start_h, stop_v) \
3006    (((stop_v)<<8&0xff00) | ((start_v)>>3&0x0040) | ((stop_v)>>4&0x0020) | \
3007     ((start_h)<<3&0x0018) | ((start_v)>>6&0x0004) | ((stop_v)>>7&0x0002) | \
3008     ((start_h)>>2&0x0001))
3009 
3010 
3011    /*
3012     *    Hardware Cursor
3013     */
3014 
3015 struct aga_cursorsprite {
3016    u_short sprpos;
3017    u_short pad1[3];
3018    u_short sprctl;
3019    u_short pad2[3];
3020    union {
3021       struct {
3022          u_long data[64*4];
3023          u_long trailer[4];
3024       } nonlaced;
3025       struct {
3026          u_long data[32*4];
3027          u_long trailer[4];
3028       } laced;
3029    } u;
3030 };
3031 
3032 struct aga_dummysprite {
3033    u_short sprpos;
3034    u_short pad1[3];
3035    u_short sprctl;
3036    u_short pad2[3];
3037    u_long data[4];
3038    u_long trailer[4];
3039 };
3040 
3041 
3042    /*
3043     *    Pixel modes for Bitplanes and Sprites
3044     */
3045 
3046 static u_short bplpixmode[3] = {
3047    BPC0_SHRES,                   /*  35 ns / 28 MHz */
3048    BPC0_HIRES,                   /*  70 ns / 14 MHz */
3049    0                             /* 140 ns /  7 MHz */
3050 };
3051 
3052 static u_short sprpixmode[3] = {
3053    BPC3_SPRES1 | BPC3_SPRES0,    /*  35 ns / 28 MHz */
3054    BPC3_SPRES1,                  /*  70 ns / 14 MHz */
3055    BPC3_SPRES0                   /* 140 ns /  7 MHz */
3056 };
3057 
3058 
3059    /*
3060     *    Initialization
3061     *
3062     *    Allocate the required chip memory.
3063     *    Set the default video mode for this chipset. If a video mode was
3064     *    specified on the command line, it will override the default mode.
3065     */
3066 
3067 static int aga_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3068 {
3069    u_long p;
3070 
3071    /*
3072     *    Disable Display DMA
3073     */
3074 
3075    custom.dmacon = DMAF_ALL | DMAF_MASTER;
3076 
3077    /*
3078     *    Set the Default Video Mode
3079     */
3080 
3081    if (!amifb_mode)
3082       amifb_mode = get_video_mode(DEFMODE_AGA);
3083 
3084    /*
3085     *    Allocate Chip RAM Structures
3086     */
3087 
3088    if (boot_info.bi_amiga.chip_size > 1048576)
3089       videomemorysize = VIDEOMEMSIZE_AGA_2M;
3090    else
3091       videomemorysize = VIDEOMEMSIZE_AGA_1M;
3092 
3093    p = chipalloc(videomemorysize+                     /* Bitplanes */
3094                  sizeof(struct clist_hdr)+            /* Copper Lists */
3095                  2*sizeof(struct clist_dyn)+
3096                  2*sizeof(struct aga_cursorsprite)+   /* Sprites */
3097                  sizeof(struct aga_dummysprite));
3098 
3099    assignchunk(videomemory, u_long, p, videomemorysize);
3100    assignchunk(clist_hdr, struct clist_hdr *, p, sizeof(struct clist_hdr));
3101    assignchunk(clist_lof, struct clist_dyn *, p, sizeof(struct clist_dyn));
3102    assignchunk(clist_shf, struct clist_dyn *, p, sizeof(struct clist_dyn));
3103    assignchunk(lofsprite, u_long *, p, sizeof(struct aga_cursorsprite));
3104    assignchunk(shfsprite, u_long *, p, sizeof(struct aga_cursorsprite));
3105    assignchunk(dummysprite, u_long *, p, sizeof(struct aga_dummysprite));
3106 
3107    /*
3108     *    Make sure the Copper has something to do
3109     */
3110 
3111    aga_build_clist_hdr(clist_hdr);
3112 
3113    custom.cop1lc = (u_short *)ZTWO_PADDR(clist_hdr);
3114    custom.cop2lc = (u_short *)ZTWO_PADDR(&clist_hdr->wait_forever);
3115    custom.copjmp1 = 0;
3116 
3117    /*
3118     *    Enable Display DMA
3119     */
3120 
3121    custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
3122                    DMAF_SPRITE;
3123 
3124    /*
3125     *    These hardware register values will never be changed later
3126     */
3127 
3128    custom.bplcon2 = BPC2_KILLEHB | BPC2_PF2P2 | BPC2_PF1P2;
3129    custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
3130 
3131    return(0);
3132 }
3133 
3134 
3135    /*
3136     *    This function should fill in the `fix' structure based on the
3137     *    values in the `par' structure.
3138     */
3139 
3140 static int aga_encode_fix(struct fb_fix_screeninfo *fix,
     /* [previous][next][first][last][top][bottom][index][help] */
3141                           struct amiga_fb_par *par)
3142 {
3143    int i;
3144 
3145    strcpy(fix->id, amiga_fb_name);
3146    fix->smem_start = videomemory;
3147    fix->smem_len = videomemorysize;
3148 
3149    if (amifb_ilbm) {
3150       fix->type = FB_TYPE_INTERLEAVED_PLANES;
3151       fix->type_aux = par->next_line;
3152    } else {
3153       fix->type = FB_TYPE_PLANES;
3154       fix->type_aux = 0;
3155    }
3156    fix->visual = FB_VISUAL_PSEUDOCOLOR;
3157 
3158    if (par->diwstrt_h >= 323)
3159       fix->xpanstep = 1;
3160    else
3161       fix->xpanstep = 64;
3162    fix->ypanstep = 1;
3163 
3164    if (hw2ddfstrt(par->ddfstrt) >= (par->bpp-1)*64)
3165       fix->ywrapstep = 1;
3166    else
3167       fix->ywrapstep = 0;
3168 
3169    fix->line_length = 0;
3170    for (i = 0; i < arraysize(fix->reserved); i++)
3171       fix->reserved[i] = 0;
3172 
3173    return(0);
3174 }
3175 
3176 
3177    /*
3178     *    Get the video params out of `var'. If a value doesn't fit, round
3179     *    it up, if it's too big, return -EINVAL.
3180     */
3181 
3182 static int aga_decode_var(struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
3183                           struct amiga_fb_par *par)
3184 {
3185    u_short clk_shift, line_shift_incd;
3186    u_long upper, lower, hslen, vslen;
3187    int xres_n, yres_n, xoffset_n;                              /* normalized */
3188    u_long left_n, right_n, upper_n, lower_n, hslen_n, vslen_n; /* normalized */
3189    u_long diwstrt_h, diwstrt_v, diwstop_h, diwstop_v;
3190    u_long hsstrt, vsstrt, hsstop, vsstop, htotal, vtotal;
3191    u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll;
3192    double hrate, vrate;
3193    u_short loopcnt = 0;
3194 
3195    /*
3196     *    Find a matching Pixel Clock
3197     */
3198 
3199    for (clk_shift = 0; clk_shift < 3; clk_shift++)
3200       if (var->pixclock <= pixclock[clk_shift])
3201          break;
3202    if (clk_shift >= 3)
3203       return(-EINVAL);
3204    par->clk_shift = clk_shift;
3205 
3206    /*
3207     *    Round up the Geometry Values (if necessary)
3208     */
3209 
3210    par->xres = max(var->xres, 64);
3211    par->yres = max(var->yres, 64);
3212    par->vxres = up64(max(var->xres_virtual, par->xres));
3213    par->vyres = max(var->yres_virtual, par->yres);
3214 
3215    par->bpp = var->bits_per_pixel;
3216    if (par->bpp > 8)
3217       return(-EINVAL);
3218 
3219    if (!var->nonstd) {
3220       if (par->bpp < 1)
3221          par->bpp = 1;
3222    } else if (var->nonstd == FB_NONSTD_HAM)
3223       par->bpp = par->bpp <= 6 ? 6 : 8;
3224    else
3225       return(-EINVAL);
3226 
3227    upper = var->upper_margin;
3228    lower = var->lower_margin;
3229    hslen = var->hsync_len;
3230    vslen = var->vsync_len;
3231 
3232    par->vmode = var->vmode;
3233    switch (par->vmode & FB_VMODE_MASK) {
3234       case FB_VMODE_NONINTERLACED:
3235          line_shift_incd = 1;
3236          break;
3237       case FB_VMODE_INTERLACED:
3238          line_shift_incd = 0;
3239          if (par->yres & 1)
3240             par->yres++;               /* even */
3241          if (upper & 1)
3242             upper++;                   /* even */
3243          if (!(lower & 1))
3244             lower++;                   /* odd */
3245          if (vslen & 1)
3246             vslen++;                   /* even */
3247          break;
3248       case FB_VMODE_DOUBLE:
3249          line_shift_incd = 2;
3250          break;
3251       default:
3252          return(-EINVAL);
3253          break;
3254    }
3255 
3256    par->xoffset = var->xoffset;
3257    par->yoffset = var->yoffset;
3258    if (par->vmode & FB_VMODE_YWRAP) {
3259       if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->yres)
3260          return(-EINVAL);
3261    } else {
3262       if (par->xoffset < 0 || par->xoffset+par->xres > par->vxres ||
3263           par->yoffset < 0 || par->yoffset+par->yres > par->vyres)
3264          return(-EINVAL);
3265    }
3266 
3267    if (var->sync & FB_SYNC_BROADCAST) {
3268       if (hslen || vslen)
3269          return(-EINVAL);
3270    } else {
3271       hslen = hslen < 1 ? 1 : hslen;
3272       vslen = vslen < 1 ? 1 : vslen;
3273    }
3274 
3275    /*
3276     *    Check the Memory Requirements
3277     */
3278 
3279    if (par->vxres*par->vyres*par->bpp > videomemorysize<<3)
3280       return(-EINVAL);
3281 
3282    /*
3283     *    Normalize all values:
3284     *
3285     *      - horizontal: in 35 ns (SHRES) pixels
3286     *      - vertical: in non-interlaced scanlines
3287     */
3288 
3289    xres_n = par->xres<<clk_shift;
3290    xoffset_n = par->xoffset<<clk_shift;
3291    yres_n = par->yres<<line_shift_incd>>1;
3292 
3293    left_n = var->left_margin<<clk_shift;
3294    right_n = var->right_margin<<clk_shift;
3295    hslen_n = hslen<<clk_shift;
3296    upper_n = upper<<line_shift_incd>>1;
3297    lower_n = lower<<line_shift_incd>>1;
3298    vslen_n = vslen<<line_shift_incd>>1;
3299 
3300    /*
3301     *    Vertical and Horizontal Timings
3302     */
3303 
3304    par->bplcon3 = sprpixmode[clk_shift];
3305 aga_calculate_timings:
3306    if (var->sync & FB_SYNC_BROADCAST) {
3307       if (upper_n+yres_n+lower_n == PAL_WINDOW_V) {
3308          /* PAL video mode */
3309          diwstrt_v = PAL_DIWSTRT_V+upper_n;
3310          diwstop_v = diwstrt_v+yres_n;
3311          diwstrt_h = PAL_DIWSTRT_H+left_n;
3312          diwstop_h = diwstrt_h+xres_n+1;
3313          par->htotal = htotal2hw(PAL_HTOTAL);
3314          hrate = 15625;
3315          vrate = 50;
3316          par->beamcon0 = BMC0_PAL;
3317       } else if (upper_n+yres_n+lower_n == NTSC_WINDOW_V) {
3318          /* NTSC video mode */
3319          diwstrt_v = NTSC_DIWSTRT_V+upper_n;
3320          diwstop_v = diwstrt_v+yres_n;
3321          diwstrt_h = NTSC_DIWSTRT_H+left_n;
3322          diwstop_h = diwstrt_h+xres_n+1;
3323          par->htotal = htotal2hw(NTSC_HTOTAL);
3324          hrate = 15750;
3325          vrate = 60;
3326          par->beamcon0 = 0;
3327       } else
3328          return(-EINVAL);
3329    } else {
3330       /* Programmable video mode */
3331       vsstrt = lower_n;
3332       vsstop = vsstrt+vslen_n;
3333       diwstrt_v = vsstop+upper_n;
3334       diwstop_v = diwstrt_v+yres_n;
3335       vtotal = diwstop_v;
3336       hslen_n = up8(hslen_n);
3337       htotal = up8(left_n+xres_n+right_n+hslen_n);
3338       if (vtotal > 2048 || htotal > 2048)
3339          return(-EINVAL);
3340       right_n = htotal-left_n-xres_n-hslen_n;
3341       hsstrt = down8(right_n+4);
3342       hsstop = hsstrt+hslen_n;
3343       diwstop_h = htotal+hsstrt-right_n+1;
3344       diwstrt_h = diwstop_h-xres_n-1;
3345       hrate = (double)amiga_masterclock/htotal;
3346       vrate = hrate/vtotal;
3347       par->bplcon3 |= BPC3_BRDRBLNK | BPC3_EXTBLKEN;
3348       par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
3349                       BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
3350                       BMC0_PAL | BMC0_VARCSYEN;
3351       if (var->sync & FB_SYNC_HOR_HIGH_ACT)
3352          par->beamcon0 |= BMC0_HSYTRUE;
3353       if (var->sync & FB_SYNC_VERT_HIGH_ACT)
3354          par->beamcon0 |= BMC0_VSYTRUE;
3355       if (var->sync & FB_SYNC_COMP_HIGH_ACT)
3356          par->beamcon0 |= BMC0_CSYTRUE;
3357       par->htotal = htotal2hw(htotal);
3358       par->hsstrt = hsstrt2hw(hsstrt);
3359       par->hsstop = hsstop2hw(hsstop);
3360       par->vtotal = vtotal2hw(vtotal);
3361       par->vsstrt = vsstrt2hw(vsstrt);
3362       par->vsstop = vsstop2hw(vsstop);
3363       par->hcenter = par->hsstrt+(par->htotal>>1);
3364    }
3365    par->diwstrt_v = diwstrt_v;
3366    par->diwstrt_h = diwstrt_h;
3367    par->crsr_x = 0;
3368    par->crsr_y = 0;
3369 
3370    /*
3371     *    DMA Timings
3372     */
3373 
3374    ddfmin = down64(xoffset_n);
3375    ddfmax = up64(xoffset_n+xres_n);
3376    hscroll = diwstrt_h-68-mod64(xoffset_n);
3377    ddfstrt = down64(hscroll);
3378    if (ddfstrt < 128) {
3379       right_n += (128-hscroll);
3380       /* Prevent an infinite loop */
3381       if (loopcnt++)
3382          return(-EINVAL);
3383       goto aga_calculate_timings;
3384    }
3385    hscroll -= ddfstrt;
3386    ddfstop = ddfstrt+ddfmax-ddfmin-(64<<clk_shift);
3387 
3388    /*
3389     *    Bitplane calculations
3390     */
3391 
3392    if (amifb_ilbm) {
3393       par->next_plane = div8(par->vxres);
3394       par->next_line = par->bpp*par->next_plane;
3395    } else {
3396       par->next_line = div8(par->vxres);
3397       par->next_plane = par->vyres*par->next_line;
3398    }
3399    par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+
3400                             par->yoffset*par->next_line);
3401    par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift);
3402    par->bpl2mod = par->bpl1mod;
3403 
3404    /*
3405     *    Hardware Register Values
3406     */
3407 
3408    par->bplcon0 = BPC0_COLOR | BPC0_ECSENA | bplpixmode[clk_shift];
3409    if (par->bpp == 8)
3410       par->bplcon0 |= BPC0_BPU3;
3411    else
3412       par->bplcon0 |= par->bpp<<12;
3413    if (var->nonstd == FB_NONSTD_HAM)
3414       par->bplcon0 |= BPC0_HAM;
3415    if (var->sync & FB_SYNC_EXT)
3416       par->bplcon0 |= BPC0_ERSY;
3417    par->bplcon1 = hscroll2hw(hscroll);
3418    par->diwstrt = diwstrt2hw(diwstrt_h, diwstrt_v);
3419    par->diwstop = diwstop2hw(diwstop_h, diwstop_v);
3420    par->diwhigh = diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v);
3421    par->ddfstrt = ddfstrt2hw(ddfstrt);
3422    par->ddfstop = ddfstop2hw(ddfstop);
3423    par->fmode = FMODE_SPAGEM | FMODE_SPR32 | FMODE_BPAGEM | FMODE_BPL32;
3424 
3425    switch (par->vmode & FB_VMODE_MASK) {
3426       case FB_VMODE_INTERLACED:
3427          par->bpl1mod += par->next_line;
3428          par->bpl2mod += par->next_line;
3429          par->bplcon0 |= BPC0_LACE;
3430          break;
3431       case FB_VMODE_DOUBLE:
3432          par->bpl1mod -= par->next_line;
3433          par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
3434          break;
3435    }
3436 
3437    if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax)
3438       return(-EINVAL);
3439 
3440    return(0);
3441 }
3442 
3443 
3444    /*
3445     *    Fill the `var' structure based on the values in `par' and maybe
3446     *    other values read out of the hardware.
3447     */
3448 
3449 static int aga_encode_var(struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
3450                           struct amiga_fb_par *par)
3451 {
3452    u_short clk_shift, line_shift_incd;
3453    u_long left, right, upper, lower, hslen, vslen;
3454    u_short diwstop_h, diwstop_v;
3455    u_short hsstrt, vsstrt, hsstop, vsstop, htotal;
3456    int i;
3457 
3458    var->xres = par->xres;
3459    var->yres = par->yres;
3460    var->xres_virtual = par->vxres;
3461    var->yres_virtual = par->vyres;
3462    var->xoffset = par->xoffset;
3463    var->yoffset = par->yoffset;
3464 
3465    var->bits_per_pixel = par->bpp;
3466    var->grayscale = 0;
3467 
3468    var->red.offset = 0;
3469    var->red.length = 8;
3470    var->red.msb_right = 0;
3471    var->blue = var->green = var->red;
3472    var->transp.offset = 0;
3473    var->transp.length = 0;
3474    var->transp.msb_right = 0;
3475 
3476    if (par->bplcon0 & BPC0_HAM)
3477       var->nonstd = FB_NONSTD_HAM;
3478    else
3479       var->nonstd = 0;
3480    var->activate = 0;
3481 
3482    var->height = -1;
3483    var->width = -1;
3484    var->accel = FB_ACCEL_NONE;
3485 
3486    clk_shift = par->clk_shift;
3487    var->pixclock = pixclock[clk_shift];
3488 
3489    diwstop_h = hw2diwstop_h(par->diwstop, par->diwhigh);
3490    if (par->beamcon0 & BMC0_VARBEAMEN) {
3491       hsstrt = hw2hsstrt(par->hsstrt);
3492       vsstrt = hw2vsstrt(par->vsstrt);
3493       hsstop = hw2hsstop(par->hsstop);
3494       vsstop = hw2vsstop(par->vsstop);
3495       htotal = hw2htotal(par->htotal);
3496       left = par->diwstrt_h-hsstop;
3497       right = htotal+hsstrt-diwstop_h+1;
3498       hslen = hsstop-hsstrt;
3499       upper = par->diwstrt_v-vsstop;
3500       lower = vsstrt;
3501       vslen = vsstop-vsstrt;
3502       var->sync = 0;
3503    } else {
3504       diwstop_v = hw2diwstop_v(par->diwstop, par->diwhigh);
3505       if (par->beamcon0 & BMC0_PAL) {
3506          left = par->diwstrt_h-PAL_DIWSTRT_H;
3507          right = PAL_DIWSTRT_H+PAL_WINDOW_H-diwstop_h+1;
3508          upper = par->diwstrt_v-PAL_DIWSTRT_V;
3509          lower = PAL_DIWSTRT_V+PAL_WINDOW_V-diwstop_v;
3510       } else {
3511          left = par->diwstrt_h-NTSC_DIWSTRT_H;
3512          right = NTSC_DIWSTRT_H+NTSC_WINDOW_H-diwstop_h;
3513          upper = par->diwstrt_v-NTSC_DIWSTRT_V;
3514          lower = NTSC_DIWSTRT_V+NTSC_WINDOW_V-diwstop_v;
3515       }
3516       hslen = 0;
3517       vslen = 0;
3518       var->sync = FB_SYNC_BROADCAST;
3519    }
3520 
3521    if (par->bplcon0 & BPC0_ERSY)
3522       var->sync |= FB_SYNC_EXT;
3523    if (par->beamcon0 & BMC0_HSYTRUE)
3524       var->sync |= FB_SYNC_HOR_HIGH_ACT;
3525    if (par->beamcon0 & BMC0_VSYTRUE)
3526       var->sync |= FB_SYNC_VERT_HIGH_ACT;
3527    if (par->beamcon0 & BMC0_CSYTRUE)
3528       var->sync |= FB_SYNC_COMP_HIGH_ACT;
3529 
3530    switch (par->vmode & FB_VMODE_MASK) {
3531       case FB_VMODE_NONINTERLACED:
3532          line_shift_incd = 1;
3533          break;
3534       case FB_VMODE_INTERLACED:
3535          line_shift_incd = 0;
3536          break;
3537       case FB_VMODE_DOUBLE:
3538          line_shift_incd = 2;
3539          break;
3540    }
3541 
3542    var->left_margin = left>>clk_shift;
3543    var->right_margin = right>>clk_shift;
3544    var->upper_margin = upper<<1>>line_shift_incd;
3545    var->lower_margin = lower<<1>>line_shift_incd;
3546    var->hsync_len = hslen>>clk_shift;
3547    var->vsync_len = vslen<<1>>line_shift_incd;
3548    var->vmode = par->vmode;
3549    for (i = 0; i < arraysize(var->reserved); i++)
3550       var->reserved[i] = 0;
3551 
3552    return(0);
3553 }
3554 
3555 
3556    /*
3557     *    Read a single color register and split it into
3558     *    colors/transparent. Return != 0 for invalid regno.
3559     */
3560 
3561 static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
     /* [previous][next][first][last][top][bottom][index][help] */
3562                          u_int *transp)
3563 {
3564    if (regno > 255)
3565       return(1);
3566 
3567    *red = palette[regno].red;
3568    *green = palette[regno].green;
3569    *blue = palette[regno].blue;
3570    return(0);
3571 }
3572 
3573 
3574    /*
3575     *    Set a single color register. The values supplied are already
3576     *    rounded down to the hardware's capabilities (according to the
3577     *    entries in the var structure). Return != 0 for invalid regno.
3578     */
3579 
3580 static int aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
     /* [previous][next][first][last][top][bottom][index][help] */
3581                          u_int transp)
3582 {
3583    u_short bplcon3 = current_par.bplcon3;
3584 
3585    if (regno > 255)
3586       return(1);
3587 
3588    /*
3589     *    Update the corresponding Hardware Color Register, unless it's Color
3590     *    Register 0 and the screen is blanked.
3591     *
3592     *    The cli()/sti() pair is here to protect bplcon3 from being changed by
3593     *    the VBlank interrupt routine.
3594     */
3595 
3596    cli();
3597    if (regno || !is_blanked) {
3598       custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
3599       custom.color[regno&31] = rgb2hw_high(red, green, blue);
3600       custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
3601       custom.color[regno&31] = rgb2hw_low(red, green, blue);
3602       custom.bplcon3 = bplcon3;
3603    }
3604    sti();
3605 
3606    palette[regno].red = red;
3607    palette[regno].green = green;
3608    palette[regno].blue = blue;
3609 
3610    return(0);
3611 }
3612 
3613 
3614    /*
3615     *    Pan or Wrap the Display
3616     *
3617     *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
3618     *    in `var'.
3619     */
3620 
3621 static int aga_pan_display(struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
3622                            struct amiga_fb_par *par)
3623 {
3624    int xoffset, yoffset, vmode, xres_n, xoffset_n;
3625    u_short clk_shift, line_shift_incd;
3626    u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll;
3627 
3628    xoffset = var->xoffset;
3629    yoffset = var->yoffset;
3630    if (var->vmode & FB_VMODE_YWRAP) {
3631       if (hw2ddfstrt(par->ddfstrt) < (par->bpp-1)*64 || xoffset ||
3632           yoffset < 0 || yoffset >= par->yres)
3633          return(-EINVAL);
3634       vmode = par->vmode | FB_VMODE_YWRAP;
3635    } else {
3636       if (par->diwstrt_h < 323)
3637          xoffset = up64(xoffset);
3638       if (xoffset < 0 || xoffset+par->xres > par->vxres ||
3639           yoffset < 0 || yoffset+par->yres > par->vyres)
3640          return(-EINVAL);
3641       vmode = par->vmode & ~FB_VMODE_YWRAP;
3642    }
3643 
3644    clk_shift = par->clk_shift;
3645    switch (vmode & FB_VMODE_MASK) {
3646       case FB_VMODE_NONINTERLACED:
3647          line_shift_incd = 1;
3648          break;
3649       case FB_VMODE_INTERLACED:
3650          line_shift_incd = 0;
3651          break;
3652       case FB_VMODE_DOUBLE:
3653          line_shift_incd = 2;
3654          break;
3655    }
3656    xres_n = par->xres<<clk_shift;
3657    xoffset_n = xoffset<<clk_shift;
3658 
3659    /*
3660     *    DMA timings
3661     */
3662 
3663    ddfmin = down64(xoffset_n);
3664    ddfmax = up64(xoffset_n+xres_n);
3665    hscroll = par->diwstrt_h-68-mod64(xoffset_n);
3666    ddfstrt = down64(hscroll);
3667    if (ddfstrt < 128)
3668       return(-EINVAL);
3669    hscroll -= ddfstrt;
3670    ddfstop = ddfstrt+ddfmax-ddfmin-(64<<clk_shift);
3671    par->bplcon1 = hscroll2hw(hscroll);
3672    par->ddfstrt = ddfstrt2hw(ddfstrt);
3673    par->ddfstop = ddfstop2hw(ddfstop);
3674 
3675    /*
3676     *    Bitplane calculations
3677     */
3678 
3679    par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+
3680                             yoffset*par->next_line);
3681    par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift);
3682    par->bpl2mod = par->bpl1mod;
3683    switch (vmode & FB_VMODE_MASK) {
3684       case FB_VMODE_INTERLACED:
3685          par->bpl1mod += par->next_line;
3686          par->bpl2mod += par->next_line;
3687          break;
3688       case FB_VMODE_DOUBLE:
3689          par->bpl1mod -= par->next_line;
3690          break;
3691    }
3692 
3693    par->xoffset = var->xoffset = xoffset;
3694    par->yoffset = var->yoffset = yoffset;
3695    par->vmode = var->vmode = vmode;
3696    return(0);
3697 }
3698 
3699 
3700    /*
3701     *    Change the video mode (called by VBlank interrupt)
3702     */
3703 
3704 void aga_do_vmode(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3705 {
3706    struct amiga_fb_par *par = &current_par;
3707 
3708    /*
3709     *    Rebuild the dynamic part of the Copper List and activate the right
3710     *    Copper List as soon as possible
3711     *
3712     *    Make sure we're in a Long Frame if the video mode is interlaced.
3713     *    This is always the case if we already were in an interlaced mode,
3714     *    since then the VBlank only calls us during a Long Frame.
3715     *    But this _is_ necessary if we're switching from a non-interlaced
3716     *    to an interlaced mode.
3717     */
3718 
3719    if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
3720       custom.vposw = 0x8000;
3721       aga_build_clist_dyn(clist_lof, clist_shf, 0, par);
3722       custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof);
3723       aga_build_clist_dyn(clist_shf, clist_lof, 1, par);
3724    } else {
3725       aga_build_clist_dyn(clist_lof, NULL, 0, par);
3726       custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof);
3727    }
3728 
3729    /*
3730     *    Update the hardware registers
3731     */
3732 
3733    if (full_vmode_change) {
3734       custom.fmode = par->fmode;
3735       custom.beamcon0 = par->beamcon0;
3736       if (par->beamcon0 & BMC0_VARBEAMEN) {
3737          custom.htotal = par->htotal;
3738          custom.vtotal = par->vtotal;
3739          custom.hsstrt = par->hsstrt;
3740          custom.hsstop = par->hsstop;
3741          custom.hbstrt = par->hsstrt;
3742          custom.hbstop = par->hsstop;
3743          custom.vsstrt = par->vsstrt;
3744          custom.vsstop = par->vsstop;
3745          custom.vbstrt = par->vsstrt;
3746          custom.vbstop = par->vsstop;
3747          custom.hcenter = par->hcenter;
3748       }
3749       custom.bplcon3 = par->bplcon3;
3750       full_vmode_change = 0;
3751    }
3752    custom.ddfstrt = par->ddfstrt;
3753    custom.ddfstop = par->ddfstop;
3754    custom.bpl1mod = par->bpl1mod;
3755    custom.bpl2mod = par->bpl2mod;
3756    custom.bplcon1 = par->bplcon1;
3757 
3758    /*
3759     *    Update the Frame Header Copper List
3760     */
3761 
3762    aga_update_clist_hdr(clist_hdr, par);
3763 
3764    /*
3765     *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
3766     */
3767 
3768    if ((boot_info.bi_amiga.chipset != CS_STONEAGE) && full_vmode_change)
3769       amiga_audio_min_period = (par->htotal>>1)+1;
3770 }
3771 
3772 
3773    /*
3774     *    (Un)Blank the screen (called by VBlank interrupt)
3775     */
3776 
3777 void aga_do_blank(int blank)
     /* [previous][next][first][last][top][bottom][index][help] */
3778 {
3779    struct amiga_fb_par *par = &current_par;
3780    u_short bplcon3 = par->bplcon3;
3781    u_char red, green, blue;
3782 
3783    if (blank) {
3784       custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
3785       red = green = blue = 0;
3786       if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) {
3787          /* VESA suspend mode, switch off HSYNC */
3788          custom.hsstrt = par->htotal+2;
3789          custom.hsstop = par->htotal+2;
3790       }
3791    } else {
3792       custom.dmacon = DMAF_SETCLR | DMAF_RASTER;
3793       red = palette[0].red;
3794       green = palette[0].green;
3795       blue = palette[0].blue;
3796       if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) {
3797          custom.hsstrt = par->hsstrt;
3798          custom.hsstop = par->hsstop;
3799       }
3800    }
3801    custom.bplcon3 = bplcon3;
3802    custom.color[0] = rgb2hw_high(red, green, blue);
3803    custom.bplcon3 = bplcon3 | BPC3_LOCT;
3804    custom.color[0] = rgb2hw_low(red, green, blue);
3805    custom.bplcon3 = bplcon3;
3806 
3807    is_blanked = blank;
3808 }
3809 
3810 
3811    /*
3812     *    Move the cursor (called by VBlank interrupt)
3813     */
3814 
3815 void aga_do_movecursor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3816 {
3817    struct amiga_fb_par *par = &current_par;
3818    struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
3819    long hs, vs, ve;
3820    u_short s1, s2, is_double = 0;
3821 
3822    if (par->crsr_x <= -64 || par->crsr_x >= par->xres || par->crsr_y <= -64 ||
3823        par->crsr_y >= par->yres)
3824       hs = vs = ve = 0;
3825    else {
3826       hs = par->diwstrt_h-4+(par->crsr_x<<par->clk_shift);
3827       vs = par->crsr_y;
3828       ve = min(vs+64, par->yres);
3829       switch (par->vmode & FB_VMODE_MASK) {
3830          case FB_VMODE_INTERLACED:
3831             vs >>= 1;
3832             ve >>= 1;
3833             break;
3834          case FB_VMODE_DOUBLE:
3835             vs <<= 1;
3836             ve <<= 1;
3837             is_double = 1;
3838             break;
3839       }
3840       vs += par->diwstrt_v;
3841       ve += par->diwstrt_v;
3842    }
3843    s1 = spr2hw_pos(vs, hs);
3844    if (is_double)
3845       s1 |= 0x80;
3846    s2 = spr2hw_ctl(vs, hs, ve);
3847    sprite->sprpos = s1;
3848    sprite->sprctl = s2;
3849 
3850    /*
3851     *    TODO: Special cases:
3852     *    
3853     *      - Interlaced: fill position in in both lofsprite & shfsprite
3854     *                    swap lofsprite & shfsprite on odd lines
3855     *    
3856     *      - Doublescan: OK?
3857     *    
3858     *      - ve <= bottom of display: OK?
3859     */
3860 }
3861 
3862 
3863    /*
3864     *    Flash the cursor (called by VBlank interrupt)
3865     */
3866 
3867 void aga_do_flashcursor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3868 {
3869 #if 1
3870    static int cursorcount = 0;
3871    static int cursorstate = 0;
3872 
3873    switch (cursormode) {
3874       case FB_CURSOR_OFF:
3875          custom.dmacon = DMAF_SPRITE;
3876          break;
3877       case FB_CURSOR_ON:
3878          custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
3879          break;
3880       case FB_CURSOR_FLASH:
3881          if (cursorcount)
3882             cursorcount--;
3883          else {
3884             cursorcount = CRSR_RATE;
3885             if ((cursorstate = !cursorstate))
3886                custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
3887             else
3888                custom.dmacon = DMAF_SPRITE;
3889          }
3890          break;
3891    }
3892 #endif
3893 }
3894 
3895 
3896 #if 1
3897 static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3898 {
3899 #if 0
3900    if (ddfstrt >= 192) {
3901 #endif
3902       fix->crsr_width = 64;
3903       fix->crsr_height = 64;
3904       fix->crsr_xsize = 64;
3905       fix->crsr_ysize = 64;
3906       fix->crsr_color1 = 17;
3907       fix->crsr_color2 = 18;
3908 #if 0
3909    } else {
3910       fix->crsr_width = 0;
3911       fix->crsr_height = 0;
3912       fix->crsr_xsize = 0;
3913       fix->crsr_ysize = 0;
3914       fix->crsr_color1 = 0;
3915       fix->crsr_color2 = 0;
3916    }
3917 #endif
3918    return(0);
3919 }
3920 
3921 
3922 static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3923 {
3924    struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
3925 
3926    /* TODO: interlaced sprites */
3927    memcpy(var->data, sprite->u.nonlaced.data, sizeof(var->data));
3928    return(0);
3929 }
3930 
3931 
3932 static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3933 {
3934    struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
3935 
3936    /* TODO: interlaced sprites */
3937    memcpy(sprite->u.nonlaced.data, var->data, sizeof(var->data));
3938    return(0);
3939 }
3940 
3941 
3942 static int aga_get_cursorstate(struct fb_cursorstate *state, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3943 {
3944    state->xoffset = current_par.crsr_x;
3945    state->yoffset = current_par.crsr_y;
3946    state->mode = cursormode;
3947    return(0);
3948 }
3949 
3950 
3951 static int aga_set_cursorstate(struct fb_cursorstate *state, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3952 {
3953    current_par.crsr_x = state->xoffset;
3954    current_par.crsr_y = state->yoffset;
3955    cursormode = state->mode;
3956    do_movecursor = 1;
3957    return(0);
3958 }
3959 #endif
3960 
3961 
3962    /*
3963     *    Build the Frame Header Copper List
3964     */
3965 
3966 static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop)
     /* [previous][next][first][last][top][bottom][index][help] */
3967 {
3968    int i, j;
3969    u_long p;
3970 
3971    cop->bplcon0.l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
3972    cop->diwstrt.l = CMOVE(0x0181, diwstrt);
3973    cop->diwstop.l = CMOVE(0x0281, diwstop);
3974    cop->diwhigh.l = CMOVE(0x0000, diwhigh);
3975    for (i = 0; i < 8; i++)
3976       cop->sprfix[i].l = CMOVE(0, spr[i].pos);
3977    for (i = 0, j = 0; i < 8; i++) {
3978       p = ZTWO_PADDR(dummysprite);
3979       cop->sprstrtup[j++].l = CMOVE(highw(p), sprpt[i]);
3980       cop->sprstrtup[j++].l = CMOVE2(loww(p), sprpt[i]);
3981    }
3982    cop->wait.l = CWAIT(0, 12);         /* Initial value */
3983    cop->jump.l = CMOVE(0, copjmp2);
3984    cop->wait_forever.l = CEND;
3985 }
3986 
3987 
3988    /*
3989     *    Update the Frame Header Copper List
3990     */
3991 
3992 static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop,
     /* [previous][next][first][last][top][bottom][index][help] */
3993                                             struct amiga_fb_par *par)
3994 {
3995    cop->bplcon0.l = CMOVE(~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) &
3996                           par->bplcon0, bplcon0);
3997    cop->wait.l = CWAIT(0, par->diwstrt_v-2);
3998 }
3999 
4000 
4001    /*
4002     *    Build the Long Frame/Short Frame Copper List
4003     */
4004 
4005 static void aga_build_clist_dyn(struct clist_dyn *cop,
     /* [previous][next][first][last][top][bottom][index][help] */
4006                                 struct clist_dyn *othercop, u_short shf,
4007                                 struct amiga_fb_par *par)
4008 {
4009    u_long y_wrap, bplpt0, p, line;
4010    int i, j = 0;
4011 
4012    cop->diwstrt.l = CMOVE(par->diwstrt, diwstrt);
4013    cop->diwstop.l = CMOVE(par->diwstop, diwstop);
4014    cop->diwhigh.l = CMOVE(par->diwhigh, diwhigh);
4015    cop->bplcon0.l = CMOVE(par->bplcon0, bplcon0);
4016 
4017    /* Point Sprite 0 at cursor sprite */
4018 
4019    /* TODO: This should depend on the vertical sprite position too */
4020    if (shf) {
4021       p = ZTWO_PADDR(shfsprite);
4022       cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]);
4023       cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]);
4024    } else {
4025       p = ZTWO_PADDR(lofsprite);
4026       cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]);
4027       cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]);
4028    }
4029 
4030    bplpt0 = par->bplpt0;
4031    if (shf)
4032       bplpt0 += par->next_line;
4033    y_wrap = par->vmode & FB_VMODE_YWRAP ? par->yoffset : 0;
4034 
4035    /* Set up initial bitplane ptrs */
4036 
4037    for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) {
4038       cop->rest[j++].l = CMOVE(highw(p), bplpt[i]);
4039       cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]);
4040    }
4041 
4042    if (y_wrap) {
4043       bplpt0 -= y_wrap*par->next_line;
4044       line = par->yres-y_wrap;
4045       switch (par->vmode & FB_VMODE_MASK) {
4046          case FB_VMODE_INTERLACED:
4047             line >>= 1;
4048             break;
4049          case FB_VMODE_DOUBLE:
4050             line <<= 1;
4051             break;
4052       }
4053       line += par->diwstrt_v;
4054 
4055       /* Handle skipping over 256-line chunks */
4056 
4057       while (line > 256) {
4058          /* Hardware limitation - 8 bit counter */
4059          cop->rest[j++].l = CWAIT(par->htotal-4, 255);
4060          /* Wait(0, 0) - make sure we're in the new segment */
4061          cop->rest[j++].l = CWAIT(0, 0);
4062          line -= 256;
4063       }
4064       cop->rest[j++].l = CWAIT(par->htotal-11, line-1);
4065 
4066       for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) {
4067          cop->rest[j++].l = CMOVE(highw(p), bplpt[i]);
4068          cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]);
4069       }
4070    }
4071 
4072    if (othercop) {
4073       p = ZTWO_PADDR(othercop);
4074       cop->rest[j++].l = CMOVE(highw(p), cop2lc);
4075       cop->rest[j++].l = CMOVE2(loww(p), cop2lc);
4076    }
4077 
4078    /* End of Copper list */
4079    cop->rest[j++].l = CEND;
4080 
4081    if (j > arraysize(cop->rest))
4082       printk("aga_build_clist_dyn: copper list overflow (%d entries)\n", j);
4083 }
4084 #endif /* CONFIG_AMIFB_AGA */
4085 
4086 
4087 /* -------------------- Interfaces to hardware functions -------------------- */
4088 
4089 
4090 #ifdef CONFIG_AMIFB_OCS
4091 static struct fb_hwswitch ocs_switch = {
4092    ocs_init, ocs_encode_fix, ocs_decode_var, ocs_encode_var, ocs_getcolreg,
4093    ocs_setcolreg, ocs_pan_display, ocs_do_vmode, ocs_do_blank,
4094    ocs_do_movecursor, ocs_do_flashcursor
4095 };
4096 #endif /* CONFIG_AMIFB_OCS */
4097 
4098 #ifdef CONFIG_AMIFB_ECS
4099 static struct fb_hwswitch ecs_switch = {
4100    ecs_init, ecs_encode_fix, ecs_decode_var, ecs_encode_var, ecs_getcolreg,
4101    ecs_setcolreg, ecs_pan_display, ecs_do_vmode, ecs_do_blank,
4102    ecs_do_movecursor, ecs_do_flashcursor
4103 };
4104 #endif /* CONFIG_AMIFB_ECS */
4105 
4106 #ifdef CONFIG_AMIFB_AGA
4107 static struct fb_hwswitch aga_switch = {
4108    aga_init, aga_encode_fix, aga_decode_var, aga_encode_var, aga_getcolreg,
4109    aga_setcolreg, aga_pan_display, aga_do_vmode, aga_do_blank,
4110    aga_do_movecursor, aga_do_flashcursor
4111 };
4112 #endif /* CONFIG_AMIFB_AGA */
4113 
4114 
4115 /* -------------------- Generic routines ------------------------------------ */
4116 
4117 
4118    /*
4119     *    Allocate, Clear and Align a Block of Chip Memory
4120     */
4121 
4122 static u_long chipalloc(u_long size)
     /* [previous][next][first][last][top][bottom][index][help] */
4123 {
4124    u_long ptr;
4125 
4126    size += PAGE_SIZE-1;
4127    if (!(ptr = (u_long)amiga_chip_alloc(size)))
4128       panic("No Chip RAM for frame buffer");
4129    memset((void *)ptr, 0, size);
4130    ptr = PAGE_ALIGN(ptr);
4131 
4132    return(ptr);
4133 }
4134 
4135 
4136    /*
4137     *    Fill the hardware's `par' structure.
4138     */
4139 
4140 static void amiga_fb_get_par(struct amiga_fb_par *par)
     /* [previous][next][first][last][top][bottom][index][help] */
4141 {
4142    if (current_par_valid)
4143       *par = current_par;
4144    else
4145       fbhw->decode_var(&amiga_fb_predefined[amifb_mode], par);
4146 }
4147 
4148 
4149 static void amiga_fb_set_par(struct amiga_fb_par *par)
     /* [previous][next][first][last][top][bottom][index][help] */
4150 {
4151    do_vmode = 0;
4152    current_par = *par;
4153    full_vmode_change = 1;
4154    do_vmode = 1;
4155    current_par_valid = 1;
4156 }
4157 
4158 
4159 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
     /* [previous][next][first][last][top][bottom][index][help] */
4160 {
4161    int err, activate;
4162    struct amiga_fb_par par;
4163 
4164    if ((err = fbhw->decode_var(var, &par)))
4165       return(err);
4166    activate = var->activate;
4167    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
4168       amiga_fb_set_par(&par);
4169    fbhw->encode_var(var, &par);
4170    var->activate = activate;
4171    return(0);
4172 }
4173 
4174 
4175    /*
4176     *    Default Colormaps
4177     */
4178 
4179 static u_short red2[] =
4180    { 0x0000, 0xc000 };
4181 static u_short green2[] =
4182    { 0x0000, 0xc000 };
4183 static u_short blue2[] =
4184    { 0x0000, 0xc000 };
4185 
4186 static u_short red4[] =
4187    { 0x0000, 0xc000, 0x8000, 0xffff };
4188 static u_short green4[] =
4189    { 0x0000, 0xc000, 0x8000, 0xffff };
4190 static u_short blue4[] =
4191    { 0x0000, 0xc000, 0x8000, 0xffff };
4192 
4193 static u_short red8[] =
4194    { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000 };
4195 static u_short green8[] =
4196    { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000 };
4197 static u_short blue8[] =
4198    { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000 };
4199 
4200 static u_short red16[] =
4201    { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
4202      0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
4203 static u_short green16[] =
4204    { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
4205      0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
4206 static u_short blue16[] =
4207    { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
4208      0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
4209 
4210 
4211 static struct fb_cmap default_2_colors =
4212    { 0, 2, red2, green2, blue2, NULL };
4213 static struct fb_cmap default_8_colors =
4214    { 0, 8, red8, green8, blue8, NULL };
4215 static struct fb_cmap default_4_colors =
4216    { 0, 4, red4, green4, blue4, NULL };
4217 static struct fb_cmap default_16_colors =
4218    { 0, 16, red16, green16, blue16, NULL };
4219 
4220 
4221 static struct fb_cmap *get_default_colormap(int bpp)
     /* [previous][next][first][last][top][bottom][index][help] */
4222 {
4223    switch (bpp) {
4224       case 1:
4225          return(&default_2_colors);
4226          break;
4227       case 2:
4228          return(&default_4_colors);
4229          break;
4230       case 3:
4231          return(&default_8_colors);
4232          break;
4233       default:
4234          return(&default_16_colors);
4235          break;
4236    }
4237 }
4238 
4239 
4240 #define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
4241 #define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
4242                                               ((1<<(width))-1)) : 0))
4243 
4244 static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
4245                           int kspc)
4246 {
4247    int i, start;
4248    u_short *red, *green, *blue, *transp;
4249    u_int hred, hgreen, hblue, htransp;
4250 
4251    red = cmap->red;
4252    green = cmap->green;
4253    blue = cmap->blue;
4254    transp = cmap->transp;
4255    start = cmap->start;
4256    if (start < 0)
4257       return(-EINVAL);
4258    for (i = 0; i < cmap->len; i++) {
4259       if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
4260          return(0);
4261       hred = CNVT_FROMHW(hred, var->red.length);
4262       hgreen = CNVT_FROMHW(hgreen, var->green.length);
4263       hblue = CNVT_FROMHW(hblue, var->blue.length);
4264       htransp = CNVT_FROMHW(htransp, var->transp.length);
4265       if (kspc) {
4266          *red = hred;
4267          *green = hgreen;
4268          *blue = hblue;
4269          if (transp)
4270             *transp = htransp;
4271       } else {
4272          put_fs_word(hred, red);
4273          put_fs_word(hgreen, green);
4274          put_fs_word(hblue, blue);
4275          if (transp)
4276             put_fs_word(htransp, transp);
4277       }
4278       red++;
4279       green++;
4280       blue++;
4281       if (transp)
4282          transp++;
4283    }
4284    return(0);
4285 }
4286 
4287 
4288 static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
4289                           int kspc)
4290 {
4291    int i, start;
4292    u_short *red, *green, *blue, *transp;
4293    u_int hred, hgreen, hblue, htransp;
4294 
4295    red = cmap->red;
4296    green = cmap->green;
4297    blue = cmap->blue;
4298    transp = cmap->transp;
4299    start = cmap->start;
4300 
4301    if (start < 0)
4302       return(-EINVAL);
4303    for (i = 0; i < cmap->len; i++) {
4304       if (kspc) {
4305          hred = *red;
4306          hgreen = *green;
4307          hblue = *blue;
4308          htransp = transp ? *transp : 0;
4309       } else {
4310          hred = get_fs_word(red);
4311          hgreen = get_fs_word(green);
4312          hblue = get_fs_word(blue);
4313          htransp = transp ? get_fs_word(transp) : 0;
4314       }
4315       hred = CNVT_TOHW(hred, var->red.length);
4316       hgreen = CNVT_TOHW(hgreen, var->green.length);
4317       hblue = CNVT_TOHW(hblue, var->blue.length);
4318       htransp = CNVT_TOHW(htransp, var->transp.length);
4319       red++;
4320       green++;
4321       blue++;
4322       if (transp)
4323          transp++;
4324       if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
4325          return(0);
4326    }
4327    return(0);
4328 }
4329 
4330 
4331 static void do_install_cmap(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4332 {
4333    if (con != currcon)
4334       return;
4335    if (disp[con].cmap.len)
4336       do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
4337    else
4338       do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
4339                                           &disp[con].var, 1);
4340 }
4341 
4342 
4343 static void memcpy_fs(int fsfromto, void *to, void *from, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
4344 {
4345    switch (fsfromto) {
4346       case 0:
4347          memcpy(to, from, len);
4348          return;
4349       case 1:
4350          memcpy_fromfs(to, from, len);
4351          return;
4352       case 2:
4353          memcpy_tofs(to, from, len);
4354          return;
4355    }
4356 }
4357 
4358 
4359 static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
     /* [previous][next][first][last][top][bottom][index][help] */
4360 {
4361    int size;
4362    int tooff = 0, fromoff = 0;
4363 
4364    if (to->start > from->start)
4365       fromoff = to->start-from->start;
4366    else
4367       tooff = from->start-to->start;
4368    size = to->len-tooff;
4369    if (size > from->len-fromoff)
4370       size = from->len-fromoff;
4371    if (size < 0)
4372       return;
4373    size *= sizeof(u_short);
4374    memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
4375    memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
4376    memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
4377    if (from->transp && to->transp)
4378       memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
4379 }
4380 
4381 
4382 static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
     /* [previous][next][first][last][top][bottom][index][help] */
4383 {
4384    int size = len*sizeof(u_short);
4385 
4386    if (cmap->len != len) {
4387       if (cmap->red)
4388          kfree(cmap->red);
4389       if (cmap->green)
4390          kfree(cmap->green);
4391       if (cmap->blue)
4392          kfree(cmap->blue);
4393       if (cmap->transp)
4394          kfree(cmap->transp);
4395       cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
4396       cmap->len = 0;
4397       if (!len)
4398          return(0);
4399       if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
4400          return(-1);
4401       if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
4402          return(-1);
4403       if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
4404          return(-1);
4405       if (transp) {
4406          if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
4407             return(-1);
4408       } else
4409          cmap->transp = NULL;
4410    }
4411    cmap->start = 0;
4412    cmap->len = len;
4413    copy_cmap(get_default_colormap(len), cmap, 0);
4414    return(0);
4415 }
4416 
4417 
4418    /*
4419     *    Get the Fixed Part of the Display
4420     */
4421 
4422 static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4423 {
4424    struct amiga_fb_par par;
4425    int error = 0;
4426 
4427    if (con == -1)
4428       amiga_fb_get_par(&par);
4429    else
4430       error = fbhw->decode_var(&disp[con].var, &par);
4431    return(error ? error : fbhw->encode_fix(fix, &par));
4432 }
4433 
4434 
4435    /*
4436     *    Get the User Defined Part of the Display
4437     */
4438 
4439 static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4440 {
4441    struct amiga_fb_par par;
4442    int error = 0;
4443 
4444    if (con == -1) {
4445       amiga_fb_get_par(&par);
4446       error = fbhw->encode_var(var, &par);
4447    } else
4448       *var = disp[con].var;
4449    return(error);
4450 }
4451 
4452 
4453 static void amiga_fb_set_disp(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4454 {
4455    struct fb_fix_screeninfo fix;
4456 
4457    amiga_fb_get_fix(&fix, con);
4458    if (con == -1)
4459       con = 0;
4460    disp[con].screen_base = (u_char *)fix.smem_start;
4461    disp[con].visual = fix.visual;
4462    disp[con].type = fix.type;
4463    disp[con].type_aux = fix.type_aux;
4464    disp[con].ypanstep = fix.ypanstep;
4465    disp[con].ywrapstep = fix.ywrapstep;
4466    disp[con].line_length = fix.line_length;
4467    disp[con].can_soft_blank = 1;
4468    disp[con].inverse = amifb_inverse;
4469 }
4470 
4471 
4472    /*
4473     *    Set the User Defined Part of the Display
4474     */
4475 
4476 static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4477 {
4478    int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
4479 
4480    if ((err = do_fb_set_var(var, con == currcon)))
4481       return(err);
4482    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
4483       oldxres = disp[con].var.xres;
4484       oldyres = disp[con].var.yres;
4485       oldvxres = disp[con].var.xres_virtual;
4486       oldvyres = disp[con].var.yres_virtual;
4487       oldbpp = disp[con].var.bits_per_pixel;
4488       disp[con].var = *var;
4489       if (oldxres != var->xres || oldyres != var->yres ||
4490           oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
4491           oldbpp != var->bits_per_pixel) {
4492          amiga_fb_set_disp(con);
4493          (*fb_info.changevar)(con);
4494          alloc_cmap(&disp[con].cmap, 0, 0);
4495          do_install_cmap(con);
4496       }
4497    }
4498    var->activate = 0;
4499    return(0);
4500 }
4501 
4502 
4503    /*
4504     *    Get the Colormap
4505     */
4506 
4507 static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4508 {
4509    if (con == currcon) /* current console? */
4510       return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
4511    else if (disp[con].cmap.len) /* non default colormap? */
4512       copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
4513    else
4514       copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), cmap,
4515                 kspc ? 0 : 2);
4516    return(0);
4517 }
4518 
4519 
4520    /*
4521     *    Set the Colormap
4522     */
4523 
4524 static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4525 {
4526    int err;
4527 
4528    if (!disp[con].cmap.len) {       /* no colormap allocated? */
4529       if ((err = alloc_cmap(&disp[con].cmap, 1<<disp[con].var.bits_per_pixel,
4530                             0)))
4531          return(err);
4532    }
4533    if (con == currcon)              /* current console? */
4534       return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
4535    else
4536       copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
4537    return(0);
4538 }
4539 
4540 
4541    /*
4542     *    Pan or Wrap the Display
4543     *
4544     *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
4545     */
4546 
4547 static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4548 {
4549    int err;
4550    u_short oldlatch;
4551 
4552    if (var->vmode & FB_VMODE_YWRAP) {
4553       if (var->xoffset || var->yoffset >= disp[con].var.yres)
4554          return(-EINVAL);
4555    } else {
4556       if (var->xoffset+disp[con].var.xres > disp[con].var.xres_virtual ||
4557           var->yoffset+disp[con].var.yres > disp[con].var.yres_virtual)
4558     return(-EINVAL);
4559    }
4560    if (con == currcon) {
4561       cli();
4562       oldlatch = do_vmode;
4563       do_vmode = 0;
4564       sti();
4565       if ((err = fbhw->pan_display(var, &current_par))) {
4566          if (oldlatch)
4567             do_vmode = 1;
4568          return(err);
4569       }
4570       do_vmode = 1;
4571    }
4572    disp[con].var.xoffset = var->xoffset;
4573    disp[con].var.yoffset = var->yoffset;
4574    if (var->vmode & FB_VMODE_YWRAP)
4575       disp[con].var.vmode |= FB_VMODE_YWRAP;
4576    else
4577       disp[con].var.vmode &= ~FB_VMODE_YWRAP;
4578    return(0);
4579 }
4580 
4581 
4582    /*
4583     *    Amiga Frame Buffer Specific ioctls
4584     */
4585 
4586 static int amiga_fb_ioctl(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
4587                           u_int cmd, u_long arg, int con)
4588 {
4589    int i;
4590    struct fb_fix_cursorinfo crsrfix;
4591    struct fb_var_cursorinfo crsrvar;
4592    struct fb_cursorstate crsrstate;
4593 
4594    switch (cmd) {
4595 #ifdef CONFIG_AMIFB_AGA
4596       case FBIOGET_FCURSORINFO:
4597          i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
4598          if (i)
4599             return(i);
4600          i = amiga_fb_get_fix_cursorinfo(&crsrfix, con);
4601          memcpy_tofs((void *)arg, &crsrfix, sizeof(crsrfix));
4602          return(i);
4603       case FBIOGET_VCURSORINFO:
4604          i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
4605          if (i)
4606             return(i);
4607          i = amiga_fb_get_var_cursorinfo(&crsrvar, con);
4608          memcpy_tofs((void *)arg, &crsrvar, sizeof(crsrvar));
4609          return(i);
4610       case FBIOPUT_VCURSORINFO:
4611          i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
4612          if (i)
4613             return(i);
4614          memcpy_fromfs(&crsrvar, (void *)arg, sizeof(crsrvar));
4615          i = amiga_fb_set_var_cursorinfo(&crsrvar, con);
4616          return(i);
4617       case FBIOGET_CURSORSTATE:
4618          i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
4619          if (i)
4620             return(i);
4621          i = amiga_fb_get_cursorstate(&crsrstate, con);
4622          memcpy_tofs((void *)arg, &crsrstate, sizeof(crsrstate));
4623          return(i);
4624       case FBIOPUT_CURSORSTATE:
4625          i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
4626          if (i)
4627             return(i);
4628          memcpy_fromfs(&crsrstate, (void *)arg, sizeof(crsrstate));
4629          i = amiga_fb_set_cursorstate(&crsrstate, con);
4630          return(i);
4631 #endif /* CONFIG_AMIFB_AGA */
4632 #if 1
4633       case FBCMD_GET_CURRENTPAR:
4634          if ((i = verify_area(VERIFY_WRITE, (void *)arg,
4635                               sizeof(struct amiga_fb_par))))
4636             return(i);
4637          memcpy_tofs((void *)arg, (void *)&current_par,
4638                      sizeof(struct amiga_fb_par));
4639          return(0);
4640          break;
4641       case FBCMD_SET_CURRENTPAR:
4642          if ((i = verify_area(VERIFY_READ, (void *)arg,
4643                               sizeof(struct amiga_fb_par))))
4644             return(i);
4645          memcpy_fromfs((void *)&current_par, (void *)arg,
4646                        sizeof(struct amiga_fb_par));
4647          return(0);
4648          break;
4649 #endif
4650    }
4651    return(-EINVAL);
4652 }
4653 
4654 
4655 #ifdef CONFIG_AMIFB_AGA
4656    /*
4657     *    Hardware Cursor
4658     */
4659 
4660 static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4661 {
4662    if (boot_info.bi_amiga.chipset == CS_AGA)
4663       return(aga_get_fix_cursorinfo(fix, con));
4664    return(-EINVAL);
4665 }
4666 
4667 
4668 static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4669 {
4670    if (boot_info.bi_amiga.chipset == CS_AGA)
4671       return(aga_get_var_cursorinfo(var, con));
4672    return(-EINVAL);
4673 }
4674 
4675 
4676 static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4677 {
4678    if (boot_info.bi_amiga.chipset == CS_AGA)
4679       return(aga_set_var_cursorinfo(var, con));
4680    return(-EINVAL);
4681 }
4682 
4683 
4684 static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4685 {
4686    if (boot_info.bi_amiga.chipset == CS_AGA)
4687       return(aga_get_cursorstate(state, con));
4688    return(-EINVAL);
4689 }
4690 
4691 
4692 static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4693 {
4694    if (boot_info.bi_amiga.chipset == CS_AGA)
4695       return(aga_set_cursorstate(state, con));
4696    return(-EINVAL);
4697 }
4698 #endif /* CONFIG_AMIFB_AGA */
4699 
4700 
4701 static struct fb_ops amiga_fb_ops = {
4702    amiga_fb_get_fix, amiga_fb_get_var, amiga_fb_set_var, amiga_fb_get_cmap,
4703    amiga_fb_set_cmap, amiga_fb_pan_display, amiga_fb_ioctl
4704 };
4705 
4706 
4707 void amiga_video_setup(char *options, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
4708 {
4709    char *this_opt;
4710    int i;
4711    char mcap_spec[80];
4712 
4713    /*
4714     *    Check for a Graphics Board
4715     */
4716 
4717 #ifdef CONFIG_FB_CYBER
4718    if (options && *options)
4719       if (!strncmp(options, "cyber", 5) && Cyber_probe()) {
4720          amifb_Cyber = 1;
4721          Cyber_video_setup(options, ints);
4722          return;
4723       }
4724 #endif /* CONFIG_FB_CYBER */
4725 
4726 #ifdef USE_MONO_AMIFB_IF_NON_AGA
4727    if (boot_info.bi_amiga.chipset != CS_AGA) {
4728       mono_video_setup(options, ints);
4729       return;
4730    }
4731 #endif /* USE_MONO_AMIFB_IF_NON_AGA */
4732 
4733    mcap_spec[0] = '\0';
4734    fb_info.fontname[0] = '\0';
4735 
4736    if (!options || !*options)
4737       return;
4738 
4739    for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ","))
4740       if (!strcmp(this_opt, "inverse")) {
4741          amifb_inverse = 1;
4742          for (i = 0; i < 16; i++) {
4743             red16[i] = ~red16[i];
4744             green16[i] = ~green16[i];
4745             blue16[i] = ~blue16[i];
4746          }
4747          for (i = 0; i < 8; i++) {
4748             red8[i] = ~red8[i];
4749             green8[i] = ~green8[i];
4750             blue8[i] = ~blue8[i];
4751          }
4752          for (i = 0; i < 4; i++) {
4753             red4[i] = ~red4[i];
4754             green4[i] = ~green4[i];
4755             blue4[i] = ~blue4[i];
4756          }
4757          for (i = 0; i < 2; i++) {
4758             red2[i] = ~red2[i];
4759             green2[i] = ~green2[i];
4760             blue2[i] = ~blue2[i];
4761          }
4762       } else if (!strcmp(this_opt, "ilbm"))
4763          amifb_ilbm = 1;
4764       else if (!strcmp(this_opt, "pwrsave"))
4765          pwrsave = 1;
4766       else if (!strncmp(this_opt, "monitorcap:", 11))
4767          strcpy(mcap_spec, this_opt+11);
4768       else if (!strncmp(this_opt, "font:", 5))
4769          strcpy(fb_info.fontname, this_opt+5);
4770       else
4771          amifb_mode = get_video_mode(this_opt);
4772 
4773    if (*mcap_spec) {
4774       char *p;
4775       int vmin, vmax, hmin, hmax;
4776 
4777       /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
4778        * <V*> vertical freq. in Hz
4779        * <H*> horizontal freq. in kHz
4780        */
4781 
4782       if (!(p = strtoke(mcap_spec, ";")) || !*p)
4783          goto cap_invalid;
4784       vmin = simple_strtoul(p, NULL, 10);
4785       if (vmin <= 0)
4786          goto cap_invalid;
4787       if (!(p = strtoke(NULL, ";")) || !*p)
4788          goto cap_invalid;
4789       vmax = simple_strtoul(p, NULL, 10);
4790       if (vmax <= 0 || vmax <= vmin)
4791          goto cap_invalid;
4792       if (!(p = strtoke(NULL, ";")) || !*p)
4793          goto cap_invalid;
4794       hmin = 1000 * simple_strtoul(p, NULL, 10);
4795       if (hmin <= 0)
4796          goto cap_invalid;
4797       if (!(p = strtoke(NULL, "")) || !*p)
4798          goto cap_invalid;
4799       hmax = 1000 * simple_strtoul(p, NULL, 10);
4800       if (hmax <= 0 || hmax <= hmin)
4801          goto cap_invalid;
4802 
4803       vfmin = vmin;
4804       vfmax = vmax;
4805       hfmin = hmin;
4806       hfmax = hmax;
4807 cap_invalid:
4808       ;
4809    }
4810 }
4811 
4812 
4813    /*
4814     *    Initialization
4815     */
4816 
4817 struct fb_info *amiga_fb_init(long *mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
4818 {
4819    int err, tag, i;
4820    struct fb_var_screeninfo *var;
4821 
4822    /*
4823     *    Check for a Graphics Board
4824     */
4825 
4826 #ifdef CONFIG_FB_CYBER
4827    if (amifb_Cyber)
4828       return(Cyber_fb_init(mem_start));
4829 #endif /* CONFIG_FB_CYBER */
4830 
4831    /*
4832     *    Use the Builtin Chipset
4833     */
4834 
4835    if (!AMIGAHW_PRESENT(AMI_VIDEO))
4836       return(NULL);
4837 
4838 #ifdef USE_MONO_AMIFB_IF_NON_AGA
4839    if (boot_info.bi_amiga.chipset != CS_AGA)
4840       return(mono_amiga_fb_init(mem_start));
4841 #endif /* USE_MONO_AMIFB_IF_NON_AGA */
4842 
4843    switch (boot_info.bi_amiga.chipset) {
4844 #ifdef CONFIG_AMIFB_OCS
4845       case CS_OCS:
4846          strcat(amiga_fb_name, "OCS");
4847 default_chipset:
4848          fbhw = &ocs_switch;
4849          maxdepth[TAG_SHRES-1] = 0;       /* OCS means no SHRES */
4850          maxdepth[TAG_HIRES-1] = 4;
4851          maxdepth[TAG_LORES-1] = 6;
4852          break;
4853 #endif /* CONFIG_AMIFB_OCS */
4854 
4855 #ifdef CONFIG_AMIFB_ECS
4856       case CS_ECS:
4857          strcat(amiga_fb_name, "ECS");
4858          fbhw = &ecs_switch;
4859          maxdepth[TAG_SHRES-1] = 2;
4860          maxdepth[TAG_HIRES-1] = 4;
4861          maxdepth[TAG_LORES-1] = 6;
4862          break;
4863 #endif /* CONFIG_AMIFB_ECS */
4864 
4865 #ifdef CONFIG_AMIFB_AGA
4866       case CS_AGA:
4867          strcat(amiga_fb_name, "AGA");
4868          fbhw = &aga_switch;
4869          maxdepth[TAG_SHRES-1] = 8;
4870          maxdepth[TAG_HIRES-1] = 8;
4871          maxdepth[TAG_LORES-1] = 8;
4872          break;
4873 #endif /* CONFIG_AMIFB_AGA */
4874 
4875       default:
4876 #ifdef CONFIG_AMIFB_OCS
4877          printk("Unknown graphics chipset, defaulting to OCS\n");
4878          strcat(amiga_fb_name, "Unknown");
4879          goto default_chipset;
4880 #else /* CONFIG_AMIFB_OCS */
4881          panic("Unknown graphics chipset, no default driver");
4882 #endif /* CONFIG_AMIFB_OCS */
4883          break;
4884    }
4885 
4886    /*
4887     *    Calculate the Pixel Clock Values for this Machine
4888     */
4889 
4890    pixclock[TAG_SHRES-1] = 25E9/amiga_eclock;   /* SHRES:  35 ns / 28 MHz */
4891    pixclock[TAG_HIRES-1] = 50E9/amiga_eclock;   /* HIRES:  70 ns / 14 MHz */
4892    pixclock[TAG_LORES-1] = 100E9/amiga_eclock;  /* LORES: 140 ns /  7 MHz */
4893 
4894    /*
4895     *    Replace the Tag Values with the Real Pixel Clock Values
4896     */
4897 
4898    for (i = 0; i < NUM_PREDEF_MODES; i++) {
4899       tag = amiga_fb_predefined[i].pixclock;
4900       if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
4901          amiga_fb_predefined[i].pixclock = pixclock[tag-1];
4902          if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag-1])
4903             amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag-1];
4904       }
4905    }
4906 
4907    err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
4908                               NUM_TOTAL_MODES, amiga_fb_predefined);
4909    if (err < 0)
4910       panic("Cannot register frame buffer");
4911 
4912    fbhw->init();
4913    check_default_mode();
4914 
4915    if (!add_isr(IRQ_AMIGA_VERTB, amifb_interrupt, 0, NULL, "frame buffer"))
4916       panic("Couldn't add vblank interrupt");
4917 
4918    strcpy(fb_info.modename, amiga_fb_name);
4919    fb_info.disp = disp;
4920    fb_info.switch_con = &amifb_switch;
4921    fb_info.updatevar = &amifb_updatevar;
4922    fb_info.blank = &amifb_blank;
4923 
4924    var = &amiga_fb_predefined[amifb_mode];
4925    do_fb_set_var(var, 1);
4926    strcat(fb_info.modename, " ");
4927    strcat(fb_info.modename, amiga_fb_modenames[amifb_mode]);
4928 
4929    amiga_fb_get_var(&disp[0].var, -1);
4930    amiga_fb_set_disp(-1);
4931    do_install_cmap(0);
4932    return(&fb_info);
4933 }
4934 
4935 
4936 static int amifb_switch(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4937 {
4938    /* Do we have to save the colormap? */
4939    if (disp[currcon].cmap.len)
4940       do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
4941 
4942    do_fb_set_var(&disp[con].var, 1);
4943    currcon = con;
4944    /* Install new colormap */
4945    do_install_cmap(con);
4946    return(0);
4947 }
4948 
4949 
4950    /*
4951     *    Update the `var' structure (called by fbcon.c)
4952     *
4953     *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
4954     *    Since it's called by a kernel driver, no range checking is done.
4955     */
4956 
4957 static int amifb_updatevar(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4958 {
4959    do_vmode = 0;
4960    current_par.yoffset = disp[con].var.yoffset;
4961    current_par.vmode = disp[con].var.vmode;
4962    current_par.bplpt0 = ZTWO_PADDR((u_long)videomemory+
4963                                    current_par.yoffset*current_par.next_line);
4964    do_vmode = 1;
4965    return(0);
4966 }
4967 
4968 
4969    /*
4970     *    Blank the display.
4971     */
4972 
4973 static void amifb_blank(int blank)
     /* [previous][next][first][last][top][bottom][index][help] */
4974 {
4975    do_blank = blank ? 1 : -1;
4976 }
4977 
4978 
4979    /*
4980     *    VBlank Display Interrupt
4981     */
4982 
4983 static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
4984 {
4985    static int is_laced = 0;
4986 
4987 #if 0
4988    /*
4989     *    This test should be here, in case current_par isn't initialized yet
4990     *
4991     *    Fortunately only do_flashcursor() will be called in that case, and
4992     *    currently that function doesn't use current_par. But this may change
4993     *    in future...
4994     */
4995    if (!current_par_valid)
4996       return;
4997 #endif
4998 
4999    /*
5000     *    If interlaced, only change the display on a long frame
5001     */
5002 
5003    if (!is_laced || custom.vposr & 0x8000) {
5004       if (do_vmode) {
5005          fbhw->do_vmode();
5006          do_vmode = 0;
5007          is_laced = (current_par.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
5008       }
5009       if (do_movecursor) {
5010          fbhw->do_movecursor();
5011          do_movecursor = 0;
5012       }
5013    }
5014    if (do_blank) {
5015       fbhw->do_blank(do_blank > 0 ? 1 : 0);
5016       do_blank = 0;
5017    }
5018    if (!is_blanked)
5019       fbhw->do_flashcursor();
5020 }
5021 
5022 
5023    /*
5024     *    A strtok which returns empty strings, too
5025     */
5026 
5027 static char * strtoke(char * s,const char * ct)
     /* [previous][next][first][last][top][bottom][index][help] */
5028 {
5029    char *sbegin, *send;
5030    static char *ssave = NULL;
5031   
5032    sbegin  = s ? s : ssave;
5033    if (!sbegin)
5034       return(NULL);
5035    if (*sbegin == '\0') {
5036       ssave = NULL;
5037       return(NULL);
5038    }
5039    send = strpbrk(sbegin, ct);
5040    if (send && *send != '\0')
5041       *send++ = '\0';
5042    ssave = send;
5043    return(sbegin);
5044 }
5045 
5046 
5047    /*
5048     *    Get a Video Modes
5049     */
5050 
5051 static int get_video_mode(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
5052 {
5053    int i;
5054 
5055    for (i = 1; i < NUM_PREDEF_MODES; i++)
5056       if (!strcmp(name, amiga_fb_modenames[i]))
5057          return(i);
5058    return(0);
5059 }
5060 
5061 
5062    /*
5063     *    Check the Default Video Mode
5064     */
5065 
5066 static void check_default_mode(void)
     /* [previous][next][first][last][top][bottom][index][help] */
5067 {
5068    struct fb_var_screeninfo var;
5069 
5070    /* First check the user supplied or system default video mode */
5071    if (amifb_mode) {
5072       var = amiga_fb_predefined[amifb_mode];
5073       var.activate = FB_ACTIVATE_TEST;
5074       if (!do_fb_set_var(&var, 1))
5075          goto found_video_mode;
5076    }
5077 
5078    /* Try some other modes... */
5079    printk("Can't use default video mode. Probing video modes...\n");
5080    for (amifb_mode = 1; amifb_mode < NUM_PREDEF_MODES; amifb_mode++) {
5081       var = amiga_fb_predefined[amifb_mode];
5082       var.activate = FB_ACTIVATE_TEST;
5083       if (!do_fb_set_var(&var, 1))
5084          goto found_video_mode;
5085    }
5086    panic("Can't find any usable video mode");
5087 
5088 found_video_mode:
5089    amiga_fb_predefined[0] = var;
5090 }

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