2004 lines
46 KiB
C
2004 lines
46 KiB
C
/* $NetBSD: px.c,v 1.47 2003/04/02 04:19:49 thorpej Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Andrew Doran.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the NetBSD
|
|
* Foundation, Inc. and its contributors.
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "px.h"
|
|
|
|
#if NPX > 1
|
|
#error Multiboard px support not in-tree right now.
|
|
#endif
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: px.c,v 1.47 2003/04/02 04:19:49 thorpej Exp $");
|
|
|
|
/*
|
|
* px.c: driver for the DEC TURBOchannel 2D and 3D accelerated framebuffers
|
|
* with PixelStamp blitter asics (and i860 accelerators, on the higher end
|
|
* cards).
|
|
*/
|
|
#include <sys/param.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/device.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/file.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/resourcevar.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/vnode.h>
|
|
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
#include <miscfs/specfs/specdev.h>
|
|
|
|
#include <dev/cons.h>
|
|
|
|
#include <dev/ic/bt459reg.h>
|
|
|
|
#include <dev/tc/tcvar.h>
|
|
|
|
#include <dev/rcons/rcons.h>
|
|
|
|
#include <dev/wscons/wsconsio.h>
|
|
#include <dev/wscons/wsdisplayvar.h>
|
|
#include <dev/wsfont/wsfont.h>
|
|
|
|
#include <machine/autoconf.h>
|
|
#include <dev/sun/fbio.h>
|
|
#include <machine/fbvar.h>
|
|
#include <machine/pmioctl.h>
|
|
|
|
#include <pmax/dev/fbreg.h>
|
|
#include <pmax/dev/pxreg.h>
|
|
#include <pmax/dev/pxvar.h>
|
|
#include <pmax/dev/qvssvar.h>
|
|
#include <pmax/dev/rconsvar.h>
|
|
|
|
struct px_softc {
|
|
struct device px_dv;
|
|
struct px_info *px_info;
|
|
};
|
|
|
|
static int px_match __P((struct device *, struct cfdata *, void *));
|
|
static void px_attach __P((struct device *, struct device *, void *));
|
|
static int px_init __P((struct fbinfo *, caddr_t, int, int));
|
|
static int px_intr __P((void *xxx_sc));
|
|
|
|
static int32_t *px_alloc_pbuf __P((struct px_info *));
|
|
static int px_send_packet __P((struct px_info *, int *buf));
|
|
static void px_init_stic __P((struct px_info *, int));
|
|
static void px_bt459_init __P((struct px_info *));
|
|
static int px_probe_planes __P((struct px_info *, int));
|
|
static void px_load_cursor __P((struct px_info *));
|
|
static void px_conv_cursor __P((struct px_info *, u_short *));
|
|
static void px_load_cmap __P((struct px_info *, int, int));
|
|
static void px_load_cursor_data __P((struct px_info *, int, int));
|
|
static void px_make_cursor __P((struct px_info *));
|
|
static int px_rect __P((struct px_info *, int, int, int, int, int));
|
|
static void px_qvss_init __P((struct px_info *));
|
|
static int px_mmap_info __P((struct proc *, dev_t, vaddr_t *));
|
|
static void px_cursor_hack __P((struct fbinfo *, int, int));
|
|
static int px_probe_sram __P((struct px_info *));
|
|
static void px_bt459_flush __P((struct px_info *));
|
|
|
|
CFATTACH_DECL(px, sizeof(struct px_softc),
|
|
px_match, px_attach, NULL, NULL);
|
|
|
|
dev_type_open(pxopen);
|
|
dev_type_close(pxclose);
|
|
dev_type_ioctl(pxioctl);
|
|
dev_type_poll(pxpoll);
|
|
dev_type_mmap(pxmmap);
|
|
dev_type_kqfilter(pxkqfilter);
|
|
|
|
const struct cdevsw px_cdevsw = {
|
|
pxopen, pxclose, noread, nowrite, pxioctl,
|
|
nostop, notty, pxpoll, pxmmap, pxkqfilter,
|
|
};
|
|
|
|
/* The different types of card that we support, for px_match(). */
|
|
static const char *px_types[] = {
|
|
"PMAG-CA ", /* 2DA */
|
|
"PMAG-DA ", /* LM-3DA */
|
|
"PMAG-FA ", /* HE-3DA */
|
|
"PMAG-FB ", /* HE+3DA */
|
|
"PMAGB-FA", /* HE+3DA */
|
|
"PMAGB-FB", /* HE+3DA */
|
|
};
|
|
|
|
#define NUM_PX_TYPES (sizeof(px_types) / sizeof(px_types[0]))
|
|
|
|
/* wscons emulator operations */
|
|
static void px_cursor __P((void *, int, int, int));
|
|
static void px_putchar __P((void *, int, int, u_int, long));
|
|
static void px_copycols __P((void *, int, int, int, int));
|
|
static void px_copyrows __P((void *, int, int, int num));
|
|
static void px_erasecols __P((void *, int, int, int num, long));
|
|
static void px_eraserows __P((void *, int, int, long));
|
|
static int px_allocattr __P((void *, int, int, int, long *));
|
|
static int px_mapchar __P((void *, int, unsigned int *));
|
|
|
|
static struct wsdisplay_emulops px_emulops = {
|
|
px_cursor,
|
|
px_mapchar,
|
|
px_putchar,
|
|
px_copycols,
|
|
px_erasecols,
|
|
px_copyrows,
|
|
px_eraserows,
|
|
px_allocattr
|
|
};
|
|
|
|
/* Colormap for wscons, matching WSCOL_*. Upper 8 are high-intensity */
|
|
static const u_char px_cmap[16*3] = {
|
|
0x00, 0x00, 0x00, /* black */
|
|
0x7f, 0x00, 0x00, /* red */
|
|
0x00, 0x7f, 0x00, /* green */
|
|
0x7f, 0x7f, 0x00, /* brown */
|
|
0x00, 0x00, 0x7f, /* blue */
|
|
0x7f, 0x00, 0x7f, /* magenta */
|
|
0x00, 0x7f, 0x7f, /* cyan */
|
|
0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
|
|
|
|
0x7f, 0x7f, 0x7f, /* black */
|
|
0xff, 0x00, 0x00, /* red */
|
|
0x00, 0xff, 0x00, /* green */
|
|
0xff, 0xff, 0x00, /* brown */
|
|
0x00, 0x00, 0xff, /* blue */
|
|
0xff, 0x00, 0xff, /* magenta */
|
|
0x00, 0xff, 0xff, /* cyan */
|
|
0xff, 0xff, 0xff, /* white */
|
|
};
|
|
|
|
/*
|
|
* Compose 2 bit/pixel cursor image. Bit order will be reversed.
|
|
* M M M M I I I I M I M I M I M I
|
|
* [ before ] [ after ]
|
|
* 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
|
|
* 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
|
|
*
|
|
* XXX duplicated in sfb.c, cfb.c, mfb.c
|
|
*/
|
|
static const u_char px_shuffle[256] = {
|
|
0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
|
|
0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
|
|
0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
|
|
0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
|
|
0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
|
|
0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
|
|
0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
|
|
0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
|
|
0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
|
|
0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
|
|
0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
|
|
0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
|
|
0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
|
|
0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
|
|
0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
|
|
0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
|
|
0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
|
|
0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
|
|
0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
|
|
0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
|
|
0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
|
|
0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
|
|
0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
|
|
0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
|
|
0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
|
|
0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
|
|
0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
|
|
0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
|
|
0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
|
|
0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
|
|
0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
|
|
0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
|
|
};
|
|
|
|
#define PXMAP_INFO_SIZE (PAGE_SIZE)
|
|
#define PXMAP_RBUF_SIZE (4096 * 16 + 8192 * 2)
|
|
|
|
/* Need alignment to 8KB here... */
|
|
static u_char px_cons_rbuf[PXMAP_INFO_SIZE + PXMAP_RBUF_SIZE + 8192];
|
|
static u_int px_cons_rbuf_use;
|
|
static struct px_info *px_cons_info;
|
|
static struct px_info *px_unit[NPX];
|
|
|
|
/* bt459 gunk. XXX should be done with driver independant interface */
|
|
struct bt459_regs {
|
|
volatile int32_t lo;
|
|
volatile int32_t hi;
|
|
volatile int32_t reg;
|
|
volatile int32_t cmap;
|
|
};
|
|
|
|
#define BT459_SELECT(vdac, regno) do { \
|
|
(vdac)->lo = DUPBYTE0(regno); \
|
|
(vdac)->hi = DUPBYTE1(regno); \
|
|
tc_wmb(); \
|
|
} while(0);
|
|
|
|
#define BT459_WRITE_REG(vdac, data) \
|
|
((vdac)->reg = (data)), tc_wmb();
|
|
|
|
#define BT459_WRITE_CMAP(vdac, data) \
|
|
((vdac)->cmap = (data)), tc_wmb();
|
|
|
|
#define BT459_READ_REG(vdac) ((vdac)->reg)
|
|
|
|
/* We have to support 3 VDACs on the 24-bit cards */
|
|
#define DUPBYTE0(x) ((((x)&0xff)<<16) | (((x)&0xff)<<8) | ((x)&0xff))
|
|
#define DUPBYTE1(x) ((((x)<<8)&0xff0000) | ((x)&0xff00) | (((x)>>8)&0xff))
|
|
#define DUPBYTE2(x) (((x)&0xff0000) | (((x)>>8)&0xff00) | (((x)>>16)&0xff))
|
|
|
|
#define PACK_WORD(p, o) ((p)[(o)] | ((p)[(o)+1] << 16))
|
|
|
|
int
|
|
px_cnattach(addr)
|
|
paddr_t addr;
|
|
{
|
|
caddr_t base;
|
|
base = (caddr_t)TC_PHYS_TO_UNCACHED(addr);
|
|
if (px_init((struct fbinfo *)1, base, 0, 1) != 1)
|
|
return (0);
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Match a supported board.
|
|
*/
|
|
static int
|
|
px_match(parent, match, aux)
|
|
struct device *parent;
|
|
struct cfdata *match;
|
|
void *aux;
|
|
{
|
|
struct tc_attach_args *ta = (struct tc_attach_args *)aux;
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_PX_TYPES; i++)
|
|
if (strncmp(px_types[i], ta->ta_modname, TC_ROM_LLEN) == 0)
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Attach the graphics board.
|
|
*/
|
|
static void
|
|
px_attach(parent, self, aux)
|
|
struct device *parent, *self;
|
|
void *aux;
|
|
{
|
|
struct px_softc *sc;
|
|
struct px_info *pxi;
|
|
struct tc_attach_args *ta;
|
|
caddr_t slotbase;
|
|
char *p;
|
|
int i;
|
|
|
|
sc = (struct px_softc *)self;
|
|
ta = (struct tc_attach_args *)aux;
|
|
slotbase = (caddr_t)TC_PHYS_TO_UNCACHED(ta->ta_addr);
|
|
|
|
/* Init the card only if it hasn't been done before... */
|
|
if (!px_cons_info || slotbase != (caddr_t)px_cons_info->pxi_slotbase)
|
|
px_init((struct fbinfo *)1, slotbase, sc->px_dv.dv_unit, 0);
|
|
|
|
/* px_init() fills in px_unit[#] */
|
|
pxi = px_unit[sc->px_dv.dv_unit];
|
|
sc->px_info = pxi;
|
|
|
|
/* Now grab the interrupt */
|
|
tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, px_intr, sc);
|
|
|
|
for (i = 0, p = ta->ta_modname; *p != ' ' && i < TC_ROM_LLEN; i++)
|
|
pxi->pxi_type[i] = *p++;
|
|
|
|
pxi->pxi_type[i] = '\0';
|
|
|
|
/* Set ISR driven packet-buffer polling addresses */
|
|
for (i = 0; i < 16; i++) {
|
|
caddr_t addr = (caddr_t)pxi->pxi_rbuf + (i << 12);
|
|
pxi->pxi_qpoll[i] = px_poll_addr(slotbase, addr);
|
|
}
|
|
|
|
/* The following values are filled in by px_init_stic. */
|
|
printf(": %cD, %dx%d stamp, %d plane", (pxi->pxi_option ? '3' : '2'),
|
|
pxi->pxi_stampw, pxi->pxi_stamph, pxi->pxi_nplanes);
|
|
if (pxi->pxi_option)
|
|
printf(", %dKB SRAM", px_probe_sram(pxi) >> 10);
|
|
printf("\n");
|
|
}
|
|
|
|
/*
|
|
* Initialize the graphics board. This can be called from tc_findcons and
|
|
* the pmax console trickery, in which case ``fi'' will be null.
|
|
*
|
|
* XXX use magic number to make sure fi isn't a real struct fbinfo?
|
|
*/
|
|
static int
|
|
px_init(fi, slotbase, unit, console)
|
|
struct fbinfo *fi;
|
|
caddr_t slotbase;
|
|
int unit, console;
|
|
{
|
|
struct px_info *pxi;
|
|
u_long bufpa;
|
|
int i;
|
|
|
|
#if NPX > 1
|
|
if (px_cons_rbuf_use)
|
|
/* XXX allocate buffers */;
|
|
else
|
|
#endif
|
|
{
|
|
bufpa = MIPS_KSEG0_TO_PHYS(px_cons_rbuf);
|
|
px_cons_rbuf_use = 1;
|
|
}
|
|
|
|
/* Align to 8KB. px_info struct gets the first 4KB */
|
|
bufpa = (bufpa + 8191) & ~8191;
|
|
pxi = (struct px_info *)MIPS_PHYS_TO_KSEG1(bufpa);
|
|
px_unit[unit] = pxi;
|
|
bufpa += PXMAP_INFO_SIZE;
|
|
|
|
if (bufpa + PXMAP_RBUF_SIZE > 8192*1024) {
|
|
printf("px%d: ring buffer outside first 8MB of RAM\n", unit);
|
|
return 0;
|
|
}
|
|
|
|
pxi->pxi_slotbase = TC_PHYS_TO_UNCACHED(slotbase);
|
|
pxi->pxi_unit = unit;
|
|
pxi->pxi_stamp = (caddr_t)(pxi->pxi_slotbase + PX_STAMP_OFFSET);
|
|
pxi->pxi_poll = (int32_t *)(pxi->pxi_slotbase + PX_STIC_POLL_OFFSET);
|
|
pxi->pxi_stic = (struct stic_regs *)(pxi->pxi_slotbase + PX_STIC_OFFSET);
|
|
pxi->pxi_rbuf = (int *)MIPS_PHYS_TO_KSEG1(bufpa);
|
|
pxi->pxi_rbuf_phys = bufpa;
|
|
pxi->pxi_rbuf_size = PXMAP_RBUF_SIZE;
|
|
pxi->pxi_pbuf_select = 0;
|
|
pxi->pxi_flg = PX_ENABLE;
|
|
|
|
/* We need to do this ASAP so we can disable the co-processor */
|
|
px_init_stic(pxi, 1);
|
|
|
|
/*
|
|
* If this is a PXG, use the SRAM and not kernel bss.
|
|
* XXX this is a big fat waste of memory.
|
|
*/
|
|
if (pxi->pxi_option) {
|
|
bufpa = MIPS_KSEG0_TO_PHYS(slotbase + PXG_SRAM_OFFSET);
|
|
pxi->pxi_rbuf = (int *)MIPS_PHYS_TO_KSEG1(bufpa);
|
|
pxi->pxi_rbuf_phys = bufpa;
|
|
pxi->pxi_rbuf_size = px_probe_sram(pxi);
|
|
}
|
|
|
|
/* Get a font and lock. If we're not the console, we don't care */
|
|
if (console) {
|
|
wsfont_init();
|
|
|
|
i = wsfont_find(NULL, 0, 0, 2, WSDISPLAY_FONTORDER_R2L,
|
|
WSDISPLAY_FONTORDER_L2R);
|
|
if (i <= 0)
|
|
panic("px_init: unable to get font");
|
|
|
|
if (wsfont_lock(i, &pxi->pxi_font))
|
|
panic("px_init: unable to lock font");
|
|
|
|
pxi->pxi_wsfcookie = i;
|
|
} else
|
|
pxi->pxi_wsfcookie = -1;
|
|
|
|
/* Only now can we init the bt459... */
|
|
px_bt459_init(pxi);
|
|
|
|
/* Clear ringbuffer and then the screen */
|
|
memset(pxi->pxi_rbuf, 0, pxi->pxi_rbuf_size);
|
|
px_rect(pxi, 0, 0, 1280, 1024, 0);
|
|
|
|
/* Connect to rcons if this is the console device */
|
|
if (console) {
|
|
pxi->pxi_fontscale = pxi->pxi_font->fontheight *
|
|
pxi->pxi_font->stride;
|
|
px_cons_info = pxi;
|
|
|
|
/* XXX no multiscreen X support yet */
|
|
px_qvss_init(pxi);
|
|
|
|
rcons_connect_native(&px_emulops, pxi, 1280, 1024,
|
|
1280 / pxi->pxi_font->fontwidth,
|
|
1024 / pxi->pxi_font->fontheight);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Initialize our DISGUSTING little hack so we can use the qvss event-buffer
|
|
* stuff for the X server.
|
|
*/
|
|
static void
|
|
px_qvss_init(pxi)
|
|
struct px_info *pxi;
|
|
{
|
|
struct fbinfo *fi;
|
|
static struct pmax_fbtty pxfb;
|
|
static struct fbdriver fbdriver = {
|
|
NULL, NULL, NULL, NULL,
|
|
NULL, px_cursor_hack, NULL, NULL
|
|
};
|
|
|
|
fi = &pxi->pxi_fbinfo;
|
|
fi->fi_driver = &fbdriver;
|
|
fi->fi_base = (caddr_t)pxi;
|
|
fi->fi_fbu = &pxi->pxi_fbuaccess;
|
|
fi->fi_type.fb_width = 1280;
|
|
fi->fi_type.fb_height = 1024;
|
|
fi->fi_type.fb_type = PMAX_FBTYPE_PX;
|
|
fi->fi_type.fb_cmsize = 256;
|
|
fi->fi_type.fb_depth = 8;
|
|
fi->fi_fbu->scrInfo.max_row = 1024 / 8;
|
|
fi->fi_fbu->scrInfo.max_col = 80;
|
|
fi->fi_glasstty = &pxfb;
|
|
|
|
tb_kbdmouseconfig(fi);
|
|
init_pmaxfbu(fi);
|
|
}
|
|
|
|
/*
|
|
* Initialize the Brooktree 459 VDAC.
|
|
*/
|
|
static void
|
|
px_bt459_init(pxi)
|
|
struct px_info *pxi;
|
|
{
|
|
struct bt459_regs *vdac = pxi->pxi_vdac;
|
|
int i;
|
|
|
|
/* Hit it... */
|
|
BT459_SELECT(vdac, BT459_IREG_COMMAND_0);
|
|
BT459_WRITE_REG(vdac, 0xc0c0c0);
|
|
|
|
/* Now reset the VDAC */
|
|
if (pxi->pxi_option)
|
|
*(int32_t *)(pxi->pxi_slotbase + PXG_VDAC_RESET_OFFSET) = 0;
|
|
else
|
|
*(int32_t *)(pxi->pxi_slotbase + PX_VDAC_RESET_OFFSET) = 0;
|
|
|
|
tc_wmb();
|
|
|
|
/* Finish the initialization */
|
|
BT459_SELECT(vdac, BT459_IREG_COMMAND_1);
|
|
BT459_WRITE_REG(vdac, 0x000000);
|
|
BT459_WRITE_REG(vdac, 0xc2c2c2);
|
|
BT459_WRITE_REG(vdac, 0xffffff);
|
|
|
|
for (i = 0; i < 7; i++)
|
|
BT459_WRITE_REG(vdac, 0);
|
|
|
|
/* Set cursor colormap */
|
|
BT459_SELECT(vdac, BT459_IREG_CCOLOR_1);
|
|
BT459_WRITE_REG(vdac, 0xffffff);
|
|
BT459_WRITE_REG(vdac, 0xffffff);
|
|
BT459_WRITE_REG(vdac, 0xffffff);
|
|
|
|
BT459_WRITE_REG(vdac, 0x00);
|
|
BT459_WRITE_REG(vdac, 0x00);
|
|
BT459_WRITE_REG(vdac, 0x00);
|
|
|
|
BT459_WRITE_REG(vdac, 0xffffff);
|
|
BT459_WRITE_REG(vdac, 0xffffff);
|
|
BT459_WRITE_REG(vdac, 0xffffff);
|
|
|
|
/* Build and load a sane colormap */
|
|
memset(pxi->pxi_cmap, 0, sizeof(pxi->pxi_cmap));
|
|
memcpy(pxi->pxi_cmap, px_cmap, 16 * 3);
|
|
pxi->pxi_cmap[255*3+0] = 0xff;
|
|
pxi->pxi_cmap[255*3+1] = 0xff;
|
|
pxi->pxi_cmap[255*3+2] = 0xff;
|
|
px_load_cmap(pxi, 0, 256);
|
|
|
|
/* Make a sane cursor and load it */
|
|
if (pxi->pxi_font != NULL) {
|
|
px_make_cursor(pxi);
|
|
px_load_cursor(pxi);
|
|
|
|
/* Enable cursor */
|
|
BT459_SELECT(vdac, BT459_IREG_CCR);
|
|
BT459_WRITE_REG(vdac, 0x1c1c1c1);
|
|
pxi->pxi_flg |= PX_CURSOR_ENABLE;
|
|
} else {
|
|
BT459_SELECT(vdac, BT459_IREG_CCR);
|
|
BT459_WRITE_REG(vdac, 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Determine the number of planes supported by the given buffer.
|
|
* XXX should know this from module name
|
|
*/
|
|
static int
|
|
px_probe_planes(pxi, buf)
|
|
struct px_info *pxi;
|
|
int buf;
|
|
{
|
|
int i;
|
|
|
|
if (buf == 0) {
|
|
/*
|
|
* For the real framebuffer (# 0), we can cheat and use the
|
|
* VDAC ID. One color is active at level 0x4a for 8 bits, all
|
|
* colors are active at 0x4a on the 24 bit cards.
|
|
*/
|
|
BT459_SELECT(pxi->pxi_vdac, BT459_IREG_ID);
|
|
i = pxi->pxi_vdac->reg & 0x00ffffff;
|
|
|
|
/* 3 VDACs */
|
|
if (i == 0x4a4a4a)
|
|
return 24;
|
|
|
|
/* 1 VDAC */
|
|
if ((i & 0xff0000) == 0x4a0000 ||
|
|
(i & 0x00ff00) == 0x004a00 ||
|
|
(i & 0x0000ff) == 0x00004a)
|
|
return 8;
|
|
|
|
/* Whoops... Assume 8 planes? */
|
|
printf("\n");
|
|
printf("px%d: invalid VDAC ID 0x%08x", pxi->pxi_unit, i);
|
|
return 8;
|
|
}
|
|
|
|
/* Don't give a damn about Z-buffers... */
|
|
panic("px_probe_planes: (buf != 0) was un-implemented (bloat)");
|
|
}
|
|
|
|
/*
|
|
* Figure out how much SRAM the PXG has: 128KB or 256KB.
|
|
*/
|
|
static int
|
|
px_probe_sram(pxi)
|
|
struct px_info *pxi;
|
|
{
|
|
volatile int32_t *a, *b;
|
|
|
|
a = (int32_t *)(pxi->pxi_slotbase + PXG_SRAM_OFFSET);
|
|
b = a + (0x20000 >> 1);
|
|
|
|
*a = 4321;
|
|
*b = 1234;
|
|
tc_wmb();
|
|
|
|
return ((*a == *b) ? 0x20000 : 0x40000);
|
|
}
|
|
|
|
/*
|
|
* Initialize the STIC (STamp Interface Chip) and stamp
|
|
*/
|
|
static void
|
|
px_init_stic(pxi, probe)
|
|
struct px_info *pxi;
|
|
int probe;
|
|
{
|
|
int modtype, xconfig, yconfig, config;
|
|
struct stic_regs *stic;
|
|
volatile int32_t *slot;
|
|
caddr_t stamp;
|
|
int i;
|
|
|
|
stic = pxi->pxi_stic;
|
|
stamp = pxi->pxi_stamp;
|
|
|
|
/* If this is a 3D board, disable the i860 co-processor. */
|
|
if (((stic->modcl >> 12) & 3) != 0) {
|
|
slot = (volatile int32_t *)pxi->pxi_slotbase;
|
|
|
|
slot[PXG_N10_RESET_OFFSET >> 2] = 0;
|
|
tc_wmb();
|
|
slot[PXG_HOST_INTR_OFFSET >> 2] = 0;
|
|
tc_wmb();
|
|
DELAY(40000); /* paranoia */
|
|
}
|
|
|
|
/*
|
|
* Initialize STIC interface chip registers. Magic sequence from
|
|
* logic analyser.
|
|
*/
|
|
stic->sticsr = 0x00000030; /* Get the STIC's attention. */
|
|
tc_wmb();
|
|
DELAY(4000); /* wait 4ms for STIC to respond. */
|
|
stic->sticsr = 0x00000000; /* Hit the STIC's csr again... */
|
|
tc_wmb();
|
|
stic->buscsr = 0xffffffff; /* and bash its bus-acess csr. */
|
|
tc_wmb(); /* Blam! */
|
|
DELAY(20000); /* wait until the stic recovers... */
|
|
|
|
/* Initialize Stamp config register for model 0. */
|
|
modtype = stic->modcl;
|
|
xconfig = (modtype & 0x800) >> 11;
|
|
yconfig = (modtype & 0x600) >> 9;
|
|
config = (yconfig << 1) | xconfig;
|
|
|
|
*(int32_t *) (stamp + __PXS(0x000b0)) = config;
|
|
*(int32_t *) (stamp + __PXS(0x000b4)) = 0x0;
|
|
|
|
if (yconfig > 0) {
|
|
/* pixelstamp 1 configuration */
|
|
*(int32_t *) (stamp + __PXS(0x100b0)) = config | 8;
|
|
*(int32_t *) (stamp + __PXS(0x100b4)) = 0x0;
|
|
}
|
|
/*
|
|
* Remember the size of the stamp, and card revision. Also
|
|
* figure out the number of planes.
|
|
*/
|
|
if (probe) {
|
|
pxi->pxi_stampw = (xconfig ? 5 : 4);
|
|
pxi->pxi_stamph = (1 << yconfig);
|
|
pxi->pxi_revision = (char)(modtype >> 24);
|
|
pxi->pxi_option = (char)((modtype >> 12) & 3);
|
|
|
|
/* PXG upwards has it's VDAC at a different location */
|
|
i = (pxi->pxi_option ? PXG_VDAC_OFFSET : PX_VDAC_OFFSET);
|
|
pxi->pxi_vdac = (struct bt459_regs *) (pxi->pxi_slotbase + i);
|
|
|
|
if (pxi->pxi_option == 0) {
|
|
/* 2D board */
|
|
pxi->pxi_nplanes = 8;
|
|
pxi->pxi_planemask = 0xff;
|
|
} else {
|
|
if (pxi->pxi_stamph > 1) {
|
|
/* high-end 3D */
|
|
pxi->pxi_nplanes = 24;
|
|
pxi->pxi_planemask = 0xffffff;
|
|
} else {
|
|
/* low/mid 3D */
|
|
pxi->pxi_nplanes = px_probe_planes(pxi, 0);
|
|
|
|
/* XXX is this right? */
|
|
if (pxi->pxi_nplanes == 8)
|
|
pxi->pxi_planemask = 0xff0000;
|
|
else
|
|
pxi->pxi_planemask = 0xffffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize STIC video registers. (if we knew what we were doing,
|
|
* we might be able to frob this to work at different montior
|
|
* frequencies.)
|
|
*/
|
|
stic->vblank = (1024 << 16) | 1063;
|
|
stic->vsync = (1027 << 16) | 1030;
|
|
stic->hblank = (255 << 16) | 340;
|
|
stic->hsync2 = 245;
|
|
stic->hsync = (261 << 16) | 293;
|
|
stic->ipdvint = STIC_INT_CLR | STIC_INT_WE;
|
|
stic->sticsr = 0x00000008;
|
|
tc_wmb();
|
|
|
|
#ifdef notdef
|
|
/* Now enable the i860 and STIC interrupts (PXG only) */
|
|
if (pxi->pxi_option) {
|
|
slot = (volatile int32_t *)pxi->pxi_slotbase;
|
|
|
|
slot[PXG_N10_START_OFFSET >> 2] = 1;
|
|
tc_wmb();
|
|
DELAY(2000);
|
|
stic->sticsr = STIC_INT_WE | STIC_INT_CLR;
|
|
tc_wmb();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Make a cursor matching the current font dimensions.
|
|
*/
|
|
static void
|
|
px_make_cursor(pxi)
|
|
struct px_info *pxi;
|
|
{
|
|
u_int8_t *ip, *mp;
|
|
int r, c, o, b;
|
|
|
|
ip = pxi->pxi_cursor;
|
|
mp = pxi->pxi_cursor + (sizeof(pxi->pxi_cursor) >> 1);
|
|
memset(pxi->pxi_cursor, 0, sizeof(pxi->pxi_cursor));
|
|
|
|
for (r = 0; r < pxi->pxi_font->fontheight; r++) {
|
|
for (c = 0; c < pxi->pxi_font->fontwidth; c++) {
|
|
o = c >> 3;
|
|
b = 1 << (c & 7);
|
|
ip[o] |= b;
|
|
mp[o] |= b;
|
|
}
|
|
|
|
ip += 8;
|
|
mp += 8;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Convert a 16x16 cursor from the Xserver.
|
|
*/
|
|
static void
|
|
px_conv_cursor(pxi, sip)
|
|
struct px_info *pxi;
|
|
u_short *sip;
|
|
{
|
|
u_short *ip, *mp;
|
|
int r;
|
|
|
|
ip = (u_short *)pxi->pxi_cursor;
|
|
mp = (u_short *)(pxi->pxi_cursor + (sizeof(pxi->pxi_cursor) >> 1));
|
|
memset(pxi->pxi_cursor, 0, sizeof(pxi->pxi_cursor));
|
|
|
|
for (r = 0; r < 16; r++) {
|
|
*ip = sip[0];
|
|
*mp = sip[16];
|
|
sip++;
|
|
ip += 4;
|
|
mp += 4;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Load a single byte into the cursor map.
|
|
*/
|
|
static void
|
|
px_load_cursor_data(pxi, pos, val)
|
|
struct px_info *pxi;
|
|
int pos, val;
|
|
{
|
|
struct bt459_regs *vdac;
|
|
int cnt;
|
|
|
|
vdac = pxi->pxi_vdac;
|
|
val = DUPBYTE0(val);
|
|
|
|
for (cnt = 10; cnt; cnt--) {
|
|
BT459_SELECT(vdac, BT459_IREG_CRAM_BASE + pos);
|
|
BT459_WRITE_REG(vdac, val);
|
|
|
|
if ((BT459_READ_REG(vdac) & pxi->pxi_planemask) == val)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Load the cursor image.
|
|
*/
|
|
static void
|
|
px_load_cursor(pxi)
|
|
struct px_info *pxi;
|
|
{
|
|
struct bt459_regs *vdac;
|
|
u_int8_t *ip, *mp, img, msk, u;
|
|
int bcnt;
|
|
|
|
vdac = pxi->pxi_vdac;
|
|
ip = pxi->pxi_cursor;
|
|
mp = pxi->pxi_cursor + (sizeof(pxi->pxi_cursor) >> 1);
|
|
|
|
bcnt = 0;
|
|
BT459_SELECT(vdac, BT459_IREG_CRAM_BASE + 0);
|
|
|
|
/* 64 pixel scan line is made with 8 bytes of cursor RAM */
|
|
while (bcnt < sizeof(pxi->pxi_cursor)) {
|
|
img = *ip++;
|
|
msk = *mp++;
|
|
img &= msk; /* cookie off image */
|
|
u = (msk & 0x0f) << 4 | (img & 0x0f);
|
|
px_load_cursor_data(pxi, bcnt++, px_shuffle[u]);
|
|
u = (msk & 0xf0) | (img & 0xf0) >> 4;
|
|
px_load_cursor_data(pxi, bcnt++, px_shuffle[u]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Load the colormap.
|
|
*/
|
|
static void
|
|
px_load_cmap(pxi, index, num)
|
|
struct px_info *pxi;
|
|
int index, num;
|
|
{
|
|
struct bt459_regs *vdac;
|
|
u_char *p;
|
|
|
|
if (index < 0 || num <= 0 || index + num > 256)
|
|
return;
|
|
|
|
vdac = pxi->pxi_vdac;
|
|
num = (num << 1) + num; /* multiply by 3 */
|
|
p = pxi->pxi_cmap + (index << 1) + index;
|
|
|
|
BT459_SELECT(vdac, index);
|
|
BT459_SELECT(vdac, index);
|
|
DELAY(20);
|
|
|
|
for (; num--; p++)
|
|
BT459_WRITE_CMAP(vdac, DUPBYTE0(*p));
|
|
}
|
|
|
|
/*
|
|
* Flush any pending updates to the bt459. This gets called during vblank
|
|
* on the PX to prevent shearing/snow. The PXG always has to flush.
|
|
*/
|
|
static void
|
|
px_bt459_flush(pxi)
|
|
struct px_info *pxi;
|
|
{
|
|
struct bt459_regs *vdac;
|
|
u_char *cp;
|
|
int i;
|
|
|
|
vdac = pxi->pxi_vdac;
|
|
|
|
if (pxi->pxi_dirty & PX_DIRTY_CURSOR_POS) {
|
|
BT459_SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(pxi->pxi_curx));
|
|
BT459_WRITE_REG(vdac, DUPBYTE1(pxi->pxi_curx));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(pxi->pxi_cury));
|
|
BT459_WRITE_REG(vdac, DUPBYTE1(pxi->pxi_cury));
|
|
}
|
|
|
|
if (pxi->pxi_dirty & PX_DIRTY_CURSOR)
|
|
px_load_cursor(pxi);
|
|
|
|
if (pxi->pxi_dirty & PX_DIRTY_CURSOR_CMAP) {
|
|
cp = pxi->pxi_curcmap;
|
|
|
|
BT459_SELECT(vdac, BT459_IREG_CCOLOR_1);
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[3]));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[4]));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[5]));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[0]));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[1]));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[2]));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[3]));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[4]));
|
|
BT459_WRITE_REG(vdac, DUPBYTE0(cp[5]));
|
|
}
|
|
|
|
if (pxi->pxi_dirty & PX_DIRTY_ENABLE) {
|
|
if (pxi->pxi_flg & PX_ENABLE) {
|
|
BT459_SELECT(vdac, BT459_IREG_PRM);
|
|
BT459_WRITE_REG(vdac, 0xffffff);
|
|
px_load_cmap(pxi, 0, 1);
|
|
pxi->pxi_dirty |= PX_DIRTY_CURSOR_ENABLE;
|
|
} else {
|
|
BT459_SELECT(vdac, BT459_IREG_PRM);
|
|
BT459_WRITE_REG(vdac, 0);
|
|
|
|
BT459_SELECT(vdac, 0);
|
|
BT459_WRITE_CMAP(vdac, 0);
|
|
BT459_WRITE_CMAP(vdac, 0);
|
|
BT459_WRITE_CMAP(vdac, 0);
|
|
|
|
BT459_SELECT(vdac, BT459_IREG_CCR);
|
|
BT459_WRITE_REG(vdac, 0);
|
|
}
|
|
}
|
|
|
|
if (pxi->pxi_flg & PX_ENABLE) {
|
|
if (pxi->pxi_dirty & PX_DIRTY_CMAP)
|
|
px_load_cmap(pxi, pxi->pxi_cmap_idx,
|
|
pxi->pxi_cmap_cnt);
|
|
|
|
if (pxi->pxi_dirty & PX_DIRTY_CURSOR_ENABLE) {
|
|
if (pxi->pxi_flg & PX_CURSOR_ENABLE) {
|
|
/* No flashing cursor for X */
|
|
if (pxi->pxi_flg & PX_OPEN)
|
|
i = 0x00c0c0c0;
|
|
else
|
|
i = 0x01c1c1c1;
|
|
} else
|
|
i = 0;
|
|
|
|
BT459_SELECT(vdac, BT459_IREG_CCR);
|
|
BT459_WRITE_REG(vdac, i);
|
|
}
|
|
}
|
|
|
|
pxi->pxi_dirty = 0;
|
|
}
|
|
|
|
/*
|
|
* PixelStamp board interrupt handler. We can get more than one interrupt
|
|
* at a time (i.e. packet+vertical retrace) so we don't return after
|
|
* handling each case.
|
|
*/
|
|
static int
|
|
px_intr(xxx_sc)
|
|
void *xxx_sc;
|
|
{
|
|
struct px_cliplist *cl;
|
|
struct stic_regs *stic;
|
|
struct px_info *pxi;
|
|
int caught, state;
|
|
|
|
pxi = (struct px_info *)
|
|
MIPS_PHYS_TO_KSEG1(((struct px_softc *)xxx_sc)->px_info);
|
|
|
|
stic = pxi->pxi_stic;
|
|
caught = 0;
|
|
state = stic->ipdvint;
|
|
|
|
#ifdef notdef
|
|
/* Getting this from the i860? */
|
|
if (pxi->pxi_option) {
|
|
hi = (int32_t *)pxi->pxi_slotbase + (PXG_HOST_INTR_OFFSET>>2);
|
|
|
|
/* Clear the interrupt condition */
|
|
i = hi[0] & 15;
|
|
hi[0] = 0;
|
|
tc_wmb();
|
|
hi[2] = 0;
|
|
tc_wmb();
|
|
|
|
if (i == 3) /* 3 == vblank */
|
|
state |= STIC_INT_V;
|
|
}
|
|
#endif
|
|
|
|
/* Vertical retrace interrupt. */
|
|
if (state & STIC_INT_V) {
|
|
stic->ipdvint = STIC_INT_V_WE | (stic->ipdvint & STIC_INT_V_EN);
|
|
tc_wmb();
|
|
caught = 1;
|
|
|
|
if (pxi->pxi_dirty)
|
|
px_bt459_flush(pxi);
|
|
}
|
|
|
|
/* Packet interrupt. Clear packet done flag. */
|
|
if (state & STIC_INT_P) {
|
|
stic->ipdvint = STIC_INT_P_WE | (stic->ipdvint & STIC_INT_P_EN);
|
|
tc_wmb();
|
|
caught = 1;
|
|
}
|
|
|
|
#ifdef notyet
|
|
/* Error/stray interrupt */
|
|
if ((stic->ipdvint & STIC_INT_E) || !caught) {
|
|
printf("px%d: %s intr, %x %x %x %x %x", pxi->pxi_unit,
|
|
(caught ? "error" : "stray"), stic->ipdvint, stic->sticsr,
|
|
stic->buscsr, stic->busadr, stic->busdat);
|
|
}
|
|
#endif
|
|
/* Abort if no packets are in the queue */
|
|
if (pxi->pxi_lpr == pxi->pxi_lpw) {
|
|
pxi->pxi_flg &= ~PX_ISR_ACTIVE;
|
|
return (0);
|
|
}
|
|
|
|
/* Abort if we're awaiting reload of cliplist */
|
|
if (pxi->pxi_flg & PX_ISR_LOAD_CLIP)
|
|
return (0);
|
|
|
|
cl = &pxi->pxi_cliplist;
|
|
|
|
/* Does this new packet need to be clipped? */
|
|
if (cl->cl_loaded != 0 && (pxi->pxi_flg & PX_ISR_PASS_CLIP) == 0) {
|
|
int32_t *buf;
|
|
|
|
buf = (int32_t *)pxi->pxi_rbuf + (pxi->pxi_lpr & 15) * 1024;
|
|
|
|
if (*buf & STAMP_CLIPRECT) {
|
|
pxi->pxi_flg |= PX_ISR_PASS_CLIP;
|
|
|
|
/* Figure out where in the packet fixup should occur */
|
|
cl->cl_fixup = buf + 4;
|
|
|
|
/* XXX this computation is wrong... */
|
|
if (*buf & STAMP_XY_PERPACKET)
|
|
cl->cl_fixup++;
|
|
|
|
if (*buf & STAMP_LW_PERPACKET)
|
|
cl->cl_fixup++;
|
|
|
|
cl->cl_cur = 0;
|
|
}
|
|
}
|
|
|
|
/* Need to fix up packet with next cliprect? */
|
|
if (pxi->pxi_flg & PX_ISR_PASS_CLIP) {
|
|
cl->cl_fixup[0] = cl->cl_minval[cl->cl_cur];
|
|
cl->cl_fixup[1] = cl->cl_maxval[cl->cl_cur];
|
|
|
|
/* Need more cliprects/finished? */
|
|
if ((cl->cl_cur + 1) >= cl->cl_loaded) {
|
|
if (cl->cl_notloaded != 0)
|
|
pxi->pxi_flg |= PX_ISR_LOAD_CLIP;
|
|
else
|
|
pxi->pxi_flg &= ~PX_ISR_PASS_CLIP;
|
|
}
|
|
}
|
|
|
|
/* Fire off the packet and move to next cliprect OR next packet */
|
|
if (*pxi->pxi_qpoll[pxi->pxi_lpr & 15] == STAMP_OK) {
|
|
if (pxi->pxi_flg & PX_ISR_PASS_CLIP)
|
|
cl->cl_cur++;
|
|
else
|
|
pxi->pxi_lpr++;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Allocate a PixelStamp packet buffer.
|
|
*/
|
|
static inline int32_t *
|
|
px_alloc_pbuf(pxi)
|
|
struct px_info *pxi;
|
|
{
|
|
volatile int32_t *poll;
|
|
int32_t *buf;
|
|
int i, j;
|
|
|
|
/* Use queueing if the ISR is enabled */
|
|
if (pxi->pxi_flg & PX_ISR_ENABLE) {
|
|
/* Wait until we have a free buffer */
|
|
for (i = STAMP_RETRIES; i; i--) {
|
|
if (pxi->pxi_lpw - pxi->pxi_lpr < 15)
|
|
break;
|
|
|
|
DELAY(STAMP_DELAY);
|
|
}
|
|
|
|
/*
|
|
* Dequeue stalled packets manually. This should only
|
|
* ever happen during prelonged periods at splhigh().
|
|
* Autoconfiguration time is an example.
|
|
*/
|
|
if (i == 0) {
|
|
for (i = pxi->pxi_lpr; i < pxi->pxi_lpw; i++) {
|
|
poll = pxi->pxi_qpoll[i & 15];
|
|
|
|
for (j = STAMP_RETRIES; j; j--) {
|
|
if (*poll == STAMP_OK)
|
|
break;
|
|
|
|
DELAY(STAMP_DELAY);
|
|
}
|
|
}
|
|
|
|
pxi->pxi_lpr = pxi->pxi_lpw;
|
|
}
|
|
|
|
return (int32_t *)((caddr_t)pxi->pxi_rbuf +
|
|
((pxi->pxi_lpw & 15) << 12));
|
|
}
|
|
|
|
#ifdef notdef
|
|
/* If this is a PXG, ask the damn i860 which buffer to use */
|
|
if (pxi->pxi_option) {
|
|
poll = (volatile int32_t *)pxi->pxi_slotbase;
|
|
poll += PXG_COPROC_INTR_OFFSET >> 2;
|
|
|
|
/*
|
|
* XXX these should be defined as constants. 0x30 is
|
|
* "pause coprocessor and interrupt."
|
|
*/
|
|
*poll = 0x30;
|
|
tc_wmb();
|
|
|
|
for (i = 1000000; i; i--) {
|
|
DELAY(4);
|
|
|
|
switch(j = *poll) {
|
|
case 2:
|
|
pxi->pxi_pbuf_select = 4096;
|
|
break;
|
|
case 1:
|
|
pxi->pxi_pbuf_select = 0;
|
|
break;
|
|
default:
|
|
if (j == 0x30)
|
|
continue;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (j != 1 || j != 2) {
|
|
/* i860 has gone mad, punish it */
|
|
px_init_stic(pxi, 0);
|
|
pxi->pxi_pbuf_select = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
buf = (int32_t *)((u_long)pxi->pxi_rbuf + pxi->pxi_pbuf_select);
|
|
pxi->pxi_pbuf_select ^= 4096;
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* Send a PixelStamp packet.
|
|
*/
|
|
static int
|
|
px_send_packet(pxi, buf)
|
|
struct px_info *pxi;
|
|
int32_t *buf;
|
|
{
|
|
volatile int32_t *poll;
|
|
int c;
|
|
|
|
if (pxi->pxi_flg & PX_ISR_ENABLE) {
|
|
struct stic_regs *stic;
|
|
|
|
pxi->pxi_lpw++;
|
|
stic = pxi->pxi_stic;
|
|
|
|
/* Generate a packet-done interrupt */
|
|
c = stic->ipdvint;
|
|
c |= (STIC_INT_P_EN | STIC_INT_P | STIC_INT_P_WE);
|
|
c &= ~(STIC_INT_E_WE | STIC_INT_V_WE);
|
|
stic->ipdvint = c;
|
|
tc_wmb();
|
|
return (0);
|
|
}
|
|
|
|
/* Convert buffer address to i860 physical address for PXG */
|
|
if (pxi->pxi_option)
|
|
buf = (int32_t *)(((long)buf-(long)pxi->pxi_rbuf) & ~0x40000);
|
|
|
|
/* Get address of poll register for this buffer */
|
|
poll = px_poll_addr((caddr_t)pxi->pxi_slotbase, buf);
|
|
|
|
/*
|
|
* Now check the poll register and make sure the stamp wants to
|
|
* accept our packet. This read will initiate the DMA. Don't
|
|
* wait for ever, just in case something's wrong.
|
|
*/
|
|
tc_wmb();
|
|
|
|
for (c = STAMP_RETRIES; c; c--) {
|
|
if (*poll == STAMP_OK) {
|
|
#ifdef notdef
|
|
/* Tell the i860 we are done */
|
|
if (pxi->pxi_option) {
|
|
poll = (volatile int32_t*)pxi->pxi_slotbase +
|
|
(PXG_HOST_INTR_OFFSET >> 2);
|
|
|
|
poll[0] = 0;
|
|
tc_wmb();
|
|
poll[2] = 0;
|
|
tc_wmb();
|
|
}
|
|
#endif
|
|
return (0);
|
|
}
|
|
|
|
DELAY(STAMP_DELAY);
|
|
}
|
|
|
|
/*
|
|
* Oops... The STIC seems to have died. Reinitialize it and hope
|
|
* for the best. This is a non destructive operation anyhow, except
|
|
* for the packet that we just dropped on the floor.
|
|
*/
|
|
px_init_stic(pxi, 0);
|
|
tc_wmb();
|
|
return (-*poll);
|
|
}
|
|
|
|
/*
|
|
* Draw a 'flat' rectangle
|
|
*/
|
|
static int
|
|
px_rect(pxi, x, y, w, h, color)
|
|
struct px_info *pxi;
|
|
int x, y, w, h, color;
|
|
{
|
|
int *pb, linewidth;
|
|
|
|
pb = px_alloc_pbuf(pxi);
|
|
|
|
linewidth = (h << 2) - 1;
|
|
y = (y << 3) + linewidth;
|
|
|
|
pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
|
|
pb[1] = 0x01ffffff;
|
|
pb[2] = 0;
|
|
pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
|
|
pb[4] = linewidth;
|
|
pb[5] = color;
|
|
pb[6] = (x << 19) | y;
|
|
pb[7] = ((((x + w) << 3) - 1) << 16) | y;
|
|
|
|
return px_send_packet(pxi, pb);
|
|
}
|
|
|
|
/*
|
|
* Allocate attribute. We just pack these into an integer.
|
|
*/
|
|
static int
|
|
px_allocattr(cookie, fg, bg, flags, attr)
|
|
void *cookie;
|
|
int fg, bg, flags;
|
|
long *attr;
|
|
{
|
|
int swap;
|
|
|
|
if (flags & (WSATTR_BLINK | WSATTR_UNDERLINE))
|
|
return (EINVAL);
|
|
|
|
if (flags & WSATTR_HILIT)
|
|
fg += 8;
|
|
|
|
if (flags & WSATTR_REVERSE) {
|
|
swap = fg;
|
|
fg = bg;
|
|
bg = swap;
|
|
}
|
|
|
|
*attr = fg | (bg << 8) | (flags << 16);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Erase columns
|
|
*/
|
|
static void
|
|
px_erasecols(cookie, row, col, num, attr)
|
|
void *cookie;
|
|
int row, col, num;
|
|
long attr;
|
|
{
|
|
struct px_info *pxi = (struct px_info *)cookie;
|
|
int32_t *pb;
|
|
u_int linewidth;
|
|
|
|
col = (col * pxi->pxi_font->fontwidth) << 19;
|
|
num = (num * pxi->pxi_font->fontwidth) << 19;
|
|
row = row * pxi->pxi_font->fontheight;
|
|
|
|
pb = px_alloc_pbuf(pxi);
|
|
|
|
linewidth = (pxi->pxi_font->fontheight << 2) - 1;
|
|
row = (row << 3) + linewidth;
|
|
|
|
pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
|
|
pb[1] = 0x01ffffff;
|
|
pb[2] = 0;
|
|
pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
|
|
pb[4] = linewidth;
|
|
pb[5] = DUPBYTE1(attr);
|
|
pb[6] = col | row;
|
|
pb[7] = (col + num) | row;
|
|
|
|
px_send_packet(pxi, pb);
|
|
}
|
|
|
|
/*
|
|
* Erase rows
|
|
*/
|
|
static void
|
|
px_eraserows(cookie, row, num, attr)
|
|
void *cookie;
|
|
int row, num;
|
|
long attr;
|
|
{
|
|
struct px_info *pxi = (struct px_info *)cookie;
|
|
int32_t *pb;
|
|
int linewidth;
|
|
|
|
row *= pxi->pxi_font->fontheight;
|
|
num *= pxi->pxi_font->fontheight;
|
|
|
|
pb = px_alloc_pbuf(pxi);
|
|
|
|
linewidth = (num << 2) - 1;
|
|
row = (row << 3) + linewidth;
|
|
|
|
pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
|
|
pb[1] = 0x01ffffff;
|
|
pb[2] = 0;
|
|
pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
|
|
pb[4] = linewidth;
|
|
pb[5] = DUPBYTE1(attr);
|
|
pb[6] = row;
|
|
pb[7] = (1280 << 19) | row;
|
|
|
|
px_send_packet(pxi, pb);
|
|
}
|
|
|
|
/*
|
|
* Copy rows.
|
|
*/
|
|
static void
|
|
px_copyrows(cookie, src, dst, height)
|
|
void *cookie;
|
|
int src, dst, height;
|
|
{
|
|
struct px_info *pxi;
|
|
int32_t *pb, *pbs;
|
|
int num, inc, adj;
|
|
|
|
pxi = (struct px_info *)cookie;
|
|
|
|
/*
|
|
* We need to do this in reverse if the destination row is below
|
|
* the source.
|
|
*/
|
|
if (dst > src) {
|
|
src += height;
|
|
dst += height;
|
|
inc = -8;
|
|
adj = -1;
|
|
} else {
|
|
inc = 8;
|
|
adj = 0;
|
|
}
|
|
|
|
src = (src * pxi->pxi_font->fontheight + adj) << 3;
|
|
dst = (dst * pxi->pxi_font->fontheight + adj) << 3;
|
|
height *= pxi->pxi_font->fontheight;
|
|
|
|
while (height > 0) {
|
|
num = (height < 255 ? height : 255);
|
|
height -= num;
|
|
|
|
pb = pbs = px_alloc_pbuf(pxi);
|
|
|
|
/*
|
|
* We can use COPYSPAN_ALIGNED here to improve performance
|
|
* since the source and destination X co-ordinates are
|
|
* identical.
|
|
*/
|
|
*pb++ = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
|
|
*pb++ = (num << 24) | 0xffffff;
|
|
*pb++ = 0x0;
|
|
*pb++ = STAMP_UPDATE_ENABLE |
|
|
STAMP_METHOD_COPY |
|
|
STAMP_SPAN |
|
|
STAMP_COPYSPAN_ALIGNED;
|
|
*pb++ = 1; /* linewidth */
|
|
|
|
for ( ; num > 0; num--, src += inc, dst += inc) {
|
|
*pb++ = 1280 << 3;
|
|
*pb++ = src;
|
|
*pb++ = dst;
|
|
}
|
|
|
|
px_send_packet(pxi, pbs);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Copy columns.
|
|
*/
|
|
static void
|
|
px_copycols(cookie, row, src, dst, num)
|
|
void *cookie;
|
|
int row, src, dst, num;
|
|
{
|
|
struct px_info *pxi = (struct px_info *)cookie;
|
|
int32_t *pb, *pbs;
|
|
int height, updword;
|
|
|
|
/*
|
|
* Due the fact that the stamp reads and writes left->right only,
|
|
* we need to "half-buffer" if the source and destination regions
|
|
* overlap, and the source is left of the destination. This is
|
|
* slower than just a simple copy.
|
|
*/
|
|
updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
|
|
|
|
if (src < dst && src + num > dst)
|
|
updword |= STAMP_HALF_BUFF;
|
|
|
|
row = (row * pxi->pxi_font->fontheight) << 3;
|
|
num = (num * pxi->pxi_font->fontwidth) << 3;
|
|
src = row | ((src * pxi->pxi_font->fontwidth) << 19);
|
|
dst = row | ((dst * pxi->pxi_font->fontwidth) << 19);
|
|
height = pxi->pxi_font->fontheight;
|
|
|
|
pb = pbs = px_alloc_pbuf(pxi);
|
|
|
|
*pb++ = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
|
|
*pb++ = (height << 24) | 0xffffff;
|
|
*pb++ = 0x0;
|
|
*pb++ = updword;
|
|
*pb++ = 1; /* linewidth */
|
|
|
|
for ( ; height; height--, src += 8, dst += 8) {
|
|
*pb++ = num;
|
|
*pb++ = src;
|
|
*pb++ = dst;
|
|
}
|
|
|
|
px_send_packet(pxi, pbs);
|
|
}
|
|
|
|
/*
|
|
* Blit a character at the specified co-ordinates.
|
|
*/
|
|
static void
|
|
px_putchar(cookie, r, c, uc, attr)
|
|
void *cookie;
|
|
int r, c;
|
|
u_int uc;
|
|
long attr;
|
|
{
|
|
struct wsdisplay_font *font;
|
|
struct px_info *pxi;
|
|
int i, bgcolor, fgcolor;
|
|
unsigned short *fr; /* font row data */
|
|
int *pb; /* packet buffer ptr */
|
|
int v1; /* mask co-ords */
|
|
int v2; /* mask co-ords */
|
|
int xya; /* saved XY position */
|
|
|
|
/* Don't bother blitting the space character */
|
|
if (uc == ' ') {
|
|
px_erasecols(cookie, r, c, 1, attr);
|
|
return;
|
|
}
|
|
|
|
pxi = (struct px_info *)cookie;
|
|
font = pxi->pxi_font;
|
|
pb = px_alloc_pbuf(pxi);
|
|
|
|
pb[0] = STAMP_CMD_LINES |
|
|
STAMP_RGB_FLAT |
|
|
STAMP_XY_PERPRIMATIVE |
|
|
STAMP_LW_PERPRIMATIVE;
|
|
pb[2] = 0x0;
|
|
pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
|
|
|
|
if (font->fontheight > 16)
|
|
pb[1] = 0x04ffffff;
|
|
else
|
|
pb[1] = 0x02ffffff;
|
|
|
|
r *= font->fontheight;
|
|
c *= font->fontwidth;
|
|
uc = (uc - font->firstchar) * pxi->pxi_fontscale;
|
|
fr = (u_short *)((caddr_t)font->data + uc);
|
|
bgcolor = DUPBYTE1(attr);
|
|
fgcolor = DUPBYTE0(attr);
|
|
|
|
i = (16 << 2) - 1;
|
|
v1 = (c << 19) | ((r << 3) + i);
|
|
v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
|
|
xya = XYMASKADDR(c, r, 0, 0);
|
|
|
|
pb[4] = PACK_WORD(fr, 0);
|
|
pb[5] = PACK_WORD(fr, 2);
|
|
pb[6] = PACK_WORD(fr, 4);
|
|
pb[7] = PACK_WORD(fr, 6);
|
|
pb[8] = PACK_WORD(fr, 8);
|
|
pb[9] = PACK_WORD(fr, 10);
|
|
pb[10] = PACK_WORD(fr, 12);
|
|
pb[11] = PACK_WORD(fr, 14);
|
|
pb[12] = xya;
|
|
pb[13] = v1;
|
|
pb[14] = v2;
|
|
pb[15] = i;
|
|
pb[16] = fgcolor;
|
|
|
|
/* opaque background mask */
|
|
pb[17] = ~pb[4];
|
|
pb[18] = ~pb[5];
|
|
pb[19] = ~pb[6];
|
|
pb[20] = ~pb[7];
|
|
pb[21] = ~pb[8];
|
|
pb[22] = ~pb[9];
|
|
pb[23] = ~pb[10];
|
|
pb[24] = ~pb[11];
|
|
pb[25] = xya;
|
|
pb[26] = v1;
|
|
pb[27] = v2;
|
|
pb[28] = i;
|
|
pb[29] = bgcolor;
|
|
|
|
if (font->fontheight > 16) {
|
|
i = ((font->fontheight - 16) << 2) - 1;
|
|
r += 16;
|
|
v1 = (c << 19) | ((r << 3) + i);
|
|
v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
|
|
|
|
/* lower part of fg character */
|
|
pb[30] = PACK_WORD(fr, 16);
|
|
pb[31] = PACK_WORD(fr, 18);
|
|
pb[32] = PACK_WORD(fr, 20);
|
|
pb[33] = PACK_WORD(fr, 22);
|
|
pb[34] = PACK_WORD(fr, 24);
|
|
pb[35] = PACK_WORD(fr, 26);
|
|
pb[36] = PACK_WORD(fr, 28);
|
|
pb[37] = PACK_WORD(fr, 30);
|
|
pb[38] = xya;
|
|
pb[39] = v1;
|
|
pb[40] = v2;
|
|
pb[41] = i;
|
|
pb[42] = fgcolor;
|
|
|
|
/* opaque background */
|
|
pb[43] = ~pb[30];
|
|
pb[44] = ~pb[31];
|
|
pb[45] = ~pb[32];
|
|
pb[46] = ~pb[33];
|
|
pb[47] = ~pb[34];
|
|
pb[48] = ~pb[35];
|
|
pb[49] = ~pb[36];
|
|
pb[50] = ~pb[37];
|
|
pb[51] = xya;
|
|
pb[52] = v1;
|
|
pb[53] = v2;
|
|
pb[54] = i;
|
|
pb[55] = bgcolor;
|
|
}
|
|
|
|
px_send_packet(pxi, pb);
|
|
}
|
|
|
|
/*
|
|
* Map a character.
|
|
*/
|
|
static int
|
|
px_mapchar(cookie, c, cp)
|
|
void *cookie;
|
|
int c;
|
|
u_int *cp;
|
|
{
|
|
struct px_info *pxi;
|
|
|
|
pxi = (struct px_info *)cookie;
|
|
|
|
if (c < pxi->pxi_font->firstchar) {
|
|
*cp = ' ';
|
|
return (0);
|
|
}
|
|
|
|
if (c - pxi->pxi_font->firstchar >= pxi->pxi_font->numchars) {
|
|
*cp = ' ';
|
|
return (0);
|
|
}
|
|
|
|
*cp = c;
|
|
return (5);
|
|
}
|
|
|
|
/*
|
|
* Position|{enable|disable} the cursor at the specified location.
|
|
*/
|
|
static void
|
|
px_cursor(cookie, on, row, col)
|
|
void *cookie;
|
|
int on, row, col;
|
|
{
|
|
struct px_info *pxi;
|
|
|
|
pxi = (struct px_info *)cookie;
|
|
#if 0
|
|
if (row < 0)
|
|
row = 0;
|
|
else if (row > pxi->pxi_max_row)
|
|
row = pxi->pxi_max_row;
|
|
|
|
if (col < 0)
|
|
col = 0;
|
|
else if (col > pxi->pxi_max_col)
|
|
col = pxi->pxi_max_col;
|
|
#endif
|
|
/*
|
|
* These magic offsets (370, 37) were obtained by looking at sfb.c
|
|
* and then bumping them until they worked right.
|
|
*/
|
|
pxi->pxi_curx = col * pxi->pxi_font->fontwidth + 370;
|
|
pxi->pxi_cury = row * pxi->pxi_font->fontheight + 37;
|
|
|
|
if (on)
|
|
pxi->pxi_flg |= PX_CURSOR_ENABLE;
|
|
else
|
|
pxi->pxi_flg &= ~PX_CURSOR_ENABLE;
|
|
|
|
pxi->pxi_dirty |= (PX_DIRTY_CURSOR_ENABLE | PX_DIRTY_CURSOR_POS);
|
|
|
|
if (pxi->pxi_option)
|
|
px_bt459_flush(pxi);
|
|
}
|
|
|
|
/*
|
|
* Move the cursor for qvss. This is disgusting.
|
|
*/
|
|
static void
|
|
px_cursor_hack(fi, x, y)
|
|
struct fbinfo *fi;
|
|
int x, y;
|
|
{
|
|
struct px_info *pxi;
|
|
|
|
pxi = (struct px_info *)fi->fi_base;
|
|
pxi->pxi_curx = x + 370;
|
|
pxi->pxi_cury = y + 37;
|
|
pxi->pxi_dirty |= PX_DIRTY_CURSOR_POS;
|
|
|
|
if (pxi->pxi_option)
|
|
px_bt459_flush(pxi);
|
|
}
|
|
|
|
int
|
|
pxopen(dev, flag, mode, p)
|
|
dev_t dev;
|
|
int flag, mode;
|
|
struct proc *p;
|
|
{
|
|
extern struct fbinfo *firstfi; /* XXX */
|
|
struct stic_regs *stic;
|
|
struct px_info *pxi;
|
|
int s;
|
|
|
|
if (minor(dev) >= NPX || px_unit[minor(dev)] == NULL)
|
|
return (ENXIO);
|
|
|
|
pxi = px_unit[minor(dev)];
|
|
|
|
if (pxi->pxi_flg & PX_OPEN)
|
|
return (EBUSY);
|
|
|
|
pxi->pxi_flg = (pxi->pxi_flg | PX_OPEN) & ~PX_CURSOR_ENABLE;
|
|
pxi->pxi_flg &= ~PX_ISR_MASK;
|
|
pxi->pxi_dirty |= PX_DIRTY_CURSOR_ENABLE;
|
|
pxi->pxi_fbinfo.fi_open = 1;
|
|
|
|
/*
|
|
* Set up event queue for later
|
|
*/
|
|
firstfi = &pxi->pxi_fbinfo; /* XXX */
|
|
pmEventQueueInit(&pxi->pxi_fbuaccess.scrInfo.qe);
|
|
genConfigMouse();
|
|
|
|
/* Turn packet-done interrupts on */
|
|
stic = pxi->pxi_stic;
|
|
s = stic->ipdvint | STIC_INT_P_WE | STIC_INT_P_EN;
|
|
s &= ~(STIC_INT_E_WE | STIC_INT_V_WE | STIC_INT_P);
|
|
stic->ipdvint = s;
|
|
tc_wmb();
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
pxclose(dev, flag, mode, p)
|
|
dev_t dev;
|
|
int flag, mode;
|
|
struct proc *p;
|
|
{
|
|
extern struct fbinfo *firstfi; /* XXX */
|
|
struct stic_regs *stic;
|
|
struct px_info *pxi;
|
|
int s;
|
|
|
|
if (minor(dev) >= NPX || px_unit[minor(dev)] == NULL)
|
|
return (EBADF);
|
|
|
|
pxi = px_unit[minor(dev)];
|
|
|
|
if ((pxi->pxi_flg & PX_OPEN) == 0)
|
|
return (EBADF);
|
|
|
|
pxi->pxi_flg = (pxi->pxi_flg & ~PX_OPEN) | PX_ENABLE;
|
|
pxi->pxi_fbinfo.fi_open = 0;
|
|
genDeconfigMouse();
|
|
firstfi = NULL;
|
|
|
|
/* Disable interrupt driven operation */
|
|
s = splhigh();
|
|
pxi->pxi_lpw = 0;
|
|
pxi->pxi_lpr = 0;
|
|
pxi->pxi_flg &= ~PX_ISR_MASK;
|
|
splx(s);
|
|
|
|
/* Turn packet-done interrupts off */
|
|
stic = pxi->pxi_stic;
|
|
s = stic->ipdvint | STIC_INT_P_WE;
|
|
s &= ~(STIC_INT_E_WE | STIC_INT_V_WE | STIC_INT_P_EN);
|
|
stic->ipdvint = s;
|
|
tc_wmb();
|
|
|
|
px_init_stic(pxi, 0);
|
|
px_bt459_init(pxi);
|
|
px_rect(pxi, 0, 0, 1280, 1024, 0);
|
|
pxi->pxi_dirty |= PX_DIRTY_ENABLE; /* make sure video is enabled */
|
|
if (pxi->pxi_option)
|
|
px_bt459_flush(pxi);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
pxioctl(dev, cmd, data, flag, p)
|
|
dev_t dev;
|
|
u_long cmd;
|
|
caddr_t data;
|
|
int flag;
|
|
struct proc *p;
|
|
{
|
|
struct pmax_fbtty *fbtty;
|
|
struct px_info *pxi;
|
|
pmKpCmd *kpCmdPtr;
|
|
u_char *cp;
|
|
u_int *ptr;
|
|
int i;
|
|
|
|
if (minor(dev) >= NPX || px_unit[minor(dev)] == NULL)
|
|
return (EBADF);
|
|
|
|
pxi = px_unit[minor(dev)];
|
|
fbtty = pxi->pxi_fbinfo.fi_glasstty;
|
|
|
|
if ((pxi->pxi_flg & PX_OPEN) == 0)
|
|
return (EBADF);
|
|
|
|
switch (cmd) {
|
|
case QIOCGINFO:
|
|
/*
|
|
* Map card info.
|
|
*/
|
|
return (px_mmap_info(p, dev, (vaddr_t *)data));
|
|
|
|
case QIOCPMSTATE:
|
|
/*
|
|
* Set mouse state.
|
|
*/
|
|
pxi->pxi_curx = ((pmCursor *)data)->x + 370;
|
|
pxi->pxi_cury = ((pmCursor *)data)->y + 37;
|
|
pxi->pxi_dirty |= PX_DIRTY_CURSOR_POS;
|
|
break;
|
|
|
|
case QIOCINIT:
|
|
px_rect(pxi, 0, 0, 1280, 1024, 0);
|
|
break;
|
|
|
|
case QIOVIDEOON:
|
|
pxi->pxi_flg |= PX_ENABLE;
|
|
pxi->pxi_dirty |= PX_DIRTY_ENABLE;
|
|
break;
|
|
|
|
case QIOVIDEOOFF:
|
|
pxi->pxi_flg &= ~PX_ENABLE;
|
|
pxi->pxi_dirty |= PX_DIRTY_ENABLE;
|
|
break;
|
|
|
|
case QIOWCURSOR:
|
|
px_conv_cursor(pxi, (u_short *)data);
|
|
pxi->pxi_flg |= PX_CURSOR_ENABLE;
|
|
pxi->pxi_dirty |= PX_DIRTY_CURSOR | PX_DIRTY_CURSOR_ENABLE;
|
|
break;
|
|
|
|
case QIOWCURSORCOLOR:
|
|
ptr = (u_int *)data;
|
|
|
|
for (i = 0; i < 6; i++)
|
|
pxi->pxi_curcmap[i] = *ptr++ >> 8;
|
|
|
|
pxi->pxi_dirty |= PX_DIRTY_CURSOR_CMAP;
|
|
break;
|
|
|
|
case QIOSETCMAP:
|
|
i = ((ColorMap *)data)->index;
|
|
if (i < 0 || i > 255)
|
|
return (-1);
|
|
|
|
pxi->pxi_cmap_idx = i;
|
|
pxi->pxi_cmap_cnt = 1;
|
|
i = (i << 1) + i;
|
|
pxi->pxi_cmap[i+0] = ((ColorMap *)data)->Entry.red;
|
|
pxi->pxi_cmap[i+1] = ((ColorMap *)data)->Entry.green;
|
|
pxi->pxi_cmap[i+2] = ((ColorMap *)data)->Entry.blue;
|
|
pxi->pxi_dirty |= PX_DIRTY_CMAP;
|
|
break;
|
|
|
|
case QIOCKPCMD:
|
|
/*
|
|
* Keyboard command.
|
|
*/
|
|
kpCmdPtr = (pmKpCmd *)data;
|
|
if (kpCmdPtr->nbytes == 0)
|
|
kpCmdPtr->cmd |= 0x80;
|
|
(*fbtty->KBDPutc)(fbtty->kbddev, (int)kpCmdPtr->cmd);
|
|
cp = &kpCmdPtr->par[0];
|
|
for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) {
|
|
if (kpCmdPtr->nbytes == 1)
|
|
*cp |= 0x80;
|
|
(*fbtty->KBDPutc)(fbtty->kbddev, (int)*cp);
|
|
}
|
|
break;
|
|
|
|
case QIOKERNLOOP:
|
|
genConfigMouse();
|
|
break;
|
|
|
|
case QIOKERNUNLOOP:
|
|
genDeconfigMouse();
|
|
break;
|
|
|
|
default:
|
|
printf("px%d: unknown ioctl %lx\n", minor(dev), cmd);
|
|
return (EINVAL);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
pxpoll(dev, events, p)
|
|
dev_t dev;
|
|
int events;
|
|
struct proc *p;
|
|
{
|
|
struct fbinfo *fi = &px_unit[minor(dev)]->pxi_fbinfo;
|
|
int revents = 0;
|
|
|
|
if (events & (POLLIN | POLLRDNORM)) {
|
|
if (fi->fi_fbu->scrInfo.qe.eHead !=
|
|
fi->fi_fbu->scrInfo.qe.eTail)
|
|
revents |= (events & (POLLIN | POLLRDNORM));
|
|
else
|
|
selrecord(p, &fi->fi_selp);
|
|
}
|
|
|
|
return (revents);
|
|
}
|
|
|
|
static void
|
|
filt_pxrdetach(struct knote *kn)
|
|
{
|
|
struct fbinfo *fi = kn->kn_hook;
|
|
int s;
|
|
|
|
s = spltty();
|
|
SLIST_REMOVE(&fi->fi_selp.sel_klist, kn, knote, kn_selnext);
|
|
splx(s);
|
|
}
|
|
|
|
static int
|
|
filt_pxread(struct knote *kn, long hint)
|
|
{
|
|
struct fbinfo *fi = kn->kn_hook;
|
|
|
|
if (fi->fi_fbu->scrInfo.qe.eHead == fi->fi_fbu->scrInfo.qe.eTail)
|
|
return (0);
|
|
|
|
kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
|
|
return (1);
|
|
}
|
|
|
|
static const struct filterops pxread_filtops =
|
|
{ 1, NULL, filt_pxrdetach, filt_pxread };
|
|
|
|
int
|
|
pxkqfilter(dev_t dev, struct knote *kn)
|
|
{
|
|
struct fbinfo *fi = &px_unit[minor(dev)]->pxi_fbinfo;
|
|
struct klist *klist;
|
|
int s;
|
|
|
|
switch (kn->kn_filter) {
|
|
case EVFILT_READ:
|
|
klist = &fi->fi_selp.sel_klist;
|
|
kn->kn_fop = &pxread_filtops;
|
|
break;
|
|
|
|
default:
|
|
return (1);
|
|
}
|
|
|
|
kn->kn_hook = fi;
|
|
|
|
s = spltty();
|
|
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
|
|
splx(s);
|
|
|
|
return (0);
|
|
}
|
|
|
|
paddr_t
|
|
pxmmap(dev, off, prot)
|
|
dev_t dev;
|
|
off_t off;
|
|
int prot;
|
|
{
|
|
struct px_info *pxi;
|
|
|
|
if (minor(dev) >= NPX || px_unit[minor(dev)] == NULL)
|
|
return (EBADF);
|
|
|
|
pxi = px_unit[minor(dev)];
|
|
|
|
if ((pxi->pxi_flg & PX_OPEN) == 0)
|
|
return (EBADF);
|
|
|
|
/*
|
|
* STIC control registers
|
|
*/
|
|
if (off < PAGE_SIZE)
|
|
return mips_btop(MIPS_KSEG1_TO_PHYS(pxi->pxi_stic) + off);
|
|
off -= PAGE_SIZE;
|
|
|
|
/*
|
|
* STIC poll registers
|
|
*/
|
|
if (off < sizeof(int32_t) * 4096)
|
|
return mips_btop(MIPS_KSEG1_TO_PHYS(pxi->pxi_poll) + off);
|
|
off -= sizeof(int32_t) * 4096;
|
|
|
|
/*
|
|
* 'struct px_info' and ringbuffer
|
|
*/
|
|
if (off < PXMAP_INFO_SIZE + PXMAP_RBUF_SIZE)
|
|
return mips_btop(MIPS_KSEG1_TO_PHYS(pxi) + off);
|
|
off -= (PXMAP_INFO_SIZE + PXMAP_RBUF_SIZE);
|
|
|
|
return (-1);
|
|
}
|
|
|
|
/*
|
|
* mmap info struct for this card into userspace.
|
|
*/
|
|
static int
|
|
px_mmap_info (p, dev, va)
|
|
struct proc *p;
|
|
dev_t dev;
|
|
vaddr_t *va;
|
|
{
|
|
struct specinfo si;
|
|
struct vnode vn;
|
|
vm_prot_t prot;
|
|
vsize_t size;
|
|
int flags;
|
|
|
|
vn.v_type = VCHR; /* XXX */
|
|
vn.v_specinfo = &si; /* XXX */
|
|
vn.v_rdev = dev; /* XXX */
|
|
|
|
size = sizeof(struct px_map);
|
|
prot = VM_PROT_READ | VM_PROT_WRITE;
|
|
flags = MAP_SHARED | MAP_FILE;
|
|
*va = VM_DEFAULT_ADDRESS(p->p_vmspace->vm_daddr, size);
|
|
return uvm_mmap(&p->p_vmspace->vm_map, va, size, prot,
|
|
VM_PROT_ALL, flags, &vn, 0, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
|
|
}
|