497 lines
12 KiB
C
497 lines
12 KiB
C
/* $NetBSD: lcspx.c,v 1.2 2004/03/19 20:12:07 mhitch Exp $ */
|
|
/*
|
|
* Copyright (c) 1998 Ludd, University of Lule}, Sweden.
|
|
* All rights reserved.
|
|
*
|
|
* 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 at Ludd, University of
|
|
* Lule}, Sweden and its contributors.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: lcspx.c,v 1.2 2004/03/19 20:12:07 mhitch Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/device.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/callout.h>
|
|
#include <sys/time.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/kernel.h>
|
|
|
|
#include <machine/vsbus.h>
|
|
#include <machine/sid.h>
|
|
#include <machine/cpu.h>
|
|
|
|
#include <dev/cons.h>
|
|
|
|
#include <dev/dec/dzreg.h>
|
|
#include <dev/dec/dzvar.h>
|
|
#include <dev/dec/dzkbdvar.h>
|
|
|
|
#include <dev/wscons/wsdisplayvar.h>
|
|
#include <dev/wscons/wsconsio.h>
|
|
#include <dev/wscons/wscons_callbacks.h>
|
|
|
|
#include "machine/scb.h"
|
|
|
|
#include "dzkbd.h"
|
|
#include "opt_wsfont.h"
|
|
|
|
/* Safety guard */
|
|
#ifndef FONT_QVSS8x15
|
|
#include <dev/wsfont/qvss8x15.h>
|
|
#endif
|
|
|
|
/* Screen hardware defs */
|
|
#define SPX_COLS 160 /* char width of screen */
|
|
#define SPX_ROWS 68 /* rows of char on screen */
|
|
#define SPX_CHEIGHT 15 /* lines a char consists of */
|
|
#define SPX_CWIDTH 8 /* cols a char consists of */
|
|
#define SPX_NEXTROW (SPX_COLS * SPX_CHEIGHT * SPX_CWIDTH)
|
|
#define SPX_YWIDTH 1024
|
|
#define SPX_XWIDTH 1280
|
|
|
|
#define SPXADDR 0x38000000 /* Frame buffer */
|
|
#define SPXSIZE 0x00800000 /* 8MB in size */
|
|
|
|
static int lcspx_match(struct device *, struct cfdata *, void *);
|
|
static void lcspx_attach(struct device *, struct device *, void *);
|
|
|
|
struct lcspx_softc {
|
|
struct device ss_dev;
|
|
};
|
|
|
|
CFATTACH_DECL(lcspx, sizeof(struct lcspx_softc),
|
|
lcspx_match, lcspx_attach, NULL, NULL);
|
|
|
|
static void lcspx_cursor(void *, int, int, int);
|
|
static int lcspx_mapchar(void *, int, unsigned int *);
|
|
static void lcspx_putchar(void *, int, int, u_int, long);
|
|
static void lcspx_copycols(void *, int, int, int,int);
|
|
static void lcspx_erasecols(void *, int, int, int, long);
|
|
static void lcspx_copyrows(void *, int, int, int);
|
|
static void lcspx_eraserows(void *, int, int, long);
|
|
static int lcspx_allocattr(void *, int, int, int, long *);
|
|
|
|
const struct wsdisplay_emulops lcspx_emulops = {
|
|
lcspx_cursor,
|
|
lcspx_mapchar,
|
|
lcspx_putchar,
|
|
lcspx_copycols,
|
|
lcspx_erasecols,
|
|
lcspx_copyrows,
|
|
lcspx_eraserows,
|
|
lcspx_allocattr
|
|
};
|
|
|
|
const struct wsscreen_descr lcspx_stdscreen = {
|
|
"160x68", SPX_COLS, SPX_ROWS,
|
|
&lcspx_emulops,
|
|
8, SPX_CHEIGHT,
|
|
WSSCREEN_UNDERLINE|WSSCREEN_REVERSE,
|
|
};
|
|
|
|
const struct wsscreen_descr *_lcspx_scrlist[] = {
|
|
&lcspx_stdscreen,
|
|
};
|
|
|
|
const struct wsscreen_list lcspx_screenlist = {
|
|
sizeof(_lcspx_scrlist) / sizeof(struct wsscreen_descr *),
|
|
_lcspx_scrlist,
|
|
};
|
|
|
|
static char *lcspxaddr;
|
|
|
|
extern struct wsdisplay_font qvss8x15;
|
|
static u_char *qf;
|
|
|
|
#define QCHAR(c) (c < 32 ? 32 : (c > 127 ? c - 66 : c - 32))
|
|
#define QFONT(c,line) qf[QCHAR(c) * 15 + line]
|
|
#define SPX_ADDR(row, col, line, dot) \
|
|
lcspxaddr[(col * SPX_CWIDTH) + (row * SPX_CHEIGHT * SPX_XWIDTH) + \
|
|
line * SPX_XWIDTH + dot]
|
|
|
|
|
|
static int lcspx_ioctl(void *, u_long, caddr_t, int, struct proc *);
|
|
static paddr_t lcspx_mmap(void *, off_t, int);
|
|
static int lcspx_alloc_screen(void *, const struct wsscreen_descr *,
|
|
void **, int *, int *, long *);
|
|
static void lcspx_free_screen(void *, void *);
|
|
static int lcspx_show_screen(void *, void *, int,
|
|
void (*) (void *, int, int), void *);
|
|
static void lcspx_crsr_blink(void *);
|
|
|
|
const struct wsdisplay_accessops lcspx_accessops = {
|
|
lcspx_ioctl,
|
|
lcspx_mmap,
|
|
lcspx_alloc_screen,
|
|
lcspx_free_screen,
|
|
lcspx_show_screen,
|
|
0 /* load_font */
|
|
};
|
|
|
|
struct lcspx_screen {
|
|
int ss_curx;
|
|
int ss_cury;
|
|
u_char ss_image[SPX_ROWS][SPX_COLS]; /* Image of current screen */
|
|
u_char ss_attr[SPX_ROWS][SPX_COLS]; /* Reversed etc... */
|
|
};
|
|
|
|
static struct lcspx_screen lcspx_conscreen;
|
|
static struct lcspx_screen *curscr;
|
|
|
|
static struct callout lcspx_cursor_ch = CALLOUT_INITIALIZER;
|
|
|
|
int
|
|
lcspx_match(struct device *parent, struct cfdata *match, void *aux)
|
|
{
|
|
struct vsbus_softc *sc = (void *)parent;
|
|
struct vsbus_attach_args *va = aux;
|
|
char *ch = (char *)va->va_addr;
|
|
|
|
if (vax_boardtype != VAX_BTYP_49)
|
|
return 0;
|
|
|
|
*ch = 1;
|
|
if ((*ch & 1) == 0)
|
|
return 0;
|
|
*ch = 0;
|
|
if ((*ch & 1) != 0)
|
|
return 0;
|
|
|
|
sc->sc_mask = 0x04; /* XXX - should be generated */
|
|
scb_fake(0x120, 0x15);
|
|
return 20;
|
|
}
|
|
|
|
void
|
|
lcspx_attach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
struct vsbus_attach_args *va = aux;
|
|
struct wsemuldisplaydev_attach_args aa;
|
|
|
|
printf("\n");
|
|
aa.console = lcspxaddr != NULL;
|
|
if (lcspxaddr == 0)
|
|
lcspxaddr = (caddr_t)vax_map_physmem(va->va_paddr, (SPXSIZE/VAX_NBPG));
|
|
if (lcspxaddr == 0) {
|
|
printf("%s: Couldn't alloc graphics memory.\n", self->dv_xname);
|
|
return;
|
|
}
|
|
curscr = &lcspx_conscreen;
|
|
|
|
aa.scrdata = &lcspx_screenlist;
|
|
aa.accessops = &lcspx_accessops;
|
|
qf = qvss8x15.data;
|
|
|
|
/* enable software cursor */
|
|
callout_reset(&lcspx_cursor_ch, hz / 2, lcspx_crsr_blink, NULL);
|
|
|
|
config_found(self, &aa, wsemuldisplaydevprint);
|
|
}
|
|
|
|
static char *cursor;
|
|
static int cur_on;
|
|
|
|
static void
|
|
lcspx_crsr_blink(void *arg)
|
|
{
|
|
int i;
|
|
|
|
if (cur_on)
|
|
for (i = 0; i < 8; ++i)
|
|
cursor[i] ^= 255;
|
|
callout_reset(&lcspx_cursor_ch, hz / 2, lcspx_crsr_blink, NULL);
|
|
}
|
|
|
|
void
|
|
lcspx_cursor(void *id, int on, int row, int col)
|
|
{
|
|
struct lcspx_screen *ss = id;
|
|
int i;
|
|
|
|
if (ss == curscr) {
|
|
char ch = QFONT(ss->ss_image[ss->ss_cury][ss->ss_curx], 14);
|
|
|
|
if (cursor != NULL)
|
|
for (i = 0; i < 8; i++)
|
|
cursor[i] = (ch >> i) & 1;
|
|
cursor = &SPX_ADDR(row, col, 14, 0);
|
|
if ((cur_on = on))
|
|
for (i = 0; i < 8; i++)
|
|
cursor[i] ^= cursor[i];
|
|
}
|
|
ss->ss_curx = col;
|
|
ss->ss_cury = row;
|
|
}
|
|
|
|
int
|
|
lcspx_mapchar(void *id, int uni, unsigned int *index)
|
|
{
|
|
if (uni < 256) {
|
|
*index = uni;
|
|
return (5);
|
|
}
|
|
*index = ' ';
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
lcspx_putchar(void *id, int row, int col, u_int c, long attr)
|
|
{
|
|
struct lcspx_screen *ss = id;
|
|
int i, j;
|
|
|
|
c &= 0xff;
|
|
|
|
ss->ss_image[row][col] = c;
|
|
ss->ss_attr[row][col] = attr;
|
|
if (ss != curscr)
|
|
return;
|
|
for (i = 0; i < 15; i++) {
|
|
unsigned char ch = QFONT(c, i);
|
|
char dot;
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
dot = (ch >> j) & 1;
|
|
if (attr & WSATTR_REVERSE)
|
|
dot = (~dot) & 1;
|
|
SPX_ADDR(row, col, i, j) = dot;
|
|
}
|
|
}
|
|
if (attr & WSATTR_UNDERLINE) {
|
|
char *p = &SPX_ADDR(row, col, i, 0);
|
|
for (i = 0; i < 8; i++)
|
|
p[i] = ~p[i];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* copies columns inside a row.
|
|
*/
|
|
static void
|
|
lcspx_copycols(void *id, int row, int srccol, int dstcol, int ncols)
|
|
{
|
|
struct lcspx_screen *ss = id;
|
|
int i;
|
|
|
|
bcopy(&ss->ss_image[row][srccol], &ss->ss_image[row][dstcol], ncols);
|
|
bcopy(&ss->ss_attr[row][srccol], &ss->ss_attr[row][dstcol], ncols);
|
|
if (ss != curscr)
|
|
return;
|
|
for (i = 0; i < SPX_CHEIGHT; i++)
|
|
memcpy(&SPX_ADDR(row, dstcol, i, 0),
|
|
&SPX_ADDR(row,srccol, i, 0), ncols * SPX_CWIDTH);
|
|
}
|
|
|
|
/*
|
|
* Erases a bunch of chars inside one row.
|
|
*/
|
|
static void
|
|
lcspx_erasecols(void *id, int row, int startcol, int ncols, long fillattr)
|
|
{
|
|
struct lcspx_screen *ss = id;
|
|
int i;
|
|
|
|
bzero(&ss->ss_image[row][startcol], ncols);
|
|
bzero(&ss->ss_attr[row][startcol], ncols);
|
|
if (ss != curscr)
|
|
return;
|
|
for (i = 0; i < SPX_CHEIGHT; i++)
|
|
memset(&SPX_ADDR(row, startcol, i, 0), 0, ncols * SPX_CWIDTH);
|
|
}
|
|
|
|
static void
|
|
lcspx_copyrows(void *id, int srcrow, int dstrow, int nrows)
|
|
{
|
|
struct lcspx_screen *ss = id;
|
|
|
|
bcopy(&ss->ss_image[srcrow][0], &ss->ss_image[dstrow][0],
|
|
nrows * SPX_COLS);
|
|
bcopy(&ss->ss_attr[srcrow][0], &ss->ss_attr[dstrow][0],
|
|
nrows * SPX_COLS);
|
|
if (ss != curscr)
|
|
return;
|
|
memcpy(&lcspxaddr[dstrow * SPX_NEXTROW],
|
|
&lcspxaddr[srcrow * SPX_NEXTROW], nrows * SPX_NEXTROW);
|
|
}
|
|
|
|
static void
|
|
lcspx_eraserows(void *id, int startrow, int nrows, long fillattr)
|
|
{
|
|
struct lcspx_screen *ss = id;
|
|
|
|
bzero(&ss->ss_image[startrow][0], nrows * SPX_COLS);
|
|
bzero(&ss->ss_attr[startrow][0], nrows * SPX_COLS);
|
|
if (ss != curscr)
|
|
return;
|
|
memset(&lcspxaddr[startrow * SPX_NEXTROW], 0, nrows * SPX_NEXTROW);
|
|
}
|
|
|
|
static int
|
|
lcspx_allocattr(void *id, int fg, int bg, int flags, long *attrp)
|
|
{
|
|
*attrp = flags;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
lcspx_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
|
|
{
|
|
struct wsdisplay_fbinfo *fb = (void *)data;
|
|
|
|
switch (cmd) {
|
|
case WSDISPLAYIO_GTYPE:
|
|
*(u_int *)data = WSDISPLAY_TYPE_SPX;
|
|
break;
|
|
|
|
case WSDISPLAYIO_GINFO:
|
|
fb->height = SPX_YWIDTH;
|
|
fb->width = SPX_XWIDTH;
|
|
fb->depth = 1;
|
|
fb->cmsize = 2;
|
|
break;
|
|
|
|
#if 0
|
|
case WSDISPLAYIO_SVIDEO:
|
|
if (*(u_int *)data == WSDISPLAYIO_VIDEO_ON) {
|
|
curcmd = curc;
|
|
} else {
|
|
curc = curcmd;
|
|
curcmd &= ~(CUR_CMD_FOPA|CUR_CMD_ENPA);
|
|
curcmd |= CUR_CMD_FOPB;
|
|
}
|
|
WRITECUR(CUR_CMD, curcmd);
|
|
break;
|
|
|
|
case WSDISPLAYIO_GVIDEO:
|
|
*(u_int *)data = (curcmd & CUR_CMD_FOPB ?
|
|
WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
return EPASSTHROUGH;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static paddr_t
|
|
lcspx_mmap(void *v, off_t offset, int prot)
|
|
{
|
|
if (offset >= SPXSIZE || offset < 0)
|
|
return -1;
|
|
return (SPXADDR + offset) >> PGSHIFT;
|
|
}
|
|
|
|
int
|
|
lcspx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
|
|
int *curxp, int *curyp, long *defattrp)
|
|
{
|
|
*cookiep = malloc(sizeof(struct lcspx_screen), M_DEVBUF, M_WAITOK);
|
|
bzero(*cookiep, sizeof(struct lcspx_screen));
|
|
*curxp = *curyp = *defattrp = 0;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
lcspx_free_screen(void *v, void *cookie)
|
|
{
|
|
}
|
|
|
|
int
|
|
lcspx_show_screen(void *v, void *cookie, int waitok,
|
|
void (*cb)(void *, int, int), void *cbarg)
|
|
{
|
|
struct lcspx_screen *ss = cookie;
|
|
int row, col, line;
|
|
|
|
if (ss == curscr)
|
|
return (0);
|
|
|
|
for (row = 0; row < SPX_ROWS; row++)
|
|
for (line = 0; line < SPX_CHEIGHT; line++) {
|
|
for (col = 0; col < SPX_COLS; col++) {
|
|
u_char s, c = ss->ss_image[row][col];
|
|
|
|
if (c < 32)
|
|
c = 32;
|
|
s = QFONT(c, line);
|
|
if (ss->ss_attr[row][col] & WSATTR_REVERSE)
|
|
s ^= 255;
|
|
SPX_ADDR(row, col, line, 0) = s;
|
|
}
|
|
if (ss->ss_attr[row][col] & WSATTR_UNDERLINE)
|
|
SPX_ADDR(row, col, line, 0) = 255;
|
|
}
|
|
cursor = &lcspxaddr[(ss->ss_cury * SPX_CHEIGHT * SPX_COLS) + ss->ss_curx +
|
|
((SPX_CHEIGHT - 1) * SPX_COLS)];
|
|
curscr = ss;
|
|
return (0);
|
|
}
|
|
|
|
cons_decl(lcspx);
|
|
|
|
void
|
|
lcspxcninit(struct consdev *cndev)
|
|
{
|
|
/* Clear screen */
|
|
memset(lcspxaddr, 0, SPX_XWIDTH * SPX_YWIDTH);
|
|
|
|
curscr = &lcspx_conscreen;
|
|
wsdisplay_cnattach(&lcspx_stdscreen, &lcspx_conscreen, 0, 0, 0);
|
|
cn_tab->cn_pri = CN_INTERNAL;
|
|
qf = qvss8x15.data;
|
|
|
|
#if NDZKBD > 0
|
|
dzkbd_cnattach(0); /* Connect keyboard and screen together */
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Called very early to setup the glass tty as console.
|
|
* Because it's called before the VM system is inited, virtual memory
|
|
* for the framebuffer can be stolen directly without disturbing anything.
|
|
*/
|
|
void
|
|
lcspxcnprobe(struct consdev *cndev)
|
|
{
|
|
extern vaddr_t virtual_avail;
|
|
extern const struct cdevsw wsdisplay_cdevsw;
|
|
|
|
if (vax_boardtype != VAX_BTYP_49)
|
|
return; /* Only for 4000/90 */
|
|
|
|
if (vax_confdata & 8)
|
|
return; /* Diagnostic console */
|
|
lcspxaddr = (caddr_t)virtual_avail;
|
|
virtual_avail += SPXSIZE;
|
|
ioaccess((vaddr_t)lcspxaddr, SPXADDR, (SPXSIZE/VAX_NBPG));
|
|
cndev->cn_pri = CN_INTERNAL;
|
|
cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
|
|
}
|