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