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

📄 fbmem.2.6

📁 S3C2410的SM501驱动程序
💻 6
📖 第 1 页 / 共 3 页
字号:
	}
	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 __init 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, 1, info);
	}
}

static void  __init 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 __init 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 __init fb_set_logo(struct fb_info *info,
			       const struct linux_logo *logo, u8 *dst,
			       int depth)
{
	int i, j, shift;
	const u8 *src = logo->data;
	u8 d, xor = 0;

	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:
		xor = 0xff;
	case 1:
		for (i = 0; i < logo->height; i++) {
			shift = 7;
			d = *src++ ^ xor;
			for (j = 0; j < logo->width; j++) {
				*dst++ = (d >> shift) & 1;
				shift = (shift-1) & 7;
				if (shift == 7)
					d = *src++ ^ xor;
			}
		}
		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)
{
	memset(&fb_logo, 0, sizeof(struct logo_data));

	switch (info->fix.visual) {
	case FB_VISUAL_TRUECOLOR:
		if (info->var.bits_per_pixel >= 8)
			fb_logo.needs_truepalette = 1;
		break;
	case FB_VISUAL_DIRECTCOLOR:
		if (info->var.bits_per_pixel >= 24) {
			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(info->var.bits_per_pixel);
	
	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 = fb_logo.depth;
	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)
		kfree(palette);
	if (saved_pseudo_palette != NULL)
		info->pseudo_palette = saved_pseudo_palette;
	if (logo_new != NULL)
		kfree(logo_new);
	return fb_logo.logo->height;
}
#else
int fb_prepare_logo(struct fb_info *info) { return 0; }
int fb_show_logo(struct fb_info *info) { return 0; }
#endif /* CONFIG_LOGO */

static int fbmem_read_proc(char *buf, char **start, off_t offset,
			   int len, int *eof, void *private)
{
	struct fb_info **fi;
	int clen;

	clen = 0;
	for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
		if (*fi)
			clen += sprintf(buf + clen, "%d %s\n",
				        (*fi)->node,
				        (*fi)->fix.id);
	*start = buf + offset;
	if (clen > offset)
		clen -= offset;
	else
		clen = 0;
	return clen < len ? clen : len;
}

static ssize_t
fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
	unsigned long p = *ppos;
	struct inode *inode = file->f_dentry->d_inode;
	int fbidx = iminor(inode);
	struct fb_info *info = registered_fb[fbidx];

	if (!info || ! info->screen_base)
		return -ENODEV;

	if (info->state != FBINFO_STATE_RUNNING)
		return -EPERM;

	if (info->fbops->fb_read)
		return info->fbops->fb_read(file, buf, count, ppos);
	
	if (p >= info->fix.smem_len)
	    return 0;
	if (count >= info->fix.smem_len)
	    count = info->fix.smem_len;
	if (count + p > info->fix.smem_len)
		count = info->fix.smem_len - p;
	if (info->fbops->fb_sync)
		info->fbops->fb_sync(info);
	if (count) {
	    char *base_addr;

	    base_addr = info->screen_base;
	    count -= copy_to_user(buf, base_addr+p, count);
	    if (!count)
		return -EFAULT;
	    *ppos += count;
	}
	return count;
}

static ssize_t
fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
	unsigned long p = *ppos;
	struct inode *inode = file->f_dentry->d_inode;
	int fbidx = iminor(inode);
	struct fb_info *info = registered_fb[fbidx];
	int err;

	if (!info || !info->screen_base)
		return -ENODEV;

	if (info->state != FBINFO_STATE_RUNNING)
		return -EPERM;

	if (info->fbops->fb_write)
		return info->fbops->fb_write(file, buf, count, ppos);
	
	if (p > info->fix.smem_len)
	    return -ENOSPC;
	if (count >= info->fix.smem_len)
	    count = info->fix.smem_len;
	err = 0;
	if (count + p > info->fix.smem_len) {
	    count = info->fix.smem_len - p;
	    err = -ENOSPC;
	}
	if (info->fbops->fb_sync)
		info->fbops->fb_sync(info);
	if (count) {
	    char *base_addr;

	    base_addr = info->screen_base;
	    count -= copy_from_user(base_addr+p, buf, count);
	    *ppos += count;
	    err = -EFAULT;
	}
	if (count)
		return count;
	return err;
}

#ifdef CONFIG_KMOD
static void try_to_load(int fb)
{
	request_module("fb%d", fb);
}
#endif /* CONFIG_KMOD */

void
fb_load_cursor_image(struct fb_info *info)
{
	unsigned int width = (info->cursor.image.width + 7) >> 3;
	u8 *data = (u8 *) info->cursor.image.data;

	info->sprite.outbuf(info, info->sprite.addr, data, width);
}

int
fb_cursor(struct fb_info *info, struct fb_cursor *sprite)
{
	struct fb_cursor cursor;
	int err;
	
	if (copy_from_user(&cursor, sprite, sizeof(struct fb_cursor)))
		return -EFAULT;

	if (cursor.set & FB_CUR_SETCUR)
		info->cursor.enable = 1;
	
	if (cursor.set & FB_CUR_SETCMAP) {
		err = fb_copy_cmap(&cursor.image.cmap, &sprite->image.cmap, 1);
		if (err)
			return err;
	}
	
	if (cursor.set & FB_CUR_SETSHAPE) {
		int size = ((cursor.image.width + 7) >> 3) * cursor.image.height;		
		if ((cursor.image.height != info->cursor.image.height) ||
		    (cursor.image.width != info->cursor.image.width))
			cursor.set |= FB_CUR_SETSIZE;
		
		cursor.image.data = kmalloc(size, GFP_KERNEL);
		if (!cursor.image.data)
			return -ENOMEM;
		
		cursor.mask = kmalloc(size, GFP_KERNEL);
		if (!cursor.mask) {
			kfree(cursor.image.data);
			return -ENOMEM;
		}
		
		if (copy_from_user(&cursor.image.data, sprite->image.data, size) ||
		    copy_from_user(cursor.mask, sprite->mask, size)) { 
			kfree(cursor.image.data);
			kfree(cursor.mask);
			return -EFAULT;
		}
	}
	info->cursor.set = cursor.set;
	info->cursor.rop = cursor.rop;
	err = info->fbops->fb_cursor(info, &cursor);
	return err;
}

int
fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
{
        int xoffset = var->xoffset;
        int yoffset = var->yoffset;
        int err;

        if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display ||
            xoffset + info->var.xres > info->var.xres_virtual ||
            yoffset + info->var.yres > info->var.yres_virtual)
                return -EINVAL;
	if ((err = info->fbops->fb_pan_display(var, info)))
		return err;
        info->var.xoffset = var->xoffset;
        info->var.yoffset = var->yoffset;
        if (var->vmode & FB_VMODE_YWRAP)
                info->var.vmode |= FB_VMODE_YWRAP;
        else
                info->var.vmode &= ~FB_VMODE_YWRAP;
        return 0;
}

int
fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{
	int err;

	if ((var->activate & FB_ACTIVATE_FORCE) ||
	    memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
		if (!info->fbops->fb_check_var) {
			*var = info->var;
			return 0;
		}

		if ((err = info->fbops->fb_check_var(var, info)))
			return err;

		if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
			info->var = *var;

			if (info->fbops->fb_set_par)
				info->fbops->fb_set_par(info);

			fb_pan_display(info, &info->var);

			fb_set_cmap(&info->cmap, 1, info);

			notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, info);
		}
	}
	return 0;
}

int
fb_blank(struct fb_info *info, int blank)
{	
	/* ??? Variable sized stack allocation.  */
	u16 black[info->cmap.len];
	struct fb_cmap cmap;
	
	if (info->fbops->fb_blank && !info->fbops->fb_blank(blank, info))
		return 0;
	if (blank) { 
		memset(black, 0, info->cmap.len * sizeof(u16));
		cmap.red = cmap.green = cmap.blue = black;
		cmap.transp = info->cmap.transp ? black : NULL;
		cmap.start = info->cmap.start;
		cmap.len = info->cmap.len;
	} else
		cmap = info->cmap;

⌨️ 快捷键说明

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