e0cc03a09b
kqueue provides a stateful and efficient event notification framework currently supported events include socket, file, directory, fifo, pipe, tty and device changes, and monitoring of processes and signals kqueue is supported by all writable filesystems in NetBSD tree (with exception of Coda) and all device drivers supporting poll(2) based on work done by Jonathan Lemon for FreeBSD initial NetBSD port done by Luke Mewburn and Jason Thorpe
2004 lines
46 KiB
C
2004 lines
46 KiB
C
/* $NetBSD: px.c,v 1.43 2002/10/23 09:11:50 jdolecek 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.43 2002/10/23 09:11:50 jdolecek 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 (NBPG)
|
|
#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.si_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.si_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 < NBPG)
|
|
return mips_btop(MIPS_KSEG1_TO_PHYS(pxi->pxi_stic) + off);
|
|
off -= NBPG;
|
|
|
|
/*
|
|
* 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 = round_page((vaddr_t)p->p_vmspace->vm_taddr + MAXTSIZ + MAXDSIZ);
|
|
return uvm_mmap(&p->p_vmspace->vm_map, va, size, prot,
|
|
VM_PROT_ALL, flags, &vn, 0, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
|
|
}
|