Skip to content
fbmem.c 32.8 KiB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
/*
 *  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>
#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)

static 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_var_screeninfo *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;
Loading
Loading full blame...