1 /*
2  * framebuffer driver for VBE 2.0 compliant graphic boards
3  *
4  * switching to graphics mode happens at boot time (while
5  * running in real mode, see arch/i386/boot/video.S).
6  *
7  * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
8  *
9  */
10 
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/string.h>
15 #include <linux/mm.h>
16 #include <linux/tty.h>
17 #include <linux/slab.h>
18 #include <linux/delay.h>
19 #include <linux/fb.h>
20 #include <linux/console.h>
21 #include <linux/selection.h>
22 #include <linux/ioport.h>
23 #include <linux/init.h>
24 
25 #include <asm/io.h>
26 #include <asm/mtrr.h>
27 
28 #include <video/fbcon.h>
29 #include <video/fbcon-cfb8.h>
30 #include <video/fbcon-cfb16.h>
31 #include <video/fbcon-cfb24.h>
32 #include <video/fbcon-cfb32.h>
33 #include <video/fbcon-mac.h>
34 
35 #define dac_reg	(0x3c8)
36 #define dac_val	(0x3c9)
37 
38 /* --------------------------------------------------------------------- */
39 
40 /*
41  * card parameters
42  */
43 
44 /* card */
45 unsigned long video_base; /* physical addr */
46 int   video_size;
47 char *video_vbase;        /* mapped */
48 
49 /* mode */
50 static int  video_bpp;
51 static int  video_width;
52 static int  video_height;
53 static int  video_height_virtual;
54 static int  video_type = FB_TYPE_PACKED_PIXELS;
55 static int  video_visual;
56 static int  video_linelength;
57 static int  video_cmap_len;
58 
59 /* --------------------------------------------------------------------- */
60 
61 static struct fb_var_screeninfo vesafb_defined = {
62 	0,0,0,0,	/* W,H, W, H (virtual) load xres,xres_virtual*/
63 	0,0,		/* virtual -> visible no offset */
64 	8,		/* depth -> load bits_per_pixel */
65 	0,		/* greyscale ? */
66 	{0,0,0},	/* R */
67 	{0,0,0},	/* G */
68 	{0,0,0},	/* B */
69 	{0,0,0},	/* transparency */
70 	0,		/* standard pixel format */
71 	FB_ACTIVATE_NOW,
72 	-1,-1,
73 	0,
74 	0L,0L,0L,0L,0L,
75 	0L,0L,0,	/* No sync info */
76 	FB_VMODE_NONINTERLACED,
77 	{0,0,0,0,0,0}
78 };
79 
80 static struct display disp;
81 static struct fb_info fb_info;
82 static struct { u_short blue, green, red, pad; } palette[256];
83 static union {
84 #ifdef FBCON_HAS_CFB16
85     u16 cfb16[16];
86 #endif
87 #ifdef FBCON_HAS_CFB24
88     u32 cfb24[16];
89 #endif
90 #ifdef FBCON_HAS_CFB32
91     u32 cfb32[16];
92 #endif
93 } fbcon_cmap;
94 
95 static int             inverse   = 0;
96 #ifdef __x86_64__
97 static int             mtrr      = 1;
98 #else
99 static int             mtrr      = 0;
100 #endif
101 static int	 vram __initdata = 0;	/* needed for vram boot option */
102 static int             currcon   = 0;
103 
104 static int             pmi_setpal = 0;	/* pmi for palette changes ??? */
105 static int             ypan       = 0;  /* 0..nothing, 1..ypan, 2..ywrap */
106 static unsigned short  *pmi_base  = 0;
107 static void            (*pmi_start)(void);
108 static void            (*pmi_pal)(void);
109 
110 static struct display_switch vesafb_sw;
111 
112 /* --------------------------------------------------------------------- */
113 
vesafb_pan_display(struct fb_var_screeninfo * var,int con,struct fb_info * info)114 static int vesafb_pan_display(struct fb_var_screeninfo *var, int con,
115                               struct fb_info *info)
116 {
117 #ifdef __i386__
118 	int offset;
119 
120 	if (!ypan)
121 		return -EINVAL;
122 	if (var->xoffset)
123 		return -EINVAL;
124 	if (var->yoffset > var->yres_virtual)
125 		return -EINVAL;
126 	if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual)
127 		return -EINVAL;
128 
129 	offset = (var->yoffset * video_linelength + var->xoffset) / 4;
130 
131         __asm__ __volatile__(
132                 "call *(%%edi)"
133                 : /* no return value */
134                 : "a" (0x4f07),         /* EAX */
135                   "b" (0),              /* EBX */
136                   "c" (offset),         /* ECX */
137                   "d" (offset >> 16),   /* EDX */
138                   "D" (&pmi_start));    /* EDI */
139 #endif
140 	return 0;
141 }
142 
vesafb_update_var(int con,struct fb_info * info)143 static int vesafb_update_var(int con, struct fb_info *info)
144 {
145 	if (con == currcon && ypan) {
146 		struct fb_var_screeninfo *var = &fb_display[currcon].var;
147 		return vesafb_pan_display(var,con,info);
148 	}
149 	return 0;
150 }
151 
vesafb_get_fix(struct fb_fix_screeninfo * fix,int con,struct fb_info * info)152 static int vesafb_get_fix(struct fb_fix_screeninfo *fix, int con,
153 			 struct fb_info *info)
154 {
155 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
156 	strcpy(fix->id,"VESA VGA");
157 
158 	fix->smem_start=video_base;
159 	fix->smem_len=video_size;
160 	fix->type = video_type;
161 	fix->visual = video_visual;
162 	fix->xpanstep  = 0;
163 	fix->ypanstep  = ypan     ? 1 : 0;
164 	fix->ywrapstep = (ypan>1) ? 1 : 0;
165 	fix->line_length=video_linelength;
166 	return 0;
167 }
168 
vesafb_get_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)169 static int vesafb_get_var(struct fb_var_screeninfo *var, int con,
170 			 struct fb_info *info)
171 {
172 	if(con==-1)
173 		memcpy(var, &vesafb_defined, sizeof(struct fb_var_screeninfo));
174 	else
175 		*var=fb_display[con].var;
176 	return 0;
177 }
178 
vesafb_set_disp(int con)179 static void vesafb_set_disp(int con)
180 {
181 	struct fb_fix_screeninfo fix;
182 	struct display *display;
183 	struct display_switch *sw;
184 
185 	if (con >= 0)
186 		display = &fb_display[con];
187 	else
188 		display = &disp;	/* used during initialization */
189 
190 	vesafb_get_fix(&fix, con, 0);
191 
192 	memset(display, 0, sizeof(struct display));
193 	display->screen_base = video_vbase;
194 	display->visual = fix.visual;
195 	display->type = fix.type;
196 	display->type_aux = fix.type_aux;
197 	display->ypanstep = fix.ypanstep;
198 	display->ywrapstep = fix.ywrapstep;
199 	display->line_length = fix.line_length;
200 	display->next_line = fix.line_length;
201 	display->can_soft_blank = 0;
202 	display->inverse = inverse;
203 	vesafb_get_var(&display->var, -1, &fb_info);
204 
205 	switch (video_bpp) {
206 #ifdef FBCON_HAS_CFB8
207 	case 8:
208 		sw = &fbcon_cfb8;
209 		break;
210 #endif
211 #ifdef FBCON_HAS_CFB16
212 	case 15:
213 	case 16:
214 		sw = &fbcon_cfb16;
215 		display->dispsw_data = fbcon_cmap.cfb16;
216 		break;
217 #endif
218 #ifdef FBCON_HAS_CFB24
219 	case 24:
220 		sw = &fbcon_cfb24;
221 		display->dispsw_data = fbcon_cmap.cfb24;
222 		break;
223 #endif
224 #ifdef FBCON_HAS_CFB32
225 	case 32:
226 		sw = &fbcon_cfb32;
227 		display->dispsw_data = fbcon_cmap.cfb32;
228 		break;
229 #endif
230 	default:
231 #ifdef FBCON_HAS_MAC
232 		sw = &fbcon_mac;
233 		break;
234 #else
235 		sw = &fbcon_dummy;
236 		return;
237 #endif
238 	}
239 	memcpy(&vesafb_sw, sw, sizeof(*sw));
240 	display->dispsw = &vesafb_sw;
241 	if (!ypan) {
242 		display->scrollmode = SCROLL_YREDRAW;
243 		vesafb_sw.bmove = fbcon_redraw_bmove;
244 	}
245 }
246 
vesafb_set_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)247 static int vesafb_set_var(struct fb_var_screeninfo *var, int con,
248 			  struct fb_info *info)
249 {
250 	static int first = 1;
251 
252 	if (var->xres           != vesafb_defined.xres           ||
253 	    var->yres           != vesafb_defined.yres           ||
254 	    var->xres_virtual   != vesafb_defined.xres_virtual   ||
255 	    var->yres_virtual   >  video_height_virtual          ||
256 	    var->yres_virtual   <  video_height                  ||
257 	    var->xoffset                                         ||
258 	    var->bits_per_pixel != vesafb_defined.bits_per_pixel ||
259 	    var->nonstd) {
260 		if (first) {
261 			printk(KERN_ERR "Vesafb does not support changing the video mode\n");
262 			first = 0;
263 		}
264 		return -EINVAL;
265 	}
266 
267 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
268 		return 0;
269 
270 	if (ypan) {
271 		if (vesafb_defined.yres_virtual != var->yres_virtual) {
272 			vesafb_defined.yres_virtual = var->yres_virtual;
273 			if (con != -1) {
274 				fb_display[con].var = vesafb_defined;
275 				info->changevar(con);
276 			}
277 		}
278 
279 		if (var->yoffset != vesafb_defined.yoffset)
280 			return vesafb_pan_display(var,con,info);
281 		return 0;
282 	}
283 
284 	if (var->yoffset)
285 		return -EINVAL;
286 	return 0;
287 }
288 
vesa_getcolreg(unsigned regno,unsigned * red,unsigned * green,unsigned * blue,unsigned * transp,struct fb_info * fb_info)289 static int vesa_getcolreg(unsigned regno, unsigned *red, unsigned *green,
290 			  unsigned *blue, unsigned *transp,
291 			  struct fb_info *fb_info)
292 {
293 	/*
294 	 *  Read a single color register and split it into colors/transparent.
295 	 *  Return != 0 for invalid regno.
296 	 */
297 
298 	if (regno >= video_cmap_len)
299 		return 1;
300 
301 	*red   = palette[regno].red;
302 	*green = palette[regno].green;
303 	*blue  = palette[regno].blue;
304 	*transp = 0;
305 	return 0;
306 }
307 
308 #ifdef FBCON_HAS_CFB8
309 
vesa_setpalette(int regno,unsigned red,unsigned green,unsigned blue)310 static void vesa_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
311 {
312 #ifdef i386
313 	struct { u_char blue, green, red, pad; } entry;
314 
315 	if (pmi_setpal) {
316 		entry.red   = red   >> 10;
317 		entry.green = green >> 10;
318 		entry.blue  = blue  >> 10;
319 		entry.pad   = 0;
320 	        __asm__ __volatile__(
321                 "call *(%%esi)"
322                 : /* no return value */
323                 : "a" (0x4f09),         /* EAX */
324                   "b" (0),              /* EBX */
325                   "c" (1),              /* ECX */
326                   "d" (regno),          /* EDX */
327                   "D" (&entry),         /* EDI */
328                   "S" (&pmi_pal));      /* ESI */
329 	} else {
330 		/* without protected mode interface, try VGA registers... */
331 		outb_p(regno,       dac_reg);
332 		outb_p(red   >> 10, dac_val);
333 		outb_p(green >> 10, dac_val);
334 		outb_p(blue  >> 10, dac_val);
335 	}
336 #endif
337 
338 }
339 
340 #endif
341 
vesa_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * fb_info)342 static int vesa_setcolreg(unsigned regno, unsigned red, unsigned green,
343 			  unsigned blue, unsigned transp,
344 			  struct fb_info *fb_info)
345 {
346 	/*
347 	 *  Set a single color register. The values supplied are
348 	 *  already rounded down to the hardware's capabilities
349 	 *  (according to the entries in the `var' structure). Return
350 	 *  != 0 for invalid regno.
351 	 */
352 
353 	if (regno >= video_cmap_len)
354 		return 1;
355 
356 	palette[regno].red   = red;
357 	palette[regno].green = green;
358 	palette[regno].blue  = blue;
359 
360 	switch (video_bpp) {
361 #ifdef FBCON_HAS_CFB8
362 	case 8:
363 		vesa_setpalette(regno,red,green,blue);
364 		break;
365 #endif
366 #ifdef FBCON_HAS_CFB16
367 	case 15:
368 	case 16:
369 		if (vesafb_defined.red.offset == 10) {
370 			/* 1:5:5:5 */
371 			fbcon_cmap.cfb16[regno] =
372 				((red   & 0xf800) >>  1) |
373 				((green & 0xf800) >>  6) |
374 				((blue  & 0xf800) >> 11);
375 		} else {
376 			/* 0:5:6:5 */
377 			fbcon_cmap.cfb16[regno] =
378 				((red   & 0xf800)      ) |
379 				((green & 0xfc00) >>  5) |
380 				((blue  & 0xf800) >> 11);
381 		}
382 		break;
383 #endif
384 #ifdef FBCON_HAS_CFB24
385 	case 24:
386 		red   >>= 8;
387 		green >>= 8;
388 		blue  >>= 8;
389 		fbcon_cmap.cfb24[regno] =
390 			(red   << vesafb_defined.red.offset)   |
391 			(green << vesafb_defined.green.offset) |
392 			(blue  << vesafb_defined.blue.offset);
393 		break;
394 #endif
395 #ifdef FBCON_HAS_CFB32
396 	case 32:
397 		red   >>= 8;
398 		green >>= 8;
399 		blue  >>= 8;
400 		fbcon_cmap.cfb32[regno] =
401 			(red   << vesafb_defined.red.offset)   |
402 			(green << vesafb_defined.green.offset) |
403 			(blue  << vesafb_defined.blue.offset);
404 		break;
405 #endif
406     }
407     return 0;
408 }
409 
do_install_cmap(int con,struct fb_info * info)410 static void do_install_cmap(int con, struct fb_info *info)
411 {
412 	if (con != currcon)
413 		return;
414 	if (fb_display[con].cmap.len)
415 		fb_set_cmap(&fb_display[con].cmap, 1, vesa_setcolreg, info);
416 	else
417 		fb_set_cmap(fb_default_cmap(video_cmap_len), 1, vesa_setcolreg,
418 			    info);
419 }
420 
vesafb_get_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)421 static int vesafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
422 			   struct fb_info *info)
423 {
424 	if (con == currcon) /* current console? */
425 		return fb_get_cmap(cmap, kspc, vesa_getcolreg, info);
426 	else if (fb_display[con].cmap.len) /* non default colormap? */
427 		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
428 	else
429 		fb_copy_cmap(fb_default_cmap(video_cmap_len),
430 		     cmap, kspc ? 0 : 2);
431 	return 0;
432 }
433 
vesafb_set_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)434 static int vesafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
435 			   struct fb_info *info)
436 {
437 	int err;
438 
439 	if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
440 		err = fb_alloc_cmap(&fb_display[con].cmap,video_cmap_len,0);
441 		if (err)
442 			return err;
443 	}
444 	if (con == currcon)			/* current console? */
445 		return fb_set_cmap(cmap, kspc, vesa_setcolreg, info);
446 	else
447 		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
448 	return 0;
449 }
450 
451 static struct fb_ops vesafb_ops = {
452 	owner:		THIS_MODULE,
453 	fb_get_fix:	vesafb_get_fix,
454 	fb_get_var:	vesafb_get_var,
455 	fb_set_var:	vesafb_set_var,
456 	fb_get_cmap:	vesafb_get_cmap,
457 	fb_set_cmap:	vesafb_set_cmap,
458 	fb_pan_display:	vesafb_pan_display,
459 };
460 
vesafb_setup(char * options)461 int __init vesafb_setup(char *options)
462 {
463 	char *this_opt;
464 
465 	fb_info.fontname[0] = '\0';
466 
467 	if (!options || !*options)
468 		return 0;
469 
470 	while ((this_opt = strsep(&options, ",")) != NULL) {
471 		if (!*this_opt) continue;
472 
473 		if (! strcmp(this_opt, "inverse"))
474 			inverse=1;
475 		else if (! strcmp(this_opt, "redraw"))
476 			ypan=0;
477 		else if (! strcmp(this_opt, "ypan"))
478 			ypan=1;
479 		else if (! strcmp(this_opt, "ywrap"))
480 			ypan=2;
481 		else if (! strcmp(this_opt, "vgapal"))
482 			pmi_setpal=0;
483 		else if (! strcmp(this_opt, "pmipal"))
484 			pmi_setpal=1;
485 		else if (! strcmp(this_opt, "mtrr"))
486 			mtrr=1;
487 		/* checks for vram boot option */
488 		else if (! strncmp(this_opt, "vram:", 5))
489 			vram = simple_strtoul(this_opt+5, NULL, 0);
490 
491 		else if (!strncmp(this_opt, "font:", 5))
492 			strcpy(fb_info.fontname, this_opt+5);
493 	}
494 	return 0;
495 }
496 
vesafb_switch(int con,struct fb_info * info)497 static int vesafb_switch(int con, struct fb_info *info)
498 {
499 	/* Do we have to save the colormap? */
500 	if (fb_display[currcon].cmap.len)
501 		fb_get_cmap(&fb_display[currcon].cmap, 1, vesa_getcolreg,
502 			    info);
503 
504 	currcon = con;
505 	/* Install new colormap */
506 	do_install_cmap(con, info);
507 	vesafb_update_var(con,info);
508 	return 1;
509 }
510 
511 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
512 
vesafb_blank(int blank,struct fb_info * info)513 static void vesafb_blank(int blank, struct fb_info *info)
514 {
515 	/* Not supported */
516 }
517 
vesafb_init(void)518 int __init vesafb_init(void)
519 {
520 	int i,j;
521 
522 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
523 		return -ENXIO;
524 
525 	video_base          = screen_info.lfb_base;
526 	video_bpp           = screen_info.lfb_depth;
527 	if (15 == video_bpp)
528 		video_bpp = 16;
529 	video_width         = screen_info.lfb_width;
530 	video_height        = screen_info.lfb_height;
531 	video_linelength    = screen_info.lfb_linelength;
532 
533 	/* remap memory according to videomode, multiply by 2 to get space for doublebuffering */
534 	video_size          = screen_info.lfb_width *	screen_info.lfb_height * video_bpp / 8 * 2;
535 
536 	/* check that we don't remap more memory than old cards have */
537 	if (video_size > screen_info.lfb_size * 65536)
538 		video_size = screen_info.lfb_size * 65536;
539 
540 	/* FIXME: Should we clip against declared size for banked devices ? */
541 
542 	/* sets video_size according to vram boot option */
543 	if (vram && vram * 1024 * 1024 != video_size)
544 		video_size = vram * 1024 * 1024;
545 
546 	video_visual = (video_bpp == 8) ?
547 		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
548 
549 #ifndef __i386__
550 	screen_info.vesapm_seg = 0;
551 #endif
552 
553 	if (!request_mem_region(video_base, video_size, "vesafb")) {
554 		printk(KERN_WARNING
555 		       "vesafb: abort, cannot reserve video memory at 0x%lx\n",
556 			video_base);
557 		/* We cannot make this fatal. Sometimes this comes from magic
558 		   spaces our resource handlers simply don't know about */
559 	}
560 
561         video_vbase = ioremap(video_base, video_size);
562 	if (!video_vbase) {
563 		release_mem_region(video_base, video_size);
564 		printk(KERN_ERR
565 		       "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
566 			video_size, video_base);
567 		return -EIO;
568 	}
569 
570 	printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
571 	       video_base, video_vbase, video_size/1024);
572 	printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
573 	       video_width, video_height, video_bpp, video_linelength, screen_info.pages);
574 
575 	if (screen_info.vesapm_seg) {
576 		printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n",
577 		       screen_info.vesapm_seg,screen_info.vesapm_off);
578 	}
579 
580 	if (screen_info.vesapm_seg < 0xc000)
581 		ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
582 
583 	if (ypan || pmi_setpal) {
584 		pmi_base  = (unsigned short*)bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
585 		pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
586 		pmi_pal   = (void*)((char*)pmi_base + pmi_base[2]);
587 		printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
588 		if (pmi_base[3]) {
589 			printk(KERN_INFO "vesafb: pmi: ports = ");
590 				for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++)
591 					printk("%x ",pmi_base[i]);
592 			printk("\n");
593 			if (pmi_base[i] != 0xffff) {
594 				/*
595 				 * memory areas not supported (yet?)
596 				 *
597 				 * Rules are: we have to set up a descriptor for the requested
598 				 * memory area and pass it in the ES register to the BIOS function.
599 				 */
600 				printk(KERN_INFO "vesafb: can't handle memory requests, pmi disabled\n");
601 				ypan = pmi_setpal = 0;
602 			}
603 		}
604 	}
605 
606 	vesafb_defined.xres=video_width;
607 	vesafb_defined.yres=video_height;
608 	vesafb_defined.xres_virtual=video_width;
609 	vesafb_defined.yres_virtual=video_size / video_linelength;
610 	vesafb_defined.bits_per_pixel=video_bpp;
611 
612 	if (ypan && vesafb_defined.yres_virtual > video_height) {
613 		printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n",
614 		       (ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
615 	} else {
616 		printk(KERN_INFO "vesafb: scrolling: redraw\n");
617 		vesafb_defined.yres_virtual = video_height;
618 		ypan = 0;
619 	}
620 	video_height_virtual = vesafb_defined.yres_virtual;
621 
622 	/* some dummy values for timing to make fbset happy */
623 	vesafb_defined.pixclock     = 10000000 / video_width * 1000 / video_height;
624 	vesafb_defined.left_margin  = (video_width / 8) & 0xf8;
625 	vesafb_defined.right_margin = 32;
626 	vesafb_defined.upper_margin = 16;
627 	vesafb_defined.lower_margin = 4;
628 	vesafb_defined.hsync_len    = (video_width / 8) & 0xf8;
629 	vesafb_defined.vsync_len    = 4;
630 
631 	if (video_bpp > 8) {
632 		vesafb_defined.red.offset    = screen_info.red_pos;
633 		vesafb_defined.red.length    = screen_info.red_size;
634 		vesafb_defined.green.offset  = screen_info.green_pos;
635 		vesafb_defined.green.length  = screen_info.green_size;
636 		vesafb_defined.blue.offset   = screen_info.blue_pos;
637 		vesafb_defined.blue.length   = screen_info.blue_size;
638 		vesafb_defined.transp.offset = screen_info.rsvd_pos;
639 		vesafb_defined.transp.length = screen_info.rsvd_size;
640 		printk(KERN_INFO "vesafb: directcolor: "
641 		       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
642 		       screen_info.rsvd_size,
643 		       screen_info.red_size,
644 		       screen_info.green_size,
645 		       screen_info.blue_size,
646 		       screen_info.rsvd_pos,
647 		       screen_info.red_pos,
648 		       screen_info.green_pos,
649 		       screen_info.blue_pos);
650 		video_cmap_len = 16;
651 	} else {
652 		vesafb_defined.red.length   = 6;
653 		vesafb_defined.green.length = 6;
654 		vesafb_defined.blue.length  = 6;
655 		for(i = 0; i < 16; i++) {
656 			j = color_table[i];
657 			palette[i].red   = default_red[j];
658 			palette[i].green = default_grn[j];
659 			palette[i].blue  = default_blu[j];
660 		}
661 		video_cmap_len = 256;
662 	}
663 
664 	/* request failure does not faze us, as vgacon probably has this
665 	 * region already (FIXME) */
666 	request_region(0x3c0, 32, "vesafb");
667 
668 	if (mtrr) {
669 		int temp_size = video_size;
670 		/* Find the largest power-of-two */
671 		while (temp_size & (temp_size - 1))
672                 	temp_size &= (temp_size - 1);
673 
674                 /* Try and find a power of two to add */
675 		while (temp_size && mtrr_add(video_base, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
676 			temp_size >>= 1;
677 		}
678 	}
679 
680 	strcpy(fb_info.modename, "VESA VGA");
681 	fb_info.changevar = NULL;
682 	fb_info.node = -1;
683 	fb_info.fbops = &vesafb_ops;
684 	fb_info.disp=&disp;
685 	fb_info.switch_con=&vesafb_switch;
686 	fb_info.updatevar=&vesafb_update_var;
687 	fb_info.blank=&vesafb_blank;
688 	fb_info.flags=FBINFO_FLAG_DEFAULT;
689 	vesafb_set_disp(-1);
690 
691 	if (register_framebuffer(&fb_info)<0)
692 		return -EINVAL;
693 
694 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
695 	       GET_FB_IDX(fb_info.node), fb_info.modename);
696 	return 0;
697 }
698 
699 /*
700  * Overrides for Emacs so that we follow Linus's tabbing style.
701  * ---------------------------------------------------------------------------
702  * Local variables:
703  * c-basic-offset: 8
704  * End:
705  */
706 
707 MODULE_LICENSE("GPL");
708