fbgen.c 6.63 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5
/*
 * linux/drivers/video/fbgen.c -- Generic routines for frame buffer devices
 *
 *  Created 3 Jan 1998 by Geert Uytterhoeven
 *
Linus Torvalds's avatar
Linus Torvalds committed
6 7 8
 *	2001 - Documented with DocBook
 *	- Brad Douglas <brad@neruo.com>
 *
Linus Torvalds's avatar
Linus Torvalds committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * 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/string.h>
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/slab.h>

#include <asm/uaccess.h>
#include <asm/io.h>

#include <video/fbcon.h>
James Simmons's avatar
James Simmons committed
24 25 26 27 28 29 30 31
#include <video/fbcon-mfb.h>
#include <video/fbcon-cfb2.h>
#include <video/fbcon-cfb4.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
#include "fbcon-accel.h"
Linus Torvalds's avatar
Linus Torvalds committed
32

James Simmons's avatar
James Simmons committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
int gen_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
	int err;

	if (con < 0 || (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 (con == info->currcon) {
				if (info->fbops->fb_set_par)
					info->fbops->fb_set_par(info);

				if (info->fbops->fb_pan_display)
					info->fbops->fb_pan_display(&info->var, con, info);

				gen_set_disp(con, info);
				fb_set_cmap(&info->cmap, 1, info);
			}
		
			if (info->changevar)
				info->changevar(con);
		}
	}
	return 0;
}

67 68 69 70 71
int gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
{
	fb_copy_cmap (&info->cmap, cmap, kspc ? 0 : 2);
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
72

James Simmons's avatar
James Simmons committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
int gen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
		 struct fb_info *info)
{
	struct display *disp = (con < 0) ? info->disp : (fb_display + con);
	struct fb_cmap *dcmap = &disp->cmap;
	int err = 0;

	/* No colormap allocated ? */
	if (!dcmap->len) {
		int size = info->cmap.len;

		err = fb_alloc_cmap(dcmap, size, 0);
	}
 	

	if (!err && con == info->currcon) {
		err = fb_set_cmap(cmap, kspc, info);
		dcmap = &info->cmap;
	}
	
	if (!err)
		fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
	return err;
}
Linus Torvalds's avatar
Linus Torvalds committed
97 98 99 100 101 102 103 104

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

105 106 107
    if (xoffset < 0 || yoffset < 0 || 
	xoffset + info->var.xres > info->var.xres_virtual ||
	yoffset + info->var.yres > info->var.yres_virtual)
Linus Torvalds's avatar
Linus Torvalds committed
108
	return -EINVAL;
109
    if (con == info->currcon) {
110 111
	if (info->fbops->fb_pan_display) {
	    if ((err = info->fbops->fb_pan_display(var, con, info)))
Linus Torvalds's avatar
Linus Torvalds committed
112 113 114 115
		return err;
	} else
	    return -EINVAL;
    }
116 117
    info->var.xoffset = var->xoffset;
    info->var.yoffset = var->yoffset;
Linus Torvalds's avatar
Linus Torvalds committed
118
    if (var->vmode & FB_VMODE_YWRAP)
119
	info->var.vmode |= FB_VMODE_YWRAP;
Linus Torvalds's avatar
Linus Torvalds committed
120
    else
121
	info->var.vmode &= ~FB_VMODE_YWRAP;
Linus Torvalds's avatar
Linus Torvalds committed
122 123 124 125 126 127
    return 0;
}


/* ---- Helper functions --------------------------------------------------- */

James Simmons's avatar
James Simmons committed
128 129
void gen_set_disp(int con, struct fb_info *info)
{
130
	struct display *display = (con < 0) ? info->disp : (fb_display + con);
James Simmons's avatar
James Simmons committed
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR ||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
		display->can_soft_blank = info->fbops->fb_blank ? 1 : 0;
		display->dispsw_data = NULL;
	} else {
		display->can_soft_blank = 0;
		display->dispsw_data = info->pseudo_palette;
	}
	display->var = info->var;

	/*
	 * If we are setting all the virtual consoles, also set
	 * the defaults used to create new consoles.
	 */
	if (con < 0 || info->var.activate & FB_ACTIVATE_ALL)
		info->disp->var = info->var;	

	if (info->var.bits_per_pixel == 24) {
#ifdef FBCON_HAS_CFB24
		display->scrollmode = SCROLL_YREDRAW;		
		display->dispsw = &fbcon_cfb24;
		return;
#endif
	}

#ifdef FBCON_HAS_ACCEL
	display->scrollmode = SCROLL_YNOMOVE;
	display->dispsw = &fbcon_accel;
James Simmons's avatar
James Simmons committed
160 161
#else
	display->dispsw = &fbcon_dummy;
James Simmons's avatar
James Simmons committed
162 163 164
#endif
	return;
}
Linus Torvalds's avatar
Linus Torvalds committed
165

Linus Torvalds's avatar
Linus Torvalds committed
166
/**
167
 *	do_install_cmap - install the current colormap
Linus Torvalds's avatar
Linus Torvalds committed
168 169 170 171 172 173 174
 *	@con: virtual console number
 *	@info: generic frame buffer info structure
 *
 *	Installs the current colormap for virtual console @con on
 *	device @info.
 *
 */
Linus Torvalds's avatar
Linus Torvalds committed
175

176
void do_install_cmap(int con, struct fb_info *info)
Linus Torvalds's avatar
Linus Torvalds committed
177
{
178
    if (con != info->currcon)
Linus Torvalds's avatar
Linus Torvalds committed
179 180
	return;
    if (fb_display[con].cmap.len)
181
	fb_set_cmap(&fb_display[con].cmap, 1, info);
Linus Torvalds's avatar
Linus Torvalds committed
182 183
    else {
	int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
184
	fb_set_cmap(fb_default_cmap(size), 1, info);
Linus Torvalds's avatar
Linus Torvalds committed
185 186 187
    }
}

James Simmons's avatar
James Simmons committed
188 189
int gen_update_var(int con, struct fb_info *info)
{
190
	struct display *disp = (con < 0) ? info->disp : (fb_display + con);
James Simmons's avatar
James Simmons committed
191 192 193
	int err;
    
	if (con == info->currcon) {
194 195 196
		info->var.xoffset = disp->var.xoffset;
		info->var.yoffset = disp->var.yoffset;
		info->var.vmode	= disp->var.vmode;	
James Simmons's avatar
James Simmons committed
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
		if (info->fbops->fb_pan_display) {
			if ((err = info->fbops->fb_pan_display(&info->var, con, info)))
				return err;
		}
	}	
	return 0;
}

int gen_switch(int con, struct fb_info *info)
{
	struct display *disp;
	struct fb_cmap *cmap;
	
	if (info->currcon >= 0) {
		disp = fb_display + info->currcon;
	
		/*
		 * Save the old colormap and graphics mode.
		 */
		disp->var = info->var;
		if (disp->cmap.len)
			fb_copy_cmap(&info->cmap, &disp->cmap, 0);
	}
	
	info->currcon = con;
	disp = fb_display + con;
	
	/*
	 * Install the new colormap and change the graphics mode. By default
	 * fbcon sets all the colormaps and graphics modes to the default
	 * values at bootup.
	 *
	 * Really, we want to set the colormap size depending on the
	 * depth of the new grpahics mode. For now, we leave it as its
	 * default 256 entry.
	 */
	if (disp->cmap.len)
		cmap = &disp->cmap;
	else
		cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
	
	fb_copy_cmap(cmap, &info->cmap, 0);
	
	disp->var.activate = FB_ACTIVATE_NOW;
	info->fbops->fb_set_var(&disp->var, con, info);
 	return 0;	  	
}

Linus Torvalds's avatar
Linus Torvalds committed
245 246 247 248 249 250 251 252
/**
 *	fbgen_blank - blank the screen
 *	@blank: boolean, 0 unblank, 1 blank
 *	@info: frame buffer info structure
 *
 *	Blank the screen on device @info.
 *
 */
Linus Torvalds's avatar
Linus Torvalds committed
253

254
int fbgen_blank(int blank, struct fb_info *info)
Linus Torvalds's avatar
Linus Torvalds committed
255 256
{
    struct fb_cmap cmap;
257 258 259
    u16 black[16];
    
    if (info->fbops->fb_blank && !info->fbops->fb_blank(blank, info))
James Simmons's avatar
James Simmons committed
260
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
261 262 263 264 265 266 267 268
    if (blank) {
	memset(black, 0, 16*sizeof(u16));
	cmap.red = black;
	cmap.green = black;
	cmap.blue = black;
	cmap.transp = NULL;
	cmap.start = 0;
	cmap.len = 16;
269
	fb_set_cmap(&cmap, 1, info);
Linus Torvalds's avatar
Linus Torvalds committed
270
    } else
271
	do_install_cmap(info->currcon, info);
272
    return 0;	
Linus Torvalds's avatar
Linus Torvalds committed
273
}
274

James Simmons's avatar
James Simmons committed
275 276
/* generic frame buffer operations */
EXPORT_SYMBOL(gen_set_var);
277
EXPORT_SYMBOL(gen_get_cmap);
278
EXPORT_SYMBOL(gen_set_cmap);
279 280
EXPORT_SYMBOL(fbgen_pan_display);
/* helper functions */
281
EXPORT_SYMBOL(do_install_cmap);
James Simmons's avatar
James Simmons committed
282 283
EXPORT_SYMBOL(gen_update_var);
EXPORT_SYMBOL(gen_switch);
284 285
EXPORT_SYMBOL(fbgen_blank);

Linus Torvalds's avatar
Linus Torvalds committed
286
MODULE_LICENSE("GPL");