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