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