cgsix.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#pragma weak setintrenable
/*
* Cgsix theory of operation:
*
* Most cg6 operations are done by mapping the cg6 components into
* user process memory. User processes that share mappings (typically
* pixrect programs) must cooperate among themselves to prevent damaging
* the state of the cg6. User processes may also acquire private
* mappings (MAP_PRIVATE flag to mmap(2)), in which case the cg6 segment
* driver will preserve device state for each mapping.
*
* Note that the segment driver may go away in the future.
*
* cg6_mmap interprets the device offset as follows:
*
* CG6_VBASE 0x70000000
* CG6_VADDR_FBC 0x70000000 fbc mapping
* CG6_VADDR_TEC 0x70001000 tec mapping
* CG6_VADDR_CMAP 0x70002000 colormap dacs
* CG6_VADDR_FHC 0x70004000 fhc mapping
* CG6_VADDR_THC 0x70005000 thc mapping
* CG6_VADDR_ROM 0x70006000 eprom mapping
* CG6_VADDR_COLOR 0x70016000 framebuffer mapping
* CG6_VADDR_DHC 0x78000000 dac hardware
* CG6_VADDR_ALT 0x78002000 alternate registers (?)
* CG6_VADDR_UART 0x78004000 uart, if any
* CG6_VADDR_VRT 0x78006000 vertical retrace counter page
*
* The lengths of these mappings should be:
*
* CG6_CMAP_SZ 0x2000
* CG6_FBCTEC_SZ 0x2000
* CG6_FHCTHC_SZ 0x2000
* CG6_ROM_SZ 0x10000
* CG6_FB_SZ 0x100000
* CG6_DHC_SZ 0x2000
* CG6_ALT_SZ 0x2000
*
* Mappings to the fbc and tec registers may be MAP_PRIVATE, in which case
* the segment driver keeps a per-context copy of the fbc and tec
* registers in local memory. Only one context at a time may have valid
* mappings. If a process tries to access the registers through an
* invalid mapping, the segment driver in invoked to swap register state
* and validate the mappings.
*
* In the case of the buggy LSC revision 2. chip, the framebuffer mapping
* is also considered part of a context. This is to ensure that the
* registers are idle before the framebuffer is touched.
*
* Mappings to FBC, TEC and framebuffer may be made seperately, in which
* case the driver uses heuristics to bind seperate mappings into a single
* context. These heuristics may break down if mappings are done in a
* funny order or in a multi-threaded environment, so seperate mappings
* are not recommended.
*
* Finally, processes have the option of mapping the "vertical retrace
* page". This is a page in shared memory containing a 32-bit integer
* that is incremented each time a vertical retrace interrupt occurs. It
* is used so that programs may synchronize themselves with vertical
* retrace.
*/
/*
* SBus accelerated 8 bit color frame buffer driver
*/
#include <sys/sysmacros.h>
#include <sys/visual_io.h>
#include <sys/pr_impl_util.h>
#include <sys/pr_planegroups.h>
#include <sys/ddi_impldefs.h>
#include <sys/machsystm.h>
#define CG6DEBUG 0
/* configuration options */
#define CG6DELAY(c, n) \
{ \
register int N = n; \
while (--N > 0) { \
if (c) \
break; \
drv_usecwait(1); \
} \
}
#if CG6DEBUG >= 2
int cg6_debug = 0;
#else
#endif
/* config info */
static struct cb_ops cg6_cb_ops = {
cg6_open, /* open */
cg6_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
cg6_ioctl, /* ioctl */
cg6_devmap, /* devmap */
cg6_mmap, /* mmap */
cg6_segmap, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* cb_prop_op */
0, /* streamtab */
CB_REV, /* rev */
nodev, /* int (*cb_aread)() */
nodev /* int (*cb_awrite)() */
};
static int cg6_power(dev_info_t *, int, int);
DEVO_REV, /* devo_rev, */
0, /* refcnt */
cg6_info, /* info */
nulldev, /* identify */
nulldev, /* probe */
cg6_attach, /* attach */
cg6_detach, /* detach */
nodev, /* reset */
&cg6_cb_ops, /* driver operations */
(struct bus_ops *)0, /* bus operations */
};
/*
* This stucture is used to contain the driver
* private mapping data (one for each requested
* device mapping). A pointer to this data is
* passed into each mapping callback routine.
*/
struct cg6map_pvt {
/* this context */
};
static struct ddi_device_acc_attr endian_attr = {
};
/* how much to map */
#define CG6MAPSIZE MMAPSIZE(0)
/* vertical retrace counter page */
#ifndef CG6_VRT_SZ
#define CG6_VRT_SZ 8192
#endif
/* boardrev bits */
#define BRDRV_GX 0x00
#define BRDRV_LSC 0x08
#define BRDRV_DUPLO 0x10
#define BRDRV_LEGOHR 0x18
#define BRDRV_QAUDRO 0x20
#define TEC_EN_VBLANK_IRQ 0x20
#define TEC_HCMISC_IRQBIT 0x10
/* position value to use to disable HW cursor */
/*
* Per-context info:
* many registers in the tec and fbc do
*/
struct cg6_cntxt {
int flag;
struct {
} tec;
struct {
struct l_fbc_misc misc;
struct l_fbc_rasterop rasterop;
union l_fbc_pattalign pattalign;
} fbc;
};
/* per-unit data */
struct cg6_softc {
struct softcur {
short enable; /* cursor enable */
short pad1;
} cur;
union { /* shadow overlay color map */
} omap_image;
union { /* shadow color map */
} cmap_image;
int *vrtpage; /* pointer to VRT page */
int vrtmaps; /* number of VRT page maps */
int vrtflag; /* vrt interrupt flag */
int chiprev; /* fbc chip revision # */
int emulation; /* emulation type, normally cgsix */
int mapped_by_prom; /* $#!@ SVr4 */
int waiting;
int cg6_suspended; /* true if driver is suspended */
int vidon; /* video enable state */
int intr_flag;
};
void **);
devmap_cookie_t, void **, devmap_cookie_t, void **);
static
struct devmap_callback_ctl cg6map_ops = {
DEVMAP_OPS_REV, /* devmap_ops version number */
cg6map_map, /* devmap_ops map routine */
cg6map_access, /* devmap_ops access routine */
cg6map_dup, /* devmap_ops dup routine */
cg6map_unmap, /* devmap_ops unmap routine */
};
static void *cg6_softc_head;
/* default structure for FBIOGATTR ioctl */
/* real_type owner */
/* fbtype: type h w depth cms size */
/* fbsattr: flags emu_type dev_specific */
{0, FBTYPE_SUN4COLOR, {0}},
/* emu_types */
};
/*
* handy macros
*/
/* convert softc to data pointers */
#define cg6_int_enable(softc) \
{\
#define cg6_int_disable_intr(softc) \
{\
#define cg6_int_disable(softc) \
{\
/* check if color map update is pending */
#define cg6_update_pending(softc) \
/*
* forward references
*/
uint_t);
static void cg6_setcurpos(struct cg6_softc *);
static void cg6_setcurshape(struct cg6_softc *);
struct cg6_cntxt *);
struct cg6_cntxt *);
/* Loadable Driver stuff */
&mod_driverops, /* Type of module. This one is a driver */
"cgsix driver v%I%", /* Name of the module. */
&cgsix_ops, /* driver ops */
};
static struct modlinkage modlinkage = {
};
int
_init(void)
{
register int e;
if ((e = ddi_soft_state_init(&cg6_softc_head,
sizeof (struct cg6_softc), 1)) != 0) {
return (e);
}
e = mod_install(&modlinkage);
if (e) {
}
return (e);
}
int
_fini(void)
{
register int e;
if ((e = mod_remove(&modlinkage)) != 0)
return (e);
return (0);
}
int
{
}
static int
{
int w, h, bytes;
char *tmp;
char name[16];
int proplen;
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (DDI_FAILURE);
if (!softc->cg6_suspended)
return (DDI_SUCCESS);
/* Restore the video state */
/* Restore non display RAM */
return (DDI_FAILURE);
}
/* Restore other frame buffer state */
}
softc->cg6_suspended = 0;
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
/* Allocate softc struct */
return (DDI_FAILURE);
}
/* link it in */
/* Grab properties from PROM */
/* TODO don't really want default w, h */
else
} else
/* Compute size of color frame buffer */
} else
/*
* only use address property if we are console fb NOTE: if the prom has
* already mapped the fb *and* it has mapped all of fbmappable, then we
* don't need a new mapping
*/
bytes = 0;
}
#ifdef DEBUG
#endif
/*
* get monitor attributes
*/
/*
* map in the registers. Map fbc&tec together. Likewise for fhc&thc.
*/
(off_t)CG6_FBCTEC_SZ) != 0) {
return (DDI_FAILURE);
}
(off_t)CG6_CMAP_SZ) != 0) {
return (DDI_FAILURE);
}
(off_t)CG6_FHCTHC_SZ) != 0) {
return (DDI_FAILURE);
}
#if 0
(off_t)CG6_ROM_SZ) != 0) {
return (DDI_FAILURE);
}
(off_t)CG6_DHC_SZ) != 0) {
return (DDI_FAILURE);
}
(off_t)CG6_ALT_SZ) != 0) {
return (DDI_FAILURE);
}
/* TODO: uart (future) */
/* map frame buffer if necessary */
if (bytes) {
return (DDI_FAILURE);
}
}
#endif
!= DDI_SUCCESS) {
"cg6_attach%d ddi_get_iblock_cookie failed\n", unit));
return (DDI_FAILURE);
}
"cg6_attach%d add_intr failed\n", unit));
return (DDI_FAILURE);
}
/*
* Initialize hardware colormap and software colormap images. It might
* make sense to read the hardware colormap here.
*/
"cg6_attach%d just before create_minor node\n", unit));
"cg6_attach%d create_minor node failed\n", unit));
return (DDI_FAILURE);
}
"?cgsix%d: screen %dx%d, %s buffered, %dM mappable, rev %d\n",
/*
* Initialize power management bookkeeping; components are created idle
*/
(void) pm_busy_component(devi, 0);
"controller", KSTAT_TYPE_INTR,
}
return (DDI_SUCCESS);
} else {
return (DDI_FAILURE);
}
}
static int
{
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
return (DDI_FAILURE);
if (softc->cg6_suspended)
return (DDI_FAILURE);
/* Save the video state */
/* Save non display RAM */
KM_NOSLEEP)) == NULL) {
return (DDI_FAILURE);
}
/*
* If FBC is busy, wait for maximum of 2 seconds for it
* to be idle
*/
4*CG6_FBC_WAIT);
/*
* if still busy, try another 2 seconds before
* giving up
*/
4*CG6_FBC_WAIT);
}
return (DDI_FAILURE);
}
/* Save other frame buffer state */
}
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
/* shut off video if not console */
if (!softc->mapped_by_prom)
cg6_set_video(softc, 0);
ddi_unmap_regs(devi, 0,
ddi_unmap_regs(devi, 0,
#if 0
/* TODO: uart (future) */
#endif
}
/* free softc struct */
return (DDI_SUCCESS);
}
static int
{
return (DDI_FAILURE);
if (level) {
/* Turn on sync and video. */
drv_usecwait(500);
} else {
/* Turn off sync and video. */
drv_usecwait(500);
}
return (DDI_SUCCESS);
}
/* ARGSUSED */
static int
{
int error = DDI_SUCCESS;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
error = DDI_FAILURE;
} else {
error = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
error = DDI_SUCCESS;
break;
default:
error = DDI_FAILURE;
}
return (error);
}
/*ARGSUSED*/
static int
{
int error = 0;
/*
* is this gorp necessary?
*/
} else
}
return (error);
}
/*ARGSUSED*/
static
int
{
int error = 0;
} else {
}
return (error);
}
/*ARGSUSED*/
static int
{
/*
* getting more and more complicated; what we return depends on what
* we're emulating
*/
else
} else { /* softc->emulation == FBTYPE_SUN4COLOR */
}
/* TODO: bw2? */
} else
if (rval == 0)
else
rval = -1;
return ((int)rval); /* XXX64 */
}
/*ARGSUSED*/
static int
{
int cursor_cmap;
int i;
/* default to updating normal colormap */
cursor_cmap = 0;
switch (cmd) {
case VIS_GETIDENTIFIER:
sizeof (struct vis_identifier),
mode))
return (EFAULT);
break;
case FBIOPUTCMAP:
case FBIOGETCMAP:
if (cursor_cmap == 0) {
return (EFAULT);
}
if (count == 0) {
return (0);
}
if (cursor_cmap == 0) {
switch (PIX_ATTRGROUP(index)) {
case 0:
case PIXPG_8BIT_COLOR:
break;
default:
return (EINVAL);
}
} else {
entries = 2;
}
return (EINVAL);
}
/*
* Allocate memory for color map RGB entries.
*/
if (cmd == FBIOPUTCMAP) {
int error;
if (error = ddi_copyin(
return (error);
}
if (error = ddi_copyin(
return (error);
}
if (error = ddi_copyin(
return (error);
}
if (cg6_update_pending(softc))
/*
* Copy color map entries from stack to the color map
* table in the softc area.
*/
/* cursor colormap update */
if (entries < CG6_CMAP_ENTRIES)
count = 0;
} else {
/* FBIOGETCMAP */
/*
* Copy color map entries from soft area to
* local storage and prepare for a copyout
*/
mode)) {
return (EFAULT);
}
mode)) {
return (EFAULT);
}
mode)) {
return (EFAULT);
}
}
break;
case FBIOSATTR: {
sizeof (attr),
mode))
return (EFAULT);
case FBTYPE_SUN3COLOR:
case FBTYPE_SUN4COLOR:
case FBTYPE_SUN2BW:
case FBTYPE_SUNFAST_COLOR:
break;
default:
return (EINVAL);
}
/* ignore device-dependent stuff */
}
break;
case FBIOGATTR: {
/* XXX not quite like a cg4 */
sizeof (struct fbgattr),
mode))
return (EFAULT);
}
break;
/*
* always claim to be a cg4 if they call this ioctl. This is to
* support older software which was staticly-linked before cg6 was
* invented, and to support newer software which has come to expect
* this behavior.
*/
case FBIOGTYPE: {
/* XXX not quite like a cg4 */
sizeof (struct fbtype),
mode))
return (EFAULT);
}
break;
case FBIOSVIDEO:
(caddr_t)&i,
sizeof (int),
mode))
return (EFAULT);
break;
case FBIOGVIDEO:
if (ddi_copyout((caddr_t)&i,
sizeof (int),
mode))
return (EFAULT);
break;
/* informational ioctls */
case FBIOGXINFO:
sizeof (struct cg6_info),
mode))
return (EFAULT);
return (0);
case FBIOMONINFO:
sizeof (struct mon_info),
mode))
return (EFAULT);
return (0);
/* vertical retrace interrupt */
case FBIOVERTICAL:
return (0);
case FBIOVRTOFFSET:
i = CG6_VADDR_VRT;
if (ddi_copyout((caddr_t)&i,
sizeof (int),
mode))
return (EFAULT);
return (0);
/* HW cursor control */
case FBIOSCURSOR: {
int set;
return (EFAULT);
/* Compute cursor bitmap bytes */
if (set & FB_CUR_SETSHAPE) {
return (EINVAL);
}
/* copy cursor image into softc */
return (EFAULT);
return (EFAULT);
}
if (set & FB_CUR_SETCUR)
if (set & FB_CUR_SETPOS)
if (set & FB_CUR_SETHOT)
/* update hardware */
if (set & FB_CUR_SETSHAPE) {
cbytes);
}
cbytes);
}
/* load into hardware */
}
/* load colormap */
if (set & FB_CUR_SETCMAP) {
cursor_cmap = 1;
cmd = FBIOPUTCMAP;
goto cmap_ioctl;
}
}
break;
case FBIOGCURSOR: {
return (EFAULT);
/* compute cursor bitmap bytes */
return (EFAULT);
/* if image pointer is non-null copy both bitmaps */
if (ddi_copyout(&stack_image,
return (EFAULT);
if (ddi_copyout(&stack_mask,
return (EFAULT);
}
/* if red pointer is non-null copy colormap */
cursor_cmap = 1;
cmd = FBIOGETCMAP;
/*
* XX64 The code used to do this:
*
* data = (int)&((struct fbcursor *)data)->cmap;
*
* However the cmap_ioctl handler doesn't look
* at 'data' so this assignment doesn't do anything.
* Instead we made it set the correct field in the
* fbcurpos structure we were passed in from
* userland.
*/
goto cmap_ioctl;
}
}
break;
case FBIOSCURPOS: {
sizeof (struct fbcurpos),
mode))
return (EFAULT);
sizeof (struct fbcurpos));
}
break;
case FBIOGCURPOS: {
sizeof (struct fbcurpos));
sizeof (struct fbcurpos),
mode))
return (EFAULT);
}
break;
case FBIOGCURMAX: {
sizeof (struct fbcurpos),
mode))
return (EFAULT);
}
break;
#if CG6DEBUG >= 3
case 255:
if (cg6_debug == -1)
break;
#endif
default:
return (ENOTTY);
} /* switch(cmd) */
return (0);
}
static uint_t
{
if (!cg6_int_pending(softc)) {
} else {
}
return (DDI_INTR_UNCLAIMED); /* nope, not mine */
}
}
/* TODO catch stray interrupts? */
}
return (DDI_INTR_CLAIMED);
}
} else
}
}
if (cg6_update_pending(softc)) {
/* load cursor color map */
if (softc->omap_update) {
/* background color */
/* foreground color */
}
/* load main color map */
if (count) {
/* count multiples of 4 RGB entries */
/* round index to 4 entry boundary */
index &= ~3;
/* copy 4 bytes (4/3 RGB entries) per loop iteration */
count *= 3;
softc->cmap_count = 0;
}
softc->omap_update = 0;
}
}
return (DDI_INTR_CLAIMED);
}
/*
* Initialize a colormap: background = white, all others = black
*/
static void
{
cmap[0] = 255;
}
/*
* Compute color map update parameters: starting index and count.
* If count is already nonzero, adjust values as necessary.
* Zero count argument indicates cursor color map update desired.
*/
static void
{
if (count == 0) {
return;
}
if (high != 0) {
} else {
}
}
/*
* Copy colormap entries between red, green, or blue array and
* interspersed rgb array.
*
* count > 0 : copy count bytes from buf to rgb
* count < 0 : copy -count bytes from rgb to buf
*/
static void
{
if (--rcount >= 0)
rgb += 3);
else {
rgb += 3);
}
}
/*
* This routine restores the color map to it's post-attach time values.
*/
static void
{
if (entries != 0) {
}
}
/*
*/
static void
{
}
/*
* load HW cursor bitmaps
*/
static void
{
int i;
/* compute right edge mask */
for (i = 0; i < 32; i++) {
}
}
static void
{
/* disable HW cursor */
/* reinitialize TEC */
{
tec->l_tec_clip = 0;
}
/* reinitialize FBC config register */
{
if (rev <= 4) {
/* PROM knows how to deal with LSC and above */
/* rev == 0 : FBC 0 (not available to customers) */
/* rev == 1 : FBC 1 */
/* rev == 2 : FBC 2 */
/* rev == 3 : Toshiba (never built) */
/* rev == 4 : Standard Cell (not built yet) */
/* rev == 5 : LSC rev 2 (buggy) */
/* rev == 6 : LSC rev 3 */
#if FBC_REV0
/* FBC0: test window = 0, disable fast rops */
if (rev == 0)
conf |= FHC_CONFIG_TEST |
else
#endif /* FBC_REV0 */
/* test window = 1K x 1K */
conf |= FHC_CONFIG_TEST |
/* FBC[01]: disable destination cache */
if (rev <= 1)
}
}
/* reprogram DAC to enable HW cursor use */
{
/* command register */
/* turn on CR1:0, overlay enable */
}
}
/*
* This code is no longer used, since OBP proms now do all device
* initialization. Nevertheless, it is instructive and I'm going to
* keep it in as a comment, should anyone ever want to know how to
* do minimal device initialization. Note the c++ style embedded
* comments.
*
* cg6_init(softc)
* struct cg6_softc *softc;
* {
* // Initialize DAC
* {
* register struct cg6_cmap *cmap = S_CMAP(softc);
* register char *p;
*
* static char dacval[] = {
* 4, 0xff,
* 5, 0,
* 6, 0x73,
* 7, 0,
* 0
* };
*
* // initialize DAC
* for (p = dacval; *p; p += 2) {
* cmap->addr = p[0] << 24;
* cmap->ctrl = p[1] << 24;
* }
* }
*
* // Initialize THC
* {
* register struct thc *thc = S_THC(softc);
* int vidon;
*
* vidon = thc_get_video(thc);
* thc->l_thc_hcmisc = THC_HCMISC_RESET | THC_HCMISC_INIT;
* thc->l_thc_hcmisc = THC_HCMISC_INIT;
*
* thc->l_thc_hchs = 0x010009;
* thc->l_thc_hchsdvs = 0x570000;
* thc->l_thc_hchd = 0x15005d;
* thc->l_thc_hcvs = 0x010005;
* thc->l_thc_hcvd = 0x2403a8;
* thc->l_thc_hcr = 0x00016b;
*
* thc->l_thc_hcmisc = THC_HCMISC_RESET | THC_HCMISC_INIT;
* thc->l_thc_hcmisc = THC_HCMISC_INIT;
*
* if (vidon)
* thc_set_video(thc, _ONE_);
*
* DEBUGF(1, (CE_CONT, "TEC rev %d\n",
* thc->l_thc_hcmisc >> THC_HCMISC_REV_SHIFT &
* THC_HCMISC_REV_MASK));
* }
*
* //
* // Initialize FHC for 1152 X 900 screen
* //
* {
* volatile uint_t *fhc = S_FHC(softc), rev;
*
* rev = *fhc >> FHC_CONFIG_REV_SHIFT & FHC_CONFIG_REV_MASK;
* DEBUGF(1, (CE_CONT, "cg6_init: FBC rev %d\n", rev));
*
* //
* // FBC0: disable fast rops FBC[01]: disable destination cache
* //
* *fhc = FHC_CONFIG_1152 |
* FHC_CONFIG_CPU_68020 |
* FHC_CONFIG_TEST |
*
* #if FBC_REV0
* (rev == 0 ? FHC_CONFIG_FROP_DISABLE : 0) |
* #endif
*
* (rev <= 1 ? FHC_CONFIG_DST_DISABLE : 0);
* }
* }
*/
/*
* from here on down, is the lego segment driver. this virtualizes the
* lego register file by associating a register save area with each
* mapping of the lego device (each lego segment). only one of these
* mappings is valid at any time; a page fault on one of the invalid
* mappings saves off the current lego context, invalidates the current
* valid mapping, restores the former register contents appropriate to
* the faulting mapping, and then validates it.
*
* this implements a graphical context switch that is transparent to the user.
*
* the TEC and FBC contain the interesting context registers.
*
*/
/*
* Per-segment info:
* Some, but not all, segments are part of a context.
* Any segment that is a MAP_PRIVATE mapping to the TEC or FBC
* will be part of a unique context. MAP_SHARED mappings are part
* of the shared context and all such programs must arbitrate among
* themselves to keep from stepping on each other's register settings.
* Mappings to the framebuffer may or may not be part of a context,
* depending on exact hardware type.
*/
static struct cg6map_pvt *
{
struct cg6map_pvt *pvt;
/*
* create the private data portion of the devmap object
*/
/*
* Link this pvt into the list of associated pvt's for this
* context
*/
return (pvt);
}
/*
* This routine is called through the cb_ops table to handle
* the creation of lego (cg6) segments.
*/
/*ARGSUSED*/
static int
{
int error;
/*
* check to see if this is a VRT page
*/
if (off == CG6_VADDR_VRT) {
"rejecting because off=vrt and len=%x\n", len))
return (EINVAL);
}
}
}
}
/*
* use the devmap framework for setting up the user mapping.
*/
return (error);
}
/* ARGSUSED */
static int
{
struct cg6map_pvt *pvt;
/*
* LSC DFB BUG KLUDGE: DFB must always be mapped private on the buggy
* (chip rev. 5) LSC chip. This is done to ensure that nobody ever
* touches the framebuffer without the segment driver getting involved
* to make sure the registers are idle. This involves taking a page
* fault, invalidating all other process's mappings to the fb, (and
* performing a context switch?)
*
* Under pixrects, which maps the chips and the FB all at once, the
* entire mapping becomes a context. This won't hurt pixrects but
* entails unnecessary context switching. Under other libraries such
* as XGL, which maps the chips private and the FB shared, the FB
* becomes part of the context. Programs which only map the FB will
* also become contexts, but since they don't map the chips, there's
* no context to switch.
*/
maptype |= CG6MAP_FBCTEC;
/*
* we now support MAP_SHARED and MAP_PRIVATE:
*
* MAP_SHARED means you get the shared context which is the traditional
* mapping method.
*
* MAP_PRIVATE means you get your very own LEGO context.
*
* Note that you can't get to here without asking for one or the other,
* but not both.
*/
ctx = shared_ctx;
} else {
ctx));
}
return (DDI_SUCCESS);
}
/*
* An access has been made to a context other than the current one
*/
/* ARGSUSED */
static int
{
}
/*
* called by the devmap framework to perform context switching.
*/
/* ARGSUSED */
static int
{
struct cg6map_pvt *pvts;
int err = 0;
curctx = %x, context = %x\n",
/*
* Do we need to switch contexts?
*/
/*
* If there's a current context, save it
*/
/*
* Set segdev for current context and all associated
* handles to intercept references to their addresses
*/
if (err) {
return (err);
}
}
"cgsix: context save failed\n"));
/*
* At this point we have no current context.
*/
return (-1);
}
}
/*
* Idle the chips
*/
fbc->l_fbc_status));
/*
* At this point we have no current context.
*/
return (-1);
}
p->context) == 0) {
"cgsix: context restore failed\n"));
/*
* At this point we have no current context.
*/
return (-1);
}
/*
* switch software "context"
*/
}
return (err);
}
} else {
rw)) != 0) {
return (err);
}
}
#if 0
cur_ctx = %x, ctx = %x\n",
return (err);
}
}
#endif
return (err);
}
/* ARGSUSED */
static void
{
struct cg6map_pvt *ptmp;
struct cg6map_pvt *ppvts;
off = %x, len = %x, dhp1 = %x, dhp2 = %x\n",
/*
* We are unmapping at the end of the mapping, if
* new_dhp1 is not NULL.
*/
p->offset,
softc);
}
/*
* We are unmapping at the beginning of the mapping, if
* new_dhp2 is not NULL.
*/
}
/*
* Remove the original pvt data
*/
} else {
}
break;
}
}
/*
* We want to remove the conext if both new_dhp1 and new_dhp2 are NULL.
*/
/*
* Remove the context if this is not the shared context
* xand there are no more associated pvt's
*/
/*
* Scan private context list for entry to remove.
* Check first to see if it's the head of our list.
*/
} else {
sizeof (struct cg6_cntxt));
}
}
}
}
/*
* If the curctx is the shared context, and there are no
* more pvt's for the shared context, set the curctx to
* NULL to force a context switch on the next device access.
*/
NULL)) {
}
}
}
/* ARGSUSED */
static int
void **newpvt)
{
struct cg6map_pvt *pvt;
} else
}
return (0);
}
/*
* please don't mess with these defines... they may look like
* a strange place for defines, but the context management code
* wants them as they are. JMP
*
*/
#define L_TEC_VDC_INTRNL0 0x8000
#define L_TEC_VDC_INTRNL1 0xa000
static int
{
int dreg; /* counts through the data registers */
fbc->l_fbc_status));
return (0);
}
/*
* start dumping stuff out.
*/
/*
* the tec matrix and clipping registers are easy.
*/
/*
* the tec data registers are a little more non-obvious.
* internally, they are 36 bits. what we see in the register
* file is a 32-bit window onto the underlying data register.
* changing the data-type in the VDC gets us either of two parts
* of the data register. the internal format is opaque to us.
*/
}
}
return (1);
}
static int
{
int dreg;
/*
* reload the tec data registers. see above for "how do they get
* 36 bits in that itty-bitty int"
*/
}
}
/*
* the tec matrix and clipping registers are next.
*/
/*
* now the FBC vertex and address registers
*/
/*
* restoring the attribute registers
*/
/*
* lastly, let's restore the status
*/
return (1);
}
/*
* ctx_map_insert()
*
* Insert a mapping into the mapping list of a private context. First
* determine if there's an existing context (e.g. one with the same PID
* as the current one and that does not already have a mapping of this
* type yet). If not, allocate a new one. Then insert mapping into this
* context's list.
*
* The softc mutex must be held across calls to this routine.
*/
static
struct cg6_cntxt *
{
/*
* If this is the first time we're here, then alloc space
* for new context and depart.
*/
return (ctx);
}
/*
* Find existing context if one exists. We have a match if
* we're the same process *and* there's not already a
* mapping of this type assigned.
*/
break;
}
/* no match, create a new one and add to softc list */
}
return (ctx);
}
/*
* getpid()
*
* Simple wrapper around process ID call to drv_getparm(9f).
*/
static pid_t
getpid()
{
return (0);
return (mypid);
}
#define DEVMEMORY 1
#define KERNELMEMORY 2
/*ARGSUSED*/
static int
{
int err = 0;
type = KERNELMEMORY;
else
} else
} else { /* softc->emulation == FBTYPE_SUN4COLOR */
softc->fbmappable) {
}
}
} else
return (-1);
}
/*
* LSC DFB BUG KLUDGE: DFB must always be mapped private on the buggy
* (chip rev. 5) LSC chip. This is done to ensure that nobody ever
* touches the framebuffer without the segment driver getting involved
* to make sure the registers are idle. This involves taking a page
* fault, invalidating all other process's mappings to the fb, (and
* performing a context switch?)
*
* Under pixrects, which maps the chips and the FB all at once, the
* entire mapping becomes a context. This won't hurt pixrects but
* entails unnecessary context switching. Under other libraries such
* as XGL, which maps the chips private and the FB shared, the FB
* becomes part of the context. Programs which only map the FB will
* also become contexts, but since they don't map the chips, there's
* no context to switch.
*/
/*
* do context switching on the TEC and FBC registers.
*/
else
callbackops = NULL;
&endian_attr)) < 0)
return (err);
} else {
&endian_attr)) < 0)
return (err);
}
return (0);
}