NetBSD/sys/arch/newsmips/apbus/xafb.c
chs e07f0b9362 eliminate uvm_useracc() in favor of checking the return value of
copyin() or copyout().

uvm_useracc() tells us whether the mapping permissions allow access to
the desired part of an address space, and many callers assume that
this is the same as knowing whether an attempt to access that part of
the address space will succeed.  however, access to user space can
fail for reasons other than insufficient permission, most notably that
paging in any non-resident data can fail due to i/o errors.  most of
the callers of uvm_useracc() make the above incorrect assumption.  the
rest are all misguided optimizations, which optimize for the case
where an operation will fail.  we'd rather optimize for operations
succeeding, in which case we should just attempt the access and handle
failures due to insufficient permissions the same way we handle i/o
errors.  since there appear to be no good uses of uvm_useracc(), we'll
just remove it.
2003-11-13 03:09:28 +00:00

434 lines
9.8 KiB
C

/* $NetBSD: xafb.c,v 1.7 2003/11/13 03:09:28 chs Exp $ */
/*-
* Copyright (c) 2000 Tsubai Masanari. 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. 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.
*/
/* "xa" frame buffer driver. Currently supports 1280x1024x8 only. */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: xafb.c,v 1.7 2003/11/13 03:09:28 chs Exp $");
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <uvm/uvm_extern.h>
#include <machine/adrsmap.h>
#include <machine/apcall.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <newsmips/apbus/apbusvar.h>
struct xafb_reg {
volatile u_int r0;
volatile u_int index;
volatile u_int r2;
volatile u_int zero;
volatile u_int r4;
volatile u_int r5;
volatile u_int r6;
volatile u_int rgb;
};
struct xafb_devconfig {
volatile u_char *dc_fbbase; /* VRAM base address */
struct xafb_reg *dc_reg; /* register address */
struct rasops_info dc_ri;
};
struct xafb_softc {
struct device sc_dev;
struct xafb_devconfig *sc_dc;
int sc_nscreens;
u_char sc_cmap_red[256];
u_char sc_cmap_green[256];
u_char sc_cmap_blue[256];
};
int xafb_match __P((struct device *, struct cfdata *, void *));
void xafb_attach __P((struct device *, struct device *, void *));
int xafb_common_init __P((struct xafb_devconfig *));
int xafb_is_console __P((void));
int xafb_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
paddr_t xafb_mmap __P((void *, off_t, int));
int xafb_alloc_screen __P((void *, const struct wsscreen_descr *,
void **, int *, int *, long *));
void xafb_free_screen __P((void *, void *));
int xafb_show_screen __P((void *, void *, int,
void (*) (void *, int, int), void *));
int xafb_cnattach __P((void));
int xafb_getcmap __P((struct xafb_softc *, struct wsdisplay_cmap *));
int xafb_putcmap __P((struct xafb_softc *, struct wsdisplay_cmap *));
static __inline void xafb_setcolor(struct xafb_devconfig *, int, int, int, int);
CFATTACH_DECL(xafb, sizeof(struct xafb_softc),
xafb_match, xafb_attach, NULL, NULL);
struct xafb_devconfig xafb_console_dc;
struct wsdisplay_accessops xafb_accessops = {
xafb_ioctl,
xafb_mmap,
xafb_alloc_screen,
xafb_free_screen,
xafb_show_screen,
NULL /* load_font */
};
struct wsscreen_descr xafb_stdscreen = {
"std",
0, 0,
0,
0, 0,
WSSCREEN_REVERSE
};
const struct wsscreen_descr *xafb_scrlist[] = {
&xafb_stdscreen
};
struct wsscreen_list xafb_screenlist = {
sizeof(xafb_scrlist) / sizeof(xafb_scrlist[0]), xafb_scrlist
};
int
xafb_match(parent, match, aux)
struct device *parent;
struct cfdata *match;
void *aux;
{
struct apbus_attach_args *apa = aux;
if (strcmp(apa->apa_name, "xa") != 0)
return 0;
return 1;
}
void
xafb_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct xafb_softc *sc = (void *)self;
struct apbus_attach_args *apa = aux;
struct wsemuldisplaydev_attach_args wsa;
struct xafb_devconfig *dc;
struct rasops_info *ri;
int console, i;
console = xafb_is_console();
if (console) {
dc = &xafb_console_dc;
ri = &dc->dc_ri;
sc->sc_nscreens = 1;
} else {
dc = malloc(sizeof(struct xafb_devconfig), M_DEVBUF, M_WAITOK);
bzero(dc, sizeof(struct xafb_devconfig));
dc->dc_fbbase = (void *)0xb0000000; /* XXX */
dc->dc_reg = (void *)(apa->apa_hwbase + 0x3000);
if (xafb_common_init(dc) != 0) {
printf(": couldn't initialize device\n");
return;
}
ri = &dc->dc_ri;
/* clear screen */
(*ri->ri_ops.eraserows)(ri, 0, ri->ri_rows, 0);
}
sc->sc_dc = dc;
for (i = 0; i < 256; i++) {
sc->sc_cmap_red[i] = i;
sc->sc_cmap_green[i] = i;
sc->sc_cmap_blue[i] = i;
}
printf(": %d x %d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
wsa.console = console;
wsa.scrdata = &xafb_screenlist;
wsa.accessops = &xafb_accessops;
wsa.accesscookie = sc;
config_found(self, &wsa, wsemuldisplaydevprint);
}
void
xafb_setcolor(dc, index, r, g, b)
struct xafb_devconfig *dc;
int index, r, g, b;
{
volatile struct xafb_reg *reg = dc->dc_reg;
reg->index = index;
reg->zero = 0;
reg->rgb = r;
reg->rgb = g;
reg->rgb = b;
}
int
xafb_common_init(dc)
struct xafb_devconfig *dc;
{
struct rasops_info *ri = &dc->dc_ri;
int i;
for (i = 0; i < 256; i++)
xafb_setcolor(dc, i, i, i, i);
/* initialize rasops */
ri->ri_width = 1280;
ri->ri_height = 1024;
ri->ri_depth = 8;
ri->ri_stride = 2048;
ri->ri_bits = (void *)dc->dc_fbbase;
ri->ri_flg = RI_FORCEMONO | RI_FULLCLEAR;
rasops_init(ri, 44, 100);
/* mono */
ri->ri_devcmap[0] = 0; /* bg */
ri->ri_devcmap[1] = 0xffffffff; /* fg */
xafb_stdscreen.nrows = ri->ri_rows;
xafb_stdscreen.ncols = ri->ri_cols;
xafb_stdscreen.textops = &ri->ri_ops;
xafb_stdscreen.capabilities = ri->ri_caps;
return 0;
}
int
xafb_is_console()
{
volatile u_int *dipsw = (void *)NEWS5000_DIP_SWITCH;
if (*dipsw & 1) /* XXX right? */
return 1;
return 0;
}
int
xafb_ioctl(v, cmd, data, flag, p)
void *v;
u_long cmd;
caddr_t data;
int flag;
struct proc *p;
{
struct xafb_softc *sc = v;
struct xafb_devconfig *dc = sc->sc_dc;
struct wsdisplay_fbinfo *wdf;
switch (cmd) {
case WSDISPLAYIO_GTYPE:
*(int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */
return 0;
case WSDISPLAYIO_GINFO:
wdf = (void *)data;
wdf->height = dc->dc_ri.ri_height;
wdf->width = dc->dc_ri.ri_width;
wdf->depth = dc->dc_ri.ri_depth;
wdf->cmsize = 256;
return 0;
case WSDISPLAYIO_GETCMAP:
return xafb_getcmap(sc, (struct wsdisplay_cmap *)data);
case WSDISPLAYIO_PUTCMAP:
return xafb_putcmap(sc, (struct wsdisplay_cmap *)data);
/* case WSDISPLAYIO_SVIDEO: */
}
return EPASSTHROUGH;
}
paddr_t
xafb_mmap(v, offset, prot)
void *v;
off_t offset;
int prot;
{
struct xafb_softc *sc = v;
struct xafb_devconfig *dc = sc->sc_dc;
struct rasops_info *ri = &dc->dc_ri;
if (offset >= (ri->ri_stride * ri->ri_height) || offset < 0)
return -1;
return mips_btop((int)dc->dc_fbbase + offset);
}
int
xafb_alloc_screen(v, scrdesc, cookiep, ccolp, crowp, attrp)
void *v;
const struct wsscreen_descr *scrdesc;
void **cookiep;
int *ccolp, *crowp;
long *attrp;
{
struct xafb_softc *sc = v;
struct rasops_info *ri = &sc->sc_dc->dc_ri;
long defattr;
if (sc->sc_nscreens > 0)
return ENOMEM;
*cookiep = ri;
*ccolp = *crowp = 0;
(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
*attrp = defattr;
sc->sc_nscreens++;
return 0;
}
void
xafb_free_screen(v, cookie)
void *v;
void *cookie;
{
struct xafb_softc *sc = v;
if (sc->sc_dc == &xafb_console_dc)
panic("xafb_free_screen: console");
sc->sc_nscreens--;
}
int
xafb_show_screen(v, cookie, waitok, cb, cbarg)
void *v;
void *cookie;
int waitok;
void (*cb) __P((void *, int, int));
void *cbarg;
{
return 0;
}
int
xafb_cnattach()
{
struct xafb_devconfig *dc = &xafb_console_dc;
struct rasops_info *ri = &dc->dc_ri;
long defattr;
int crow = 0;
if (!xafb_is_console())
return -1;
dc->dc_fbbase = (void *)0xb0000000; /* XXX */
dc->dc_reg = (void *)0xb4903000; /* XXX */
xafb_common_init(dc);
crow = 0; /* XXX current cursor pos */
(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
wsdisplay_cnattach(&xafb_stdscreen, &dc->dc_ri, 0, crow, defattr);
return 0;
}
int
xafb_getcmap(sc, cm)
struct xafb_softc *sc;
struct wsdisplay_cmap *cm;
{
u_int index = cm->index;
u_int count = cm->count;
int error;
if (index >= 256 || count > 256 || index + count > 256)
return EINVAL;
error = copyout(&sc->sc_cmap_red[index], cm->red, count);
if (error)
return error;
error = copyout(&sc->sc_cmap_green[index], cm->green, count);
if (error)
return error;
error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
if (error)
return error;
return 0;
}
int
xafb_putcmap(sc, cm)
struct xafb_softc *sc;
struct wsdisplay_cmap *cm;
{
u_int index = cm->index;
u_int count = cm->count;
int i, error;
u_char rbuf[256], gbuf[256], bbuf[256];
u_char *r, *g, *b;
if (cm->index >= 256 || cm->count > 256 ||
(cm->index + cm->count) > 256)
return EINVAL;
error = copyin(cm->red, &rbuf[index], count);
if (error)
return error;
error = copyin(cm->green, &gbuf[index], count);
if (error)
return error;
error = copyin(cm->blue, &bbuf[index], count);
if (error)
return error;
memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
r = &sc->sc_cmap_red[index];
g = &sc->sc_cmap_green[index];
b = &sc->sc_cmap_blue[index];
for (i = 0; i < count; i++)
xafb_setcolor(sc->sc_dc, index++, *r++, *g++, *b++);
return 0;
}