/* * linux/drivers/video/fbcon.c -- Low level frame buffer based console driver * * Copyright (C) 1995 Geert Uytterhoeven * * * This file is based on the original Amiga console driver (amicon.c): * * Copyright (C) 1993 Hamish Macdonald * Greg Harp * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] * * with work by William Rucklidge (wjr@cs.cornell.edu) * Geert Uytterhoeven * Jes Sorensen (jds@kom.auc.dk) * Martin Apel * * and on the original Atari console driver (atacon.c): * * Copyright (C) 1993 Bjoern Brauel * Roman Hodek * * with work by Guenther Kelleter * Martin Schaller * Andreas Schwab * * Hardware cursor support added by Emmanuel Marty (core@ggi-project.org) * Smart redraw scrolling, arbitrary font width support, 512char font support * and software scrollback added by * Jakub Jelinek (jj@ultra.linux.cz) * * Random hacking by Martin Mares <mj@ucw.cz> * * 2001 - Documented with DocBook * - Brad Douglas <brad@neruo.com> * * The low level operations for the various display memory organizations are * now in separate source files. * * Currently the following organizations are supported: * * o afb Amiga bitplanes * o cfb{2,4,8,16,24,32} Packed pixels * o ilbm Amiga interleaved bitplanes * o iplan2p[248] Atari interleaved bitplanes * o mfb Monochrome * o vga VGA characters/attributes * * To do: * * - Implement 16 plane mode (iplan2p16) * * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details.
*/
/* * FIXME: Locking * * - fbcon state itself is protected by the console_lock, and the code does a * pretty good job at making sure that lock is held everywhere it's needed. * * - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it * means concurrent access to the same fbdev from both fbcon and userspace * will blow up. To fix this all fbcon calls from fbmem.c need to be moved out * of fb_lock/unlock protected sections, since otherwise we'll recurse and * deadlock eventually. Aside: Due to these deadlock issues the fbdev code in * fbmem.c cannot use locking asserts, and there's lots of callers which get * the rules wrong, e.g. fbsysfs.c entirely missed fb_lock/unlock calls too.
*/
enum {
FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */
FBCON_LOGO_DRAW = -2, /* draw the logo to a console */
FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */
};
staticbool fbcon_skip_panic(struct fb_info *info)
{ /* panic_cpu is not exported, and can't be used if built as module. Use * oops_in_progress instead, but non-fatal oops won't be printed.
*/ #ifdefined(MODULE) return (info->skip_panic && unlikely(oops_in_progress)); #else return (info->skip_panic && unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID)); #endif
}
if (depth != 1)
color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c)
: attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c);
switch (depth) { case 1:
{ int col = mono_col(info); /* 0 or 1 */ int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0; int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col;
if (console_blanked)
fg = bg;
color = (is_fg) ? fg : bg; break;
} case 2: /* * Scale down 16-colors to 4 colors. Default 4-color palette * is grayscale. However, simply dividing the values by 4 * will not work, as colors 1, 2 and 3 will be scaled-down * to zero rendering them invisible. So empirically convert * colors to a sane 4-level grayscale.
*/ switch (color) { case 0:
color = 0; /* black */ break; case 1 ... 6:
color = 2; /* white */ break; case 7 ... 8:
color = 1; /* gray */ break; default:
color = 3; /* intense white */ break;
} break; case 3: /* * Last 8 entries of default 16-color palette is a more intense * version of the first 8 (i.e., same chrominance, different * luminance).
*/
color &= 7; break;
}
/* FIXME: we should sort out the unbind locking instead */ /* instead we just fail to flash the cursor if we can't get
* the lock instead of blocking fbcon deinit */
ret = console_trylock(); if (ret == 0) return;
/* protected by console_lock */
info = ops->info;
if (ops->currcon != -1)
vc = vc_cons[ops->currcon].d;
if (!vc || !con_is_visible(vc) ||
fbcon_info_from_console(vc->vc_num) != info ||
vc->vc_deccm != 1) {
console_unlock(); return;
}
if (err) { for (i = first_fb_vc; i <= last_fb_vc; i++)
con2fb_map[i] = -1;
info_idx = -1;
} else {
fbcon_has_console_bind = true;
}
return err;
}
#ifdef MODULE staticvoid fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, int cols, int rows, int new_cols, int new_rows)
{
logo_shown = FBCON_LOGO_DONTSHOW;
} #else staticvoid fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, int cols, int rows, int new_cols, int new_rows)
{ /* Need to make room for the logo */ struct fbcon_ops *ops = info->fbcon_par; int cnt, erase = vc->vc_video_erase_char, step; unsignedshort *save = NULL, *r, *q; int logo_height;
if (info->fbops->owner) {
logo_shown = FBCON_LOGO_DONTSHOW; return;
}
/* * remove underline attribute from erase character * if black and white framebuffer.
*/ if (fb_get_color_depth(&info->var, &info->fix) == 1)
erase &= ~0x400;
logo_height = fb_prepare_logo(info, ops->rotate);
logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height);
q = (unsignedshort *) (vc->vc_origin +
vc->vc_size_row * rows);
step = logo_lines * cols; for (r = q - logo_lines * cols; r < q; r++) if (scr_readw(r) != vc->vc_video_erase_char) break; if (r != q && new_rows >= rows + logo_lines) {
save = kmalloc(array3_size(logo_lines, new_cols, 2),
GFP_KERNEL); if (save) { int i = min(cols, new_cols);
scr_memsetw(save, erase, array3_size(logo_lines, new_cols, 2));
r = q - step; for (cnt = 0; cnt < logo_lines; cnt++, r += i)
scr_memcpyw(save + cnt * new_cols, r, 2 * i);
r = q;
}
} if (r == q) { /* We can scroll screen down */
r = q - step - cols; for (cnt = rows - logo_lines; cnt > 0; cnt--) {
scr_memcpyw(r + step, r, vc->vc_size_row);
r -= cols;
} if (!save) { int lines; if (vc->state.y + logo_lines >= rows)
lines = rows - vc->state.y - 1; else
lines = logo_lines;
vc->state.y += lines;
vc->vc_pos += lines * vc->vc_size_row;
}
}
scr_memsetw((unsignedshort *) vc->vc_origin,
erase,
vc->vc_size_row * logo_lines);
/* If oldinfo and newinfo are driving the same hardware, the fb_release() method of oldinfo may attempt to restore the hardware state. This will leave the newinfo in an undefined state. Thus, a call to fb_set_par() may be needed for the newinfo.
*/ if (newinfo && newinfo->fbops->fb_set_par) {
ret = newinfo->fbops->fb_set_par(newinfo);
if (fg_console != unit)
update_screen(vc_cons[fg_console].d);
}
/** * set_con2fb_map - map console to frame buffer device * @unit: virtual console number to map * @newidx: frame buffer index to map virtual console to * @user: user request * * Maps a virtual console @unit to a frame buffer device * @newidx. * * This should be called with the console lock held.
*/ staticint set_con2fb_map(int unit, int newidx, int user)
{ struct vc_data *vc = vc_cons[unit].d; int oldidx = con2fb_map[unit]; struct fb_info *info = fbcon_registered_fb[newidx]; struct fb_info *oldinfo = NULL; int err = 0, show_logo;
/* * If old fb is not mapped to any of the consoles, * fbcon should release it.
*/ if (oldinfo && !search_fb_in_map(oldidx))
con2fb_release_oldinfo(vc, oldinfo, info);
/* * If fbcon_num_registered_fb is zero, this is a call for the dummy part. * The frame buffer devices weren't initialized yet.
*/ if (!fbcon_num_registered_fb || info_idx == -1) return display_desc; /* * Instead of blindly using fbcon_registered_fb[0], we use info_idx, set by * fbcon_fb_registered();
*/
info = fbcon_registered_fb[info_idx]; if (!info) return NULL;
if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||
(info->fix.type == FB_TYPE_TEXT))
logo = 0;
if (var_to_display(p, &info->var, info)) return;
if (!info->fbcon_par)
con2fb_acquire_newinfo(vc, info, vc->vc_num);
/* If we are not the first console on this
fb, copy the font from that console */
t = &fb_display[fg_console]; if (!p->fontdata) { if (t->fontdata) { struct vc_data *fvc = vc_cons[fg_console].d;
/* * We must always set the mode. The mode of the previous console * driver could be in the same resolution but we are using different * hardware so we have to initialize the hardware. * * We need to do it in fbcon_init() to prevent screen corruption.
*/ if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { if (info->fbops->fb_set_par && !ops->initialized) {
ret = info->fbops->fb_set_par(info);
/* * ++guenther: console.c:vc_allocate() relies on initializing * vc_{cols,rows}, but we must not set those if we are only * resizing the console.
*/ if (init) {
vc->vc_cols = new_cols;
vc->vc_rows = new_rows;
} else
vc_resize(vc, new_cols, new_rows);
if (logo)
fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
/* fbcon_XXX routines - interface used by the world * * This system is now divided into two levels because of complications * caused by hardware scrolling. Top level functions: * * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins() * * handles y values in range [0, scr_height-1] that correspond to real * screen positions. y_wrap shift means that first line of bitmap may be * anywhere on this display. These functions convert lineoffsets to * bitmap offsets and deal with the wrap-around case by splitting blits. * * fbcon_bmove_physical_8() -- These functions fast implementations * fbcon_clear_physical_8() -- of original fbcon_XXX fns. * fbcon_putc_physical_8() -- (font width != 8) may be added later * * WARNING: * * At the moment fbcon_putc() cannot blit across vertical wrap boundary * Implies should only really hardware scroll in rows. Only reason for * restriction is simplicity & efficiency at the moment.
*/
if (sy < vc->vc_top && vc->vc_top == logo_lines) {
vc->vc_top = 0; /* * If the font dimensions are not an integral of the display * dimensions then the ops->clear below won't end up clearing * the margins. Call clear_margins here in case the logo * bitmap stretched into the margin area.
*/
fbcon_clear_margins(vc, 0);
}
staticvoid fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, int line, int count, int dy)
{ unsignedshort *s = (unsignedshort *)
(vc->vc_origin + vc->vc_size_row * line);
while (count--) { unsignedshort *start = s; unsignedshort *le = advance_row(s, 1); unsignedshort c; int x = 0; unsignedshort attr = 1;
do {
c = scr_readw(s); if (attr != (c & 0xff00)) {
attr = c & 0xff00; if (s > start) {
fbcon_putcs(vc, start, s - start,
dy, x);
x += s - start;
start = s;
}
}
console_conditional_schedule();
s++;
} while (s < le); if (s > start)
fbcon_putcs(vc, start, s - start, dy, x);
console_conditional_schedule();
dy++;
}
}
staticvoid fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, struct fbcon_display *p, int line, int count, int ycount)
{ int offset = ycount * vc->vc_cols; unsignedshort *d = (unsignedshort *)
(vc->vc_origin + vc->vc_size_row * line); unsignedshort *s = d + offset; struct fbcon_ops *ops = info->fbcon_par;
while (count--) { unsignedshort *start = s; unsignedshort *le = advance_row(s, 1); unsignedshort c; int x = 0;
do {
c = scr_readw(s);
if (c == scr_readw(d)) { if (s > start) {
ops->bmove(vc, info, line + ycount, x,
line, x, 1, s-start);
x += s - start + 1;
start = s + 1;
} else {
x++;
start++;
}
}
scr_writew(c, d);
console_conditional_schedule();
s++;
d++;
} while (s < le); if (s > start)
ops->bmove(vc, info, line + ycount, x, line, x, 1,
s-start);
console_conditional_schedule(); if (ycount > 0)
line++; else {
line--; /* NOTE: We subtract two lines from these pointers */
s -= vc->vc_size_row;
d -= vc->vc_size_row;
}
}
}
staticvoid fbcon_redraw(struct vc_data *vc, int line, int count, int offset)
{ unsignedshort *d = (unsignedshort *)
(vc->vc_origin + vc->vc_size_row * line); unsignedshort *s = d + offset;
while (count--) { unsignedshort *start = s; unsignedshort *le = advance_row(s, 1); unsignedshort c; int x = 0; unsignedshort attr = 1;
do {
c = scr_readw(s); if (attr != (c & 0xff00)) {
attr = c & 0xff00; if (s > start) {
fbcon_putcs(vc, start, s - start,
line, x);
x += s - start;
start = s;
}
} if (c == scr_readw(d)) { if (s > start) {
fbcon_putcs(vc, start, s - start,
line, x);
x += s - start + 1;
start = s + 1;
} else {
x++;
start++;
}
}
scr_writew(c, d);
console_conditional_schedule();
s++;
d++;
} while (s < le); if (s > start)
fbcon_putcs(vc, start, s - start, line, x);
console_conditional_schedule(); if (offset > 0)
line++; else {
line--; /* NOTE: We subtract two lines from these pointers */
s -= vc->vc_size_row;
d -= vc->vc_size_row;
}
}
}
staticvoid fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break)
{ struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par;
u_int b;
if (sy < y_break && sy + height > y_break) {
b = y_break - sy; if (dy < sy) { /* Avoid trashing self */
fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
y_break);
fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
height - b, width, y_break);
} else {
fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
height - b, width, y_break);
fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
y_break);
} return;
}
staticvoid fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, int height, int width)
{ struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_display *p = &fb_display[vc->vc_num];
if (!fbcon_is_active(vc, info)) return;
if (!width || !height) return;
/* Split blits that cross physical y_wrap case. * Pathological case involves 4 blits, better to use recursive * code rather than unrolled case * * Recursive invocations don't need to erase the cursor over and * over again, so we use fbcon_bmove_rec()
*/
fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
p->vrows - p->yscroll);
}
/* * ++Geert: Only use ywrap/ypan if the console is in text mode * ++Andrew: Only use ypan on hardware text mode when scrolling the * whole screen (prevents flicker).
*/
switch (dir) { case SM_UP: if (count > vc->vc_rows) /* Maximum realistic size */
count = vc->vc_rows; switch (fb_scrollmode(p)) { case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, t, b - t - count,
count);
__fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
scr_memsetw((unsignedshort *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
vc->vc_video_erase_char,
vc->vc_size_row * count); returntrue;
case SCROLL_WRAP_MOVE: if (b - t - count > 3 * vc->vc_rows >> 2) { if (t > 0)
fbcon_bmove(vc, 0, 0, count, 0, t,
vc->vc_cols);
ywrap_up(vc, count); if (vc->vc_rows - b > 0)
fbcon_bmove(vc, b - count, 0, b, 0,
vc->vc_rows - b,
vc->vc_cols);
} elseif (info->flags & FBINFO_READS_FAST)
fbcon_bmove(vc, t + count, 0, t, 0,
b - t - count, vc->vc_cols); else goto redraw_up;
__fbcon_clear(vc, b - count, 0, count, vc->vc_cols); break;
case SCROLL_PAN_REDRAW: if ((p->yscroll + count <=
2 * (p->vrows - vc->vc_rows))
&& ((!scroll_partial && (b - t == vc->vc_rows))
|| (scroll_partial
&& (b - t - count >
3 * vc->vc_rows >> 2)))) { if (t > 0)
fbcon_redraw_move(vc, p, 0, t, count);
ypan_up_redraw(vc, t, count); if (vc->vc_rows - b > 0)
fbcon_redraw_move(vc, p, b,
vc->vc_rows - b, b);
} else
fbcon_redraw_move(vc, p, t + count, b - t - count, t);
__fbcon_clear(vc, b - count, 0, count, vc->vc_cols); break;
case SCROLL_PAN_MOVE: if ((p->yscroll + count <=
2 * (p->vrows - vc->vc_rows))
&& ((!scroll_partial && (b - t == vc->vc_rows))
|| (scroll_partial
&& (b - t - count >
3 * vc->vc_rows >> 2)))) { if (t > 0)
fbcon_bmove(vc, 0, 0, count, 0, t,
vc->vc_cols);
ypan_up(vc, count); if (vc->vc_rows - b > 0)
fbcon_bmove(vc, b - count, 0, b, 0,
vc->vc_rows - b,
vc->vc_cols);
} elseif (info->flags & FBINFO_READS_FAST)
fbcon_bmove(vc, t + count, 0, t, 0,
b - t - count, vc->vc_cols); else goto redraw_up;
__fbcon_clear(vc, b - count, 0, count, vc->vc_cols); break;
case SCROLL_REDRAW:
redraw_up:
fbcon_redraw(vc, t, b - t - count,
count * vc->vc_cols);
__fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
scr_memsetw((unsignedshort *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
vc->vc_video_erase_char,
vc->vc_size_row * count); returntrue;
} break;
case SM_DOWN: if (count > vc->vc_rows) /* Maximum realistic size */
count = vc->vc_rows; switch (fb_scrollmode(p)) { case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
-count);
__fbcon_clear(vc, t, 0, count, vc->vc_cols);
scr_memsetw((unsignedshort *) (vc->vc_origin +
vc->vc_size_row *
t),
vc->vc_video_erase_char,
vc->vc_size_row * count); returntrue;
case SCROLL_WRAP_MOVE: if (b - t - count > 3 * vc->vc_rows >> 2) { if (vc->vc_rows - b > 0)
fbcon_bmove(vc, b, 0, b - count, 0,
vc->vc_rows - b,
vc->vc_cols);
ywrap_down(vc, count); if (t > 0)
fbcon_bmove(vc, count, 0, 0, 0, t,
vc->vc_cols);
} elseif (info->flags & FBINFO_READS_FAST)
fbcon_bmove(vc, t, 0, t + count, 0,
b - t - count, vc->vc_cols); else goto redraw_down;
__fbcon_clear(vc, t, 0, count, vc->vc_cols); break;
case SCROLL_PAN_MOVE: if ((count - p->yscroll <= p->vrows - vc->vc_rows)
&& ((!scroll_partial && (b - t == vc->vc_rows))
|| (scroll_partial
&& (b - t - count >
3 * vc->vc_rows >> 2)))) { if (vc->vc_rows - b > 0)
fbcon_bmove(vc, b, 0, b - count, 0,
vc->vc_rows - b,
vc->vc_cols);
ypan_down(vc, count); if (t > 0)
fbcon_bmove(vc, count, 0, 0, 0, t,
vc->vc_cols);
} elseif (info->flags & FBINFO_READS_FAST)
fbcon_bmove(vc, t, 0, t + count, 0,
b - t - count, vc->vc_cols); else goto redraw_down;
__fbcon_clear(vc, t, 0, count, vc->vc_cols); break;
case SCROLL_PAN_REDRAW: if ((count - p->yscroll <= p->vrows - vc->vc_rows)
&& ((!scroll_partial && (b - t == vc->vc_rows))
|| (scroll_partial
&& (b - t - count >
3 * vc->vc_rows >> 2)))) { if (vc->vc_rows - b > 0)
fbcon_redraw_move(vc, p, b, vc->vc_rows - b,
b - count);
ypan_down_redraw(vc, t, count); if (t > 0)
fbcon_redraw_move(vc, p, count, t, 0);
} else
fbcon_redraw_move(vc, p, t, b - t - count, t + count);
__fbcon_clear(vc, t, 0, count, vc->vc_cols); break;
case SCROLL_REDRAW:
redraw_down:
fbcon_redraw(vc, b - 1, b - t - count,
-count * vc->vc_cols);
__fbcon_clear(vc, t, 0, count, vc->vc_cols);
scr_memsetw((unsignedshort *) (vc->vc_origin +
vc->vc_size_row *
t),
vc->vc_video_erase_char,
vc->vc_size_row * count); returntrue;
}
} returnfalse;
}
staticvoid updatescrollmode_accel(struct fbcon_display *p, struct fb_info *info, struct vc_data *vc)
{ #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION struct fbcon_ops *ops = info->fbcon_par; int cap = info->flags;
u16 t = 0; int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
info->fix.xpanstep); int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
info->var.xres_virtual); int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
divides(ypan, vc->vc_font.height) && vyres > yres; int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
divides(ywrap, vc->vc_font.height) &&
divides(vc->vc_font.height, vyres) &&
divides(vc->vc_font.height, yres); int reading_fast = cap & FBINFO_READS_FAST; int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
!(cap & FBINFO_HWACCEL_DISABLED); int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
!(cap & FBINFO_HWACCEL_DISABLED);
if (p->userfont && FNTSIZE(vc->vc_font.data)) { int size; int pitch = PITCH(vc->vc_font.width);
/* * If user font, ensure that a possible change to user font * height or width will not allow a font data out-of-bounds access. * NOTE: must use original charcount in calculation as font * charcount can change and cannot be used to determine the * font data allocated size.
*/ if (pitch <= 0) return -EINVAL;
size = CALC_FONTSZ(vc->vc_font.height, pitch, vc->vc_font.charcount); if (size > FNTSIZE(vc->vc_font.data)) return -EINVAL;
}
prev_console = ops->currcon; if (prev_console != -1)
old_info = fbcon_info_from_console(prev_console); /* * FIXME: If we have multiple fbdev's loaded, we need to * update all info->currcon. Perhaps, we can place this * in a centralized structure, but this might break some * drivers. * * info->currcon = vc->vc_num;
*/
fbcon_for_each_registered_fb(i) { if (fbcon_registered_fb[i]->fbcon_par) { struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par;
/* * make sure we don't unnecessarily trip the memcmp() * in fb_set_var()
*/
info->var.activate = var.activate;
var.vmode |= info->var.vmode & ~FB_VMODE_MASK;
fb_set_var(info, &var);
ops->var = info->var;
if (old_info != NULL && (old_info != info ||
info->flags & FBINFO_MISC_ALWAYS_SETPAR)) { if (info->fbops->fb_set_par) {
ret = info->fbops->fb_set_par(info);
/* * User asked to set font; we are guaranteed that charcount does not exceed 512 * but lets not assume that, since charcount of 512 is small for unicode support.
*/
staticint fbcon_set_font(struct vc_data *vc, conststruct console_font *font, unsignedint vpitch, unsignedint flags)
{ struct fb_info *info = fbcon_info_from_console(vc->vc_num); unsigned charcount = font->charcount; int w = font->width; int h = font->height; int size, alloc_size; int i, csum;
u8 *new_data, *data = font->data; int pitch = PITCH(font->width);
/* Is there a reason why fbconsole couldn't handle any charcount >256?
* If not this check should be changed to charcount < 256 */ if (charcount != 256 && charcount != 512) return -EINVAL;
/* font bigger than screen resolution ? */ if (w > FBCON_SWAP(info->var.rotate, info->var.xres, info->var.yres) ||
h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres)) return -EINVAL;
if (font->width > FB_MAX_BLIT_WIDTH || font->height > FB_MAX_BLIT_HEIGHT) return -EINVAL;
/* Make sure drawing engine can handle the font */ if (!test_bit(font->width - 1, info->pixmap.blit_x) ||
!test_bit(font->height - 1, info->pixmap.blit_y)) return -EINVAL;
/* Make sure driver can handle the font length */ if (fbcon_invalid_charcount(info, charcount)) return -EINVAL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Hier finden Sie eine Liste der Produkte des Unternehmens