make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / video / vga16fb.c
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/slab.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 65536
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         while ((this_opt = strsep(&options, ",")) != 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         if (!vga16fb.video_vbase) {
901                 printk(KERN_ERR "vga16fb: unable to map device\n");
902                 return -ENOMEM;
903         }
904         printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
905
906         vga16fb.isVGA = ORIG_VIDEO_ISVGA;
907         vga16fb.palette_blanked = 0;
908         vga16fb.vesa_blanked = 0;
909
910         i = vga16fb.isVGA? 6 : 2;
911         
912         vga16fb_defined.red.length   = i;
913         vga16fb_defined.green.length = i;
914         vga16fb_defined.blue.length  = i;       
915         for(i = 0; i < 16; i++) {
916                 j = color_table[i];
917                 palette[i].red   = default_red[j];
918                 palette[i].green = default_grn[j];
919                 palette[i].blue  = default_blu[j];
920         }
921
922         /* XXX share VGA I/O region with vgacon and others */
923
924         disp.var = vga16fb_defined;
925
926         /* name should not depend on EGA/VGA */
927         strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
928         vga16fb.fb_info.changevar = NULL;
929         vga16fb.fb_info.node = -1;
930         vga16fb.fb_info.fbops = &vga16fb_ops;
931         vga16fb.fb_info.disp=&disp;
932         vga16fb.fb_info.switch_con=&vga16fb_switch;
933         vga16fb.fb_info.updatevar=&vga16fb_update_var;
934         vga16fb.fb_info.blank=&vga16fb_blank;
935         vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT;
936         vga16fb_set_disp(-1, &vga16fb);
937
938         if (register_framebuffer(&vga16fb.fb_info)<0) {
939                 iounmap(vga16fb.video_vbase);
940                 return -EINVAL;
941         }
942
943         printk(KERN_INFO "fb%d: %s frame buffer device\n",
944                GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
945
946         return 0;
947 }
948
949 static void __exit vga16fb_exit(void)
950 {
951     unregister_framebuffer(&vga16fb.fb_info);
952     iounmap(vga16fb.video_vbase);
953     /* XXX unshare VGA regions */
954 }
955
956 #ifdef MODULE
957 MODULE_LICENSE("GPL");
958 module_init(vga16fb_init);
959 #endif
960 module_exit(vga16fb_exit);
961
962
963 /*
964  * Overrides for Emacs so that we follow Linus's tabbing style.
965  * ---------------------------------------------------------------------------
966  * Local variables:
967  * c-basic-offset: 8
968  * End:
969  */
970