NetBSD/sys/arch/pmax/dev/qvss_compat.c
atatat df0a9badc6 Introduce "top down" memory management for mmap()ed allocations. This
means that the dynamic linker gets mapped in at the top of available
user virtual memory (typically just below the stack), shared libraries
get mapped downwards from that point, and calls to mmap() that don't
specify a preferred address will get mapped in below those.

This means that the heap and the mmap()ed allocations will grow
towards each other, allowing one or the other to grow larger than
before.  Previously, the heap was limited to MAXDSIZ by the placement
of the dynamic linker (and the process's rlimits) and the space
available to mmap was hobbled by this reservation.

This is currently only enabled via an *option* for the i386 platform
(though other platforms are expected to follow).  Add "options
USE_TOPDOWN_VM" to your kernel config file, rerun config, and rebuild
your kernel to take advantage of this.

Note that the pmap_prefer() interface has not yet been modified to
play nicely with this, so those platforms require a bit more work
(most notably the sparc) before they can use this new memory
arrangement.

This change also introduces a VM_DEFAULT_ADDRESS() macro that picks
the appropriate default address based on the size of the allocation or
the size of the process's text segment accordingly.  Several drivers
and the SYSV SHM address assignment were changed to use this instead
of each one picking their own "default".
2003-02-20 22:16:05 +00:00

652 lines
16 KiB
C

/* $NetBSD: qvss_compat.c,v 1.32 2003/02/20 22:16:06 atatat Exp $ */
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Ralph Campbell and Rick Macklem.
*
* 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 University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)fb.c 8.1 (Berkeley) 6/10/93
*/
/*
* devGraphics.c --
*
* This file contains machine-dependent routines for the graphics device.
*
* Copyright (C) 1989 Digital Equipment Corporation.
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies.
* Digital Equipment Corporation makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* from: Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c,
* v 9.2 90/02/13 22:16:24 shirriff Exp SPRITE (DECWRL)";
*/
/*
* This file has all the routines common to the various frame buffer drivers
* including a generic ioctl routine. The pmax_fb structure is passed into the
* routines and has device specifics stored in it.
* The LK201 keycode mapping routine is also here along with initialization
* functions for the keyboard and mouse.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/mman.h>
#include <sys/vnode.h>
#include <sys/resourcevar.h>
#include <uvm/uvm_extern.h>
#include <miscfs/specfs/specdev.h>
#include <dev/cons.h>
#include <dev/dec/lk201.h> /* LK-201 keycodes */
#include <dev/sun/fbio.h>
#include <machine/fbvar.h>
#include <machine/pmioctl.h> /* X11R5 Xserver ioctls */
#include <pmax/dev/dcvar.h> /* DZ-11 chip console I/O */
#include <pmax/dev/dtopvar.h> /* dtop console I/O decls */
#include <pmax/dev/fbreg.h> /* XXX should be renamed fbvar.h */
#include <pmax/dev/qvssvar.h> /* our own externs */
#include <pmax/pmax/pmaxtype.h>
#include <pmax/tc/sccvar.h> /* ioasic z8530 I/O decls */
#include "dc.h"
#include "scc.h"
#include "dtop.h"
/*
* Prototypes of local functions
*/
static void genKbdEvent __P((int ch));
static void genMouseEvent __P((void *newRepPtr));
static void genMouseButtons __P((void *newRepPtr));
extern struct fbinfo *firstfi; /* XXX */
/*
* Initialize the old-style pmax framebuffer structure from a new-style
* rcons structure. Can die when all the old style pmax_fb structures
* are gone. Note that the QVSS/pm mapped event buffer includes the
* fbu field initialized below.
*/
void
init_pmaxfbu(fi)
struct fbinfo *fi;
{
int tty_rows, tty_cols; /* rows, cols for glass-tty mode */
struct fbuaccess *fbu = NULL;
if (fi == NULL || fi->fi_fbu == NULL)
panic("init_pmaxfb: given null pointer to framebuffer");
/* XXX don't rely on there being a pmax_fb struct */
fbu = fi->fi_fbu;
/* fb dimensions */
fbu->scrInfo.max_x = fi->fi_type.fb_width;
fbu->scrInfo.max_y = fi->fi_type.fb_height;
fbu->scrInfo.max_cur_x = fbu->scrInfo.max_x - 1;
fbu->scrInfo.max_cur_y = fbu->scrInfo.max_y - 1;
/* these have the same initial value on qvss-style framebuffers */
fbu->scrInfo.version = 11;
fbu->scrInfo.mthreshold = 4;
fbu->scrInfo.mscale = 2;
/* this is not always right (pm on kn01) but it's a common case */
fbu->scrInfo.min_cur_x = 0;
fbu->scrInfo.min_cur_y = 0;
/*
* Compute glass-tty dimensions. These don't belong here
* anymore, but the Ultrix and 4.3+ bsd drivers put them
* in the event structure mapped into user address space.
*/
tty_cols = 80;
/* A guess, but correct for 1024x864, 1024x768 and 1280x1024 */
tty_rows = (fi->fi_type.fb_height / 15) - 1;
#ifdef notdef
if (tty_rows != fbu->scrInfo.max_row ||
tty_cols != fbu->scrInfo.max_col)
printf("framebuffer init: size mismatch: given %dx%d, compute %dx%d\n",
fbu->scrInfo.max_row, fbu->scrInfo.max_col,
tty_rows, tty_cols);
#endif
pmEventQueueInit(&fi->fi_fbu->scrInfo.qe);
}
/*
* Initialize the qvss-style ringbuffer of mouse button/move
* events to be empty. Called both when initializing the
* console softc and on each new open of that device.
*/
void
pmEventQueueInit(qe)
pmEventQueue *qe;
{
qe->timestamp_ms = TO_MS(time);
qe->eSize = PM_MAXEVQ;
qe->eHead = qe->eTail = 0;
qe->tcSize = MOTION_BUFFER_SIZE;
qe->tcNext = 0;
}
/*
*----------------------------------------------------------------------
*
* fbKbdEvent --
*
* Process a received character.
*
* Results:
* None.
*
* Side effects:
* Events added to the queue.
*
*----------------------------------------------------------------------
*/
void
fbKbdEvent(ch, fi)
int ch;
struct fbinfo *fi;
{
pmEvent *eventPtr;
int i;
struct fbuaccess *fbu = NULL;
if (!fi->fi_open)
return;
fbu = fi->fi_fbu;
/*
* See if there is room in the queue.
*/
i = PM_EVROUND(fbu->scrInfo.qe.eTail + 1);
if (i == fbu->scrInfo.qe.eHead)
return;
/*
* Add the event to the queue.
*/
eventPtr = &fbu->events[fbu->scrInfo.qe.eTail];
eventPtr->type = BUTTON_RAW_TYPE;
eventPtr->device = KEYBOARD_DEVICE;
eventPtr->x = fbu->scrInfo.mouse.x;
eventPtr->y = fbu->scrInfo.mouse.y;
eventPtr->time = TO_MS(time);
eventPtr->key = ch;
fbu->scrInfo.qe.eTail = i;
selnotify(&fi->fi_selp, 0);
}
/*
*----------------------------------------------------------------------
*
* fbMouseEvent --
*
* Process a mouse event.
*
* Results:
* None.
*
* Side effects:
* An event is added to the event queue.
*
*----------------------------------------------------------------------
*/
void
fbMouseEvent(newRepPtr, fi)
MouseReport *newRepPtr;
struct fbinfo *fi;
{
unsigned milliSec;
int i;
pmEvent *eventPtr;
struct fbuaccess *fbu = NULL;
if (!fi->fi_open)
return;
fbu = fi->fi_fbu;
milliSec = TO_MS(time);
/*
* Check to see if we have to accelerate the mouse
*/
if (fbu->scrInfo.mscale >= 0) {
if (newRepPtr->dx >= fbu->scrInfo.mthreshold) {
newRepPtr->dx +=
(newRepPtr->dx - fbu->scrInfo.mthreshold) *
fbu->scrInfo.mscale;
}
if (newRepPtr->dy >= fbu->scrInfo.mthreshold) {
newRepPtr->dy +=
(newRepPtr->dy - fbu->scrInfo.mthreshold) *
fbu->scrInfo.mscale;
}
}
/*
* Update mouse position
*/
if (newRepPtr->state & MOUSE_X_SIGN) {
fbu->scrInfo.mouse.x += newRepPtr->dx;
if (fbu->scrInfo.mouse.x > fbu->scrInfo.max_cur_x)
fbu->scrInfo.mouse.x = fbu->scrInfo.max_cur_x;
} else {
fbu->scrInfo.mouse.x -= newRepPtr->dx;
if (fbu->scrInfo.mouse.x < fbu->scrInfo.min_cur_x)
fbu->scrInfo.mouse.x = fbu->scrInfo.min_cur_x;
}
if (newRepPtr->state & MOUSE_Y_SIGN) {
fbu->scrInfo.mouse.y -= newRepPtr->dy;
if (fbu->scrInfo.mouse.y < fbu->scrInfo.min_cur_y)
fbu->scrInfo.mouse.y = fbu->scrInfo.min_cur_y;
} else {
fbu->scrInfo.mouse.y += newRepPtr->dy;
if (fbu->scrInfo.mouse.y > fbu->scrInfo.max_cur_y)
fbu->scrInfo.mouse.y = fbu->scrInfo.max_cur_y;
}
/*
* Move the hardware cursor.
*/
(*fi->fi_driver->fbd_poscursor)
(fi, fbu->scrInfo.mouse.x, fbu->scrInfo.mouse.y);
/*
* Store the motion event in the motion buffer.
*/
fbu->tcs[fbu->scrInfo.qe.tcNext].time = milliSec;
fbu->tcs[fbu->scrInfo.qe.tcNext].x = fbu->scrInfo.mouse.x;
fbu->tcs[fbu->scrInfo.qe.tcNext].y = fbu->scrInfo.mouse.y;
if (++fbu->scrInfo.qe.tcNext >= MOTION_BUFFER_SIZE)
fbu->scrInfo.qe.tcNext = 0;
if (fbu->scrInfo.mouse.y < fbu->scrInfo.mbox.bottom &&
fbu->scrInfo.mouse.y >= fbu->scrInfo.mbox.top &&
fbu->scrInfo.mouse.x < fbu->scrInfo.mbox.right &&
fbu->scrInfo.mouse.x >= fbu->scrInfo.mbox.left)
return;
fbu->scrInfo.mbox.bottom = 0;
if (PM_EVROUND(fbu->scrInfo.qe.eTail + 1) == fbu->scrInfo.qe.eHead)
return;
i = PM_EVROUND(fbu->scrInfo.qe.eTail - 1);
if ((fbu->scrInfo.qe.eTail != fbu->scrInfo.qe.eHead) &&
(i != fbu->scrInfo.qe.eHead)) {
pmEvent *eventPtr;
eventPtr = &fbu->events[i];
if (eventPtr->type == MOTION_TYPE) {
eventPtr->x = fbu->scrInfo.mouse.x;
eventPtr->y = fbu->scrInfo.mouse.y;
eventPtr->time = milliSec;
eventPtr->device = MOUSE_DEVICE;
return;
}
}
/*
* Put event into queue and wakeup any waiters.
*/
eventPtr = &fbu->events[fbu->scrInfo.qe.eTail];
eventPtr->type = MOTION_TYPE;
eventPtr->time = milliSec;
eventPtr->x = fbu->scrInfo.mouse.x;
eventPtr->y = fbu->scrInfo.mouse.y;
eventPtr->device = MOUSE_DEVICE;
fbu->scrInfo.qe.eTail = PM_EVROUND(fbu->scrInfo.qe.eTail + 1);
selnotify(&fi->fi_selp, 0);
}
/*
*----------------------------------------------------------------------
*
* fbMouseButtons --
*
* Process mouse buttons.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
fbMouseButtons(newRepPtr, fi)
MouseReport *newRepPtr;
struct fbinfo *fi;
{
static char temp, oldSwitch, newSwitch;
int i, j;
pmEvent *eventPtr;
static MouseReport lastRep;
struct fbuaccess *fbu = NULL;
if (!fi->fi_open)
return;
fbu = fi->fi_fbu;
newSwitch = newRepPtr->state & 0x07;
oldSwitch = lastRep.state & 0x07;
temp = oldSwitch ^ newSwitch;
if (temp == 0)
return;
for (j = 1; j < 8; j <<= 1) {
if ((j & temp) == 0)
continue;
/*
* Check for room in the queue
*/
i = PM_EVROUND(fbu->scrInfo.qe.eTail+1);
if (i == fbu->scrInfo.qe.eHead)
return;
/*
* Put event into queue.
*/
eventPtr = &fbu->events[fbu->scrInfo.qe.eTail];
switch (j) {
case RIGHT_BUTTON:
eventPtr->key = EVENT_RIGHT_BUTTON;
break;
case MIDDLE_BUTTON:
eventPtr->key = EVENT_MIDDLE_BUTTON;
break;
case LEFT_BUTTON:
eventPtr->key = EVENT_LEFT_BUTTON;
}
if (newSwitch & j)
eventPtr->type = BUTTON_DOWN_TYPE;
else
eventPtr->type = BUTTON_UP_TYPE;
eventPtr->device = MOUSE_DEVICE;
eventPtr->time = TO_MS(time);
eventPtr->x = fbu->scrInfo.mouse.x;
eventPtr->y = fbu->scrInfo.mouse.y;
fbu->scrInfo.qe.eTail = i;
}
selnotify(&fi->fi_selp, 0);
lastRep = *newRepPtr;
fbu->scrInfo.mswitches = newSwitch;
}
/*
* Use vm_mmap() to map the frame buffer and shared data into the user's
* address space.
* Return errno if there was an error.
*/
int
fbmmap_fb(fi, dev, data, p)
struct fbinfo *fi;
dev_t dev;
caddr_t data;
struct proc *p;
{
int error;
vaddr_t addr;
vsize_t len;
struct vnode vn;
struct specinfo si;
struct fbuaccess *fbp;
struct fbuaccess *fbu = fi->fi_fbu;
len = mips_round_page(((vaddr_t)fbu & PGOFSET) +
sizeof(struct fbuaccess)) +
mips_round_page(fi->fi_type.fb_size);
addr = VM_DEFAULT_ADDRESS(p->p_vmspace->vm_daddr, len);
vn.v_type = VCHR; /* XXX */
vn.v_specinfo = &si; /* XXX */
vn.v_rdev = dev; /* XXX */
/*
* Map the all the data the user needs access to into
* user space.
*/
error = uvm_mmap(&p->p_vmspace->vm_map, &addr, len,
VM_PROT_ALL, VM_PROT_ALL, MAP_SHARED, &vn, 0,
p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
if (error)
return (error);
fbp = (struct fbuaccess *)(addr + ((vaddr_t)fbu & PGOFSET));
*(PM_Info **)data = &fbp->scrInfo;
fbu->scrInfo.qe.events = fbp->events;
fbu->scrInfo.qe.tcs = fbp->tcs;
fbu->scrInfo.planemask = (char *)0;
/*
* Map the frame buffer into the user's address space.
*/
fbu->scrInfo.bitmap = (char *)mips_round_page(fbp + 1);
return (0);
}
/*
* Generic functions for keyboard and mouse input.
* Just use the "generic" qvss/pm-compatible functions above, but pass them
* the soft state for the first framebuffer found on this system.
* We don't support more than one mouse, even for multiple
* framebuffers, so this should be adequate.
* It also relieves each fb driver from having to provide its own
* version of these functions.
*
* TODO: change the callers of these to pass a pointer to the struct fbinfo,
* thus finessing the problem.
*/
static void
genKbdEvent(ch)
int ch;
{
fbKbdEvent(ch, firstfi);
}
static void
genMouseEvent(newRepPtr)
void *newRepPtr;
{
fbMouseEvent(newRepPtr, firstfi);
}
static void
genMouseButtons(newRepPtr)
void *newRepPtr;
{
fbMouseButtons(newRepPtr, firstfi);
}
/*
* Configure the mouse and keyboard based on machine type
*/
void
genConfigMouse()
{
int s;
s = spltty();
switch (systype) {
#if NDC > 0
case DS_PMAX:
case DS_3MAX:
dcDivertXInput = genKbdEvent;
dcMouseEvent = genMouseEvent;
dcMouseButtons = genMouseButtons;
break;
#endif /* NDC */
#if NSCC > 0
case DS_3MIN:
case DS_3MAXPLUS:
sccDivertXInput = genKbdEvent;
sccMouseEvent = genMouseEvent;
sccMouseButtons = genMouseButtons;
break;
#endif
#if NDTOP > 0
case DS_MAXINE:
dtopDivertXInput = genKbdEvent;
dtopMouseEvent = genMouseEvent;
dtopMouseButtons = genMouseButtons;
break;
#endif
default:
printf("Can't configure mouse/keyboard\n");
};
splx(s);
}
/*
* and deconfigure them
*/
void
genDeconfigMouse()
{
int s;
s = spltty();
switch (systype) {
#if NDC > 0
case DS_PMAX:
case DS_3MAX:
dcDivertXInput = NULL;
dcMouseEvent = NULL;
dcMouseButtons = NULL;
break;
#endif /* NDC */
#if NSCC > 0
case DS_3MIN:
case DS_3MAXPLUS:
sccDivertXInput = NULL;
sccMouseEvent = NULL;
sccMouseButtons = NULL;
break;
#endif
#if NDTOP > 0
case DS_MAXINE:
dtopDivertXInput = NULL;
dtopMouseEvent = NULL;
dtopMouseButtons = NULL;
break;
#endif
default:
printf("Can't deconfigure mouse/keyboard\n");
};
}
/**
** And a mouse-report handler for redirected mouse input.
** Could arguably be in its own source file, but it's only
** used when the kernel is performing mouse tracking.
**/
/*
* Mouse-event parser. Called as an upcall with each character
* read from a serial port. Accumulates complete mouse-event
* reports and passes them up to framebuffer layer.
* Mouse events are reported as a 3-byte sequence:
* header+button state, delta-x, delta-y
*/
void
mouseInput(cc)
int cc;
{
MouseReport *mrp;
static MouseReport currentRep;
mrp = &currentRep;
mrp->byteCount++;
if (cc & MOUSE_START_FRAME) {
/*
* The first mouse report byte (button state).
*/
mrp->state = cc;
if (mrp->byteCount > 1)
mrp->byteCount = 1;
} else if (mrp->byteCount == 2) {
/*
* The second mouse report byte (delta x).
*/
mrp->dx = cc;
} else if (mrp->byteCount == 3) {
/*
* The final mouse report byte (delta y).
*/
mrp->dy = cc;
mrp->byteCount = 0;
if (mrp->dx != 0 || mrp->dy != 0) {
/*
* If the mouse moved,
* post a motion event.
*/
(genMouseEvent)(mrp);
}
(genMouseButtons)(mrp);
}
}