⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fbmem.c

📁 linux lcd 的标准接口
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  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/module.h>#include <linux/compat.h>#include <linux/types.h>#include <linux/errno.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/vt.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/err.h>#include <linux/device.h>#include <linux/efi.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	(1024 * 8)struct fb_info *registered_fb[FB_MAX] __read_mostly;int num_registered_fb __read_mostly;/* * Helpers */int fb_get_color_depth(struct fb_var_screeninfo *var,		       struct fb_fix_screeninfo *fix){	int depth = 0;	if (fix->visual == FB_VISUAL_MONO01 ||	    fix->visual == FB_VISUAL_MONO10)		depth = 1;	else {		if (var->green.length == var->blue.length &&		    var->green.length == var->red.length &&		    var->green.offset == var->blue.offset &&		    var->green.offset == var->red.offset)			depth = var->green.length;		else			depth = var->green.length + var->red.length +				var->blue.length;	}	return depth;}EXPORT_SYMBOL(fb_get_color_depth);/* * Data padding functions. */void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height){	__fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);}EXPORT_SYMBOL(fb_pad_aligned_buffer);void fb_pad_unaligned_buffer(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;	}}EXPORT_SYMBOL(fb_pad_unaligned_buffer);/* * 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_LOGOstatic 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){	static const unsigned char mask[] = { 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;	const u8 *src = logo->data;	u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;	u8 fg = 1, d;	if (fb_get_color_depth(&info->var, &info->fix) == 3)		fg = 7;	if (info->fix.visual == FB_VISUAL_MONO01 ||	    info->fix.visual == FB_VISUAL_MONO10)		fg = ~((u8) (0xfff << info->var.green.length));	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 __read_mostly;static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height){	u32 size = width * height, i;	out += size - 1;	for (i = size; i--; )		*out-- = *in++;}static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height){	int i, j, h = height - 1;	for (i = 0; i < height; i++)		for (j = 0; j < width; j++)				out[height * j + h - i] = *in++;}static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height){	int i, j, w = width - 1;	for (i = 0; i < height; i++)		for (j = 0; j < width; j++)			out[height * (w - j) + i] = *in++;}static void fb_rotate_logo(struct fb_info *info, u8 *dst,			   struct fb_image *image, int rotate){	u32 tmp;	if (rotate == FB_ROTATE_UD) {		fb_rotate_logo_ud(image->data, dst, image->width,				  image->height);		image->dx = info->var.xres - image->width - image->dx;		image->dy = info->var.yres - image->height - image->dy;	} else if (rotate == FB_ROTATE_CW) {		fb_rotate_logo_cw(image->data, dst, image->width,				  image->height);		tmp = image->width;		image->width = image->height;		image->height = tmp;		tmp = image->dy;		image->dy = image->dx;		image->dx = info->var.xres - image->width - tmp;	} else if (rotate == FB_ROTATE_CCW) {		fb_rotate_logo_ccw(image->data, dst, image->width,				   image->height);		tmp = image->width;		image->width = image->height;		image->height = tmp;		tmp = image->dx;		image->dx = image->dy;		image->dy = info->var.yres - image->height - tmp;	}	image->data = dst;}static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,			    int rotate, unsigned int num){	unsigned int x;	if (rotate == FB_ROTATE_UR) {		for (x = 0;		     x < num && image->dx + image->width <= info->var.xres;		     x++) {			info->fbops->fb_imageblit(info, image);			image->dx += image->width + 8;		}	} else if (rotate == FB_ROTATE_UD) {		for (x = 0; x < num && image->dx >= 0; x++) {			info->fbops->fb_imageblit(info, image);			image->dx -= image->width + 8;		}	} else if (rotate == FB_ROTATE_CW) {		for (x = 0;		     x < num && image->dy + image->height <= info->var.yres;		     x++) {			info->fbops->fb_imageblit(info, image);			image->dy += image->height + 8;		}	} else if (rotate == FB_ROTATE_CCW) {		for (x = 0; x < num && image->dy >= 0; x++) {			info->fbops->fb_imageblit(info, image);			image->dy -= image->height + 8;		}	}}int fb_prepare_logo(struct fb_info *info, int rotate){	int depth = fb_get_color_depth(&info->var, &info->fix);	int yres;	memset(&fb_logo, 0, sizeof(struct logo_data));	if (info->flags & FBINFO_MISC_TILEBLITTING ||	    info->flags & FBINFO_MODULE)		return 0;	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 (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {		/* assume console colormap */		depth = 4;	}	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) {		return 0;	}		if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)		yres = info->var.yres;	else		yres = info->var.xres;	if (fb_logo.logo->height > 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, int rotate){	u32 *palette = NULL, *saved_pseudo_palette = NULL;	unsigned char *logo_new = NULL, *logo_rotate = NULL;	struct fb_image image;	/* Return if the frame buffer is not mapped or suspended */	if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING ||	    info->flags & FBINFO_MODULE)		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) {			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.dx = 0;	image.dy = 0;	image.width = fb_logo.logo->width;	image.height = fb_logo.logo->height;	if (rotate) {		logo_rotate = kmalloc(fb_logo.logo->width *				      fb_logo.logo->height, GFP_KERNEL);		if (logo_rotate)			fb_rotate_logo(info, logo_rotate, &image, rotate);	}	fb_do_show_logo(info, &image, rotate, num_online_cpus());	kfree(palette);	if (saved_pseudo_palette != NULL)		info->pseudo_palette = saved_pseudo_palette;	kfree(logo_new);	kfree(logo_rotate);	return fb_logo.logo->height;}#elseint fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }int fb_show_logo(struct fb_info *info, int rotate) { return 0; }#endif /* CONFIG_LOGO */

⌨️ 快捷键说明

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