OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [video/] [vga16fb.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.