NetBSD/sys/arch/mac68k/dev/console.c

1955 lines
48 KiB
C

/*-
* Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo,
* Michael L. Finch, Bradley A. Grantham, and
* Lawrence A. Kesteloot
* 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 Alice Group.
* 4. The names of the Alice Group or any of its members may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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.
*
*/
/*
* The console device driver for Alice.
* $Id: console.c,v 1.15 1994/07/05 03:48:56 briggs Exp $
*
* April 11th, 1992 LK
* Original
* August 20-Sep 9, 1993 MF
* Added support for nubus, multiple monitors
* Added different width screen info
* ability to scroll on two monitors
* ioctls to move monitors
* September 19th, 1993 LK
* Added multi-font support
* Integrated AKB 19 Sept.
* September 28th-ish, 1993 LK
* Added reversepixel and updated reversecursor.
* Integrated AKB 1 Oct.
* October 12th, 1993 AKB
* Fixed bugs in 6-bit code. Also changed x,y in VT
* structure to SIGNED ints because of VT100 parsing...
* (see ESC [ ; H, e.g.)
* October 14th, 1993 AKB
* Added support for T_REVERSE and T_UNDERLINE
* for drawweirdcharacter.
*/
/* Received from MacBSDBoot, stored by Locore: */
unsigned long videoaddr;
long videorowbytes;
long videobitdepth;
int serial_boot_echo=0;
#include "8x14.h"
#include "6x10.h"
#include <sys/cdefs.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/systm.h>
#include <sys/tty.h>
#include <sys/conf.h>
#include <types.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include "../mac68k/cons.h"
#include <machine/frame.h>
#include "serreg.h"
#include "console.h"
#include "asc.h" /* for sound */
#include "grf.h"
#include "grfioctl.h"
#include "grfvar.h"
extern struct grf_softc grf_softc[NGRF];
#define NFONT 2
#define OUTBUFLEN 128
#define CONBUFLEN 128
#define SCROLLBACK 16384 /* Size of scrollback buffer */
#include "con.h"
#define CL *(to++)=*(from++)
struct font {
int width; /* In pixels */
int height; /* In pixels */
unsigned char *normalfont; /* Pointer to bitmap for font */
unsigned char *boldfont; /* Pointer to bitmap for bold font */
int sevenbit; /* True if the font only has 0..127 */
};
struct vt {
int x; /* Cursor position [0..numtcols-1] */
int y; /* Cursor position [0..numtrows-1] */
unsigned int oldx, oldy; /* Saved cursor position */
unsigned int attr, fgcolor, bgcolor; /* Current attribute & color */
unsigned int hanging_cursor; /* Cursor at last column */
unsigned int vt100; /* Status/length of vt100 sequence */
unsigned char vtstr[200]; /* vt100 sequence */
unsigned char scr[50][132]; /* Contents of screen */
unsigned char att[50][132]; /* Attributes of screen */
unsigned char sb[SCROLLBACK]; /* Scrollback buffer */
unsigned int sbhead, sbtail, sblen; /* Scrollback is ring buffer */
unsigned int numtcols; /* # of text columns on the screen */
unsigned int numtrows; /* # of text lines on the screen */
unsigned int toptrow; /* Top line of text scroll region */
unsigned int bottrow; /* Bottom line of text scroll region */
unsigned int numgcols; /* # of visible pixels across */
unsigned int numgrows; /* # of visible pixels down */
unsigned int linelen; /* # of bytes/line (incl. non-visible) */
unsigned int numbits; /* # of bits per pixel */
unsigned char *screen; /* Pointer to the screen */
struct font *font; /* Current font for this vt */
int visible; /* Is this vt visible (on a screen) ? */
};
extern unsigned long videoaddr; /* in srt0.c */
unsigned long videosize;
extern int gNumGrfDev;
static unsigned char outbuf[OUTBUFLEN];
static unsigned char conbuf[OUTBUFLEN];
static int outhead = 0, outtail = 0, outlen = 0, write_ack = 0;
static int conhead = 0, contail = 0, conlen = 0, do_conintr = 0, intr_enabled = 0;
static volatile unsigned char *sccaddr = NULL; /* Set in macserinit */
static struct vt vt[NCON];
static struct font font[NFONT]; /* for now, 0 = large, 1 = small */
int curvt; /* Current virtual terminal -- Used by adb */
int numsb; /* Number of lines scrolling back -- Used by adb */
static int cursoron, cursorlit, cursortype = C_BLOCK | C_SOLID;
int screen_is_cool = 0;
void macconputchar(int, u_char);
void macputchar(dev_t, u_char);
static getvideoparams()
{
/* Get these from hardware and set video to 1 bit if possible */
int i=0;
/* numgcols=640; */
/* numgrows=480; */
for(i=0;i<NCON;i++)
{
vt[i].numgcols=videosize & 0xffff;
vt[i].numgrows=(videosize >>16) & 0xffff;
vt[i].numbits=videobitdepth;
vt[i].linelen=videorowbytes; /* HACK -- LAK */
vt[i].screen = (unsigned char *)videoaddr;
}
vt[0].visible=1;
}
void
NewScreenAddress(void)
{
int i;
sccaddr = sccA + 2;
for(i=0;i<NCON;i++)
{
vt[i].screen = (unsigned char *)videoaddr;
}
}
static putpixel(struct vt *v, int xx, int yy, int c)
{
unsigned int mask, i;
mask = (1<<v->numbits)-1;
c &= mask;
switch (v->numbits)
{
case 1: i = 7 - (xx & 7);
c <<= i;
mask <<= i;
i = yy * v->linelen + (xx>>3);
v->screen[i] &= ~mask;
v->screen[i] |= c;
break;
case 2: i = 6 - ((xx & 3) << 1);
c <<= i;
mask <<= i;
i = yy * v->linelen + (xx>>2);
v->screen[i] &= ~mask;
v->screen[i] |= c;
break;
case 4: i = 4 - ((xx & 1) << 2);
c <<= i;
mask <<= i;
i = yy * v->linelen + (xx>>1);
v->screen[i] &= ~mask;
v->screen[i] |= c;
break;
case 8: v->screen[yy * v->linelen + xx] = c;
break;
}
}
static void reversepixel (struct vt *v, unsigned int xx, unsigned int yy)
{
unsigned int i;
switch (v->numbits)
{
case 1: i = yy * v->linelen + (xx / 8);
v->screen[i] ^= 0x80 >> (xx % 8);
break;
case 2: i = yy * v->linelen + (xx / 4);
v->screen[i] ^= 0xC0 >> ((xx % 4) * 2);
break;
case 4: i = yy * v->linelen + (xx / 2);
v->screen[i] ^= 0xF0 >> ((xx % 2) * 4);
break;
case 8: v->screen[yy * v->linelen + xx] ^= 0xFF;
break;
}
}
static reversecursor(int vtnum)
{
unsigned int i, p, linelongs, px, py, offset, plx;
int x, y;
struct vt *v = &vt[vtnum];
register unsigned long *sc;
unsigned long mask;
static int __p=0;
if (v->y + numsb >= v->numtrows)
{
cursorlit = 0;
return;
}
cursorlit = !cursorlit;
px = v->x * v->font->width;
linelongs = v->linelen/4;
switch (v->numbits)
{
case 1:
plx = px & ~31;
if (((px + v->font->width - 1) & ~31) > plx)
plx += 16;
p = (v->y+numsb) * v->font->height * v->linelen + plx/8;
offset = 32 - v->font->width + (plx % 32) - (px % 32);
mask = ((1L << v->font->width) - 1) << offset;
if (cursortype & C_BLOCK)
{
sc = (unsigned long *)&(v->screen[p]);
if (v->font->height == 14)
{
#define RL *sc ^= mask; sc += linelongs;
RL; RL; RL; RL; RL; RL; RL;
RL; RL; RL; RL; RL; RL; RL;
#undef RL
}
else
{
for (i = 0; i < v->font->height; i++) {
*sc ^= mask;
sc += linelongs;
}
}
}
else
{
sc = (unsigned long *)&(v->screen[p+(v->font->height-2)*v->linelen]);
*sc ^= mask;
*(sc+linelongs) ^= mask;
}
break;
case 2:
case 4:
case 8:
/* Okay, this is a real quick hack so that people in non-1-bit mode
will see a cursor. It's real slow and should be fixed later. */
px = v->x * v->font->width;
py = v->y * v->font->height;
for (y = v->font->height-1; y >= 0; y--) {
for (x = v->font->width-1; x >= 0; x--) {
reversepixel (v, x + px, y + py);
}
}
break;
}
}
static drawcursor(int vtnum)
{
if (vtnum != curvt) return;
if (!cursorlit) reversecursor(vtnum);
cursoron = 1;
}
static erasecursor(int vtnum)
{
if (!vt[vtnum].visible) return;
if (cursorlit) reversecursor(vtnum);
cursoron = 0;
}
static void cls(struct vt *v)
{
register int i;
register unsigned long *sc;
for (sc = (unsigned long *)v->screen, i = v->linelen*v->numgrows/4; i; i--)
*sc++ = 0;
}
static clearscreen(int vtnum, int which)
{
/* which=0=to end of screen, 1=to beginning of screen, 2=all screen */
int i, j, start, end;
struct vt *v = &vt[vtnum];
switch (which)
{
case 0: start = v->y;
end = v->numtrows;
break;
case 1: start = 0;
end = v->y;
break;
case 2: start = 0;
end = v->numtrows;
break;
}
for (i = start; i < end; i++)
for (j = 0; j < v->numtcols; j++)
{
v->scr[i][j] = ' ';
v->att[i][j] = T_NORMAL;
}
if (!v->visible )
return;
switch (which)
{
case 0: start=v->y*v->font->height*v->linelen; end=v->linelen*v->numgrows; break;
case 1: start=0; end=v->y*v->font->height*v->linelen; break;
case 2: cls(v); return;
}
for (i = start; i < end; i++)
v->screen[i] = 0;
}
extern void conattach(int n)
{
static int initt=0;
int i;
if (initt) {
return;
}
initt = 1;
getvideoparams();
cursoron = 0;
cursorlit = 0;
font[0].width = 8;
font[0].height = 14;
font[0].normalfont = Font8x14; /* In 8x14.h */
font[0].boldfont = Font8x14B; /* In 8x14.h */
font[0].sevenbit = 0;
font[1].width = 6;
font[1].height = 10;
font[1].normalfont = Font6x10; /* In 6x10.h */
font[1].boldfont = Font6x10; /* Same font for now */
font[1].sevenbit = 1;
curvt = 0; /* Start at vt 0 */
for (i = 0; i < NCON; i++)
{
vt[i].x = 0;
vt[i].y = 0;
vt[i].oldx = 0;
vt[i].oldy = 0;
vt[i].attr = T_NORMAL;
vt[i].fgcolor = 37;
vt[i].bgcolor = 40;
vt[i].hanging_cursor = 0;
vt[i].vt100 = 0;
vt[i].vtstr[0] = 0;
vt[i].sbhead = 0;
vt[i].sbtail = 0;
vt[i].sblen = 0;
/* BARF: Here should check if SE/30 and set it to font[1] as default: */
if ((vt[i].numgcols >= 640) && (vt[i].numgrows >= 480))
vt[i].font = &font[0];
else
vt[i].font = &font[1];
vt[i].numtcols = min(vt[i].numgcols/vt[i].font->width, 132);
vt[i].numtrows = min(vt[i].numgrows/vt[i].font->height, 50);
vt[i].toptrow = 1;
vt[i].bottrow = vt[i].numtrows;
if (i==0) {
vt[i].visible=1;
}
else
vt[i].visible=0;
clearscreen(i,2);
}
drawcursor(curvt);
strprintf("numtcols", vt[0].numtcols);
strprintf("numtrows", vt[0].numtrows);
}
static void flashscreen(int vtnum)
{
register int i;
register unsigned long *sc;
struct vt *v=&vt[vtnum];
if (!v->visible )
return;
for (sc = (unsigned long *)v->screen, i = v->linelen*v->numgrows/4; i; i--)
*sc++ ^= 0xFFFFFFFF;
for (sc = (unsigned long *)v->screen, i = v->linelen*v->numgrows/4; i; i--)
*sc++ ^= 0xFFFFFFFF;
}
static beep(int vtnum)
{
struct vt *v=&vt[vtnum];
if (v->visible) asc_ringbell();
}
static void drawweirdcharacter (struct vt *v, int x, int y, int attr,
unsigned char *ca)
{
/*
* LAK: This function is for character sets that are not 8 pixels across.
* Does GCC have inline functions? If so, we should make this inline to
* save a function call (it's only called from one place).
*/
unsigned int px, py;
signed int offset;
unsigned long mask, attrmask;
register unsigned long *sc, *savesc;
unsigned char *saveca;
struct font *font = v->font;
/* Position of the upper-left hand of the character, in pixels: */
px = x * font->width;
py = y * font->height;
sc = (unsigned long *) (v->screen + (px/32)*4 + py*v->linelen);
/* offset is the distance (right of the char) to the next long boundary */
offset = 31 - font->width - px % 32;
/* e.g.: px = 25, font->width = 6, offset = 32-6-25 = 1 */
/* 0 1 2 3 */
/* 01234567890123456789012345678901234567 */
/* ^ ****** ^ */
/* +------ Long Boundary ----------+ */
/*
* If offset < 0, then the character is split across long boundaries, and
* we must do two writes. I don't know how much more expensive a long
* write is than a word or byte write, but if it's much more expensive, we
* may want to check to see if the character can be written with one word
* write or one byte write.
*/
/*
* The following loops should be optimized in assembly (eventually...).
* Maybe the case for height = 10 should be unrolled. A minimal
* effort has been made to make it easy for the compiler to optimize this.
*/
attrmask = (((unsigned long) 1 << (font->width+1)) - 1);
if (offset >= 0) { /* Easy case first... */
/* Thank goodness mac is big-endian... :-) */
mask = ~((((unsigned long) 1 << font->width) - 1) << (offset+1));
if (attr & T_REVERSE) {
for (y = font->height; y > 0; y--) {
*sc &= mask;
*sc |= ((unsigned long)*ca ^ attrmask) << offset;
ca++;
sc += v->linelen/4;
}
} else {
for (y = font->height; y > 0; y--) {
*sc &= mask;
*sc |= (unsigned long)*ca << offset;
ca++;
sc += v->linelen/4;
}
}
if (attr & T_UNDERLINE) {
sc -= v->linelen/4;
*sc |= (attrmask << offset);
}
} else {
/* First long... */
offset = -offset;
mask = ~((((unsigned long) 1 << font->width) - 1) >> (offset-1));
savesc = sc;
saveca = ca;
if (attr & T_REVERSE) {
for (y = font->height; y > 0; y--) {
*sc &= mask;
*sc |= ((unsigned long)*ca ^ attrmask) >> offset;
ca++;
sc += v->linelen/4;
}
} else {
for (y = font->height; y > 0; y--) {
*sc &= mask;
*sc |= (unsigned long)*ca >> offset;
ca++;
sc += v->linelen/4;
}
}
if (attr & T_UNDERLINE) {
sc -= v->linelen/4;
*sc |= (attrmask >> offset);
}
/* Second long... */
offset = 32 - offset;
mask = ~((((unsigned long) 1 << font->width) - 1) << offset);
sc = savesc + 1;
ca = saveca;
if (attr & T_REVERSE) {
for (y = font->height; y > 0; y--) {
*sc &= mask;
*sc |= ((unsigned long)*ca ^ attrmask) << offset;
ca++;
sc += v->linelen/4;
}
} else {
for (y = font->height; y > 0; y--) {
*sc &= mask;
*sc |= (unsigned long)*ca << offset;
ca++;
sc += v->linelen/4;
}
}
if (attr & T_UNDERLINE) {
sc -= v->linelen/4;
*sc |= (attrmask << offset);
}
}
}
static drawcharacter(struct vt *v, int x, int y, int attr, unsigned char c)
{
register unsigned int i, j, width, height, linelen;
register unsigned char *ca, *sc;
struct font *font;
font = v->font;
width = font->width;
height = font->height;
linelen = v->linelen;
if (font->sevenbit && c >= 128) {
/* LAK: What should we do here? Maybe c &= 0x7F. */
c = ' ';
}
if (attr & T_BOLD)
ca = &font->boldfont[c*(long)height];
else
ca = &font->normalfont[c*(long)height];
/*
* LAK: The fastest way to do this is to have a horrible tree of
* possible cases. If numbits != 1, then we put up each pixel (yuk).
* Otherwise, if width != 8, then we have to do fancy shifting. If
* width == 8, then we can just stick it up there. Also handle reverse
* video and underlining. Plus unroll common heights (10 and 14).
*/
if (v->numbits == 1)
{
if (width == 8)
{
j = y * height * linelen + (x * width) / 8;
if (attr & T_REVERSE)
{
for (i = 0; i < height; i++)
v->screen[j + i * linelen] = ~ca[i];
}
else
{
if (height == 14) {
/* Look at assembly to optimize this: */
sc = &v->screen[j];
#define CB *sc = *ca++; sc += linelen
CB; CB; CB; CB; CB; CB; CB;
CB; CB; CB; CB; CB; CB; CB;
#undef CB
} else {
for (i = 0; i < height; i++)
v->screen[j + i * linelen] = ca[i];
}
}
if (attr & T_UNDERLINE)
v->screen[j + (height - 1) * linelen] = 255; /* ^= 255 ? */
}
else /* width != 8 */
{
drawweirdcharacter (v, x, y, attr, ca);
}
}
else
{
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
if (ca[i] & (1<<j))
putpixel (v, (x+1)*width-j-1, y*height+i, 255);
else
putpixel (v, (x+1)*width-j-1, y*height+i, 0);
}
}
}
}
void drawsb(int vtnum)
{
register int x, y;
register struct vt *v = &vt[vtnum];
int len, head, i;
if (numsb < 0) numsb = 0;
/* Draw scroll back: */
len = v->sblen;
head = v->sbhead;
i = numsb+1;
while (i)
{
if (len == 0)
{
i--;
break;
}
head--;
if (head < 0) head = SCROLLBACK - 1;
len--;
if (v->sb[head] == '\n') i--;
if (i == 0) head = (head + 1) % SCROLLBACK;
}
numsb -= i; /* Can't scroll back more than what's in buffer */
for (y = 0; y < numsb && y < v->numtrows; y++)
{
for (x = 0; v->sb[head] != '\n'; x++)
{
drawcharacter(v,x, y, 0, v->sb[head]);
head = (head + 1) % SCROLLBACK;
}
head = (head + 1) % SCROLLBACK; /* Skip \n */
}
/* Draw part of screen: */
if (numsb < v->numtrows)
{
for (y = 0; y < v->numtrows - numsb; y++)
for (x = 0; x < v->numtcols; x++)
drawcharacter(v, x, y+numsb, v->att[y][x], v->scr[y][x]);
}
if (cursoron)
{
if (cursortype & (C_FAST|C_SLOW))
cursorlit = 0;
else if (cursorlit)
{
cursorlit = 1;
reversecursor(vtnum);
}
}
}
static void restoresb(void)
{
/* Turn off scrollback. */
/* Don't do if numsb == 0 because this routine is called a lot */
if (numsb)
{
numsb = 0;
drawsb(curvt);
}
}
static putcharacter(int vtnum, char c)
{
struct vt *v = &vt[vtnum];
v->scr[v->y][v->x] = c;
v->att[v->y][v->x] = v->attr;
if (v->visible )
drawcharacter(v, v->x, v->y, v->attr, c);
}
#define splconsole spl3
static scrollup(int vtnum)
{
/* scrolls the screen up by one text line */
register int i, j, x, maxx;
register long *from, *to;
register struct vt *v = &vt[vtnum];
char tempbuf[133];
int buflen, s;
/* Save the top line: */
for (j = 0; j < v->numtcols; j++)
tempbuf[j] = v->scr[v->toptrow-1][j];
tempbuf[j++] = '\n'; /* End of line */
buflen = j;
if (v->toptrow == 1) {
s = splconsole(); /* Exclusive access to sblen */
while (v->sblen + buflen > SCROLLBACK) {
while (v->sb[v->sbtail] != '\n') {
v->sbtail = (v->sbtail + 1) % SCROLLBACK;
v->sblen--;
}
v->sbtail = (v->sbtail + 1) % SCROLLBACK;
v->sblen--;
}
for (i = 0; i < buflen; i++) {
v->sb[v->sbhead] = tempbuf[i];
v->sbhead = (v->sbhead + 1) % SCROLLBACK;
v->sblen++;
}
splx(s);
}
/* Scroll: */
for (i = v->toptrow-1; i < v->bottrow-1; i++)
for (j = 0; j < v->numtcols; j++)
{
v->scr[i][j] = v->scr[i+1][j];
v->att[i][j] = v->att[i+1][j];
}
for (j = 0; j < v->numtcols; j++)
{
v->scr[v->bottrow-1][j] = 32;
v->att[v->bottrow-1][j] = T_NORMAL;
}
if (!v->visible)
return;
from = (long *)&v->screen[v->toptrow*v->font->height * v->linelen];
to = (long *)&v->screen[(v->toptrow-1)*v->font->height * v->linelen];
maxx = v->numbits*(v->numgcols+31)/32; /* 32 == bits per long */
j = v->linelen / 4 - maxx;
for (i = (v->bottrow-v->toptrow)*v->font->height; i; i--)
{
int depth;
/* for (depth = v->numbits ; depth ; depth --) */ { /* HACK */
x = maxx;
while (x >= 16) { /* assume at least 512 pixel wide screen. */
CL; CL; CL; CL;
CL; CL; CL; CL;
CL; CL; CL; CL;
CL; CL; CL; CL;
x -= 16;
}
if (x)
switch (x) {
case 15: CL; case 14: CL; case 13: CL;
case 12: CL; case 11: CL; case 10: CL;
case 9: CL; case 8: CL; case 7: CL;
case 6: CL; case 5: CL; case 4: CL;
case 3: CL; case 2: CL; case 1: CL;
default:;
}
}
to += j;
from += j;
}
to = (long *)&v->screen[(v->bottrow-1)*v->font->height * v->linelen];
for (i = v->font->height * v->linelen/4; i; i--)
*to++ = 0;
}
static clearline(int vtnum, int which)
{
/* which=0=to end of line, 1=to beginning of line, 2=all line */
int start, end, i, j, b;
struct vt *v = &vt[vtnum];
switch (which)
{
case 0: start=v->x; end=v->numtcols; break;
case 1: start=0; end=v->x+1; break;
case 2: start=0; end=v->numtcols; break;
}
for (j = start; j < end; j++)
{
v->scr[v->y][j] = 32;
v->att[v->y][j] = T_NORMAL;
}
if (!v->visible)
return;
if (v->font->width%8 == 0 || v->numbits == 8) {
start = v->y*v->font->height*v->linelen + start*v->font->width*v->numbits/8;
end = v->y*v->font->height*v->linelen + end*v->font->width*v->numbits/8;
for (i = start; i < end; i++)
for (j = 0; j < v->font->height; j++)
v->screen[i + j * v->linelen] = 0;
} else {
b = start*v->font->width*v->numbits % 8;
if (b > 0) {
start = i = v->y*v->font->height*v->linelen + start*v->font->width*v->numbits/8;
for (j = 0; j < v->font->height; j++)
v->screen[i + j * v->linelen] &= ~((1<<(8-b))-1);
start++;
} else {
start = v->y*v->font->height*v->linelen + start*v->font->width*v->numbits/8;
}
end = v->y*v->font->height*v->linelen + end*v->font->width*v->numbits/8;
for (i = start; i < end; i++)
for (j = 0; j < v->font->height; j++)
v->screen[i + j * v->linelen] = 0;
}
}
static movecursordown(int vtnum)
{
struct vt *v = &vt[vtnum];
v->y++;
if (v->y >= v->numtrows)
{
v->y--;
scrollup(vtnum);
}
}
static movecursorforward(int vtnum)
{
struct vt *v = &vt[vtnum];
/* If x == numtcols - 1, then we were just on the last column.
We should stay there until the next character. If the
next character is a C/R, then don't do the movecursordown().
Otherwise, wrap around. */
if (v->hanging_cursor)
{
v->x = 0;
movecursordown(vtnum);
v->hanging_cursor = 0;
}
if (v->x == v->numtcols - 1)
v->hanging_cursor = 1;
else
v->x++;
}
static scrolldown(int vtnum)
{
/* scrolls the screen down by one text line */
register int i, j, x, maxx;
register long *from, *to;
struct vt *v = &vt[vtnum];
for (i = v->bottrow - 1; i >= v->toptrow; i--)
for (j = 0; j < v->numtcols; j++)
{
v->scr[i][j] = v->scr[i-1][j];
v->att[i][j] = v->att[i-1][j];
}
for (j = 0; j < v->numtcols; j++)
{
v->scr[v->toptrow-1][j] = 32;
v->att[v->toptrow-1][j] = T_NORMAL;
}
if (!v->visible )
return;
from = (long *)&v->screen[(v->bottrow-1)*v->font->height*v->linelen-v->linelen];
to = (long *)&v->screen[v->bottrow*v->font->height*v->linelen-v->linelen];
maxx = v->numbits*(v->numgcols+31)/32;
j = v->linelen / 4 + maxx;
for (i = (v->bottrow-v->toptrow)*v->font->height; i; i--)
{
int depth;
/* for (depth = v->numbits ; depth ; depth --) */ { /* HACK */
x = maxx;
while (x >= 16) { /* assume at least 512 pixel wide screen. */
CL; CL; CL; CL;
CL; CL; CL; CL;
CL; CL; CL; CL;
CL; CL; CL; CL;
x -= 16;
}
if (x)
switch (x) {
case 15: CL; case 14: CL; case 13: CL;
case 12: CL; case 11: CL; case 10: CL;
case 9: CL; case 8: CL; case 7: CL;
case 6: CL; case 5: CL; case 4: CL;
case 3: CL; case 2: CL; case 1: CL;
default:;
}
}
to -= j;
from -= j;
}
to = (long *)&v->screen[(v->toptrow-1)*v->font->height*v->linelen];
for (i = v->font->height*v->linelen/4; i; i--)
*to++ = 0;
}
static deletechar(int vtnum, int n)
{
int i, j, p, endp;
struct vt *v = &vt[vtnum];
if (n == 0) return;
for (j = v->x; j < v->numtcols-1; j++)
{
v->scr[v->y][j] = v->scr[v->y][j+1];
v->att[v->y][j] = v->att[v->y][j+1];
}
v->scr[v->y][v->numtcols-1] = 32;
v->att[v->y][v->numtcols-1] = T_NORMAL;
if (!v->visible )
return;
p = v->y*v->font->height*v->linelen + v->x*v->font->width*v->numbits/8;
endp = v->y*v->font->height*v->linelen + (v->numtcols-1)*v->font->width*v->numbits/8;
for (i = p; i < endp; i++)
{
for (j = 0; j < v->font->height; j++)
v->screen[i+j*v->linelen] = v->screen[i+j*v->linelen+1];
}
for (j = 0; j < v->font->height; j++)
v->screen[endp+j*v->linelen] = 0;
}
static savecursorpos(int vtnum, int save)
{
/* Should we save more here, e.g., text attribute, etc. ? */
struct vt *v = &vt[vtnum];
if (save)
{
v->oldx = v->x;
v->oldy = v->y;
}
else
{
v->x = v->oldx;
v->y = v->oldy;
}
}
static setcolor(int vtnum, int col)
{
struct vt *v = &vt[vtnum];
switch (col)
{
case 0: v->attr = T_NORMAL;
v->fgcolor = 37;
v->bgcolor = 40;
break;
case 1: v->attr |= T_BOLD; break; /* This isn't documented anywhere. */
case 2: break; /* Half bright */ /* We could do this */
case 4: v->attr |= T_UNDERLINE; break;
case 5: break; /* Blink */ /* Should we do this? :-) */
case 7: v->attr |= T_REVERSE; break;
default:
/* 0 = Black
* 1 = Red
* 2 = Green
* 3 = Yellow + 30 = Foreground
* 4 = Blue + 40 = Background
* 5 = Magenta
* 6 = Cyan
* 7 = White
*/
if (col >= 30 && col <= 37)
{
v->fgcolor = col;
/* Clip to white for B/W screen: */
if (v->fgcolor > 30) v->fgcolor = 37;
}
else if (col >= 40 && col <= 47)
{
v->bgcolor = col;
/* Clip to white for B/W screen: */
if (v->bgcolor > 40) v->bgcolor = 47;
}
if (v->fgcolor == 30 && v->bgcolor == 47) /* effective reverse */
{
/* Elvis uses 30,43 for reverse: (Black on Yellow) */
v->fgcolor = 37;
v->bgcolor = 40;
v->attr |= T_REVERSE;
}
break;
}
}
static int isalpha(char c)
{
return(c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z');
}
static int isdigit(char c)
{
return(c >= '0' && c <= '9');
}
static void puts(int vtnum, char *s)
{
/* This function is for functions called by printf(). It seems
that printf() in the kernel is non-reentrant, so I wrote this
so that parseVT100 could print stuff. Same as puts() except
that it doesn't print a \n at the end. */
while (*s)
macconputchar(vtnum, (unsigned char)(*s++));
}
static parseVT100(int vtnum, char *s)
{
int n[100], num, i, ques;
char *old=s;
struct vt *v = &vt[vtnum];
ques = (*s == '?');
if (ques) s++;
for (num = 0; num < 100; num++)
n[num] = 0;
num = 0;
/* Parse all of the numbers at the start of the sequence: */
if (isdigit(*s) || *s == ';')
{
do
{
if (*s == ';')
{
s++;
num++;
}
while (isdigit(*s))
{
n[num] = n[num]*10 + (*s-'0');
s++;
}
}
while (*s == ';');
num++;
}
switch (*s)
{
case 'H': /* Move Cursor */
case 'f': /* Move cursor */
v->x=n[1]-1;
v->y=n[0]-1 + v->toptrow-1;
if (v->x < 0) v->x=0;
if (v->y < 0) v->y=0;
if (v->x >= v->numtcols) v->x = v->numtcols-1;
if (v->y >= v->numtrows) v->y = v->numtrows-1;
break;
case 's': savecursorpos(vtnum, 1); break; /* Save cursor pos */
case 'u': savecursorpos(vtnum, 0); break; /* Restore cursor pos */
case 'J': /* Clear part of screen */
clearscreen(vtnum, n[0]);
break;
case 'K': /* Clear part of line */
clearline(vtnum, n[0]);
break;
case 'P': /* Delete character */
deletechar(vtnum, n[0]);
break;
case 'A': /* Cursor up */
if (num == 0) n[0] = 1;
v->y -= n[0];
if (v->y < 0) v->y = 0;
break;
case 'B': /* Cursor down */
if (num == 0) n[0] = 1;
v->y += n[0];
if (v->y >= v->numtrows) v->y = v->numtrows;
break;
case 'C': /* Cursor right */
if (num == 0) n[0] = 1;
v->x -= n[0];
if (v->x < 0) v->x = 0;
break;
case 'c': /* What are you? */
/* Say something like ^[[?5c (I am GIGI) */
break;
case 'D': /* Cursor left */
if (num == 0) n[0]=1;
v->x += n[0];
if (v->x >= v->numtcols) v->y =v-> numtcols;
break;
case 'h': break; /* Keyboard enable? */
case 'l': break; /* Keyboard disable? */
case 'm': /* Set color */
if (num == 0)
setcolor(vtnum, 0); /* Should this always be done? */
else for (i = 0; i < num; i++)
setcolor(vtnum, n[i]);
break;
case 'n': /* Reports */
if (n[0] == 5) /* Status report */
/* Returns ^[0n */;
if (n[0] == 6) /* Cursor position report */
/* Returns ^[[Pl;PcR */;
break;
case 'r':
if (num == 0) {
/* I think this should return something like ncols;nrows */
} else {
if (num == 1)
n[1] = v->bottrow;
if (n[0] < 1) n[0] = 1;
if (n[1] < 1) n[1] = 1;
if (n[0] > v->bottrow) n[0] = v->bottrow;
if (n[1] > v->bottrow) n[1] = v->bottrow;
if (n[0] < n[1]) {
v->toptrow = n[0];
v->bottrow = n[1];
} else {
/* This isn't right. */
/* But it's better than nothing :-) */
/* And I don't know what "right" is */
v->toptrow = n[1];
v->bottrow = n[0];
}
}
break;
default:
puts (vtnum, "Unknown VT100 code: \"");
puts (vtnum, old);
puts (vtnum, "\", \"");
puts (vtnum, s);
puts (vtnum, "\".\n");
}
}
static int writechar(int vtnum, unsigned char c)
{
char s[20];
struct vt *v;
if (c == 0) return; /* Ignore nulls */
v = &vt[vtnum];
if (v->vt100 >= 2) /* Got ESC and [ */
{
if (c < 32) /* Invalid character in VT100 sequence -- Abort */
v->vt100 = 0;
else
{
v->vtstr[v->vt100++ - 2] = c;
if (isalpha(c))
{
v->vtstr[v->vt100 - 2] = 0;
v->vt100 = 0;
parseVT100(vtnum, v->vtstr);
}
return;
}
}
if (v->vt100 == 1) /* Only got ESC */
{
v->vt100 = 0; /* This should finish sequence except if [ */
switch (c)
{
case '=': break; /* Turn keypad on */
case '>': break; /* Turn keypad off */
case 'D': movecursordown(vtnum); break; /* Line feed */
case 'E': break; /* New line */
case 'M': scrolldown(vtnum); break; /* Scroll down */
case '7': savecursorpos(vtnum,1); break; /* Save cursor pos */
case '8': savecursorpos(vtnum,0); break; /* Restore cursor pos */
case '[': /* Misc stuff */
v->vt100 = 2;
v->vtstr[0] = 0;
break;
}
return;
}
switch (c)
{
case 7: beep(vtnum); /* Bell */
break;
case 8: if (v->x > 0) v->x--; /* Backspace (^H) */
v->hanging_cursor = 0;
break;
case 9: v->hanging_cursor = 0; /* Tab */
do
writechar(vtnum, ' ');
while (v->x%8);
break;
case 10: movecursordown(vtnum); /* Line feed */
/* v->x=0; <-- Should not always do this, but when? */
v->hanging_cursor = 0; /* Should I do this here? */
break;
case 13: v->x=0; /* Carriage return */
v->hanging_cursor = 0;
break;
case 27: v->vt100 = 1; /* Start of VT-100 */
v->hanging_cursor = 0;
break;
case 127: break; /* Rubout (Delete) */
default: if (c < 32)
{
/*c=1;*/ /* smiley face */
sprintf (s, "<%d>", (int)c);
puts(vtnum, s);
}
else
{
if (v->hanging_cursor)
{
v->x = 0;
movecursordown(vtnum);
v->hanging_cursor = 0;
}
putcharacter(vtnum, c);
movecursorforward(vtnum);
}
break;
}
}
static void make_visible(unsigned char *screen)
{
/* try to find a vt that belongs on this screen, and make it visible */
/* in order to redraw we call vtselect, but that changes the curvt, */
/* so save that and restore it, what the heck i'm already going to hell */
/* make sure that is the screen is not changing, that we do nothing */
int i=0;
if (screen==vt[curvt].screen)
return;
for(i=0;i< NCON;i++)
{
if ((vt[i].screen==screen) )
{
int realcurvt=curvt;
if (i == curvt)
return;
vt[i].visible=1;
vtselect(i);
erasecursor(i);
curvt=realcurvt;
return;
}
}
}
static void fix_visible(struct vt *v)
{
/* make sure there is only one visible vt per screen */
int i=0;
unsigned char *screen=v->screen;
for(i=0;i< NCON;i++)
{
if ((vt[i].screen==screen) && vt[i].visible)
vt[i].visible=0;
}
v->visible=1;
}
vtselect(int newvt)
{
/* ADB calls this when you select a virtual terminal */
int x, y;
struct vt *v;
if (newvt == curvt) restoresb();
if (newvt < 0 || newvt >= NCON || newvt == curvt)
return;
numsb = 0;
erasecursor(curvt);
curvt = newvt;
v = &vt[curvt];
fix_visible(v);
#if 1
cls(v);
for (y = 0; y < v->numtrows; y++)
for (x = 0; x < v->numtcols; x++)
if (v->scr[y][x] != ' ' || v->att[y][x] != T_NORMAL)
drawcharacter(v,x, y, v->att[y][x], v->scr[y][x]);
#else
for (y = 0; y < numtrows; y++)
for (x = 0; x < numtcols; x++)
drawcharacter(x, y, v->att[y][x], v->scr[y][x]);
#endif
drawcursor(curvt);
}
static struct tty *maccon_tty[NCON];
static int maccon_flags = 0;
/* These routines are the actual device driver: */
#if 0
static char maccon_id_string[128] ;
coninit(register struct macdriver *md)
{
md->hwfound = 1;
/*
md->name = maccon_id_string;
sprintf(md->name,"Video Device -- Width: %d Height: %d Depth: %d Bit%c",
vt[0].numgcols,
vt[0].numgrows,
videobitdepth,
videobitdepth==1?' ':'s');
*/
grfconfig();
}
#endif
void
constart(register struct tty *tp)
{
int s, unit, c, buflen, i;
u_char buf[CONBUFLEN];
unit = minor(tp->t_dev);
if (unit >= NCON)
return;
if (unit == curvt) restoresb();
s = spltty();
if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
goto out;
tp->t_state |= TS_BUSY;
splx(s);
buflen = q_to_b(&tp->t_outq, buf, sizeof(buf)/sizeof(buf[0]));
for (i=0 ; i<buflen ; i++)
if (buf[i]) macputchar(tp->t_dev, buf[i]&0xff);
s = spltty();
tp->t_state &= ~TS_BUSY;
if (tp->t_outq.c_cc) {
tp->t_state |= TS_TIMEOUT;
timeout((void *) ttrstrt, (caddr_t) tp, 1);
}
if (tp->t_outq.c_cc <= tp->t_lowat) {
if (tp->t_state&TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
wakeup((caddr_t)&tp->t_outq);
}
selwakeup(&(tp->t_wsel));
}
out:
splx(s);
}
conparam(
register struct tty *tp,
register struct termios *t)
{
register int cfcr, cflag;
int unit;
int ospeed;
cflag = t->c_cflag;
unit = minor(tp->t_dev);
if (unit >= NCON)
return ENODEV;
/* check requested parameters */
if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
return (EINVAL);
/* and copy to tty */
tp->t_ispeed = t->c_ispeed;
tp->t_ospeed = t->c_ospeed;
tp->t_cflag = cflag;
return (0);
}
int adb_poll_setup = 0;
static void flashcursor(caddr_t unused)
{
if (cursortype & C_SOLID)
{
/* Turn it back on for solid */
if (cursoron && !cursorlit)
reversecursor(curvt);
}
else
{
if (cursoron)
reversecursor(curvt);
timeout((void *) flashcursor, 0, (cursortype & C_SLOW) ? 30 : 15);
}
}
conopen(dev_t dev, int mode, int flag, struct proc *p)
{
register struct tty *tp;
register int unit = minor(dev);
int error = 0;
char s[100];
if (unit >= NCON)
return (ENODEV);
if (!maccon_tty[unit]) {
tp = maccon_tty[unit] = ttymalloc();
} else {
tp = maccon_tty[unit];
}
tp->t_oproc = constart;
tp->t_param = conparam;
tp->t_dev = dev;
/* MF BARF This is gonna be zeroed later, where does this go? */
/* tp->t_winsize.ws_xpixel=numgcols; */
/* tp->t_winsize.ws_ypixel=numgrows; */
if ((tp->t_state & TS_ISOPEN) == 0) {
tp->t_state |= TS_WOPEN | TS_CARR_ON;
ttychars(tp);
if (tp->t_ispeed == 0) {
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;
}
conparam(tp, &tp->t_termios);
ttsetwater(tp);
} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
return (EBUSY);
(void) spltty(); /* BARF -- mutual exclusion. */
while ((mode&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
(tp->t_state & TS_CARR_ON) == 0) {
tp->t_state |= TS_WOPEN;
if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
ttopen, 0))
break;
}
(void) spl0();
if (error == 0)
{
error = (*linesw[tp->t_line].l_open)(dev, tp);
if(!adb_poll_setup){
adb_poll_timeout();
adb_poll_setup = 1;
}
}
return (error);
}
conclose(dev_t dev, int flag, int mode, struct proc *p)
{
register struct tty *tp;
register struct dcadevice *dca;
register int unit = minor(dev);
char s[100];
if (unit >= NCON)
return (ENODEV);
tp = maccon_tty[unit];
(*linesw[tp->t_line].l_close)(tp, flag);
ttyclose(tp);
ttyfree(tp);
maccon_tty[unit] = NULL;
return (0);
}
conread(dev_t dev, struct uio *uio, int flag)
{
u_int unit = minor(dev);
if (unit >= NCON)
return (ENODEV);
return ((*linesw[maccon_tty[unit]->t_line].l_read)(maccon_tty[unit], uio, flag));
}
conwrite(dev_t dev, struct uio *uio, int flag)
{
int unit = minor(dev);
if (unit >= NCON)
return (ENODEV);
return ((*linesw[maccon_tty[unit]->t_line].l_write)(maccon_tty[unit], uio, flag));
}
conioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
{
register struct tty *tp;
register int unit = minor(dev);
register struct dcadevice *dca;
register int error;
int tmp, oldcursoron, oldcursortype;
if (unit >= NCON)
return (ENODEV);
tp = maccon_tty[unit];
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);
switch (cmd) {
case CON_SETCURSOR: /* Change cursor type */
tmp = *(int *)data;
if (tmp != cursortype)
{
oldcursoron = cursoron;
oldcursortype = cursortype;
if (oldcursoron) erasecursor(curvt);
cursortype = tmp;
if (oldcursoron) drawcursor(curvt);
if ((oldcursortype & C_SOLID) &&
(cursortype & (C_SLOW | C_FAST)))
timeout((void *) flashcursor, 0, 1);
}
break;
case CON_GETCURSOR: /* Get cursor type */
*(int *)data = cursortype;
break;
case CON_SETVT:
/* MF this is hacked, The interface should be better, fix later */
{
int i=*(int *)data;
unsigned char *oldscreen;
if ( (i <0) || (i >=gNumGrfDev) )
{
return EINVAL;
}
/* printf("set vt to %d\n",*(int *)data ); */
/* printf("address %x\n",grf_softc[*(int *)data].g_display.gd_fbaddr); */
/* printf("rowbytes = %d\n",grf_softc[*(int *)data].g_display.gd_fbrowbytes); */
/* set numgcols, numgrows, numtcols, numtrows, screen, linelen, numbits */
oldscreen=vt[curvt].screen;
vt[curvt].screen=(unsigned char *)grf_softc[i].g_display.gd_fbaddr;
vt[curvt].linelen=grf_softc[i].g_display.gd_fbrowbytes;
vt[curvt].numgcols=grf_softc[i].g_display.gd_fbwidth;
vt[curvt].numgrows=grf_softc[i].g_display.gd_fbheight;
vt[curvt].numbits=grf_softc[i].g_display.gd_planes;
if (vt[curvt].numgcols >= 640) /* Big screen */
vt[curvt].font=&font[0];
else
vt[curvt].font=&font[1];
vt[curvt].numtrows=vt[curvt].numgrows/vt[curvt].font->height;
vt[curvt].numtcols=vt[curvt].numgcols/vt[curvt].font->width;
make_visible(oldscreen);
/* redraw screen at new place */
/* all this is to trick it into redrawing the screen */
{
int newvt=curvt;
curvt++;
vtselect(newvt);
}
/* printf("screen = %x, rowbytes= %d\n", */
/* vt[curvt].screen, */
/* vt[curvt].linelen); */
/* printf("gcol %d, grow %d, tcol %d, trow %d\n", */
/* vt[curvt].numgcols, */
/* vt[curvt].numgrows, */
/* vt[curvt].numtcols, */
/* vt[curvt].numtrows); */
}
break;
case CON_SETBEEP:
{
struct beeps beep;
int i;
beep = *(struct beeps *) data;
return (asc_setbellparams(beep.freq,
beep.length,
beep.vol));
}
break;
case CON_GETBEEP:
{
int freq, len, vol;
asc_getbellparams(&freq, &len, &vol);
((struct beeps *)data)->freq = freq;
((struct beeps *)data)->length = len;
((struct beeps *)data)->vol = vol;
}
break;
default:
printf ("ioctl(): default cmd = 0x%x\n",cmd);
return (ENOTTY);
}
return (0);
}
conselect(dev_t dev, int rw, struct proc *p)
{
long len;
unsigned char buf[8];
if (minor(dev) >= NCON) return ENODEV;
return (ttselect(dev, rw, p));
}
conintr(register int unit, int data)
{
/* Jeez. Should this be doing more? -XXX */
if (unit >= NCON)
return 0;
if ((maccon_tty[unit]->t_state & TS_ISOPEN) != 0)
(*linesw[maccon_tty[unit]->t_line].l_rint)(data, maccon_tty[unit]);
return 1;
}
ser_intr(struct frame *fp)
{
/* This function is called by locore.s on a level 4 interrupt. */
int reg0, ch, s;
unsigned char c;
char str[20];
if(!serial_boot_echo)
return(serintr());
while(*sccaddr & SER_R0_RXREADY)
{
ch = *(sccaddr+4);
*sccaddr = SER_W0_RSTESINTS; /* Reset external/status interrupt */
conintr(0, ch);
}
reg0 = *sccaddr; /* Get status */
if(reg0 & SER_R0_TXUNDERRUN)
{
*sccaddr = SER_W0_RSTTXUNDERRUN;
*sccaddr = SER_W0_RSTESINTS;
/* macconputchar(0, (int)'!'); */
}
if(reg0 & SER_R0_TXREADY)
{
/* sprintf(str,"<%d>",outlen);
puts(vtnum, str); */
write_ack = 0;
*sccaddr = SER_W0_RSTTXPND;
*sccaddr = SER_W0_RSTIUS; /* Reset highest interrupt pending */
if (outlen > 0)
{
c = outbuf[outtail];
outtail = (outtail + 1) % OUTBUFLEN;
s = splhigh();
*(sccaddr+4) = c;
write_ack = 1;
outlen--;
splx(s);
}
}
return(1);
}
/* Routines to link with cons.c of standalone stuff */
/* SCC initialization string from Steve Allen (wormey@eskimo.com) */
static unsigned char ser_init_str[]={
9, 0xc0, /* hardware reset */
3, 0xc0, /* select receiver control. Bit d0 (rx enable)
must be set to 0 at this time. */
5, 0xe2, /* select transmit control. Bit d3 (tx enable)
must be set to 0 at this time. */
9, 0x06, /* select interrupt control. Bit d3 (mie)
must be set to 0 at this time. */
10, 0x00, /* miscellaneous control. */
11, 0x50, /* clock control. */
12, 0x0b, /* time constant LB. */
13, 0x00, /* time constant HB. */
14, 0x82, /* miscellaneous control. Bit d0 (BR gen enable)
must be set to 0 at this time. */
3, 0xc1, /* set d0 (rx enable). */
5, 0xea, /* set d3 (tx enable). */
0, 0x80, /* reset txCRC. */
14, 0x83, /* BR gen enable. Enable DPLL. */
1, 0x00, /* make sure DMA not set. */
15, 0x00, /* disable external interrupts. */
0, 0x10, /* reset ext/status twice. */
0, 0x10, /* don't do intr. yet
1, 0x0a, * * enable rcv and xmit interrupts. *
9, 0x0e, * * enable master interrupt bit d3. */
};
macprobe(struct consdev *cp)
{
int maj, unit;
/*
* macprobe(): This function returns a priority to tell the console
* init function cninit() whether it is functional or not. In the
* standalone this is all we must do, but I think that in the kernel
* we must also fill in the rest of the *cp structure, especially
* the tty pointer. It should also set the cn_dev field. I don't
* exactly know how this function should pick a number, but 0 seems
* just fine to me.
*/
/* locate the major number */
for (maj = 0; maj < nchrdev; maj++)
if (cdevsw[maj].d_open == conopen)
break;
/* BARF -- what happens if maj == nchrdev? */
if (maj == nchrdev)
return;
cdevsw[maj].d_ttys = maccon_tty;
/* double BARF panic -- I guess we can assume 0 */
unit = 0;
/* initialize required fields */
cp->cn_dev = makedev(maj, unit);
cp->cn_tp = NULL; /* Was maccon_tty[unit] but this isn't allocated yet. */
/* Hopefully we don't need the tty structure until the */
/* open routine is called after VM is setup. */
cp->cn_pri = CN_INTERNAL;
}
void
macserinit(struct consdev *cntab)
{
extern volatile unsigned char *sccA;
unsigned char *chr;
sccaddr = sccA + 2;
if (serial_boot_echo) {
chr = ser_init_str;
while (chr < ser_init_str + sizeof(ser_init_str))
{
*sccaddr = *chr++;
*sccaddr = *chr++;
}
}
ddprintf("Testing... %d.\n", 1);
}
static void
macwritestr(char *str)
{
while(*str)
writechar(0, *str++);
}
macinit(struct consdev *cntab)
{
static int alreadyinit=0;
if (alreadyinit) return;
alreadyinit = 1;
conattach(NCON);
screen_is_cool = 1;
/* macserinit(cntab); */
}
#if 0
extern unsigned char keyboard[128][3];
int mactestkey(unsigned char key)
{
/* Naturally we assume that this array is initialized to zero: */
/* Which is fine since UNIX stupidly zeros the bss. Thanks, UCB.. -XXX */
static unsigned char keydown[128];
if (key != 255)
{
if (key & 0x80)
keydown[key & 0x7F] = 0;
else
{
keydown[key] = 1;
if (keyboard[key][0] != 0)
{
if (keydown[0x36]) /* CTRL */
return(keyboard[key][2]);
else if (keydown[0x38]) /* SHIFT */
return(keyboard[key][1]);
else
return(keyboard[key][0]);
}
}
}
return(-1);
}
#endif
macgetchar() /* THIS WILL BLOCK!!!! */
{
char c;
c = adb_poll_for_char();
return c;
}
enable_interrupt_console()
{
intr_enabled = 1;
}
void
con_intr(caddr_t unused) /* One arg here we could use */
{
int s;
char str[20], *ss;
if (conlen > 0)
{
s = splconsole();
erasecursor(0);
while (conlen > 0)
{
writechar(0, (char)conbuf[contail]);
contail = (contail + 1) % CONBUFLEN;
conlen--;
}
drawcursor(0); /* <-- Fix vtnum */
splx(s);
}
do_conintr = 0;
}
void
macconputchar(int vtnum, u_char c)
{
int s;
if (0 && intr_enabled) /* Disable for now because of vt */
{
/* Put character in queue: */
while (conlen == CONBUFLEN) /* Wait if buffer full */
/* DO NOTHING */;
conbuf[conhead] = c;
conhead = (conhead + 1) % CONBUFLEN;
s = splconsole();
conlen++; /* Must be exclusive access to "conlen" */
splx(s);
/* Schedule the interrupt: */
if (!do_conintr)
{
do_conintr = 1;
timeout((void *) con_intr, 0, 1);
}
}
else
{
/* This should be atomic because interrupt could want to
display something: */
s = splconsole();
erasecursor(vtnum);
writechar(vtnum, (char)c);
drawcursor(vtnum);
splx(s);
}
}
macserputchar(unsigned char c)
{
int delay, s;
if (!serial_boot_echo) return;
while (!((*sccaddr) & 0x04));
/* while xmit buffer !ready */
*(sccaddr+4) = c;
}
void
macputchar(dev_t dev, u_char c)
{
if (serial_boot_echo && minor(dev) == 0)
macserputchar((unsigned char)c);
restoresb(); /* Try to take this line out */
if (screen_is_cool)
macconputchar(minor(dev), c);
}
macconputstr(char *str)
{
char *s=str;
vtselect(0);
while (*s) macconputchar(0, *s++);
}