vga16fb.c (38818B)
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#if defined(CONFIG_X86) 1355 par->isVGA = screen_info.orig_video_isVGA == VIDEO_TYPE_VGAC; 1356#else 1357 /* non-x86 architectures treat orig_video_isVGA as a boolean flag */ 1358 par->isVGA = screen_info.orig_video_isVGA; 1359#endif 1360 par->palette_blanked = 0; 1361 par->vesa_blanked = 0; 1362 1363 i = par->isVGA? 6 : 2; 1364 1365 vga16fb_defined.red.length = i; 1366 vga16fb_defined.green.length = i; 1367 vga16fb_defined.blue.length = i; 1368 1369 /* name should not depend on EGA/VGA */ 1370 info->fbops = &vga16fb_ops; 1371 info->var = vga16fb_defined; 1372 info->fix = vga16fb_fix; 1373 /* supports rectangles with widths of multiples of 8 */ 1374 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31; 1375 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE | 1376 FBINFO_HWACCEL_YPAN; 1377 1378 i = (info->var.bits_per_pixel == 8) ? 256 : 16; 1379 ret = fb_alloc_cmap(&info->cmap, i, 0); 1380 if (ret) { 1381 printk(KERN_ERR "vga16fb: unable to allocate colormap\n"); 1382 ret = -ENOMEM; 1383 goto err_alloc_cmap; 1384 } 1385 1386 if (vga16fb_check_var(&info->var, info)) { 1387 printk(KERN_ERR "vga16fb: unable to validate variable\n"); 1388 ret = -EINVAL; 1389 goto err_check_var; 1390 } 1391 1392 vga16fb_update_fix(info); 1393 1394 info->apertures->ranges[0].base = VGA_FB_PHYS; 1395 info->apertures->ranges[0].size = VGA_FB_PHYS_LEN; 1396 1397 if (register_framebuffer(info) < 0) { 1398 printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); 1399 ret = -EINVAL; 1400 goto err_check_var; 1401 } 1402 1403 fb_info(info, "%s frame buffer device\n", info->fix.id); 1404 platform_set_drvdata(dev, info); 1405 1406 return 0; 1407 1408 err_check_var: 1409 fb_dealloc_cmap(&info->cmap); 1410 err_alloc_cmap: 1411 iounmap(info->screen_base); 1412 err_ioremap: 1413 framebuffer_release(info); 1414 err_fb_alloc: 1415 return ret; 1416} 1417 1418static int vga16fb_remove(struct platform_device *dev) 1419{ 1420 struct fb_info *info = platform_get_drvdata(dev); 1421 1422 if (info) 1423 unregister_framebuffer(info); 1424 1425 return 0; 1426} 1427 1428static struct platform_driver vga16fb_driver = { 1429 .probe = vga16fb_probe, 1430 .remove = vga16fb_remove, 1431 .driver = { 1432 .name = "vga16fb", 1433 }, 1434}; 1435 1436static struct platform_device *vga16fb_device; 1437 1438static int __init vga16fb_init(void) 1439{ 1440 int ret; 1441#ifndef MODULE 1442 char *option = NULL; 1443 1444 if (fb_get_options("vga16fb", &option)) 1445 return -ENODEV; 1446 1447 vga16fb_setup(option); 1448#endif 1449 1450 ret = check_mode_supported(); 1451 if (ret) 1452 return ret; 1453 1454 ret = platform_driver_register(&vga16fb_driver); 1455 1456 if (!ret) { 1457 vga16fb_device = platform_device_alloc("vga16fb", 0); 1458 1459 if (vga16fb_device) 1460 ret = platform_device_add(vga16fb_device); 1461 else 1462 ret = -ENOMEM; 1463 1464 if (ret) { 1465 platform_device_put(vga16fb_device); 1466 platform_driver_unregister(&vga16fb_driver); 1467 } 1468 } 1469 1470 return ret; 1471} 1472 1473static void __exit vga16fb_exit(void) 1474{ 1475 platform_device_unregister(vga16fb_device); 1476 platform_driver_unregister(&vga16fb_driver); 1477} 1478 1479MODULE_DESCRIPTION("Legacy VGA framebuffer device driver"); 1480MODULE_LICENSE("GPL"); 1481module_init(vga16fb_init); 1482module_exit(vga16fb_exit);