fbcon.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,412 行 · 第 1/5 页

C
2,412
字号
/* *  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;}/** *	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. */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;		fb_console_init();		return 0;	}	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. */void accel_bmove(struct vc_data *vc, struct fb_info *info, int sy, 		int sx, int dy, int dx, int height, int width){	struct fb_copyarea area;	area.sx = sx * vc->vc_font.width;	area.sy = sy * vc->vc_font.height;	area.dx = dx * vc->vc_font.width;	area.dy = dy * vc->vc_font.height;	area.height = height * vc->vc_font.height;	area.width = width * vc->vc_font.width;	info->fbops->fb_copyarea(info, &area);}void accel_clear(struct vc_data *vc, struct fb_info *info, int sy,			int sx, int height, int width){	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;	struct fb_fillrect region;	region.color = attr_bgcol_ec(bgshift, vc);	region.dx = sx * vc->vc_font.width;	region.dy = sy * vc->vc_font.height;	region.width = width * vc->vc_font.width;	region.height = height * vc->vc_font.height;	region.rop = ROP_COPY;	info->fbops->fb_fillrect(info, &region);}	void accel_putcs(struct vc_data *vc, struct fb_info *info,		 const unsigned short *s, int count, int yy, int xx){	void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf,			       u8 *dst, u32 d_pitch, u8 *src, u32 idx,			       u32 height, u32 shift_high, u32 shift_low,			       u32 mod);	void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf,			     u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,			     u32 height);	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;	unsigned int width = (vc->vc_font.width + 7) >> 3;	unsigned int cellsize = vc->vc_font.height * width;	unsigned int maxcnt = info->pixmap.size/cellsize;	unsigned int scan_align = info->pixmap.scan_align - 1;	unsigned int buf_align = info->pixmap.buf_align - 1;	unsigned int shift_low = 0, mod = vc->vc_font.width % 8;	unsigned int shift_high = 8, pitch, cnt, size, k;	unsigned int idx = vc->vc_font.width >> 3;	struct fb_image image;	u8 *src, *dst;	image.fg_color = attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8,				    scr_readw(s));	image.bg_color = attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12,				    scr_readw(s));	image.dx = xx * vc->vc_font.width;	image.dy = yy * vc->vc_font.height;	image.height = vc->vc_font.height;	image.depth = 1;	if (info->pixmap.outbuf && info->pixmap.inbuf) {		move_aligned = fb_iomove_buf_aligned;		move_unaligned = fb_iomove_buf_unaligned;	} else {		move_aligned = fb_sysmove_buf_aligned;		move_unaligned = fb_sysmove_buf_unaligned;	}	while (count) {		if (count > maxcnt)			cnt = k = maxcnt;		else			cnt = k = count;		image.width = vc->vc_font.width * cnt;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?