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