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