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 #include <linux/types.h>
0030 #include <linux/fs.h>
0031 #include <linux/kernel.h>
0032 #include <linux/module.h>
0033 #include <linux/console.h>
0034 #include <linux/string.h>
0035 #include <linux/kd.h>
0036 #include <linux/vt_kern.h>
0037 #include <linux/vt_buffer.h>
0038 #include <linux/selection.h>
0039 #include <linux/spinlock.h>
0040 #include <linux/ioport.h>
0041 #include <linux/delay.h>
0042 #include <linux/init.h>
0043
0044 #include <asm/io.h>
0045 #include <asm/vga.h>
0046
0047 static DEFINE_SPINLOCK(mda_lock);
0048
0049
0050
0051 static u16 *mda_vram_base;
0052 static unsigned long mda_vram_len;
0053 static unsigned int mda_num_columns;
0054 static unsigned int mda_num_lines;
0055
0056 static unsigned int mda_index_port;
0057 static unsigned int mda_value_port;
0058 static unsigned int mda_mode_port;
0059 static unsigned int mda_status_port;
0060 static unsigned int mda_gfx_port;
0061
0062
0063
0064 static int mda_cursor_loc=-1;
0065 static int mda_cursor_size_from=-1;
0066 static int mda_cursor_size_to=-1;
0067
0068 static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type;
0069 static char *mda_type_name;
0070
0071
0072
0073 static int mda_first_vc = 13;
0074 static int mda_last_vc = 16;
0075
0076 static struct vc_data *mda_display_fg = NULL;
0077
0078 module_param(mda_first_vc, int, 0);
0079 MODULE_PARM_DESC(mda_first_vc, "First virtual console. Default: 13");
0080 module_param(mda_last_vc, int, 0);
0081 MODULE_PARM_DESC(mda_last_vc, "Last virtual console. Default: 16");
0082
0083
0084
0085
0086 #define MDA_CURSOR_BLINKING 0x00
0087 #define MDA_CURSOR_OFF 0x20
0088 #define MDA_CURSOR_SLOWBLINK 0x60
0089
0090 #define MDA_MODE_GRAPHICS 0x02
0091 #define MDA_MODE_VIDEO_EN 0x08
0092 #define MDA_MODE_BLINK_EN 0x20
0093 #define MDA_MODE_GFX_PAGE1 0x80
0094
0095 #define MDA_STATUS_HSYNC 0x01
0096 #define MDA_STATUS_VSYNC 0x80
0097 #define MDA_STATUS_VIDEO 0x08
0098
0099 #define MDA_CONFIG_COL132 0x08
0100 #define MDA_GFX_MODE_EN 0x01
0101 #define MDA_GFX_PAGE_EN 0x02
0102
0103
0104
0105
0106
0107
0108 static void write_mda_b(unsigned int val, unsigned char reg)
0109 {
0110 unsigned long flags;
0111
0112 spin_lock_irqsave(&mda_lock, flags);
0113
0114 outb_p(reg, mda_index_port);
0115 outb_p(val, mda_value_port);
0116
0117 spin_unlock_irqrestore(&mda_lock, flags);
0118 }
0119
0120 static void write_mda_w(unsigned int val, unsigned char reg)
0121 {
0122 unsigned long flags;
0123
0124 spin_lock_irqsave(&mda_lock, flags);
0125
0126 outb_p(reg, mda_index_port); outb_p(val >> 8, mda_value_port);
0127 outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port);
0128
0129 spin_unlock_irqrestore(&mda_lock, flags);
0130 }
0131
0132 #ifdef TEST_MDA_B
0133 static int test_mda_b(unsigned char val, unsigned char reg)
0134 {
0135 unsigned long flags;
0136
0137 spin_lock_irqsave(&mda_lock, flags);
0138
0139 outb_p(reg, mda_index_port);
0140 outb (val, mda_value_port);
0141
0142 udelay(20); val = (inb_p(mda_value_port) == val);
0143
0144 spin_unlock_irqrestore(&mda_lock, flags);
0145 return val;
0146 }
0147 #endif
0148
0149 static inline void mda_set_cursor(unsigned int location)
0150 {
0151 if (mda_cursor_loc == location)
0152 return;
0153
0154 write_mda_w(location >> 1, 0x0e);
0155
0156 mda_cursor_loc = location;
0157 }
0158
0159 static inline void mda_set_cursor_size(int from, int to)
0160 {
0161 if (mda_cursor_size_from==from && mda_cursor_size_to==to)
0162 return;
0163
0164 if (from > to) {
0165 write_mda_b(MDA_CURSOR_OFF, 0x0a);
0166 } else {
0167 write_mda_b(from, 0x0a);
0168 write_mda_b(to, 0x0b);
0169 }
0170
0171 mda_cursor_size_from = from;
0172 mda_cursor_size_to = to;
0173 }
0174
0175
0176 #ifndef MODULE
0177 static int __init mdacon_setup(char *str)
0178 {
0179
0180
0181 int ints[3];
0182
0183 str = get_options(str, ARRAY_SIZE(ints), ints);
0184
0185 if (ints[0] < 2)
0186 return 0;
0187
0188 if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES ||
0189 ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
0190 return 0;
0191
0192 mda_first_vc = ints[1];
0193 mda_last_vc = ints[2];
0194 return 1;
0195 }
0196
0197 __setup("mdacon=", mdacon_setup);
0198 #endif
0199
0200 static int mda_detect(void)
0201 {
0202 int count=0;
0203 u16 *p, p_save;
0204 u16 *q, q_save;
0205
0206
0207
0208 p = mda_vram_base;
0209 q = mda_vram_base + 0x01000 / 2;
0210
0211 p_save = scr_readw(p);
0212 q_save = scr_readw(q);
0213
0214 scr_writew(0xAA55, p);
0215 if (scr_readw(p) == 0xAA55)
0216 count++;
0217
0218 scr_writew(0x55AA, p);
0219 if (scr_readw(p) == 0x55AA)
0220 count++;
0221
0222 scr_writew(p_save, p);
0223
0224 if (count != 2) {
0225 return 0;
0226 }
0227
0228
0229
0230 scr_writew(0xA55A, q);
0231 scr_writew(0x0000, p);
0232 if (scr_readw(q) == 0xA55A)
0233 count++;
0234
0235 scr_writew(0x5AA5, q);
0236 scr_writew(0x0000, p);
0237 if (scr_readw(q) == 0x5AA5)
0238 count++;
0239
0240 scr_writew(p_save, p);
0241 scr_writew(q_save, q);
0242
0243 if (count == 4) {
0244 mda_vram_len = 0x02000;
0245 }
0246
0247
0248
0249
0250
0251 #ifdef TEST_MDA_B
0252
0253
0254
0255 if (!test_mda_b(0x66, 0x0f))
0256 return 0;
0257
0258
0259 if (!test_mda_b(0x99, 0x0f))
0260 return 0;
0261 #endif
0262
0263
0264
0265
0266
0267
0268 p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC;
0269
0270 for (count = 0; count < 50000 && p_save == q_save; count++) {
0271 q_save = inb(mda_status_port) & MDA_STATUS_VSYNC;
0272 udelay(2);
0273 }
0274
0275 if (p_save != q_save) {
0276 switch (inb_p(mda_status_port) & 0x70) {
0277 case 0x10:
0278 mda_type = TYPE_HERCPLUS;
0279 mda_type_name = "HerculesPlus";
0280 break;
0281 case 0x50:
0282 mda_type = TYPE_HERCCOLOR;
0283 mda_type_name = "HerculesColor";
0284 break;
0285 default:
0286 mda_type = TYPE_HERC;
0287 mda_type_name = "Hercules";
0288 break;
0289 }
0290 }
0291
0292 return 1;
0293 }
0294
0295 static void mda_initialize(void)
0296 {
0297 write_mda_b(97, 0x00);
0298 write_mda_b(80, 0x01);
0299 write_mda_b(82, 0x02);
0300 write_mda_b(15, 0x03);
0301
0302 write_mda_b(25, 0x04);
0303 write_mda_b(6, 0x05);
0304 write_mda_b(25, 0x06);
0305 write_mda_b(25, 0x07);
0306
0307 write_mda_b(2, 0x08);
0308 write_mda_b(13, 0x09);
0309 write_mda_b(12, 0x0a);
0310 write_mda_b(13, 0x0b);
0311
0312 write_mda_w(0x0000, 0x0c);
0313 write_mda_w(0x0000, 0x0e);
0314
0315 outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
0316 outb_p(0x00, mda_status_port);
0317 outb_p(0x00, mda_gfx_port);
0318 }
0319
0320 static const char *mdacon_startup(void)
0321 {
0322 mda_num_columns = 80;
0323 mda_num_lines = 25;
0324
0325 mda_vram_len = 0x01000;
0326 mda_vram_base = (u16 *)VGA_MAP_MEM(0xb0000, mda_vram_len);
0327
0328 mda_index_port = 0x3b4;
0329 mda_value_port = 0x3b5;
0330 mda_mode_port = 0x3b8;
0331 mda_status_port = 0x3ba;
0332 mda_gfx_port = 0x3bf;
0333
0334 mda_type = TYPE_MDA;
0335 mda_type_name = "MDA";
0336
0337 if (! mda_detect()) {
0338 printk("mdacon: MDA card not detected.\n");
0339 return NULL;
0340 }
0341
0342 if (mda_type != TYPE_MDA) {
0343 mda_initialize();
0344 }
0345
0346
0347 mda_set_cursor(mda_vram_len - 1);
0348
0349 printk("mdacon: %s with %ldK of memory detected.\n",
0350 mda_type_name, mda_vram_len/1024);
0351
0352 return "MDA-2";
0353 }
0354
0355 static void mdacon_init(struct vc_data *c, int init)
0356 {
0357 c->vc_complement_mask = 0x0800;
0358 c->vc_display_fg = &mda_display_fg;
0359
0360 if (init) {
0361 c->vc_cols = mda_num_columns;
0362 c->vc_rows = mda_num_lines;
0363 } else
0364 vc_resize(c, mda_num_columns, mda_num_lines);
0365
0366
0367
0368 if (mda_display_fg == NULL)
0369 mda_display_fg = c;
0370 }
0371
0372 static void mdacon_deinit(struct vc_data *c)
0373 {
0374
0375
0376 if (mda_display_fg == c)
0377 mda_display_fg = NULL;
0378 }
0379
0380 static inline u16 mda_convert_attr(u16 ch)
0381 {
0382 u16 attr = 0x0700;
0383
0384
0385
0386
0387
0388
0389 if (ch & 0x0800) attr = 0x7000;
0390 else if (ch & 0x0400) attr = 0x0100;
0391
0392 return ((ch & 0x0200) << 2) |
0393 (ch & 0x8000) |
0394 (ch & 0x00ff) | attr;
0395 }
0396
0397 static u8 mdacon_build_attr(struct vc_data *c, u8 color,
0398 enum vc_intensity intensity,
0399 bool blink, bool underline, bool reverse,
0400 bool italic)
0401 {
0402
0403
0404
0405
0406
0407
0408
0409
0410 return (intensity & VCI_MASK) |
0411 (underline << 2) |
0412 (reverse << 3) |
0413 (italic << 4) |
0414 (blink << 7);
0415 }
0416
0417 static void mdacon_invert_region(struct vc_data *c, u16 *p, int count)
0418 {
0419 for (; count > 0; count--) {
0420 scr_writew(scr_readw(p) ^ 0x0800, p);
0421 p++;
0422 }
0423 }
0424
0425 static inline u16 *mda_addr(unsigned int x, unsigned int y)
0426 {
0427 return mda_vram_base + y * mda_num_columns + x;
0428 }
0429
0430 static void mdacon_putc(struct vc_data *c, int ch, int y, int x)
0431 {
0432 scr_writew(mda_convert_attr(ch), mda_addr(x, y));
0433 }
0434
0435 static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
0436 int count, int y, int x)
0437 {
0438 u16 *dest = mda_addr(x, y);
0439
0440 for (; count > 0; count--) {
0441 scr_writew(mda_convert_attr(scr_readw(s++)), dest++);
0442 }
0443 }
0444
0445 static void mdacon_clear(struct vc_data *c, int y, int x,
0446 int height, int width)
0447 {
0448 u16 *dest = mda_addr(x, y);
0449 u16 eattr = mda_convert_attr(c->vc_video_erase_char);
0450
0451 if (width <= 0 || height <= 0)
0452 return;
0453
0454 if (x==0 && width==mda_num_columns) {
0455 scr_memsetw(dest, eattr, height*width*2);
0456 } else {
0457 for (; height > 0; height--, dest+=mda_num_columns)
0458 scr_memsetw(dest, eattr, width*2);
0459 }
0460 }
0461
0462 static int mdacon_switch(struct vc_data *c)
0463 {
0464 return 1;
0465 }
0466
0467 static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
0468 {
0469 if (mda_type == TYPE_MDA) {
0470 if (blank)
0471 scr_memsetw(mda_vram_base,
0472 mda_convert_attr(c->vc_video_erase_char),
0473 c->vc_screenbuf_size);
0474
0475 return 1;
0476 } else {
0477 if (blank)
0478 outb_p(0x00, mda_mode_port);
0479 else
0480 outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN,
0481 mda_mode_port);
0482 return 0;
0483 }
0484 }
0485
0486 static void mdacon_cursor(struct vc_data *c, int mode)
0487 {
0488 if (mode == CM_ERASE) {
0489 mda_set_cursor(mda_vram_len - 1);
0490 return;
0491 }
0492
0493 mda_set_cursor(c->state.y * mda_num_columns * 2 + c->state.x * 2);
0494
0495 switch (CUR_SIZE(c->vc_cursor_type)) {
0496
0497 case CUR_LOWER_THIRD: mda_set_cursor_size(10, 13); break;
0498 case CUR_LOWER_HALF: mda_set_cursor_size(7, 13); break;
0499 case CUR_TWO_THIRDS: mda_set_cursor_size(4, 13); break;
0500 case CUR_BLOCK: mda_set_cursor_size(1, 13); break;
0501 case CUR_NONE: mda_set_cursor_size(14, 13); break;
0502 default: mda_set_cursor_size(12, 13); break;
0503 }
0504 }
0505
0506 static bool mdacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
0507 enum con_scroll dir, unsigned int lines)
0508 {
0509 u16 eattr = mda_convert_attr(c->vc_video_erase_char);
0510
0511 if (!lines)
0512 return false;
0513
0514 if (lines > c->vc_rows)
0515 lines = c->vc_rows;
0516
0517 switch (dir) {
0518
0519 case SM_UP:
0520 scr_memmovew(mda_addr(0, t), mda_addr(0, t + lines),
0521 (b-t-lines)*mda_num_columns*2);
0522 scr_memsetw(mda_addr(0, b - lines), eattr,
0523 lines*mda_num_columns*2);
0524 break;
0525
0526 case SM_DOWN:
0527 scr_memmovew(mda_addr(0, t + lines), mda_addr(0, t),
0528 (b-t-lines)*mda_num_columns*2);
0529 scr_memsetw(mda_addr(0, t), eattr, lines*mda_num_columns*2);
0530 break;
0531 }
0532
0533 return false;
0534 }
0535
0536
0537
0538
0539
0540
0541 static const struct consw mda_con = {
0542 .owner = THIS_MODULE,
0543 .con_startup = mdacon_startup,
0544 .con_init = mdacon_init,
0545 .con_deinit = mdacon_deinit,
0546 .con_clear = mdacon_clear,
0547 .con_putc = mdacon_putc,
0548 .con_putcs = mdacon_putcs,
0549 .con_cursor = mdacon_cursor,
0550 .con_scroll = mdacon_scroll,
0551 .con_switch = mdacon_switch,
0552 .con_blank = mdacon_blank,
0553 .con_build_attr = mdacon_build_attr,
0554 .con_invert_region = mdacon_invert_region,
0555 };
0556
0557 int __init mda_console_init(void)
0558 {
0559 int err;
0560
0561 if (mda_first_vc > mda_last_vc)
0562 return 1;
0563 console_lock();
0564 err = do_take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
0565 console_unlock();
0566 return err;
0567 }
0568
0569 static void __exit mda_console_exit(void)
0570 {
0571 give_up_console(&mda_con);
0572 }
0573
0574 module_init(mda_console_init);
0575 module_exit(mda_console_exit);
0576
0577 MODULE_LICENSE("GPL");
0578