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