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
29 * and software scrollback added by
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 #ifdef CONFIG_FBCON_VGA_PLANES
97 #define INCLUDE_LINUX_LOGO_DATA
98 #include <asm/linux_logo.h>
100 #include <video/fbcon.h>
101 #include <video/fbcon-mac.h> /* for 6x11 font on mac */
102 #include <video/font.h>
105 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
107 # define DPRINTK(fmt, args...)
112 #define LOGO_LINE (LOGO_W/8)
114 struct display fb_display
[MAX_NR_CONSOLES
];
115 char con2fb_map
[MAX_NR_CONSOLES
];
116 static int logo_lines
;
117 static int logo_shown
= -1;
118 /* Software scrollback */
119 int fbcon_softback_size
= 32768;
120 static unsigned long softback_buf
, softback_curr
;
121 static unsigned long softback_in
;
122 static unsigned long softback_top
, softback_end
;
123 static int softback_lines
;
125 #define REFCOUNT(fd) (((int *)(fd))[-1])
126 #define FNTSIZE(fd) (((int *)(fd))[-2])
127 #define FNTCHARCNT(fd) (((int *)(fd))[-3])
128 #define FNTSUM(fd) (((int *)(fd))[-4])
129 #define FONT_EXTRA_WORDS 4
131 #define CM_SOFTBACK (8)
133 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * conp->vc_size_row)
135 static void fbcon_free_font(struct display
*);
136 static int fbcon_set_origin(struct vc_data
*);
139 * Emmanuel: fbcon will now use a hardware cursor if the
140 * low-level driver provides a non-NULL dispsw->cursor pointer,
141 * in which case the hardware should do blinking, etc.
143 * if dispsw->cursor is NULL, use Atari alike software cursor
146 static int cursor_drawn
;
148 #define CURSOR_DRAW_DELAY (1)
150 /* # VBL ints between cursor state changes */
151 #define ARM_CURSOR_BLINK_RATE (10)
152 #define AMIGA_CURSOR_BLINK_RATE (20)
153 #define ATARI_CURSOR_BLINK_RATE (42)
154 #define MAC_CURSOR_BLINK_RATE (32)
155 #define DEFAULT_CURSOR_BLINK_RATE (20)
157 static int vbl_cursor_cnt
;
158 static int cursor_on
;
159 static int cursor_blink_rate
;
161 static inline void cursor_undrawn(void)
168 #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
172 * Interface used by the world
175 static const char *fbcon_startup(void);
176 static void fbcon_init(struct vc_data
*conp
, int init
);
177 static void fbcon_deinit(struct vc_data
*conp
);
178 static int fbcon_changevar(int con
);
179 static void fbcon_clear(struct vc_data
*conp
, int sy
, int sx
, int height
,
181 static void fbcon_putc(struct vc_data
*conp
, int c
, int ypos
, int xpos
);
182 static void fbcon_putcs(struct vc_data
*conp
, const unsigned short *s
, int count
,
184 static void fbcon_cursor(struct vc_data
*conp
, int mode
);
185 static int fbcon_scroll(struct vc_data
*conp
, int t
, int b
, int dir
,
187 static void fbcon_bmove(struct vc_data
*conp
, int sy
, int sx
, int dy
, int dx
,
188 int height
, int width
);
189 static int fbcon_switch(struct vc_data
*conp
);
190 static int fbcon_blank(struct vc_data
*conp
, int blank
);
191 static int fbcon_font_op(struct vc_data
*conp
, struct console_font_op
*op
);
192 static int fbcon_set_palette(struct vc_data
*conp
, unsigned char *table
);
193 static int fbcon_scrolldelta(struct vc_data
*conp
, int lines
);
200 static void fbcon_setup(int con
, int init
, int logo
);
201 static __inline__
int real_y(struct display
*p
, int ypos
);
202 static void fbcon_vbl_handler(int irq
, void *dummy
, struct pt_regs
*fp
);
203 static __inline__
void updatescrollmode(struct display
*p
);
204 static __inline__
void ywrap_up(int unit
, struct vc_data
*conp
,
205 struct display
*p
, int count
);
206 static __inline__
void ywrap_down(int unit
, struct vc_data
*conp
,
207 struct display
*p
, int count
);
208 static __inline__
void ypan_up(int unit
, struct vc_data
*conp
,
209 struct display
*p
, int count
);
210 static __inline__
void ypan_down(int unit
, struct vc_data
*conp
,
211 struct display
*p
, int count
);
212 static void fbcon_bmove_rec(struct display
*p
, int sy
, int sx
, int dy
, int dx
,
213 int height
, int width
, u_int y_break
);
215 static int fbcon_show_logo(void);
219 * On the Macintoy, there may or may not be a working VBL int. We need to probe
221 static int vbl_detected
;
223 static void fbcon_vbl_detect(int irq
, void *dummy
, struct pt_regs
*fp
)
229 static void cursor_timer_handler(unsigned long dev_addr
);
231 static struct timer_list cursor_timer
= {
232 function
: cursor_timer_handler
235 static void cursor_timer_handler(unsigned long dev_addr
)
237 fbcon_vbl_handler(0, NULL
, NULL
);
238 cursor_timer
.expires
= jiffies
+HZ
/50;
239 add_timer(&cursor_timer
);
242 int PROC_CONSOLE(const struct fb_info
*info
)
246 if (info
->display_fg
!= NULL
)
247 fgc
= info
->display_fg
->vc_num
;
254 if (current
->tty
->driver
.type
!= TTY_DRIVER_TYPE_CONSOLE
)
255 /* XXX Should report error here? */
258 if (MINOR(current
->tty
->device
) < 1)
261 return MINOR(current
->tty
->device
) - 1;
264 int set_all_vcs(int fbidx
, struct fb_ops
*fb
, struct fb_var_screeninfo
*var
,
265 struct fb_info
*info
)
269 var
->activate
|= FB_ACTIVATE_TEST
;
270 err
= fb
->fb_set_var(var
, PROC_CONSOLE(info
), info
);
271 var
->activate
&= ~FB_ACTIVATE_TEST
;
274 for (unit
= 0; unit
< MAX_NR_CONSOLES
; unit
++)
275 if (fb_display
[unit
].conp
&& con2fb_map
[unit
] == fbidx
)
276 fb
->fb_set_var(var
, unit
, info
);
280 void set_con2fb_map(int unit
, int newidx
)
282 int oldidx
= con2fb_map
[unit
];
283 struct fb_info
*oldfb
, *newfb
;
284 struct vc_data
*conp
;
286 unsigned short fontwidth
, fontheight
, fontwidthlog
, fontheightlog
;
289 if (newidx
!= con2fb_map
[unit
]) {
290 oldfb
= registered_fb
[oldidx
];
291 newfb
= registered_fb
[newidx
];
292 if (newfb
->fbops
->owner
)
293 __MOD_INC_USE_COUNT(newfb
->fbops
->owner
);
294 if (newfb
->fbops
->fb_open
&& newfb
->fbops
->fb_open(newfb
,0)) {
295 if (newfb
->fbops
->owner
)
296 __MOD_DEC_USE_COUNT(newfb
->fbops
->owner
);
299 if (oldfb
->fbops
->fb_release
)
300 oldfb
->fbops
->fb_release(oldfb
,0);
301 if (oldfb
->fbops
->owner
)
302 __MOD_DEC_USE_COUNT(oldfb
->fbops
->owner
);
303 conp
= fb_display
[unit
].conp
;
304 fontdata
= fb_display
[unit
].fontdata
;
305 fontwidth
= fb_display
[unit
]._fontwidth
;
306 fontheight
= fb_display
[unit
]._fontheight
;
307 fontwidthlog
= fb_display
[unit
]._fontwidthlog
;
308 fontheightlog
= fb_display
[unit
]._fontheightlog
;
309 userfont
= fb_display
[unit
].userfont
;
310 con2fb_map
[unit
] = newidx
;
311 fb_display
[unit
] = *(newfb
->disp
);
312 fb_display
[unit
].conp
= conp
;
313 fb_display
[unit
].fontdata
= fontdata
;
314 fb_display
[unit
]._fontwidth
= fontwidth
;
315 fb_display
[unit
]._fontheight
= fontheight
;
316 fb_display
[unit
]._fontwidthlog
= fontwidthlog
;
317 fb_display
[unit
]._fontheightlog
= fontheightlog
;
318 fb_display
[unit
].userfont
= userfont
;
319 fb_display
[unit
].fb_info
= newfb
;
321 conp
->vc_display_fg
= &newfb
->display_fg
;
322 if (!newfb
->display_fg
)
323 newfb
->display_fg
= conp
;
324 if (!newfb
->changevar
)
325 newfb
->changevar
= oldfb
->changevar
;
326 /* tell console var has changed */
327 if (newfb
->changevar
)
328 newfb
->changevar(unit
);
333 * Low Level Operations
336 struct display_switch fbcon_dummy
;
338 /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
340 static const char *fbcon_startup(void)
342 const char *display_desc
= "frame buffer device";
347 * If num_registered_fb is zero, this is a call for the dummy part.
348 * The frame buffer devices weren't initialized yet.
350 if (!num_registered_fb
|| done
)
356 cursor_blink_rate
= AMIGA_CURSOR_BLINK_RATE
;
357 irqres
= request_irq(IRQ_AMIGA_VERTB
, fbcon_vbl_handler
, 0,
358 "console/cursor", fbcon_vbl_handler
);
360 #endif /* CONFIG_AMIGA */
363 cursor_blink_rate
= ATARI_CURSOR_BLINK_RATE
;
364 irqres
= request_irq(IRQ_AUTO_4
, fbcon_vbl_handler
, IRQ_TYPE_PRIO
,
365 "console/cursor", fbcon_vbl_handler
);
367 #endif /* CONFIG_ATARI */
371 * On a Macintoy, the VBL interrupt may or may not be active.
372 * As interrupt based cursor is more reliable and race free, we
373 * probe for VBL interrupts.
378 * Probe for VBL: set temp. handler ...
380 irqres
= request_irq(IRQ_MAC_VBL
, fbcon_vbl_detect
, 0,
381 "console/cursor", fbcon_vbl_detect
);
385 * ... and spin for 20 ms ...
387 while (!vbl_detected
&& ++ct
<1000)
391 printk("fbcon_startup: No VBL detected, using timer based cursor.\n");
393 free_irq(IRQ_MAC_VBL
, fbcon_vbl_detect
);
397 * interrupt based cursor ok
399 cursor_blink_rate
= MAC_CURSOR_BLINK_RATE
;
400 irqres
= request_irq(IRQ_MAC_VBL
, fbcon_vbl_handler
, 0,
401 "console/cursor", fbcon_vbl_handler
);
404 * VBL not detected: fall through, use timer based cursor
409 #endif /* CONFIG_MAC */
411 #if defined(__arm__) && defined(IRQ_VSYNCPULSE)
412 cursor_blink_rate
= ARM_CURSOR_BLINK_RATE
;
413 irqres
= request_irq(IRQ_VSYNCPULSE
, fbcon_vbl_handler
, SA_SHIRQ
,
414 "console/cursor", fbcon_vbl_handler
);
418 cursor_blink_rate
= DEFAULT_CURSOR_BLINK_RATE
;
419 cursor_timer
.expires
= jiffies
+HZ
/50;
420 add_timer(&cursor_timer
);
427 static void fbcon_init(struct vc_data
*conp
, int init
)
429 int unit
= conp
->vc_num
;
430 struct fb_info
*info
;
432 /* on which frame buffer will we open this console? */
433 info
= registered_fb
[(int)con2fb_map
[unit
]];
435 info
->changevar
= &fbcon_changevar
;
436 fb_display
[unit
] = *(info
->disp
); /* copy from default */
437 DPRINTK("mode: %s\n",info
->modename
);
438 DPRINTK("visual: %d\n",fb_display
[unit
].visual
);
439 DPRINTK("res: %dx%d-%d\n",fb_display
[unit
].var
.xres
,
440 fb_display
[unit
].var
.yres
,
441 fb_display
[unit
].var
.bits_per_pixel
);
442 fb_display
[unit
].conp
= conp
;
443 fb_display
[unit
].fb_info
= info
;
444 /* clear out the cmap so we don't have dangling pointers */
445 fb_display
[unit
].cmap
.len
= 0;
446 fb_display
[unit
].cmap
.red
= 0;
447 fb_display
[unit
].cmap
.green
= 0;
448 fb_display
[unit
].cmap
.blue
= 0;
449 fb_display
[unit
].cmap
.transp
= 0;
450 fbcon_setup(unit
, init
, !init
);
451 /* Must be done after fbcon_setup to prevent excess updates */
452 conp
->vc_display_fg
= &info
->display_fg
;
453 if (!info
->display_fg
)
454 info
->display_fg
= conp
;
458 static void fbcon_deinit(struct vc_data
*conp
)
460 int unit
= conp
->vc_num
;
461 struct display
*p
= &fb_display
[unit
];
464 p
->dispsw
= &fbcon_dummy
;
469 static int fbcon_changevar(int con
)
471 if (fb_display
[con
].conp
)
472 fbcon_setup(con
, 0, 0);
477 static __inline__
void updatescrollmode(struct display
*p
)
480 if (p
->scrollmode
& __SCROLL_YFIXED
)
482 if (divides(p
->ywrapstep
, fontheight(p
)) &&
483 divides(fontheight(p
), p
->var
.yres_virtual
))
485 else if (divides(p
->ypanstep
, fontheight(p
)) &&
486 p
->var
.yres_virtual
>= p
->var
.yres
+fontheight(p
))
488 else if (p
->scrollmode
& __SCROLL_YNOMOVE
)
489 m
= __SCROLL_YREDRAW
;
492 p
->scrollmode
= (p
->scrollmode
& ~__SCROLL_YMASK
) | m
;
495 static void fbcon_font_widths(struct display
*p
)
499 p
->_fontwidthlog
= 0;
500 for (i
= 2; i
<= 6; i
++)
501 if (fontwidth(p
) == (1 << i
))
502 p
->_fontwidthlog
= i
;
503 p
->_fontheightlog
= 0;
504 for (i
= 2; i
<= 6; i
++)
505 if (fontheight(p
) == (1 << i
))
506 p
->_fontheightlog
= i
;
509 #define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))
511 static void fbcon_setup(int con
, int init
, int logo
)
513 struct display
*p
= &fb_display
[con
];
514 struct vc_data
*conp
= p
->conp
;
515 int nr_rows
, nr_cols
;
516 int old_rows
, old_cols
;
517 unsigned short *save
= NULL
, *r
, *q
;
518 int i
, charcnt
= 256;
519 struct fbcon_font_desc
*font
;
521 if (con
!= fg_console
|| (p
->fb_info
->flags
& FBINFO_FLAG_MODULE
) ||
522 p
->type
== FB_TYPE_TEXT
)
525 p
->var
.xoffset
= p
->var
.yoffset
= p
->yscroll
= 0; /* reset wrap/pan */
527 if (con
== fg_console
&& p
->type
!= FB_TYPE_TEXT
) {
528 if (fbcon_softback_size
) {
530 softback_buf
= (unsigned long)kmalloc(fbcon_softback_size
, GFP_KERNEL
);
532 fbcon_softback_size
= 0;
538 kfree((void *)softback_buf
);
544 softback_in
= softback_top
= softback_curr
= softback_buf
;
548 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
549 if (i
!= con
&& fb_display
[i
].fb_info
== p
->fb_info
&&
550 fb_display
[i
].conp
&& fb_display
[i
].fontdata
)
554 if (i
< MAX_NR_CONSOLES
) {
555 struct display
*q
= &fb_display
[i
];
557 if (fontwidthvalid(p
,fontwidth(q
))) {
558 /* If we are not the first console on this
559 fb, copy the font from that console */
560 p
->_fontwidth
= q
->_fontwidth
;
561 p
->_fontheight
= q
->_fontheight
;
562 p
->_fontwidthlog
= q
->_fontwidthlog
;
563 p
->_fontheightlog
= q
->_fontheightlog
;
564 p
->fontdata
= q
->fontdata
;
565 p
->userfont
= q
->userfont
;
567 REFCOUNT(p
->fontdata
)++;
568 charcnt
= FNTCHARCNT(p
->fontdata
);
570 con_copy_unimap(con
, i
);
575 if (!p
->fb_info
->fontname
[0] ||
576 !(font
= fbcon_find_font(p
->fb_info
->fontname
)))
577 font
= fbcon_get_default_font(p
->var
.xres
, p
->var
.yres
);
578 p
->_fontwidth
= font
->width
;
579 p
->_fontheight
= font
->height
;
580 p
->fontdata
= font
->data
;
581 fbcon_font_widths(p
);
584 if (!fontwidthvalid(p
,fontwidth(p
))) {
587 /* ++Geert: hack to make 6x11 fonts work on mac */
588 p
->dispsw
= &fbcon_mac
;
592 /* ++Geert: changed from panic() to `correct and continue' */
593 printk(KERN_ERR
"fbcon_setup: No support for fontwidth %d\n", fontwidth(p
));
594 p
->dispsw
= &fbcon_dummy
;
597 if (p
->dispsw
->set_font
)
598 p
->dispsw
->set_font(p
, fontwidth(p
), fontheight(p
));
601 old_cols
= conp
->vc_cols
;
602 old_rows
= conp
->vc_rows
;
604 nr_cols
= p
->var
.xres
/fontwidth(p
);
605 nr_rows
= p
->var
.yres
/fontheight(p
);
608 /* Need to make room for the logo */
612 logo_lines
= (LOGO_H
+ fontheight(p
) - 1) / fontheight(p
);
613 q
= (unsigned short *)(conp
->vc_origin
+ conp
->vc_size_row
* old_rows
);
614 step
= logo_lines
* old_cols
;
615 for (r
= q
- logo_lines
* old_cols
; r
< q
; r
++)
616 if (scr_readw(r
) != conp
->vc_video_erase_char
)
618 if (r
!= q
&& nr_rows
>= old_rows
+ logo_lines
) {
619 save
= kmalloc(logo_lines
* nr_cols
* 2, GFP_KERNEL
);
621 int i
= old_cols
< nr_cols
? old_cols
: nr_cols
;
622 scr_memsetw(save
, conp
->vc_video_erase_char
, logo_lines
* nr_cols
* 2);
624 for (cnt
= 0; cnt
< logo_lines
; cnt
++, r
+= i
)
625 scr_memcpyw_from(save
+ cnt
* nr_cols
, r
, 2 * i
);
630 /* We can scroll screen down */
631 r
= q
- step
- old_cols
;
632 for (cnt
= old_rows
- logo_lines
; cnt
> 0; cnt
--) {
633 scr_memcpyw(r
+ step
, r
, conp
->vc_size_row
);
637 conp
->vc_y
+= logo_lines
;
638 conp
->vc_pos
+= logo_lines
* conp
->vc_size_row
;
641 scr_memsetw((unsigned short *)conp
->vc_origin
,
642 conp
->vc_video_erase_char
,
643 conp
->vc_size_row
* logo_lines
);
647 * ++guenther: console.c:vc_allocate() relies on initializing
648 * vc_{cols,rows}, but we must not set those if we are only
649 * resizing the console.
652 conp
->vc_cols
= nr_cols
;
653 conp
->vc_rows
= nr_rows
;
655 p
->vrows
= p
->var
.yres_virtual
/fontheight(p
);
656 if ((p
->var
.yres
% fontheight(p
)) &&
657 (p
->var
.yres_virtual
% fontheight(p
) < p
->var
.yres
% fontheight(p
)))
659 conp
->vc_can_do_color
= p
->var
.bits_per_pixel
!= 1;
660 conp
->vc_complement_mask
= conp
->vc_can_do_color
? 0x7700 : 0x0800;
661 if (charcnt
== 256) {
662 conp
->vc_hi_font_mask
= 0;
667 conp
->vc_hi_font_mask
= 0x100;
668 if (conp
->vc_can_do_color
)
669 conp
->vc_complement_mask
<<= 1;
675 if (p
->dispsw
== &fbcon_dummy
)
676 printk(KERN_WARNING
"fbcon_setup: type %d (aux %d, depth %d) not "
677 "supported\n", p
->type
, p
->type_aux
, p
->var
.bits_per_pixel
);
680 p
->fgcol
= p
->var
.bits_per_pixel
> 2 ? 7 : (1<<p
->var
.bits_per_pixel
)-1;
684 if (conp
->vc_cols
!= nr_cols
|| conp
->vc_rows
!= nr_rows
)
685 vc_resize_con(nr_rows
, nr_cols
, con
);
686 else if (CON_IS_VISIBLE(conp
) &&
687 vt_cons
[conp
->vc_num
]->vc_mode
== KD_TEXT
) {
688 if (p
->dispsw
->clear_margins
)
689 p
->dispsw
->clear_margins(conp
, p
, 0);
693 q
= (unsigned short *)(conp
->vc_origin
+ conp
->vc_size_row
* old_rows
);
694 scr_memcpyw(q
, save
, logo_lines
* nr_cols
* 2);
695 conp
->vc_y
+= logo_lines
;
696 conp
->vc_pos
+= logo_lines
* conp
->vc_size_row
;
703 conp
->vc_top
= logo_lines
;
706 if (con
== fg_console
&& softback_buf
) {
707 int l
= fbcon_softback_size
/ conp
->vc_size_row
;
709 softback_end
= softback_buf
+ l
* conp
->vc_size_row
;
711 /* Smaller scrollback makes no sense, and 0 would screw
712 the operation totally */
719 /* ====================================================================== */
721 /* fbcon_XXX routines - interface used by the world
723 * This system is now divided into two levels because of complications
724 * caused by hardware scrolling. Top level functions:
726 * fbcon_bmove(), fbcon_clear(), fbcon_putc()
728 * handles y values in range [0, scr_height-1] that correspond to real
729 * screen positions. y_wrap shift means that first line of bitmap may be
730 * anywhere on this display. These functions convert lineoffsets to
731 * bitmap offsets and deal with the wrap-around case by splitting blits.
733 * fbcon_bmove_physical_8() -- These functions fast implementations
734 * fbcon_clear_physical_8() -- of original fbcon_XXX fns.
735 * fbcon_putc_physical_8() -- (fontwidth != 8) may be added later
739 * At the moment fbcon_putc() cannot blit across vertical wrap boundary
740 * Implies should only really hardware scroll in rows. Only reason for
741 * restriction is simplicity & efficiency at the moment.
744 static __inline__
int real_y(struct display
*p
, int ypos
)
749 return ypos
< rows
? ypos
: ypos
-rows
;
753 static void fbcon_clear(struct vc_data
*conp
, int sy
, int sx
, int height
,
756 int unit
= conp
->vc_num
;
757 struct display
*p
= &fb_display
[unit
];
759 int redraw_cursor
= 0;
761 if (!p
->can_soft_blank
&& console_blanked
)
764 if (!height
|| !width
)
767 if ((sy
<= p
->cursor_y
) && (p
->cursor_y
< sy
+height
) &&
768 (sx
<= p
->cursor_x
) && (p
->cursor_x
< sx
+width
)) {
773 /* Split blits that cross physical y_wrap boundary */
775 y_break
= p
->vrows
-p
->yscroll
;
776 if (sy
< y_break
&& sy
+height
-1 >= y_break
) {
777 u_int b
= y_break
-sy
;
778 p
->dispsw
->clear(conp
, p
, real_y(p
, sy
), sx
, b
, width
);
779 p
->dispsw
->clear(conp
, p
, real_y(p
, sy
+b
), sx
, height
-b
, width
);
781 p
->dispsw
->clear(conp
, p
, real_y(p
, sy
), sx
, height
, width
);
784 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
788 static void fbcon_putc(struct vc_data
*conp
, int c
, int ypos
, int xpos
)
790 int unit
= conp
->vc_num
;
791 struct display
*p
= &fb_display
[unit
];
792 int redraw_cursor
= 0;
794 if (!p
->can_soft_blank
&& console_blanked
)
797 if (vt_cons
[unit
]->vc_mode
!= KD_TEXT
)
800 if ((p
->cursor_x
== xpos
) && (p
->cursor_y
== ypos
)) {
805 p
->dispsw
->putc(conp
, p
, c
, real_y(p
, ypos
), xpos
);
808 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
812 static void fbcon_putcs(struct vc_data
*conp
, const unsigned short *s
, int count
,
815 int unit
= conp
->vc_num
;
816 struct display
*p
= &fb_display
[unit
];
817 int redraw_cursor
= 0;
819 if (!p
->can_soft_blank
&& console_blanked
)
822 if (vt_cons
[unit
]->vc_mode
!= KD_TEXT
)
825 if ((p
->cursor_y
== ypos
) && (xpos
<= p
->cursor_x
) &&
826 (p
->cursor_x
< (xpos
+ count
))) {
830 p
->dispsw
->putcs(conp
, p
, s
, count
, real_y(p
, ypos
), xpos
);
832 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
836 static void fbcon_cursor(struct vc_data
*conp
, int mode
)
838 int unit
= conp
->vc_num
;
839 struct display
*p
= &fb_display
[unit
];
842 if (mode
& CM_SOFTBACK
) {
843 mode
&= ~CM_SOFTBACK
;
844 if (softback_lines
) {
845 if (y
+ softback_lines
>= conp
->vc_rows
)
850 } else if (softback_lines
)
851 fbcon_set_origin(conp
);
853 /* do we have a hardware cursor ? */
854 if (p
->dispsw
->cursor
) {
855 p
->cursor_x
= conp
->vc_x
;
857 p
->dispsw
->cursor(p
, mode
, p
->cursor_x
, real_y(p
, p
->cursor_y
));
861 /* Avoid flickering if there's no real change. */
862 if (p
->cursor_x
== conp
->vc_x
&& p
->cursor_y
== y
&&
863 (mode
== CM_ERASE
) == !cursor_on
)
868 p
->dispsw
->revc(p
, p
->cursor_x
, real_y(p
, p
->cursor_y
));
870 p
->cursor_x
= conp
->vc_x
;
880 p
->dispsw
->revc(p
, p
->cursor_x
, real_y(p
, p
->cursor_y
));
881 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
888 static void fbcon_vbl_handler(int irq
, void *dummy
, struct pt_regs
*fp
)
895 if (vbl_cursor_cnt
&& --vbl_cursor_cnt
== 0) {
896 p
= &fb_display
[fg_console
];
898 p
->dispsw
->revc(p
, p
->cursor_x
, real_y(p
, p
->cursor_y
));
900 vbl_cursor_cnt
= cursor_blink_rate
;
904 static int scrollback_phys_max
= 0;
905 static int scrollback_max
= 0;
906 static int scrollback_current
= 0;
908 static __inline__
void ywrap_up(int unit
, struct vc_data
*conp
,
909 struct display
*p
, int count
)
912 if (p
->yscroll
>= p
->vrows
) /* Deal with wrap */
913 p
->yscroll
-= p
->vrows
;
915 p
->var
.yoffset
= p
->yscroll
*fontheight(p
);
916 p
->var
.vmode
|= FB_VMODE_YWRAP
;
917 p
->fb_info
->updatevar(unit
, p
->fb_info
);
918 scrollback_max
+= count
;
919 if (scrollback_max
> scrollback_phys_max
)
920 scrollback_max
= scrollback_phys_max
;
921 scrollback_current
= 0;
925 static __inline__
void ywrap_down(int unit
, struct vc_data
*conp
,
926 struct display
*p
, int count
)
929 if (p
->yscroll
< 0) /* Deal with wrap */
930 p
->yscroll
+= p
->vrows
;
932 p
->var
.yoffset
= p
->yscroll
*fontheight(p
);
933 p
->var
.vmode
|= FB_VMODE_YWRAP
;
934 p
->fb_info
->updatevar(unit
, p
->fb_info
);
935 scrollback_max
-= count
;
936 if (scrollback_max
< 0)
938 scrollback_current
= 0;
942 static __inline__
void ypan_up(int unit
, struct vc_data
*conp
,
943 struct display
*p
, int count
)
946 if (p
->yscroll
> p
->vrows
-conp
->vc_rows
) {
947 p
->dispsw
->bmove(p
, p
->vrows
-conp
->vc_rows
, 0, 0, 0,
948 conp
->vc_rows
, conp
->vc_cols
);
949 p
->yscroll
-= p
->vrows
-conp
->vc_rows
;
952 p
->var
.yoffset
= p
->yscroll
*fontheight(p
);
953 p
->var
.vmode
&= ~FB_VMODE_YWRAP
;
954 p
->fb_info
->updatevar(unit
, p
->fb_info
);
955 if (p
->dispsw
->clear_margins
)
956 p
->dispsw
->clear_margins(conp
, p
, 1);
957 scrollback_max
+= count
;
958 if (scrollback_max
> scrollback_phys_max
)
959 scrollback_max
= scrollback_phys_max
;
960 scrollback_current
= 0;
964 static __inline__
void ypan_down(int unit
, struct vc_data
*conp
,
965 struct display
*p
, int count
)
968 if (p
->yscroll
< 0) {
969 p
->dispsw
->bmove(p
, 0, 0, p
->vrows
-conp
->vc_rows
, 0,
970 conp
->vc_rows
, conp
->vc_cols
);
971 p
->yscroll
+= p
->vrows
-conp
->vc_rows
;
974 p
->var
.yoffset
= p
->yscroll
*fontheight(p
);
975 p
->var
.vmode
&= ~FB_VMODE_YWRAP
;
976 p
->fb_info
->updatevar(unit
, p
->fb_info
);
977 if (p
->dispsw
->clear_margins
)
978 p
->dispsw
->clear_margins(conp
, p
, 1);
979 scrollback_max
-= count
;
980 if (scrollback_max
< 0)
982 scrollback_current
= 0;
985 static void fbcon_redraw_softback(struct vc_data
*conp
, struct display
*p
, long delta
)
987 unsigned short *d
, *s
;
990 int count
= conp
->vc_rows
;
992 d
= (u16
*)softback_curr
;
993 if (d
== (u16
*)softback_in
)
994 d
= (u16
*)conp
->vc_origin
;
995 n
= softback_curr
+ delta
* conp
->vc_size_row
;
996 softback_lines
-= delta
;
998 if (softback_curr
< softback_top
&& n
< softback_buf
) {
999 n
+= softback_end
- softback_buf
;
1000 if (n
< softback_top
) {
1001 softback_lines
-= (softback_top
- n
) / conp
->vc_size_row
;
1004 } else if (softback_curr
>= softback_top
&& n
< softback_top
) {
1005 softback_lines
-= (softback_top
- n
) / conp
->vc_size_row
;
1009 if (softback_curr
> softback_in
&& n
>= softback_end
) {
1010 n
+= softback_buf
- softback_end
;
1011 if (n
> softback_in
) {
1015 } else if (softback_curr
<= softback_in
&& n
> softback_in
) {
1020 if (n
== softback_curr
)
1023 s
= (u16
*)softback_curr
;
1024 if (s
== (u16
*)softback_in
)
1025 s
= (u16
*)conp
->vc_origin
;
1027 unsigned short *start
;
1031 unsigned short attr
= 1;
1034 le
= advance_row(s
, 1);
1037 if (attr
!= (c
& 0xff00)) {
1040 p
->dispsw
->putcs(conp
, p
, start
, s
- start
,
1041 real_y(p
, line
), x
);
1046 if (c
== scr_readw(d
)) {
1048 p
->dispsw
->putcs(conp
, p
, start
, s
- start
,
1049 real_y(p
, line
), x
);
1061 p
->dispsw
->putcs(conp
, p
, start
, s
- start
, real_y(p
, line
), x
);
1063 if (d
== (u16
*)softback_end
)
1064 d
= (u16
*)softback_buf
;
1065 if (d
== (u16
*)softback_in
)
1066 d
= (u16
*)conp
->vc_origin
;
1067 if (s
== (u16
*)softback_end
)
1068 s
= (u16
*)softback_buf
;
1069 if (s
== (u16
*)softback_in
)
1070 s
= (u16
*)conp
->vc_origin
;
1074 static void fbcon_redraw(struct vc_data
*conp
, struct display
*p
,
1075 int line
, int count
, int offset
)
1077 unsigned short *d
= (unsigned short *)
1078 (conp
->vc_origin
+ conp
->vc_size_row
* line
);
1079 unsigned short *s
= d
+ offset
;
1082 unsigned short *start
= s
;
1083 unsigned short *le
= advance_row(s
, 1);
1086 unsigned short attr
= 1;
1090 if (attr
!= (c
& 0xff00)) {
1093 p
->dispsw
->putcs(conp
, p
, start
, s
- start
,
1094 real_y(p
, line
), x
);
1099 if (c
== scr_readw(d
)) {
1101 p
->dispsw
->putcs(conp
, p
, start
, s
- start
,
1102 real_y(p
, line
), x
);
1115 p
->dispsw
->putcs(conp
, p
, start
, s
- start
, real_y(p
, line
), x
);
1120 /* NOTE: We subtract two lines from these pointers */
1121 s
-= conp
->vc_size_row
;
1122 d
-= conp
->vc_size_row
;
1127 void fbcon_redraw_clear(struct vc_data
*conp
, struct display
*p
, int sy
, int sx
,
1128 int height
, int width
)
1131 for (y
=0; y
<height
; y
++)
1132 for (x
=0; x
<width
; x
++)
1133 fbcon_putc(conp
, ' ', sy
+y
, sx
+x
);
1136 /* This cannot be used together with ypan or ywrap */
1137 void fbcon_redraw_bmove(struct display
*p
, int sy
, int sx
, int dy
, int dx
, int h
, int w
)
1140 panic("fbcon_redraw_bmove width sy != dy");
1141 /* h will be always 1, but it does not matter if we are more generic */
1144 struct vc_data
*conp
= p
->conp
;
1145 unsigned short *d
= (unsigned short *)
1146 (conp
->vc_origin
+ conp
->vc_size_row
* dy
+ dx
* 2);
1147 unsigned short *s
= d
+ (dx
- sx
);
1148 unsigned short *start
= d
;
1149 unsigned short *ls
= d
;
1150 unsigned short *le
= d
+ w
;
1153 unsigned short attr
= 1;
1157 if (attr
!= (c
& 0xff00)) {
1160 p
->dispsw
->putcs(conp
, p
, start
, d
- start
, dy
, x
);
1165 if (s
>= ls
&& s
< le
&& c
== scr_readw(s
)) {
1167 p
->dispsw
->putcs(conp
, p
, start
, d
- start
, dy
, x
);
1179 p
->dispsw
->putcs(conp
, p
, start
, d
- start
, dy
, x
);
1185 static inline void fbcon_softback_note(struct vc_data
*conp
, int t
, int count
)
1189 if (conp
->vc_num
!= fg_console
)
1191 p
= (unsigned short *)(conp
->vc_origin
+ t
* conp
->vc_size_row
);
1194 scr_memcpyw((u16
*)softback_in
, p
, conp
->vc_size_row
);
1196 p
= advance_row(p
, 1);
1197 softback_in
+= conp
->vc_size_row
;
1198 if (softback_in
== softback_end
)
1199 softback_in
= softback_buf
;
1200 if (softback_in
== softback_top
) {
1201 softback_top
+= conp
->vc_size_row
;
1202 if (softback_top
== softback_end
)
1203 softback_top
= softback_buf
;
1206 softback_curr
= softback_in
;
1209 static int fbcon_scroll(struct vc_data
*conp
, int t
, int b
, int dir
,
1212 int unit
= conp
->vc_num
;
1213 struct display
*p
= &fb_display
[unit
];
1214 int scroll_partial
= !(p
->scrollmode
& __SCROLL_YNOPARTIAL
);
1216 if (!p
->can_soft_blank
&& console_blanked
)
1219 if (!count
|| vt_cons
[unit
]->vc_mode
!= KD_TEXT
)
1222 fbcon_cursor(conp
, CM_ERASE
);
1225 * ++Geert: Only use ywrap/ypan if the console is in text mode
1226 * ++Andrew: Only use ypan on hardware text mode when scrolling the
1227 * whole screen (prevents flicker).
1232 if (count
> conp
->vc_rows
) /* Maximum realistic size */
1233 count
= conp
->vc_rows
;
1235 fbcon_softback_note(conp
, t
, count
);
1236 if (logo_shown
>= 0) goto redraw_up
;
1237 switch (p
->scrollmode
& __SCROLL_YMASK
) {
1238 case __SCROLL_YMOVE
:
1239 p
->dispsw
->bmove(p
, t
+count
, 0, t
, 0, b
-t
-count
,
1241 p
->dispsw
->clear(conp
, p
, b
-count
, 0, count
,
1245 case __SCROLL_YWRAP
:
1246 if (b
-t
-count
> 3*conp
->vc_rows
>>2) {
1248 fbcon_bmove(conp
, 0, 0, count
, 0, t
,
1250 ywrap_up(unit
, conp
, p
, count
);
1251 if (conp
->vc_rows
-b
> 0)
1252 fbcon_bmove(conp
, b
-count
, 0, b
, 0,
1253 conp
->vc_rows
-b
, conp
->vc_cols
);
1254 } else if (p
->scrollmode
& __SCROLL_YPANREDRAW
)
1257 fbcon_bmove(conp
, t
+count
, 0, t
, 0, b
-t
-count
,
1259 fbcon_clear(conp
, b
-count
, 0, count
, conp
->vc_cols
);
1263 if (( p
->yscroll
+ count
<= 2 * (p
->vrows
- conp
->vc_rows
)) &&
1264 (( !scroll_partial
&& (b
-t
== conp
->vc_rows
)) ||
1265 ( scroll_partial
&& (b
-t
-count
> 3*conp
->vc_rows
>>2)))) {
1267 fbcon_bmove(conp
, 0, 0, count
, 0, t
,
1269 ypan_up(unit
, conp
, p
, count
);
1270 if (conp
->vc_rows
-b
> 0)
1271 fbcon_bmove(conp
, b
-count
, 0, b
, 0,
1272 conp
->vc_rows
-b
, conp
->vc_cols
);
1273 } else if (p
->scrollmode
& __SCROLL_YPANREDRAW
)
1276 fbcon_bmove(conp
, t
+count
, 0, t
, 0, b
-t
-count
,
1278 fbcon_clear(conp
, b
-count
, 0, count
, conp
->vc_cols
);
1281 case __SCROLL_YREDRAW
:
1283 fbcon_redraw(conp
, p
, t
, b
-t
-count
, count
*conp
->vc_cols
);
1284 p
->dispsw
->clear(conp
, p
, real_y(p
, b
-count
), 0,
1285 count
, conp
->vc_cols
);
1286 scr_memsetw((unsigned short *)(conp
->vc_origin
+
1287 conp
->vc_size_row
* (b
-count
)),
1288 conp
->vc_video_erase_char
,
1289 conp
->vc_size_row
* count
);
1295 if (count
> conp
->vc_rows
) /* Maximum realistic size */
1296 count
= conp
->vc_rows
;
1297 switch (p
->scrollmode
& __SCROLL_YMASK
) {
1298 case __SCROLL_YMOVE
:
1299 p
->dispsw
->bmove(p
, t
, 0, t
+count
, 0, b
-t
-count
,
1301 p
->dispsw
->clear(conp
, p
, t
, 0,
1302 count
, conp
->vc_cols
);
1305 case __SCROLL_YWRAP
:
1306 if (b
-t
-count
> 3*conp
->vc_rows
>>2) {
1307 if (conp
->vc_rows
-b
> 0)
1308 fbcon_bmove(conp
, b
, 0, b
-count
, 0,
1309 conp
->vc_rows
-b
, conp
->vc_cols
);
1310 ywrap_down(unit
, conp
, p
, count
);
1312 fbcon_bmove(conp
, count
, 0, 0, 0, t
,
1314 } else if (p
->scrollmode
& __SCROLL_YPANREDRAW
)
1317 fbcon_bmove(conp
, t
, 0, t
+count
, 0, b
-t
-count
,
1319 fbcon_clear(conp
, t
, 0, count
, conp
->vc_cols
);
1323 if (( count
-p
->yscroll
<= p
->vrows
-conp
->vc_rows
) &&
1324 (( !scroll_partial
&& (b
-t
== conp
->vc_rows
)) ||
1325 ( scroll_partial
&& (b
-t
-count
> 3*conp
->vc_rows
>>2)))) {
1326 if (conp
->vc_rows
-b
> 0)
1327 fbcon_bmove(conp
, b
, 0, b
-count
, 0,
1328 conp
->vc_rows
-b
, conp
->vc_cols
);
1329 ypan_down(unit
, conp
, p
, count
);
1331 fbcon_bmove(conp
, count
, 0, 0, 0, t
,
1333 } else if (p
->scrollmode
& __SCROLL_YPANREDRAW
)
1336 fbcon_bmove(conp
, t
, 0, t
+count
, 0, b
-t
-count
,
1338 fbcon_clear(conp
, t
, 0, count
, conp
->vc_cols
);
1341 case __SCROLL_YREDRAW
:
1343 fbcon_redraw(conp
, p
, b
- 1, b
-t
-count
, -count
*conp
->vc_cols
);
1344 p
->dispsw
->clear(conp
, p
, real_y(p
, t
), 0,
1345 count
, conp
->vc_cols
);
1346 scr_memsetw((unsigned short *)(conp
->vc_origin
+
1347 conp
->vc_size_row
* t
),
1348 conp
->vc_video_erase_char
,
1349 conp
->vc_size_row
* count
);
1357 static void fbcon_bmove(struct vc_data
*conp
, int sy
, int sx
, int dy
, int dx
,
1358 int height
, int width
)
1360 int unit
= conp
->vc_num
;
1361 struct display
*p
= &fb_display
[unit
];
1363 if (!p
->can_soft_blank
&& console_blanked
)
1366 if (!width
|| !height
)
1369 if (((sy
<= p
->cursor_y
) && (p
->cursor_y
< sy
+height
) &&
1370 (sx
<= p
->cursor_x
) && (p
->cursor_x
< sx
+width
)) ||
1371 ((dy
<= p
->cursor_y
) && (p
->cursor_y
< dy
+height
) &&
1372 (dx
<= p
->cursor_x
) && (p
->cursor_x
< dx
+width
)))
1373 fbcon_cursor(conp
, CM_ERASE
|CM_SOFTBACK
);
1375 /* Split blits that cross physical y_wrap case.
1376 * Pathological case involves 4 blits, better to use recursive
1377 * code rather than unrolled case
1379 * Recursive invocations don't need to erase the cursor over and
1380 * over again, so we use fbcon_bmove_rec()
1382 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, height
, width
, p
->vrows
-p
->yscroll
);
1385 static void fbcon_bmove_rec(struct display
*p
, int sy
, int sx
, int dy
, int dx
,
1386 int height
, int width
, u_int y_break
)
1390 if (sy
< y_break
&& sy
+height
> y_break
) {
1392 if (dy
< sy
) { /* Avoid trashing self */
1393 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, b
, width
, y_break
);
1394 fbcon_bmove_rec(p
, sy
+b
, sx
, dy
+b
, dx
, height
-b
, width
, y_break
);
1396 fbcon_bmove_rec(p
, sy
+b
, sx
, dy
+b
, dx
, height
-b
, width
, y_break
);
1397 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, b
, width
, y_break
);
1402 if (dy
< y_break
&& dy
+height
> y_break
) {
1404 if (dy
< sy
) { /* Avoid trashing self */
1405 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, b
, width
, y_break
);
1406 fbcon_bmove_rec(p
, sy
+b
, sx
, dy
+b
, dx
, height
-b
, width
, y_break
);
1408 fbcon_bmove_rec(p
, sy
+b
, sx
, dy
+b
, dx
, height
-b
, width
, y_break
);
1409 fbcon_bmove_rec(p
, sy
, sx
, dy
, dx
, b
, width
, y_break
);
1413 p
->dispsw
->bmove(p
, real_y(p
, sy
), sx
, real_y(p
, dy
), dx
, height
, width
);
1417 static int fbcon_switch(struct vc_data
*conp
)
1419 int unit
= conp
->vc_num
;
1420 struct display
*p
= &fb_display
[unit
];
1421 struct fb_info
*info
= p
->fb_info
;
1424 int l
= fbcon_softback_size
/ conp
->vc_size_row
;
1426 fbcon_set_origin(conp
);
1427 softback_top
= softback_curr
= softback_in
= softback_buf
;
1431 softback_end
= softback_buf
+ l
* conp
->vc_size_row
;
1433 /* Smaller scrollback makes no sense, and 0 would screw
1434 the operation totally */
1438 if (logo_shown
>= 0) {
1439 struct vc_data
*conp2
= vc_cons
[logo_shown
].d
;
1441 if (conp2
->vc_top
== logo_lines
&& conp2
->vc_bottom
== conp2
->vc_rows
)
1445 p
->var
.yoffset
= p
->yscroll
= 0;
1446 switch (p
->scrollmode
& __SCROLL_YMASK
) {
1447 case __SCROLL_YWRAP
:
1448 scrollback_phys_max
= p
->vrows
-conp
->vc_rows
;
1451 scrollback_phys_max
= p
->vrows
-2*conp
->vc_rows
;
1452 if (scrollback_phys_max
< 0)
1453 scrollback_phys_max
= 0;
1456 scrollback_phys_max
= 0;
1460 scrollback_current
= 0;
1462 if (info
&& info
->switch_con
)
1463 (*info
->switch_con
)(unit
, info
);
1464 if (p
->dispsw
->clear_margins
&& vt_cons
[unit
]->vc_mode
== KD_TEXT
)
1465 p
->dispsw
->clear_margins(conp
, p
, 0);
1466 if (logo_shown
== -2) {
1467 logo_shown
= fg_console
;
1468 fbcon_show_logo(); /* This is protected above by initmem_freed */
1469 update_region(fg_console
,
1470 conp
->vc_origin
+ conp
->vc_size_row
* conp
->vc_top
,
1471 conp
->vc_size_row
* (conp
->vc_bottom
- conp
->vc_top
) / 2);
1478 static int fbcon_blank(struct vc_data
*conp
, int blank
)
1480 struct display
*p
= &fb_display
[conp
->vc_num
];
1481 struct fb_info
*info
= p
->fb_info
;
1483 if (blank
< 0) /* Entering graphics mode */
1486 fbcon_cursor(p
->conp
, blank
? CM_ERASE
: CM_DRAW
);
1488 if (!p
->can_soft_blank
) {
1490 if (p
->visual
== FB_VISUAL_MONO01
) {
1492 fb_memset255(p
->screen_base
,
1493 p
->var
.xres_virtual
*p
->var
.yres_virtual
*
1494 p
->var
.bits_per_pixel
>>3);
1496 unsigned short oldc
;
1500 oldc
= conp
->vc_video_erase_char
;
1501 conp
->vc_video_erase_char
&= p
->charmask
;
1502 height
= conp
->vc_rows
;
1503 y_break
= p
->vrows
-p
->yscroll
;
1504 if (height
> y_break
) {
1505 p
->dispsw
->clear(conp
, p
, real_y(p
, 0), 0, y_break
, conp
->vc_cols
);
1506 p
->dispsw
->clear(conp
, p
, real_y(p
, y_break
), 0, height
-y_break
, conp
->vc_cols
);
1508 p
->dispsw
->clear(conp
, p
, real_y(p
, 0), 0, height
, conp
->vc_cols
);
1509 conp
->vc_video_erase_char
= oldc
;
1513 /* Tell console.c that it has to restore the screen itself */
1517 (*info
->blank
)(blank
, info
);
1521 static void fbcon_free_font(struct display
*p
)
1523 if (p
->userfont
&& p
->fontdata
&&
1524 (--REFCOUNT(p
->fontdata
) == 0))
1525 kfree(p
->fontdata
- FONT_EXTRA_WORDS
*sizeof(int));
1530 static inline int fbcon_get_font(int unit
, struct console_font_op
*op
)
1532 struct display
*p
= &fb_display
[unit
];
1533 u8
*data
= op
->data
;
1534 u8
*fontdata
= p
->fontdata
;
1537 #ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
1538 if (fontwidth(p
) != 8) return -EINVAL
;
1540 op
->width
= fontwidth(p
);
1541 op
->height
= fontheight(p
);
1542 op
->charcount
= (p
->charmask
== 0x1ff) ? 512 : 256;
1543 if (!op
->data
) return 0;
1545 if (op
->width
<= 8) {
1547 for (i
= 0; i
< op
->charcount
; i
++) {
1548 memcpy(data
, fontdata
, j
);
1549 memset(data
+j
, 0, 32-j
);
1554 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
1555 else if (op
->width
<= 16) {
1556 j
= fontheight(p
) * 2;
1557 for (i
= 0; i
< op
->charcount
; i
++) {
1558 memcpy(data
, fontdata
, j
);
1559 memset(data
+j
, 0, 64-j
);
1563 } else if (op
->width
<= 24) {
1564 for (i
= 0; i
< op
->charcount
; i
++) {
1565 for (j
= 0; j
< fontheight(p
); j
++) {
1566 *data
++ = fontdata
[0];
1567 *data
++ = fontdata
[1];
1568 *data
++ = fontdata
[2];
1569 fontdata
+= sizeof(u32
);
1571 memset(data
, 0, 3*(32-j
));
1572 data
+= 3 * (32 - j
);
1575 j
= fontheight(p
) * 4;
1576 for (i
= 0; i
< op
->charcount
; i
++) {
1577 memcpy(data
, fontdata
, j
);
1578 memset(data
+j
, 0, 128-j
);
1587 static int fbcon_do_set_font(int unit
, struct console_font_op
*op
, u8
*data
, int userfont
)
1589 struct display
*p
= &fb_display
[unit
];
1594 char *old_data
= NULL
;
1596 if (!fontwidthvalid(p
,w
)) {
1597 if (userfont
&& op
->op
!= KD_FONT_OP_COPY
)
1598 kfree(data
- FONT_EXTRA_WORDS
*sizeof(int));
1602 if (CON_IS_VISIBLE(p
->conp
) && softback_lines
)
1603 fbcon_set_origin(p
->conp
);
1605 resize
= (w
!= fontwidth(p
)) || (h
!= fontheight(p
));
1607 old_data
= p
->fontdata
;
1609 cnt
= FNTCHARCNT(data
);
1613 if ((p
->userfont
= userfont
))
1617 if (p
->conp
->vc_hi_font_mask
&& cnt
== 256) {
1618 p
->conp
->vc_hi_font_mask
= 0;
1619 if (p
->conp
->vc_can_do_color
)
1620 p
->conp
->vc_complement_mask
>>= 1;
1625 /* ++Edmund: reorder the attribute bits */
1626 if (p
->conp
->vc_can_do_color
) {
1627 struct vc_data
*conp
= p
->conp
;
1628 unsigned short *cp
= (unsigned short *) conp
->vc_origin
;
1629 int count
= conp
->vc_screenbuf_size
/2;
1631 for (; count
> 0; count
--, cp
++) {
1633 scr_writew(((c
& 0xfe00) >> 1) | (c
& 0xff), cp
);
1635 c
= conp
->vc_video_erase_char
;
1636 conp
->vc_video_erase_char
= ((c
& 0xfe00) >> 1) | (c
& 0xff);
1637 conp
->vc_attr
>>= 1;
1640 } else if (!p
->conp
->vc_hi_font_mask
&& cnt
== 512) {
1641 p
->conp
->vc_hi_font_mask
= 0x100;
1642 if (p
->conp
->vc_can_do_color
)
1643 p
->conp
->vc_complement_mask
<<= 1;
1646 p
->charmask
= 0x1ff;
1648 /* ++Edmund: reorder the attribute bits */
1650 struct vc_data
*conp
= p
->conp
;
1651 unsigned short *cp
= (unsigned short *) conp
->vc_origin
;
1652 int count
= conp
->vc_screenbuf_size
/2;
1654 for (; count
> 0; count
--, cp
++) {
1655 unsigned short newc
;
1657 if (conp
->vc_can_do_color
)
1658 newc
= ((c
& 0xff00) << 1) | (c
& 0xff);
1661 scr_writew(newc
, cp
);
1663 c
= conp
->vc_video_erase_char
;
1664 if (conp
->vc_can_do_color
) {
1665 conp
->vc_video_erase_char
= ((c
& 0xff00) << 1) | (c
& 0xff);
1666 conp
->vc_attr
<<= 1;
1668 conp
->vc_video_erase_char
= c
& ~0x100;
1672 fbcon_font_widths(p
);
1675 struct vc_data
*conp
= p
->conp
;
1676 /* reset wrap/pan */
1677 p
->var
.xoffset
= p
->var
.yoffset
= p
->yscroll
= 0;
1678 p
->vrows
= p
->var
.yres_virtual
/h
;
1679 if ((p
->var
.yres
% h
) && (p
->var
.yres_virtual
% h
< p
->var
.yres
% h
))
1681 updatescrollmode(p
);
1682 vc_resize_con( p
->var
.yres
/h
, p
->var
.xres
/w
, unit
);
1683 if (CON_IS_VISIBLE(conp
) && softback_buf
) {
1684 int l
= fbcon_softback_size
/ conp
->vc_size_row
;
1686 softback_end
= softback_buf
+ l
* conp
->vc_size_row
;
1688 /* Smaller scrollback makes no sense, and 0 would screw
1689 the operation totally */
1693 } else if (CON_IS_VISIBLE(p
->conp
) && vt_cons
[unit
]->vc_mode
== KD_TEXT
) {
1694 if (p
->dispsw
->clear_margins
)
1695 p
->dispsw
->clear_margins(p
->conp
, p
, 0);
1696 update_screen(unit
);
1699 if (old_data
&& (--REFCOUNT(old_data
) == 0))
1700 kfree(old_data
- FONT_EXTRA_WORDS
*sizeof(int));
1705 static inline int fbcon_copy_font(int unit
, struct console_font_op
*op
)
1707 struct display
*od
, *p
= &fb_display
[unit
];
1710 if (h
< 0 || !vc_cons_allocated( h
))
1713 return 0; /* nothing to do */
1714 od
= &fb_display
[h
];
1715 if (od
->fontdata
== p
->fontdata
)
1716 return 0; /* already the same font... */
1717 op
->width
= fontwidth(od
);
1718 op
->height
= fontheight(od
);
1719 return fbcon_do_set_font(unit
, op
, od
->fontdata
, od
->userfont
);
1722 static inline int fbcon_set_font(int unit
, struct console_font_op
*op
)
1728 u8
*new_data
, *data
= op
->data
, *p
;
1730 #ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
1734 if ((w
<= 0) || (w
> 32) || (op
->charcount
!= 256 && op
->charcount
!= 512))
1743 size
*= op
->charcount
;
1745 if (!(new_data
= kmalloc(FONT_EXTRA_WORDS
*sizeof(int)+size
, GFP_USER
)))
1747 new_data
+= FONT_EXTRA_WORDS
*sizeof(int);
1748 FNTSIZE(new_data
) = size
;
1749 FNTCHARCNT(new_data
) = op
->charcount
;
1750 REFCOUNT(new_data
) = 0; /* usage counter */
1753 for (i
= 0; i
< op
->charcount
; i
++) {
1759 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
1762 for (i
= 0; i
< op
->charcount
; i
++) {
1767 } else if (w
<= 24) {
1768 for (i
= 0; i
< op
->charcount
; i
++) {
1770 for (j
= 0; j
< h
; j
++) {
1780 for (i
= 0; i
< op
->charcount
; i
++) {
1787 /* we can do it in u32 chunks because of charcount is 256 or 512, so
1788 font length must be multiple of 256, at least. And 256 is multiple
1791 while (p
> new_data
) k
+= *--(u32
*)p
;
1792 FNTSUM(new_data
) = k
;
1793 /* Check if the same font is on some other console already */
1794 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++) {
1795 if (fb_display
[i
].userfont
&&
1796 fb_display
[i
].fontdata
&&
1797 FNTSUM(fb_display
[i
].fontdata
) == k
&&
1798 FNTSIZE(fb_display
[i
].fontdata
) == size
&&
1799 fontwidth(&fb_display
[i
]) == w
&&
1800 !memcmp(fb_display
[i
].fontdata
, new_data
, size
)) {
1801 kfree(new_data
- FONT_EXTRA_WORDS
*sizeof(int));
1802 new_data
= fb_display
[i
].fontdata
;
1806 return fbcon_do_set_font(unit
, op
, new_data
, 1);
1809 static inline int fbcon_set_def_font(int unit
, struct console_font_op
*op
)
1811 char name
[MAX_FONT_NAME
];
1812 struct fbcon_font_desc
*f
;
1813 struct display
*p
= &fb_display
[unit
];
1816 f
= fbcon_get_default_font(p
->var
.xres
, p
->var
.yres
);
1817 else if (strncpy_from_user(name
, op
->data
, MAX_FONT_NAME
-1) < 0)
1820 name
[MAX_FONT_NAME
-1] = 0;
1821 if (!(f
= fbcon_find_font(name
)))
1824 op
->width
= f
->width
;
1825 op
->height
= f
->height
;
1826 return fbcon_do_set_font(unit
, op
, f
->data
, 0);
1829 static int fbcon_font_op(struct vc_data
*conp
, struct console_font_op
*op
)
1831 int unit
= conp
->vc_num
;
1834 case KD_FONT_OP_SET
:
1835 return fbcon_set_font(unit
, op
);
1836 case KD_FONT_OP_GET
:
1837 return fbcon_get_font(unit
, op
);
1838 case KD_FONT_OP_SET_DEFAULT
:
1839 return fbcon_set_def_font(unit
, op
);
1840 case KD_FONT_OP_COPY
:
1841 return fbcon_copy_font(unit
, op
);
1847 static u16 palette_red
[16];
1848 static u16 palette_green
[16];
1849 static u16 palette_blue
[16];
1851 static struct fb_cmap palette_cmap
= {
1852 0, 16, palette_red
, palette_green
, palette_blue
, NULL
1855 static int fbcon_set_palette(struct vc_data
*conp
, unsigned char *table
)
1857 int unit
= conp
->vc_num
;
1858 struct display
*p
= &fb_display
[unit
];
1862 if (!conp
->vc_can_do_color
|| (!p
->can_soft_blank
&& console_blanked
))
1864 for (i
= j
= 0; i
< 16; i
++) {
1866 val
= conp
->vc_palette
[j
++];
1867 palette_red
[k
] = (val
<<8)|val
;
1868 val
= conp
->vc_palette
[j
++];
1869 palette_green
[k
] = (val
<<8)|val
;
1870 val
= conp
->vc_palette
[j
++];
1871 palette_blue
[k
] = (val
<<8)|val
;
1873 if (p
->var
.bits_per_pixel
<= 4)
1874 palette_cmap
.len
= 1<<p
->var
.bits_per_pixel
;
1876 palette_cmap
.len
= 16;
1877 palette_cmap
.start
= 0;
1878 return p
->fb_info
->fbops
->fb_set_cmap(&palette_cmap
, 1, unit
, p
->fb_info
);
1881 static u16
*fbcon_screen_pos(struct vc_data
*conp
, int offset
)
1886 if (conp
->vc_num
!= fg_console
|| !softback_lines
)
1887 return (u16
*)(conp
->vc_origin
+ offset
);
1888 line
= offset
/ conp
->vc_size_row
;
1889 if (line
>= softback_lines
)
1890 return (u16
*)(conp
->vc_origin
+ offset
- softback_lines
* conp
->vc_size_row
);
1891 p
= softback_curr
+ offset
;
1892 if (p
>= softback_end
)
1893 p
+= softback_buf
- softback_end
;
1897 static unsigned long fbcon_getxy(struct vc_data
*conp
, unsigned long pos
, int *px
, int *py
)
1901 if (pos
>= conp
->vc_origin
&& pos
< conp
->vc_scr_end
) {
1902 unsigned long offset
= (pos
- conp
->vc_origin
) / 2;
1904 x
= offset
% conp
->vc_cols
;
1905 y
= offset
/ conp
->vc_cols
;
1906 if (conp
->vc_num
== fg_console
)
1907 y
+= softback_lines
;
1908 ret
= pos
+ (conp
->vc_cols
- x
) * 2;
1909 } else if (conp
->vc_num
== fg_console
&& softback_lines
) {
1910 unsigned long offset
= (pos
- softback_curr
) / 2;
1912 x
= offset
% conp
->vc_cols
;
1913 y
= offset
/ conp
->vc_cols
;
1914 if (pos
< softback_curr
)
1915 y
+= (softback_end
- softback_buf
) / conp
->vc_size_row
;
1916 ret
= pos
+ (conp
->vc_cols
- x
) * 2;
1917 if (ret
== softback_end
)
1919 if (ret
== softback_in
)
1920 ret
= conp
->vc_origin
;
1922 /* Should not happen */
1924 ret
= conp
->vc_origin
;
1931 /* As we might be inside of softback, we may work with non-contiguous buffer,
1932 that's why we have to use a separate routine. */
1933 static void fbcon_invert_region(struct vc_data
*conp
, u16
*p
, int cnt
)
1936 if (!conp
->vc_can_do_color
)
1938 else if (conp
->vc_hi_font_mask
== 0x100) {
1940 a
= ((a
) & 0x11ff) | (((a
) & 0xe000) >> 4) | (((a
) & 0x0e00) << 4);
1944 a
= ((a
) & 0x88ff) | (((a
) & 0x7000) >> 4) | (((a
) & 0x0700) << 4);
1947 if (p
== (u16
*)softback_end
)
1948 p
= (u16
*)softback_buf
;
1949 if (p
== (u16
*)softback_in
)
1950 p
= (u16
*)conp
->vc_origin
;
1954 static int fbcon_scrolldelta(struct vc_data
*conp
, int lines
)
1956 int unit
, offset
, limit
, scrollback_old
;
1960 p
= &fb_display
[unit
];
1962 if (conp
->vc_num
!= unit
)
1964 if (vt_cons
[unit
]->vc_mode
!= KD_TEXT
|| !lines
)
1966 if (logo_shown
>= 0) {
1967 struct vc_data
*conp2
= vc_cons
[logo_shown
].d
;
1969 if (conp2
->vc_top
== logo_lines
&& conp2
->vc_bottom
== conp2
->vc_rows
)
1971 if (logo_shown
== unit
) {
1976 q
= conp
->vc_origin
+ logo_lines
* conp
->vc_size_row
;
1977 for (i
= 0; i
< logo_lines
; i
++) {
1978 if (p
== softback_top
) break;
1979 if (p
== softback_buf
) p
= softback_end
;
1980 p
-= conp
->vc_size_row
;
1981 q
-= conp
->vc_size_row
;
1982 scr_memcpyw((u16
*)q
, (u16
*)p
, conp
->vc_size_row
);
1985 update_region(unit
, conp
->vc_origin
, logo_lines
* conp
->vc_cols
);
1989 fbcon_cursor(conp
, CM_ERASE
|CM_SOFTBACK
);
1990 fbcon_redraw_softback(conp
, p
, lines
);
1991 fbcon_cursor(conp
, CM_DRAW
|CM_SOFTBACK
);
1995 if (!scrollback_phys_max
)
1998 scrollback_old
= scrollback_current
;
1999 scrollback_current
-= lines
;
2000 if (scrollback_current
< 0)
2001 scrollback_current
= 0;
2002 else if (scrollback_current
> scrollback_max
)
2003 scrollback_current
= scrollback_max
;
2004 if (scrollback_current
== scrollback_old
)
2007 if (!p
->can_soft_blank
&&
2008 (console_blanked
|| vt_cons
[unit
]->vc_mode
!= KD_TEXT
|| !lines
))
2010 fbcon_cursor(conp
, CM_ERASE
);
2012 offset
= p
->yscroll
-scrollback_current
;
2014 switch (p
->scrollmode
&& __SCROLL_YMASK
) {
2015 case __SCROLL_YWRAP
:
2016 p
->var
.vmode
|= FB_VMODE_YWRAP
;
2019 limit
-= conp
->vc_rows
;
2020 p
->var
.vmode
&= ~FB_VMODE_YWRAP
;
2025 else if (offset
>= limit
)
2028 p
->var
.yoffset
= offset
*fontheight(p
);
2029 p
->fb_info
->updatevar(unit
, p
->fb_info
);
2030 if (!scrollback_current
)
2031 fbcon_cursor(conp
, CM_DRAW
);
2035 static int fbcon_set_origin(struct vc_data
*conp
)
2037 if (softback_lines
&& !console_blanked
)
2038 fbcon_scrolldelta(conp
, softback_lines
);
2042 static inline unsigned safe_shift(unsigned d
,int n
)
2044 return n
<0 ? d
>>-n
: d
<<n
;
2047 static int __init
fbcon_show_logo( void )
2049 struct display
*p
= &fb_display
[fg_console
]; /* draw to vt in foreground */
2050 int depth
= p
->var
.bits_per_pixel
;
2051 int line
= p
->next_line
;
2052 unsigned char *fb
= p
->screen_base
;
2053 unsigned char *logo
;
2054 unsigned char *dst
, *src
;
2055 int i
, j
, n
, x1
, y1
, x
;
2056 int logo_depth
, done
= 0;
2058 /* Return if the frame buffer is not mapped */
2062 /* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
2064 if ((p
->visual
== FB_VISUAL_PSEUDOCOLOR
&& depth
>= 4) ||
2065 p
->visual
== FB_VISUAL_DIRECTCOLOR
) {
2066 int is_truecolor
= (p
->visual
== FB_VISUAL_DIRECTCOLOR
);
2067 int use_256
= (!is_truecolor
&& depth
>= 8) ||
2068 (is_truecolor
&& depth
>= 24);
2069 int first_col
= use_256
? 32 : depth
> 4 ? 16 : 0;
2070 int num_cols
= use_256
? LINUX_LOGO_COLORS
: 16;
2071 unsigned char *red
, *green
, *blue
;
2074 red
= linux_logo_red
;
2075 green
= linux_logo_green
;
2076 blue
= linux_logo_blue
;
2079 red
= linux_logo16_red
;
2080 green
= linux_logo16_green
;
2081 blue
= linux_logo16_blue
;
2084 for( i
= 0; i
< num_cols
; i
+= n
) {
2087 /* palette_cmap provides space for only 16 colors at once */
2089 palette_cmap
.start
= first_col
+ i
;
2090 palette_cmap
.len
= n
;
2091 for( j
= 0; j
< n
; ++j
) {
2092 palette_cmap
.red
[j
] = (red
[i
+j
] << 8) | red
[i
+j
];
2093 palette_cmap
.green
[j
] = (green
[i
+j
] << 8) | green
[i
+j
];
2094 palette_cmap
.blue
[j
] = (blue
[i
+j
] << 8) | blue
[i
+j
];
2096 p
->fb_info
->fbops
->fb_set_cmap(&palette_cmap
, 1, fg_console
,
2105 else if (depth
>= 4) {
2106 logo
= linux_logo16
;
2110 logo
= linux_logo_bw
;
2114 if (p
->fb_info
->fbops
->fb_rasterimg
)
2115 p
->fb_info
->fbops
->fb_rasterimg(p
->fb_info
, 1);
2117 for (x
= 0; x
< smp_num_cpus
* (LOGO_W
+ 8) &&
2118 x
< p
->var
.xres
- (LOGO_W
+ 8); x
+= (LOGO_W
+ 8)) {
2120 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
2121 defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
2122 if (p
->visual
== FB_VISUAL_DIRECTCOLOR
) {
2123 unsigned int val
; /* max. depth 32! */
2125 int redshift
, greenshift
, blueshift
;
2127 /* Bug: Doesn't obey msb_right ... (who needs that?) */
2128 redshift
= p
->var
.red
.offset
;
2129 greenshift
= p
->var
.green
.offset
;
2130 blueshift
= p
->var
.blue
.offset
;
2132 if (depth
>= 24 && (depth
% 8) == 0) {
2133 /* have at least 8 bits per color */
2136 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
2137 dst
= fb
+ y1
*line
+ x
*bdepth
;
2138 for( x1
= 0; x1
< LOGO_W
; x1
++, src
++ ) {
2139 val
= (*src
<< redshift
) |
2140 (*src
<< greenshift
) |
2141 (*src
<< blueshift
);
2142 if (bdepth
== 4 && !((long)dst
& 3)) {
2143 /* Some cards require 32bit access */
2144 fb_writel (val
, dst
);
2147 #ifdef __LITTLE_ENDIAN
2148 for( i
= 0; i
< bdepth
; ++i
)
2150 for( i
= bdepth
-1; i
>= 0; --i
)
2152 fb_writeb (val
>> (i
*8), dst
++);
2157 else if (depth
>= 15 && depth
<= 23) {
2158 /* have 5..7 bits per color, using 16 color image */
2161 bdepth
= (depth
+7)/8;
2162 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
2163 dst
= fb
+ y1
*line
+ x
*bdepth
;
2164 for( x1
= 0; x1
< LOGO_W
/2; x1
++, src
++ ) {
2165 pix
= (*src
>> 4) | 0x10; /* upper nibble */
2166 val
= (pix
<< redshift
) |
2167 (pix
<< greenshift
) |
2169 #ifdef __LITTLE_ENDIAN
2170 for( i
= 0; i
< bdepth
; ++i
)
2172 for( i
= bdepth
-1; i
>= 0; --i
)
2174 fb_writeb (val
>> (i
*8), dst
++);
2175 pix
= (*src
& 0x0f) | 0x10; /* lower nibble */
2176 val
= (pix
<< redshift
) |
2177 (pix
<< greenshift
) |
2179 #ifdef __LITTLE_ENDIAN
2180 for( i
= 0; i
< bdepth
; ++i
)
2182 for( i
= bdepth
-1; i
>= 0; --i
)
2184 fb_writeb (val
>> (i
*8), dst
++);
2191 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
2192 defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
2193 if ((depth
% 8 == 0) && (p
->visual
== FB_VISUAL_TRUECOLOR
)) {
2194 /* Modes without color mapping, needs special data transformation... */
2195 unsigned int val
; /* max. depth 32! */
2196 int bdepth
= depth
/8;
2197 unsigned char mask
[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
2198 unsigned char redmask
, greenmask
, bluemask
;
2199 int redshift
, greenshift
, blueshift
;
2201 /* Bug: Doesn't obey msb_right ... (who needs that?) */
2202 redmask
= mask
[p
->var
.red
.length
< 8 ? p
->var
.red
.length
: 8];
2203 greenmask
= mask
[p
->var
.green
.length
< 8 ? p
->var
.green
.length
: 8];
2204 bluemask
= mask
[p
->var
.blue
.length
< 8 ? p
->var
.blue
.length
: 8];
2205 redshift
= p
->var
.red
.offset
- (8-p
->var
.red
.length
);
2206 greenshift
= p
->var
.green
.offset
- (8-p
->var
.green
.length
);
2207 blueshift
= p
->var
.blue
.offset
- (8-p
->var
.blue
.length
);
2210 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
2211 dst
= fb
+ y1
*line
+ x
*bdepth
;
2212 for( x1
= 0; x1
< LOGO_W
; x1
++, src
++ ) {
2213 val
= safe_shift((linux_logo_red
[*src
-32] & redmask
), redshift
) |
2214 safe_shift((linux_logo_green
[*src
-32] & greenmask
), greenshift
) |
2215 safe_shift((linux_logo_blue
[*src
-32] & bluemask
), blueshift
);
2216 if (bdepth
== 4 && !((long)dst
& 3)) {
2217 /* Some cards require 32bit access */
2218 fb_writel (val
, dst
);
2221 #ifdef __LITTLE_ENDIAN
2222 for( i
= 0; i
< bdepth
; ++i
)
2224 for( i
= bdepth
-1; i
>= 0; --i
)
2226 fb_writeb (val
>> (i
*8), dst
++);
2233 #if defined(CONFIG_FBCON_CFB4)
2234 if (depth
== 4 && p
->type
== FB_TYPE_PACKED_PIXELS
) {
2236 for( y1
= 0; y1
< LOGO_H
; y1
++) {
2237 dst
= fb
+ y1
*line
+ x
/2;
2238 for( x1
= 0; x1
< LOGO_W
/2; x1
++) {
2240 q
= (q
<< 4) | (q
>> 4);
2241 fb_writeb (q
, dst
++);
2247 #if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FB_SBUS)
2248 if (depth
== 8 && p
->type
== FB_TYPE_PACKED_PIXELS
) {
2249 /* depth 8 or more, packed, with color registers */
2252 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
2253 dst
= fb
+ y1
*line
+ x
;
2254 for( x1
= 0; x1
< LOGO_W
; x1
++ )
2255 fb_writeb (*src
++, dst
++);
2260 #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
2261 defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
2262 defined(CONFIG_FBCON_IPLAN2P8)
2263 if (depth
>= 2 && (p
->type
== FB_TYPE_PLANES
||
2264 p
->type
== FB_TYPE_INTERLEAVED_PLANES
)) {
2265 /* planes (normal or interleaved), with color registers */
2267 unsigned char val
, mask
;
2268 int plane
= p
->next_plane
;
2270 #if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
2271 defined(CONFIG_FBCON_IPLAN2P8)
2272 int line_length
= p
->line_length
;
2274 /* for support of Atari interleaved planes */
2275 #define MAP_X(x) (line_length ? (x) : ((x) & ~1)*depth + ((x) & 1))
2277 #define MAP_X(x) (x)
2279 /* extract a bit from the source image */
2280 #define BIT(p,pix,bit) (p[pix*logo_depth/8] & \
2281 (1 << ((8-((pix*logo_depth)&7)-logo_depth) + bit)))
2284 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
2285 for( x1
= 0; x1
< LOGO_LINE
; x1
++, src
+= logo_depth
) {
2286 dst
= fb
+ y1
*line
+ MAP_X(x
/8+x1
);
2287 for( bit
= 0; bit
< logo_depth
; bit
++ ) {
2289 for( mask
= 0x80, i
= 0; i
< 8; mask
>>= 1, i
++ ) {
2290 if (BIT( src
, i
, bit
))
2299 /* fill remaining planes
2300 * special case for logo_depth == 4: we used color registers 16..31,
2301 * so fill plane 4 with 1 bits instead of 0 */
2302 if (depth
> logo_depth
) {
2303 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
2304 for( x1
= 0; x1
< LOGO_LINE
; x1
++ ) {
2305 dst
= fb
+ y1
*line
+ MAP_X(x
/8+x1
) + logo_depth
*plane
;
2306 for( i
= logo_depth
; i
< depth
; i
++, dst
+= plane
)
2307 *dst
= (i
== logo_depth
&& logo_depth
== 4)
2316 #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \
2317 defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_HGA)
2319 if (depth
== 1 && (p
->type
== FB_TYPE_PACKED_PIXELS
||
2320 p
->type
== FB_TYPE_PLANES
||
2321 p
->type
== FB_TYPE_INTERLEAVED_PLANES
)) {
2324 unsigned char inverse
= p
->inverse
|| p
->visual
== FB_VISUAL_MONO01
2327 int is_hga
= !strncmp(p
->fb_info
->modename
, "HGA", 3);
2328 /* can't use simply memcpy because need to apply inverse */
2329 for( y1
= 0; y1
< LOGO_H
; y1
++ ) {
2330 src
= logo
+ y1
*LOGO_LINE
;
2332 dst
= fb
+ (y1
%4)*8192 + (y1
>>2)*line
+ x
/8;
2334 dst
= fb
+ y1
*line
+ x
/8;
2335 for( x1
= 0; x1
< LOGO_LINE
; ++x1
)
2336 fb_writeb(fb_readb(src
++) ^ inverse
, dst
++);
2341 #if defined(CONFIG_FBCON_VGA_PLANES)
2342 if (depth
== 4 && p
->type
== FB_TYPE_VGA_PLANES
) {
2343 outb_p(1,0x3ce); outb_p(0xf,0x3cf);
2344 outb_p(3,0x3ce); outb_p(0,0x3cf);
2345 outb_p(5,0x3ce); outb_p(0,0x3cf);
2348 for (y1
= 0; y1
< LOGO_H
; y1
++) {
2349 for (x1
= 0; x1
< LOGO_W
/ 2; x1
++) {
2350 dst
= fb
+ y1
*line
+ x1
/4 + x
/8;
2353 outb_p(*src
>> 4,0x3cf);
2355 outb_p(1 << (7 - x1
% 4 * 2),0x3cf);
2360 outb_p(*src
& 0xf,0x3cf);
2362 outb_p(1 << (7 - (1 + x1
% 4 * 2)),0x3cf);
2374 if (p
->fb_info
->fbops
->fb_rasterimg
)
2375 p
->fb_info
->fbops
->fb_rasterimg(p
->fb_info
, 0);
2377 /* Modes not yet supported: packed pixels with depth != 8 (does such a
2378 * thing exist in reality?) */
2380 return done
? (LOGO_H
+ fontheight(p
) - 1) / fontheight(p
) : 0 ;
2384 * The console `switch' structure for the frame buffer based console
2387 struct consw fb_con
= {
2388 con_startup
: fbcon_startup
,
2389 con_init
: fbcon_init
,
2390 con_deinit
: fbcon_deinit
,
2391 con_clear
: fbcon_clear
,
2392 con_putc
: fbcon_putc
,
2393 con_putcs
: fbcon_putcs
,
2394 con_cursor
: fbcon_cursor
,
2395 con_scroll
: fbcon_scroll
,
2396 con_bmove
: fbcon_bmove
,
2397 con_switch
: fbcon_switch
,
2398 con_blank
: fbcon_blank
,
2399 con_font_op
: fbcon_font_op
,
2400 con_set_palette
: fbcon_set_palette
,
2401 con_scrolldelta
: fbcon_scrolldelta
,
2402 con_set_origin
: fbcon_set_origin
,
2403 con_invert_region
: fbcon_invert_region
,
2404 con_screen_pos
: fbcon_screen_pos
,
2405 con_getxy
: fbcon_getxy
,
2410 * Dummy Low Level Operations
2413 static void fbcon_dummy_op(void) {}
2415 #define DUMMY (void *)fbcon_dummy_op
2417 struct display_switch fbcon_dummy
= {
2428 * Visible symbols for modules
2431 EXPORT_SYMBOL(fb_display
);
2432 EXPORT_SYMBOL(fbcon_redraw_bmove
);
2433 EXPORT_SYMBOL(fbcon_redraw_clear
);
2434 EXPORT_SYMBOL(fbcon_dummy
);
2435 EXPORT_SYMBOL(fb_con
);