2 * linux/drivers/video/fbcon.c -- Low level frame buffer based console driver
4 * Copyright (C) 1995 Geert Uytterhoeven
7 * This file is based on the original Amiga console driver (amicon.c):
9 * Copyright (C) 1993 Hamish Macdonald
11 * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
13 * with work by William Rucklidge (wjr@cs.cornell.edu)
15 * Jes Sorensen (jds@kom.auc.dk)
18 * and on the original Atari console driver (atacon.c):
20 * Copyright (C) 1993 Bjoern Brauel
23 * with work by Guenther Kelleter
27 * Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
28 * Smart redraw scrolling, arbitrary font width support, 512char font support
30 * Jakub Jelinek (jj@ultra.linux.cz)
32 * Random hacking by Martin Mares <mj@ucw.cz>
35 * The low level operations for the various display memory organizations are
36 * now in separate source files.
38 * Currently the following organizations are supported:
40 * o afb Amiga bitplanes
41 * o cfb{2,4,8,16,24,32} Packed pixels
42 * o ilbm Amiga interleaved bitplanes
43 * o iplan2p[248] Atari interleaved bitplanes
45 * o vga VGA characters/attributes
49 * - Implement 16 plane mode (iplan2p16)
52 * This file is subject to the terms and conditions of the GNU General Public
53 * License. See the file COPYING in the main directory of this archive for
59 #include <linux/config.h>
60 #include <linux/module.h>
61 #include <linux/types.h>
62 #include <linux/sched.h>
64 #include <linux/kernel.h>
65 #include <linux/delay.h> /* MSch: for IRQ probe */
66 #include <linux/tty.h>
67 #include <linux/console.h>
68 #include <linux/string.h>
70 #include <linux/malloc.h>
72 #include <linux/vt_kern.h>
73 #include <linux/selection.h>
74 #include <linux/smp.h>
75 #include <linux/init.h>
78 #include <asm/system.h>
79 #include <asm/uaccess.h>
81 #include <asm/amigahw.h>
82 #include <asm/amigaints.h>
83 #endif /* CONFIG_AMIGA */
85 #include <asm/atariints.h>
88 #include <asm/macints.h>
90 #if defined(__mc68000__) || defined(CONFIG_APUS)
91 #include <asm/machdep.h>
92 #include <asm/setup.h>
94 #define INCLUDE_LINUX_LOGO_DATA
95 #include <asm/linux_logo.h>
97 #include <video/fbcon.h>
98 #include <video/fbcon-mac.h> /* for 6x11 font on mac */
99 #include <video/font.h>
102 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
104 # define DPRINTK(fmt, args...)
109 #define LOGO_LINE (LOGO_W/8)
111 struct display fb_display
[MAX_NR_CONSOLES
];
112 static int logo_lines
;
113 static int logo_shown
= -1;
115 #define REFCOUNT(fd) (((int *)(fd))[-1])
116 #define FNTSIZE(fd) (((int *)(fd))[-2])
117 #define FNTCHARCNT(fd) (((int *)(fd))[-3])
118 #define FNTSUM(fd) (((int *)(fd))[-4])
119 #define FONT_EXTRA_WORDS 4
121 static void fbcon_free_font(struct display
*p
);
124 * Emmanuel: fbcon will now use a hardware cursor if the
125 * low-level driver provides a non-NULL dispsw->cursor pointer,
126 * in which case the hardware should do blinking, etc.
128 * if dispsw->cursor is NULL, use Atari alike software cursor
131 static int cursor_drawn
= 0;
133 #define CURSOR_DRAW_DELAY (1)
135 /* # VBL ints between cursor state changes */
136 #define ARM_CURSOR_BLINK_RATE (10)
137 #define AMIGA_CURSOR_BLINK_RATE (20)
138 #define ATARI_CURSOR_BLINK_RATE (42)
139 #define MAC_CURSOR_BLINK_RATE (32)
140 #define DEFAULT_CURSOR_BLINK_RATE (20)
142 static int vbl_cursor_cnt
= 0;
143 static int cursor_on
= 0;
144 static int cursor_blink_rate
;
146 static inline void cursor_undrawn(void)
153 #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
157 * Interface used by the world
160 static const char *fbcon_startup(void);
161 static void fbcon_init(struct vc_data
*conp
, int init
);
162 static void fbcon_deinit(struct vc_data
*conp
);
163 static int fbcon_changevar(int con
);
164 static void fbcon_clear(struct vc_data
*conp
, int sy
, int sx
, int height
,
166 static void fbcon_putc(struct vc_data
*conp
, int c
, int ypos
, int xpos
);
167 static void fbcon_putcs(struct vc_data
*conp
, const unsigned short *s
, int count
,
169 static void fbcon_cursor(struct vc_data
*conp
, int mode
);
170 static int fbcon_scroll(struct vc_data
*conp
, int t
, int b
, int dir
,
172 static void fbcon_bmove(struct vc_data
*conp
, int sy
, int sx
, int dy
, int dx
,
173 int height
, int width
);
174 static int fbcon_switch(struct vc_data
*conp
);
175 static int fbcon_blank(struct vc_data
*conp
, int blank
);
176 static int fbcon_font_op(struct vc_data
*conp
, struct console_font_op
*op
);
177 static int fbcon_set_palette(struct vc_data
*conp
, unsigned char *table
);
178 static int fbcon_scrolldelta(struct vc_data
*conp
, int lines
);
185 static void fbcon_setup(int con
, int init
, int logo
);
186 static __inline__
int real_y(struct display
*p
, int ypos
);
187 static void fbcon_vbl_handler(int irq
, void *dummy
, struct pt_regs
*fp
);
188 static __inline__
void updatescrollmode(struct display
*p
);
189 static __inline__
void ywrap_up(int unit
, struct vc_data
*conp
,
190 struct display
*p
, int count
);
191 static __inline__
void ywrap_down(int unit
, struct vc_data
*conp
,
192 struct display
*p
, int count
);
193 static __inline__
void ypan_up(int unit
, struct vc_data
*conp
,
194 struct display
*p
, int count
);
195 static __inline__
void ypan_down(int unit
, struct vc_data
*conp
,
196 struct display
*p
, int count
);
197 static void fbcon_bmove_rec(struct display
*p
, int sy
, int sx
, int dy
, int dx
,
198 int height
, int width
, u_int y_break
);
200 static int fbcon_show_logo(void);
204 * On the Macintoy, there may or may not be a working VBL int. We need to prob
206 static int vbl_detected
= 0;
208 static void fbcon_vbl_detect(int irq
, void *dummy
, struct pt_regs
*fp
)
214 static void cursor_timer_handler(unsigned long dev_addr
);
216 static struct timer_list cursor_timer
= {
217 NULL
, NULL
, 0, 0L, cursor_timer_handler
220 static void cursor_timer_handler(unsigned long dev_addr
)
222 fbcon_vbl_handler(0, NULL
, NULL
);
223 cursor_timer
.expires
= jiffies
+HZ
/50;
224 cursor_timer
.data
= 0;
225 cursor_timer
.next
= cursor_timer
.next
= NULL
;
226 add_timer(&cursor_timer
);
230 * Low Level Operations
233 struct display_switch fbcon_dummy
;
235 /* NOTE: fbcon cannot be __initfunc: it may be called from take_over_console later */
237 static const char *fbcon_startup(void)
239 const char *display_desc
= "frame buffer device";
244 * If num_registered_fb is zero, this is a call for the dummy part.
245 * The frame buffer devices weren't initialized yet.
247 if (!num_registered_fb
|| done
)
253 cursor_blink_rate
= AMIGA_CURSOR_BLINK_RATE
;
254 irqres
= request_irq(IRQ_AMIGA_VERTB
, fbcon_vbl_handler
, 0,
255 "console/cursor", fbcon_vbl_handler
);
257 #endif /* CONFIG_AMIGA */
260 cursor_blink_rate
= ATARI_CURSOR_BLINK_RATE
;
261 irqres
= request_irq(IRQ_AUTO_4
, fbcon_vbl_handler
, IRQ_TYPE_PRIO
,
262 "console/cursor", fbcon_vbl_handler
);
264 #endif /* CONFIG_ATARI */
268 * On a Macintoy, the VBL interrupt may or may not be active.
269 * As interrupt based cursor is more reliable and race free, we
270 * probe for VBL interrupts.
275 * Probe for VBL: set temp. handler ...
277 irqres
= request_irq(IRQ_MAC_VBL
, fbcon_vbl_detect
, 0,
278 "console/cursor", fbcon_vbl_detect
);
282 * ... and spin for 20 ms ...
284 while (!vbl_detected
&& ++ct
<1000)
288 printk("fbcon_startup: No VBL detected, using timer based cursor.\n");
290 free_irq(IRQ_MAC_VBL
, fbcon_vbl_detect
);
294 * interrupt based cursor ok
296 cursor_blink_rate
= MAC_CURSOR_BLINK_RATE
;
297 irqres
= request_irq(IRQ_MAC_VBL
, fbcon_vbl_handler
, 0,
298 "console/cursor", fbcon_vbl_handler
);
301 * VBL not detected: fall through, use timer based cursor
306 #endif /* CONFIG_MAC */
308 #if defined(__arm__) && defined(IRQ_VSYNCPULSE)
309 cursor_blink_rate
= ARM_CURSOR_BLINK_RATE
;
310 irqres
= request_irq(IRQ_VSYNCPULSE
, fbcon_vbl_handler
, SA_SHIRQ
,
311 "console/cursor", fbcon_vbl_handler
);
315 cursor_blink_rate
= DEFAULT_CURSOR_BLINK_RATE
;
316 cursor_timer
.expires
= jiffies
+HZ
/50;
317 cursor_timer
.data
= 0;
318 cursor_timer
.next
= cursor_timer
.prev
= NULL
;
319 add_timer(&cursor_timer
);
326 static void fbcon_init(struct vc_data
*conp
, int init
)
328 int unit
= conp
->vc_num
;
329 struct fb_info
*info
;
331 /* on which frame buffer will we open this console? */
332 info
= registered_fb
[(int)con2fb_map
[unit
]];
334 info
->changevar
= &fbcon_changevar
;
335 fb_display
[unit
] = *(info
->disp
); /* copy from default */
336 DPRINTK("mode: %s\n",info
->modename
);
337 DPRINTK("visual: %d\n",fb_display
[unit
].visual
);
338 DPRINTK("res: %dx%d-%d\n",fb_display
[unit
].var
.xres
,
339 fb_display
[unit
].var
.yres
,
340 fb_display
[unit
].var
.bits_per_pixel
);
341 fb_display
[unit
].conp
= conp
;
342 fb_display
[unit
].fb_info
= info
;
343 /* clear out the cmap so we don't have dangling pointers */
344 fb_display
[unit
].cmap
.len
= 0;
345 fb_display
[unit
].cmap
.red
= 0;
346 fb_display
[unit
].cmap
.green
= 0;
347 fb_display
[unit
].cmap
.blue
= 0;
348 fb_display
[unit
].cmap
.transp
= 0;
349 fbcon_setup(unit
, init
, !init
);
350 /* Must be done after fbcon_setup to prevent excess updates */
351 conp
->vc_display_fg
= &info
->display_fg
;
352 if (!info
->display_fg
)
353 info
->display_fg
= conp
;
357 static void fbcon_deinit(struct vc_data
*conp
)
359 int unit
= conp
->vc_num
;
360 struct display
*p
= &fb_display
[unit
];
363 p
->dispsw
= &fbcon_dummy
;
368 static int fbcon_changevar(int con
)
370 if (fb_display
[con
].conp
)
371 fbcon_setup(con
, 0, 0);
376 static __inline__
void updatescrollmode(struct display
*p
)
379 if (p
->scrollmode
& __SCROLL_YFIXED
)
381 if (divides(p
->ywrapstep
, fontheight(p
)) &&
382 divides(fontheight(p
), p
->var
.yres_virtual
))
384 else if (divides(p
->ypanstep
, fontheight(p
)) &&
385 p
->var
.yres_virtual
>= p
->var
.yres
+fontheight(p
))
387 else if (p
->scrollmode
& __SCROLL_YNOMOVE
)
388 m
= __SCROLL_YREDRAW
;
391 p
->scrollmode
= (p
->scrollmode
& ~__SCROLL_YMASK
) | m
;
394 static void fbcon_font_widths(struct display
*p
)
398 p
->_fontwidthlog
= 0;
399 for (i
= 2; i
<= 6; i
++)
400 if (fontwidth(p
) == (1 << i
))
401 p
->_fontwidthlog
= i
;
402 p
->_fontheightlog
= 0;
403 for (i
= 2; i
<= 6; i
++)
404 if (fontheight(p
) == (1 << i
))
405 p
->_fontheightlog
= i
;
408 #define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))
410 static void fbcon_setup(int con
, int init
, int logo
)
412 struct display
*p
= &fb_display
[con
];
413 struct vc_data
*conp
= p
->conp
;
414 int nr_rows
, nr_cols
;
415 int old_rows
, old_cols
;
416 unsigned short *save
= NULL
, *r
, *q
;
417 int i
, charcnt
= 256;
418 struct fbcon_font_desc
*font
;
420 if (con
!= fg_console
|| (p
->fb_info
->flags
& FBINFO_FLAG_MODULE
) ||
421 p
->type
== FB_TYPE_TEXT
)
424 p
->var
.xoffset
= p
->var
.yoffset
= p
->yscroll
= 0; /* reset wrap/pan */
426 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
427 if (i
!= con
&& fb_display
[i
].fb_info
== p
->fb_info
&&
428 fb_display
[i
].conp
&& fb_display
[i
].fontdata
)
432 if (i
< MAX_NR_CONSOLES
) {
433 struct display
*q
= &fb_display
[i
];
435 if (fontwidthvalid(p
,fontwidth(q
))) {
436 /* If we are not the first console on this
437 fb, copy the font from that console */
438 p
->_fontwidth
= q
->_fontwidth
;
439 p
->_fontheight
= q
->_fontheight
;
440 p
->_fontwidthlog
= q
->_fontwidthlog
;
441 p
->_fontheightlog
= q
->_fontheightlog
;
442 p
->fontdata
= q
->fontdata
;
443 p
->userfont
= q
->userfont
;
445 REFCOUNT(p
->fontdata
)++;
446 charcnt
= FNTCHARCNT(p
->fontdata
);
448 con_copy_unimap(con
, i
);
453 if (!p
->fb_info
->fontname
[0] ||
454 !(font
= fbcon_find_font(p
->fb_info
->fontname
)))
455 font
= fbcon_get_default_font(p
->var
.xres
, p
->var
.yres
);
456 p
->_fontwidth
= font
->width
;
457 p
->_fontheight
= font
->height
;
458 p
->fontdata
= font
->data
;
459 fbcon_font_widths(p
);
462 if (!fontwidthvalid(p
,fontwidth(p
))) {
465 /* ++Geert: hack to make 6x11 fonts work on mac */
466 p
->dispsw
= &fbcon_mac
;
470 /* ++Geert: changed from panic() to `correct and continue' */
471 printk(KERN_ERR
"fbcon_setup: No support for fontwidth %d\n", fontwidth(p
));
472 p
->dispsw
= &fbcon_dummy
;
475 if (p
->dispsw
->set_font
)
476 p
->dispsw
->set_font(p
, fontwidth(p
), fontheight(p
));
479 old_cols
= conp
->vc_cols
;
480 old_rows
= conp
->vc_rows
;
482 nr_cols
= p
->var
.xres
/fontwidth(p
);
483 nr_rows
= p
->var
.yres
/fontheight(p
);
486 /* Need to make room for the logo */
490 logo_lines
= (LOGO_H
+ fontheight(p
) - 1) / fontheight(p
);
491 q
= (unsigned short *)(conp
->vc_origin
+ conp
->vc_size_row
* old_rows
);
492 step
= logo_lines
* old_cols
;
493 for (r
= q
- logo_lines
* old_cols
; r
< q
; r
++)
494 if (*r
!= conp
->vc_video_erase_char
)
496 if (r
!= q
&& nr_rows
>= old_rows
+ logo_lines
) {
497 save
= kmalloc(logo_lines
* nr_cols
* 2, GFP_KERNEL
);
499 int i
= old_cols
< nr_cols
? old_cols
: nr_cols
;
500 scr_memsetw(save
, conp
->vc_video_erase_char
, logo_lines
* nr_cols
* 2);
502 for (cnt
= 0; cnt
< logo_lines
; cnt
++, r
+= i
)
503 scr_memcpyw_to(save
+ cnt
* nr_cols
, r
, 2 * i
);
508 /* We can scroll screen down */
509 r
= q
- step
- old_cols
;
510 for (cnt
= old_rows
- logo_lines
; cnt
> 0; cnt
--) {
511 scr_memcpyw(r
+ step
, r
, conp
->vc_size_row
);
515 conp
->vc_y
+= logo_lines
;
516 conp
->vc_pos
+= logo_lines
* conp
->vc_size_row
;
519 scr_memsetw((unsigned short *)conp
->vc_origin
, conp
->vc_video_erase_char
,
520 conp
->vc_size_row
* logo_lines
);
524 * ++guenther: console.c:vc_allocate() relies on initializing
525 * vc_{cols,rows}, but we must not set those if we are only
526 * resizing the console.
529 conp
->vc_cols
= nr_cols
;
530 conp
->vc_rows
= nr_rows
;
532 p
->vrows
= p
->var
.yres_virtual
/fontheight(p
);
533 if ((p
->var
.yres
% fontheight(p
)) &&
534 (p
->var
.yres_virtual
% fontheight(p
) < p
->var
.yres
% fontheight(p
)))
536 conp
->vc_can_do_color
= p
->var
.bits_per_pixel
!= 1;
537 conp
->vc_complement_mask
= conp
->vc_can_do_color
? 0x7700 : 0x0800;
538 if (charcnt
== 256) {
539 conp
->vc_hi_font_mask
= 0;
544 conp
->vc_hi_font_mask
= 0x100;
545 if (conp
->vc_can_do_color
)
546 conp
->vc_complement_mask
<<= 1;
552 if (p
->dispsw
== &fbcon_dummy
)
553 printk(KERN_WARNING
"fbcon_setup: type %d (aux %d, depth %d) not "
554 "supported\n", p
->type
, p
->type_aux
, p
->var
.bits_per_pixel
);
557 p
->fgcol
= p
->var
.bits_per_pixel
> 2 ? 7 : (1<<p
->var
.bits_per_pixel
)-1;
561 if (conp
->vc_cols
!= nr_cols
|| conp
->vc_rows
!= nr_rows
)
562 vc_resize_con(nr_rows
, nr_cols
, con
);
563 else if (CON_IS_VISIBLE(conp
) &&
564 vt_cons
[conp
->vc_num
]->vc_mode
== KD_TEXT
) {
565 if (p
->dispsw
->clear_margins
)
566 p
->dispsw
->clear_margins(conp
, p
, 0);
570 q
= (unsigned short *)(conp
->vc_origin
+ conp
->vc_size_row
* old_rows
);
571 scr_memcpyw_from(q
, save
, logo_lines
* nr_cols
* 2);
572 conp
->vc_y
+= logo_lines
;
573 conp
->vc_pos
+= logo_lines
* conp
->vc_size_row
;
580 conp
->vc_top
= logo_lines
;
585 /* ====================================================================== */
587 /* fbcon_XXX routines - interface used by the world
589 * This system is now divided into two levels because of complications
590 * caused by hardware scrolling. Top level functions:
592 * fbcon_bmove(), fbcon_clear(), fbcon_putc()
594 * handles y values in range [0, scr_height-1] that correspond to real
595 * screen positions. y_wrap shift means that first line of bitmap may be
596 * anywhere on this display. These functions convert lineoffsets to
597 * bitmap offsets and deal with the wrap-around case by splitting blits.
599 * fbcon_bmove_physical_8() -- These functions fast implementations
600 * fbcon_clear_physical_8() -- of original fbcon_XXX fns.
601 * fbcon_putc_physical_8() -- (fontwidth != 8) may be added later
605 * At the moment fbcon_putc() cannot blit across vertical wrap boundary
606 * Implies should only really hardware scroll in rows. Only reason for
607 * restriction is simplicity & efficiency at the moment.
610 static __inline__
int real_y(struct display
*p
, int ypos
)
615 return ypos
< rows
? ypos
: ypos
-rows
;
619 static void fbcon_clear(struct vc_data
*conp
, int sy
, int sx
, int height
,
622 int unit
= conp
->vc_num
;
623 struct display
*p
= &fb_display
[unit
];
625 int redraw_cursor
= 0;
627 if (!p
->can_soft_blank
&& console_blanked
)
630 if (!height
|| !width
)
633 if ((sy
<= p
->cursor_y
) && (p
->cursor_y
< sy
+height
) &&
634 (sx
<= p
->cursor_x
) && (p
->cursor_x
< sx
+width
)) {
639 /* Split blits that cross physical y_wrap boundary */
641 y_break
= p
->vrows
-p
->yscroll
;
642 if (sy
< y_break
&& sy
+height
-1 >= y_break
) {
643 u_int b
= y_break
-sy
;
644 p
->dispsw
->clear(conp
, p
, real_y(p
, sy
), sx
, b
, width
);
645 p
->dispsw
->clear(conp
, p
, real_y(p
, sy
+b
), sx
, height
-b
, width
);
647 p
->dispsw
->clear(conp
, p
, real_y(p
, sy
), sx
, height
, width
);
650 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
654 static void fbcon_putc(struct vc_data
*conp
, int c
, int ypos
, int xpos
)
656 int unit
= conp
->vc_num
;
657 struct display
*p
= &fb_display
[unit
];
658 int redraw_cursor
= 0;
660 if (!p
->can_soft_blank
&& console_blanked
)
663 if (vt_cons
[unit
]->vc_mode
!= KD_TEXT
)
666 if ((p
->cursor_x
== xpos
) && (p
->cursor_y
== ypos
)) {
671 p
->dispsw
->putc(conp
, p
, c
, real_y(p
, ypos
), xpos
);
674 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
678 static void fbcon_putcs(struct vc_data
*conp
, const unsigned short *s
, int count
,
681 int unit
= conp
->vc_num
;
682 struct display
*p
= &fb_display
[unit
];
683 int redraw_cursor
= 0;
685 if (!p
->can_soft_blank
&& console_blanked
)
688 if (vt_cons
[unit
]->vc_mode
!= KD_TEXT
)
691 if ((p
->cursor_y
== ypos
) && (xpos
<= p
->cursor_x
) &&
692 (p
->cursor_x
< (xpos
+ count
))) {
696 p
->dispsw
->putcs(conp
, p
, s
, count
, real_y(p
, ypos
), xpos
);
698 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
702 static void fbcon_cursor(struct vc_data
*conp
, int mode
)
704 int unit
= conp
->vc_num
;
705 struct display
*p
= &fb_display
[unit
];
707 /* do we have a hardware cursor ? */
708 if (p
->dispsw
->cursor
) {
709 p
->cursor_x
= conp
->vc_x
;
710 p
->cursor_y
= conp
->vc_y
;
711 p
->dispsw
->cursor(p
, mode
, p
->cursor_x
, real_y(p
, p
->cursor_y
));
715 /* Avoid flickering if there's no real change. */
716 if (p
->cursor_x
== conp
->vc_x
&& p
->cursor_y
== conp
->vc_y
&&
717 (mode
== CM_ERASE
) == !cursor_on
)
722 p
->dispsw
->revc(p
, p
->cursor_x
, real_y(p
, p
->cursor_y
));
724 p
->cursor_x
= conp
->vc_x
;
725 p
->cursor_y
= conp
->vc_y
;
734 p
->dispsw
->revc(p
, p
->cursor_x
, real_y(p
, p
->cursor_y
));
735 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
742 static void fbcon_vbl_handler(int irq
, void *dummy
, struct pt_regs
*fp
)
749 if (vbl_cursor_cnt
&& --vbl_cursor_cnt
== 0) {
750 p
= &fb_display
[fg_console
];
752 p
->dispsw
->revc(p
, p
->cursor_x
, real_y(p
, p
->cursor_y
));
754 vbl_cursor_cnt
= cursor_blink_rate
;
758 static int scrollback_phys_max
= 0;
759 static int scrollback_max
= 0;
760 static int scrollback_current
= 0;
762 static __inline__
void ywrap_up(int unit
, struct vc_data
*conp
,
763 struct display
*p
, int count
)
766 if (p
->yscroll
>= p
->vrows
) /* Deal with wrap */
767 p
->yscroll
-= p
->vrows
;
769 p
->var
.yoffset
= p
->yscroll
*fontheight(p
);
770 p
->var
.vmode
|= FB_VMODE_YWRAP
;
771 p
->fb_info
->updatevar(unit
, p
->fb_info
);
772 scrollback_max
+= count
;
773 if (scrollback_max
> scrollback_phys_max
)
774 scrollback_max
= scrollback_phys_max
;
775 scrollback_current
= 0;
779 static __inline__
void ywrap_down(int unit
, struct vc_data
*conp
,
780 struct display
*p
, int count
)
783 if (p
->yscroll
< 0) /* Deal with wrap */
784 p
->yscroll
+= p
->vrows
;
786 p
->var
.yoffset
= p
->yscroll
*fontheight(p
);
787 p
->var
.vmode
|= FB_VMODE_YWRAP
;
788 p
->fb_info
->updatevar(unit
, p
->fb_info
);
789 scrollback_max
-= count
;
790 if (scrollback_max
< 0)
792 scrollback_current
= 0;
796 static __inline__
void ypan_up(int unit
, struct vc_data
*conp
,
797 struct display
*p
, int count
)
800 if (p
->yscroll
> p
->vrows
-conp
->vc_rows
) {
801 p
->dispsw
->bmove(p
, p
->vrows
-conp
->vc_rows
, 0, 0, 0,
802 conp
->vc_rows
, conp
->vc_cols
);
803 p
->yscroll
-= p
->vrows
-conp
->vc_rows
;
806 p
->var
.yoffset
= p
->yscroll
*fontheight(p
);
807 p
->var
.vmode
&= ~FB_VMODE_YWRAP
;
808 p
->fb_info
->updatevar(unit
, p
->fb_info
);
809 if (p
->dispsw
->clear_margins
)
810 p
->dispsw
->clear_margins(conp
, p
, 1);
811 scrollback_max
+= count
;
812 if (scrollback_max
> scrollback_phys_max
)
813 scrollback_max
= scrollback_phys_max
;
814 scrollback_current
= 0;
818 static __inline__
void ypan_down(int unit
, struct vc_data
*conp
,
819 struct display
*p
, int count
)
822 if (p
->yscroll
< 0) {
823 p
->dispsw
->bmove(p
, 0, 0, p
->vrows
-conp
->vc_rows
, 0,
824 conp
->vc_rows
, conp
->vc_cols
);
825 p
->yscroll
+= p
->vrows
-conp
->vc_rows
;
828 p
->var
.yoffset
= p
->yscroll
*fontheight(p
);
829 p
->var
.vmode
&= ~FB_VMODE_YWRAP
;
830 p
->fb_info
->updatevar(unit
, p
->fb_info
);
831 if (p
->dispsw
->clear_margins
)
832 p
->dispsw
->clear_margins(conp
, p
, 1);
833 scrollback_max
-= count
;
834 if (scrollback_max
< 0)
836 scrollback_current
= 0;
840 static void fbcon_redraw(struct vc_data
*conp
, struct display
*p
,
841 int line
, int count
, int offset
)
843 unsigned short *d
= (unsigned short *)
844 (conp
->vc_origin
+ conp
->vc_size_row
* line
);
845 unsigned short *s
= d
+ offset
;
848 unsigned short *start
= s
;
849 unsigned short *le
= (unsigned short *)
850 ((unsigned long)s
+ conp
->vc_size_row
);
853 unsigned short attr
= 1;
857 if (attr
!= (c
& 0xff00)) {
860 p
->dispsw
->putcs(conp
, p
, start
, s
- start
,
866 if (c
== scr_readw(d
)) {
868 p
->dispsw
->putcs(conp
, p
, start
, s
- start
,
882 p
->dispsw
->putcs(conp
, p
, start
, s
- start
, real_y(p
, line
), x
);
887 /* NOTE: We subtract two lines from these pointers */
888 s
-= conp
->vc_size_row
;
889 d
-= conp
->vc_size_row
;
894 /* This cannot be used together with ypan or ywrap */
895 void fbcon_redraw_bmove(struct display
*p
, int sy
, int sx
, int dy
, int dx
, int h
, int w
)
898 panic("fbcon_redraw_bmove width sy != dy");
899 /* h will be always 1, but it does not matter if we are more generic */
902 struct vc_data
*conp
= p
->conp
;
903 unsigned short *d
= (unsigned short *)
904 (conp
->vc_origin
+ conp
->vc_size_row
* dy
+ dx
* 2);
905 unsigned short *s
= d
+ (dx
- sx
);
906 unsigned short *start
= d
;
907 unsigned short *ls
= d
;
908 unsigned short *le
= d
+ w
;
911 unsigned short attr
= 1;
915 if (attr
!= (c
& 0xff00)) {
918 p
->dispsw
->putcs(conp
, p
, start
, d
- start
, dy
, x
);
923 if (s
>= ls
&& s
< le
&& c
== scr_readw(s
)) {
925 p
->dispsw
->putcs(conp
, p
, start
, d
- start
, dy
, x
);
937 p
->dispsw
->putcs(conp
, p
, start
, d
- start
, dy
, x
);
943 static int fbcon_scroll(struct vc_data
*conp
, int t
, int b
, int dir
,
946 int unit
= conp
->vc_num
;
947 struct display
*p
= &fb_display
[unit
];
948 int scroll_partial
= !(p
->scrollmode
& __SCROLL_YNOPARTIAL
);
949 int logos_left
= 0; int logos_width
= conp
->vc_cols
;
951 if (!p
->can_soft_blank
&& console_blanked
)
954 if (!count
|| vt_cons
[unit
]->vc_mode
!= KD_TEXT
)
957 fbcon_cursor(conp
, CM_ERASE
);
960 * ++Geert: Only use ywrap/ypan if the console is in text mode
961 * ++Andrew: Only use ypan on hardware text mode when scrolling the
962 * whole screen (prevents flicker).
967 /* K.Garloff@ping.de, 98/10/21: If logo is diplayed, only save logo
968 * and not the hole top region. In combination with the logo being
969 * displayed on the right side, this allows scrollback feature
970 * when bootlogo is displayed. */
971 if (t
!= 0 && logo_shown
== fg_console
) {
972 struct display
*p
= &fb_display
[unit
];
973 int lw
= (smp_num_cpus
* (LOGO_W
+ 8) - 7) / fontwidth(p
) + 1;
974 logos_left
= conp
->vc_cols
- lw
;
975 while (logos_left
< 0) logos_left
+= (LOGO_W
+ 8 - 7) / fontwidth(p
);
976 logos_width
= conp
->vc_cols
- logos_left
;
978 if (count
> conp
->vc_rows
) /* Maximum realistic size */
979 count
= conp
->vc_rows
;
980 switch (p
->scrollmode
& __SCROLL_YMASK
) {
982 if (t
> 0) p
->dispsw
->bmove(p
, 0, logos_left
, count
,
983 logos_left
, t
, logos_width
);
984 p
->dispsw
->bmove(p
, count
, 0, 0, 0, b
-count
,
986 p
->dispsw
->clear(conp
, p
, b
-count
, 0, count
,
991 if (b
-t
-count
> 2*conp
->vc_rows
/3) {
993 fbcon_bmove(conp
, 0, logos_left
, count
, logos_left
, t
, logos_width
);
994 ywrap_up(unit
, conp
, p
, count
);
995 if (conp
->vc_rows
-b
> 0)
996 fbcon_bmove(conp
, b
-count
, 0, b
, 0,
997 conp
->vc_rows
-b
, conp
->vc_cols
);
998 } else if (p
->scrollmode
& __SCROLL_YPANREDRAW
)
1001 fbcon_bmove(conp
, t
+count
, 0, t
, 0, b
-t
-count
,
1003 fbcon_clear(conp
, b
-count
, 0, count
, conp
->vc_cols
);
1007 if (( !scroll_partial
&& (b
-t
== conp
->vc_rows
)) ||
1008 ( scroll_partial
&& (b
-t
-count
> 3*conp
->vc_rows
>>2))) {
1010 fbcon_bmove(conp
, 0, logos_left
, count
, logos_left
, t
,
1012 ypan_up(unit
, conp
, p
, count
);
1013 if (conp
->vc_rows
-b
> 0)
1014 fbcon_bmove(conp
, b
-count
, 0, b
, 0,
1015 conp
->vc_rows
-b
, conp
->vc_cols
);
1016 } else if (p
->scrollmode
& __SCROLL_YPANREDRAW
)
1019 fbcon_bmove(conp
, t
+count
, 0, t
, 0, b
-t
-count
,
1021 fbcon_clear(conp
, b
-count
, 0, count
, conp
->vc_cols
);
1024 case __SCROLL_YREDRAW
:
1026 fbcon_redraw(conp
, p
, t
, b
-t
-count
, count
*conp
->vc_cols
);
1027 p
->dispsw
->clear(conp
, p
, real_y(p
, b
-count
), 0,
1028 count
, conp
->vc_cols
);
1029 scr_memsetw((unsigned short *)(conp
->vc_origin
+
1030 conp
->vc_size_row
* (b
-count
)),
1031 conp
->vc_video_erase_char
,
1032 conp
->vc_size_row
* count
);
1038 if (count
> conp
->vc_rows
) /* Maximum realistic size */
1039 count
= conp
->vc_rows
;
1040 switch (p
->scrollmode
& __SCROLL_YMASK
) {
1041 case __SCROLL_YMOVE
:
1042 p
->dispsw
->bmove(p
, t
, 0, t
+count
, 0, b
-t
-count
,
1044 p
->dispsw
->clear(conp
, p
, t
, 0,
1045 count
, conp
->vc_cols
);
1048 case __SCROLL_YWRAP
:
1049 if (b
-t
-count
> 3*conp
->vc_rows
>>2) {
1050 if (conp
->vc_rows
-b
> 0)
1051 fbcon_bmove(conp
, b
, 0, b
-count
, 0,
1052 conp
->vc_rows
-b
, conp
->vc_cols
);
1053 ywrap_down(unit
, conp
, p
, count
);
1055 fbcon_bmove(conp
, count
, 0, 0, 0, t
,
1057 } else if (p
->scrollmode
& __SCROLL_YPANREDRAW
)
1060 fbcon_bmove(conp
, t
, 0, t
+count
, 0, b
-t
-count
,
1062 fbcon_clear(conp
, t
, 0, count
, conp
->vc_cols
);
1066 if (( !scroll_partial
&& (b
-t
== conp
->vc_rows
)) ||
1067 ( scroll_partial
&& (b
-t
-count
> 3*conp
->vc_rows
>>2))) {
1068 if (conp
->vc_rows
-b
> 0)
1069 fbcon_bmove(conp
, b
, 0, b
-count
, 0,
1070 conp
->vc_rows
-b
, conp
->vc_cols
);
1071 ypan_down(unit
, conp
, p
, count
);
1073 fbcon_bmove(conp
, count
, 0, 0, 0, t
,
1075 } else if (p
->scrollmode
& __SCROLL_YPANREDRAW
)
1078 fbcon_bmove(conp
, t
, 0, t
+count
, 0, b
-t
-count
,
1080 fbcon_clear(conp
, t
, 0, count
, conp
->vc_cols
);
1083 case __SCROLL_YREDRAW
:
1085 fbcon_redraw(conp
, p
, b
- 1, b
-t
-count
, -count
*conp
->vc_cols
);
1086 p
->dispsw
->clear(conp
, p
, real_y(p
, t
), 0,
1087 count
, conp
->vc_cols
);
1088 scr_memsetw((unsigned short *)(conp
->vc_origin
+
1089 conp
->vc_size_row
* t
),
1090 conp
->vc_video_erase_char
,
1091 conp
->vc_size_row
* count
);
1099 static void fbcon_bmove(struct vc_data
*conp
, int sy
, int sx
, int dy
, int dx
,
1100 int height
, int width
)
1102 int unit
= conp
->vc_num
;
1103 struct display
*p
= &fb_display
[unit
];
1105 if (!p
->can_soft_blank
&& console_blanked
)
1108 if (!width
|| !height
)
1111 if (((sy
<= p
->cursor_y
) && (p
->cursor_y
< sy
+height
) &&
1112 (sx
<= p
->cursor_x
) && (p
->cursor_x
< sx
+width
)) ||
1113 ((dy
<= p
->cursor_y
) && (p
->cursor_y
< dy
+height
) &&
1114 (dx
<= p
->cursor_x
) && (p
->cursor_x
< dx
+width
)))
1115 fbcon_cursor(conp
, CM_ERASE
);
1117 /* Split blits that cross physical y_wrap case.
1118 * Pathological case involves 4 blits, better to use recursive
1119 * code rather than unrolled case
1121 * Recursive invocations don't need to erase the cursor over and
1122 * over again, so we use fbcon_bmove_rec()
1124 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, height
, width
, p
->vrows
-p
->yscroll
);
1127 static void fbcon_bmove_rec(struct display
*p
, int sy
, int sx
, int dy
, int dx
,
1128 int height
, int width
, u_int y_break
)
1132 if (sy
< y_break
&& sy
+height
> y_break
) {
1134 if (dy
< sy
) { /* Avoid trashing self */
1135 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, b
, width
, y_break
);
1136 fbcon_bmove_rec(p
, sy
+b
, sx
, dy
+b
, dx
, height
-b
, width
, y_break
);
1138 fbcon_bmove_rec(p
, sy
+b
, sx
, dy
+b
, dx
, height
-b
, width
, y_break
);
1139 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, b
, width
, y_break
);
1144 if (dy
< y_break
&& dy
+height
> y_break
) {
1146 if (dy
< sy
) { /* Avoid trashing self */
1147 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, b
, width
, y_break
);
1148 fbcon_bmove_rec(p
, sy
+b
, sx
, dy
+b
, dx
, height
-b
, width
, y_break
);
1150 fbcon_bmove_rec(p
, sy
+b
, sx
, dy
+b
, dx
, height
-b
, width
, y_break
);
1151 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, b
, width
, y_break
);
1155 p
->dispsw
->bmove(p
, real_y(p
, sy
), sx
, real_y(p
, dy
), dx
, height
, width
);
1159 static int fbcon_switch(struct vc_data
*conp
)
1161 int unit
= conp
->vc_num
;
1162 struct display
*p
= &fb_display
[unit
];
1163 struct fb_info
*info
= p
->fb_info
;
1165 if (logo_shown
>= 0) {
1166 struct vc_data
*conp2
= vc_cons
[logo_shown
].d
;
1168 if (conp2
->vc_top
== logo_lines
&& conp2
->vc_bottom
== conp2
->vc_rows
)
1172 p
->var
.yoffset
= p
->yscroll
= 0;
1173 switch (p
->scrollmode
& __SCROLL_YMASK
) {
1174 case __SCROLL_YWRAP
:
1175 scrollback_phys_max
= p
->vrows
-conp
->vc_rows
;
1178 scrollback_phys_max
= p
->vrows
-2*conp
->vc_rows
;
1179 if (scrollback_phys_max
< 0)
1180 scrollback_phys_max
= 0;
1183 scrollback_phys_max
= 0;
1187 scrollback_current
= 0;
1189 if (info
&& info
->switch_con
)
1190 (*info
->switch_con
)(unit
, info
);
1191 if (p
->dispsw
->clear_margins
&& vt_cons
[unit
]->vc_mode
== KD_TEXT
)
1192 p
->dispsw
->clear_margins(conp
, p
, 0);
1193 if (logo_shown
== -2) {
1194 logo_shown
= fg_console
;
1195 fbcon_show_logo(); /* This is protected above by initmem_freed */
1196 update_region(fg_console
,
1197 conp
->vc_origin
+ conp
->vc_size_row
* conp
->vc_top
,
1198 conp
->vc_size_row
* (conp
->vc_bottom
- conp
->vc_top
) / 2);
1205 static int fbcon_blank(struct vc_data
*conp
, int blank
)
1207 struct display
*p
= &fb_display
[conp
->vc_num
];
1208 struct fb_info
*info
= p
->fb_info
;
1210 if (blank
< 0) /* Entering graphics mode */
1213 fbcon_cursor(p
->conp
, blank
? CM_ERASE
: CM_DRAW
);
1215 if (!p
->can_soft_blank
) {
1220 mymemset(p
->screen_base
,
1221 p
->var
.xres_virtual
*p
->var
.yres_virtual
*
1222 p
->var
.bits_per_pixel
>>3);
1225 if (p
->visual
== FB_VISUAL_MONO01
) {
1227 mymemset(p
->screen_base
,
1228 p
->var
.xres_virtual
*p
->var
.yres_virtual
*
1229 p
->var
.bits_per_pixel
>>3);
1231 p
->dispsw
->clear(conp
, p
, 0, 0, conp
->vc_rows
, conp
->vc_cols
);
1234 /* Tell console.c that it has to restore the screen itself */
1238 (*info
->blank
)(blank
, info
);
1242 static void fbcon_free_font(struct display
*p
)
1244 if (p
->userfont
&& p
->fontdata
&&
1245 (--REFCOUNT(p
->fontdata
) == 0))
1246 kfree(p
->fontdata
- FONT_EXTRA_WORDS
*sizeof(int));
1251 static inline int fbcon_get_font(int unit
, struct console_font_op
*op
)
1253 struct display
*p
= &fb_display
[unit
];
1254 u8
*data
= op
->data
;
1255 u8
*fontdata
= p
->fontdata
;
1258 #ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
1259 if (fontwidth(p
) != 8) return -EINVAL
;
1261 op
->width
= fontwidth(p
);
1262 op
->height
= fontheight(p
);
1263 op
->charcount
= (p
->charmask
== 0x1ff) ? 512 : 256;
1264 if (!op
->data
) return 0;
1266 if (op
->width
<= 8) {
1268 for (i
= 0; i
< op
->charcount
; i
++) {
1269 memcpy(data
, fontdata
, j
);
1270 memset(data
+j
, 0, 32-j
);
1275 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
1276 else if (op
->width
<= 16) {
1277 j
= fontheight(p
) * 2;
1278 for (i
= 0; i
< op
->charcount
; i
++) {
1279 memcpy(data
, fontdata
, j
);
1280 memset(data
+j
, 0, 64-j
);
1284 } else if (op
->width
<= 24) {
1285 for (i
= 0; i
< op
->charcount
; i
++) {
1286 for (j
= 0; j
< fontheight(p
); j
++) {
1287 *data
++ = fontdata
[0];
1288 *data
++ = fontdata
[1];
1289 *data
++ = fontdata
[2];
1290 fontdata
+= sizeof(u32
);
1292 memset(data
, 0, 3*(32-j
));
1293 data
+= 3 * (32 - j
);
1296 j
= fontheight(p
) * 4;
1297 for (i
= 0; i
< op
->charcount
; i
++) {
1298 memcpy(data
, fontdata
, j
);
1299 memset(data
+j
, 0, 128-j
);
1308 static int fbcon_do_set_font(int unit
, struct console_font_op
*op
, u8
*data
, int userfont
)
1310 struct display
*p
= &fb_display
[unit
];
1315 char *old_data
= NULL
;
1317 if (!fontwidthvalid(p
,w
)) {
1318 if (userfont
&& op
->op
!= KD_FONT_OP_COPY
)
1319 kfree(data
- FONT_EXTRA_WORDS
*sizeof(int));
1323 resize
= (w
!= fontwidth(p
)) || (h
!= fontheight(p
));
1325 old_data
= p
->fontdata
;
1327 cnt
= FNTCHARCNT(data
);
1331 if ((p
->userfont
= userfont
))
1335 if (p
->conp
->vc_hi_font_mask
&& cnt
== 256) {
1336 p
->conp
->vc_hi_font_mask
= 0;
1337 if (p
->conp
->vc_can_do_color
)
1338 p
->conp
->vc_complement_mask
>>= 1;
1343 /* ++Edmund: reorder the attribute bits */
1344 if (p
->conp
->vc_can_do_color
) {
1345 struct vc_data
*conp
= p
->conp
;
1346 unsigned short *cp
= (unsigned short *) conp
->vc_origin
;
1347 int count
= conp
->vc_screenbuf_size
/2;
1349 for (; count
> 0; count
--, cp
++) {
1351 scr_writew(((c
& 0xfe00) >> 1) | (c
& 0xff), cp
);
1353 c
= conp
->vc_video_erase_char
;
1354 conp
->vc_video_erase_char
= ((c
& 0xfe00) >> 1) | (c
& 0xff);
1355 conp
->vc_attr
>>= 1;
1358 } else if (!p
->conp
->vc_hi_font_mask
&& cnt
== 512) {
1359 p
->conp
->vc_hi_font_mask
= 0x100;
1360 if (p
->conp
->vc_can_do_color
)
1361 p
->conp
->vc_complement_mask
<<= 1;
1364 p
->charmask
= 0x1ff;
1366 /* ++Edmund: reorder the attribute bits */
1368 struct vc_data
*conp
= p
->conp
;
1369 unsigned short *cp
= (unsigned short *) conp
->vc_origin
;
1370 int count
= conp
->vc_screenbuf_size
/2;
1372 for (; count
> 0; count
--, cp
++) {
1373 unsigned short newc
;
1375 if (conp
->vc_can_do_color
)
1376 newc
= ((c
& 0xff00) << 1) | (c
& 0xff);
1379 scr_writew(newc
, cp
);
1381 c
= conp
->vc_video_erase_char
;
1382 if (conp
->vc_can_do_color
) {
1383 conp
->vc_video_erase_char
= ((c
& 0xff00) << 1) | (c
& 0xff);
1384 conp
->vc_attr
<<= 1;
1386 conp
->vc_video_erase_char
= c
& ~0x100;
1390 fbcon_font_widths(p
);
1393 /* reset wrap/pan */
1394 p
->var
.xoffset
= p
->var
.yoffset
= p
->yscroll
= 0;
1395 p
->vrows
= p
->var
.yres_virtual
/h
;
1396 if ((p
->var
.yres
% h
) && (p
->var
.yres_virtual
% h
< p
->var
.yres
% h
))
1398 updatescrollmode(p
);
1399 vc_resize_con( p
->var
.yres
/h
, p
->var
.xres
/w
, unit
);
1400 } else if (CON_IS_VISIBLE(p
->conp
) && vt_cons
[unit
]->vc_mode
== KD_TEXT
) {
1401 if (p
->dispsw
->clear_margins
)
1402 p
->dispsw
->clear_margins(p
->conp
, p
, 0);
1403 update_screen(unit
);
1406 if (old_data
&& (--REFCOUNT(old_data
) == 0))
1407 kfree(old_data
- FONT_EXTRA_WORDS
*sizeof(int));
1412 static inline int fbcon_copy_font(int unit
, struct console_font_op
*op
)
1414 struct display
*od
, *p
= &fb_display
[unit
];
1417 if (h
< 0 || !vc_cons_allocated( h
))
1420 return 0; /* nothing to do */
1421 od
= &fb_display
[h
];
1422 if (od
->fontdata
== p
->fontdata
)
1423 return 0; /* already the same font... */
1424 op
->width
= fontwidth(od
);
1425 op
->height
= fontheight(od
);
1426 return fbcon_do_set_font(unit
, op
, od
->fontdata
, od
->userfont
);
1429 static inline int fbcon_set_font(int unit
, struct console_font_op
*op
)
1435 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
1438 u8
*new_data
, *data
= op
->data
, *p
;
1440 #ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
1444 if ((w
<= 0) || (w
> 32) || (op
->charcount
!= 256 && op
->charcount
!= 512))
1453 size
*= op
->charcount
;
1455 if (!(new_data
= kmalloc(FONT_EXTRA_WORDS
*sizeof(int)+size
, GFP_USER
)))
1457 new_data
+= FONT_EXTRA_WORDS
*sizeof(int);
1458 FNTSIZE(new_data
) = size
;
1459 FNTCHARCNT(new_data
) = op
->charcount
;
1460 REFCOUNT(new_data
) = 0; /* usage counter */
1463 for (i
= 0; i
< op
->charcount
; i
++) {
1469 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
1472 for (i
= 0; i
< op
->charcount
; i
++) {
1477 } else if (w
<= 24) {
1478 for (i
= 0; i
< op
->charcount
; i
++) {
1479 for (j
= 0; j
< h
; j
++) {
1489 for (i
= 0; i
< op
->charcount
; i
++) {
1496 /* we can do it in u32 chunks because of charcount is 256 or 512, so
1497 font length must be multiple of 256, at least. And 256 is multiple
1500 while (p
> new_data
) k
+= *--(u32
*)p
;
1501 FNTSUM(new_data
) = k
;
1502 /* Check if the same font is on some other console already */
1503 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++) {
1504 if (fb_display
[i
].userfont
&&
1505 fb_display
[i
].fontdata
&&
1506 FNTSUM(fb_display
[i
].fontdata
) == k
&&
1507 FNTSIZE(fb_display
[i
].fontdata
) == size
&&
1508 !memcmp(fb_display
[i
].fontdata
, new_data
, size
)) {
1509 kfree(new_data
- FONT_EXTRA_WORDS
*sizeof(int));
1510 new_data
= fb_display
[i
].fontdata
;
1514 return fbcon_do_set_font(unit
, op
, new_data
, 1);
1517 static inline int fbcon_set_def_font(int unit
, struct console_font_op
*op
)
1519 char name
[MAX_FONT_NAME
];
1520 struct fbcon_font_desc
*f
;
1521 struct display
*p
= &fb_display
[unit
];
1524 f
= fbcon_get_default_font(p
->var
.xres
, p
->var
.yres
);
1525 else if (strncpy_from_user(name
, op
->data
, MAX_FONT_NAME
-1) < 0)
1528 name
[MAX_FONT_NAME
-1] = 0;
1529 if (!(f
= fbcon_find_font(name
)))
1532 op
->width
= f
->width
;
1533 op
->height
= f
->height
;
1534 return fbcon_do_set_font(unit
, op
, f
->data
, 0);
1537 static int fbcon_font_op(struct vc_data
*conp
, struct console_font_op
*op
)
1539 int unit
= conp
->vc_num
;
1542 case KD_FONT_OP_SET
:
1543 return fbcon_set_font(unit
, op
);
1544 case KD_FONT_OP_GET
:
1545 return fbcon_get_font(unit
, op
);
1546 case KD_FONT_OP_SET_DEFAULT
:
1547 return fbcon_set_def_font(unit
, op
);
1548 case KD_FONT_OP_COPY
:
1549 return fbcon_copy_font(unit
, op
);
1555 static u16 palette_red
[16];
1556 static u16 palette_green
[16];
1557 static u16 palette_blue
[16];
1559 static struct fb_cmap palette_cmap
= {
1560 0, 16, palette_red
, palette_green
, palette_blue
, NULL
1563 static int fbcon_set_palette(struct vc_data
*conp
, unsigned char *table
)
1565 int unit
= conp
->vc_num
;
1566 struct display
*p
= &fb_display
[unit
];
1570 if (!conp
->vc_can_do_color
|| (!p
->can_soft_blank
&& console_blanked
))
1572 for (i
= j
= 0; i
< 16; i
++) {
1574 val
= conp
->vc_palette
[j
++];
1575 palette_red
[k
] = (val
<<8)|val
;
1576 val
= conp
->vc_palette
[j
++];
1577 palette_green
[k
] = (val
<<8)|val
;
1578 val
= conp
->vc_palette
[j
++];
1579 palette_blue
[k
] = (val
<<8)|val
;
1581 if (p
->var
.bits_per_pixel
<= 4)
1582 palette_cmap
.len
= 1<<p
->var
.bits_per_pixel
;
1584 palette_cmap
.len
= 16;
1585 palette_cmap
.start
= 0;
1586 return p
->fb_info
->fbops
->fb_set_cmap(&palette_cmap
, 1, unit
, p
->fb_info
);
1589 static int fbcon_scrolldelta(struct vc_data
*conp
, int lines
)
1591 int unit
, offset
, limit
, scrollback_old
;
1594 if (!scrollback_phys_max
)
1597 scrollback_old
= scrollback_current
;
1598 scrollback_current
-= lines
;
1599 if (scrollback_current
< 0)
1600 scrollback_current
= 0;
1601 else if (scrollback_current
> scrollback_max
)
1602 scrollback_current
= scrollback_max
;
1603 if (scrollback_current
== scrollback_old
)
1607 p
= &fb_display
[unit
];
1608 if (!p
->can_soft_blank
&&
1609 (console_blanked
|| vt_cons
[unit
]->vc_mode
!= KD_TEXT
|| !lines
))
1611 fbcon_cursor(conp
, CM_ERASE
);
1613 offset
= p
->yscroll
-scrollback_current
;
1615 switch (p
->scrollmode
&& __SCROLL_YMASK
) {
1616 case __SCROLL_YWRAP
:
1617 p
->var
.vmode
|= FB_VMODE_YWRAP
;
1620 limit
-= conp
->vc_rows
;
1621 p
->var
.vmode
&= ~FB_VMODE_YWRAP
;
1626 else if (offset
>= limit
)
1629 p
->var
.yoffset
= offset
*fontheight(p
);
1630 p
->fb_info
->updatevar(unit
, p
->fb_info
);
1631 if (!scrollback_current
)
1632 fbcon_cursor(conp
, CM_DRAW
);
1636 static inline unsigned safe_shift(unsigned d
,int n
)
1638 return n
<0 ? d
>>-n
: d
<<n
;
1641 __initfunc(static int fbcon_show_logo( void ))
1643 struct display
*p
= &fb_display
[fg_console
]; /* draw to vt in foreground */
1644 int depth
= p
->var
.bits_per_pixel
;
1645 int line
= p
->next_line
;
1646 unsigned char *fb
= p
->screen_base
;
1647 unsigned char *logo
;
1648 unsigned char *dst
, *src
;
1649 int i
, j
, n
, x1
, y1
, x
;
1650 int logo_depth
, done
= 0;
1652 /* Return if the frame buffer is not mapped */
1656 /* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
1658 if ((p
->visual
== FB_VISUAL_PSEUDOCOLOR
&& depth
>= 4) ||
1659 p
->visual
== FB_VISUAL_DIRECTCOLOR
) {
1660 int is_truecolor
= (p
->visual
== FB_VISUAL_DIRECTCOLOR
);
1661 int use_256
= (!is_truecolor
&& depth
>= 8) ||
1662 (is_truecolor
&& depth
>= 24);
1663 int first_col
= use_256
? 32 : depth
> 4 ? 16 : 0;
1664 int num_cols
= use_256
? LINUX_LOGO_COLORS
: 16;
1665 unsigned char *red
, *green
, *blue
;
1668 red
= linux_logo_red
;
1669 green
= linux_logo_green
;
1670 blue
= linux_logo_blue
;
1673 red
= linux_logo16_red
;
1674 green
= linux_logo16_green
;
1675 blue
= linux_logo16_blue
;
1678 for( i
= 0; i
< num_cols
; i
+= n
) {
1681 /* palette_cmap provides space for only 16 colors at once */
1683 palette_cmap
.start
= first_col
+ i
;
1684 palette_cmap
.len
= n
;
1685 for( j
= 0; j
< n
; ++j
) {
1686 palette_cmap
.red
[j
] = (red
[i
+j
] << 8) | red
[i
+j
];
1687 palette_cmap
.green
[j
] = (green
[i
+j
] << 8) | green
[i
+j
];
1688 palette_cmap
.blue
[j
] = (blue
[i
+j
] << 8) | blue
[i
+j
];
1690 p
->fb_info
->fbops
->fb_set_cmap(&palette_cmap
, 1, fg_console
,
1699 else if (depth
>= 4) {
1700 logo
= linux_logo16
;
1704 logo
= linux_logo_bw
;
1708 for (x
= p
->var
.xres
- LOGO_W
; x
> 0 && x
> (int)p
->var
.xres
1709 - smp_num_cpus
* (LOGO_W
+ 8); x
-= (LOGO_W
+ 8)) {
1711 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
1712 defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
1713 if (p
->visual
== FB_VISUAL_DIRECTCOLOR
) {
1714 unsigned int val
; /* max. depth 32! */
1716 int redshift
, greenshift
, blueshift
;
1718 /* Bug: Doesn't obey msb_right ... (who needs that?) */
1719 redshift
= p
->var
.red
.offset
;
1720 greenshift
= p
->var
.green
.offset
;
1721 blueshift
= p
->var
.blue
.offset
;
1723 if (depth
>= 24 && (depth
% 8) == 0) {
1724 /* have at least 8 bits per color */
1727 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
1728 dst
= fb
+ y1
*line
+ x
*bdepth
;
1729 for( x1
= 0; x1
< LOGO_W
; x1
++, src
++ ) {
1730 val
= (*src
<< redshift
) |
1731 (*src
<< greenshift
) |
1732 (*src
<< blueshift
);
1733 #ifdef __LITTLE_ENDIAN
1734 for( i
= 0; i
< bdepth
; ++i
)
1736 for( i
= bdepth
-1; i
>= 0; --i
)
1738 *dst
++ = val
>> (i
*8);
1742 else if (depth
>= 15 && depth
<= 23) {
1743 /* have 5..7 bits per color, using 16 color image */
1746 bdepth
= (depth
+7)/8;
1747 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
1748 dst
= fb
+ y1
*line
+ x
*bdepth
;
1749 for( x1
= 0; x1
< LOGO_W
/2; x1
++, src
++ ) {
1750 pix
= (*src
>> 4) | 0x10; /* upper nibble */
1751 val
= (pix
<< redshift
) |
1752 (pix
<< greenshift
) |
1754 #ifdef __LITTLE_ENDIAN
1755 for( i
= 0; i
< bdepth
; ++i
)
1757 for( i
= bdepth
-1; i
>= 0; --i
)
1759 *dst
++ = val
>> (i
*8);
1760 pix
= (*src
& 0x0f) | 0x10; /* lower nibble */
1761 val
= (pix
<< redshift
) |
1762 (pix
<< greenshift
) |
1764 #ifdef __LITTLE_ENDIAN
1765 for( i
= 0; i
< bdepth
; ++i
)
1767 for( i
= bdepth
-1; i
>= 0; --i
)
1769 *dst
++ = val
>> (i
*8);
1776 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
1777 defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
1778 if ((depth
% 8 == 0) && (p
->visual
== FB_VISUAL_TRUECOLOR
)) {
1779 /* Modes without color mapping, needs special data transformation... */
1780 unsigned int val
; /* max. depth 32! */
1781 int bdepth
= depth
/8;
1782 unsigned char mask
[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
1783 unsigned char redmask
, greenmask
, bluemask
;
1784 int redshift
, greenshift
, blueshift
;
1786 /* Bug: Doesn't obey msb_right ... (who needs that?) */
1787 redmask
= mask
[p
->var
.red
.length
< 8 ? p
->var
.red
.length
: 8];
1788 greenmask
= mask
[p
->var
.green
.length
< 8 ? p
->var
.green
.length
: 8];
1789 bluemask
= mask
[p
->var
.blue
.length
< 8 ? p
->var
.blue
.length
: 8];
1790 redshift
= p
->var
.red
.offset
- (8-p
->var
.red
.length
);
1791 greenshift
= p
->var
.green
.offset
- (8-p
->var
.green
.length
);
1792 blueshift
= p
->var
.blue
.offset
- (8-p
->var
.blue
.length
);
1795 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
1796 dst
= fb
+ y1
*line
+ x
*bdepth
;
1797 for( x1
= 0; x1
< LOGO_W
; x1
++, src
++ ) {
1798 val
= safe_shift((linux_logo_red
[*src
-32] & redmask
), redshift
) |
1799 safe_shift((linux_logo_green
[*src
-32] & greenmask
), greenshift
) |
1800 safe_shift((linux_logo_blue
[*src
-32] & bluemask
), blueshift
);
1801 #ifdef __LITTLE_ENDIAN
1802 for( i
= 0; i
< bdepth
; ++i
)
1804 for( i
= bdepth
-1; i
>= 0; --i
)
1806 *dst
++ = val
>> (i
*8);
1812 #if defined(CONFIG_FBCON_CFB4)
1813 if (depth
== 4 && p
->type
== FB_TYPE_PACKED_PIXELS
) {
1815 for( y1
= 0; y1
< LOGO_H
; y1
++) {
1816 dst
= fb
+ y1
*line
+ x
/2;
1817 for( x1
= 0; x1
< LOGO_W
/2; x1
++) {
1819 q
= (q
<< 4) | (q
>> 4);
1826 #if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FB_SBUS)
1827 if (depth
== 8 && p
->type
== FB_TYPE_PACKED_PIXELS
) {
1828 /* depth 8 or more, packed, with color registers */
1831 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
1832 dst
= fb
+ y1
*line
+ x
;
1833 for( x1
= 0; x1
< LOGO_W
; x1
++ )
1839 #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
1840 defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
1841 defined(CONFIG_FBCON_IPLAN2P8)
1842 if (depth
>= 2 && (p
->type
== FB_TYPE_PLANES
||
1843 p
->type
== FB_TYPE_INTERLEAVED_PLANES
)) {
1844 /* planes (normal or interleaved), with color registers */
1846 unsigned char val
, mask
;
1847 int plane
= p
->next_plane
;
1849 #if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
1850 defined(CONFIG_FBCON_IPLAN2P8)
1851 int line_length
= p
->line_length
;
1853 /* for support of Atari interleaved planes */
1854 #define MAP_X(x) (line_length ? (x) : ((x) & ~1)*depth + ((x) & 1))
1856 #define MAP_X(x) (x)
1858 /* extract a bit from the source image */
1859 #define BIT(p,pix,bit) (p[pix*logo_depth/8] & \
1860 (1 << ((8-((pix*logo_depth)&7)-logo_depth) + bit)))
1863 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
1864 for( x1
= 0; x1
< LOGO_LINE
; x1
++, src
+= logo_depth
) {
1865 dst
= fb
+ y1
*line
+ MAP_X(x
/8+x1
);
1866 for( bit
= 0; bit
< logo_depth
; bit
++ ) {
1868 for( mask
= 0x80, i
= 0; i
< 8; mask
>>= 1, i
++ ) {
1869 if (BIT( src
, i
, bit
))
1878 /* fill remaining planes
1879 * special case for logo_depth == 4: we used color registers 16..31,
1880 * so fill plane 4 with 1 bits instead of 0 */
1881 if (depth
> logo_depth
) {
1882 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
1883 for( x1
= 0; x1
< LOGO_LINE
; x1
++ ) {
1884 dst
= fb
+ y1
*line
+ MAP_X(x
/8+x1
) + logo_depth
*plane
;
1885 for( i
= logo_depth
; i
< depth
; i
++, dst
+= plane
)
1886 *dst
= (i
== logo_depth
&& logo_depth
== 4)
1895 #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \
1896 defined(CONFIG_FBCON_ILBM)
1898 if (depth
== 1 && (p
->type
== FB_TYPE_PACKED_PIXELS
||
1899 p
->type
== FB_TYPE_PLANES
||
1900 p
->type
== FB_TYPE_INTERLEAVED_PLANES
)) {
1903 unsigned char inverse
= p
->inverse
? 0x00 : 0xff;
1905 /* can't use simply memcpy because need to apply inverse */
1906 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
1907 src
= logo
+ y1
*LOGO_LINE
+ x
/8;
1909 for( x1
= 0; x1
< LOGO_LINE
; ++x1
)
1910 *dst
++ = *src
++ ^ inverse
;
1917 /* Modes not yet supported: packed pixels with depth != 8 (does such a
1918 * thing exist in reality?) */
1920 return done
? (LOGO_H
+ fontheight(p
) - 1) / fontheight(p
) : 0 ;
1924 * The console `switch' structure for the frame buffer based console
1927 struct consw fb_con
= {
1928 con_startup
: fbcon_startup
,
1929 con_init
: fbcon_init
,
1930 con_deinit
: fbcon_deinit
,
1931 con_clear
: fbcon_clear
,
1932 con_putc
: fbcon_putc
,
1933 con_putcs
: fbcon_putcs
,
1934 con_cursor
: fbcon_cursor
,
1935 con_scroll
: fbcon_scroll
,
1936 con_bmove
: fbcon_bmove
,
1937 con_switch
: fbcon_switch
,
1938 con_blank
: fbcon_blank
,
1939 con_font_op
: fbcon_font_op
,
1940 con_set_palette
: fbcon_set_palette
,
1941 con_scrolldelta
: fbcon_scrolldelta
,
1942 con_set_origin
: NULL
,
1943 con_save_screen
: NULL
,
1944 con_build_attr
: NULL
,
1945 con_invert_region
: NULL
,
1950 * Dummy Low Level Operations
1953 static void fbcon_dummy_op(void) {}
1955 struct display_switch fbcon_dummy
= {
1956 (void *)fbcon_dummy_op
, /* fbcon_dummy_setup */
1957 (void *)fbcon_dummy_op
, /* fbcon_dummy_bmove */
1958 (void *)fbcon_dummy_op
, /* fbcon_dummy_clear */
1959 (void *)fbcon_dummy_op
, /* fbcon_dummy_putc */
1960 (void *)fbcon_dummy_op
, /* fbcon_dummy_putcs */
1961 (void *)fbcon_dummy_op
, /* fbcon_dummy_revc */
1962 NULL
, /* fbcon_dummy_cursor */
1967 * Visible symbols for modules
1970 EXPORT_SYMBOL(fb_display
);
1971 EXPORT_SYMBOL(fbcon_redraw_bmove
);
1972 EXPORT_SYMBOL(fbcon_dummy
);