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