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/smp.h>
77 #include <linux/init.h>
81 #include <asm/system.h>
82 #include <asm/uaccess.h>
84 #include <asm/amigahw.h>
85 #include <asm/amigaints.h>
86 #endif /* CONFIG_AMIGA */
88 #include <asm/atariints.h>
91 #include <asm/macints.h>
93 #if defined(__mc68000__) || defined(CONFIG_APUS)
94 #include <asm/machdep.h>
95 #include <asm/setup.h>
97 #ifdef CONFIG_FBCON_VGA_PLANES
100 #define INCLUDE_LINUX_LOGO_DATA
101 #include <asm/linux_logo.h>
103 #include <video/fbcon.h>
104 #include <video/fbcon-mac.h> /* for 6x11 font on mac */
105 #include <video/font.h>
108 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
110 # define DPRINTK(fmt, args...)
115 #define LOGO_LINE (LOGO_W/8)
117 struct display fb_display[MAX_NR_CONSOLES];
118 char con2fb_map[MAX_NR_CONSOLES];
119 static int logo_lines;
120 static int logo_shown = -1;
121 /* Software scrollback */
122 int fbcon_softback_size = 32768;
123 static unsigned long softback_buf, softback_curr;
124 static unsigned long softback_in;
125 static unsigned long softback_top, softback_end;
126 static int softback_lines;
128 #define REFCOUNT(fd) (((int *)(fd))[-1])
129 #define FNTSIZE(fd) (((int *)(fd))[-2])
130 #define FNTCHARCNT(fd) (((int *)(fd))[-3])
131 #define FNTSUM(fd) (((int *)(fd))[-4])
132 #define FONT_EXTRA_WORDS 4
134 #define CM_SOFTBACK (8)
136 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * conp->vc_size_row)
138 static void fbcon_free_font(struct display *);
139 static int fbcon_set_origin(struct vc_data *);
142 static int pm_fbcon_request(struct pm_dev *dev, pm_request_t rqst, void *data);
143 static struct pm_dev *pm_fbcon;
144 static int fbcon_sleeping;
148 * Emmanuel: fbcon will now use a hardware cursor if the
149 * low-level driver provides a non-NULL dispsw->cursor pointer,
150 * in which case the hardware should do blinking, etc.
152 * if dispsw->cursor is NULL, use Atari alike software cursor
155 static int cursor_drawn;
157 #define CURSOR_DRAW_DELAY (1)
159 /* # VBL ints between cursor state changes */
160 #define ARM_CURSOR_BLINK_RATE (10)
161 #define AMIGA_CURSOR_BLINK_RATE (20)
162 #define ATARI_CURSOR_BLINK_RATE (42)
163 #define MAC_CURSOR_BLINK_RATE (32)
164 #define DEFAULT_CURSOR_BLINK_RATE (20)
166 static int vbl_cursor_cnt;
167 static int cursor_on;
168 static int cursor_blink_rate;
170 static inline void cursor_undrawn(void)
177 #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
181 * Interface used by the world
184 static const char *fbcon_startup(void);
185 static void fbcon_init(struct vc_data *conp, int init);
186 static void fbcon_deinit(struct vc_data *conp);
187 static int fbcon_changevar(int con);
188 static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
190 static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos);
191 static void fbcon_putcs(struct vc_data *conp, const unsigned short *s, int count,
193 static void fbcon_cursor(struct vc_data *conp, int mode);
194 static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
196 static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
197 int height, int width);
198 static int fbcon_switch(struct vc_data *conp);
199 static int fbcon_blank(struct vc_data *conp, int blank);
200 static int fbcon_font_op(struct vc_data *conp, struct console_font_op *op);
201 static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
202 static int fbcon_scrolldelta(struct vc_data *conp, int lines);
209 static void fbcon_setup(int con, int init, int logo);
210 static __inline__ int real_y(struct display *p, int ypos);
211 static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
212 static __inline__ void updatescrollmode(struct display *p);
213 static __inline__ void ywrap_up(int unit, struct vc_data *conp,
214 struct display *p, int count);
215 static __inline__ void ywrap_down(int unit, struct vc_data *conp,
216 struct display *p, int count);
217 static __inline__ void ypan_up(int unit, struct vc_data *conp,
218 struct display *p, int count);
219 static __inline__ void ypan_down(int unit, struct vc_data *conp,
220 struct display *p, int count);
221 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
222 int height, int width, u_int y_break);
224 static int fbcon_show_logo(void);
228 * On the Macintoy, there may or may not be a working VBL int. We need to probe
230 static int vbl_detected;
232 static void fbcon_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
238 static void cursor_timer_handler(unsigned long dev_addr);
240 static struct timer_list cursor_timer = {
241 function: cursor_timer_handler
243 static int use_timer_cursor;
245 static void cursor_timer_handler(unsigned long dev_addr)
247 fbcon_vbl_handler(0, NULL, NULL);
248 cursor_timer.expires = jiffies+HZ/50;
249 add_timer(&cursor_timer);
254 * PROC_CONSOLE - find the attached tty or visible console
255 * @info: frame buffer info structure
257 * Finds the tty attached to the process or visible console if
258 * the process is not directly attached to a tty (e.g. remote
259 * user) for device @info.
261 * Returns -1 errno on error, or tty/visible console number
266 int PROC_CONSOLE(const struct fb_info *info)
270 if (info->display_fg != NULL)
271 fgc = info->display_fg->vc_num;
278 if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
279 /* XXX Should report error here? */
282 if (MINOR(current->tty->device) < 1)
285 return MINOR(current->tty->device) - 1;
290 * set_all_vcs - set all virtual consoles to match
291 * @fbidx: frame buffer index (e.g. fb0, fb1, ...)
292 * @fb: frame buffer ops structure
293 * @var: frame buffer screen structure to set
294 * @info: frame buffer info structure
296 * Set all virtual consoles to match screen info set in @var
299 * Returns negative errno on error, or zero on success.
303 int set_all_vcs(int fbidx, struct fb_ops *fb, struct fb_var_screeninfo *var,
304 struct fb_info *info)
308 var->activate |= FB_ACTIVATE_TEST;
309 err = fb->fb_set_var(var, PROC_CONSOLE(info), info);
310 var->activate &= ~FB_ACTIVATE_TEST;
313 for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
314 if (fb_display[unit].conp && con2fb_map[unit] == fbidx)
315 fb->fb_set_var(var, unit, info);
321 * set_con2fb_map - map console to frame buffer device
322 * @unit: virtual console number to map
323 * @newidx: frame buffer index to map virtual console to
325 * Maps a virtual console @unit to a frame buffer device
330 void set_con2fb_map(int unit, int newidx)
332 int oldidx = con2fb_map[unit];
333 struct fb_info *oldfb, *newfb;
334 struct vc_data *conp;
336 unsigned short fontwidth, fontheight, fontwidthlog, fontheightlog;
339 if (newidx != con2fb_map[unit]) {
340 oldfb = registered_fb[oldidx];
341 newfb = registered_fb[newidx];
342 if (newfb->fbops->owner)
343 __MOD_INC_USE_COUNT(newfb->fbops->owner);
344 if (newfb->fbops->fb_open && newfb->fbops->fb_open(newfb,0)) {
345 if (newfb->fbops->owner)
346 __MOD_DEC_USE_COUNT(newfb->fbops->owner);
349 if (oldfb->fbops->fb_release)
350 oldfb->fbops->fb_release(oldfb,0);
351 if (oldfb->fbops->owner)
352 __MOD_DEC_USE_COUNT(oldfb->fbops->owner);
353 conp = fb_display[unit].conp;
354 fontdata = fb_display[unit].fontdata;
355 fontwidth = fb_display[unit]._fontwidth;
356 fontheight = fb_display[unit]._fontheight;
357 fontwidthlog = fb_display[unit]._fontwidthlog;
358 fontheightlog = fb_display[unit]._fontheightlog;
359 userfont = fb_display[unit].userfont;
360 con2fb_map[unit] = newidx;
361 fb_display[unit] = *(newfb->disp);
362 fb_display[unit].conp = conp;
363 fb_display[unit].fontdata = fontdata;
364 fb_display[unit]._fontwidth = fontwidth;
365 fb_display[unit]._fontheight = fontheight;
366 fb_display[unit]._fontwidthlog = fontwidthlog;
367 fb_display[unit]._fontheightlog = fontheightlog;
368 fb_display[unit].userfont = userfont;
369 fb_display[unit].fb_info = newfb;
371 conp->vc_display_fg = &newfb->display_fg;
372 if (!newfb->display_fg)
373 newfb->display_fg = conp;
374 if (!newfb->changevar)
375 newfb->changevar = oldfb->changevar;
376 /* tell console var has changed */
377 if (newfb->changevar)
378 newfb->changevar(unit);
383 * Low Level Operations
386 struct display_switch fbcon_dummy;
388 /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
390 static const char *fbcon_startup(void)
392 const char *display_desc = "frame buffer device";
397 * If num_registered_fb is zero, this is a call for the dummy part.
398 * The frame buffer devices weren't initialized yet.
400 if (!num_registered_fb || done)
406 cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE;
407 irqres = request_irq(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0,
408 "console/cursor", fbcon_vbl_handler);
410 #endif /* CONFIG_AMIGA */
413 cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
414 irqres = request_irq(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO,
415 "console/cursor", fbcon_vbl_handler);
417 #endif /* CONFIG_ATARI */
421 * On a Macintoy, the VBL interrupt may or may not be active.
422 * As interrupt based cursor is more reliable and race free, we
423 * probe for VBL interrupts.
428 * Probe for VBL: set temp. handler ...
430 irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_detect, 0,
431 "console/cursor", fbcon_vbl_detect);
435 * ... and spin for 20 ms ...
437 while (!vbl_detected && ++ct<1000)
441 printk("fbcon_startup: No VBL detected, using timer based cursor.\n");
443 free_irq(IRQ_MAC_VBL, fbcon_vbl_detect);
447 * interrupt based cursor ok
449 cursor_blink_rate = MAC_CURSOR_BLINK_RATE;
450 irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_handler, 0,
451 "console/cursor", fbcon_vbl_handler);
454 * VBL not detected: fall through, use timer based cursor
459 #endif /* CONFIG_MAC */
461 #if defined(__arm__) && defined(IRQ_VSYNCPULSE)
462 cursor_blink_rate = ARM_CURSOR_BLINK_RATE;
463 irqres = request_irq(IRQ_VSYNCPULSE, fbcon_vbl_handler, SA_SHIRQ,
464 "console/cursor", fbcon_vbl_handler);
468 use_timer_cursor = 1;
469 cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE;
470 cursor_timer.expires = jiffies+HZ/50;
471 add_timer(&cursor_timer);
475 pm_fbcon = pm_register(PM_SYS_DEV, PM_SYS_VGA, pm_fbcon_request);
482 static void fbcon_init(struct vc_data *conp, int init)
484 int unit = conp->vc_num;
485 struct fb_info *info;
487 /* on which frame buffer will we open this console? */
488 info = registered_fb[(int)con2fb_map[unit]];
490 info->changevar = &fbcon_changevar;
491 fb_display[unit] = *(info->disp); /* copy from default */
492 DPRINTK("mode: %s\n",info->modename);
493 DPRINTK("visual: %d\n",fb_display[unit].visual);
494 DPRINTK("res: %dx%d-%d\n",fb_display[unit].var.xres,
495 fb_display[unit].var.yres,
496 fb_display[unit].var.bits_per_pixel);
497 fb_display[unit].conp = conp;
498 fb_display[unit].fb_info = info;
499 /* clear out the cmap so we don't have dangling pointers */
500 fb_display[unit].cmap.len = 0;
501 fb_display[unit].cmap.red = 0;
502 fb_display[unit].cmap.green = 0;
503 fb_display[unit].cmap.blue = 0;
504 fb_display[unit].cmap.transp = 0;
505 fbcon_setup(unit, init, !init);
506 /* Must be done after fbcon_setup to prevent excess updates */
507 conp->vc_display_fg = &info->display_fg;
508 if (!info->display_fg)
509 info->display_fg = conp;
513 static void fbcon_deinit(struct vc_data *conp)
515 int unit = conp->vc_num;
516 struct display *p = &fb_display[unit];
519 p->dispsw = &fbcon_dummy;
524 static int fbcon_changevar(int con)
526 if (fb_display[con].conp)
527 fbcon_setup(con, 0, 0);
532 static __inline__ void updatescrollmode(struct display *p)
535 if (p->scrollmode & __SCROLL_YFIXED)
537 if (divides(p->ywrapstep, fontheight(p)) &&
538 divides(fontheight(p), p->var.yres_virtual))
540 else if (divides(p->ypanstep, fontheight(p)) &&
541 p->var.yres_virtual >= p->var.yres+fontheight(p))
543 else if (p->scrollmode & __SCROLL_YNOMOVE)
544 m = __SCROLL_YREDRAW;
547 p->scrollmode = (p->scrollmode & ~__SCROLL_YMASK) | m;
550 static void fbcon_font_widths(struct display *p)
554 p->_fontwidthlog = 0;
555 for (i = 2; i <= 6; i++)
556 if (fontwidth(p) == (1 << i))
557 p->_fontwidthlog = i;
558 p->_fontheightlog = 0;
559 for (i = 2; i <= 6; i++)
560 if (fontheight(p) == (1 << i))
561 p->_fontheightlog = i;
564 #define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))
566 static void fbcon_setup(int con, int init, int logo)
568 struct display *p = &fb_display[con];
569 struct vc_data *conp = p->conp;
570 int nr_rows, nr_cols;
571 int old_rows, old_cols;
572 unsigned short *save = NULL, *r, *q;
573 int i, charcnt = 256;
574 struct fbcon_font_desc *font;
576 if (con != fg_console || (p->fb_info->flags & FBINFO_FLAG_MODULE) ||
577 p->type == FB_TYPE_TEXT)
580 p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
582 if (con == fg_console && p->type != FB_TYPE_TEXT) {
583 if (fbcon_softback_size) {
585 softback_buf = (unsigned long)kmalloc(fbcon_softback_size, GFP_KERNEL);
587 fbcon_softback_size = 0;
593 kfree((void *)softback_buf);
599 softback_in = softback_top = softback_curr = softback_buf;
603 for (i = 0; i < MAX_NR_CONSOLES; i++)
604 if (i != con && fb_display[i].fb_info == p->fb_info &&
605 fb_display[i].conp && fb_display[i].fontdata)
609 if (i < MAX_NR_CONSOLES) {
610 struct display *q = &fb_display[i];
612 if (fontwidthvalid(p,fontwidth(q))) {
613 /* If we are not the first console on this
614 fb, copy the font from that console */
615 p->_fontwidth = q->_fontwidth;
616 p->_fontheight = q->_fontheight;
617 p->_fontwidthlog = q->_fontwidthlog;
618 p->_fontheightlog = q->_fontheightlog;
619 p->fontdata = q->fontdata;
620 p->userfont = q->userfont;
622 REFCOUNT(p->fontdata)++;
623 charcnt = FNTCHARCNT(p->fontdata);
625 con_copy_unimap(con, i);
630 if (!p->fb_info->fontname[0] ||
631 !(font = fbcon_find_font(p->fb_info->fontname)))
632 font = fbcon_get_default_font(p->var.xres, p->var.yres);
633 p->_fontwidth = font->width;
634 p->_fontheight = font->height;
635 p->fontdata = font->data;
636 fbcon_font_widths(p);
639 if (!fontwidthvalid(p,fontwidth(p))) {
640 #if defined(CONFIG_FBCON_MAC) && defined(CONFIG_MAC)
642 /* ++Geert: hack to make 6x11 fonts work on mac */
643 p->dispsw = &fbcon_mac;
647 /* ++Geert: changed from panic() to `correct and continue' */
648 printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", fontwidth(p));
649 p->dispsw = &fbcon_dummy;
652 if (p->dispsw->set_font)
653 p->dispsw->set_font(p, fontwidth(p), fontheight(p));
656 old_cols = conp->vc_cols;
657 old_rows = conp->vc_rows;
659 nr_cols = p->var.xres/fontwidth(p);
660 nr_rows = p->var.yres/fontheight(p);
663 /* Need to make room for the logo */
667 logo_lines = (LOGO_H + fontheight(p) - 1) / fontheight(p);
668 q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
669 step = logo_lines * old_cols;
670 for (r = q - logo_lines * old_cols; r < q; r++)
671 if (scr_readw(r) != conp->vc_video_erase_char)
673 if (r != q && nr_rows >= old_rows + logo_lines) {
674 save = kmalloc(logo_lines * nr_cols * 2, GFP_KERNEL);
676 int i = old_cols < nr_cols ? old_cols : nr_cols;
677 scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2);
679 for (cnt = 0; cnt < logo_lines; cnt++, r += i)
680 scr_memcpyw(save + cnt * nr_cols, r, 2 * i);
685 /* We can scroll screen down */
686 r = q - step - old_cols;
687 for (cnt = old_rows - logo_lines; cnt > 0; cnt--) {
688 scr_memcpyw(r + step, r, conp->vc_size_row);
692 conp->vc_y += logo_lines;
693 conp->vc_pos += logo_lines * conp->vc_size_row;
696 scr_memsetw((unsigned short *)conp->vc_origin,
697 conp->vc_video_erase_char,
698 conp->vc_size_row * logo_lines);
702 * ++guenther: console.c:vc_allocate() relies on initializing
703 * vc_{cols,rows}, but we must not set those if we are only
704 * resizing the console.
707 conp->vc_cols = nr_cols;
708 conp->vc_rows = nr_rows;
710 p->vrows = p->var.yres_virtual/fontheight(p);
711 if ((p->var.yres % fontheight(p)) &&
712 (p->var.yres_virtual % fontheight(p) < p->var.yres % fontheight(p)))
714 conp->vc_can_do_color = p->var.bits_per_pixel != 1;
715 conp->vc_complement_mask = conp->vc_can_do_color ? 0x7700 : 0x0800;
716 if (charcnt == 256) {
717 conp->vc_hi_font_mask = 0;
722 conp->vc_hi_font_mask = 0x100;
723 if (conp->vc_can_do_color)
724 conp->vc_complement_mask <<= 1;
730 if (p->dispsw == &fbcon_dummy)
731 printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
732 "supported\n", p->type, p->type_aux, p->var.bits_per_pixel);
735 p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
739 if (conp->vc_cols != nr_cols || conp->vc_rows != nr_rows)
740 vc_resize_con(nr_rows, nr_cols, con);
741 else if (CON_IS_VISIBLE(conp) &&
742 vt_cons[conp->vc_num]->vc_mode == KD_TEXT) {
743 if (p->dispsw->clear_margins)
744 p->dispsw->clear_margins(conp, p, 0);
748 q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
749 scr_memcpyw(q, save, logo_lines * nr_cols * 2);
750 conp->vc_y += logo_lines;
751 conp->vc_pos += logo_lines * conp->vc_size_row;
758 conp->vc_top = logo_lines;
761 if (con == fg_console && softback_buf) {
762 int l = fbcon_softback_size / conp->vc_size_row;
764 softback_end = softback_buf + l * conp->vc_size_row;
766 /* Smaller scrollback makes no sense, and 0 would screw
767 the operation totally */
774 /* ====================================================================== */
776 /* fbcon_XXX routines - interface used by the world
778 * This system is now divided into two levels because of complications
779 * caused by hardware scrolling. Top level functions:
781 * fbcon_bmove(), fbcon_clear(), fbcon_putc()
783 * handles y values in range [0, scr_height-1] that correspond to real
784 * screen positions. y_wrap shift means that first line of bitmap may be
785 * anywhere on this display. These functions convert lineoffsets to
786 * bitmap offsets and deal with the wrap-around case by splitting blits.
788 * fbcon_bmove_physical_8() -- These functions fast implementations
789 * fbcon_clear_physical_8() -- of original fbcon_XXX fns.
790 * fbcon_putc_physical_8() -- (fontwidth != 8) may be added later
794 * At the moment fbcon_putc() cannot blit across vertical wrap boundary
795 * Implies should only really hardware scroll in rows. Only reason for
796 * restriction is simplicity & efficiency at the moment.
799 static __inline__ int real_y(struct display *p, int ypos)
804 return ypos < rows ? ypos : ypos-rows;
808 static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
811 int unit = conp->vc_num;
812 struct display *p = &fb_display[unit];
814 int redraw_cursor = 0;
816 if (!p->can_soft_blank && console_blanked)
819 if (!height || !width)
822 if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
823 (sx <= p->cursor_x) && (p->cursor_x < sx+width)) {
828 /* Split blits that cross physical y_wrap boundary */
830 y_break = p->vrows-p->yscroll;
831 if (sy < y_break && sy+height-1 >= y_break) {
832 u_int b = y_break-sy;
833 p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width);
834 p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width);
836 p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width);
839 vbl_cursor_cnt = CURSOR_DRAW_DELAY;
843 static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos)
845 int unit = conp->vc_num;
846 struct display *p = &fb_display[unit];
847 int redraw_cursor = 0;
849 if (!p->can_soft_blank && console_blanked)
852 if (vt_cons[unit]->vc_mode != KD_TEXT)
855 if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
860 p->dispsw->putc(conp, p, c, real_y(p, ypos), xpos);
863 vbl_cursor_cnt = CURSOR_DRAW_DELAY;
867 static void fbcon_putcs(struct vc_data *conp, const unsigned short *s, int count,
870 int unit = conp->vc_num;
871 struct display *p = &fb_display[unit];
872 int redraw_cursor = 0;
874 if (!p->can_soft_blank && console_blanked)
877 if (vt_cons[unit]->vc_mode != KD_TEXT)
880 if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
881 (p->cursor_x < (xpos + count))) {
885 p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos);
887 vbl_cursor_cnt = CURSOR_DRAW_DELAY;
891 static void fbcon_cursor(struct vc_data *conp, int mode)
893 int unit = conp->vc_num;
894 struct display *p = &fb_display[unit];
897 if (mode & CM_SOFTBACK) {
898 mode &= ~CM_SOFTBACK;
899 if (softback_lines) {
900 if (y + softback_lines >= conp->vc_rows)
905 } else if (softback_lines)
906 fbcon_set_origin(conp);
908 /* do we have a hardware cursor ? */
909 if (p->dispsw->cursor) {
910 p->cursor_x = conp->vc_x;
912 p->dispsw->cursor(p, mode, p->cursor_x, real_y(p, p->cursor_y));
916 /* Avoid flickering if there's no real change. */
917 if (p->cursor_x == conp->vc_x && p->cursor_y == y &&
918 (mode == CM_ERASE) == !cursor_on)
923 p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
925 p->cursor_x = conp->vc_x;
935 p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
936 vbl_cursor_cnt = CURSOR_DRAW_DELAY;
943 static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp)
950 if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
951 p = &fb_display[fg_console];
953 p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
955 vbl_cursor_cnt = cursor_blink_rate;
959 static int scrollback_phys_max = 0;
960 static int scrollback_max = 0;
961 static int scrollback_current = 0;
963 static __inline__ void ywrap_up(int unit, struct vc_data *conp,
964 struct display *p, int count)
967 if (p->yscroll >= p->vrows) /* Deal with wrap */
968 p->yscroll -= p->vrows;
970 p->var.yoffset = p->yscroll*fontheight(p);
971 p->var.vmode |= FB_VMODE_YWRAP;
972 p->fb_info->updatevar(unit, p->fb_info);
973 scrollback_max += count;
974 if (scrollback_max > scrollback_phys_max)
975 scrollback_max = scrollback_phys_max;
976 scrollback_current = 0;
980 static __inline__ void ywrap_down(int unit, struct vc_data *conp,
981 struct display *p, int count)
984 if (p->yscroll < 0) /* Deal with wrap */
985 p->yscroll += p->vrows;
987 p->var.yoffset = p->yscroll*fontheight(p);
988 p->var.vmode |= FB_VMODE_YWRAP;
989 p->fb_info->updatevar(unit, p->fb_info);
990 scrollback_max -= count;
991 if (scrollback_max < 0)
993 scrollback_current = 0;
997 static __inline__ void ypan_up(int unit, struct vc_data *conp,
998 struct display *p, int count)
1000 p->yscroll += count;
1001 if (p->yscroll > p->vrows-conp->vc_rows) {
1002 p->dispsw->bmove(p, p->vrows-conp->vc_rows, 0, 0, 0,
1003 conp->vc_rows, conp->vc_cols);
1004 p->yscroll -= p->vrows-conp->vc_rows;
1007 p->var.yoffset = p->yscroll*fontheight(p);
1008 p->var.vmode &= ~FB_VMODE_YWRAP;
1009 p->fb_info->updatevar(unit, p->fb_info);
1010 if (p->dispsw->clear_margins)
1011 p->dispsw->clear_margins(conp, p, 1);
1012 scrollback_max += count;
1013 if (scrollback_max > scrollback_phys_max)
1014 scrollback_max = scrollback_phys_max;
1015 scrollback_current = 0;
1019 static __inline__ void ypan_down(int unit, struct vc_data *conp,
1020 struct display *p, int count)
1022 p->yscroll -= count;
1023 if (p->yscroll < 0) {
1024 p->dispsw->bmove(p, 0, 0, p->vrows-conp->vc_rows, 0,
1025 conp->vc_rows, conp->vc_cols);
1026 p->yscroll += p->vrows-conp->vc_rows;
1029 p->var.yoffset = p->yscroll*fontheight(p);
1030 p->var.vmode &= ~FB_VMODE_YWRAP;
1031 p->fb_info->updatevar(unit, p->fb_info);
1032 if (p->dispsw->clear_margins)
1033 p->dispsw->clear_margins(conp, p, 1);
1034 scrollback_max -= count;
1035 if (scrollback_max < 0)
1037 scrollback_current = 0;
1040 static void fbcon_redraw_softback(struct vc_data *conp, struct display *p, long delta)
1042 unsigned short *d, *s;
1045 int count = conp->vc_rows;
1047 d = (u16 *)softback_curr;
1048 if (d == (u16 *)softback_in)
1049 d = (u16 *)conp->vc_origin;
1050 n = softback_curr + delta * conp->vc_size_row;
1051 softback_lines -= delta;
1053 if (softback_curr < softback_top && n < softback_buf) {
1054 n += softback_end - softback_buf;
1055 if (n < softback_top) {
1056 softback_lines -= (softback_top - n) / conp->vc_size_row;
1059 } else if (softback_curr >= softback_top && n < softback_top) {
1060 softback_lines -= (softback_top - n) / conp->vc_size_row;
1064 if (softback_curr > softback_in && n >= softback_end) {
1065 n += softback_buf - softback_end;
1066 if (n > softback_in) {
1070 } else if (softback_curr <= softback_in && n > softback_in) {
1075 if (n == softback_curr)
1078 s = (u16 *)softback_curr;
1079 if (s == (u16 *)softback_in)
1080 s = (u16 *)conp->vc_origin;
1082 unsigned short *start;
1086 unsigned short attr = 1;
1089 le = advance_row(s, 1);
1092 if (attr != (c & 0xff00)) {
1095 p->dispsw->putcs(conp, p, start, s - start,
1096 real_y(p, line), x);
1101 if (c == scr_readw(d)) {
1103 p->dispsw->putcs(conp, p, start, s - start,
1104 real_y(p, line), x);
1116 p->dispsw->putcs(conp, p, start, s - start, real_y(p, line), x);
1118 if (d == (u16 *)softback_end)
1119 d = (u16 *)softback_buf;
1120 if (d == (u16 *)softback_in)
1121 d = (u16 *)conp->vc_origin;
1122 if (s == (u16 *)softback_end)
1123 s = (u16 *)softback_buf;
1124 if (s == (u16 *)softback_in)
1125 s = (u16 *)conp->vc_origin;
1129 static void fbcon_redraw(struct vc_data *conp, struct display *p,
1130 int line, int count, int offset)
1132 unsigned short *d = (unsigned short *)
1133 (conp->vc_origin + conp->vc_size_row * line);
1134 unsigned short *s = d + offset;
1137 unsigned short *start = s;
1138 unsigned short *le = advance_row(s, 1);
1141 unsigned short attr = 1;
1145 if (attr != (c & 0xff00)) {
1148 p->dispsw->putcs(conp, p, start, s - start,
1149 real_y(p, line), x);
1154 if (c == scr_readw(d)) {
1156 p->dispsw->putcs(conp, p, start, s - start,
1157 real_y(p, line), x);
1166 console_conditional_schedule();
1171 p->dispsw->putcs(conp, p, start, s - start, real_y(p, line), x);
1172 console_conditional_schedule();
1177 /* NOTE: We subtract two lines from these pointers */
1178 s -= conp->vc_size_row;
1179 d -= conp->vc_size_row;
1185 * fbcon_redraw_clear - clear area of the screen
1186 * @conp: stucture pointing to current active virtual console
1187 * @p: display structure
1188 * @sy: starting Y coordinate
1189 * @sx: starting X coordinate
1190 * @height: height of area to clear
1191 * @width: width of area to clear
1193 * Clears a specified area of the screen. All dimensions are in
1198 void fbcon_redraw_clear(struct vc_data *conp, struct display *p, int sy, int sx,
1199 int height, int width)
1202 for (y=0; y<height; y++)
1203 for (x=0; x<width; x++)
1204 fbcon_putc(conp, ' ', sy+y, sx+x);
1209 * fbcon_redraw_bmove - copy area of screen to another area
1210 * @p: display structure
1211 * @sy: origin Y coordinate
1212 * @sx: origin X coordinate
1213 * @dy: destination Y coordinate
1214 * @dx: destination X coordinate
1215 * @h: height of area to copy
1216 * @w: width of area to copy
1218 * Copies an area of the screen to another area of the same screen.
1219 * All dimensions are in pixels.
1221 * Note that this function cannot be used together with ypan or
1226 void fbcon_redraw_bmove(struct display *p, int sy, int sx, int dy, int dx, int h, int w)
1229 panic("fbcon_redraw_bmove width sy != dy");
1230 /* h will be always 1, but it does not matter if we are more generic */
1233 struct vc_data *conp = p->conp;
1234 unsigned short *d = (unsigned short *)
1235 (conp->vc_origin + conp->vc_size_row * dy + dx * 2);
1236 unsigned short *s = d + (dx - sx);
1237 unsigned short *start = d;
1238 unsigned short *ls = d;
1239 unsigned short *le = d + w;
1242 unsigned short attr = 1;
1246 if (attr != (c & 0xff00)) {
1249 p->dispsw->putcs(conp, p, start, d - start, dy, x);
1254 if (s >= ls && s < le && c == scr_readw(s)) {
1256 p->dispsw->putcs(conp, p, start, d - start, dy, x);
1268 p->dispsw->putcs(conp, p, start, d - start, dy, x);
1274 static inline void fbcon_softback_note(struct vc_data *conp, int t, int count)
1278 if (conp->vc_num != fg_console)
1280 p = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row);
1283 scr_memcpyw((u16 *)softback_in, p, conp->vc_size_row);
1285 p = advance_row(p, 1);
1286 softback_in += conp->vc_size_row;
1287 if (softback_in == softback_end)
1288 softback_in = softback_buf;
1289 if (softback_in == softback_top) {
1290 softback_top += conp->vc_size_row;
1291 if (softback_top == softback_end)
1292 softback_top = softback_buf;
1295 softback_curr = softback_in;
1298 static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
1301 int unit = conp->vc_num;
1302 struct display *p = &fb_display[unit];
1303 int scroll_partial = !(p->scrollmode & __SCROLL_YNOPARTIAL);
1305 if (!p->can_soft_blank && console_blanked)
1308 if (!count || vt_cons[unit]->vc_mode != KD_TEXT)
1311 fbcon_cursor(conp, CM_ERASE);
1314 * ++Geert: Only use ywrap/ypan if the console is in text mode
1315 * ++Andrew: Only use ypan on hardware text mode when scrolling the
1316 * whole screen (prevents flicker).
1321 if (count > conp->vc_rows) /* Maximum realistic size */
1322 count = conp->vc_rows;
1324 fbcon_softback_note(conp, t, count);
1325 if (logo_shown >= 0) goto redraw_up;
1326 switch (p->scrollmode & __SCROLL_YMASK) {
1327 case __SCROLL_YMOVE:
1328 p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count,
1330 p->dispsw->clear(conp, p, b-count, 0, count,
1334 case __SCROLL_YWRAP:
1335 if (b-t-count > 3*conp->vc_rows>>2) {
1337 fbcon_bmove(conp, 0, 0, count, 0, t,
1339 ywrap_up(unit, conp, p, count);
1340 if (conp->vc_rows-b > 0)
1341 fbcon_bmove(conp, b-count, 0, b, 0,
1342 conp->vc_rows-b, conp->vc_cols);
1343 } else if (p->scrollmode & __SCROLL_YPANREDRAW)
1346 fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
1348 fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
1352 if (( p->yscroll + count <= 2 * (p->vrows - conp->vc_rows)) &&
1353 (( !scroll_partial && (b-t == conp->vc_rows)) ||
1354 ( scroll_partial && (b-t-count > 3*conp->vc_rows>>2)))) {
1356 fbcon_bmove(conp, 0, 0, count, 0, t,
1358 ypan_up(unit, conp, p, count);
1359 if (conp->vc_rows-b > 0)
1360 fbcon_bmove(conp, b-count, 0, b, 0,
1361 conp->vc_rows-b, conp->vc_cols);
1362 } else if (p->scrollmode & __SCROLL_YPANREDRAW)
1365 fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
1367 fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
1370 case __SCROLL_YREDRAW:
1372 fbcon_redraw(conp, p, t, b-t-count, count*conp->vc_cols);
1373 p->dispsw->clear(conp, p, real_y(p, b-count), 0,
1374 count, conp->vc_cols);
1375 scr_memsetw((unsigned short *)(conp->vc_origin +
1376 conp->vc_size_row * (b-count)),
1377 conp->vc_video_erase_char,
1378 conp->vc_size_row * count);
1384 if (count > conp->vc_rows) /* Maximum realistic size */
1385 count = conp->vc_rows;
1386 switch (p->scrollmode & __SCROLL_YMASK) {
1387 case __SCROLL_YMOVE:
1388 p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count,
1390 p->dispsw->clear(conp, p, t, 0,
1391 count, conp->vc_cols);
1394 case __SCROLL_YWRAP:
1395 if (b-t-count > 3*conp->vc_rows>>2) {
1396 if (conp->vc_rows-b > 0)
1397 fbcon_bmove(conp, b, 0, b-count, 0,
1398 conp->vc_rows-b, conp->vc_cols);
1399 ywrap_down(unit, conp, p, count);
1401 fbcon_bmove(conp, count, 0, 0, 0, t,
1403 } else if (p->scrollmode & __SCROLL_YPANREDRAW)
1406 fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
1408 fbcon_clear(conp, t, 0, count, conp->vc_cols);
1412 if (( count-p->yscroll <= p->vrows-conp->vc_rows) &&
1413 (( !scroll_partial && (b-t == conp->vc_rows)) ||
1414 ( scroll_partial && (b-t-count > 3*conp->vc_rows>>2)))) {
1415 if (conp->vc_rows-b > 0)
1416 fbcon_bmove(conp, b, 0, b-count, 0,
1417 conp->vc_rows-b, conp->vc_cols);
1418 ypan_down(unit, conp, p, count);
1420 fbcon_bmove(conp, count, 0, 0, 0, t,
1422 } else if (p->scrollmode & __SCROLL_YPANREDRAW)
1425 fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
1427 fbcon_clear(conp, t, 0, count, conp->vc_cols);
1430 case __SCROLL_YREDRAW:
1432 fbcon_redraw(conp, p, b - 1, b-t-count, -count*conp->vc_cols);
1433 p->dispsw->clear(conp, p, real_y(p, t), 0,
1434 count, conp->vc_cols);
1435 scr_memsetw((unsigned short *)(conp->vc_origin +
1436 conp->vc_size_row * t),
1437 conp->vc_video_erase_char,
1438 conp->vc_size_row * count);
1446 static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
1447 int height, int width)
1449 int unit = conp->vc_num;
1450 struct display *p = &fb_display[unit];
1452 if (!p->can_soft_blank && console_blanked)
1455 if (!width || !height)
1458 if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
1459 (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
1460 ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
1461 (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
1462 fbcon_cursor(conp, CM_ERASE|CM_SOFTBACK);
1464 /* Split blits that cross physical y_wrap case.
1465 * Pathological case involves 4 blits, better to use recursive
1466 * code rather than unrolled case
1468 * Recursive invocations don't need to erase the cursor over and
1469 * over again, so we use fbcon_bmove_rec()
1471 fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
1474 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
1475 int height, int width, u_int y_break)
1479 if (sy < y_break && sy+height > y_break) {
1481 if (dy < sy) { /* Avoid trashing self */
1482 fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
1483 fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
1485 fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
1486 fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
1491 if (dy < y_break && dy+height > y_break) {
1493 if (dy < sy) { /* Avoid trashing self */
1494 fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
1495 fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
1497 fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
1498 fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
1502 p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
1506 static int fbcon_switch(struct vc_data *conp)
1508 int unit = conp->vc_num;
1509 struct display *p = &fb_display[unit];
1510 struct fb_info *info = p->fb_info;
1513 int l = fbcon_softback_size / conp->vc_size_row;
1515 fbcon_set_origin(conp);
1516 softback_top = softback_curr = softback_in = softback_buf;
1520 softback_end = softback_buf + l * conp->vc_size_row;
1522 /* Smaller scrollback makes no sense, and 0 would screw
1523 the operation totally */
1527 if (logo_shown >= 0) {
1528 struct vc_data *conp2 = vc_cons[logo_shown].d;
1530 if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows)
1534 p->var.yoffset = p->yscroll = 0;
1535 switch (p->scrollmode & __SCROLL_YMASK) {
1536 case __SCROLL_YWRAP:
1537 scrollback_phys_max = p->vrows-conp->vc_rows;
1540 scrollback_phys_max = p->vrows-2*conp->vc_rows;
1541 if (scrollback_phys_max < 0)
1542 scrollback_phys_max = 0;
1545 scrollback_phys_max = 0;
1549 scrollback_current = 0;
1551 if (info && info->switch_con)
1552 (*info->switch_con)(unit, info);
1553 if (p->dispsw->clear_margins && vt_cons[unit]->vc_mode == KD_TEXT)
1554 p->dispsw->clear_margins(conp, p, 0);
1555 if (logo_shown == -2) {
1556 logo_shown = fg_console;
1557 fbcon_show_logo(); /* This is protected above by initmem_freed */
1558 update_region(fg_console,
1559 conp->vc_origin + conp->vc_size_row * conp->vc_top,
1560 conp->vc_size_row * (conp->vc_bottom - conp->vc_top) / 2);
1567 static int fbcon_blank(struct vc_data *conp, int blank)
1569 struct display *p = &fb_display[conp->vc_num];
1570 struct fb_info *info = p->fb_info;
1572 if (blank < 0) /* Entering graphics mode */
1575 fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
1577 if (!p->can_soft_blank) {
1579 if (p->visual == FB_VISUAL_MONO01) {
1581 fb_memset255(p->screen_base,
1582 p->var.xres_virtual*p->var.yres_virtual*
1583 p->var.bits_per_pixel>>3);
1585 unsigned short oldc;
1589 oldc = conp->vc_video_erase_char;
1590 conp->vc_video_erase_char &= p->charmask;
1591 height = conp->vc_rows;
1592 y_break = p->vrows-p->yscroll;
1593 if (height > y_break) {
1594 p->dispsw->clear(conp, p, real_y(p, 0), 0, y_break, conp->vc_cols);
1595 p->dispsw->clear(conp, p, real_y(p, y_break), 0, height-y_break, conp->vc_cols);
1597 p->dispsw->clear(conp, p, real_y(p, 0), 0, height, conp->vc_cols);
1598 conp->vc_video_erase_char = oldc;
1602 /* Tell console.c that it has to restore the screen itself */
1606 (*info->blank)(blank, info);
1610 static void fbcon_free_font(struct display *p)
1612 if (p->userfont && p->fontdata &&
1613 (--REFCOUNT(p->fontdata) == 0))
1614 kfree(p->fontdata - FONT_EXTRA_WORDS*sizeof(int));
1619 static inline int fbcon_get_font(int unit, struct console_font_op *op)
1621 struct display *p = &fb_display[unit];
1622 u8 *data = op->data;
1623 u8 *fontdata = p->fontdata;
1626 #ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
1627 if (fontwidth(p) != 8) return -EINVAL;
1629 op->width = fontwidth(p);
1630 op->height = fontheight(p);
1631 op->charcount = (p->charmask == 0x1ff) ? 512 : 256;
1632 if (!op->data) return 0;
1634 if (op->width <= 8) {
1636 for (i = 0; i < op->charcount; i++) {
1637 memcpy(data, fontdata, j);
1638 memset(data+j, 0, 32-j);
1643 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
1644 else if (op->width <= 16) {
1645 j = fontheight(p) * 2;
1646 for (i = 0; i < op->charcount; i++) {
1647 memcpy(data, fontdata, j);
1648 memset(data+j, 0, 64-j);
1652 } else if (op->width <= 24) {
1653 for (i = 0; i < op->charcount; i++) {
1654 for (j = 0; j < fontheight(p); j++) {
1655 *data++ = fontdata[0];
1656 *data++ = fontdata[1];
1657 *data++ = fontdata[2];
1658 fontdata += sizeof(u32);
1660 memset(data, 0, 3*(32-j));
1661 data += 3 * (32 - j);
1664 j = fontheight(p) * 4;
1665 for (i = 0; i < op->charcount; i++) {
1666 memcpy(data, fontdata, j);
1667 memset(data+j, 0, 128-j);
1676 static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont)
1678 struct display *p = &fb_display[unit];
1683 char *old_data = NULL;
1685 if (!fontwidthvalid(p,w)) {
1686 if (userfont && op->op != KD_FONT_OP_COPY)
1687 kfree(data - FONT_EXTRA_WORDS*sizeof(int));
1691 if (CON_IS_VISIBLE(p->conp) && softback_lines)
1692 fbcon_set_origin(p->conp);
1694 resize = (w != fontwidth(p)) || (h != fontheight(p));
1696 old_data = p->fontdata;
1698 cnt = FNTCHARCNT(data);
1702 if ((p->userfont = userfont))
1706 if (p->conp->vc_hi_font_mask && cnt == 256) {
1707 p->conp->vc_hi_font_mask = 0;
1708 if (p->conp->vc_can_do_color)
1709 p->conp->vc_complement_mask >>= 1;
1714 /* ++Edmund: reorder the attribute bits */
1715 if (p->conp->vc_can_do_color) {
1716 struct vc_data *conp = p->conp;
1717 unsigned short *cp = (unsigned short *) conp->vc_origin;
1718 int count = conp->vc_screenbuf_size/2;
1720 for (; count > 0; count--, cp++) {
1722 scr_writew(((c & 0xfe00) >> 1) | (c & 0xff), cp);
1724 c = conp->vc_video_erase_char;
1725 conp->vc_video_erase_char = ((c & 0xfe00) >> 1) | (c & 0xff);
1726 conp->vc_attr >>= 1;
1729 } else if (!p->conp->vc_hi_font_mask && cnt == 512) {
1730 p->conp->vc_hi_font_mask = 0x100;
1731 if (p->conp->vc_can_do_color)
1732 p->conp->vc_complement_mask <<= 1;
1735 p->charmask = 0x1ff;
1737 /* ++Edmund: reorder the attribute bits */
1739 struct vc_data *conp = p->conp;
1740 unsigned short *cp = (unsigned short *) conp->vc_origin;
1741 int count = conp->vc_screenbuf_size/2;
1743 for (; count > 0; count--, cp++) {
1744 unsigned short newc;
1746 if (conp->vc_can_do_color)
1747 newc = ((c & 0xff00) << 1) | (c & 0xff);
1750 scr_writew(newc, cp);
1752 c = conp->vc_video_erase_char;
1753 if (conp->vc_can_do_color) {
1754 conp->vc_video_erase_char = ((c & 0xff00) << 1) | (c & 0xff);
1755 conp->vc_attr <<= 1;
1757 conp->vc_video_erase_char = c & ~0x100;
1761 fbcon_font_widths(p);
1764 struct vc_data *conp = p->conp;
1765 /* reset wrap/pan */
1766 p->var.xoffset = p->var.yoffset = p->yscroll = 0;
1767 p->vrows = p->var.yres_virtual/h;
1768 if ((p->var.yres % h) && (p->var.yres_virtual % h < p->var.yres % h))
1770 updatescrollmode(p);
1771 vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
1772 if (CON_IS_VISIBLE(conp) && softback_buf) {
1773 int l = fbcon_softback_size / conp->vc_size_row;
1775 softback_end = softback_buf + l * conp->vc_size_row;
1777 /* Smaller scrollback makes no sense, and 0 would screw
1778 the operation totally */
1782 } else if (CON_IS_VISIBLE(p->conp) && vt_cons[unit]->vc_mode == KD_TEXT) {
1783 if (p->dispsw->clear_margins)
1784 p->dispsw->clear_margins(p->conp, p, 0);
1785 update_screen(unit);
1788 if (old_data && (--REFCOUNT(old_data) == 0))
1789 kfree(old_data - FONT_EXTRA_WORDS*sizeof(int));
1794 static inline int fbcon_copy_font(int unit, struct console_font_op *op)
1796 struct display *od, *p = &fb_display[unit];
1799 if (h < 0 || !vc_cons_allocated( h ))
1802 return 0; /* nothing to do */
1803 od = &fb_display[h];
1804 if (od->fontdata == p->fontdata)
1805 return 0; /* already the same font... */
1806 op->width = fontwidth(od);
1807 op->height = fontheight(od);
1808 return fbcon_do_set_font(unit, op, od->fontdata, od->userfont);
1811 static inline int fbcon_set_font(int unit, struct console_font_op *op)
1817 u8 *new_data, *data = op->data, *p;
1819 #ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
1823 if ((w <= 0) || (w > 32) || (op->charcount != 256 && op->charcount != 512))
1832 size *= op->charcount;
1834 if (!(new_data = kmalloc(FONT_EXTRA_WORDS*sizeof(int)+size, GFP_USER)))
1836 new_data += FONT_EXTRA_WORDS*sizeof(int);
1837 FNTSIZE(new_data) = size;
1838 FNTCHARCNT(new_data) = op->charcount;
1839 REFCOUNT(new_data) = 0; /* usage counter */
1842 for (i = 0; i < op->charcount; i++) {
1848 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
1851 for (i = 0; i < op->charcount; i++) {
1856 } else if (w <= 24) {
1857 for (i = 0; i < op->charcount; i++) {
1859 for (j = 0; j < h; j++) {
1869 for (i = 0; i < op->charcount; i++) {
1876 /* we can do it in u32 chunks because of charcount is 256 or 512, so
1877 font length must be multiple of 256, at least. And 256 is multiple
1880 while (p > new_data) k += *--(u32 *)p;
1881 FNTSUM(new_data) = k;
1882 /* Check if the same font is on some other console already */
1883 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1884 if (fb_display[i].userfont &&
1885 fb_display[i].fontdata &&
1886 FNTSUM(fb_display[i].fontdata) == k &&
1887 FNTSIZE(fb_display[i].fontdata) == size &&
1888 fontwidth(&fb_display[i]) == w &&
1889 !memcmp(fb_display[i].fontdata, new_data, size)) {
1890 kfree(new_data - FONT_EXTRA_WORDS*sizeof(int));
1891 new_data = fb_display[i].fontdata;
1895 return fbcon_do_set_font(unit, op, new_data, 1);
1898 static inline int fbcon_set_def_font(int unit, struct console_font_op *op)
1900 char name[MAX_FONT_NAME];
1901 struct fbcon_font_desc *f;
1902 struct display *p = &fb_display[unit];
1905 f = fbcon_get_default_font(p->var.xres, p->var.yres);
1906 else if (strncpy_from_user(name, op->data, MAX_FONT_NAME-1) < 0)
1909 name[MAX_FONT_NAME-1] = 0;
1910 if (!(f = fbcon_find_font(name)))
1913 op->width = f->width;
1914 op->height = f->height;
1915 return fbcon_do_set_font(unit, op, f->data, 0);
1918 static int fbcon_font_op(struct vc_data *conp, struct console_font_op *op)
1920 int unit = conp->vc_num;
1923 case KD_FONT_OP_SET:
1924 return fbcon_set_font(unit, op);
1925 case KD_FONT_OP_GET:
1926 return fbcon_get_font(unit, op);
1927 case KD_FONT_OP_SET_DEFAULT:
1928 return fbcon_set_def_font(unit, op);
1929 case KD_FONT_OP_COPY:
1930 return fbcon_copy_font(unit, op);
1936 static u16 palette_red[16];
1937 static u16 palette_green[16];
1938 static u16 palette_blue[16];
1940 static struct fb_cmap palette_cmap = {
1941 0, 16, palette_red, palette_green, palette_blue, NULL
1944 static int fbcon_set_palette(struct vc_data *conp, unsigned char *table)
1946 int unit = conp->vc_num;
1947 struct display *p = &fb_display[unit];
1951 if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked))
1953 for (i = j = 0; i < 16; i++) {
1955 val = conp->vc_palette[j++];
1956 palette_red[k] = (val<<8)|val;
1957 val = conp->vc_palette[j++];
1958 palette_green[k] = (val<<8)|val;
1959 val = conp->vc_palette[j++];
1960 palette_blue[k] = (val<<8)|val;
1962 if (p->var.bits_per_pixel <= 4)
1963 palette_cmap.len = 1<<p->var.bits_per_pixel;
1965 palette_cmap.len = 16;
1966 palette_cmap.start = 0;
1967 return p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, unit, p->fb_info);
1970 static u16 *fbcon_screen_pos(struct vc_data *conp, int offset)
1975 if (conp->vc_num != fg_console || !softback_lines)
1976 return (u16 *)(conp->vc_origin + offset);
1977 line = offset / conp->vc_size_row;
1978 if (line >= softback_lines)
1979 return (u16 *)(conp->vc_origin + offset - softback_lines * conp->vc_size_row);
1980 p = softback_curr + offset;
1981 if (p >= softback_end)
1982 p += softback_buf - softback_end;
1986 static unsigned long fbcon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py)
1990 if (pos >= conp->vc_origin && pos < conp->vc_scr_end) {
1991 unsigned long offset = (pos - conp->vc_origin) / 2;
1993 x = offset % conp->vc_cols;
1994 y = offset / conp->vc_cols;
1995 if (conp->vc_num == fg_console)
1996 y += softback_lines;
1997 ret = pos + (conp->vc_cols - x) * 2;
1998 } else if (conp->vc_num == fg_console && softback_lines) {
1999 unsigned long offset = pos - softback_curr;
2001 if (pos < softback_curr)
2002 offset += softback_end - softback_buf;
2004 x = offset % conp->vc_cols;
2005 y = offset / conp->vc_cols;
2006 ret = pos + (conp->vc_cols - x) * 2;
2007 if (ret == softback_end)
2009 if (ret == softback_in)
2010 ret = conp->vc_origin;
2012 /* Should not happen */
2014 ret = conp->vc_origin;
2021 /* As we might be inside of softback, we may work with non-contiguous buffer,
2022 that's why we have to use a separate routine. */
2023 static void fbcon_invert_region(struct vc_data *conp, u16 *p, int cnt)
2026 u16 a = scr_readw(p);
2027 if (!conp->vc_can_do_color)
2029 else if (conp->vc_hi_font_mask == 0x100)
2030 a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
2032 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
2034 if (p == (u16 *)softback_end)
2035 p = (u16 *)softback_buf;
2036 if (p == (u16 *)softback_in)
2037 p = (u16 *)conp->vc_origin;
2041 static int fbcon_scrolldelta(struct vc_data *conp, int lines)
2043 int unit, offset, limit, scrollback_old;
2047 p = &fb_display[unit];
2049 if (conp->vc_num != unit)
2051 if (vt_cons[unit]->vc_mode != KD_TEXT || !lines)
2053 if (logo_shown >= 0) {
2054 struct vc_data *conp2 = vc_cons[logo_shown].d;
2056 if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows)
2058 if (logo_shown == unit) {
2063 q = conp->vc_origin + logo_lines * conp->vc_size_row;
2064 for (i = 0; i < logo_lines; i++) {
2065 if (p == softback_top) break;
2066 if (p == softback_buf) p = softback_end;
2067 p -= conp->vc_size_row;
2068 q -= conp->vc_size_row;
2069 scr_memcpyw((u16 *)q, (u16 *)p, conp->vc_size_row);
2072 update_region(unit, conp->vc_origin, logo_lines * conp->vc_cols);
2076 fbcon_cursor(conp, CM_ERASE|CM_SOFTBACK);
2077 fbcon_redraw_softback(conp, p, lines);
2078 fbcon_cursor(conp, CM_DRAW|CM_SOFTBACK);
2082 if (!scrollback_phys_max)
2085 scrollback_old = scrollback_current;
2086 scrollback_current -= lines;
2087 if (scrollback_current < 0)
2088 scrollback_current = 0;
2089 else if (scrollback_current > scrollback_max)
2090 scrollback_current = scrollback_max;
2091 if (scrollback_current == scrollback_old)
2094 if (!p->can_soft_blank &&
2095 (console_blanked || vt_cons[unit]->vc_mode != KD_TEXT || !lines))
2097 fbcon_cursor(conp, CM_ERASE);
2099 offset = p->yscroll-scrollback_current;
2101 switch (p->scrollmode && __SCROLL_YMASK) {
2102 case __SCROLL_YWRAP:
2103 p->var.vmode |= FB_VMODE_YWRAP;
2106 limit -= conp->vc_rows;
2107 p->var.vmode &= ~FB_VMODE_YWRAP;
2112 else if (offset >= limit)
2115 p->var.yoffset = offset*fontheight(p);
2116 p->fb_info->updatevar(unit, p->fb_info);
2117 if (!scrollback_current)
2118 fbcon_cursor(conp, CM_DRAW);
2122 static int fbcon_set_origin(struct vc_data *conp)
2124 if (softback_lines && !console_blanked)
2125 fbcon_scrolldelta(conp, softback_lines);
2129 static inline unsigned safe_shift(unsigned d,int n)
2131 return n<0 ? d>>-n : d<<n;
2134 static int __init fbcon_show_logo( void )
2136 struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
2137 int depth = p->var.bits_per_pixel;
2138 int line = p->next_line;
2139 unsigned char *fb = p->screen_base;
2140 unsigned char *logo;
2141 unsigned char *dst, *src;
2142 int i, j, n, x1, y1, x;
2143 int logo_depth, done = 0;
2145 /* Return if the frame buffer is not mapped */
2150 * Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
2152 * We don't have to set the colors for the 16-color logo, since that logo
2153 * uses the standard VGA text console palette
2155 if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) ||
2156 (p->visual == FB_VISUAL_DIRECTCOLOR && depth >= 24))
2157 for (i = 0; i < LINUX_LOGO_COLORS; i += n) {
2158 n = LINUX_LOGO_COLORS - i;
2160 /* palette_cmap provides space for only 16 colors at once */
2162 palette_cmap.start = 32 + i;
2163 palette_cmap.len = n;
2164 for( j = 0; j < n; ++j ) {
2165 palette_cmap.red[j] = (linux_logo_red[i+j] << 8) |
2166 linux_logo_red[i+j];
2167 palette_cmap.green[j] = (linux_logo_green[i+j] << 8) |
2168 linux_logo_green[i+j];
2169 palette_cmap.blue[j] = (linux_logo_blue[i+j] << 8) |
2170 linux_logo_blue[i+j];
2172 p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console,
2180 else if (depth >= 4) {
2181 logo = linux_logo16;
2185 logo = linux_logo_bw;
2189 if (p->fb_info->fbops->fb_rasterimg)
2190 p->fb_info->fbops->fb_rasterimg(p->fb_info, 1);
2192 for (x = 0; x < smp_num_cpus * (LOGO_W + 8) &&
2193 x < p->var.xres - (LOGO_W + 8); x += (LOGO_W + 8)) {
2195 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
2196 defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
2197 if (p->visual == FB_VISUAL_DIRECTCOLOR) {
2198 unsigned int val; /* max. depth 32! */
2200 int redshift, greenshift, blueshift;
2202 /* Bug: Doesn't obey msb_right ... (who needs that?) */
2203 redshift = p->var.red.offset;
2204 greenshift = p->var.green.offset;
2205 blueshift = p->var.blue.offset;
2207 if (depth >= 24 && (depth % 8) == 0) {
2208 /* have at least 8 bits per color */
2211 for( y1 = 0; y1 < LOGO_H; y1++ ) {
2212 dst = fb + y1*line + x*bdepth;
2213 for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
2214 val = (*src << redshift) |
2215 (*src << greenshift) |
2216 (*src << blueshift);
2217 if (bdepth == 4 && !((long)dst & 3)) {
2218 /* Some cards require 32bit access */
2219 fb_writel (val, dst);
2221 } else if (bdepth == 2 && !((long)dst & 1)) {
2222 /* others require 16bit access */
2223 fb_writew (val,dst);
2226 #ifdef __LITTLE_ENDIAN
2227 for( i = 0; i < bdepth; ++i )
2229 for( i = bdepth-1; i >= 0; --i )
2231 fb_writeb (val >> (i*8), dst++);
2236 else if (depth >= 12 && depth <= 23) {
2237 /* have 4..7 bits per color, using 16 color image */
2240 bdepth = (depth+7)/8;
2241 for( y1 = 0; y1 < LOGO_H; y1++ ) {
2242 dst = fb + y1*line + x*bdepth;
2243 for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
2244 pix = *src >> 4; /* upper nibble */
2245 val = (pix << redshift) |
2246 (pix << greenshift) |
2248 #ifdef __LITTLE_ENDIAN
2249 for( i = 0; i < bdepth; ++i )
2251 for( i = bdepth-1; i >= 0; --i )
2253 fb_writeb (val >> (i*8), dst++);
2254 pix = *src & 0x0f; /* lower nibble */
2255 val = (pix << redshift) |
2256 (pix << greenshift) |
2258 #ifdef __LITTLE_ENDIAN
2259 for( i = 0; i < bdepth; ++i )
2261 for( i = bdepth-1; i >= 0; --i )
2263 fb_writeb (val >> (i*8), dst++);
2270 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
2271 defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
2272 if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR)) {
2273 /* Modes without color mapping, needs special data transformation... */
2274 unsigned int val; /* max. depth 32! */
2275 int bdepth = depth/8;
2276 unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
2277 unsigned char redmask, greenmask, bluemask;
2278 int redshift, greenshift, blueshift;
2280 /* Bug: Doesn't obey msb_right ... (who needs that?) */
2281 redmask = mask[p->var.red.length < 8 ? p->var.red.length : 8];
2282 greenmask = mask[p->var.green.length < 8 ? p->var.green.length : 8];
2283 bluemask = mask[p->var.blue.length < 8 ? p->var.blue.length : 8];
2284 redshift = p->var.red.offset - (8-p->var.red.length);
2285 greenshift = p->var.green.offset - (8-p->var.green.length);
2286 blueshift = p->var.blue.offset - (8-p->var.blue.length);
2289 for( y1 = 0; y1 < LOGO_H; y1++ ) {
2290 dst = fb + y1*line + x*bdepth;
2291 for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
2292 val = safe_shift((linux_logo_red[*src-32] & redmask), redshift) |
2293 safe_shift((linux_logo_green[*src-32] & greenmask), greenshift) |
2294 safe_shift((linux_logo_blue[*src-32] & bluemask), blueshift);
2295 if (bdepth == 4 && !((long)dst & 3)) {
2296 /* Some cards require 32bit access */
2297 fb_writel (val, dst);
2299 } else if (bdepth == 2 && !((long)dst & 1)) {
2300 /* others require 16bit access */
2301 fb_writew (val,dst);
2304 #ifdef __LITTLE_ENDIAN
2305 for( i = 0; i < bdepth; ++i )
2307 for( i = bdepth-1; i >= 0; --i )
2309 fb_writeb (val >> (i*8), dst++);
2316 #if defined(CONFIG_FBCON_CFB4)
2317 if (depth == 4 && p->type == FB_TYPE_PACKED_PIXELS) {
2319 for( y1 = 0; y1 < LOGO_H; y1++) {
2320 dst = fb + y1*line + x/2;
2321 for( x1 = 0; x1 < LOGO_W/2; x1++) {
2323 q = (q << 4) | (q >> 4);
2324 fb_writeb (q, dst++);
2330 #if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FB_SBUS)
2331 if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
2332 /* depth 8 or more, packed, with color registers */
2335 for( y1 = 0; y1 < LOGO_H; y1++ ) {
2336 dst = fb + y1*line + x;
2337 for( x1 = 0; x1 < LOGO_W; x1++ )
2338 fb_writeb (*src++, dst++);
2343 #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \
2344 defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
2345 defined(CONFIG_FBCON_IPLAN2P8)
2346 if (depth >= 2 && (p->type == FB_TYPE_PLANES ||
2347 p->type == FB_TYPE_INTERLEAVED_PLANES)) {
2348 /* planes (normal or interleaved), with color registers */
2350 unsigned char val, mask;
2351 int plane = p->next_plane;
2353 #if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \
2354 defined(CONFIG_FBCON_IPLAN2P8)
2355 int line_length = p->line_length;
2357 /* for support of Atari interleaved planes */
2358 #define MAP_X(x) (line_length ? (x) : ((x) & ~1)*depth + ((x) & 1))
2360 #define MAP_X(x) (x)
2362 /* extract a bit from the source image */
2363 #define BIT(p,pix,bit) (p[pix*logo_depth/8] & \
2364 (1 << ((8-((pix*logo_depth)&7)-logo_depth) + bit)))
2367 for( y1 = 0; y1 < LOGO_H; y1++ ) {
2368 for( x1 = 0; x1 < LOGO_LINE; x1++, src += logo_depth ) {
2369 dst = fb + y1*line + MAP_X(x/8+x1);
2370 for( bit = 0; bit < logo_depth; bit++ ) {
2372 for( mask = 0x80, i = 0; i < 8; mask >>= 1, i++ ) {
2373 if (BIT( src, i, bit ))
2382 /* fill remaining planes */
2383 if (depth > logo_depth) {
2384 for( y1 = 0; y1 < LOGO_H; y1++ ) {
2385 for( x1 = 0; x1 < LOGO_LINE; x1++ ) {
2386 dst = fb + y1*line + MAP_X(x/8+x1) + logo_depth*plane;
2387 for( i = logo_depth; i < depth; i++, dst += plane )
2396 #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \
2397 defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_HGA)
2399 if (depth == 1 && (p->type == FB_TYPE_PACKED_PIXELS ||
2400 p->type == FB_TYPE_PLANES ||
2401 p->type == FB_TYPE_INTERLEAVED_PLANES)) {
2404 unsigned char inverse = p->inverse || p->visual == FB_VISUAL_MONO01
2407 int is_hga = !strncmp(p->fb_info->modename, "HGA", 3);
2408 /* can't use simply memcpy because need to apply inverse */
2409 for( y1 = 0; y1 < LOGO_H; y1++ ) {
2410 src = logo + y1*LOGO_LINE;
2412 dst = fb + (y1%4)*8192 + (y1>>2)*line + x/8;
2414 dst = fb + y1*line + x/8;
2415 for( x1 = 0; x1 < LOGO_LINE; ++x1 )
2416 fb_writeb(*src++ ^ inverse, dst++);
2421 #if defined(CONFIG_FBCON_VGA_PLANES)
2422 if (depth == 4 && p->type == FB_TYPE_VGA_PLANES) {
2423 outb_p(1,0x3ce); outb_p(0xf,0x3cf);
2424 outb_p(3,0x3ce); outb_p(0,0x3cf);
2425 outb_p(5,0x3ce); outb_p(0,0x3cf);
2428 for (y1 = 0; y1 < LOGO_H; y1++) {
2429 for (x1 = 0; x1 < LOGO_W / 2; x1++) {
2430 dst = fb + y1*line + x1/4 + x/8;
2433 outb_p(*src >> 4,0x3cf);
2435 outb_p(1 << (7 - x1 % 4 * 2),0x3cf);
2440 outb_p(*src & 0xf,0x3cf);
2442 outb_p(1 << (7 - (1 + x1 % 4 * 2)),0x3cf);
2454 if (p->fb_info->fbops->fb_rasterimg)
2455 p->fb_info->fbops->fb_rasterimg(p->fb_info, 0);
2457 /* Modes not yet supported: packed pixels with depth != 8 (does such a
2458 * thing exist in reality?) */
2460 return done ? (LOGO_H + fontheight(p) - 1) / fontheight(p) : 0 ;
2464 /* console.c doesn't do enough here */
2466 pm_fbcon_request(struct pm_dev *dev, pm_request_t rqst, void *data)
2468 unsigned long flags;
2473 acquire_console_sem();
2475 if (use_timer_cursor) {
2476 cursor_timer.expires = jiffies+HZ/50;
2477 add_timer(&cursor_timer);
2479 release_console_sem();
2482 acquire_console_sem();
2485 if (use_timer_cursor)
2486 del_timer(&cursor_timer);
2488 restore_flags(flags);
2489 release_console_sem();
2494 #endif /* CONFIG_PM */
2497 * The console `switch' structure for the frame buffer based console
2500 const struct consw fb_con = {
2501 con_startup: fbcon_startup,
2502 con_init: fbcon_init,
2503 con_deinit: fbcon_deinit,
2504 con_clear: fbcon_clear,
2505 con_putc: fbcon_putc,
2506 con_putcs: fbcon_putcs,
2507 con_cursor: fbcon_cursor,
2508 con_scroll: fbcon_scroll,
2509 con_bmove: fbcon_bmove,
2510 con_switch: fbcon_switch,
2511 con_blank: fbcon_blank,
2512 con_font_op: fbcon_font_op,
2513 con_set_palette: fbcon_set_palette,
2514 con_scrolldelta: fbcon_scrolldelta,
2515 con_set_origin: fbcon_set_origin,
2516 con_invert_region: fbcon_invert_region,
2517 con_screen_pos: fbcon_screen_pos,
2518 con_getxy: fbcon_getxy,
2523 * Dummy Low Level Operations
2526 static void fbcon_dummy_op(void) {}
2528 #define DUMMY (void *)fbcon_dummy_op
2530 struct display_switch fbcon_dummy = {
2541 * Visible symbols for modules
2544 EXPORT_SYMBOL(fb_display);
2545 EXPORT_SYMBOL(fbcon_redraw_bmove);
2546 EXPORT_SYMBOL(fbcon_redraw_clear);
2547 EXPORT_SYMBOL(fbcon_dummy);
2548 EXPORT_SYMBOL(fb_con);
2550 MODULE_LICENSE("GPL");