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