~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/video/vga16fb.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
  3  * 
  4  * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
  5  * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
  6  * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
  7  *
  8  * This file is subject to the terms and conditions of the GNU General
  9  * Public License.  See the file COPYING in the main directory of this
 10  * archive for more details.  */
 11 
 12 #include <linux/module.h>
 13 #include <linux/kernel.h>
 14 #include <linux/errno.h>
 15 #include <linux/string.h>
 16 #include <linux/mm.h>
 17 #include <linux/tty.h>
 18 #include <linux/malloc.h>
 19 #include <linux/delay.h>
 20 #include <linux/fb.h>
 21 #include <linux/console.h>
 22 #include <linux/selection.h>
 23 #include <linux/ioport.h>
 24 #include <linux/init.h>
 25 
 26 #include <asm/io.h>
 27 
 28 #include <video/fbcon.h>
 29 #include <video/fbcon-vga-planes.h>
 30 #include "vga.h"
 31 
 32 #define dac_reg (0x3c8)
 33 #define dac_val (0x3c9)
 34 
 35 #define VGA_FB_PHYS 0xA0000
 36 #define VGA_FB_PHYS_LEN 65535
 37 
 38 /* --------------------------------------------------------------------- */
 39 
 40 /*
 41  * card parameters
 42  */
 43 
 44 static struct vga16fb_info {
 45         struct fb_info  fb_info;
 46         char *video_vbase;                      /* 0xa0000 map address */
 47         int isVGA;
 48         
 49         /* structure holding original VGA register settings when the
 50            screen is blanked */
 51         struct {
 52                 unsigned char   SeqCtrlIndex;           /* Sequencer Index reg.   */
 53                 unsigned char   CrtCtrlIndex;           /* CRT-Contr. Index reg.  */
 54                 unsigned char   CrtMiscIO;              /* Miscellaneous register */
 55                 unsigned char   HorizontalTotal;        /* CRT-Controller:00h */
 56                 unsigned char   HorizDisplayEnd;        /* CRT-Controller:01h */
 57                 unsigned char   StartHorizRetrace;      /* CRT-Controller:04h */
 58                 unsigned char   EndHorizRetrace;        /* CRT-Controller:05h */
 59                 unsigned char   Overflow;               /* CRT-Controller:07h */
 60                 unsigned char   StartVertRetrace;       /* CRT-Controller:10h */
 61                 unsigned char   EndVertRetrace;         /* CRT-Controller:11h */
 62                 unsigned char   ModeControl;            /* CRT-Controller:17h */
 63                 unsigned char   ClockingMode;           /* Seq-Controller:01h */
 64         } vga_state;
 65 
 66         int palette_blanked;
 67         int vesa_blanked;
 68 } vga16fb;
 69 
 70 
 71 struct vga16fb_par {
 72         u8 crtc[VGA_CRT_C];
 73         u8 atc[VGA_ATT_C];
 74         u8 gdc[VGA_GFX_C];
 75         u8 seq[VGA_SEQ_C];
 76         u8 misc;
 77         u8 vss;
 78         struct fb_var_screeninfo var;
 79 };
 80 
 81 /* --------------------------------------------------------------------- */
 82 
 83 static struct fb_var_screeninfo vga16fb_defined = {
 84         640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
 85         0,0,            /* virtual -> visible no offset */
 86         4,              /* depth -> load bits_per_pixel */
 87         0,              /* greyscale ? */
 88         {0,0,0},        /* R */
 89         {0,0,0},        /* G */
 90         {0,0,0},        /* B */
 91         {0,0,0},        /* transparency */
 92         0,              /* standard pixel format */
 93         FB_ACTIVATE_NOW,
 94         -1,-1,
 95         0,
 96         39721, 48, 16, 39, 8,
 97         96, 2, 0,       /* No sync info */
 98         FB_VMODE_NONINTERLACED,
 99         {0,0,0,0,0,0}
100 };
101 
102 static struct display disp;
103 static struct { u_short blue, green, red, pad; } palette[256];
104 
105 static int             currcon   = 0;
106 
107 /* --------------------------------------------------------------------- */
108 
109 static void vga16fb_pan_var(struct fb_info *info, struct fb_var_screeninfo *var)
110 {
111         u32 pos = (var->xres_virtual * var->yoffset + var->xoffset) >> 3;
112         outb(VGA_CRTC_START_HI, VGA_CRT_IC);
113         outb(pos >> 8, VGA_CRT_DC);
114         outb(VGA_CRTC_START_LO, VGA_CRT_IC);
115         outb(pos & 0xFF, VGA_CRT_DC);
116 #if 0
117         /* if someone supports xoffset in bit resolution */
118         inb(VGA_IS1_RC);                /* reset flip-flop */
119         outb(VGA_ATC_PEL, VGA_ATT_IW);
120         outb(xoffset & 7, VGA_ATT_IW);
121         inb(VGA_IS1_RC);
122         outb(0x20, VGA_ATT_IW);
123 #endif
124 }
125 
126 static int vga16fb_update_var(int con, struct fb_info *info)
127 {
128         vga16fb_pan_var(info, &fb_display[con].var);
129         return 0;
130 }
131 
132 static int vga16fb_get_fix(struct fb_fix_screeninfo *fix, int con,
133                            struct fb_info *info)
134 {
135         struct display *p;
136 
137         if (con < 0)
138                 p = &disp;
139         else
140                 p = fb_display + con;
141 
142         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
143         strcpy(fix->id,"VGA16 VGA");
144 
145         fix->smem_start = VGA_FB_PHYS;
146         fix->smem_len = VGA_FB_PHYS_LEN;
147         fix->type = FB_TYPE_VGA_PLANES;
148         fix->visual = FB_VISUAL_PSEUDOCOLOR;
149         fix->xpanstep  = 8;
150         fix->ypanstep  = 1;
151         fix->ywrapstep = 0;
152         fix->line_length = p->var.xres_virtual / 8;
153         return 0;
154 }
155 
156 static int vga16fb_get_var(struct fb_var_screeninfo *var, int con,
157                          struct fb_info *info)
158 {
159         if(con==-1)
160                 memcpy(var, &vga16fb_defined, sizeof(struct fb_var_screeninfo));
161         else
162                 *var=fb_display[con].var;
163         return 0;
164 }
165 
166 static void vga16fb_set_disp(int con, struct vga16fb_info *info)
167 {
168         struct fb_fix_screeninfo fix;
169         struct display *display;
170 
171         if (con < 0)
172                 display = &disp;
173         else
174                 display = fb_display + con;
175 
176         
177         vga16fb_get_fix(&fix, con, &info->fb_info);
178 
179         display->screen_base = info->video_vbase;
180         display->visual = fix.visual;
181         display->type = fix.type;
182         display->type_aux = fix.type_aux;
183         display->ypanstep = fix.ypanstep;
184         display->ywrapstep = fix.ywrapstep;
185         display->line_length = fix.line_length;
186         display->next_line = fix.line_length;
187         display->can_soft_blank = 1;
188         display->inverse = 0;
189 
190         if (info->isVGA)
191                 display->dispsw = &fbcon_vga_planes;
192         else
193                 display->dispsw = &fbcon_ega_planes;
194         display->scrollmode = SCROLL_YREDRAW;
195 }
196 
197 static void vga16fb_encode_var(struct fb_var_screeninfo *var,
198                                const struct vga16fb_par *par,
199                                const struct vga16fb_info *info)
200 {
201         *var = par->var;
202 }
203 
204 static void vga16fb_clock_chip(struct vga16fb_par *par,
205                                unsigned int pixclock,
206                                const struct vga16fb_info *info)
207 {
208         static struct {
209                 u32 pixclock;
210                 u8  misc;
211                 u8  seq_clock_mode;
212         } *ptr, *best, vgaclocks[] = {
213                 { 79442 /* 12.587 */, 0x00, 0x08},
214                 { 70616 /* 14.161 */, 0x04, 0x08},
215                 { 39721 /* 25.175 */, 0x00, 0x00},
216                 { 35308 /* 28.322 */, 0x04, 0x00},
217                 {     0 /* bad */,    0x00, 0x00}};
218         int err;
219 
220         best = vgaclocks;
221         err = pixclock - best->pixclock;
222         if (err < 0) err = -err;
223         for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
224                 int tmp;
225 
226                 tmp = pixclock - ptr->pixclock;
227                 if (tmp < 0) tmp = -tmp;
228                 if (tmp < err) {
229                         err = tmp;
230                         best = ptr;
231                 }
232         }
233         par->misc |= best->misc;
234         par->seq[VGA_SEQ_CLOCK_MODE] |= best->seq_clock_mode;
235         par->var.pixclock = best->pixclock;             
236 }
237                                
238 #define FAIL(X) return -EINVAL
239 
240 static int vga16fb_decode_var(const struct fb_var_screeninfo *var,
241                               struct vga16fb_par *par,
242                               const struct vga16fb_info *info)
243 {
244         u32 xres, right, hslen, left, xtotal;
245         u32 yres, lower, vslen, upper, ytotal;
246         u32 vxres, xoffset, vyres, yoffset;
247         u32 pos;
248         u8 r7, rMode;
249         int i;
250 
251         if (var->bits_per_pixel != 4)
252                 return -EINVAL;
253         xres = (var->xres + 7) & ~7;
254         vxres = (var->xres_virtual + 0xF) & ~0xF;
255         xoffset = (var->xoffset + 7) & ~7;
256         left = (var->left_margin + 7) & ~7;
257         right = (var->right_margin + 7) & ~7;
258         hslen = (var->hsync_len + 7) & ~7;
259 
260         if (vxres < xres)
261                 vxres = xres;
262         if (xres + xoffset > vxres)
263                 xoffset = vxres - xres;
264 
265         par->var.xres = xres;
266         par->var.right_margin = right;
267         par->var.hsync_len = hslen;
268         par->var.left_margin = left;
269         par->var.xres_virtual = vxres;
270         par->var.xoffset = xoffset;
271 
272         xres >>= 3;
273         right >>= 3;
274         hslen >>= 3;
275         left >>= 3;
276         vxres >>= 3;
277         xtotal = xres + right + hslen + left;
278         if (xtotal >= 256)
279                 FAIL("xtotal too big");
280         if (hslen > 32)
281                 FAIL("hslen too big");
282         if (right + hslen + left > 64)
283                 FAIL("hblank too big");
284         par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
285         par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
286         par->crtc[VGA_CRTC_H_DISP] = xres - 1;
287         pos = xres + right;
288         par->crtc[VGA_CRTC_H_SYNC_START] = pos;
289         pos += hslen;
290         par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
291         pos += left - 2; /* blank_end + 2 <= total + 5 */
292         par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
293         if (pos & 0x20)
294                 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
295 
296         yres = var->yres;
297         lower = var->lower_margin;
298         vslen = var->vsync_len;
299         upper = var->upper_margin;
300         vyres = var->yres_virtual;
301         yoffset = var->yoffset;
302 
303         if (yres > vyres)
304                 vyres = yres;
305         if (vxres * vyres > 65536) {
306                 vyres = 65536 / vxres;
307                 if (vyres < yres)
308                         return -ENOMEM;
309         }
310         if (yoffset + yres > vyres)
311                 yoffset = vyres - yres;
312         par->var.yres = yres;
313         par->var.lower_margin = lower;
314         par->var.vsync_len = vslen;
315         par->var.upper_margin = upper;
316         par->var.yres_virtual = vyres;
317         par->var.yoffset = yoffset;
318 
319         if (var->vmode & FB_VMODE_DOUBLE) {
320                 yres <<= 1;
321                 lower <<= 1;
322                 vslen <<= 1;
323                 upper <<= 1;
324         }
325         ytotal = yres + lower + vslen + upper;
326         if (ytotal > 1024) {
327                 ytotal >>= 1;
328                 yres >>= 1;
329                 lower >>= 1;
330                 vslen >>= 1;
331                 upper >>= 1;
332                 rMode = 0x04;
333         } else
334                 rMode = 0x00;
335         if (ytotal > 1024)
336                 FAIL("ytotal too big");
337         if (vslen > 16)
338                 FAIL("vslen too big");
339         par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
340         r7 = 0x10;      /* disable linecompare */
341         if (ytotal & 0x100) r7 |= 0x01;
342         if (ytotal & 0x200) r7 |= 0x20;
343         par->crtc[VGA_CRTC_PRESET_ROW] = 0;
344         par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;    /* 1 scanline, no linecmp */
345         par->var.vmode = var->vmode;
346         if (var->vmode & FB_VMODE_DOUBLE)
347                 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
348         par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
349         par->crtc[VGA_CRTC_CURSOR_END]   = 0x00;
350         pos = yoffset * vxres + (xoffset >> 3);
351         par->crtc[VGA_CRTC_START_HI]     = pos >> 8;
352         par->crtc[VGA_CRTC_START_LO]     = pos & 0xFF;
353         par->crtc[VGA_CRTC_CURSOR_HI]    = 0x00;
354         par->crtc[VGA_CRTC_CURSOR_LO]    = 0x00;
355         pos = yres - 1;
356         par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
357         par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
358         if (pos & 0x100)
359                 r7 |= 0x0A;     /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
360         if (pos & 0x200) {
361                 r7 |= 0x40;     /* 0x40 -> DISP_END */
362                 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
363         }
364         pos += lower;
365         par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
366         if (pos & 0x100)
367                 r7 |= 0x04;
368         if (pos & 0x200)
369                 r7 |= 0x80;
370         pos += vslen;
371         par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
372         pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
373         par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
374                      but some SVGA chips requires all 8 bits to set */
375         if (vxres >= 512)
376                 FAIL("vxres too long");
377         par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
378         par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;
379         par->crtc[VGA_CRTC_MODE] = rMode | 0xE3;
380         par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
381         par->crtc[VGA_CRTC_OVERFLOW] = r7;
382 
383         par->vss = 0x00;        /* 3DA */
384 
385         for (i = 0x00; i < 0x10; i++)
386                 par->atc[i] = i;
387         par->atc[VGA_ATC_MODE] = 0x81;
388         par->atc[VGA_ATC_OVERSCAN] = 0x00;      /* 0 for EGA, 0xFF for VGA */
389         par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
390         par->atc[VGA_ATC_PEL] = xoffset & 7;
391         par->atc[VGA_ATC_COLOR_PAGE] = 0x00;
392         
393         par->misc = 0xC3;       /* enable CPU, ports 0x3Dx, positive sync */
394         par->var.sync = var->sync;
395         if (var->sync & FB_SYNC_HOR_HIGH_ACT)
396                 par->misc &= ~0x40;
397         if (var->sync & FB_SYNC_VERT_HIGH_ACT)
398                 par->misc &= ~0x80;
399         
400         par->seq[VGA_SEQ_CLOCK_MODE] = 0x01;
401         par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
402         par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
403         par->seq[VGA_SEQ_MEMORY_MODE] = 0x06;
404         
405         par->gdc[VGA_GFX_SR_VALUE] = 0x00;
406         par->gdc[VGA_GFX_SR_ENABLE] = 0x0F;
407         par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
408         par->gdc[VGA_GFX_DATA_ROTATE] = 0x20;
409         par->gdc[VGA_GFX_PLANE_READ] = 0;
410         par->gdc[VGA_GFX_MODE] = 0x00;
411         par->gdc[VGA_GFX_MISC] = 0x05;
412         par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
413         par->gdc[VGA_GFX_BIT_MASK] = 0xFF;
414 
415         vga16fb_clock_chip(par, var->pixclock, info);
416 
417         par->var.bits_per_pixel = 4;
418         par->var.grayscale = var->grayscale;
419         par->var.red.offset = par->var.green.offset = par->var.blue.offset = 
420         par->var.transp.offset = 0;
421         par->var.red.length = par->var.green.length = par->var.blue.length =
422                 (info->isVGA) ? 6 : 2;
423         par->var.transp.length = 0;
424         par->var.nonstd = 0;
425         par->var.activate = FB_ACTIVATE_NOW;
426         par->var.height = -1;
427         par->var.width = -1;
428         par->var.accel_flags = 0;
429         
430         return 0;
431 }
432 #undef FAIL
433 
434 static int vga16fb_set_par(const struct vga16fb_par *par,
435                            struct vga16fb_info *info)
436 {
437         int i;
438 
439         outb(inb(VGA_MIS_R) | 0x01, VGA_MIS_W);
440 
441         /* Enable graphics register modification */
442         if (!info->isVGA) {
443                 outb(0x00, EGA_GFX_E0);
444                 outb(0x01, EGA_GFX_E1);
445         }
446         
447         /* update misc output register */
448         outb(par->misc, VGA_MIS_W);
449         
450         /* synchronous reset on */
451         outb(0x00, VGA_SEQ_I);
452         outb(0x01, VGA_SEQ_D);
453         
454         /* write sequencer registers */
455         outb(1, VGA_SEQ_I);
456         outb(par->seq[1] | 0x20, VGA_SEQ_D);
457         for (i = 2; i < VGA_SEQ_C; i++) {
458                 outb(i, VGA_SEQ_I);
459                 outb(par->seq[i], VGA_SEQ_D);
460         }
461         
462         /* synchronous reset off */
463         outb(0x00, VGA_SEQ_I);
464         outb(0x03, VGA_SEQ_D);
465         
466         /* deprotect CRT registers 0-7 */
467         outb(0x11, VGA_CRT_IC);
468         outb(par->crtc[0x11], VGA_CRT_DC);
469 
470         /* write CRT registers */
471         for (i = 0; i < VGA_CRT_C; i++) {
472                 outb(i, VGA_CRT_IC);
473                 outb(par->crtc[i], VGA_CRT_DC);
474         }
475         
476         /* write graphics controller registers */
477         for (i = 0; i < VGA_GFX_C; i++) {
478                 outb(i, VGA_GFX_I);
479                 outb(par->gdc[i], VGA_GFX_D);
480         }
481         
482         /* write attribute controller registers */
483         for (i = 0; i < VGA_ATT_C; i++) {
484                 inb_p(VGA_IS1_RC);              /* reset flip-flop */
485                 outb_p(i, VGA_ATT_IW);
486                 outb_p(par->atc[i], VGA_ATT_IW);
487         }
488 
489         /* Wait for screen to stabilize. */
490         mdelay(50);
491 
492         outb(0x01, VGA_SEQ_I);
493         outb(par->seq[1], VGA_SEQ_D);
494 
495         inb(VGA_IS1_RC);
496         outb(0x20, VGA_ATT_IW);
497         
498         return 0;
499 }
500 
501 static int vga16fb_set_var(struct fb_var_screeninfo *var, int con,
502                           struct fb_info *fb)
503 {
504         struct vga16fb_info *info = (struct vga16fb_info*)fb;
505         struct vga16fb_par par;
506         struct display *display;
507         int err;
508 
509         if (con < 0)
510                 display = fb->disp;
511         else
512                 display = fb_display + con;
513         if ((err = vga16fb_decode_var(var, &par, info)) != 0)
514                 return err;
515         vga16fb_encode_var(var, &par, info);
516         
517         if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
518                 return 0;
519 
520         if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
521                 u32 oldxres, oldyres, oldvxres, oldvyres, oldbpp;
522 
523                 oldxres = display->var.xres;
524                 oldyres = display->var.yres;
525                 oldvxres = display->var.xres_virtual;
526                 oldvyres = display->var.yres_virtual;
527                 oldbpp = display->var.bits_per_pixel;
528 
529                 display->var = *var;
530 
531                 if (oldxres != var->xres || oldyres != var->yres ||
532                     oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
533                     oldbpp != var->bits_per_pixel) {
534                         vga16fb_set_disp(con, info);
535                         if (info->fb_info.changevar)
536                                 info->fb_info.changevar(con);
537                 }
538                 if (con == currcon)
539                         vga16fb_set_par(&par, info);
540         }
541 
542         return 0;
543 }
544 
545 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
546 {
547         static unsigned char map[] = { 000, 001, 010, 011 };
548         int val;
549         
550         val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
551         inb_p(0x3DA);   /* ! 0x3BA */
552         outb_p(regno, 0x3C0);
553         outb_p(val, 0x3C0);
554         inb_p(0x3DA);   /* some clones need it */
555         outb_p(0x20, 0x3C0); /* unblank screen */
556 }
557 
558 static int vga16_getcolreg(unsigned regno, unsigned *red, unsigned *green,
559                           unsigned *blue, unsigned *transp,
560                           struct fb_info *fb_info)
561 {
562         /*
563          *  Read a single color register and split it into colors/transparent.
564          *  Return != 0 for invalid regno.
565          */
566 
567         if (regno >= 16)
568                 return 1;
569 
570         *red   = palette[regno].red;
571         *green = palette[regno].green;
572         *blue  = palette[regno].blue;
573         *transp = 0;
574         return 0;
575 }
576 
577 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
578 {
579         outb(regno,       dac_reg);
580         outb(red   >> 10, dac_val);
581         outb(green >> 10, dac_val);
582         outb(blue  >> 10, dac_val);
583 }
584 
585 static int vga16_setcolreg(unsigned regno, unsigned red, unsigned green,
586                           unsigned blue, unsigned transp,
587                           struct fb_info *fb_info)
588 {
589         int gray;
590 
591         /*
592          *  Set a single color register. The values supplied are
593          *  already rounded down to the hardware's capabilities
594          *  (according to the entries in the `var' structure). Return
595          *  != 0 for invalid regno.
596          */
597         
598         if (regno >= 16)
599                 return 1;
600 
601         palette[regno].red   = red;
602         palette[regno].green = green;
603         palette[regno].blue  = blue;
604         
605         if (currcon < 0)
606                 gray = disp.var.grayscale;
607         else
608                 gray = fb_display[currcon].var.grayscale;
609         if (gray) {
610                 /* gray = 0.30*R + 0.59*G + 0.11*B */
611                 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
612         }
613         if (((struct vga16fb_info *) fb_info)->isVGA) 
614                 vga16_setpalette(regno,red,green,blue);
615         else
616                 ega16_setpalette(regno,red,green,blue);
617         
618         return 0;
619 }
620 
621 static void do_install_cmap(int con, struct fb_info *info)
622 {
623         if (con != currcon)
624                 return;
625         if (fb_display[con].cmap.len)
626                 fb_set_cmap(&fb_display[con].cmap, 1, vga16_setcolreg, info);
627         else
628                 fb_set_cmap(fb_default_cmap(16), 1, vga16_setcolreg,
629                             info);
630 }
631 
632 static int vga16fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
633                            struct fb_info *info)
634 {
635         if (con == currcon) /* current console? */
636                 return fb_get_cmap(cmap, kspc, vga16_getcolreg, info);
637         else if (fb_display[con].cmap.len) /* non default colormap? */
638                 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
639         else
640                 fb_copy_cmap(fb_default_cmap(16),
641                      cmap, kspc ? 0 : 2);
642         return 0;
643 }
644 
645 static int vga16fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
646                            struct fb_info *info)
647 {
648         int err;
649 
650         if (!fb_display[con].cmap.len) {        /* no colormap allocated? */
651                 err = fb_alloc_cmap(&fb_display[con].cmap,16,0);
652                 if (err)
653                         return err;
654         }
655         if (con == currcon)                     /* current console? */
656                 return fb_set_cmap(cmap, kspc, vga16_setcolreg, info);
657         else
658                 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
659         return 0;
660 }
661 
662 static int vga16fb_pan_display(struct fb_var_screeninfo *var, int con,
663                                struct fb_info *info) 
664 {
665         if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
666             var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
667                 return -EINVAL;
668         if (con == currcon)
669                 vga16fb_pan_var(info, var);
670         fb_display[con].var.xoffset = var->xoffset;
671         fb_display[con].var.yoffset = var->yoffset;
672         fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
673         return 0;
674 }
675 
676 static struct fb_ops vga16fb_ops = {
677         owner:          THIS_MODULE,
678         fb_get_fix:     vga16fb_get_fix,
679         fb_get_var:     vga16fb_get_var,
680         fb_set_var:     vga16fb_set_var,
681         fb_get_cmap:    vga16fb_get_cmap,
682         fb_set_cmap:    vga16fb_set_cmap,
683         fb_pan_display: vga16fb_pan_display,
684 };
685 
686 int vga16fb_setup(char *options)
687 {
688         char *this_opt;
689         
690         vga16fb.fb_info.fontname[0] = '\0';
691         
692         if (!options || !*options)
693                 return 0;
694         
695         for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
696                 if (!*this_opt) continue;
697                 
698                 if (!strncmp(this_opt, "font:", 5))
699                         strcpy(vga16fb.fb_info.fontname, this_opt+5);
700         }
701         return 0;
702 }
703 
704 static int vga16fb_switch(int con, struct fb_info *fb)
705 {
706         struct vga16fb_par par;
707         struct vga16fb_info *info = (struct vga16fb_info*)fb;
708 
709         /* Do we have to save the colormap? */
710         if (fb_display[currcon].cmap.len)
711                 fb_get_cmap(&fb_display[currcon].cmap, 1, vga16_getcolreg,
712                             fb);
713         
714         currcon = con;
715         vga16fb_decode_var(&fb_display[con].var, &par, info);
716         vga16fb_set_par(&par, info);
717         vga16fb_set_disp(con, info);
718 
719         /* Install new colormap */
720         do_install_cmap(con, fb);
721 /*      vga16fb_update_var(con, fb); */
722         return 1;
723 }
724 
725 /* The following VESA blanking code is taken from vgacon.c.  The VGA
726    blanking code was originally by Huang shi chao, and modified by
727    Christoph Rimek (chrimek@toppoint.de) and todd j. derr
728    (tjd@barefoot.org) for Linux. */
729 #define attrib_port     0x3c0
730 #define seq_port_reg    0x3c4
731 #define seq_port_val    0x3c5
732 #define gr_port_reg     0x3ce
733 #define gr_port_val     0x3cf
734 #define video_misc_rd   0x3cc
735 #define video_misc_wr   0x3c2
736 #define vga_video_port_reg      0x3d4
737 #define vga_video_port_val      0x3d5
738 
739 static void vga_vesa_blank(struct vga16fb_info *info, int mode)
740 {
741         unsigned char SeqCtrlIndex;
742         unsigned char CrtCtrlIndex;
743         
744         cli();
745         SeqCtrlIndex = inb_p(seq_port_reg);
746         CrtCtrlIndex = inb_p(vga_video_port_reg);
747 
748         /* save original values of VGA controller registers */
749         if(!info->vesa_blanked) {
750                 info->vga_state.CrtMiscIO = inb_p(video_misc_rd);
751                 sti();
752 
753                 outb_p(0x00,vga_video_port_reg);        /* HorizontalTotal */
754                 info->vga_state.HorizontalTotal = inb_p(vga_video_port_val);
755                 outb_p(0x01,vga_video_port_reg);        /* HorizDisplayEnd */
756                 info->vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
757                 outb_p(0x04,vga_video_port_reg);        /* StartHorizRetrace */
758                 info->vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
759                 outb_p(0x05,vga_video_port_reg);        /* EndHorizRetrace */
760                 info->vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
761                 outb_p(0x07,vga_video_port_reg);        /* Overflow */
762                 info->vga_state.Overflow = inb_p(vga_video_port_val);
763                 outb_p(0x10,vga_video_port_reg);        /* StartVertRetrace */
764                 info->vga_state.StartVertRetrace = inb_p(vga_video_port_val);
765                 outb_p(0x11,vga_video_port_reg);        /* EndVertRetrace */
766                 info->vga_state.EndVertRetrace = inb_p(vga_video_port_val);
767                 outb_p(0x17,vga_video_port_reg);        /* ModeControl */
768                 info->vga_state.ModeControl = inb_p(vga_video_port_val);
769                 outb_p(0x01,seq_port_reg);              /* ClockingMode */
770                 info->vga_state.ClockingMode = inb_p(seq_port_val);
771         }
772 
773         /* assure that video is enabled */
774         /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
775         cli();
776         outb_p(0x01,seq_port_reg);
777         outb_p(info->vga_state.ClockingMode | 0x20,seq_port_val);
778 
779         /* test for vertical retrace in process.... */
780         if ((info->vga_state.CrtMiscIO & 0x80) == 0x80)
781                 outb_p(info->vga_state.CrtMiscIO & 0xef,video_misc_wr);
782 
783         /*
784          * Set <End of vertical retrace> to minimum (0) and
785          * <Start of vertical Retrace> to maximum (incl. overflow)
786          * Result: turn off vertical sync (VSync) pulse.
787          */
788         if (mode & VESA_VSYNC_SUSPEND) {
789                 outb_p(0x10,vga_video_port_reg);        /* StartVertRetrace */
790                 outb_p(0xff,vga_video_port_val);        /* maximum value */
791                 outb_p(0x11,vga_video_port_reg);        /* EndVertRetrace */
792                 outb_p(0x40,vga_video_port_val);        /* minimum (bits 0..3)  */
793                 outb_p(0x07,vga_video_port_reg);        /* Overflow */
794                 outb_p(info->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
795         }
796 
797         if (mode & VESA_HSYNC_SUSPEND) {
798                 /*
799                  * Set <End of horizontal retrace> to minimum (0) and
800                  *  <Start of horizontal Retrace> to maximum
801                  * Result: turn off horizontal sync (HSync) pulse.
802                  */
803                 outb_p(0x04,vga_video_port_reg);        /* StartHorizRetrace */
804                 outb_p(0xff,vga_video_port_val);        /* maximum */
805                 outb_p(0x05,vga_video_port_reg);        /* EndHorizRetrace */
806                 outb_p(0x00,vga_video_port_val);        /* minimum (0) */
807         }
808 
809         /* restore both index registers */
810         outb_p(SeqCtrlIndex,seq_port_reg);
811         outb_p(CrtCtrlIndex,vga_video_port_reg);
812         sti();
813 }
814 
815 static void vga_vesa_unblank(struct vga16fb_info *info)
816 {
817         unsigned char SeqCtrlIndex;
818         unsigned char CrtCtrlIndex;
819         
820         cli();
821         SeqCtrlIndex = inb_p(seq_port_reg);
822         CrtCtrlIndex = inb_p(vga_video_port_reg);
823 
824         /* restore original values of VGA controller registers */
825         outb_p(info->vga_state.CrtMiscIO,video_misc_wr);
826 
827         outb_p(0x00,vga_video_port_reg);                /* HorizontalTotal */
828         outb_p(info->vga_state.HorizontalTotal,vga_video_port_val);
829         outb_p(0x01,vga_video_port_reg);                /* HorizDisplayEnd */
830         outb_p(info->vga_state.HorizDisplayEnd,vga_video_port_val);
831         outb_p(0x04,vga_video_port_reg);                /* StartHorizRetrace */
832         outb_p(info->vga_state.StartHorizRetrace,vga_video_port_val);
833         outb_p(0x05,vga_video_port_reg);                /* EndHorizRetrace */
834         outb_p(info->vga_state.EndHorizRetrace,vga_video_port_val);
835         outb_p(0x07,vga_video_port_reg);                /* Overflow */
836         outb_p(info->vga_state.Overflow,vga_video_port_val);
837         outb_p(0x10,vga_video_port_reg);                /* StartVertRetrace */
838         outb_p(info->vga_state.StartVertRetrace,vga_video_port_val);
839         outb_p(0x11,vga_video_port_reg);                /* EndVertRetrace */
840         outb_p(info->vga_state.EndVertRetrace,vga_video_port_val);
841         outb_p(0x17,vga_video_port_reg);                /* ModeControl */
842         outb_p(info->vga_state.ModeControl,vga_video_port_val);
843         outb_p(0x01,seq_port_reg);              /* ClockingMode */
844         outb_p(info->vga_state.ClockingMode,seq_port_val);
845 
846         /* restore index/control registers */
847         outb_p(SeqCtrlIndex,seq_port_reg);
848         outb_p(CrtCtrlIndex,vga_video_port_reg);
849         sti();
850 }
851 
852 static void vga_pal_blank(void)
853 {
854         int i;
855 
856         for (i=0; i<16; i++) {
857                 outb_p (i, dac_reg) ;
858                 outb_p (0, dac_val) ;
859                 outb_p (0, dac_val) ;
860                 outb_p (0, dac_val) ;
861         }
862 }
863 
864 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
865 static void vga16fb_blank(int blank, struct fb_info *fb_info)
866 {
867         struct vga16fb_info *info = (struct vga16fb_info*)fb_info;
868 
869         switch (blank) {
870         case 0:                         /* Unblank */
871                 if (info->vesa_blanked) {
872                         vga_vesa_unblank(info);
873                         info->vesa_blanked = 0;
874                 }
875                 if (info->palette_blanked) {
876                         do_install_cmap(currcon, fb_info);
877                         info->palette_blanked = 0;
878                 }
879                 break;
880         case 1:                         /* blank */
881                 vga_pal_blank();
882                 info->palette_blanked = 1;
883                 break;
884         default:                        /* VESA blanking */
885                 vga_vesa_blank(info, blank-1);
886                 info->vesa_blanked = 1;
887                 break;
888         }
889 }
890 
891 int __init vga16fb_init(void)
892 {
893         int i,j;
894 
895         printk(KERN_DEBUG "vga16fb: initializing\n");
896 
897         /* XXX share VGA_FB_PHYS region with vgacon */
898 
899         vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
900         printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
901 
902         vga16fb.isVGA = ORIG_VIDEO_ISVGA;
903         vga16fb.palette_blanked = 0;
904         vga16fb.vesa_blanked = 0;
905 
906         i = vga16fb.isVGA? 6 : 2;
907         
908         vga16fb_defined.red.length   = i;
909         vga16fb_defined.green.length = i;
910         vga16fb_defined.blue.length  = i;       
911         for(i = 0; i < 16; i++) {
912                 j = color_table[i];
913                 palette[i].red   = default_red[j];
914                 palette[i].green = default_grn[j];
915                 palette[i].blue  = default_blu[j];
916         }
917 
918         /* XXX share VGA I/O region with vgacon and others */
919 
920         disp.var = vga16fb_defined;
921 
922         /* name should not depend on EGA/VGA */
923         strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
924         vga16fb.fb_info.changevar = NULL;
925         vga16fb.fb_info.node = -1;
926         vga16fb.fb_info.fbops = &vga16fb_ops;
927         vga16fb.fb_info.disp=&disp;
928         vga16fb.fb_info.switch_con=&vga16fb_switch;
929         vga16fb.fb_info.updatevar=&vga16fb_update_var;
930         vga16fb.fb_info.blank=&vga16fb_blank;
931         vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT;
932         vga16fb_set_disp(-1, &vga16fb);
933 
934         if (register_framebuffer(&vga16fb.fb_info)<0)
935                 return -EINVAL;
936 
937         printk(KERN_INFO "fb%d: %s frame buffer device\n",
938                GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
939 
940         return 0;
941 }
942 
943 static void __exit vga16fb_exit(void)
944 {
945     unregister_framebuffer(&vga16fb.fb_info);
946     iounmap(vga16fb.video_vbase);
947     /* XXX unshare VGA regions */
948 }
949 
950 #ifdef MODULE
951 module_init(vga16fb_init);
952 #endif
953 module_exit(vga16fb_exit);
954 
955 
956 /*
957  * Overrides for Emacs so that we follow Linus's tabbing style.
958  * ---------------------------------------------------------------------------
959  * Local variables:
960  * c-basic-offset: 8
961  * End:
962  */
963 
964 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.