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