grf_cc.c revision 1.5 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