fbcon.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,454 行 · 第 1/5 页
C
2,454 行
/* * 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/font.h>#include <linux/smp.h>#include <linux/init.h>#include <linux/interrupt.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/uaccess.h>#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#include "fbcon.h"#ifdef FBCONDEBUG# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)#else# define DPRINTK(fmt, args...)#endifstruct display fb_display[MAX_NR_CONSOLES];signed char con2fb_map[MAX_NR_CONSOLES];static int logo_height;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;/* console mappings */static int first_fb_vc;static int last_fb_vc = MAX_NR_CONSOLES - 1;static int fbcon_is_default = 1; /* font data */static char fontname[40];/* current fb_info */static int info_idx = -1;#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) * vc->vc_size_row)static void fbcon_free_font(struct display *);static int fbcon_set_origin(struct vc_data *);#define CURSOR_DRAW_DELAY (1)/* # VBL ints between cursor state changes */#define ARM_CURSOR_BLINK_RATE (10)#define ATARI_CURSOR_BLINK_RATE (42)#define MAC_CURSOR_BLINK_RATE (32)#define DEFAULT_CURSOR_BLINK_RATE (20)static int vbl_cursor_cnt;#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 *vc, int init);static void fbcon_deinit(struct vc_data *vc);static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, int width);static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos);static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos);static void fbcon_cursor(struct vc_data *vc, int mode);static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, int count);static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, int height, int width);static int fbcon_switch(struct vc_data *vc);static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);static int fbcon_set_palette(struct vc_data *vc, unsigned char *table);static int fbcon_scrolldelta(struct vc_data *vc, int lines);void accel_clear_margins(struct vc_data *vc, struct fb_info *info, int bottom_only);/* * Internal routines */static __inline__ int real_y(struct display *p, int ypos);static __inline__ void ywrap_up(struct vc_data *vc, int count);static __inline__ void ywrap_down(struct vc_data *vc, int count);static __inline__ void ypan_up(struct vc_data *vc, int count);static __inline__ void ypan_down(struct vc_data *vc, int count);static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break);static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc);static void fbcon_redraw_move(struct vc_data *vc, struct display *p, int line, int count, int dy);#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 irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp){ vbl_detected++; return IRQ_HANDLED;}#endifstatic void fb_flashcursor(void *private){ struct fb_info *info = (struct fb_info *) private; struct vc_data *vc = NULL; if (info->currcon != -1) vc = vc_cons[info->currcon].d; if (info->state != FBINFO_STATE_RUNNING || info->cursor.rop == ROP_COPY || !vc || !CON_IS_VISIBLE(vc) || registered_fb[(int) con2fb_map[vc->vc_num]] != info) return; acquire_console_sem(); info->cursor.enable ^= 1; info->fbops->fb_cursor(info, &info->cursor); release_console_sem();}#if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC)static int cursor_blink_rate;static irqreturn_t fb_vbl_handler(int irq, void *dev_id, struct pt_regs *fp){ struct fb_info *info = dev_id; if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) { schedule_work(&info->queue); vbl_cursor_cnt = cursor_blink_rate; } return IRQ_HANDLED;}#endif static void cursor_timer_handler(unsigned long dev_addr){ struct fb_info *info = (struct fb_info *) dev_addr; schedule_work(&info->queue); mod_timer(&info->cursor_timer, jiffies + HZ/5);}int __init fb_console_setup(char *this_opt){ char *options; int i, j; if (!this_opt || !*this_opt) return 0; while ((options = strsep(&this_opt, ",")) != NULL) { if (!strncmp(options, "font:", 5)) strcpy(fontname, options + 5); if (!strncmp(options, "scrollback:", 11)) { options += 11; if (*options) { fbcon_softback_size = simple_strtoul(options, &options, 0); if (*options == 'k' || *options == 'K') { fbcon_softback_size *= 1024; options++; } if (*options != ',') return 0; options++; } else return 0; } if (!strncmp(options, "map:", 4)) { options += 4; if (*options) for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { if (!options[j]) j = 0; con2fb_map[i] = (options[j++]-'0') % FB_MAX; } return 0; } if (!strncmp(options, "vc:", 3)) { options += 3; if (*options) first_fb_vc = simple_strtoul(options, &options, 10) - 1; if (first_fb_vc < 0) first_fb_vc = 0; if (*options++ == '-') last_fb_vc = simple_strtoul(options, &options, 10) - 1; fbcon_is_default = 0; } } return 0;}__setup("fbcon=", fb_console_setup);static int search_fb_in_map(int idx){ int i; for (i = 0; i < MAX_NR_CONSOLES; i++) { if (con2fb_map[i] == idx) return 1; } return 0;}static int search_for_mapped_con(void){ int i; for (i = 0; i < MAX_NR_CONSOLES; i++) { if (con2fb_map[i] != -1) return 1; } return 0;}static int fbcon_takeover(void){ int err, i; if (!num_registered_fb) return -ENODEV; for (i = first_fb_vc; i <= last_fb_vc; i++) con2fb_map[i] = info_idx; err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); if (err) { for (i = first_fb_vc; i <= last_fb_vc; i++) { con2fb_map[i] = -1; } info_idx = -1; } return err;}/** * 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. */static int set_con2fb_map(int unit, int newidx){ struct vc_data *vc = vc_cons[unit].d; int oldidx = con2fb_map[unit]; struct fb_info *info = registered_fb[newidx]; struct fb_info *oldinfo = NULL; int found; if (oldidx == newidx) return 0; if (!vc) return -ENODEV; if (!search_for_mapped_con()) { info_idx = newidx; return fbcon_takeover(); } if (oldidx != -1) oldinfo = registered_fb[oldidx]; found = search_fb_in_map(newidx); acquire_console_sem(); con2fb_map[unit] = newidx; if (!found) { if (!try_module_get(info->fbops->owner)) { con2fb_map[unit] = oldidx; release_console_sem(); return -ENODEV; } if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) { module_put(info->fbops->owner); con2fb_map[unit] = oldidx; release_console_sem(); return -ENODEV; } } /* * If old fb is not mapped to any of the consoles, * fbcon should release it. */ if (oldinfo && !search_fb_in_map(oldidx)) { if (oldinfo->fbops->fb_release && oldinfo->fbops->fb_release(oldinfo, 0)) { con2fb_map[unit] = oldidx; if (!found && info->fbops->fb_release) info->fbops->fb_release(info, 0); if (!found) module_put(info->fbops->owner); release_console_sem(); return -ENODEV; } if (oldinfo->queue.func == fb_flashcursor) del_timer_sync(&oldinfo->cursor_timer); module_put(oldinfo->fbops->owner); } info->currcon = -1; if (!found) { if (!info->queue.func || info->queue.func == fb_flashcursor) { if (!info->queue.func) INIT_WORK(&info->queue, fb_flashcursor, info); init_timer(&info->cursor_timer); info->cursor_timer.function = cursor_timer_handler; info->cursor_timer.expires = jiffies + HZ / 5; info->cursor_timer.data = (unsigned long ) info; add_timer(&info->cursor_timer); } } if (info->fbops->fb_set_par) info->fbops->fb_set_par(info); fbcon_set_disp(info, vc); release_console_sem(); return 0;}/* * Accelerated handlers. */static inline int get_color(struct vc_data *vc, struct fb_info *info, u16 c, int is_fg){ int depth = fb_get_color_depth(info); int color = 0; 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: { /* 0 or 1 */ int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; color = (is_fg) ? fg : bg; break; } case 2: /* * Scale down 16-colors to 4 colors. Default 4-color palette * is grayscale. */ color /= 4; 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; } return color;}#define FBCON_ATTRIBUTE_UNDERLINE 1#define FBCON_ATTRIBUTE_REVERSE 2#define FBCON_ATTRIBUTE_BOLD 4static inline int get_attribute(struct fb_info *info, u16 c){ int attribute = 0; if (fb_get_color_depth(info) == 1) { if (attr_underline(c)) attribute |= FBCON_ATTRIBUTE_UNDERLINE; if (attr_reverse(c)) attribute |= FBCON_ATTRIBUTE_REVERSE; if (attr_bold(c)) attribute |= FBCON_ATTRIBUTE_BOLD; } return attribute;}static inline void update_attr(u8 *dst, u8 *src, int attribute, struct vc_data *vc){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?