summaryrefslogtreecommitdiffstats
path: root/drivers/video/fbcon.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
commit86464aed71025541805e7b1515541aee89879e33 (patch)
treee01a457a4912a8553bc65524aa3125d51f29f810 /drivers/video/fbcon.c
parent88f99939ecc6a95a79614574cb7d95ffccfc3466 (diff)
Merge with Linux 2.2.1.
Diffstat (limited to 'drivers/video/fbcon.c')
-rw-r--r--drivers/video/fbcon.c229
1 files changed, 142 insertions, 87 deletions
diff --git a/drivers/video/fbcon.c b/drivers/video/fbcon.c
index 9bdc9020b..033118f61 100644
--- a/drivers/video/fbcon.c
+++ b/drivers/video/fbcon.c
@@ -536,13 +536,14 @@ static void fbcon_setup(int con, int init, int logo)
conp->vc_can_do_color = p->var.bits_per_pixel != 1;
conp->vc_complement_mask = conp->vc_can_do_color ? 0x7700 : 0x0800;
if (charcnt == 256) {
- p->conp->vc_hi_font_mask = 0;
+ conp->vc_hi_font_mask = 0;
p->fgshift = 8;
p->bgshift = 12;
p->charmask = 0xff;
} else {
- p->conp->vc_hi_font_mask = 0x100;
- p->conp->vc_complement_mask <<= 1;
+ conp->vc_hi_font_mask = 0x100;
+ if (conp->vc_can_do_color)
+ conp->vc_complement_mask <<= 1;
p->fgshift = 9;
p->bgshift = 13;
p->charmask = 0x1ff;
@@ -944,7 +945,8 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
- int is_txt = (p->type == FB_TYPE_TEXT);
+ int scroll_partial = !(p->scrollmode & __SCROLL_YNOPARTIAL);
+ int logos_left = 0; int logos_width = conp->vc_cols;
if (!p->can_soft_blank && console_blanked)
return 0;
@@ -962,22 +964,34 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
switch (dir) {
case SM_UP:
+ /* K.Garloff@ping.de, 98/10/21: If logo is diplayed, only save logo
+ * and not the hole top region. In combination with the logo being
+ * displayed on the right side, this allows scrollback feature
+ * when bootlogo is displayed. */
+ if (t != 0 && logo_shown == fg_console) {
+ struct display *p = &fb_display[unit];
+ int lw = (smp_num_cpus * (LOGO_W + 8) - 7) / fontwidth(p) + 1;
+ logos_left = conp->vc_cols - lw;
+ while (logos_left < 0) logos_left += (LOGO_W + 8 - 7) / fontwidth(p);
+ logos_width = conp->vc_cols - logos_left;
+ }
if (count > conp->vc_rows) /* Maximum realistic size */
count = conp->vc_rows;
switch (p->scrollmode & __SCROLL_YMASK) {
case __SCROLL_YMOVE:
- p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count,
+ if (t > 0) p->dispsw->bmove(p, 0, logos_left, count,
+ logos_left, t, logos_width);
+ p->dispsw->bmove(p, count, 0, 0, 0, b-count,
conp->vc_cols);
- p->dispsw->clear(conp, p, b-count, 0, count,
+ p->dispsw->clear(conp, p, b-count, 0, count,
conp->vc_cols);
break;
case __SCROLL_YWRAP:
- if (b-t-count > 3*conp->vc_rows>>2) {
+ if (b-t-count > 2*conp->vc_rows/3) {
if (t > 0)
- fbcon_bmove(conp, 0, 0, count, 0, t,
- conp->vc_cols);
- ywrap_up(unit, conp, p, count);
+ fbcon_bmove(conp, 0, logos_left, count, logos_left, t, logos_width);
+ ywrap_up(unit, conp, p, count);
if (conp->vc_rows-b > 0)
fbcon_bmove(conp, b-count, 0, b, 0,
conp->vc_rows-b, conp->vc_cols);
@@ -990,11 +1004,11 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
break;
case __SCROLL_YPAN:
- if (( is_txt && (b-t == conp->vc_rows)) ||
- (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) {
+ if (( !scroll_partial && (b-t == conp->vc_rows)) ||
+ ( scroll_partial && (b-t-count > 3*conp->vc_rows>>2))) {
if (t > 0)
- fbcon_bmove(conp, 0, 0, count, 0, t,
- conp->vc_cols);
+ fbcon_bmove(conp, 0, logos_left, count, logos_left, t,
+ logos_width);
ypan_up(unit, conp, p, count);
if (conp->vc_rows-b > 0)
fbcon_bmove(conp, b-count, 0, b, 0,
@@ -1049,8 +1063,8 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
break;
case __SCROLL_YPAN:
- if (( is_txt && (b-t == conp->vc_rows)) ||
- (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) {
+ if (( !scroll_partial && (b-t == conp->vc_rows)) ||
+ ( scroll_partial && (b-t-count > 3*conp->vc_rows>>2))) {
if (conp->vc_rows-b > 0)
fbcon_bmove(conp, b, 0, b-count, 0,
conp->vc_rows-b, conp->vc_cols);
@@ -1250,46 +1264,41 @@ static inline int fbcon_get_font(int unit, struct console_font_op *op)
if (!op->data) return 0;
if (op->width <= 8) {
+ j = fontheight(p);
for (i = 0; i < op->charcount; i++) {
- for (j = 0; j < fontheight(p); j++)
- *data++ = *fontdata++;
- memset(data, 0, 32-j);
- data += 32 - j;
+ memcpy(data, fontdata, j);
+ memset(data+j, 0, 32-j);
+ data += 32;
+ fontdata += j;
}
}
#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
else if (op->width <= 16) {
+ j = fontheight(p) * 2;
for (i = 0; i < op->charcount; i++) {
- for (j = 0; j < fontheight(p); j++) {
- *data++ = *(u16 *)fontdata >> 8;
- *data++ = *(u16 *)fontdata;
- fontdata += sizeof(u16);
- }
- memset(data, 0, 2*(32-j));
- data += 2 * (32 - j);
+ memcpy(data, fontdata, j);
+ memset(data+j, 0, 64-j);
+ data += 64;
+ fontdata += j;
}
} else if (op->width <= 24) {
for (i = 0; i < op->charcount; i++) {
for (j = 0; j < fontheight(p); j++) {
- *data++ = *(u32 *)fontdata >> 24;
- *data++ = *(u32 *)fontdata >> 16;
- *data++ = *(u32 *)fontdata >> 8;
+ *data++ = fontdata[0];
+ *data++ = fontdata[1];
+ *data++ = fontdata[2];
fontdata += sizeof(u32);
}
memset(data, 0, 3*(32-j));
data += 3 * (32 - j);
}
} else {
+ j = fontheight(p) * 4;
for (i = 0; i < op->charcount; i++) {
- for (j = 0; j < fontheight(p); j++) {
- *data++ = *(u32 *)fontdata >> 24;
- *data++ = *(u32 *)fontdata >> 16;
- *data++ = *(u32 *)fontdata >> 8;
- *data++ = *(u32 *)fontdata;
- fontdata += sizeof(u32);
- }
- memset(data, 0, 4*(32-j));
- data += 4 * (32 - j);
+ memcpy(data, fontdata, j);
+ memset(data+j, 0, 128-j);
+ data += 128;
+ fontdata += j;
}
}
#endif
@@ -1325,16 +1334,58 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int
p->_fontheight = h;
if (p->conp->vc_hi_font_mask && cnt == 256) {
p->conp->vc_hi_font_mask = 0;
- p->conp->vc_complement_mask >>= 1;
+ if (p->conp->vc_can_do_color)
+ p->conp->vc_complement_mask >>= 1;
p->fgshift--;
p->bgshift--;
p->charmask = 0xff;
+
+ /* ++Edmund: reorder the attribute bits */
+ if (p->conp->vc_can_do_color) {
+ struct vc_data *conp = p->conp;
+ unsigned short *cp = (unsigned short *) conp->vc_origin;
+ int count = conp->vc_screenbuf_size/2;
+ unsigned short c;
+ for (; count > 0; count--, cp++) {
+ c = scr_readw(cp);
+ scr_writew(((c & 0xfe00) >> 1) | (c & 0xff), cp);
+ }
+ c = conp->vc_video_erase_char;
+ conp->vc_video_erase_char = ((c & 0xfe00) >> 1) | (c & 0xff);
+ conp->vc_attr >>= 1;
+ }
+
} else if (!p->conp->vc_hi_font_mask && cnt == 512) {
p->conp->vc_hi_font_mask = 0x100;
- p->conp->vc_complement_mask <<= 1;
+ if (p->conp->vc_can_do_color)
+ p->conp->vc_complement_mask <<= 1;
p->fgshift++;
p->bgshift++;
p->charmask = 0x1ff;
+
+ /* ++Edmund: reorder the attribute bits */
+ {
+ struct vc_data *conp = p->conp;
+ unsigned short *cp = (unsigned short *) conp->vc_origin;
+ int count = conp->vc_screenbuf_size/2;
+ unsigned short c;
+ for (; count > 0; count--, cp++) {
+ unsigned short newc;
+ c = scr_readw(cp);
+ if (conp->vc_can_do_color)
+ newc = ((c & 0xff00) << 1) | (c & 0xff);
+ else
+ newc = c & ~0x100;
+ scr_writew(newc, cp);
+ }
+ c = conp->vc_video_erase_char;
+ if (conp->vc_can_do_color) {
+ conp->vc_video_erase_char = ((c & 0xff00) << 1) | (c & 0xff);
+ conp->vc_attr <<= 1;
+ } else
+ conp->vc_video_erase_char = c & ~0x100;
+ }
+
}
fbcon_font_widths(p);
@@ -1380,17 +1431,17 @@ static inline int fbcon_set_font(int unit, struct console_font_op *op)
int w = op->width;
int h = op->height;
int size = h;
- int i, j, k;
- u8 *new_data, *data = op->data, c, *p;
+ int i, k;
#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
- u32 d;
-#else
+ int j;
+#endif
+ u8 *new_data, *data = op->data, *p;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
if (w != 8)
return -EINVAL;
#endif
-
- if (w > 32 || (op->charcount != 256 && op->charcount != 512))
+ if ((w <= 0) || (w > 32) || (op->charcount != 256 && op->charcount != 512))
return -EINVAL;
if (w > 8) {
@@ -1407,56 +1458,46 @@ static inline int fbcon_set_font(int unit, struct console_font_op *op)
FNTSIZE(new_data) = size;
FNTCHARCNT(new_data) = op->charcount;
REFCOUNT(new_data) = 0; /* usage counter */
- k = 0;
p = new_data;
if (w <= 8) {
for (i = 0; i < op->charcount; i++) {
- for (j = 0; j < h; j++) {
- c = *data++;
- k += c;
- *p++ = c;
- }
- data += 32 - h;
+ memcpy(p, data, h);
+ data += 32;
+ p += h;
}
}
#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
else if (w <= 16) {
+ h *= 2;
for (i = 0; i < op->charcount; i++) {
- for (j = 0; j < h; j++) {
- d = (data[0] << 8) | data[1];
- data += 2;
- k += d;
- *(u16 *)p = d;
- p += sizeof(u16);
- }
- data += 2*(32 - h);
+ memcpy(p, data, h);
+ data += 64;
+ p += h;
}
- } else {
+ } else if (w <= 24) {
for (i = 0; i < op->charcount; i++) {
for (j = 0; j < h; j++) {
- if (w <= 24) {
- d = (data[0] << 24) |
- (data[1] << 16) |
- (data[2] << 8);
- data += 3;
- } else {
- d = (data[0] << 24) |
- (data[1] << 16) |
- (data[2] << 8) |
- data[3];
- data += 4;
- }
- k += d;
- *(u32 *)p = d;
+ memcpy(p, data, 3);
+ p[3] = 0;
+ data += 3;
p += sizeof(u32);
}
- if (w <= 24)
- data += 3*(32 - h);
- else
- data += 4*(32 - h);
+ data += 3*(32 - h);
+ }
+ } else {
+ h *= 4;
+ for (i = 0; i < op->charcount; i++) {
+ memcpy(p, data, h);
+ data += 128;
+ p += h;
}
}
#endif
+ /* we can do it in u32 chunks because of charcount is 256 or 512, so
+ font length must be multiple of 256, at least. And 256 is multiple
+ of 4 */
+ k = 0;
+ while (p > new_data) k += *--(u32 *)p;
FNTSUM(new_data) = k;
/* Check if the same font is on some other console already */
for (i = 0; i < MAX_NR_CONSOLES; i++) {
@@ -1587,7 +1628,7 @@ static int fbcon_scrolldelta(struct vc_data *conp, int lines)
p->var.xoffset = 0;
p->var.yoffset = offset*fontheight(p);
p->fb_info->updatevar(unit, p->fb_info);
- if (!offset)
+ if (!scrollback_current)
fbcon_cursor(conp, CM_DRAW);
return 0;
}
@@ -1664,8 +1705,8 @@ __initfunc(static int fbcon_show_logo( void ))
logo_depth = 1;
}
- for (x = 0; x < smp_num_cpus * (LOGO_W + 8) &&
- x < p->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) {
+ for (x = p->var.xres - LOGO_W; x > 0 && x > (int)p->var.xres
+ - smp_num_cpus * (LOGO_W + 8); x -= (LOGO_W + 8)) {
#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
@@ -1768,6 +1809,20 @@ __initfunc(static int fbcon_show_logo( void ))
done = 1;
}
#endif
+#if defined(CONFIG_FBCON_CFB4)
+ if (depth == 4 && p->type == FB_TYPE_PACKED_PIXELS) {
+ src = logo;
+ for( y1 = 0; y1 < LOGO_H; y1++) {
+ dst = fb + y1*line + x/2;
+ for( x1 = 0; x1 < LOGO_W/2; x1++) {
+ u8 q = *src++;
+ q = (q << 4) | (q >> 4);
+ *dst++ = q;
+ }
+ }
+ done = 1;
+ }
+#endif
#if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FB_SBUS)
if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
/* depth 8 or more, packed, with color registers */
@@ -1796,7 +1851,7 @@ __initfunc(static int fbcon_show_logo( void ))
int line_length = p->line_length;
/* for support of Atari interleaved planes */
-#define MAP_X(x) (line_length ? x : (x & ~1)*depth + (x & 1))
+#define MAP_X(x) (line_length ? (x) : ((x) & ~1)*depth + ((x) & 1))
#else
#define MAP_X(x) (x)
#endif
@@ -1807,7 +1862,7 @@ __initfunc(static int fbcon_show_logo( void ))
src = logo;
for( y1 = 0; y1 < LOGO_H; y1++ ) {
for( x1 = 0; x1 < LOGO_LINE; x1++, src += logo_depth ) {
- dst = fb + y1*line + MAP_X(x1);
+ dst = fb + y1*line + MAP_X(x/8+x1);
for( bit = 0; bit < logo_depth; bit++ ) {
val = 0;
for( mask = 0x80, i = 0; i < 8; mask >>= 1, i++ ) {
@@ -1826,7 +1881,7 @@ __initfunc(static int fbcon_show_logo( void ))
if (depth > logo_depth) {
for( y1 = 0; y1 < LOGO_H; y1++ ) {
for( x1 = 0; x1 < LOGO_LINE; x1++ ) {
- dst = fb + y1*line + MAP_X(x1) + logo_depth*plane;
+ dst = fb + y1*line + MAP_X(x/8+x1) + logo_depth*plane;
for( i = logo_depth; i < depth; i++, dst += plane )
*dst = (i == logo_depth && logo_depth == 4)
? 0xff : 0x00;