Files
Arquivotheca.SunOS-4.1.4/sys/sundev/bwtwo.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

591 lines
12 KiB
C

#ifndef lint
static char sccsid[] = "@(#)bwtwo.c 1.1 94/10/31 SMI";
#endif
/*
* Copyright 1986, 1987 by Sun Microsystems, Inc.
*/
/*
* Sun Two Black & White Board(s) Driver
*/
#include "bwtwo.h"
#if NBWTWO > 0
#include "win.h"
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/map.h>
#include <sys/vmmac.h>
#include <sun/fbio.h>
#include <machine/pte.h>
#include <machine/mmu.h>
#include <machine/cpu.h>
#include <sundev/mbvar.h>
#include <pixrect/pixrect.h>
#include <pixrect/memvar.h>
#include <sundev/bw2reg.h>
#include <pixrect/bw2var.h>
#ifndef sun2
#include <machine/eeprom.h>
#include <machine/enable.h>
#include <sundev/p4reg.h>
#ifdef sun3x
extern u_short enablereg;
#else
extern u_char enablereg;
#endif sun3x
#endif !sun2
/* macros */
#ifdef sun2
#define BW2_PROBESIZE (BW2_FBSIZE + sizeof (struct bw2cr))
#else
#define BW2_PROBESIZE (BW2_FBSIZE_HIRES + NBPG)
#endif
/*
* Driver information for auto-configuration stuff.
*/
int bwtwoprobe(), bwtwoattach(), bwtwointr();
extern struct mb_device *bwtwoinfo[];
struct mb_driver bwtwodriver = {
bwtwoprobe, 0, bwtwoattach, 0, 0, bwtwointr,
BW2_PROBESIZE, "bwtwo", bwtwoinfo, 0, 0, 0,
};
#if NWIN > 0
/* SunWindows specific stuff */
struct pixrectops bw2_ops = {
mem_rop,
mem_putcolormap,
mem_putattributes,
# ifdef _PR_IOCTL_KERNEL_DEFINED
0
# endif
};
#endif NWIN > 0
extern struct bw2_softc bw2_softc[];
bwtwoopen(dev, flag)
dev_t dev;
int flag;
{
extern int nbwtwo;
return fbopen(dev, flag, nbwtwo, bwtwoinfo);
}
/*ARGSUSED*/
bwtwoclose(dev, flag)
dev_t dev;
int flag;
{
return 0;
}
/*ARGSUSED*/
bwtwommap(dev, off, prot)
dev_t dev;
off_t off;
int prot;
{
register struct bw2_softc *softc = &bw2_softc[minor(dev)];
if (off >= (off_t) softc->size)
return -1;
return fbgetpage(softc->image + off);
}
/*
* Determine if a bwtwo exists at the given address.
* If it exists, determine its size.
*/
/*ARGSUSED*/
bwtwoprobe(reg, unit)
caddr_t reg;
int unit;
{
register struct bw2_softc *softc = &bw2_softc[unit];
struct size_tab {
#ifndef sun2
char sizecode;
#endif !sun2
int w, h;
int size;
};
#ifdef lint
#define SIZE_TAB_ENT(w,h) { 0 }
#else lint
#ifdef sun2
#define SIZE_TAB_ENT(w,h) \
{ w, h, mpr_linebytes(w, 1) * h }
#else sun2
#define SIZE_TAB_ENT(w,h) \
{ EED_SCR_/**/w/**/X/**/h, w, h, mpr_linebytes(w, 1) * h }
#endif sun2
#endif lint
/* first table entry is default size */
static struct size_tab size_tab[] = {
SIZE_TAB_ENT(1152,900),
SIZE_TAB_ENT(1024,1024),
#ifndef sun2
SIZE_TAB_ENT(1600,1280),
SIZE_TAB_ENT(1440,1440)
#endif !sun2
};
#undef SIZE_TAB_ENT
register struct size_tab *sizep = size_tab;
if (softc->image || peek((short *) reg) == -1)
return 0;
#ifndef sun2
{
/*
* Determine resolution:
*
* 1. If this is a P4 frame buffer, use the P4 type code.
* 2. If it's unit 0:
* a. look at the code in the EEPROM.
* b. on 3/60s only, look at the resolution jumper
* 3. Otherwise, punt and assume 1152 x 900.
*/
int id, w, h;
if ((id = p4probe(reg, &w, &h)) >= 0) {
if (id != P4_ID_BW &&
id != P4_ID_COLOR8P1)
return 0;
softc->p4reg = (u_long *) reg;
softc->w = w;
softc->h = h;
fbmapin(softc->image = reg + NBPG,
fbgetpage(reg) + (int) (id == P4_ID_BW ?
btop(P4_BW_OFF) :
btop(P4_COLOR_OFF_OVERLAY)),
softc->size =
pr_product(mpr_linebytes(w, 1), h));
return softc->size;
}
softc->p4reg = 0;
sizep = size_tab;
if (unit == 0) {
for (; sizep->sizecode != EEPROM->ee_diag.eed_scrsize;
sizep++)
if (sizep >= &size_tab[sizeof(size_tab) /
sizeof(size_tab[0])]) {
sizep = size_tab;
break;
}
#ifdef SUN3_60
/*
* The Sun-3/60 on-board frame buffer has a
* resolution jumper. We map it to the spare page
* after the frame buffer image and probe it.
*
* Even if the EEPROM is wrong about the resolution,
* we still go along with its idea of whether the
* monitor is normal or square.
*/
if (cpu == CPU_SUN3_60) {
fbmapin(reg + BW2_FBSIZE_HIRES,
(int) (BW2_RES_SENSE_PGT |
btop(BW2_RES_SENSE_ADDR)), 1);
if ((id = peekc(reg + BW2_FBSIZE_HIRES)) >= 0)
if (id & BW2_RES_SENSE_LOWRES) {
if (sizep->h > 1152)
sizep -= 2;
}
else
if (sizep->w <= 1152)
sizep += 2;
}
#endif SUN3_60
}
#ifdef SUN3_50
/*
* If we are on a SUN3_50 then we must reserve
* the on board memory for the frame buffer.
*/
if (cpu == CPU_SUN3_50)
if (fbobmemavail)
fbobmemavail = 0;
else
return 0;
#endif SUN3_50
}
#else !sun2
{
struct bw2dev *bw2dev = (struct bw2dev *) reg;
register struct bw2cr *alias1, *alias2;
short w1, w2, wrestore;
bw2crmapin(bw2dev);
alias1 = &bw2dev->bw2cr;
alias2 = alias1 + 1;
/*
* Two adjacent shorts should be the same because
* the control register is replicated every 2 bytes
* throughout the control page.
*/
if ((w1 = peek((short *) alias1)) == -1)
return 0;
wrestore = w1;
((struct bw2cr *) &w1)->vc_copybase = 0xAA & BW2_COPYBASEMASK;
if (poke((short *) alias1, w1) ||
(w2 = peek((short *) alias2)) == -1 ||
w1 != w2) {
(void) poke((short *) alias1, wrestore);
return 0;
}
((struct bw2cr *) &w1)->vc_copybase = ~0xAA & BW2_COPYBASEMASK;
if (poke((short *) alias1, w1) ||
(w2 = peek((short *) alias2)) == -1 ||
w1 != w2) {
(void) poke((short *) alias1, wrestore);
return 0;
}
if (poke((short *) alias1, wrestore))
panic("bwtwoprobe");
if (cpu != CPU_SUN2_120 &&
((struct bw2cr *) &wrestore)->vc_1024_jumper)
sizep++;
softc->cr = alias1;
}
#endif sun2
softc->image = reg;
softc->w = sizep->w;
softc->h = sizep->h;
return softc->size = sizep->size;
}
bwtwoattach(md)
register struct mb_device *md;
{
register struct bw2_softc *softc = &bw2_softc[md->md_unit];
printf("%s%d: resolution %d x %d\n",
md->md_driver->mdr_dname, md->md_unit,
softc->w, softc->h);
#if BW2_COPY_MEM_AVAIL
{
/* pfnum before shadow memory mapped in */
static int copyenpfnum;
/* virtual address mapped to shadow memory */
static caddr_t copyenvirt = 0;
int pfnum;
caddr_t fbvirtaddr;
caddr_t v;
int i;
int s;
extern char CADDR1[];
pfnum = fbgetpage(md->md_addr);
/*
* Have we passed this way before?
*/
if (fbobmemavail == 0) {
if (copyenvirt == 0) {
copyenvirt = (caddr_t)(*romp->v_fbaddr);
if (pfnum == copyenpfnum)
softc->image = copyenvirt;
}
return;
}
/*
* We know that the copy memory can be used. Use the
* shadow memory if the config flags say to use it.
*/
#ifdef sun3
if (md->md_flags & BW2_USECOPYMEM && cpu != CPU_SUN3_160) {
printf(
"WARNING: copy memory not available on this CPU\n"
);
md->md_flags &= ~BW2_USECOPYMEM;
}
#endif sun3
if (!(md->md_flags & BW2_USECOPYMEM)) {
/* don't bother using reserved shadow memory */
copyenvirt = md->md_addr;
return;
}
/*
* Mark the onboard frame buffer memory as not available
* anymore as we are going to use it for copy memory.
*/
fbobmemavail = 0;
/*
* If this frame buffer is the console, throw away
* config's mapping and use the boot PROM's.
*/
if (md->md_unit == 0 &&
*romp->v_outsink == OUTSCREEN &&
*romp->v_fbtype == FBTYPE_SUN2BW)
fbvirtaddr = (caddr_t) md->md_addr;
else {
s = splhigh();
rmfree(kernelmap, (long) btoc(softc->size),
(u_long) btokmx((struct pte *) md->md_addr));
(void)splx(s);
fbmapout(md->md_addr, softc->size);
fbvirtaddr = (caddr_t) (*romp->v_fbaddr);
}
copyenvirt = fbvirtaddr;
copyenpfnum = fbgetpage(fbvirtaddr);
/*
* Copy the current frame buffer memory
* to the copy memory as we map it in.
*/
for (v = (caddr_t) fbvirtaddr, i = btop(OBFBADDR);
i < btop(OBFBADDR + softc->size); v += NBPG, i++) {
mapin(CMAP1, btop(CADDR1),
(u_int) (PGT_OBMEM | i), 1, PG_V | PG_KW);
bcopy(v, CADDR1, NBPG);
fbmapin(v, PGT_OBMEM | i, NBPG);
}
#ifdef sun2
(void) bwtwosetcr(softc->cr,
(OBFBADDR>>BW2_COPYSHIFT) | BW2_COPYENABLEMASK, 1);
#else sun2
(void) setcopyenable(1);
#endif sun2
if (pfnum == copyenpfnum)
softc->image = copyenvirt;
}
#endif BW2_COPY_MEM_AVAIL
}
/*ARGSUSED*/
bwtwoioctl(dev, cmd, data, flag)
dev_t dev;
int cmd;
caddr_t data;
int flag;
{
register struct bw2_softc *softc = &bw2_softc[minor(dev)];
switch (cmd) {
case FBIOGTYPE: {
register struct fbtype *fb = (struct fbtype *) data;
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;
softc->pr.pr_ops = &bw2_ops;
softc->pr.pr_size.x = softc->w;
softc->pr.pr_size.y = softc->h;
softc->pr.pr_depth = 1;
softc->pr.pr_data = (caddr_t) &softc->prd;
softc->prd.md_linebytes = mpr_linebytes(softc->w, 1);
softc->prd.md_image = (short *) softc->image;
softc->prd.md_offset.x = 0;
softc->prd.md_offset.y = 0;
softc->prd.md_primary = 0;
softc->prd.md_flags = MP_DISPLAY;
/*
* Enable video and clear interrupt
*/
#ifdef sun2
bwtwosetcr(softc->cr, BW2_VIDEOENABLEMASK, 1);
bwtwosetcr(softc->cr, BW2_INTENABLEMASK, 0);
#else sun2
if (softc->p4reg)
*softc->p4reg = P4_REG_VIDEO | P4_REG_INTCLR;
else {
(void) setvideoenable(1);
(void) setintrenable(0);
}
#endif sun2
}
break;
#endif NWIN > 0
case FBIOSVIDEO: {
register int on = * (int *) data & FBVIDEO_ON;
#ifdef sun2
bwtwosetcr(softc->cr, BW2_VIDEOENABLEMASK, on);
#else sun2
if (softc->p4reg)
*softc->p4reg = *softc->p4reg &
~(P4_REG_INTCLR | P4_REG_VIDEO) |
(on ? P4_REG_VIDEO : 0);
else
setvideoenable((u_int) on);
#endif sun2
}
break;
/* get video flags */
case FBIOGVIDEO:
* (int *) data =
#ifdef sun2
softc->cr->vc_video_en
#else sun2
(softc->p4reg ?
*softc->p4reg & P4_REG_VIDEO :
enablereg & ENA_VIDEO)
#endif sun2
? FBVIDEO_ON : FBVIDEO_OFF;
break;
default:
return ENOTTY;
} /* switch(cmd) */
return 0;
}
bwtwointr()
{
register struct bw2_softc *softc;
int serviced = 0;
for (softc = bw2_softc; softc < &bw2_softc[nbwtwo]; softc++) {
if (!softc->image)
continue;
#ifdef sun2
if (softc->cr->vc_int) {
bwtwosetcr(softc->cr, BW2_INTENABLEMASK, 0);
serviced++;
}
#else sun2
if (softc->p4reg && *softc->p4reg & P4_REG_INTCLR) {
*softc->p4reg |= P4_REG_INTCLR;
serviced++;
}
(void) setintrenable(0);
#endif sun2
}
return serviced;
}
#ifdef sun2
/* Sun-2 support routines */
/*
* Special access approach to video ctrl register needed because byte writes,
* generated when do bit writes, replicates itself on the subsequent byte as
* well (this is a hardware bug). Thus, we need to access the register as a
* word. Also these routines assume that only one bit changes at a time.
*/
static
bwtwosetcr(bw2cr, mask, value)
struct bw2cr *bw2cr;
short mask;
int value;
{
register short w;
/*
* Read word from video control register.
*/
w = *((short *)bw2cr);
/*
* Modify bit as requested.
*/
if (value)
w |= mask;
else
w &= ~mask;
/*
* Write word back to video control register.
*/
*((short *)bw2cr) = w;
}
/*
* Given the frame buffer virtual address, map in the control register.
* Guess the location from the frame buffer's address space.
*/
static
bw2crmapin(bw2dev)
register struct bw2dev *bw2dev;
{
int page = fbgetpage((caddr_t) bw2dev);
switch (page & PGT_MASK) {
case BW2MB_PGT:
page += btop(BW2MB_CR - BW2MB_FB);
break;
case BW2VME_PGT:
page += btop(BW2VME_CR - BW2VME_FB);
break;
default:
panic("bwtwoprobe: cannot find control register");
/*NOTREACHED*/
}
fbmapin((caddr_t) &bw2dev->bw2cr, page, NBPG);
}
#endif sun2
#endif NBWTWO > 0