patch-2.1.109 linux/drivers/video/fbcon.c
Next file: linux/drivers/video/fbcon.h
Previous file: linux/drivers/video/fbcon-vga.h
Back to the patch index
Back to the overall index
- Lines: 1237
- Date:
Fri Jul 10 15:18:31 1998
- Orig file:
v2.1.108/linux/drivers/video/fbcon.c
- Orig date:
Wed Jun 24 22:54:07 1998
diff -u --recursive --new-file v2.1.108/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
@@ -25,6 +25,7 @@
* Andreas Schwab
*
* Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
+ * Smart redraw scrolling added by Jakub Jelinek (jj@ultra.linux.cz)
*
*
* The low level operations for the various display memory organizations are
@@ -37,6 +38,7 @@
* o ilbm Amiga interleaved bitplanes
* o iplan2p[248] Atari interleaved bitplanes
* o mfb Monochrome
+ * o vga VGA characters/attributes
*
* To do:
*
@@ -50,7 +52,6 @@
#undef FBCONDEBUG
-#define SUPPORT_SCROLLBACK 0
#define FLASHING_CURSOR 1
#include <linux/config.h>
@@ -68,6 +69,7 @@
#include <linux/fb.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
+#include <linux/smp.h>
#include <linux/init.h>
#include <asm/irq.h>
@@ -87,6 +89,7 @@
#include <asm/machdep.h>
#include <asm/setup.h>
#endif
+#define INCLUDE_LINUX_LOGO_DATA
#include <asm/linux_logo.h>
#include "fbcon.h"
@@ -99,6 +102,10 @@
# define DPRINTK(fmt, args...)
#endif
+#define LOGO_H 80
+#define LOGO_W 80
+#define LOGO_LINE (LOGO_W/8)
+
struct display fb_display[MAX_NR_CONSOLES];
@@ -131,7 +138,7 @@
vbl_cursor_cnt = 0;
cursor_was_drawn = cursor_drawn;
cursor_drawn = 0;
- return(cursor_was_drawn);
+ return cursor_was_drawn;
}
#endif
@@ -139,10 +146,6 @@
* Scroll Method
*/
-#define SCROLL_YWRAP (0)
-#define SCROLL_YPAN (1)
-#define SCROLL_YMOVE (2)
-
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
@@ -150,18 +153,17 @@
* Interface used by the world
*/
-static unsigned long fbcon_startup(unsigned long kmem_start,
- const char **display_desc);
-static void fbcon_init(struct vc_data *conp);
+static const char *fbcon_startup(void);
+static void fbcon_init(struct vc_data *conp, int init);
static void fbcon_deinit(struct vc_data *conp);
static int fbcon_changevar(int con);
static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
int width);
static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos);
-static void fbcon_putcs(struct vc_data *conp, const char *s, int count,
+static void fbcon_putcs(struct vc_data *conp, const unsigned short *s, int count,
int ypos, int xpos);
static void fbcon_cursor(struct vc_data *conp, int mode);
-static void fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
+static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
int count);
static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
int height, int width);
@@ -177,21 +179,16 @@
* Internal routines
*/
-static void fbcon_setup(int con, int setcol, int init);
+static void fbcon_setup(int con, int init, int logo);
static __inline__ int real_y(struct display *p, int ypos);
#if FLASHING_CURSOR
static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
#endif
static __inline__ void updatescrollmode(struct display *p);
-#if SUPPORT_SCROLLBACK
static __inline__ void ywrap_up(int unit, struct vc_data *conp,
struct display *p, int count);
static __inline__ void ywrap_down(int unit, struct vc_data *conp,
struct display *p, int count);
-#else
-static __inline__ void ywrap_up(int unit, struct display *p, int count);
-static __inline__ void ywrap_down(int unit, struct display *p, int count);
-#endif
static __inline__ void ypan_up(int unit, struct vc_data *conp,
struct display *p, int count);
static __inline__ void ypan_down(int unit, struct vc_data *conp,
@@ -237,21 +234,21 @@
static struct display_switch fbcon_dummy;
+/* NOTE: fbcon cannot be __initfunc: it may be called from take_over_console later */
-__initfunc(static unsigned long fbcon_startup(unsigned long kmem_start,
- const char **display_desc))
+static const char *fbcon_startup(void)
{
+ const char *display_desc = "frame buffer device";
int irqres = 1;
+ static int done = 0;
- /* Probe all frame buffer devices */
- kmem_start = probe_framebuffers(kmem_start);
-
- if (!num_registered_fb) {
- DPRINTK("no framebuffer registered\n");
- return kmem_start;
- }
-
- *display_desc = "frame buffer device";
+ /*
+ * If num_registered_fb is zero, this is a call for the dummy part.
+ * The frame buffer devices weren't initialized yet.
+ */
+ if (!num_registered_fb || done)
+ return display_desc;
+ done = 1;
#ifdef CONFIG_AMIGA
if (MACH_IS_AMIGA) {
@@ -307,6 +304,11 @@
}
#endif /* CONFIG_MAC */
+#if defined(__arm__) && defined(IRQ_VSYNCPULSE)
+ irqres = request_irq(IRQ_VSYNCPULSE, fbcon_vbl_handler, 0,
+ "console/cursor", fbcon_vbl_handler);
+#endif
+
if (irqres) {
cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE;
cursor_timer.expires = jiffies+HZ/50;
@@ -315,14 +317,11 @@
add_timer(&cursor_timer);
}
- if (!console_show_logo)
- console_show_logo = fbcon_show_logo;
-
- return kmem_start;
+ return display_desc;
}
-static void fbcon_init(struct vc_data *conp)
+static void fbcon_init(struct vc_data *conp, int init)
{
int unit = conp->vc_num;
struct fb_info *info;
@@ -339,7 +338,7 @@
fb_display[unit].var.bits_per_pixel);
fb_display[unit].conp = conp;
fb_display[unit].fb_info = info;
- fbcon_setup(unit, 1, 1);
+ fbcon_setup(unit, init, !init);
}
@@ -356,13 +355,15 @@
static int fbcon_changevar(int con)
{
if (fb_display[con].conp)
- fbcon_setup(con, 1, 0);
- return(0);
+ fbcon_setup(con, 0, 0);
+ return 0;
}
static __inline__ void updatescrollmode(struct display *p)
{
+ if (p->scrollmode == SCROLL_YREDRAW)
+ return;
if (divides(p->ywrapstep, p->fontheight) &&
divides(p->fontheight, p->var.yres_virtual))
p->scrollmode = SCROLL_YWRAP;
@@ -374,11 +375,17 @@
}
-static void fbcon_setup(int con, int setcol, int init)
+static void fbcon_setup(int con, int init, int logo)
{
struct display *p = &fb_display[con];
struct vc_data *conp = p->conp;
int nr_rows, nr_cols;
+ int old_rows, old_cols;
+ /* Only if not module */
+ extern int initmem_freed;
+
+ if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT)
+ logo = 0;
p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
@@ -401,7 +408,37 @@
}
}
updatescrollmode(p);
-
+
+ if (logo) {
+ /* Need to make room for the logo */
+ int logo_lines = (LOGO_H + p->fontheight - 1) / p->fontheight;
+ unsigned short *q = (unsigned short *)(conp->vc_origin +
+ conp->vc_size_row * conp->vc_rows);
+ unsigned short *r;
+
+ for (r = q - logo_lines * conp->vc_cols; r < q; r++)
+ if (*r != conp->vc_video_erase_char)
+ break;
+ if (r == q) {
+ /* We can scroll screen down */
+ int cnt;
+ int step = logo_lines * conp->vc_cols;
+
+ r = q - step - conp->vc_cols;
+ for (cnt = conp->vc_rows - logo_lines; cnt > 0; cnt--) {
+ scr_memcpyw(r + step, r, conp->vc_size_row);
+ r -= conp->vc_cols;
+ }
+ conp->vc_y += logo_lines;
+ conp->vc_pos += logo_lines * conp->vc_size_row;
+ }
+ scr_memsetw((unsigned short *)conp->vc_origin, conp->vc_video_erase_char,
+ conp->vc_size_row * logo_lines);
+ }
+
+ old_cols = conp->vc_cols;
+ old_rows = conp->vc_rows;
+
nr_cols = p->var.xres/p->fontwidth;
nr_rows = p->var.yres/p->fontheight;
/*
@@ -423,13 +460,18 @@
}
p->dispsw->setup(p);
- if (setcol) {
- p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
- p->bgcol = 0;
- }
+ p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
+ p->bgcol = 0;
- if (!init)
+ if (!init) {
vc_resize_con(nr_rows, nr_cols, con);
+ if (con == fg_console &&
+ old_rows == nr_rows && old_cols == nr_cols)
+ update_screen(con); /* So that we set origin correctly */
+ }
+
+ if (logo)
+ fbcon_show_logo(); /* This is protected above by initmem_freed */
}
@@ -463,7 +505,7 @@
int rows = p->vrows;
ypos += p->yscroll;
- return(ypos < rows ? ypos : ypos-rows);
+ return ypos < rows ? ypos : ypos-rows;
}
@@ -511,7 +553,7 @@
}
-static void fbcon_putcs(struct vc_data *conp, const char *s, int count,
+static void fbcon_putcs(struct vc_data *conp, const unsigned short *s, int count,
int ypos, int xpos)
{
int unit = conp->vc_num;
@@ -545,18 +587,21 @@
(mode == CM_ERASE) == !cursor_on)
return;
- if (CURSOR_UNDRAWN ())
+ cursor_on = 0;
+ if (cursor_drawn)
p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
+
p->cursor_x = conp->vc_x;
p->cursor_y = conp->vc_y;
switch (mode) {
case CM_ERASE:
- cursor_on = 0;
- break;
-
+ cursor_drawn = 0;
+ break;
case CM_MOVE:
case CM_DRAW:
+ if (cursor_drawn)
+ p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
cursor_on = 1;
break;
@@ -568,33 +613,29 @@
static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp)
{
struct display *p;
+ static int _vbl_cursor_cnt = 1, _vbl_cursor_drawn;
- if (!cursor_on)
- return;
+ if (!--_vbl_cursor_cnt) {
+ _vbl_cursor_cnt = cursor_blink_rate;
+ _vbl_cursor_drawn = !_vbl_cursor_drawn;
+ }
- if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
- /* Here no check is possible for console changing. The console
- * switching code should set vbl_cursor_cnt to an appropriate value.
- */
- p = &fb_display[fg_console];
- p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
- cursor_drawn ^= 1;
- vbl_cursor_cnt = cursor_blink_rate;
+ if (cursor_on && vbl_cursor_cnt) {
+ if (cursor_drawn != _vbl_cursor_drawn) {
+ p = &fb_display[fg_console];
+ p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
+ }
+ cursor_drawn = _vbl_cursor_drawn;
}
}
#endif
-#if SUPPORT_SCROLLBACK
+static int scrollback_phys_max = 0;
static int scrollback_max = 0;
static int scrollback_current = 0;
-#endif
-#if SUPPORT_SCROLLBACK
static __inline__ void ywrap_up(int unit, struct vc_data *conp,
struct display *p, int count)
-#else
-static __inline__ void ywrap_up(int unit, struct display *p, int count)
-#endif
{
p->yscroll += count;
if (p->yscroll >= p->vrows) /* Deal with wrap */
@@ -603,21 +644,15 @@
p->var.yoffset = p->yscroll*p->fontheight;
p->var.vmode |= FB_VMODE_YWRAP;
p->fb_info->updatevar(unit, p->fb_info);
-#if SUPPORT_SCROLLBACK
scrollback_max += count;
- if (scrollback_max > p->vrows-conp->vc_rows)
- scrollback_max = p->vrows-conp->vc_rows;
+ if (scrollback_max > scrollback_phys_max)
+ scrollback_max = scrollback_phys_max;
scrollback_current = 0;
-#endif
}
-#if SUPPORT_SCROLLBACK
static __inline__ void ywrap_down(int unit, struct vc_data *conp,
struct display *p, int count)
-#else
-static __inline__ void ywrap_down(int unit, struct display *p, int count)
-#endif
{
p->yscroll -= count;
if (p->yscroll < 0) /* Deal with wrap */
@@ -626,12 +661,10 @@
p->var.yoffset = p->yscroll*p->fontheight;
p->var.vmode |= FB_VMODE_YWRAP;
p->fb_info->updatevar(unit, p->fb_info);
-#if SUPPORT_SCROLLBACK
scrollback_max -= count;
if (scrollback_max < 0)
scrollback_max = 0;
scrollback_current = 0;
-#endif
}
@@ -639,15 +672,19 @@
struct display *p, int count)
{
p->yscroll += count;
- if (p->yscroll+conp->vc_rows > p->vrows) {
- p->dispsw->bmove(p, p->yscroll, 0, 0, 0, conp->vc_rows-count,
- conp->vc_cols);
- p->yscroll = 0;
+ if (p->yscroll > p->vrows-conp->vc_rows) {
+ p->dispsw->bmove(p, p->vrows-conp->vc_rows, 0, 0, 0,
+ conp->vc_rows, conp->vc_cols);
+ p->yscroll -= p->vrows-conp->vc_rows;
}
p->var.xoffset = 0;
p->var.yoffset = p->yscroll*p->fontheight;
p->var.vmode &= ~FB_VMODE_YWRAP;
p->fb_info->updatevar(unit, p->fb_info);
+ scrollback_max += count;
+ if (scrollback_max > scrollback_phys_max)
+ scrollback_max = scrollback_phys_max;
+ scrollback_current = 0;
}
@@ -656,34 +693,92 @@
{
p->yscroll -= count;
if (p->yscroll < 0) {
- p->dispsw->bmove(p, p->yscroll + count, 0,
- p->vrows - conp->vc_rows + count, 0,
- conp->vc_rows - count, conp->vc_cols);
- p->yscroll = p->vrows - conp->vc_rows;
+ p->dispsw->bmove(p, 0, 0, p->vrows-conp->vc_rows, 0,
+ conp->vc_rows, conp->vc_cols);
+ p->yscroll += p->vrows-conp->vc_rows;
}
p->var.xoffset = 0;
p->var.yoffset = p->yscroll*p->fontheight;
p->var.vmode &= ~FB_VMODE_YWRAP;
p->fb_info->updatevar(unit, p->fb_info);
+ scrollback_max -= count;
+ if (scrollback_max < 0)
+ scrollback_max = 0;
+ scrollback_current = 0;
+}
+
+
+static void fbcon_redraw(struct vc_data *conp, struct display *p,
+ int line, int count, int offset)
+{
+ unsigned short *d = (unsigned short *)
+ (conp->vc_origin + conp->vc_size_row * line);
+ unsigned short *s = d + offset;
+ while (count--) {
+ unsigned short *start = s;
+ unsigned short *le = (unsigned short *)
+ ((unsigned long)s + conp->vc_size_row);
+ unsigned short c;
+ int x = 0;
+ unsigned short attr = 1;
+
+ do {
+ c = scr_readw(s);
+ if (attr != (c & 0xff00)) {
+ attr = c & 0xff00;
+ if (s > start) {
+ p->dispsw->putcs(conp, p, start, s - start, line, x);
+ x += s - start;
+ start = s;
+ }
+ }
+ if (c == scr_readw(d)) {
+ if (s > start) {
+ p->dispsw->putcs(conp, p, start, s - start, line, x);
+ x += s - start + 1;
+ start = s + 1;
+ } else {
+ x++;
+ start++;
+ }
+ }
+ scr_writew(c, d);
+ s++;
+ d++;
+ } while (s < le);
+ if (s > start)
+ p->dispsw->putcs(conp, p, start, s - start, line, x);
+ if (offset > 0)
+ line++;
+ else {
+ line--;
+ /* NOTE: We subtract two lines from these pointers */
+ s -= conp->vc_size_row;
+ d -= conp->vc_size_row;
+ }
+ }
}
-static void fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
- int count)
+static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
+ int count)
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
+ int is_txt = (p->type == FB_TYPE_TEXT);
if (!p->can_soft_blank && console_blanked)
- return;
+ return 0;
if (!count)
- return;
+ return 0;
fbcon_cursor(conp, CM_ERASE);
/*
* ++Geert: Only use ywrap/ypan if the console is in text mode
+ * ++Andrew: Only use ypan on hardware text mode when scrolling the
+ * whole screen (prevents flicker).
*/
switch (dir) {
@@ -697,11 +792,7 @@
if (t > 0)
fbcon_bmove(conp, 0, 0, count, 0, t,
conp->vc_cols);
-#if SUPPORT_SCROLLBACK
ywrap_up(unit, conp, p, count);
-#else
- ywrap_up(unit, p, count);
-#endif
if (conp->vc_rows-b > 0)
fbcon_bmove(conp, b-count, 0, b, 0,
conp->vc_rows-b, conp->vc_cols);
@@ -712,7 +803,8 @@
break;
case SCROLL_YPAN:
- if (b-t-count > 3*conp->vc_rows>>2) {
+ if (( is_txt && (b-t == conp->vc_rows)) ||
+ (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) {
if (t > 0)
fbcon_bmove(conp, 0, 0, count, 0, t,
conp->vc_cols);
@@ -732,6 +824,15 @@
p->dispsw->clear(conp, p, b-count, 0, count,
conp->vc_cols);
break;
+ case SCROLL_YREDRAW:
+ fbcon_redraw(conp, p, t, b-t-count, count*conp->vc_cols);
+ p->dispsw->clear(conp, p, b-count, 0, count,
+ conp->vc_cols);
+ scr_memsetw((unsigned short *)(conp->vc_origin +
+ conp->vc_size_row * (b-count)),
+ conp->vc_video_erase_char,
+ conp->vc_size_row * count);
+ return 1;
}
else {
fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols);
@@ -749,11 +850,7 @@
if (conp->vc_rows-b > 0)
fbcon_bmove(conp, b, 0, b-count, 0,
conp->vc_rows-b, conp->vc_cols);
-#if SUPPORT_SCROLLBACK
ywrap_down(unit, conp, p, count);
-#else
- ywrap_down(unit, p, count);
-#endif
if (t > 0)
fbcon_bmove(conp, count, 0, 0, 0, t,
conp->vc_cols);
@@ -764,7 +861,8 @@
break;
case SCROLL_YPAN:
- if (b-t-count > 3*conp->vc_rows>>2) {
+ if (( is_txt && (b-t == conp->vc_rows)) ||
+ (!is_txt && (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);
@@ -783,6 +881,15 @@
conp->vc_cols);
p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols);
break;
+
+ case SCROLL_YREDRAW:
+ fbcon_redraw(conp, p, b - 1, b-t-count, -count*conp->vc_cols);
+ p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols);
+ scr_memsetw((unsigned short *)(conp->vc_origin +
+ conp->vc_size_row * t),
+ conp->vc_video_erase_char,
+ conp->vc_size_row * count);
+ return 1;
}
else {
/*
@@ -806,6 +913,7 @@
fbcon_clear(conp, 0, t, conp->vc_rows, count);
break;
}
+ return 0;
}
@@ -876,13 +984,26 @@
struct display *p = &fb_display[unit];
struct fb_info *info = p->fb_info;
- if (info && info->switch_con)
- (*info->switch_con)(conp->vc_num, info);
-#if SUPPORT_SCROLLBACK
+ p->var.yoffset = p->yscroll*p->fontheight;
+ switch (p->scrollmode) {
+ case SCROLL_YWRAP:
+ scrollback_phys_max = p->vrows-conp->vc_rows;
+ break;
+ case SCROLL_YPAN:
+ scrollback_phys_max = p->vrows-2*conp->vc_rows;
+ if (scrollback_phys_max < 0)
+ scrollback_phys_max = 0;
+ break;
+ default:
+ scrollback_phys_max = 0;
+ break;
+ }
scrollback_max = 0;
scrollback_current = 0;
-#endif
- return(0);
+
+ if (info && info->switch_con)
+ (*info->switch_con)(conp->vc_num, info);
+ return 1;
}
@@ -896,28 +1017,28 @@
if (!p->can_soft_blank) {
if (blank) {
#ifdef CONFIG_MAC
- if (MACH_IS_MAC)
- mymemset(p->screen_base,
- p->var.xres_virtual*p->var.yres_virtual*
- p->var.bits_per_pixel>>3);
- else
-#endif
- if (p->visual == FB_VISUAL_MONO01)
- mymemset(p->screen_base,
- p->var.xres_virtual*p->var.yres_virtual*
- p->var.bits_per_pixel>>3);
- else
- mymemclear(p->screen_base,
- p->var.xres_virtual*p->var.yres_virtual*
- p->var.bits_per_pixel>>3);
- return(0);
+ if (MACH_IS_MAC) {
+ if (p->screen_base)
+ mymemset(p->screen_base,
+ p->var.xres_virtual*p->var.yres_virtual*
+ p->var.bits_per_pixel>>3);
+ } else
+#endif
+ if (p->visual == FB_VISUAL_MONO01) {
+ if (p->screen_base)
+ mymemset(p->screen_base,
+ p->var.xres_virtual*p->var.yres_virtual*
+ p->var.bits_per_pixel>>3);
+ } else
+ p->dispsw->clear(p->conp, p, 0, 0, p->conp->vc_rows, p->conp->vc_cols);
+ return 0;
} else {
/* Tell console.c that it has to restore the screen itself */
- return(1);
+ return 1;
}
}
(*info->blank)(blank, info);
- return(0);
+ return 0;
}
@@ -934,12 +1055,12 @@
if (alloc < size)
/* allocation length not sufficient */
- return( -ENAMETOOLONG );
+ return -ENAMETOOLONG;
for (i = 0; i < 256; i++)
for (j = 0; j < p->fontheight; j++)
data[i*32+j] = p->fontdata[i*p->fontheight+j];
- return( 0 );
+ return 0;
}
@@ -967,19 +1088,19 @@
name[sizeof(name)-1] = 0;
if (!findsoftfont( name, &w, &h, (u8 **)&data ))
- return( -ENOENT );
+ return -ENOENT;
userspace = 0;
} else if (w == 1) {
/* copy font from some other console in 'h'*/
struct display *op;
if (h < 0 || !vc_cons_allocated( h ))
- return( -ENOTTY );
+ return -ENOTTY;
if (h == unit)
- return( 0 ); /* nothing to do */
+ return 0; /* nothing to do */
op = &fb_display[h];
if (op->fontdata == p->fontdata)
- return( 0 ); /* already the same font... */
+ return 0; /* already the same font... */
resize = (op->fontwidth != p->fontwidth) ||
(op->fontheight != p->fontheight);
@@ -995,7 +1116,7 @@
if (w != 8)
/* Currently only fontwidth == 8 supported */
- return( -ENXIO );
+ return -ENXIO;
resize = (w != p->fontwidth) || (h != p->fontheight);
size = (w+7)/8 * h * 256;
@@ -1005,7 +1126,7 @@
if (userspace) {
if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER )))
- return( -ENOMEM );
+ return -ENOMEM;
new_data += sizeof(int);
REFCOUNT(new_data) = 1; /* usage counter */
@@ -1037,7 +1158,7 @@
if (old_data && (--REFCOUNT(old_data) == 0))
kfree( old_data - sizeof(int) );
- return( 0 );
+ return 0;
}
static u16 palette_red[16];
@@ -1056,7 +1177,7 @@
u8 val;
if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked))
- return(-EINVAL);
+ return -EINVAL;
for (i = j = 0; i < 16; i++) {
k = table[i];
val = conp->vc_palette[j++];
@@ -1075,43 +1196,52 @@
static int fbcon_scrolldelta(struct vc_data *conp, int lines)
{
-#if SUPPORT_SCROLLBACK
- int unit = fg_console; /* xxx */
- struct display *p = &fb_display[unit];
- int offset;
+ int unit, offset, limit, scrollback_old;
+ struct display *p;
- if (!p->can_soft_blank && console_blanked ||
- vt_cons[unit]->vc_mode != KD_TEXT || !lines ||
- p->scrollmode != SCROLL_YWRAP)
- return 0;
+ /* FIXME: Sync to new code, remember to set visible_origin */
- fbcon_cursor(conp, CM_ERASE);
+ if (!scrollback_phys_max)
+ return -ENOSYS;
+ scrollback_old = scrollback_current;
scrollback_current -= lines;
if (scrollback_current < 0)
scrollback_current = 0;
else if (scrollback_current > scrollback_max)
scrollback_current = scrollback_max;
+ if (scrollback_current == scrollback_old)
+ return 0;
+
+ unit = fg_console;
+ p = &fb_display[unit];
+ if (!p->can_soft_blank &&
+ (console_blanked || vt_cons[unit]->vc_mode != KD_TEXT || !lines))
+ return 0;
+ fbcon_cursor(conp, CM_ERASE);
offset = p->yscroll-scrollback_current;
+ limit = p->vrows;
+ switch (p->scrollmode) {
+ case SCROLL_YWRAP:
+ p->var.vmode |= FB_VMODE_YWRAP;
+ break;
+ case SCROLL_YPAN:
+ limit -= conp->vc_rows;
+ p->var.vmode &= ~FB_VMODE_YWRAP;
+ break;
+ }
if (offset < 0)
- offset += p->vrows;
- else if (offset > p->vrows)
- offset -= p->vrows;
- p->var.vmode |= FB_VMODE_YWRAP;
+ offset += limit;
+ else if (offset >= limit)
+ offset -= limit;
p->var.xoffset = 0;
p->var.yoffset = offset*p->fontheight;
p->fb_info->updatevar(unit, p->fb_info);
-#else
- return -ENOSYS;
-#endif
+ return 0;
}
-#define LOGO_H 80
-#define LOGO_W 80
-#define LOGO_LINE (LOGO_W/8)
-
__initfunc(static int fbcon_show_logo( void ))
{
struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
@@ -1120,9 +1250,13 @@
unsigned char *fb = p->screen_base;
unsigned char *logo;
unsigned char *dst, *src;
- int i, j, n, x1, y1;
+ int i, j, n, x1, y1, x;
int logo_depth, done = 0;
+ /* Return if the frame buffer is not mapped */
+ if (!fb)
+ return 0;
+
/* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
* TRUECOLOR */
if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) ||
@@ -1182,216 +1316,214 @@
logo_depth = 1;
}
+ for (x = 0; x < smp_num_cpus * (LOGO_W + 8) &&
+ x < p->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) {
+
#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
- defined(CONFIG_FBCON_CFB32)
- if (p->visual == FB_VISUAL_TRUECOLOR) {
- unsigned int val; /* max. depth 32! */
- int bdepth;
- int redshift, greenshift, blueshift;
+ defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
+ if (p->visual == FB_VISUAL_TRUECOLOR) {
+ unsigned int val; /* max. depth 32! */
+ int bdepth;
+ int redshift, greenshift, blueshift;
- /* Bug: Doesn't obey msb_right ... (who needs that?) */
- redshift = p->var.red.offset;
- greenshift = p->var.green.offset;
- blueshift = p->var.blue.offset;
-
- if (depth >= 24 && (depth % 8) == 0) {
- /* have at least 8 bits per color */
- src = logo;
- bdepth = depth/8;
- for( y1 = 0; y1 < LOGO_H; y1++ ) {
- dst = fb + y1*line;
- for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
- val = (*src << redshift) |
- (*src << greenshift) |
- (*src << blueshift);
+ /* Bug: Doesn't obey msb_right ... (who needs that?) */
+ redshift = p->var.red.offset;
+ greenshift = p->var.green.offset;
+ blueshift = p->var.blue.offset;
+
+ if (depth >= 24 && (depth % 8) == 0) {
+ /* have at least 8 bits per color */
+ src = logo;
+ bdepth = depth/8;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+ dst = fb + y1*line + x*bdepth;
+ for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
+ val = (*src << redshift) |
+ (*src << greenshift) |
+ (*src << blueshift);
#ifdef __LITTLE_ENDIAN
- for( i = 0; i < bdepth; ++i )
+ for( i = 0; i < bdepth; ++i )
#else
- for( i = bdepth-1; i >= 0; --i )
+ for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ *dst++ = val >> (i*8);
+ }
}
}
- }
- else if (depth >= 15 && depth <= 23) {
- /* have 5..7 bits per color, using 16 color image */
- unsigned int pix;
- src = linux_logo16;
- bdepth = (depth+7)/8;
- for( y1 = 0; y1 < LOGO_H; y1++ ) {
- dst = fb + y1*line;
- for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
- pix = (*src >> 4) | 0x10; /* upper nibble */
- val = (pix << redshift) |
- (pix << greenshift) |
- (pix << blueshift);
- for( i = 0; i < bdepth; ++i )
- *dst++ = val >> (i*8);
- pix = (*src & 0x0f) | 0x10; /* lower nibble */
- val = (pix << redshift) |
- (pix << greenshift) |
- (pix << blueshift);
- for( i = bdepth-1; i >= 0; --i )
- *dst++ = val >> (i*8);
+ else if (depth >= 15 && depth <= 23) {
+ /* have 5..7 bits per color, using 16 color image */
+ unsigned int pix;
+ src = linux_logo16;
+ bdepth = (depth+7)/8;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+ dst = fb + y1*line + x*bdepth;
+ for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
+ pix = (*src >> 4) | 0x10; /* upper nibble */
+ val = (pix << redshift) |
+ (pix << greenshift) |
+ (pix << blueshift);
+ for( i = 0; i < bdepth; ++i )
+ *dst++ = val >> (i*8);
+ pix = (*src & 0x0f) | 0x10; /* lower nibble */
+ val = (pix << redshift) |
+ (pix << greenshift) |
+ (pix << blueshift);
+ for( i = bdepth-1; i >= 0; --i )
+ *dst++ = val >> (i*8);
+ }
}
}
- }
-
- done = 1;
- }
+ done = 1;
+ }
#endif
#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
- defined(CONFIG_FBCON_CFB32)
- if ((depth % 8 == 0) && (p->visual == FB_VISUAL_DIRECTCOLOR)) {
- /* Modes without color mapping, needs special data transformation... */
- unsigned int val; /* max. depth 32! */
- int bdepth = depth/8;
- unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
- unsigned char redmask, greenmask, bluemask;
- int redshift, greenshift, blueshift;
+ defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
+ if ((depth % 8 == 0) && (p->visual == FB_VISUAL_DIRECTCOLOR)) {
+ /* Modes without color mapping, needs special data transformation... */
+ unsigned int val; /* max. depth 32! */
+ int bdepth = depth/8;
+ unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
+ unsigned char redmask, greenmask, bluemask;
+ int redshift, greenshift, blueshift;
- /* Bug: Doesn't obey msb_right ... (who needs that?) */
- redmask = mask[p->var.red.length < 8 ? p->var.red.length : 8];
- greenmask = mask[p->var.green.length < 8 ? p->var.green.length : 8];
- bluemask = mask[p->var.blue.length < 8 ? p->var.blue.length : 8];
- redshift = p->var.red.offset - (8-p->var.red.length);
- greenshift = p->var.green.offset - (8-p->var.green.length);
- blueshift = p->var.blue.offset - (8-p->var.blue.length);
-
- src = logo;
- for( y1 = 0; y1 < LOGO_H; y1++ ) {
- dst = fb + y1*line;
- for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
- val = ((linux_logo_red[*src-32] & redmask) << redshift) |
- ((linux_logo_green[*src-32] & greenmask) << greenshift) |
- ((linux_logo_blue[*src-32] & bluemask) << blueshift);
+ /* Bug: Doesn't obey msb_right ... (who needs that?) */
+ redmask = mask[p->var.red.length < 8 ? p->var.red.length : 8];
+ greenmask = mask[p->var.green.length < 8 ? p->var.green.length : 8];
+ bluemask = mask[p->var.blue.length < 8 ? p->var.blue.length : 8];
+ redshift = p->var.red.offset - (8-p->var.red.length);
+ greenshift = p->var.green.offset - (8-p->var.green.length);
+ blueshift = p->var.blue.offset - (8-p->var.blue.length);
+
+ src = logo;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+ dst = fb + y1*line + x*bdepth;
+ for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
+ val = ((linux_logo_red[*src-32] & redmask) << redshift) |
+ ((linux_logo_green[*src-32] & greenmask) << greenshift) |
+ ((linux_logo_blue[*src-32] & bluemask) << blueshift);
#ifdef __LITTLE_ENDIAN
- for( i = 0; i < bdepth; ++i )
+ for( i = 0; i < bdepth; ++i )
#else
- for( i = bdepth-1; i >= 0; --i )
+ for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ *dst++ = val >> (i*8);
+ }
}
+ done = 1;
}
-
- done = 1;
- }
#endif
-#if defined(CONFIG_FBCON_CFB8)
- if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
- /* depth 8 or more, packed, with color registers */
+#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 */
- src = logo;
- for( y1 = 0; y1 < LOGO_H; y1++ ) {
- dst = fb + y1*line;
- for( x1 = 0; x1 < LOGO_W; x1++ ) {
- *dst++ = *src++;
+ src = logo;
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+ dst = fb + y1*line + x;
+ for( x1 = 0; x1 < LOGO_W; x1++ )
+ *dst++ = *src++;
}
+ done = 1;
}
-
- done = 1;
- }
#endif
#if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
defined(CONFIG_FBCON_IPLAN2P8)
- if (depth >= 2 && (p->type == FB_TYPE_PLANES ||
- p->type == FB_TYPE_INTERLEAVED_PLANES)) {
- /* planes (normal or interleaved), with color registers */
- int bit;
- unsigned char val, mask;
- int plane = p->next_plane;
+ if (depth >= 2 && (p->type == FB_TYPE_PLANES ||
+ p->type == FB_TYPE_INTERLEAVED_PLANES)) {
+ /* planes (normal or interleaved), with color registers */
+ int bit;
+ unsigned char val, mask;
+ int plane = p->next_plane;
- /* for support of Atari interleaved planes */
+ /* for support of Atari interleaved planes */
#define MAP_X(x) (plane > line ? x : (x & ~1)*depth + (x & 1))
- /* extract a bit from the source image */
+ /* extract a bit from the source image */
#define BIT(p,pix,bit) (p[pix*logo_depth/8] & \
(1 << ((8-((pix*logo_depth)&7)-logo_depth) + bit)))
- 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);
- for( bit = 0; bit < logo_depth; bit++ ) {
- val = 0;
- for( mask = 0x80, i = 0; i < 8; mask >>= 1, i++ ) {
- if (BIT( src, i, bit ))
- val |= mask;
+ 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);
+ for( bit = 0; bit < logo_depth; bit++ ) {
+ val = 0;
+ for( mask = 0x80, i = 0; i < 8; mask >>= 1, i++ ) {
+ if (BIT( src, i, bit ))
+ val |= mask;
+ }
+ *dst = val;
+ dst += plane;
}
- *dst = val;
- dst += plane;
}
}
- }
- /* fill remaining planes
- * special case for logo_depth == 4: we used color registers 16..31,
- * so fill plane 4 with 1 bits instead of 0 */
- 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;
- for( i = logo_depth; i < depth; i++, dst += plane )
- *dst = (i == logo_depth && logo_depth == 4)
- ? 0xff : 0x00;
+ /* fill remaining planes
+ * special case for logo_depth == 4: we used color registers 16..31,
+ * so fill plane 4 with 1 bits instead of 0 */
+ 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;
+ for( i = logo_depth; i < depth; i++, dst += plane )
+ *dst = (i == logo_depth && logo_depth == 4)
+ ? 0xff : 0x00;
+ }
}
}
+ done = 1;
+ break;
}
-
- done = 1;
- }
#endif
#if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \
defined(CONFIG_FBCON_ILBM)
- if (depth == 1 && (p->type == FB_TYPE_PACKED_PIXELS ||
- p->type == FB_TYPE_PLANES ||
- p->type == FB_TYPE_INTERLEAVED_PLANES)) {
- /* monochrome */
- unsigned char inverse = p->inverse ? 0x00 : 0xff;
-
- /* can't use simply memcpy because need to apply inverse */
- for( y1 = 0; y1 < LOGO_H; y1++ ) {
- src = logo + y1*LOGO_LINE;
- dst = fb + y1*line;
- for( x1 = 0; x1 < LOGO_LINE; ++x1 )
- *dst++ = *src++ ^ inverse;
- }
-
- done = 1;
- }
-#endif
-#ifdef CONFIG_FBCON_VGA
- if (depth == 1 && p->type == FB_TYPE_VGA_TEXT) {
- int height = 0;
- char *p;
-
- printk(linux_mda_image);
+ if (depth == 1 && (p->type == FB_TYPE_PACKED_PIXELS ||
+ p->type == FB_TYPE_PLANES ||
+ p->type == FB_TYPE_INTERLEAVED_PLANES)) {
- for (p = linux_mda_image; *p; p++)
- if (*p == '\n')
- height++;
+ /* monochrome */
+ unsigned char inverse = p->inverse ? 0x00 : 0xff;
- return height;
- }
+ /* can't use simply memcpy because need to apply inverse */
+ for( y1 = 0; y1 < LOGO_H; y1++ ) {
+ src = logo + y1*LOGO_LINE + x/8;
+ dst = fb + y1*line;
+ for( x1 = 0; x1 < LOGO_LINE; ++x1 )
+ *dst++ = *src++ ^ inverse;
+ }
+ done = 1;
+ }
#endif
+ }
+
/* Modes not yet supported: packed pixels with depth != 8 (does such a
* thing exist in reality?) */
- return( done ? LOGO_H/p->fontheight + 1 : 0 );
+ return done ? (LOGO_H + p->fontheight - 1) / p->fontheight : 0 ;
}
-
-
/*
* The console `switch' structure for the frame buffer based console
*/
-
+
struct consw fb_con = {
- fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
- fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
- fbcon_blank, fbcon_get_font, fbcon_set_font, fbcon_set_palette,
- fbcon_scrolldelta
+ con_startup: fbcon_startup,
+ con_init: fbcon_init,
+ con_deinit: fbcon_deinit,
+ con_clear: fbcon_clear,
+ con_putc: fbcon_putc,
+ con_putcs: fbcon_putcs,
+ con_cursor: fbcon_cursor,
+ con_scroll: fbcon_scroll,
+ con_bmove: fbcon_bmove,
+ con_switch: fbcon_switch,
+ con_blank: fbcon_blank,
+ con_get_font: fbcon_get_font,
+ con_set_font: fbcon_set_font,
+ con_set_palette: fbcon_set_palette,
+ con_scrolldelta: fbcon_scrolldelta,
+ con_set_origin: NULL,
+ con_save_screen: NULL,
};
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov