#if !defined(lint) && !defined(NOID) static char sccsid[] = "@(#)bwtwo.c 1.1 94/10/31 SMI"; #endif /* * Copyright 1988-1989, Sun Microsystems, Inc. */ /* * Sbus monochrome memory frame buffer driver */ #include "win.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include addr_t kmem_zalloc(); addr_t map_regs(); void report_dev(); /* configuration options */ #ifndef OLDDEVSW #define OLDDEVSW 1 #endif OLDDEVSW #ifndef NOHWINIT #define NOHWINIT 1 #endif NOHWINIT #ifndef BW2DEBUG #define BW2DEBUG 0 #endif BW2DEBUG #if NOHWINIT int bw2_hwinit = 1; int bw2_type = 1; int bw2_on = 1; /* must be 1 to enable bw2 */ #endif NOHWINIT #if BW2DEBUG int bw2_debug = 0; #define DEBUGF(level, args) _STMT(if (bw2_debug >= (level)) printf args; ) #else BW2DEBUG #define DEBUGF(level, args) /* nothing */ #endif BW2DEBUG #if OLDDEVSW #define STATIC /* nothing */ #define bw2_open bwtwoopen #define bw2_close bwtwoclose #define bw2_mmap bwtwommap #define bw2_ioctl bwtwoioctl #else OLDDEVSW #define STATIC static #endif OLDDEVSW /* config info */ static int bw2_identify(); static int bw2_attach(); STATIC int bw2_open(); STATIC int bw2_close(); STATIC int bw2_ioctl(); STATIC int bw2_mmap(); struct dev_ops bwtwo_ops = { 0, /* revision */ bw2_identify, bw2_attach, bw2_open, bw2_close, 0, 0, 0, 0, 0, bw2_ioctl, 0, bw2_mmap, }; /* per-unit data */ struct bw2_softc { struct mfb_reg *reg; /* video chip registers */ #if NWIN > 0 Pixrect pr; /* kernel pixrect */ struct mpr_data prd; /* pixrect private data */ #define _w pr.pr_size.x #define _h pr.pr_size.y #define _fb prd.md_image #define _linebytes prd.md_linebytes #else NWIN > 0 int _w, _h; /* resolution */ #endif NWIN > 0 int size; /* total size of frame buffer */ int basepage; /* page # for base address */ }; static int nbw2; static struct bw2_softc *bw2_softc; /* * handy macros */ #define getsoftc(unit) (&bw2_softc[unit]) static bw2_identify(name) char *name; { DEBUGF(1, ("bw2_identify(%s)\n", name)); #if NOHWINIT if (!bw2_on) return (0); #endif NOHWINIT if (strcmp(name, "bwtwo") == 0) return (++nbw2); else return (0); } static bw2_attach(devi) struct dev_info *devi; { register struct bw2_softc *softc; register addr_t reg; int nodeid, bytes, basepage; static int unit; extern struct dev_info *top_devinfo; /* in autoconf.c */ DEBUGF(1, ("bw2_attach nbw2=%d unit=%d\n", nbw2, unit)); /* Allocate softc structs on first attach */ if (!bw2_softc) bw2_softc = (struct bw2_softc *) kmem_zalloc((u_int) sizeof (struct bw2_softc) * nbw2); softc = getsoftc(unit); /* Grab properties from PROM */ nodeid = devi->devi_nodeid; softc->_w = getprop(nodeid, "width", 1152); softc->_h = getprop(nodeid, "height", 900); #if NOHWINIT /* if properties are missing initialize the hardware */ if (getproplen(nodeid, "width") != sizeof (int)) { if (!bw2_probe(devi, softc)) return (-1); } #endif NOHWINIT bytes = getprop(nodeid, "linebytes", mpr_linebytes(softc->_w, 1)); #if NWIN > 0 softc->_linebytes = bytes; #endif NWIN > 0 /* Compute size of frame buffer */ softc->size = bytes = ptob(btopr(bytes * softc->_h)); #if NWIN > 0 /* only use address property if we are console fb */ if (reg = (addr_t) getprop(nodeid, "address", 0)) { int fbid = getprop(top_devinfo->devi_nodeid, "fb", -1); if (fbid == nodeid) { softc->_fb = (MPR_T *) reg; bytes = 0; DEBUGF(2, ("bw2 mapped by PROM\n")); } } #else NWIN > 0 bytes = 0; #endif NWIN > 0 /* * Allocate virtual space for registers and maybe frame buffer. * Map registers. */ if (!(reg = map_regs(devi->devi_reg[0].reg_addr + MFB_OFF_REG, (u_int) bytes + NBPG, devi->devi_reg[0].reg_bustype))) return (-1); softc->reg = (struct mfb_reg *) reg; /* save base page # for registers */ softc->basepage = basepage = fbgetpage(reg); DEBUGF(1, ("bw2_attach reg=0x%x/0x%x (0x%x)\n", (u_int) reg, basepage << PGSHIFT, basepage)); #if NWIN > 0 /* map frame buffer if necessary */ if (bytes) { fbmapin(reg + NBPG, (int) (basepage + btop(MFB_OFF_FB - MFB_OFF_REG)), bytes); softc->_fb = (MPR_T *) (reg + NBPG); } DEBUGF(1, ("bw2_attach fb=0x%x/0x%x (0x%x)\n", (u_int) softc->_fb, fbgetpage((addr_t) softc->_fb) << PGSHIFT, fbgetpage((addr_t) softc->_fb))); #endif NWIN > 0 /* save unit number */ devi->devi_unit = unit; /* save back pointer to softc */ devi->devi_data = (addr_t) softc; /* prepare for next attach */ unit++; report_dev(devi); return (0); } STATIC bw2_open(dev, flag) dev_t dev; int flag; { DEBUGF(2, ("bw2_open(%d)\n", minor(dev))); return (fbopen(dev, flag, nbw2)); } /*ARGSUSED*/ STATIC bw2_close(dev, flag) dev_t dev; int flag; { DEBUGF(2, ("bw2_close(%d)\n", minor(dev))); /* disable cursor compare */ getsoftc(minor(dev))->reg->control &= ~MFB_CR_CURSOR; return (0); } /*ARGSUSED*/ STATIC bw2_mmap(dev, off, prot) dev_t dev; register off_t off; int prot; { register struct bw2_softc *softc = getsoftc(minor(dev)); DEBUGF(off ? 9 : 1, ("bw2_mmap(%d, 0x%x)\n", minor(dev), (u_int) off)); if (off == MFB_REG_MMAP_OFFSET && suser()) off = 0; else if ((u_int) off < softc->size) off += MFB_OFF_FB - MFB_OFF_REG; else return (-1); DEBUGF(off != MFB_OFF_FB - MFB_OFF_REG ? 9 : 1, ("bw2_mmap returning 0x%x (0x%x)\n", ptob(softc->basepage) + off, softc->basepage + btop(off))); return (softc->basepage + btop(off)); } /*ARGSUSED*/ STATIC bw2_ioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag; { register struct bw2_softc *softc = getsoftc(minor(dev)); DEBUGF(2, ("bw2_ioctl(%d, 0x%x)\n", minor(dev), cmd)); switch (cmd) { case FBIOGTYPE: { register struct fbtype *fb = (struct fbtype *) data; DEBUGF(2, ("FBIOGTYPE\n")); fb->fb_type = FBTYPE_SUN2BW; fb->fb_height = softc->_h; fb->fb_width = softc->_w; fb->fb_depth = 1; fb->fb_cmsize = 2; fb->fb_size = softc->size; } break; #if NWIN > 0 case FBIOGPIXRECT: ((struct fbpixrect *) data)->fbpr_pixrect = &softc->pr; DEBUGF(2, ("FBIOGPIXRECT\n")); /* initialize pixrect and private data */ softc->pr.pr_ops = &mem_ops; /* pr_size set in attach */ softc->pr.pr_depth = 1; softc->pr.pr_data = (caddr_t) &softc->prd; /* md_linebytes, md_image set in attach */ /* md_offset already zero */ softc->prd.md_primary = minor(dev); softc->prd.md_flags = MP_DISPLAY; /* enable video */ mfb_set_video(softc->reg, _ONE_); break; #endif NWIN > 0 case FBIOSVIDEO: DEBUGF(2, ("FBIOSVIDEO\n")); mfb_set_video(softc->reg, * (int *) data & FBVIDEO_ON); break; case FBIOGVIDEO: DEBUGF(2, ("FBIOGVIDEO\n")); * (int *) data = mfb_get_video(softc->reg) ? FBVIDEO_ON : FBVIDEO_OFF; break; default: return (ENOTTY); } return (0); } #if NOHWINIT static int bw2_probe(devi, softc) struct dev_info *devi; struct bw2_softc *softc; { struct mfb_reg *mfb; int stat, monitor_type, retval = 0; void unmap_regs(); if (!(mfb = (struct mfb_reg *) map_regs(devi->devi_reg[0].reg_addr + MFB_OFF_REG, (u_int) NBPG, devi->devi_reg[0].reg_bustype))) goto bad; if ((stat = peekc((char *)&mfb->status)) == -1) goto bad; /* New sense codes only for BW2 FB 501-1561 (prom 1.5) */ #define MFB_SR_1152_900_76HZ_A 0x40 /* 76Hz monitor sense codes */ #define MFB_SR_1152_900_76HZ_B 0x60 #define MFB_SR_ID_MSYNC 0x04 /* SR id of 501-1561 BW2 */ monitor_type = stat & MFB_SR_RES_MASK; switch (stat & MFB_SR_ID_MASK) { case MFB_SR_ID_MONO_ECL: if (monitor_type == MFB_SR_1600_1280) bw2_type = 0; else bw2_type = 1; break; case MFB_SR_ID_MONO: bw2_type = 2; break; case MFB_SR_ID_MSYNC: if ((monitor_type == MFB_SR_1152_900_76HZ_A) || (monitor_type == MFB_SR_1152_900_76HZ_B)) bw2_type = 4; else bw2_type = 3; break; default: DEBUGF(1, ("bw2_hwinit bad type SR=0x%x\n", (u_int) stat)); goto bad; } if (bw2_type == 0) { softc->_w = 1600; softc->_h = 1280; } if (bw2_hwinit) bw2_init(mfb); DEBUGF(1, ("bw2_hwinit type=%d (%d,%d)\n", bw2_type, softc->_w, softc->_h)); retval = 1; bad: if (!retval) { DEBUGF(2, ("bw2_probe failed\n")); } unmap_regs((addr_t) mfb, (u_int) NBPG); return (retval); } /* high-res ECL */ char bw2_mfbval0[] = { 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13, 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e, 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01, 0x10, 0x21, 0 }; /* low-res ECL */ char bw2_mfbval1[] = { 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c, 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, /* increase for > 900 lines */ 0x1b, 0x23, 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01, 0x10, 0x20, 0 }; /* low-res analog */ char bw2_mfbval2[] = { 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13, 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22, 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, 0x10, 0x20, 0 }; /* BW2 FB 501-1561 (prom 1.5) 66 Hz */ char bw2_mfbval3[] = { 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14, 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24, 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, 0x10, 0x20, 0 }; /* BW2 FB 501-1561 (prom 1.5) 76 Hz */ char bw2_mfbval4[] = { 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f, 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a, 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01, 0x10, 0x24, 0 }; static char *mfbvals[] = { bw2_mfbval0, bw2_mfbval1, bw2_mfbval2, bw2_mfbval3, bw2_mfbval4, }; static bw2_init(mfb) struct mfb_reg *mfb; { register char *p; /* initialize video chip */ for (p = mfbvals[bw2_type]; *p; p += 2) ((char *) mfb)[p[0]] = p[1]; } #endif NOHWINIT