1235 lines
24 KiB
C
1235 lines
24 KiB
C
/* $NetBSD: console.c,v 1.16 1999/09/17 19:59:40 thorpej Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1994-1995 Melvyn Tang-Richardson
|
|
* Copyright (c) 1994-1995 RiscBSD kernel team
|
|
* 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 by the RiscBSD kernel team
|
|
* 4. The name of the company nor the name of the author may be used to
|
|
* endorse or promote products derived from this software without specific
|
|
* prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE RISCBSD TEAM ``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 AUTHORS 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.
|
|
*
|
|
* RiscBSD kernel project
|
|
*
|
|
* console.c
|
|
*
|
|
* Console functions
|
|
*
|
|
* Created : 17/09/94
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/device.h>
|
|
#include <sys/time.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/tty.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/msgbuf.h>
|
|
#include <sys/user.h>
|
|
#include <sys/syslog.h>
|
|
#include <sys/kernel.h>
|
|
|
|
#include <dev/cons.h>
|
|
|
|
#include <machine/vidc.h>
|
|
#include <machine/vconsole.h>
|
|
#include <machine/katelib.h>
|
|
#include <machine/bootconfig.h>
|
|
|
|
#include "vt.h"
|
|
|
|
#define CONSOLE_VERSION "[V203E]"
|
|
|
|
/*
|
|
* Externals
|
|
*/
|
|
|
|
extern videomemory_t videomemory;
|
|
extern struct tty *constty;
|
|
extern int debug_flags;
|
|
#define consmap_col(x) (x & 0x3)
|
|
#define CONSMAP_BOLD 8
|
|
#define CONSMAP_ITALIC 16
|
|
|
|
/*
|
|
* Local variables (to this file)
|
|
*/
|
|
|
|
int locked=0; /* Nut - is this really safe ? */
|
|
struct tty *physcon_tty[NVT];
|
|
struct vconsole vconsole_master_store;
|
|
struct vconsole *vconsole_master = &vconsole_master_store;
|
|
struct vconsole *vconsole_current;
|
|
struct vconsole *vconsole_head;
|
|
struct vconsole *vconsole_default;
|
|
extern struct vconsole *debug_vc; /* rename this to vconsole_debug */
|
|
int physcon_major=4;
|
|
static char undefined_string[] = "UNDEFINED";
|
|
int lastconsole;
|
|
static int printing=0;
|
|
static int want_switch=-1;
|
|
|
|
/*
|
|
* Prototypes
|
|
*/
|
|
|
|
int physcon_switch __P((u_int /*number*/));
|
|
void physconstart __P((struct tty */*tp*/));
|
|
static struct vconsole *vconsole_spawn __P((dev_t , struct vconsole *));
|
|
int physconparam __P((struct tty */*tp*/, struct termios */*t*/));
|
|
int physcon_switchup __P((void));
|
|
int physcon_switchdown __P((void));
|
|
|
|
/*
|
|
* Exported variables
|
|
*/
|
|
|
|
#define BLANKINIT (10*60*70)
|
|
int vconsole_pending=0;
|
|
int vconsole_blankinit=BLANKINIT;
|
|
int vconsole_blankcounter=BLANKINIT;
|
|
|
|
/*
|
|
* Now list all my render engines and terminal emulators
|
|
*/
|
|
|
|
extern struct render_engine vidcconsole;
|
|
extern struct terminal_emulator vt220;
|
|
|
|
/*
|
|
* These find functions should move the console it finds to the top of
|
|
* the list to achieve a caching type of operation. A doubly
|
|
* linked list would be faster methinks.
|
|
*/
|
|
|
|
struct tty *
|
|
find_tp(dev)
|
|
dev_t dev;
|
|
{
|
|
struct vconsole *vc;
|
|
struct vconsole *last=0;
|
|
int unit = minor (dev);
|
|
int s;
|
|
|
|
s = spltty();
|
|
|
|
for (vc=vconsole_head; vc != NULL; vc=vc->next) {
|
|
if (vc->number==unit) {
|
|
if (vc != vconsole_head) {
|
|
last->next = vc->next;
|
|
vc->next = vconsole_head;
|
|
vconsole_head = vc;
|
|
}
|
|
(void)splx(s);
|
|
return vc->tp;
|
|
}
|
|
last = vc;
|
|
}
|
|
(void)splx(s);
|
|
return NULL;
|
|
}
|
|
|
|
struct vconsole *
|
|
find_vc(dev)
|
|
dev_t dev;
|
|
{
|
|
struct vconsole *vc;
|
|
struct vconsole *last=NULL;
|
|
int unit = minor (dev);
|
|
int s;
|
|
|
|
s = spltty();
|
|
|
|
for (vc=vconsole_head; vc!=NULL; vc=vc->next) {
|
|
if (vc->number==unit) {
|
|
if (vc!=vconsole_head) {
|
|
last->next = vc->next;
|
|
vc->next = vconsole_head;
|
|
vconsole_head = vc;
|
|
}
|
|
(void)splx(s);
|
|
return vc;
|
|
}
|
|
last=vc;
|
|
}
|
|
(void)splx(s);
|
|
return NULL;
|
|
}
|
|
|
|
struct tty *console_tty = NULL;
|
|
|
|
/*
|
|
* Place a graphics driver under virtual console switching control.
|
|
*/
|
|
|
|
struct vconsole *
|
|
vconsole_spawn_re(dev, vc)
|
|
dev_t dev;
|
|
struct vconsole *vc;
|
|
{
|
|
struct vconsole *new;
|
|
register int num = minor(dev);
|
|
|
|
MALLOC(new, struct vconsole *, sizeof(struct vconsole),
|
|
M_DEVBUF,M_NOWAIT );
|
|
/* printf("spawn_re:new=%08x\n", new);*/
|
|
memset((char *)new, 0, sizeof(struct vconsole));
|
|
*new = *vc;
|
|
new->number = num;
|
|
new->next = vconsole_head;
|
|
new->tp = vc->tp; /* Implied */
|
|
new->data=0;
|
|
new->t_scrolledback=0;
|
|
new->r_scrolledback=0;
|
|
new->r_data=0;
|
|
new->flags=LOSSY;
|
|
new->vtty = 0;
|
|
vconsole_head = new;
|
|
new->R_INIT ( new );
|
|
new->SPAWN ( new );
|
|
new->data = 0;
|
|
/*new->charmap = 0;*/
|
|
new->flags=LOSSY;
|
|
new->proc = curproc;
|
|
new->vtty = 0;
|
|
return new;
|
|
}
|
|
|
|
static struct vconsole *
|
|
vconsole_spawn(dev, vc)
|
|
dev_t dev;
|
|
struct vconsole *vc;
|
|
{
|
|
struct vconsole *new;
|
|
register int num = minor(dev);
|
|
|
|
if ( find_vc ( dev ) != 0 )
|
|
return 0;
|
|
|
|
MALLOC(new, struct vconsole *, sizeof(struct vconsole),
|
|
M_DEVBUF, M_NOWAIT );
|
|
/* printf("spawn:new=%08x\n", new);*/
|
|
|
|
memset((char *)new, 0, sizeof(struct vconsole));
|
|
*new = *vc;
|
|
new->number = num;
|
|
new->next = vconsole_head;
|
|
new->tp=NULL;
|
|
new->opened=0;
|
|
new->data=0;
|
|
new->t_scrolledback=0;
|
|
new->r_scrolledback=0;
|
|
new->r_data=0;
|
|
new->vtty = 1;
|
|
vconsole_head = new;
|
|
new->R_INIT ( new );
|
|
new->FLASH ( new, 1 );
|
|
new->CURSOR_FLASH ( new, 1 );
|
|
new->SPAWN ( new );
|
|
new->vtty = 1;
|
|
|
|
MALLOC (new->charmap, int *, sizeof(int)*((new->xchars)*(new->ychars)),
|
|
M_DEVBUF, M_NOWAIT );
|
|
/* printf("spawn:charmap=%08x\n", new->charmap);*/
|
|
|
|
if (new->charmap==0)
|
|
return 0;
|
|
{
|
|
int counter=0;
|
|
for ( counter=0; counter<((new->xchars)*(new->ychars)); counter++ )
|
|
(new->charmap)[counter]=' ';
|
|
}
|
|
new->TERM_INIT ( new );
|
|
new->proc = curproc;
|
|
return new;
|
|
}
|
|
|
|
void
|
|
vconsole_addcharmap(vc)
|
|
struct vconsole *vc;
|
|
{
|
|
int counter=0;
|
|
|
|
MALLOC (vc->charmap, int *, sizeof(int)*((vc->xchars)*(vc->ychars)),
|
|
M_DEVBUF, M_NOWAIT );
|
|
/* printf("vc=%08x charmap=%08x\n", vc, vc->charmap);*/
|
|
for ( counter=0; counter<((vc->xchars)*(vc->ychars)); counter++ )
|
|
(vc->charmap)[counter]=' ';
|
|
}
|
|
|
|
int
|
|
physconopen(dev, flag, mode, p)
|
|
dev_t dev;
|
|
int flag;
|
|
int mode;
|
|
struct proc *p;
|
|
{
|
|
struct vconsole *new;
|
|
|
|
struct vconsole *vc;
|
|
int unit = minor(dev);
|
|
int found=0;
|
|
int majorhack=0;
|
|
int ret;
|
|
|
|
/*
|
|
* To allow the raw consoles a permanat hook for ioctls
|
|
* Spawning another virtual console will actuall configure it
|
|
*/
|
|
|
|
if ( unit >= NVT ) {
|
|
if ( find_vc(dev)==0 )
|
|
return ENXIO;
|
|
}
|
|
/*
|
|
if (unit >= rpc_cd.cd_ndevs || !rpc_cd.cd_devs[unit])
|
|
return ENXIO;
|
|
*/
|
|
|
|
/* If this virtual console is the real virtual console and hasn't got */
|
|
/* a charmap then to allocate it one. We can be sure addcharmap works */
|
|
/* here since this is the open routine. This is incase the console */
|
|
/* was initialised before the system was brought up */
|
|
|
|
if ((unit==0)&&(vconsole_master->charmap==0)) {
|
|
if (vconsole_master==vconsole_current)
|
|
majorhack=1;
|
|
vconsole_addcharmap ( vconsole_master );
|
|
vconsole_master->flags &= ~LOSSY;
|
|
}
|
|
|
|
/* Check to see if this console has already been spawned */
|
|
|
|
for ( vc = vconsole_head; vc!=NULL; vc=vc->next ) {
|
|
if ( vc->number == unit ) {
|
|
found=1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Sanity check. If we have no default console, set it to the master one */
|
|
|
|
if ( vconsole_default==0 )
|
|
vconsole_default = vconsole_master;
|
|
|
|
/* Ensure we have a vconsole structure. Allocate one if we dont already */
|
|
|
|
if (found==0)
|
|
new = vconsole_spawn ( dev, vconsole_default );
|
|
else
|
|
new = vc;
|
|
|
|
new->proc = p;
|
|
|
|
/* Initialise the terminal subsystem for this device */
|
|
|
|
#define TP (new->tp)
|
|
|
|
if (TP == NULL)
|
|
TP = ttymalloc();
|
|
|
|
physcon_tty[unit] = TP;
|
|
|
|
TP->t_oproc = physconstart;
|
|
TP->t_param = physconparam;
|
|
TP->t_dev = dev;
|
|
if ((TP->t_state & TS_ISOPEN) == 0) {
|
|
ttychars(TP);
|
|
TP->t_iflag = TTYDEF_IFLAG;
|
|
TP->t_oflag = TTYDEF_OFLAG;
|
|
TP->t_cflag = TTYDEF_CFLAG;
|
|
TP->t_lflag = TTYDEF_LFLAG;
|
|
TP->t_ispeed = TP->t_ospeed = TTYDEF_SPEED;
|
|
physconparam(TP, &TP->t_termios);
|
|
ttsetwater(TP);
|
|
} else if (TP->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
|
|
return EBUSY;
|
|
TP->t_state |= TS_CARR_ON;
|
|
|
|
new->opened=1;
|
|
|
|
TP->t_winsize.ws_col = new->xchars;
|
|
TP->t_winsize.ws_row = new->ychars;
|
|
ret = ((*linesw[TP->t_line].l_open)(dev, TP));
|
|
|
|
if ( majorhack==1 ) {
|
|
struct vconsole *vc_store;
|
|
int counter;
|
|
int end;
|
|
int lines;
|
|
int xs;
|
|
|
|
end = msgbufp->msg_bufx-1;
|
|
if (end>=MSGBUFSIZE) end-=MSGBUFSIZE;
|
|
|
|
/*
|
|
* Try some cute things. Count the number of lines in the msgbuf
|
|
* then scroll the real screen up, just to fit the msgbuf on the
|
|
* screen, then sink all output, and spew the msgbuf to the
|
|
* new consoles charmap!
|
|
*/
|
|
|
|
lines = 0; xs=0;
|
|
|
|
for (counter=0;counter<end;counter++) {
|
|
xs++;
|
|
if (*((msgbufp->msg_bufc)+counter)==0x0a) {
|
|
if (xs>vc->xchars) lines++;
|
|
lines++;
|
|
xs=0;
|
|
}
|
|
}
|
|
|
|
if ( lines < vc->ychars ) {
|
|
counter=vc->ycur;
|
|
while ( (counter--) > lines )
|
|
new->PUTSTRING ( "\x0a", 1, new );
|
|
}
|
|
|
|
new->SLEEP(new);
|
|
|
|
vc_store = vconsole_current;
|
|
vconsole_current = 0; /* !!! */
|
|
|
|
/* HAHA, cant do this */
|
|
/* new->CLS ( new ); */
|
|
|
|
new->PUTSTRING ( "\x0c", 1, new );
|
|
|
|
/*
|
|
* Hmmm, I could really pass the whole damn thing to putstring
|
|
* since it doesn't have zeros, but I need to do the crlf
|
|
* conversion
|
|
*/
|
|
|
|
xs=0;
|
|
|
|
if ( end < 0 )
|
|
panic ( "msgbuf trashed reboot and try again" );
|
|
|
|
for (counter=0;counter<end;counter++) {
|
|
if (*((msgbufp->msg_bufc)+counter)==0x0a) {
|
|
new->PUTSTRING ( "\x0d", 1, new );
|
|
xs=0;
|
|
}
|
|
if ( (xs++)<new->xchars )
|
|
new->PUTSTRING ((msgbufp->msg_bufc)+counter, 1, new );
|
|
}
|
|
vconsole_master->ycur = lines;
|
|
vconsole_current = vc_store;
|
|
new->WAKE(new);
|
|
vconsole_current->xcur = 0;
|
|
|
|
printf ( "\x0a" );
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/*
|
|
* int physconclose(dev_t dev, int flag, int mode, struct proc *p)
|
|
*
|
|
* Close the physical console
|
|
*/
|
|
|
|
int
|
|
physconclose(dev, flag, mode, p)
|
|
dev_t dev;
|
|
int flag;
|
|
int mode;
|
|
struct proc *p;
|
|
{
|
|
register struct tty *tp;
|
|
|
|
tp = find_tp ( dev );
|
|
if (tp == NULL) {
|
|
printf("physconclose: tp=0 dev=%04x\n", dev);
|
|
return(ENXIO);
|
|
}
|
|
(*linesw[tp->t_line].l_close)(tp, flag);
|
|
ttyclose(tp);
|
|
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
physconread(dev, uio, flag)
|
|
dev_t dev;
|
|
struct uio *uio;
|
|
int flag;
|
|
{
|
|
register struct tty *tp = find_tp ( dev );
|
|
if (tp == NULL) {
|
|
printf("physconread: tp=0 dev=%04x\n", dev);
|
|
return(ENXIO);
|
|
}
|
|
return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
|
|
}
|
|
|
|
int
|
|
physconwrite(dev, uio, flag)
|
|
dev_t dev;
|
|
struct uio *uio;
|
|
int flag;
|
|
{
|
|
register struct tty *tp;
|
|
|
|
tp = find_tp(dev);
|
|
|
|
if (tp == NULL) {
|
|
printf("physconwrite: tp=0 dev=%04x\n", dev);
|
|
return(ENXIO);
|
|
}
|
|
|
|
return((*linesw[tp->t_line].l_write)(tp, uio, flag));
|
|
}
|
|
|
|
struct tty *
|
|
physcontty(dev)
|
|
dev_t dev;
|
|
{
|
|
return(find_tp(dev));
|
|
}
|
|
|
|
int ioctlconsolebug;
|
|
|
|
int
|
|
physconioctl(dev, cmd, data, flag, p)
|
|
dev_t dev;
|
|
int cmd;
|
|
caddr_t data;
|
|
int flag;
|
|
struct proc *p;
|
|
{
|
|
struct vconsole vconsole_new;
|
|
struct tty *tp=(struct tty *)0xDEADDEAD ;
|
|
int error;
|
|
int s;
|
|
struct vconsole *vc = find_vc(dev);
|
|
|
|
ioctlconsolebug = cmd;
|
|
|
|
tp = find_tp(dev);
|
|
|
|
if ((vc==0)||(tp==0))
|
|
return ENXIO;
|
|
|
|
switch ( cmd ) {
|
|
case CONSOLE_SWITCHUP:
|
|
physcon_switchup ();
|
|
return 0;
|
|
case CONSOLE_SWITCHDOWN:
|
|
physcon_switchdown ();
|
|
return 0;
|
|
case CONSOLE_SWITCHTO:
|
|
if (!physcon_switch ( *(int *)data ))
|
|
return 0;
|
|
else
|
|
return EINVAL;
|
|
case CONSOLE_SWITCHPREV:
|
|
physcon_switch ( lastconsole );
|
|
return 0;
|
|
case CONSOLE_CREATE:
|
|
if ( vconsole_spawn ( makedev ( physcon_major, *(int *)data ),
|
|
vconsole_default ) == 0 )
|
|
return ENOMEM;
|
|
else
|
|
return 0;
|
|
break;
|
|
|
|
case CONSOLE_RENDERTYPE:
|
|
strncpy ( (char *)data, vc->T_NAME, 20 );
|
|
return 0;
|
|
|
|
case CONSOLE_TERMTYPE:
|
|
strncpy ( (char *)data, vc->T_NAME, 20 );
|
|
return 0;
|
|
|
|
case CONSOLE_LOCK:
|
|
s = spltty();
|
|
locked++;
|
|
(void)splx(s);
|
|
return 0;
|
|
case CONSOLE_UNLOCK:
|
|
s = spltty();
|
|
locked--;
|
|
if ( locked<0 )
|
|
locked=0;
|
|
(void)splx(s);
|
|
return 0;
|
|
case CONSOLE_SPAWN_VIDC:
|
|
/*
|
|
vconsole_new = *vconsole_default;
|
|
*/
|
|
vconsole_new = *vc;
|
|
vconsole_new.render_engine = &vidcconsole;
|
|
if ( vconsole_spawn_re (
|
|
makedev ( physcon_major, *(int *)data ),
|
|
&vconsole_new ) == 0 )
|
|
return ENOMEM;
|
|
else
|
|
return 0;
|
|
|
|
case CONSOLE_GETVC:
|
|
{
|
|
/* struct vconsole *vc_p;
|
|
vc_p = find_vc(dev);
|
|
*(int *)data = vc_p->number;*/
|
|
*(int *)data = vconsole_current->number;
|
|
return 0;
|
|
}
|
|
|
|
case CONSOLE_CURSORFLASHRATE:
|
|
vc->CURSORFLASHRATE ( vc, *(int *)data );
|
|
return 0;
|
|
|
|
case CONSOLE_BLANKTIME:
|
|
{
|
|
int time = (*(int *)data);
|
|
struct vidc_mode *vm = &((struct vidc_info *)vc->r_data)->mode;
|
|
|
|
/*
|
|
* +ve set blank time
|
|
* 0 force blank immediately (no time change)
|
|
* -ve disable blank time
|
|
*/
|
|
|
|
if (vm->frame_rate)
|
|
time *= vm->frame_rate;
|
|
else
|
|
time *= 70;
|
|
|
|
if (time == 0) {
|
|
if (vc == vconsole_current)
|
|
vconsole_current->BLANK(vconsole_current, BLANK_OFF);
|
|
} else {
|
|
if (vc == vconsole_current)
|
|
vconsole_blankinit = time;
|
|
vc->blanktime = time;
|
|
if (time < 0)
|
|
vconsole_current->BLANK(vconsole_current, BLANK_NONE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case CONSOLE_DEBUGPRINT:
|
|
{
|
|
struct vconsole *vc_p;
|
|
|
|
vc_p = find_vc(makedev(physcon_major,*(int*)data));
|
|
if (vc_p==0) return EINVAL;
|
|
printf ( "DEBUGPRINT for console %d\n", *(int*)data );
|
|
printf ( "flags %08x vtty %01x\n", vc_p->flags, vc_p->vtty );
|
|
printf ( "TTY INFO - winsize (%d, %d)\n",
|
|
vc_p->tp->t_winsize.ws_col,
|
|
vc_p->tp->t_winsize.ws_row);
|
|
vc_p->R_DEBUGPRINT ( vc_p );
|
|
vc_p->T_DEBUGPRINT ( vc_p );
|
|
return 0;
|
|
}
|
|
|
|
default:
|
|
error = vc->IOCTL ( vc, dev, cmd, data, flag, p );
|
|
if ( error >=0 )
|
|
return error;
|
|
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
|
|
if (error >= 0)
|
|
return error;
|
|
error = ttioctl(tp, cmd, data, flag, p);
|
|
if (error >= 0)
|
|
return error;
|
|
}
|
|
return(ENOTTY);
|
|
}
|
|
|
|
int
|
|
physconmmap(dev, offset, nprot)
|
|
dev_t dev;
|
|
int offset;
|
|
int nprot;
|
|
{
|
|
struct vconsole *vc = find_vc(dev);
|
|
u_int physaddr;
|
|
|
|
if (minor(dev) < 64) {
|
|
log(LOG_WARNING, "You should no longer use ttyv to mmap a frame buffer\n");
|
|
log(LOG_WARNING, "For vidc use /dev/vidcvideo0\n");
|
|
}
|
|
physaddr = vc->MMAP(vc, offset, nprot);
|
|
return(physaddr);
|
|
}
|
|
|
|
/*
|
|
* Perform output on specified tty stream
|
|
*/
|
|
|
|
void
|
|
physconstart(tp)
|
|
struct tty *tp;
|
|
{
|
|
int s, len;
|
|
struct clist *cl;
|
|
struct vconsole *vc;
|
|
u_char buf[128];
|
|
|
|
s = spltty();
|
|
|
|
vc = find_vc ( tp->t_dev );
|
|
|
|
/* Are we ready to perform output */
|
|
|
|
if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
|
|
(void)splx(s);
|
|
return;
|
|
}
|
|
|
|
tp->t_state |= TS_BUSY;
|
|
|
|
/* Fill our buffer with the data to print */
|
|
|
|
cl = &tp->t_outq;
|
|
|
|
if ( vc->r_scrolledback ) vc->R_SCROLLBACKEND ( vc );
|
|
if ( vc->t_scrolledback ) vc->T_SCROLLBACKEND ( vc );
|
|
|
|
(void)splx(s);
|
|
|
|
/* Apparently we do this out of spl since it _IS_ fairly expensive */
|
|
/* and it stops the serial ports overflowing */
|
|
|
|
while ( (len = q_to_b(cl, buf, 128)) ) {
|
|
if ( vc!=NULL )
|
|
vc->PUTSTRING(buf, len, vc);
|
|
}
|
|
|
|
s = spltty ();
|
|
|
|
tp->t_state &= ~TS_BUSY;
|
|
|
|
if (cl->c_cc) {
|
|
tp->t_state |= TS_TIMEOUT;
|
|
timeout(ttrstrt, tp, 1);
|
|
}
|
|
|
|
if (cl->c_cc <= tp->t_lowat) {
|
|
if (tp->t_state & TS_ASLEEP) {
|
|
tp->t_state &= ~TS_ASLEEP;
|
|
wakeup(cl);
|
|
}
|
|
selwakeup(&tp->t_wsel);
|
|
}
|
|
|
|
if ( want_switch != -1 ) {
|
|
physcon_switch ( want_switch );
|
|
want_switch=-1;
|
|
}
|
|
|
|
(void)splx(s);
|
|
}
|
|
|
|
int
|
|
physconparam(tp, t)
|
|
struct tty *tp;
|
|
struct termios *t;
|
|
{
|
|
tp->t_ispeed = t->c_ispeed;
|
|
tp->t_ospeed = t->c_ospeed;
|
|
tp->t_cflag = t->c_cflag;
|
|
return(0);
|
|
}
|
|
|
|
void
|
|
physconstop(tp, flag)
|
|
struct tty *tp;
|
|
int flag;
|
|
{
|
|
/* Nothing necessary */
|
|
}
|
|
|
|
int
|
|
physconkbd(key)
|
|
int key;
|
|
{
|
|
char *string;
|
|
register struct tty *tp;
|
|
int s;
|
|
|
|
s = spltty();
|
|
|
|
tp = vconsole_current->tp;
|
|
|
|
if (tp == NULL) return(1);
|
|
|
|
if ((tp->t_state & TS_ISOPEN) == 0) {
|
|
(void)splx(s);
|
|
return(1);
|
|
}
|
|
|
|
if (key < 0x100)
|
|
(*linesw[tp->t_line].l_rint)(key, tp);
|
|
else {
|
|
switch (key) {
|
|
case 0x100:
|
|
string = "\x1b[A";
|
|
break;
|
|
case 0x101:
|
|
string = "\x1b[B";
|
|
break;
|
|
case 0x102:
|
|
string = "\x1b[D";
|
|
break;
|
|
case 0x103:
|
|
string = "\x1b[C";
|
|
break;
|
|
case 0x104:
|
|
string = "\x1b[6~";
|
|
break;
|
|
case 0x105:
|
|
string = "\x1b[5~";
|
|
break;
|
|
case 0x108:
|
|
string = "\x1b[2~";
|
|
break;
|
|
case 0x109:
|
|
string = "\x7f";
|
|
break;
|
|
default:
|
|
string = "";
|
|
break;
|
|
}
|
|
while (*string != 0) {
|
|
(*linesw[tp->t_line].l_rint)(*string, tp);
|
|
++string;
|
|
}
|
|
}
|
|
(void)splx(s);
|
|
return(0);
|
|
}
|
|
|
|
static int physconinit_called = 0;
|
|
|
|
void
|
|
physconinit(cp)
|
|
struct consdev *cp;
|
|
{
|
|
int *test;
|
|
int counter;
|
|
|
|
/*
|
|
* Incase we're called more than once. All routines below here
|
|
* undergo once time initialisation
|
|
*/
|
|
|
|
if (physconinit_called)
|
|
return;
|
|
|
|
physconinit_called=1;
|
|
|
|
locked=0;
|
|
|
|
physcon_major = major(cp->cn_dev);
|
|
|
|
/*
|
|
* Create the master console
|
|
*/
|
|
|
|
vconsole_master->next = NULL;
|
|
vconsole_master->number = 0;
|
|
vconsole_master->opened = 1;
|
|
vconsole_master->tp = NULL;
|
|
|
|
/*
|
|
* Right, here I can choose some render routines
|
|
*/
|
|
|
|
vconsole_master->render_engine = &vidcconsole;
|
|
vconsole_master->terminal_emulator = &vt220;
|
|
|
|
/*
|
|
* We will very soon loose the master console, and number 0 will
|
|
* become the current console so as not to waste a struct vconsole
|
|
*/
|
|
vconsole_current = vconsole_head = vconsole_master;
|
|
vconsole_master->data = NULL;
|
|
vconsole_master->vtty = 1;
|
|
|
|
/*
|
|
* Perform initial checking
|
|
*/
|
|
|
|
if (vconsole_master->terminal_emulator->name == 0)
|
|
vconsole_master->terminal_emulator->name = undefined_string;
|
|
if (vconsole_master->render_engine->name == 0)
|
|
vconsole_master->render_engine->name = undefined_string;
|
|
|
|
/*
|
|
* Right, I have to assume the init and print procedures are ok
|
|
* or there's nothing else that can be done
|
|
*/
|
|
|
|
vconsole_master->R_INIT(vconsole_master);
|
|
vconsole_master->SPAWN(vconsole_master);
|
|
vconsole_master->TERM_INIT(vconsole_master);
|
|
vconsole_master->flags = LOSSY;
|
|
vconsole_master->blanktime = BLANKINIT;
|
|
|
|
/*
|
|
* Now I can do some productive verification
|
|
*/
|
|
|
|
/* Ensure there are no zeros in the termulation and render_engine */
|
|
|
|
test = (int *) vconsole_master->render_engine;
|
|
for (counter=0; counter<(sizeof(struct render_engine)/4)-1; counter++)
|
|
if (test[counter]==0)
|
|
panic ( "Render engine %s is missins a routine",
|
|
vconsole_master->render_engine->name );
|
|
|
|
test = (int *) vconsole_master->terminal_emulator;
|
|
for (counter=0; counter<(sizeof(struct terminal_emulator)/4)-1; counter++)
|
|
if (test[counter]==0)
|
|
panic ( "Render engine %s is missing a routine",
|
|
vconsole_master->terminal_emulator->name );
|
|
vconsole_master->PUTSTRING("\x0c", 1, vconsole_master);
|
|
}
|
|
|
|
/*
|
|
* void physconputstring(char *string, int length)
|
|
*
|
|
* Render a string on the physical console
|
|
*/
|
|
|
|
void
|
|
physconputstring(string, length)
|
|
char *string;
|
|
int length;
|
|
{
|
|
vconsole_current->PUTSTRING(string, length, vconsole_current);
|
|
}
|
|
|
|
/*
|
|
* void physcongetchar(void)
|
|
*
|
|
* Get a character from the physical console
|
|
*/
|
|
|
|
int getkey_polled __P(());
|
|
|
|
char
|
|
physcongetchar(void)
|
|
{
|
|
return(getkey_polled());
|
|
}
|
|
|
|
void
|
|
rpcconsolecnprobe(cp)
|
|
struct consdev *cp;
|
|
{
|
|
int major;
|
|
|
|
/*
|
|
* Locate the major number for the physical console device
|
|
* We do this by searching the character device list until we find
|
|
* the device with the open function for the physical console
|
|
*/
|
|
|
|
for (major = 0; major < nchrdev; ++major) {
|
|
if (cdevsw[major].d_open == physconopen)
|
|
break;
|
|
}
|
|
|
|
/* Initialise the required fields */
|
|
|
|
cp->cn_dev = makedev(major, 0);
|
|
cp->cn_pri = CN_INTERNAL;
|
|
}
|
|
|
|
#define RPC_BUF_LEN (64)
|
|
char rpc_buf[RPC_BUF_LEN];
|
|
int rpc_buf_ptr = 0;
|
|
static int cnpolling = 0;
|
|
|
|
#define RPC_BUF_FLUSH \
|
|
{ \
|
|
vconsole_current->PUTSTRING(rpc_buf, rpc_buf_ptr, vconsole_current); \
|
|
rpc_buf_ptr=0; \
|
|
}
|
|
|
|
void
|
|
rpcconsolecninit(cp)
|
|
struct consdev *cp;
|
|
{
|
|
physconinit(cp); /* woo Woo WOO!!!, woo, woo, yes ok bye */
|
|
}
|
|
|
|
void
|
|
rpcconsolecnputc(dev, character)
|
|
dev_t dev;
|
|
char character;
|
|
{
|
|
|
|
if (rpc_buf_ptr==RPC_BUF_LEN)
|
|
RPC_BUF_FLUSH
|
|
|
|
rpc_buf[rpc_buf_ptr++] = character;
|
|
|
|
if ((character == 0x0a) || (character == 0x0d) || (character == '.') || (cold == 0) || cnpolling)
|
|
RPC_BUF_FLUSH
|
|
}
|
|
|
|
void
|
|
console_flush()
|
|
RPC_BUF_FLUSH
|
|
|
|
int
|
|
console_switchdown()
|
|
{
|
|
physcon_switchdown();
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
console_switchup()
|
|
{
|
|
physcon_switchup();
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
console_unblank()
|
|
{
|
|
if (vconsole_current) {
|
|
vconsole_blankcounter = vconsole_current->blanktime;
|
|
vconsole_current->BLANK(vconsole_current, BLANK_NONE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
console_scrollback ()
|
|
{
|
|
if (vconsole_current == NULL)
|
|
return 0;
|
|
if (vconsole_current->R_SCROLLBACK(vconsole_current) == -1) {
|
|
if (vconsole_current->T_SCROLLBACK(vconsole_current) == -1) {
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
console_scrollforward ()
|
|
{
|
|
if (vconsole_current == NULL)
|
|
return 0;
|
|
if (vconsole_current->R_SCROLLFORWARD(vconsole_current) == -1) {
|
|
if (vconsole_current->T_SCROLLFORWARD(vconsole_current) == -1) {
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
console_switchlast()
|
|
{
|
|
return (physcon_switch(lastconsole));
|
|
}
|
|
|
|
int
|
|
physcon_switchdown()
|
|
{
|
|
int start;
|
|
int next = (vconsole_current->number);
|
|
start=next;
|
|
do {
|
|
next--;
|
|
next = next&0xff;
|
|
if (next == start) return 0;
|
|
} while (physcon_switch(next));
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
physcon_switchup ()
|
|
{
|
|
int start;
|
|
int next = (vconsole_current->number);
|
|
start=next;
|
|
do {
|
|
next++;
|
|
next = next&0xff;
|
|
if (next == start) return 0;
|
|
} while (physcon_switch(next));
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
console_switch(number)
|
|
u_int number;
|
|
{
|
|
physcon_switch(number);
|
|
}
|
|
|
|
/* switchto */
|
|
int
|
|
physcon_switch(number)
|
|
u_int number;
|
|
{
|
|
register struct vconsole *vc;
|
|
int s = spltty ();
|
|
int ret;
|
|
|
|
if (locked != 0) {
|
|
ret=0;
|
|
goto out;
|
|
}
|
|
|
|
if (printing) {
|
|
want_switch = number;
|
|
ret=0;
|
|
goto out;
|
|
}
|
|
|
|
vc = find_vc(makedev(physcon_major, number));
|
|
|
|
if (vc == 0) {
|
|
ret = 1;
|
|
goto out;
|
|
}
|
|
|
|
if (vc == vconsole_current) {
|
|
ret = 1;
|
|
goto out;
|
|
}
|
|
|
|
/* Point of no return */
|
|
|
|
locked++; /* We cannot reenter this routine now */
|
|
|
|
/* De-activate the render engine functions */
|
|
if ( vconsole_current->vtty==1 ) {
|
|
vconsole_current->SLEEP(vconsole_current);
|
|
vconsole_current->FLASH ( vc, 0 );
|
|
vconsole_current->CURSOR_FLASH ( vc, 0 );
|
|
}
|
|
|
|
/* Swap in the new consoles state */
|
|
|
|
lastconsole = vconsole_current->number;
|
|
vconsole_current=vc;
|
|
vconsole_current->R_SWAPIN ( vc );
|
|
|
|
console_unblank();
|
|
|
|
/* Re-activate the render engine functions */
|
|
|
|
if ( vconsole_current->vtty==1 ) {
|
|
vconsole_current->T_SWAPIN ( vc );
|
|
vconsole_current->WAKE(vconsole_current);
|
|
vconsole_current->FLASH ( vc, 1 );
|
|
vconsole_current->CURSOR_FLASH ( vc, 1 );
|
|
}
|
|
|
|
locked--;
|
|
|
|
/* Tell the process about the switch, like the X server */
|
|
|
|
if ( vc->proc )
|
|
psignal ( vc->proc, SIGIO );
|
|
|
|
ret = 0;
|
|
out:
|
|
(void)splx(s);
|
|
return(ret);
|
|
}
|
|
|
|
char
|
|
rpcconsolecngetc(dev)
|
|
dev_t dev;
|
|
{
|
|
return( physcongetchar () );
|
|
}
|
|
|
|
void
|
|
rpcconsolecnpollc(dev, on)
|
|
dev_t dev;
|
|
int on;
|
|
{
|
|
RPC_BUF_FLUSH
|
|
cnpolling = on;
|
|
}
|
|
|
|
int
|
|
rpcprobe(parent, match, aux)
|
|
struct device *parent;
|
|
void *match;
|
|
void *aux;
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
void
|
|
rpcattach(parent, self, aux)
|
|
struct device *parent;
|
|
struct device *self;
|
|
void *aux;
|
|
{
|
|
printf(": console driver %s using %s %s\n",
|
|
CONSOLE_VERSION, vconsole_master->terminal_emulator->name,
|
|
vconsole_master->render_engine->name);
|
|
|
|
vconsole_master->T_ATTACH(vconsole_master, parent, self, aux);
|
|
vconsole_master->R_ATTACH(vconsole_master, parent, self, aux);
|
|
}
|
|
|
|
/*
|
|
struct cfattach rpc_ca = {
|
|
sizeof(struct device), rpcprobe, rpcattach
|
|
};
|
|
|
|
extern struct cfdriver rpc_cd;
|
|
*/
|
|
|
|
struct cfattach vt_ca = {
|
|
sizeof(struct device), rpcprobe, rpcattach
|
|
};
|
|
|
|
extern struct terminal_emulator vt220;
|
|
|
|
struct render_engine *render_engine_tab[] = {
|
|
&vidcconsole,
|
|
};
|
|
|
|
struct terminal_emulator *terminal_emulator_tab[] = {
|
|
&vt220,
|
|
};
|