#include "grf.h" #if NGRF > 0 /* Graphics routines for the AMIGA native custom chip set. */ #include "sys/param.h" #include "sys/errno.h" #include "grfioctl.h" #include "grfvar.h" #include "grf_ccreg.h" #include "../include/cpu.h" #include "../amiga/custom.h" #include "../amiga/cia.h" extern caddr_t CHIPMEMADDR; extern caddr_t chipmem_steal (); struct ccfb ccfb = { DEF_DISP_WIDTH, DEF_DISP_HEIGHT, DEF_DISP_X, DEF_DISP_Y, DEF_DISP_Z, 0, DEF_FB_WIDTH, DEF_FB_HEIGHT, 0, DEF_FB_X, DEF_FB_Y, DEF_FB_Z, #if 0 DEF_DIWSTRT, DEF_DIWSTOP, DEF_DDFSTRT, DEF_DDFSTOP, #endif DEF_COL0, DEF_COL1, DEF_COL2, DEF_COL3, 0,0,0,0,0,0,0,0,0,0,0,0, DEF_COL10, DEF_COL11, DEF_COL12, DEF_COL13, 0,0,0,0,0,0,0,0,0,0,0,0, 0, /* chip ram for beep sample */ DEF_PERIOD, DEF_VOLUME, /* beep sample period and volume */ 0,DEF_ABEEP, /* beep timer, timer init value */ 0,DEF_DBEEP, /* beep timer, timer init value */ 0,0, /* cop1, cop2 */ 0, /* pointer */ 0,0, /* mouseH, mouseV */ 0,0, /* lastMouseH, lastMouseV */ 0,0, /* mouseX, mouseY */ 0,0,0, /* mouseb1, mouseb2, mouseb3 */ 0,0, /* joy1, joy2 */ DEF_SCREEN,DEF_MOUSE, /* screen/mouse blank timer init */ 0,0, /* screenblank, mouseblank */ 0,0, /* enableFlag, pad */ }; /* * custom copper list structure. It replaces the macro method of * building copper lists for a good reason. You want to change * diwstrt in an ioctl() handler? well, with this struct, it is * trivial :-) * * YOU DON'T WANT! ioctl's to the console should NOT use any * implementation dependant data format to set values, they * should pass hi-level information that is processed by * the different console drivers. This driver would recalculate * diwstrt (for example) from given disp_* values. */ typedef struct { u_short planes[6][4]; /* move + hi word, move + lo word */ u_short bplcon0[2]; /* move + viewmode */ u_short bplcon1[2]; /* move + BPLCON1 */ u_short bpl1mod[2]; /* move + BPL1MOD */ u_short bpl2mod[2]; /* move + BPL2MOD */ u_short diwstrt[2]; /* move + DIWSTRT */ u_short diwstop[2]; /* move + DIWSTOP */ u_short ddfstrt[2]; /* move + DDFSTRT */ u_short ddfstop[2]; /* move + DDFSTOP */ u_short sprites[4*8]; /* 8 sprites (0 = mouseptr, 7 unused) */ u_short colors[32*2]; /* move + color, 32 color regs */ u_short copother[4]; /* move + COP1LC (to point to other copper list) */ u_short finish[6]; /* COPEND instruction, -or- move + (COP2LC, COP2LC + 2, COPJMP2) */ } COPPERLIST; /* * custom struct to describe the mousepointer sprite in chipram. * the header is tweaked by the vbl handler to move the mouse sprite * around. the image[] array can be modified by the ioctl() handler * to change the image for the sprite! * * Again, we should probably have a much higher resolution, generic * sprite, and scale that down if necessary in the invidial drivers. */ typedef struct { u_char header[4]; u_short image[16*2]; u_short footer[2]; } SPRITEPTR; /* * initializer values for the pointer struct in chip ram. It is a stupid * crosshair sprite, in just one color. Do NOT change the first 4 bytes! */ static SPRITEPTR pointerInit = { 0x50,0x50,0x60,0x00, /* header */ 0x0000,0x0000, /* image */ 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x7f7f,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0080,0x0000, 0x0000,0x0000, /* footer */ }; /* * void initbeep(struct ccfb *fb); * * synopsis: * allocates 20 bytes for a sine wave sample (in chip ram) and * initializes it. The audio hardware is turned on to play * the sine wave sample in an infinite loop! The volume is just * set to zero so you don't hear it... The sample is played in * channels 0 and 1 so it goes out left+right audio jacks in the * back of the machine. The DMA is not enabled here... it is * enabled in cc_init() below... To make an audible beep, all * that is needed is to turn on the volume, and then have the * vbl handler turn off the volume after the desired beep duration * has elapsed. * * The custom chip console should really be broken down into a * physical and logical layer. The physical layer should have things * like the bitplanes, copper list, mousepointer chipram, and the * audible beep. The logical layers should have their own private * mousepointer image, color palette, and beep parameters. The logical * layer can keep an image of chipram for its own context - layers of * sorts, in amigaos parlance. */ static inline void initbeep (fb) struct ccfb *fb; { static char sample[20] = { 0,39,75,103,121,127,121,103,75,39,0, -39,-75,-103,-121,-127,-121,-103,-75,-39 }; short i; char *ptr = chipmem_steal(20); if (!ptr) panic("Can't chipmem_steal 20 bytes!\n"); fb->beepSample = ptr; for (i=0; i<20; i++) *ptr++ = sample[i]; fb->beepTimer = fb->beepTime; custom.aud[0].lc = custom.aud[1].lc = (void *)((caddr_t)fb->beepSample - CHIPMEMADDR); custom.aud[0].len = custom.aud[1].len = 10; custom.aud[0].per = custom.aud[1].per = fb->beepPeriod; custom.aud[0].vol = custom.aud[1].vol = 0; fb->beepTimer = fb->dbeepTimer = 0; /* make SURE to disallow any audio interrupts - we don't need them */ custom.intena = INTF_AUD0 | INTF_AUD1 | INTF_AUD2 | INTF_AUD3; } /* * void initpointer (struct ccfb *fb); * * synopsis: * this routine initializes the mouse pointer part of the ccfb. * currently, it only needs to copy the initializer data to the * allocated chip ram. */ static inline void initpointer (fb) struct ccfb *fb; { SPRITEPTR *pointer = (SPRITEPTR *)fb->pointer; /* initialize pointer structure */ *pointer = pointerInit; } /* * void initcop (COPPERLIST *cop, COPPERLIST *othercop, int shf, * struct ccfb *fb); * * synopsis: * this function initializes one copperlist, treated as short- * frame list if SHF is TRUE. * it is assumed that initpointer has been called by the time * initcop() is called. * * This is REALLY basic stuff... even teenaged eurodemo coders * understand it :-) Normally, I'd have done this in assembly * as a bunch of dc.w statements... it is just translated into * struct form here... * * (yep, since this *is no* eurodemo here :-)) Hey, and we * even have symbolic names for registers too :-)) */ static void inline initcop (cop, othercop, shf, fb) COPPERLIST *cop, *othercop; int shf; struct ccfb *fb; { SPRITEPTR *pointer = (SPRITEPTR *)fb->pointer; unsigned long screen; unsigned long rowbytes = fb->fb_width >> 3; /* width of display, in bytes */ u_short *plptr; u_short c, i, strt, stop; /* get PA of display area */ screen = (unsigned long) fb->fb - (unsigned long) CHIPMEMADDR; fb->fb_planesize = fb->fb_height * rowbytes; /* account for possible interlaced half-frame */ if (shf) screen += rowbytes; /* account for oversized framebuffers */ screen += (fb->fb_x >> 3) + (fb->fb_y * rowbytes); #define MOVE COP_MOVE /* initialize bitplane pointers for all planes */ for (plptr = &cop->planes[0][0], i = 0; i < fb->fb_z; i++) { MOVE (plptr, bplpth(i), HIADDR (screen)); plptr += 2; MOVE (plptr, bplptl(i), LOADDR (screen)); plptr += 2; screen += fb->fb_planesize; } /* set the other bitplane pointers to 0, I hate this fixed size array.. */ while (i < 6) { MOVE (plptr, bplpth(i), 0); plptr += 2; MOVE (plptr, bplptl(i), 0); plptr += 2; i++; } c = 0x8000 /* HIRES */ | ((fb->fb_z & 7) << 12) /* bitplane use */ | 0x0200 /* composite COLOR enable (whatever this is..) */ | 0x0004; /* LACE */ MOVE (cop->bplcon0, bplcon0, c); MOVE (cop->bplcon1, bplcon1, 0); /* nothing */ /* modulo is one line for interlaced displays, plus difference between virtual and effective framebuffer size */ MOVE (cop->bpl1mod, bpl1mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3); MOVE (cop->bpl2mod, bpl2mod, (fb->fb_width + (fb->fb_width - fb->disp_width)) >> 3); /* these use pre-ECS register interpretation. Might want to go ECS ? */ strt = (((fb->disp_y >> 1) & 0xff)<<8) | ((fb->disp_x >> 1) & 0xff); MOVE (cop->diwstrt, diwstrt, strt); stop = (((((fb->disp_y + fb->disp_height + 1-shf)>>1) & 0xff)<<8) | (((fb->disp_x + fb->disp_width)>>1) & 0xff)); MOVE (cop->diwstop, diwstop, stop); /* NOTE: default values for strt: 0x2c81, stop: 0xf4c1 */ /* these are from from HW-manual.. */ strt = ((strt & 0xff) - 9) >> 1; MOVE (cop->ddfstrt, ddfstrt, strt); stop = strt + (((fb->disp_width >> 4) - 2) << 2); MOVE (cop->ddfstop, ddfstop, stop); /* sprites */ { /* some cleverness... footer[0] is a ZERO longword in chip */ u_short *spr = &cop->sprites[0]; u_short addr = CUSTOM_OFS(sprpt[0]); u_short i; for (i=0; i<8; i++) { /* for all sprites (8 of em) do */ *spr++ = addr; *spr++ = HIADDR(&pointer->footer[0]); addr += 2; *spr++ = addr; *spr++ = LOADDR(&pointer->footer[0]); addr += 2; } } cop->sprites[0*4+1] = HIADDR((caddr_t)pointer-CHIPMEMADDR); cop->sprites[0*4+3] = LOADDR((caddr_t)pointer-CHIPMEMADDR); /* colors */ for (i = 0; i < 32; i++) MOVE (cop->colors+i*2, color[i], fb->col[i]); /* setup interlaced display by constantly toggling between two copperlists */ MOVE (cop->copother, cop1lch, HIADDR ((unsigned long) othercop - (unsigned long) CHIPMEMADDR)); MOVE (cop->copother+2, cop1lcl, LOADDR ((unsigned long) othercop - (unsigned long) CHIPMEMADDR)); /* terminate copper list */ COP_END (cop->finish); } /* * Install a sprite. * The sprites to be loaded on the alternate frames * can be specified separately, * so interlaced sprites are possible. */ cc_install_sprite(gp, num, spr1, spr2) struct grf_softc *gp; int num; u_short *spr1, *spr2; { struct ccfb *fb = &ccfb; COPPERLIST *cop; cop = (COPPERLIST*)fb->cop1; cop->sprites[num*4+1] = HIADDR((caddr_t)spr1-CHIPMEMADDR); cop->sprites[num*4+3] = LOADDR((caddr_t)spr1-CHIPMEMADDR); cop = (COPPERLIST*)fb->cop2; cop->sprites[num*4+1] = HIADDR((caddr_t)spr2-CHIPMEMADDR); cop->sprites[num*4+3] = LOADDR((caddr_t)spr2-CHIPMEMADDR); } /* * Uninstall a sprite. */ cc_uninstall_sprite(gp, num) struct grf_softc *gp; int num; { struct ccfb *fb = &ccfb; SPRITEPTR *pointer = (SPRITEPTR*)fb->pointer; COPPERLIST *cop; /* some cleverness... footer[0] is a ZERO longword in chip */ cop = (COPPERLIST*)fb->cop1; cop->sprites[num*4+1] = HIADDR(&pointer->footer[0]); cop->sprites[num*4+3] = LOADDR(&pointer->footer[0]); cop = (COPPERLIST*)fb->cop2; cop->sprites[num*4+1] = HIADDR(&pointer->footer[0]); cop->sprites[num*4+3] = LOADDR(&pointer->footer[0]); } /* * Install a copper list extension. */ cc_install_cop_ext(gp, cl1, cl2) struct grf_softc *gp; u_short *cl1, *cl2; { struct ccfb *fb = &ccfb; COPPERLIST *cop; cop = (COPPERLIST*)fb->cop1; COP_MOVE (cop->finish+0, cop2lch, HIADDR((caddr_t)cl1-CHIPMEMADDR)); COP_MOVE (cop->finish+2, cop2lcl, LOADDR((caddr_t)cl1-CHIPMEMADDR)); COP_MOVE (cop->finish+4, copjmp2, 0); cop = (COPPERLIST*)fb->cop2; COP_MOVE (cop->finish+0, cop2lch, HIADDR((caddr_t)cl2-CHIPMEMADDR)); COP_MOVE (cop->finish+2, cop2lcl, LOADDR((caddr_t)cl2-CHIPMEMADDR)); COP_MOVE (cop->finish+4, copjmp2, 0); } /* * Uninstall a copper list extension. */ cc_uninstall_cop_ext(gp, cl1, cl2) struct grf_softc *gp; u_short *cl1, *cl2; { register struct ccfb *fb = &ccfb; COPPERLIST *cop; cop = (COPPERLIST*)fb->cop1; COP_END (cop->finish); cop = (COPPERLIST*)fb->cop2; COP_END (cop->finish); } /* * Call this function any time a key is hit to ensure screen blanker unblanks */ void cc_unblank () { if (!ccfb.screenBlank) { /* screenblank timer 0 means blank! */ COPPERLIST *c1 = (COPPERLIST *)ccfb.cop1, *c2 = (COPPERLIST *)ccfb.cop2; /* turn on sprite and raster DMA */ custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; ccfb.mouseBlank = ccfb.mouseTime; /* start mouseblank timer */ /* screen was black, reset background color to the one in ccfb! */ c1->colors[1] = c2->colors[1] = ccfb.col[0]; } /* restart the screenblank timer */ ccfb.screenBlank = ccfb.screenTime; } /* * void cc_bell(void); * * Synopsis: * trigger audible bell * Description * Call this function to start a beep tone. The beep lasts for * ccfb.beepTime 60ths of a second (can adjust it in the ccfb structure * in an ioctl(). The sample is playing in left+right aud0+aud1 hardware * channels all the time, just the volume is off when the beep isn't * heard. So here we just turn on the volume (ccfb.beepVolume, it can * also be set by ioctl() call) and set the timer (ccfb.beepTime can * be set by ioctl() as well). The cc_vbl() routine counts down the * timer and shuts off the volume when it reaches zero. */ void cc_bell () { custom.aud[0].vol = ccfb.beepVolume; custom.aud[1].vol = ccfb.beepVolume; ccfb.beepTimer = ccfb.beepTime; } /* * void cc_vbl(void); * * synopsis: * vertical blank service routine for the console. * provides the following: * samples mouse counters and positions mouse sprite * samples joystick inputs * counts down mouseblanker timer and blanks mouse if it is time * counts down screenblanker timer and blanks if it is time * counts down audio beep timer and shuts of the volume if the beep is done * unblanks mouse/screen if mouse is moved * not implemented yet: * it should adjust color palette in copper list over time to effect * display beep. * * There's black magic going on here with assembly-in-C.. Since this * is an interrupt handler, and it should be fast, ignore the obscure but * probably fast processing of the mouse for now... */ void cc_vbl () { u_short w0, w1; u_char *b0 = (u_char *)&w0, *b1 = (u_char *)&w1; SPRITEPTR *p = (SPRITEPTR *)ccfb.pointer; ccfb.lastMouseH = ccfb.mouseH; ccfb.lastMouseV = ccfb.mouseV; /* horizontal mouse counter */ w1 = custom.joy0dat; b0[1] = ccfb.mouseH; /* last counter val */ ccfb.mouseH = b1[1]; /* current is now last */ b1[1] -= b0[1]; /* current - last */ b1[0] = (b1[1] & 0x80) ? 0xff : 0x00; /* ext.w */ ccfb.mouseX += w1; if (ccfb.mouseX < 0) ccfb.mouseX = 0; if (ccfb.mouseX > ccfb.fb_width-1) ccfb.mouseX = ccfb.fb_width-1; /* vertical mouse counter */ w1 = custom.joy0dat; b1[1] = b1[0]; b0[1] = ccfb.mouseV; ccfb.mouseV = b1[1]; b1[1] -= b0[1]; b1[0] = (b1[1] & 0x80) ? 0xff : 0x00; /* ext.w */ ccfb.mouseY += w1; if (ccfb.mouseY < 0) ccfb.mouseY = 0; if (ccfb.mouseY > ccfb.fb_height-1) ccfb.mouseY = ccfb.fb_height-1; /* mouse buttons (should renumber them, middle button should be #2!) */ ccfb.mouseb1 = (ciaa.pra & (1<<6)) ? 0 : !0; ccfb.mouseb2 = (custom.pot1dat & (1<<2)) ? 0 : !0; ccfb.mouseb3 = (custom.pot1dat & (1<<0)) ? 0 : !0; /* position pointer sprite */ w0 = ccfb.mouseY >> 1; b0[1] += 0x24; p->header[0] = b0[1]; b0[1] += 16; p->header[2] = b0[1]; w0 = ccfb.mouseX >> 1; w0 += 120; if (w0 & 1) p->header[3] |= 1; else p->header[3] &= ~1; w0 >>= 1; p->header[1] = b0[1]; /* joystick #1 */ ccfb.joy0 = 0; w0 = custom.joy1dat; w1 = w0 >> 1; w1 ^= w0; if (w1 & (1<<9)) ccfb.joy0 |= JOYLEFT; if (w1 & (1<<1)) ccfb.joy0 |= JOYRIGHT; if (w1 & (1<<8)) ccfb.joy0 |= JOYUP; if (w1 & (1<<0)) ccfb.joy0 |= JOYDOWN; if ( (ciaa.pra & (1<<7)) == 0 ) ccfb.joy0 |= JOYBUTTON; /* joystick #2 (normally mouse port) */ ccfb.joy1 = 0; w0 = custom.joy0dat; w1 = w0 >> 1; w1 ^= w0; if (w1 & (1<<9)) ccfb.joy1 |= JOYLEFT; if (w1 & (1<<1)) ccfb.joy1 |= JOYRIGHT; if (w1 & (1<<8)) ccfb.joy1 |= JOYUP; if (w1 & (1<<0)) ccfb.joy1 |= JOYDOWN; if ( (ciaa.pra & (1<<6)) == 0 ) ccfb.joy1 |= JOYBUTTON; /* only do screenblanker/mouseblanker/display beep if screen is enabled */ if (ccfb.enableFlag) { /* handle screen blanker */ if (ccfb.screenBlank) { COPPERLIST *c1 = (COPPERLIST *)ccfb.cop1, *c2 = (COPPERLIST *)ccfb.cop2; ccfb.screenBlank--; if (!ccfb.screenBlank) { custom.dmacon = DMAF_RASTER | DMAF_SPRITE; c1->colors[1] = c2->colors[1] = 0; /* make screen BLACK */ } } /* handle mouse blanker */ if (ccfb.mouseBlank) { ccfb.mouseBlank--; if (!ccfb.mouseBlank) custom.dmacon = DMAF_SPRITE; } else if (ccfb.lastMouseH != ccfb.mouseH || ccfb.lastMouseV != ccfb.mouseV) { cc_unblank(); ccfb.mouseBlank = ccfb.mouseTime; custom.dmacon = DMAF_SETCLR | DMAF_SPRITE; } /* handle visual beep (not implemented yet) */ } /* handle audible beep */ if (ccfb.beepTimer) ccfb.beepTimer--; if (!ccfb.beepTimer) custom.aud[0].vol = custom.aud[1].vol = 0; } /* useful function for debugging.. */ int amiga_mouse_button (num) int num; { switch (num) { case 1: return ccfb.mouseb1; case 2: return ccfb.mouseb2; case 3: return ccfb.mouseb3; default: return 0; } } /* Initialize hardware. * Must point g_display at a grfinfo structure describing the hardware. * Returns 0 if hardware not present, non-zero ow. */ cc_init(gp, ad) struct grf_softc *gp; struct amiga_device *ad; { register struct ccfb *fb = &ccfb; struct grfinfo *gi = &gp->g_display; u_char *fbp, save; int fboff, fbsize; int s; /* if already initialized, fail */ if (fb->fb) return 0; /* disable dma */ custom.dmacon = DMAF_BLTDONE | DMAF_BLTNZERO | DMAF_BLITHOG | DMAF_BLITTER | DMAF_DISK | DMAF_AUD3 | DMAF_AUD2 | DMAF_AUD1 | DMAF_AUD0; fb->mouseBlank = fb->mouseTime; fb->screenBlank = fb->screenTime; /* testing for the result is really redundant because chipmem_steal panics if it runs out of memory.. */ fbsize = (fb->fb_width >> 3) * fb->fb_height * fb->fb_z; if (! (fb->fb = (u_char *) chipmem_steal (fbsize)) || !(fb->cop1 = (u_short *) chipmem_steal (sizeof(COPPERLIST))) || !(fb->cop2 = (u_short *) chipmem_steal (sizeof(COPPERLIST))) || !(fb->pointer = (u_short *)chipmem_steal (sizeof(SPRITEPTR))) ) return 0; /* clear the display. bzero only likes regions up to 64k, so call multiple times */ for (fboff = 0; fboff < fbsize; fboff += 64*1024) bzero (fb->fb + fboff, fbsize - fboff > 64*1024 ? 64*1024 : fbsize - fboff); /* init the audio beep */ initbeep(fb); /* initialize the sprite pointer */ initpointer(fb); /* initialize the copper lists */ initcop (fb->cop1, fb->cop2, 0, fb); initcop (fb->cop2, fb->cop1, 1, fb); /* start the new display */ /* ok, this is a bit rough.. */ /* mtk: not any more! :-) */ /* mykes: phew, thanks :-) */ s = splhigh (); /* install dummy, to get display going (for vposr to count.. ) */ custom.cop1lc = (void *) ((unsigned long)fb->cop1 - (unsigned long) CHIPMEMADDR); custom.copjmp1 = 0; /* enable DMA (so the copperlists are executed and eventually cause a switch to an interlaced display on system not already booting that way. THANKS HAMISH for finding this bug!!) */ custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE | DMAF_AUD0 | DMAF_AUD1; /* this is real simple: wait for LOF bit of vposr to go high - then start the copper list! :-) */ while (custom.vposr & 0x8000); while (!(custom.vposr & 0x8000)); custom.cop1lc = (void *) ((unsigned long)fb->cop1 - (unsigned long) CHIPMEMADDR); custom.copjmp1 = 0; custom.intreq = INTF_VERTB; splx (s); #if 0 /* tame the blitter. Copying one word onto itself should put it into a consistent state. This is black magic... */ custom.bltapt = custom.bltbpt = custom.bltcpt = custom.bltdpt = 0; custom.bltamod = custom.bltbmod = custom.bltcmod = custom.bltdmod = 0; custom.bltafwm = custom.bltalwn = 0xffff; custom.bltcon0 = 0x09f0; custom.bltcon1 = 0; custom.bltsize = 1; #endif /* enable VBR interrupts. This is also done in the serial driver, but it really belongs here.. */ custom.intena = INTF_SETCLR | INTF_VERTB; /* under amigaos, INTF_INTEN is needed */ #if 0 #ifdef DEBUG /* prove the display is up.. */ for (fboff = 0; fboff < fbsize; fboff++) { fb->fb[fboff] = 0xff; DELAY(10); } for (fboff = 0; fboff < fbsize; fboff++) { fb->fb[fboff] = 0; DELAY(10); } #endif #endif gp->g_data = (caddr_t) fb; gi->gd_regaddr = 0xdff000; gi->gd_regsize = sizeof (custom); gi->gd_fbaddr = fb->fb - (u_char *) CHIPMEMADDR; #if 0 /* mykes kludges here to make gi look like 1 bitplane */ gi->gd_fbsize = fbsize/2; #else /* don't see why we should kludge here.. we have disp_z to indicate the real depth of the display */ gi->gd_fbsize = fbsize; #endif gi->gd_colors = 1 << fb->disp_z; gi->gd_planes = fb->disp_z; gi->gd_fbwidth = fb->fb_width; gi->gd_fbheight = fb->fb_height; gi->gd_fbx = fb->fb_x; gi->gd_fby = fb->fb_y; gi->gd_dwidth = fb->disp_width; gi->gd_dheight = fb->disp_height; gi->gd_dx = fb->disp_x; gi->gd_dy = fb->disp_y; gp->g_regkva = 0; /* builtin */ gp->g_fbkva = fb->fb; fb->enableFlag = !0; return(1); } cc_config(gp, di) register struct grf_softc *gp; struct grfdyninfo *di; { register struct ccfb *fb = &ccfb; struct grfinfo *gi = &gp->g_display; u_char *fbp, save; int fboff, fbsize; int s; /* bottom missing... */ } /* * Change the mode of the display. * Right now all we can do is grfon/grfoff. * Return a UNIX error number or 0 for success. */ cc_mode(gp, cmd, arg) register struct grf_softc *gp; int cmd; void *arg; { switch (cmd) { case GM_GRFON: ccfb.enableFlag = !0; ccfb.screenBlank = ccfb.screenTime; ccfb.mouseBlank = ccfb.mouseTime; custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE; return 0; case GM_GRFOFF: ccfb.enableFlag = 0; custom.dmacon = DMAF_RASTER | DMAF_COPPER | DMAF_SPRITE; return 0; case GM_GRFCONFIG: return cc_config (gp, (struct grfdyninfo *) arg); default: break; } return EINVAL; } #endif