📄 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> * * 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. */#undef FBCONDEBUG#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/slab.h>#include <linux/fb.h>#include <linux/vt_kern.h>#include <linux/selection.h>#include <linux/smp.h>#include <linux/init.h>#include <linux/pm.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/* * The #include <asm/linux_logo.h> didn't seem to work for us. * so I use #include <linux/linux_logo.h> if compiling for * our board * (20030314 - hede) */#if defined(CONFIG_FB_COBRA5272) || defined (CONFIG_DRAGEN2)#include <linux/linux_logo.h>#else#include <asm/linux_logo.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)struct display fb_display[MAX_NR_CONSOLES];char con2fb_map[MAX_NR_CONSOLES];static int logo_lines;static int logo_shown = -1;/* Software scrollback */int fbcon_softback_size = 32768;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 *);#ifdef CONFIG_PMstatic int pm_fbcon_request(struct pm_dev *dev, pm_request_t rqst, void *data);static struct pm_dev *pm_fbcon;static int fbcon_sleeping;#endif/* * 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;#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;static int cursor_on;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;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 = { function: cursor_timer_handler};static int use_timer_cursor;static void cursor_timer_handler(unsigned long dev_addr){ fbcon_vbl_handler(0, NULL, NULL); cursor_timer.expires = jiffies+HZ/50; add_timer(&cursor_timer);}/** * PROC_CONSOLE - find the attached tty or visible console * @info: frame buffer info structure * * Finds the tty attached to the process or visible console if * the process is not directly attached to a tty (e.g. remote * user) for device @info. * * Returns -1 errno on error, or tty/visible console number * on success. * */int PROC_CONSOLE(const struct fb_info *info){ int fgc; if (info->display_fg == NULL) return -1; if (!current->tty || current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE || MINOR(current->tty->device) < 1) fgc = info->display_fg->vc_num; else fgc = MINOR(current->tty->device)-1; /* Does this virtual console belong to the specified fbdev? */ if (fb_display[fgc].fb_info != info) return -1; return fgc;}/** * set_all_vcs - set all virtual consoles to match * @fbidx: frame buffer index (e.g. fb0, fb1, ...) * @fb: frame buffer ops structure * @var: frame buffer screen structure to set * @info: frame buffer info structure * * Set all virtual consoles to match screen info set in @var * for device @info. * * Returns negative errno on error, or zero on success. * */int set_all_vcs(int fbidx, struct fb_ops *fb, struct fb_var_screeninfo *var, struct fb_info *info){ int unit, err; var->activate |= FB_ACTIVATE_TEST; err = fb->fb_set_var(var, PROC_CONSOLE(info), info); var->activate &= ~FB_ACTIVATE_TEST; if (err) return err; for (unit = 0; unit < MAX_NR_CONSOLES; unit++) if (fb_display[unit].conp && con2fb_map[unit] == fbidx) fb->fb_set_var(var, unit, info); return 0;}/** * set_con2fb_map - map console to frame buffer device * @unit: virtual console number to map * @newidx: frame buffer index to map virtual console to * * Maps a virtual console @unit to a frame buffer device * @newidx. * */void set_con2fb_map(int unit, int newidx){ int oldidx = con2fb_map[unit]; struct fb_info *oldfb, *newfb; struct vc_data *conp; char *fontdata; unsigned short fontwidth, fontheight, fontwidthlog, fontheightlog; int userfont; if (newidx != con2fb_map[unit]) { oldfb = registered_fb[oldidx]; newfb = registered_fb[newidx]; if (newfb->fbops->owner) __MOD_INC_USE_COUNT(newfb->fbops->owner); if (newfb->fbops->fb_open && newfb->fbops->fb_open(newfb,0)) { if (newfb->fbops->owner) __MOD_DEC_USE_COUNT(newfb->fbops->owner); return; } if (oldfb->fbops->fb_release) oldfb->fbops->fb_release(oldfb,0); if (oldfb->fbops->owner) __MOD_DEC_USE_COUNT(oldfb->fbops->owner); conp = fb_display[unit].conp; fontdata = fb_display[unit].fontdata; fontwidth = fb_display[unit]._fontwidth; fontheight = fb_display[unit]._fontheight; fontwidthlog = fb_display[unit]._fontwidthlog; fontheightlog = fb_display[unit]._fontheightlog; userfont = fb_display[unit].userfont; con2fb_map[unit] = newidx; fb_display[unit] = *(newfb->disp); fb_display[unit].conp = conp; fb_display[unit].fontdata = fontdata; fb_display[unit]._fontwidth = fontwidth; fb_display[unit]._fontheight = fontheight; fb_display[unit]._fontwidthlog = fontwidthlog; fb_display[unit]._fontheightlog = fontheightlog; fb_display[unit].userfont = userfont; fb_display[unit].fb_info = newfb; if (conp) conp->vc_display_fg = &newfb->display_fg; if (!newfb->display_fg) newfb->display_fg = conp; if (!newfb->changevar) newfb->changevar = oldfb->changevar; /* tell console var has changed */ if (newfb->changevar) newfb->changevar(unit); }}/* * Low Level Operations */struct display_switch fbcon_dummy;/* NOTE: fbcon cannot be __init: 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -