Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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