xref: /netbsd-src/sys/arch/amiga/dev/grf_cc.c (revision 448e711c7835101c94f75b7ebddf58046df58290)
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 /* useful function for debugging.. */
546 int
547 amiga_mouse_button (num)
548      int num;
549 {
550   switch (num)
551     {
552     case 1:
553       return ccfb.mouseb1;
554 
555     case 2:
556       return ccfb.mouseb2;
557 
558     case 3:
559       return ccfb.mouseb3;
560 
561     default:
562       return 0;
563     }
564 }
565 
566 
567 /* Initialize hardware.
568  * Must point g_display at a grfinfo structure describing the hardware.
569  * Returns 0 if hardware not present, non-zero ow.
570  */
571 cc_init(gp, ad)
572 	struct grf_softc *gp;
573 	struct amiga_device *ad;
574 {
575   register struct ccfb *fb = &ccfb;
576   struct grfinfo *gi = &gp->g_display;
577   u_char *fbp, save;
578   int fboff, fbsize;
579   int s;
580 
581   /* if already initialized, fail */
582   if (fb->fb) return 0;
583 
584   /* disable dma */
585   custom.dmacon  = DMAF_BLTDONE
586     | DMAF_BLTNZERO | DMAF_BLITHOG | DMAF_BLITTER | DMAF_DISK
587       | DMAF_AUD3 | DMAF_AUD2 | DMAF_AUD1 | DMAF_AUD0;
588 
589   fb->mouseBlank = fb->mouseTime;
590   fb->screenBlank = fb->screenTime;
591 
592   /* testing for the result is really redundant because chipmem_steal
593      panics if it runs out of memory.. */
594   fbsize = (fb->fb_width >> 3) * fb->fb_height * fb->fb_z;
595   if (! (fb->fb = (u_char *) chipmem_steal (fbsize))
596       || !(fb->cop1 = (u_short *) chipmem_steal (sizeof(COPPERLIST)))
597       || !(fb->cop2 = (u_short *) chipmem_steal (sizeof(COPPERLIST)))
598       || !(fb->pointer = (u_short *)chipmem_steal (sizeof(SPRITEPTR)))
599       )
600     return 0;
601 
602   /* clear the display. bzero only likes regions up to 64k, so call multiple times */
603   for (fboff = 0; fboff < fbsize; fboff += 64*1024)
604     bzero (fb->fb + fboff, fbsize - fboff > 64*1024 ? 64*1024 : fbsize - fboff);
605 
606   /* init the audio beep */
607   initbeep(fb);
608   /* initialize the sprite pointer */
609   initpointer(fb);
610 
611   /* initialize the copper lists  */
612   initcop (fb->cop1, fb->cop2, 0, fb);
613   initcop (fb->cop2, fb->cop1, 1, fb);
614 
615   /* start the new display */
616 
617   /* ok, this is a bit rough.. */
618   /* mtk: not any more! :-) */
619   /* mykes: phew, thanks :-) */
620   s = splhigh ();
621 
622   /* install dummy, to get display going (for vposr to count.. ) */
623   custom.cop1lc  = (void *) ((unsigned long)fb->cop1 - (unsigned long) CHIPMEMADDR);
624   custom.copjmp1 = 0;
625 
626   /* enable DMA (so the copperlists are executed and eventually
627      cause a switch to an interlaced display on system not already booting that
628      way. THANKS HAMISH for finding this bug!!) */
629   custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER |
630 		  DMAF_COPPER | DMAF_SPRITE | DMAF_AUD0 | DMAF_AUD1;
631 
632   /* this is real simple:  wait for LOF bit of vposr to go high - then start
633      the copper list! :-) */
634   while (custom.vposr & 0x8000);
635   while (!(custom.vposr & 0x8000));
636 
637   custom.cop1lc  = (void *) ((unsigned long)fb->cop1 - (unsigned long) CHIPMEMADDR);
638   custom.copjmp1 = 0;
639 
640   custom.intreq = INTF_VERTB;
641 
642   splx (s);
643 
644 #if 0
645   /* tame the blitter. Copying one word onto itself should put it into
646      a consistent state. This is black magic... */
647   custom.bltapt =
648     custom.bltbpt =
649       custom.bltcpt =
650         custom.bltdpt = 0;
651   custom.bltamod =
652     custom.bltbmod =
653       custom.bltcmod =
654         custom.bltdmod = 0;
655   custom.bltafwm =
656     custom.bltalwn = 0xffff;
657   custom.bltcon0 = 0x09f0;
658   custom.bltcon1 = 0;
659   custom.bltsize = 1;
660 #endif
661 
662   /* enable VBR interrupts. This is also done in the serial driver, but it
663      really belongs here.. */
664   custom.intena = INTF_SETCLR | INTF_VERTB; /* under amigaos, INTF_INTEN is needed */
665 
666 #if 0
667 #ifdef DEBUG
668   /* prove the display is up.. */
669   for (fboff = 0; fboff < fbsize; fboff++)
670     {
671       fb->fb[fboff] = 0xff;
672       DELAY(10);
673     }
674   for (fboff = 0; fboff < fbsize; fboff++)
675     {
676       fb->fb[fboff] = 0;
677       DELAY(10);
678     }
679 #endif
680 #endif
681 
682   gp->g_data = (caddr_t) fb;
683   gi->gd_regaddr = 0xdff000;
684   gi->gd_regsize = sizeof (custom);
685 
686   gi->gd_fbaddr  = fb->fb - (u_char *) CHIPMEMADDR;
687 #if 0
688   /* mykes kludges here to make gi look like 1 bitplane */
689   gi->gd_fbsize  = fbsize/2;
690 #else
691   /* don't see why we should kludge here.. we have
692      disp_z to indicate the real depth of the display */
693   gi->gd_fbsize  = fbsize;
694 #endif
695 
696   gi->gd_colors = 1 << fb->disp_z;
697   gi->gd_planes = fb->disp_z;
698 
699   gi->gd_fbwidth  = fb->fb_width;
700   gi->gd_fbheight = fb->fb_height;
701   gi->gd_fbx	  = fb->fb_x;
702   gi->gd_fby	  = fb->fb_y;
703   gi->gd_dwidth   = fb->disp_width;
704   gi->gd_dheight  = fb->disp_height;
705   gi->gd_dx	  = fb->disp_x;
706   gi->gd_dy	  = fb->disp_y;
707 
708   gp->g_regkva = 0;		/* builtin */
709   gp->g_fbkva  = fb->fb;
710 
711   fb->enableFlag = !0;
712   return(1);
713 }
714 
715 cc_config(gp, di)
716 	register struct grf_softc *gp;
717 	struct grfdyninfo *di;
718 {
719   register struct ccfb *fb = &ccfb;
720   struct grfinfo *gi = &gp->g_display;
721   u_char *fbp, save;
722   int fboff, fbsize;
723   int s;
724 
725   /* bottom missing... */
726 
727 }
728 
729 /*
730  * Change the mode of the display.
731  * Right now all we can do is grfon/grfoff.
732  * Return a UNIX error number or 0 for success.
733  */
734 cc_mode(gp, cmd, arg)
735 	register struct grf_softc *gp;
736 	int cmd;
737 	void *arg;
738 {
739   switch (cmd)
740     {
741     case GM_GRFON:
742       ccfb.enableFlag = !0;
743       ccfb.screenBlank = ccfb.screenTime;
744       ccfb.mouseBlank = ccfb.mouseTime;
745       custom.dmacon  = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
746       return 0;
747 
748     case GM_GRFOFF:
749       ccfb.enableFlag = 0;
750       custom.dmacon  = DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE;
751       return 0;
752 
753     case GM_GRFCONFIG:
754       return cc_config (gp, (struct grfdyninfo *) arg);
755 
756     default:
757       break;
758     }
759 
760   return EINVAL;
761 }
762 
763 #endif
764 
765