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

📄 fbmem.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
		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, 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:#ifndef	CONFIG_LOGO_LINUX_TFT16			if (info->var.bits_per_pixel >= 8)			fb_logo.needs_truepalette = 1;#endif		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_TFT16)		fb_logo.depth = 16;	else 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;#ifndef	CONFIG_LOGO_LINUX_TFT16		info->fbops->fb_imageblit(info, &image);#else		image.dy = 0;		for(; image.dy<image.height&&image.dy<info->var.yres; image.dy++)			memcpy(info->screen_base+info->fix.line_length*image.dy+image.dx*2, image.data+image.dy*image.width*2, image.width*2);#endif	}		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;}#elseint 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_tfb_read(struct file *file, char __user *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_tfb_write(struct file *file, const char __user *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_KMODstatic void try_to_load(int fb){	request_module("fb%d", fb);}#endif /* CONFIG_KMOD */voidfb_load_cursor_image(struct fb_info *info){	unsigned int width = (info->cursor.image.width + 7) >> 3;	u8 *data = (u8 *) info->cursor.image.data;	if (info->sprite.outbuf)	    info->sprite.outbuf(info, info->sprite.addr, data, width);	else	    memcpy(info->sprite.addr, data, width);}intfb_cursor(struct fb_info *info, struct fb_cursor_user __user *sprite){	struct fb_cursor_user cursor_user;	struct fb_cursor cursor;	char *data = NULL, *mask = NULL;	u16 *red = NULL, *green = NULL, *blue = NULL, *transp = NULL;	int err = -EINVAL;		if (copy_from_user(&cursor_user, sprite, sizeof(struct fb_cursor_user)))		return -EFAULT;	memcpy(&cursor, &cursor_user, sizeof(cursor));	cursor.mask = NULL;	cursor.image.data = NULL;	cursor.image.cmap.red = NULL;	cursor.image.cmap.green = NULL;	cursor.image.cmap.blue = NULL;	cursor.image.cmap.transp = NULL;	if (cursor.set & FB_CUR_SETCUR)		info->cursor.enable = 1;		if (cursor.set & FB_CUR_SETCMAP) {		unsigned len = cursor.image.cmap.len;		if ((int)len <= 0)			goto out;		len *= 2;		err = -ENOMEM;		red = kmalloc(len, GFP_USER);		green = kmalloc(len, GFP_USER);		blue = kmalloc(len, GFP_USER);		if (!red || !green || !blue)			goto out;		if (cursor_user.image.cmap.transp) {			transp = kmalloc(len, GFP_USER);			if (!transp)				goto out;		}		err = -EFAULT;		if (copy_from_user(red, cursor_user.image.cmap.red, len))			goto out;		if (copy_from_user(green, cursor_user.image.cmap.green, len))			goto out;		if (copy_from_user(blue, cursor_user.image.cmap.blue, len))			goto out;		if (transp) {			if (copy_from_user(transp,					   cursor_user.image.cmap.transp, len))				goto out;		}		cursor.image.cmap.red = red;		cursor.image.cmap.green = green;		cursor.image.cmap.blue = blue;		cursor.image.cmap.transp = transp;	}		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;				err = -ENOMEM;		data = kmalloc(size, GFP_USER);		mask = kmalloc(size, GFP_USER);		if (!mask || !data)			goto out;				err = -EFAULT;		if (copy_from_user(data, cursor_user.image.data, size) ||		    copy_from_user(mask, cursor_user.mask, size))			goto out;				cursor.image.data = data;		cursor.mask = mask;	}	info->cursor.set = cursor.set;	info->cursor.rop = cursor.rop;	err = info->fbops->fb_cursor(info, &cursor);out:	kfree(data);	kfree(mask);	kfree(red);	kfree(green);	kfree(blue);	kfree(transp);	return err;}intfb_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;}intfb_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);

⌨️ 快捷键说明

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