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