Subversion Repositories shark

Rev

Rev 468 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
468 giacomo 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
 
13
#include <linuxcomp.h>
14
 
15
#include <linux/module.h>
16
#include <linux/kernel.h>
17
#include <linux/errno.h>
18
#include <linux/string.h>
19
#include <linux/mm.h>
20
#include <linux/tty.h>
21
#include <linux/slab.h>
22
#include <linux/delay.h>
23
#include <linux/fb.h>
24
#include <linux/ioport.h>
25
#include <linux/init.h>
26
 
27
#include <asm/io.h>
28
#include <video/vga.h>
29
 
30
#define GRAPHICS_ADDR_REG VGA_GFX_I     /* Graphics address register. */
31
#define GRAPHICS_DATA_REG VGA_GFX_D     /* Graphics data register. */
32
 
33
#define SET_RESET_INDEX         VGA_GFX_SR_VALUE        /* Set/Reset Register index. */
34
#define ENABLE_SET_RESET_INDEX  VGA_GFX_SR_ENABLE       /* Enable Set/Reset Register index. */
35
#define DATA_ROTATE_INDEX       VGA_GFX_DATA_ROTATE     /* Data Rotate Register index. */
36
#define GRAPHICS_MODE_INDEX     VGA_GFX_MODE            /* Graphics Mode Register index. */
37
#define BIT_MASK_INDEX          VGA_GFX_BIT_MASK        /* Bit Mask Register index. */
38
 
39
#define dac_reg (VGA_PEL_IW)
40
#define dac_val (VGA_PEL_D)
41
 
42
#define VGA_FB_PHYS 0xA0000
43
#define VGA_FB_PHYS_LEN 65536
44
 
45
#define MODE_SKIP4      1
46
#define MODE_8BPP       2
47
#define MODE_CFB        4
48
#define MODE_TEXT       8
49
 
50
/* --------------------------------------------------------------------- */
51
 
52
/*
53
 * card parameters
54
 */
55
 
56
static struct fb_info vga16fb;
57
 
58
static struct vga16fb_par {
59
        /* structure holding original VGA register settings when the
60
           screen is blanked */
61
        struct {
62
                unsigned char   SeqCtrlIndex;           /* Sequencer Index reg.   */
63
                unsigned char   CrtCtrlIndex;           /* CRT-Contr. Index reg.  */
64
                unsigned char   CrtMiscIO;              /* Miscellaneous register */
65
                unsigned char   HorizontalTotal;        /* CRT-Controller:00h */
66
                unsigned char   HorizDisplayEnd;        /* CRT-Controller:01h */
67
                unsigned char   StartHorizRetrace;      /* CRT-Controller:04h */
68
                unsigned char   EndHorizRetrace;        /* CRT-Controller:05h */
69
                unsigned char   Overflow;               /* CRT-Controller:07h */
70
                unsigned char   StartVertRetrace;       /* CRT-Controller:10h */
71
                unsigned char   EndVertRetrace;         /* CRT-Controller:11h */
72
                unsigned char   ModeControl;            /* CRT-Controller:17h */
73
                unsigned char   ClockingMode;           /* Seq-Controller:01h */
74
        } vga_state;
75
        struct vgastate state;
76
        atomic_t ref_count;
77
        int palette_blanked, vesa_blanked, mode, isVGA;
78
        u8 misc, pel_msk, vss, clkdiv;
79
        u8 crtc[VGA_CRT_C];
80
} vga16_par;
81
 
82
/* --------------------------------------------------------------------- */
83
 
84
static struct fb_var_screeninfo vga16fb_defined = {
85
        .xres           = 640,
86
        .yres           = 480,
87
        .xres_virtual   = 640,
88
        .yres_virtual   = 480,
89
        .bits_per_pixel = 4,   
90
        .activate       = FB_ACTIVATE_TEST,
91
        .height         = -1,
92
        .width          = -1,
93
        .pixclock       = 39721,
94
        .left_margin    = 48,
95
        .right_margin   = 16,
96
        .upper_margin   = 39,
97
        .lower_margin   = 8,
98
        .hsync_len      = 96,
99
        .vsync_len      = 2,
100
        .vmode          = FB_VMODE_NONINTERLACED,
101
};
102
 
103
/* name should not depend on EGA/VGA */
104
static struct fb_fix_screeninfo vga16fb_fix __initdata = {
105
        .id             = "VGA16 VGA",
106
        .smem_start     = VGA_FB_PHYS,
107
        .smem_len       = VGA_FB_PHYS_LEN,
108
        .type           = FB_TYPE_VGA_PLANES,
109
        .type_aux       = FB_AUX_VGA_PLANES_VGA4,
110
        .visual         = FB_VISUAL_PSEUDOCOLOR,
111
        .xpanstep       = 8,
112
        .ypanstep       = 1,
113
        .line_length    = 640/8,
114
        .accel          = FB_ACCEL_NONE
115
};
116
 
117
/* The VGA's weird architecture often requires that we read a byte and
118
   write a byte to the same location.  It doesn't matter *what* byte
119
   we write, however.  This is because all the action goes on behind
120
   the scenes in the VGA's 32-bit latch register, and reading and writing
121
   video memory just invokes latch behavior.
122
 
123
   To avoid race conditions (is this necessary?), reading and writing
124
   the memory byte should be done with a single instruction.  One
125
   suitable instruction is the x86 bitwise OR.  The following
126
   read-modify-write routine should optimize to one such bitwise
127
   OR. */
128
static inline void rmw(volatile char *p)
129
{
130
        readb(p);
131
        writeb(1, p);
132
}
133
 
134
/* Set the Graphics Mode Register, and return its previous value.
135
   Bits 0-1 are write mode, bit 3 is read mode. */
136
static inline int setmode(int mode)
137
{
138
        int oldmode;
139
 
140
        vga_io_w(GRAPHICS_ADDR_REG, GRAPHICS_MODE_INDEX);
141
        oldmode = vga_io_r(GRAPHICS_DATA_REG);
142
        vga_io_w(GRAPHICS_DATA_REG, mode);
143
        return oldmode;
144
}
145
 
146
/* Select the Bit Mask Register and return its value. */
147
static inline int selectmask(void)
148
{
149
        return vga_io_rgfx(BIT_MASK_INDEX);
150
}
151
 
152
/* Set the value of the Bit Mask Register.  It must already have been
153
   selected with selectmask(). */
154
static inline void setmask(int mask)
155
{
156
        vga_io_w(GRAPHICS_DATA_REG, mask);
157
}
158
 
159
/* Set the Data Rotate Register and return its old value.
160
   Bits 0-2 are rotate count, bits 3-4 are logical operation
161
   (0=NOP, 1=AND, 2=OR, 3=XOR). */
162
static inline int setop(int op)
163
{
164
        int oldop;
165
 
166
        vga_io_w(GRAPHICS_ADDR_REG, DATA_ROTATE_INDEX);
167
        oldop = vga_io_r(GRAPHICS_DATA_REG);
168
        vga_io_w(GRAPHICS_DATA_REG, op);
169
        return oldop;
170
}
171
 
172
/* Set the Enable Set/Reset Register and return its old value.  
173
   The code here always uses value 0xf for thsi register. */
174
static inline int setsr(int sr)
175
{
176
        int oldsr;
177
 
178
        vga_io_w(GRAPHICS_ADDR_REG, ENABLE_SET_RESET_INDEX);
179
        oldsr = vga_io_r(GRAPHICS_DATA_REG);
180
        vga_io_w(GRAPHICS_DATA_REG, sr);
181
        return oldsr;
182
}
183
 
184
/* Set the Set/Reset Register and return its old value. */
185
static inline int setcolor(int color)
186
{
187
        int oldcolor;
188
 
189
        vga_io_w(GRAPHICS_ADDR_REG, SET_RESET_INDEX);
190
        oldcolor = vga_io_r(GRAPHICS_DATA_REG);
191
        vga_io_w(GRAPHICS_DATA_REG, color);
192
        return oldcolor;
193
}
194
 
195
/* Return the value in the Graphics Address Register. */
196
static inline int getindex(void)
197
{
198
        return vga_io_r(GRAPHICS_ADDR_REG);
199
}
200
 
201
/* Set the value in the Graphics Address Register. */
202
static inline void setindex(int index)
203
{
204
        vga_io_w(GRAPHICS_ADDR_REG, index);
205
}
206
 
207
static void vga16fb_pan_var(struct fb_info *info,
208
                            struct fb_var_screeninfo *var)
209
{
210
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
211
        u32 xoffset, pos;
212
 
213
        xoffset = var->xoffset;
214
        if (info->var.bits_per_pixel == 8) {
215
                pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
216
        } else if (par->mode & MODE_TEXT) {
217
                int fh = 16; // FIXME !!! font height. Fugde for now.
218
                pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
219
        } else {
220
                if (info->var.nonstd)
221
                        xoffset--;
222
                pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
223
        }
224
        vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
225
        vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
226
        /* if we support CFB4, then we must! support xoffset with pixel
227
         * granularity if someone supports xoffset in bit resolution */
228
        vga_io_r(VGA_IS1_RC);           /* reset flip-flop */
229
        vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
230
        if (var->bits_per_pixel == 8)
231
                vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
232
        else
233
                vga_io_w(VGA_ATT_IW, xoffset & 7);
234
        vga_io_r(VGA_IS1_RC);
235
        vga_io_w(VGA_ATT_IW, 0x20);
236
}
237
 
238
static void vga16fb_update_fix(struct fb_info *info)
239
{
240
        if (info->var.bits_per_pixel == 4) {
241
                if (info->var.nonstd) {
242
                        info->fix.type = FB_TYPE_PACKED_PIXELS;
243
                        info->fix.line_length = info->var.xres_virtual / 2;
244
                } else {
245
                        info->fix.type = FB_TYPE_VGA_PLANES;
246
                        info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
247
                        info->fix.line_length = info->var.xres_virtual / 8;
248
                }
249
        } else if (info->var.bits_per_pixel == 0) {
250
                info->fix.type = FB_TYPE_TEXT;
251
                info->fix.type_aux = FB_AUX_TEXT_CGA;
252
                info->fix.line_length = info->var.xres_virtual / 4;
253
        } else {        /* 8bpp */
254
                if (info->var.nonstd) {
255
                        info->fix.type = FB_TYPE_VGA_PLANES;
256
                        info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
257
                        info->fix.line_length = info->var.xres_virtual / 4;
258
                } else {
259
                        info->fix.type = FB_TYPE_PACKED_PIXELS;
260
                        info->fix.line_length = info->var.xres_virtual;
261
                }
262
        }
263
}
264
 
265
static void vga16fb_clock_chip(struct vga16fb_par *par,
266
                               unsigned int pixclock,
267
                               const struct fb_info *info,
268
                               int mul, int div)
269
{
270
        static struct {
271
                u32 pixclock;
272
                u8  misc;
273
                u8  seq_clock_mode;
274
        } *ptr, *best, vgaclocks[] = {
275
                { 79442 /* 12.587 */, 0x00, 0x08},
276
                { 70616 /* 14.161 */, 0x04, 0x08},
277
                { 39721 /* 25.175 */, 0x00, 0x00},
278
                { 35308 /* 28.322 */, 0x04, 0x00},
279
                {     0 /* bad */,    0x00, 0x00}};
280
        int err;
281
 
282
        pixclock = (pixclock * mul) / div;
283
        best = vgaclocks;
284
        err = pixclock - best->pixclock;
285
        if (err < 0) err = -err;
286
        for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
287
                int tmp;
288
 
289
                tmp = pixclock - ptr->pixclock;
290
                if (tmp < 0) tmp = -tmp;
291
                if (tmp < err) {
292
                        err = tmp;
293
                        best = ptr;
294
                }
295
        }
296
        par->misc |= best->misc;
297
        par->clkdiv = best->seq_clock_mode;
298
        pixclock = (best->pixclock * div) / mul;               
299
}
300
 
301
#define FAIL(X) return -EINVAL
302
 
303
static int vga16fb_open(struct fb_info *info, int user)
304
{
305
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
306
        int cnt = atomic_read(&par->ref_count);
307
 
308
        if (!cnt) {
309
                memset(&par->state, 0, sizeof(struct vgastate));
310
                par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
311
                        VGA_SAVE_CMAP;
312
                save_vga(&par->state);
313
        }
314
        atomic_inc(&par->ref_count);
315
        return 0;
316
}
317
 
318
static int vga16fb_release(struct fb_info *info, int user)
319
{
320
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
321
        int cnt = atomic_read(&par->ref_count);
322
 
323
        if (!cnt)
324
                return -EINVAL;
325
        if (cnt == 1)
326
                restore_vga(&par->state);
327
        atomic_dec(&par->ref_count);
328
 
329
        return 0;
330
}
331
 
332
static int vga16fb_check_var(struct fb_var_screeninfo *var,
333
                             struct fb_info *info)
334
{
335
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
336
        u32 xres, right, hslen, left, xtotal;
337
        u32 yres, lower, vslen, upper, ytotal;
338
        u32 vxres, xoffset, vyres, yoffset;
339
        u32 pos;
340
        u8 r7, rMode;
341
        int shift;
342
        int mode;
343
        u32 maxmem;
344
 
345
        par->pel_msk = 0xFF;
346
 
347
        if (var->bits_per_pixel == 4) {
348
                if (var->nonstd) {
349
                        if (!par->isVGA)
350
                                return -EINVAL;
351
                        shift = 3;
352
                        mode = MODE_SKIP4 | MODE_CFB;
353
                        maxmem = 16384;
354
                        par->pel_msk = 0x0F;
355
                } else {
356
                        shift = 3;
357
                        mode = 0;
358
                        maxmem = 65536;
359
                }
360
        } else if (var->bits_per_pixel == 8) {
361
                if (!par->isVGA)
362
                        return -EINVAL; /* no support on EGA */
363
                shift = 2;
364
                if (var->nonstd) {
365
                        mode = MODE_8BPP | MODE_CFB;
366
                        maxmem = 65536;
367
                } else {
368
                        mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
369
                        maxmem = 16384;
370
                }
371
        } else
372
                return -EINVAL;
373
 
374
        xres = (var->xres + 7) & ~7;
375
        vxres = (var->xres_virtual + 0xF) & ~0xF;
376
        xoffset = (var->xoffset + 7) & ~7;
377
        left = (var->left_margin + 7) & ~7;
378
        right = (var->right_margin + 7) & ~7;
379
        hslen = (var->hsync_len + 7) & ~7;
380
 
381
        if (vxres < xres)
382
                vxres = xres;
383
        if (xres + xoffset > vxres)
384
                xoffset = vxres - xres;
385
 
386
        var->xres = xres;
387
        var->right_margin = right;
388
        var->hsync_len = hslen;
389
        var->left_margin = left;
390
        var->xres_virtual = vxres;
391
        var->xoffset = xoffset;
392
 
393
        xres >>= shift;
394
        right >>= shift;
395
        hslen >>= shift;
396
        left >>= shift;
397
        vxres >>= shift;
398
        xtotal = xres + right + hslen + left;
399
        if (xtotal >= 256)
400
                FAIL("xtotal too big");
401
        if (hslen > 32)
402
                FAIL("hslen too big");
403
        if (right + hslen + left > 64)
404
                FAIL("hblank too big");
405
        par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
406
        par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
407
        par->crtc[VGA_CRTC_H_DISP] = xres - 1;
408
        pos = xres + right;
409
        par->crtc[VGA_CRTC_H_SYNC_START] = pos;
410
        pos += hslen;
411
        par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
412
        pos += left - 2; /* blank_end + 2 <= total + 5 */
413
        par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
414
        if (pos & 0x20)
415
                par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
416
 
417
        yres = var->yres;
418
        lower = var->lower_margin;
419
        vslen = var->vsync_len;
420
        upper = var->upper_margin;
421
        vyres = var->yres_virtual;
422
        yoffset = var->yoffset;
423
 
424
        if (yres > vyres)
425
                vyres = yres;
426
        if (vxres * vyres > maxmem) {
427
                vyres = maxmem / vxres;
428
                if (vyres < yres)
429
                        return -ENOMEM;
430
        }
431
        if (yoffset + yres > vyres)
432
                yoffset = vyres - yres;
433
        var->yres = yres;
434
        var->lower_margin = lower;
435
        var->vsync_len = vslen;
436
        var->upper_margin = upper;
437
        var->yres_virtual = vyres;
438
        var->yoffset = yoffset;
439
 
440
        if (var->vmode & FB_VMODE_DOUBLE) {
441
                yres <<= 1;
442
                lower <<= 1;
443
                vslen <<= 1;
444
                upper <<= 1;
445
        }
446
        ytotal = yres + lower + vslen + upper;
447
        if (ytotal > 1024) {
448
                ytotal >>= 1;
449
                yres >>= 1;
450
                lower >>= 1;
451
                vslen >>= 1;
452
                upper >>= 1;
453
                rMode = 0x04;
454
        } else
455
                rMode = 0x00;
456
        if (ytotal > 1024)
457
                FAIL("ytotal too big");
458
        if (vslen > 16)
459
                FAIL("vslen too big");
460
        par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
461
        r7 = 0x10;      /* disable linecompare */
462
        if (ytotal & 0x100) r7 |= 0x01;
463
        if (ytotal & 0x200) r7 |= 0x20;
464
        par->crtc[VGA_CRTC_PRESET_ROW] = 0;
465
        par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;    /* 1 scanline, no linecmp */
466
        if (var->vmode & FB_VMODE_DOUBLE)
467
                par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
468
        par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
469
        par->crtc[VGA_CRTC_CURSOR_END]   = 0x00;
470
        if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
471
                xoffset--;
472
        pos = yoffset * vxres + (xoffset >> shift);
473
        par->crtc[VGA_CRTC_START_HI]     = pos >> 8;
474
        par->crtc[VGA_CRTC_START_LO]     = pos & 0xFF;
475
        par->crtc[VGA_CRTC_CURSOR_HI]    = 0x00;
476
        par->crtc[VGA_CRTC_CURSOR_LO]    = 0x00;
477
        pos = yres - 1;
478
        par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
479
        par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
480
        if (pos & 0x100)
481
                r7 |= 0x0A;     /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
482
        if (pos & 0x200) {
483
                r7 |= 0x40;     /* 0x40 -> DISP_END */
484
                par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
485
        }
486
        pos += lower;
487
        par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
488
        if (pos & 0x100)
489
                r7 |= 0x04;
490
        if (pos & 0x200)
491
                r7 |= 0x80;
492
        pos += vslen;
493
        par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
494
        pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
495
        par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
496
                     but some SVGA chips requires all 8 bits to set */
497
        if (vxres >= 512)
498
                FAIL("vxres too long");
499
        par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
500
        if (mode & MODE_SKIP4)
501
                par->crtc[VGA_CRTC_UNDERLINE] = 0x5F;   /* 256, cfb8 */
502
        else
503
                par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;   /* 16, vgap */
504
        par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
505
        par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
506
        par->crtc[VGA_CRTC_OVERFLOW] = r7;
507
 
508
        par->vss = 0x00;        /* 3DA */
509
 
510
        par->misc = 0xE3;       /* enable CPU, ports 0x3Dx, positive sync */
511
        if (var->sync & FB_SYNC_HOR_HIGH_ACT)
512
                par->misc &= ~0x40;
513
        if (var->sync & FB_SYNC_VERT_HIGH_ACT)
514
                par->misc &= ~0x80;
515
 
516
        par->mode = mode;
517
 
518
        if (mode & MODE_8BPP)
519
                /* pixel clock == vga clock / 2 */
520
                vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
521
        else
522
                /* pixel clock == vga clock */
523
                vga16fb_clock_chip(par, var->pixclock, info, 1, 1);
524
 
525
        var->red.offset = var->green.offset = var->blue.offset =
526
        var->transp.offset = 0;
527
        var->red.length = var->green.length = var->blue.length =
528
                (par->isVGA) ? 6 : 2;
529
        var->transp.length = 0;
530
        var->activate = FB_ACTIVATE_NOW;
531
        var->height = -1;
532
        var->width = -1;
533
        var->accel_flags = 0;
534
        return 0;
535
}
536
#undef FAIL
537
 
538
static int vga16fb_set_par(struct fb_info *info)
539
{
540
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
541
        u8 gdc[VGA_GFX_C];
542
        u8 seq[VGA_SEQ_C];
543
        u8 atc[VGA_ATT_C];
544
        int fh, i;
545
 
546
        seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
547
        if (par->mode & MODE_TEXT)
548
                seq[VGA_SEQ_PLANE_WRITE] = 0x03;
549
        else
550
                seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
551
        seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
552
        if (par->mode & MODE_TEXT)
553
                seq[VGA_SEQ_MEMORY_MODE] = 0x03;
554
        else if (par->mode & MODE_SKIP4)
555
                seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
556
        else
557
                seq[VGA_SEQ_MEMORY_MODE] = 0x06;
558
 
559
        gdc[VGA_GFX_SR_VALUE] = 0x00;
560
        gdc[VGA_GFX_SR_ENABLE] = 0x00;
561
        gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
562
        gdc[VGA_GFX_DATA_ROTATE] = 0x00;
563
        gdc[VGA_GFX_PLANE_READ] = 0;
564
        if (par->mode & MODE_TEXT) {
565
                gdc[VGA_GFX_MODE] = 0x10;
566
                gdc[VGA_GFX_MISC] = 0x06;
567
        } else {
568
                if (par->mode & MODE_CFB)
569
                        gdc[VGA_GFX_MODE] = 0x40;
570
                else
571
                        gdc[VGA_GFX_MODE] = 0x00;
572
                gdc[VGA_GFX_MISC] = 0x05;
573
        }
574
        gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
575
        gdc[VGA_GFX_BIT_MASK] = 0xFF;
576
 
577
        for (i = 0x00; i < 0x10; i++)
578
                atc[i] = i;
579
        if (par->mode & MODE_TEXT)
580
                atc[VGA_ATC_MODE] = 0x04;
581
        else if (par->mode & MODE_8BPP)
582
                atc[VGA_ATC_MODE] = 0x41;
583
        else
584
                atc[VGA_ATC_MODE] = 0x81;
585
        atc[VGA_ATC_OVERSCAN] = 0x00;   /* 0 for EGA, 0xFF for VGA */
586
        atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
587
        if (par->mode & MODE_8BPP)
588
                atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
589
        else
590
                atc[VGA_ATC_PEL] = info->var.xoffset & 7;
591
        atc[VGA_ATC_COLOR_PAGE] = 0x00;
592
 
593
        if (par->mode & MODE_TEXT) {
594
                fh = 16; // FIXME !!! Fudge font height. 
595
                par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN]
596
                                               & ~0x1F) | (fh - 1);
597
        }
598
 
599
        vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
600
 
601
        /* Enable graphics register modification */
602
        if (!par->isVGA) {
603
                vga_io_w(EGA_GFX_E0, 0x00);
604
                vga_io_w(EGA_GFX_E1, 0x01);
605
        }
606
 
607
        /* update misc output register */
608
        vga_io_w(VGA_MIS_W, par->misc);
609
 
610
        /* synchronous reset on */
611
        vga_io_wseq(0x00, 0x01);
612
 
613
        if (par->isVGA)
614
                vga_io_w(VGA_PEL_MSK, par->pel_msk);
615
 
616
        /* write sequencer registers */
617
        vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
618
        for (i = 2; i < VGA_SEQ_C; i++) {
619
                vga_io_wseq(i, seq[i]);
620
        }
621
 
622
        /* synchronous reset off */
623
        vga_io_wseq(0x00, 0x03);
624
 
625
        /* deprotect CRT registers 0-7 */
626
        vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
627
 
628
        /* write CRT registers */
629
        for (i = 0; i < VGA_CRTC_REGS; i++) {
630
                vga_io_wcrt(i, par->crtc[i]);
631
        }
632
 
633
        /* write graphics controller registers */
634
        for (i = 0; i < VGA_GFX_C; i++) {
635
                vga_io_wgfx(i, gdc[i]);
636
        }
637
 
638
        /* write attribute controller registers */
639
        for (i = 0; i < VGA_ATT_C; i++) {
640
                vga_io_r(VGA_IS1_RC);           /* reset flip-flop */
641
                vga_io_wattr(i, atc[i]);
642
        }
643
 
644
        /* Wait for screen to stabilize. */
645
        mdelay(50);
646
 
647
        vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
648
 
649
        vga_io_r(VGA_IS1_RC);
650
        vga_io_w(VGA_ATT_IW, 0x20);
651
 
652
        vga16fb_update_fix(info);
653
        return 0;
654
}
655
 
656
static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
657
{
658
        static unsigned char map[] = { 000, 001, 010, 011 };
659
        int val;
660
 
661
        if (regno >= 16)
662
                return;
663
        val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
664
        vga_io_r(VGA_IS1_RC);   /* ! 0x3BA */
665
        vga_io_wattr(regno, val);
666
        vga_io_r(VGA_IS1_RC);   /* some clones need it */
667
        vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
668
}
669
 
670
static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
671
{
672
        outb(regno,       dac_reg);
673
        outb(red   >> 10, dac_val);
674
        outb(green >> 10, dac_val);
675
        outb(blue  >> 10, dac_val);
676
}
677
 
678
static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
679
                             unsigned blue, unsigned transp,
680
                             struct fb_info *info)
681
{
682
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
683
        int gray;
684
 
685
        /*
686
         *  Set a single color register. The values supplied are
687
         *  already rounded down to the hardware's capabilities
688
         *  (according to the entries in the `var' structure). Return
689
         *  != 0 for invalid regno.
690
         */
691
 
692
        if (regno >= 256)
693
                return 1;
694
 
695
        gray = info->var.grayscale;
696
 
697
        if (gray) {
698
                /* gray = 0.30*R + 0.59*G + 0.11*B */
699
                red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
700
        }
701
        if (par->isVGA)
702
                vga16_setpalette(regno,red,green,blue);
703
        else
704
                ega16_setpalette(regno,red,green,blue);
705
        return 0;
706
}
707
 
708
static int vga16fb_pan_display(struct fb_var_screeninfo *var,
709
                               struct fb_info *info)
710
{
711
        if (var->xoffset + info->var.xres > info->var.xres_virtual ||
712
            var->yoffset + info->var.yres > info->var.yres_virtual)
713
                return -EINVAL;
714
 
715
        vga16fb_pan_var(info, var);
716
 
717
        info->var.xoffset = var->xoffset;
718
        info->var.yoffset = var->yoffset;
719
        info->var.vmode &= ~FB_VMODE_YWRAP;
720
        return 0;
721
}
722
 
723
/* The following VESA blanking code is taken from vgacon.c.  The VGA
724
   blanking code was originally by Huang shi chao, and modified by
725
   Christoph Rimek (chrimek@toppoint.de) and todd j. derr
726
   (tjd@barefoot.org) for Linux. */
727
#define attrib_port             VGA_ATC_IW
728
#define seq_port_reg            VGA_SEQ_I
729
#define seq_port_val            VGA_SEQ_D
730
#define gr_port_reg             VGA_GFX_I
731
#define gr_port_val             VGA_GFX_D
732
#define video_misc_rd           VGA_MIS_R
733
#define video_misc_wr           VGA_MIS_W
734
#define vga_video_port_reg      VGA_CRT_IC
735
#define vga_video_port_val      VGA_CRT_DC
736
 
737
static void vga_vesa_blank(struct vga16fb_par *par, int mode)
738
{
739
        unsigned char SeqCtrlIndex;
740
        unsigned char CrtCtrlIndex;
741
 
742
        //cli();
743
        SeqCtrlIndex = vga_io_r(seq_port_reg);
744
        CrtCtrlIndex = vga_io_r(vga_video_port_reg);
745
 
746
        /* save original values of VGA controller registers */
747
        if(!par->vesa_blanked) {
748
                par->vga_state.CrtMiscIO = vga_io_r(video_misc_rd);
749
                //sti();
750
 
751
                par->vga_state.HorizontalTotal = vga_io_rcrt(0x00);     /* HorizontalTotal */
752
                par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01);     /* HorizDisplayEnd */
753
                par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04);   /* StartHorizRetrace */
754
                par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05);     /* EndHorizRetrace */
755
                par->vga_state.Overflow = vga_io_rcrt(0x07);            /* Overflow */
756
                par->vga_state.StartVertRetrace = vga_io_rcrt(0x10);    /* StartVertRetrace */
757
                par->vga_state.EndVertRetrace = vga_io_rcrt(0x11);      /* EndVertRetrace */
758
                par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */
759
                par->vga_state.ClockingMode = vga_io_rseq(0x01);        /* ClockingMode */
760
        }
761
 
762
        /* assure that video is enabled */
763
        /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
764
        //cli();
765
        vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
766
 
767
        /* test for vertical retrace in process.... */
768
        if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
769
                vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO & 0xef);
770
 
771
        /*
772
         * Set <End of vertical retrace> to minimum (0) and
773
         * <Start of vertical Retrace> to maximum (incl. overflow)
774
         * Result: turn off vertical sync (VSync) pulse.
775
         */
776
        if (mode & VESA_VSYNC_SUSPEND) {
777
                outb_p(0x10,vga_video_port_reg);        /* StartVertRetrace */
778
                outb_p(0xff,vga_video_port_val);        /* maximum value */
779
                outb_p(0x11,vga_video_port_reg);        /* EndVertRetrace */
780
                outb_p(0x40,vga_video_port_val);        /* minimum (bits 0..3)  */
781
                outb_p(0x07,vga_video_port_reg);        /* Overflow */
782
                outb_p(par->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
783
        }
784
 
785
        if (mode & VESA_HSYNC_SUSPEND) {
786
                /*
787
                 * Set <End of horizontal retrace> to minimum (0) and
788
                 *  <Start of horizontal Retrace> to maximum
789
                 * Result: turn off horizontal sync (HSync) pulse.
790
                 */
791
                outb_p(0x04,vga_video_port_reg);        /* StartHorizRetrace */
792
                outb_p(0xff,vga_video_port_val);        /* maximum */
793
                outb_p(0x05,vga_video_port_reg);        /* EndHorizRetrace */
794
                outb_p(0x00,vga_video_port_val);        /* minimum (0) */
795
        }
796
 
797
        /* restore both index registers */
798
        outb_p(SeqCtrlIndex,seq_port_reg);
799
        outb_p(CrtCtrlIndex,vga_video_port_reg);
800
        //sti();
801
}
802
 
803
static void vga_vesa_unblank(struct vga16fb_par *par)
804
{
805
        unsigned char SeqCtrlIndex;
806
        unsigned char CrtCtrlIndex;
807
 
808
        //cli();
809
        SeqCtrlIndex = vga_io_r(seq_port_reg);
810
        CrtCtrlIndex = vga_io_r(vga_video_port_reg);
811
 
812
        /* restore original values of VGA controller registers */
813
        vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO);
814
 
815
        /* HorizontalTotal */
816
        vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
817
        /* HorizDisplayEnd */
818
        vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
819
        /* StartHorizRetrace */
820
        vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
821
        /* EndHorizRetrace */
822
        vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
823
        /* Overflow */
824
        vga_io_wcrt(0x07, par->vga_state.Overflow);
825
        /* StartVertRetrace */
826
        vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
827
        /* EndVertRetrace */
828
        vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
829
        /* ModeControl */
830
        vga_io_wcrt(0x17, par->vga_state.ModeControl);
831
        /* ClockingMode */
832
        vga_io_wseq(0x01, par->vga_state.ClockingMode);
833
 
834
        /* restore index/control registers */
835
        vga_io_w(seq_port_reg, SeqCtrlIndex);
836
        vga_io_w(vga_video_port_reg, CrtCtrlIndex);
837
        //sti();
838
}
839
 
840
static void vga_pal_blank(void)
841
{
842
        int i;
843
 
844
        for (i=0; i<16; i++) {
845
                outb_p (i, dac_reg) ;
846
                outb_p (0, dac_val) ;
847
                outb_p (0, dac_val) ;
848
                outb_p (0, dac_val) ;
849
        }
850
}
851
 
852
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
853
static int vga16fb_blank(int blank, struct fb_info *info)
854
{
855
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
856
 
857
        switch (blank) {
858
        case 0:                         /* Unblank */
859
                if (par->vesa_blanked) {
860
                        vga_vesa_unblank(par);
861
                        par->vesa_blanked = 0;
862
                }
863
                if (par->palette_blanked) {
864
                        //do_install_cmap(info->currcon, info);
865
                        par->palette_blanked = 0;
866
                }
867
                break;
868
        case 1:                         /* blank */
869
                vga_pal_blank();
870
                par->palette_blanked = 1;
871
                break;
872
        default:                        /* VESA blanking */
873
                vga_vesa_blank(par, blank-1);
874
                par->vesa_blanked = 1;
875
                break;
876
        }
877
        return 0;
878
}
879
 
880
void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
881
{
882
        u32 dx = rect->dx, width = rect->width;
883
        char oldindex = getindex();
884
        char oldmode = setmode(0x40);
885
        char oldmask = selectmask();
886
        int line_ofs, height;
887
        char oldop, oldsr;
888
        char *where;
889
 
890
        dx /= 4;
891
        where = info->screen_base + dx + rect->dy * info->fix.line_length;
892
 
893
        if (rect->rop == ROP_COPY) {
894
                oldop = setop(0);
895
                oldsr = setsr(0);
896
 
897
                width /= 4;
898
                line_ofs = info->fix.line_length - width;
899
                setmask(0xff);
900
 
901
                height = rect->height;
902
 
903
                while (height--) {
904
                        int x;
905
 
906
                        /* we can do memset... */
907
                        for (x = width; x > 0; --x) {
908
                                writeb(rect->color, where);
909
                                where++;
910
                        }
911
                        where += line_ofs;
912
                }
913
        } else {
914
                char oldcolor = setcolor(0xf);
915
                int y;
916
 
917
                oldop = setop(0x18);
918
                oldsr = setsr(0xf);
919
                setmask(0x0F);
920
                for (y = 0; y < rect->height; y++) {
921
                        rmw(where);
922
                        rmw(where+1);
923
                        where += info->fix.line_length;
924
                }
925
                setcolor(oldcolor);
926
        }
927
        setmask(oldmask);
928
        setsr(oldsr);
929
        setop(oldop);
930
        setmode(oldmode);
931
        setindex(oldindex);
932
}
933
 
934
void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
935
{
936
        int x, x2, y2, vxres, vyres, width, height, line_ofs;
937
        char *dst;
938
 
939
        vxres = info->var.xres_virtual;
940
        vyres = info->var.yres_virtual;
941
 
942
        if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
943
                return;
944
 
945
        /* We could use hardware clipping but on many cards you get around
946
         * hardware clipping by writing to framebuffer directly. */
947
 
948
        x2 = rect->dx + rect->width;
949
        y2 = rect->dy + rect->height;
950
        x2 = x2 < vxres ? x2 : vxres;
951
        y2 = y2 < vyres ? y2 : vyres;
952
        width = x2 - rect->dx;
953
 
954
        switch (info->fix.type) {
955
        case FB_TYPE_VGA_PLANES:
956
                if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
957
 
958
                        height = y2 - rect->dy;
959
                        width = rect->width/8;
960
 
961
                        line_ofs = info->fix.line_length - width;
962
                        dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
963
 
964
                        switch (rect->rop) {
965
                        case ROP_COPY:
966
                                setmode(0);
967
                                setop(0);
968
                                setsr(0xf);
969
                                setcolor(rect->color);
970
                                selectmask();
971
 
972
                                setmask(0xff);
973
 
974
                                while (height--) {
975
                                        for (x = 0; x < width; x++) {
976
                                                writeb(0, dst);
977
                                                dst++;
978
                                        }
979
                                        dst += line_ofs;
980
                                }
981
                                break;
982
                        case ROP_XOR:
983
                                setmode(0);
984
                                setop(0x18);
985
                                setsr(0xf);
986
                                setcolor(0xf);
987
                                selectmask();
988
 
989
                                setmask(0xff);
990
                                while (height--) {
991
                                        for (x = 0; x < width; x++) {
992
                                                rmw(dst);
993
                                                dst++;
994
                                        }
995
                                        dst += line_ofs;
996
                                }
997
                                break;
998
                        }
999
                } else
1000
                        vga_8planes_fillrect(info, rect);
1001
                break;
1002
        case FB_TYPE_PACKED_PIXELS:
1003
        default:
1004
                cfb_fillrect(info, rect);
1005
                break;
1006
        }
1007
}
1008
 
1009
void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1010
{
1011
        char oldindex = getindex();
1012
        char oldmode = setmode(0x41);
1013
        char oldop = setop(0);
1014
        char oldsr = setsr(0xf);
1015
        int height, line_ofs, x;
1016
        u32 sx, dx, width;
1017
        char *dest, *src;
1018
 
1019
        height = area->height;
1020
 
1021
        sx = area->sx / 4;
1022
        dx = area->dx / 4;
1023
        width = area->width / 4;
1024
 
1025
        if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
1026
                line_ofs = info->fix.line_length - width;
1027
                dest = info->screen_base + dx + area->dy * info->fix.line_length;
1028
                src = info->screen_base + sx + area->sy * info->fix.line_length;
1029
                while (height--) {
1030
                        for (x = 0; x < width; x++) {
1031
                                readb(src);
1032
                                writeb(0, dest);
1033
                                src++;
1034
                                dest++;
1035
                        }
1036
                        src += line_ofs;
1037
                        dest += line_ofs;
1038
                }
1039
        } else {
1040
                line_ofs = info->fix.line_length - width;
1041
                dest = info->screen_base + dx + width +
1042
                        (area->dy + height - 1) * info->fix.line_length;
1043
                src = info->screen_base + sx + width +
1044
                        (area->sy + height - 1) * info->fix.line_length;
1045
                while (height--) {
1046
                        for (x = 0; x < width; x++) {
1047
                                --src;
1048
                                --dest;
1049
                                readb(src);
1050
                                writeb(0, dest);
1051
                        }
1052
                        src -= line_ofs;
1053
                        dest -= line_ofs;
1054
                }
1055
        }
1056
 
1057
        setsr(oldsr);
1058
        setop(oldop);
1059
        setmode(oldmode);
1060
        setindex(oldindex);
1061
}
1062
 
1063
void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1064
{
1065
        u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
1066
        int x, x2, y2, old_dx, old_dy, vxres, vyres;
1067
        int height, width, line_ofs;
1068
        char *dst = NULL, *src = NULL;
1069
 
1070
        vxres = info->var.xres_virtual;
1071
        vyres = info->var.yres_virtual;
1072
 
1073
        if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1074
            area->sy > vyres)
1075
                return;
1076
 
1077
        /* clip the destination */
1078
        old_dx = area->dx;
1079
        old_dy = area->dy;
1080
 
1081
        /*
1082
         * We could use hardware clipping but on many cards you get around
1083
         * hardware clipping by writing to framebuffer directly.
1084
         */
1085
        x2 = area->dx + area->width;
1086
        y2 = area->dy + area->height;
1087
        dx = area->dx > 0 ? area->dx : 0;
1088
        dy = area->dy > 0 ? area->dy : 0;
1089
        x2 = x2 < vxres ? x2 : vxres;
1090
        y2 = y2 < vyres ? y2 : vyres;
1091
        width = x2 - dx;
1092
        height = y2 - dy;
1093
 
1094
        /* update sx1,sy1 */
1095
        sx += (dx - old_dx);
1096
        sy += (dy - old_dy);
1097
 
1098
        /* the source must be completely inside the virtual screen */
1099
        if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres)
1100
                return;
1101
 
1102
        switch (info->fix.type) {
1103
        case FB_TYPE_VGA_PLANES:
1104
                if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1105
                        width = width/8;
1106
                        height = height;
1107
                        line_ofs = info->fix.line_length - width;
1108
 
1109
                        setmode(1);
1110
                        setop(0);
1111
                        setsr(0xf);
1112
 
1113
                        if (dy < sy || (dy == sy && dx < sx)) {
1114
                                dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1115
                                src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1116
                                while (height--) {
1117
                                        for (x = 0; x < width; x++) {
1118
                                                readb(src);
1119
                                                writeb(0, dst);
1120
                                                dst++;
1121
                                                src++;
1122
                                        }
1123
                                        src += line_ofs;
1124
                                        dst += line_ofs;
1125
                                }
1126
                        } else {
1127
                                dst = info->screen_base + (dx/8) + width +
1128
                                        (dy + height - 1) * info->fix.line_length;
1129
                                src = info->screen_base + (sx/8) + width +
1130
                                        (sy + height  - 1) * info->fix.line_length;
1131
                                while (height--) {
1132
                                        for (x = 0; x < width; x++) {
1133
                                                dst--;
1134
                                                src--;
1135
                                                readb(src);
1136
                                                writeb(0, dst);
1137
                                        }
1138
                                        src -= line_ofs;
1139
                                        dst -= line_ofs;
1140
                                }
1141
                        }
1142
                } else
1143
                        vga_8planes_copyarea(info, area);
1144
                break;
1145
        case FB_TYPE_PACKED_PIXELS:
1146
        default:
1147
                cfb_copyarea(info, area);
1148
                break;
1149
        }
1150
}
1151
 
1152
#ifdef __LITTLE_ENDIAN
1153
static unsigned int transl_l[] =
1154
{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
1155
static unsigned int transl_h[] =
1156
{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
1157
 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
1158
#else
1159
#ifdef __BIG_ENDIAN
1160
static unsigned int transl_h[] =
1161
{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
1162
static unsigned int transl_l[] =
1163
{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
1164
 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
1165
#else
1166
#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1167
#endif
1168
#endif
1169
 
1170
void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1171
{
1172
        char oldindex = getindex();
1173
        char oldmode = setmode(0x40);
1174
        char oldop = setop(0);
1175
        char oldsr = setsr(0);
1176
        char oldmask = selectmask();
1177
        const char *cdat = image->data;
1178
        u32 dx = image->dx;
1179
        char *where;
1180
        int y;
1181
 
1182
        dx /= 4;
1183
        where = info->screen_base + dx + image->dy * info->fix.line_length;
1184
 
1185
        setmask(0xff);
1186
        writeb(image->bg_color, where);
1187
        readb(where);
1188
        selectmask();
1189
        setmask(image->fg_color ^ image->bg_color);
1190
        setmode(0x42);
1191
        setop(0x18);
1192
        for (y = 0; y < image->height; y++, where += info->fix.line_length)
1193
                writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1194
        setmask(oldmask);
1195
        setsr(oldsr);
1196
        setop(oldop);
1197
        setmode(oldmode);
1198
        setindex(oldindex);
1199
}
1200
 
1201
void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1202
{
1203
        char *where = info->screen_base + (image->dx/8) +
1204
                image->dy * info->fix.line_length;
1205
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
1206
        char *cdat = (char *) image->data, *dst;
1207
        int x, y;
1208
 
1209
        switch (info->fix.type) {
1210
        case FB_TYPE_VGA_PLANES:
1211
                if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1212
                        if (par->isVGA) {
1213
                                setmode(2);
1214
                                setop(0);
1215
                                setsr(0xf);
1216
                                setcolor(image->fg_color);
1217
                                selectmask();
1218
 
1219
                                setmask(0xff);
1220
                                writeb(image->bg_color, where);
1221
                                rmb();
1222
                                readb(where); /* fill latches */
1223
                                setmode(3);
1224
                                wmb();
1225
                                for (y = 0; y < image->height; y++) {
1226
                                        dst = where;
1227
                                        for (x = image->width/8; x--;)
1228
                                                writeb(*cdat++, dst++);
1229
                                        where += info->fix.line_length;
1230
                                }
1231
                                wmb();
1232
                        } else {
1233
                                setmode(0);
1234
                                setop(0);
1235
                                setsr(0xf);
1236
                                setcolor(image->bg_color);
1237
                                selectmask();
1238
 
1239
                                setmask(0xff);
1240
                                for (y = 0; y < image->height; y++) {
1241
                                        dst = where;
1242
                                        for (x=image->width/8; x--;){
1243
                                                rmw(dst);
1244
                                                setcolor(image->fg_color);
1245
                                                selectmask();
1246
                                                if (*cdat) {
1247
                                                        setmask(*cdat++);
1248
                                                        rmw(dst++);
1249
                                                }
1250
                                        }
1251
                                        where += info->fix.line_length;
1252
                                }
1253
                        }
1254
                } else
1255
                        vga_8planes_imageblit(info, image);
1256
                break;
1257
        case FB_TYPE_PACKED_PIXELS:
1258
        default:
1259
                cfb_imageblit(info, image);
1260
                break;
1261
        }
1262
}
1263
 
1264
void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1265
{
1266
        /*
1267
         * Draw logo
1268
         */
1269
        struct vga16fb_par *par = (struct vga16fb_par *) info->par;
1270
        char *where = info->screen_base + image->dy * info->fix.line_length +
1271
                image->dx/8;
1272
        const char *cdat = image->data, *dst;
1273
        int x, y;
1274
 
1275
        switch (info->fix.type) {
1276
        case FB_TYPE_VGA_PLANES:
1277
                if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1278
                    par->isVGA) {
1279
                        setsr(0xf);
1280
                        setop(0);
1281
                        setmode(0);
1282
 
1283
                        for (y = 0; y < image->height; y++) {
1284
                                for (x = 0; x < image->width; x++) {
1285
                                        dst = where + x/8;
1286
 
1287
                                        setcolor(*cdat);
1288
                                        selectmask();
1289
                                        setmask(1 << (7 - (x % 8)));
1290
                                        fb_readb(dst);
1291
                                        fb_writeb(0, dst);
1292
 
1293
                                        cdat++;
1294
                                }
1295
                                where += info->fix.line_length;
1296
                        }
1297
                }
1298
                break;
1299
        case FB_TYPE_PACKED_PIXELS:
1300
                cfb_imageblit(info, image);
1301
                break;
1302
        default:
1303
                break;
1304
        }
1305
}
1306
 
1307
void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1308
{
1309
        if (image->depth == 1)
1310
                vga_imageblit_expand(info, image);
1311
        else if (image->depth <= info->var.bits_per_pixel)
1312
                vga_imageblit_color(info, image);
1313
}
1314
 
1315
static struct fb_ops vga16fb_ops = {
1316
        .owner          = THIS_MODULE,
1317
        .fb_open        = vga16fb_open,
1318
        .fb_release     = vga16fb_release,
1319
        .fb_check_var   = vga16fb_check_var,
1320
        .fb_set_par     = vga16fb_set_par,
1321
        .fb_setcolreg   = vga16fb_setcolreg,
1322
        .fb_pan_display = vga16fb_pan_display,
1323
        .fb_blank       = vga16fb_blank,
1324
        .fb_fillrect    = vga16fb_fillrect,
1325
        .fb_copyarea    = vga16fb_copyarea,
1326
        .fb_imageblit   = vga16fb_imageblit,
1327
        .fb_cursor      = soft_cursor,
1328
};
1329
 
1330
int vga16fb_setup(char *options)
1331
{
1332
        char *this_opt;
1333
 
1334
        if (!options || !*options)
1335
                return 0;
1336
 
1337
        while ((this_opt = strsep(&options, ",")) != NULL) {
1338
                if (!*this_opt) continue;
1339
        }
1340
        return 0;
1341
}
1342
 
1343
int __init vga16fb_init(void)
1344
{
1345
        int i;
1346
 
1347
        printk(KERN_DEBUG "vga16fb: initializing\n");
1348
 
1349
        /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1350
 
1351
        vga16fb.screen_base = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
1352
        if (!vga16fb.screen_base) {
1353
                printk(KERN_ERR "vga16fb: unable to map device\n");
1354
                return -ENOMEM;
1355
        }
1356
        printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base);
1357
 
1358
        vga16_par.isVGA = ORIG_VIDEO_ISVGA;
1359
        vga16_par.palette_blanked = 0;
1360
        vga16_par.vesa_blanked = 0;
1361
 
1362
        i = vga16_par.isVGA? 6 : 2;
1363
 
1364
        vga16fb_defined.red.length   = i;
1365
        vga16fb_defined.green.length = i;
1366
        vga16fb_defined.blue.length  = i;      
1367
 
1368
        /* name should not depend on EGA/VGA */
1369
        vga16fb.fbops = &vga16fb_ops;
1370
        vga16fb.var = vga16fb_defined;
1371
        vga16fb.fix = vga16fb_fix;
1372
        vga16fb.par = &vga16_par;
1373
        vga16fb.flags = FBINFO_FLAG_DEFAULT;
1374
 
1375
        i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16;
1376
        fb_alloc_cmap(&vga16fb.cmap, i, 0);
1377
 
1378
        if (vga16fb_check_var(&vga16fb.var, &vga16fb))
1379
                return -EINVAL;
1380
 
1381
        vga16fb_update_fix(&vga16fb);
1382
 
1383
        if (register_framebuffer(&vga16fb) < 0) {
1384
                iounmap(vga16fb.screen_base);
1385
                return -EINVAL;
1386
        }
1387
 
1388
        printk(KERN_INFO "fb%d: %s frame buffer device\n",
1389
               vga16fb.node, vga16fb.fix.id);
1390
 
1391
        return 0;
1392
}
1393
 
1394
static void __exit vga16fb_exit(void)
1395
{
1396
    unregister_framebuffer(&vga16fb);
1397
    iounmap(vga16fb.screen_base);
1398
    /* XXX unshare VGA regions */
1399
}
1400
 
1401
#ifdef MODULE
1402
MODULE_LICENSE("GPL");
1403
module_init(vga16fb_init);
1404
#endif
1405
module_exit(vga16fb_exit);
1406
 
1407
 
1408
/*
1409
 * Overrides for Emacs so that we follow Linus's tabbing style.
1410
 * ---------------------------------------------------------------------------
1411
 * Local variables:
1412
 * c-basic-offset: 8
1413
 * End:
1414
 */
1415