fbmem.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,399 行 · 第 1/3 页

C
1,399
字号
/* *  linux/drivers/video/fbmem.c * *  Copyright (C) 1994 Martin Schaller * *	2001 - Documented with DocBook *	- Brad Douglas <brad@neruo.com> * * 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. */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/tty.h>#include <linux/init.h>#include <linux/linux_logo.h>#include <linux/proc_fs.h>#include <linux/console.h>#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#include <linux/devfs_fs_kernel.h>#include <linux/err.h>#include <linux/kernel.h>#include <linux/device.h>#if defined(__mc68000__) || defined(CONFIG_APUS)#include <asm/setup.h>#endif#include <asm/io.h>#include <asm/uaccess.h>#include <asm/page.h>#include <asm/pgtable.h>#include <linux/fb.h>    /*     *  Frame buffer device initialization and setup routines     */#define FBPIXMAPSIZE	16384static struct notifier_block *fb_notifier_list;struct fb_info *registered_fb[FB_MAX];int num_registered_fb;/* * Helpers */int fb_get_color_depth(struct fb_info *info){	struct fb_var_screeninfo *var = &info->var;	if (var->green.length == var->blue.length &&	    var->green.length == var->red.length &&	    !var->green.offset && !var->blue.offset &&	    !var->red.offset)		return var->green.length;	else		return (var->green.length + var->red.length +			var->blue.length);}EXPORT_SYMBOL(fb_get_color_depth);/* * Drawing helpers. */void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,			   u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,			   u32 height){	int i;	for (i = height; i--; ) {		buf->outbuf(info, dst, src, s_pitch);		src += s_pitch;		dst += d_pitch;	}}void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,			    u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,			    u32 height){	int i, j;	for (i = height; i--; ) {		for (j = 0; j < s_pitch; j++)			dst[j] = src[j];		src += s_pitch;		dst += d_pitch;	}}void fb_iomove_buf_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){	u8 mask = (u8) (0xfff << shift_high), tmp;	int i, j;	for (i = height; i--; ) {		for (j = 0; j < idx; j++) {			tmp = buf->inbuf(info, dst+j);			tmp &= mask;			tmp |= *src >> shift_low;			buf->outbuf(info, dst+j, &tmp, 1);			tmp = *src << shift_high;			buf->outbuf(info, dst+j+1, &tmp, 1);			src++;		}		tmp = buf->inbuf(info, dst+idx);		tmp &= mask;		tmp |= *src >> shift_low;		buf->outbuf(info, dst+idx, &tmp, 1);		if (shift_high < mod) {			tmp = *src << shift_high;			buf->outbuf(info, dst+idx+1, &tmp, 1);		}			src++;		dst += d_pitch;	}}void fb_sysmove_buf_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){	u8 mask = (u8) (0xfff << shift_high), tmp;	int i, j;	for (i = height; i--; ) {		for (j = 0; j < idx; j++) {			tmp = dst[j];			tmp &= mask;			tmp |= *src >> shift_low;			dst[j] = tmp;			tmp = *src << shift_high;			dst[j+1] = tmp;			src++;		}		tmp = dst[idx];		tmp &= mask;		tmp |= *src >> shift_low;		dst[idx] = tmp;		if (shift_high < mod) {			tmp = *src << shift_high;			dst[idx+1] = tmp;		}		src++;		dst += d_pitch;	}}/* * we need to lock this section since fb_cursor * may use fb_imageblit() */char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size){	u32 align = buf->buf_align - 1, offset;	char *addr = buf->addr;	/* If IO mapped, we need to sync before access, no sharing of	 * the pixmap is done	 */	if (buf->flags & FB_PIXMAP_IO) {		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))			info->fbops->fb_sync(info);		return addr;	}	/* See if we fit in the remaining pixmap space */	offset = buf->offset + align;	offset &= ~align;	if (offset + size > buf->size) {		/* We do not fit. In order to be able to re-use the buffer,		 * we must ensure no asynchronous DMA'ing or whatever operation		 * is in progress, we sync for that.		 */		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))			info->fbops->fb_sync(info);		offset = 0;	}	buf->offset = offset + size;	addr += offset;	return addr;}#ifdef CONFIG_LOGO#include <linux/linux_logo.h>static inline unsigned safe_shift(unsigned d, int n){	return n < 0 ? d >> -n : d << n;}static void fb_set_logocmap(struct fb_info *info,				   const struct linux_logo *logo){	struct fb_cmap palette_cmap;	u16 palette_green[16];	u16 palette_blue[16];	u16 palette_red[16];	int i, j, n;	const unsigned char *clut = logo->clut;	palette_cmap.start = 0;	palette_cmap.len = 16;	palette_cmap.red = palette_red;	palette_cmap.green = palette_green;	palette_cmap.blue = palette_blue;	palette_cmap.transp = NULL;	for (i = 0; i < logo->clutsize; i += n) {		n = logo->clutsize - i;		/* palette_cmap provides space for only 16 colors at once */		if (n > 16)			n = 16;		palette_cmap.start = 32 + i;		palette_cmap.len = n;		for (j = 0; j < n; ++j) {			palette_cmap.red[j] = clut[0] << 8 | clut[0];			palette_cmap.green[j] = clut[1] << 8 | clut[1];			palette_cmap.blue[j] = clut[2] << 8 | clut[2];			clut += 3;		}		fb_set_cmap(&palette_cmap, info);	}}static void  fb_set_logo_truepalette(struct fb_info *info,					    const struct linux_logo *logo,					    u32 *palette){	unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };	unsigned char redmask, greenmask, bluemask;	int redshift, greenshift, blueshift;	int i;	const unsigned char *clut = logo->clut;	/*	 * We have to create a temporary palette since console palette is only	 * 16 colors long.	 */	/* Bug: Doesn't obey msb_right ... (who needs that?) */	redmask   = mask[info->var.red.length   < 8 ? info->var.red.length   : 8];	greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];	bluemask  = mask[info->var.blue.length  < 8 ? info->var.blue.length  : 8];	redshift   = info->var.red.offset   - (8 - info->var.red.length);	greenshift = info->var.green.offset - (8 - info->var.green.length);	blueshift  = info->var.blue.offset  - (8 - info->var.blue.length);	for ( i = 0; i < logo->clutsize; i++) {		palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |				 safe_shift((clut[1] & greenmask), greenshift) |				 safe_shift((clut[2] & bluemask), blueshift));		clut += 3;	}}static void fb_set_logo_directpalette(struct fb_info *info,					     const struct linux_logo *logo,					     u32 *palette){	int redshift, greenshift, blueshift;	int i;	redshift = info->var.red.offset;	greenshift = info->var.green.offset;	blueshift = info->var.blue.offset;	for (i = 32; i < logo->clutsize; i++)		palette[i] = i << redshift | i << greenshift | i << blueshift;}static void fb_set_logo(struct fb_info *info,			       const struct linux_logo *logo, u8 *dst,			       int depth){	int i, j, k, fg = 1;	const u8 *src = logo->data;	u8 d, xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;	if (fb_get_color_depth(info) == 3)		fg = 7;	switch (depth) {	case 4:		for (i = 0; i < logo->height; i++)			for (j = 0; j < logo->width; src++) {				*dst++ = *src >> 4;				j++;				if (j < logo->width) {					*dst++ = *src & 0x0f;					j++;				}			}		break;	case 1:		for (i = 0; i < logo->height; i++) {			for (j = 0; j < logo->width; src++) {				d = *src ^ xor;				for (k = 7; k >= 0; k--) {					*dst++ = ((d >> k) & 1) ? fg : 0;					j++;				}			}		}		break;	}}/* * Three (3) kinds of logo maps exist.  linux_logo_clut224 (>16 colors), * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors).  Depending on * the visual format and color depth of the framebuffer, the DAC, the * pseudo_palette, and the logo data will be adjusted accordingly. * * Case 1 - linux_logo_clut224: * Color exceeds the number of console colors (16), thus we set the hardware DAC * using fb_set_cmap() appropriately.  The "needs_cmapreset"  flag will be set. * * For visuals that require color info from the pseudo_palette, we also construct * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags * will be set. * * Case 2 - linux_logo_vga16: * The number of colors just matches the console colors, thus there is no need * to set the DAC or the pseudo_palette.  However, the bitmap is packed, ie, * each byte contains color information for two pixels (upper and lower nibble). * To be consistent with fb_imageblit() usage, we therefore separate the two * nibbles into separate bytes. The "depth" flag will be set to 4. * * Case 3 - linux_logo_mono: * This is similar with Case 2.  Each byte contains information for 8 pixels. * We isolate each bit and expand each into a byte. The "depth" flag will * be set to 1. */static struct logo_data {	int depth;	int needs_directpalette;	int needs_truepalette;	int needs_cmapreset;	const struct linux_logo *logo;} fb_logo;int fb_prepare_logo(struct fb_info *info){	int depth = fb_get_color_depth(info);	memset(&fb_logo, 0, sizeof(struct logo_data));	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {		depth = info->var.blue.length;		if (info->var.red.length < depth)			depth = info->var.red.length;		if (info->var.green.length < depth)			depth = info->var.green.length;	}	if (depth >= 8) {		switch (info->fix.visual) {		case FB_VISUAL_TRUECOLOR:			fb_logo.needs_truepalette = 1;			break;		case FB_VISUAL_DIRECTCOLOR:			fb_logo.needs_directpalette = 1;			fb_logo.needs_cmapreset = 1;			break;		case FB_VISUAL_PSEUDOCOLOR:			fb_logo.needs_cmapreset = 1;			break;		}	}	/* Return if no suitable logo was found */	fb_logo.logo = fb_find_logo(depth);		if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {		fb_logo.logo = NULL;		return 0;	}	/* What depth we asked for might be different from what we get */	if (fb_logo.logo->type == LINUX_LOGO_CLUT224)		fb_logo.depth = 8;	else if (fb_logo.logo->type == LINUX_LOGO_VGA16)		fb_logo.depth = 4;	else		fb_logo.depth = 1;			return fb_logo.logo->height;}int fb_show_logo(struct fb_info *info){	u32 *palette = NULL, *saved_pseudo_palette = NULL;	unsigned char *logo_new = NULL;	struct fb_image image;	int x;	/* Return if the frame buffer is not mapped or suspended */	if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)		return 0;	image.depth = 8;	image.data = fb_logo.logo->data;	if (fb_logo.needs_cmapreset)		fb_set_logocmap(info, fb_logo.logo);	if (fb_logo.needs_truepalette || 	    fb_logo.needs_directpalette) {		palette = kmalloc(256 * 4, GFP_KERNEL);		if (palette == NULL)			return 0;		if (fb_logo.needs_truepalette)			fb_set_logo_truepalette(info, fb_logo.logo, palette);		else			fb_set_logo_directpalette(info, fb_logo.logo, palette);		saved_pseudo_palette = info->pseudo_palette;		info->pseudo_palette = palette;	}	if (fb_logo.depth <= 4) {		logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, 				   GFP_KERNEL);		if (logo_new == NULL) {			if (palette)				kfree(palette);			if (saved_pseudo_palette)				info->pseudo_palette = saved_pseudo_palette;			return 0;		}		image.data = logo_new;		fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);	}	image.width = fb_logo.logo->width;	image.height = fb_logo.logo->height;	image.dy = 0;	for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) &&	     x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {		image.dx = x;		info->fbops->fb_imageblit(info, &image);	}		if (palette != NULL)

⌨️ 快捷键说明

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