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