NetBSD/sys/arch/vax/vsa/lcspx.c
mhitch a5e785cccf Don't map the framebuffer again when attaching the lcspx driver if it was
already mapped in the early console startup.

The software cursor isn't going to blink if we don't start it - set up the
callout when attaching.

Now that the cursor blink routine is actually called, blink the entire cursor
line rather than just the first pixel.

Don't try to clear the current cursor if the pointer to it hasn't been
initialized.  This seems to happen when using the display as console, but
not when using a serial console.

On early console startup, use the framebuffer sizes, not the character cell
size to compute how much to clear.

The lcspx display will now initialize when booting with the display console,
but the dz device is not detected and the keyboard will not work yet.  I
haven't tracked down why the dz device isn't found (it works fine when
using a serial console).
2004-03-19 20:12:07 +00:00

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);
}