1/* 2 * linux/drivers/video/hgafb.c -- Hercules graphics adaptor frame buffer device 3 * 4 * Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu) 5 * Based on skeletonfb.c by Geert Uytterhoeven and 6 * mdacon.c by Andrew Apted 7 * 8 * History: 9 * 10 * - Revision 0.1.7 (23 Jan 2001): fix crash resulting from MDA only cards 11 * being detected as Hercules. (Paul G.) 12 * - Revision 0.1.6 (17 Aug 2000): new style structs 13 * documentation 14 * - Revision 0.1.5 (13 Mar 2000): spinlocks instead of saveflags();cli();etc 15 * minor fixes 16 * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for 17 * HGA-only systems 18 * - Revision 0.1.3 (22 Jan 2000): modified for the new fb_info structure 19 * screen is cleared after rmmod 20 * virtual resolutions 21 * kernel parameter 'video=hga:font:{fontname}' 22 * module parameter 'font={fontname}' 23 * module parameter 'nologo={0|1}' 24 * the most important: boot logo :) 25 * - Revision 0.1.0 (6 Dec 1999): faster scrolling and minor fixes 26 * - First release (25 Nov 1999) 27 * 28 * This file is subject to the terms and conditions of the GNU General Public 29 * License. See the file COPYING in the main directory of this archive 30 * for more details. 31 */ 32 33#include <linux/module.h> 34#include <linux/kernel.h> 35#include <linux/errno.h> 36#include <linux/spinlock.h> 37#include <linux/string.h> 38#include <linux/mm.h> 39#include <linux/tty.h> 40#include <linux/slab.h> 41#include <linux/delay.h> 42#include <linux/fb.h> 43#include <linux/init.h> 44#include <linux/ioport.h> 45#include <asm/io.h> 46#include <asm/vga.h> 47#include <video/fbcon.h> 48#include <video/fbcon-hga.h> 49 50#ifdef MODULE 51 52#define INCLUDE_LINUX_LOGO_DATA 53#include <linux/linux_logo.h> 54 55#endif /* MODULE */ 56 57#define DPRINTK(args...) 58 59#define CHKINFO(ret) 60 61/* Description of the hardware layout */ 62 63static unsigned long hga_vram_base; /* Base of video memory */ 64static unsigned long hga_vram_len; /* Size of video memory */ 65 66#define HGA_TXT 0 67#define HGA_GFX 1 68 69static int hga_mode = -1; /* 0 = txt, 1 = gfx mode */ 70 71static enum { TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } hga_type; 72static char *hga_type_name; 73 74#define HGA_INDEX_PORT 0x3b4 /* Register select port */ 75#define HGA_VALUE_PORT 0x3b5 /* Register value port */ 76#define HGA_MODE_PORT 0x3b8 /* Mode control port */ 77#define HGA_STATUS_PORT 0x3ba /* Status and Config port */ 78#define HGA_GFX_PORT 0x3bf /* Graphics control port */ 79 80/* HGA register values */ 81 82#define HGA_CURSOR_BLINKING 0x00 83#define HGA_CURSOR_OFF 0x20 84#define HGA_CURSOR_SLOWBLINK 0x60 85 86#define HGA_MODE_GRAPHICS 0x02 87#define HGA_MODE_VIDEO_EN 0x08 88#define HGA_MODE_BLINK_EN 0x20 89#define HGA_MODE_GFX_PAGE1 0x80 90 91#define HGA_STATUS_HSYNC 0x01 92#define HGA_STATUS_VSYNC 0x80 93#define HGA_STATUS_VIDEO 0x08 94 95#define HGA_CONFIG_COL132 0x08 96#define HGA_GFX_MODE_EN 0x01 97#define HGA_GFX_PAGE_EN 0x02 98 99/* Global locks */ 100 101static spinlock_t hga_reg_lock = SPIN_LOCK_UNLOCKED; 102 103/* Framebuffer driver structures */ 104 105static struct fb_var_screeninfo hga_default_var = { 106 xres: 720, 107 yres: 348, 108 xres_virtual: 720, 109 yres_virtual: 348, 110 xoffset: 0, 111 yoffset: 0, 112 bits_per_pixel: 1, 113 grayscale: 0, 114 red: {0, 1, 0}, 115 green: {0, 1, 0}, 116 blue: {0, 1, 0}, 117 transp: {0, 0, 0}, 118 nonstd: 0, /* (FB_NONSTD_HGA ?) */ 119 activate: 0, 120 height: -1, 121 width: -1, 122 accel_flags: 0, 123 /* pixclock */ 124 /* left_margin, right_margin */ 125 /* upper_margin, lower_margin */ 126 /* hsync_len, vsync_len */ 127 /* sync */ 128 /* vmode */ 129}; 130 131static struct fb_fix_screeninfo hga_fix = { 132 id: "HGA", 133 smem_start: (unsigned long) NULL, 134 smem_len: 0, 135 type: FB_TYPE_PACKED_PIXELS, /* (not sure) */ 136 type_aux: 0, /* (not sure) */ 137 visual: FB_VISUAL_MONO10, 138 xpanstep: 8, 139 ypanstep: 8, 140 ywrapstep: 0, 141 line_length: 90, 142 mmio_start: 0, 143 mmio_len: 0, 144 accel: FB_ACCEL_NONE 145}; 146 147static struct fb_info fb_info; 148static struct display disp; 149 150/* Don't assume that tty1 will be the initial current console. */ 151static int currcon = -1; 152static int release_io_port = 0; 153static int release_io_ports = 0; 154 155#ifdef MODULE 156static char *font = NULL; 157static int nologo = 0; 158#endif 159 160/* ------------------------------------------------------------------------- 161 * 162 * Low level hardware functions 163 * 164 * ------------------------------------------------------------------------- */ 165 166static void write_hga_b(unsigned int val, unsigned char reg) 167{ 168 outb_p(reg, HGA_INDEX_PORT); 169 outb_p(val, HGA_VALUE_PORT); 170} 171 172static void write_hga_w(unsigned int val, unsigned char reg) 173{ 174 outb_p(reg, HGA_INDEX_PORT); outb_p(val >> 8, HGA_VALUE_PORT); 175 outb_p(reg+1, HGA_INDEX_PORT); outb_p(val & 0xff, HGA_VALUE_PORT); 176} 177 178static int test_hga_b(unsigned char val, unsigned char reg) 179{ 180 outb_p(reg, HGA_INDEX_PORT); 181 outb (val, HGA_VALUE_PORT); 182 udelay(20); val = (inb_p(HGA_VALUE_PORT) == val); 183 return val; 184} 185 186static void hga_clear_screen(void) 187{ 188 unsigned char fillchar = 0xbf; /* magic */ 189 unsigned long flags; 190 191 spin_lock_irqsave(&hga_reg_lock, flags); 192 if (hga_mode == HGA_TXT) 193 fillchar = ' '; 194 else if (hga_mode == HGA_GFX) 195 fillchar = 0x00; 196 spin_unlock_irqrestore(&hga_reg_lock, flags); 197 if (fillchar != 0xbf) 198 isa_memset_io(hga_vram_base, fillchar, hga_vram_len); 199} 200 201 202#ifdef MODULE 203static void hga_txt_mode(void) 204{ 205 unsigned long flags; 206 207 spin_lock_irqsave(&hga_reg_lock, flags); 208 outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_BLINK_EN, HGA_MODE_PORT); 209 outb_p(0x00, HGA_GFX_PORT); 210 outb_p(0x00, HGA_STATUS_PORT); 211 212 write_hga_b(0x61, 0x00); /* horizontal total */ 213 write_hga_b(0x50, 0x01); /* horizontal displayed */ 214 write_hga_b(0x52, 0x02); /* horizontal sync pos */ 215 write_hga_b(0x0f, 0x03); /* horizontal sync width */ 216 217 write_hga_b(0x19, 0x04); /* vertical total */ 218 write_hga_b(0x06, 0x05); /* vertical total adjust */ 219 write_hga_b(0x19, 0x06); /* vertical displayed */ 220 write_hga_b(0x19, 0x07); /* vertical sync pos */ 221 222 write_hga_b(0x02, 0x08); /* interlace mode */ 223 write_hga_b(0x0d, 0x09); /* maximum scanline */ 224 write_hga_b(0x0c, 0x0a); /* cursor start */ 225 write_hga_b(0x0d, 0x0b); /* cursor end */ 226 227 write_hga_w(0x0000, 0x0c); /* start address */ 228 write_hga_w(0x0000, 0x0e); /* cursor location */ 229 230 hga_mode = HGA_TXT; 231 spin_unlock_irqrestore(&hga_reg_lock, flags); 232} 233#endif /* MODULE */ 234 235static void hga_gfx_mode(void) 236{ 237 unsigned long flags; 238 239 spin_lock_irqsave(&hga_reg_lock, flags); 240 outb_p(0x00, HGA_STATUS_PORT); 241 outb_p(HGA_GFX_MODE_EN, HGA_GFX_PORT); 242 outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT); 243 244 write_hga_b(0x35, 0x00); /* horizontal total */ 245 write_hga_b(0x2d, 0x01); /* horizontal displayed */ 246 write_hga_b(0x2e, 0x02); /* horizontal sync pos */ 247 write_hga_b(0x07, 0x03); /* horizontal sync width */ 248 249 write_hga_b(0x5b, 0x04); /* vertical total */ 250 write_hga_b(0x02, 0x05); /* vertical total adjust */ 251 write_hga_b(0x57, 0x06); /* vertical displayed */ 252 write_hga_b(0x57, 0x07); /* vertical sync pos */ 253 254 write_hga_b(0x02, 0x08); /* interlace mode */ 255 write_hga_b(0x03, 0x09); /* maximum scanline */ 256 write_hga_b(0x00, 0x0a); /* cursor start */ 257 write_hga_b(0x00, 0x0b); /* cursor end */ 258 259 write_hga_w(0x0000, 0x0c); /* start address */ 260 write_hga_w(0x0000, 0x0e); /* cursor location */ 261 262 hga_mode = HGA_GFX; 263 spin_unlock_irqrestore(&hga_reg_lock, flags); 264} 265 266#ifdef MODULE 267static void hga_show_logo(void) 268{ 269 int x, y; 270 unsigned long dest = hga_vram_base; 271 char *logo = linux_logo_bw; 272 for (y = 134; y < 134 + 80 ; y++) /* this needs some cleanup */ 273 for (x = 0; x < 10 ; x++) 274 isa_writeb(~*(logo++), 275 (dest + (y%4)*8192 + (y>>2)*90 + x + 40)); 276} 277#endif /* MODULE */ 278 279static void hga_pan(unsigned int xoffset, unsigned int yoffset) 280{ 281 unsigned int base; 282 unsigned long flags; 283 284 base = (yoffset / 8) * 90 + xoffset; 285 spin_lock_irqsave(&hga_reg_lock, flags); 286 write_hga_w(base, 0x0c); /* start address */ 287 spin_unlock_irqrestore(&hga_reg_lock, flags); 288 DPRINTK("hga_pan: base:%d\n", base); 289} 290 291static void hga_blank(int blank_mode) 292{ 293 unsigned long flags; 294 295 spin_lock_irqsave(&hga_reg_lock, flags); 296 if (blank_mode) { 297 outb_p(0x00, HGA_MODE_PORT); /* disable video */ 298 } else { 299 outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT); 300 } 301 spin_unlock_irqrestore(&hga_reg_lock, flags); 302} 303 304static int __init hga_card_detect(void) 305{ 306 int count=0; 307 unsigned long p, q; 308 unsigned short p_save, q_save; 309 310 hga_vram_base = 0xb0000; 311 hga_vram_len = 0x08000; 312 313 if (request_region(0x3b0, 12, "hgafb")) 314 release_io_ports = 1; 315 if (request_region(0x3bf, 1, "hgafb")) 316 release_io_port = 1; 317 318 /* do a memory check */ 319 320 p = hga_vram_base; 321 q = hga_vram_base + 0x01000; 322 323 p_save = isa_readw(p); q_save = isa_readw(q); 324 325 isa_writew(0xaa55, p); if (isa_readw(p) == 0xaa55) count++; 326 isa_writew(0x55aa, p); if (isa_readw(p) == 0x55aa) count++; 327 isa_writew(p_save, p); 328 329 if (count != 2) { 330 return 0; 331 } 332 333 /* Ok, there is definitely a card registering at the correct 334 * memory location, so now we do an I/O port test. 335 */ 336 337 if (!test_hga_b(0x66, 0x0f)) { /* cursor low register */ 338 return 0; 339 } 340 if (!test_hga_b(0x99, 0x0f)) { /* cursor low register */ 341 return 0; 342 } 343 344 /* See if the card is a Hercules, by checking whether the vsync 345 * bit of the status register is changing. This test lasts for 346 * approximately 1/10th of a second. 347 */ 348 349 p_save = q_save = inb_p(HGA_STATUS_PORT) & HGA_STATUS_VSYNC; 350 351 for (count=0; count < 50000 && p_save == q_save; count++) { 352 q_save = inb(HGA_STATUS_PORT) & HGA_STATUS_VSYNC; 353 udelay(2); 354 } 355 356 if (p_save == q_save) 357 return 0; 358 359 switch (inb_p(HGA_STATUS_PORT) & 0x70) { 360 case 0x10: 361 hga_type = TYPE_HERCPLUS; 362 hga_type_name = "HerculesPlus"; 363 break; 364 case 0x50: 365 hga_type = TYPE_HERCCOLOR; 366 hga_type_name = "HerculesColor"; 367 break; 368 default: 369 hga_type = TYPE_HERC; 370 hga_type_name = "Hercules"; 371 break; 372 } 373 return 1; 374} 375 376/* ------------------------------------------------------------------------- * 377 * 378 * dispsw functions 379 * 380 * ------------------------------------------------------------------------- */ 381 382/** 383 * hga_get_fix - get the fixed part of the display 384 * @fix:struct fb_fix_screeninfo to fill in 385 * @con:unused 386 * @info:pointer to fb_info object containing info for current hga board 387 * 388 * This wrapper function copies @info->fix to @fix. 389 * A zero is returned on success and %-EINVAL for failure. 390 */ 391 392int hga_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) 393{ 394 CHKINFO(-EINVAL); 395 DPRINTK("hga_get_fix: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info); 396 397 *fix = info->fix; 398 return 0; 399} 400 401/** 402 * hga_get_var - get the user defined part of the display 403 * @var:struct fb_var_screeninfo to fill in 404 * @con:unused 405 * @info:pointer to fb_info object containing info for current hga board 406 * 407 * This wrapper function copies @info->var to @var. 408 * A zero is returned on success and %-EINVAL for failure. 409 */ 410 411int hga_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) 412{ 413 CHKINFO(-EINVAL); 414 DPRINTK("hga_get_var: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info); 415 416 *var = info->var; 417 return 0; 418} 419 420 421int hga_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) 422{ 423 CHKINFO(-EINVAL); 424 DPRINTK("hga_set_var: con:%d, activate:%x, info:0x%x, fb_info:%x\n", con, var->activate, (unsigned)info, (unsigned)&fb_info); 425 426 if (var->xres != 720 || var->yres != 348 || 427 var->xres_virtual != 720 || 428 var->yres_virtual < 348 || var->yres_virtual > 348 + 16 || 429 var->bits_per_pixel != 1 || var->grayscale != 0) { 430 return -EINVAL; 431 } 432 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { 433 info->var = *var; 434 if (info->changevar) 435 (*info->changevar)(con); 436 } 437 return 0; 438} 439 440/** 441 * hga_getcolreg - read color registers 442 * @regno:register index to read out 443 * @red:red value 444 * @green:green value 445 * @blue:blue value 446 * @transp:transparency value 447 * @info:unused 448 * 449 * This callback function is used to read the color registers of a HGA 450 * board. Since we have only two fixed colors, RGB values are 0x0000 451 * for register0 and 0xaaaa for register1. 452 * A zero is returned on success and 1 for failure. 453 */ 454 455static int hga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, 456 u_int *transp, struct fb_info *info) 457{ 458 if (regno == 0) { 459 *red = *green = *blue = 0x0000; 460 *transp = 0; 461 } else if (regno == 1) { 462 *red = *green = *blue = 0xaaaa; 463 *transp = 0; 464 } else 465 return 1; 466 return 0; 467} 468 469/** 470 * hga_get_cmap - get the colormap 471 * @cmap:struct fb_cmap to fill in 472 * @kspc:called from kernel space? 473 * @con:unused 474 * @info:pointer to fb_info object containing info for current hga board 475 * 476 * This wrapper function passes it's input parameters to fb_get_cmap(). 477 * Callback function hga_getcolreg() is used to read the color registers. 478 */ 479 480int hga_get_cmap(struct fb_cmap *cmap, int kspc, int con, 481 struct fb_info *info) 482{ 483 CHKINFO(-EINVAL); 484 DPRINTK("hga_get_cmap: con:%d\n", con); 485 return fb_get_cmap(cmap, kspc, hga_getcolreg, info); 486} 487 488/** 489 * hga_setcolreg - set color registers 490 * @regno:register index to set 491 * @red:red value, unused 492 * @green:green value, unused 493 * @blue:blue value, unused 494 * @transp:transparency value, unused 495 * @info:unused 496 * 497 * This callback function is used to set the color registers of a HGA 498 * board. Since we have only two fixed colors only @regno is checked. 499 * A zero is returned on success and 1 for failure. 500 */ 501 502static int hga_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 503 u_int transp, struct fb_info *info) 504{ 505 if (regno > 1) 506 return 1; 507 return 0; 508} 509 510/** 511 * hga_set_cmap - set the colormap 512 * @cmap:struct fb_cmap to set 513 * @kspc:called from kernel space? 514 * @con:unused 515 * @info:pointer to fb_info object containing info for current hga board 516 * 517 * This wrapper function passes it's input parameters to fb_set_cmap(). 518 * Callback function hga_setcolreg() is used to set the color registers. 519 */ 520 521int hga_set_cmap(struct fb_cmap *cmap, int kspc, int con, 522 struct fb_info *info) 523{ 524 CHKINFO(-EINVAL); 525 DPRINTK("hga_set_cmap: con:%d\n", con); 526 return fb_set_cmap(cmap, kspc, hga_setcolreg, info); 527} 528 529/** 530 * hga_pan_display - pan or wrap the display 531 * @var:contains new xoffset, yoffset and vmode values 532 * @con:unused 533 * @info:pointer to fb_info object containing info for current hga board 534 * 535 * This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP 536 * flag in @var. If input parameters are correct it calls hga_pan() to 537 * program the hardware. @info->var is updated to the new values. 538 * A zero is returned on success and %-EINVAL for failure. 539 */ 540 541int hga_pan_display(struct fb_var_screeninfo *var, int con, 542 struct fb_info *info) 543{ 544 CHKINFO(-EINVAL); 545 DPRINTK("pan_disp: con:%d, wrap:%d, xoff:%d, yoff:%d\n", con, var->vmode & FB_VMODE_YWRAP, var->xoffset, var->yoffset); 546 547 if (var->vmode & FB_VMODE_YWRAP) { 548 if (var->yoffset < 0 || 549 var->yoffset >= info->var.yres_virtual || 550 var->xoffset) 551 return -EINVAL; 552 } else { 553 if (var->xoffset + var->xres > info->var.xres_virtual 554 || var->yoffset + var->yres > info->var.yres_virtual 555 || var->yoffset % 8) 556 return -EINVAL; 557 } 558 559 hga_pan(var->xoffset, var->yoffset); 560 561 info->var.xoffset = var->xoffset; 562 info->var.yoffset = var->yoffset; 563 if (var->vmode & FB_VMODE_YWRAP) 564 info->var.vmode |= FB_VMODE_YWRAP; 565 else 566 info->var.vmode &= ~FB_VMODE_YWRAP; 567 return 0; 568} 569 570 571static struct fb_ops hgafb_ops = { 572 owner: THIS_MODULE, 573 fb_get_fix: hga_get_fix, 574 fb_get_var: hga_get_var, 575 fb_set_var: hga_set_var, 576 fb_get_cmap: hga_get_cmap, 577 fb_set_cmap: hga_set_cmap, 578 fb_pan_display: hga_pan_display, 579}; 580 581 582/* ------------------------------------------------------------------------- * 583 * 584 * Functions in fb_info 585 * 586 * ------------------------------------------------------------------------- */ 587 588/** 589 * hgafbcon_switch - switch console 590 * @con:new console to switch to 591 * @info:pointer to fb_info object containing info for current hga board 592 * 593 * This function should install a new colormap and change the video mode. 594 * Since we have fixed colors and only one video mode we have nothing to 595 * do. 596 * Only console administration is done but it should go to fbcon.c IMHO. 597 * A zero is returned on success and %-EINVAL for failure. 598 */ 599 600static int hgafbcon_switch(int con, struct fb_info *info) 601{ 602 CHKINFO(-EINVAL); 603 DPRINTK("hgafbcon_switch: currcon:%d, con:%d, info:%x, fb_info:%x\n", currcon, con, (unsigned)info, (unsigned)&fb_info); 604 605 /* Save the colormap and video mode */ 606 607 if (currcon != -1) /* this check is absolute necessary! */ 608 memcpy(&fb_display[currcon].var, &info->var, 609 sizeof(struct fb_var_screeninfo)); 610 611 /* Install a new colormap and change the video mode. By default fbcon 612 * sets all the colormaps and video modes to the default values at 613 * bootup. 614 */ 615 616 memcpy(&info->var, &fb_display[con].var, 617 sizeof(struct fb_var_screeninfo)); 618 /* hga_set_var(&info->var, con, &fb_info); is it necessary? */ 619 currcon = con; 620 621 /* Hack to work correctly with XF86_Mono */ 622 hga_gfx_mode(); 623 return 0; 624} 625 626/** 627 * hgafbcon_updatevar - update the user defined part of the display 628 * @con:console to update or -1 when no consoles defined on this fb 629 * @info:pointer to fb_info object containing info for current hga board 630 * 631 * This function is called when @var is changed by fbcon.c without calling 632 * hga_set_var(). It usually means scrolling. hga_pan_display() is called 633 * to update the hardware and @info->var. 634 * A zero is returned on success and %-EINVAL for failure. 635 */ 636 637static int hgafbcon_updatevar(int con, struct fb_info *info) 638{ 639 CHKINFO(-EINVAL); 640 DPRINTK("hga_update_var: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info); 641 return (con < 0) ? -EINVAL : hga_pan_display(&fb_display[con].var, con, info); 642} 643 644/** 645 * hgafbcon_blank - (un)blank the screen 646 * @blank_mode:blanking method to use 647 * @info:unused 648 * 649 * Blank the screen if blank_mode != 0, else unblank. 650 * Implements VESA suspend and powerdown modes on hardware that supports 651 * disabling hsync/vsync: 652 * @blank_mode == 2 means suspend vsync, 653 * @blank_mode == 3 means suspend hsync, 654 * @blank_mode == 4 means powerdown. 655 */ 656 657static void hgafbcon_blank(int blank_mode, struct fb_info *info) 658{ 659 CHKINFO( ); 660 DPRINTK("hga_blank: blank_mode:%d, info:%x, fb_info:%x\n", blank_mode, (unsigned)info, (unsigned)&fb_info); 661 662 hga_blank(blank_mode); 663} 664 665 666/* ------------------------------------------------------------------------- */ 667 668 /* 669 * Initialization 670 */ 671 672int __init hgafb_init(void) 673{ 674 if (! hga_card_detect()) { 675 printk(KERN_ERR "hgafb: HGA card not detected.\n"); 676 return -EINVAL; 677 } 678 679 printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n", 680 hga_type_name, hga_vram_len/1024); 681 682 hga_gfx_mode(); 683 hga_clear_screen(); 684#ifdef MODULE 685 if (!nologo) hga_show_logo(); 686#endif /* MODULE */ 687 688 hga_fix.smem_start = VGA_MAP_MEM(hga_vram_base); 689 hga_fix.smem_len = hga_vram_len; 690 691 disp.var = hga_default_var; 692/* disp.cmap = ???; */ 693 disp.screen_base = (char*)hga_fix.smem_start; 694 disp.visual = hga_fix.visual; 695 disp.type = hga_fix.type; 696 disp.type_aux = hga_fix.type_aux; 697 disp.ypanstep = hga_fix.ypanstep; 698 disp.ywrapstep = hga_fix.ywrapstep; 699 disp.line_length = hga_fix.line_length; 700 disp.can_soft_blank = 1; 701 disp.inverse = 0; 702#ifdef FBCON_HAS_HGA 703 disp.dispsw = &fbcon_hga; 704#else 705#warning HGAFB will not work as a console! 706 disp.dispsw = &fbcon_dummy; 707#endif 708 disp.dispsw_data = NULL; 709 710 disp.scrollmode = SCROLL_YREDRAW; 711 712 strcpy (fb_info.modename, hga_fix.id); 713 fb_info.node = -1; 714 fb_info.flags = FBINFO_FLAG_DEFAULT; 715/* fb_info.open = ??? */ 716 fb_info.var = hga_default_var; 717 fb_info.fix = hga_fix; 718 fb_info.monspecs.hfmin = 0; 719 fb_info.monspecs.hfmax = 0; 720 fb_info.monspecs.vfmin = 10000; 721 fb_info.monspecs.vfmax = 10000; 722 fb_info.monspecs.dpms = 0; 723 fb_info.fbops = &hgafb_ops; 724 fb_info.screen_base = (char *)hga_fix.smem_start; 725 fb_info.disp = &disp; 726/* fb_info.display_fg = ??? */ 727/* fb_info.fontname initialized later */ 728 fb_info.changevar = NULL; 729 fb_info.switch_con = hgafbcon_switch; 730 fb_info.updatevar = hgafbcon_updatevar; 731 fb_info.blank = hgafbcon_blank; 732 fb_info.pseudo_palette = NULL; /* ??? */ 733 fb_info.par = NULL; 734 735 if (register_framebuffer(&fb_info) < 0) 736 return -EINVAL; 737 738 printk(KERN_INFO "fb%d: %s frame buffer device\n", 739 GET_FB_IDX(fb_info.node), fb_info.modename); 740 741 return 0; 742} 743 744 /* 745 * Setup 746 */ 747 748#ifndef MODULE 749int __init hgafb_setup(char *options) 750{ 751 /* 752 * Parse user speficied options 753 * `video=hga:font:VGA8x16' or 754 * `video=hga:font:SUN8x16' recommended 755 * Other supported fonts: VGA8x8, Acorn8x8, PEARL8x8 756 * More different fonts can be used with the `setfont' utility. 757 */ 758 759 char *this_opt; 760 761 fb_info.fontname[0] = '\0'; 762 763 if (!options || !*options) 764 return 0; 765 766 while ((this_opt = strsep(&options, ","))) { 767 if (!strncmp(this_opt, "font:", 5)) 768 strcpy(fb_info.fontname, this_opt+5); 769 } 770 return 0; 771} 772#endif /* !MODULE */ 773 774 775 /* 776 * Cleanup 777 */ 778 779#ifdef MODULE 780static void hgafb_cleanup(struct fb_info *info) 781{ 782 hga_txt_mode(); 783 hga_clear_screen(); 784 unregister_framebuffer(info); 785 if (release_io_ports) release_region(0x3b0, 12); 786 if (release_io_port) release_region(0x3bf, 1); 787} 788#endif /* MODULE */ 789 790 791 792/* ------------------------------------------------------------------------- 793 * 794 * Modularization 795 * 796 * ------------------------------------------------------------------------- */ 797 798#ifdef MODULE 799int init_module(void) 800{ 801 if (font) 802 strncpy(fb_info.fontname, font, sizeof(fb_info.fontname)-1); 803 else 804 fb_info.fontname[0] = '\0'; 805 806 return hgafb_init(); 807} 808 809void cleanup_module(void) 810{ 811 hgafb_cleanup(&fb_info); 812} 813 814MODULE_AUTHOR("Ferenc Bakonyi (fero@drama.obuda.kando.hu)"); 815MODULE_DESCRIPTION("FBDev driver for Hercules Graphics Adaptor"); 816MODULE_LICENSE("GPL"); 817 818MODULE_PARM(font, "s"); 819MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (VGA8x8, VGA8x16, SUN8x16, Acorn8x8, PEARL8x8) (default=none)"); 820MODULE_PARM(nologo, "i"); 821MODULE_PARM_DESC(nologo, "Disables startup logo if != 0 (default=0)"); 822 823#endif /* MODULE */ 824