61 #include <linux/module.h>
62 #include <linux/types.h>
64 #include <linux/kernel.h>
67 #include <linux/string.h>
69 #include <linux/slab.h>
84 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
86 # define DPRINTK(fmt, args...)
100 static int logo_lines;
105 static int fbcon_softback_size = 32768;
106 static unsigned long softback_buf, softback_curr;
107 static unsigned long softback_in;
108 static unsigned long softback_top, softback_end;
109 static int softback_lines;
111 static int first_fb_vc;
113 static int fbcon_is_default = 1;
114 static int fbcon_has_exited;
115 static int primary_device = -1;
116 static int fbcon_has_console_bind;
118 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
119 static int map_override;
121 static inline void fbcon_map_override(
void)
126 static inline void fbcon_map_override(
void)
132 static char fontname[40];
135 static int info_idx = -1;
138 static int initial_rotation;
139 static int fbcon_has_sysfs;
141 static const struct consw fb_con;
143 #define CM_SOFTBACK (8)
145 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
147 static int fbcon_set_origin(
struct vc_data *);
149 #define CURSOR_DRAW_DELAY (1)
151 static int vbl_cursor_cnt;
152 static int fbcon_cursor_noblink;
154 #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
160 static const char *fbcon_startup(
void);
162 static void fbcon_deinit(
struct vc_data *
vc);
165 static void fbcon_putc(
struct vc_data *
vc,
int c,
int ypos,
int xpos);
166 static void fbcon_putcs(
struct vc_data *
vc,
const unsigned short *
s,
167 int count,
int ypos,
int xpos);
168 static void fbcon_clear_margins(
struct vc_data *
vc,
int bottom_only);
170 static int fbcon_scroll(
struct vc_data *
vc,
int t,
int b,
int dir,
172 static void fbcon_bmove(
struct vc_data *
vc,
int sy,
int sx,
int dy,
int dx,
174 static int fbcon_switch(
struct vc_data *
vc);
175 static int fbcon_blank(
struct vc_data *
vc,
int blank,
int mode_switch);
176 static int fbcon_set_palette(
struct vc_data *
vc,
unsigned char *
table);
177 static int fbcon_scrolldelta(
struct vc_data *
vc,
int lines);
192 static void fbcon_modechanged(
struct fb_info *
info);
193 static void fbcon_set_all_vcs(
struct fb_info *
info);
194 static void fbcon_start(
void);
195 static void fbcon_exit(
void);
196 static struct device *fbcon_device;
198 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
199 static inline void fbcon_set_rotation(
struct fb_info *
info)
204 ops->
p->con_rotate < 4)
205 ops->
rotate = ops->
p->con_rotate;
215 if (!ops || ops->
currcon == -1)
220 if (info == fb_info) {
228 fbcon_modechanged(info);
232 static void fbcon_rotate_all(
struct fb_info *info,
u32 rotate)
239 if (!ops || ops->
currcon < 0 || rotate > 3)
242 for (i = first_fb_vc; i <= last_fb_vc; i++) {
245 registered_fb[con2fb_map[i]] != info)
248 p = &fb_display[vc->
vc_num];
252 fbcon_set_all_vcs(info);
255 static inline void fbcon_set_rotation(
struct fb_info *info)
262 static void fbcon_rotate(
struct fb_info *info,
u32 rotate)
267 static void fbcon_rotate_all(
struct fb_info *info,
u32 rotate)
273 static int fbcon_get_rotate(
struct fb_info *info)
277 return (ops) ? ops->
rotate : 0;
280 static inline int fbcon_is_inactive(
struct vc_data *vc,
struct fb_info *info)
286 !vt_force_oops_output(vc);
289 static int get_color(
struct vc_data *vc,
struct fb_info *info,
308 int col = mono_col(info);
316 color = (is_fg) ? fg : bg;
356 static void fbcon_update_softback(
struct vc_data *vc)
388 registered_fb[con2fb_map[vc->
vc_num]] != info ||
397 ops->
cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
398 get_color(vc, info, c, 0));
402 static void cursor_timer_handler(
unsigned long dev_addr)
404 struct fb_info *info = (
struct fb_info *) dev_addr;
411 static void fbcon_add_cursor_timer(
struct fb_info *info)
415 if ((!info->
queue.func || info->
queue.func == fb_flashcursor) &&
417 !fbcon_cursor_noblink) {
418 if (!info->
queue.func)
430 static void fbcon_del_cursor_timer(
struct fb_info *info)
434 if (info->
queue.func == fb_flashcursor &&
442 static int __init fb_console_setup(
char *this_opt)
447 if (!this_opt || !*this_opt)
450 while ((options =
strsep(&this_opt,
",")) !=
NULL) {
451 if (!
strncmp(options,
"font:", 5))
452 strlcpy(fontname, options + 5,
sizeof(fontname));
454 if (!
strncmp(options,
"scrollback:", 11)) {
458 if (*options ==
'k' || *options ==
'K') {
459 fbcon_softback_size *= 1024;
469 if (!
strncmp(options,
"map:", 4)) {
476 (options[j++]-
'0') %
FB_MAX;
479 fbcon_map_override();
485 if (!
strncmp(options,
"vc:", 3)) {
491 if (*options++ ==
'-')
493 fbcon_is_default = 0;
496 if (!
strncmp(options,
"rotate:", 7)) {
500 if (initial_rotation > 3)
501 initial_rotation = 0;
507 __setup(
"fbcon=", fb_console_setup);
510 static int search_fb_in_map(
int idx)
514 for (i = first_fb_vc; i <= last_fb_vc; i++) {
515 if (con2fb_map[i] == idx)
521 static int search_for_mapped_con(
void)
525 for (i = first_fb_vc; i <= last_fb_vc; i++) {
526 if (con2fb_map[i] != -1)
532 static int fbcon_takeover(
int show_logo)
536 if (!num_registered_fb)
542 for (i = first_fb_vc; i <= last_fb_vc; i++)
543 con2fb_map[i] = info_idx;
549 for (i = first_fb_vc; i <= last_fb_vc; i++) {
554 fbcon_has_console_bind = 1;
561 static void fbcon_prepare_logo(
struct vc_data *vc,
struct fb_info *info,
562 int cols,
int rows,
int new_cols,
int new_rows)
567 static void fbcon_prepare_logo(
struct vc_data *vc,
struct fb_info *info,
568 int cols,
int rows,
int new_cols,
int new_rows)
573 unsigned short *save =
NULL, *
r, *
q;
592 for (r = q - logo_lines * cols; r <
q; r++)
595 if (r != q && new_rows >= rows + logo_lines) {
598 int i = cols < new_cols ? cols : new_cols;
599 scr_memsetw(save, erase, logo_lines * new_cols * 2);
601 for (cnt = 0; cnt < logo_lines; cnt++, r +=
i)
609 for (cnt = rows - logo_lines; cnt > 0; cnt--) {
615 if (vc->
vc_y + logo_lines >= rows)
616 lines = rows - vc->
vc_y - 1;
623 scr_memsetw((
unsigned short *) vc->
vc_origin,
628 fbcon_clear_margins(vc, 0);
637 vc->
vc_y += logo_lines;
645 "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n");
653 #ifdef CONFIG_FB_TILEBLITTING
654 static void set_blitting_type(
struct vc_data *vc,
struct fb_info *info)
658 ops->
p = &fb_display[vc->
vc_num];
663 fbcon_set_rotation(info);
668 static int fbcon_invalid_charcount(
struct fb_info *info,
unsigned charcount)
673 info->tileops->fb_get_tilemax(info) < charcount)
679 static void set_blitting_type(
struct vc_data *vc,
struct fb_info *info)
684 ops->
p = &fb_display[vc->
vc_num];
685 fbcon_set_rotation(info);
689 static int fbcon_invalid_charcount(
struct fb_info *info,
unsigned charcount)
697 static int con2fb_acquire_newinfo(
struct vc_data *vc,
struct fb_info *info,
698 int unit,
int oldidx)
703 if (!try_module_get(info->
fbops->owner))
706 if (!err && info->
fbops->fb_open &&
707 info->
fbops->fb_open(info, 0))
720 set_blitting_type(vc, info);
724 con2fb_map[
unit] = oldidx;
725 module_put(info->
fbops->owner);
731 static int con2fb_release_oldinfo(
struct vc_data *vc,
struct fb_info *oldinfo,
732 struct fb_info *newinfo,
int unit,
733 int oldidx,
int found)
738 if (oldinfo->
fbops->fb_release &&
739 oldinfo->
fbops->fb_release(oldinfo, 0)) {
740 con2fb_map[
unit] = oldidx;
741 if (!found && newinfo->
fbops->fb_release)
742 newinfo->
fbops->fb_release(newinfo, 0);
744 module_put(newinfo->
fbops->owner);
749 fbcon_del_cursor_timer(oldinfo);
755 module_put(oldinfo->
fbops->owner);
763 if (newinfo->
fbops->fb_set_par) {
764 ret = newinfo->
fbops->fb_set_par(newinfo);
768 "detected unhandled fb_set_par error, "
769 "error code %d\n", ret);
776 static void con2fb_init_display(
struct vc_data *vc,
struct fb_info *info,
777 int unit,
int show_logo)
785 ret = info->
fbops->fb_set_par(info);
789 "unhandled fb_set_par error, "
790 "error code %d\n", ret);
795 fbcon_set_disp(info, &info->
var, unit);
799 struct fb_info *fg_info =
802 fbcon_prepare_logo(fg_vc, fg_info, fg_vc->
vc_cols,
819 static int set_con2fb_map(
int unit,
int newidx,
int user)
822 int oldidx = con2fb_map[
unit];
824 struct fb_info *oldinfo =
NULL;
827 if (oldidx == newidx)
833 if (!search_for_mapped_con() || !
con_is_bound(&fb_con)) {
835 return fbcon_takeover(0);
841 found = search_fb_in_map(newidx);
844 con2fb_map[
unit] = newidx;
846 err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
853 if (!err && oldinfo && !search_fb_in_map(oldidx))
854 err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx,
862 fbcon_add_cursor_timer(info);
863 con2fb_map_boot[
unit] = newidx;
864 con2fb_init_display(vc, info, unit, show_logo);
867 if (!search_fb_in_map(info_idx))
878 static int var_to_display(
struct display *disp,
880 struct fb_info *info)
921 static const char *fbcon_startup(
void)
923 const char *display_desc =
"frame buffer device";
928 struct fb_info *info =
NULL;
936 if (!num_registered_fb || info_idx == -1)
946 owner = info->
fbops->owner;
947 if (!try_module_get(owner))
949 if (info->
fbops->fb_open && info->
fbops->fb_open(info, 0)) {
965 set_blitting_type(vc, info);
968 if (fbcon_softback_size) {
975 fbcon_softback_size = 0;
981 kfree((
void *) softback_buf);
987 softback_in = softback_top = softback_curr =
994 if (!fontname[0] || !(font =
find_font(fontname)))
1015 info->
var.bits_per_pixel);
1017 fbcon_add_cursor_timer(info);
1018 fbcon_has_exited = 0;
1019 return display_desc;
1022 static void fbcon_init(
struct vc_data *vc,
int init)
1027 struct vc_data *svc = *default_mode;
1029 int logo = 1, new_rows, new_cols,
rows,
cols, charcnt = 256;
1032 if (info_idx == -1 || info ==
NULL)
1041 if (var_to_display(p, &info->
var, info))
1045 con2fb_acquire_newinfo(vc, info, vc->
vc_num, -1);
1065 if (!fontname[0] || !(font =
find_font(fontname)))
1084 if (charcnt == 256) {
1099 set_blitting_type(vc, info);
1105 new_cols /= vc->
vc_font.width;
1106 new_rows /= vc->
vc_font.height;
1116 if (info->
fbops->fb_set_par &&
1118 ret = info->
fbops->fb_set_par(info);
1122 "unhandled fb_set_par error, "
1123 "error code %d\n", ret);
1149 fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
1151 if (vc == svc && softback_buf)
1152 fbcon_update_softback(vc);
1156 set_blitting_type(vc, info);
1162 static void fbcon_free_font(
struct display *p)
1170 static void fbcon_deinit(
struct vc_data *vc)
1173 struct fb_info *
info;
1178 idx = con2fb_map[vc->
vc_num];
1194 fbcon_del_cursor_timer(info);
1230 static void fbcon_clear(
struct vc_data *vc,
int sy,
int sx,
int height,
1239 if (fbcon_is_inactive(vc, info))
1242 if (!height || !width)
1245 if (sy < vc->vc_top && vc->
vc_top == logo_lines)
1251 if (sy < y_break && sy + height - 1 >= y_break) {
1253 ops->
clear(vc, info, real_y(p, sy), sx, b, width);
1254 ops->
clear(vc, info, real_y(p, sy + b), sx, height - b,
1257 ops->
clear(vc, info, real_y(p, sy), sx, height, width);
1260 static void fbcon_putcs(
struct vc_data *vc,
const unsigned short *
s,
1261 int count,
int ypos,
int xpos)
1267 if (!fbcon_is_inactive(vc, info))
1268 ops->
putcs(vc, info, s, count, real_y(p, ypos), xpos,
1273 static void fbcon_putc(
struct vc_data *vc,
int c,
int ypos,
int xpos)
1278 fbcon_putcs(vc, &chr, 1, ypos, xpos);
1281 static void fbcon_clear_margins(
struct vc_data *vc,
int bottom_only)
1286 if (!fbcon_is_inactive(vc, info))
1290 static void fbcon_cursor(
struct vc_data *vc,
int mode)
1297 if (fbcon_is_inactive(vc, info) || vc->
vc_deccm != 1)
1301 fbcon_del_cursor_timer(info);
1303 fbcon_add_cursor_timer(info);
1307 mode &= ~CM_SOFTBACK;
1311 fbcon_set_origin(vc);
1315 ops->
cursor(vc, info, mode, y, get_color(vc, info, c, 1),
1316 get_color(vc, info, c, 0));
1320 static int scrollback_phys_max = 0;
1321 static int scrollback_max = 0;
1322 static int scrollback_current = 0;
1328 struct vc_data **default_mode, *vc;
1333 p = &fb_display[
unit];
1335 if (var_to_display(p, var, info))
1344 svc = *default_mode;
1345 t = &fb_display[svc->
vc_num];
1349 vc->
vc_font.width = (*default_mode)->vc_font.width;
1350 vc->
vc_font.height = (*default_mode)->vc_font.height;
1366 if (charcnt == 256) {
1388 fbcon_update_softback(vc);
1401 ops->
var.xoffset = 0;
1405 scrollback_max +=
count;
1406 if (scrollback_max > scrollback_phys_max)
1407 scrollback_max = scrollback_phys_max;
1408 scrollback_current = 0;
1420 ops->
var.xoffset = 0;
1424 scrollback_max -=
count;
1425 if (scrollback_max < 0)
1427 scrollback_current = 0;
1443 ops->
var.xoffset = 0;
1447 fbcon_clear_margins(vc, 1);
1448 scrollback_max +=
count;
1449 if (scrollback_max > scrollback_phys_max)
1450 scrollback_max = scrollback_phys_max;
1451 scrollback_current = 0;
1464 fbcon_redraw_move(vc, p, t + count, vc->
vc_rows - count, t);
1467 ops->
var.xoffset = 0;
1471 fbcon_clear_margins(vc, 1);
1472 scrollback_max +=
count;
1473 if (scrollback_max > scrollback_phys_max)
1474 scrollback_max = scrollback_phys_max;
1475 scrollback_current = 0;
1491 ops->
var.xoffset = 0;
1495 fbcon_clear_margins(vc, 1);
1496 scrollback_max -=
count;
1497 if (scrollback_max < 0)
1499 scrollback_current = 0;
1512 fbcon_redraw_move(vc, p, t, vc->
vc_rows - count, t + count);
1515 ops->
var.xoffset = 0;
1519 fbcon_clear_margins(vc, 1);
1520 scrollback_max -=
count;
1521 if (scrollback_max < 0)
1523 scrollback_current = 0;
1526 static void fbcon_redraw_softback(
struct vc_data *vc,
struct display *p,
1530 unsigned short *
d, *
s;
1534 d = (
u16 *) softback_curr;
1535 if (d == (
u16 *) softback_in)
1538 softback_lines -=
delta;
1540 if (softback_curr < softback_top && n < softback_buf) {
1541 n += softback_end - softback_buf;
1542 if (n < softback_top) {
1547 }
else if (softback_curr >= softback_top
1548 && n < softback_top) {
1554 if (softback_curr > softback_in && n >= softback_end) {
1555 n += softback_buf - softback_end;
1556 if (n > softback_in) {
1560 }
else if (softback_curr <= softback_in && n > softback_in) {
1565 if (n == softback_curr)
1568 s = (
u16 *) softback_curr;
1569 if (s == (
u16 *) softback_in)
1572 unsigned short *
start;
1576 unsigned short attr = 1;
1582 if (attr != (c & 0xff00)) {
1585 fbcon_putcs(vc, start, s - start,
1593 fbcon_putcs(vc, start, s - start,
1606 fbcon_putcs(vc, start, s - start, line, x);
1608 if (d == (
u16 *) softback_end)
1609 d = (
u16 *) softback_buf;
1610 if (d == (
u16 *) softback_in)
1612 if (s == (
u16 *) softback_end)
1613 s = (
u16 *) softback_buf;
1614 if (s == (
u16 *) softback_in)
1619 static void fbcon_redraw_move(
struct vc_data *vc,
struct display *p,
1620 int line,
int count,
int dy)
1622 unsigned short *s = (
unsigned short *)
1626 unsigned short *start =
s;
1630 unsigned short attr = 1;
1634 if (attr != (c & 0xff00)) {
1637 fbcon_putcs(vc, start, s - start,
1647 fbcon_putcs(vc, start, s - start, dy, x);
1653 static void fbcon_redraw_blit(
struct vc_data *vc,
struct fb_info *info,
1654 struct display *p,
int line,
int count,
int ycount)
1657 unsigned short *d = (
unsigned short *)
1659 unsigned short *s = d +
offset;
1663 unsigned short *start =
s;
1673 ops->
bmove(vc, info, line + ycount, x,
1674 line, x, 1, s-start);
1689 ops->
bmove(vc, info, line + ycount, x, line, x, 1,
1704 int line,
int count,
int offset)
1706 unsigned short *d = (
unsigned short *)
1708 unsigned short *s = d +
offset;
1711 unsigned short *start =
s;
1715 unsigned short attr = 1;
1719 if (attr != (c & 0xff00)) {
1722 fbcon_putcs(vc, start, s - start,
1730 fbcon_putcs(vc, start, s - start,
1745 fbcon_putcs(vc, start, s - start, line, x);
1758 static inline void fbcon_softback_note(
struct vc_data *vc,
int t,
1772 if (softback_in == softback_end)
1773 softback_in = softback_buf;
1774 if (softback_in == softback_top) {
1776 if (softback_top == softback_end)
1777 softback_top = softback_buf;
1780 softback_curr = softback_in;
1783 static int fbcon_scroll(
struct vc_data *vc,
int t,
int b,
int dir,
1790 if (fbcon_is_inactive(vc, info))
1806 fbcon_softback_note(vc, t, count);
1807 if (logo_shown >= 0)
1811 fbcon_redraw_blit(vc, info, p, t, b - t - count,
1813 fbcon_clear(vc, b - count, 0, count, vc->
vc_cols);
1814 scr_memsetw((
unsigned short *) (vc->
vc_origin +
1823 if (b - t - count > 3 * vc->
vc_rows >> 2) {
1825 fbcon_bmove(vc, 0, 0, count, 0, t,
1827 ywrap_up(vc, count);
1829 fbcon_bmove(vc, b - count, 0, b, 0,
1833 fbcon_bmove(vc, t + count, 0, t, 0,
1837 fbcon_clear(vc, b - count, 0, count, vc->
vc_cols);
1843 && ((!scroll_partial && (b - t == vc->
vc_rows))
1848 fbcon_redraw_move(vc, p, 0, t, count);
1849 ypan_up_redraw(vc, t, count);
1851 fbcon_redraw_move(vc, p, b,
1854 fbcon_redraw_move(vc, p, t + count, b - t - count, t);
1855 fbcon_clear(vc, b - count, 0, count, vc->
vc_cols);
1861 && ((!scroll_partial && (b - t == vc->
vc_rows))
1866 fbcon_bmove(vc, 0, 0, count, 0, t,
1870 fbcon_bmove(vc, b - count, 0, b, 0,
1874 fbcon_bmove(vc, t + count, 0, t, 0,
1878 fbcon_clear(vc, b - count, 0, count, vc->
vc_cols);
1883 fbcon_redraw(vc, p, t, b - t - count,
1885 fbcon_clear(vc, b - count, 0, count, vc->
vc_cols);
1886 scr_memsetw((
unsigned short *) (vc->
vc_origin +
1898 if (logo_shown >= 0)
1902 fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
1904 fbcon_clear(vc, t, 0, count, vc->
vc_cols);
1905 scr_memsetw((
unsigned short *) (vc->
vc_origin +
1914 if (b - t - count > 3 * vc->
vc_rows >> 2) {
1916 fbcon_bmove(vc, b, 0, b - count, 0,
1919 ywrap_down(vc, count);
1921 fbcon_bmove(vc, count, 0, 0, 0, t,
1924 fbcon_bmove(vc, t, 0, t + count, 0,
1928 fbcon_clear(vc, t, 0, count, vc->
vc_cols);
1933 && ((!scroll_partial && (b - t == vc->
vc_rows))
1938 fbcon_bmove(vc, b, 0, b - count, 0,
1941 ypan_down(vc, count);
1943 fbcon_bmove(vc, count, 0, 0, 0, t,
1946 fbcon_bmove(vc, t, 0, t + count, 0,
1950 fbcon_clear(vc, t, 0, count, vc->
vc_cols);
1955 && ((!scroll_partial && (b - t == vc->
vc_rows))
1960 fbcon_redraw_move(vc, p, b, vc->
vc_rows - b,
1962 ypan_down_redraw(vc, t, count);
1964 fbcon_redraw_move(vc, p, count, t, 0);
1966 fbcon_redraw_move(vc, p, t, b - t - count, t + count);
1967 fbcon_clear(vc, t, 0, count, vc->
vc_cols);
1972 fbcon_redraw(vc, p, b - 1, b - t - count,
1974 fbcon_clear(vc, t, 0, count, vc->
vc_cols);
1975 scr_memsetw((
unsigned short *) (vc->
vc_origin +
1987 static void fbcon_bmove(
struct vc_data *vc,
int sy,
int sx,
int dy,
int dx,
1988 int height,
int width)
1993 if (fbcon_is_inactive(vc, info))
1996 if (!width || !height)
2006 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
2010 static void fbcon_bmove_rec(
struct vc_data *vc,
struct display *p,
int sy,
int sx,
2011 int dy,
int dx,
int height,
int width,
u_int y_break)
2017 if (sy < y_break && sy + height > y_break) {
2020 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
2022 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
2023 height - b, width, y_break);
2025 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
2026 height - b, width, y_break);
2027 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
2033 if (dy < y_break && dy + height > y_break) {
2036 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
2038 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
2039 height - b, width, y_break);
2041 fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
2042 height - b, width, y_break);
2043 fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
2048 ops->
bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
2052 static void updatescrollmode(
struct display *p,
2053 struct fb_info *info,
2058 int cap = info->
flags;
2061 info->
fix.xpanstep);
2065 info->
var.xres_virtual);
2074 !(cap & FBINFO_HWACCEL_DISABLED);
2076 !(cap & FBINFO_HWACCEL_DISABLED);
2078 p->
vrows = vyres/fh;
2079 if (yres > (fh * (vc->
vc_rows + 1)))
2081 if ((yres % fh) && (vyres % fh < yres % fh))
2084 if (good_wrap || good_pan) {
2085 if (reading_fast || fast_copyarea)
2092 if (reading_fast || (fast_copyarea && !fast_imageblit))
2099 static int fbcon_resize(
struct vc_data *vc,
unsigned int width,
2100 unsigned int height,
unsigned int user)
2106 int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
2114 var.
xres = virt_w * virt_fw;
2115 var.
yres = virt_h * virt_fh;
2116 x_diff = info->
var.xres - var.
xres;
2117 y_diff = info->
var.yres - var.
yres;
2118 if (x_diff < 0 || x_diff > virt_fw ||
2119 y_diff < 0 || y_diff > virt_fh) {
2126 display_to_var(&var, p);
2129 if (virt_w > var.
xres/virt_fw || virt_h > var.
yres/virt_fh)
2138 var_to_display(p, &info->
var, info);
2141 updatescrollmode(p, info, vc);
2145 static int fbcon_switch(
struct vc_data *vc)
2147 struct fb_info *
info, *old_info =
NULL;
2151 int i,
ret, prev_console, charcnt = 256;
2158 fbcon_set_origin(vc);
2159 softback_top = softback_curr = softback_in = softback_buf;
2161 fbcon_update_softback(vc);
2164 if (logo_shown >= 0) {
2167 if (conp2->
vc_top == logo_lines
2174 if (prev_console != -1)
2184 for (i = 0; i <
FB_MAX; i++) {
2185 if (registered_fb[i] !=
NULL && registered_fb[i]->fbcon_par) {
2192 display_to_var(&var, p);
2204 if (old_info !=
NULL && (old_info != info ||
2206 if (info->
fbops->fb_set_par) {
2207 ret = info->
fbops->fb_set_par(info);
2211 "unhandled fb_set_par error, "
2212 "error code %d\n", ret);
2215 if (old_info != info)
2216 fbcon_del_cursor_timer(old_info);
2219 if (fbcon_is_inactive(vc, info) ||
2221 fbcon_del_cursor_timer(info);
2223 fbcon_add_cursor_timer(info);
2225 set_blitting_type(vc, info);
2230 set_blitting_type(vc, info);
2242 updatescrollmode(p, info, vc);
2251 if (scrollback_phys_max < 0)
2252 scrollback_phys_max = 0;
2255 scrollback_phys_max = 0;
2260 scrollback_current = 0;
2262 if (!fbcon_is_inactive(vc, info)) {
2268 fbcon_clear_margins(vc, 0);
2284 static void fbcon_generic_blank(
struct vc_data *vc,
struct fb_info *info,
2292 unsigned short oldc;
2304 event.data = ␣
2306 unlock_fb_info(info);
2309 static int fbcon_blank(
struct vc_data *vc,
int blank,
int mode_switch)
2327 if (!fbcon_is_inactive(vc, info)) {
2335 fbcon_generic_blank(vc, info, blank);
2342 if (mode_switch || fbcon_is_inactive(vc, info) ||
2344 fbcon_del_cursor_timer(info);
2346 fbcon_add_cursor_timer(info);
2351 static int fbcon_debug_enter(
struct vc_data *vc)
2358 if (info->
fbops->fb_debug_enter)
2359 info->
fbops->fb_debug_enter(info);
2364 static int fbcon_debug_leave(
struct vc_data *vc)
2370 if (info->
fbops->fb_debug_leave)
2371 info->
fbops->fb_debug_leave(info);
2387 if (font->
width <= 8) {
2390 memcpy(data, fontdata, j);
2391 memset(data + j, 0, 32 - j);
2395 }
else if (font->
width <= 16) {
2398 memcpy(data, fontdata, j);
2399 memset(data + j, 0, 64 - j);
2403 }
else if (font->
width <= 24) {
2405 for (j = 0; j < vc->
vc_font.height; j++) {
2406 *data++ = fontdata[0];
2407 *data++ = fontdata[1];
2408 *data++ = fontdata[2];
2409 fontdata +=
sizeof(
u32);
2411 memset(data, 0, 3 * (32 - j));
2412 data += 3 * (32 -
j);
2417 memcpy(data, fontdata, j);
2418 memset(data + j, 0, 128 - j);
2426 static int fbcon_do_set_font(
struct vc_data *vc,
int w,
int h,
2427 const u8 * data,
int userfont)
2434 char *old_data =
NULL;
2437 fbcon_set_origin(vc);
2460 unsigned short *
cp =
2464 for (; count > 0; count--, cp++) {
2471 ((c & 0xfe00) >> 1) | (c & 0xff);
2483 unsigned short *cp =
2487 for (; count > 0; count--, cp++) {
2488 unsigned short newc;
2492 ((c & 0xff00) << 1) | (c &
2501 ((c & 0xff00) << 1) | (c & 0xff);
2518 fbcon_update_softback(vc);
2521 fbcon_clear_margins(vc, 0);
2525 if (old_data && (--
REFCOUNT(old_data) == 0))
2530 static int fbcon_copy_font(
struct vc_data *vc,
int con)
2556 int w = font->
width;
2560 u8 *new_data, *data = font->
data;
2561 int pitch = (font->
width+7) >> 3;
2565 if (charcount != 256 && charcount != 512)
2569 if (!(info->
pixmap.blit_x & (1 << (font->
width - 1))) ||
2574 if (fbcon_invalid_charcount(info, charcount))
2577 size = h * pitch * charcount;
2588 for (i=0; i< charcount; i++) {
2589 memcpy(new_data + i*h*pitch, data + i*32*pitch, h*pitch);
2594 csum =
crc32(0, new_data, size);
2598 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2601 if (fb_display[i].userfont &&
2602 fb_display[i].fontdata &&
2603 FNTSUM(fb_display[i].fontdata) == csum &&
2604 FNTSIZE(fb_display[i].fontdata) == size &&
2606 !
memcmp(fb_display[i].fontdata, new_data, size)) {
2608 new_data = (
u8 *)fb_display[i].fontdata;
2612 return fbcon_do_set_font(vc, font->
width, font->
height, new_data, 1);
2631 static u16 palette_red[16];
2632 static u16 palette_green[16];
2633 static u16 palette_blue[16];
2635 static struct fb_cmap palette_cmap = {
2636 0, 16, palette_red, palette_green, palette_blue,
NULL
2639 static int fbcon_set_palette(
struct vc_data *vc,
unsigned char *
table)
2645 if (fbcon_is_inactive(vc, info))
2653 for (i = j = 0; i < 16; i++) {
2656 palette_red[
k] = (val << 8) | val;
2658 palette_green[
k] = (val << 8) | val;
2660 palette_blue[
k] = (val << 8) | val;
2662 palette_cmap.
len = 16;
2663 palette_cmap.
start = 0;
2674 static u16 *fbcon_screen_pos(
struct vc_data *vc,
int offset)
2682 if (line >= softback_lines)
2685 p = softback_curr +
offset;
2686 if (p >= softback_end)
2687 p += softback_buf - softback_end;
2691 static unsigned long fbcon_getxy(
struct vc_data *vc,
unsigned long pos,
2697 if (pos >= vc->
vc_origin && pos < vc->vc_scr_end) {
2698 unsigned long offset = (pos - vc->
vc_origin) / 2;
2703 y += softback_lines;
2706 unsigned long offset = pos - softback_curr;
2708 if (pos < softback_curr)
2709 offset += softback_end - softback_buf;
2714 if (ret == softback_end)
2716 if (ret == softback_in)
2732 static void fbcon_invert_region(
struct vc_data *vc,
u16 * p,
int cnt)
2739 a = ((
a) & 0x11ff) | (((
a) & 0xe000) >> 4) |
2740 (((a) & 0x0e00) << 4);
2742 a = ((
a) & 0x88ff) | (((
a) & 0x7000) >> 4) |
2743 (((a) & 0x0700) << 4);
2745 if (p == (
u16 *) softback_end)
2746 p = (
u16 *) softback_buf;
2747 if (p == (
u16 *) softback_in)
2752 static int fbcon_scrolldelta(
struct vc_data *vc,
int lines)
2764 if (logo_shown >= 0) {
2767 if (conp2->
vc_top == logo_lines
2770 if (logo_shown == vc->
vc_num) {
2777 for (i = 0; i < logo_lines; i++) {
2778 if (p == softback_top)
2780 if (p == softback_buf)
2787 softback_in = softback_curr =
p;
2793 fbcon_cursor(vc,
CM_ERASE | CM_SOFTBACK);
2794 fbcon_redraw_softback(vc, disp, lines);
2795 fbcon_cursor(vc,
CM_DRAW | CM_SOFTBACK);
2799 if (!scrollback_phys_max)
2802 scrollback_old = scrollback_current;
2803 scrollback_current -= lines;
2804 if (scrollback_current < 0)
2805 scrollback_current = 0;
2806 else if (scrollback_current > scrollback_max)
2807 scrollback_current = scrollback_max;
2808 if (scrollback_current == scrollback_old)
2811 if (fbcon_is_inactive(vc, info))
2816 offset = disp->
yscroll - scrollback_current;
2817 limit = disp->
vrows;
2830 else if (offset >= limit)
2833 ops->
var.xoffset = 0;
2834 ops->
var.yoffset = offset * vc->
vc_font.height;
2837 if (!scrollback_current)
2842 static int fbcon_set_origin(
struct vc_data *vc)
2845 fbcon_scrolldelta(vc, softback_lines);
2849 static void fbcon_suspended(
struct fb_info *info)
2862 static void fbcon_resumed(
struct fb_info *info)
2874 static void fbcon_modechanged(
struct fb_info *info)
2885 registered_fb[con2fb_map[ops->
currcon]] != info)
2888 p = &fb_display[vc->
vc_num];
2889 set_blitting_type(vc, info);
2892 var_to_display(p, &info->
var, info);
2898 updatescrollmode(p, info, vc);
2900 scrollback_current = 0;
2902 if (!fbcon_is_inactive(vc, info)) {
2910 fbcon_update_softback(vc);
2914 static void fbcon_set_all_vcs(
struct fb_info *info)
2924 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2927 registered_fb[con2fb_map[i]] != info)
2935 p = &fb_display[vc->
vc_num];
2936 set_blitting_type(vc, info);
2937 var_to_display(p, &info->
var, info);
2946 fbcon_modechanged(info);
2949 static int fbcon_mode_deleted(
struct fb_info *info,
2954 int i,
j, found = 0;
2957 for (i = first_fb_vc; i <= last_fb_vc; i++) {
2962 if (fb_info != info)
2975 #ifdef CONFIG_VT_HW_CONSOLE_BINDING
2976 static int fbcon_unbind(
void)
2984 fbcon_has_console_bind = 0;
2989 static inline int fbcon_unbind(
void)
2995 static int fbcon_fb_unbind(
int idx)
2997 int i, new_idx = -1, ret = 0;
2999 if (!fbcon_has_console_bind)
3002 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3003 if (con2fb_map[i] != idx &&
3004 con2fb_map[i] != -1) {
3010 if (new_idx != -1) {
3011 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3012 if (con2fb_map[i] == idx)
3013 set_con2fb_map(i, new_idx, 0);
3016 ret = fbcon_unbind();
3021 static int fbcon_fb_unregistered(
struct fb_info *info)
3026 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3027 if (con2fb_map[i] == idx)
3031 if (idx == info_idx) {
3034 for (i = 0; i <
FB_MAX; i++) {
3035 if (registered_fb[i] !=
NULL) {
3042 if (info_idx != -1) {
3043 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3044 if (con2fb_map[i] == -1)
3045 con2fb_map[
i] = info_idx;
3049 if (primary_device == idx)
3050 primary_device = -1;
3052 if (!num_registered_fb)
3058 static void fbcon_remap_all(
int idx)
3061 for (i = first_fb_vc; i <= last_fb_vc; i++)
3062 set_con2fb_map(i, idx, 0);
3066 "fb%i, to tty %i-%i\n", idx,
3067 first_fb_vc + 1, last_fb_vc + 1);
3072 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
3073 static void fbcon_select_primary(
struct fb_info *info)
3075 if (!map_override && primary_device == -1 &&
3081 primary_device = info->
node;
3083 for (i = first_fb_vc; i <= last_fb_vc; i++)
3084 con2fb_map_boot[i] = primary_device;
3088 "fb%i, to tty %i-%i\n", info->
node,
3089 first_fb_vc + 1, last_fb_vc + 1);
3090 info_idx = primary_device;
3096 static inline void fbcon_select_primary(
struct fb_info *info)
3102 static int fbcon_fb_registered(
struct fb_info *info)
3104 int ret = 0,
i,
idx;
3107 fbcon_select_primary(info);
3109 if (info_idx == -1) {
3110 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3111 if (con2fb_map_boot[i] == idx) {
3118 ret = fbcon_takeover(1);
3120 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3121 if (con2fb_map_boot[i] == idx)
3122 set_con2fb_map(i, idx, 0);
3129 static void fbcon_fb_blanked(
struct fb_info *info,
int blank)
3139 registered_fb[con2fb_map[ops->
currcon]] != info)
3151 static void fbcon_new_modelist(
struct fb_info *info)
3158 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3159 if (registered_fb[con2fb_map[i]] != info)
3161 if (!fb_display[i].mode)
3164 display_to_var(&var, &fb_display[i]);
3168 fbcon_set_disp(info, &var, vc->
vc_num);
3172 static void fbcon_get_requirement(
struct fb_info *info,
3181 for (i = first_fb_vc; i <= last_fb_vc; i++) {
3184 info->
node == con2fb_map[i]) {
3186 caps->
x |= 1 << (vc->
vc_font.width - 1);
3187 caps->
y |= 1 << (vc->
vc_font.height - 1);
3190 if (caps->
len < charcnt)
3191 caps->
len = charcnt;
3200 caps->
x = 1 << (vc->
vc_font.width - 1);
3201 caps->
y = 1 << (vc->
vc_font.height - 1);
3209 unsigned long action,
void *data)
3212 struct fb_info *info =
event->info;
3228 fbcon_suspended(info);
3231 fbcon_resumed(info);
3234 fbcon_modechanged(info);
3237 fbcon_set_all_vcs(info);
3241 ret = fbcon_mode_deleted(info, mode);
3245 ret = fbcon_fb_unbind(idx);
3248 ret = fbcon_fb_registered(info);
3251 ret = fbcon_fb_unregistered(info);
3254 con2fb =
event->data;
3255 ret = set_con2fb_map(con2fb->
console - 1,
3259 con2fb =
event->data;
3263 fbcon_fb_blanked(info, *(
int *)
event->
data);
3266 fbcon_new_modelist(info);
3270 fbcon_get_requirement(info, caps);
3274 fbcon_remap_all(idx);
3285 static const struct consw fb_con = {
3287 .con_startup = fbcon_startup,
3288 .con_init = fbcon_init,
3289 .con_deinit = fbcon_deinit,
3290 .con_clear = fbcon_clear,
3291 .con_putc = fbcon_putc,
3292 .con_putcs = fbcon_putcs,
3293 .con_cursor = fbcon_cursor,
3294 .con_scroll = fbcon_scroll,
3295 .con_bmove = fbcon_bmove,
3296 .con_switch = fbcon_switch,
3297 .con_blank = fbcon_blank,
3298 .con_font_set = fbcon_set_font,
3299 .con_font_get = fbcon_get_font,
3300 .con_font_default = fbcon_set_def_font,
3301 .con_font_copy = fbcon_copy_font,
3302 .con_set_palette = fbcon_set_palette,
3303 .con_scrolldelta = fbcon_scrolldelta,
3304 .con_set_origin = fbcon_set_origin,
3305 .con_invert_region = fbcon_invert_region,
3306 .con_screen_pos = fbcon_screen_pos,
3307 .con_getxy = fbcon_getxy,
3308 .con_resize = fbcon_resize,
3309 .con_debug_enter = fbcon_debug_enter,
3310 .con_debug_leave = fbcon_debug_leave,
3314 .notifier_call = fbcon_event_notify,
3321 struct fb_info *
info;
3325 if (fbcon_has_exited)
3331 if (idx == -1 || registered_fb[idx] ==
NULL)
3336 fbcon_rotate(info, rotate);
3342 static ssize_t store_rotate_all(
struct device *device,
3346 struct fb_info *
info;
3350 if (fbcon_has_exited)
3356 if (idx == -1 || registered_fb[idx] ==
NULL)
3361 fbcon_rotate_all(info, rotate);
3367 static ssize_t show_rotate(
struct device *device,
3370 struct fb_info *
info;
3371 int rotate = 0,
idx;
3373 if (fbcon_has_exited)
3379 if (idx == -1 || registered_fb[idx] ==
NULL)
3383 rotate = fbcon_get_rotate(info);
3389 static ssize_t show_cursor_blink(
struct device *device,
3392 struct fb_info *
info;
3394 int idx, blink = -1;
3396 if (fbcon_has_exited)
3402 if (idx == -1 || registered_fb[idx] ==
NULL)
3417 static ssize_t store_cursor_blink(
struct device *device,
3419 const char *buf,
size_t count)
3421 struct fb_info *
info;
3425 if (fbcon_has_exited)
3431 if (idx == -1 || registered_fb[idx] ==
NULL)
3442 fbcon_cursor_noblink = 0;
3443 fbcon_add_cursor_timer(info);
3445 fbcon_cursor_noblink = 1;
3446 fbcon_del_cursor_timer(info);
3458 store_cursor_blink),
3461 static int fbcon_init_device(
void)
3465 fbcon_has_sysfs = 1;
3467 for (i = 0; i <
ARRAY_SIZE(device_attrs); i++) {
3478 fbcon_has_sysfs = 0;
3484 static void fbcon_start(
void)
3486 if (num_registered_fb) {
3491 for (i = 0; i <
FB_MAX; i++) {
3492 if (registered_fb[i] !=
NULL) {
3503 static void fbcon_exit(
void)
3505 struct fb_info *
info;
3508 if (fbcon_has_exited)
3511 kfree((
void *)softback_buf);
3514 for (i = 0; i <
FB_MAX; i++) {
3523 if (info->
queue.func)
3525 DPRINTK(
"fbcon: %s pending work\n", (pending ?
"canceled" :
3528 for (j = first_fb_vc; j <= last_fb_vc; j++) {
3529 if (con2fb_map[j] == i)
3534 if (info->
fbops->fb_release)
3535 info->
fbops->fb_release(info, 0);
3536 module_put(info->
fbops->owner);
3541 fbcon_del_cursor_timer(info);
3547 if (info->
queue.func == fb_flashcursor)
3552 fbcon_has_exited = 1;
3555 static int __init fb_console_init(
void)
3564 if (IS_ERR(fbcon_device)) {
3566 "for fbcon; errno = %ld\n",
3567 PTR_ERR(fbcon_device));
3568 fbcon_device =
NULL;
3570 fbcon_init_device();
3584 static void __exit fbcon_deinit_device(
void)
3588 if (fbcon_has_sysfs) {
3589 for (i = 0; i <
ARRAY_SIZE(device_attrs); i++)
3592 fbcon_has_sysfs = 0;
3596 static void __exit fb_console_exit(
void)
3600 fbcon_deinit_device();