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