0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/module.h>
0034 #include <linux/kernel.h>
0035 #include <linux/errno.h>
0036 #include <linux/spinlock.h>
0037 #include <linux/string.h>
0038 #include <linux/mm.h>
0039 #include <linux/delay.h>
0040 #include <linux/fb.h>
0041 #include <linux/init.h>
0042 #include <linux/ioport.h>
0043 #include <linux/platform_device.h>
0044 #include <asm/io.h>
0045 #include <asm/vga.h>
0046
0047 #if 0
0048 #define DPRINTK(args...) printk(KERN_DEBUG __FILE__": " ##args)
0049 #else
0050 #define DPRINTK(args...)
0051 #endif
0052
0053 #if 0
0054 #define CHKINFO(ret) if (info != &fb_info) { printk(KERN_DEBUG __FILE__": This should never happen, line:%d \n", __LINE__); return ret; }
0055 #else
0056 #define CHKINFO(ret)
0057 #endif
0058
0059
0060
0061 static void __iomem *hga_vram;
0062 static unsigned long hga_vram_len;
0063
0064 #define HGA_ROWADDR(row) ((row%4)*8192 + (row>>2)*90)
0065 #define HGA_TXT 0
0066 #define HGA_GFX 1
0067
0068 static inline u8 __iomem * rowaddr(struct fb_info *info, u_int row)
0069 {
0070 return info->screen_base + HGA_ROWADDR(row);
0071 }
0072
0073 static int hga_mode = -1;
0074
0075 static enum { TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } hga_type;
0076 static char *hga_type_name;
0077
0078 #define HGA_INDEX_PORT 0x3b4
0079 #define HGA_VALUE_PORT 0x3b5
0080 #define HGA_MODE_PORT 0x3b8
0081 #define HGA_STATUS_PORT 0x3ba
0082 #define HGA_GFX_PORT 0x3bf
0083
0084
0085
0086 #define HGA_CURSOR_BLINKING 0x00
0087 #define HGA_CURSOR_OFF 0x20
0088 #define HGA_CURSOR_SLOWBLINK 0x60
0089
0090 #define HGA_MODE_GRAPHICS 0x02
0091 #define HGA_MODE_VIDEO_EN 0x08
0092 #define HGA_MODE_BLINK_EN 0x20
0093 #define HGA_MODE_GFX_PAGE1 0x80
0094
0095 #define HGA_STATUS_HSYNC 0x01
0096 #define HGA_STATUS_VSYNC 0x80
0097 #define HGA_STATUS_VIDEO 0x08
0098
0099 #define HGA_CONFIG_COL132 0x08
0100 #define HGA_GFX_MODE_EN 0x01
0101 #define HGA_GFX_PAGE_EN 0x02
0102
0103
0104
0105 static DEFINE_SPINLOCK(hga_reg_lock);
0106
0107
0108
0109 static const struct fb_var_screeninfo hga_default_var = {
0110 .xres = 720,
0111 .yres = 348,
0112 .xres_virtual = 720,
0113 .yres_virtual = 348,
0114 .bits_per_pixel = 1,
0115 .red = {0, 1, 0},
0116 .green = {0, 1, 0},
0117 .blue = {0, 1, 0},
0118 .transp = {0, 0, 0},
0119 .height = -1,
0120 .width = -1,
0121 };
0122
0123 static struct fb_fix_screeninfo hga_fix = {
0124 .id = "HGA",
0125 .type = FB_TYPE_PACKED_PIXELS,
0126 .visual = FB_VISUAL_MONO10,
0127 .xpanstep = 8,
0128 .ypanstep = 8,
0129 .line_length = 90,
0130 .accel = FB_ACCEL_NONE
0131 };
0132
0133
0134 static int release_io_port = 0;
0135 static int release_io_ports = 0;
0136 static bool nologo = 0;
0137
0138
0139
0140
0141
0142
0143
0144 static void write_hga_b(unsigned int val, unsigned char reg)
0145 {
0146 outb_p(reg, HGA_INDEX_PORT);
0147 outb_p(val, HGA_VALUE_PORT);
0148 }
0149
0150 static void write_hga_w(unsigned int val, unsigned char reg)
0151 {
0152 outb_p(reg, HGA_INDEX_PORT); outb_p(val >> 8, HGA_VALUE_PORT);
0153 outb_p(reg+1, HGA_INDEX_PORT); outb_p(val & 0xff, HGA_VALUE_PORT);
0154 }
0155
0156 static int test_hga_b(unsigned char val, unsigned char reg)
0157 {
0158 outb_p(reg, HGA_INDEX_PORT);
0159 outb (val, HGA_VALUE_PORT);
0160 udelay(20); val = (inb_p(HGA_VALUE_PORT) == val);
0161 return val;
0162 }
0163
0164 static void hga_clear_screen(void)
0165 {
0166 unsigned char fillchar = 0xbf;
0167 unsigned long flags;
0168
0169 spin_lock_irqsave(&hga_reg_lock, flags);
0170 if (hga_mode == HGA_TXT)
0171 fillchar = ' ';
0172 else if (hga_mode == HGA_GFX)
0173 fillchar = 0x00;
0174 spin_unlock_irqrestore(&hga_reg_lock, flags);
0175 if (fillchar != 0xbf)
0176 memset_io(hga_vram, fillchar, hga_vram_len);
0177 }
0178
0179 static void hga_txt_mode(void)
0180 {
0181 unsigned long flags;
0182
0183 spin_lock_irqsave(&hga_reg_lock, flags);
0184 outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_BLINK_EN, HGA_MODE_PORT);
0185 outb_p(0x00, HGA_GFX_PORT);
0186 outb_p(0x00, HGA_STATUS_PORT);
0187
0188 write_hga_b(0x61, 0x00);
0189 write_hga_b(0x50, 0x01);
0190 write_hga_b(0x52, 0x02);
0191 write_hga_b(0x0f, 0x03);
0192
0193 write_hga_b(0x19, 0x04);
0194 write_hga_b(0x06, 0x05);
0195 write_hga_b(0x19, 0x06);
0196 write_hga_b(0x19, 0x07);
0197
0198 write_hga_b(0x02, 0x08);
0199 write_hga_b(0x0d, 0x09);
0200 write_hga_b(0x0c, 0x0a);
0201 write_hga_b(0x0d, 0x0b);
0202
0203 write_hga_w(0x0000, 0x0c);
0204 write_hga_w(0x0000, 0x0e);
0205
0206 hga_mode = HGA_TXT;
0207 spin_unlock_irqrestore(&hga_reg_lock, flags);
0208 }
0209
0210 static void hga_gfx_mode(void)
0211 {
0212 unsigned long flags;
0213
0214 spin_lock_irqsave(&hga_reg_lock, flags);
0215 outb_p(0x00, HGA_STATUS_PORT);
0216 outb_p(HGA_GFX_MODE_EN, HGA_GFX_PORT);
0217 outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT);
0218
0219 write_hga_b(0x35, 0x00);
0220 write_hga_b(0x2d, 0x01);
0221 write_hga_b(0x2e, 0x02);
0222 write_hga_b(0x07, 0x03);
0223
0224 write_hga_b(0x5b, 0x04);
0225 write_hga_b(0x02, 0x05);
0226 write_hga_b(0x57, 0x06);
0227 write_hga_b(0x57, 0x07);
0228
0229 write_hga_b(0x02, 0x08);
0230 write_hga_b(0x03, 0x09);
0231 write_hga_b(0x00, 0x0a);
0232 write_hga_b(0x00, 0x0b);
0233
0234 write_hga_w(0x0000, 0x0c);
0235 write_hga_w(0x0000, 0x0e);
0236
0237 hga_mode = HGA_GFX;
0238 spin_unlock_irqrestore(&hga_reg_lock, flags);
0239 }
0240
0241 static void hga_show_logo(struct fb_info *info)
0242 {
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252 }
0253
0254 static void hga_pan(unsigned int xoffset, unsigned int yoffset)
0255 {
0256 unsigned int base;
0257 unsigned long flags;
0258
0259 base = (yoffset / 8) * 90 + xoffset;
0260 spin_lock_irqsave(&hga_reg_lock, flags);
0261 write_hga_w(base, 0x0c);
0262 spin_unlock_irqrestore(&hga_reg_lock, flags);
0263 DPRINTK("hga_pan: base:%d\n", base);
0264 }
0265
0266 static void hga_blank(int blank_mode)
0267 {
0268 unsigned long flags;
0269
0270 spin_lock_irqsave(&hga_reg_lock, flags);
0271 if (blank_mode) {
0272 outb_p(0x00, HGA_MODE_PORT);
0273 } else {
0274 outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT);
0275 }
0276 spin_unlock_irqrestore(&hga_reg_lock, flags);
0277 }
0278
0279 static int hga_card_detect(void)
0280 {
0281 int count = 0;
0282 void __iomem *p, *q;
0283 unsigned short p_save, q_save;
0284
0285 hga_vram_len = 0x08000;
0286
0287 hga_vram = ioremap(0xb0000, hga_vram_len);
0288 if (!hga_vram)
0289 return -ENOMEM;
0290
0291 if (request_region(0x3b0, 12, "hgafb"))
0292 release_io_ports = 1;
0293 if (request_region(0x3bf, 1, "hgafb"))
0294 release_io_port = 1;
0295
0296
0297
0298 p = hga_vram;
0299 q = hga_vram + 0x01000;
0300
0301 p_save = readw(p); q_save = readw(q);
0302
0303 writew(0xaa55, p); if (readw(p) == 0xaa55) count++;
0304 writew(0x55aa, p); if (readw(p) == 0x55aa) count++;
0305 writew(p_save, p);
0306
0307 if (count != 2)
0308 goto error;
0309
0310
0311
0312
0313
0314 if (!test_hga_b(0x66, 0x0f))
0315 goto error;
0316
0317 if (!test_hga_b(0x99, 0x0f))
0318 goto error;
0319
0320
0321
0322
0323
0324
0325 p_save = q_save = inb_p(HGA_STATUS_PORT) & HGA_STATUS_VSYNC;
0326
0327 for (count=0; count < 50000 && p_save == q_save; count++) {
0328 q_save = inb(HGA_STATUS_PORT) & HGA_STATUS_VSYNC;
0329 udelay(2);
0330 }
0331
0332 if (p_save == q_save)
0333 goto error;
0334
0335 switch (inb_p(HGA_STATUS_PORT) & 0x70) {
0336 case 0x10:
0337 hga_type = TYPE_HERCPLUS;
0338 hga_type_name = "HerculesPlus";
0339 break;
0340 case 0x50:
0341 hga_type = TYPE_HERCCOLOR;
0342 hga_type_name = "HerculesColor";
0343 break;
0344 default:
0345 hga_type = TYPE_HERC;
0346 hga_type_name = "Hercules";
0347 break;
0348 }
0349 return 0;
0350 error:
0351 if (release_io_ports)
0352 release_region(0x3b0, 12);
0353 if (release_io_port)
0354 release_region(0x3bf, 1);
0355
0356 iounmap(hga_vram);
0357
0358 pr_err("hgafb: HGA card not detected.\n");
0359
0360 return -EINVAL;
0361 }
0362
0363
0364
0365
0366
0367
0368
0369 static int hgafb_open(struct fb_info *info, int init)
0370 {
0371 hga_gfx_mode();
0372 hga_clear_screen();
0373 if (!nologo) hga_show_logo(info);
0374 return 0;
0375 }
0376
0377
0378
0379
0380
0381
0382
0383 static int hgafb_release(struct fb_info *info, int init)
0384 {
0385 hga_txt_mode();
0386 hga_clear_screen();
0387 return 0;
0388 }
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404 static int hgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0405 u_int transp, struct fb_info *info)
0406 {
0407 if (regno > 1)
0408 return 1;
0409 return 0;
0410 }
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423 static int hgafb_pan_display(struct fb_var_screeninfo *var,
0424 struct fb_info *info)
0425 {
0426 if (var->vmode & FB_VMODE_YWRAP) {
0427 if (var->yoffset >= info->var.yres_virtual ||
0428 var->xoffset)
0429 return -EINVAL;
0430 } else {
0431 if (var->xoffset + info->var.xres > info->var.xres_virtual
0432 || var->yoffset + info->var.yres > info->var.yres_virtual
0433 || var->yoffset % 8)
0434 return -EINVAL;
0435 }
0436
0437 hga_pan(var->xoffset, var->yoffset);
0438 return 0;
0439 }
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454 static int hgafb_blank(int blank_mode, struct fb_info *info)
0455 {
0456 hga_blank(blank_mode);
0457 return 0;
0458 }
0459
0460
0461
0462
0463 static void hgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0464 {
0465 u_int rows, y;
0466 u8 __iomem *dest;
0467
0468 y = rect->dy;
0469
0470 for (rows = rect->height; rows--; y++) {
0471 dest = rowaddr(info, y) + (rect->dx >> 3);
0472 switch (rect->rop) {
0473 case ROP_COPY:
0474 memset_io(dest, rect->color, (rect->width >> 3));
0475 break;
0476 case ROP_XOR:
0477 fb_writeb(~(fb_readb(dest)), dest);
0478 break;
0479 }
0480 }
0481 }
0482
0483 static void hgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
0484 {
0485 u_int rows, y1, y2;
0486 u8 __iomem *src;
0487 u8 __iomem *dest;
0488
0489 if (area->dy <= area->sy) {
0490 y1 = area->sy;
0491 y2 = area->dy;
0492
0493 for (rows = area->height; rows--; ) {
0494 src = rowaddr(info, y1) + (area->sx >> 3);
0495 dest = rowaddr(info, y2) + (area->dx >> 3);
0496 memmove(dest, src, (area->width >> 3));
0497 y1++;
0498 y2++;
0499 }
0500 } else {
0501 y1 = area->sy + area->height - 1;
0502 y2 = area->dy + area->height - 1;
0503
0504 for (rows = area->height; rows--;) {
0505 src = rowaddr(info, y1) + (area->sx >> 3);
0506 dest = rowaddr(info, y2) + (area->dx >> 3);
0507 memmove(dest, src, (area->width >> 3));
0508 y1--;
0509 y2--;
0510 }
0511 }
0512 }
0513
0514 static void hgafb_imageblit(struct fb_info *info, const struct fb_image *image)
0515 {
0516 u8 __iomem *dest;
0517 u8 *cdat = (u8 *) image->data;
0518 u_int rows, y = image->dy;
0519 u_int x;
0520 u8 d;
0521
0522 for (rows = image->height; rows--; y++) {
0523 for (x = 0; x < image->width; x+= 8) {
0524 d = *cdat++;
0525 dest = rowaddr(info, y) + ((image->dx + x)>> 3);
0526 fb_writeb(d, dest);
0527 }
0528 }
0529 }
0530
0531 static const struct fb_ops hgafb_ops = {
0532 .owner = THIS_MODULE,
0533 .fb_open = hgafb_open,
0534 .fb_release = hgafb_release,
0535 .fb_setcolreg = hgafb_setcolreg,
0536 .fb_pan_display = hgafb_pan_display,
0537 .fb_blank = hgafb_blank,
0538 .fb_fillrect = hgafb_fillrect,
0539 .fb_copyarea = hgafb_copyarea,
0540 .fb_imageblit = hgafb_imageblit,
0541 };
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555 static int hgafb_probe(struct platform_device *pdev)
0556 {
0557 struct fb_info *info;
0558 int ret;
0559
0560 ret = hga_card_detect();
0561 if (ret)
0562 return ret;
0563
0564 printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n",
0565 hga_type_name, hga_vram_len/1024);
0566
0567 info = framebuffer_alloc(0, &pdev->dev);
0568 if (!info) {
0569 iounmap(hga_vram);
0570 return -ENOMEM;
0571 }
0572
0573 hga_fix.smem_start = (unsigned long)hga_vram;
0574 hga_fix.smem_len = hga_vram_len;
0575
0576 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
0577 info->var = hga_default_var;
0578 info->fix = hga_fix;
0579 info->monspecs.hfmin = 0;
0580 info->monspecs.hfmax = 0;
0581 info->monspecs.vfmin = 10000;
0582 info->monspecs.vfmax = 10000;
0583 info->monspecs.dpms = 0;
0584 info->fbops = &hgafb_ops;
0585 info->screen_base = hga_vram;
0586
0587 if (register_framebuffer(info) < 0) {
0588 framebuffer_release(info);
0589 iounmap(hga_vram);
0590 return -EINVAL;
0591 }
0592
0593 fb_info(info, "%s frame buffer device\n", info->fix.id);
0594 platform_set_drvdata(pdev, info);
0595 return 0;
0596 }
0597
0598 static int hgafb_remove(struct platform_device *pdev)
0599 {
0600 struct fb_info *info = platform_get_drvdata(pdev);
0601
0602 hga_txt_mode();
0603 hga_clear_screen();
0604
0605 if (info) {
0606 unregister_framebuffer(info);
0607 framebuffer_release(info);
0608 }
0609
0610 iounmap(hga_vram);
0611
0612 if (release_io_ports)
0613 release_region(0x3b0, 12);
0614
0615 if (release_io_port)
0616 release_region(0x3bf, 1);
0617
0618 return 0;
0619 }
0620
0621 static struct platform_driver hgafb_driver = {
0622 .probe = hgafb_probe,
0623 .remove = hgafb_remove,
0624 .driver = {
0625 .name = "hgafb",
0626 },
0627 };
0628
0629 static struct platform_device *hgafb_device;
0630
0631 static int __init hgafb_init(void)
0632 {
0633 int ret;
0634
0635 if (fb_get_options("hgafb", NULL))
0636 return -ENODEV;
0637
0638 ret = platform_driver_register(&hgafb_driver);
0639
0640 if (!ret) {
0641 hgafb_device = platform_device_register_simple("hgafb", 0, NULL, 0);
0642
0643 if (IS_ERR(hgafb_device)) {
0644 platform_driver_unregister(&hgafb_driver);
0645 ret = PTR_ERR(hgafb_device);
0646 }
0647 }
0648
0649 return ret;
0650 }
0651
0652 static void __exit hgafb_exit(void)
0653 {
0654 platform_device_unregister(hgafb_device);
0655 platform_driver_unregister(&hgafb_driver);
0656 }
0657
0658
0659
0660
0661
0662
0663
0664 MODULE_AUTHOR("Ferenc Bakonyi (fero@drama.obuda.kando.hu)");
0665 MODULE_DESCRIPTION("FBDev driver for Hercules Graphics Adaptor");
0666 MODULE_LICENSE("GPL");
0667
0668 module_param(nologo, bool, 0);
0669 MODULE_PARM_DESC(nologo, "Disables startup logo if != 0 (default=0)");
0670 module_init(hgafb_init);
0671 module_exit(hgafb_exit);