Files
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

3273 lines
81 KiB
C

#ifndef lint
static char sccsid[] = "@(#)cgtwelve.c 1.1 94/10/31 SMI";
#endif
/*
* Sbus accelerated 24 bit color frame buffer driver
*/
/*
* EIC-COMMENTS
* There are two hardware bugs in the EIC ASIC (SBus to Local bus interface
* Chip). One requires a write to some non-eic location following any host
* updates to an eic register. This requires special attention to any code
* involving the eic and should be carefully examined before making any
* changes. apu.res2 is the APU-ID read only register thus theoretically
* safe to write at any time.
* Second one requires a write to an eic location if a write access caused
* an eic timer interrupt. Hence the dummy write to eic.eic_control which
* is the EIC_ID read only register in the cg12_poll routine.
*/
#include "cgtwelve.h"
#include "win.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/buf.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/map.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/vmmac.h>
#include <sys/mman.h>
#include <sun/fbio.h>
#include <sun/gpio.h>
#include <sundev/mbvar.h>
#include <sbusdev/cg12reg.h>
#include <machine/mmu.h>
#include <machine/pte.h>
#include <machine/seg_kmem.h>
#include <machine/vm_hat.h>
#include <machine/psl.h>
#include <machine/cpu.h>
#include <vm/as.h>
#include <vm/seg.h>
#include <pixrect/pixrect.h>
#include <pixrect/pr_impl_util.h>
#include <pixrect/pr_planegroups.h>
#include <pixrect/pr_dblbuf.h>
#include <pixrect/memvar.h>
#include <pixrect/gp1reg.h>
#include <pixrect/cg12_var.h>
addr_t kmem_zalloc();
addr_t map_regs();
void unmap_regs();
void report_dev();
/* configuration options */
#ifndef OLDDEVSW
#define OLDDEVSW 1
#endif OLDDEVSW
#define NOHWINIT 1
#ifndef NOHWINIT
#define NOHWINIT 0
#endif NOHWINIT
#if NOHWINIT
int cg12_hwinit = 0;
#endif NOHWINIT
#define CG12DEBUG 1
#ifndef CG12DEBUG
#define CG12DEBUG 0
#endif CG12DEBUG
#if CG12DEBUG
int cg12_debug = 0;
#define DEBUGF(level, args) _STMT(if (cg12_debug >= (level)) printf args;)
#else CG12DEBUG
#define DEBUGF(level, args)
#endif CG12DEBUG
#if OLDDEVSW
#define STATIC /* nothing */
#define cg12_open cgtwelveopen
#define cg12_close cgtwelveclose
#define cg12_mmap cgtwelvemmap
#else OLDDEVSW
#define STATIC static
#endif OLDDEVSW
/* config info */
static int cg12_identify();
static int cg12_attach();
STATIC int cg12_open();
STATIC int cg12_close();
STATIC int cgtwelveioctl();
STATIC int cgtwelvesegmap();
#define CG12_OWNER_WANTS_COLOR 4
#define CG12_PHYSADDR(p) (softc->basepage + btop(p))
#define RAMDACWRITE(x) ((x) << 16 | (x) << 8 | (x))
#define FBUNIT(unit) ((unit) &3)
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
#define ENABLE_INTR(softc) \
((softc)->ctl_sp->apu.msg0 |= CG12_APU_EN_HINT, \
(softc)->ctl_sp->eic.interrupt |= CG12_EIC_EN_HINT, \
(softc)->ctl_sp->apu.res2 = 0)
/* !!! */
#define getsoftc(unit) (&cg12_softc[unit])
#define btob(n) ctob(btoc(n))
#define NMINOR 128
struct dev_ops cgtwelve_ops = {
0, /* revision */
cg12_identify,
cg12_attach,
cg12_open,
cg12_close,
0, 0, 0, 0, 0,
cgtwelveioctl,
0,
cgtwelvesegmap,
};
struct cg12_mapped
{
struct cg12_mapped *next; /* -> next process */
struct cg12_mapped *prev; /* -> prior process */
int pid; /* owner of the mappings */
int total; /* total size mapped by this process */
};
#define NULL_MAPPED ((struct cg12_mapped *) 0)
/* driver per-unit data */
struct cg12_softc
{
int w; /* width */
int h; /* height */
int size; /* size of frame buffer */
int bw2size; /* size of overlay */
int gb; /* for gp2 compatibility */
addr_t base; /* mapped base address */
int basepage; /* page # for base address */
struct proc *owner; /* owner of the frame buffer */
struct fbgattr *gattr; /* current attrributes */
u_int dev_id; /* device id for gpconfig */
int restart; /* restart count */
u_int dsp_active; /* dsp is active */
u_int ucode_ver; /* version of gs.ucode */
struct cg12_ctl_sp *ctl_sp; /* control space */
struct gp1_shmem *shmem; /* shmem pointer */
char *o_ptr; /* overlay and enable pointers */
char *e_ptr; /* for cursor */
char *i_ptr; /* for 8 bit indexed pointer */
char *w_ptr; /* for wid plane pointer */
char *d_ptr; /* for dram pointer */
int reg_bustype;
addr_t reg_addr;
int cg12pri;
struct cg12_mapped *total_mapped;
struct seg *curcntxt;
u_int cntxt_regs[6];
struct seg_tbl
{
struct proc *owner;
int gpminor;
} seg_tbl[NMINOR];
union fbunit cmap_rgb[CG12_CMAP_SIZE];
union fbunit cmap_indexed[CG12_CMAP_SIZE];
union fbunit cmap_a12[CG12_CMAP_SIZE];
union fbunit cmap_b12[CG12_CMAP_SIZE];
union fbunit cmap_alt[CG12_CMAP_SIZE];
union fbunit cmap_overlay[4];
union fbunit cmap_4bit_ovr[CG12_OMAP_SIZE - 4];
int cmap_begin_rgb;
int cmap_end_rgb;
int cmap_begin_indexed;
int cmap_end_indexed;
int cmap_begin_a12;
int cmap_end_a12;
int cmap_begin_b12;
int cmap_end_b12;
int cmap_begin_alt;
int cmap_end_alt;
int cmap_begin_overlay;
int cmap_end_overlay;
int cmap_begin_4bit_ovr;
int cmap_end_4bit_ovr;
struct cg12_wid_alloc
{
struct proc *owner;
int type;
} wid_alloc[NWIDS];
int wid_tbl[NWIDS];
int wid_begin;
int wid_end;
struct gp1_sblock
{
struct proc *owner;
int gpminor;
} sblock[CG12_STATIC_BLOCKS];
struct cg12_data cg12d;
#if NWIN > 0
Pixrect pr; /* kernel pixrect and private data */
#endif /* NWIN > 0 */
struct addrmap *addr_tbl;
};
struct cg9_fbdesc
{
short depth; /* depth, bits */
short group; /* plane group */
int allplanes; /* initial plane mask */
} cg12_fb_desc[CG12_NFBS] =
{
{ 1, PIXPG_OVERLAY, 0 },
{ 1, PIXPG_OVERLAY_ENABLE, 0 },
{ 32, PIXPG_24BIT_COLOR, 0x00ffffff },
{ 8, PIXPG_8BIT_COLOR, 0x000000ff },
{ 8, PIXPG_WID, 0x0000003f },
{ 16, PIXPG_ZBUF, 0x0000ffff }
};
/*
* Table of CG12 addresses
*/
struct addrmap
{
u_int offset; /* mmap offset */
u_int paddr; /* physical address */
u_int size; /* size */
u_char prot; /* superuser flag */
};
struct addrmap addr_tbl_lr[] =
{
{ CG12_VOFF_OVERLAY, CG12_OFF_OVERLAY0, CG12_OVERLAY_SIZE, 0 },
{ CG12_VOFF_ENABLE, CG12_OFF_OVERLAY1, CG12_ENABLE_SIZE, 0 },
{ CG12_VOFF_COLOR24, CG12_OFF_INTEN, CG12_COLOR24_SIZE, 0 },
{ CG12_VOFF_COLOR8, CG12_OFF_INTEN, CG12_COLOR8_SIZE, 0 },
{ CG12_VOFF_WID, CG12_OFF_WID, CG12_WID_SIZE, 0 },
{ CG12_VOFF_ZBUF, CG12_OFF_DEPTH, CG12_ZBUF_SIZE, 0 },
{ CG12_VOFF_CTL, CG12_OFF_CTL, 0x2000, 0 },
{ CG12_VOFF_SHMEM, CG12_OFF_SHMEM, CG12_SHMEM_SIZE, 0 },
{ CG12_VOFF_DRAM, CG12_OFF_DRAM, CG12_DRAM_SIZE, 0 },
{ CG12_VOFF_PROM, CG12_OFF_PROM, CG12_PROM_SIZE, 0 },
{ 0 }
};
struct addrmap addr_tbl_hr[] =
{
{ CG12_VOFF_OVERLAY_HR, CG12_OFF_OVERLAY0_HR, CG12_OVERLAY_SIZE_HR, 0 },
{ CG12_VOFF_ENABLE_HR, CG12_OFF_OVERLAY1_HR, CG12_ENABLE_SIZE_HR, 0 },
{ CG12_VOFF_COLOR24_HR, CG12_OFF_INTEN_HR, CG12_COLOR24_SIZE_HR, 0 },
{ CG12_VOFF_COLOR8_HR, CG12_OFF_INTEN_HR, CG12_COLOR8_SIZE_HR, 0 },
{ CG12_VOFF_WID_HR, CG12_OFF_WID_HR, CG12_WID_SIZE_HR, 0 },
{ CG12_VOFF_ZBUF_HR, CG12_OFF_DEPTH_HR, CG12_ZBUF_SIZE_HR, 0 },
{ CG12_VOFF_CTL_HR, CG12_OFF_CTL, 0x2000, 0 },
{ CG12_VOFF_SHMEM_HR, CG12_OFF_SHMEM, CG12_SHMEM_SIZE, 0 },
{ CG12_VOFF_DRAM_HR, CG12_OFF_DRAM, CG12_DRAM_SIZE, 0 },
{ CG12_VOFF_PROM_HR, CG12_OFF_PROM, CG12_PROM_SIZE, 0 },
{ 0 }
};
/* default structure for FBIOGTYPE ioctl */
static struct fbtype cg12typedefault =
{
/* zero entries filled in attach */
FBTYPE_SUN2GP, /* type */
0, /* height */
0, /* width */
CG12_DEPTH, /* depth */
CG12_CMAP_SIZE, /* color map size */
0 /* total mmap size */
};
/* default structure for FBIOGATTR ioctl */
static struct fbgattr cg12attrdefault =
{
FBTYPE_SUNGP3, /* real_type */
0, /* owner */
{
FBTYPE_SUN2GP, /* type */
0,
0,
CG12_DEPTH,
CG12_CMAP_SIZE,
0
},
/* fbsattr */
{
0, /* flags */
-1, /* emu_type */
/* dev_specific */
{
0,
0,
0,
FBTYPE_SUNGP3, /* gp real type indication */
0,
GP2_SHMEM_SIZE /* how much shared mem to mmap */
}
},
/* emu_types */
{
FBTYPE_SUNGP3,
FBTYPE_SUN2BW, /* bwtwo */
-1, -1
}
};
#if NWIN > 0
/* SunWindows specific stuff */
/* kernel pixrect ops vector */
struct pixrectops cg12_ops = {
cg12_rop,
cg12_putcolormap,
cg12_putattributes,
cg12_ioctl
};
#endif /* NWIN > 0 */
static int ncg12;
static struct cg12_softc *cg12_softc;
static void cg12_intr();
extern int cpu;
static cg12_poll();
int cg12_sync_timeout = 1500 * 1000;
int cg12_width;
static
cg12_identify(name)
char *name;
{
DEBUGF(1, ("cg12_identify(%s)\n", name));
if (strcmp(name, "cgtwelve") == 0)
return ++ncg12;
else
return 0;
}
static
cg12_attach(devi)
struct dev_info *devi;
{
struct cg12_softc *softc;
addr_t reg;
int bytes_8, bytes_1, i, d_size, wsc_val;
static int unit;
union fbunit *map, *imap, *a12map, *b12map;
addr_t devid;
DEBUGF(1, ("cg12_attach: ncg12=%d unit=%d\n", ncg12, unit));
/* Allocate softc structs on first attach */
if (!cg12_softc)
{
cg12_softc = (struct cg12_softc *)
kmem_zalloc((u_int) sizeof (struct cg12_softc) * ncg12);
unit = 0;
}
softc = getsoftc(unit);
/* get the device id for gpconfig */
d_size = getproplen(devi->devi_nodeid, "dev_id");
if (d_size && (devid = getlongprop(devi->devi_nodeid, "dev_id")))
{
if (strcmp(devid, "gsxr") == 0)
{
softc->dev_id = 3;
softc->addr_tbl = addr_tbl_hr;
}
else if (strcmp(devid, "cg12+") == 0)
{
softc->dev_id = 2;
softc->addr_tbl = addr_tbl_lr;
}
else if ((strncmp(devid, "eg", 2) == 0) ||
(strcmp(devid, "cg12") == 0))
{
softc->dev_id = 1;
softc->addr_tbl = addr_tbl_lr;
}
kmem_free(devid, (u_int)d_size);
}
/* grab properties from PROM */
if (softc->dev_id <= 2)
{
softc->w = getprop(devi->devi_nodeid, "width", 1152);
softc->h = getprop(devi->devi_nodeid, "height", 900);
}
else if (softc->dev_id == 3)
{
softc->w = getprop(devi->devi_nodeid, "width", 1280);
softc->h = getprop(devi->devi_nodeid, "height", 1024);
}
cg12_width = softc->w;
bytes_8 = mpr_linebytes(softc->w,8);
DEBUGF(2, ("cg12_attach: w =%d, h =%d, linebytes =%d, dev_id=%d\n",
softc->w, softc->h, bytes_8, softc->dev_id));
/* compute size of frame buffer */
bytes_8 = btob(bytes_8 * softc->h);
bytes_1 = btob(mpr_linebytes(softc->w,1) * softc->h);
softc->bw2size = bytes_1;
#if NWIN > 0
softc->o_ptr = (char *) getprop(devi->devi_nodeid, "overlay", 0);
softc->e_ptr = (char *) getprop(devi->devi_nodeid, "enable", 0);
if(softc->o_ptr && softc->e_ptr) {
DEBUGF(2, ("cg12_attach: o=%x, e=%x\n", softc->o_ptr,softc->e_ptr));
bytes_1 = 0;
}
#else /* NWIN > 0 */
bytes_8 = 0;
bytes_1 = 0;
#endif /* NWIN > 0 */
/*
* Allocate virtual space for registers, shared memory
* and may be frame buffer.
*/
DEBUGF(2, ("cg12_attach: bytes_8= %x, bytes_1= %x\n", bytes_8,bytes_1));
if (!(reg = map_regs(devi->devi_reg[0].reg_addr,
(u_int) NBPG * 6, devi->devi_reg[0].reg_bustype)))
return -1;
softc->base = reg;
softc->basepage = fbgetpage(reg);
if (!(reg = map_regs(devi->devi_reg[0].reg_addr+CG12_OFF_CTL,
(u_int) (NBPG * 2 + bytes_8 + bytes_1 * 2 + CG12_SHMEM_SIZE),
devi->devi_reg[0].reg_bustype)))
return -1;
softc->reg_bustype = devi->devi_reg[0].reg_bustype;
softc->reg_addr = devi->devi_reg[0].reg_addr;
DEBUGF(1, ("cg12_attach: reg=0x%x/0x%x (0x%x)\n", (u_int) reg,
fbgetpage((addr_t) reg) << PGSHIFT, fbgetpage((addr_t) reg)));
softc->ctl_sp = (struct cg12_ctl_sp *) reg;
softc->shmem =
(struct gp1_shmem *)((caddr_t)softc->ctl_sp
+ btob(sizeof(struct cg12_ctl_sp)));
(void) fbmapin((char *) softc->shmem,
(int) CG12_PHYSADDR(CG12_OFF_SHMEM), (int)CG12_SHMEM_SIZE);
softc->d_ptr =
(char *)((caddr_t)softc->shmem + btob(sizeof(struct gp1_shmem)));
(void) fbmapin(softc->d_ptr,
(int) CG12_PHYSADDR(CG12_OFF_DRAM), NBPG);
DEBUGF(2, ("cg12_attach: shmem=0x%x, dram=0x%x\n",
softc->shmem, softc->d_ptr));
#if NWIN > 0
softc->i_ptr =
(char *)((caddr_t)softc->d_ptr + NBPG);
if (softc->dev_id <= 2)
{
(void) fbmapin(softc->i_ptr,
(int) CG12_PHYSADDR(CG12_OFF_INTEN), bytes_8);
}
else if (softc->dev_id == 3)
{
(void) fbmapin(softc->i_ptr,
(int) CG12_PHYSADDR(CG12_OFF_INTEN_HR), bytes_8);
}
if (!softc->o_ptr)
{
softc->o_ptr = softc->i_ptr + bytes_8;
if (softc->dev_id <= 2)
{
(void) fbmapin(softc->o_ptr,
(int) CG12_PHYSADDR(CG12_OFF_OVERLAY1), bytes_1);
}
else if (softc->dev_id == 3)
{
(void) fbmapin(softc->o_ptr,
(int) CG12_PHYSADDR(CG12_OFF_OVERLAY1_HR), bytes_1);
}
}
if (!softc->e_ptr)
{
softc->e_ptr = softc->o_ptr + bytes_1;
if (softc->dev_id <= 2)
{
(void) fbmapin(softc->e_ptr,
(int) CG12_PHYSADDR(CG12_OFF_OVERLAY0), bytes_1);
}
else if (softc->dev_id == 3)
{
(void) fbmapin(softc->e_ptr,
(int) CG12_PHYSADDR(CG12_OFF_OVERLAY0_HR), bytes_1);
}
}
DEBUGF(2, ("cg12_attach: o_ptr=%x, e_ptr=%x, i_ptr=%x, w_ptr=%x\n",
softc->o_ptr, softc->e_ptr, softc->i_ptr, softc->w_ptr));
#endif /* NWIN > 0 */
#if NOHWINIT
if (cg12_hwinit)
cg12_binit(softc->ctl_sp);
#endif /* NOHWINIT */
cg12_init(softc->ctl_sp, softc->dev_id);
/* save unit number */
devi->devi_unit = unit;
/* attach interrupt */
softc->cg12pri = ipltospl(devi->devi_intr[0].int_pri);
addintr(devi->devi_intr[0].int_pri, cg12_poll, devi->devi_name, unit);
/* save back pointer to softc */
devi->devi_data = (addr_t) softc;
printf("cgtwelve%d: screen pixel resolution %dx%d\n",
unit, softc->w, softc->h);
/* prepare for next attach */
unit++;
report_dev(devi);
softc->restart = 0;
softc->ucode_ver = 0;
bzero((caddr_t) softc->sblock,sizeof softc->sblock);
softc->gattr = &cg12attrdefault;
softc->gattr->fbtype.fb_height = softc->h;
softc->gattr->fbtype.fb_width = softc->w;
if (softc->dev_id <= 2)
{
softc->gattr->fbtype.fb_size = CG12_FBCTL_SIZE;
softc->size = CG12_FBCTL_SIZE;
}
else if (softc->dev_id == 3)
{
softc->gattr->fbtype.fb_size = CG12_FBCTL_SIZE_HR;
softc->size = CG12_FBCTL_SIZE_HR;
}
softc->gb = 0;
softc->dsp_active = 0;
softc->cmap_begin_overlay = 4;
softc->cmap_end_overlay = 0;
softc->cmap_begin_indexed = CG12_CMAP_SIZE;
softc->cmap_end_indexed = 0;
softc->cmap_begin_rgb = CG12_CMAP_SIZE;
softc->cmap_end_rgb = 0;
softc->cmap_begin_4bit_ovr = CG12_OMAP_SIZE - 4;
softc->cmap_end_4bit_ovr = 0;
softc->wid_begin = NWIDS;
softc->wid_end = 0;
/*
* wsc 1 (dev_id == 0 or 1) = 3-color overlay, 8-bit;
* wsc 2 = just 8-bit
*/
wsc_val = (softc->dev_id == 0 || softc->dev_id == 1) ? 9 : 1;
/* initialize the shadow window-id table */
for (i = 0; i < NWIDS; i++)
softc->wid_tbl[i] = wsc_val;
/* initialize the window-id allocation table */
bzero((caddr_t) softc->wid_alloc, sizeof softc->wid_alloc);
/* initilaize the soft copies of the colormaps */
map = softc->cmap_rgb;
imap = softc->cmap_indexed;
a12map = softc->cmap_a12;
b12map = softc->cmap_b12;
for ( i = 0 ; i < 256; i++, map++, imap++, a12map++, b12map++)
{
map->packed = RAMDACWRITE(i);
imap->packed = RAMDACWRITE((i) ? 0x00 : 0xff);
a12map->packed = RAMDACWRITE((i & 0xf0) | ((i & 0xf0) >> 4));
b12map->packed = RAMDACWRITE(((i & 0x0f) << 4) | (i & 0x0f));
}
map = softc->cmap_overlay;
map->packed = 0xffffff; /* white */
map++;
map->packed = 0xffffff; /* white */
map++;
map->packed = 0x00ff00; /* green */
map++;
map->packed = 0x000000; /* black */
map = softc->cmap_4bit_ovr;
for ( i = 0; i <27; i++, map++)
map->packed = 0;
map->packed = 0xffffff;
map = softc->cmap_alt;
map->packed = 0xffffff;
for ( i = 0; i <255; i++, map++)
map->packed = 0;
softc->ctl_sp->apu.msg0 = 0;
softc->ctl_sp->apu.msg1 = 0;
softc->ctl_sp->apu.ien0 = 0;
#ifdef sun4c
/* sun4c-75 cache bug workaround */
if(cpu == CPU_SUN4C_75)
on_enablereg(1);
#endif /* sun4c */
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.interrupt |= CG12_EIC_EN_EICINT;
softc->ctl_sp->apu.res2 = 0;
softc->ctl_sp->eic.host_control |= CG12_EIC_WSTATUS;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
softc->cntxt_regs[0] = softc->ctl_sp->apu.hpage;
softc->cntxt_regs[1] = softc->ctl_sp->apu.haccess;
softc->cntxt_regs[2] = softc->ctl_sp->dpu.pln_sl_host;
softc->cntxt_regs[3] = softc->ctl_sp->dpu.pln_rd_msk_host;
softc->cntxt_regs[4] = softc->ctl_sp->dpu.pln_wr_msk_host;
softc->cntxt_regs[5] = softc->ctl_sp->eic.host_control;
return 0;
}
STATIC
cg12_open(dev, flag)
dev_t dev;
int flag;
{
int gpminor = minor(dev);
DEBUGF(4, ("cg12_open(%d), flag:%x\n", gpminor, flag));
return fbopen(dev, flag, ncg12);
}
/*ARGSUSED*/
STATIC
cg12_close(dev, flag)
dev_t dev;
int flag;
{
struct cg12_softc *softc;
int gpminor = minor(dev);
softc = getsoftc(minor(dev));
DEBUGF(3, ("cg12_close(%d)\n", gpminor));
{
struct gp1_sblock *sbp = softc->sblock;
PR_LOOPP(CG12_STATIC_BLOCKS - 1,
if (sbp->owner)
sbp->owner = 0;
sbp++);
}
{
struct cg12_wid_alloc *widp = softc->wid_alloc;
PR_LOOPP(NWIDS - 1,
if (widp->owner)
{
widp->owner = 0;
widp->type = 0;
}
widp++);
}
{
struct seg_tbl *segtbl = softc->seg_tbl;
PR_LOOPP(NMINOR - 1,
if(segtbl->owner && (segtbl->owner->p_pid == u.u_procp->p_pid))
{
DEBUGF(3, ("cg12_close:segtbl_pid:%x,gpminor:%x\n",
segtbl->owner->p_pid,segtbl->gpminor));
segtbl->owner = 0;
(void) cg12_cleanup(softc, segtbl->gpminor);
segtbl->gpminor = 0;
}
segtbl++);
}
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.host_control = softc->cntxt_regs[5];
/* !!! */
softc->ctl_sp->apu.hpage = softc->cntxt_regs[0];
softc->ctl_sp->apu.haccess = softc->cntxt_regs[1];
softc->ctl_sp->dpu.pln_sl_host = softc->cntxt_regs[2];
softc->ctl_sp->dpu.pln_rd_msk_host = softc->cntxt_regs[3];
softc->ctl_sp->dpu.pln_wr_msk_host = softc->cntxt_regs[4];
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.host_control |= CG12_EIC_WSTATUS;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
return 0;
}
/*ARGSUSED*/
STATIC
cg12_mmap(dev, off, prot)
dev_t dev;
register off_t off;
int prot;
{
register struct cg12_softc *softc = getsoftc(minor(dev));
register struct addrmap *mp;
DEBUGF(off ? 9 : 4, ("cg12_mmap(%d, 0x%x)\n", minor(dev), (u_int) off));
if (softc->gattr->sattr.flags & FB_ATTR_AUTOINIT)
{
int i, j, k;
/*
* !!! see cgtwelve.c EIC-COMMENTS before changing !!!
* set WSTATUS bit so that the PROM will save the context
* before displaying any character to the console.
*/
softc->ctl_sp->eic.host_control = CG12_EIC_WSTATUS;
/* !!! */
softc->ctl_sp->apu.hpage =
(softc->w == 1280) ? CG12_HPAGE_ENABLE_HR : CG12_HPAGE_ENABLE;
softc->ctl_sp->apu.haccess = CG12_HACCESS_ENABLE;
softc->ctl_sp->dpu.pln_sl_host = CG12_PLN_SL_ENABLE;
softc->ctl_sp->dpu.pln_wr_msk_host = CG12_PLN_WR_ENABLE;
softc->ctl_sp->dpu.pln_rd_msk_host = CG12_PLN_RD_ENABLE;
/* set enable if monochrome, clear if color */
for (i = 0, j = softc->bw2size,
k = (softc->gattr->sattr.flags &
CG12_OWNER_WANTS_COLOR) ? 0 : 0xff; i < j; i++)
*(softc->e_ptr + i) = k;
/*
* !!! see cgtwelve.c EIC-COMMENTS before changing !!!
* set WSTATUS bit so that the PROM will save the context
* before displaying any character to the console.
*/
softc->ctl_sp->eic.host_control = CG12_EIC_WSTATUS;
/* !!! */
softc->ctl_sp->apu.hpage =
(softc->w == 1280) ? CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY;
softc->ctl_sp->apu.haccess = CG12_HACCESS_OVERLAY;
softc->ctl_sp->dpu.pln_sl_host = CG12_PLN_SL_OVERLAY;
softc->ctl_sp->dpu.pln_wr_msk_host = CG12_PLN_WR_OVERLAY;
softc->ctl_sp->dpu.pln_rd_msk_host = CG12_PLN_RD_OVERLAY;
for (i = 0; i < j; i++)
*(softc->o_ptr + i) = 0x0; /* clear the overlay */
softc->gattr->sattr.flags &= ~FB_ATTR_AUTOINIT;
}
for ( mp = softc->addr_tbl; mp->size; mp++) {
if( off >= (off_t) mp->offset &&
off < (off_t) (mp->offset + mp->size)) {
/* Checkup if only root can map this section */
if (mp->prot && !suser()) {
return (-1);
}
DEBUGF((off == mp->offset) ? 4 : 9, ("\toff:%x pa:%x\n",
off, CG12_PHYSADDR(mp->paddr + (off-mp->offset))));
return (CG12_PHYSADDR(mp->paddr + (off-mp->offset)));
}
}
DEBUGF(1, ("cg12_mmap returning error\n"));
return (-1);
}
/*ARGSUSED*/
STATIC
cgtwelveioctl(dev, cmd, data, flag)
dev_t dev;
int cmd;
caddr_t data;
int flag;
{
register int gpminor = minor(dev);
register struct cg12_softc *softc = getsoftc(minor(dev));
struct gp1_shmem *shp = (struct gp1_shmem *)softc->shmem;
register int i, j;
DEBUGF(4, ("cgtwelveioctl(%d, 0x%x)\n", gpminor, cmd));
switch (cmd)
{
case FBIO_DEVID:
*(int *) data = softc->dev_id;
break;
case FBIO_U_RST:
{
int dsphlt = *(int *) data;
DEBUGF(3, ("cgtwelveioctl: URST called with %x\n", dsphlt));
if (!dsphlt) {
struct gp1_sblock *sbp = softc->sblock;
PR_LOOPP(CG12_STATIC_BLOCKS - 1,
if (sbp->owner)
psignal(sbp->owner, SIGXCPU);
sbp++);
softc->dsp_active = 0xff;
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.reset &= ~CG12_EIC_DSPRST;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
}
else
{
shp->fill280[0] = 0x00ff;
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.reset |= CG12_EIC_DSPRST;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
}
break;
}
case GP1IO_GET_STATIC_BLOCK:
{
register int block;
{
register struct gp1_sblock *sbp = softc->sblock;
DEBUGF(3, ("CG12_GET_STATIC_BLOCK:sbp:%x\n", sbp));
block = 0;
while (sbp->owner)
{
if (++block >= CG12_STATIC_BLOCKS)
{
*(int *) data = -1;
return 0;
}
sbp++;
}
sbp->owner = u.u_procp;
sbp->gpminor = minor(dev);
*(int *) data = block;
}
break;
}
case GP1IO_FREE_STATIC_BLOCK:
{
register int block = *(int *) data;
register struct gp1_sblock *sbp = &softc->sblock[block];
DEBUGF(3, ("CG12_FREE_STATIC_BLOCK:block:%x,sbp:%x\n",
block, sbp));
if ((u_int) block >= CG12_STATIC_BLOCKS ||
sbp->owner == 0 ||
sbp->gpminor != minor(dev))
return EINVAL;
sbp->owner = 0;
}
break;
case GP1IO_INFO_STATIC_BLOCK:
{
char tmp[CG12_STATIC_BLOCKS];
struct static_block_info *binfo =
(struct static_block_info *) data;
struct gp1_sblock *sbp = softc->sblock;
DEBUGF(3, ("CG12_INFO_STATIC_BLOCK:sbp:%x\n", sbp));
for (i = 0, binfo->sbi_count = 0; i < CG12_STATIC_BLOCKS;
i++, sbp++)
{
if (sbp->owner && (sbp->owner->p_pid == u.u_procp->p_pid))
{
tmp[binfo->sbi_count] = i;
DEBUGF(3, ("CG12_INFO_STATIC_BLOCK: tmp[%x]:%x\n",
binfo->sbi_count, tmp[binfo->sbi_count]));
binfo->sbi_count++;
}
}
if (copyout(tmp, binfo->sbi_array, (u_int) binfo->sbi_count))
return (EFAULT);
}
break;
case GP1IO_CHK_GP:
if (!(*(int *) data && cg12_cleanup(softc, gpminor)))
cg12_restart(gpminor, "");
break;
case GP1IO_GET_RESTART_COUNT:
*(int *) data = softc->restart;
break;
case FBIOGTYPE:
{
register struct fbtype *fb = (struct fbtype *) data;
if (softc->owner == NULL ||
softc->owner->p_stat == NULL ||
(int) softc->owner->p_pid != softc->gattr->owner)
{
softc->owner = u.u_procp;
softc->gattr->owner = (int) u.u_procp->p_pid;
}
*fb = cg12typedefault;
fb->fb_height = softc->h;
fb->fb_width = softc->w;
if (softc->gattr->sattr.emu_type == FBTYPE_SUN2BW)
{
fb->fb_type = FBTYPE_SUN2BW;
fb->fb_depth = 1;
fb->fb_size = softc->bw2size;
fb->fb_cmsize = 2;
}
else
{
fb->fb_type = FBTYPE_SUN2GP;
fb->fb_depth = CG12_DEPTH;
fb->fb_size = softc->size;
fb->fb_cmsize = CG12_CMAP_SIZE;
}
break;
}
#if NWIN > 0
case FBIOGPIXRECT:
{
struct fbpixrect *fbpix = (struct fbpixrect *) data;
unsigned int initplanes;
/* point to the softc pixrect and private data */
fbpix->fbpr_pixrect = &softc->pr;
softc->pr.pr_data = (caddr_t) & softc->cg12d;
/* initialize pixrect */
softc->pr.pr_ops = &cg12_ops;
softc->pr.pr_size.x = softc->w;
softc->pr.pr_size.y = softc->h;
/* initialize private data */
softc->cg12d.gp_shmem = (char *) softc->shmem;
softc->cg12d.flags = 0;
softc->cg12d.planes = 0;
softc->cg12d.fd = gpminor;
softc->cg12d.ctl_sp = softc->ctl_sp;
softc->cg12d.wid_dbl_info.dbl_wid.wa_type = 0;
softc->cg12d.wid_dbl_info.dbl_wid.wa_index = -1;
softc->cg12d.wid_dbl_info.dbl_wid.wa_count = 1;
softc->cg12d.wid_dbl_info.dbl_fore = PR_DBL_A;
softc->cg12d.wid_dbl_info.dbl_back = PR_DBL_B;
softc->cg12d.wid_dbl_info.dbl_read_state = PR_DBL_A;
softc->cg12d.wid_dbl_info.dbl_write_state = PR_DBL_BOTH;
/* set up the plane group data */
for (i = 0; i < CG12_NFBS; i++)
{
softc->cg12d.fb[i].group = cg12_fb_desc[i].group;
softc->cg12d.fb[i].depth = cg12_fb_desc[i].depth;
softc->cg12d.fb[i].mprp.mpr.md_offset.x = 0;
softc->cg12d.fb[i].mprp.mpr.md_offset.y = 0;
softc->cg12d.fb[i].mprp.mpr.md_primary = 0;
softc->cg12d.fb[i].mprp.mpr.md_flags =
(cg12_fb_desc[i].allplanes != 0)
? MP_DISPLAY | MP_PLANEMASK : MP_DISPLAY;
softc->cg12d.fb[i].mprp.planes = cg12_fb_desc[i].allplanes;
softc->cg12d.fb[i].mprp.mpr.md_linebytes =
mpr_linebytes(softc->w, cg12_fb_desc[i].depth);
initplanes = PIX_GROUP(cg12_fb_desc[i].group) |
cg12_fb_desc[i].allplanes;
if (softc->cg12d.fb[i].group == PIXPG_OVERLAY)
{
softc->cg12d.fb[i].mprp.mpr.md_image =
(short *) softc->o_ptr;
(void) cg12_putattributes(&softc->pr, &initplanes);
pr_rop(&softc->pr, 0, 0, softc->pr.pr_size.x,
softc->pr.pr_size.y, PIX_CLR, (Pixrect *) 0, 0, 0);
}
else if (softc->cg12d.fb[i].group == PIXPG_OVERLAY_ENABLE)
{
softc->cg12d.fb[i].mprp.mpr.md_image =
(short *) softc->e_ptr;
(void) cg12_putattributes(&softc->pr, &initplanes);
pr_rop(&softc->pr, 0, 0, softc->pr.pr_size.x,
softc->pr.pr_size.y, PIX_SET, (Pixrect *) 0, 0, 0);
}
else if (softc->cg12d.fb[i].group == PIXPG_8BIT_COLOR)
{
softc->cg12d.fb[i].mprp.mpr.md_image =
(short *) softc->i_ptr;
(void) cg12_putattributes(&softc->pr, &initplanes);
pr_rop(&softc->pr, 0, 0, softc->pr.pr_size.x,
softc->pr.pr_size.y, PIX_CLR, (Pixrect *) 0, 0, 0);
}
else
softc->cg12d.fb[i].mprp.mpr.md_image = (short *) -1;
}
/* leave it in overlay */
initplanes = PIX_GROUP(PIXPG_OVERLAY) | PIX_ALL_PLANES;
(void) cg12_putattributes(&softc->pr, &initplanes);
}
break;
#endif /* NWIN > 0 */
case FBIOSATTR:
{
struct fbsattr *sattr = (struct fbsattr *) data;
softc->gattr->sattr.flags = sattr->flags;
if (sattr->emu_type != -1)
softc->gattr->sattr.emu_type = sattr->emu_type;
if (sattr->flags & FB_ATTR_DEVSPECIFIC)
bcopy((char *) sattr->dev_specific,
(char *) softc->gattr->sattr.dev_specific,
sizeof sattr->dev_specific);
/* under new ownership */
softc->owner = u.u_procp;
softc->gattr->owner = (int) u.u_procp->p_pid;
break;
}
case FBIOGATTR:
{
register struct fbgattr *gattr = (struct fbgattr *) data;
/* set owner if not owned, or if prev. owner is dead */
if (softc->owner == NULL ||
softc->owner->p_stat == NULL ||
(int) softc->owner->p_pid != softc->gattr->owner)
{
softc->owner = u.u_procp;
softc->gattr->owner = (int) u.u_procp->p_pid;
}
*gattr = *(softc->gattr);
if (u.u_procp == softc->owner)
{
gattr->owner = 0;
/* softc->gattr->sattr.flags |= CG12_OWNER_WANTS_COLOR; */
}
break;
}
case FBIOSVIDEO:
{
register int on = *(int *) data & FBVIDEO_ON;
if (!on)
softc->ctl_sp->apu.vsg_ctl &= ~CG12_APU_EN_VID;
else if (on && !(softc->ctl_sp->apu.vsg_ctl & CG12_APU_EN_VID))
softc->ctl_sp->apu.vsg_ctl |= CG12_APU_EN_VID;
break;
}
case FBIOGVIDEO:
*(int *) data = softc->ctl_sp->apu.vsg_ctl & CG12_APU_EN_VID
? FBVIDEO_ON : FBVIDEO_OFF;
break;
case FBIOVERTICAL:
cg12_wait(minor(dev));
break;
case FBIOVRTOFFSET:
if (softc->dev_id <= 2)
*(int *) data = CG12_VOFF_VERTCOUNT;
else if (softc->dev_id == 3)
*(int *) data = CG12_VOFF_VERTCOUNT_HR;
break;
case FBIOGINFO:
{
register struct fbinfo *fbinfo = (struct fbinfo *) data;
fbinfo->fb_physaddr = CG12_OFF_INTEN;
fbinfo->fb_addrdelta = softc->size;
fbinfo->fb_unit = FBUNIT(gpminor);
fbinfo->fb_hwwidth = softc->w;
fbinfo->fb_hwheight = softc->h;
break;
}
case GP1IO_CHK_FOR_GBUFFER:
*(int *) data = (softc->gb >= 0);
break;
case GP1IO_GET_GBUFFER_STATE:
*(int *) data = (softc->gb == FBUNIT(gpminor));
break;
case GP1IO_GET_TRUMINORDEV:
{
struct seg_tbl *segtbl = softc->seg_tbl;
DEBUGF(3, ("GP1IO_GET_TRUMINORDEV:segtbl:%x\n", segtbl));
for (i = 0; i < NMINOR; i++, segtbl++)
{
if (segtbl->owner &&
(segtbl->owner->p_pid == u.u_procp->p_pid))
{
DEBUGF(3, ("TRUMINORDEV:pid:%x,gpminor:%x\n",
segtbl->owner->p_pid, segtbl->gpminor));
*(char *) data = segtbl->gpminor;
}
}
}
break;
case GP1IO_PUT_INFO:
case GP1IO_SET_USING_GBUFFER:
case GP1IO_REDIRECT_DEVFB:
case GP1IO_GET_REQDEV:
break;
case FBIOPUTCMAP:
case FBIOGETCMAP:
{
struct fbcmap *cmap = (struct fbcmap *) data;
u_int index = (u_int) cmap->index;
u_int count = (u_int) cmap->count;
u_int pgroup = PIX_ATTRGROUP(index);
union fbunit *map;
union fbunit *mapa12;
union fbunit *mapb12;
int *begin;
int *end;
int entries;
u_int intr_flag;
u_char tmp[3][CG12_CMAP_SIZE];
u_int color;
u_int lo_addr;
u_int hi_addr;
u_int *map_addr;
if (count == 0 || !cmap->red || !cmap->green || !cmap->blue)
return (EINVAL);
switch (pgroup)
{
case PIXPG_OVERLAY:
case PIXPG_OVERLAY_ENABLE:
begin = &softc->cmap_begin_overlay;
end = &softc->cmap_end_overlay;
map = softc->cmap_overlay;
intr_flag = CG12_OVERLAY_CMAP;
lo_addr = 0;
hi_addr = 1;
map_addr = &softc->ctl_sp->ramdac.control;
entries = 4;
break;
case PIXPG_4BIT_OVERLAY:
if((softc->dev_id != 2) && (softc->dev_id !=3))
return (EINVAL);
begin = &softc->cmap_begin_4bit_ovr;
end = &softc->cmap_end_4bit_ovr;
map = &softc->cmap_4bit_ovr[CG12_OMAP_SIZE - 5];
intr_flag = CG12_4BIT_OVR_CMAP;
lo_addr = 0;
hi_addr = 1;
map_addr = &softc->ctl_sp->ramdac.control;
entries = CG12_OMAP_SIZE - 4;
break;
case PIXPG_8BIT_COLOR:
begin = &softc->cmap_begin_indexed;
end = &softc->cmap_end_indexed;
map = softc->cmap_indexed;
intr_flag = CG12_8BIT_CMAP;
lo_addr = 0;
hi_addr = 1;
map_addr = &softc->ctl_sp->ramdac.color;
entries = CG12_CMAP_SIZE;
break;
case PIXPG_24BIT_COLOR:
begin = &softc->cmap_begin_rgb;
end = &softc->cmap_end_rgb;
map = softc->cmap_rgb;
intr_flag = CG12_24BIT_CMAP;
lo_addr = 0;
hi_addr = 0;
map_addr = &softc->ctl_sp->ramdac.color;
entries = CG12_CMAP_SIZE;
break;
case PIXPG_ALT_COLOR:
begin = &softc->cmap_begin_alt;
end = &softc->cmap_end_alt;
map = softc->cmap_alt;
intr_flag = CG12_ALT_CMAP;
lo_addr = 0;
hi_addr = 0;
map_addr = &softc->ctl_sp->ramdac.control;
entries = CG12_CMAP_SIZE;
break;
case PIXPG_A12BIT_COLOR:
begin = &softc->cmap_begin_a12;
end = &softc->cmap_end_a12;
map = softc->cmap_a12;
intr_flag = CG12_A12BIT_CMAP;
lo_addr = 0;
hi_addr = 2;
map_addr = &softc->ctl_sp->ramdac.color;
entries = CG12_CMAP_SIZE;
break;
case PIXPG_B12BIT_COLOR:
begin = &softc->cmap_begin_b12;
end = &softc->cmap_end_b12;
map = softc->cmap_b12;
intr_flag = CG12_B12BIT_CMAP;
lo_addr = 0;
hi_addr = 3;
map_addr = &softc->ctl_sp->ramdac.color;
entries = CG12_CMAP_SIZE;
break;
default:
return (EINVAL);
}
if ((index &= PIX_ALL_PLANES) >= entries || index + count > entries)
return (EINVAL);
if (cmd == FBIOPUTCMAP)
{
if (softc->cg12d.flags & CG12_KERNEL_UPDATE)
{
DEBUGF(3, ("kernel putcmap\n"));
softc->cg12d.flags &= ~CG12_KERNEL_UPDATE;
bcopy((caddr_t) cmap->red, (caddr_t) tmp[0], count);
bcopy((caddr_t) cmap->green, (caddr_t) tmp[1], count);
bcopy((caddr_t) cmap->blue, (caddr_t) tmp[2], count);
}
else
{
DEBUGF(3, ("user putcmap\n"));
if (copyin((caddr_t) cmap->red, (caddr_t) tmp[0], count) ||
copyin((caddr_t) cmap->green, (caddr_t) tmp[1],count) ||
copyin((caddr_t) cmap->blue, (caddr_t) tmp[2], count))
return (EFAULT);
}
*begin = MIN(*begin, index);
*end = MAX(*end, index + count);
if (pgroup == PIXPG_24BIT_COLOR)
{
DEBUGF(3, ("24bit cmap: index:%x,count:%x\n",index,count));
mapa12 = softc->cmap_a12;
mapb12 = softc->cmap_b12;
for (i = 0, map += index; count; i++, count--, map++)
{
map->packed =
tmp[0][i] | (tmp[1][i] << 8) | (tmp[2][i] << 16);
if (((i+index) & 0xf) == (((i+index) & 0xf0) >> 4))
{
mapa12 = softc->cmap_a12 + (i & 0xf0);
mapb12 = softc->cmap_b12 + (i & 0x0f);
DEBUGF(3, ("24bit: i:%x, mapa12:%x, mapb12:%x\n",
i, mapa12, mapb12));
for (j = 0; j < 16; j++, mapa12++, mapb12 += 16)
{
mapa12->packed = map->packed;
mapb12->packed = map->packed;
}
}
}
if ((mapa12 >softc->cmap_a12) || (mapb12 > softc->cmap_b12))
{
DEBUGF(3, ("24bit cmap: mapa12:%x, mapb12:%x\n",
mapa12,mapb12));
softc->cmap_begin_a12 = *begin & 0xf0;
softc->cmap_begin_b12 = 0;
softc->cmap_end_a12 = mapa12 - softc->cmap_a12;
softc->cmap_end_b12 = mapb12 - softc->cmap_b12 - 15;
softc->cg12d.flags |= CG12_A12BIT_CMAP;
softc->cg12d.flags |= CG12_B12BIT_CMAP;
}
}
else if (pgroup == PIXPG_4BIT_OVERLAY)
{
DEBUGF(3, ("4bit cmap: index:%x,count:%x\n",index,count));
for (i = 0, map -= index; count; i++, count--, map--)
map->packed =
tmp[0][i] | (tmp[1][i] << 8) | (tmp[2][i] << 16);
}
else
{
for (i = 0, map += index; count; i++, count--, map++)
map->packed =
tmp[0][i] | (tmp[1][i] << 8) | (tmp[2][i] << 16);
}
softc->cg12d.flags |= intr_flag;
if((shp->ver_release >> 8) <= 6)
enable_intr(softc);
else
ENABLE_INTR(softc);
}
/* FBIOGETCMAP */
else
{
if (softc->cg12d.flags &
(CG12_8BIT_CMAP | CG12_24BIT_CMAP | CG12_A12BIT_CMAP|
CG12_B12BIT_CMAP | CG12_ALT_CMAP | CG12_OVERLAY_CMAP |
CG12_4BIT_OVR_CMAP))
cg12_wait(minor(dev));
if (pgroup == PIXPG_4BIT_OVERLAY)
{
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + CG12_OMAP_SIZE - (index+count)));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for (i = 0, j = count; j; i++, j--)
{
color = *map_addr;
tmp[0][j - 1] = (color & 0x0000ff);
tmp[1][j - 1] = (color & 0x00ff00) >> 8;
tmp[2][j - 1] = (color & 0xff0000) >> 16;
}
}
else
{
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + index));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for (i = 0, j = count; j; i++, j--)
{
color = *map_addr;
tmp[0][i] = (color & 0x0000ff);
tmp[1][i] = (color & 0x00ff00) >> 8;
tmp[2][i] = (color & 0xff0000) >> 16;
}
}
if (copyout((caddr_t) tmp[0], (caddr_t) cmap->red, count) ||
copyout((caddr_t) tmp[1], (caddr_t) cmap->green, count) ||
copyout((caddr_t) tmp[2], (caddr_t) cmap->blue, count))
return (EFAULT);
}
}
break;
case FBIO_WID_ALLOC:
{
struct fb_wid_alloc *widalloc = (struct fb_wid_alloc *) data;
u_int type = widalloc->wa_type;
u_int count = widalloc->wa_count;
u_int index;
int pwr_of_2, found;
struct cg12_wid_alloc *widp = softc->wid_alloc;
DEBUGF(3, ("FBIO_WID_ALLOC: type:%x, count:%x\n", type, count));
switch (type)
{
case FB_WID_SHARED_8:
case FB_WID_SHARED_24:
{
for (index = 0; index < NWIDS; widp++, index++)
{
if(widp->type == type +1)
{
widalloc->wa_index = index;
return(0);
}
}
widp = softc->wid_alloc;
for (index = 0; index < NWIDS; widp++, index++)
{
if(!widp->owner)
{
widp->owner = u.u_procp;
widp->type = type + 1;
widalloc->wa_index = index;
return(0);
}
}
widalloc->wa_index = -1;
}
break;
case FB_WID_DBL_24:
{
if ((int)count < 0 || count > NWIDS ||
(pwr_of_2 = cg12_find_power(count)) == -1)
{
widalloc->wa_index = -1;
return(EINVAL);
}
for (j = 0; j < NWIDS; j += pwr_of_2)
{
found = 1;
widp = &softc->wid_alloc[j];
for (i = 0; i < count; i++, widp++)
{
if (widp->owner)
{
found = 0;
break;
}
}
if (found)
{
widp = &softc->wid_alloc[j];
for ( i = 0; i < count; i++, widp++)
{
widp->owner = u.u_procp;
widp->type = type + 1;
}
widalloc->wa_index = j;
return(0);
}
}
widalloc->wa_index = -1;
}
break;
default:
widalloc->wa_index = -1;
return(EINVAL);
}
if (widalloc->wa_index == -1)
return (ENOMEM);
}
break;
case FBIO_WID_FREE:
{
struct fb_wid_alloc *widalloc = (struct fb_wid_alloc *) data;
u_int type = widalloc->wa_type;
u_int count = widalloc->wa_count;
u_int index = widalloc->wa_index;
struct cg12_wid_alloc *widp = &softc->wid_alloc[index];
int cc;
DEBUGF(3, ("FBIO_WID_FREE: type:%x, count:%x, index:%x \n",
type, count, index));
if ((type == FB_WID_SHARED_8) || (type == FB_WID_SHARED_24))
return(0);
if (index >= NWIDS)
return EINVAL;
for (i = cc = 0; i < count; i++, widp++)
{
if (widp->owner == u.u_procp)
{
widp->owner = 0;
widp->type = 0;
}
else
cc = EINVAL;
}
if (cc == EINVAL)
return (cc);
}
break;
case FBIO_WID_GET:
case FBIO_WID_PUT:
{
struct fb_wid_list *widlist = (struct fb_wid_list *) data;
u_int index;
u_int count = widlist->wl_count;
struct fb_wid_item tmp[NWIDS];
u_int value;
DEBUGF(3, ("FBIO_WID_PUT/GET: count:%x, flags:%x\n", count,
widlist->wl_flags));
if ((count == 0) || (!widlist->wl_list))
return (EINVAL);
if (copyin((caddr_t) widlist->wl_list, (caddr_t) & tmp[0],
sizeof(struct fb_wid_item) * count))
return (EFAULT);
if (cmd == FBIO_WID_PUT)
{
for (i = 0; i < count; i++)
{
if (tmp[i].wi_type)
return (EINVAL);
index = tmp[i].wi_index & 0x3f;
softc->ctl_sp->wsc.addr = index;
softc->wid_tbl[index] = softc->ctl_sp->wsc.data;
for (j = 0; j < CG12_WID_ATTRS && tmp[i].wi_attrs;
j++, tmp[i].wi_attrs >>= 1)
{
if (tmp[i].wi_attrs & 1)
{
switch (j)
{
case CG12_WID_8_BIT:
case CG12_WID_24_BIT:
case CG12_WID_DBL_BUF_DISP_A:
case CG12_WID_DBL_BUF_DISP_B:
softc->wid_tbl[index] =
(softc->wid_tbl[index] & 0xc) |
(tmp[i].wi_values[j] & 3);
break;
case CG12_WID_ENABLE_2:
case CG12_WID_ENABLE_3:
softc->wid_tbl[index] =
(softc->wid_tbl[index] & 0x7) |
(tmp[i].wi_values[j] & 8);
break;
case CG12_WID_ALT_CMAP:
softc->wid_tbl[index] =
(softc->wid_tbl[index] & 0xb) |
(tmp[i].wi_values[j] & 4);
break;
default:
return (EINVAL);
}
}
}
}
softc->wid_begin = MIN(softc->wid_begin, tmp[0].wi_index);
softc->wid_end = MAX(softc->wid_end, tmp[0].wi_index + count);
softc->cg12d.flags |= CG12_WID_UPDATE;
if (widlist->wl_flags & FBDBL_DONT_BLOCK) {
if ((shp->ver_release >> 8) <= 6)
enable_intr(softc);
else
ENABLE_INTR(softc);
}
else
cg12_wait(minor(dev));
}
else
{
if (softc->cg12d.flags & CG12_WID_UPDATE)
cg12_wait(minor(dev));
for (i = 0; i < count; i++)
{
if (tmp[i].wi_type)
return (EINVAL);
softc->ctl_sp->wsc.addr = tmp[i].wi_index & 0x3f;
tmp[i].wi_attrs = 0xffff;
value = softc->ctl_sp->wsc.data;
for (j = 0; j < (NBBY*sizeof(int)); j++)
tmp[i].wi_values[j] = value;
}
if (copyout((caddr_t)tmp, (caddr_t) widlist->wl_list,
sizeof(struct fb_wid_item) * count))
return (EFAULT);
}
}
break;
default:
return ENOTTY;
}
return 0;
}
cg12_find_power(count)
u_int count;
{
int i;
for (i = 1; i <= NWIDS; i = i << 1)
if (i >= count)
return (i);
return (-1);
}
cg12_wait(unit)
int unit;
{
struct cg12_softc *softc = getsoftc(unit);
struct gp1_shmem *shp = (struct gp1_shmem *)softc->shmem;
int s;
DEBUGF(3, ("cg12_wait: entered\n"));
s = splr(softc->cg12pri);
softc->cg12d.flags |= CG12_SLEEPING;
if ((shp->ver_release >> 8) <= 6)
enable_intr(softc);
else
ENABLE_INTR(softc);
(void) sleep((caddr_t) softc, PZERO - 1);
(void) splx(s);
DEBUGF(3, ("cg12_wait: woken up\n"));
}
static
cg12_poll()
{
register int i, serviced = 0;
register struct cg12_softc *softc;
u_int cg12ctl;
DEBUGF(7, ("cg12_poll\n"));
for (softc = cg12_softc, i = ncg12; --i >= 0; softc++) {
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.eic_control = 0xffffffff;
softc->ctl_sp->apu.res2 = 0;
cg12ctl = softc->ctl_sp->eic.interrupt;
/* !!! */
if(cg12ctl & CG12_EIC_INT){
cg12_intr(softc);
serviced++;
}
}
return serviced;
}
static void
cg12_intr(softc)
register struct cg12_softc *softc;
{
register union fbunit *map;
u_int lo_addr, hi_addr, data;
int i, j;
u_int eic_int, istatus;
u_int *oprl, *oprh, *umemacc, *ctrl, *dram;
u_int *prom_ptr, *buffer, *buffer2;
u_char *prom_cptr, *cbuffer;
struct gp1_shmem *shp = (struct gp1_shmem *)softc->shmem;
struct gp1_sblock *sbp = softc->sblock;
eic_int = softc->ctl_sp->eic.interrupt;
if (eic_int & CG12_EIC_EICINT )
{
DEBUGF(1, ("cg12_intr: timer interrupt,c30_control:%x,int_reg:%x\n",
softc->ctl_sp->eic.c30_control, eic_int));
softc->ctl_sp->eic.timeout_reg = 0; /* ### */
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.reset = 0x03000000;
softc->ctl_sp->eic.reset = 0x02000000;
softc->ctl_sp->eic.interrupt = 0;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
softc->ctl_sp->ramdac.addr_lo = RAMDACWRITE(01);
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(02);
softc->ctl_sp->ramdac.control = RAMDACWRITE(0x40);
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.reset = 0x03000000;
softc->ctl_sp->eic.reset = 0x02000000;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
shp->fill280[0] = 0xffff;
PR_LOOPP(GP1_STATIC_BLOCKS - 1,
if (sbp->owner)
psignal(sbp->owner, SIGXCPU);
sbp++);
prom_ptr = (unsigned int *)(softc->base + 4);
prom_cptr = (unsigned char *)(softc->base + *prom_ptr);
DEBUGF(1, ("cg12_intr: prom_cptr:%x, *prom_cptr:%x\n",
prom_cptr, *prom_cptr));
oprl = (unsigned int *)softc->ctl_sp;
oprh = (unsigned int *)(4 + (unsigned int)softc->ctl_sp);
umemacc = (unsigned int *)(8 + (unsigned int)softc->ctl_sp);
ctrl = (unsigned int *)(12 + (unsigned int)softc->ctl_sp);
buffer =
(unsigned int *) new_kmem_zalloc(sizeof(data)*512*8,
KMEM_NOSLEEP);
buffer2 = buffer;
cbuffer = (u_char *)buffer;
DEBUGF(1, ("buffer:%x\n",buffer));
for (i = 0; i < 512 * 4; i++)
{
for (j = 0; j < 8; j++)
{
*cbuffer++ = *prom_cptr++;
}
}
DEBUGF(1, ("cbuffer:%x\n",cbuffer));
*ctrl |= 0x00000202;
*ctrl &= ~0x00000808;
*oprl = 0;
*oprh = 0;
*ctrl &= ~0x00000404;
for (i = 0; i <512; i++)
{
for (j = 0; j < 8; j++)
{
while(*ctrl & 0x00002020);
*umemacc = *buffer2++;
}
}
*oprh = 0x00000707;
*oprl = 0x00002a2a;
*ctrl &= ~0x00000303;
dram = (unsigned int *)softc->d_ptr;
*dram = 0x00001f0;
*(dram + 0x00001ee) = 0x08780006;
*(dram + 0x00001ef) = 0x16000000;
*(dram + 0x00001f0) = 0x6a00ffff;
softc->ctl_sp->eic.reset = 0x00000000;
softc->ctl_sp->apu.res2 = 0;
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.interrupt |= CG12_EIC_EN_EICINT;
softc->ctl_sp->apu.res2 = 0;
softc->ctl_sp->eic.host_control |= CG12_EIC_WSTATUS;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
kmem_free((char *)buffer, sizeof(data)*512*8);
cg12_binit(softc->ctl_sp);
cg12_init(softc->ctl_sp, softc->dev_id);
softc->ctl_sp->apu.vsg_ctl |= CG12_APU_EN_VID;
DEBUGF(0, ("Graphic accelerator panic.\n"));
DEBUGF(0, ("gpconfig called to download /usr/lib/gs.ucode.\n"));
return;
}
istatus = softc->ctl_sp->apu.istatus;
DEBUGF(3, ("cg12_intr:istatus:%x,int_reg:%x\n",
istatus, eic_int));
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.interrupt &= ~CG12_EIC_EN_HINT;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
if ((eic_int & CG12_EIC_HINT) && (istatus & CG12_APU_EN_HINT))
{
softc->ctl_sp->apu.ien0 &= ~CG12_APU_EN_HINT;
if ((shp->ver_release >> 8) >= 7)
softc->ctl_sp->apu.msg0 &= ~CG12_APU_EN_HINT;
if (softc->cg12d.flags & CG12_OVERLAY_CMAP)
{
map = softc->cmap_overlay + softc->cmap_begin_overlay;
lo_addr = 0;
hi_addr = 1;
softc->cg12d.flags &= ~CG12_OVERLAY_CMAP;
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + softc->cmap_begin_overlay));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for( i= softc->cmap_begin_overlay; i < softc->cmap_end_overlay;
i++, map++)
softc->ctl_sp->ramdac.control = map->packed;
softc->cmap_begin_overlay = 4;
softc->cmap_end_overlay = 0;
}
if (softc->cg12d.flags & CG12_4BIT_OVR_CMAP)
{
map = softc->cmap_4bit_ovr + 28 - softc->cmap_end_4bit_ovr;
lo_addr = 4;
hi_addr = 1;
softc->cg12d.flags &= ~CG12_4BIT_OVR_CMAP;
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + 28 - softc->cmap_end_4bit_ovr));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for( i= softc->cmap_begin_4bit_ovr; i< softc->cmap_end_4bit_ovr;
i++, map++)
softc->ctl_sp->ramdac.control = map->packed;
softc->cmap_begin_4bit_ovr = CG12_OMAP_SIZE - 4;
softc->cmap_end_4bit_ovr = 0;
}
if (softc->cg12d.flags & CG12_8BIT_CMAP)
{
map = softc->cmap_indexed + softc->cmap_begin_indexed;
lo_addr = 0;
hi_addr = 1;
softc->cg12d.flags &= ~CG12_8BIT_CMAP;
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + softc->cmap_begin_indexed));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for( i= softc->cmap_begin_indexed; i < softc->cmap_end_indexed;
i++, map++)
softc->ctl_sp->ramdac.color = map->packed;
softc->cmap_begin_indexed = CG12_CMAP_SIZE;
softc->cmap_end_indexed = 0;
}
if (softc->cg12d.flags & CG12_ALT_CMAP)
{
map = softc->cmap_alt + softc->cmap_begin_alt;
lo_addr = 0;
hi_addr = 0;
softc->cg12d.flags &= ~CG12_ALT_CMAP;
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + softc->cmap_begin_alt));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for( i= softc->cmap_begin_alt; i < softc->cmap_end_alt;
i++, map++)
softc->ctl_sp->ramdac.control = map->packed;
softc->cmap_begin_alt = CG12_CMAP_SIZE;
softc->cmap_end_alt = 0;
}
if (softc->cg12d.flags & CG12_WID_UPDATE)
{
softc->ctl_sp->wsc.addr = softc->wid_begin & 0x3f;
for (i = softc->wid_begin; i < softc->wid_end; i++)
{
softc->ctl_sp->wsc.data = softc->wid_tbl[i];
}
softc->cg12d.flags &= ~CG12_WID_UPDATE;
softc->wid_begin = NWIDS;
softc->wid_end = 0;
}
if (softc->cg12d.flags & CG12_24BIT_CMAP)
{
map = softc->cmap_rgb + softc->cmap_begin_rgb;
lo_addr = 0;
hi_addr = 0;
softc->cg12d.flags &= ~CG12_24BIT_CMAP;
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + softc->cmap_begin_rgb));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for( i= softc->cmap_begin_rgb; i < softc->cmap_end_rgb;
i++, map++)
softc->ctl_sp->ramdac.color = map->packed;
softc->cmap_begin_rgb = CG12_CMAP_SIZE;
softc->cmap_end_rgb = 0;
}
if (softc->cg12d.flags & CG12_A12BIT_CMAP)
{
map = softc->cmap_a12 + softc->cmap_begin_a12;
lo_addr = 0;
hi_addr = 2;
softc->cg12d.flags &= ~CG12_A12BIT_CMAP;
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + softc->cmap_begin_a12));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for( i= softc->cmap_begin_a12; i < softc->cmap_end_a12;
i++, map++)
softc->ctl_sp->ramdac.color = map->packed;
softc->cmap_begin_a12 = CG12_CMAP_SIZE;
softc->cmap_end_a12 = 0;
}
if (softc->cg12d.flags & CG12_B12BIT_CMAP)
{
map = softc->cmap_b12 + softc->cmap_begin_b12;
lo_addr = 0;
hi_addr = 3;
softc->cg12d.flags &= ~CG12_B12BIT_CMAP;
softc->ctl_sp->ramdac.addr_lo =
RAMDACWRITE((lo_addr + softc->cmap_begin_b12));
softc->ctl_sp->ramdac.addr_hi = RAMDACWRITE(hi_addr);
for( i= softc->cmap_begin_b12; i < softc->cmap_end_b12;
i++, map++)
softc->ctl_sp->ramdac.color = map->packed;
softc->cmap_begin_b12 = CG12_CMAP_SIZE;
softc->cmap_end_b12 = 0;
}
if (softc->cg12d.flags & CG12_SLEEPING)
{
softc->cg12d.flags &= ~CG12_SLEEPING;
wakeup((caddr_t) softc);
}
if((shp->ver_release >> 8) <=6)
softc->ctl_sp->apu.iclear |= CG12_APU_EN_HINT;
}
/* stary interrupts ? */
else if ((eic_int & CG12_EIC_HINT) && !(istatus & CG12_APU_EN_HINT))
{
istatus &= ~CG12_APU_EN_HINT;
softc->ctl_sp->apu.ien0 &= ~istatus;
softc->ctl_sp->apu.iclear |= istatus;
}
return;
}
cg12_cleanup(softc, gpunit)
struct cg12_softc *softc;
int gpunit;
{
register struct gp1_shmem *shp = (struct gp1_shmem *) softc->shmem;
register int allo, free, bit;
register u_char *own, m;
DEBUGF(3, ("cg12_cleanup:shp:%x,softc:%x,gpunit:%x\n",
shp, softc, gpunit));
if (shp->alloc_sem || cg12_sync((caddr_t) shp, 0))
return 0;
allo = IF68000(* (long *) &shp->host_alloc_h ^
* (long *) &shp->gp_alloc_h,
(shp->host_alloc_h ^ shp->gp_alloc_h) << 16 |
(shp->host_alloc_l ^ shp->gp_alloc_l));
free = 0;
bit = GP1_ALLOC_BIT(23);
own = shp->block_owners + GP1_OWNER_INDEX(23);
do {
if (allo & bit &&
((m = *own) >= NMINOR ||
m == (u_char) gpunit))
free |= bit;
own++;
} while ((bit <<= 1) >= 0);
IF68000(* (int *) &shp->host_alloc_h ^= free,
shp->host_alloc_h ^= free >> 16;
shp->host_alloc_l ^= free);
DEBUGF(3, ("cg12_cleanup: free:%x\n",free));
return free;
}
static
cg12_restart(gpminor, msg)
int gpminor;
char *msg;
{
register struct cg12_softc *softc = getsoftc(gpminor);
register struct gp1_sblock *sbp = softc->sblock;
register u_short *cp = (u_short *) softc->shmem;
register u_short *p =
(u_short *) &((struct gp1_shmem *)softc->shmem)->gp_alloc_h;
DEBUGF(3, ("cg12_restart:sbp:%x,cp:%x,p:%x,softc:%x,gpminor:%x,m:%s\n",
sbp,cp,p,softc,gpminor,msg));
PR_LOOPP(CG12_STATIC_BLOCKS - 1,
if (sbp->owner)
psignal(sbp->owner, SIGXCPU);
sbp++);
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.reset |= CG12_EIC_DSPRST;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
PR_LOOPP(GP1_BLOCK_SHORTS - 1, *cp++ = 0);
*p++ = 0x8000;
/* *p = 0x00ff; */
if (softc->dsp_active)
{
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.reset &= ~CG12_EIC_DSPRST;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
}
softc->restart++;
printf("Graphics processor restarted%s after time limit exceeded.\n\
\t You may see display garbage because of this action.\n", msg);
}
cg12_sync(shmem, fd)
caddr_t shmem;
int fd;
{
register short *shp,
host,
diff;
DEBUGF(3, ("cg12_sync: shmem:%x,fd:%x\n",shmem,fd));
if (!shmem)
return 0;
shp = (short *) &((struct gp1_shmem *) shmem)->host_count;
host = *shp++;
CDELAY ((diff = *shp - host, diff >= 0), cg12_sync_timeout);
if (diff < 0)
cg12_restart (fd >> 8, " by kernel");
return 0;
}
#if NOHWINIT
cg12_binit(ctl_sp)
struct cg12_ctl_sp *ctl_sp;
{
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
ctl_sp->eic.host_control = 0; /* no z-buf or dbl-buf */
ctl_sp->apu.res2 = 0;
/* !!! */
ctl_sp->apu.h_sync = 0x000b700b;
ctl_sp->apu.hblank = 0x0009d00d;
ctl_sp->apu.v_sync = 0x003ae00f;
ctl_sp->apu.vblank = 0x003ab027;
ctl_sp->apu.vdpyint = 0x00000000;
ctl_sp->apu.vssyncs = 0x000000af;
ctl_sp->apu.hdelays = 0x00013013;
ctl_sp->apu.hpitches = 0x00370090;
ctl_sp->apu.vsg_ctl = 0x0013181b;
ctl_sp->apu.stdaddr = 0x000a0000;
ctl_sp->apu.zoom = 0x00000000;
/*
* pixel swap within byte. the least significant pixel should go in the
* most significant bit.
*/
ctl_sp->dpu.control = 0x10000;
ctl_sp->dpu.reload_stb = 1;
ctl_sp->ramdac.addr_lo = RAMDACWRITE(0x01);
ctl_sp->ramdac.addr_hi = RAMDACWRITE(0x02);
ctl_sp->ramdac.control = RAMDACWRITE(0x50);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(0x02);
ctl_sp->ramdac.control = RAMDACWRITE(0);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(3);
ctl_sp->ramdac.control = RAMDACWRITE(0x40);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(4);
ctl_sp->ramdac.control = RAMDACWRITE(0xff);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(5);
ctl_sp->ramdac.control = RAMDACWRITE(3);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(6);
ctl_sp->ramdac.control = RAMDACWRITE(0);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(7);
ctl_sp->ramdac.control = RAMDACWRITE(0);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(8);
ctl_sp->ramdac.control = RAMDACWRITE(0x1f);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(9);
ctl_sp->ramdac.control = RAMDACWRITE(0);
ctl_sp->ramdac.addr_lo = RAMDACWRITE(0xc);
ctl_sp->ramdac.control = RAMDACWRITE(0);
}
#endif /* NOHWINIT */
cg12_init(ctl_sp, dev_id)
struct cg12_ctl_sp *ctl_sp;
unsigned int dev_id;
{
int i, wsc_val;
/* if cg12-B, overlay read mask for 5 bit overlay, else 2 */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(8);
ctl_sp->ramdac.addr_hi = RAMDACWRITE(0x02);
if ((dev_id == 3) || (dev_id == 2))
ctl_sp->ramdac.control = RAMDACWRITE(0x1f);
else if ((dev_id == 1) || (dev_id == 0))
ctl_sp->ramdac.control = RAMDACWRITE(0x3);
/* Here come the colormaps */
/* overlay */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(0);
ctl_sp->ramdac.addr_hi = RAMDACWRITE(1);
ctl_sp->ramdac.control = 0xffffff; /* white */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(1);
ctl_sp->ramdac.control = 0xffffff; /* white */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(2);
ctl_sp->ramdac.control = 0x00ff00; /* green */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(3);
ctl_sp->ramdac.control = 0x000000; /* black */
if ((dev_id == 2) || (dev_id ==3))
{
for (i = 0; i < 27; i++)
ctl_sp->ramdac.control = 0x000000; /* black */
ctl_sp->ramdac.control = 0xffffff; /* white */
}
/* init the gamma, indexed, buff-a, and buf-b */
for (i = 0; i < 256; i++)
{
/* gamma = grayscale ramp */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(i);
ctl_sp->ramdac.addr_hi = RAMDACWRITE(0);
ctl_sp->ramdac.color = RAMDACWRITE(i);
/* indexed has entry 0 white ... all others black */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(i);
ctl_sp->ramdac.addr_hi = RAMDACWRITE(1);
ctl_sp->ramdac.color = RAMDACWRITE((i) ? 0x00 : 0xff);
/*
* 12 bit buffer-a is a color repeated 16 times for 16 different
* colors
*/
ctl_sp->ramdac.addr_lo = RAMDACWRITE(i);
ctl_sp->ramdac.addr_hi = RAMDACWRITE(2);
ctl_sp->ramdac.color = RAMDACWRITE((i & 0xf0) | ((i & 0xf0) >> 4));
/* 12 bit buffer-b is 16 colors repeated 16 times */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(i);
ctl_sp->ramdac.addr_hi = RAMDACWRITE(3);
ctl_sp->ramdac.color = RAMDACWRITE(((i & 0x0f) << 4) | (i & 0x0f));
}
/* init the alternate cmap */
ctl_sp->ramdac.addr_lo = RAMDACWRITE(0);
ctl_sp->ramdac.addr_hi = RAMDACWRITE(0);
ctl_sp->ramdac.control = 0xffffff; /* white */
for (i = 0; i < 255; i++)
ctl_sp->ramdac.control = 0x000000; /* black */
/* and now the window-ids */
/* wsc 1 (dev_id == 0 or 1) = 3-color overlay, 8-bit; wsc 2 = just 8-bit */
wsc_val = (dev_id == 0 || dev_id == 1) ? 9 : 1;
ctl_sp->wsc.addr = 0;
for (i = 0; i < 64; i++)
ctl_sp->wsc.data = wsc_val;
ctl_sp->wsc.addr = 0;
}
struct cg12_cntxt {
struct {
u_int haccess;
u_int hpage;
} apu;
struct {
u_int pln_rd_msk_host;
u_int pln_wr_msk_host;
u_int pln_sl_host;
} dpu;
struct {
u_int host_control;
} eic;
};
cg12_rop(dpr, dx, dy, dw, dh, op, spr, sx, sy)
Pixrect *dpr;
int dx, dy, dw, dh;
int op;
Pixrect *spr;
int sx, sy;
{
Pixrect dmempr, smempr;
int cc, d_group, s_group;
struct cg12_cntxt context;
struct cg12_ctl_sp *ctl_sp;
/*
* only overlay, overlay_enable, 8bit_color, and control are mapped into
* the kernel. don't allow other planes to be manipulated in the kernel.
*/
d_group = s_group = PIXPG_CURRENT;
if (dpr->pr_ops == &cg12_ops)
{
d_group = PIX_ATTRGROUP(cg12_d(dpr)->planes);
ctl_sp = cg12_d(dpr)->ctl_sp;
}
if (spr && spr->pr_ops == &cg12_ops)
{
s_group = PIX_ATTRGROUP(cg12_d(spr)->planes);
ctl_sp = cg12_d(spr)->ctl_sp;
}
(void) cg12_cntxsave(ctl_sp, &context);
switch (d_group)
{
case PIXPG_CURRENT:
case PIXPG_8BIT_COLOR:
case PIXPG_OVERLAY:
case PIXPG_OVERLAY_ENABLE:
CG12_PR_TO_MEM(dpr, dmempr);
break;
default:
return 0;
}
switch (s_group)
{
case PIXPG_CURRENT:
case PIXPG_8BIT_COLOR:
case PIXPG_OVERLAY:
case PIXPG_OVERLAY_ENABLE:
CG12_PR_TO_MEM(spr, smempr);
break;
default:
return 0;
}
/* punt to mem_rop */
cc = cg12_no_accel_rop(dpr, dx, dy, dw, dh, op, spr, sx, sy);
(void) cg12_cntxrestore(ctl_sp, &context);
return cc;
}
/* Segment driver */
struct segcg12_data {
int flag;
struct cg12_cntxt *cntxtp; /* pointer to context */
struct segcg12_data *link; /* shared_list */
dev_t dev;
u_int offset;
};
struct segcg12_data *cg12_shared_list;
struct cg12_cntxt cg12_shared_context;
#define segcg12_crargs segcg12_data
#define SEG_CTXINIT (1) /* not initted */
#define SEG_SHARED (2) /* shared context */
#define SEG_LOCK (4) /* lock page */
/*ARGSUSED*/
int
cgtwelvesegmap(dev, offset, as, addr, len, prot, maxprot, flags, cred)
dev_t dev;
register u_int offset;
struct as *as;
addr_t *addr;
register u_int len;
u_int prot, maxprot;
u_int flags;
struct ucred *cred;
{
register struct cg12_softc *softc;
struct segcg12_crargs dev_a;
int segcg12_create();
register i;
int ctxflag = 0;
enum as_res as_unmap();
int as_map();
DEBUGF(3, ("cg12segmap:dev:%x,off:%x,as:%x, addr:%x, len:%x,flags:%x\n",
dev, offset, as, addr, len, flags));
softc = getsoftc(minor(dev));
for (i = 0; i < len; i += PAGESIZE)
{
if (cgtwelvemmap(dev, (off_t)offset + i, (int)maxprot) == -1)
return (ENXIO);
if ((offset+i >= (off_t)softc->addr_tbl[0].offset) &&
(offset+i < (off_t)softc->addr_tbl[5].offset +
softc->addr_tbl[5].size))
ctxflag++;
}
if ((flags & MAP_FIXED) == 0)
{
/*
* Pick an address w/o worrying about
* any vac alignment contraints.
*/
map_addr(addr, len, (off_t)0, 0);
if (*addr == NULL)
return (ENOMEM);
}
else
{
/*
* User specified address -
* Blow away any previous mappings.
*/
i = (int)as_unmap((struct as *)as, *addr, len);
}
/*
* record device number; mapping function doesn't do anything smart
* with it, but it takes it as an argument. the offset is needed
* for mapping objects beginning some ways into them.
*/
dev_a.dev = dev;
dev_a.offset = offset;
/*
* determine whether this is a shared mapping, or a private
* one. if shared, link it onto the shared list, if private,
* create a private cg12 context.
*/
if (flags & MAP_SHARED) { /* shared mapping */
struct segcg12_crargs *a;
/* link it onto the shared list */
a = cg12_shared_list;
cg12_shared_list = &dev_a;
dev_a.link = a;
dev_a.flag = SEG_SHARED;
dev_a.cntxtp = (ctxflag) ? &cg12_shared_context : NULL;
} else { /* private mapping */
dev_a.link = NULL;
dev_a.flag = 0;
dev_a.cntxtp =
(ctxflag) ?
(struct cg12_cntxt *)
new_kmem_zalloc(sizeof (struct cg12_cntxt),KMEM_NOSLEEP) : NULL;
}
DEBUGF(3, ("cg12segmap: as:%x,*addr:%x,len:%x,&dev_a:%x,ctxflag:%x\n",
as, *addr, len, &dev_a,ctxflag));
return(as_map((struct as *)as, *addr,len, segcg12_create, (caddr_t)&dev_a));
}
static int segcg12_dup(/* seg, newsegp */);
static int segcg12_unmap(/* seg, addr, len */);
static int segcg12_free(/* seg */);
static faultcode_t segcg12_fault(/* seg, addr, len, type, rw */);
static int segcg12_checkprot(/* seg, addr, size, prot */);
static int segcg12_badop();
static int segcg12_incore();
struct seg_ops segcg12_ops = {
segcg12_dup, /* dup */
segcg12_unmap, /* unmap */
segcg12_free, /* free */
segcg12_fault, /* fault */
segcg12_badop, /* faulta */
segcg12_badop, /* unload */
segcg12_badop, /* setprot */
segcg12_checkprot,/* checkprot */
segcg12_badop, /* kluster */
(u_int (*)()) NULL, /* swapout */
segcg12_badop, /* sync */
segcg12_incore /* incore */
};
/*
* Gets a cg12_mapped entry for the specified process. Either returns
* pointer to existing entry or allocates new one if not found.
*/
static struct cg12_mapped *
get_cg12_mapped(softc, pid)
register struct cg12_softc *softc;
register int pid;
{
register struct cg12_mapped *mp, *new_mp;
if ((new_mp = softc->total_mapped) != NULL_MAPPED)
do {
if ((mp = new_mp)->pid == pid)
return(mp);
} while((new_mp = mp->next) != NULL_MAPPED);
new_mp = (struct cg12_mapped *)
new_kmem_zalloc(sizeof (struct cg12_mapped),KMEM_NOSLEEP);
if (new_mp == NULL_MAPPED)
panic("Can't allocate cg12_mapped structure");
DEBUGF(3, ("get_cg12_mapped: new_mp:%x, pid:%x\n", new_mp, pid));
if (softc->total_mapped == NULL_MAPPED)
softc->total_mapped = new_mp;
else {
mp->next = new_mp;
new_mp->prev = mp;
}
new_mp->pid = pid;
return(new_mp);
}
static void
free_cg12_mapped(softc, mp)
register struct cg12_softc *softc;
register struct cg12_mapped *mp;
{
DEBUGF(3, ("free_cg12_mapped: mp:%x, pid:%x, size left=%d\n", mp, mp->pid, mp->total));
if (mp->next != NULL_MAPPED)
mp->next->prev = mp->prev;
if (mp->prev != NULL_MAPPED)
mp->prev->next = mp->next;
else
softc->total_mapped = mp->next;
kmem_free((char *) mp, sizeof (struct cg12_mapped));
}
static
int
segcg12_create(seg, argsp)
struct seg *seg;
caddr_t argsp;
{
register struct segcg12_data *dp;
register struct cg12_softc *softc;
register struct cg12_mapped *mp;
int i;
DEBUGF(3, ("segcg12_create: seg:%x, argsp:%x\n", seg, argsp));
dp = (struct segcg12_data *)
new_kmem_zalloc(sizeof (struct segcg12_data),KMEM_NOSLEEP);
*dp = *((struct segcg12_crargs *)argsp);
seg->s_ops = &segcg12_ops;
seg->s_data = (char *)dp;
softc = getsoftc(minor(dp->dev));
mp = get_cg12_mapped(softc, u.u_procp->p_pid);
mp->total += seg->s_size;
DEBUGF(3, ("segcg12_create: mp:%x, pid:%x, size now=%d\n", mp, mp->pid, mp->total));
{
struct seg_tbl *segtbl = softc->seg_tbl;
for ( i = 0; i < NMINOR; i++, segtbl++)
{
if (segtbl->owner && (segtbl->owner->p_pid == u.u_procp->p_pid))
{
DEBUGF(3, ("segcg12_create: pid:%x, gpminor:%x, i:%x\n",
segtbl->owner->p_pid, segtbl->gpminor, i));
return (0);
}
}
segtbl = softc->seg_tbl;
for ( i = 4; i < NMINOR; i++, segtbl++)
{
if (!segtbl->owner)
{
segtbl->owner = u.u_procp;
segtbl->gpminor = i;
DEBUGF(3, ("segcg12_create: pid:%x,gpminor:%x\n",
segtbl->owner->p_pid, segtbl->gpminor));
return (0);
}
}
}
mp->total -= seg->s_size;
DEBUGF(3, ("segcg12_create failed: mp:%x, pid:%x, size left=%d\n", mp, mp->pid, mp->total));
if (mp->total == 0)
free_cg12_mapped(softc, mp);
return (ENXIO);
}
static
int
segcg12_dup(seg, newseg)
struct seg *seg, *newseg;
{
register struct segcg12_data *sdp = (struct segcg12_data *)seg->s_data;
register struct segcg12_data *ndp;
DEBUGF(3, ("segcg12_dup: seg:%x, newseg:%x\n", seg, newseg));
(void) segcg12_create(newseg, (caddr_t)sdp);
ndp = (struct segcg12_data *)newseg->s_data;
if (sdp->flag & SEG_SHARED) {
struct segcg12_crargs *a;
a = cg12_shared_list;
cg12_shared_list = ndp;
ndp->link = a;
} else if ((sdp->flag & SEG_LOCK) == 0) {
if (sdp->cntxtp == NULL)
ndp->cntxtp = NULL;
else {
ndp->cntxtp =
(struct cg12_cntxt *)
new_kmem_zalloc(sizeof (struct cg12_cntxt),KMEM_NOSLEEP);
*ndp->cntxtp = *sdp->cntxtp;
}
}
return(0);
}
static
int
segcg12_unmap(seg, addr, len)
register struct seg *seg;
register addr_t addr;
u_int len;
{
register struct segcg12_data *sdp = (struct segcg12_data *)seg->s_data;
register struct seg *nseg;
addr_t nbase;
u_int nsize;
void hat_unload();
void hat_newseg();
DEBUGF(3, ("segcg12_unmap: seg:%x, addr:%x, len:%x\n", seg, addr, len));
/*
* Check for bad sizes
*/
if (addr < seg->s_base || addr + len > seg->s_base + seg->s_size ||
(len & PAGEOFFSET) || ((u_int)addr & PAGEOFFSET))
panic("segdev_unmap");
/*
* Unload any hardware translations in the range to be taken out.
*/
hat_unload(seg,addr,len);
/*
* Check for entire segment
*/
if (addr == seg->s_base && len == seg->s_size) {
seg_free(seg);
return (0);
}
/*
* Partial unmap - keep track of how much is still mapped by this
* process
*/
{
register struct cg12_softc *softc;
register struct cg12_mapped *mp;
softc = getsoftc(minor(sdp->dev));
mp = get_cg12_mapped(softc, u.u_procp->p_pid);
mp->total -= len;
DEBUGF(3, ("segcg12_unmap: mp:%x, pid:%x, size left=%d\n", mp, mp->pid, mp->total));
}
/*
* Check for beginning of segment
*/
if (addr == seg->s_base) {
seg->s_base += len;
seg->s_size -= len;
return (0);
}
/*
* Check for end of segment
*/
if (addr + len == seg->s_base + seg->s_size) {
seg->s_size -= len;
return (0);
}
/*
* The section to go is in the middle of the segment,
* have to make it into two segments. nseg is made for
* the high end while seg is cut down at the low end.
*/
nbase = addr + len; /* new seg base */
nsize = (seg->s_base + seg->s_size) - nbase; /* new seg size */
seg->s_size = addr - seg->s_base; /* shrink old seg */
nseg = seg_alloc(seg->s_as, nbase, nsize);
if (nseg == NULL)
panic("segcg12_unmap seg_alloc");
nseg->s_ops = seg->s_ops;
/* figure out what to do about the new context */
nseg->s_data = (caddr_t)new_kmem_alloc(sizeof (struct segcg12_data),KMEM_NOSLEEP);
if (sdp->flag & SEG_SHARED) {
struct segcg12_crargs *a;
a = cg12_shared_list;
cg12_shared_list = (struct segcg12_data *)nseg->s_data;
((struct segcg12_data *)nseg->s_data)->link = a;
} else {
if (sdp->cntxtp == NULL)
((struct segcg12_data *)nseg->s_data)->cntxtp = NULL;
else {
((struct segcg12_data *)nseg->s_data)->cntxtp =
(struct cg12_cntxt *)
new_kmem_zalloc(sizeof (struct cg12_cntxt),KMEM_NOSLEEP);
*((struct segcg12_data *)nseg->s_data)->cntxtp =
*sdp->cntxtp;
}
}
/*
* Now we do something so that all the translations which used
* to be associated with seg but are now associated with nseg.
*/
hat_newseg(seg, nseg->s_base, nseg->s_size, nseg);
return(0);
}
static
int
segcg12_free(seg)
struct seg *seg;
{
register struct segcg12_data *sdp = (struct segcg12_data *)seg->s_data;
register struct cg12_softc *softc = getsoftc(minor(sdp->dev));
DEBUGF(3, ("segcg12_free: seg:%x,pid:%x\n", seg, u.u_procp->p_pid));
/* If this process has anything else mapped then skip cleanup */
{
register struct cg12_mapped *mp;
mp = get_cg12_mapped(softc, u.u_procp->p_pid);
mp->total -= seg->s_size;
DEBUGF(3, ("segcg12_free: mp:%x, pid:%x, size left=%d\n", mp, mp->pid, mp->total));
/* if still has mappings, just clean up segment only */
if (mp->total > 0) {
if ((sdp->flag & SEG_SHARED) == 0 && (sdp->cntxtp != NULL))
kmem_free((char *)sdp->cntxtp, sizeof(struct cg12_cntxt));
if (seg == softc->curcntxt)
softc->curcntxt = NULL;
kmem_free((char *)sdp, sizeof (*sdp));
return(0);
}
free_cg12_mapped(softc, mp);
}
if (seg == softc->curcntxt) {
softc->curcntxt = NULL;
}
{
struct gp1_sblock *sbp = softc->sblock;
PR_LOOPP(CG12_STATIC_BLOCKS - 1,
if(sbp->owner) {
DEBUGF(4, ("segcg12_free:sbp_pid:%x\n",sbp->owner->p_pid));
if (sbp->owner->p_pid == u.u_procp->p_pid)
sbp->owner = 0;
}
sbp++);
}
{
struct cg12_wid_alloc *widp = softc->wid_alloc;
PR_LOOPP(NWIDS - 1,
if(widp->owner) {
DEBUGF(4, ("segcg12_free:wid_pid:%x\n",widp->owner->p_pid));
if ((widp->type != FB_WID_SHARED_8 + 1) &&
(widp->type != FB_WID_SHARED_24 + 1) &&
(widp->owner->p_pid == u.u_procp->p_pid))
{
widp->owner = 0;
widp->type = 0;
}
}
widp++);
}
{
struct seg_tbl *segtbl = softc->seg_tbl;
PR_LOOPP(NMINOR - 1,
if(segtbl->owner && (segtbl->owner->p_pid == u.u_procp->p_pid))
{
DEBUGF(3, ("segcg12_free:segtbl_pid:%x,gpminor:%x\n",
segtbl->owner->p_pid,segtbl->gpminor));
segtbl->owner = 0;
(void) cg12_cleanup(softc, segtbl->gpminor);
segtbl->gpminor = 0;
}
segtbl++);
}
if ((sdp->flag & SEG_SHARED) == 0 && (sdp->cntxtp != NULL))
kmem_free((char *)sdp->cntxtp, sizeof(struct cg12_cntxt));
kmem_free((char *)sdp, sizeof (*sdp));
return(0);
}
/*ARGSUSED*/
static
faultcode_t
segcg12_fault(seg, addr, len, type, rw)
register struct seg *seg;
addr_t addr;
u_int len;
enum fault_type type;
enum seg_rw rw;
{
register addr_t adr;
register struct segcg12_data *current
= (struct segcg12_data *)seg->s_data;
register struct segcg12_data *old;
int pf;
register struct cg12_softc *softc = getsoftc(minor(current->dev));
void hat_devload();
void hat_unload();
if (type != F_INVAL) {
return(FC_MAKE_ERR(EFAULT));
}
if (current->cntxtp && softc->curcntxt != seg) {
if (softc->curcntxt != NULL) {
old = (struct segcg12_data *)softc->curcntxt->s_data;
/*
* wipe out old valid mapping.
*/
hat_unload(softc->curcntxt,
softc->curcntxt->s_base,
softc->curcntxt->s_size);
if (!(current->flag == SEG_SHARED &&
old->flag == SEG_SHARED))
{
if (cg12_cntxsave(
(struct cg12_ctl_sp *)softc->ctl_sp,
old->cntxtp) == 0)
return(FC_HWERR);
if (cg12_cntxrestore(
(struct cg12_ctl_sp *)softc->ctl_sp,
current->cntxtp) == 0)
return(FC_HWERR);
}
} else {
if ((current->flag != SEG_SHARED) &&
(current->cntxtp->apu.haccess != 0))
{
if (cg12_cntxrestore(
(struct cg12_ctl_sp *)softc->ctl_sp,
current->cntxtp) == 0)
return(FC_HWERR);
} else {
DEBUGF(2, ("segcg12_fault: seg:%x, addr:%x, len:%x\n",
seg, addr, len));
}
}
/*
* switch software "context"
*/
softc->curcntxt = seg;
}
for (adr = addr; adr < addr + len; adr += PAGESIZE) {
pf = cgtwelvemmap(current->dev,
(off_t)current->offset+(adr-seg->s_base),
PROT_READ|PROT_WRITE);
if (pf == -1)
return (FC_MAKE_ERR(EFAULT));
hat_devload(seg, adr, pf, PROT_READ|PROT_WRITE|PROT_USER, 0 /*don't lock*/);
}
return(0);
}
/*ARGSUSED*/
static
int
segcg12_checkprot(seg, addr, len, prot)
struct seg *seg;
addr_t addr;
u_int len, prot;
{
DEBUGF(3, ("segcg12_checkprot: seg:%x, addr:%x, len:%x, prot:%x\n",
seg, addr, len, prot));
return(PROT_READ|PROT_WRITE);
}
/*
* segdev pages are always "in core".
*/
/*ARGSUSED*/
static
segcg12_incore(seg, addr, len, vec)
struct seg *seg;
addr_t addr;
register u_int len;
register char *vec;
{
u_int v = 0;
DEBUGF(3, ("segcg12_incore: seg:%x, addr:%x, len:%x, vec:%x\n",
seg, addr, len, vec));
for (len = (len + PAGEOFFSET) & PAGEMASK; len; len -= PAGESIZE,
v += PAGESIZE)
*vec++ = 1;
return (v);
}
static
segcg12_badop()
{
/*
* silently fail.
*/
DEBUGF(3, ("segcg12_badop:\n"));
return(0);
}
cg12_cntxsave(ctl_sp, saved)
struct cg12_ctl_sp *ctl_sp;
struct cg12_cntxt *saved;
{
saved->eic.host_control = ctl_sp->eic.host_control;
saved->apu.hpage = ctl_sp->apu.hpage;
saved->apu.haccess = ctl_sp->apu.haccess;
saved->dpu.pln_sl_host = ctl_sp->dpu.pln_sl_host;
saved->dpu.pln_rd_msk_host = ctl_sp->dpu.pln_rd_msk_host;
saved->dpu.pln_wr_msk_host = ctl_sp->dpu.pln_wr_msk_host;
return(1);
}
cg12_cntxrestore(ctl_sp, saved)
struct cg12_ctl_sp *ctl_sp;
struct cg12_cntxt *saved;
{
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
ctl_sp->eic.host_control = saved->eic.host_control;
/* !!! */
ctl_sp->apu.hpage = saved->apu.hpage;
ctl_sp->apu.haccess = saved->apu.haccess;
ctl_sp->dpu.pln_sl_host = saved->dpu.pln_sl_host;
ctl_sp->dpu.pln_rd_msk_host = saved->dpu.pln_rd_msk_host;
ctl_sp->dpu.pln_wr_msk_host = saved->dpu.pln_wr_msk_host;
return(1);
}
/*
* The following code is only necessary because the cg12 8-bit and 24-bit
* frame buffers share the same vram. The normal mem_rop code (properly)
* handles left and right end non-32-bit-aligned entries by reading a 32-bit
* int and leaving the unused portion unaffected, then writing back the
* 32-bit int. On the cg12, this has the unfortunate effect of converting
* the unused portion to 8-bit values which is bad if the underlying pixels
* were 24-bit values.
*
* we can only flow to this code if the operation could not be accelerated
* and we will only use this code if the destination is 8-bit. otherwise,
* mem_rop will still be used. this code is optimized more for space than
* for speed. the user code version is better optimized for speed than space.
*/
cg12_no_accel_rop(dpr, dx, dy, w, h, op, spr, sx, sy)
Pixrect *dpr, *spr;
int dx, dy, w, h, op, sx, sy;
{
int i, j, incr, end;
int wsx, src_offset, src_bytes, src_line;
int wdx, dst_offset, dst_bytes, dst_line;
unsigned char *src, src_val, *dst;
struct mprp_data *src_data, *dst_data;
/*
* we only need this routine for 8-bit sharing memory with 24-bit. if the
* destination is not 8-bit, then mem_rop can handle things just fine.
*/
if (dpr->pr_depth != 8)
return pr_rop(dpr, dx, dy, w, h, op, spr, sx, sy);
/* make sure all coordinates are within screen or region bounds */
if (!(op & PIX_DONTCLIP))
{
struct pr_subregion d;
struct pr_prpos s;
extern int pr_clip();
d.pr = dpr;
d.pos.x = dx;
d.pos.y = dy;
d.size.x = w;
d.size.y = h;
s.pr = spr;
if (spr)
{
s.pos.x = sx;
s.pos.y = sy;
}
(void) pr_clip(&d, &s);
dx = d.pos.x;
dy = d.pos.y;
w = d.size.x;
h = d.size.y;
if (spr)
{
sx = s.pos.x;
sy = s.pos.y;
}
}
if (w <= 0 || h <= 0)
return 0;
/* translate the origin */
dx += mprp_d(dpr)->mpr.md_offset.x;
dy += mprp_d(dpr)->mpr.md_offset.y;
if (spr)
{
sx += mprp_d(spr)->mpr.md_offset.x;
sy += mprp_d(spr)->mpr.md_offset.y;
}
--w;
/*
* Because of overlapping copies, must decide bottom up or top down. If
* null source, then initialize the first destination line as the source
* and start the copy from the second line.
*/
if ((sy < dy) && (spr && spr->pr_ops == dpr->pr_ops))
{
incr = -1;
end = dy - 1;
if (spr)
{
dst_line = dy + h - 1;
src_line = sy + h - 1;
}
else
{
dst_line = dy + h - 2;
sx = dx;
src_line = dy + h - 1;
}
}
else
{
incr = 1;
end = dy + h;
if (spr)
{
dst_line = dy;
src_line = sy;
}
else
{
dst_line = dy + 1;
sx = dx;
src_line = dy;
}
}
/* data structure and destination memory address */
dst_data = mprp_d(dpr);
dst = (unsigned char *) dst_data->mpr.md_image;
dst_bytes = dst_data->mpr.md_linebytes;
if (spr)
{
src_data = mprp_d(spr);
src = (unsigned char *) src_data->mpr.md_image;
src_bytes = src_data->mpr.md_linebytes;
}
else
{
src_bytes = 0;
dst_line -= incr; /* didn't seed for bitblt */
}
if (sx > dx) /* forward */
{
i = sx + w + 1;
j = 1;
}
else
{
i = sx - 1;
j = -1;
}
for (; dst_line != end; src_line += incr, dst_line += incr)
{
src_offset = src_line * src_bytes;
dst_offset = dst_line * dst_bytes;
if (j == 1)
{
wsx = sx;
wdx = dx + dst_offset;
}
else
{
wsx = sx + w;
wdx = dx + w + dst_offset;
}
for (; wsx != i; wsx += j, wdx += j)
{
if (spr)
{
switch (spr->pr_depth)
{
case 1:
src_val = (src[(wsx>>3)+src_offset] >> (7-(wsx%8)))&1;
if (src_data->mpr.md_flags & MP_REVERSEVIDEO)
src_val = ~src_val & 1;
src_val = src_val
? ((PIX_OPCOLOR(op)) ? PIX_OPCOLOR(op) : ~0) : 0;
break;
case 8:
src_val = src[wsx + src_offset];
break;
}
}
else
src_val = PIX_OPCOLOR(op);
switch (PIX_OP(op) >> 1)
{
case 0: /* CLR */
dst[wdx] = 0;
break;
case 1: /* ~s&~d or ~(s|d) */
dst[wdx] = ~(src_val | dst[wdx]);
break;
case 2: /* ~s&d */
dst[wdx] = ~src_val & dst[wdx];
break;
case 3: /* ~s */
dst[wdx] = ~src_val;
break;
case 4: /* s&~d */
dst[wdx] = src_val & ~dst[wdx];
break;
case 5: /* ~d */
dst[wdx] = ~dst[wdx];
break;
case 6: /* s^d */
dst[wdx] = src_val ^ dst[wdx];
break;
case 7: /* ~s|~d or ~(s&d) */
dst[wdx] = ~(src_val & dst[wdx]);
break;
case 8: /* s&d */
dst[wdx] = src_val & dst[wdx];
break;
case 9: /* ~(s^d) */
dst[wdx] = ~(src_val ^ dst[wdx]);
break;
case 10: /* DST */
break;
case 11: /* ~s|d */
dst[wdx] = ~src_val | dst[wdx];
break;
case 12: /* SRC */
dst[wdx] = src_val;
break;
case 13: /* s|~d */
dst[wdx] = src_val | ~dst[wdx];
break;
case 14: /* s|d */
dst[wdx] = src_val | dst[wdx];
break;
case 15: /* SET */
dst[wdx] = PIX_ALL_PLANES;
break;
}
}
}
return 0;
}
enable_intr(softc)
struct cg12_softc *softc;
{
if (!(softc->ctl_sp->apu.ien0 & CG12_APU_EN_HINT))
softc->ctl_sp->apu.iclear |= CG12_APU_EN_HINT;
softc->ctl_sp->apu.ien0 |= CG12_APU_EN_HINT;
/* !!! see cgtwelve.c EIC-COMMENTS before changing !!! */
softc->ctl_sp->eic.interrupt |= CG12_EIC_EN_HINT;
softc->ctl_sp->apu.res2 = 0;
/* !!! */
}