1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#include <linux/module.h>
37#include <linux/types.h>
38#include <linux/fs.h>
39#include <linux/kernel.h>
40#include <linux/console.h>
41#include <linux/string.h>
42#include <linux/kd.h>
43#include <linux/slab.h>
44#include <linux/vt_kern.h>
45#include <linux/selection.h>
46#include <linux/spinlock.h>
47#include <linux/ioport.h>
48#include <linux/init.h>
49#include <linux/screen_info.h>
50#include <linux/smp_lock.h>
51#include <video/vga.h>
52#include <asm/io.h>
53
54static DEFINE_SPINLOCK(vga_lock);
55static int cursor_size_lastfrom;
56static int cursor_size_lastto;
57static u32 vgacon_xres;
58static u32 vgacon_yres;
59static struct vgastate state;
60
61#define BLANK 0x0020
62
63#define CAN_LOAD_EGA_FONTS
64#define CAN_LOAD_PALETTE
65
66
67
68
69
70
71#undef TRIDENT_GLITCH
72#define VGA_FONTWIDTH 8
73
74
75
76
77static const char *vgacon_startup(void);
78static void vgacon_init(struct vc_data *c, int init);
79static void vgacon_deinit(struct vc_data *c);
80static void vgacon_cursor(struct vc_data *c, int mode);
81static int vgacon_switch(struct vc_data *c);
82static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
83static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);
84static int vgacon_scrolldelta(struct vc_data *c, int lines);
85static int vgacon_set_origin(struct vc_data *c);
86static void vgacon_save_screen(struct vc_data *c);
87static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
88 int lines);
89static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
90static unsigned long vgacon_uni_pagedir[2];
91
92
93static int vga_init_done __read_mostly;
94static unsigned long vga_vram_base __read_mostly;
95static unsigned long vga_vram_end __read_mostly;
96static unsigned int vga_vram_size __read_mostly;
97static u16 vga_video_port_reg __read_mostly;
98static u16 vga_video_port_val __read_mostly;
99static unsigned int vga_video_num_columns;
100static unsigned int vga_video_num_lines;
101static int vga_can_do_color __read_mostly;
102static unsigned int vga_default_font_height __read_mostly;
103static unsigned char vga_video_type __read_mostly;
104static unsigned char vga_hardscroll_enabled __read_mostly;
105static unsigned char vga_hardscroll_user_enable __read_mostly = 1;
106static unsigned char vga_font_is_default = 1;
107static int vga_vesa_blanked;
108static int vga_palette_blanked;
109static int vga_is_gfx;
110static int vga_512_chars;
111static int vga_video_font_height;
112static int vga_scan_lines __read_mostly;
113static unsigned int vga_rolled_over;
114
115int vgacon_text_mode_force = 0;
116
117bool vgacon_text_force(void)
118{
119 return vgacon_text_mode_force ? true : false;
120}
121EXPORT_SYMBOL(vgacon_text_force);
122
123static int __init text_mode(char *str)
124{
125 vgacon_text_mode_force = 1;
126 return 1;
127}
128
129
130__setup("nomodeset", text_mode);
131
132static int __init no_scroll(char *str)
133{
134
135
136
137
138
139 vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
140 return 1;
141}
142
143__setup("no-scroll", no_scroll);
144
145
146
147
148
149
150
151
152static inline void write_vga(unsigned char reg, unsigned int val)
153{
154 unsigned int v1, v2;
155 unsigned long flags;
156
157
158
159
160
161 spin_lock_irqsave(&vga_lock, flags);
162
163#ifndef SLOW_VGA
164 v1 = reg + (val & 0xff00);
165 v2 = reg + 1 + ((val << 8) & 0xff00);
166 outw(v1, vga_video_port_reg);
167 outw(v2, vga_video_port_reg);
168#else
169 outb_p(reg, vga_video_port_reg);
170 outb_p(val >> 8, vga_video_port_val);
171 outb_p(reg + 1, vga_video_port_reg);
172 outb_p(val & 0xff, vga_video_port_val);
173#endif
174 spin_unlock_irqrestore(&vga_lock, flags);
175}
176
177static inline void vga_set_mem_top(struct vc_data *c)
178{
179 write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
180}
181
182#ifdef CONFIG_VGACON_SOFT_SCROLLBACK
183
184static void *vgacon_scrollback;
185static int vgacon_scrollback_tail;
186static int vgacon_scrollback_size;
187static int vgacon_scrollback_rows;
188static int vgacon_scrollback_cnt;
189static int vgacon_scrollback_cur;
190static int vgacon_scrollback_save;
191static int vgacon_scrollback_restore;
192
193static void vgacon_scrollback_init(int pitch)
194{
195 int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch;
196
197 if (vgacon_scrollback) {
198 vgacon_scrollback_cnt = 0;
199 vgacon_scrollback_tail = 0;
200 vgacon_scrollback_cur = 0;
201 vgacon_scrollback_rows = rows - 1;
202 vgacon_scrollback_size = rows * pitch;
203 }
204}
205
206
207
208
209
210static void __init_refok vgacon_scrollback_startup(void)
211{
212 vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT);
213 vgacon_scrollback_init(vga_video_num_columns * 2);
214}
215
216static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
217{
218 void *p;
219
220 if (!vgacon_scrollback_size || c->vc_num != fg_console)
221 return;
222
223 p = (void *) (c->vc_origin + t * c->vc_size_row);
224
225 while (count--) {
226 scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail,
227 p, c->vc_size_row);
228 vgacon_scrollback_cnt++;
229 p += c->vc_size_row;
230 vgacon_scrollback_tail += c->vc_size_row;
231
232 if (vgacon_scrollback_tail >= vgacon_scrollback_size)
233 vgacon_scrollback_tail = 0;
234
235 if (vgacon_scrollback_cnt > vgacon_scrollback_rows)
236 vgacon_scrollback_cnt = vgacon_scrollback_rows;
237
238 vgacon_scrollback_cur = vgacon_scrollback_cnt;
239 }
240}
241
242static void vgacon_restore_screen(struct vc_data *c)
243{
244 vgacon_scrollback_save = 0;
245
246 if (!vga_is_gfx && !vgacon_scrollback_restore) {
247 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
248 c->vc_screenbuf_size > vga_vram_size ?
249 vga_vram_size : c->vc_screenbuf_size);
250 vgacon_scrollback_restore = 1;
251 vgacon_scrollback_cur = vgacon_scrollback_cnt;
252 }
253}
254
255static int vgacon_scrolldelta(struct vc_data *c, int lines)
256{
257 int start, end, count, soff;
258
259 if (!lines) {
260 c->vc_visible_origin = c->vc_origin;
261 vga_set_mem_top(c);
262 return 1;
263 }
264
265 if (!vgacon_scrollback)
266 return 1;
267
268 if (!vgacon_scrollback_save) {
269 vgacon_cursor(c, CM_ERASE);
270 vgacon_save_screen(c);
271 vgacon_scrollback_save = 1;
272 }
273
274 vgacon_scrollback_restore = 0;
275 start = vgacon_scrollback_cur + lines;
276 end = start + abs(lines);
277
278 if (start < 0)
279 start = 0;
280
281 if (start > vgacon_scrollback_cnt)
282 start = vgacon_scrollback_cnt;
283
284 if (end < 0)
285 end = 0;
286
287 if (end > vgacon_scrollback_cnt)
288 end = vgacon_scrollback_cnt;
289
290 vgacon_scrollback_cur = start;
291 count = end - start;
292 soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) *
293 c->vc_size_row);
294 soff -= count * c->vc_size_row;
295
296 if (soff < 0)
297 soff += vgacon_scrollback_size;
298
299 count = vgacon_scrollback_cnt - start;
300
301 if (count > c->vc_rows)
302 count = c->vc_rows;
303
304 if (count) {
305 int copysize;
306
307 int diff = c->vc_rows - count;
308 void *d = (void *) c->vc_origin;
309 void *s = (void *) c->vc_screenbuf;
310
311 count *= c->vc_size_row;
312
313 copysize = min(count, vgacon_scrollback_size - soff);
314 scr_memcpyw(d, vgacon_scrollback + soff, copysize);
315 d += copysize;
316 count -= copysize;
317
318 if (count) {
319 scr_memcpyw(d, vgacon_scrollback, count);
320 d += count;
321 }
322
323 if (diff)
324 scr_memcpyw(d, s, diff * c->vc_size_row);
325 } else
326 vgacon_cursor(c, CM_MOVE);
327
328 return 1;
329}
330#else
331#define vgacon_scrollback_startup(...) do { } while (0)
332#define vgacon_scrollback_init(...) do { } while (0)
333#define vgacon_scrollback_update(...) do { } while (0)
334
335static void vgacon_restore_screen(struct vc_data *c)
336{
337 if (c->vc_origin != c->vc_visible_origin)
338 vgacon_scrolldelta(c, 0);
339}
340
341static int vgacon_scrolldelta(struct vc_data *c, int lines)
342{
343 if (!lines)
344 c->vc_visible_origin = c->vc_origin;
345 else {
346 int margin = c->vc_size_row * 4;
347 int ul, we, p, st;
348
349 if (vga_rolled_over >
350 (c->vc_scr_end - vga_vram_base) + margin) {
351 ul = c->vc_scr_end - vga_vram_base;
352 we = vga_rolled_over + c->vc_size_row;
353 } else {
354 ul = 0;
355 we = vga_vram_size;
356 }
357 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
358 lines * c->vc_size_row;
359 st = (c->vc_origin - vga_vram_base - ul + we) % we;
360 if (st < 2 * margin)
361 margin = 0;
362 if (p < margin)
363 p = 0;
364 if (p > st - margin)
365 p = st;
366 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
367 }
368 vga_set_mem_top(c);
369 return 1;
370}
371#endif
372
373static const char *vgacon_startup(void)
374{
375 const char *display_desc = NULL;
376 u16 saved1, saved2;
377 volatile u16 *p;
378
379 if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) {
380 no_vga:
381#ifdef CONFIG_DUMMY_CONSOLE
382 conswitchp = &dummy_con;
383 return conswitchp->con_startup();
384#else
385 return NULL;
386#endif
387 }
388
389
390 if ((screen_info.orig_video_mode == 0) &&
391 (screen_info.orig_video_lines == 0) &&
392 (screen_info.orig_video_cols == 0))
393 goto no_vga;
394
395
396 if ((screen_info.orig_video_mode == 0x0D) ||
397 (screen_info.orig_video_mode == 0x0E) ||
398 (screen_info.orig_video_mode == 0x10) ||
399 (screen_info.orig_video_mode == 0x12) ||
400 (screen_info.orig_video_mode == 0x6A))
401 goto no_vga;
402
403 vga_video_num_lines = screen_info.orig_video_lines;
404 vga_video_num_columns = screen_info.orig_video_cols;
405 state.vgabase = NULL;
406
407 if (screen_info.orig_video_mode == 7) {
408
409 vga_vram_base = 0xb0000;
410 vga_video_port_reg = VGA_CRT_IM;
411 vga_video_port_val = VGA_CRT_DM;
412 if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
413 static struct resource ega_console_resource =
414 { .name = "ega", .start = 0x3B0, .end = 0x3BF };
415 vga_video_type = VIDEO_TYPE_EGAM;
416 vga_vram_size = 0x8000;
417 display_desc = "EGA+";
418 request_resource(&ioport_resource,
419 &ega_console_resource);
420 } else {
421 static struct resource mda1_console_resource =
422 { .name = "mda", .start = 0x3B0, .end = 0x3BB };
423 static struct resource mda2_console_resource =
424 { .name = "mda", .start = 0x3BF, .end = 0x3BF };
425 vga_video_type = VIDEO_TYPE_MDA;
426 vga_vram_size = 0x2000;
427 display_desc = "*MDA";
428 request_resource(&ioport_resource,
429 &mda1_console_resource);
430 request_resource(&ioport_resource,
431 &mda2_console_resource);
432 vga_video_font_height = 14;
433 }
434 } else {
435
436 vga_can_do_color = 1;
437 vga_vram_base = 0xb8000;
438 vga_video_port_reg = VGA_CRT_IC;
439 vga_video_port_val = VGA_CRT_DC;
440 if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
441 int i;
442
443 vga_vram_size = 0x8000;
444
445 if (!screen_info.orig_video_isVGA) {
446 static struct resource ega_console_resource
447 = { .name = "ega", .start = 0x3C0, .end = 0x3DF };
448 vga_video_type = VIDEO_TYPE_EGAC;
449 display_desc = "EGA";
450 request_resource(&ioport_resource,
451 &ega_console_resource);
452 } else {
453 static struct resource vga_console_resource
454 = { .name = "vga+", .start = 0x3C0, .end = 0x3DF };
455 vga_video_type = VIDEO_TYPE_VGAC;
456 display_desc = "VGA+";
457 request_resource(&ioport_resource,
458 &vga_console_resource);
459
460#ifdef VGA_CAN_DO_64KB
461
462
463
464
465
466
467 vga_vram_base = 0xa0000;
468 vga_vram_size = 0x10000;
469 outb_p(6, VGA_GFX_I);
470 outb_p(6, VGA_GFX_D);
471#endif
472
473
474
475
476
477
478 for (i = 0; i < 16; i++) {
479 inb_p(VGA_IS1_RC);
480 outb_p(i, VGA_ATT_W);
481 outb_p(i, VGA_ATT_W);
482 }
483 outb_p(0x20, VGA_ATT_W);
484
485
486
487
488
489 for (i = 0; i < 16; i++) {
490 outb_p(color_table[i], VGA_PEL_IW);
491 outb_p(default_red[i], VGA_PEL_D);
492 outb_p(default_grn[i], VGA_PEL_D);
493 outb_p(default_blu[i], VGA_PEL_D);
494 }
495 }
496 } else {
497 static struct resource cga_console_resource =
498 { .name = "cga", .start = 0x3D4, .end = 0x3D5 };
499 vga_video_type = VIDEO_TYPE_CGA;
500 vga_vram_size = 0x2000;
501 display_desc = "*CGA";
502 request_resource(&ioport_resource,
503 &cga_console_resource);
504 vga_video_font_height = 8;
505 }
506 }
507
508 vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
509 vga_vram_end = vga_vram_base + vga_vram_size;
510
511
512
513
514
515 p = (volatile u16 *) vga_vram_base;
516 saved1 = scr_readw(p);
517 saved2 = scr_readw(p + 1);
518 scr_writew(0xAA55, p);
519 scr_writew(0x55AA, p + 1);
520 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
521 scr_writew(saved1, p);
522 scr_writew(saved2, p + 1);
523 goto no_vga;
524 }
525 scr_writew(0x55AA, p);
526 scr_writew(0xAA55, p + 1);
527 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
528 scr_writew(saved1, p);
529 scr_writew(saved2, p + 1);
530 goto no_vga;
531 }
532 scr_writew(saved1, p);
533 scr_writew(saved2, p + 1);
534
535 if (vga_video_type == VIDEO_TYPE_EGAC
536 || vga_video_type == VIDEO_TYPE_VGAC
537 || vga_video_type == VIDEO_TYPE_EGAM) {
538 vga_hardscroll_enabled = vga_hardscroll_user_enable;
539 vga_default_font_height = screen_info.orig_video_points;
540 vga_video_font_height = screen_info.orig_video_points;
541
542 vga_scan_lines =
543 vga_video_font_height * vga_video_num_lines;
544 }
545
546 vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
547 vgacon_yres = vga_scan_lines;
548
549 if (!vga_init_done) {
550 vgacon_scrollback_startup();
551 vga_init_done = 1;
552 }
553
554 return display_desc;
555}
556
557static void vgacon_init(struct vc_data *c, int init)
558{
559 unsigned long p;
560
561
562
563
564
565
566 c->vc_can_do_color = vga_can_do_color;
567
568
569 if (init) {
570 c->vc_cols = vga_video_num_columns;
571 c->vc_rows = vga_video_num_lines;
572 } else
573 vc_resize(c, vga_video_num_columns, vga_video_num_lines);
574
575 c->vc_scan_lines = vga_scan_lines;
576 c->vc_font.height = vga_video_font_height;
577 c->vc_complement_mask = 0x7700;
578 if (vga_512_chars)
579 c->vc_hi_font_mask = 0x0800;
580 p = *c->vc_uni_pagedir_loc;
581 if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
582 !--c->vc_uni_pagedir_loc[1])
583 con_free_unimap(c);
584 c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
585 vgacon_uni_pagedir[1]++;
586 if (!vgacon_uni_pagedir[0] && p)
587 con_set_default_unimap(c);
588}
589
590static void vgacon_deinit(struct vc_data *c)
591{
592
593 if (CON_IS_VISIBLE(c)) {
594 c->vc_visible_origin = vga_vram_base;
595 vga_set_mem_top(c);
596 }
597
598 if (!--vgacon_uni_pagedir[1])
599 con_free_unimap(c);
600 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
601 con_set_default_unimap(c);
602}
603
604static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
605 u8 blink, u8 underline, u8 reverse, u8 italic)
606{
607 u8 attr = color;
608
609 if (vga_can_do_color) {
610 if (italic)
611 attr = (attr & 0xF0) | c->vc_itcolor;
612 else if (underline)
613 attr = (attr & 0xf0) | c->vc_ulcolor;
614 else if (intensity == 0)
615 attr = (attr & 0xf0) | c->vc_halfcolor;
616 }
617 if (reverse)
618 attr =
619 ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
620 0x77);
621 if (blink)
622 attr ^= 0x80;
623 if (intensity == 2)
624 attr ^= 0x08;
625 if (!vga_can_do_color) {
626 if (italic)
627 attr = (attr & 0xF8) | 0x02;
628 else if (underline)
629 attr = (attr & 0xf8) | 0x01;
630 else if (intensity == 0)
631 attr = (attr & 0xf0) | 0x08;
632 }
633 return attr;
634}
635
636static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
637{
638 int col = vga_can_do_color;
639
640 while (count--) {
641 u16 a = scr_readw(p);
642 if (col)
643 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
644 (((a) & 0x0700) << 4);
645 else
646 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
647 scr_writew(a, p++);
648 }
649}
650
651static void vgacon_set_cursor_size(int xpos, int from, int to)
652{
653 unsigned long flags;
654 int curs, cure;
655
656#ifdef TRIDENT_GLITCH
657 if (xpos < 16)
658 from--, to--;
659#endif
660
661 if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
662 return;
663 cursor_size_lastfrom = from;
664 cursor_size_lastto = to;
665
666 spin_lock_irqsave(&vga_lock, flags);
667 if (vga_video_type >= VIDEO_TYPE_VGAC) {
668 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
669 curs = inb_p(vga_video_port_val);
670 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
671 cure = inb_p(vga_video_port_val);
672 } else {
673 curs = 0;
674 cure = 0;
675 }
676
677 curs = (curs & 0xc0) | from;
678 cure = (cure & 0xe0) | to;
679
680 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
681 outb_p(curs, vga_video_port_val);
682 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
683 outb_p(cure, vga_video_port_val);
684 spin_unlock_irqrestore(&vga_lock, flags);
685}
686
687static void vgacon_cursor(struct vc_data *c, int mode)
688{
689 if (c->vc_mode != KD_TEXT)
690 return;
691
692 vgacon_restore_screen(c);
693
694 switch (mode) {
695 case CM_ERASE:
696 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
697 if (vga_video_type >= VIDEO_TYPE_VGAC)
698 vgacon_set_cursor_size(c->vc_x, 31, 30);
699 else
700 vgacon_set_cursor_size(c->vc_x, 31, 31);
701 break;
702
703 case CM_MOVE:
704 case CM_DRAW:
705 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
706 switch (c->vc_cursor_type & 0x0f) {
707 case CUR_UNDERLINE:
708 vgacon_set_cursor_size(c->vc_x,
709 c->vc_font.height -
710 (c->vc_font.height <
711 10 ? 2 : 3),
712 c->vc_font.height -
713 (c->vc_font.height <
714 10 ? 1 : 2));
715 break;
716 case CUR_TWO_THIRDS:
717 vgacon_set_cursor_size(c->vc_x,
718 c->vc_font.height / 3,
719 c->vc_font.height -
720 (c->vc_font.height <
721 10 ? 1 : 2));
722 break;
723 case CUR_LOWER_THIRD:
724 vgacon_set_cursor_size(c->vc_x,
725 (c->vc_font.height * 2) / 3,
726 c->vc_font.height -
727 (c->vc_font.height <
728 10 ? 1 : 2));
729 break;
730 case CUR_LOWER_HALF:
731 vgacon_set_cursor_size(c->vc_x,
732 c->vc_font.height / 2,
733 c->vc_font.height -
734 (c->vc_font.height <
735 10 ? 1 : 2));
736 break;
737 case CUR_NONE:
738 if (vga_video_type >= VIDEO_TYPE_VGAC)
739 vgacon_set_cursor_size(c->vc_x, 31, 30);
740 else
741 vgacon_set_cursor_size(c->vc_x, 31, 31);
742 break;
743 default:
744 vgacon_set_cursor_size(c->vc_x, 1,
745 c->vc_font.height);
746 break;
747 }
748 break;
749 }
750}
751
752static int vgacon_doresize(struct vc_data *c,
753 unsigned int width, unsigned int height)
754{
755 unsigned long flags;
756 unsigned int scanlines = height * c->vc_font.height;
757 u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
758
759 spin_lock_irqsave(&vga_lock, flags);
760
761 vgacon_xres = width * VGA_FONTWIDTH;
762 vgacon_yres = height * c->vc_font.height;
763 if (vga_video_type >= VIDEO_TYPE_VGAC) {
764 outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
765 max_scan = inb_p(vga_video_port_val);
766
767 if (max_scan & 0x80)
768 scanlines <<= 1;
769
770 outb_p(VGA_CRTC_MODE, vga_video_port_reg);
771 mode = inb_p(vga_video_port_val);
772
773 if (mode & 0x04)
774 scanlines >>= 1;
775
776 scanlines -= 1;
777 scanlines_lo = scanlines & 0xff;
778
779 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
780 r7 = inb_p(vga_video_port_val) & ~0x42;
781
782 if (scanlines & 0x100)
783 r7 |= 0x02;
784 if (scanlines & 0x200)
785 r7 |= 0x40;
786
787
788 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
789 vsync_end = inb_p(vga_video_port_val);
790 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
791 outb_p(vsync_end & ~0x80, vga_video_port_val);
792 }
793
794 outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
795 outb_p(width - 1, vga_video_port_val);
796 outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
797 outb_p(width >> 1, vga_video_port_val);
798
799 if (vga_video_type >= VIDEO_TYPE_VGAC) {
800 outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
801 outb_p(scanlines_lo, vga_video_port_val);
802 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
803 outb_p(r7,vga_video_port_val);
804
805
806 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
807 outb_p(vsync_end, vga_video_port_val);
808 }
809
810 spin_unlock_irqrestore(&vga_lock, flags);
811 return 0;
812}
813
814static int vgacon_switch(struct vc_data *c)
815{
816 int x = c->vc_cols * VGA_FONTWIDTH;
817 int y = c->vc_rows * c->vc_font.height;
818 int rows = screen_info.orig_video_lines * vga_default_font_height/
819 c->vc_font.height;
820
821
822
823
824
825 vga_video_num_columns = c->vc_cols;
826 vga_video_num_lines = c->vc_rows;
827
828
829
830
831 if (!vga_is_gfx) {
832 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
833 c->vc_screenbuf_size > vga_vram_size ?
834 vga_vram_size : c->vc_screenbuf_size);
835
836 if ((vgacon_xres != x || vgacon_yres != y) &&
837 (!(vga_video_num_columns % 2) &&
838 vga_video_num_columns <= screen_info.orig_video_cols &&
839 vga_video_num_lines <= rows))
840 vgacon_doresize(c, c->vc_cols, c->vc_rows);
841 }
842
843 vgacon_scrollback_init(c->vc_size_row);
844 return 0;
845}
846
847static void vga_set_palette(struct vc_data *vc, unsigned char *table)
848{
849 int i, j;
850
851 vga_w(state.vgabase, VGA_PEL_MSK, 0xff);
852 for (i = j = 0; i < 16; i++) {
853 vga_w(state.vgabase, VGA_PEL_IW, table[i]);
854 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
855 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
856 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
857 }
858}
859
860static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
861{
862#ifdef CAN_LOAD_PALETTE
863 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
864 || !CON_IS_VISIBLE(vc))
865 return -EINVAL;
866 vga_set_palette(vc, table);
867 return 0;
868#else
869 return -EINVAL;
870#endif
871}
872
873
874static struct {
875 unsigned char SeqCtrlIndex;
876 unsigned char CrtCtrlIndex;
877 unsigned char CrtMiscIO;
878 unsigned char HorizontalTotal;
879 unsigned char HorizDisplayEnd;
880 unsigned char StartHorizRetrace;
881 unsigned char EndHorizRetrace;
882 unsigned char Overflow;
883 unsigned char StartVertRetrace;
884 unsigned char EndVertRetrace;
885 unsigned char ModeControl;
886 unsigned char ClockingMode;
887} vga_state;
888
889static void vga_vesa_blank(struct vgastate *state, int mode)
890{
891
892 if (!vga_vesa_blanked) {
893 spin_lock_irq(&vga_lock);
894 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
895 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
896 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
897 spin_unlock_irq(&vga_lock);
898
899 outb_p(0x00, vga_video_port_reg);
900 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
901 outb_p(0x01, vga_video_port_reg);
902 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
903 outb_p(0x04, vga_video_port_reg);
904 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
905 outb_p(0x05, vga_video_port_reg);
906 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
907 outb_p(0x07, vga_video_port_reg);
908 vga_state.Overflow = inb_p(vga_video_port_val);
909 outb_p(0x10, vga_video_port_reg);
910 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
911 outb_p(0x11, vga_video_port_reg);
912 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
913 outb_p(0x17, vga_video_port_reg);
914 vga_state.ModeControl = inb_p(vga_video_port_val);
915 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
916 }
917
918
919
920 spin_lock_irq(&vga_lock);
921 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
922
923
924 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
925 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
926
927
928
929
930
931
932 if (mode & VESA_VSYNC_SUSPEND) {
933 outb_p(0x10, vga_video_port_reg);
934 outb_p(0xff, vga_video_port_val);
935 outb_p(0x11, vga_video_port_reg);
936 outb_p(0x40, vga_video_port_val);
937 outb_p(0x07, vga_video_port_reg);
938 outb_p(vga_state.Overflow | 0x84, vga_video_port_val);
939 }
940
941 if (mode & VESA_HSYNC_SUSPEND) {
942
943
944
945
946
947 outb_p(0x04, vga_video_port_reg);
948 outb_p(0xff, vga_video_port_val);
949 outb_p(0x05, vga_video_port_reg);
950 outb_p(0x00, vga_video_port_val);
951 }
952
953
954 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
955 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
956 spin_unlock_irq(&vga_lock);
957}
958
959static void vga_vesa_unblank(struct vgastate *state)
960{
961
962 spin_lock_irq(&vga_lock);
963 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
964
965 outb_p(0x00, vga_video_port_reg);
966 outb_p(vga_state.HorizontalTotal, vga_video_port_val);
967 outb_p(0x01, vga_video_port_reg);
968 outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
969 outb_p(0x04, vga_video_port_reg);
970 outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
971 outb_p(0x05, vga_video_port_reg);
972 outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
973 outb_p(0x07, vga_video_port_reg);
974 outb_p(vga_state.Overflow, vga_video_port_val);
975 outb_p(0x10, vga_video_port_reg);
976 outb_p(vga_state.StartVertRetrace, vga_video_port_val);
977 outb_p(0x11, vga_video_port_reg);
978 outb_p(vga_state.EndVertRetrace, vga_video_port_val);
979 outb_p(0x17, vga_video_port_reg);
980 outb_p(vga_state.ModeControl, vga_video_port_val);
981
982 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
983
984
985 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
986 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
987 spin_unlock_irq(&vga_lock);
988}
989
990static void vga_pal_blank(struct vgastate *state)
991{
992 int i;
993
994 vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
995 for (i = 0; i < 16; i++) {
996 vga_w(state->vgabase, VGA_PEL_IW, i);
997 vga_w(state->vgabase, VGA_PEL_D, 0);
998 vga_w(state->vgabase, VGA_PEL_D, 0);
999 vga_w(state->vgabase, VGA_PEL_D, 0);
1000 }
1001}
1002
1003static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
1004{
1005 switch (blank) {
1006 case 0:
1007 if (vga_vesa_blanked) {
1008 vga_vesa_unblank(&state);
1009 vga_vesa_blanked = 0;
1010 }
1011 if (vga_palette_blanked) {
1012 vga_set_palette(c, color_table);
1013 vga_palette_blanked = 0;
1014 return 0;
1015 }
1016 vga_is_gfx = 0;
1017
1018 return 1;
1019 case 1:
1020 case -1:
1021 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
1022 vga_pal_blank(&state);
1023 vga_palette_blanked = 1;
1024 return 0;
1025 }
1026 vgacon_set_origin(c);
1027 scr_memsetw((void *) vga_vram_base, BLANK,
1028 c->vc_screenbuf_size);
1029 if (mode_switch)
1030 vga_is_gfx = 1;
1031 return 1;
1032 default:
1033 if (vga_video_type == VIDEO_TYPE_VGAC) {
1034 vga_vesa_blank(&state, blank - 1);
1035 vga_vesa_blanked = blank;
1036 }
1037 return 0;
1038 }
1039}
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053#ifdef CAN_LOAD_EGA_FONTS
1054
1055#define colourmap 0xa0000
1056
1057
1058#define blackwmap 0xa0000
1059#define cmapsz 8192
1060
1061static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
1062{
1063 unsigned short video_port_status = vga_video_port_reg + 6;
1064 int font_select = 0x00, beg, i;
1065 char *charmap;
1066
1067 if (vga_video_type != VIDEO_TYPE_EGAM) {
1068 charmap = (char *) VGA_MAP_MEM(colourmap, 0);
1069 beg = 0x0e;
1070#ifdef VGA_CAN_DO_64KB
1071 if (vga_video_type == VIDEO_TYPE_VGAC)
1072 beg = 0x06;
1073#endif
1074 } else {
1075 charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
1076 beg = 0x0a;
1077 }
1078
1079#ifdef BROKEN_GRAPHICS_PROGRAMS
1080
1081
1082
1083
1084 if (!arg)
1085 return -EINVAL;
1086
1087 vga_font_is_default = 0;
1088 font_select = ch512 ? 0x04 : 0x00;
1089#else
1090
1091
1092
1093
1094
1095 if (set) {
1096 vga_font_is_default = !arg;
1097 if (!arg)
1098 ch512 = 0;
1099 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
1100 }
1101
1102 if (!vga_font_is_default)
1103 charmap += 4 * cmapsz;
1104#endif
1105
1106 unlock_kernel();
1107 spin_lock_irq(&vga_lock);
1108
1109 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
1110
1111 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
1112
1113 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
1114
1115 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1116
1117
1118 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
1119
1120 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
1121
1122 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
1123 spin_unlock_irq(&vga_lock);
1124
1125 if (arg) {
1126 if (set)
1127 for (i = 0; i < cmapsz; i++)
1128 vga_writeb(arg[i], charmap + i);
1129 else
1130 for (i = 0; i < cmapsz; i++)
1131 arg[i] = vga_readb(charmap + i);
1132
1133
1134
1135
1136
1137
1138 if (ch512) {
1139 charmap += 2 * cmapsz;
1140 arg += cmapsz;
1141 if (set)
1142 for (i = 0; i < cmapsz; i++)
1143 vga_writeb(arg[i], charmap + i);
1144 else
1145 for (i = 0; i < cmapsz; i++)
1146 arg[i] = vga_readb(charmap + i);
1147 }
1148 }
1149
1150 spin_lock_irq(&vga_lock);
1151
1152 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
1153
1154 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
1155
1156 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
1157
1158 if (set)
1159 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
1160
1161 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1162
1163
1164 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
1165
1166 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
1167
1168 vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
1169
1170
1171 if ((set) && (ch512 != vga_512_chars)) {
1172
1173 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1174 struct vc_data *c = vc_cons[i].d;
1175 if (c && c->vc_sw == &vga_con)
1176 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1177 }
1178 vga_512_chars = ch512;
1179
1180
1181 inb_p(video_port_status);
1182
1183 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
1184
1185
1186 inb_p(video_port_status);
1187 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
1188 }
1189 spin_unlock_irq(&vga_lock);
1190 lock_kernel();
1191 return 0;
1192}
1193
1194
1195
1196
1197static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
1198{
1199 unsigned char ovr, vde, fsr;
1200 int rows, maxscan, i;
1201
1202 rows = vc->vc_scan_lines / fontheight;
1203 maxscan = rows * fontheight - 1;
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215 spin_lock_irq(&vga_lock);
1216 outb_p(0x07, vga_video_port_reg);
1217 ovr = inb_p(vga_video_port_val);
1218 outb_p(0x09, vga_video_port_reg);
1219 fsr = inb_p(vga_video_port_val);
1220 spin_unlock_irq(&vga_lock);
1221
1222 vde = maxscan & 0xff;
1223 ovr = (ovr & 0xbd) +
1224 ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
1225 fsr = (fsr & 0xe0) + (fontheight - 1);
1226
1227 spin_lock_irq(&vga_lock);
1228 outb_p(0x07, vga_video_port_reg);
1229 outb_p(ovr, vga_video_port_val);
1230 outb_p(0x09, vga_video_port_reg);
1231 outb_p(fsr, vga_video_port_val);
1232 outb_p(0x12, vga_video_port_reg);
1233 outb_p(vde, vga_video_port_val);
1234 spin_unlock_irq(&vga_lock);
1235 vga_video_font_height = fontheight;
1236
1237 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1238 struct vc_data *c = vc_cons[i].d;
1239
1240 if (c && c->vc_sw == &vga_con) {
1241 if (CON_IS_VISIBLE(c)) {
1242
1243 cursor_size_lastfrom = 0;
1244 cursor_size_lastto = 0;
1245 c->vc_sw->con_cursor(c, CM_DRAW);
1246 }
1247 c->vc_font.height = fontheight;
1248 vc_resize(c, 0, rows);
1249 }
1250 }
1251 return 0;
1252}
1253
1254static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
1255{
1256 unsigned charcount = font->charcount;
1257 int rc;
1258
1259 if (vga_video_type < VIDEO_TYPE_EGAM)
1260 return -EINVAL;
1261
1262 if (font->width != VGA_FONTWIDTH ||
1263 (charcount != 256 && charcount != 512))
1264 return -EINVAL;
1265
1266 rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
1267 if (rc)
1268 return rc;
1269
1270 if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1271 rc = vgacon_adjust_height(c, font->height);
1272 return rc;
1273}
1274
1275static int vgacon_font_get(struct vc_data *c, struct console_font *font)
1276{
1277 if (vga_video_type < VIDEO_TYPE_EGAM)
1278 return -EINVAL;
1279
1280 font->width = VGA_FONTWIDTH;
1281 font->height = c->vc_font.height;
1282 font->charcount = vga_512_chars ? 512 : 256;
1283 if (!font->data)
1284 return 0;
1285 return vgacon_do_font_op(&state, font->data, 0, vga_512_chars);
1286}
1287
1288#else
1289
1290#define vgacon_font_set NULL
1291#define vgacon_font_get NULL
1292
1293#endif
1294
1295static int vgacon_resize(struct vc_data *c, unsigned int width,
1296 unsigned int height, unsigned int user)
1297{
1298 if (width % 2 || width > screen_info.orig_video_cols ||
1299 height > (screen_info.orig_video_lines * vga_default_font_height)/
1300 c->vc_font.height)
1301
1302
1303 return (user) ? 0 : -EINVAL;
1304
1305 if (CON_IS_VISIBLE(c) && !vga_is_gfx)
1306 vgacon_doresize(c, width, height);
1307 return 0;
1308}
1309
1310static int vgacon_set_origin(struct vc_data *c)
1311{
1312 if (vga_is_gfx ||
1313 (console_blanked && !vga_palette_blanked))
1314 return 0;
1315 c->vc_origin = c->vc_visible_origin = vga_vram_base;
1316 vga_set_mem_top(c);
1317 vga_rolled_over = 0;
1318 return 1;
1319}
1320
1321static void vgacon_save_screen(struct vc_data *c)
1322{
1323 static int vga_bootup_console = 0;
1324
1325 if (!vga_bootup_console) {
1326
1327
1328
1329
1330 vga_bootup_console = 1;
1331 c->vc_x = screen_info.orig_x;
1332 c->vc_y = screen_info.orig_y;
1333 }
1334
1335
1336
1337
1338 if (!vga_is_gfx)
1339 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1340 c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1341}
1342
1343static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1344 int lines)
1345{
1346 unsigned long oldo;
1347 unsigned int delta;
1348
1349 if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1350 return 0;
1351
1352 if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1353 return 0;
1354
1355 vgacon_restore_screen(c);
1356 oldo = c->vc_origin;
1357 delta = lines * c->vc_size_row;
1358 if (dir == SM_UP) {
1359 vgacon_scrollback_update(c, t, lines);
1360 if (c->vc_scr_end + delta >= vga_vram_end) {
1361 scr_memcpyw((u16 *) vga_vram_base,
1362 (u16 *) (oldo + delta),
1363 c->vc_screenbuf_size - delta);
1364 c->vc_origin = vga_vram_base;
1365 vga_rolled_over = oldo - vga_vram_base;
1366 } else
1367 c->vc_origin += delta;
1368 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1369 delta), c->vc_video_erase_char,
1370 delta);
1371 } else {
1372 if (oldo - delta < vga_vram_base) {
1373 scr_memmovew((u16 *) (vga_vram_end -
1374 c->vc_screenbuf_size +
1375 delta), (u16 *) oldo,
1376 c->vc_screenbuf_size - delta);
1377 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1378 vga_rolled_over = 0;
1379 } else
1380 c->vc_origin -= delta;
1381 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1382 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1383 delta);
1384 }
1385 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1386 c->vc_visible_origin = c->vc_origin;
1387 vga_set_mem_top(c);
1388 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1389 return 1;
1390}
1391
1392
1393
1394
1395
1396
1397static int vgacon_dummy(struct vc_data *c)
1398{
1399 return 0;
1400}
1401
1402#define DUMMY (void *) vgacon_dummy
1403
1404const struct consw vga_con = {
1405 .owner = THIS_MODULE,
1406 .con_startup = vgacon_startup,
1407 .con_init = vgacon_init,
1408 .con_deinit = vgacon_deinit,
1409 .con_clear = DUMMY,
1410 .con_putc = DUMMY,
1411 .con_putcs = DUMMY,
1412 .con_cursor = vgacon_cursor,
1413 .con_scroll = vgacon_scroll,
1414 .con_bmove = DUMMY,
1415 .con_switch = vgacon_switch,
1416 .con_blank = vgacon_blank,
1417 .con_font_set = vgacon_font_set,
1418 .con_font_get = vgacon_font_get,
1419 .con_resize = vgacon_resize,
1420 .con_set_palette = vgacon_set_palette,
1421 .con_scrolldelta = vgacon_scrolldelta,
1422 .con_set_origin = vgacon_set_origin,
1423 .con_save_screen = vgacon_save_screen,
1424 .con_build_attr = vgacon_build_attr,
1425 .con_invert_region = vgacon_invert_region,
1426};
1427
1428MODULE_LICENSE("GPL");
1429