#ifndef lint static char sccsid[] = "@(#)cgtwo.c 1.1 92/07/30 SMI"; #endif /* * Copyright 1986, 1987 by Sun Microsystems, Inc. */ /* * Sun-2/Sun-3 color board driver */ #include "cgtwo.h" #include "win.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef sun3x #include #endif sun3x #include #include #include #include #include #include /* mapped (probed) and total size of board */ #define CG2_PROBESIZE CG2_MAPPED_SIZE #define CG2_TOTAL_SIZE (CG2_MAPPED_OFFSET + CG2_MAPPED_SIZE) /* Mainbus device data */ int cgtwoprobe(), cgtwoattach(); struct mb_device *cgtwoinfo[NCGTWO]; struct mb_driver cgtwodriver = { cgtwoprobe, 0, cgtwoattach, 0, 0, 0, CG2_PROBESIZE, "cgtwo", cgtwoinfo, 0, 0, 0, 0 }; /* driver per-unit data */ struct cg2_softc { int flags; /* misc. flags; bits defined in cg2var.h */ /* (struct cg2pr, flags member) */ struct cg2fb *fb; /* virtual address */ int w, h; /* resolution */ #if NWIN > 0 Pixrect pr; /* kernel pixrect and private data */ struct cg2pr prd; #endif NWIN > 0 } cg2_softc[NCGTWO]; /* default structure for FBIOGATTR/FBIOGTYPE ioctls */ static struct fbgattr fbgattr_default = { /* real_type owner */ FBTYPE_SUN2COLOR, 0, /* fbtype: type h w depth cms size */ { FBTYPE_SUN2COLOR, 0, 0, 8, 256, CG2_TOTAL_SIZE }, /* fbsattr: flags emu_type */ { FB_ATTR_DEVSPECIFIC, -1, /* dev_specific: FLAGS, BUFFERS, PRFLAGS */ { FB_ATTR_CG2_FLAGS_PRFLAGS, 1, 0 } }, /* emu_types */ { -1, -1, -1, -1} }; /* double buffering enable flag */ int cg2_dblbuf_enable = 1; #if NWIN > 0 /* SunWindows specific stuff */ /* kernel pixrect ops vector */ struct pixrectops cg2_ops = { cg2_rop, cg2_putcolormap, cg2_putattributes, # ifdef _PR_IOCTL_KERNEL_DEFINED 0 # endif }; /* need gp1_sync stub if no GPs configured */ #include "gpone.h" #if NGPONE == 0 gp1_sync() { return -1; } #endif NGPONE == 0 #endif NWIN > 0 cgtwoprobe(reg, unit) caddr_t reg; int unit; { register struct cg2fb *fb = (struct cg2fb *) reg; register struct cg2_softc *softc; /* * Config address is base address of board, so we actually * have the plane mode memory (and a little bit of pixel mode) * mapped at this point. Re-map 2M higher to get the rasterop * mode memory and control registers mapped. */ fbmapin((caddr_t) fb, fbgetpage((caddr_t) fb) + (int) btop(CG2_MAPPED_OFFSET), CG2_MAPPED_SIZE); if (probeit(fb)) return 0; softc = &cg2_softc[unit]; softc->fb = fb; softc->flags = 0; /* check for supported resolution */ switch (fb->status.reg.resolution) { case CG2_SCR_1152X900: softc->w = 1152; softc->h = 900; softc->flags = CG2D_STDRES; break; case CG2_SCR_1024X1024: softc->w = 1024; softc->h = 1024; break; default: printf("%s%d: unsupported resolution (%d)\n", cgtwodriver.mdr_cname, unit, fb->status.reg.resolution); return 0; } return CG2_PROBESIZE; } static probeit(fb) register struct cg2fb *fb; { union { struct cg2statusreg reg; short word; } status; #define allrop(fb, reg) ((short *) &(fb)->ropcontrol[CG2_ALLROP].ropregs.reg) #define pixel0(fb) ((char *) &fb->ropio.roppixel.pixel[0][0]) /* * Probe sequence: * * set board for pixel mode access * enable all planes * set rasterop function to CG_SRC * disable end masks * set fifo shift/direction to zero/left-to-right * write 0xa5 to pixel at (0,0) * check pixel value * enable subset of planes (0xcc) * set rasterop function to ~CG_DEST * write to pixel at (0,0) again * enable all planes again * read pixel value; should be 0xa5 ^ 0xcc = 0x69 */ status.word = peek(&fb->status.word); status.reg.ropmode = SWWPIX; if (poke(&fb->status.word, status.word) || poke((short *) &fb->ppmask.reg, 255) || poke(allrop(fb, mrc_op), CG_SRC) || poke(allrop(fb, mrc_mask1), 0) || poke(allrop(fb, mrc_mask2), 0) || poke(allrop(fb, mrc_shift), 1 << 8) || pokec(pixel0(fb), 0xa5) || pokec(pixel0(fb), 0) || peekc(pixel0(fb)) != 0xa5 || poke((short *) &fb->ppmask.reg, 0xcc) || poke(allrop(fb, mrc_op), ~CG_DEST) || pokec(pixel0(fb), 0) || poke((short *) &fb->ppmask.reg, 255) || peekc(pixel0(fb)) != (0xa5 ^ 0xcc)) return 1; return 0; #undef allrop #undef pixel0 } cgtwoattach(md) struct mb_device *md; { register struct cg2_softc *softc = &cg2_softc[md->md_unit]; register struct cg2fb *fb = softc->fb; register int flags = softc->flags; #define dummy flags /* set interrupt vector */ if (md->md_intr) fb->intrptvec.reg = md->md_intr->v_vec; else printf( "WARNING: no interrupt vector specified in config file\n"); /* * Determine whether this is a Sun-2 or Sun-3 color board * by setting the wait bit in the double buffering register * and seeing if it clears itself during retrace. * * On the Sun-2 color board this just writes a bit in the * "wordpan" register. */ fb->misc.nozoom.dblbuf.word = 0; fb->misc.nozoom.dblbuf.reg.wait = 1; /* wait for leading edge, then trailing edge of retrace */ while (fb->status.reg.retrace) /* nothing */ ; while (!fb->status.reg.retrace) /* nothing */ ; while (fb->status.reg.retrace) /* nothing */ ; if (fb->misc.nozoom.dblbuf.reg.wait) { /* Sun-2 color board */ fb->misc.nozoom.dblbuf.reg.wait = 0; flags |= CG2D_ZOOM; } else { /* Sun-3 color board (or better) */ flags |= CG2D_32BIT | CG2D_NOZOOM; if (fb->status.reg.fastread) flags |= CG2D_FASTREAD; if (fb->status.reg.id) flags |= CG2D_ID | CG2D_ROPMODE; /* * Probe for double buffering feature. * Write distinctive values to one pixel in both buffers, * then two pixels in buffer B only. * Read from buffer B and see what we get. * * Warning: assumes we were called right after cgtwoprobe. */ cg2_setfunction(fb, CG2_ALLROP, CG_SRC); fb->ropio.roppixel.pixel[0][0] = 0x5a; fb->ropio.roppixel.pixel[0][0] = 0xa5; fb->misc.nozoom.dblbuf.reg.nowrite_a = 1; fb->ropio.roppixel.pixel[0][0] = 0xc3; fb->ropio.roppixel.pixel[0][4] = dummy; if (fb->ropio.roppixel.pixel[0][0] == 0x5a) { fb->misc.nozoom.dblbuf.reg.read_b = 1; if (fb->ropio.roppixel.pixel[0][0] == 0xa5 && fb->ropio.roppixel.pixel[0][4] == 0xc3 && cg2_dblbuf_enable) flags |= CG2D_DBLBUF; } fb->misc.nozoom.dblbuf.word = 0; } softc->flags = flags; #ifndef sun2 /* re-map into correct VME space if necessary */ { int page = fbgetpage((caddr_t) fb); #ifndef sun3x if (((flags & CG2D_32BIT) != 0) != ((page & PGT_MASK) == PGT_VME_D32)) fbmapin((caddr_t) fb, page ^ (PGT_VME_D16 ^ PGT_VME_D32), CG2_MAPPED_SIZE); #endif !sun3x #ifdef sun3x if (page < mmu_btop(VME24D32_BASE) && ((flags & CG2D_32BIT) != 0)) fbmapin((caddr_t)fb, (int) (page - mmu_btop(VME24D16_BASE) + mmu_btop(VME24D32_BASE)), CG2_MAPPED_SIZE); else if (page >= mmu_btop(VME24D32_BASE) && ((flags & CG2D_32BIT) == 0)) fbmapin((caddr_t)fb, (int) (page - mmu_btop(VME24D32_BASE) + mmu_btop(VME24D16_BASE)), CG2_MAPPED_SIZE); #endif sun3x } #endif !sun2 /* print informative message */ printf("%s%d: Sun-%c color board%s%s\n", md->md_driver->mdr_dname, md->md_unit, flags & CG2D_ZOOM ? '2' : '3', flags & CG2D_DBLBUF ? ", double buffered" : "", flags & CG2D_FASTREAD ? ", fast read" : ""); } cgtwoopen(dev, flag) dev_t dev; int flag; { return fbopen(dev, flag, NCGTWO, cgtwoinfo); } /*ARGSUSED*/ cgtwoclose(dev, flag) dev_t dev; { register struct cg2_softc *softc = &cg2_softc[minor(dev)]; register struct cg2fb *fb = softc->fb; /* fix up zoom and/or double buffering on close */ if (softc->flags & CG2D_ZOOM) { fb->misc.zoom.wordpan.reg = 0; /* hi pixel adr = 0 */ fb->misc.zoom.zoom.word = 0; /* zoom=0, yoff=0 */ fb->misc.zoom.pixpan.word = 0; /* pix adr=0, xoff=0 */ fb->misc.zoom.varzoom.reg = 255; /* unzoom at line 4*255 */ } if (softc->flags & CG2D_NOZOOM) fb->misc.nozoom.dblbuf.word = 0; return 0; } /*ARGSUSED*/ cgtwommap(dev, off, prot) dev_t dev; off_t off; int prot; { if ((u_int) off >= CG2_TOTAL_SIZE) return -1; return fbgetpage((caddr_t) cg2_softc[minor(dev)].fb) + btop(off) - btop(CG2_MAPPED_OFFSET); } /*ARGSUSED*/ cgtwoioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag; { register struct cg2_softc *softc = &cg2_softc[minor(dev)]; switch (cmd) { case FBIOGTYPE: { register struct fbtype *fbtype = (struct fbtype *) data; *fbtype = fbgattr_default.fbtype; fbtype->fb_height = softc->h; fbtype->fb_width = softc->w; } break; case FBIOGATTR: { register struct fbgattr *gattr = (struct fbgattr *) data; *gattr = fbgattr_default; gattr->fbtype.fb_height = softc->h; gattr->fbtype.fb_width = softc->w; if (softc->flags & CG2D_NOZOOM) gattr->sattr.dev_specific[FB_ATTR_CG2_FLAGS] |= FB_ATTR_CG2_FLAGS_SUN3; if (softc->flags & CG2D_DBLBUF) gattr->sattr.dev_specific[FB_ATTR_CG2_BUFFERS] = 2; gattr->sattr.dev_specific[FB_ATTR_CG2_PRFLAGS] = softc->flags; } break; case FBIOSATTR: break; #if NWIN > 0 case FBIOGPIXRECT: ((struct fbpixrect *) data)->fbpr_pixrect = &softc->pr; /* initialize pixrect */ softc->pr.pr_ops = &cg2_ops; softc->pr.pr_size.x = softc->w; softc->pr.pr_size.y = softc->h; softc->pr.pr_depth = CG2_DEPTH; softc->pr.pr_data = (caddr_t) &softc->prd; /* initialize private data */ bzero((char *) &softc->prd, sizeof softc->prd); softc->prd.cgpr_va = softc->fb; softc->prd.cgpr_fd = 0; softc->prd.cgpr_planes = 255; softc->prd.ioctl_fd = minor(dev); softc->prd.flags = softc->flags; softc->prd.linebytes = softc->w; /* enable video */ softc->fb->status.reg.video_enab = 1; break; #endif NWIN > 0 /* get info for GP */ case FBIOGINFO: { register struct fbinfo *fbinfo = (struct fbinfo *) data; fbinfo->fb_physaddr = (fbgetpage((caddr_t) softc->fb) << PGSHIFT) - CG2_MAPPED_OFFSET & 0xffffff; fbinfo->fb_hwwidth = softc->w; fbinfo->fb_hwheight = softc->h; fbinfo->fb_ropaddr = (u_char *) softc->fb; } break; /* set video flags */ case FBIOSVIDEO: softc->fb->status.reg.video_enab = (* (int *) data) & FBVIDEO_ON ? 1 : 0; break; /* get video flags */ case FBIOGVIDEO: * (int *) data = softc->fb->status.reg.video_enab ? FBVIDEO_ON : FBVIDEO_OFF; break; case FBIOVERTICAL: cgtwo_wait(minor(dev)); break; default: return ENOTTY; } return 0; } /* * This oneshot timeout is needed to ensure that requested vertical * retrace interrupts are serviced. It works around a problem exhibited * by pixrects on sparc platforms: pixrects code performs exclusive-or * operations on the ropmode bits in the status register. On the sparc, * the exclusive-or requires three instructions, ie it is nonatomic, and * can/does get interrupted in the middle of the 3-instruction sequence. */ static cgtwotimeout(unit) int unit; { register struct cg2_softc *softc = &cg2_softc[unit & 255]; register struct mb_device *md = cgtwoinfo[unit & 255]; int s; s = splx(pritospl(md->md_intpri)); softc->fb->status.reg.inten = 1; timeout(cgtwotimeout, (caddr_t) (unit & 255), hz); (void) splx(s); } /* wait for vertical retrace interrupt */ cgtwo_wait(unit) int unit; { register struct mb_device *md = cgtwoinfo[unit & 255]; register struct cg2_softc *softc = &cg2_softc[unit & 255]; int s; if (md->md_intr == 0) return; s = splx(pritospl(md->md_intpri)); softc->fb->status.reg.inten = 1; /* see comments on cgtwotimeout() */ timeout(cgtwotimeout, (caddr_t) (unit & 255), hz); (void) sleep((caddr_t) softc, PZERO - 1); (void) splx(s); } /* vertical retrace interrupt service routine */ cgtwointr(unit) int unit; { register struct cg2_softc *softc = &cg2_softc[unit]; untimeout(cgtwotimeout, (caddr_t) unit); softc->fb->status.reg.inten = 0; wakeup((caddr_t) softc); #ifdef lint cgtwointr(unit); #endif }