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