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>
34 * 2001 - Documented with DocBook
35 * - Brad Douglas <brad@neruo.com>
37 * The low level operations for the various display memory organizations are
38 * now in separate source files.
40 * Currently the following organizations are supported:
42 * o afb Amiga bitplanes
43 * o cfb{2,4,8,16,24,32} Packed pixels
44 * o ilbm Amiga interleaved bitplanes
45 * o iplan2p[248] Atari interleaved bitplanes
47 * o vga VGA characters/attributes
51 * - Implement 16 plane mode (iplan2p16)
54 * This file is subject to the terms and conditions of the GNU General Public
55 * License. See the file COPYING in the main directory of this archive for
61 #include <linux/config.h>
62 #include <linux/module.h>
63 #include <linux/types.h>
64 #include <linux/sched.h>
66 #include <linux/kernel.h>
67 #include <linux/delay.h> /* MSch: for IRQ probe */
68 #include <linux/tty.h>
69 #include <linux/console.h>
70 #include <linux/string.h>
72 #include <linux/slab.h>
74 #include <linux/vt_kern.h>
75 #include <linux/selection.h>
76 #include <linux/font.h>
77 #include <linux/smp.h>
78 #include <linux/init.h>
79 #include <linux/interrupt.h>
82 #include <asm/system.h>
83 #include <asm/uaccess.h>
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>
98 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
100 # define DPRINTK(fmt, args...)
103 struct display fb_display
[MAX_NR_CONSOLES
];
104 signed char con2fb_map
[MAX_NR_CONSOLES
];
105 static int logo_height
;
106 static int logo_lines
;
107 static int logo_shown
= -1;
108 /* Software scrollback */
109 int fbcon_softback_size
= 32768;
110 static unsigned long softback_buf
, softback_curr
;
111 static unsigned long softback_in
;
112 static unsigned long softback_top
, softback_end
;
113 static int softback_lines
;
114 /* console mappings */
115 static int first_fb_vc
;
116 static int last_fb_vc
= MAX_NR_CONSOLES
- 1;
117 static int fbcon_is_default
= 1;
119 static char fontname
[40];
121 /* current fb_info */
122 static int info_idx
= -1;
124 #define REFCOUNT(fd) (((int *)(fd))[-1])
125 #define FNTSIZE(fd) (((int *)(fd))[-2])
126 #define FNTCHARCNT(fd) (((int *)(fd))[-3])
127 #define FNTSUM(fd) (((int *)(fd))[-4])
128 #define FONT_EXTRA_WORDS 4
130 #define CM_SOFTBACK (8)
132 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
134 static void fbcon_free_font(struct display
*);
135 static int fbcon_set_origin(struct vc_data
*);
137 #define CURSOR_DRAW_DELAY (1)
139 /* # VBL ints between cursor state changes */
140 #define ARM_CURSOR_BLINK_RATE (10)
141 #define ATARI_CURSOR_BLINK_RATE (42)
142 #define MAC_CURSOR_BLINK_RATE (32)
143 #define DEFAULT_CURSOR_BLINK_RATE (20)
145 static int vbl_cursor_cnt
;
147 #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
150 * Interface used by the world
153 static const char *fbcon_startup(void);
154 static void fbcon_init(struct vc_data
*vc
, int init
);
155 static void fbcon_deinit(struct vc_data
*vc
);
156 static void fbcon_clear(struct vc_data
*vc
, int sy
, int sx
, int height
,
158 static void fbcon_putc(struct vc_data
*vc
, int c
, int ypos
, int xpos
);
159 static void fbcon_putcs(struct vc_data
*vc
, const unsigned short *s
,
160 int count
, int ypos
, int xpos
);
161 static void fbcon_cursor(struct vc_data
*vc
, int mode
);
162 static int fbcon_scroll(struct vc_data
*vc
, int t
, int b
, int dir
,
164 static void fbcon_bmove(struct vc_data
*vc
, int sy
, int sx
, int dy
, int dx
,
165 int height
, int width
);
166 static int fbcon_switch(struct vc_data
*vc
);
167 static int fbcon_blank(struct vc_data
*vc
, int blank
, int mode_switch
);
168 static int fbcon_set_palette(struct vc_data
*vc
, unsigned char *table
);
169 static int fbcon_scrolldelta(struct vc_data
*vc
, int lines
);
170 void accel_clear_margins(struct vc_data
*vc
, struct fb_info
*info
,
177 static __inline__
int real_y(struct display
*p
, int ypos
);
178 static __inline__
void ywrap_up(struct vc_data
*vc
, int count
);
179 static __inline__
void ywrap_down(struct vc_data
*vc
, int count
);
180 static __inline__
void ypan_up(struct vc_data
*vc
, int count
);
181 static __inline__
void ypan_down(struct vc_data
*vc
, int count
);
182 static void fbcon_bmove_rec(struct vc_data
*vc
, struct display
*p
, int sy
, int sx
,
183 int dy
, int dx
, int height
, int width
, u_int y_break
);
184 static void fbcon_set_disp(struct fb_info
*info
, struct vc_data
*vc
);
185 static void fbcon_redraw_move(struct vc_data
*vc
, struct display
*p
,
186 int line
, int count
, int dy
);
190 * On the Macintoy, there may or may not be a working VBL int. We need to probe
192 static int vbl_detected
;
194 static irqreturn_t
fb_vbl_detect(int irq
, void *dummy
, struct pt_regs
*fp
)
201 static void fb_flashcursor(void *private)
203 struct fb_info
*info
= (struct fb_info
*) private;
204 struct vc_data
*vc
= NULL
;
206 if (info
->currcon
!= -1)
207 vc
= vc_cons
[info
->currcon
].d
;
209 if (info
->state
!= FBINFO_STATE_RUNNING
||
210 info
->cursor
.rop
== ROP_COPY
|| !vc
|| !CON_IS_VISIBLE(vc
)
211 || registered_fb
[(int) con2fb_map
[vc
->vc_num
]] != info
)
213 acquire_console_sem();
214 info
->cursor
.enable
^= 1;
215 info
->fbops
->fb_cursor(info
, &info
->cursor
);
216 release_console_sem();
219 #if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC)
220 static int cursor_blink_rate
;
221 static irqreturn_t
fb_vbl_handler(int irq
, void *dev_id
, struct pt_regs
*fp
)
223 struct fb_info
*info
= dev_id
;
225 if (vbl_cursor_cnt
&& --vbl_cursor_cnt
== 0) {
226 schedule_work(&info
->queue
);
227 vbl_cursor_cnt
= cursor_blink_rate
;
233 static void cursor_timer_handler(unsigned long dev_addr
)
235 struct fb_info
*info
= (struct fb_info
*) dev_addr
;
237 schedule_work(&info
->queue
);
238 mod_timer(&info
->cursor_timer
, jiffies
+ HZ
/5);
241 int __init
fb_console_setup(char *this_opt
)
246 if (!this_opt
|| !*this_opt
)
249 while ((options
= strsep(&this_opt
, ",")) != NULL
) {
250 if (!strncmp(options
, "font:", 5))
251 strcpy(fontname
, options
+ 5);
253 if (!strncmp(options
, "scrollback:", 11)) {
256 fbcon_softback_size
= simple_strtoul(options
, &options
, 0);
257 if (*options
== 'k' || *options
== 'K') {
258 fbcon_softback_size
*= 1024;
268 if (!strncmp(options
, "map:", 4)) {
271 for (i
= 0, j
= 0; i
< MAX_NR_CONSOLES
; i
++) {
274 con2fb_map
[i
] = (options
[j
++]-'0') % FB_MAX
;
279 if (!strncmp(options
, "vc:", 3)) {
282 first_fb_vc
= simple_strtoul(options
, &options
, 10) - 1;
285 if (*options
++ == '-')
286 last_fb_vc
= simple_strtoul(options
, &options
, 10) - 1;
287 fbcon_is_default
= 0;
293 __setup("fbcon=", fb_console_setup
);
295 static int search_fb_in_map(int idx
)
299 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++) {
300 if (con2fb_map
[i
] == idx
)
306 static int search_for_mapped_con(void)
310 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++) {
311 if (con2fb_map
[i
] != -1)
317 static int fbcon_takeover(void)
321 if (!num_registered_fb
)
324 for (i
= first_fb_vc
; i
<= last_fb_vc
; i
++)
325 con2fb_map
[i
] = info_idx
;
327 err
= take_over_console(&fb_con
, first_fb_vc
, last_fb_vc
,
330 for (i
= first_fb_vc
; i
<= last_fb_vc
; i
++) {
340 * set_con2fb_map - map console to frame buffer device
341 * @unit: virtual console number to map
342 * @newidx: frame buffer index to map virtual console to
344 * Maps a virtual console @unit to a frame buffer device
347 static int set_con2fb_map(int unit
, int newidx
)
349 struct vc_data
*vc
= vc_cons
[unit
].d
;
350 int oldidx
= con2fb_map
[unit
];
351 struct fb_info
*info
= registered_fb
[newidx
];
352 struct fb_info
*oldinfo
= NULL
;
355 if (oldidx
== newidx
)
361 if (!search_for_mapped_con()) {
363 return fbcon_takeover();
367 oldinfo
= registered_fb
[oldidx
];
369 found
= search_fb_in_map(newidx
);
371 acquire_console_sem();
372 con2fb_map
[unit
] = newidx
;
374 if (!try_module_get(info
->fbops
->owner
)) {
375 con2fb_map
[unit
] = oldidx
;
376 release_console_sem();
379 if (info
->fbops
->fb_open
&& info
->fbops
->fb_open(info
, 0)) {
380 module_put(info
->fbops
->owner
);
381 con2fb_map
[unit
] = oldidx
;
382 release_console_sem();
388 * If old fb is not mapped to any of the consoles,
389 * fbcon should release it.
391 if (oldinfo
&& !search_fb_in_map(oldidx
)) {
392 if (oldinfo
->fbops
->fb_release
&&
393 oldinfo
->fbops
->fb_release(oldinfo
, 0)) {
394 con2fb_map
[unit
] = oldidx
;
395 if (!found
&& info
->fbops
->fb_release
)
396 info
->fbops
->fb_release(info
, 0);
398 module_put(info
->fbops
->owner
);
399 release_console_sem();
402 if (oldinfo
->queue
.func
== fb_flashcursor
)
403 del_timer_sync(&oldinfo
->cursor_timer
);
404 module_put(oldinfo
->fbops
->owner
);
408 if (!info
->queue
.func
|| info
->queue
.func
== fb_flashcursor
) {
409 if (!info
->queue
.func
)
410 INIT_WORK(&info
->queue
, fb_flashcursor
, info
);
412 init_timer(&info
->cursor_timer
);
413 info
->cursor_timer
.function
= cursor_timer_handler
;
414 info
->cursor_timer
.expires
= jiffies
+ HZ
/ 5;
415 info
->cursor_timer
.data
= (unsigned long ) info
;
416 add_timer(&info
->cursor_timer
);
419 if (info
->fbops
->fb_set_par
)
420 info
->fbops
->fb_set_par(info
);
421 fbcon_set_disp(info
, vc
);
422 release_console_sem();
427 * Accelerated handlers.
429 static inline int get_color(struct vc_data
*vc
, struct fb_info
*info
,
432 int depth
= fb_get_color_depth(info
);
436 color
= (is_fg
) ? attr_fgcol((vc
->vc_hi_font_mask
) ? 9 : 8, c
)
437 : attr_bgcol((vc
->vc_hi_font_mask
) ? 13 : 12, c
);
443 int fg
= (info
->fix
.visual
!= FB_VISUAL_MONO01
) ? 1 : 0;
444 int bg
= (info
->fix
.visual
!= FB_VISUAL_MONO01
) ? 0 : 1;
446 color
= (is_fg
) ? fg
: bg
;
451 * Scale down 16-colors to 4 colors. Default 4-color palette
458 * Last 8 entries of default 16-color palette is a more intense
459 * version of the first 8 (i.e., same chrominance, different
469 #define FBCON_ATTRIBUTE_UNDERLINE 1
470 #define FBCON_ATTRIBUTE_REVERSE 2
471 #define FBCON_ATTRIBUTE_BOLD 4
473 static inline int get_attribute(struct fb_info
*info
, u16 c
)
477 if (fb_get_color_depth(info
) == 1) {
478 if (attr_underline(c
))
479 attribute
|= FBCON_ATTRIBUTE_UNDERLINE
;
481 attribute
|= FBCON_ATTRIBUTE_REVERSE
;
483 attribute
|= FBCON_ATTRIBUTE_BOLD
;
489 static inline void update_attr(u8
*dst
, u8
*src
, int attribute
,
492 int i
, offset
= (vc
->vc_font
.height
< 10) ? 1 : 2;
493 int width
= (vc
->vc_font
.width
+ 7) >> 3;
494 unsigned int cellsize
= vc
->vc_font
.height
* width
;
497 offset
= cellsize
- (offset
* width
);
498 for (i
= 0; i
< cellsize
; i
++) {
500 if (attribute
& FBCON_ATTRIBUTE_UNDERLINE
&& i
>= offset
)
502 if (attribute
& FBCON_ATTRIBUTE_BOLD
)
504 if (attribute
& FBCON_ATTRIBUTE_REVERSE
)
510 void accel_bmove(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
511 int sx
, int dy
, int dx
, int height
, int width
)
513 struct fb_copyarea area
;
515 area
.sx
= sx
* vc
->vc_font
.width
;
516 area
.sy
= sy
* vc
->vc_font
.height
;
517 area
.dx
= dx
* vc
->vc_font
.width
;
518 area
.dy
= dy
* vc
->vc_font
.height
;
519 area
.height
= height
* vc
->vc_font
.height
;
520 area
.width
= width
* vc
->vc_font
.width
;
522 info
->fbops
->fb_copyarea(info
, &area
);
525 void accel_clear(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
526 int sx
, int height
, int width
)
528 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
529 struct fb_fillrect region
;
531 region
.color
= attr_bgcol_ec(bgshift
, vc
);
532 region
.dx
= sx
* vc
->vc_font
.width
;
533 region
.dy
= sy
* vc
->vc_font
.height
;
534 region
.width
= width
* vc
->vc_font
.width
;
535 region
.height
= height
* vc
->vc_font
.height
;
536 region
.rop
= ROP_COPY
;
538 info
->fbops
->fb_fillrect(info
, ®ion
);
541 void accel_putcs(struct vc_data
*vc
, struct fb_info
*info
,
542 const unsigned short *s
, int count
, int yy
, int xx
)
544 void (*move_unaligned
)(struct fb_info
*info
, struct fb_pixmap
*buf
,
545 u8
*dst
, u32 d_pitch
, u8
*src
, u32 idx
,
546 u32 height
, u32 shift_high
, u32 shift_low
,
548 void (*move_aligned
)(struct fb_info
*info
, struct fb_pixmap
*buf
,
549 u8
*dst
, u32 d_pitch
, u8
*src
, u32 s_pitch
,
551 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
552 unsigned int width
= (vc
->vc_font
.width
+ 7) >> 3;
553 unsigned int cellsize
= vc
->vc_font
.height
* width
;
554 unsigned int maxcnt
= info
->pixmap
.size
/cellsize
;
555 unsigned int scan_align
= info
->pixmap
.scan_align
- 1;
556 unsigned int buf_align
= info
->pixmap
.buf_align
- 1;
557 unsigned int shift_low
= 0, mod
= vc
->vc_font
.width
% 8;
558 unsigned int shift_high
= 8, pitch
, cnt
, size
, k
;
559 unsigned int idx
= vc
->vc_font
.width
>> 3;
560 unsigned int attribute
= get_attribute(info
, scr_readw(s
));
561 struct fb_image image
;
562 u8
*src
, *dst
, *buf
= NULL
;
565 buf
= kmalloc(cellsize
, GFP_KERNEL
);
570 image
.fg_color
= get_color(vc
, info
, scr_readw(s
), 1);
571 image
.bg_color
= get_color(vc
, info
, scr_readw(s
), 0);
573 image
.dx
= xx
* vc
->vc_font
.width
;
574 image
.dy
= yy
* vc
->vc_font
.height
;
575 image
.height
= vc
->vc_font
.height
;
578 if (info
->pixmap
.outbuf
&& info
->pixmap
.inbuf
) {
579 move_aligned
= fb_iomove_buf_aligned
;
580 move_unaligned
= fb_iomove_buf_unaligned
;
582 move_aligned
= fb_sysmove_buf_aligned
;
583 move_unaligned
= fb_sysmove_buf_unaligned
;
591 image
.width
= vc
->vc_font
.width
* cnt
;
592 pitch
= ((image
.width
+ 7) >> 3) + scan_align
;
593 pitch
&= ~scan_align
;
594 size
= pitch
* image
.height
+ buf_align
;
596 dst
= fb_get_buffer_offset(info
, &info
->pixmap
, size
);
600 src
= vc
->vc_font
.data
+ (scr_readw(s
++)&
604 update_attr(buf
, src
, attribute
, vc
);
608 move_unaligned(info
, &info
->pixmap
, dst
, pitch
,
609 src
, idx
, image
.height
,
610 shift_high
, shift_low
, mod
);
612 dst
+= (shift_low
>= 8) ? width
: width
- 1;
614 shift_high
= 8 - shift_low
;
618 src
= vc
->vc_font
.data
+ (scr_readw(s
++)&
622 update_attr(buf
, src
, attribute
, vc
);
626 move_aligned(info
, &info
->pixmap
, dst
, pitch
,
627 src
, idx
, image
.height
);
631 info
->fbops
->fb_imageblit(info
, &image
);
632 image
.dx
+= cnt
* vc
->vc_font
.width
;
640 void accel_clear_margins(struct vc_data
*vc
, struct fb_info
*info
,
643 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
644 unsigned int cw
= vc
->vc_font
.width
;
645 unsigned int ch
= vc
->vc_font
.height
;
646 unsigned int rw
= info
->var
.xres
- (vc
->vc_cols
*cw
);
647 unsigned int bh
= info
->var
.yres
- (vc
->vc_rows
*ch
);
648 unsigned int rs
= info
->var
.xres
- rw
;
649 unsigned int bs
= info
->var
.yres
- bh
;
650 struct fb_fillrect region
;
652 region
.color
= attr_bgcol_ec(bgshift
, vc
);
653 region
.rop
= ROP_COPY
;
655 if (rw
&& !bottom_only
) {
656 region
.dx
= info
->var
.xoffset
+ rs
;
659 region
.height
= info
->var
.yres_virtual
;
660 info
->fbops
->fb_fillrect(info
, ®ion
);
664 region
.dx
= info
->var
.xoffset
;
665 region
.dy
= info
->var
.yoffset
+ bs
;
668 info
->fbops
->fb_fillrect(info
, ®ion
);
673 * Low Level Operations
675 /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
676 static int var_to_display(struct display
*disp
,
677 struct fb_var_screeninfo
*var
,
678 struct fb_info
*info
)
680 disp
->xres_virtual
= var
->xres_virtual
;
681 disp
->yres_virtual
= var
->yres_virtual
;
682 disp
->bits_per_pixel
= var
->bits_per_pixel
;
683 disp
->grayscale
= var
->grayscale
;
684 disp
->nonstd
= var
->nonstd
;
685 disp
->accel_flags
= var
->accel_flags
;
686 disp
->height
= var
->height
;
687 disp
->width
= var
->width
;
688 disp
->red
= var
->red
;
689 disp
->green
= var
->green
;
690 disp
->blue
= var
->blue
;
691 disp
->transp
= var
->transp
;
692 disp
->mode
= fb_match_mode(var
, &info
->modelist
);
693 if (disp
->mode
== NULL
)
694 /* This should not happen */
699 static void display_to_var(struct fb_var_screeninfo
*var
,
700 struct display
*disp
)
702 fb_videomode_to_var(var
, disp
->mode
);
703 var
->xres_virtual
= disp
->xres_virtual
;
704 var
->yres_virtual
= disp
->yres_virtual
;
705 var
->bits_per_pixel
= disp
->bits_per_pixel
;
706 var
->grayscale
= disp
->grayscale
;
707 var
->nonstd
= disp
->nonstd
;
708 var
->accel_flags
= disp
->accel_flags
;
709 var
->height
= disp
->height
;
710 var
->width
= disp
->width
;
711 var
->red
= disp
->red
;
712 var
->green
= disp
->green
;
713 var
->blue
= disp
->blue
;
714 var
->transp
= disp
->transp
;
717 static const char *fbcon_startup(void)
719 const char *display_desc
= "frame buffer device";
720 struct display
*p
= &fb_display
[fg_console
];
721 struct vc_data
*vc
= vc_cons
[fg_console
].d
;
722 struct font_desc
*font
= NULL
;
723 struct module
*owner
;
724 struct fb_info
*info
= NULL
;
730 * If num_registered_fb is zero, this is a call for the dummy part.
731 * The frame buffer devices weren't initialized yet.
733 if (!num_registered_fb
|| info_idx
== -1)
736 * Instead of blindly using registered_fb[0], we use info_idx, set by
739 info
= registered_fb
[info_idx
];
744 owner
= info
->fbops
->owner
;
745 if (!try_module_get(owner
))
747 if (info
->fbops
->fb_open
&& info
->fbops
->fb_open(info
, 0)) {
751 if (info
->fix
.type
!= FB_TYPE_TEXT
) {
752 if (fbcon_softback_size
) {
756 kmalloc(fbcon_softback_size
,
759 fbcon_softback_size
= 0;
765 kfree((void *) softback_buf
);
771 softback_in
= softback_top
= softback_curr
=
776 /* Setup default font */
778 if (!fontname
[0] || !(font
= find_font(fontname
)))
779 font
= get_default_font(info
->var
.xres
,
781 vc
->vc_font
.width
= font
->width
;
782 vc
->vc_font
.height
= font
->height
;
783 vc
->vc_font
.data
= p
->fontdata
= font
->data
;
784 vc
->vc_font
.charcount
= 256; /* FIXME Need to support more fonts */
787 cols
= info
->var
.xres
/ vc
->vc_font
.width
;
788 rows
= info
->var
.yres
/ vc
->vc_font
.height
;
789 vc_resize(vc
->vc_num
, cols
, rows
);
791 DPRINTK("mode: %s\n", info
->fix
.id
);
792 DPRINTK("visual: %d\n", info
->fix
.visual
);
793 DPRINTK("res: %dx%d-%d\n", info
->var
.xres
,
795 info
->var
.bits_per_pixel
);
796 con_set_default_unimap(vc
->vc_num
);
800 cursor_blink_rate
= ATARI_CURSOR_BLINK_RATE
;
802 request_irq(IRQ_AUTO_4
, fb_vbl_handler
,
803 IRQ_TYPE_PRIO
, "framebuffer vbl",
806 #endif /* CONFIG_ATARI */
810 * On a Macintoy, the VBL interrupt may or may not be active.
811 * As interrupt based cursor is more reliable and race free, we
812 * probe for VBL interrupts.
817 * Probe for VBL: set temp. handler ...
819 irqres
= request_irq(IRQ_MAC_VBL
, fb_vbl_detect
, 0,
820 "framebuffer vbl", info
);
824 * ... and spin for 20 ms ...
826 while (!vbl_detected
&& ++ct
< 1000)
831 ("fbcon_startup: No VBL detected, using timer based cursor.\n");
833 free_irq(IRQ_MAC_VBL
, fb_vbl_detect
);
837 * interrupt based cursor ok
839 cursor_blink_rate
= MAC_CURSOR_BLINK_RATE
;
841 request_irq(IRQ_MAC_VBL
, fb_vbl_handler
, 0,
842 "framebuffer vbl", info
);
845 * VBL not detected: fall through, use timer based cursor
850 #endif /* CONFIG_MAC */
852 #if defined(__arm__) && defined(IRQ_VSYNCPULSE)
853 cursor_blink_rate
= ARM_CURSOR_BLINK_RATE
;
854 irqres
= request_irq(IRQ_VSYNCPULSE
, fb_vbl_handler
, SA_SHIRQ
,
855 "framebuffer vbl", info
);
857 /* Initialize the work queue. If the driver provides its
858 * own work queue this means it will use something besides
859 * default timer to flash the cursor. */
860 if (!info
->queue
.func
) {
861 INIT_WORK(&info
->queue
, fb_flashcursor
, info
);
863 init_timer(&info
->cursor_timer
);
864 info
->cursor_timer
.function
= cursor_timer_handler
;
865 info
->cursor_timer
.expires
= jiffies
+ HZ
/ 5;
866 info
->cursor_timer
.data
= (unsigned long ) info
;
867 add_timer(&info
->cursor_timer
);
872 static void fbcon_init(struct vc_data
*vc
, int init
)
874 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
875 struct vc_data
**default_mode
= vc
->vc_display_fg
;
876 struct display
*t
, *p
= &fb_display
[vc
->vc_num
];
877 int display_fg
= (*default_mode
)->vc_num
;
878 int logo
= 1, new_rows
, new_cols
, rows
, cols
, charcnt
= 256;
879 unsigned short *save
= NULL
, *r
, *q
;
880 int cap
= info
->flags
;
882 if (info_idx
== -1 || info
== NULL
)
884 if (vc
->vc_num
!= display_fg
|| (info
->flags
& FBINFO_MODULE
) ||
885 (info
->fix
.type
== FB_TYPE_TEXT
))
888 info
->var
.xoffset
= info
->var
.yoffset
= p
->yscroll
= 0; /* reset wrap/pan */
890 if (var_to_display(p
, &info
->var
, info
))
893 /* If we are not the first console on this
894 fb, copy the font from that console */
895 t
= &fb_display
[display_fg
];
896 if (!vc
->vc_font
.data
) {
897 vc
->vc_font
.data
= p
->fontdata
= t
->fontdata
;
898 vc
->vc_font
.width
= (*default_mode
)->vc_font
.width
;
899 vc
->vc_font
.height
= (*default_mode
)->vc_font
.height
;
900 p
->userfont
= t
->userfont
;
902 REFCOUNT(p
->fontdata
)++;
903 con_copy_unimap(vc
->vc_num
, display_fg
);
906 charcnt
= FNTCHARCNT(p
->fontdata
);
907 vc
->vc_can_do_color
= (fb_get_color_depth(info
) != 1);
908 vc
->vc_complement_mask
= vc
->vc_can_do_color
? 0x7700 : 0x0800;
909 if (charcnt
== 256) {
910 vc
->vc_hi_font_mask
= 0;
912 vc
->vc_hi_font_mask
= 0x100;
913 if (vc
->vc_can_do_color
)
914 vc
->vc_complement_mask
<<= 1;
918 new_cols
= info
->var
.xres
/ vc
->vc_font
.width
;
919 new_rows
= info
->var
.yres
/ vc
->vc_font
.height
;
920 vc_resize(vc
->vc_num
, new_cols
, new_rows
);
922 * We must always set the mode. The mode of the previous console
923 * driver could be in the same resolution but we are using different
924 * hardware so we have to initialize the hardware.
926 * We need to do it in fbcon_init() to prevent screen corruption.
928 if (CON_IS_VISIBLE(vc
) && info
->fbops
->fb_set_par
)
929 info
->fbops
->fb_set_par(info
);
932 if ((cap
& FBINFO_HWACCEL_COPYAREA
) &&
933 !(cap
& FBINFO_HWACCEL_DISABLED
))
934 p
->scrollmode
= SCROLL_MOVE
;
935 else /* default to something safe */
936 p
->scrollmode
= SCROLL_REDRAW
;
939 * ++guenther: console.c:vc_allocate() relies on initializing
940 * vc_{cols,rows}, but we must not set those if we are only
941 * resizing the console.
944 vc
->vc_cols
= new_cols
;
945 vc
->vc_rows
= new_rows
;
949 /* Need to make room for the logo */
950 int cnt
, erase
= vc
->vc_video_erase_char
;
954 * remove underline attribute from erase character
955 * if black and white framebuffer.
957 if (fb_get_color_depth(info
) == 1)
959 logo_height
= fb_prepare_logo(info
);
960 logo_lines
= (logo_height
+ vc
->vc_font
.height
- 1) /
962 q
= (unsigned short *) (vc
->vc_origin
+
963 vc
->vc_size_row
* rows
);
964 step
= logo_lines
* cols
;
965 for (r
= q
- logo_lines
* cols
; r
< q
; r
++)
966 if (scr_readw(r
) != vc
->vc_video_erase_char
)
968 if (r
!= q
&& new_rows
>= rows
+ logo_lines
) {
969 save
= kmalloc(logo_lines
* new_cols
* 2, GFP_KERNEL
);
971 int i
= cols
< new_cols
? cols
: new_cols
;
972 scr_memsetw(save
, erase
, logo_lines
* new_cols
* 2);
974 for (cnt
= 0; cnt
< logo_lines
; cnt
++, r
+= i
)
975 scr_memcpyw(save
+ cnt
* new_cols
, r
, 2 * i
);
980 /* We can scroll screen down */
982 for (cnt
= rows
- logo_lines
; cnt
> 0; cnt
--) {
983 scr_memcpyw(r
+ step
, r
, vc
->vc_size_row
);
987 vc
->vc_y
+= logo_lines
;
988 vc
->vc_pos
+= logo_lines
* vc
->vc_size_row
;
991 scr_memsetw((unsigned short *) vc
->vc_origin
,
993 vc
->vc_size_row
* logo_lines
);
995 if (CON_IS_VISIBLE(vc
) && vt_cons
[vc
->vc_num
]->vc_mode
== KD_TEXT
) {
996 accel_clear_margins(vc
, info
, 0);
997 update_screen(vc
->vc_num
);
1000 q
= (unsigned short *) (vc
->vc_origin
+
1003 scr_memcpyw(q
, save
, logo_lines
* new_cols
* 2);
1004 vc
->vc_y
+= logo_lines
;
1005 vc
->vc_pos
+= logo_lines
* vc
->vc_size_row
;
1008 if (logo_lines
> vc
->vc_bottom
) {
1011 "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n");
1014 vc
->vc_top
= logo_lines
;
1018 if (vc
->vc_num
== display_fg
&& softback_buf
) {
1019 int l
= fbcon_softback_size
/ vc
->vc_size_row
;
1021 softback_end
= softback_buf
+ l
* vc
->vc_size_row
;
1023 /* Smaller scrollback makes no sense, and 0 would screw
1024 the operation totally */
1030 static void fbcon_deinit(struct vc_data
*vc
)
1032 struct display
*p
= &fb_display
[vc
->vc_num
];
1039 /* ====================================================================== */
1041 /* fbcon_XXX routines - interface used by the world
1043 * This system is now divided into two levels because of complications
1044 * caused by hardware scrolling. Top level functions:
1046 * fbcon_bmove(), fbcon_clear(), fbcon_putc()
1048 * handles y values in range [0, scr_height-1] that correspond to real
1049 * screen positions. y_wrap shift means that first line of bitmap may be
1050 * anywhere on this display. These functions convert lineoffsets to
1051 * bitmap offsets and deal with the wrap-around case by splitting blits.
1053 * fbcon_bmove_physical_8() -- These functions fast implementations
1054 * fbcon_clear_physical_8() -- of original fbcon_XXX fns.
1055 * fbcon_putc_physical_8() -- (font width != 8) may be added later
1059 * At the moment fbcon_putc() cannot blit across vertical wrap boundary
1060 * Implies should only really hardware scroll in rows. Only reason for
1061 * restriction is simplicity & efficiency at the moment.
1064 static __inline__
int real_y(struct display
*p
, int ypos
)
1066 int rows
= p
->vrows
;
1069 return ypos
< rows
? ypos
: ypos
- rows
;
1073 static void fbcon_clear(struct vc_data
*vc
, int sy
, int sx
, int height
,
1076 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1078 struct display
*p
= &fb_display
[vc
->vc_num
];
1081 if (!info
->fbops
->fb_blank
&& console_blanked
)
1083 if (info
->state
!= FBINFO_STATE_RUNNING
)
1086 if (!height
|| !width
)
1089 /* Split blits that cross physical y_wrap boundary */
1091 y_break
= p
->vrows
- p
->yscroll
;
1092 if (sy
< y_break
&& sy
+ height
- 1 >= y_break
) {
1093 u_int b
= y_break
- sy
;
1094 accel_clear(vc
, info
, real_y(p
, sy
), sx
, b
, width
);
1095 accel_clear(vc
, info
, real_y(p
, sy
+ b
), sx
, height
- b
,
1098 accel_clear(vc
, info
, real_y(p
, sy
), sx
, height
, width
);
1101 static void fbcon_putcs(struct vc_data
*vc
, const unsigned short *s
,
1102 int count
, int ypos
, int xpos
)
1104 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1105 struct display
*p
= &fb_display
[vc
->vc_num
];
1107 if (!info
->fbops
->fb_blank
&& console_blanked
)
1109 if (info
->state
!= FBINFO_STATE_RUNNING
)
1112 if (vt_cons
[vc
->vc_num
]->vc_mode
!= KD_TEXT
)
1115 accel_putcs(vc
, info
, s
, count
, real_y(p
, ypos
), xpos
);
1118 static void fbcon_putc(struct vc_data
*vc
, int c
, int ypos
, int xpos
)
1120 fbcon_putcs(vc
, (const unsigned short *) &c
, 1, ypos
, xpos
);
1123 static void fbcon_cursor(struct vc_data
*vc
, int mode
)
1125 struct fb_cursor cursor
;
1126 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1127 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
1128 struct display
*p
= &fb_display
[vc
->vc_num
];
1129 int w
= (vc
->vc_font
.width
+ 7) >> 3, c
;
1130 int y
= real_y(p
, vc
->vc_y
), fg
, bg
;
1134 if (mode
& CM_SOFTBACK
) {
1135 mode
&= ~CM_SOFTBACK
;
1136 if (softback_lines
) {
1137 if (y
+ softback_lines
>= vc
->vc_rows
)
1140 y
+= softback_lines
;
1142 } else if (softback_lines
)
1143 fbcon_set_origin(vc
);
1145 c
= scr_readw((u16
*) vc
->vc_pos
);
1146 attribute
= get_attribute(info
, c
);
1147 src
= vc
->vc_font
.data
+ ((c
& charmask
) * (w
* vc
->vc_font
.height
));
1151 dst
= kmalloc(w
* vc
->vc_font
.height
, GFP_ATOMIC
);
1154 if (info
->cursor
.data
)
1155 kfree(info
->cursor
.data
);
1156 info
->cursor
.data
= dst
;
1157 update_attr(dst
, src
, attribute
, vc
);
1161 cursor
.image
.data
= src
;
1162 cursor
.set
= FB_CUR_SETCUR
;
1163 cursor
.image
.depth
= 1;
1167 if (info
->cursor
.rop
== ROP_XOR
) {
1168 info
->cursor
.enable
= 0;
1169 info
->cursor
.rop
= ROP_COPY
;
1170 info
->fbops
->fb_cursor(info
, &cursor
);
1175 info
->cursor
.enable
= 1;
1176 fg
= get_color(vc
, info
, c
, 1);
1177 bg
= get_color(vc
, info
, c
, 0);
1179 if (info
->cursor
.image
.fg_color
!= fg
||
1180 info
->cursor
.image
.bg_color
!= bg
) {
1181 cursor
.image
.fg_color
= fg
;
1182 cursor
.image
.bg_color
= bg
;
1183 cursor
.set
|= FB_CUR_SETCMAP
;
1186 if ((info
->cursor
.image
.dx
!= (vc
->vc_font
.width
* vc
->vc_x
)) ||
1187 (info
->cursor
.image
.dy
!= (vc
->vc_font
.height
* y
))) {
1188 cursor
.image
.dx
= vc
->vc_font
.width
* vc
->vc_x
;
1189 cursor
.image
.dy
= vc
->vc_font
.height
* y
;
1190 cursor
.set
|= FB_CUR_SETPOS
;
1193 if (info
->cursor
.image
.height
!= vc
->vc_font
.height
||
1194 info
->cursor
.image
.width
!= vc
->vc_font
.width
) {
1195 cursor
.image
.height
= vc
->vc_font
.height
;
1196 cursor
.image
.width
= vc
->vc_font
.width
;
1197 cursor
.set
|= FB_CUR_SETSIZE
;
1200 if (info
->cursor
.hot
.x
|| info
->cursor
.hot
.y
) {
1201 cursor
.hot
.x
= cursor
.hot
.y
= 0;
1202 cursor
.set
|= FB_CUR_SETHOT
;
1205 if ((cursor
.set
& FB_CUR_SETSIZE
) ||
1206 ((vc
->vc_cursor_type
& 0x0f) != p
->cursor_shape
)
1207 || info
->cursor
.mask
== NULL
) {
1208 char *mask
= kmalloc(w
*vc
->vc_font
.height
, GFP_ATOMIC
);
1209 int cur_height
, size
, i
= 0;
1215 if (info
->cursor
.mask
)
1216 kfree(info
->cursor
.mask
);
1217 info
->cursor
.mask
= mask
;
1218 p
->cursor_shape
= vc
->vc_cursor_type
& 0x0f;
1219 cursor
.set
|= FB_CUR_SETSHAPE
;
1221 switch (vc
->vc_cursor_type
& 0x0f) {
1226 cur_height
= (vc
->vc_font
.height
< 10) ? 1 : 2;
1228 case CUR_LOWER_THIRD
:
1229 cur_height
= vc
->vc_font
.height
/3;
1231 case CUR_LOWER_HALF
:
1232 cur_height
= vc
->vc_font
.height
>> 1;
1234 case CUR_TWO_THIRDS
:
1235 cur_height
= (vc
->vc_font
.height
<< 1)/3;
1239 cur_height
= vc
->vc_font
.height
;
1242 size
= (vc
->vc_font
.height
- cur_height
) * w
;
1245 size
= cur_height
* w
;
1249 info
->cursor
.rop
= ROP_XOR
;
1250 info
->fbops
->fb_cursor(info
, &cursor
);
1251 vbl_cursor_cnt
= CURSOR_DRAW_DELAY
;
1256 static int scrollback_phys_max
= 0;
1257 static int scrollback_max
= 0;
1258 static int scrollback_current
= 0;
1260 int update_var(int con
, struct fb_info
*info
)
1262 if (con
== info
->currcon
)
1263 return fb_pan_display(info
, &info
->var
);
1267 static void fbcon_set_disp(struct fb_info
*info
, struct vc_data
*vc
)
1269 struct display
*p
= &fb_display
[vc
->vc_num
], *t
;
1270 struct vc_data
**default_mode
= vc
->vc_display_fg
;
1271 int display_fg
= (*default_mode
)->vc_num
;
1272 int rows
, cols
, charcnt
= 256;
1274 info
->var
.xoffset
= info
->var
.yoffset
= p
->yscroll
= 0;
1275 if (var_to_display(p
, &info
->var
, info
))
1277 t
= &fb_display
[display_fg
];
1278 if (!vc
->vc_font
.data
) {
1279 vc
->vc_font
.data
= p
->fontdata
= t
->fontdata
;
1280 vc
->vc_font
.width
= (*default_mode
)->vc_font
.width
;
1281 vc
->vc_font
.height
= (*default_mode
)->vc_font
.height
;
1282 p
->userfont
= t
->userfont
;
1284 REFCOUNT(p
->fontdata
)++;
1285 con_copy_unimap(vc
->vc_num
, display_fg
);
1288 charcnt
= FNTCHARCNT(p
->fontdata
);
1290 vc
->vc_can_do_color
= (fb_get_color_depth(info
) != 1);
1291 vc
->vc_complement_mask
= vc
->vc_can_do_color
? 0x7700 : 0x0800;
1292 if (charcnt
== 256) {
1293 vc
->vc_hi_font_mask
= 0;
1295 vc
->vc_hi_font_mask
= 0x100;
1296 if (vc
->vc_can_do_color
)
1297 vc
->vc_complement_mask
<<= 1;
1299 cols
= info
->var
.xres
/ vc
->vc_font
.width
;
1300 rows
= info
->var
.yres
/ vc
->vc_font
.height
;
1301 vc_resize(vc
->vc_num
, cols
, rows
);
1302 if (CON_IS_VISIBLE(vc
)) {
1303 update_screen(vc
->vc_num
);
1305 int l
= fbcon_softback_size
/ vc
->vc_size_row
;
1308 softback_end
= softback_buf
+ l
*
1311 /* Smaller scrollback makes no sense, and 0
1312 would screw the operation totally */
1317 switch_screen(fg_console
);
1320 static __inline__
void ywrap_up(struct vc_data
*vc
, int count
)
1322 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1323 struct display
*p
= &fb_display
[vc
->vc_num
];
1325 p
->yscroll
+= count
;
1326 if (p
->yscroll
>= p
->vrows
) /* Deal with wrap */
1327 p
->yscroll
-= p
->vrows
;
1328 info
->var
.xoffset
= 0;
1329 info
->var
.yoffset
= p
->yscroll
* vc
->vc_font
.height
;
1330 info
->var
.vmode
|= FB_VMODE_YWRAP
;
1331 update_var(vc
->vc_num
, info
);
1332 scrollback_max
+= count
;
1333 if (scrollback_max
> scrollback_phys_max
)
1334 scrollback_max
= scrollback_phys_max
;
1335 scrollback_current
= 0;
1338 static __inline__
void ywrap_down(struct vc_data
*vc
, int count
)
1340 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1341 struct display
*p
= &fb_display
[vc
->vc_num
];
1343 p
->yscroll
-= count
;
1344 if (p
->yscroll
< 0) /* Deal with wrap */
1345 p
->yscroll
+= p
->vrows
;
1346 info
->var
.xoffset
= 0;
1347 info
->var
.yoffset
= p
->yscroll
* vc
->vc_font
.height
;
1348 info
->var
.vmode
|= FB_VMODE_YWRAP
;
1349 update_var(vc
->vc_num
, info
);
1350 scrollback_max
-= count
;
1351 if (scrollback_max
< 0)
1353 scrollback_current
= 0;
1356 static __inline__
void ypan_up(struct vc_data
*vc
, int count
)
1358 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1359 struct display
*p
= &fb_display
[vc
->vc_num
];
1361 p
->yscroll
+= count
;
1362 if (p
->yscroll
> p
->vrows
- vc
->vc_rows
) {
1363 accel_bmove(vc
, info
, p
->vrows
- vc
->vc_rows
,
1364 0, 0, 0, vc
->vc_rows
, vc
->vc_cols
);
1365 p
->yscroll
-= p
->vrows
- vc
->vc_rows
;
1367 info
->var
.xoffset
= 0;
1368 info
->var
.yoffset
= p
->yscroll
* vc
->vc_font
.height
;
1369 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
1370 update_var(vc
->vc_num
, info
);
1371 accel_clear_margins(vc
, info
, 1);
1372 scrollback_max
+= count
;
1373 if (scrollback_max
> scrollback_phys_max
)
1374 scrollback_max
= scrollback_phys_max
;
1375 scrollback_current
= 0;
1378 static __inline__
void ypan_up_redraw(struct vc_data
*vc
, int t
, int count
)
1380 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1381 struct display
*p
= &fb_display
[vc
->vc_num
];
1384 p
->yscroll
+= count
;
1385 if (p
->yscroll
> p
->vrows
- vc
->vc_rows
) {
1386 p
->yscroll
-= p
->vrows
- vc
->vc_rows
;
1390 info
->var
.xoffset
= 0;
1391 info
->var
.yoffset
= p
->yscroll
* vc
->vc_font
.height
;
1392 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
1394 fbcon_redraw_move(vc
, p
, t
+ count
, vc
->vc_rows
- count
, t
);
1395 update_var(vc
->vc_num
, info
);
1396 accel_clear_margins(vc
, info
, 1);
1397 scrollback_max
+= count
;
1398 if (scrollback_max
> scrollback_phys_max
)
1399 scrollback_max
= scrollback_phys_max
;
1400 scrollback_current
= 0;
1403 static __inline__
void ypan_down(struct vc_data
*vc
, int count
)
1405 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1406 struct display
*p
= &fb_display
[vc
->vc_num
];
1408 p
->yscroll
-= count
;
1409 if (p
->yscroll
< 0) {
1410 accel_bmove(vc
, info
, 0, 0, p
->vrows
- vc
->vc_rows
,
1411 0, vc
->vc_rows
, vc
->vc_cols
);
1412 p
->yscroll
+= p
->vrows
- vc
->vc_rows
;
1414 info
->var
.xoffset
= 0;
1415 info
->var
.yoffset
= p
->yscroll
* vc
->vc_font
.height
;
1416 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
1417 update_var(vc
->vc_num
, info
);
1418 accel_clear_margins(vc
, info
, 1);
1419 scrollback_max
-= count
;
1420 if (scrollback_max
< 0)
1422 scrollback_current
= 0;
1425 static __inline__
void ypan_down_redraw(struct vc_data
*vc
, int t
, int count
)
1427 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1428 struct display
*p
= &fb_display
[vc
->vc_num
];
1431 p
->yscroll
-= count
;
1432 if (p
->yscroll
< 0) {
1433 p
->yscroll
+= p
->vrows
- vc
->vc_rows
;
1436 info
->var
.xoffset
= 0;
1437 info
->var
.yoffset
= p
->yscroll
* vc
->vc_font
.height
;
1438 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
1440 fbcon_redraw_move(vc
, p
, t
, vc
->vc_rows
- count
, t
+ count
);
1441 update_var(vc
->vc_num
, info
);
1442 accel_clear_margins(vc
, info
, 1);
1443 scrollback_max
-= count
;
1444 if (scrollback_max
< 0)
1446 scrollback_current
= 0;
1449 static void fbcon_redraw_softback(struct vc_data
*vc
, struct display
*p
,
1452 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1453 int count
= vc
->vc_rows
;
1454 unsigned short *d
, *s
;
1458 d
= (u16
*) softback_curr
;
1459 if (d
== (u16
*) softback_in
)
1460 d
= (u16
*) vc
->vc_origin
;
1461 n
= softback_curr
+ delta
* vc
->vc_size_row
;
1462 softback_lines
-= delta
;
1464 if (softback_curr
< softback_top
&& n
< softback_buf
) {
1465 n
+= softback_end
- softback_buf
;
1466 if (n
< softback_top
) {
1468 (softback_top
- n
) / vc
->vc_size_row
;
1471 } else if (softback_curr
>= softback_top
1472 && n
< softback_top
) {
1474 (softback_top
- n
) / vc
->vc_size_row
;
1478 if (softback_curr
> softback_in
&& n
>= softback_end
) {
1479 n
+= softback_buf
- softback_end
;
1480 if (n
> softback_in
) {
1484 } else if (softback_curr
<= softback_in
&& n
> softback_in
) {
1489 if (n
== softback_curr
)
1492 s
= (u16
*) softback_curr
;
1493 if (s
== (u16
*) softback_in
)
1494 s
= (u16
*) vc
->vc_origin
;
1496 unsigned short *start
;
1500 unsigned short attr
= 1;
1503 le
= advance_row(s
, 1);
1506 if (attr
!= (c
& 0xff00)) {
1509 accel_putcs(vc
, info
, start
, s
- start
,
1510 real_y(p
, line
), x
);
1515 if (c
== scr_readw(d
)) {
1517 accel_putcs(vc
, info
, start
, s
- start
,
1518 real_y(p
, line
), x
);
1530 accel_putcs(vc
, info
, start
, s
- start
,
1531 real_y(p
, line
), x
);
1533 if (d
== (u16
*) softback_end
)
1534 d
= (u16
*) softback_buf
;
1535 if (d
== (u16
*) softback_in
)
1536 d
= (u16
*) vc
->vc_origin
;
1537 if (s
== (u16
*) softback_end
)
1538 s
= (u16
*) softback_buf
;
1539 if (s
== (u16
*) softback_in
)
1540 s
= (u16
*) vc
->vc_origin
;
1544 static void fbcon_redraw_move(struct vc_data
*vc
, struct display
*p
,
1545 int line
, int count
, int dy
)
1547 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1548 unsigned short *s
= (unsigned short *)
1549 (vc
->vc_origin
+ vc
->vc_size_row
* line
);
1552 unsigned short *start
= s
;
1553 unsigned short *le
= advance_row(s
, 1);
1556 unsigned short attr
= 1;
1560 if (attr
!= (c
& 0xff00)) {
1563 accel_putcs(vc
, info
, start
, s
- start
,
1569 console_conditional_schedule();
1573 accel_putcs(vc
, info
, start
, s
- start
,
1575 console_conditional_schedule();
1580 static void fbcon_redraw(struct vc_data
*vc
, struct display
*p
,
1581 int line
, int count
, int offset
)
1583 unsigned short *d
= (unsigned short *)
1584 (vc
->vc_origin
+ vc
->vc_size_row
* line
);
1585 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1586 unsigned short *s
= d
+ offset
;
1589 unsigned short *start
= s
;
1590 unsigned short *le
= advance_row(s
, 1);
1593 unsigned short attr
= 1;
1597 if (attr
!= (c
& 0xff00)) {
1600 accel_putcs(vc
, info
, start
, s
- start
,
1601 real_y(p
, line
), x
);
1606 if (c
== scr_readw(d
)) {
1608 accel_putcs(vc
, info
, start
, s
- start
,
1609 real_y(p
, line
), x
);
1618 console_conditional_schedule();
1623 accel_putcs(vc
, info
, start
, s
- start
,
1624 real_y(p
, line
), x
);
1625 console_conditional_schedule();
1630 /* NOTE: We subtract two lines from these pointers */
1631 s
-= vc
->vc_size_row
;
1632 d
-= vc
->vc_size_row
;
1637 static inline void fbcon_softback_note(struct vc_data
*vc
, int t
,
1642 if (vc
->vc_num
!= fg_console
)
1644 p
= (unsigned short *) (vc
->vc_origin
+ t
* vc
->vc_size_row
);
1647 scr_memcpyw((u16
*) softback_in
, p
, vc
->vc_size_row
);
1649 p
= advance_row(p
, 1);
1650 softback_in
+= vc
->vc_size_row
;
1651 if (softback_in
== softback_end
)
1652 softback_in
= softback_buf
;
1653 if (softback_in
== softback_top
) {
1654 softback_top
+= vc
->vc_size_row
;
1655 if (softback_top
== softback_end
)
1656 softback_top
= softback_buf
;
1659 softback_curr
= softback_in
;
1662 static int fbcon_scroll(struct vc_data
*vc
, int t
, int b
, int dir
,
1665 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1666 struct display
*p
= &fb_display
[vc
->vc_num
];
1667 int scroll_partial
= info
->flags
& FBINFO_PARTIAL_PAN_OK
;
1669 if (!info
->fbops
->fb_blank
&& console_blanked
)
1672 if (!count
|| vt_cons
[vc
->vc_num
]->vc_mode
!= KD_TEXT
)
1675 fbcon_cursor(vc
, CM_ERASE
);
1678 * ++Geert: Only use ywrap/ypan if the console is in text mode
1679 * ++Andrew: Only use ypan on hardware text mode when scrolling the
1680 * whole screen (prevents flicker).
1685 if (count
> vc
->vc_rows
) /* Maximum realistic size */
1686 count
= vc
->vc_rows
;
1688 fbcon_softback_note(vc
, t
, count
);
1689 if (logo_shown
>= 0)
1691 switch (p
->scrollmode
) {
1693 accel_bmove(vc
, info
, t
+ count
, 0, t
, 0,
1694 b
- t
- count
, vc
->vc_cols
);
1695 accel_clear(vc
, info
, b
- count
, 0, count
,
1699 case SCROLL_WRAP_MOVE
:
1700 if (b
- t
- count
> 3 * vc
->vc_rows
>> 2) {
1702 fbcon_bmove(vc
, 0, 0, count
, 0, t
,
1704 ywrap_up(vc
, count
);
1705 if (vc
->vc_rows
- b
> 0)
1706 fbcon_bmove(vc
, b
- count
, 0, b
, 0,
1709 } else if (info
->flags
& FBINFO_READS_FAST
)
1710 fbcon_bmove(vc
, t
+ count
, 0, t
, 0,
1711 b
- t
- count
, vc
->vc_cols
);
1714 fbcon_clear(vc
, b
- count
, 0, count
, vc
->vc_cols
);
1717 case SCROLL_PAN_REDRAW
:
1718 if ((p
->yscroll
+ count
<=
1719 2 * (p
->vrows
- vc
->vc_rows
))
1720 && ((!scroll_partial
&& (b
- t
== vc
->vc_rows
))
1723 3 * vc
->vc_rows
>> 2)))) {
1725 fbcon_redraw_move(vc
, p
, 0, t
, count
);
1726 ypan_up_redraw(vc
, t
, count
);
1727 if (vc
->vc_rows
- b
> 0)
1728 fbcon_redraw_move(vc
, p
, b
- count
,
1729 vc
->vc_rows
- b
, b
);
1731 fbcon_redraw_move(vc
, p
, t
+ count
, b
- t
- count
, t
);
1732 fbcon_clear(vc
, b
- count
, 0, count
, vc
->vc_cols
);
1735 case SCROLL_PAN_MOVE
:
1736 if ((p
->yscroll
+ count
<=
1737 2 * (p
->vrows
- vc
->vc_rows
))
1738 && ((!scroll_partial
&& (b
- t
== vc
->vc_rows
))
1741 3 * vc
->vc_rows
>> 2)))) {
1743 fbcon_bmove(vc
, 0, 0, count
, 0, t
,
1746 if (vc
->vc_rows
- b
> 0)
1747 fbcon_bmove(vc
, b
- count
, 0, b
, 0,
1750 } else if (info
->flags
& FBINFO_READS_FAST
)
1751 fbcon_bmove(vc
, t
+ count
, 0, t
, 0,
1752 b
- t
- count
, vc
->vc_cols
);
1755 fbcon_clear(vc
, b
- count
, 0, count
, vc
->vc_cols
);
1760 fbcon_redraw(vc
, p
, t
, b
- t
- count
,
1761 count
* vc
->vc_cols
);
1762 accel_clear(vc
, info
, real_y(p
, b
- count
), 0,
1763 count
, vc
->vc_cols
);
1764 scr_memsetw((unsigned short *) (vc
->vc_origin
+
1767 vc
->vc_video_erase_char
,
1768 vc
->vc_size_row
* count
);
1774 if (count
> vc
->vc_rows
) /* Maximum realistic size */
1775 count
= vc
->vc_rows
;
1776 switch (p
->scrollmode
) {
1778 accel_bmove(vc
, info
, t
, 0, t
+ count
, 0,
1779 b
- t
- count
, vc
->vc_cols
);
1780 accel_clear(vc
, info
, t
, 0, count
, vc
->vc_cols
);
1783 case SCROLL_WRAP_MOVE
:
1784 if (b
- t
- count
> 3 * vc
->vc_rows
>> 2) {
1785 if (vc
->vc_rows
- b
> 0)
1786 fbcon_bmove(vc
, b
, 0, b
- count
, 0,
1789 ywrap_down(vc
, count
);
1791 fbcon_bmove(vc
, count
, 0, 0, 0, t
,
1793 } else if (info
->flags
& FBINFO_READS_FAST
)
1794 fbcon_bmove(vc
, t
, 0, t
+ count
, 0,
1795 b
- t
- count
, vc
->vc_cols
);
1798 fbcon_clear(vc
, t
, 0, count
, vc
->vc_cols
);
1801 case SCROLL_PAN_MOVE
:
1802 if ((count
- p
->yscroll
<= p
->vrows
- vc
->vc_rows
)
1803 && ((!scroll_partial
&& (b
- t
== vc
->vc_rows
))
1806 3 * vc
->vc_rows
>> 2)))) {
1807 if (vc
->vc_rows
- b
> 0)
1808 fbcon_bmove(vc
, b
, 0, b
- count
, 0,
1811 ypan_down(vc
, count
);
1813 fbcon_bmove(vc
, count
, 0, 0, 0, t
,
1815 } else if (info
->flags
& FBINFO_READS_FAST
)
1816 fbcon_bmove(vc
, t
, 0, t
+ count
, 0,
1817 b
- t
- count
, vc
->vc_cols
);
1820 fbcon_clear(vc
, t
, 0, count
, vc
->vc_cols
);
1823 case SCROLL_PAN_REDRAW
:
1824 if ((count
- p
->yscroll
<= p
->vrows
- vc
->vc_rows
)
1825 && ((!scroll_partial
&& (b
- t
== vc
->vc_rows
))
1828 3 * vc
->vc_rows
>> 2)))) {
1829 if (vc
->vc_rows
- b
> 0)
1830 fbcon_redraw_move(vc
, p
, b
, vc
->vc_rows
- b
,
1832 ypan_down_redraw(vc
, t
, count
);
1834 fbcon_redraw_move(vc
, p
, count
, t
, 0);
1836 fbcon_redraw_move(vc
, p
, t
, b
- t
- count
, t
+ count
);
1837 fbcon_clear(vc
, t
, 0, count
, vc
->vc_cols
);
1842 fbcon_redraw(vc
, p
, b
- 1, b
- t
- count
,
1843 -count
* vc
->vc_cols
);
1844 accel_clear(vc
, info
, real_y(p
, t
), 0, count
,
1846 scr_memsetw((unsigned short *) (vc
->vc_origin
+
1849 vc
->vc_video_erase_char
,
1850 vc
->vc_size_row
* count
);
1858 static void fbcon_bmove(struct vc_data
*vc
, int sy
, int sx
, int dy
, int dx
,
1859 int height
, int width
)
1861 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1862 struct display
*p
= &fb_display
[vc
->vc_num
];
1864 if (!info
->fbops
->fb_blank
&& console_blanked
)
1867 if (!width
|| !height
)
1870 /* Split blits that cross physical y_wrap case.
1871 * Pathological case involves 4 blits, better to use recursive
1872 * code rather than unrolled case
1874 * Recursive invocations don't need to erase the cursor over and
1875 * over again, so we use fbcon_bmove_rec()
1877 fbcon_bmove_rec(vc
, p
, sy
, sx
, dy
, dx
, height
, width
,
1878 p
->vrows
- p
->yscroll
);
1881 static void fbcon_bmove_rec(struct vc_data
*vc
, struct display
*p
, int sy
, int sx
,
1882 int dy
, int dx
, int height
, int width
, u_int y_break
)
1884 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1887 if (sy
< y_break
&& sy
+ height
> y_break
) {
1889 if (dy
< sy
) { /* Avoid trashing self */
1890 fbcon_bmove_rec(vc
, p
, sy
, sx
, dy
, dx
, b
, width
,
1892 fbcon_bmove_rec(vc
, p
, sy
+ b
, sx
, dy
+ b
, dx
,
1893 height
- b
, width
, y_break
);
1895 fbcon_bmove_rec(vc
, p
, sy
+ b
, sx
, dy
+ b
, dx
,
1896 height
- b
, width
, y_break
);
1897 fbcon_bmove_rec(vc
, p
, sy
, sx
, dy
, dx
, b
, width
,
1903 if (dy
< y_break
&& dy
+ height
> y_break
) {
1905 if (dy
< sy
) { /* Avoid trashing self */
1906 fbcon_bmove_rec(vc
, p
, sy
, sx
, dy
, dx
, b
, width
,
1908 fbcon_bmove_rec(vc
, p
, sy
+ b
, sx
, dy
+ b
, dx
,
1909 height
- b
, width
, y_break
);
1911 fbcon_bmove_rec(vc
, p
, sy
+ b
, sx
, dy
+ b
, dx
,
1912 height
- b
, width
, y_break
);
1913 fbcon_bmove_rec(vc
, p
, sy
, sx
, dy
, dx
, b
, width
,
1918 accel_bmove(vc
, info
, real_y(p
, sy
), sx
, real_y(p
, dy
), dx
,
1922 static __inline__
void updatescrollmode(struct display
*p
, struct fb_info
*info
,
1925 int fh
= vc
->vc_font
.height
;
1926 int cap
= info
->flags
;
1927 int good_pan
= (cap
& FBINFO_HWACCEL_YPAN
)
1928 && divides(info
->fix
.ypanstep
, vc
->vc_font
.height
)
1929 && info
->var
.yres_virtual
> info
->var
.yres
;
1930 int good_wrap
= (cap
& FBINFO_HWACCEL_YWRAP
)
1931 && divides(info
->fix
.ywrapstep
, vc
->vc_font
.height
)
1932 && divides(vc
->vc_font
.height
, info
->var
.yres_virtual
);
1933 int reading_fast
= cap
& FBINFO_READS_FAST
;
1934 int fast_copyarea
= (cap
& FBINFO_HWACCEL_COPYAREA
) && !(cap
& FBINFO_HWACCEL_DISABLED
);
1935 int fast_imageblit
= (cap
& FBINFO_HWACCEL_IMAGEBLIT
) && !(cap
& FBINFO_HWACCEL_DISABLED
);
1937 p
->vrows
= info
->var
.yres_virtual
/fh
;
1938 if (info
->var
.yres
> (fh
* (vc
->vc_rows
+ 1)))
1939 p
->vrows
-= (info
->var
.yres
- (fh
* vc
->vc_rows
)) / fh
;
1940 if ((info
->var
.yres
% fh
) && (info
->var
.yres_virtual
% fh
<
1941 info
->var
.yres
% fh
))
1944 if (good_wrap
|| good_pan
) {
1945 if (reading_fast
|| fast_copyarea
)
1946 p
->scrollmode
= good_wrap
? SCROLL_WRAP_MOVE
: SCROLL_PAN_MOVE
;
1948 p
->scrollmode
= good_wrap
? SCROLL_REDRAW
:
1951 if (reading_fast
|| (fast_copyarea
&& !fast_imageblit
))
1952 p
->scrollmode
= SCROLL_MOVE
;
1954 p
->scrollmode
= SCROLL_REDRAW
;
1958 static int fbcon_resize(struct vc_data
*vc
, unsigned int width
,
1959 unsigned int height
)
1961 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
1962 struct display
*p
= &fb_display
[vc
->vc_num
];
1963 struct fb_var_screeninfo var
= info
->var
;
1965 int fw
= vc
->vc_font
.width
;
1966 int fh
= vc
->vc_font
.height
;
1968 var
.xres
= width
* fw
;
1969 var
.yres
= height
* fh
;
1970 x_diff
= info
->var
.xres
- var
.xres
;
1971 y_diff
= info
->var
.yres
- var
.yres
;
1972 if (x_diff
< 0 || x_diff
> fw
|| (y_diff
< 0 || y_diff
> fh
)) {
1973 struct fb_videomode
*mode
;
1975 DPRINTK("attempting resize %ix%i\n", var
.xres
, var
.yres
);
1976 mode
= fb_find_best_mode(&var
, &info
->modelist
);
1979 fb_videomode_to_var(&var
, mode
);
1980 if (width
> var
.xres
/fw
|| height
> var
.yres
/fh
)
1983 * The following can probably have any value... Do we need to
1986 var
.bits_per_pixel
= p
->bits_per_pixel
;
1987 var
.xres_virtual
= p
->xres_virtual
;
1988 var
.yres_virtual
= p
->yres_virtual
;
1989 var
.accel_flags
= p
->accel_flags
;
1990 var
.width
= p
->width
;
1991 var
.height
= p
->height
;
1993 var
.green
= p
->green
;
1995 var
.transp
= p
->transp
;
1996 var
.nonstd
= p
->nonstd
;
1998 DPRINTK("resize now %ix%i\n", var
.xres
, var
.yres
);
1999 if (CON_IS_VISIBLE(vc
)) {
2000 var
.activate
= FB_ACTIVATE_NOW
|
2002 fb_set_var(info
, &var
);
2003 info
->flags
&= ~FBINFO_MISC_MODESWITCH
;
2005 var_to_display(p
, &info
->var
, info
);
2007 updatescrollmode(p
, info
, vc
);
2011 static int fbcon_switch(struct vc_data
*vc
)
2013 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
2014 struct display
*p
= &fb_display
[vc
->vc_num
];
2015 struct fb_var_screeninfo var
;
2019 int l
= fbcon_softback_size
/ vc
->vc_size_row
;
2021 fbcon_set_origin(vc
);
2022 softback_top
= softback_curr
= softback_in
= softback_buf
;
2026 softback_end
= softback_buf
+ l
* vc
->vc_size_row
;
2028 /* Smaller scrollback makes no sense, and 0 would screw
2029 the operation totally */
2033 if (logo_shown
>= 0) {
2034 struct vc_data
*conp2
= vc_cons
[logo_shown
].d
;
2036 if (conp2
->vc_top
== logo_lines
2037 && conp2
->vc_bottom
== conp2
->vc_rows
)
2043 * FIXME: If we have multiple fbdev's loaded, we need to
2044 * update all info->currcon. Perhaps, we can place this
2045 * in a centralized structure, but this might break some
2048 * info->currcon = vc->vc_num;
2050 for (i
= 0; i
< FB_MAX
; i
++) {
2051 if (registered_fb
[i
] != NULL
)
2052 registered_fb
[i
]->currcon
= vc
->vc_num
;
2055 memset(&var
, 0, sizeof(struct fb_var_screeninfo
));
2056 fb_videomode_to_var(&var
, p
->mode
);
2057 display_to_var(&var
, p
);
2058 var
.activate
= FB_ACTIVATE_NOW
;
2061 * make sure we don't unnecessarily trip the memcmp()
2064 info
->var
.activate
= var
.activate
;
2065 info
->var
.yoffset
= info
->var
.xoffset
= p
->yscroll
= 0;
2066 fb_set_var(info
, &var
);
2068 if (info
->flags
& FBINFO_MISC_MODESWITCH
) {
2069 if (info
->fbops
->fb_set_par
)
2070 info
->fbops
->fb_set_par(info
);
2071 info
->flags
&= ~FBINFO_MISC_MODESWITCH
;
2074 vc
->vc_can_do_color
= (fb_get_color_depth(info
) != 1);
2075 vc
->vc_complement_mask
= vc
->vc_can_do_color
? 0x7700 : 0x0800;
2076 updatescrollmode(p
, info
, vc
);
2078 switch (p
->scrollmode
) {
2079 case SCROLL_WRAP_MOVE
:
2080 scrollback_phys_max
= p
->vrows
- vc
->vc_rows
;
2082 case SCROLL_PAN_MOVE
:
2083 case SCROLL_PAN_REDRAW
:
2084 scrollback_phys_max
= p
->vrows
- 2 * vc
->vc_rows
;
2085 if (scrollback_phys_max
< 0)
2086 scrollback_phys_max
= 0;
2089 scrollback_phys_max
= 0;
2093 scrollback_current
= 0;
2095 update_var(vc
->vc_num
, info
);
2096 fbcon_set_palette(vc
, color_table
);
2098 if (vt_cons
[vc
->vc_num
]->vc_mode
== KD_TEXT
)
2099 accel_clear_margins(vc
, info
, 0);
2100 if (logo_shown
== -2) {
2101 logo_shown
= fg_console
;
2102 /* This is protected above by initmem_freed */
2104 update_region(fg_console
,
2105 vc
->vc_origin
+ vc
->vc_size_row
* vc
->vc_top
,
2106 vc
->vc_size_row
* (vc
->vc_bottom
-
2113 static int fbcon_blank(struct vc_data
*vc
, int blank
, int mode_switch
)
2115 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
2116 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
2117 struct display
*p
= &fb_display
[vc
->vc_num
];
2120 struct fb_var_screeninfo var
= info
->var
;
2123 * HACK ALERT: Some hardware will require reinitializion at this stage,
2124 * others will require it to be done as late as possible.
2125 * For now, we differentiate this with the
2126 * FBINFO_MISC_MODESWITCHLATE bitflag. Worst case will be
2127 * hardware that requires it here and another one later.
2128 * A definitive solution may require fixing X or the VT
2131 if (info
->flags
& FBINFO_MISC_MODESWITCHLATE
)
2132 info
->flags
|= FBINFO_MISC_MODESWITCH
;
2135 fbcon_cursor(vc
, CM_ERASE
);
2139 if (!(info
->flags
& FBINFO_MISC_MODESWITCHLATE
)) {
2140 var
.activate
= FB_ACTIVATE_NOW
| FB_ACTIVATE_FORCE
;
2141 fb_set_var(info
, &var
);
2145 fbcon_cursor(vc
, blank
? CM_ERASE
: CM_DRAW
);
2147 if (!info
->fbops
->fb_blank
) {
2149 unsigned short oldc
;
2153 oldc
= vc
->vc_video_erase_char
;
2154 vc
->vc_video_erase_char
&= charmask
;
2155 height
= vc
->vc_rows
;
2156 y_break
= p
->vrows
- p
->yscroll
;
2157 if (height
> y_break
) {
2158 accel_clear(vc
, info
, real_y(p
, 0),
2159 0, y_break
, vc
->vc_cols
);
2160 accel_clear(vc
, info
, real_y(p
, y_break
),
2161 0, height
- y_break
,
2164 accel_clear(vc
, info
, real_y(p
, 0),
2165 0, height
, vc
->vc_cols
);
2166 vc
->vc_video_erase_char
= oldc
;
2168 update_screen(vc
->vc_num
);
2171 return fb_blank(info
, blank
);
2174 static void fbcon_free_font(struct display
*p
)
2176 if (p
->userfont
&& p
->fontdata
&& (--REFCOUNT(p
->fontdata
) == 0))
2177 kfree(p
->fontdata
- FONT_EXTRA_WORDS
* sizeof(int));
2182 static int fbcon_get_font(struct vc_data
*vc
, struct console_font
*font
)
2184 u8
*fontdata
= vc
->vc_font
.data
;
2185 u8
*data
= font
->data
;
2188 font
->width
= vc
->vc_font
.width
;
2189 font
->height
= vc
->vc_font
.height
;
2190 font
->charcount
= vc
->vc_hi_font_mask
? 512 : 256;
2194 if (font
->width
<= 8) {
2195 j
= vc
->vc_font
.height
;
2196 for (i
= 0; i
< font
->charcount
; i
++) {
2197 memcpy(data
, fontdata
, j
);
2198 memset(data
+ j
, 0, 32 - j
);
2202 } else if (font
->width
<= 16) {
2203 j
= vc
->vc_font
.height
* 2;
2204 for (i
= 0; i
< font
->charcount
; i
++) {
2205 memcpy(data
, fontdata
, j
);
2206 memset(data
+ j
, 0, 64 - j
);
2210 } else if (font
->width
<= 24) {
2211 for (i
= 0; i
< font
->charcount
; i
++) {
2212 for (j
= 0; j
< vc
->vc_font
.height
; j
++) {
2213 *data
++ = fontdata
[0];
2214 *data
++ = fontdata
[1];
2215 *data
++ = fontdata
[2];
2216 fontdata
+= sizeof(u32
);
2218 memset(data
, 0, 3 * (32 - j
));
2219 data
+= 3 * (32 - j
);
2222 j
= vc
->vc_font
.height
* 4;
2223 for (i
= 0; i
< font
->charcount
; i
++) {
2224 memcpy(data
, fontdata
, j
);
2225 memset(data
+ j
, 0, 128 - j
);
2233 static int fbcon_do_set_font(struct vc_data
*vc
, int w
, int h
,
2234 u8
* data
, int userfont
)
2236 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
2237 struct display
*p
= &fb_display
[vc
->vc_num
];
2240 char *old_data
= NULL
;
2242 if (CON_IS_VISIBLE(vc
) && softback_lines
)
2243 fbcon_set_origin(vc
);
2245 resize
= (w
!= vc
->vc_font
.width
) || (h
!= vc
->vc_font
.height
);
2247 old_data
= vc
->vc_font
.data
;
2249 cnt
= FNTCHARCNT(data
);
2252 vc
->vc_font
.data
= p
->fontdata
= data
;
2253 if ((p
->userfont
= userfont
))
2255 vc
->vc_font
.width
= w
;
2256 vc
->vc_font
.height
= h
;
2257 if (vc
->vc_hi_font_mask
&& cnt
== 256) {
2258 vc
->vc_hi_font_mask
= 0;
2259 if (vc
->vc_can_do_color
) {
2260 vc
->vc_complement_mask
>>= 1;
2261 vc
->vc_s_complement_mask
>>= 1;
2264 /* ++Edmund: reorder the attribute bits */
2265 if (vc
->vc_can_do_color
) {
2266 unsigned short *cp
=
2267 (unsigned short *) vc
->vc_origin
;
2268 int count
= vc
->vc_screenbuf_size
/ 2;
2270 for (; count
> 0; count
--, cp
++) {
2272 scr_writew(((c
& 0xfe00) >> 1) |
2275 c
= vc
->vc_video_erase_char
;
2276 vc
->vc_video_erase_char
=
2277 ((c
& 0xfe00) >> 1) | (c
& 0xff);
2280 } else if (!vc
->vc_hi_font_mask
&& cnt
== 512) {
2281 vc
->vc_hi_font_mask
= 0x100;
2282 if (vc
->vc_can_do_color
) {
2283 vc
->vc_complement_mask
<<= 1;
2284 vc
->vc_s_complement_mask
<<= 1;
2287 /* ++Edmund: reorder the attribute bits */
2289 unsigned short *cp
=
2290 (unsigned short *) vc
->vc_origin
;
2291 int count
= vc
->vc_screenbuf_size
/ 2;
2293 for (; count
> 0; count
--, cp
++) {
2294 unsigned short newc
;
2296 if (vc
->vc_can_do_color
)
2298 ((c
& 0xff00) << 1) | (c
&
2302 scr_writew(newc
, cp
);
2304 c
= vc
->vc_video_erase_char
;
2305 if (vc
->vc_can_do_color
) {
2306 vc
->vc_video_erase_char
=
2307 ((c
& 0xff00) << 1) | (c
& 0xff);
2310 vc
->vc_video_erase_char
= c
& ~0x100;
2316 /* reset wrap/pan */
2317 info
->var
.xoffset
= info
->var
.yoffset
= p
->yscroll
= 0;
2318 vc_resize(vc
->vc_num
, info
->var
.xres
/ w
, info
->var
.yres
/ h
);
2319 if (CON_IS_VISIBLE(vc
) && softback_buf
) {
2320 int l
= fbcon_softback_size
/ vc
->vc_size_row
;
2323 softback_buf
+ l
* vc
->vc_size_row
;
2325 /* Smaller scrollback makes no sense, and 0 would screw
2326 the operation totally */
2330 } else if (CON_IS_VISIBLE(vc
)
2331 && vt_cons
[vc
->vc_num
]->vc_mode
== KD_TEXT
) {
2332 accel_clear_margins(vc
, info
, 0);
2333 update_screen(vc
->vc_num
);
2336 if (old_data
&& (--REFCOUNT(old_data
) == 0))
2337 kfree(old_data
- FONT_EXTRA_WORDS
* sizeof(int));
2341 static int fbcon_copy_font(struct vc_data
*vc
, int con
)
2343 struct display
*od
= &fb_display
[con
];
2344 struct console_font
*f
= &vc
->vc_font
;
2346 if (od
->fontdata
== f
->data
)
2347 return 0; /* already the same font... */
2348 return fbcon_do_set_font(vc
, f
->width
, f
->height
, od
->fontdata
, od
->userfont
);
2352 * User asked to set font; we are guaranteed that
2353 * a) width and height are in range 1..32
2354 * b) charcount does not exceed 512
2357 static int fbcon_set_font(struct vc_data
*vc
, struct console_font
*font
, unsigned flags
)
2359 unsigned charcount
= font
->charcount
;
2360 int w
= font
->width
;
2361 int h
= font
->height
;
2364 u8
*new_data
, *data
= font
->data
, *p
;
2366 if (charcount
!= 256 && charcount
!= 512)
2377 new_data
= kmalloc(FONT_EXTRA_WORDS
* sizeof(int) + size
, GFP_USER
);
2382 new_data
+= FONT_EXTRA_WORDS
* sizeof(int);
2383 FNTSIZE(new_data
) = size
;
2384 FNTCHARCNT(new_data
) = charcount
;
2385 REFCOUNT(new_data
) = 0; /* usage counter */
2388 for (i
= 0; i
< charcount
; i
++) {
2393 } else if (w
<= 16) {
2395 for (i
= 0; i
< charcount
; i
++) {
2400 } else if (w
<= 24) {
2401 for (i
= 0; i
< charcount
; i
++) {
2403 for (j
= 0; j
< h
; j
++) {
2409 data
+= 3 * (32 - h
);
2413 for (i
= 0; i
< charcount
; i
++) {
2419 /* we can do it in u32 chunks because of charcount is 256 or 512, so
2420 font length must be multiple of 256, at least. And 256 is multiple
2423 while (p
> new_data
) {
2424 p
= (u8
*)((u32
*)p
- 1);
2427 FNTSUM(new_data
) = k
;
2428 /* Check if the same font is on some other console already */
2429 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++) {
2430 struct vc_data
*tmp
= vc_cons
[i
].d
;
2432 if (fb_display
[i
].userfont
&&
2433 fb_display
[i
].fontdata
&&
2434 FNTSUM(fb_display
[i
].fontdata
) == k
&&
2435 FNTSIZE(fb_display
[i
].fontdata
) == size
&&
2436 tmp
->vc_font
.width
== w
&&
2437 !memcmp(fb_display
[i
].fontdata
, new_data
, size
)) {
2438 kfree(new_data
- FONT_EXTRA_WORDS
* sizeof(int));
2439 new_data
= fb_display
[i
].fontdata
;
2443 return fbcon_do_set_font(vc
, font
->width
, font
->height
, new_data
, 1);
2446 static int fbcon_set_def_font(struct vc_data
*vc
, struct console_font
*font
, char *name
)
2448 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
2449 struct font_desc
*f
;
2452 f
= get_default_font(info
->var
.xres
, info
->var
.yres
);
2453 else if (!(f
= find_font(name
)))
2456 font
->width
= f
->width
;
2457 font
->height
= f
->height
;
2458 return fbcon_do_set_font(vc
, f
->width
, f
->height
, f
->data
, 0);
2461 static u16 palette_red
[16];
2462 static u16 palette_green
[16];
2463 static u16 palette_blue
[16];
2465 static struct fb_cmap palette_cmap
= {
2466 0, 16, palette_red
, palette_green
, palette_blue
, NULL
2469 static int fbcon_set_palette(struct vc_data
*vc
, unsigned char *table
)
2471 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[vc
->vc_num
]];
2475 if (!info
->fbops
->fb_blank
&& console_blanked
)
2477 depth
= fb_get_color_depth(info
);
2479 for (i
= j
= 0; i
< 16; i
++) {
2481 val
= vc
->vc_palette
[j
++];
2482 palette_red
[k
] = (val
<< 8) | val
;
2483 val
= vc
->vc_palette
[j
++];
2484 palette_green
[k
] = (val
<< 8) | val
;
2485 val
= vc
->vc_palette
[j
++];
2486 palette_blue
[k
] = (val
<< 8) | val
;
2488 palette_cmap
.len
= 16;
2489 palette_cmap
.start
= 0;
2491 * If framebuffer is capable of less than 16 colors,
2492 * use default palette of fbcon.
2495 fb_copy_cmap(fb_default_cmap(1 << depth
), &palette_cmap
);
2497 return fb_set_cmap(&palette_cmap
, info
);
2500 static u16
*fbcon_screen_pos(struct vc_data
*vc
, int offset
)
2505 if (vc
->vc_num
!= fg_console
|| !softback_lines
)
2506 return (u16
*) (vc
->vc_origin
+ offset
);
2507 line
= offset
/ vc
->vc_size_row
;
2508 if (line
>= softback_lines
)
2509 return (u16
*) (vc
->vc_origin
+ offset
-
2510 softback_lines
* vc
->vc_size_row
);
2511 p
= softback_curr
+ offset
;
2512 if (p
>= softback_end
)
2513 p
+= softback_buf
- softback_end
;
2517 static unsigned long fbcon_getxy(struct vc_data
*vc
, unsigned long pos
,
2523 if (pos
>= vc
->vc_origin
&& pos
< vc
->vc_scr_end
) {
2524 unsigned long offset
= (pos
- vc
->vc_origin
) / 2;
2526 x
= offset
% vc
->vc_cols
;
2527 y
= offset
/ vc
->vc_cols
;
2528 if (vc
->vc_num
== fg_console
)
2529 y
+= softback_lines
;
2530 ret
= pos
+ (vc
->vc_cols
- x
) * 2;
2531 } else if (vc
->vc_num
== fg_console
&& softback_lines
) {
2532 unsigned long offset
= pos
- softback_curr
;
2534 if (pos
< softback_curr
)
2535 offset
+= softback_end
- softback_buf
;
2537 x
= offset
% vc
->vc_cols
;
2538 y
= offset
/ vc
->vc_cols
;
2539 ret
= pos
+ (vc
->vc_cols
- x
) * 2;
2540 if (ret
== softback_end
)
2542 if (ret
== softback_in
)
2543 ret
= vc
->vc_origin
;
2545 /* Should not happen */
2547 ret
= vc
->vc_origin
;
2556 /* As we might be inside of softback, we may work with non-contiguous buffer,
2557 that's why we have to use a separate routine. */
2558 static void fbcon_invert_region(struct vc_data
*vc
, u16
* p
, int cnt
)
2561 u16 a
= scr_readw(p
);
2562 if (!vc
->vc_can_do_color
)
2564 else if (vc
->vc_hi_font_mask
== 0x100)
2565 a
= ((a
) & 0x11ff) | (((a
) & 0xe000) >> 4) |
2566 (((a
) & 0x0e00) << 4);
2568 a
= ((a
) & 0x88ff) | (((a
) & 0x7000) >> 4) |
2569 (((a
) & 0x0700) << 4);
2571 if (p
== (u16
*) softback_end
)
2572 p
= (u16
*) softback_buf
;
2573 if (p
== (u16
*) softback_in
)
2574 p
= (u16
*) vc
->vc_origin
;
2578 static int fbcon_scrolldelta(struct vc_data
*vc
, int lines
)
2580 struct fb_info
*info
= registered_fb
[(int) con2fb_map
[fg_console
]];
2581 struct display
*p
= &fb_display
[fg_console
];
2582 int offset
, limit
, scrollback_old
;
2585 if (vc
->vc_num
!= fg_console
)
2587 if (vt_cons
[vc
->vc_num
]->vc_mode
!= KD_TEXT
|| !lines
)
2589 if (logo_shown
>= 0) {
2590 struct vc_data
*conp2
= vc_cons
[logo_shown
].d
;
2592 if (conp2
->vc_top
== logo_lines
2593 && conp2
->vc_bottom
== conp2
->vc_rows
)
2595 if (logo_shown
== vc
->vc_num
) {
2601 logo_lines
* vc
->vc_size_row
;
2602 for (i
= 0; i
< logo_lines
; i
++) {
2603 if (p
== softback_top
)
2605 if (p
== softback_buf
)
2607 p
-= vc
->vc_size_row
;
2608 q
-= vc
->vc_size_row
;
2609 scr_memcpyw((u16
*) q
, (u16
*) p
,
2613 update_region(vc
->vc_num
, vc
->vc_origin
,
2614 logo_lines
* vc
->vc_cols
);
2618 fbcon_cursor(vc
, CM_ERASE
| CM_SOFTBACK
);
2619 fbcon_redraw_softback(vc
, p
, lines
);
2620 fbcon_cursor(vc
, CM_DRAW
| CM_SOFTBACK
);
2624 if (!scrollback_phys_max
)
2627 scrollback_old
= scrollback_current
;
2628 scrollback_current
-= lines
;
2629 if (scrollback_current
< 0)
2630 scrollback_current
= 0;
2631 else if (scrollback_current
> scrollback_max
)
2632 scrollback_current
= scrollback_max
;
2633 if (scrollback_current
== scrollback_old
)
2636 if (!info
->fbops
->fb_blank
&&
2637 (console_blanked
|| vt_cons
[vc
->vc_num
]->vc_mode
!= KD_TEXT
2640 fbcon_cursor(vc
, CM_ERASE
);
2642 offset
= p
->yscroll
- scrollback_current
;
2644 switch (p
->scrollmode
) {
2645 case SCROLL_WRAP_MOVE
:
2646 info
->var
.vmode
|= FB_VMODE_YWRAP
;
2648 case SCROLL_PAN_MOVE
:
2649 case SCROLL_PAN_REDRAW
:
2650 limit
-= vc
->vc_rows
;
2651 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
2656 else if (offset
>= limit
)
2658 info
->var
.xoffset
= 0;
2659 info
->var
.yoffset
= offset
* vc
->vc_font
.height
;
2660 update_var(vc
->vc_num
, info
);
2661 if (!scrollback_current
)
2662 fbcon_cursor(vc
, CM_DRAW
);
2666 static int fbcon_set_origin(struct vc_data
*vc
)
2668 if (softback_lines
&& !console_blanked
)
2669 fbcon_scrolldelta(vc
, softback_lines
);
2673 static void fbcon_suspended(struct fb_info
*info
)
2675 /* Clear cursor, restore saved data */
2676 info
->cursor
.enable
= 0;
2677 info
->fbops
->fb_cursor(info
, &info
->cursor
);
2680 static void fbcon_resumed(struct fb_info
*info
)
2684 if (info
->currcon
< 0)
2686 vc
= vc_cons
[info
->currcon
].d
;
2688 update_screen(vc
->vc_num
);
2691 static void fbcon_modechanged(struct fb_info
*info
)
2693 struct vc_data
*vc
= vc_cons
[info
->currcon
].d
;
2697 if (info
->currcon
< 0 || vt_cons
[info
->currcon
]->vc_mode
!=
2700 p
= &fb_display
[vc
->vc_num
];
2702 info
->var
.xoffset
= info
->var
.yoffset
= p
->yscroll
= 0;
2704 if (CON_IS_VISIBLE(vc
)) {
2705 var_to_display(p
, &info
->var
, info
);
2706 cols
= info
->var
.xres
/ vc
->vc_font
.width
;
2707 rows
= info
->var
.yres
/ vc
->vc_font
.height
;
2708 vc_resize(vc
->vc_num
, cols
, rows
);
2709 updatescrollmode(p
, info
, vc
);
2711 scrollback_current
= 0;
2712 update_var(vc
->vc_num
, info
);
2713 fbcon_set_palette(vc
, color_table
);
2714 update_screen(vc
->vc_num
);
2716 int l
= fbcon_softback_size
/ vc
->vc_size_row
;
2718 softback_end
= softback_buf
+ l
* vc
->vc_size_row
;
2720 /* Smaller scrollback makes no sense, and 0
2721 would screw the operation totally */
2728 static int fbcon_mode_deleted(struct fb_info
*info
,
2729 struct fb_videomode
*mode
)
2731 struct fb_info
*fb_info
;
2733 int i
, j
, found
= 0;
2735 /* before deletion, ensure that mode is not in use */
2736 for (i
= first_fb_vc
; i
<= last_fb_vc
; i
++) {
2737 j
= (int) con2fb_map
[i
];
2740 fb_info
= registered_fb
[j
];
2741 if (fb_info
!= info
)
2746 if (fb_mode_is_equal(p
->mode
, mode
)) {
2754 static int fbcon_fb_registered(int idx
)
2758 if (info_idx
== -1) {
2760 ret
= fbcon_takeover();
2766 static int fbcon_event_notify(struct notifier_block
*self
,
2767 unsigned long action
, void *data
)
2769 struct fb_event
*event
= (struct fb_event
*) data
;
2770 struct fb_info
*info
= event
->info
;
2771 struct fb_videomode
*mode
;
2772 struct fb_con2fbmap
*con2fb
;
2776 case FB_EVENT_SUSPEND
:
2777 fbcon_suspended(info
);
2779 case FB_EVENT_RESUME
:
2780 fbcon_resumed(info
);
2782 case FB_EVENT_MODE_CHANGE
:
2783 fbcon_modechanged(info
);
2785 case FB_EVENT_MODE_DELETE
:
2786 mode
= (struct fb_videomode
*) event
->data
;
2787 ret
= fbcon_mode_deleted(info
, mode
);
2789 case FB_EVENT_FB_REGISTERED
:
2790 ret
= fbcon_fb_registered(info
->node
);
2792 case FB_EVENT_SET_CONSOLE_MAP
:
2793 con2fb
= (struct fb_con2fbmap
*) event
->data
;
2794 ret
= set_con2fb_map(con2fb
->console
- 1, con2fb
->framebuffer
);
2796 case FB_EVENT_GET_CONSOLE_MAP
:
2797 con2fb
= (struct fb_con2fbmap
*) event
->data
;
2798 con2fb
->framebuffer
= con2fb_map
[con2fb
->console
- 1];
2806 * The console `switch' structure for the frame buffer based console
2809 const struct consw fb_con
= {
2810 .owner
= THIS_MODULE
,
2811 .con_startup
= fbcon_startup
,
2812 .con_init
= fbcon_init
,
2813 .con_deinit
= fbcon_deinit
,
2814 .con_clear
= fbcon_clear
,
2815 .con_putc
= fbcon_putc
,
2816 .con_putcs
= fbcon_putcs
,
2817 .con_cursor
= fbcon_cursor
,
2818 .con_scroll
= fbcon_scroll
,
2819 .con_bmove
= fbcon_bmove
,
2820 .con_switch
= fbcon_switch
,
2821 .con_blank
= fbcon_blank
,
2822 .con_font_set
= fbcon_set_font
,
2823 .con_font_get
= fbcon_get_font
,
2824 .con_font_default
= fbcon_set_def_font
,
2825 .con_font_copy
= fbcon_copy_font
,
2826 .con_set_palette
= fbcon_set_palette
,
2827 .con_scrolldelta
= fbcon_scrolldelta
,
2828 .con_set_origin
= fbcon_set_origin
,
2829 .con_invert_region
= fbcon_invert_region
,
2830 .con_screen_pos
= fbcon_screen_pos
,
2831 .con_getxy
= fbcon_getxy
,
2832 .con_resize
= fbcon_resize
,
2835 static struct notifier_block fbcon_event_notifier
= {
2836 .notifier_call
= fbcon_event_notify
,
2839 int __init
fb_console_init(void)
2843 acquire_console_sem();
2844 fb_register_client(&fbcon_event_notifier
);
2845 release_console_sem();
2847 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
2850 if (num_registered_fb
) {
2851 for (i
= 0; i
< FB_MAX
; i
++) {
2852 if (registered_fb
[i
] != NULL
) {
2863 module_init(fb_console_init
);
2867 void __exit
fb_console_exit(void)
2869 acquire_console_sem();
2870 fb_unregister_client(&fbcon_event_notifier
);
2871 release_console_sem();
2872 give_up_console(&fb_con
);
2875 module_exit(fb_console_exit
);
2880 * Visible symbols for modules
2883 EXPORT_SYMBOL(fb_display
);
2884 EXPORT_SYMBOL(fb_con
);
2886 MODULE_LICENSE("GPL");