patch-2.1.110 linux/drivers/video/fbcon.c
Next file: linux/drivers/video/fbcon.h
Previous file: linux/drivers/video/fbcon-vga.c
Back to the patch index
Back to the overall index
- Lines: 451
- Date:
Sat Jul 18 13:55:46 1998
- Orig file:
v2.1.109/linux/drivers/video/fbcon.c
- Orig date:
Thu Jul 16 18:09:27 1998
diff -u --recursive --new-file v2.1.109/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
@@ -25,7 +25,8 @@
* Andreas Schwab
*
* Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
- * Smart redraw scrolling added by Jakub Jelinek (jj@ultra.linux.cz)
+ * Smart redraw scrolling, arbitrary font width support added by
+ * Jakub Jelinek (jj@ultra.linux.cz)
*
*
* The low level operations for the various display memory organizations are
@@ -132,13 +133,10 @@
static int cursor_on = 0;
static int cursor_blink_rate;
-static __inline__ int CURSOR_UNDRAWN(void)
+static __inline__ void CURSOR_UNDRAWN(void)
{
- int cursor_was_drawn;
vbl_cursor_cnt = 0;
- cursor_was_drawn = cursor_drawn;
cursor_drawn = 0;
- return cursor_was_drawn;
}
#endif
@@ -168,7 +166,7 @@
static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
int height, int width);
static int fbcon_switch(struct vc_data *conp);
-static int fbcon_blank(int blank);
+static int fbcon_blank(struct vc_data *conp, int blank);
static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data);
static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
@@ -330,6 +328,9 @@
info = registered_fb[(int)con2fb_map[unit]];
info->changevar = &fbcon_changevar;
+ conp->vc_display_fg = &info->display_fg;
+ if (!info->display_fg)
+ info->display_fg = conp;
fb_display[unit] = *(info->disp); /* copy from default */
DPRINTK("mode: %s\n",info->modename);
DPRINTK("visual: %d\n",fb_display[unit].visual);
@@ -374,6 +375,20 @@
p->scrollmode = SCROLL_YMOVE;
}
+static void fbcon_font_widths(struct display *p)
+{
+ int i;
+ p->fontwidthlog = 0;
+ for (i = 2; i <= 6; i++)
+ if (p->fontwidth == (1 << i))
+ p->fontwidthlog = i;
+ p->fontheightlog = 0;
+ for (i = 2; i <= 6; i++)
+ if (p->fontheight == (1 << i))
+ p->fontheightlog = i;
+}
+
+#define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))
static void fbcon_setup(int con, int init, int logo)
{
@@ -381,6 +396,8 @@
struct vc_data *conp = p->conp;
int nr_rows, nr_cols;
int old_rows, old_cols;
+ unsigned short *save = NULL, *r, *q;
+ int logo_lines = 0;
/* Only if not module */
extern int initmem_freed;
@@ -391,10 +408,12 @@
if (!p->fb_info->fontname[0] ||
!findsoftfont(p->fb_info->fontname, &p->fontwidth, &p->fontheight,
- &p->fontdata) || p->fontwidth != 8)
+ &p->fontdata) || !fontwidthvalid(p,p->fontwidth))
getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth,
&p->fontheight, &p->fontdata);
- if (p->fontwidth != 8) {
+
+ fbcon_font_widths(p);
+ if (!fontwidthvalid(p,p->fontwidth)) {
#ifdef CONFIG_MAC
if (MACH_IS_MAC)
/* ++Geert: hack to make 6x11 fonts work on mac */
@@ -403,44 +422,58 @@
#endif
{
/* ++Geert: changed from panic() to `correct and continue' */
- printk(KERN_ERR "fbcon_setup: No support for fontwidth != 8");
+ printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", p->fontwidth);
p->dispsw = &fbcon_dummy;
}
}
+ if (p->dispsw->set_font)
+ p->dispsw->set_font(p, p->fontwidth, p->fontheight);
updatescrollmode(p);
+ old_cols = conp->vc_cols;
+ old_rows = conp->vc_rows;
+
+ nr_cols = p->var.xres/p->fontwidth;
+ nr_rows = p->var.yres/p->fontheight;
+
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;
+ int cnt;
+ int step;
- for (r = q - logo_lines * conp->vc_cols; r < q; r++)
+ logo_lines = (LOGO_H + p->fontheight - 1) / p->fontheight;
+ q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
+ step = logo_lines * old_cols;
+ for (r = q - logo_lines * old_cols; r < q; r++)
if (*r != conp->vc_video_erase_char)
break;
+ if (r != q && nr_rows >= old_rows + logo_lines) {
+ save = kmalloc(logo_lines * nr_cols * 2, GFP_KERNEL);
+ if (save) {
+ int i = old_cols < nr_cols ? old_cols : nr_cols;
+ scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2);
+ r = q - step;
+ for (cnt = 0; cnt < logo_lines; cnt++, r += i)
+ scr_memcpyw(save + cnt * nr_cols, r, 2 * i);
+ r = q;
+ }
+ }
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--) {
+ r = q - step - old_cols;
+ for (cnt = old_rows - logo_lines; cnt > 0; cnt--) {
scr_memcpyw(r + step, r, conp->vc_size_row);
- r -= conp->vc_cols;
+ r -= old_cols;
+ }
+ if (!save) {
+ conp->vc_y += logo_lines;
+ conp->vc_pos += logo_lines * conp->vc_size_row;
}
- 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;
/*
* ++guenther: console.c:vc_allocate() relies on initializing
* vc_{cols,rows}, but we must not set those if we are only
@@ -465,8 +498,14 @@
if (!init) {
vc_resize_con(nr_rows, nr_cols, con);
- if (con == fg_console &&
- old_rows == nr_rows && old_cols == nr_cols)
+ if (save) {
+ q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
+ scr_memcpyw(q, save, logo_lines * nr_cols * 2);
+ conp->vc_y += logo_lines;
+ conp->vc_pos += logo_lines * conp->vc_size_row;
+ kfree(save);
+ }
+ if (con == fg_console)
update_screen(con); /* So that we set origin correctly */
}
@@ -515,6 +554,7 @@
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
u_int y_break;
+ int redraw_cursor = 0;
if (!p->can_soft_blank && console_blanked)
return;
@@ -523,8 +563,10 @@
return;
if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
- (sx <= p->cursor_x) && (p->cursor_x < sx+width))
+ (sx <= p->cursor_x) && (p->cursor_x < sx+width)) {
CURSOR_UNDRAWN();
+ redraw_cursor = 1;
+ }
/* Split blits that cross physical y_wrap boundary */
@@ -535,6 +577,9 @@
p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width);
} else
p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width);
+
+ if (redraw_cursor)
+ vbl_cursor_cnt = CURSOR_DRAW_DELAY;
}
@@ -542,14 +587,20 @@
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
+ int redraw_cursor = 0;
if (!p->can_soft_blank && console_blanked)
return;
- if ((p->cursor_x == xpos) && (p->cursor_y == ypos))
+ if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
CURSOR_UNDRAWN();
+ redraw_cursor = 1;
+ }
p->dispsw->putc(conp, p, c, real_y(p, ypos), xpos);
+
+ if (redraw_cursor)
+ vbl_cursor_cnt = CURSOR_DRAW_DELAY;
}
@@ -558,14 +609,19 @@
{
int unit = conp->vc_num;
struct display *p = &fb_display[unit];
+ int redraw_cursor = 0;
if (!p->can_soft_blank && console_blanked)
return;
if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
- (p->cursor_x < (xpos + count)))
+ (p->cursor_x < (xpos + count))) {
CURSOR_UNDRAWN();
+ redraw_cursor = 1;
+ }
p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos);
+ if (redraw_cursor)
+ vbl_cursor_cnt = CURSOR_DRAW_DELAY;
}
@@ -613,19 +669,16 @@
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 (!--_vbl_cursor_cnt) {
- _vbl_cursor_cnt = cursor_blink_rate;
- _vbl_cursor_drawn = !_vbl_cursor_drawn;
- }
+ if (!cursor_on)
+ return;
- 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;
+ if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
+ p = &fb_display[fg_console];
+ if (p->dispsw->revc)
+ p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
+ cursor_drawn ^= 1;
+ vbl_cursor_cnt = cursor_blink_rate;
}
}
#endif
@@ -759,6 +812,53 @@
}
}
+/* This cannot be used together with ypan or ywrap */
+void fbcon_redraw_bmove(struct display *p, int sy, int sx, int dy, int dx, int h, int w)
+{
+ if (sy != dy)
+ panic("fbcon_redraw_bmove width sy != dy");
+ /* h will be always 1, but it does not matter if we are more generic */
+ while (h-- > 0) {
+ struct vc_data *conp = p->conp;
+ unsigned short *d = (unsigned short *)
+ (conp->vc_origin + conp->vc_size_row * dy + dx * 2);
+ unsigned short *s = d + (dx - sx);
+ unsigned short *start = d;
+ unsigned short *ls = d;
+ unsigned short *le = d + w;
+ unsigned short c;
+ int x = dx;
+ unsigned short attr = 1;
+
+ do {
+ c = scr_readw(d);
+ if (attr != (c & 0xff00)) {
+ attr = c & 0xff00;
+ if (d > start) {
+ p->dispsw->putcs(conp, p, start, d - start, dy, x);
+ x += d - start;
+ start = d;
+ }
+ }
+ if (s >= ls && s < le && c == scr_readw(s)) {
+ if (d > start) {
+ p->dispsw->putcs(conp, p, start, d - start, dy, x);
+ x += d - start + 1;
+ start = d + 1;
+ } else {
+ x++;
+ start++;
+ }
+ }
+ s++;
+ d++;
+ } while (d < le);
+ if (d > start)
+ p->dispsw->putcs(conp, p, start, d - start, dy, x);
+ sy++;
+ dy++;
+ }
+}
static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
int count)
@@ -1007,11 +1107,14 @@
}
-static int fbcon_blank(int blank)
+static int fbcon_blank(struct vc_data *conp, int blank)
{
- struct display *p = &fb_display[fg_console];
+ struct display *p = &fb_display[conp->vc_num];
struct fb_info *info = p->fb_info;
+ if (blank < 0) /* Entering graphics mode */
+ return 0;
+
fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
if (!p->can_soft_blank) {
@@ -1030,7 +1133,7 @@
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);
+ p->dispsw->clear(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 */
@@ -1065,6 +1168,7 @@
#define REFCOUNT(fd) (((int *)(fd))[-1])
+#define FNTSIZE(fd) (((int *)(fd))[-2])
static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
{
@@ -1080,15 +1184,12 @@
if (w == 0) {
/* engage predefined font, name in 'data' */
- char name[MAX_FONT_NAME+1];
-
- if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME )))
- return i;
- copy_from_user( name, data, MAX_FONT_NAME );
- name[sizeof(name)-1] = 0;
+ unsigned short width, height;
+ data[MAX_FONT_NAME] = 0;
- if (!findsoftfont( name, &w, &h, (u8 **)&data ))
+ if (!findsoftfont( data, &width, &height, (u8 **)&data ))
return -ENOENT;
+ w = width; h = height;
userspace = 0;
} else if (w == 1) {
/* copy font from some other console in 'h'*/
@@ -1109,12 +1210,14 @@
p->fontdata = op->fontdata;
w = p->fontwidth = op->fontwidth;
h = p->fontheight = op->fontheight;
+ p->fontwidthlog = op->fontwidthlog;
+ p->fontheightlog = op->fontheightlog;
if ((p->userfont = op->userfont))
REFCOUNT(p->fontdata)++; /* increment usage counter */
goto activate;
}
- if (w != 8)
+ if (!fontwidthvalid(p,w))
/* Currently only fontwidth == 8 supported */
return -ENXIO;
@@ -1125,9 +1228,10 @@
old_data = p->fontdata;
if (userspace) {
- if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER )))
+ if (!(new_data = kmalloc( 2*sizeof(int)+size, GFP_USER )))
return -ENOMEM;
- new_data += sizeof(int);
+ new_data += 2*sizeof(int);
+ FNTSIZE(new_data) = size;
REFCOUNT(new_data) = 1; /* usage counter */
for (i = 0; i < 256; i++)
@@ -1142,13 +1246,17 @@
}
p->fontwidth = w;
p->fontheight = h;
+ fbcon_font_widths(p);
activate:
if (resize) {
/* reset wrap/pan */
p->var.xoffset = p->var.yoffset = p->yscroll = 0;
- /* Adjust the virtual screen-size to fontheight*rows */
- p->var.yres_virtual = (p->var.yres/h)*h;
+ if (!p->dispsw->set_font ||
+ !p->dispsw->set_font(p, p->fontwidth, p->fontheight)) {
+ /* Adjust the virtual screen-size to fontheight*rows */
+ p->var.yres_virtual = (p->var.yres/h)*h;
+ }
p->vrows = p->var.yres_virtual/h;
updatescrollmode(p);
vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
@@ -1156,7 +1264,7 @@
update_screen( unit );
if (old_data && (--REFCOUNT(old_data) == 0))
- kfree( old_data - sizeof(int) );
+ kfree( old_data - 2*sizeof(int) );
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov