mirror of https://gitee.com/openkylin/linux.git
600 lines
12 KiB
C
600 lines
12 KiB
C
|
/* $Id: promcon.c,v 1.17 2000/07/26 23:02:52 davem Exp $
|
||
|
* Console driver utilizing PROM sun terminal emulation
|
||
|
*
|
||
|
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
|
||
|
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
|
||
|
*/
|
||
|
|
||
|
#include <linux/config.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/errno.h>
|
||
|
#include <linux/string.h>
|
||
|
#include <linux/mm.h>
|
||
|
#include <linux/tty.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/console.h>
|
||
|
#include <linux/vt_kern.h>
|
||
|
#include <linux/selection.h>
|
||
|
#include <linux/fb.h>
|
||
|
#include <linux/init.h>
|
||
|
#include <linux/kd.h>
|
||
|
|
||
|
#include <asm/oplib.h>
|
||
|
#include <asm/uaccess.h>
|
||
|
|
||
|
static short pw = 80 - 1, ph = 34 - 1;
|
||
|
static short px, py;
|
||
|
static unsigned long promcon_uni_pagedir[2];
|
||
|
|
||
|
extern u8 promfont_unicount[];
|
||
|
extern u16 promfont_unitable[];
|
||
|
|
||
|
#define PROMCON_COLOR 0
|
||
|
|
||
|
#if PROMCON_COLOR
|
||
|
#define inverted(s) ((((s) & 0x7700) == 0x0700) ? 0 : 1)
|
||
|
#else
|
||
|
#define inverted(s) (((s) & 0x0800) ? 1 : 0)
|
||
|
#endif
|
||
|
|
||
|
static __inline__ void
|
||
|
promcon_puts(char *buf, int cnt)
|
||
|
{
|
||
|
prom_printf("%*.*s", cnt, cnt, buf);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
promcon_start(struct vc_data *conp, char *b)
|
||
|
{
|
||
|
unsigned short *s = (unsigned short *)
|
||
|
(conp->vc_origin + py * conp->vc_size_row + (px << 1));
|
||
|
u16 cs;
|
||
|
|
||
|
cs = scr_readw(s);
|
||
|
if (px == pw) {
|
||
|
unsigned short *t = s - 1;
|
||
|
u16 ct = scr_readw(t);
|
||
|
|
||
|
if (inverted(cs) && inverted(ct))
|
||
|
return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs,
|
||
|
ct);
|
||
|
else if (inverted(cs))
|
||
|
return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs,
|
||
|
ct);
|
||
|
else if (inverted(ct))
|
||
|
return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs,
|
||
|
ct);
|
||
|
else
|
||
|
return sprintf(b, "\b%c\b\033[@%c", cs, ct);
|
||
|
}
|
||
|
|
||
|
if (inverted(cs))
|
||
|
return sprintf(b, "\033[7m%c\033[m\b", cs);
|
||
|
else
|
||
|
return sprintf(b, "%c\b", cs);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
promcon_end(struct vc_data *conp, char *b)
|
||
|
{
|
||
|
unsigned short *s = (unsigned short *)
|
||
|
(conp->vc_origin + py * conp->vc_size_row + (px << 1));
|
||
|
char *p = b;
|
||
|
u16 cs;
|
||
|
|
||
|
b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
|
||
|
|
||
|
cs = scr_readw(s);
|
||
|
if (px == pw) {
|
||
|
unsigned short *t = s - 1;
|
||
|
u16 ct = scr_readw(t);
|
||
|
|
||
|
if (inverted(cs) && inverted(ct))
|
||
|
b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct);
|
||
|
else if (inverted(cs))
|
||
|
b += sprintf(b, "\b%c\b\033[@%c", cs, ct);
|
||
|
else if (inverted(ct))
|
||
|
b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct);
|
||
|
else
|
||
|
b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct);
|
||
|
return b - p;
|
||
|
}
|
||
|
|
||
|
if (inverted(cs))
|
||
|
b += sprintf(b, "%c\b", cs);
|
||
|
else
|
||
|
b += sprintf(b, "\033[7m%c\033[m\b", cs);
|
||
|
return b - p;
|
||
|
}
|
||
|
|
||
|
const char __init *promcon_startup(void)
|
||
|
{
|
||
|
const char *display_desc = "PROM";
|
||
|
int node;
|
||
|
char buf[40];
|
||
|
|
||
|
node = prom_getchild(prom_root_node);
|
||
|
node = prom_searchsiblings(node, "options");
|
||
|
if (prom_getproperty(node, "screen-#columns", buf, 40) != -1) {
|
||
|
pw = simple_strtoul(buf, NULL, 0);
|
||
|
if (pw < 10 || pw > 256)
|
||
|
pw = 80;
|
||
|
pw--;
|
||
|
}
|
||
|
if (prom_getproperty(node, "screen-#rows", buf, 40) != -1) {
|
||
|
ph = simple_strtoul(buf, NULL, 0);
|
||
|
if (ph < 10 || ph > 256)
|
||
|
ph = 34;
|
||
|
ph--;
|
||
|
}
|
||
|
promcon_puts("\033[H\033[J", 6);
|
||
|
return display_desc;
|
||
|
}
|
||
|
|
||
|
static void __init
|
||
|
promcon_init_unimap(struct vc_data *conp)
|
||
|
{
|
||
|
mm_segment_t old_fs = get_fs();
|
||
|
struct unipair *p, *p1;
|
||
|
u16 *q;
|
||
|
int i, j, k;
|
||
|
|
||
|
p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL);
|
||
|
if (!p) return;
|
||
|
|
||
|
q = promfont_unitable;
|
||
|
p1 = p;
|
||
|
k = 0;
|
||
|
for (i = 0; i < 256; i++)
|
||
|
for (j = promfont_unicount[i]; j; j--) {
|
||
|
p1->unicode = *q++;
|
||
|
p1->fontpos = i;
|
||
|
p1++;
|
||
|
k++;
|
||
|
}
|
||
|
set_fs(KERNEL_DS);
|
||
|
con_clear_unimap(conp, NULL);
|
||
|
con_set_unimap(conp, k, p);
|
||
|
con_protect_unimap(conp, 1);
|
||
|
set_fs(old_fs);
|
||
|
kfree(p);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
promcon_init(struct vc_data *conp, int init)
|
||
|
{
|
||
|
unsigned long p;
|
||
|
|
||
|
conp->vc_can_do_color = PROMCON_COLOR;
|
||
|
if (init) {
|
||
|
conp->vc_cols = pw + 1;
|
||
|
conp->vc_rows = ph + 1;
|
||
|
}
|
||
|
p = *conp->vc_uni_pagedir_loc;
|
||
|
if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
|
||
|
!--conp->vc_uni_pagedir_loc[1])
|
||
|
con_free_unimap(conp);
|
||
|
conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
|
||
|
promcon_uni_pagedir[1]++;
|
||
|
if (!promcon_uni_pagedir[0] && p) {
|
||
|
promcon_init_unimap(conp);
|
||
|
}
|
||
|
if (!init) {
|
||
|
if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
|
||
|
vc_resize(conp, pw + 1, ph + 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
promcon_deinit(struct vc_data *conp)
|
||
|
{
|
||
|
/* When closing the last console, reset video origin */
|
||
|
if (!--promcon_uni_pagedir[1])
|
||
|
con_free_unimap(conp);
|
||
|
conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
|
||
|
con_set_default_unimap(conp);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
promcon_switch(struct vc_data *conp)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static unsigned short *
|
||
|
promcon_repaint_line(unsigned short *s, unsigned char *buf, unsigned char **bp)
|
||
|
{
|
||
|
int cnt = pw + 1;
|
||
|
int attr = -1;
|
||
|
unsigned char *b = *bp;
|
||
|
|
||
|
while (cnt--) {
|
||
|
u16 c = scr_readw(s);
|
||
|
if (attr != inverted(c)) {
|
||
|
attr = inverted(c);
|
||
|
if (attr) {
|
||
|
strcpy (b, "\033[7m");
|
||
|
b += 4;
|
||
|
} else {
|
||
|
strcpy (b, "\033[m");
|
||
|
b += 3;
|
||
|
}
|
||
|
}
|
||
|
*b++ = c;
|
||
|
s++;
|
||
|
if (b - buf >= 224) {
|
||
|
promcon_puts(buf, b - buf);
|
||
|
b = buf;
|
||
|
}
|
||
|
}
|
||
|
*bp = b;
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
promcon_putcs(struct vc_data *conp, const unsigned short *s,
|
||
|
int count, int y, int x)
|
||
|
{
|
||
|
unsigned char buf[256], *b = buf;
|
||
|
unsigned short attr = scr_readw(s);
|
||
|
unsigned char save;
|
||
|
int i, last = 0;
|
||
|
|
||
|
if (console_blanked)
|
||
|
return;
|
||
|
|
||
|
if (count <= 0)
|
||
|
return;
|
||
|
|
||
|
b += promcon_start(conp, b);
|
||
|
|
||
|
if (x + count >= pw + 1) {
|
||
|
if (count == 1) {
|
||
|
x -= 1;
|
||
|
save = scr_readw((unsigned short *)(conp->vc_origin
|
||
|
+ y * conp->vc_size_row
|
||
|
+ (x << 1)));
|
||
|
|
||
|
if (px != x || py != y) {
|
||
|
b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
|
||
|
px = x;
|
||
|
py = y;
|
||
|
}
|
||
|
|
||
|
if (inverted(attr))
|
||
|
b += sprintf(b, "\033[7m%c\033[m", scr_readw(s++));
|
||
|
else
|
||
|
b += sprintf(b, "%c", scr_readw(s++));
|
||
|
|
||
|
strcpy(b, "\b\033[@");
|
||
|
b += 4;
|
||
|
|
||
|
if (inverted(save))
|
||
|
b += sprintf(b, "\033[7m%c\033[m", save);
|
||
|
else
|
||
|
b += sprintf(b, "%c", save);
|
||
|
|
||
|
px++;
|
||
|
|
||
|
b += promcon_end(conp, b);
|
||
|
promcon_puts(buf, b - buf);
|
||
|
return;
|
||
|
} else {
|
||
|
last = 1;
|
||
|
count = pw - x - 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (inverted(attr)) {
|
||
|
strcpy(b, "\033[7m");
|
||
|
b += 4;
|
||
|
}
|
||
|
|
||
|
if (px != x || py != y) {
|
||
|
b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
|
||
|
px = x;
|
||
|
py = y;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < count; i++) {
|
||
|
if (b - buf >= 224) {
|
||
|
promcon_puts(buf, b - buf);
|
||
|
b = buf;
|
||
|
}
|
||
|
*b++ = scr_readw(s++);
|
||
|
}
|
||
|
|
||
|
px += count;
|
||
|
|
||
|
if (last) {
|
||
|
save = scr_readw(s++);
|
||
|
b += sprintf(b, "%c\b\033[@%c", scr_readw(s++), save);
|
||
|
px++;
|
||
|
}
|
||
|
|
||
|
if (inverted(attr)) {
|
||
|
strcpy(b, "\033[m");
|
||
|
b += 3;
|
||
|
}
|
||
|
|
||
|
b += promcon_end(conp, b);
|
||
|
promcon_puts(buf, b - buf);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
promcon_putc(struct vc_data *conp, int c, int y, int x)
|
||
|
{
|
||
|
unsigned short s;
|
||
|
|
||
|
if (console_blanked)
|
||
|
return;
|
||
|
|
||
|
scr_writew(c, &s);
|
||
|
promcon_putcs(conp, &s, 1, y, x);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
promcon_clear(struct vc_data *conp, int sy, int sx, int height, int width)
|
||
|
{
|
||
|
unsigned char buf[256], *b = buf;
|
||
|
int i, j;
|
||
|
|
||
|
if (console_blanked)
|
||
|
return;
|
||
|
|
||
|
b += promcon_start(conp, b);
|
||
|
|
||
|
if (!sx && width == pw + 1) {
|
||
|
|
||
|
if (!sy && height == ph + 1) {
|
||
|
strcpy(b, "\033[H\033[J");
|
||
|
b += 6;
|
||
|
b += promcon_end(conp, b);
|
||
|
promcon_puts(buf, b - buf);
|
||
|
return;
|
||
|
} else if (sy + height == ph + 1) {
|
||
|
b += sprintf(b, "\033[%dH\033[J", sy + 1);
|
||
|
b += promcon_end(conp, b);
|
||
|
promcon_puts(buf, b - buf);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
b += sprintf(b, "\033[%dH", sy + 1);
|
||
|
for (i = 1; i < height; i++) {
|
||
|
strcpy(b, "\033[K\n");
|
||
|
b += 4;
|
||
|
}
|
||
|
|
||
|
strcpy(b, "\033[K");
|
||
|
b += 3;
|
||
|
|
||
|
b += promcon_end(conp, b);
|
||
|
promcon_puts(buf, b - buf);
|
||
|
return;
|
||
|
|
||
|
} else if (sx + width == pw + 1) {
|
||
|
|
||
|
b += sprintf(b, "\033[%d;%dH", sy + 1, sx + 1);
|
||
|
for (i = 1; i < height; i++) {
|
||
|
strcpy(b, "\033[K\n");
|
||
|
b += 4;
|
||
|
}
|
||
|
|
||
|
strcpy(b, "\033[K");
|
||
|
b += 3;
|
||
|
|
||
|
b += promcon_end(conp, b);
|
||
|
promcon_puts(buf, b - buf);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (i = sy + 1; i <= sy + height; i++) {
|
||
|
b += sprintf(b, "\033[%d;%dH", i, sx + 1);
|
||
|
for (j = 0; j < width; j++)
|
||
|
*b++ = ' ';
|
||
|
if (b - buf + width >= 224) {
|
||
|
promcon_puts(buf, b - buf);
|
||
|
b = buf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
b += promcon_end(conp, b);
|
||
|
promcon_puts(buf, b - buf);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
promcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
|
||
|
int height, int width)
|
||
|
{
|
||
|
char buf[256], *b = buf;
|
||
|
|
||
|
if (console_blanked)
|
||
|
return;
|
||
|
|
||
|
b += promcon_start(conp, b);
|
||
|
if (sy == dy && height == 1) {
|
||
|
if (dx > sx && dx + width == conp->vc_cols)
|
||
|
b += sprintf(b, "\033[%d;%dH\033[%d@\033[%d;%dH",
|
||
|
sy + 1, sx + 1, dx - sx, py + 1, px + 1);
|
||
|
else if (dx < sx && sx + width == conp->vc_cols)
|
||
|
b += sprintf(b, "\033[%d;%dH\033[%dP\033[%d;%dH",
|
||
|
dy + 1, dx + 1, sx - dx, py + 1, px + 1);
|
||
|
|
||
|
b += promcon_end(conp, b);
|
||
|
promcon_puts(buf, b - buf);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* FIXME: What to do here???
|
||
|
* Current console.c should not call it like that ever.
|
||
|
*/
|
||
|
prom_printf("\033[7mFIXME: bmove not handled\033[m\n");
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
promcon_cursor(struct vc_data *conp, int mode)
|
||
|
{
|
||
|
char buf[32], *b = buf;
|
||
|
|
||
|
switch (mode) {
|
||
|
case CM_ERASE:
|
||
|
break;
|
||
|
|
||
|
case CM_MOVE:
|
||
|
case CM_DRAW:
|
||
|
b += promcon_start(conp, b);
|
||
|
if (px != conp->vc_x || py != conp->vc_y) {
|
||
|
px = conp->vc_x;
|
||
|
py = conp->vc_y;
|
||
|
b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
|
||
|
}
|
||
|
promcon_puts(buf, b - buf);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
promcon_blank(struct vc_data *conp, int blank, int mode_switch)
|
||
|
{
|
||
|
if (blank) {
|
||
|
promcon_puts("\033[H\033[J\033[7m \033[m\b", 15);
|
||
|
return 0;
|
||
|
} else {
|
||
|
/* Let console.c redraw */
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
|
||
|
{
|
||
|
unsigned char buf[256], *p = buf;
|
||
|
unsigned short *s;
|
||
|
int i;
|
||
|
|
||
|
if (console_blanked)
|
||
|
return 0;
|
||
|
|
||
|
p += promcon_start(conp, p);
|
||
|
|
||
|
switch (dir) {
|
||
|
case SM_UP:
|
||
|
if (b == ph + 1) {
|
||
|
p += sprintf(p, "\033[%dH\033[%dM", t + 1, count);
|
||
|
px = 0;
|
||
|
py = t;
|
||
|
p += promcon_end(conp, p);
|
||
|
promcon_puts(buf, p - buf);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
s = (unsigned short *)(conp->vc_origin
|
||
|
+ (t + count) * conp->vc_size_row);
|
||
|
|
||
|
p += sprintf(p, "\033[%dH", t + 1);
|
||
|
|
||
|
for (i = t; i < b - count; i++)
|
||
|
s = promcon_repaint_line(s, buf, &p);
|
||
|
|
||
|
for (; i < b - 1; i++) {
|
||
|
strcpy(p, "\033[K\n");
|
||
|
p += 4;
|
||
|
if (p - buf >= 224) {
|
||
|
promcon_puts(buf, p - buf);
|
||
|
p = buf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
strcpy(p, "\033[K");
|
||
|
p += 3;
|
||
|
|
||
|
p += promcon_end(conp, p);
|
||
|
promcon_puts(buf, p - buf);
|
||
|
break;
|
||
|
|
||
|
case SM_DOWN:
|
||
|
if (b == ph + 1) {
|
||
|
p += sprintf(p, "\033[%dH\033[%dL", t + 1, count);
|
||
|
px = 0;
|
||
|
py = t;
|
||
|
p += promcon_end(conp, p);
|
||
|
promcon_puts(buf, p - buf);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row);
|
||
|
|
||
|
p += sprintf(p, "\033[%dH", t + 1);
|
||
|
|
||
|
for (i = t; i < t + count; i++) {
|
||
|
strcpy(p, "\033[K\n");
|
||
|
p += 4;
|
||
|
if (p - buf >= 224) {
|
||
|
promcon_puts(buf, p - buf);
|
||
|
p = buf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (; i < b; i++)
|
||
|
s = promcon_repaint_line(s, buf, &p);
|
||
|
|
||
|
p += promcon_end(conp, p);
|
||
|
promcon_puts(buf, p - buf);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#if !(PROMCON_COLOR)
|
||
|
static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
|
||
|
{
|
||
|
return (_reverse) ? 0xf : 0x7;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* The console 'switch' structure for the VGA based console
|
||
|
*/
|
||
|
|
||
|
static int promcon_dummy(void)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#define DUMMY (void *) promcon_dummy
|
||
|
|
||
|
const struct consw prom_con = {
|
||
|
.owner = THIS_MODULE,
|
||
|
.con_startup = promcon_startup,
|
||
|
.con_init = promcon_init,
|
||
|
.con_deinit = promcon_deinit,
|
||
|
.con_clear = promcon_clear,
|
||
|
.con_putc = promcon_putc,
|
||
|
.con_putcs = promcon_putcs,
|
||
|
.con_cursor = promcon_cursor,
|
||
|
.con_scroll = promcon_scroll,
|
||
|
.con_bmove = promcon_bmove,
|
||
|
.con_switch = promcon_switch,
|
||
|
.con_blank = promcon_blank,
|
||
|
.con_set_palette = DUMMY,
|
||
|
.con_scrolldelta = DUMMY,
|
||
|
#if !(PROMCON_COLOR)
|
||
|
.con_build_attr = promcon_build_attr,
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
void __init prom_con_init(void)
|
||
|
{
|
||
|
#ifdef CONFIG_DUMMY_CONSOLE
|
||
|
if (conswitchp == &dummy_con)
|
||
|
take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1);
|
||
|
else
|
||
|
#endif
|
||
|
if (conswitchp == &prom_con)
|
||
|
promcon_init_unimap(vc_cons[fg_console].d);
|
||
|
}
|