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 depencies 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 independant 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 provdes 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 aswell, 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 occures 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 perculiar 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         for (i = 0; i < arraysize(fix->reserved); i++)
2494                 fix->reserved[i] = 0;
2495         return(0);
2496 }
2497 
2498 
2499 static int mono_amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2500 {
2501         int i;
2502 
2503         var->xres = mono_current_par.geometry->scr_width;
2504         var->yres = mono_current_par.geometry->scr_height;
2505         var->xres_virtual = var->xres;
2506         var->yres_virtual = var->yres;
2507         var->xoffset = 0;
2508         var->yoffset = 0;
2509 
2510         var->bits_per_pixel = mono_current_par.geometry->scr_depth;
2511         var->grayscale = 0;
2512 
2513         if (boot_info.bi_amiga.chipset == CS_AGA) {
2514                 var->red.offset = 0;
2515                 var->red.length = 8;
2516                 var->red.msb_right = 0;
2517                 var->green = var->red;
2518                 var->blue = var->red;
2519         } else {
2520                 var->red.offset = 0;
2521                 var->red.length = 4;
2522                 var->red.msb_right = 0;
2523                 var->green = var->red;
2524                 var->blue = var->red;
2525         }
2526 
2527         var->nonstd = 0;
2528         var->activate = 0;
2529 
2530         var->width = -1;
2531         var->height = -1;
2532 
2533         var->accel = FB_ACCEL_NONE;
2534 
2535         var->pixclock = 35242;
2536         var->left_margin = (mono_current_par.geometry->hbstop-mono_current_par.geometry->hsstrt)*8;
2537         var->right_margin = (mono_current_par.geometry->hsstrt-mono_current_par.geometry->hbstrt)*8;
2538         var->upper_margin = (mono_current_par.geometry->vbstop-mono_current_par.geometry->vsstrt)*8;
2539         var->lower_margin = (mono_current_par.geometry->vsstrt-mono_current_par.geometry->vbstrt)*8;
2540         var->hsync_len = (mono_current_par.geometry->hsstop-mono_current_par.geometry->hsstrt)*8;
2541         var->vsync_len = (mono_current_par.geometry->vsstop-mono_current_par.geometry->vsstrt)*8;
2542         var->sync = 0;
2543         if (mono_current_par.geometry->bplcon0 & BPC0_LACE)
2544                 var->vmode = FB_VMODE_INTERLACED;
2545         else if ((boot_info.bi_amiga.chipset == CS_AGA) && (mono_current_par.geometry->fmode & FMODE_BSCAN2))
2546                 var->vmode = FB_VMODE_DOUBLE;
2547         else
2548                 var->vmode = FB_VMODE_NONINTERLACED;
2549 
2550         for (i = 0; i < arraysize(var->reserved); i++)
2551                 var->reserved[i] = 0;
2552 
2553         return(0);
2554 }
2555 
2556 
2557 static void mono_amiga_fb_set_disp(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2558 {
2559         struct fb_fix_screeninfo fix;
2560 
2561         mono_amiga_fb_get_fix(&fix, con);
2562         if (con == -1)
2563                 con = 0;
2564         disp[con].screen_base = (u_char *)fix.smem_start;
2565         disp[con].visual = fix.visual;
2566         disp[con].type = fix.type;
2567         disp[con].type_aux = fix.type_aux;
2568         disp[con].ypanstep = fix.ypanstep;
2569         disp[con].ywrapstep = fix.ywrapstep;
2570         disp[con].can_soft_blank = 1;
2571         disp[con].inverse = mono_amifb_inverse;
2572 }
2573 
2574 
2575 static int mono_amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2576 {
2577         /*
2578          *              Not yet implemented
2579          */
2580         return 0;                               /* The X server needs this */
2581         return(-EINVAL);
2582 }
2583 
2584 
2585 static short mono_red_normal[] = {
2586         ((BG_COLOR & 0xff0000)>>8) | ((BG_COLOR & 0xff0000)>>16),
2587         ((FG_COLOR & 0xff0000)>>8) | ((FG_COLOR & 0xff0000)>>16)
2588 };
2589 static short mono_green_normal[] = {
2590         ((BG_COLOR & 0x00ff00)) | ((BG_COLOR & 0x00ff00)>>8),
2591         ((FG_COLOR & 0x00ff00)) | ((FG_COLOR & 0x00ff00)>>8)
2592 };
2593 static short mono_blue_normal[] = {
2594         ((BG_COLOR & 0x0000ff)<<8) | ((BG_COLOR & 0x0000ff)),
2595         ((FG_COLOR & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff))
2596 };
2597 
2598 static short mono_red_inverse[] = {
2599         ((BG_COLOR_INV & 0xff0000)>>8) | ((BG_COLOR_INV & 0xff0000)>>16),
2600         ((FG_COLOR_INV & 0xff0000)>>8) | ((FG_COLOR_INV & 0xff0000)>>16)
2601 };
2602 static short mono_green_inverse[] = {
2603         ((BG_COLOR_INV & 0x00ff00)) | ((BG_COLOR_INV & 0x00ff00)>>8),
2604         ((FG_COLOR_INV & 0x00ff00)) | ((FG_COLOR_INV & 0x00ff00)>>8)
2605 };
2606 static short mono_blue_inverse[] = {
2607         ((BG_COLOR_INV & 0x0000ff)<<8) | ((BG_COLOR_INV & 0x0000ff)),
2608         ((FG_COLOR_INV & 0x0000ff)<<8) | ((FG_COLOR & 0x0000ff))
2609 };
2610 
2611 static struct fb_cmap mono_default_cmap_normal = { 0, 2, mono_red_normal, mono_green_normal, mono_blue_normal, NULL };
2612 static struct fb_cmap mono_default_cmap_inverse = { 0, 2, mono_red_inverse, mono_green_inverse, mono_blue_inverse, NULL };
2613 
2614 static int mono_amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2615 {
2616         int i, start;
2617         unsigned short *red, *green, *blue, *transp;
2618         unsigned int hred, hgreen, hblue, htransp;
2619         struct fb_cmap *def_cmap;
2620 
2621         red = cmap->red;
2622         green = cmap->green;
2623         blue = cmap->blue;
2624         transp = cmap->transp;
2625         start = cmap->start;
2626         if (start < 0)
2627                 return(-EINVAL);
2628 
2629         if (mono_amifb_inverse)
2630                 def_cmap = &mono_default_cmap_inverse;
2631         else
2632                 def_cmap = &mono_default_cmap_normal;
2633 
2634         for (i = 0; i < cmap->len; i++) {
2635                 if (i < def_cmap->len) {
2636                         hred = def_cmap->red[i];
2637                         hgreen = def_cmap->green[i];
2638                         hblue = def_cmap->blue[i];
2639                         if (def_cmap->transp)
2640                                 htransp = def_cmap->transp[i];
2641                         else
2642                                 htransp = 0;
2643                 } else
2644                         hred = hgreen = hblue = htransp = 0;
2645                 if (kspc) {
2646                         *red = hred;
2647                         *green = hgreen;
2648                         *blue = hblue;
2649                         if (transp)
2650                                 *transp = htransp;
2651                 } else {
2652                         put_fs_word(hred, red);
2653                         put_fs_word(hgreen, green);
2654                         put_fs_word(hblue, blue);
2655                         if (transp)
2656                                 put_fs_word(htransp, transp);
2657                 }
2658                 red++;
2659                 green++;
2660                 blue++;
2661                 if (transp)
2662                         transp++;
2663         }
2664         return(0);
2665 }
2666 
2667 
2668 static int mono_amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2669 {
2670         /*
2671          *              Not yet implemented
2672          */
2673         return(-EINVAL);
2674 }
2675 
2676 
2677 static int mono_amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2678 {
2679         /*
2680          *              Not yet implemented
2681          */
2682         return(-EINVAL);
2683 }
2684 
2685 
2686 static int mono_amiga_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
2687                                                                   unsigned long arg, int con)
2688 {
2689         return(-EINVAL);
2690 }
2691 
2692 static struct fb_ops mono_amiga_fb_ops = {
2693         mono_amiga_fb_get_fix, mono_amiga_fb_get_var, mono_amiga_fb_set_var, mono_amiga_fb_get_cmap,
2694         mono_amiga_fb_set_cmap, mono_amiga_fb_pan_display, mono_amiga_fb_ioctl  
2695 };
2696 
2697 
2698 static int mono_amifb_switch (int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2699 {
2700         mono_current_par.y_wrap = disp[con].var.yoffset;
2701         mono_current_par.cursor_latch = 1;
2702         mono_current_par.scroll_latch = 1;
2703         return(0);
2704 }
2705 
2706 
2707 static int mono_amifb_updatevar(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
2708 {
2709         mono_current_par.y_wrap = disp[con].var.yoffset;
2710         mono_current_par.cursor_latch = 1;
2711         mono_current_par.scroll_latch = 1;
2712         return(0);
2713 }
2714 
2715 
2716 static void mono_amifb_blank(int blank)
     /* [previous][next][first][last][top][bottom][index][help] */
2717 {
2718         if (blank)
2719                 mono_do_blank = 1;
2720         else
2721                 mono_do_unblank = 1;
2722 }
2723 
2724 
2725 static struct fb_info *mono_amiga_fb_init(long *mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
2726 {
2727         int mode = mono_amifb_mode;
2728         ulong model;
2729         int inverse_video = mono_amifb_inverse;
2730         int err;
2731 
2732         err=register_framebuffer("Amiga Builtin", &node, &mono_amiga_fb_ops,  mono_num_mono_amiga_fb_predefined,
2733                                                                          mono_mono_amiga_fb_predefined);
2734 
2735         model = boot_info.bi_un.bi_ami.model;
2736         if (mode == -1)
2737                 if (boot_info.bi_amiga.chipset == CS_AGA)
2738                         mode = AGA_DEFMODE;
2739                 else if (model == AMI_3000)
2740                         mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_3000_DEFMODE : OCS_NTSC_3000_DEFMODE;
2741                 else
2742                         mode = boot_info.bi_un.bi_ami.vblank == 50 ? OCS_PAL_LOWEND_DEFMODE : OCS_NTSC_LOWEND_DEFMODE;
2743 
2744         mono_init_vblank();
2745         mono_display_init(disp, &mono_modes[mode], inverse_video);
2746         if (!add_isr(IRQ_AMIGA_VERTB, mono_amifb_interrupt, 0, NULL, "frame buffer"))
2747                 panic("Couldn't add vblank interrupt");
2748 
2749         mono_amiga_fb_get_var(&disp[0].var, 0);
2750         if (mono_amifb_inverse)
2751                 disp[0].cmap = mono_default_cmap_inverse;
2752         else
2753                 disp[0].cmap = mono_default_cmap_normal;
2754         mono_amiga_fb_set_disp(-1);
2755 
2756         strcpy(fb_info.modename, "Amiga Builtin ");
2757         fb_info.disp = disp;
2758         fb_info.switch_con = &mono_amifb_switch;
2759         fb_info.updatevar = &mono_amifb_updatevar;
2760         fb_info.blank = &mono_amifb_blank;      
2761         strcat(fb_info.modename, mono_modes[mode].modename);
2762 
2763         return(&fb_info);
2764 }
2765 #endif /* USE_MONO_AMIFB_IF_NON_AGA */
2766 
2767 
2768 /* -------------------- OCS specific routines ------------------------------- */
2769 
2770 
2771 #ifdef CONFIG_AMIFB_OCS
2772    /*
2773     *    Initialization
2774     *
2775     *    Allocate the required chip memory.
2776     *    Set the default video mode for this chipset. If a video mode was
2777     *    specified on the command line, it will override the default mode.
2778     */
2779 
2780 static int ocs_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2781 {
2782    u_long p;
2783 
2784    /*
2785     *    Disable Display DMA
2786     */
2787 
2788    custom.dmacon = DMAF_ALL | DMAF_MASTER;
2789 
2790    /*
2791     *    Set the Default Video Mode
2792     */
2793 
2794    if (!amifb_mode)
2795       amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
2796                                   DEFMODE_PAL : DEFMODE_NTSC);
2797 
2798    /*
2799     *    Allocate Chip RAM Structures
2800     */
2801 
2802    videomemorysize = VIDEOMEMSIZE_OCS;
2803 
2804 
2805    ...
2806    ...
2807    ...
2808 
2809 
2810    /*
2811     *    Enable Display DMA
2812     */
2813 
2814    custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
2815                    DMAF_SPRITE;
2816 
2817    return(0);
2818 }
2819 #endif /* CONFIG_AMIFB_OCS */
2820 
2821 
2822 /* -------------------- ECS specific routines ------------------------------- */
2823 
2824 
2825 #ifdef CONFIG_AMIFB_ECS
2826    /*
2827     *    Initialization
2828     *
2829     *    Allocate the required chip memory.
2830     *    Set the default video mode for this chipset. If a video mode was
2831     *    specified on the command line, it will override the default mode.
2832     */
2833 
2834 static int ecs_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2835 {
2836    u_long p;
2837 
2838    /*
2839     *    Disable Display DMA
2840     */
2841 
2842    custom.dmacon = DMAF_ALL | DMAF_MASTER;
2843 
2844    /*
2845     *    Set the Default Video Mode
2846     */
2847 
2848    if (!amifb_mode)
2849       if (AMIGAHW_PRESENT(AMBER_FF))
2850          amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
2851                                      DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC);
2852       else
2853          amifb_mode = get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ?
2854                                      DEFMODE_PAL : DEFMODE_NTSC);
2855 
2856    /*
2857     *    Allocate Chip RAM Structures
2858     */
2859 
2860    if (boot_info.bi_amiga.chip_size > 1048576)
2861       videomemorysize = VIDEOMEMSIZE_ECS_2M;
2862    else
2863       videomemorysize = VIDEOMEMSIZE_ECS_1M;
2864 
2865 
2866    ...
2867    ...
2868    ...
2869 
2870 
2871    /*
2872     *    Enable Display DMA
2873     */
2874 
2875    custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
2876                    DMAF_SPRITE;
2877 
2878    return(0);
2879 }
2880 #endif /* CONFIG_AMIFB_ECS */
2881 
2882 
2883 /* -------------------- AGA specific routines ------------------------------- */
2884 
2885 
2886 #ifdef CONFIG_AMIFB_AGA
2887    /*
2888     *    Macros for the conversion from real world values to hardware register
2889     *    values (and vice versa).
2890     *
2891     *    This helps us to keep our attention on the real stuff...
2892     *
2893     *    Hardware limits:
2894     *
2895     *       parameter     min      max     step
2896     *       ---------     ---     ----     ----
2897     *       diwstrt_h       0     2047        1
2898     *       diwstrt_v       0     2047        1
2899     *       diwstop_h       0     2047        1
2900     *       diwstop_v       0     2047        1
2901     *
2902     *       ddfstrt         0     2032       16
2903     *       ddfstop         0     2032       16
2904     *
2905     *       htotal          8     2048        8
2906     *       hsstrt          0     2040        8
2907     *       hsstop          0     2040        8
2908     *       vtotal          1     2048        1
2909     *       vsstrt          0     2047        1
2910     *       vsstop          0     2047        1
2911     *       hcenter         0     2040        8
2912     *
2913     *       hbstrt          0     2047        1
2914     *       hbstop          0     2047        1
2915     *       vbstrt          0     2047        1
2916     *       vbstop          0     2047        1
2917     *
2918     *    Horizontal values are in 35 ns (SHRES) pixels
2919     *    Vertical values are in scanlines
2920     */
2921 
2922 /* bplcon1 (smooth scrolling) */
2923 
2924 #define hscroll2hw(hscroll) \
2925    (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
2926     ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
2927 
2928 #define hw2hscroll(hscroll) \
2929    (((hscroll)>>8 & 0x00c3) | ((hscroll)<<2 & 0x003c))
2930 
2931 /* diwstrt/diwstop/diwhigh (visible display window) */
2932 
2933 #define diwstrt2hw(diwstrt_h, diwstrt_v) \
2934    (((diwstrt_v)<<8 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
2935 #define diwstop2hw(distop_h, diwstop_v) \
2936    (((diwstop_v)<<8 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
2937 #define diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v) \
2938    (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
2939     ((diwstop_v) & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
2940     ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>8 & 0x0007))
2941 
2942 #define hw2diwstrt_h(diwstrt, diwhigh) \
2943    (((diwhigh)<<5 & 0x0400) | ((diwstrt)<<2 & 0x03fc) | ((diwhigh)>>3 & 0x0003))
2944 #define hw2diwstrt_v(diwstrt, diwhigh) \
2945    (((diwhigh)<<8 & 0x0700) | ((diwstrt)>>8 & 0x00ff))
2946 #define hw2diwstop_h(diwstop, diwhigh) \
2947    (((diwhigh)>>3 & 0x0400) | ((diwstop)<<2 & 0x03fc) | \
2948     ((diwhigh)>>11 & 0x0003))
2949 #define hw2diwstop_v(diwstop, diwhigh) \
2950    (((diwhigh) & 0x0700) | ((diwstop)>>8 & 0x00ff))
2951 
2952 /* ddfstrt/ddfstop (display DMA) */
2953 
2954 #define ddfstrt2hw(ddfstrt)   (div8(ddfstrt) & 0x00fe)
2955 #define ddfstop2hw(ddfstop)   (div8(ddfstop) & 0x00fe)
2956 
2957 #define hw2ddfstrt(ddfstrt)   ((ddfstrt)<<3)
2958 #define hw2ddfstop(ddfstop)   ((ddfstop)<<3)
2959 
2960 /* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal (sync timings) */
2961 
2962 #define hsstrt2hw(hsstrt)     (div8(hsstrt))
2963 #define hsstop2hw(hsstop)     (div8(hsstop))
2964 #define htotal2hw(htotal)     (div8(htotal)-1)
2965 #define vsstrt2hw(vsstrt)     (vsstrt)
2966 #define vsstop2hw(vsstop)     (vsstop)
2967 #define vtotal2hw(vtotal)     ((vtotal)-1)
2968 
2969 #define hw2hsstrt(hsstrt)     ((hsstrt)<<3)
2970 #define hw2hsstop(hsstop)     ((hsstop)<<3)
2971 #define hw2htotal(htotal)     (((htotal)+1)<<3)
2972 #define hw2vsstrt(vsstrt)     (vsstrt)
2973 #define hw2vsstop(vsstop)     (vsstop)
2974 #define hw2vtotal(vtotal)     ((vtotal)+1)
2975 
2976 /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
2977 
2978 #define hbstrt2hw(hbstrt)     (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
2979 #define hbstop2hw(hbstop)     (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
2980 #define vbstrt2hw(vbstrt)     (vbstrt)
2981 #define vbstop2hw(vbstop)     (vbstop)
2982 
2983 #define hw2hbstrt(hbstrt)     (((hbstrt)<<3 & 0x07f8) | ((hbstrt)>>8 & 0x0007))
2984 #define hw2hbstop(hbstop)     (((hbstop)<<3 & 0x07f8) | ((hbstop)>>8 & 0x0007))
2985 #define hw2vbstrt(vbstrt)     (vbstrt)
2986 #define hw2vbstop(vbstop)     (vbstop)
2987 
2988 /* color */
2989 
2990 #define rgb2hw_high(red, green, blue) \
2991    (((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f))
2992 #define rgb2hw_low(red, green, blue) \
2993    (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
2994 
2995 #define hw2red(high, low)     (((high)>>4 & 0xf0) | ((low)>>8 & 0x0f))
2996 #define hw2green(high, low)   (((high) & 0xf0) | ((low)>>4 & 0x0f))
2997 #define hw2blue(high, low)    (((high)<<4 & 0xf0) | ((low) & 0x0f))
2998 
2999 /* sprpos/sprctl (sprite positioning) */
3000 
3001 #define spr2hw_pos(start_v, start_h) \
3002    (((start_v)<<8&0xff00) | ((start_h)>>3&0x00ff))
3003 #define spr2hw_ctl(start_v, start_h, stop_v) \
3004    (((stop_v)<<8&0xff00) | ((start_v)>>3&0x0040) | ((stop_v)>>4&0x0020) | \
3005     ((start_h)<<3&0x0018) | ((start_v)>>6&0x0004) | ((stop_v)>>7&0x0002) | \
3006     ((start_h)>>2&0x0001))
3007 
3008 
3009    /*
3010     *    Hardware Cursor
3011     */
3012 
3013 struct aga_cursorsprite {
3014    u_short sprpos;
3015    u_short pad1[3];
3016    u_short sprctl;
3017    u_short pad2[3];
3018    union {
3019       struct {
3020          u_long data[64*4];
3021          u_long trailer[4];
3022       } nonlaced;
3023       struct {
3024          u_long data[32*4];
3025          u_long trailer[4];
3026       } laced;
3027    } u;
3028 };
3029 
3030 struct aga_dummysprite {
3031    u_short sprpos;
3032    u_short pad1[3];
3033    u_short sprctl;
3034    u_short pad2[3];
3035    u_long data[4];
3036    u_long trailer[4];
3037 };
3038 
3039 
3040    /*
3041     *    Pixel modes for Bitplanes and Sprites
3042     */
3043 
3044 static u_short bplpixmode[3] = {
3045    BPC0_SHRES,                   /*  35 ns / 28 MHz */
3046    BPC0_HIRES,                   /*  70 ns / 14 MHz */
3047    0                             /* 140 ns /  7 MHz */
3048 };
3049 
3050 static u_short sprpixmode[3] = {
3051    BPC3_SPRES1 | BPC3_SPRES0,    /*  35 ns / 28 MHz */
3052    BPC3_SPRES1,                  /*  70 ns / 14 MHz */
3053    BPC3_SPRES0                   /* 140 ns /  7 MHz */
3054 };
3055 
3056 
3057    /*
3058     *    Initialization
3059     *
3060     *    Allocate the required chip memory.
3061     *    Set the default video mode for this chipset. If a video mode was
3062     *    specified on the command line, it will override the default mode.
3063     */
3064 
3065 static int aga_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3066 {
3067    u_long p;
3068 
3069    /*
3070     *    Disable Display DMA
3071     */
3072 
3073    custom.dmacon = DMAF_ALL | DMAF_MASTER;
3074 
3075    /*
3076     *    Set the Default Video Mode
3077     */
3078 
3079    if (!amifb_mode)
3080       amifb_mode = get_video_mode(DEFMODE_AGA);
3081 
3082    /*
3083     *    Allocate Chip RAM Structures
3084     */
3085 
3086    if (boot_info.bi_amiga.chip_size > 1048576)
3087       videomemorysize = VIDEOMEMSIZE_AGA_2M;
3088    else
3089       videomemorysize = VIDEOMEMSIZE_AGA_1M;
3090 
3091    p = chipalloc(videomemorysize+                     /* Bitplanes */
3092                  sizeof(struct clist_hdr)+            /* Copper Lists */
3093                  2*sizeof(struct clist_dyn)+
3094                  2*sizeof(struct aga_cursorsprite)+   /* Sprites */
3095                  sizeof(struct aga_dummysprite));
3096 
3097    assignchunk(videomemory, u_long, p, videomemorysize);
3098    assignchunk(clist_hdr, struct clist_hdr *, p, sizeof(struct clist_hdr));
3099    assignchunk(clist_lof, struct clist_dyn *, p, sizeof(struct clist_dyn));
3100    assignchunk(clist_shf, struct clist_dyn *, p, sizeof(struct clist_dyn));
3101    assignchunk(lofsprite, u_long *, p, sizeof(struct aga_cursorsprite));
3102    assignchunk(shfsprite, u_long *, p, sizeof(struct aga_cursorsprite));
3103    assignchunk(dummysprite, u_long *, p, sizeof(struct aga_dummysprite));
3104 
3105    /*
3106     *    Make sure the Copper has something to do
3107     */
3108 
3109    aga_build_clist_hdr(clist_hdr);
3110 
3111    custom.cop1lc = (u_short *)ZTWO_PADDR(clist_hdr);
3112    custom.cop2lc = (u_short *)ZTWO_PADDR(&clist_hdr->wait_forever);
3113    custom.copjmp1 = 0;
3114 
3115    /*
3116     *    Enable Display DMA
3117     */
3118 
3119    custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
3120                    DMAF_SPRITE;
3121 
3122    /*
3123     *    These hardware register values will never be changed later
3124     */
3125 
3126    custom.bplcon2 = BPC2_KILLEHB | BPC2_PF2P2 | BPC2_PF1P2;
3127    custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
3128 
3129    return(0);
3130 }
3131 
3132 
3133    /*
3134     *    This function should fill in the `fix' structure based on the
3135     *    values in the `par' structure.
3136     */
3137 
3138 static int aga_encode_fix(struct fb_fix_screeninfo *fix,
     /* [previous][next][first][last][top][bottom][index][help] */
3139                           struct amiga_fb_par *par)
3140 {
3141    int i;
3142 
3143    strcpy(fix->id, amiga_fb_name);
3144    fix->smem_start = videomemory;
3145    fix->smem_len = videomemorysize;
3146 
3147    if (amifb_ilbm) {
3148       fix->type = FB_TYPE_INTERLEAVED_PLANES;
3149       fix->type_aux = par->next_line;
3150    } else {
3151       fix->type = FB_TYPE_PLANES;
3152       fix->type_aux = 0;
3153    }
3154    fix->visual = FB_VISUAL_PSEUDOCOLOR;
3155 
3156    if (par->diwstrt_h >= 323)
3157       fix->xpanstep = 1;
3158    else
3159       fix->xpanstep = 64;
3160    fix->ypanstep = 1;
3161 
3162    if (hw2ddfstrt(par->ddfstrt) >= (par->bpp-1)*64)
3163       fix->ywrapstep = 1;
3164    else
3165       fix->ywrapstep = 0;
3166 
3167    for (i = 0; i < arraysize(fix->reserved); i++)
3168       fix->reserved[i] = 0;
3169 
3170    return(0);
3171 }
3172 
3173 
3174    /*
3175     *    Get the video params out of `var'. If a value doesn't fit, round
3176     *    it up, if it's too big, return -EINVAL.
3177     */
3178 
3179 static int aga_decode_var(struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
3180                           struct amiga_fb_par *par)
3181 {
3182    u_short clk_shift, line_shift_incd;
3183    u_long upper, lower, hslen, vslen;
3184    int xres_n, yres_n, xoffset_n;                              /* normalized */
3185    u_long left_n, right_n, upper_n, lower_n, hslen_n, vslen_n; /* normalized */
3186    u_long diwstrt_h, diwstrt_v, diwstop_h, diwstop_v;
3187    u_long hsstrt, vsstrt, hsstop, vsstop, htotal, vtotal;
3188    u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll;
3189    double hrate, vrate;
3190    u_short loopcnt = 0;
3191 
3192    /*
3193     *    Find a matching Pixel Clock
3194     */
3195 
3196    for (clk_shift = 0; clk_shift < 3; clk_shift++)
3197       if (var->pixclock <= pixclock[clk_shift])
3198          break;
3199    if (clk_shift >= 3)
3200       return(-EINVAL);
3201    par->clk_shift = clk_shift;
3202 
3203    /*
3204     *    Round up the Geometry Values (if necessary)
3205     */
3206 
3207    par->xres = max(var->xres, 64);
3208    par->yres = max(var->yres, 64);
3209    par->vxres = up64(max(var->xres_virtual, par->xres));
3210    par->vyres = max(var->yres_virtual, par->yres);
3211 
3212    par->bpp = var->bits_per_pixel;
3213    if (par->bpp > 8)
3214       return(-EINVAL);
3215 
3216    if (!var->nonstd) {
3217       if (par->bpp < 1)
3218          par->bpp = 1;
3219    } else if (var->nonstd == FB_NONSTD_HAM)
3220       par->bpp = par->bpp <= 6 ? 6 : 8;
3221    else
3222       return(-EINVAL);
3223 
3224    upper = var->upper_margin;
3225    lower = var->lower_margin;
3226    hslen = var->hsync_len;
3227    vslen = var->vsync_len;
3228 
3229    par->vmode = var->vmode;
3230    switch (par->vmode & FB_VMODE_MASK) {
3231       case FB_VMODE_NONINTERLACED:
3232          line_shift_incd = 1;
3233          break;
3234       case FB_VMODE_INTERLACED:
3235          line_shift_incd = 0;
3236          if (par->yres & 1)
3237             par->yres++;               /* even */
3238          if (upper & 1)
3239             upper++;                   /* even */
3240          if (!(lower & 1))
3241             lower++;                   /* odd */
3242          if (vslen & 1)
3243             vslen++;                   /* even */
3244          break;
3245       case FB_VMODE_DOUBLE:
3246          line_shift_incd = 2;
3247          break;
3248       default:
3249          return(-EINVAL);
3250          break;
3251    }
3252 
3253    par->xoffset = var->xoffset;
3254    par->yoffset = var->yoffset;
3255    if (par->vmode & FB_VMODE_YWRAP) {
3256       if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->yres)
3257          return(-EINVAL);
3258    } else {
3259       if (par->xoffset < 0 || par->xoffset+par->xres > par->vxres ||
3260           par->yoffset < 0 || par->yoffset+par->yres > par->vyres)
3261          return(-EINVAL);
3262    }
3263 
3264    if (var->sync & FB_SYNC_BROADCAST) {
3265       if (hslen || vslen)
3266          return(-EINVAL);
3267    } else {
3268       hslen = hslen < 1 ? 1 : hslen;
3269       vslen = vslen < 1 ? 1 : vslen;
3270    }
3271 
3272    /*
3273     *    Check the Memory Requirements
3274     */
3275 
3276    if (par->vxres*par->vyres*par->bpp > videomemorysize<<3)
3277       return(-EINVAL);
3278 
3279    /*
3280     *    Normalize all values:
3281     *
3282     *      - horizontal: in 35 ns (SHRES) pixels
3283     *      - vertical: in non-interlaced scanlines
3284     */
3285 
3286    xres_n = par->xres<<clk_shift;
3287    xoffset_n = par->xoffset<<clk_shift;
3288    yres_n = par->yres<<line_shift_incd>>1;
3289 
3290    left_n = var->left_margin<<clk_shift;
3291    right_n = var->right_margin<<clk_shift;
3292    hslen_n = hslen<<clk_shift;
3293    upper_n = upper<<line_shift_incd>>1;
3294    lower_n = lower<<line_shift_incd>>1;
3295    vslen_n = vslen<<line_shift_incd>>1;
3296 
3297    /*
3298     *    Vertical and Horizontal Timings
3299     */
3300 
3301    par->bplcon3 = sprpixmode[clk_shift];
3302 aga_calculate_timings:
3303    if (var->sync & FB_SYNC_BROADCAST) {
3304       if (upper_n+yres_n+lower_n == PAL_WINDOW_V) {
3305          /* PAL video mode */
3306          diwstrt_v = PAL_DIWSTRT_V+upper_n;
3307          diwstop_v = diwstrt_v+yres_n;
3308          diwstrt_h = PAL_DIWSTRT_H+left_n;
3309          diwstop_h = diwstrt_h+xres_n+1;
3310          par->htotal = htotal2hw(PAL_HTOTAL);
3311          hrate = 15625;
3312          vrate = 50;
3313          par->beamcon0 = BMC0_PAL;
3314       } else if (upper_n+yres_n+lower_n == NTSC_WINDOW_V) {
3315          /* NTSC video mode */
3316          diwstrt_v = NTSC_DIWSTRT_V+upper_n;
3317          diwstop_v = diwstrt_v+yres_n;
3318          diwstrt_h = NTSC_DIWSTRT_H+left_n;
3319          diwstop_h = diwstrt_h+xres_n+1;
3320          par->htotal = htotal2hw(NTSC_HTOTAL);
3321          hrate = 15750;
3322          vrate = 60;
3323          par->beamcon0 = 0;
3324       } else
3325          return(-EINVAL);
3326    } else {
3327       /* Programmable video mode */
3328       vsstrt = lower_n;
3329       vsstop = vsstrt+vslen_n;
3330       diwstrt_v = vsstop+upper_n;
3331       diwstop_v = diwstrt_v+yres_n;
3332       vtotal = diwstop_v;
3333       hslen_n = up8(hslen_n);
3334       htotal = up8(left_n+xres_n+right_n+hslen_n);
3335       if (vtotal > 2048 || htotal > 2048)
3336          return(-EINVAL);
3337       right_n = htotal-left_n-xres_n-hslen_n;
3338       hsstrt = down8(right_n+4);
3339       hsstop = hsstrt+hslen_n;
3340       diwstop_h = htotal+hsstrt-right_n+1;
3341       diwstrt_h = diwstop_h-xres_n-1;
3342       hrate = (double)amiga_masterclock/htotal;
3343       vrate = hrate/vtotal;
3344       par->bplcon3 |= BPC3_BRDRBLNK | BPC3_EXTBLKEN;
3345       par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
3346                       BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
3347                       BMC0_PAL | BMC0_VARCSYEN;
3348       if (var->sync & FB_SYNC_HOR_HIGH_ACT)
3349          par->beamcon0 |= BMC0_HSYTRUE;
3350       if (var->sync & FB_SYNC_VERT_HIGH_ACT)
3351          par->beamcon0 |= BMC0_VSYTRUE;
3352       if (var->sync & FB_SYNC_COMP_HIGH_ACT)
3353          par->beamcon0 |= BMC0_CSYTRUE;
3354       par->htotal = htotal2hw(htotal);
3355       par->hsstrt = hsstrt2hw(hsstrt);
3356       par->hsstop = hsstop2hw(hsstop);
3357       par->vtotal = vtotal2hw(vtotal);
3358       par->vsstrt = vsstrt2hw(vsstrt);
3359       par->vsstop = vsstop2hw(vsstop);
3360       par->hcenter = par->hsstrt+(par->htotal>>1);
3361    }
3362    par->diwstrt_v = diwstrt_v;
3363    par->diwstrt_h = diwstrt_h;
3364    par->crsr_x = 0;
3365    par->crsr_y = 0;
3366 
3367    /*
3368     *    DMA Timings
3369     */
3370 
3371    ddfmin = down64(xoffset_n);
3372    ddfmax = up64(xoffset_n+xres_n);
3373    hscroll = diwstrt_h-68-mod64(xoffset_n);
3374    ddfstrt = down64(hscroll);
3375    if (ddfstrt < 128) {
3376       right_n += (128-hscroll);
3377       /* Prevent an infinite loop */
3378       if (loopcnt++)
3379          return(-EINVAL);
3380       goto aga_calculate_timings;
3381    }
3382    hscroll -= ddfstrt;
3383    ddfstop = ddfstrt+ddfmax-ddfmin-(64<<clk_shift);
3384 
3385    /*
3386     *    Bitplane calculations
3387     */
3388 
3389    if (amifb_ilbm) {
3390       par->next_plane = div8(par->vxres);
3391       par->next_line = par->bpp*par->next_plane;
3392    } else {
3393       par->next_line = div8(par->vxres);
3394       par->next_plane = par->vyres*par->next_line;
3395    }
3396    par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+
3397                             par->yoffset*par->next_line);
3398    par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift);
3399    par->bpl2mod = par->bpl1mod;
3400 
3401    /*
3402     *    Hardware Register Values
3403     */
3404 
3405    par->bplcon0 = BPC0_COLOR | BPC0_ECSENA | bplpixmode[clk_shift];
3406    if (par->bpp == 8)
3407       par->bplcon0 |= BPC0_BPU3;
3408    else
3409       par->bplcon0 |= par->bpp<<12;
3410    if (var->nonstd == FB_NONSTD_HAM)
3411       par->bplcon0 |= BPC0_HAM;
3412    if (var->sync & FB_SYNC_EXT)
3413       par->bplcon0 |= BPC0_ERSY;
3414    par->bplcon1 = hscroll2hw(hscroll);
3415    par->diwstrt = diwstrt2hw(diwstrt_h, diwstrt_v);
3416    par->diwstop = diwstop2hw(diwstop_h, diwstop_v);
3417    par->diwhigh = diw2hw_high(diwstrt_h, diwstrt_v, distop_h, diwstop_v);
3418    par->ddfstrt = ddfstrt2hw(ddfstrt);
3419    par->ddfstop = ddfstop2hw(ddfstop);
3420    par->fmode = FMODE_SPAGEM | FMODE_SPR32 | FMODE_BPAGEM | FMODE_BPL32;
3421 
3422    switch (par->vmode & FB_VMODE_MASK) {
3423       case FB_VMODE_INTERLACED:
3424          par->bpl1mod += par->next_line;
3425          par->bpl2mod += par->next_line;
3426          par->bplcon0 |= BPC0_LACE;
3427          break;
3428       case FB_VMODE_DOUBLE:
3429          par->bpl1mod -= par->next_line;
3430          par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
3431          break;
3432    }
3433 
3434    if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax)
3435       return(-EINVAL);
3436 
3437    return(0);
3438 }
3439 
3440 
3441    /*
3442     *    Fill the `var' structure based on the values in `par' and maybe
3443     *    other values read out of the hardware.
3444     */
3445 
3446 static int aga_encode_var(struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
3447                           struct amiga_fb_par *par)
3448 {
3449    u_short clk_shift, line_shift_incd;
3450    u_long left, right, upper, lower, hslen, vslen;
3451    u_short diwstop_h, diwstop_v;
3452    u_short hsstrt, vsstrt, hsstop, vsstop, htotal;
3453    int i;
3454 
3455    var->xres = par->xres;
3456    var->yres = par->yres;
3457    var->xres_virtual = par->vxres;
3458    var->yres_virtual = par->vyres;
3459    var->xoffset = par->xoffset;
3460    var->yoffset = par->yoffset;
3461 
3462    var->bits_per_pixel = par->bpp;
3463    var->grayscale = 0;
3464 
3465    var->red.offset = 0;
3466    var->red.length = 8;
3467    var->red.msb_right = 0;
3468    var->blue = var->green = var->red;
3469    var->transp.offset = 0;
3470    var->transp.length = 0;
3471    var->transp.msb_right = 0;
3472 
3473    if (par->bplcon0 & BPC0_HAM)
3474       var->nonstd = FB_NONSTD_HAM;
3475    else
3476       var->nonstd = 0;
3477    var->activate = 0;
3478 
3479    var->height = -1;
3480    var->width = -1;
3481    var->accel = FB_ACCEL_NONE;
3482 
3483    clk_shift = par->clk_shift;
3484    var->pixclock = pixclock[clk_shift];
3485 
3486    diwstop_h = hw2diwstop_h(par->diwstop, par->diwhigh);
3487    if (par->beamcon0 & BMC0_VARBEAMEN) {
3488       hsstrt = hw2hsstrt(par->hsstrt);
3489       vsstrt = hw2vsstrt(par->vsstrt);
3490       hsstop = hw2hsstop(par->hsstop);
3491       vsstop = hw2vsstop(par->vsstop);
3492       htotal = hw2htotal(par->htotal);
3493       left = par->diwstrt_h-hsstop;
3494       right = htotal+hsstrt-diwstop_h+1;
3495       hslen = hsstop-hsstrt;
3496       upper = par->diwstrt_v-vsstop;
3497       lower = vsstrt;
3498       vslen = vsstop-vsstrt;
3499       var->sync = 0;
3500    } else {
3501       diwstop_v = hw2diwstop_v(par->diwstop, par->diwhigh);
3502       if (par->beamcon0 & BMC0_PAL) {
3503          left = par->diwstrt_h-PAL_DIWSTRT_H;
3504          right = PAL_DIWSTRT_H+PAL_WINDOW_H-diwstop_h+1;
3505          upper = par->diwstrt_v-PAL_DIWSTRT_V;
3506          lower = PAL_DIWSTRT_V+PAL_WINDOW_V-diwstop_v;
3507       } else {
3508          left = par->diwstrt_h-NTSC_DIWSTRT_H;
3509          right = NTSC_DIWSTRT_H+NTSC_WINDOW_H-diwstop_h;
3510          upper = par->diwstrt_v-NTSC_DIWSTRT_V;
3511          lower = NTSC_DIWSTRT_V+NTSC_WINDOW_V-diwstop_v;
3512       }
3513       hslen = 0;
3514       vslen = 0;
3515       var->sync = FB_SYNC_BROADCAST;
3516    }
3517 
3518    if (par->bplcon0 & BPC0_ERSY)
3519       var->sync |= FB_SYNC_EXT;
3520    if (par->beamcon0 & BMC0_HSYTRUE)
3521       var->sync |= FB_SYNC_HOR_HIGH_ACT;
3522    if (par->beamcon0 & BMC0_VSYTRUE)
3523       var->sync |= FB_SYNC_VERT_HIGH_ACT;
3524    if (par->beamcon0 & BMC0_CSYTRUE)
3525       var->sync |= FB_SYNC_COMP_HIGH_ACT;
3526 
3527    switch (par->vmode & FB_VMODE_MASK) {
3528       case FB_VMODE_NONINTERLACED:
3529          line_shift_incd = 1;
3530          break;
3531       case FB_VMODE_INTERLACED:
3532          line_shift_incd = 0;
3533          break;
3534       case FB_VMODE_DOUBLE:
3535          line_shift_incd = 2;
3536          break;
3537    }
3538 
3539    var->left_margin = left>>clk_shift;
3540    var->right_margin = right>>clk_shift;
3541    var->upper_margin = upper<<1>>line_shift_incd;
3542    var->lower_margin = lower<<1>>line_shift_incd;
3543    var->hsync_len = hslen>>clk_shift;
3544    var->vsync_len = vslen<<1>>line_shift_incd;
3545    var->vmode = par->vmode;
3546    for (i = 0; i < arraysize(var->reserved); i++)
3547       var->reserved[i] = 0;
3548 
3549    return(0);
3550 }
3551 
3552 
3553    /*
3554     *    Read a single color register and split it into
3555     *    colors/transparent. Return != 0 for invalid regno.
3556     */
3557 
3558 static int aga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
     /* [previous][next][first][last][top][bottom][index][help] */
3559                          u_int *transp)
3560 {
3561    if (regno > 255)
3562       return(1);
3563 
3564    *red = palette[regno].red;
3565    *green = palette[regno].green;
3566    *blue = palette[regno].blue;
3567    return(0);
3568 }
3569 
3570 
3571    /*
3572     *    Set a single color register. The values supplied are already
3573     *    rounded down to the hardware's capabilities (according to the
3574     *    entries in the var structure). Return != 0 for invalid regno.
3575     */
3576 
3577 static int aga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
     /* [previous][next][first][last][top][bottom][index][help] */
3578                          u_int transp)
3579 {
3580    u_short bplcon3 = current_par.bplcon3;
3581 
3582    if (regno > 255)
3583       return(1);
3584 
3585    /*
3586     *    Update the corresponding Hardware Color Register, unless it's Color
3587     *    Register 0 and the screen is blanked.
3588     *
3589     *    The cli()/sti() pair is here to protect bplcon3 from being changed by
3590     *    the VBlank interrupt routine.
3591     */
3592 
3593    cli();
3594    if (regno || !is_blanked) {
3595       custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
3596       custom.color[regno&31] = rgb2hw_high(red, green, blue);
3597       custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
3598       custom.color[regno&31] = rgb2hw_low(red, green, blue);
3599       custom.bplcon3 = bplcon3;
3600    }
3601    sti();
3602 
3603    palette[regno].red = red;
3604    palette[regno].green = green;
3605    palette[regno].blue = blue;
3606 
3607    return(0);
3608 }
3609 
3610 
3611    /*
3612     *    Pan or Wrap the Display
3613     *
3614     *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
3615     *    in `var'.
3616     */
3617 
3618 static int aga_pan_display(struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
3619                            struct amiga_fb_par *par)
3620 {
3621    int xoffset, yoffset, vmode, xres_n, xoffset_n;
3622    u_short clk_shift, line_shift_incd;
3623    u_long ddfmin, ddfmax, ddfstrt, ddfstop, hscroll;
3624 
3625    xoffset = var->xoffset;
3626    yoffset = var->yoffset;
3627    if (var->vmode & FB_VMODE_YWRAP) {
3628       if (hw2ddfstrt(par->ddfstrt) < (par->bpp-1)*64 || xoffset ||
3629           yoffset < 0 || yoffset >= par->yres)
3630          return(-EINVAL);
3631       vmode = par->vmode | FB_VMODE_YWRAP;
3632    } else {
3633       if (par->diwstrt_h < 323)
3634          xoffset = up64(xoffset);
3635       if (xoffset < 0 || xoffset+par->xres > par->vxres ||
3636           yoffset < 0 || yoffset+par->yres > par->vyres)
3637          return(-EINVAL);
3638       vmode = par->vmode & ~FB_VMODE_YWRAP;
3639    }
3640 
3641    clk_shift = par->clk_shift;
3642    switch (vmode & FB_VMODE_MASK) {
3643       case FB_VMODE_NONINTERLACED:
3644          line_shift_incd = 1;
3645          break;
3646       case FB_VMODE_INTERLACED:
3647          line_shift_incd = 0;
3648          break;
3649       case FB_VMODE_DOUBLE:
3650          line_shift_incd = 2;
3651          break;
3652    }
3653    xres_n = par->xres<<clk_shift;
3654    xoffset_n = xoffset<<clk_shift;
3655 
3656    /*
3657     *    DMA timings
3658     */
3659 
3660    ddfmin = down64(xoffset_n);
3661    ddfmax = up64(xoffset_n+xres_n);
3662    hscroll = par->diwstrt_h-68-mod64(xoffset_n);
3663    ddfstrt = down64(hscroll);
3664    if (ddfstrt < 128)
3665       return(-EINVAL);
3666    hscroll -= ddfstrt;
3667    ddfstop = ddfstrt+ddfmax-ddfmin-(64<<clk_shift);
3668    par->bplcon1 = hscroll2hw(hscroll);
3669    par->ddfstrt = ddfstrt2hw(ddfstrt);
3670    par->ddfstop = ddfstop2hw(ddfstop);
3671 
3672    /*
3673     *    Bitplane calculations
3674     */
3675 
3676    par->bplpt0 = ZTWO_PADDR((u_long)videomemory+div8(ddfmin>>clk_shift)+
3677                             yoffset*par->next_line);
3678    par->bpl1mod = par->next_line-div8((ddfmax-ddfmin)>>clk_shift);
3679    par->bpl2mod = par->bpl1mod;
3680    switch (vmode & FB_VMODE_MASK) {
3681       case FB_VMODE_INTERLACED:
3682          par->bpl1mod += par->next_line;
3683          par->bpl2mod += par->next_line;
3684          break;
3685       case FB_VMODE_DOUBLE:
3686          par->bpl1mod -= par->next_line;
3687          break;
3688    }
3689 
3690    par->xoffset = var->xoffset = xoffset;
3691    par->yoffset = var->yoffset = yoffset;
3692    par->vmode = var->vmode = vmode;
3693    return(0);
3694 }
3695 
3696 
3697    /*
3698     *    Change the video mode (called by VBlank interrupt)
3699     */
3700 
3701 void aga_do_vmode(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3702 {
3703    struct amiga_fb_par *par = &current_par;
3704 
3705    /*
3706     *    Rebuild the dynamic part of the Copper List and activate the right
3707     *    Copper List as soon as possible
3708     *
3709     *    Make sure we're in a Long Frame if the video mode is interlaced.
3710     *    This is always the case if we already were in an interlaced mode,
3711     *    since then the VBlank only calls us during a Long Frame.
3712     *    But this _is_ necessary if we're switching from a non-interlaced
3713     *    to an interlaced mode.
3714     */
3715 
3716    if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
3717       custom.vposw = 0x8000;
3718       aga_build_clist_dyn(clist_lof, clist_shf, 0, par);
3719       custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof);
3720       aga_build_clist_dyn(clist_shf, clist_lof, 1, par);
3721    } else {
3722       aga_build_clist_dyn(clist_lof, NULL, 0, par);
3723       custom.cop2lc = (u_short *)ZTWO_PADDR(clist_lof);
3724    }
3725 
3726    /*
3727     *    Update the hardware registers
3728     */
3729 
3730    if (full_vmode_change) {
3731       custom.fmode = par->fmode;
3732       custom.beamcon0 = par->beamcon0;
3733       if (par->beamcon0 & BMC0_VARBEAMEN) {
3734          custom.htotal = par->htotal;
3735          custom.vtotal = par->vtotal;
3736          custom.hsstrt = par->hsstrt;
3737          custom.hsstop = par->hsstop;
3738          custom.hbstrt = par->hsstrt;
3739          custom.hbstop = par->hsstop;
3740          custom.vsstrt = par->vsstrt;
3741          custom.vsstop = par->vsstop;
3742          custom.vbstrt = par->vsstrt;
3743          custom.vbstop = par->vsstop;
3744          custom.hcenter = par->hcenter;
3745       }
3746       custom.bplcon3 = par->bplcon3;
3747       full_vmode_change = 0;
3748    }
3749    custom.ddfstrt = par->ddfstrt;
3750    custom.ddfstop = par->ddfstop;
3751    custom.bpl1mod = par->bpl1mod;
3752    custom.bpl2mod = par->bpl2mod;
3753    custom.bplcon1 = par->bplcon1;
3754 
3755    /*
3756     *    Update the Frame Header Copper List
3757     */
3758 
3759    aga_update_clist_hdr(clist_hdr, par);
3760 
3761    /*
3762     *    The minimum period for audio depends on htotal (for OCS/ECS/AGA)
3763     */
3764 
3765    if ((boot_info.bi_amiga.chipset != CS_STONEAGE) && full_vmode_change)
3766       amiga_audio_min_period = (par->htotal>>1)+1;
3767 }
3768 
3769 
3770    /*
3771     *    (Un)Blank the screen (called by VBlank interrupt)
3772     */
3773 
3774 void aga_do_blank(int blank)
     /* [previous][next][first][last][top][bottom][index][help] */
3775 {
3776    struct amiga_fb_par *par = &current_par;
3777    u_short bplcon3 = par->bplcon3;
3778    u_char red, green, blue;
3779 
3780    if (blank) {
3781       custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
3782       red = green = blue = 0;
3783       if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) {
3784          /* VESA suspend mode, switch off HSYNC */
3785          custom.hsstrt = par->htotal+2;
3786          custom.hsstop = par->htotal+2;
3787       }
3788    } else {
3789       custom.dmacon = DMAF_SETCLR | DMAF_RASTER;
3790       red = palette[0].red;
3791       green = palette[0].green;
3792       blue = palette[0].blue;
3793       if (pwrsave && par->beamcon0 & BMC0_VARBEAMEN) {
3794          custom.hsstrt = par->hsstrt;
3795          custom.hsstop = par->hsstop;
3796       }
3797    }
3798    custom.bplcon3 = bplcon3;
3799    custom.color[0] = rgb2hw_high(red, green, blue);
3800    custom.bplcon3 = bplcon3 | BPC3_LOCT;
3801    custom.color[0] = rgb2hw_low(red, green, blue);
3802    custom.bplcon3 = bplcon3;
3803 
3804    is_blanked = blank;
3805 }
3806 
3807 
3808    /*
3809     *    Move the cursor (called by VBlank interrupt)
3810     */
3811 
3812 void aga_do_movecursor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3813 {
3814    struct amiga_fb_par *par = &current_par;
3815    struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
3816    long hs, vs, ve;
3817    u_short s1, s2, is_double = 0;
3818 
3819    if (par->crsr_x <= -64 || par->crsr_x >= par->xres || par->crsr_y <= -64 ||
3820        par->crsr_y >= par->yres)
3821       hs = vs = ve = 0;
3822    else {
3823       hs = par->diwstrt_h-4+(par->crsr_x<<par->clk_shift);
3824       vs = par->crsr_y;
3825       ve = min(vs+64, par->yres);
3826       switch (par->vmode & FB_VMODE_MASK) {
3827          case FB_VMODE_INTERLACED:
3828             vs >>= 1;
3829             ve >>= 1;
3830             break;
3831          case FB_VMODE_DOUBLE:
3832             vs <<= 1;
3833             ve <<= 1;
3834             is_double = 1;
3835             break;
3836       }
3837       vs += par->diwstrt_v;
3838       ve += par->diwstrt_v;
3839    }
3840    s1 = spr2hw_pos(vs, hs);
3841    if (is_double)
3842       s1 |= 0x80;
3843    s2 = spr2hw_ctl(vs, hs, ve);
3844    sprite->sprpos = s1;
3845    sprite->sprctl = s2;
3846 
3847    /*
3848     *    TODO: Special cases:
3849     *    
3850     *      - Interlaced: fill position in in both lofsprite & shfsprite
3851     *                    swap lofsprite & shfsprite on odd lines
3852     *    
3853     *      - Doublescan: OK?
3854     *    
3855     *      - ve <= bottom of display: OK?
3856     */
3857 }
3858 
3859 
3860    /*
3861     *    Flash the cursor (called by VBlank interrupt)
3862     */
3863 
3864 void aga_do_flashcursor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
3865 {
3866 #if 1
3867    static int cursorcount = 0;
3868    static int cursorstate = 0;
3869 
3870    switch (cursormode) {
3871       case FB_CURSOR_OFF:
3872          custom.dmacon = DMAF_SPRITE;
3873          break;
3874       case FB_CURSOR_ON:
3875          custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
3876          break;
3877       case FB_CURSOR_FLASH:
3878          if (cursorcount)
3879             cursorcount--;
3880          else {
3881             cursorcount = CRSR_RATE;
3882             if ((cursorstate = !cursorstate))
3883                custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
3884             else
3885                custom.dmacon = DMAF_SPRITE;
3886          }
3887          break;
3888    }
3889 #endif
3890 }
3891 
3892 
3893 #if 1
3894 static int aga_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3895 {
3896 #if 0
3897    if (ddfstrt >= 192) {
3898 #endif
3899       fix->crsr_width = 64;
3900       fix->crsr_height = 64;
3901       fix->crsr_xsize = 64;
3902       fix->crsr_ysize = 64;
3903       fix->crsr_color1 = 17;
3904       fix->crsr_color2 = 18;
3905 #if 0
3906    } else {
3907       fix->crsr_width = 0;
3908       fix->crsr_height = 0;
3909       fix->crsr_xsize = 0;
3910       fix->crsr_ysize = 0;
3911       fix->crsr_color1 = 0;
3912       fix->crsr_color2 = 0;
3913    }
3914 #endif
3915    return(0);
3916 }
3917 
3918 
3919 static int aga_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3920 {
3921    struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
3922 
3923    /* TODO: interlaced sprites */
3924    memcpy(var->data, sprite->u.nonlaced.data, sizeof(var->data));
3925    return(0);
3926 }
3927 
3928 
3929 static int aga_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3930 {
3931    struct aga_cursorsprite *sprite = (struct aga_cursorsprite *)lofsprite;
3932 
3933    /* TODO: interlaced sprites */
3934    memcpy(sprite->u.nonlaced.data, var->data, sizeof(var->data));
3935    return(0);
3936 }
3937 
3938 
3939 static int aga_get_cursorstate(struct fb_cursorstate *state, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3940 {
3941    state->xoffset = current_par.crsr_x;
3942    state->yoffset = current_par.crsr_y;
3943    state->mode = cursormode;
3944    return(0);
3945 }
3946 
3947 
3948 static int aga_set_cursorstate(struct fb_cursorstate *state, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
3949 {
3950    current_par.crsr_x = state->xoffset;
3951    current_par.crsr_y = state->yoffset;
3952    cursormode = state->mode;
3953    do_movecursor = 1;
3954    return(0);
3955 }
3956 #endif
3957 
3958 
3959    /*
3960     *    Build the Frame Header Copper List
3961     */
3962 
3963 static __inline__ void aga_build_clist_hdr(struct clist_hdr *cop)
     /* [previous][next][first][last][top][bottom][index][help] */
3964 {
3965    int i, j;
3966    u_long p;
3967 
3968    cop->bplcon0.l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
3969    cop->diwstrt.l = CMOVE(0x0181, diwstrt);
3970    cop->diwstop.l = CMOVE(0x0281, diwstop);
3971    cop->diwhigh.l = CMOVE(0x0000, diwhigh);
3972    for (i = 0; i < 8; i++)
3973       cop->sprfix[i].l = CMOVE(0, spr[i].pos);
3974    for (i = 0, j = 0; i < 8; i++) {
3975       p = ZTWO_PADDR(dummysprite);
3976       cop->sprstrtup[j++].l = CMOVE(highw(p), sprpt[i]);
3977       cop->sprstrtup[j++].l = CMOVE2(loww(p), sprpt[i]);
3978    }
3979    cop->wait.l = CWAIT(0, 12);         /* Initial value */
3980    cop->jump.l = CMOVE(0, copjmp2);
3981    cop->wait_forever.l = CEND;
3982 }
3983 
3984 
3985    /*
3986     *    Update the Frame Header Copper List
3987     */
3988 
3989 static __inline__ void aga_update_clist_hdr(struct clist_hdr *cop,
     /* [previous][next][first][last][top][bottom][index][help] */
3990                                             struct amiga_fb_par *par)
3991 {
3992    cop->bplcon0.l = CMOVE(~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) &
3993                           par->bplcon0, bplcon0);
3994    cop->wait.l = CWAIT(0, par->diwstrt_v-2);
3995 }
3996 
3997 
3998    /*
3999     *    Build the Long Frame/Short Frame Copper List
4000     */
4001 
4002 static void aga_build_clist_dyn(struct clist_dyn *cop,
     /* [previous][next][first][last][top][bottom][index][help] */
4003                                 struct clist_dyn *othercop, u_short shf,
4004                                 struct amiga_fb_par *par)
4005 {
4006    u_long y_wrap, bplpt0, p, line;
4007    int i, j = 0;
4008 
4009    cop->diwstrt.l = CMOVE(par->diwstrt, diwstrt);
4010    cop->diwstop.l = CMOVE(par->diwstop, diwstop);
4011    cop->diwhigh.l = CMOVE(par->diwhigh, diwhigh);
4012    cop->bplcon0.l = CMOVE(par->bplcon0, bplcon0);
4013 
4014    /* Point Sprite 0 at cursor sprite */
4015 
4016    /* TODO: This should depend on the vertical sprite position too */
4017    if (shf) {
4018       p = ZTWO_PADDR(shfsprite);
4019       cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]);
4020       cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]);
4021    } else {
4022       p = ZTWO_PADDR(lofsprite);
4023       cop->sprpt[0].l = CMOVE(highw(p), sprpt[0]);
4024       cop->sprpt[1].l = CMOVE2(loww(p), sprpt[0]);
4025    }
4026 
4027    bplpt0 = par->bplpt0;
4028    if (shf)
4029       bplpt0 += par->next_line;
4030    y_wrap = par->vmode & FB_VMODE_YWRAP ? par->yoffset : 0;
4031 
4032    /* Set up initial bitplane ptrs */
4033 
4034    for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) {
4035       cop->rest[j++].l = CMOVE(highw(p), bplpt[i]);
4036       cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]);
4037    }
4038 
4039    if (y_wrap) {
4040       bplpt0 -= y_wrap*par->next_line;
4041       line = par->yres-y_wrap;
4042       switch (par->vmode & FB_VMODE_MASK) {
4043          case FB_VMODE_INTERLACED:
4044             line >>= 1;
4045             break;
4046          case FB_VMODE_DOUBLE:
4047             line <<= 1;
4048             break;
4049       }
4050       line += par->diwstrt_v;
4051 
4052       /* Handle skipping over 256-line chunks */
4053 
4054       while (line > 256) {
4055          /* Hardware limitation - 8 bit counter */
4056          cop->rest[j++].l = CWAIT(par->htotal-4, 255);
4057          /* Wait(0, 0) - make sure we're in the new segment */
4058          cop->rest[j++].l = CWAIT(0, 0);
4059          line -= 256;
4060       }
4061       cop->rest[j++].l = CWAIT(par->htotal-11, line-1);
4062 
4063       for (i = 0, p = bplpt0; i < par->bpp; i++, p += par->next_plane) {
4064          cop->rest[j++].l = CMOVE(highw(p), bplpt[i]);
4065          cop->rest[j++].l = CMOVE2(loww(p), bplpt[i]);
4066       }
4067    }
4068 
4069    if (othercop) {
4070       p = ZTWO_PADDR(othercop);
4071       cop->rest[j++].l = CMOVE(highw(p), cop2lc);
4072       cop->rest[j++].l = CMOVE2(loww(p), cop2lc);
4073    }
4074 
4075    /* End of Copper list */
4076    cop->rest[j++].l = CEND;
4077 
4078    if (j > arraysize(cop->rest))
4079       printk("aga_build_clist_dyn: copper list overflow (%d entries)\n", j);
4080 }
4081 #endif /* CONFIG_AMIFB_AGA */
4082 
4083 
4084 /* -------------------- Interfaces to hardware functions -------------------- */
4085 
4086 
4087 #ifdef CONFIG_AMIFB_OCS
4088 static struct fb_hwswitch ocs_switch = {
4089    ocs_init, ocs_encode_fix, ocs_decode_var, ocs_encode_var, ocs_getcolreg,
4090    ocs_setcolreg, ocs_pan_display, ocs_do_vmode, ocs_do_blank,
4091    ocs_do_movecursor, ocs_do_flashcursor
4092 };
4093 #endif /* CONFIG_AMIFB_OCS */
4094 
4095 #ifdef CONFIG_AMIFB_ECS
4096 static struct fb_hwswitch ecs_switch = {
4097    ecs_init, ecs_encode_fix, ecs_decode_var, ecs_encode_var, ecs_getcolreg,
4098    ecs_setcolreg, ecs_pan_display, ecs_do_vmode, ecs_do_blank,
4099    ecs_do_movecursor, ecs_do_flashcursor
4100 };
4101 #endif /* CONFIG_AMIFB_ECS */
4102 
4103 #ifdef CONFIG_AMIFB_AGA
4104 static struct fb_hwswitch aga_switch = {
4105    aga_init, aga_encode_fix, aga_decode_var, aga_encode_var, aga_getcolreg,
4106    aga_setcolreg, aga_pan_display, aga_do_vmode, aga_do_blank,
4107    aga_do_movecursor, aga_do_flashcursor
4108 };
4109 #endif /* CONFIG_AMIFB_AGA */
4110 
4111 
4112 /* -------------------- Generic routines ------------------------------------ */
4113 
4114 
4115    /*
4116     *    Allocate, Clear and Align a Block of Chip Memory
4117     */
4118 
4119 static u_long chipalloc(u_long size)
     /* [previous][next][first][last][top][bottom][index][help] */
4120 {
4121    u_long ptr;
4122 
4123    size += PAGE_SIZE-1;
4124    if (!(ptr = (u_long)amiga_chip_alloc(size)))
4125       panic("No Chip RAM for frame buffer");
4126    memset((void *)ptr, 0, size);
4127    ptr = PAGE_ALIGN(ptr);
4128 
4129    return(ptr);
4130 }
4131 
4132 
4133    /*
4134     *    Fill the hardware's `par' structure.
4135     */
4136 
4137 static void amiga_fb_get_par(struct amiga_fb_par *par)
     /* [previous][next][first][last][top][bottom][index][help] */
4138 {
4139    if (current_par_valid)
4140       *par = current_par;
4141    else
4142       fbhw->decode_var(&amiga_fb_predefined[amifb_mode], par);
4143 }
4144 
4145 
4146 static void amiga_fb_set_par(struct amiga_fb_par *par)
     /* [previous][next][first][last][top][bottom][index][help] */
4147 {
4148    do_vmode = 0;
4149    current_par = *par;
4150    full_vmode_change = 1;
4151    do_vmode = 1;
4152    current_par_valid = 1;
4153 }
4154 
4155 
4156 static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
     /* [previous][next][first][last][top][bottom][index][help] */
4157 {
4158    int err, activate;
4159    struct amiga_fb_par par;
4160 
4161    if ((err = fbhw->decode_var(var, &par)))
4162       return(err);
4163    activate = var->activate;
4164    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
4165       amiga_fb_set_par(&par);
4166    fbhw->encode_var(var, &par);
4167    var->activate = activate;
4168    return(0);
4169 }
4170 
4171 
4172    /*
4173     *    Default Colormaps
4174     */
4175 
4176 static u_short red2[] =
4177    { 0x0000, 0xc000 };
4178 static u_short green2[] =
4179    { 0x0000, 0xc000 };
4180 static u_short blue2[] =
4181    { 0x0000, 0xc000 };
4182 
4183 static u_short red4[] =
4184    { 0x0000, 0xc000, 0x8000, 0xffff };
4185 static u_short green4[] =
4186    { 0x0000, 0xc000, 0x8000, 0xffff };
4187 static u_short blue4[] =
4188    { 0x0000, 0xc000, 0x8000, 0xffff };
4189 
4190 static u_short red8[] =
4191    { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000 };
4192 static u_short green8[] =
4193    { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000 };
4194 static u_short blue8[] =
4195    { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000 };
4196 
4197 static u_short red16[] =
4198    { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
4199      0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
4200 static u_short green16[] =
4201    { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
4202      0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
4203 static u_short blue16[] =
4204    { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
4205      0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
4206 
4207 
4208 static struct fb_cmap default_2_colors =
4209    { 0, 2, red2, green2, blue2, NULL };
4210 static struct fb_cmap default_8_colors =
4211    { 0, 8, red8, green8, blue8, NULL };
4212 static struct fb_cmap default_4_colors =
4213    { 0, 4, red4, green4, blue4, NULL };
4214 static struct fb_cmap default_16_colors =
4215    { 0, 16, red16, green16, blue16, NULL };
4216 
4217 
4218 static struct fb_cmap *get_default_colormap(int bpp)
     /* [previous][next][first][last][top][bottom][index][help] */
4219 {
4220    switch (bpp) {
4221       case 1:
4222          return(&default_2_colors);
4223          break;
4224       case 2:
4225          return(&default_4_colors);
4226          break;
4227       case 3:
4228          return(&default_8_colors);
4229          break;
4230       default:
4231          return(&default_16_colors);
4232          break;
4233    }
4234 }
4235 
4236 
4237 #define CNVT_TOHW(val,width)     ((((val)<<(width))+0x7fff-(val))>>16)
4238 #define CNVT_FROMHW(val,width)   (((width) ? ((((val)<<16)-(val)) / \
4239                                               ((1<<(width))-1)) : 0))
4240 
4241 static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
4242                           int kspc)
4243 {
4244    int i, start;
4245    u_short *red, *green, *blue, *transp;
4246    u_int hred, hgreen, hblue, htransp;
4247 
4248    red = cmap->red;
4249    green = cmap->green;
4250    blue = cmap->blue;
4251    transp = cmap->transp;
4252    start = cmap->start;
4253    if (start < 0)
4254       return(-EINVAL);
4255    for (i = 0; i < cmap->len; i++) {
4256       if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
4257          return(0);
4258       hred = CNVT_FROMHW(hred, var->red.length);
4259       hgreen = CNVT_FROMHW(hgreen, var->green.length);
4260       hblue = CNVT_FROMHW(hblue, var->blue.length);
4261       htransp = CNVT_FROMHW(htransp, var->transp.length);
4262       if (kspc) {
4263          *red = hred;
4264          *green = hgreen;
4265          *blue = hblue;
4266          if (transp)
4267             *transp = htransp;
4268       } else {
4269          put_fs_word(hred, red);
4270          put_fs_word(hgreen, green);
4271          put_fs_word(hblue, blue);
4272          if (transp)
4273             put_fs_word(htransp, transp);
4274       }
4275       red++;
4276       green++;
4277       blue++;
4278       if (transp)
4279          transp++;
4280    }
4281    return(0);
4282 }
4283 
4284 
4285 static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
     /* [previous][next][first][last][top][bottom][index][help] */
4286                           int kspc)
4287 {
4288    int i, start;
4289    u_short *red, *green, *blue, *transp;
4290    u_int hred, hgreen, hblue, htransp;
4291 
4292    red = cmap->red;
4293    green = cmap->green;
4294    blue = cmap->blue;
4295    transp = cmap->transp;
4296    start = cmap->start;
4297 
4298    if (start < 0)
4299       return(-EINVAL);
4300    for (i = 0; i < cmap->len; i++) {
4301       if (kspc) {
4302          hred = *red;
4303          hgreen = *green;
4304          hblue = *blue;
4305          htransp = transp ? *transp : 0;
4306       } else {
4307          hred = get_fs_word(red);
4308          hgreen = get_fs_word(green);
4309          hblue = get_fs_word(blue);
4310          htransp = transp ? get_fs_word(transp) : 0;
4311       }
4312       hred = CNVT_TOHW(hred, var->red.length);
4313       hgreen = CNVT_TOHW(hgreen, var->green.length);
4314       hblue = CNVT_TOHW(hblue, var->blue.length);
4315       htransp = CNVT_TOHW(htransp, var->transp.length);
4316       red++;
4317       green++;
4318       blue++;
4319       if (transp)
4320          transp++;
4321       if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
4322          return(0);
4323    }
4324    return(0);
4325 }
4326 
4327 
4328 static void do_install_cmap(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4329 {
4330    if (con != currcon)
4331       return;
4332    if (disp[con].cmap.len)
4333       do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
4334    else
4335       do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
4336                                           &disp[con].var, 1);
4337 }
4338 
4339 
4340 static void memcpy_fs(int fsfromto, void *to, void *from, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
4341 {
4342    switch (fsfromto) {
4343       case 0:
4344          memcpy(to, from, len);
4345          return;
4346       case 1:
4347          memcpy_fromfs(to, from, len);
4348          return;
4349       case 2:
4350          memcpy_tofs(to, from, len);
4351          return;
4352    }
4353 }
4354 
4355 
4356 static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
     /* [previous][next][first][last][top][bottom][index][help] */
4357 {
4358    int size;
4359    int tooff = 0, fromoff = 0;
4360 
4361    if (to->start > from->start)
4362       fromoff = to->start-from->start;
4363    else
4364       tooff = from->start-to->start;
4365    size = to->len-tooff;
4366    if (size > from->len-fromoff)
4367       size = from->len-fromoff;
4368    if (size < 0)
4369       return;
4370    size *= sizeof(u_short);
4371    memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
4372    memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
4373    memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
4374    if (from->transp && to->transp)
4375       memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
4376 }
4377 
4378 
4379 static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
     /* [previous][next][first][last][top][bottom][index][help] */
4380 {
4381    int size = len*sizeof(u_short);
4382 
4383    if (cmap->len != len) {
4384       if (cmap->red)
4385          kfree(cmap->red);
4386       if (cmap->green)
4387          kfree(cmap->green);
4388       if (cmap->blue)
4389          kfree(cmap->blue);
4390       if (cmap->transp)
4391          kfree(cmap->transp);
4392       cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
4393       cmap->len = 0;
4394       if (!len)
4395          return(0);
4396       if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
4397          return(-1);
4398       if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
4399          return(-1);
4400       if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
4401          return(-1);
4402       if (transp) {
4403          if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
4404             return(-1);
4405       } else
4406          cmap->transp = NULL;
4407    }
4408    cmap->start = 0;
4409    cmap->len = len;
4410    copy_cmap(get_default_colormap(len), cmap, 0);
4411    return(0);
4412 }
4413 
4414 
4415    /*
4416     *    Get the Fixed Part of the Display
4417     */
4418 
4419 static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4420 {
4421    struct amiga_fb_par par;
4422    int error = 0;
4423 
4424    if (con == -1)
4425       amiga_fb_get_par(&par);
4426    else
4427       error = fbhw->decode_var(&disp[con].var, &par);
4428    return(error ? error : fbhw->encode_fix(fix, &par));
4429 }
4430 
4431 
4432    /*
4433     *    Get the User Defined Part of the Display
4434     */
4435 
4436 static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4437 {
4438    struct amiga_fb_par par;
4439    int error = 0;
4440 
4441    if (con == -1) {
4442       amiga_fb_get_par(&par);
4443       error = fbhw->encode_var(var, &par);
4444    } else
4445       *var = disp[con].var;
4446    return(error);
4447 }
4448 
4449 
4450 static void amiga_fb_set_disp(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4451 {
4452    struct fb_fix_screeninfo fix;
4453 
4454    amiga_fb_get_fix(&fix, con);
4455    if (con == -1)
4456       con = 0;
4457    disp[con].screen_base = (u_char *)fix.smem_start;
4458    disp[con].visual = fix.visual;
4459    disp[con].type = fix.type;
4460    disp[con].type_aux = fix.type_aux;
4461    disp[con].ypanstep = fix.ypanstep;
4462    disp[con].ywrapstep = fix.ywrapstep;
4463    disp[con].can_soft_blank = 1;
4464    disp[con].inverse = amifb_inverse;
4465 }
4466 
4467 
4468    /*
4469     *    Set the User Defined Part of the Display
4470     */
4471 
4472 static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4473 {
4474    int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
4475 
4476    if ((err = do_fb_set_var(var, con == currcon)))
4477       return(err);
4478    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
4479       oldxres = disp[con].var.xres;
4480       oldyres = disp[con].var.yres;
4481       oldvxres = disp[con].var.xres_virtual;
4482       oldvyres = disp[con].var.yres_virtual;
4483       oldbpp = disp[con].var.bits_per_pixel;
4484       disp[con].var = *var;
4485       if (oldxres != var->xres || oldyres != var->yres ||
4486           oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
4487           oldbpp != var->bits_per_pixel) {
4488          amiga_fb_set_disp(con);
4489          (*fb_info.changevar)(con);
4490          alloc_cmap(&disp[con].cmap, 0, 0);
4491          do_install_cmap(con);
4492       }
4493    }
4494    var->activate = 0;
4495    return(0);
4496 }
4497 
4498 
4499    /*
4500     *    Get the Colormap
4501     */
4502 
4503 static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4504 {
4505    if (con == currcon) /* current console? */
4506       return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
4507    else if (disp[con].cmap.len) /* non default colormap? */
4508       copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
4509    else
4510       copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), cmap,
4511                 kspc ? 0 : 2);
4512    return(0);
4513 }
4514 
4515 
4516    /*
4517     *    Set the Colormap
4518     */
4519 
4520 static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4521 {
4522    int err;
4523 
4524    if (!disp[con].cmap.len) {       /* no colormap allocated? */
4525       if ((err = alloc_cmap(&disp[con].cmap, 1<<disp[con].var.bits_per_pixel,
4526                             0)))
4527          return(err);
4528    }
4529    if (con == currcon)              /* current console? */
4530       return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
4531    else
4532       copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
4533    return(0);
4534 }
4535 
4536 
4537    /*
4538     *    Pan or Wrap the Display
4539     *
4540     *    This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
4541     */
4542 
4543 static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4544 {
4545    int err;
4546    u_short oldlatch;
4547 
4548    if (var->vmode & FB_VMODE_YWRAP) {
4549       if (var->xoffset || var->yoffset >= disp[con].var.yres)
4550          return(-EINVAL);
4551    } else {
4552       if (var->xoffset+disp[con].var.xres > disp[con].var.xres_virtual ||
4553           var->yoffset+disp[con].var.yres > disp[con].var.yres_virtual)
4554     return(-EINVAL);
4555    }
4556    if (con == currcon) {
4557       cli();
4558       oldlatch = do_vmode;
4559       do_vmode = 0;
4560       sti();
4561       if ((err = fbhw->pan_display(var, &current_par))) {
4562          if (oldlatch)
4563             do_vmode = 1;
4564          return(err);
4565       }
4566       do_vmode = 1;
4567    }
4568    disp[con].var.xoffset = var->xoffset;
4569    disp[con].var.yoffset = var->yoffset;
4570    if (var->vmode & FB_VMODE_YWRAP)
4571       disp[con].var.vmode |= FB_VMODE_YWRAP;
4572    else
4573       disp[con].var.vmode &= ~FB_VMODE_YWRAP;
4574    return(0);
4575 }
4576 
4577 
4578    /*
4579     *    Amiga Frame Buffer Specific ioctls
4580     */
4581 
4582 static int amiga_fb_ioctl(struct inode *inode, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
4583                           u_int cmd, u_long arg, int con)
4584 {
4585    int i;
4586    struct fb_fix_cursorinfo crsrfix;
4587    struct fb_var_cursorinfo crsrvar;
4588    struct fb_cursorstate crsrstate;
4589 
4590    switch (cmd) {
4591 #ifdef CONFIG_AMIFB_AGA
4592       case FBIOGET_FCURSORINFO:
4593          i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
4594          if (i)
4595             return(i);
4596          i = amiga_fb_get_fix_cursorinfo(&crsrfix, con);
4597          memcpy_tofs((void *)arg, &crsrfix, sizeof(crsrfix));
4598          return(i);
4599       case FBIOGET_VCURSORINFO:
4600          i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
4601          if (i)
4602             return(i);
4603          i = amiga_fb_get_var_cursorinfo(&crsrvar, con);
4604          memcpy_tofs((void *)arg, &crsrvar, sizeof(crsrvar));
4605          return(i);
4606       case FBIOPUT_VCURSORINFO:
4607          i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
4608          if (i)
4609             return(i);
4610          memcpy_fromfs(&crsrvar, (void *)arg, sizeof(crsrvar));
4611          i = amiga_fb_set_var_cursorinfo(&crsrvar, con);
4612          return(i);
4613       case FBIOGET_CURSORSTATE:
4614          i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
4615          if (i)
4616             return(i);
4617          i = amiga_fb_get_cursorstate(&crsrstate, con);
4618          memcpy_tofs((void *)arg, &crsrstate, sizeof(crsrstate));
4619          return(i);
4620       case FBIOPUT_CURSORSTATE:
4621          i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
4622          if (i)
4623             return(i);
4624          memcpy_fromfs(&crsrstate, (void *)arg, sizeof(crsrstate));
4625          i = amiga_fb_set_cursorstate(&crsrstate, con);
4626          return(i);
4627 #endif /* CONFIG_AMIFB_AGA */
4628 #if 1
4629       case FBCMD_GET_CURRENTPAR:
4630          if ((i = verify_area(VERIFY_WRITE, (void *)arg,
4631                               sizeof(struct amiga_fb_par))))
4632             return(i);
4633          memcpy_tofs((void *)arg, (void *)&current_par,
4634                      sizeof(struct amiga_fb_par));
4635          return(0);
4636          break;
4637       case FBCMD_SET_CURRENTPAR:
4638          if ((i = verify_area(VERIFY_READ, (void *)arg,
4639                               sizeof(struct amiga_fb_par))))
4640             return(i);
4641          memcpy_fromfs((void *)&current_par, (void *)arg,
4642                        sizeof(struct amiga_fb_par));
4643          return(0);
4644          break;
4645 #endif
4646    }
4647    return(-EINVAL);
4648 }
4649 
4650 
4651 #ifdef CONFIG_AMIFB_AGA
4652    /*
4653     *    Hardware Cursor
4654     */
4655 
4656 static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4657 {
4658    if (boot_info.bi_amiga.chipset == CS_AGA)
4659       return(aga_get_fix_cursorinfo(fix, con));
4660    return(-EINVAL);
4661 }
4662 
4663 
4664 static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4665 {
4666    if (boot_info.bi_amiga.chipset == CS_AGA)
4667       return(aga_get_var_cursorinfo(var, con));
4668    return(-EINVAL);
4669 }
4670 
4671 
4672 static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4673 {
4674    if (boot_info.bi_amiga.chipset == CS_AGA)
4675       return(aga_set_var_cursorinfo(var, con));
4676    return(-EINVAL);
4677 }
4678 
4679 
4680 static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4681 {
4682    if (boot_info.bi_amiga.chipset == CS_AGA)
4683       return(aga_get_cursorstate(state, con));
4684    return(-EINVAL);
4685 }
4686 
4687 
4688 static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4689 {
4690    if (boot_info.bi_amiga.chipset == CS_AGA)
4691       return(aga_set_cursorstate(state, con));
4692    return(-EINVAL);
4693 }
4694 #endif /* CONFIG_AMIFB_AGA */
4695 
4696 
4697 static struct fb_ops amiga_fb_ops = {
4698    amiga_fb_get_fix, amiga_fb_get_var, amiga_fb_set_var, amiga_fb_get_cmap,
4699    amiga_fb_set_cmap, amiga_fb_pan_display, amiga_fb_ioctl
4700 };
4701 
4702 
4703 void amiga_video_setup(char *options, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
4704 {
4705    char *this_opt;
4706    int i;
4707    char mcap_spec[80];
4708 
4709    /*
4710     *    Check for a Graphics Board
4711     */
4712 
4713 #ifdef CONFIG_FB_CYBER
4714    if (options && *options)
4715       if (!strncmp(options, "cyber", 5) && Cyber_probe()) {
4716          amifb_Cyber = 1;
4717          Cyber_video_setup(options, ints);
4718          return;
4719       }
4720 #endif /* CONFIG_FB_CYBER */
4721 
4722 #ifdef USE_MONO_AMIFB_IF_NON_AGA
4723    if (boot_info.bi_amiga.chipset != CS_AGA) {
4724       mono_video_setup(options, ints);
4725       return;
4726    }
4727 #endif /* USE_MONO_AMIFB_IF_NON_AGA */
4728 
4729    mcap_spec[0] = '\0';
4730    fb_info.fontname[0] = '\0';
4731 
4732    if (!options || !*options)
4733       return;
4734 
4735    for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ","))
4736       if (!strcmp(this_opt, "inverse")) {
4737          amifb_inverse = 1;
4738          for (i = 0; i < 16; i++) {
4739             red16[i] = ~red16[i];
4740             green16[i] = ~green16[i];
4741             blue16[i] = ~blue16[i];
4742          }
4743          for (i = 0; i < 8; i++) {
4744             red8[i] = ~red8[i];
4745             green8[i] = ~green8[i];
4746             blue8[i] = ~blue8[i];
4747          }
4748          for (i = 0; i < 4; i++) {
4749             red4[i] = ~red4[i];
4750             green4[i] = ~green4[i];
4751             blue4[i] = ~blue4[i];
4752          }
4753          for (i = 0; i < 2; i++) {
4754             red2[i] = ~red2[i];
4755             green2[i] = ~green2[i];
4756             blue2[i] = ~blue2[i];
4757          }
4758       } else if (!strcmp(this_opt, "ilbm"))
4759          amifb_ilbm = 1;
4760       else if (!strcmp(this_opt, "pwrsave"))
4761          pwrsave = 1;
4762       else if (!strncmp(this_opt, "monitorcap:", 11))
4763          strcpy(mcap_spec, this_opt+11);
4764       else if (!strncmp(this_opt, "font:", 5))
4765          strcpy(fb_info.fontname, this_opt+5);
4766       else
4767          amifb_mode = get_video_mode(this_opt);
4768 
4769    if (*mcap_spec) {
4770       char *p;
4771       int vmin, vmax, hmin, hmax;
4772 
4773       /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
4774        * <V*> vertical freq. in Hz
4775        * <H*> horizontal freq. in kHz
4776        */
4777 
4778       if (!(p = strtoke(mcap_spec, ";")) || !*p)
4779          goto cap_invalid;
4780       vmin = simple_strtoul(p, NULL, 10);
4781       if (vmin <= 0)
4782          goto cap_invalid;
4783       if (!(p = strtoke(NULL, ";")) || !*p)
4784          goto cap_invalid;
4785       vmax = simple_strtoul(p, NULL, 10);
4786       if (vmax <= 0 || vmax <= vmin)
4787          goto cap_invalid;
4788       if (!(p = strtoke(NULL, ";")) || !*p)
4789          goto cap_invalid;
4790       hmin = 1000 * simple_strtoul(p, NULL, 10);
4791       if (hmin <= 0)
4792          goto cap_invalid;
4793       if (!(p = strtoke(NULL, "")) || !*p)
4794          goto cap_invalid;
4795       hmax = 1000 * simple_strtoul(p, NULL, 10);
4796       if (hmax <= 0 || hmax <= hmin)
4797          goto cap_invalid;
4798 
4799       vfmin = vmin;
4800       vfmax = vmax;
4801       hfmin = hmin;
4802       hfmax = hmax;
4803 cap_invalid:
4804       ;
4805    }
4806 }
4807 
4808 
4809    /*
4810     *    Initialization
4811     */
4812 
4813 struct fb_info *amiga_fb_init(long *mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
4814 {
4815    int err, tag, i;
4816    struct fb_var_screeninfo *var;
4817 
4818    /*
4819     *    Check for a Graphics Board
4820     */
4821 
4822 #ifdef CONFIG_FB_CYBER
4823    if (amifb_Cyber)
4824       return(Cyber_fb_init(mem_start));
4825 #endif /* CONFIG_FB_CYBER */
4826 
4827    /*
4828     *    Use the Builtin Chipset
4829     */
4830 
4831    if (!AMIGAHW_PRESENT(AMI_VIDEO))
4832       return(NULL);
4833 
4834 #ifdef USE_MONO_AMIFB_IF_NON_AGA
4835    if (boot_info.bi_amiga.chipset != CS_AGA)
4836       return(mono_amiga_fb_init(mem_start));
4837 #endif /* USE_MONO_AMIFB_IF_NON_AGA */
4838 
4839    switch (boot_info.bi_amiga.chipset) {
4840 #ifdef CONFIG_AMIFB_OCS
4841       case CS_OCS:
4842          strcat(amiga_fb_name, "OCS");
4843 default_chipset:
4844          fbhw = &ocs_switch;
4845          maxdepth[TAG_SHRES-1] = 0;       /* OCS means no SHRES */
4846          maxdepth[TAG_HIRES-1] = 4;
4847          maxdepth[TAG_LORES-1] = 6;
4848          break;
4849 #endif /* CONFIG_AMIFB_OCS */
4850 
4851 #ifdef CONFIG_AMIFB_ECS
4852       case CS_ECS:
4853          strcat(amiga_fb_name, "ECS");
4854          fbhw = &ecs_switch;
4855          maxdepth[TAG_SHRES-1] = 2;
4856          maxdepth[TAG_HIRES-1] = 4;
4857          maxdepth[TAG_LORES-1] = 6;
4858          break;
4859 #endif /* CONFIG_AMIFB_ECS */
4860 
4861 #ifdef CONFIG_AMIFB_AGA
4862       case CS_AGA:
4863          strcat(amiga_fb_name, "AGA");
4864          fbhw = &aga_switch;
4865          maxdepth[TAG_SHRES-1] = 8;
4866          maxdepth[TAG_HIRES-1] = 8;
4867          maxdepth[TAG_LORES-1] = 8;
4868          break;
4869 #endif /* CONFIG_AMIFB_AGA */
4870 
4871       default:
4872 #ifdef CONFIG_AMIFB_OCS
4873          printk("Unknown graphics chipset, defaulting to OCS\n");
4874          strcat(amiga_fb_name, "Unknown");
4875          goto default_chipset;
4876 #else /* CONFIG_AMIFB_OCS */
4877          panic("Unknown graphics chipset, no default driver");
4878 #endif /* CONFIG_AMIFB_OCS */
4879          break;
4880    }
4881 
4882    /*
4883     *    Calculate the Pixel Clock Values for this Machine
4884     */
4885 
4886    pixclock[TAG_SHRES-1] = 25E9/amiga_eclock;   /* SHRES:  35 ns / 28 MHz */
4887    pixclock[TAG_HIRES-1] = 50E9/amiga_eclock;   /* HIRES:  70 ns / 14 MHz */
4888    pixclock[TAG_LORES-1] = 100E9/amiga_eclock;  /* LORES: 140 ns /  7 MHz */
4889 
4890    /*
4891     *    Replace the Tag Values with the Real Pixel Clock Values
4892     */
4893 
4894    for (i = 0; i < NUM_PREDEF_MODES; i++) {
4895       tag = amiga_fb_predefined[i].pixclock;
4896       if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
4897          amiga_fb_predefined[i].pixclock = pixclock[tag-1];
4898          if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag-1])
4899             amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag-1];
4900       }
4901    }
4902 
4903    err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
4904                               NUM_TOTAL_MODES, amiga_fb_predefined);
4905    if (err < 0)
4906       panic("Cannot register frame buffer");
4907 
4908    fbhw->init();
4909    check_default_mode();
4910 
4911    if (!add_isr(IRQ_AMIGA_VERTB, amifb_interrupt, 0, NULL, "frame buffer"))
4912       panic("Couldn't add vblank interrupt");
4913 
4914    strcpy(fb_info.modename, amiga_fb_name);
4915    fb_info.disp = disp;
4916    fb_info.switch_con = &amifb_switch;
4917    fb_info.updatevar = &amifb_updatevar;
4918    fb_info.blank = &amifb_blank;
4919 
4920    var = &amiga_fb_predefined[amifb_mode];
4921    do_fb_set_var(var, 1);
4922    strcat(fb_info.modename, " ");
4923    strcat(fb_info.modename, amiga_fb_modenames[amifb_mode]);
4924 
4925    amiga_fb_get_var(&disp[0].var, -1);
4926    amiga_fb_set_disp(-1);
4927    do_install_cmap(0);
4928    return(&fb_info);
4929 }
4930 
4931 
4932 static int amifb_switch(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4933 {
4934    /* Do we have to save the colormap? */
4935    if (disp[currcon].cmap.len)
4936       do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
4937 
4938    do_fb_set_var(&disp[con].var, 1);
4939    currcon = con;
4940    /* Install new colormap */
4941    do_install_cmap(con);
4942    return(0);
4943 }
4944 
4945 
4946    /*
4947     *    Update the `var' structure (called by fbcon.c)
4948     *
4949     *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
4950     *    Since it's called by a kernel driver, no range checking is done.
4951     */
4952 
4953 static int amifb_updatevar(int con)
     /* [previous][next][first][last][top][bottom][index][help] */
4954 {
4955    do_vmode = 0;
4956    current_par.yoffset = disp[con].var.yoffset;
4957    current_par.vmode = disp[con].var.vmode;
4958    current_par.bplpt0 = ZTWO_PADDR((u_long)videomemory+
4959                                    current_par.yoffset*current_par.next_line);
4960    do_vmode = 1;
4961    return(0);
4962 }
4963 
4964 
4965    /*
4966     *    Blank the display.
4967     */
4968 
4969 static void amifb_blank(int blank)
     /* [previous][next][first][last][top][bottom][index][help] */
4970 {
4971    do_blank = blank ? 1 : -1;
4972 }
4973 
4974 
4975    /*
4976     *    VBlank Display Interrupt
4977     */
4978 
4979 static void amifb_interrupt(int irq, struct pt_regs *fp, void *dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
4980 {
4981    static int is_laced = 0;
4982 
4983 #if 0
4984    /*
4985     *    This test should be here, in case current_par isn't initialized yet
4986     *
4987     *    Fortunately only do_flashcursor() will be called in that case, and
4988     *    currently that function doesn't use current_par. But this may change
4989     *    in future...
4990     */
4991    if (!current_par_valid)
4992       return;
4993 #endif
4994 
4995    /*
4996     *    If interlaced, only change the display on a long frame
4997     */
4998 
4999    if (!is_laced || custom.vposr & 0x8000) {
5000       if (do_vmode) {
5001          fbhw->do_vmode();
5002          do_vmode = 0;
5003          is_laced = (current_par.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
5004       }
5005       if (do_movecursor) {
5006          fbhw->do_movecursor();
5007          do_movecursor = 0;
5008       }
5009    }
5010    if (do_blank) {
5011       fbhw->do_blank(do_blank > 0 ? 1 : 0);
5012       do_blank = 0;
5013    }
5014    if (!is_blanked)
5015       fbhw->do_flashcursor();
5016 }
5017 
5018 
5019    /*
5020     *    A strtok which returns empty strings, too
5021     */
5022 
5023 static char * strtoke(char * s,const char * ct)
     /* [previous][next][first][last][top][bottom][index][help] */
5024 {
5025    char *sbegin, *send;
5026    static char *ssave = NULL;
5027   
5028    sbegin  = s ? s : ssave;
5029    if (!sbegin)
5030       return(NULL);
5031    if (*sbegin == '\0') {
5032       ssave = NULL;
5033       return(NULL);
5034    }
5035    send = strpbrk(sbegin, ct);
5036    if (send && *send != '\0')
5037       *send++ = '\0';
5038    ssave = send;
5039    return(sbegin);
5040 }
5041 
5042 
5043    /*
5044     *    Get a Video Modes
5045     */
5046 
5047 static int get_video_mode(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
5048 {
5049    int i;
5050 
5051    for (i = 1; i < NUM_PREDEF_MODES; i++)
5052       if (!strcmp(name, amiga_fb_modenames[i]))
5053          return(i);
5054    return(0);
5055 }
5056 
5057 
5058    /*
5059     *    Check the Default Video Mode
5060     */
5061 
5062 static void check_default_mode(void)
     /* [previous][next][first][last][top][bottom][index][help] */
5063 {
5064    struct fb_var_screeninfo var;
5065 
5066    /* First check the user supplied or system default video mode */
5067    if (amifb_mode) {
5068       var = amiga_fb_predefined[amifb_mode];
5069       var.activate = FB_ACTIVATE_TEST;
5070       if (!do_fb_set_var(&var, 1))
5071          goto found_video_mode;
5072    }
5073 
5074    /* Try some other modes... */
5075    printk("Can't use default video mode. Probing video modes...\n");
5076    for (amifb_mode = 1; amifb_mode < NUM_PREDEF_MODES; amifb_mode++) {
5077       var = amiga_fb_predefined[amifb_mode];
5078       var.activate = FB_ACTIVATE_TEST;
5079       if (!do_fb_set_var(&var, 1))
5080          goto found_video_mode;
5081    }
5082    panic("Can't find any usable video mode");
5083 
5084 found_video_mode:
5085    amiga_fb_predefined[0] = var;
5086 }

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