Home | History | Annotate | Line # | Download | only in dev
grf_cc.c revision 1.3
      1 /*	$Id: grf_cc.c,v 1.3 1993/09/02 18:07:57 mw Exp $ */
      2 
      3 #include "grf.h"
      4 #if NGRF > 0
      5 
      6 /* Graphics routines for the AMIGA native custom chip set. */
      7 
      8 #include "sys/param.h"
      9 #include "sys/errno.h"
     10 #include "grfioctl.h"
     11 #include "grfvar.h"
     12 #include "grf_ccreg.h"
     13 #include "../include/cpu.h"
     14 #include "../amiga/custom.h"
     15 <<<<<<< grf_cc.c
     16 
     17 ||||||| 1.1.1.2
     18 =======
     19 #include "../amiga/cia.h"
     20 >>>>>>> /tmp/T4009586
     21 
     22 <<<<<<< 1.1.1.2
     23 
     24 =======
     25 >>>>>>> /tmp/T4009586
     26 extern caddr_t CHIPMEMADDR;
     27 extern caddr_t chipmem_steal ();
     28 
     29 struct ccfb ccfb = {
     30   DEF_DISP_WIDTH,
     31   DEF_DISP_HEIGHT,
     32   DEF_DISP_X, DEF_DISP_Y,
     33   DEF_DISP_Z,
     34   0,
     35   DEF_FB_WIDTH,
     36   DEF_FB_HEIGHT,
     37   0,
     38   DEF_FB_X, DEF_FB_Y, DEF_FB_Z,
     39 #if 0
     40   DEF_DIWSTRT, DEF_DIWSTOP, DEF_DDFSTRT, DEF_DDFSTOP,
     41 #endif
     42   DEF_COL0, DEF_COL1, DEF_COL2, DEF_COL3, 0,0,0,0,0,0,0,0,0,0,0,0,
     43   DEF_COL10, DEF_COL11, DEF_COL12, DEF_COL13, 0,0,0,0,0,0,0,0,0,0,0,0,
     44   0,				/* chip ram for beep sample */
     45   DEF_PERIOD, DEF_VOLUME,	/* beep sample period and volume */
     46   0,DEF_ABEEP,			/* beep timer, timer init value */
     47   0,DEF_DBEEP,			/* beep timer, timer init value */
     48   0,0,				/* cop1, cop2 */
     49   0,				/* pointer */
     50   0,0,				/* mouseH, mouseV */
     51   0,0,				/* lastMouseH, lastMouseV */
     52   0,0,				/* mouseX, mouseY */
     53   0,0,0,			/* mouseb1, mouseb2, mouseb3 */
     54   0,0,				/* joy1, joy2 */
     55   DEF_SCREEN,DEF_MOUSE,		/* screen/mouse blank timer init */
     56   0,0,				/* screenblank, mouseblank */
     57   0,0,				/* enableFlag, pad */
     58 };
     59 
     60 /*
     61  * custom copper list structure.  It replaces the macro method of
     62  * building copper lists for a good reason.  You want to change
     63  * diwstrt in an ioctl() handler?  well, with this struct, it is
     64  * trivial :-)
     65  *
     66  * YOU DON'T WANT! ioctl's to the console should NOT use any
     67  * implementation dependant data format to set values, they
     68  * should pass hi-level information that is processed by
     69  * the different console drivers. This driver would recalculate
     70  * diwstrt (for example) from given disp_* values.
     71  */
     72 typedef struct {
     73   u_short planes[6][4];		/* move + hi word, move + lo word */
     74   u_short bplcon0[2];		/* move + viewmode */
     75   u_short bplcon1[2];		/* move + BPLCON1 */
     76   u_short bpl1mod[2];		/* move + BPL1MOD */
     77   u_short bpl2mod[2];		/* move + BPL2MOD */
     78   u_short diwstrt[2];		/* move + DIWSTRT */
     79   u_short diwstop[2];		/* move + DIWSTOP */
     80   u_short ddfstrt[2];		/* move + DDFSTRT */
     81   u_short ddfstop[2];		/* move + DDFSTOP */
     82   u_short sprites[4*8];		/* 8  sprites (0 = mouseptr, 7 unused) */
     83   u_short colors[32*2];		/* move + color, 32 color regs */
     84   u_short copother[4];		/* move + COP1LC (to point to other copper list) */
     85   u_short finish[6];		/* COPEND instruction, -or-
     86 				   move + (COP2LC, COP2LC + 2, COPJMP2) */
     87 } COPPERLIST;
     88 
     89 /*
     90  * custom struct to describe the mousepointer sprite in chipram.
     91  * the header is tweaked by the vbl handler to move the mouse sprite
     92  * around.  the image[] array can be modified by the ioctl() handler
     93  * to change the image for the sprite!
     94  *
     95  * Again, we should probably have a much higher resolution, generic
     96  * sprite, and scale that down if necessary in the invidial drivers.
     97  */
     98 typedef struct {
     99   u_char header[4];
    100   u_short image[16*2];
    101   u_short footer[2];
    102 } SPRITEPTR;
    103 
    104 /*
    105  * initializer values for the pointer struct in chip ram.  It is a stupid
    106  * crosshair sprite, in just one color.  Do NOT change the first 4 bytes!
    107  */
    108 static SPRITEPTR pointerInit = {
    109   0x50,0x50,0x60,0x00,		/* header */
    110   0x0000,0x0000,		/* image */
    111   0x0080,0x0000,
    112   0x0080,0x0000,
    113   0x0080,0x0000,
    114   0x0080,0x0000,
    115   0x0080,0x0000,
    116   0x0080,0x0000,
    117   0x0080,0x0000,
    118   0x7f7f,0x0000,
    119   0x0080,0x0000,
    120   0x0080,0x0000,
    121   0x0080,0x0000,
    122   0x0080,0x0000,
    123   0x0080,0x0000,
    124   0x0080,0x0000,
    125   0x0080,0x0000,
    126   0x0000,0x0000,		/* footer */
    127 };
    128 
    129 /*
    130  * void initbeep(struct ccfb *fb);
    131  *
    132  * synopsis:
    133  *  allocates 20 bytes for a sine wave sample (in chip ram) and
    134  *  initializes it.  The audio hardware is turned on to play
    135  *  the sine wave sample in an infinite loop!  The volume is just
    136  *  set to zero so you don't hear it...  The sample is played in
    137  *  channels 0 and 1 so it goes out left+right audio jacks in the
    138  *  back of the machine.  The DMA is not enabled here... it is
    139  *  enabled in cc_init() below...  To make an audible beep, all
    140  *  that is needed is to turn on the volume, and then have the
    141  *  vbl handler turn off the volume after the desired beep duration
    142  *  has elapsed.
    143  *
    144  *  The custom chip console should really be broken down into a
    145  *  physical and logical layer.  The physical layer should have things
    146  *  like the bitplanes, copper list, mousepointer chipram, and the
    147  *  audible beep.  The logical layers should have their own private
    148  *  mousepointer image, color palette, and beep parameters.  The logical
    149  *  layer can keep an image of chipram for its own context - layers of
    150  *  sorts, in amigaos parlance.
    151  */
    152 static inline void
    153 initbeep (fb)
    154     struct ccfb *fb;
    155 {
    156   static char sample[20] = {
    157     0,39,75,103,121,127,121,103,75,39,0,
    158     -39,-75,-103,-121,-127,-121,-103,-75,-39
    159   };
    160   short i;
    161   char *ptr = chipmem_steal(20);
    162 
    163   if (!ptr) panic("Can't chipmem_steal 20 bytes!\n");
    164   fb->beepSample = ptr;
    165   for (i=0; i<20; i++) *ptr++ = sample[i];
    166   fb->beepTimer = fb->beepTime;
    167   custom.aud[0].lc = custom.aud[1].lc =
    168     (void *)((caddr_t)fb->beepSample - CHIPMEMADDR);
    169   custom.aud[0].len = custom.aud[1].len = 10;
    170   custom.aud[0].per = custom.aud[1].per = fb->beepPeriod;
    171   custom.aud[0].vol = custom.aud[1].vol = 0;
    172   fb->beepTimer = fb->dbeepTimer = 0;
    173   /* make SURE to disallow any audio interrupts - we don't need them */
    174   custom.intena = INTF_AUD0 | INTF_AUD1 | INTF_AUD2 | INTF_AUD3;
    175 }
    176 
    177 /*
    178  * void initpointer (struct ccfb *fb);
    179  *
    180  * synopsis:
    181  *  this routine initializes the mouse pointer part of the ccfb.
    182  *  currently, it only needs to copy the initializer data to the
    183  *  allocated chip ram.
    184  */
    185 static inline void
    186 initpointer (fb)
    187     struct ccfb *fb;
    188 {
    189   SPRITEPTR *pointer = (SPRITEPTR *)fb->pointer;
    190 
    191   /* initialize pointer structure */
    192   *pointer = pointerInit;
    193 }
    194 
    195 /*
    196  * void initcop (COPPERLIST *cop, COPPERLIST *othercop, int shf,
    197  *               struct ccfb *fb);
    198  *
    199  * synopsis:
    200  *  this function initializes one copperlist, treated as short-
    201  *  frame list if SHF is TRUE.
    202  *  it is assumed that initpointer has been called by the time
    203  *  initcop() is called.
    204  *
    205  *  This is REALLY basic stuff... even teenaged eurodemo coders
    206  *  understand it :-)  Normally, I'd have done this in assembly
    207  *  as a bunch of dc.w statements...  it is just translated into
    208  *  struct form here...
    209  *
    210  *  (yep, since this *is no* eurodemo here :-)) Hey, and we
    211  *  even have symbolic names for registers too :-))
    212  */
    213 static void inline
    214 initcop (cop, othercop, shf, fb)
    215     COPPERLIST *cop, *othercop;
    216     int shf;
    217     struct ccfb *fb;
    218 {
    219   SPRITEPTR *pointer = (SPRITEPTR *)fb->pointer;
    220   unsigned long screen;
    221   unsigned long rowbytes = fb->fb_width >> 3; /* width of display, in bytes */
    222   u_short *plptr;
    223   u_short c, i, strt, stop;
    224 
    225   /* get PA of display area */
    226   screen = (unsigned long) fb->fb - (unsigned long) CHIPMEMADDR;
    227   fb->fb_planesize = fb->fb_height * rowbytes;
    228 
    229   /* account for possible interlaced half-frame */
    230   if (shf)
    231     screen += rowbytes;
    232 
    233   /* account for oversized framebuffers */
    234   screen += (fb->fb_x >> 3) + (fb->fb_y * rowbytes);
    235 
    236 #define MOVE COP_MOVE
    237 
    238   /* initialize bitplane pointers for all planes */
    239   for (plptr = &cop->planes[0][0], i = 0; i < fb->fb_z; i++)
    240     {
    241       MOVE (plptr, bplpth(i), HIADDR (screen));
    242       plptr += 2;
    243       MOVE (plptr, bplptl(i), LOADDR (screen));
    244       plptr += 2;
    245       screen += fb->fb_planesize;
    246     }
    247   /* set the other bitplane pointers to 0, I hate this fixed size array.. */
    248   while (i < 6)
    249     {
    250       MOVE (plptr, bplpth(i), 0);
    251       plptr += 2;
    252       MOVE (plptr, bplptl(i), 0);
    253       plptr += 2;
    254       i++;
    255     }
    256 
    257   c =   0x8000 				/* HIRES */
    258       | ((fb->fb_z & 7) << 12)		/* bitplane use */
    259       | 0x0200				/* composite COLOR enable (whatever this is..) */
    260       | 0x0004;				/* LACE */
    261   MOVE (cop->bplcon0, bplcon0, c);
    262   MOVE (cop->bplcon1, bplcon1, 0);	/* nothing */
    263 
    264   /* modulo is one line for interlaced displays, plus difference between
    265      virtual and effective framebuffer size */
    266   MOVE (cop->bpl1mod, bpl1mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
    267   MOVE (cop->bpl2mod, bpl2mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3);
    268 
    269   /* these use pre-ECS register interpretation. Might want to go ECS ? */
    270   strt = (((fb->disp_y >> 1) & 0xff)<<8) | ((fb->disp_x >> 1) & 0xff);
    271   MOVE (cop->diwstrt, diwstrt, strt);
    272   stop = (((((fb->disp_y + fb->disp_height + 1-shf)>>1) & 0xff)<<8)
    273           | (((fb->disp_x + fb->disp_width)>>1) & 0xff));
    274   MOVE (cop->diwstop, diwstop, stop);
    275   /* NOTE: default values for strt: 0x2c81, stop: 0xf4c1 */
    276 
    277   /* these are from from HW-manual.. */
    278   strt = ((strt & 0xff) - 9) >> 1;
    279   MOVE (cop->ddfstrt, ddfstrt, strt);
    280   stop = strt + (((fb->disp_width >> 4) - 2) << 2);
    281   MOVE (cop->ddfstop, ddfstop, stop);
    282 
    283   /* sprites */
    284   {
    285     /* some cleverness... footer[0] is a ZERO longword in chip */
    286     u_short *spr = &cop->sprites[0];
    287     u_short addr = CUSTOM_OFS(sprpt[0]);
    288     u_short i;
    289     for (i=0; i<8; i++) {	/* for all sprites (8 of em) do */
    290       *spr++ = addr; *spr++ = HIADDR(&pointer->footer[0]);
    291       addr += 2;
    292       *spr++ = addr; *spr++ = LOADDR(&pointer->footer[0]);
    293       addr += 2;
    294     }
    295   }
    296   cop->sprites[0*4+1] = HIADDR((caddr_t)pointer-CHIPMEMADDR);
    297   cop->sprites[0*4+3] = LOADDR((caddr_t)pointer-CHIPMEMADDR);
    298 
    299   /* colors */
    300   for (i = 0; i < 32; i++)
    301     MOVE (cop->colors+i*2, color[i], fb->col[i]);
    302 
    303   /* setup interlaced display by constantly toggling between two copperlists */
    304   MOVE (cop->copother,   cop1lch, HIADDR ((unsigned long) othercop - (unsigned long) CHIPMEMADDR));
    305   MOVE (cop->copother+2, cop1lcl, LOADDR ((unsigned long) othercop - (unsigned long) CHIPMEMADDR));
    306 
    307   /* terminate copper list */
    308   COP_END (cop->finish);
    309 }
    310 
    311 /*
    312  * Install a sprite.
    313  * The sprites to be loaded on the alternate frames
    314  * can be specified separately,
    315  * so interlaced sprites are possible.
    316  */
    317 cc_install_sprite(gp, num, spr1, spr2)
    318 	struct grf_softc *gp;
    319 	int num;
    320 	u_short *spr1, *spr2;
    321 {
    322   struct ccfb *fb = &ccfb;
    323   COPPERLIST *cop;
    324 
    325   cop = (COPPERLIST*)fb->cop1;
    326   cop->sprites[num*4+1] = HIADDR((caddr_t)spr1-CHIPMEMADDR);
    327   cop->sprites[num*4+3] = LOADDR((caddr_t)spr1-CHIPMEMADDR);
    328 
    329   cop = (COPPERLIST*)fb->cop2;
    330   cop->sprites[num*4+1] = HIADDR((caddr_t)spr2-CHIPMEMADDR);
    331   cop->sprites[num*4+3] = LOADDR((caddr_t)spr2-CHIPMEMADDR);
    332 }
    333 
    334 /*
    335  * Uninstall a sprite.
    336  */
    337 cc_uninstall_sprite(gp, num)
    338 	struct grf_softc *gp;
    339 	int num;
    340 {
    341   struct ccfb *fb = &ccfb;
    342   SPRITEPTR *pointer = (SPRITEPTR*)fb->pointer;
    343   COPPERLIST *cop;
    344 
    345     /* some cleverness... footer[0] is a ZERO longword in chip */
    346   cop = (COPPERLIST*)fb->cop1;
    347   cop->sprites[num*4+1] = HIADDR(&pointer->footer[0]);
    348   cop->sprites[num*4+3] = LOADDR(&pointer->footer[0]);
    349 
    350   cop = (COPPERLIST*)fb->cop2;
    351   cop->sprites[num*4+1] = HIADDR(&pointer->footer[0]);
    352   cop->sprites[num*4+3] = LOADDR(&pointer->footer[0]);
    353 }
    354 
    355 /*
    356  * Install a copper list extension.
    357  */
    358 cc_install_cop_ext(gp, cl1, cl2)
    359 	struct grf_softc *gp;
    360 	u_short *cl1, *cl2;
    361 {
    362   struct ccfb *fb = &ccfb;
    363   COPPERLIST *cop;
    364 
    365   cop = (COPPERLIST*)fb->cop1;
    366   COP_MOVE (cop->finish+0, cop2lch, HIADDR((caddr_t)cl1-CHIPMEMADDR));
    367   COP_MOVE (cop->finish+2, cop2lcl, LOADDR((caddr_t)cl1-CHIPMEMADDR));
    368   COP_MOVE (cop->finish+4, copjmp2, 0);
    369 
    370   cop = (COPPERLIST*)fb->cop2;
    371   COP_MOVE (cop->finish+0, cop2lch, HIADDR((caddr_t)cl2-CHIPMEMADDR));
    372   COP_MOVE (cop->finish+2, cop2lcl, LOADDR((caddr_t)cl2-CHIPMEMADDR));
    373   COP_MOVE (cop->finish+4, copjmp2, 0);
    374 }
    375 
    376 /*
    377  * Uninstall a copper list extension.
    378  */
    379 cc_uninstall_cop_ext(gp, cl1, cl2)
    380 	struct grf_softc *gp;
    381 	u_short *cl1, *cl2;
    382 {
    383   register struct ccfb *fb = &ccfb;
    384   COPPERLIST *cop;
    385 
    386   cop = (COPPERLIST*)fb->cop1;
    387   COP_END (cop->finish);
    388 
    389   cop = (COPPERLIST*)fb->cop2;
    390   COP_END (cop->finish);
    391 }
    392 
    393 /*
    394  * Call this function any time a key is hit to ensure screen blanker unblanks
    395  */
    396 void
    397 cc_unblank ()
    398 {
    399   if (!ccfb.screenBlank) {	/* screenblank timer 0 means blank! */
    400     COPPERLIST *c1 = (COPPERLIST *)ccfb.cop1, *c2 = (COPPERLIST *)ccfb.cop2;
    401     /* turn on sprite and raster DMA */
    402     custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
    403     ccfb.mouseBlank = ccfb.mouseTime; /* start mouseblank timer */
    404     /* screen was black, reset background color to the one in ccfb! */
    405     c1->colors[1] = c2->colors[1] = ccfb.col[0];
    406   }
    407   /* restart the screenblank timer */
    408   ccfb.screenBlank = ccfb.screenTime;
    409 }
    410 
    411 /*
    412  * void cc_bell(void);
    413  *
    414  * Synopsis:
    415  *  trigger audible bell
    416  * Description
    417  *  Call this function to start a beep tone.  The beep lasts for
    418  *  ccfb.beepTime 60ths of a second (can adjust it in the ccfb structure
    419  *  in an ioctl().  The sample is playing in left+right aud0+aud1 hardware
    420  *  channels all the time, just the volume is off when the beep isn't
    421  *  heard.  So here we just turn on the volume (ccfb.beepVolume, it can
    422  *  also be set by ioctl() call) and set the timer (ccfb.beepTime can
    423  *  be set by ioctl() as well).  The cc_vbl() routine counts down the
    424  *  timer and shuts off the volume when it reaches zero.
    425  */
    426 void
    427 cc_bell ()
    428 {
    429   custom.aud[0].vol = ccfb.beepVolume;
    430   custom.aud[1].vol = ccfb.beepVolume;
    431   ccfb.beepTimer = ccfb.beepTime;
    432 }
    433 
    434 /*
    435  * void cc_vbl(void);
    436  *
    437  * synopsis:
    438  *  vertical blank service routine for the console.
    439  *  provides the following:
    440  *   samples mouse counters and positions mouse sprite
    441  *   samples joystick inputs
    442  *   counts down mouseblanker timer and blanks mouse if it is time
    443  *   counts down screenblanker timer and blanks if it is time
    444  *   counts down audio beep timer and shuts of the volume if the beep is done
    445  *   unblanks mouse/screen if mouse is moved
    446  * not implemented yet:
    447  *  it should adjust color palette in copper list over time to effect
    448  *   display beep.
    449  *
    450  * There's black magic going on here with assembly-in-C.. Since this
    451  * is an interrupt handler, and it should be fast, ignore the obscure but
    452  * probably fast processing of the mouse for now...
    453  */
    454 void
    455 cc_vbl ()
    456 {
    457   u_short w0, w1;
    458   u_char *b0 = (u_char *)&w0, *b1 = (u_char *)&w1;
    459   SPRITEPTR *p = (SPRITEPTR *)ccfb.pointer;
    460 
    461   ccfb.lastMouseH = ccfb.mouseH;
    462   ccfb.lastMouseV = ccfb.mouseV;
    463 
    464   /* horizontal mouse counter */
    465   w1 = custom.joy0dat;
    466   b0[1] = ccfb.mouseH;		/* last counter val */
    467   ccfb.mouseH = b1[1];		/* current is now last */
    468   b1[1] -= b0[1];		/* current - last */
    469   b1[0] = (b1[1] & 0x80) ? 0xff : 0x00; /* ext.w */
    470   ccfb.mouseX += w1;
    471   if (ccfb.mouseX < 0) ccfb.mouseX = 0;
    472   if (ccfb.mouseX > ccfb.fb_width-1) ccfb.mouseX = ccfb.fb_width-1;
    473 
    474   /* vertical mouse counter */
    475   w1 = custom.joy0dat;
    476   b1[1] = b1[0];
    477   b0[1] = ccfb.mouseV;
    478   ccfb.mouseV = b1[1];
    479   b1[1] -= b0[1];
    480   b1[0] = (b1[1] & 0x80) ? 0xff : 0x00; /* ext.w */
    481   ccfb.mouseY += w1;
    482   if (ccfb.mouseY < 0) ccfb.mouseY = 0;
    483   if (ccfb.mouseY > ccfb.fb_height-1) ccfb.mouseY = ccfb.fb_height-1;
    484 
    485   /* mouse buttons (should renumber them, middle button should be #2!) */
    486   ccfb.mouseb1 = (ciaa.pra & (1<<6)) ? 0 : !0;
    487   ccfb.mouseb2 = (custom.pot1dat & (1<<2)) ? 0 : !0;
    488   ccfb.mouseb3 = (custom.pot1dat & (1<<0)) ? 0 : !0;
    489 
    490   /* position pointer sprite */
    491   w0 = ccfb.mouseY >> 1;
    492   b0[1] += 0x24;
    493   p->header[0] = b0[1];
    494   b0[1] += 16;
    495   p->header[2] = b0[1];
    496 
    497   w0 = ccfb.mouseX >> 1;
    498   w0 += 120;
    499   if (w0 & 1) p->header[3] |= 1; else p->header[3] &= ~1;
    500   w0 >>= 1;
    501   p->header[1] = b0[1];
    502 
    503   /* joystick #1 */
    504   ccfb.joy0 = 0;
    505   w0 = custom.joy1dat;
    506   w1 = w0 >> 1;
    507   w1 ^= w0;
    508   if (w1 & (1<<9)) ccfb.joy0 |= JOYLEFT;
    509   if (w1 & (1<<1)) ccfb.joy0 |= JOYRIGHT;
    510   if (w1 & (1<<8)) ccfb.joy0 |= JOYUP;
    511   if (w1 & (1<<0)) ccfb.joy0 |= JOYDOWN;
    512   if ( (ciaa.pra & (1<<7)) == 0 ) ccfb.joy0 |= JOYBUTTON;
    513 
    514   /* joystick #2 (normally mouse port) */
    515   ccfb.joy1 = 0;
    516   w0 = custom.joy0dat;
    517   w1 = w0 >> 1;
    518   w1 ^= w0;
    519   if (w1 & (1<<9)) ccfb.joy1 |= JOYLEFT;
    520   if (w1 & (1<<1)) ccfb.joy1 |= JOYRIGHT;
    521   if (w1 & (1<<8)) ccfb.joy1 |= JOYUP;
    522   if (w1 & (1<<0)) ccfb.joy1 |= JOYDOWN;
    523   if ( (ciaa.pra & (1<<6)) == 0 ) ccfb.joy1 |= JOYBUTTON;
    524 
    525   /* only do screenblanker/mouseblanker/display beep if screen is enabled */
    526   if (ccfb.enableFlag) {
    527     /* handle screen blanker */
    528     if (ccfb.screenBlank) {
    529       COPPERLIST *c1 = (COPPERLIST *)ccfb.cop1, *c2 = (COPPERLIST *)ccfb.cop2;
    530       ccfb.screenBlank--;
    531       if (!ccfb.screenBlank) {
    532 	custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
    533 	c1->colors[1] = c2->colors[1] = 0; /* make screen BLACK */
    534       }
    535     }
    536 
    537     /* handle mouse blanker */
    538     if (ccfb.mouseBlank) {
    539       ccfb.mouseBlank--;
    540       if (!ccfb.mouseBlank) custom.dmacon = DMAF_SPRITE;
    541     }
    542     else if (ccfb.lastMouseH != ccfb.mouseH || ccfb.lastMouseV != ccfb.mouseV) {
    543       cc_unblank();
    544       ccfb.mouseBlank = ccfb.mouseTime;
    545       custom.dmacon = DMAF_SETCLR | DMAF_SPRITE;
    546     }
    547 
    548     /* handle visual beep (not implemented yet) */
    549   }
    550 
    551   /* handle audible beep */
    552   if (ccfb.beepTimer) ccfb.beepTimer--;
    553   if (!ccfb.beepTimer) custom.aud[0].vol = custom.aud[1].vol = 0;
    554 }
    555 
    556 /* Initialize hardware.
    557  * Must point g_display at a grfinfo structure describing the hardware.
    558  * Returns 0 if hardware not present, non-zero ow.
    559  */
    560 cc_init(gp, ad)
    561 	struct grf_softc *gp;
    562 	struct amiga_device *ad;
    563 {
    564   register struct ccfb *fb = &ccfb;
    565   struct grfinfo *gi = &gp->g_display;
    566   u_char *fbp, save;
    567   int fboff, fbsize;
    568   int s;
    569 
    570   /* if already initialized, fail */
    571   if (fb->fb) return 0;
    572 
    573   /* disable dma */
    574   custom.dmacon  = DMAF_BLTDONE
    575     | DMAF_BLTNZERO | DMAF_BLITHOG | DMAF_BLITTER | DMAF_DISK
    576       | DMAF_AUD3 | DMAF_AUD2 | DMAF_AUD1 | DMAF_AUD0;
    577 
    578   fb->mouseBlank = fb->mouseTime;
    579   fb->screenBlank = fb->screenTime;
    580 
    581   /* testing for the result is really redundant because chipmem_steal
    582      panics if it runs out of memory.. */
    583   fbsize = (fb->fb_width >> 3) * fb->fb_height * fb->fb_z;
    584   if (! (fb->fb = (u_char *) chipmem_steal (fbsize))
    585       || !(fb->cop1 = (u_short *) chipmem_steal (sizeof(COPPERLIST)))
    586       || !(fb->cop2 = (u_short *) chipmem_steal (sizeof(COPPERLIST)))
    587       || !(fb->pointer = (u_short *)chipmem_steal (sizeof(SPRITEPTR)))
    588       )
    589     return 0;
    590 
    591   /* clear the display. bzero only likes regions up to 64k, so call multiple times */
    592   for (fboff = 0; fboff < fbsize; fboff += 64*1024)
    593     bzero (fb->fb + fboff, fbsize - fboff > 64*1024 ? 64*1024 : fbsize - fboff);
    594 
    595   /* init the audio beep */
    596   initbeep(fb);
    597   /* initialize the sprite pointer */
    598   initpointer(fb);
    599 
    600   /* initialize the copper lists  */
    601   initcop (fb->cop1, fb->cop2, 0, fb);
    602   initcop (fb->cop2, fb->cop1, 1, fb);
    603 
    604   /* start the new display */
    605 
    606   /* ok, this is a bit rough.. */
    607   /* mtk: not any more! :-) */
    608   /* mykes: phew, thanks :-) */
    609   s = splhigh ();
    610 
    611   /* install dummy, to get display going (for vposr to count.. ) */
    612   custom.cop1lc  = (void *) ((unsigned long)fb->cop1 - (unsigned long) CHIPMEMADDR);
    613   custom.copjmp1 = 0;
    614 
    615   /* enable DMA (so the copperlists are executed and eventually
    616      cause a switch to an interlaced display on system not already booting that
    617      way. THANKS HAMISH for finding this bug!!) */
    618   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER |
    619 		  DMAF_COPPER | DMAF_SPRITE | DMAF_AUD0 | DMAF_AUD1;
    620 
    621   /* this is real simple:  wait for LOF bit of vposr to go high - then start
    622      the copper list! :-) */
    623   while (custom.vposr & 0x8000);
    624   while (!(custom.vposr & 0x8000));
    625 
    626   custom.cop1lc  = (void *) ((unsigned long)fb->cop1 - (unsigned long) CHIPMEMADDR);
    627   custom.copjmp1 = 0;
    628 
    629   custom.intreq = INTF_VERTB;
    630 
    631   splx (s);
    632 
    633 #if 0
    634   /* tame the blitter. Copying one word onto itself should put it into
    635      a consistent state. This is black magic... */
    636   custom.bltapt =
    637     custom.bltbpt =
    638       custom.bltcpt =
    639         custom.bltdpt = 0;
    640   custom.bltamod =
    641     custom.bltbmod =
    642       custom.bltcmod =
    643         custom.bltdmod = 0;
    644   custom.bltafwm =
    645     custom.bltalwn = 0xffff;
    646   custom.bltcon0 = 0x09f0;
    647   custom.bltcon1 = 0;
    648   custom.bltsize = 1;
    649 #endif
    650 
    651   /* enable VBR interrupts. This is also done in the serial driver, but it
    652      really belongs here.. */
    653   custom.intena = INTF_SETCLR | INTF_VERTB; /* under amigaos, INTF_INTEN is needed */
    654 
    655 #if 0
    656 #ifdef DEBUG
    657   /* prove the display is up.. */
    658   for (fboff = 0; fboff < fbsize; fboff++)
    659     {
    660       fb->fb[fboff] = 0xff;
    661       DELAY(10);
    662     }
    663   for (fboff = 0; fboff < fbsize; fboff++)
    664     {
    665       fb->fb[fboff] = 0;
    666       DELAY(10);
    667     }
    668 #endif
    669 #endif
    670 
    671   gi->gd_regaddr = (caddr_t) fb; /* XXX */
    672   gi->gd_regsize = 0;
    673 
    674   gi->gd_fbaddr  = fb->fb - (u_char *) CHIPMEMADDR;
    675 #if 0
    676   /* mykes kludges here to make gi look like 1 bitplane */
    677   gi->gd_fbsize  = fbsize/2;
    678 #else
    679   /* don't see why we should kludge here.. we have
    680      disp_z to indicate the real depth of the display */
    681   gi->gd_fbsize  = fbsize;
    682 #endif
    683 
    684   gi->gd_colors = 1 << fb->disp_z;
    685   gi->gd_planes = fb->disp_z;
    686 
    687   gi->gd_fbwidth  = fb->fb_width;
    688   gi->gd_fbheight = fb->fb_height;
    689   gi->gd_fbx	  = fb->fb_x;
    690   gi->gd_fby	  = fb->fb_y;
    691   gi->gd_dwidth   = fb->disp_width;
    692   gi->gd_dheight  = fb->disp_height;
    693   gi->gd_dx	  = fb->disp_x;
    694   gi->gd_dy	  = fb->disp_y;
    695 
    696   gp->g_regkva = 0;		/* builtin */
    697   gp->g_fbkva  = fb->fb;
    698 
    699   fb->enableFlag = !0;
    700   return(1);
    701 }
    702 
    703 cc_config(gp, di)
    704 	register struct grf_softc *gp;
    705 	struct grfdyninfo *di;
    706 {
    707   register struct ccfb *fb = &ccfb;
    708   struct grfinfo *gi = &gp->g_display;
    709   u_char *fbp, save;
    710   int fboff, fbsize;
    711   int s;
    712 
    713   /* bottom missing... */
    714 
    715 }
    716 
    717 /*
    718  * Change the mode of the display.
    719  * Right now all we can do is grfon/grfoff.
    720  * Return a UNIX error number or 0 for success.
    721  */
    722 cc_mode(gp, cmd, arg)
    723 	register struct grf_softc *gp;
    724 	int cmd;
    725 	void *arg;
    726 {
    727   switch (cmd)
    728     {
    729     case GM_GRFON:
    730       ccfb.enableFlag = !0;
    731       ccfb.screenBlank = ccfb.screenTime;
    732       ccfb.mouseBlank = ccfb.mouseTime;
    733       custom.dmacon  = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
    734       return 0;
    735 
    736     case GM_GRFOFF:
    737       ccfb.enableFlag = 0;
    738       custom.dmacon  = DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
    739       return 0;
    740 
    741     case GM_GRFCONFIG:
    742       return cc_config (gp, (struct grfdyninfo *) arg);
    743 
    744     default:
    745       break;
    746     }
    747 
    748   return EINVAL;
    749 }
    750 
    751 #endif
    752