📄 fbcon.c
字号:
/* * 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> * * * 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. */#undef FBCONDEBUG#define CONFIG_MY_LOGO#define CONFIG_MINI_LOGO#if defined(CONFIG_MINI_LOGO) && !defined(CONFIG_MY_LOGO)#error "CONFIG_MINI_LOGO must be used with CONFIG_MY_LOGO"#endif#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/delay.h> /* MSch: for IRQ probe */#include <linux/tty.h>#include <linux/console.h>#include <linux/string.h>#include <linux/kd.h>#include <linux/malloc.h>#include <linux/fb.h>#include <linux/vt_kern.h>#include <linux/selection.h>#include <linux/smp.h>#include <linux/init.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/uaccess.h>#ifdef CONFIG_AMIGA#include <asm/amigahw.h>#include <asm/amigaints.h>#endif /* CONFIG_AMIGA */#ifdef CONFIG_ATARI#include <asm/atariints.h>#endif#ifdef CONFIG_MAC#include <asm/macints.h>#endif#if defined(__mc68000__) || defined(CONFIG_APUS)#include <asm/machdep.h>#include <asm/setup.h>#endif#ifdef CONFIG_FBCON_VGA_PLANES#include <asm/io.h>#endif#define INCLUDE_LINUX_LOGO_DATA#include <asm/linux_logo.h>/* HACKED by zerow_jp*/#ifdef CONFIG_MINI_LOGO/* mini logo (for SMP)*//* define MINI_LOGO_H, MINI_LOGO_W, MINI_LOGO_X, MINI_LOGO_Y, MINI_LOGO_ADD unsigned char mini_logo[MINI_LOGO_H*MINI_LOGO_W] */#include <linux/linux_logo_mini.h>#endif#include <video/fbcon.h>#include <video/fbcon-mac.h> /* for 6x11 font on mac */#include <video/font.h>#ifdef FBCONDEBUG# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)#else# define DPRINTK(fmt, args...)#endif#define LOGO_H 80#define LOGO_W 80#define LOGO_LINE (LOGO_W/8)#ifdef CONFIG_MY_LOGO#define MY_LOGO_LINE (MY_LOGO_W/8)#endifstruct display fb_display[MAX_NR_CONSOLES];static int logo_lines;static int logo_shown = -1;/* Software scrollback */extern int fbcon_softback_size;static unsigned long softback_buf, softback_curr;static unsigned long softback_in;static unsigned long softback_top, softback_end;static int softback_lines;#define REFCOUNT(fd) (((int *)(fd))[-1])#define FNTSIZE(fd) (((int *)(fd))[-2])#define FNTCHARCNT(fd) (((int *)(fd))[-3])#define FNTSUM(fd) (((int *)(fd))[-4])#define FONT_EXTRA_WORDS 4#define CM_SOFTBACK (8)#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * conp->vc_size_row)static void fbcon_free_font(struct display *);static int fbcon_set_origin(struct vc_data *);/* * Emmanuel: fbcon will now use a hardware cursor if the * low-level driver provides a non-NULL dispsw->cursor pointer, * in which case the hardware should do blinking, etc. * * if dispsw->cursor is NULL, use Atari alike software cursor */static int cursor_drawn = 0;#define CURSOR_DRAW_DELAY (1)/* # VBL ints between cursor state changes */#define ARM_CURSOR_BLINK_RATE (10)#define AMIGA_CURSOR_BLINK_RATE (20)#define ATARI_CURSOR_BLINK_RATE (42)#define MAC_CURSOR_BLINK_RATE (32)#define DEFAULT_CURSOR_BLINK_RATE (20)static int vbl_cursor_cnt = 0;static int cursor_on = 0;static int cursor_blink_rate;static inline void cursor_undrawn(void){ vbl_cursor_cnt = 0; cursor_drawn = 0;}#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)/* * Interface used by the world */static const char *fbcon_startup(void);static void fbcon_init(struct vc_data *conp, int init);static void fbcon_deinit(struct vc_data *conp);static int fbcon_changevar(int con);static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height, int width);static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos);static void fbcon_putcs(struct vc_data *conp, const unsigned short *s, int count, int ypos, int xpos);static void fbcon_cursor(struct vc_data *conp, int mode);static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count);static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, int height, int width);static int fbcon_switch(struct vc_data *conp);static int fbcon_blank(struct vc_data *conp, int blank);static int fbcon_font_op(struct vc_data *conp, struct console_font_op *op);static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);static int fbcon_scrolldelta(struct vc_data *conp, int lines);/* * Internal routines */static void fbcon_setup(int con, int init, int logo);static __inline__ int real_y(struct display *p, int ypos);static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);static __inline__ void updatescrollmode(struct display *p);static __inline__ void ywrap_up(int unit, struct vc_data *conp, struct display *p, int count);static __inline__ void ywrap_down(int unit, struct vc_data *conp, struct display *p, int count);static __inline__ void ypan_up(int unit, struct vc_data *conp, struct display *p, int count);static __inline__ void ypan_down(int unit, struct vc_data *conp, struct display *p, int count);static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break);static int fbcon_show_logo(void);#ifdef CONFIG_MAC/* * On the Macintoy, there may or may not be a working VBL int. We need to probe */static int vbl_detected = 0;static void fbcon_vbl_detect(int irq, void *dummy, struct pt_regs *fp){ vbl_detected++;}#endifstatic void cursor_timer_handler(unsigned long dev_addr);static struct timer_list cursor_timer = { NULL, NULL, 0, 0L, cursor_timer_handler};static void cursor_timer_handler(unsigned long dev_addr){ fbcon_vbl_handler(0, NULL, NULL); cursor_timer.expires = jiffies+HZ/50; cursor_timer.data = 0; cursor_timer.next = cursor_timer.next = NULL; add_timer(&cursor_timer);}/* * Low Level Operations */struct display_switch fbcon_dummy;/* NOTE: fbcon cannot be __initfunc: it may be called from take_over_console later */static const char *fbcon_startup(void){ const char *display_desc = "frame buffer device"; int irqres = 1; static int done = 0; /* * If num_registered_fb is zero, this is a call for the dummy part. * The frame buffer devices weren't initialized yet. */ if (!num_registered_fb || done) return display_desc; done = 1;#ifdef CONFIG_AMIGA if (MACH_IS_AMIGA) { cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0, "console/cursor", fbcon_vbl_handler); }#endif /* CONFIG_AMIGA */#ifdef CONFIG_ATARI if (MACH_IS_ATARI) { cursor_blink_rate = ATARI_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO, "console/cursor", fbcon_vbl_handler); }#endif /* CONFIG_ATARI */#ifdef CONFIG_MAC /* * On a Macintoy, the VBL interrupt may or may not be active. * As interrupt based cursor is more reliable and race free, we * probe for VBL interrupts. */ if (MACH_IS_MAC) { int ct = 0; /* * Probe for VBL: set temp. handler ... */ irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_detect, 0, "console/cursor", fbcon_vbl_detect); vbl_detected = 0; /* * ... and spin for 20 ms ... */ while (!vbl_detected && ++ct<1000) udelay(20); if(ct==1000) printk("fbcon_startup: No VBL detected, using timer based cursor.\n"); free_irq(IRQ_MAC_VBL, fbcon_vbl_detect); if (vbl_detected) { /* * interrupt based cursor ok */ cursor_blink_rate = MAC_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_handler, 0, "console/cursor", fbcon_vbl_handler); } else { /* * VBL not detected: fall through, use timer based cursor */ irqres = 1; } }#endif /* CONFIG_MAC */#if defined(__arm__) && defined(IRQ_VSYNCPULSE) cursor_blink_rate = ARM_CURSOR_BLINK_RATE; irqres = request_irq(IRQ_VSYNCPULSE, fbcon_vbl_handler, SA_SHIRQ, "console/cursor", fbcon_vbl_handler);#endif if (irqres) { cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE; cursor_timer.expires = jiffies+HZ/50; cursor_timer.data = 0; cursor_timer.next = cursor_timer.prev = NULL; add_timer(&cursor_timer); } return display_desc;}static void fbcon_init(struct vc_data *conp, int init){ int unit = conp->vc_num; struct fb_info *info; /* on which frame buffer will we open this console? */ info = registered_fb[(int)con2fb_map[unit]]; info->changevar = &fbcon_changevar; fb_display[unit] = *(info->disp); /* copy from default */ DPRINTK("mode: %s\n",info->modename); DPRINTK("visual: %d\n",fb_display[unit].visual); DPRINTK("res: %dx%d-%d\n",fb_display[unit].var.xres, fb_display[unit].var.yres, fb_display[unit].var.bits_per_pixel); fb_display[unit].conp = conp; fb_display[unit].fb_info = info; /* clear out the cmap so we don't have dangling pointers */ fb_display[unit].cmap.len = 0; fb_display[unit].cmap.red = 0; fb_display[unit].cmap.green = 0; fb_display[unit].cmap.blue = 0; fb_display[unit].cmap.transp = 0; fbcon_setup(unit, init, !init); /* Must be done after fbcon_setup to prevent excess updates */ conp->vc_display_fg = &info->display_fg; if (!info->display_fg) info->display_fg = conp;}static void fbcon_deinit(struct vc_data *conp){ int unit = conp->vc_num; struct display *p = &fb_display[unit]; fbcon_free_font(p); p->dispsw = &fbcon_dummy; p->conp = 0;}static int fbcon_changevar(int con){ if (fb_display[con].conp) fbcon_setup(con, 0, 0); return 0;}static __inline__ void updatescrollmode(struct display *p){ int m; if (p->scrollmode & __SCROLL_YFIXED) return; if (divides(p->ywrapstep, fontheight(p)) && divides(fontheight(p), p->var.yres_virtual)) m = __SCROLL_YWRAP; else if (divides(p->ypanstep, fontheight(p)) && p->var.yres_virtual >= p->var.yres+fontheight(p)) m = __SCROLL_YPAN; else if (p->scrollmode & __SCROLL_YNOMOVE) m = __SCROLL_YREDRAW; else m = __SCROLL_YMOVE; p->scrollmode = (p->scrollmode & ~__SCROLL_YMASK) | m;}static void fbcon_font_widths(struct display *p){ int i; p->_fontwidthlog = 0; for (i = 2; i <= 6; i++) if (fontwidth(p) == (1 << i)) p->_fontwidthlog = i; p->_fontheightlog = 0; for (i = 2; i <= 6; i++) if (fontheight(p) == (1 << i)) p->_fontheightlog = i;}#define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))static void fbcon_setup(int con, int init, int logo){ struct display *p = &fb_display[con]; struct vc_data *conp = p->conp; int nr_rows, nr_cols; int old_rows, old_cols; unsigned short *save = NULL, *r, *q; int i, charcnt = 256; struct fbcon_font_desc *font; if (con != fg_console || (p->fb_info->flags & FBINFO_FLAG_MODULE) || p->type == FB_TYPE_TEXT) logo = 0; p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ if (con == fg_console && p->type != FB_TYPE_TEXT) { if (fbcon_softback_size) { if (!softback_buf) { softback_buf = (unsigned long)kmalloc(fbcon_softback_size, GFP_KERNEL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -