xref: /netbsd-src/sys/arch/amiga/dev/grf_cc.c (revision 0b9f50897e9a9c6709320fafb4c3787fddcc0a45)
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